Add dynafed helper functions

This commit is contained in:
Gregory Sanders 2019-05-31 11:19:46 -04:00
parent 4aa5f991f4
commit f17d7de526
5 changed files with 127 additions and 0 deletions

View file

@ -134,6 +134,7 @@ BITCOIN_CORE_H = \
core_io.h \
core_memusage.h \
cuckoocache.h \
dynafed.h \
fs.h \
httprpc.h \
httpserver.h \
@ -401,10 +402,13 @@ libbitcoin_consensus_a_SOURCES = \
arith_uint256.cpp \
arith_uint256.h \
asset.cpp \
chain.h \
chain.cpp \
consensus/merkle.cpp \
consensus/merkle.h \
consensus/params.h \
consensus/validation.h \
dynafed.cpp \
hash.cpp \
hash.h \
prevector.h \
@ -433,6 +437,8 @@ libbitcoin_consensus_a_SOURCES = \
script/script.h \
script/script_error.cpp \
script/script_error.h \
script/standard.h \
script/standard.cpp \
serialize.h \
span.h \
tinyformat.h \

View file

@ -482,6 +482,9 @@ class CCustomParams : public CRegTestParams {
consensus.nMinimumChainWork = uint256S(args.GetArg("-con_nminimumchainwork", "0x0"));
consensus.defaultAssumeValid = uint256S(args.GetArg("-con_defaultassumevalid", "0x00"));
// TODO: pass in serialized vector of byte vectors, parse into extension space
// Junk keys for testing
consensus.first_extension_space = {ParseHex("02fcba7ecf41bc7e1be4ee122d9d22e3333671eb0a3a87b5cdf099d59874e1940f02fcba7ecf41bc7e1be4ee122d9d22e3333671eb0a3a87b5cdf099d59874e1940f")};
nPruneAfterHeight = (uint64_t)args.GetArg("-npruneafterheight", nPruneAfterHeight);
fDefaultConsistencyChecks = args.GetBoolArg("-fdefaultconsistencychecks", fDefaultConsistencyChecks);

View file

@ -99,6 +99,8 @@ struct Params {
CScript signblockscript;
uint32_t max_block_signature_size;
// g_signed_blocks - Whether blocks are signed or not, get around circular dep
// Used to seed the extension space for first dynamic blocks
std::vector<std::vector<unsigned char>> first_extension_space;
};
} // namespace Consensus

97
src/dynafed.cpp Normal file
View file

@ -0,0 +1,97 @@
#include <dynafed.h>
#include <script/standard.h>
bool NextBlockIsParameterTransition(const CBlockIndex* pindexPrev, const Consensus::Params& consensus, ConsensusParamEntry& winning_entry)
{
uint32_t next_height = pindexPrev->nHeight + 1;
assert(consensus.dynamic_epoch_length != 0);
if (next_height % consensus.dynamic_epoch_length != 0) {
winning_entry.SetNull();
return false;
}
std::map<uint256, uint32_t> vote_tally;
assert(next_height >= consensus.dynamic_epoch_length);
for (int32_t height = next_height - 1; height >= (int32_t)(next_height - consensus.dynamic_epoch_length); --height) {
const CBlockIndex* p_epoch_walk = pindexPrev->GetAncestor(height);
assert(p_epoch_walk);
const ConsensusParamEntry& proposal = p_epoch_walk->d_params.m_proposed;
const uint256 proposal_root = proposal.CalculateRoot();
vote_tally[proposal_root]++;
// Short-circuit once 4/5 threshhold is reached
if (vote_tally[proposal_root] >=
(consensus.dynamic_epoch_length*4)/5) {
winning_entry = proposal;
return true;
}
// Also stop early if "no-vote" crosses 1/4
if (proposal_root.IsNull() &&
vote_tally[proposal_root] > consensus.dynamic_epoch_length/5) {
winning_entry.SetNull();
return false;
}
}
winning_entry.SetNull();
return false;
}
ConsensusParamEntry ComputeNextBlockFullCurrentParameters(const CBlockIndex* pindexPrev, const Consensus::Params& consensus)
{
assert(pindexPrev);
uint32_t next_height = pindexPrev->nHeight+1;
const uint32_t epoch_length = consensus.dynamic_epoch_length;
uint32_t epoch_age = next_height % epoch_length;
ConsensusParamEntry winning_proposal;
// Early return when there is a winning proposal
if (NextBlockIsParameterTransition(pindexPrev, consensus, winning_proposal)) {
assert(epoch_age == 0);
return winning_proposal;
}
// Since no transition took place, find most recent epoch start
// If next block is start of new epoch, walk backwards one epoch
uint32_t epoch_start_height = next_height - epoch_age;
if (epoch_age == 0) {
epoch_start_height -= epoch_length;
}
// We need to put in place the previous epoch's current which
// may be pre-dynafed params
const CBlockIndex* p_epoch_start = pindexPrev->GetAncestor(epoch_start_height);
assert(p_epoch_start);
if (p_epoch_start->d_params.IsNull()) {
// We need to construct the "full" current parameters of pre-dynafed
// consensus
// Convert signblockscript to P2WSH
CScript p2wsh_signblock_script = GetScriptForDestination(WitnessV0ScriptHash(p_epoch_start->proof.challenge));
winning_proposal = ConsensusParamEntry(p2wsh_signblock_script, consensus.max_block_signature_size+consensus.signblockscript.size(), consensus.fedpegScript, consensus.first_extension_space);
} else {
winning_proposal = p_epoch_start->d_params.m_current;
}
return winning_proposal;
}
// TODO cache this in CBlockIndex itself?
ConsensusParamEntry ComputeNextBlockCurrentParameters(const CBlockIndex* pindexPrev, const Consensus::Params& consensus)
{
assert(pindexPrev);
ConsensusParamEntry entry = ComputeNextBlockFullCurrentParameters(pindexPrev, consensus);
uint32_t next_height = pindexPrev->nHeight+1;
const uint32_t epoch_length = consensus.dynamic_epoch_length;
uint32_t epoch_age = next_height % epoch_length;
// Return appropriate format based on epoch age
if (epoch_age > 0) {
// TODO implement "prune" function to remove fields in place and change serialize type
return ConsensusParamEntry(entry.m_signblockscript, entry.m_sbs_wit_limit);
} else {
return entry;
}
}

19
src/dynafed.h Normal file
View file

@ -0,0 +1,19 @@
#ifndef BITCOIN_DYNAFED_H
#define BITCOIN_DYNAFED_H
#include <chain.h>
#include <chainparams.h>
#include <primitives/block.h>
bool NextBlockIsParameterTransition(const CBlockIndex* pindexPrev, const Consensus::Params& consensus, ConsensusParamEntry& winning_entry);
/* Compute the next block's enforced parameters */
ConsensusParamEntry ComputeNextBlockFullCurrentParameters(const CBlockIndex* pindexPrev, const Consensus::Params& consensus);
/* Compute the next block's expected published parameters. Blocks at "epoch_age" of non-0 only
* publish signblockscript-related fields */
ConsensusParamEntry ComputeNextBlockCurrentParameters(const CBlockIndex* pindexPrev, const Consensus::Params& consensus);
#endif // BITCOIN_DYNAFED_H