Merge #6189: backport: bitcoin#16333, #21862, #22385, #22550, #22597, #22632, #22718, #22907 - fire up test chains by first block - 2/n

e4e7c440f4 fix: use proper chain instead using ActiveChain for test framework (Konstantin Akimov)
65b92fa093 Merge bitcoin/bitcoin#21862: test: Set regtest.BIP65Height = 111 to speed up tests (fanquake)
adcf095ab9 Merge bitcoin/bitcoin#22718: doc: Add missing PR 16333 release note (MarcoFalke)
101a863399 Merge bitcoin/bitcoin#16333: test: Set BIP34Height = 2 for regtest (MarcoFalke)
71af8816ef Merge bitcoin/bitcoin#22907: test: Avoid intermittent test failure in feature_csv_activation.py (merge-script)
fc25503cbc Merge bitcoin/bitcoin#22632: test: Set regtest.BIP66Height = 102 to speed up tests (W. J. van der Laan)
cbd2be8e18 Merge bitcoin/bitcoin#22597: consensus/params: simplify ValidDeployment check to avoid gcc warning (MarcoFalke)
8928146bfa Merge bitcoin/bitcoin#22550: test: improve `test_signing_with_{csv,cltv}` subtests (speed, prevent timeout) (MarcoFalke)
fb00431b7c Merge bitcoin/bitcoin#22385: refactor: Use DeploymentEnabled to hide VB deployments (MarcoFalke)

Pull request description:

  ## Issue being fixed or feature implemented
  Backports from bitcoin related to hard-fork mechanism and accelerated action

  ## What was done?
  see commits for backports.
  Also fixed an issue of using from ChainState on RegTest: should be used specified chain, not the "best chain".

  ## How Has This Been Tested?
  Run unit & functional tests

  ## Breaking Changes
  That's a breaking changes for RegTest

  ## Checklist:
  - [x] I have performed a self-review of my own code
  - [ ] I have commented my code, particularly in hard-to-understand areas
  - [ ] I have added or updated relevant unit/integration/functional/e2e tests
  - [ ] I have made corresponding changes to the documentation
  - [x] I have assigned this pull request to a milestone

ACKs for top commit:
  PastaPastaPasta:
    utACK e4e7c440f4

Tree-SHA512: c02813179177781a0da3beaff65732e12017f0056565b897891b2c5a06fda125a4e032571a02fad9d8640728df82c117393bd78bc6d406e0a30f72587b2d7344
This commit is contained in:
pasta 2024-08-14 13:14:55 +07:00
commit df07c38151
No known key found for this signature in database
GPG Key ID: 52527BEDABE87984
17 changed files with 100 additions and 48 deletions

View File

