Skip to content

Commit f7f9555

Browse files
committed
Merge #1044: Define Taproot activation parameters for Liquid
3cb9612 test: add test for Taproot activation (Andrew Poelstra) 5291c0d chainparams: add undocumented regtest/testnet only -con_taproot_signal_start option (Andrew Poelstra) cc6b933 add missing taproot activation params for Liquid v1 (Andrew Poelstra) bec6bcf versionbits: allow specific deployments to override the signalling/threshold values (Andrew Poelstra) Pull request description: Sets Taproot to start signalling around noon (California time) on Nov 1, 2021, assuming 95% of blocks are produced between now and then. Will activate after one week of 100% signalling. If we can pull this off on the first or second try, we will beat Bitcoin which currently looks like it will activate on Nov 16. **Edit:** actually, even without Speedy Trial, there is one full period (week) where Taproot will be "locked in" but not "active". So it will activate on Nov 15 at the earliest. ACKs for top commit: achow101: ACK 3cb9612 Tree-SHA512: c3a80d39ba86a0d762a3057cb9c45e379c70c2daee8ff2e54978a4c32118c935c8909d872ac9f873e283441c52c1974c06268f10dc7bf9e9e000c21063ac84d7
2 parents ade3237 + 3cb9612 commit f7f9555

File tree

6 files changed

+156
-3
lines changed

6 files changed

+156
-3
lines changed

src/chainparams.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -478,8 +478,10 @@ class CRegTestParams : public CChainParams {
478478
consensus.vDeployments[Consensus::DEPLOYMENT_DYNA_FED].nStartTime = 1199145601; // January 1, 2008
479479
consensus.vDeployments[Consensus::DEPLOYMENT_DYNA_FED].nTimeout = 1230767999; // December 31, 2008
480480
consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].bit = 2;
481-
consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nStartTime = Consensus::BIP9Deployment::ALWAYS_ACTIVE;
481+
consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nStartTime = gArgs.GetArg("-con_taproot_signal_start", Consensus::BIP9Deployment::ALWAYS_ACTIVE);
482482
consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT;
483+
consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nPeriod = 128; // test ability to change from default
484+
consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nThreshold = 128;
483485

484486
consensus.nMinimumChainWork = uint256{};
485487
consensus.defaultAssumeValid = uint256{};
@@ -978,6 +980,12 @@ class CLiquidV1Params : public CChainParams {
978980
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 0;
979981
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT;
980982

983+
consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].bit = 2;
984+
consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nStartTime = 1554500; // November 1, 2021
985+
consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT;
986+
consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nPeriod = 10080; // one week...
987+
consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nThreshold = 10080; // ...of 100% signalling
988+
981989
// Activated from block 1,000,000.
982990
consensus.vDeployments[Consensus::DEPLOYMENT_DYNA_FED].bit = 25;
983991
// Allow blocksigners to delay activation.
@@ -1245,6 +1253,10 @@ class CLiquidV1TestParams : public CLiquidV1Params {
12451253
consensus.vDeployments[Consensus::DEPLOYMENT_DYNA_FED].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT;
12461254
}
12471255

1256+
if (args.IsArgSet("-con_taproot_signal_start")) {
1257+
consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nStartTime = gArgs.GetArg("-con_taproot_signal_start", 0);
1258+
}
1259+
12481260
// END ELEMENTS fields
12491261
}
12501262

src/chainparamsbase.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ void SetupChainParamsBaseOptions(ArgsManager& argsman)
6060
argsman.AddArg("-con_dyna_deploy_signal", "Whether to signal for the Dynamic Federations deployment (default: false).", ArgsManager::ALLOW_ANY, OptionsCategory::ELEMENTS);
6161
argsman.AddArg("-dynamic_epoch_length", "Per-chain parameter that sets how many blocks dynamic federation voting and enforcement are in effect for.", ArgsManager::ALLOW_ANY, OptionsCategory::ELEMENTS);
6262
argsman.AddArg("-total_valid_epochs", "Per-chain parameter that sets how long a particular fedpegscript is in effect for.", ArgsManager::ALLOW_ANY, OptionsCategory::ELEMENTS);
63+
argsman.AddArg("-con_taproot_signal_start", "Whether, and at what blockheight, to start signalling for Taproot activation (default: false) (regtest, Liquid testnet, or custom only).", ArgsManager::ALLOW_ANY, OptionsCategory::ELEMENTS);
6364
// END ELEMENTS
6465
//
6566
}

src/consensus/params.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#define BITCOIN_CONSENSUS_PARAMS_H
88

