From 0f9b1a2ed14b4b92d5775e04db47ef9af75a350c Mon Sep 17 00:00:00 2001 From: Steven Roose Date: Tue, 9 Feb 2021 02:00:23 +0100 Subject: [PATCH 1/3] dynafed: Only verify proposed parameters if they differ from current This allows the initial relaxed restriction on non-segwit fedpeg programs to be extended as long as the fedpeg program is not changed while the block signing parameters can be changed. --- src/validation.cpp | 91 ++++++++++++++++++++++++++-------------------- 1 file changed, 52 insertions(+), 39 deletions(-) diff --git a/src/validation.cpp b/src/validation.cpp index 3c5694e3d9..a8c1f60306 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -3485,49 +3485,62 @@ static bool ContextualCheckDynaFedHeader(const CBlockHeader& block, CValidationS return state.Invalid(false, REJECT_INVALID, "invalid-dyna-fed", "dynamic block header's current parameters do not match expected"); } - // Lastly, enforce rules on proposals. - const DynaFedParamEntry& proposed = dynafed_params.m_proposed; - if (!proposed.IsNull()) { + // Lastly, enforce rules on proposals if they make changes. + if (!dynafed_params.m_proposed.IsNull()) { + // Compare the new proposed parameters with the current full parameters. + const DynaFedParamEntry current = ComputeNextBlockFullCurrentParameters(pindexPrev, params.GetConsensus()); + const DynaFedParamEntry& proposed = dynafed_params.m_proposed; - // signblockscript proposals *must* be segwit versions - int block_version = 0; - std::vector block_program; - if (!proposed.m_signblockscript.IsWitnessProgram(block_version, block_program)) { - return state.Invalid(false, REJECT_INVALID, "invalid-dyna-fed", "proposed signblockscript must be native segwit scriptPubkey"); - } - - int fedpeg_version = 0; - std::vector fedpeg_program; - if (!proposed.m_fedpeg_program.IsWitnessProgram(fedpeg_version, fedpeg_program)) { - return state.Invalid(false, REJECT_INVALID, "invalid-dyna-fed", "proposed fedpegs program must be native segwit scriptPubkey"); - } - - // for v0, fedpegscript's scriptPubKey must match. v1+ is unencumbered. - if (fedpeg_version == 0) { - uint256 fedpeg_program; - CSHA256().Write(proposed.m_fedpegscript.data(), proposed.m_fedpegscript.size()).Finalize(fedpeg_program.begin()); - CScript computed_program = CScript() << OP_0 << ToByteVector(fedpeg_program); - if (computed_program != proposed.m_fedpeg_program) { - return state.Invalid(false, REJECT_INVALID, "invalid-dyna-fed", "proposed v0 segwit fedpegscript must match proposed fedpeg witness program"); - } - - // fedpegscript proposals *must not* start with OP_DEPTH - // This forbids the first Liquid watchman script which is a hack. - // Use miniscript, which doesn't even have OP_DEPTH. - // We don't encumber future segwit versions as opcodes may change. - if (!proposed.m_fedpegscript.empty() && - proposed.m_fedpegscript.front() == OP_DEPTH) { - return state.Invalid(false, REJECT_INVALID, "invalid-dyna-fed", "Proposed fedpegscript starts with OP_DEPTH, which is illegal"); + if (proposed.m_signblockscript != current.m_signblockscript) { + // signblockscript proposals *must* be segwit versions + int block_version = 0; + std::vector block_program; + if (!proposed.m_signblockscript.IsWitnessProgram(block_version, block_program)) { + return state.Invalid(false, REJECT_INVALID, "invalid-dyna-fed", + "proposed signblockscript must be native segwit scriptPubkey" + ); } } - // When enforcing PAK, extension_space must give non-empty PAK list when - // the vector itself is non-empty. Otherwise this means there were "junk" - // entries - if (params.GetEnforcePak()) { - if (!proposed.m_extension_space.empty() && - CreatePAKListFromExtensionSpace(proposed.m_extension_space).IsReject()) { - return state.Invalid(false, REJECT_INVALID, "invalid-dyna-fed", "Extension space is not list of valid PAK entries"); + if (proposed.m_fedpeg_program != current.m_fedpeg_program || proposed.m_fedpegscript != current.m_fedpegscript) { + int fedpeg_version = 0; + std::vector fedpeg_program; + if (!proposed.m_fedpeg_program.IsWitnessProgram(fedpeg_version, fedpeg_program)) { + return state.Invalid(false, REJECT_INVALID, "invalid-dyna-fed", "proposed fedpegs program must be native segwit scriptPubkey"); + } + + // for v0, fedpegscript's scriptPubKey must match. v1+ is unencumbered. + if (fedpeg_version == 0) { + uint256 fedpeg_program; + CSHA256().Write(proposed.m_fedpegscript.data(), proposed.m_fedpegscript.size()).Finalize(fedpeg_program.begin()); + CScript computed_program = CScript() << OP_0 << ToByteVector(fedpeg_program); + if (computed_program != proposed.m_fedpeg_program) { + return state.Invalid(false, REJECT_INVALID, "invalid-dyna-fed", + "proposed v0 segwit fedpegscript must match proposed fedpeg witness program" + ); + } + + // fedpegscript proposals *must not* start with OP_DEPTH + // This forbids the first Liquid watchman script which is a hack. + // Use miniscript, which doesn't even have OP_DEPTH. + // We don't encumber future segwit versions as opcodes may change. + if (!proposed.m_fedpegscript.empty() && proposed.m_fedpegscript.front() == OP_DEPTH) { + return state.Invalid(false, REJECT_INVALID, "invalid-dyna-fed", "Proposed fedpegscript starts with OP_DEPTH, which is illegal"); + } + } + } + + if (proposed.m_extension_space != current.m_extension_space) { + // When enforcing PAK, extension_space must give non-empty PAK list when + // the vector itself is non-empty. Otherwise this means there were "junk" + // entries + if (params.GetEnforcePak()) { + if (!proposed.m_extension_space.empty() && + CreatePAKListFromExtensionSpace(proposed.m_extension_space).IsReject()) { + return state.Invalid(false, REJECT_INVALID, "invalid-dyna-fed", + "Extension space is not list of valid PAK entries" + ); + } } } } From ae54a1bad404813c7f7bd6a44f8abbf2c0d09aec Mon Sep 17 00:00:00 2001 From: Steven Roose Date: Tue, 9 Feb 2021 13:10:04 +0100 Subject: [PATCH 2/3] dynafed: Support changing mainnet dynafed activation This should obviously only be done by blocksigners. The flag used is not documented. --- src/chainparams.cpp | 5 +++-- test/functional/feature_dynafed.py | 2 ++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 7ab1a9a91e..356e9bc306 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -882,9 +882,10 @@ public: consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 0; consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT; - // Not active yet. + // Activated from block 1,000,000. consensus.vDeployments[Consensus::DEPLOYMENT_DYNA_FED].bit = 25; - consensus.vDeployments[Consensus::DEPLOYMENT_DYNA_FED].nStartTime = 1000000; + // Allow blocksigners to delay activation. + consensus.vDeployments[Consensus::DEPLOYMENT_DYNA_FED].nStartTime = gArgs.GetArg("-con_dyna_deploy_start", 1000000); consensus.vDeployments[Consensus::DEPLOYMENT_DYNA_FED].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT; diff --git a/test/functional/feature_dynafed.py b/test/functional/feature_dynafed.py index 2ce325e380..df48956e77 100755 --- a/test/functional/feature_dynafed.py +++ b/test/functional/feature_dynafed.py @@ -66,6 +66,8 @@ class DynaFedTest(BitcoinTestFramework): self.extra_args = [["-con_dyna_deploy_start=1000", "-enforce_pak=1", "-con_parent_chain_signblockscript=51", "-peginconfirmationdepth=1", "-parentscriptprefix=75", "-parent_bech32_hrp=ert"] for i in range(self.num_nodes)] # second node will not mine transactions self.extra_args[1].append("-blocksonly=1") + # Make sure nothing breaks if peers have a different activation. + self.extra_args[1][0] = "-con_dyna_deploy_start=937" def skip_test_if_missing_module(self): self.skip_if_no_wallet() From 868e92f78cdcbd7ed0e4aa904f24e85482c4eaaa Mon Sep 17 00:00:00 2001 From: Steven Roose Date: Wed, 24 Feb 2021 15:23:09 +0000 Subject: [PATCH 3/3] Add two missing dynafed fields to getblockchaininfo --- src/rpc/blockchain.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 63d1f2c1aa..22da922b62 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -1469,6 +1469,8 @@ UniValue getblockchaininfo(const JSONRPCRequest& request) obj.pushKV("current_signblock_asm", ScriptToAsmStr(entry.m_signblockscript)); obj.pushKV("current_signblock_hex", HexStr(entry.m_signblockscript)); obj.pushKV("max_block_witness", (uint64_t)entry.m_signblock_witness_limit); + obj.pushKV("current_fedpeg_program", HexStr(entry.m_fedpeg_program)); + obj.pushKV("current_fedpeg_script", HexStr(entry.m_fedpegscript)); UniValue arr(UniValue::VARR); for (const auto& extension : entry.m_extension_space) { arr.push_back(HexStr(extension));