@ -0,0 +1,8 @@
Tests
-----
- For the `regtest` network the activation heights of several softforks were
changed. (dash#6189)
* BIP 34 (blockheight in coinbase) from 500 to 2
* BIP 66 (DERSIG) from 1251 to 102
* BIP 65 (CLTV) from 1351 to 111

View File

@ -794,10 +794,10 @@ public:
consensus.nGovernanceMinQuorum = 1;
consensus.nGovernanceFilterElements = 100;
consensus.nMasternodeMinimumConfirmations = 1;
consensus.BIP34Height = 500; // BIP34 activated on regtest (Used in functional tests)
consensus.BIP34Height = 2; // BIP34 activated on regtest (Block at height 1 not enforced for testing purposes)
consensus.BIP34Hash = uint256();
consensus.BIP65Height = 1351; // BIP65 activated on regtest (Used in functional tests)
consensus.BIP66Height = 1251; // BIP66 activated on regtest (Used in functional tests)
consensus.BIP65Height = 111; // BIP65 activated on regtest (Block at height 110 and earlier not enforced for testing purposes)
consensus.BIP66Height = 102; // BIP66 activated on regtest (Block at height 101 and earlier not enforced for testing purposes)
consensus.BIP147Height = 432; // BIP147 activated on regtest (Used in functional tests)
consensus.CSVHeight = 432; // CSV activated on regtest (Used in rpc activation tests)
consensus.DIP0001Height = 2000;

View File

@ -14,8 +14,12 @@
namespace Consensus {
enum BuriedDeployment : int16_t
{
/**
* A buried deployment is one where the height of the activation has been hardcoded into
* the client implementation long after the consensus change has activated. See BIP 90.
*/
enum BuriedDeployment : int16_t {
// buried deployments get negative values to avoid overlap with DeploymentPos
DEPLOYMENT_HEIGHTINCB = std::numeric_limits<int16_t>::min(),
DEPLOYMENT_DERSIG,
DEPLOYMENT_CLTV,
@ -29,17 +33,16 @@ enum BuriedDeployment : int16_t
DEPLOYMENT_BRR,
DEPLOYMENT_V19,
};
constexpr bool ValidDeployment(BuriedDeployment dep) { return DEPLOYMENT_HEIGHTINCB <= dep && dep <= DEPLOYMENT_V19; }
constexpr bool ValidDeployment(BuriedDeployment dep) { return dep <= DEPLOYMENT_V19; }
enum DeploymentPos : uint16_t
{
enum DeploymentPos : uint16_t {
DEPLOYMENT_TESTDUMMY,
DEPLOYMENT_V20, // Deployment of EHF, LLMQ Randomness Beacon
DEPLOYMENT_MN_RR, // Deployment of Masternode Reward Location Reallocation
// NOTE: Also add new deployments to VersionBitsDeploymentInfo in deploymentinfo.cpp
MAX_VERSION_BITS_DEPLOYMENTS
};
constexpr bool ValidDeployment(DeploymentPos dep) { return DEPLOYMENT_TESTDUMMY <= dep && dep <= DEPLOYMENT_MN_RR; }
constexpr bool ValidDeployment(DeploymentPos dep) { return dep < MAX_VERSION_BITS_DEPLOYMENTS; }
/**
* Struct for each individual consensus rule change using BIP9.

View File

@ -7,6 +7,8 @@
#include <consensus/params.h>
#include <versionbits.h>
#include <type_traits>
VersionBitsCache g_versionbitscache;
/* Basic sanity checking for BuriedDeployment/DeploymentPos enums and
@ -15,3 +17,18 @@ VersionBitsCache g_versionbitscache;
static_assert(ValidDeployment(Consensus::DEPLOYMENT_TESTDUMMY), "sanity check of DeploymentPos failed (TESTDUMMY not valid)");
static_assert(!ValidDeployment(Consensus::MAX_VERSION_BITS_DEPLOYMENTS), "sanity check of DeploymentPos failed (MAX value considered valid)");
static_assert(!ValidDeployment(static_cast<Consensus::BuriedDeployment>(Consensus::DEPLOYMENT_TESTDUMMY)), "sanity check of BuriedDeployment failed (overlaps with DeploymentPos)");
/* ValidDeployment only checks upper bounds for ensuring validity.
* This checks that the lowest possible value or the type is also a
* (specific) valid deployment so that lower bounds don't need to be checked.
*/
template<typename T, T x>
static constexpr bool is_minimum()
{
using U = typename std::underlying_type<T>::type;
return x == std::numeric_limits<U>::min();
}
static_assert(is_minimum<Consensus::BuriedDeployment, Consensus::DEPLOYMENT_HEIGHTINCB>(), "heightincb is not minimum value for BuriedDeployment");
static_assert(is_minimum<Consensus::DeploymentPos, Consensus::DEPLOYMENT_TESTDUMMY>(), "testdummy is not minimum value for DeploymentPos");

View File

@ -49,7 +49,7 @@ inline bool DeploymentEnabled(const Consensus::Params& params, Consensus::Buried
inline bool DeploymentEnabled(const Consensus::Params& params, Consensus::DeploymentPos dep)
{
assert(Consensus::ValidDeployment(dep));
return params.vDeployments[dep].nTimeout != 0;
return params.vDeployments[dep].nStartTime != Consensus::BIP9Deployment::NEVER_ACTIVE;
}
/** this function is convenient helper for DIP0003 because 'active' and 'enforced' are different statuses for DIP0003 */

View File

@ -64,9 +64,9 @@ BlockAssembler::Options::Options()
}
BlockAssembler::BlockAssembler(CChainState& chainstate, const NodeContext& node, const CTxMemPool& mempool, const CChainParams& params, const Options& options) :
m_blockman(Assert(node.chainman)->m_blockman),
m_blockman(chainstate.m_blockman),
m_cpoolman(*Assert(node.cpoolman)),
m_chain_helper(*Assert(node.chain_helper)),
m_chain_helper(chainstate.ChainHelper()),
m_chainstate(chainstate),
m_dmnman(*Assert(node.dmnman)),
m_evoDb(*Assert(node.evodb)),

View File

@ -1620,10 +1620,7 @@ static RPCHelpMan verifychain()
static void SoftForkDescPushBack(const CBlockIndex* active_chain_tip, UniValue& softforks, const Consensus::Params& params, Consensus::BuriedDeployment dep)
{
// For buried deployments.
// A buried deployment is one where the height of the activation has been hardcoded into
// the client implementation long after the consensus change has activated. See BIP 90.
// Buried deployments with activation height value of
// std::numeric_limits<int>::max() are disabled and thus hidden.
if (!DeploymentEnabled(params, dep)) return;
UniValue rv(UniValue::VOBJ);
@ -1638,8 +1635,8 @@ static void SoftForkDescPushBack(const CBlockIndex* active_chain_tip, UniValue&
static void SoftForkDescPushBack(const CBlockIndex* active_chain_tip, const std::unordered_map<uint8_t, int>& signals, UniValue& softforks, const Consensus::Params& consensusParams, Consensus::DeploymentPos id)
{
// For BIP9 deployments.
// Deployments that are never active are hidden.
if (consensusParams.vDeployments[id].nStartTime == Consensus::BIP9Deployment::NEVER_ACTIVE) return;
if (!DeploymentEnabled(consensusParams, id)) return;
UniValue bip9(UniValue::VOBJ);
const ThresholdState thresholdState = g_versionbitscache.State(active_chain_tip, consensusParams, id);

View File

@ -428,10 +428,10 @@ CBlock TestChainSetup::CreateBlock(
auto cbTx = GetTxPayload<CCbTx>(*block.vtx[0]);
BOOST_ASSERT(cbTx.has_value());
BlockValidationState state;
if (!CalcCbTxMerkleRootMNList(block, m_node.chainman->ActiveChain().Tip(), cbTx->merkleRootMNList, *m_node.dmnman, state, m_node.chainman->ActiveChainstate().CoinsTip())) {
if (!CalcCbTxMerkleRootMNList(block, chainstate.m_chain.Tip(), cbTx->merkleRootMNList, *m_node.dmnman, state, chainstate.CoinsTip())) {
BOOST_ASSERT(false);
}
if (!CalcCbTxMerkleRootQuorums(block, m_node.chainman->ActiveChain().Tip(), *m_node.llmq_ctx->quorum_block_processor, cbTx->merkleRootQuorums, state)) {
if (!CalcCbTxMerkleRootQuorums(block, chainstate.m_chain.Tip(), *m_node.llmq_ctx->quorum_block_processor, cbTx->merkleRootQuorums, state)) {
BOOST_ASSERT(false);
}
CMutableTransaction tmpTx{*block.vtx[0]};
@ -443,7 +443,7 @@ CBlock TestChainSetup::CreateBlock(
{
LOCK(cs_main);
unsigned int extraNonce = 0;
IncrementExtraNonce(&block, m_node.chainman->ActiveChain().Tip(), extraNonce);
IncrementExtraNonce(&block, chainstate.m_chain.Tip(), extraNonce);
}
while (!CheckProofOfWork(block.GetHash(), block.nBits, chainparams.GetConsensus())) ++block.nNonce;

View File

@ -79,6 +79,8 @@ std::shared_ptr<CBlock> MinerTestingSetup::Block(const uint256& prev_hash)
txCoinbase.vout[1].scriptPubKey = P2SH_OP_TRUE;
txCoinbase.vout[1].nValue = txCoinbase.vout[0].nValue;
txCoinbase.vout[0].nValue = 0;
// Always pad with OP_0 at the end to avoid bad-cb-length error
txCoinbase.vin[0].scriptSig = CScript{} << WITH_LOCK(::cs_main, return m_node.chainman->m_blockman.LookupBlockIndex(prev_hash)->nHeight + 1) << OP_0;
pblock->vtx[0] = MakeTransactionRef(std::move(txCoinbase));
return pblock;
@ -92,6 +94,11 @@ std::shared_ptr<CBlock> MinerTestingSetup::FinalizeBlock(std::shared_ptr<CBlock>
++(pblock->nNonce);
}
// submit block header, so that miner can get the block height from the
// global state and the node has the topology of the chain
BlockValidationState ignored;
BOOST_CHECK(Assert(m_node.chainman)->ProcessNewBlockHeaders({pblock->GetBlockHeader()}, ignored, Params()));
return pblock;
}
@ -146,13 +153,6 @@ BOOST_AUTO_TEST_CASE(processnewblock_signals_ordering)
}
bool ignored;
BlockValidationState state;
std::vector<CBlockHeader> headers;
std::transform(blocks.begin(), blocks.end(), std::back_inserter(headers), [](std::shared_ptr<const CBlock> b) { return b->GetBlockHeader(); });
// Process all the headers so we understand the toplogy of the chain
BOOST_CHECK(Assert(m_node.chainman)->ProcessNewBlockHeaders(headers, state, Params()));
// Connect the genesis block and drain any outstanding events
BOOST_CHECK(Assert(m_node.chainman)->ProcessNewBlock(Params(), std::make_shared<CBlock>(Params().GenesisBlock()), true, &ignored));
SyncWithValidationInterfaceQueue();

View File

@ -378,7 +378,9 @@ class FullBlockTest(BitcoinTestFramework):
# b30 has a max-sized coinbase scriptSig.
self.move_tip(23)
b30 = self.next_block(30)
b30.vtx[0].vin[0].scriptSig = b'\x00' * 100
b30.vtx[0].vin[0].scriptSig = bytes(b30.vtx[0].vin[0].scriptSig) # Convert CScript to raw bytes
b30.vtx[0].vin[0].scriptSig += b'\x00' * (100 - len(b30.vtx[0].vin[0].scriptSig)) # Fill with 0s
assert_equal(len(b30.vtx[0].vin[0].scriptSig), 100)
b30.vtx[0].rehash()
b30 = self.update_block(30, [])
self.send_blocks([b30], True)
@ -839,6 +841,7 @@ class FullBlockTest(BitcoinTestFramework):
b61.vtx[0].rehash()
b61 = self.update_block(61, [])
assert_equal(duplicate_tx.serialize(), b61.vtx[0].serialize())
# BIP30 is always checked on regtest, regardless of the BIP34 activation height
self.send_blocks([b61], success=False, reject_reason='bad-txns-BIP30', reconnect=True)
# Test BIP30 (allow duplicate if spent)

View File

@ -4,11 +4,11 @@
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test BIP65 (CHECKLOCKTIMEVERIFY).
Test that the CHECKLOCKTIMEVERIFY soft-fork activates at (regtest) block height
1351.
Test that the CHECKLOCKTIMEVERIFY soft-fork activates.
"""
from test_framework.blocktools import (
CLTV_HEIGHT,
create_block,
create_coinbase,
)
@ -34,8 +34,6 @@ from test_framework.wallet import (
MiniWalletMode,
)
CLTV_HEIGHT = 1351
# Helper function to modify a transaction by
# 1) prepending a given script to the scriptSig of vin 0 and
@ -66,9 +64,9 @@ def cltv_invalidate(tx, failure_reason):
# +-------------------------------------------------+------------+--------------+
[[OP_CHECKLOCKTIMEVERIFY], None, None],
[[OP_1NEGATE, OP_CHECKLOCKTIMEVERIFY, OP_DROP], None, None],
[[CScriptNum(1000), OP_CHECKLOCKTIMEVERIFY, OP_DROP], 0, 1296688602], # timestamp of genesis block
[[CScriptNum(1000), OP_CHECKLOCKTIMEVERIFY, OP_DROP], 0, 500],
[[CScriptNum(500), OP_CHECKLOCKTIMEVERIFY, OP_DROP], 0xffffffff, 500],
[[CScriptNum(100), OP_CHECKLOCKTIMEVERIFY, OP_DROP], 0, 1296688602], # timestamp of genesis block
[[CScriptNum(100), OP_CHECKLOCKTIMEVERIFY, OP_DROP], 0, 50],
[[CScriptNum(50), OP_CHECKLOCKTIMEVERIFY, OP_DROP], 0xffffffff, 50],
][failure_reason]
cltv_modify_tx(tx, prepend_scriptsig=scheme[0], nsequence=scheme[1], nlocktime=scheme[2])
@ -111,6 +109,7 @@ class BIP65Test(BitcoinTestFramework):
self.log.info("Mining %d blocks", CLTV_HEIGHT - 2)
wallet.generate(10)
self.nodes[0].generate(CLTV_HEIGHT - 2 - 10)
assert_equal(self.nodes[0].getblockcount(), CLTV_HEIGHT - 2)
self.log.info("Test that invalid-according-to-CLTV transactions can still appear in a block")

View File

@ -40,6 +40,7 @@ bip112tx_emptystack - test empty stack (= no argument) OP_CSV
from itertools import product
from test_framework.blocktools import (
CSV_ACTIVATION_HEIGHT,
create_block,
create_coinbase,
TIME_GENESIS_BLOCK,
@ -63,12 +64,12 @@ from test_framework.wallet import (
TESTING_TX_COUNT = 83 # Number of testing transactions: 1 BIP113 tx, 16 BIP68 txs, 66 BIP112 txs (see comments above)
COINBASE_BLOCK_COUNT = TESTING_TX_COUNT # Number of coinbase blocks we need to generate as inputs for our txs
BASE_RELATIVE_LOCKTIME = 10
CSV_ACTIVATION_HEIGHT = 432
SEQ_DISABLE_FLAG = 1 << 31
SEQ_RANDOM_HIGH_BIT = 1 << 25
SEQ_TYPE_FLAG = 1 << 22
SEQ_RANDOM_LOW_BIT = 1 << 18
def relative_locktime(sdf, srhb, stf, srlb):
"""Returns a locktime with certain bits set."""
@ -83,6 +84,7 @@ def relative_locktime(sdf, srhb, stf, srlb):
locktime |= SEQ_RANDOM_LOW_BIT
return locktime
def all_rlt_txs(txs):
return [tx['tx'] for tx in txs]
@ -93,6 +95,7 @@ class BIP68_112_113Test(BitcoinTestFramework):
self.setup_clean_chain = True
# Must set '-dip3params=2000:2000' to create pre-dip3 blocks only
self.extra_args = [[
'-peertimeout=999999', # bump because mocktime might cause a disconnect otherwise
'-whitelist=noban@127.0.0.1',
'-dip3params=2000:2000',
'-par=1', # Use only one script thread to get the exact reject reason for testing
@ -148,13 +151,13 @@ class BIP68_112_113Test(BitcoinTestFramework):
for i, (sdf, srhb, stf, srlb) in enumerate(product(*[[True, False]] * 4)):
locktime = relative_locktime(sdf, srhb, stf, srlb)
tx = self.create_self_transfer_from_utxo(bip112inputs[i])
if (varyOP_CSV): # if varying OP_CSV, nSequence is fixed
if varyOP_CSV: # if varying OP_CSV, nSequence is fixed
tx.vin[0].nSequence = BASE_RELATIVE_LOCKTIME + locktime_delta
else: # vary nSequence instead, OP_CSV is fixed
tx.vin[0].nSequence = locktime + locktime_delta
tx.nVersion = txversion
self.miniwallet.sign_tx(tx)
if (varyOP_CSV):
if varyOP_CSV:
tx.vin[0].scriptSig = CScript([locktime, OP_CHECKSEQUENCEVERIFY, OP_DROP] + list(CScript(tx.vin[0].scriptSig)))
else:
tx.vin[0].scriptSig = CScript([BASE_RELATIVE_LOCKTIME, OP_CHECKSEQUENCEVERIFY, OP_DROP] + list(CScript(tx.vin[0].scriptSig)))
@ -201,7 +204,7 @@ class BIP68_112_113Test(BitcoinTestFramework):
self.tip = int(self.nodes[0].getbestblockhash(), 16)
# Activation height is hardcoded
test_blocks = self.generate_blocks(CSV_ACTIVATION_HEIGHT-5 - COINBASE_BLOCK_COUNT)
test_blocks = self.generate_blocks(CSV_ACTIVATION_HEIGHT - 5 - COINBASE_BLOCK_COUNT)
#test_blocks = self.generate_blocks(345)
self.send_blocks(test_blocks)
assert not softfork_active(self.nodes[0], 'csv')
@ -487,5 +490,6 @@ class BIP68_112_113Test(BitcoinTestFramework):
self.send_blocks([self.create_test_block(time_txs)])
self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash())
if __name__ == '__main__':
BIP68_112_113Test().main()

View File

@ -4,10 +4,11 @@
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test BIP66 (DER SIG).
Test that the DERSIG soft-fork activates at (regtest) height 1251.
Test the DERSIG soft-fork activation on regtest.
"""
from test_framework.blocktools import (
DERSIG_HEIGHT,
create_block,
create_coinbase,
)
@ -24,8 +25,6 @@ from test_framework.wallet import (
MiniWalletMode,
)
DERSIG_HEIGHT = 1251
# A canonical signature consists of:
# <30> <total len> <02> <len R> <R> <02> <len S> <S> <hashtype>
@ -88,8 +87,10 @@ class BIP66Test(BitcoinTestFramework):
block.rehash()
block.solve()
assert_equal(self.nodes[0].getblockcount(), DERSIG_HEIGHT - 2)
self.test_dersig_info(is_active=False) # Not active as of current tip and next block does not need to obey rules
peer.send_and_ping(msg_block(block))
assert_equal(self.nodes[0].getblockcount(), DERSIG_HEIGHT - 1)
self.test_dersig_info(is_active=True) # Not active as of current tip, but next block must obey rules
assert_equal(self.nodes[0].getbestblockhash(), block.hash)

View File

@ -27,6 +27,8 @@ import subprocess
from test_framework.address import ADDRESS_BCRT1_P2SH_OP_TRUE
from test_framework.blocktools import (
CLTV_HEIGHT,
DERSIG_HEIGHT,
create_block,
create_coinbase,
TIME_GENESIS_BLOCK,
@ -142,9 +144,9 @@ class BlockchainTest(BitcoinTestFramework):
assert_equal(res['prune_target_size'], 576716800)
assert_greater_than(res['size_on_disk'], 0)
assert_equal(res['softforks'], {
'bip34': {'type': 'buried', 'active': False, 'height': 500},
'bip66': {'type': 'buried', 'active': False, 'height': 1251},
'bip65': {'type': 'buried', 'active': False, 'height': 1351},
'bip34': {'type': 'buried', 'active': True, 'height': 2},
'bip66': {'type': 'buried', 'active': True, 'height': DERSIG_HEIGHT},
'bip65': {'type': 'buried', 'active': True, 'height': CLTV_HEIGHT},
'bip147': { 'type': 'buried', 'active': False, 'height': 432},
'csv': {'type': 'buried', 'active': False, 'height': 432},
'dip0001': { 'type': 'buried', 'active': False, 'height': 2000},

View File

@ -35,14 +35,21 @@ TIME_GENESIS_BLOCK = 1417713337
# Coinbase transaction outputs can only be spent after this number of new blocks (network rule)
COINBASE_MATURITY = 100
# Soft-fork activation heights
DERSIG_HEIGHT = 102 # BIP 66
CLTV_HEIGHT = 111 # BIP 65
CSV_ACTIVATION_HEIGHT = 432
NORMAL_GBT_REQUEST_PARAMS = {"rules": []} # type: ignore[var-annotated]
VERSIONBITS_LAST_OLD_BLOCK_VERSION = 4
def create_block(hashprev=None, coinbase=None, ntime=None, *, version=None, tmpl=None, txlist=None, dip4_activated=False, v20_activated=False):
"""Create a block (with regtest difficulty)."""
block = CBlock()
if tmpl is None:
tmpl = {}
block.nVersion = version or tmpl.get('version') or 1
block.nVersion = version or tmpl.get('version') or VERSIONBITS_LAST_OLD_BLOCK_VERSION
block.nTime = ntime or tmpl.get('curtime') or int(time.time() + 600)
block.hashPrevBlock = hashprev or int(tmpl['previousblockhash'], 0x10)
if tmpl and not tmpl.get('bits') is None:

View File

@ -564,7 +564,7 @@ class CBlockHeader:
self.calc_sha256()
def set_null(self):
self.nVersion = 1
self.nVersion = 4
self.hashPrevBlock = 0
self.hashMerkleRoot = 0
self.nTime = 0

View File

@ -601,6 +601,17 @@ def mine_large_block(node, utxos=None):
node.generate(1)
def generate_to_height(node, target_height):
"""Generates blocks until a given target block height has been reached.
To prevent timeouts, only up to 200 blocks are generated per RPC call.
Can be used to activate certain soft-forks (e.g. CSV, CLTV)."""
current_height = node.getblockcount()
while current_height < target_height:
nblocks = min(200, target_height - current_height)
current_height += len(node.generate(nblocks))
assert_equal(node.getblockcount(), target_height)
def find_vout_for_address(node, txid, addr):
"""
Locate the vout index of the given transaction sending to the