99
#include <asset.h>
10+
#include <optional.h>
1011
#include <uint256.h>
1112
#include <limits>
1213

@@ -37,6 +38,11 @@ struct BIP9Deployment {
3738
// ELEMENTS: Interpreted as block height!
3839
int64_t nTimeout;
3940

41+
// ELEMENTS: allow overriding the signalling period length rather than using `nMinerConfirmationWindow`
42+
Optional<uint32_t> nPeriod{nullopt};
43+
// ELEMENTS: allow overriding the activation threshold rather than using `nRuleChangeActivationThreshold`
44+
Optional<uint32_t> nThreshold{nullopt};
45+
4046
/** Constant for nTimeout very far in the future. */
4147
static constexpr int64_t NO_TIMEOUT = std::numeric_limits<int64_t>::max();
4248

src/versionbits.cpp

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -180,8 +180,20 @@ class VersionBitsConditionChecker : public AbstractThresholdConditionChecker {
180180
protected:
181181
int64_t BeginTime(const Consensus::Params& params) const override { return params.vDeployments[id].nStartTime; }
182182
int64_t EndTime(const Consensus::Params& params) const override { return params.vDeployments[id].nTimeout; }
183-
int Period(const Consensus::Params& params) const override { return params.nMinerConfirmationWindow; }
184-
int Threshold(const Consensus::Params& params) const override { return params.nRuleChangeActivationThreshold; }
183+
int Period(const Consensus::Params& params) const override {
184+
if (params.vDeployments[id].nPeriod) {
185+
return *params.vDeployments[id].nPeriod;
186+
} else {
187+
return params.nMinerConfirmationWindow;
188+
}
189+
}
190+
int Threshold(const Consensus::Params& params) const override {
191+
if (params.vDeployments[id].nThreshold) {
192+
return *params.vDeployments[id].nThreshold;
193+
} else {
194+
return params.nRuleChangeActivationThreshold;
195+
}
196+
}
185197

186198
bool Condition(const CBlockIndex* pindex, const Consensus::Params& params) const override
187199
{
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
#!/usr/bin/env python3
2+
# Copyright (c) 2015-2020 The Bitcoin Core developers
3+
# Distributed under the MIT software license, see the accompanying
4+
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
5+
"""Test Taproot soft fork activation for Elements
6+
7+
Unlike Bitcoin, this (a) does not use Speedy Trial, and (b) does use
8+
a pair of new versionbits features which allows Taproot to have its
9+
own signalling period length (128 blocks on regtest) and activation
10+
threshold (100%).
11+
12+
The primary purpose of this test is to confirm that this configuration
13+
works; the actual activation (e.g. how are Taproot-enabled transactions
14+
treated) is covered by other tests and by manual testing.
15+
16+
There is an undocumented option `con_taproot_signal_start` which sets
17+
the block at which signalling starts; otherwise it is set to "always
18+
on" which means that signalling will not occur.
19+
"""
20+
21+
from test_framework.test_framework import BitcoinTestFramework
22+
from test_framework.util import assert_equal
23+
24+
class TaprootActivationTest(BitcoinTestFramework):
25+
def set_test_params(self):
26+
self.setup_clean_chain = True
27+
self.num_nodes = 1
28+
29+
def skip_test_if_missing_module(self):
30+
self.skip_if_no_wallet()
31+
32+
def test_activation(self, rpc, activation_height):
33+
self.log.info("Testing activation at height %d" % activation_height)
34+
activation_height = 128 * ((activation_height + 127) // 128)
35+
36+
assert_equal(rpc.getblockcount(), 0)
37+
38+
blocks = rpc.generatetoaddress(activation_height - 2, rpc.getnewaddress())
39+
assert_equal(rpc.getblockcount(), activation_height - 2)
40+
41+
for n, block in enumerate(blocks):
42+
decode = rpc.getblockheader(block)
43+
if n < 143:
44+
assert_equal (decode["versionHex"], "20000000")
45+
elif n < 431:
46+
# TESTDUMMY deployment: 144 blocks active, 144 blocks locked in
47+
assert_equal (decode["versionHex"], "30000000")
48+
else:
49+
assert_equal (decode["versionHex"], "20000000")
50+
51+
assert_equal(rpc.getblockchaininfo()["softforks"]["taproot"]["bip9"]["status"], "defined")
52+
# The 1023rd block does not signal, but changes the signalling state
53+
# to "started" from "defined"
54+
blocks = rpc.generatetoaddress(1, rpc.getnewaddress())
55+
assert_equal(rpc.getblockchaininfo()["softforks"]["taproot"]["bip9"]["status"], "started")
56+
assert_equal(rpc.getblockheader(blocks[0])["versionHex"], "20000000")
57+
58+
blocks = rpc.generatetoaddress(127, rpc.getnewaddress())
59+
for n, block in enumerate(blocks):
60+
decode = rpc.getblockheader(block)
61+
assert_equal (decode["versionHex"], "20000004")
62+
assert_equal(rpc.getblockchaininfo()["softforks"]["taproot"]["bip9"]["status"], "started")
63+
64+
# Fail to signal on the 128th block. Since the threshold for Taproot is
65+
# 100% this will prevent activation. Note that our period is 128, not
66+
# 144 (the default), as we have overridden the period for Taproot. On
67+
# the main Liquid chain it is overridden to be one week of signalling.
68+
block = rpc.getnewblockhex()
69+
block = block[:1] + "0" + block[2:] # turn off Taproot signal
70+
rpc.submitblock(block)
71+
assert_equal(rpc.getblockchaininfo()["softforks"]["taproot"]["bip9"]["status"], "started")
72+
73+
# Run through another 128 blocks, without failing to signal
74+
blocks = rpc.generatetoaddress(127, rpc.getnewaddress())
75+
for n, block in enumerate(blocks):
76+
decode = rpc.getblockheader(block)
77+
assert_equal (decode["versionHex"], "20000004")
78+
assert_equal(rpc.getblockchaininfo()["softforks"]["taproot"]["bip9"]["status"], "started")
79+
# The 128th block then switches from "started" to "locked_in"
80+
blocks = rpc.generatetoaddress(1, rpc.getnewaddress())
81+
assert_equal(rpc.getblockchaininfo()["softforks"]["taproot"]["bip9"]["status"], "locked_in")
82+
assert_equal(rpc.getblockheader(blocks[0])["versionHex"], "20000004")
83+
84+
# Run through another 128 blocks, which will go from "locked in" to "active" regardless of signalling
85+
blocks = rpc.generatetoaddress(127, rpc.getnewaddress())
86+
for n, block in enumerate(blocks):
87+
decode = rpc.getblockheader(block)
88+
assert_equal (decode["versionHex"], "20000004")
89+
assert_equal(rpc.getblockchaininfo()["softforks"]["taproot"]["bip9"]["status"], "locked_in")
90+
block = rpc.getnewblockhex()
91+
block = block[:1] + "0" + block[2:] # turn off Taproot signal
92+
rpc.submitblock(block)
93+
assert_equal(rpc.getblockchaininfo()["softforks"]["taproot"]["bip9"]["status"], "active")
94+
95+
# After the state is "active", signallng stops by default.
96+
blocks = rpc.generatetoaddress(1, self.nodes[0].getnewaddress())
97+
assert_equal(rpc.getblockchaininfo()["softforks"]["taproot"]["bip9"]["status"], "active")
98+
assert_equal(rpc.getblockheader(blocks[0])["versionHex"], "20000000")
99+
100+
def run_test(self):
101+
# Test that regtest nodes without -con_taproot_signal_start never signal
102+
self.log.info("Testing node not configured to activate taproot")
103+
blocks = self.nodes[0].generatetoaddress(2500, self.nodes[0].getnewaddress())
104+
assert_equal(self.nodes[0].getblockcount(), 2500)
105+
for n, block in enumerate(blocks):
106+
decode = self.nodes[0].getblockheader(block)
107+
if n < 143:
108+
assert_equal (decode["versionHex"], "20000000")
109+
elif n < 431:
110+
# TESTDUMMY deployment: 144 blocks active, 144 blocks locked in
111+
assert_equal (decode["versionHex"], "30000000")
112+
else:
113+
assert_equal (decode["versionHex"], "20000000")
114+
115+
# Test activation starting from height 1000
116+
self.restart_node(0, ["-con_taproot_signal_start=500"])
117+
self.nodes[0].invalidateblock(self.nodes[0].getblockhash(1))
118+
self.test_activation(self.nodes[0], 500)
119+
120+
if __name__ == '__main__':
121+
TaprootActivationTest().main()

test/functional/test_runner.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,7 @@
216216
'mining_prioritisetransaction.py',
217217
'p2p_invalid_locator.py',
218218
'p2p_invalid_block.py',
219+
'feature_elements_taproot_activation.py',
219220
# ELEMENTS: needs to be fixed
220221
#'p2p_invalid_messages.py',
221222
'p2p_invalid_tx.py',

0 commit comments

Comments
 (0)