Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HF: Dyanfed pruned header now has extra root #773

Merged
merged 3 commits into from
Nov 11, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/chainparams.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -720,7 +720,8 @@ class CLiquidV1Params : public CChainParams {
// Block signing encumberance script, default of 51 aka OP_TRUE
std::vector<unsigned char> sign_bytes = ParseHex("5b21026a2a106ec32c8a1e8052e5d02a7b0a150423dbd9b116fc48d46630ff6e6a05b92102791646a8b49c2740352b4495c118d876347bf47d0551c01c4332fdc2df526f1a2102888bda53a424466b0451627df22090143bbf7c060e9eacb1e38426f6b07f2ae12102aee8967150dee220f613de3b239320355a498808084a93eaf39a34dcd62024852102d46e9259d0a0bb2bcbc461a3e68f34adca27b8d08fbe985853992b4b104e27412102e9944e35e5750ab621e098145b8e6cf373c273b7c04747d1aa020be0af40ccd62102f9a9d4b10a6d6c56d8c955c547330c589bb45e774551d46d415e51cd9ad5116321033b421566c124dfde4db9defe4084b7aa4e7f36744758d92806b8f72c2e943309210353dcc6b4cf6ad28aceb7f7b2db92a4bf07ac42d357adf756f3eca790664314b621037f55980af0455e4fb55aad9b85a55068bb6dc4740ea87276dc693f4598db45fa210384001daa88dabd23db878dbb1ce5b4c2a5fa72c3113e3514bf602325d0c37b8e21039056d089f2fe72dbc0a14780b4635b0dc8a1b40b7a59106325dd1bc45cc70493210397ab8ea7b0bf85bc7fc56bb27bf85e75502e94e76a6781c409f3f2ec3d1122192103b00e3b5b77884bf3cae204c4b4eac003601da75f96982ffcb3dcb29c5ee419b92103c1f3c0874cfe34b8131af34699589aacec4093399739ae352e8a46f80a6f68375fae");
consensus.signblockscript = CScript(sign_bytes.begin(), sign_bytes.end());
consensus.max_block_signature_size = 12*74; // 11 signatures plus wiggle room
// 11 signatures, 15 pubkeys, plus wiggle room
consensus.max_block_signature_size = 12*74+16*33;
g_signed_blocks = true;

g_con_blockheightinheader = true;
Expand Down
13 changes: 7 additions & 6 deletions src/dynafed.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ DynaFedParamEntry ComputeNextBlockFullCurrentParameters(const CBlockIndex* pinde
CScript sh_wsh_fedpeg_program = CScript() << OP_HASH160 << ToByteVector(fedpeg_p2sh) << OP_EQUAL;

// Put them in winning proposal
winning_proposal = DynaFedParamEntry(p2wsh_signblock_script, consensus.max_block_signature_size+consensus.signblockscript.size(), sh_wsh_fedpeg_program, consensus.fedpegScript, consensus.first_extension_space);
winning_proposal = DynaFedParamEntry(p2wsh_signblock_script, consensus.max_block_signature_size, sh_wsh_fedpeg_program, consensus.fedpegScript, consensus.first_extension_space);
} else {
winning_proposal = p_epoch_start->dynafed_params.m_current;
}
Expand All @@ -91,12 +91,13 @@ DynaFedParamEntry ComputeNextBlockCurrentParameters(const CBlockIndex* pindexPre
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 DynaFedParamEntry(entry.m_signblockscript, entry.m_signblock_witness_limit);
} else {
// Return appropriate format based on epoch age or if we *just* activated
// dynafed via BIP9
if (epoch_age == 0 || pindexPrev->dynafed_params.IsNull()) {
return entry;
} else {
return DynaFedParamEntry(entry.m_signblockscript, entry.m_signblock_witness_limit, entry.CalculateExtraRoot());

}
}

4 changes: 2 additions & 2 deletions src/miner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -151,8 +151,8 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc
fIncludeWitness = IsWitnessEnabled(pindexPrev, chainparams.GetConsensus());

if (IsDynaFedEnabled(pindexPrev, chainparams.GetConsensus())) {
DynaFedParamEntry current_params = ComputeNextBlockCurrentParameters(chainActive.Tip(), chainparams.GetConsensus());
DynaFedParams block_params(current_params, proposed_entry ? *proposed_entry : DynaFedParamEntry());
const DynaFedParamEntry current_params = ComputeNextBlockCurrentParameters(chainActive.Tip(), chainparams.GetConsensus());
const DynaFedParams block_params(current_params, proposed_entry ? *proposed_entry : DynaFedParamEntry());
pblock->m_dynafed_params = block_params;
nBlockWeight += ::GetSerializeSize(block_params, PROTOCOL_VERSION)*WITNESS_SCALE_FACTOR;
nBlockWeight += current_params.m_signblock_witness_limit; // Note witness discount
Expand Down
32 changes: 26 additions & 6 deletions src/primitives/block.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,19 +43,39 @@ std::string CBlock::ToString() const

uint256 DynaFedParamEntry::CalculateRoot() const
{
if (IsNull()) {
if (m_serialize_type == 0) {
return uint256();
}

std::vector<uint256> compact_leaves;
compact_leaves.push_back(SerializeHash(m_signblockscript, SER_GETHASH, 0));
compact_leaves.push_back(SerializeHash(m_signblock_witness_limit, SER_GETHASH, 0));
uint256 compact_root(ComputeFastMerkleRoot(compact_leaves));

uint256 extra_root;
if (m_serialize_type ==1 ) {
// It's pruned, take the stored value
extra_root = m_elided_root;
} else if (m_serialize_type == 2) {
// It's unpruned, compute the node value
extra_root = CalculateExtraRoot();
}

std::vector<uint256> leaves;
leaves.push_back(SerializeHash(m_signblockscript, SER_GETHASH, 0));
leaves.push_back(SerializeHash(m_signblock_witness_limit, SER_GETHASH, 0));
leaves.push_back(SerializeHash(m_fedpeg_program, SER_GETHASH, 0));
leaves.push_back(SerializeHash(m_fedpegscript, SER_GETHASH, 0));
leaves.push_back(SerializeHash(m_extension_space, SER_GETHASH, 0));
leaves.push_back(compact_root);
leaves.push_back(extra_root);
return ComputeFastMerkleRoot(leaves);
}

uint256 DynaFedParamEntry::CalculateExtraRoot() const
{
std::vector<uint256> extra_leaves;
extra_leaves.push_back(SerializeHash(m_fedpeg_program, SER_GETHASH, 0));
extra_leaves.push_back(SerializeHash(m_fedpegscript, SER_GETHASH, 0));
extra_leaves.push_back(SerializeHash(m_extension_space, SER_GETHASH, 0));
return ComputeFastMerkleRoot(extra_leaves);
}

uint256 DynaFedParams::CalculateRoot() const
{
if (IsNull()) {
Expand Down
14 changes: 12 additions & 2 deletions src/primitives/block.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,18 +58,25 @@ class CProof
class DynaFedParamEntry
{
public:
unsigned char m_serialize_type; // Determines how it is serialized, defaults to null
// Determines how these entries are serialized and stored
// 0 -> Null. Only used for proposed parameter "null votes"
// 1 -> Pruned. Doesn't have non-signblockscript data. That elided data
// is committed to in m_elided_root, and validated against chainstate.
// 2 -> Full. Typically only consensus-legal at epoch start.
unsigned char m_serialize_type;

CScript m_signblockscript;
uint32_t m_signblock_witness_limit; // Max block signature witness serialized size
CScript m_fedpeg_program; // The "scriptPubKey" of the fedpegscript
CScript m_fedpegscript; // The witnessScript for witness v0 or undefined otherwise.
// No consensus meaning to the particular bytes, currently we interpret as PAK keys, details in pak.h
std::vector<std::vector<unsigned char>> m_extension_space;
uint256 m_elided_root; // non-zero only when m_serialize_type == 1

// Each constructor sets its own serialization type implicitly based on which
// arguments are given
DynaFedParamEntry() { m_signblock_witness_limit = 0; m_serialize_type = 0; };
DynaFedParamEntry(const CScript& signblockscript_in, const uint32_t sbs_wit_limit_in) : m_signblockscript(signblockscript_in), m_signblock_witness_limit(sbs_wit_limit_in) { m_serialize_type = 1; };
DynaFedParamEntry(const CScript& signblockscript_in, const uint32_t sbs_wit_limit_in, const uint256 elided_root_in) : m_signblockscript(signblockscript_in), m_signblock_witness_limit(sbs_wit_limit_in), m_elided_root(elided_root_in) { m_serialize_type = 1; };
DynaFedParamEntry(const CScript& signblockscript_in, const uint32_t sbs_wit_limit_in, const CScript& fedpeg_program_in, const CScript& fedpegscript_in, const std::vector<std::vector<unsigned char>> extension_space_in) : m_signblockscript(signblockscript_in), m_signblock_witness_limit(sbs_wit_limit_in), m_fedpeg_program(fedpeg_program_in), m_fedpegscript(fedpegscript_in), m_extension_space(extension_space_in) { m_serialize_type = 2; };

ADD_SERIALIZE_METHODS;
Expand All @@ -84,6 +91,7 @@ class DynaFedParamEntry
case 1:
READWRITE(m_signblockscript);
READWRITE(m_signblock_witness_limit);
READWRITE(m_elided_root);
break;
case 2:
READWRITE(m_signblockscript);
Expand All @@ -98,6 +106,8 @@ class DynaFedParamEntry
}

uint256 CalculateRoot() const;
// Calculates root for the non-blocksigning merkle fields
uint256 CalculateExtraRoot() const;

bool IsNull() const
{
Expand Down
8 changes: 4 additions & 4 deletions src/test/dynafed_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,23 +21,23 @@ BOOST_AUTO_TEST_CASE(dynafed_params_root)
CScript fp_script(opcodetype(4));
std::vector<std::vector<unsigned char>> ext{ {5, 6}, {7} };

DynaFedParamEntry compact_entry = DynaFedParamEntry(signblockscript, signblock_wl);
DynaFedParamEntry compact_entry = DynaFedParamEntry(signblockscript, signblock_wl, uint256());
BOOST_CHECK_EQUAL(
compact_entry.CalculateRoot().GetHex(),
"dff5f3793abc06a6d75e80fe3cfd47406f732fa4ec9305960ae2a229222a1ad5"
"f98f149fd11da6fbe26d0ee53cadd28372fa9eed2cb7080f41da7ca311531777"
);

DynaFedParamEntry full_entry =
DynaFedParamEntry(signblockscript, signblock_wl, fp_program, fp_script, ext);
BOOST_CHECK_EQUAL(
full_entry.CalculateRoot().GetHex(),
"175be2087ba7cc0e33348bef493bd3e34f31f64bf9226e5881ab310dafa432ff"
"8eb1b83cce69a3d8b0bfb7fbe77ae8f1d24b57a9cae047b8c0aba084ad878249"
);

DynaFedParams params = DynaFedParams(compact_entry, full_entry);
BOOST_CHECK_EQUAL(
params.CalculateRoot().GetHex(),
"e56cf79487952dfa85fe6a85829600adc19714ba6ab1157fdff02b25ae60cee2"
"113160f76dc17fe367a2def79aefe06feeea9c795310c9e88aeedc23e145982e"
);
}

Expand Down
10 changes: 6 additions & 4 deletions test/functional/feature_blocksign.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ def set_test_params(self):
self.witnessScript = signblockscript # post-dynafed this becomes witnessScript
self.extra_args = [[
"-signblockscript={}".format(signblockscript),
"-con_max_block_sig_size={}".format(self.required_signers*74),
"-con_max_block_sig_size={}".format(self.required_signers*74+self.num_nodes*33),
"-anyonecanspendaremine=1",
"-con_dyna_deploy_start=0",
]] * self.num_nodes
Expand Down Expand Up @@ -218,14 +218,16 @@ def run_test(self):

# Next let's activate dynafed
blocks_til_dynafed = 431 - self.nodes[0].getblockcount()
self.log.info("Activating dynafed")
self.mine_blocks(blocks_til_dynafed, False)
self.check_height(111+blocks_til_dynafed)

assert_equal(self.nodes[0].getblockchaininfo()['bip9_softforks']['dynafed']['status'], "active")

self.log.info("Mine some dynamic federation blocks without and with txns")
self.mine_blocks(50, False)
self.mine_blocks(50, True)
self.log.info("Mine some dynamic federation blocks without txns")
self.mine_blocks(10, False)
self.log.info("Mine some dynamic federation blocks with txns")
self.mine_blocks(10, True)

if __name__ == '__main__':
BlockSignTest().main()
20 changes: 10 additions & 10 deletions test/functional/feature_dynafed.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def go_to_epoch_end(node):
blocks_to_mine = epoch_info["epoch_length"] - epoch_info["epoch_age"] - 1
node.generatetoaddress(blocks_to_mine, node.getnewaddress())

def validate_no_vote_op_true(node, block):
def validate_no_vote_op_true(node, block, first_dynafed_active_block):

block_info = node.getblock(block)
dynamic_parameters = block_info["dynamic_parameters"]
Expand All @@ -44,14 +44,13 @@ def validate_no_vote_op_true(node, block):
# signblockscript is now the P2WSH-ification of OP_TRUE
WSH_OP_TRUE = node.decodescript("51")["segwit"]["hex"]
assert_equal(dynamic_parameters["current"]["signblockscript"], WSH_OP_TRUE)
if block_height % 10 == 0:
if block_height % 10 == 0 or first_dynafed_active_block:
assert_equal(dynamic_parameters["current"]["fedpegscript"], "51")
assert_equal(dynamic_parameters["current"]["extension_space"], initial_extension)
else:
assert_equal(dynamic_parameters["current"]["fedpegscript"], "")
assert_equal(dynamic_parameters["current"]["extension_space"], [])
# TODO workshop this bump, or commit to new value in chainparams instead
assert_equal(dynamic_parameters["current"]["max_block_witness"], 75)
assert_equal(dynamic_parameters["current"]["max_block_witness"], 74)
# nothing was proposed, null fields make impossible to be valid blockheader
# due to script rules requiring bool true on stack
assert_equal(dynamic_parameters["proposed"]["signblockscript"], "")
Expand Down Expand Up @@ -118,8 +117,9 @@ def test_dynafed_activation(self):
# Next block is first dynamic federation block
block = self.nodes[0].generatetoaddress(1, self.nodes[0].getnewaddress())[0]
self.sync_all()
# We publish full block on BIP9 transition
for i in range(self.num_nodes):
validate_no_vote_op_true(self.nodes[i], block)
validate_no_vote_op_true(self.nodes[i], block, True)

def test_illegal_proposals(self):

Expand Down Expand Up @@ -148,14 +148,14 @@ def test_no_vote(self):

for i in range(self.num_nodes):
for block in blocks:
validate_no_vote_op_true(self.nodes[i], block)
validate_no_vote_op_true(self.nodes[i], block, False)

# Now transition using vanilla getnewblockhex, nothing changed
block = self.nodes[0].generatetoaddress(1, self.nodes[0].getnewaddress())[0]
self.sync_all()

for i in range(self.num_nodes):
validate_no_vote_op_true(self.nodes[i], block)
validate_no_vote_op_true(self.nodes[i], block, False)

def test_under_vote(self):
self.log.info("Testing failed voting epoch...")
Expand All @@ -176,7 +176,7 @@ def test_under_vote(self):
self.sync_all()

for i in range(self.num_nodes):
validate_no_vote_op_true(self.nodes[i], block)
validate_no_vote_op_true(self.nodes[i], block, False)

def test_four_fifth_vote(self):
self.log.info("Testing just-successful transition epoch...")
Expand All @@ -192,7 +192,7 @@ def test_four_fifth_vote(self):
chain_info = self.nodes[i].getblockchaininfo()
fedpeg_info = self.nodes[i].getsidechaininfo()
assert_equal(chain_info["current_signblock_hex"], WSH_OP_TRUE)
assert_equal(chain_info["max_block_witness"], 75)
assert_equal(chain_info["max_block_witness"], 74)
assert_equal(chain_info["extension_space"], initial_extension)
assert_equal(fedpeg_info["current_fedpegscripts"], ["51", "51"])

Expand All @@ -210,7 +210,7 @@ def test_four_fifth_vote(self):
chain_info = self.nodes[i].getblockchaininfo()
fedpeg_info = self.nodes[i].getsidechaininfo()
assert_equal(chain_info["current_signblock_hex"], WSH_OP_TRUE)
assert_equal(chain_info["max_block_witness"], 75)
assert_equal(chain_info["max_block_witness"], 74)
assert_equal(chain_info["extension_space"], initial_extension)
assert_equal(fedpeg_info["current_fedpegscripts"], ["51", "51"])

Expand Down
11 changes: 8 additions & 3 deletions test/functional/test_framework/messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -836,22 +836,24 @@ def __repr__(self):
% (self.challenge, self.solution)

class DynaFedParamEntry:
__slots__ = ("m_serialize_type", "m_signblockscript", "m_signblock_witness_limit", "m_fedpeg_program", "m_fedpegscript", "m_extension_space")
__slots__ = ("m_serialize_type", "m_signblockscript", "m_signblock_witness_limit", "m_fedpeg_program", "m_fedpegscript", "m_extension_space", "m_elided_root")

# Constructor args will define serialization type:
# null = 0
# signblock-related fields = 1, required for m_current on non-epoch-starts
# all fields = 2, required for epoch starts
def __init__(self, m_signblockscript=b"", m_signblock_witness_limit=0, m_fedpeg_program=b"", m_fedpegscript=b"", m_extension_space=[]):
def __init__(self, m_signblockscript=b"", m_signblock_witness_limit=0, m_fedpeg_program=b"", m_fedpegscript=b"", m_extension_space=[], m_elided_root=0):
self.m_signblockscript = m_signblockscript
self.m_signblock_witness_limit = m_signblock_witness_limit
self.m_fedpeg_program = m_fedpeg_program
self.m_fedpegscript = m_fedpegscript
self.m_extension_space = m_extension_space
if self.is_null():
self.m_serialize_type = 0
elif m_fedpegscript==b"" and m_extension_space == []:
elif m_fedpegscript==b"" and m_fedpeg_program==b"" and m_extension_space == []:
self.m_serialize_type = 1
# We also set the "extra root" in this case
self.m_elided_root = m_elided_root
else:
self.m_serialize_type = 2

Expand All @@ -862,6 +864,7 @@ def set_null(self):
self.m_fedpegscript = b""
self.m_extension_space = []
self.m_serialize_type = 0
self.m_elided_root = 0

def is_null(self):
return self.m_signblockscript == b"" and self.m_signblock_witness_limit == 0 and \
Expand All @@ -874,6 +877,7 @@ def serialize(self):
if self.m_serialize_type == 1:
r += ser_string(self.m_signblockscript)
r += struct.pack("<I", self.m_signblock_witness_limit)
r += ser_uint256(self.m_elided_root)
elif self.m_serialize_type == 2:
r += ser_string(self.m_signblockscript)
r += struct.pack("<I", self.m_signblock_witness_limit)
Expand All @@ -889,6 +893,7 @@ def deserialize(self, f):
if self.m_serialize_type == 1:
self.m_signblockscript = deser_string(f)
self.m_signblock_witness_limit = struct.unpack("<I", f.read(4))[0]
self.m_elided_root = deser_uint256(f)
elif self.m_serialize_type == 2:
self.m_signblockscript = deser_string(f)
self.m_signblock_witness_limit = struct.unpack("<I", f.read(4))[0]
Expand Down