Merge 5d83e7d714 into merged_master (Bitcoin PR bitcoin/bitcoin#21090)

We comment out a newly-added assert from the Bitcoin
side, because it's unclear how to replicate it
correctly in Elements.

Co-authored-by: Glenn Willen <gwillen@nerdnet.org>
This commit is contained in:
James Dorfman 2023-03-21 20:03:58 +00:00 committed by Glenn Willen
commit 17e6efe7fe
9 changed files with 121 additions and 139 deletions

View file

@ -688,11 +688,8 @@ void CRegTestParams::UpdateActivationParametersFromArgs(const ArgsManager& args)
{
if (args.IsArgSet("-segwitheight")) {
int64_t height = args.GetArg("-segwitheight", consensus.SegwitHeight);
if (height < -1 || height >= std::numeric_limits<int>::max()) {
throw std::runtime_error(strprintf("Activation height %ld for segwit is out of valid range. Use -1 to disable segwit.", height));
} else if (height == -1) {
LogPrintf("Segwit disabled for testing\n");
height = std::numeric_limits<int>::max();
if (height < 0 || height >= std::numeric_limits<int>::max()) {
throw std::runtime_error(strprintf("Activation height %ld for segwit is out of valid range.", height));
}
consensus.SegwitHeight = static_cast<int>(height);
}

View file

@ -25,7 +25,7 @@ void SetupChainParamsBaseOptions(ArgsManager& argsman)
argsman.AddArg("-chain=<chain>", "Use the chain <chain> (default: liquidv1). Reserved values: main, test, signet, regtest, liquidv1, liquidv1test", ArgsManager::ALLOW_ANY, OptionsCategory::CHAINPARAMS);
argsman.AddArg("-regtest", "Enter regression test mode, which uses a special chain in which blocks can be solved instantly. "
"This is intended for regression testing tools and app development. Equivalent to -chain=regtest.", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::CHAINPARAMS);
argsman.AddArg("-segwitheight=<n>", "Set the activation height of segwit. -1 to disable. (regtest-only)", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
argsman.AddArg("-segwitheight=<n>", "Set the activation height of segwit. (regtest-only)", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
argsman.AddArg("-testnet", "Use the test chain. Equivalent to -chain=test.", ArgsManager::ALLOW_ANY, OptionsCategory::CHAINPARAMS);
argsman.AddArg("-vbparams=deployment:start:end[:min_activation_height]", "Use given start/end times and min_activation_height for specified version bits deployment (regtest or custom only)", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::CHAINPARAMS);
argsman.AddArg("-seednode=<ip>", "Use specified node as seed node. This option can be specified multiple times to connect to multiple nodes. (custom only)", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::CHAINPARAMS);

View file

@ -770,7 +770,7 @@ namespace { // Variables internal to initialization process only
int nMaxConnections;
int nUserMaxConnections;
int nFD;
ServiceFlags nLocalServices = ServiceFlags(NODE_NETWORK | NODE_NETWORK_LIMITED);
ServiceFlags nLocalServices = ServiceFlags(NODE_NETWORK | NODE_NETWORK_LIMITED | NODE_WITNESS);
int64_t peer_connect_timeout;
std::set<BlockFilterType> g_enabled_filter_types;
@ -1728,12 +1728,6 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
nLocalServices = ServiceFlags(nLocalServices & ~NODE_NETWORK_LIMITED);
}
if (DeploymentEnabled(chainparams.GetConsensus(), Consensus::DEPLOYMENT_SEGWIT)) {
// Advertise witness capabilities.
// The option to not set NODE_WITNESS is only used in the tests and should be removed.
nLocalServices = ServiceFlags(nLocalServices | NODE_WITNESS);
}
// ********************************************************* Step 11: import blocks
if (!CheckDiskSpace(gArgs.GetDataDirNet())) {

View file

@ -877,7 +877,7 @@ void PeerManagerImpl::MaybeSetPeerAsAnnouncingHeaderAndIDs(NodeId nodeid)
}
m_connman.ForNode(nodeid, [this](CNode* pfrom) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) {
AssertLockHeld(::cs_main);
uint64_t nCMPCTBLOCKVersion = (pfrom->GetLocalServices() & NODE_WITNESS) ? 2 : 1;
uint64_t nCMPCTBLOCKVersion = 2;
if (lNodesAnnouncingHeaderAndIDs.size() >= 3) {
// As per BIP152, we only get 3 of our peers to announce
// blocks using compact encodings.
@ -1977,7 +1977,7 @@ void PeerManagerImpl::ProcessGetData(CNode& pfrom, Peer& peer, const std::atomic
static uint32_t GetFetchFlags(const CNode& pfrom) EXCLUSIVE_LOCKS_REQUIRED(cs_main) {
uint32_t nFetchFlags = 0;
if ((pfrom.GetLocalServices() & NODE_WITNESS) && State(pfrom.GetId())->fHaveWitness) {
if (State(pfrom.GetId())->fHaveWitness) {
nFetchFlags |= MSG_WITNESS_FLAG;
}
return nFetchFlags;
@ -2739,8 +2739,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
// they may wish to request compact blocks from us
bool fAnnounceUsingCMPCTBLOCK = false;
uint64_t nCMPCTBLOCKVersion = 2;
if (pfrom.GetLocalServices() & NODE_WITNESS)
m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion));
m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion));
nCMPCTBLOCKVersion = 1;
m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion));
}
@ -2758,7 +2757,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
bool fAnnounceUsingCMPCTBLOCK = false;
uint64_t nCMPCTBLOCKVersion = 0;
vRecv >> fAnnounceUsingCMPCTBLOCK >> nCMPCTBLOCKVersion;
if (nCMPCTBLOCKVersion == 1 || ((pfrom.GetLocalServices() & NODE_WITNESS) && nCMPCTBLOCKVersion == 2)) {
if (nCMPCTBLOCKVersion == 1 || nCMPCTBLOCKVersion == 2) {
LOCK(cs_main);
// fProvidesHeaderAndIDs is used to "lock in" version of compact blocks we send (fWantsCmpctWitness)
if (!State(pfrom.GetId())->fProvidesHeaderAndIDs) {
@ -2772,10 +2771,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
pfrom.m_bip152_highbandwidth_from = fAnnounceUsingCMPCTBLOCK;
}
if (!State(pfrom.GetId())->fSupportsDesiredCmpctVersion) {
if (pfrom.GetLocalServices() & NODE_WITNESS)
State(pfrom.GetId())->fSupportsDesiredCmpctVersion = (nCMPCTBLOCKVersion == 2);
else
State(pfrom.GetId())->fSupportsDesiredCmpctVersion = (nCMPCTBLOCKVersion == 1);
State(pfrom.GetId())->fSupportsDesiredCmpctVersion = (nCMPCTBLOCKVersion == 2);
}
}
return;

View file

@ -1782,13 +1782,8 @@ static unsigned int GetBlockScriptFlags(const CBlockIndex* pindex, const Consens
pindex->phashBlock == nullptr || // this is a new candidate block, eg from TestBlockValidity()
*pindex->phashBlock != consensusparams.BIP16Exception) // this block isn't the historical exception
{
flags |= SCRIPT_VERIFY_P2SH;
}
// Enforce WITNESS rules whenever P2SH is in effect (and the segwit
// deployment is defined).
if (flags & SCRIPT_VERIFY_P2SH && DeploymentEnabled(consensusparams, Consensus::DEPLOYMENT_SEGWIT)) {
flags |= SCRIPT_VERIFY_WITNESS;
// Enforce WITNESS rules whenever P2SH is in effect
flags |= SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS;
}
// Enforce the DERSIG (BIP66) rule
@ -3400,38 +3395,36 @@ std::vector<unsigned char> GenerateCoinbaseCommitment(CBlock& block, const CBloc
std::vector<unsigned char> commitment;
int commitpos = GetWitnessCommitmentIndex(block);
std::vector<unsigned char> ret(32, 0x00);
if (DeploymentEnabled(consensusParams, Consensus::DEPLOYMENT_SEGWIT)) {
if (commitpos == NO_WITNESS_COMMITMENT) {
// ELEMENTS: Shim in blank coinbase output for witness output hash
// Previous iterations of CA could have allowed witness data
// in coinbase transactions, and this witness data must be committed
// to here.
//
// Is No-op in Bitcoin
CMutableTransaction tx0(*block.vtx[0]);
tx0.vout.push_back(CTxOut());
block.vtx[0] = MakeTransactionRef(std::move(tx0));
// END
uint256 witnessroot = BlockWitnessMerkleRoot(block, nullptr);
CHash256().Write(witnessroot).Write(ret).Finalize(witnessroot);
CTxOut out;
out.nValue = 0;
out.nAsset = policyAsset;
out.scriptPubKey.resize(MINIMUM_WITNESS_COMMITMENT);
out.scriptPubKey[0] = OP_RETURN;
out.scriptPubKey[1] = 0x24;
out.scriptPubKey[2] = 0xaa;
out.scriptPubKey[3] = 0x21;
out.scriptPubKey[4] = 0xa9;
out.scriptPubKey[5] = 0xed;
memcpy(&out.scriptPubKey[6], witnessroot.begin(), 32);
commitment = std::vector<unsigned char>(out.scriptPubKey.begin(), out.scriptPubKey.end());
CMutableTransaction tx(*block.vtx[0]);
// Elements: replace shimmed output with real coinbase rather than push
tx.vout.back() = out;
// END
block.vtx[0] = MakeTransactionRef(std::move(tx));
}
if (commitpos == NO_WITNESS_COMMITMENT) {
// ELEMENTS: Shim in blank coinbase output for witness output hash
// Previous iterations of CA could have allowed witness data
// in coinbase transactions, and this witness data must be committed
// to here.
//
// Is No-op in Bitcoin
CMutableTransaction tx0(*block.vtx[0]);
tx0.vout.push_back(CTxOut());
block.vtx[0] = MakeTransactionRef(std::move(tx0));
// END
uint256 witnessroot = BlockWitnessMerkleRoot(block, nullptr);
CHash256().Write(witnessroot).Write(ret).Finalize(witnessroot);
CTxOut out;
out.nValue = 0;
out.nAsset = policyAsset;
out.scriptPubKey.resize(MINIMUM_WITNESS_COMMITMENT);
out.scriptPubKey[0] = OP_RETURN;
out.scriptPubKey[1] = 0x24;
out.scriptPubKey[2] = 0xaa;
out.scriptPubKey[3] = 0x21;
out.scriptPubKey[4] = 0xa9;
out.scriptPubKey[5] = 0xed;
memcpy(&out.scriptPubKey[6], witnessroot.begin(), 32);
commitment = std::vector<unsigned char>(out.scriptPubKey.begin(), out.scriptPubKey.end());
CMutableTransaction tx(*block.vtx[0]);
// Elements: replace shimmed output with real coinbase rather than push
tx.vout.back() = out;
// END
block.vtx[0] = MakeTransactionRef(std::move(tx));
}
UpdateUncommittedBlockStructures(block, pindexPrev, consensusParams);
return commitment;

View file

@ -0,0 +1,52 @@
#!/usr/bin/env python3
# Copyright (c) 2017-2020 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test a pre-segwit node upgrading to segwit consensus"""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
softfork_active,
)
class SegwitUpgradeTest(BitcoinTestFramework):
def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 1
self.extra_args = [["-segwitheight=10"]]
def run_test(self):
"""A pre-segwit node with insufficiently validated blocks needs to redownload blocks"""
self.log.info("Testing upgrade behaviour for pre-segwit node to segwit rules")
node = self.nodes[0]
# Node hasn't been used or connected yet
assert_equal(node.getblockcount(), 0)
assert not softfork_active(node, "segwit")
# Generate 8 blocks without witness data
node.generate(8)
assert_equal(node.getblockcount(), 8)
self.stop_node(0)
# Restarting the node (with segwit activation height set to 5) should result in a shutdown
# because the blockchain consists of 3 insufficiently validated blocks per segwit consensus rules.
node.assert_start_raises_init_error(
extra_args=["-segwitheight=5"],
expected_msg=": Witness data for blocks after height 5 requires validation. Please restart with -reindex..\nPlease restart with -reindex or -reindex-chainstate to recover.")
# As directed, the user restarts the node with -reindex
self.start_node(0, extra_args=["-reindex", "-segwitheight=5"])
# With the segwit consensus rules, the node is able to validate only up to block 4
assert_equal(node.getblockcount(), 4)
# The upgraded node should now have segwit activated
assert softfork_active(node, "segwit")
if __name__ == '__main__':
SegwitUpgradeTest().main()

View file

@ -12,6 +12,7 @@ import copy
from test_framework.blocktools import (
create_coinbase,
get_witness_script,
NORMAL_GBT_REQUEST_PARAMS,
TIME_GENESIS_BLOCK,
)
@ -19,6 +20,7 @@ from test_framework.messages import (
CBlock,
CBlockHeader,
BLOCK_HEADER_SIZE,
ser_uint256,
)
from test_framework.p2p import P2PDataStore
from test_framework.test_framework import BitcoinTestFramework
@ -48,6 +50,9 @@ class MiningTest(BitcoinTestFramework):
self.setup_clean_chain = True
self.supports_cli = False
def skip_test_if_missing_module(self):
self.skip_if_no_wallet()
def mine_chain(self):
self.log.info('Create some old blocks')
for t in range(TIME_GENESIS_BLOCK, TIME_GENESIS_BLOCK + 200 * 600, 600):
@ -86,7 +91,27 @@ class MiningTest(BitcoinTestFramework):
assert 'currentblockweight' not in mining_info
assert_equal(mining_info['pooledtx'], 0)
# Mine a block to leave initial block download
self.log.info("getblocktemplate: Test default witness commitment")
txid = int(node.sendtoaddress(node.getnewaddress(), 1), 16)
tmpl = node.getblocktemplate(NORMAL_GBT_REQUEST_PARAMS)
# Check that default_witness_commitment is present.
assert 'default_witness_commitment' in tmpl
witness_commitment = tmpl['default_witness_commitment']
# Check that default_witness_commitment is correct.
witness_root = CBlock.get_merkle_root([ser_uint256(0),
ser_uint256(txid)])
script = get_witness_script(witness_root, 0)
# ELEMENTS: The following assertion fails because
# (1) Elements appears to use a different merkle tree computation than Bitcoin here
# (ComputeFastMerkleRoot vs ComputeMerkleRoot)
# (2) Elements does some slightly different thing than Bitcoin with what goes into the merkle tree
# (see the "ELEMENTS:" comment in validation.cpp:3399.)
# assert_equal(witness_commitment, script.hex())
# Mine a block to leave initial block download and clear the mempool
node.generatetoaddress(1, node.get_deterministic_priv_key().address)
tmpl = node.getblocktemplate(NORMAL_GBT_REQUEST_PARAMS)
self.log.info("getblocktemplate: Test capability advertised")

View file

@ -209,24 +209,17 @@ class TestP2PConn(P2PInterface):
class SegWitTest(BitcoinTestFramework):
def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 3
self.num_nodes = 2
# This test tests SegWit both pre and post-activation, so use the normal BIP9 activation.
self.extra_args = [
["-acceptnonstdtxn=1", "-segwitheight={}".format(SEGWIT_HEIGHT), "-whitelist=noban@127.0.0.1"],
["-acceptnonstdtxn=0", "-segwitheight={}".format(SEGWIT_HEIGHT)],
["-acceptnonstdtxn=1", "-segwitheight=-1"],
]
self.supports_cli = False
def skip_test_if_missing_module(self):
self.skip_if_no_wallet()
def setup_network(self):
self.setup_nodes()
self.connect_nodes(0, 1)
self.connect_nodes(0, 2)
self.sync_all()
# Helper functions
def build_next_block(self, version=4):
@ -268,7 +261,6 @@ class SegWitTest(BitcoinTestFramework):
self.test_non_witness_transaction()
self.test_v0_outputs_arent_spendable()
self.test_block_relay()
self.test_getblocktemplate_before_lockin()
self.test_unnecessary_witness_before_segwit_activation()
self.test_witness_tx_relay_before_segwit_activation()
self.test_standardness_v0()
@ -296,7 +288,6 @@ class SegWitTest(BitcoinTestFramework):
self.test_signature_version_1()
self.test_non_standard_witness_blinding()
self.test_non_standard_witness()
self.test_upgrade_after_activation()
self.test_witness_sigops()
self.test_superfluous_witness()
self.test_wtxid_relay()
@ -488,11 +479,6 @@ class SegWitTest(BitcoinTestFramework):
witness, and so can't be spent before segwit activation (the point at which
blocks are permitted to contain witnesses)."""
# node2 doesn't need to be connected for this test.
# (If it's connected, node0 may propagate an invalid block to it over
# compact blocks and the nodes would have inconsistent tips.)
self.disconnect_nodes(0, 2)
# Create two outputs, a p2wsh and p2sh-p2wsh
witness_program = CScript([OP_TRUE])
script_pubkey = script_to_p2wsh_script(witness_program)
@ -552,40 +538,11 @@ class SegWitTest(BitcoinTestFramework):
# TODO: support multiple acceptable reject reasons.
test_witness_block(self.nodes[0], self.test_node, block, accepted=False, with_witness=False)
self.connect_nodes(0, 2)
self.utxo.pop(0)
self.utxo.append(UTXO(txid, 2, value))
@subtest # type: ignore
def test_getblocktemplate_before_lockin(self):
#txid = int(self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1), 16)
int(self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1), 16)
for node in [self.nodes[0], self.nodes[2]]:
gbt_results = node.getblocktemplate({"rules": ["segwit"]})
if node == self.nodes[2]:
# If this is a non-segwit node, we should not get a witness
# commitment.
assert 'default_witness_commitment' not in gbt_results
else:
# For segwit-aware nodes, check the version bit and the witness
# commitment are correct.
assert 'default_witness_commitment' in gbt_results
# ELEMENTS: disabled
#witness_commitment = gbt_results['default_witness_commitment']
# Check that default_witness_commitment is present.
#witness_root = CBlock.get_merkle_root([ser_uint256(0),
# ser_uint256(txid)])
#script = get_witness_script(witness_root, 0)
#assert_equal(witness_commitment, script.hex())
# Clear out the mempool
self.nodes[0].generate(1)
self.sync_blocks()
@subtest # type: ignore
def test_witness_tx_relay_before_segwit_activation(self):
# Generate a transaction that doesn't require a witness, but send it
@ -1991,39 +1948,6 @@ class SegWitTest(BitcoinTestFramework):
self.utxo.pop(0)
@subtest # type: ignore
def test_upgrade_after_activation(self):
"""Test the behavior of starting up a segwit-aware node after the softfork has activated."""
# All nodes are caught up and node 2 is a pre-segwit node that will soon upgrade.
for n in range(2):
assert_equal(self.nodes[n].getblockcount(), self.nodes[2].getblockcount())
assert softfork_active(self.nodes[n], "segwit")
assert SEGWIT_HEIGHT < self.nodes[2].getblockcount()
assert 'segwit' not in self.nodes[2].getblockchaininfo()['softforks']
# Restarting node 2 should result in a shutdown because the blockchain consists of
# insufficiently validated blocks per segwit consensus rules.
self.stop_node(2)
self.nodes[2].assert_start_raises_init_error(
extra_args=[f"-segwitheight={SEGWIT_HEIGHT}"],
expected_msg=f": Witness data for blocks after height {SEGWIT_HEIGHT} requires validation. Please restart with -reindex..\nPlease restart with -reindex or -reindex-chainstate to recover.",
)
# As directed, the user restarts the node with -reindex
self.start_node(2, extra_args=["-reindex", f"-segwitheight={SEGWIT_HEIGHT}"])
# With the segwit consensus rules, the node is able to validate only up to SEGWIT_HEIGHT - 1
assert_equal(self.nodes[2].getblockcount(), SEGWIT_HEIGHT - 1)
self.connect_nodes(0, 2)
# We reconnect more than 100 blocks, give it plenty of time
# sync_blocks() also verifies the best block hash is the same for all nodes
self.sync_blocks(timeout=240)
# The upgraded node should now have segwit activated
assert softfork_active(self.nodes[2], "segwit")
@subtest # type: ignore
def test_witness_sigops(self):
"""Test sigop counting is correct inside witnesses."""

View file

@ -331,6 +331,7 @@ BASE_SCRIPTS = [
'wallet_startup.py',
'p2p_i2p_ports.py',
'feature_config_args.py',
'feature_presegwit_node_upgrade.py',
'feature_settings.py',
'rpc_getdescriptorinfo.py',
'rpc_addresses_deprecation.py',