mirror of
https://github.com/ElementsProject/elements.git
synced 2026-08-17 13:07:54 +02:00
Merge 338b9d82dc into merged_master (Bitcoin PR bitcoin/bitcoin#30681)
This commit is contained in:
commit
f60016e6ad
8 changed files with 73 additions and 11 deletions
4
doc/release-notes-30647.md
Normal file
4
doc/release-notes-30647.md
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
Tests
|
||||
-----
|
||||
|
||||
- The BIP94 timewarp attack mitigation is now active on the `regtest` network
|
||||
|
|
@ -27,4 +27,11 @@ static const size_t MIN_SERIALIZABLE_TRANSACTION_WEIGHT = WITNESS_SCALE_FACTOR *
|
|||
/** Interpret sequence numbers as relative lock-time constraints. */
|
||||
static constexpr unsigned int LOCKTIME_VERIFY_SEQUENCE = (1 << 0);
|
||||
|
||||
/**
|
||||
* Maximum number of seconds that the timestamp of the first
|
||||
* block of a difficulty adjustment period is allowed to
|
||||
* be earlier than the last block of the previous period (BIP94).
|
||||
*/
|
||||
static constexpr int64_t MAX_TIMEWARP = 600;
|
||||
|
||||
#endif // BITCOIN_CONSENSUS_CONSENSUS_H
|
||||
|
|
|
|||
|
|
@ -122,6 +122,10 @@ struct Params {
|
|||
/** Proof of work parameters */
|
||||
uint256 powLimit;
|
||||
bool fPowAllowMinDifficultyBlocks;
|
||||
/**
|
||||
* Enfore BIP94 timewarp attack mitigation. On testnet4 this also enforces
|
||||
* the block storm mitigation.
|
||||
*/
|
||||
bool enforce_BIP94;
|
||||
bool fPowNoRetargeting;
|
||||
int64_t nPowTargetSpacing;
|
||||
|
|
|
|||
|
|
@ -762,10 +762,10 @@ public:
|
|||
consensus.SegwitHeight = 0; // Always active unless overridden
|
||||
consensus.MinBIP9WarningHeight = 0;
|
||||
consensus.powLimit = uint256{"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"};
|
||||
consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; // two weeks
|
||||
consensus.nPowTargetTimespan = 24 * 60 * 60; // one day
|
||||
consensus.nPowTargetSpacing = 10 * 60;
|
||||
consensus.fPowAllowMinDifficultyBlocks = true;
|
||||
consensus.enforce_BIP94 = false;
|
||||
consensus.enforce_BIP94 = true;
|
||||
consensus.fPowNoRetargeting = true;
|
||||
consensus.nRuleChangeActivationThreshold = 108; // 75% for testchains
|
||||
consensus.nMinerConfirmationWindow = 144; // Faster than normal for regtest (144 instead of 2016)
|
||||
|
|
|
|||
|
|
@ -45,6 +45,14 @@ int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParam
|
|||
int64_t nOldTime = pblock->nTime;
|
||||
int64_t nNewTime{std::max<int64_t>(pindexPrev->GetMedianTimePast() + 1, TicksSinceEpoch<std::chrono::seconds>(NodeClock::now()))};
|
||||
|
||||
if (consensusParams.enforce_BIP94) {
|
||||
// Height of block to be mined.
|
||||
const int height{pindexPrev->nHeight + 1};
|
||||
if (height % consensusParams.DifficultyAdjustmentInterval() == 0) {
|
||||
nNewTime = std::max<int64_t>(nNewTime, pindexPrev->GetBlockTime() - MAX_TIMEWARP);
|
||||
}
|
||||
}
|
||||
|
||||
if (nOldTime < nNewTime) {
|
||||
pblock->nTime = nNewTime;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -114,13 +114,6 @@ const std::vector<std::string> CHECKLEVEL_DOC {
|
|||
* */
|
||||
static constexpr int PRUNE_LOCK_BUFFER{10};
|
||||
|
||||
/**
|
||||
* Maximum number of seconds that the timestamp of the first
|
||||
* block of a difficulty adjustment period is allowed to
|
||||
* be earlier than the last block of the previous period (BIP94).
|
||||
*/
|
||||
static constexpr int64_t MAX_TIMEWARP = 600;
|
||||
|
||||
GlobalMutex g_best_block_mutex;
|
||||
std::condition_variable g_best_block_cv;
|
||||
uint256 g_best_block;
|
||||
|
|
@ -4775,7 +4768,7 @@ static bool ContextualCheckBlockHeader(const CBlockHeader& block, BlockValidatio
|
|||
return state.Invalid(BlockValidationResult::BLOCK_INVALID_HEADER, "bad-header-height");
|
||||
}
|
||||
|
||||
// Testnet4 only: Check timestamp against prev for difficulty-adjustment
|
||||
// Testnet4 and regtest only: Check timestamp against prev for difficulty-adjustment
|
||||
// blocks to prevent timewarp attacks (see https://github.com/bitcoin/bitcoin/pull/15482).
|
||||
if (consensusParams.enforce_BIP94) {
|
||||
// Check timestamp for the first block of each difficulty adjustment
|
||||
|
|
|
|||
|
|
@ -28,12 +28,16 @@ from test_framework.p2p import P2PDataStore
|
|||
from test_framework.test_framework import BitcoinTestFramework
|
||||
from test_framework.util import (
|
||||
assert_equal,
|
||||
assert_greater_than_or_equal,
|
||||
assert_raises_rpc_error,
|
||||
get_fee,
|
||||
)
|
||||
from test_framework.wallet import MiniWallet
|
||||
|
||||
|
||||
DIFFICULTY_ADJUSTMENT_INTERVAL = 144
|
||||
MAX_FUTURE_BLOCK_TIME = 2 * 3600
|
||||
MAX_TIMEWARP = 600
|
||||
VERSIONBITS_TOP_BITS = 0x20000000
|
||||
VERSIONBITS_DEPLOYMENT_TESTDUMMY_BIT = 28
|
||||
DEFAULT_BLOCK_MIN_TX_FEE = 100 # default `-blockmintxfee` setting [sat/kvB] # ELEMENTS
|
||||
|
|
@ -115,6 +119,47 @@ class MiningTest(BitcoinTestFramework):
|
|||
assert tx_below_min_feerate['txid'] not in block_template_txids
|
||||
assert tx_below_min_feerate['txid'] not in block_txids
|
||||
|
||||
def test_timewarp(self):
|
||||
self.log.info("Test timewarp attack mitigation (BIP94)")
|
||||
node = self.nodes[0]
|
||||
|
||||
self.log.info("Mine until the last block of the retarget period")
|
||||
blockchain_info = self.nodes[0].getblockchaininfo()
|
||||
n = DIFFICULTY_ADJUSTMENT_INTERVAL - blockchain_info['blocks'] % DIFFICULTY_ADJUSTMENT_INTERVAL - 2
|
||||
t = blockchain_info['time']
|
||||
|
||||
for _ in range(n):
|
||||
t += 600
|
||||
self.nodes[0].setmocktime(t)
|
||||
self.generate(self.wallet, 1, sync_fun=self.no_op)
|
||||
|
||||
self.log.info("Create block two hours in the future")
|
||||
self.nodes[0].setmocktime(t + MAX_FUTURE_BLOCK_TIME)
|
||||
self.generate(self.wallet, 1, sync_fun=self.no_op)
|
||||
assert_equal(node.getblock(node.getbestblockhash())['time'], t + MAX_FUTURE_BLOCK_TIME)
|
||||
|
||||
self.log.info("First block template of retarget period can't use wall clock time")
|
||||
self.nodes[0].setmocktime(t)
|
||||
# The template will have an adjusted timestamp, which we then modify
|
||||
tmpl = node.getblocktemplate(NORMAL_GBT_REQUEST_PARAMS)
|
||||
assert_greater_than_or_equal(tmpl['curtime'], t + MAX_FUTURE_BLOCK_TIME - MAX_TIMEWARP)
|
||||
|
||||
block = CBlock()
|
||||
block.nVersion = tmpl["version"]
|
||||
block.hashPrevBlock = int(tmpl["previousblockhash"], 16)
|
||||
block.nTime = tmpl["curtime"]
|
||||
block.nBits = int(tmpl["bits"], 16)
|
||||
block.block_height = node.getblockcount()+1
|
||||
block.nNonce = 0
|
||||
block.vtx = [create_coinbase(height=int(tmpl["height"]))]
|
||||
block.solve()
|
||||
assert_template(node, block, None)
|
||||
|
||||
bad_block = copy.deepcopy(block)
|
||||
bad_block.nTime = t
|
||||
bad_block.solve()
|
||||
assert_raises_rpc_error(-25, 'time-timewarp-attack', lambda: node.submitheader(hexdata=CBlockHeader(bad_block).serialize().hex()))
|
||||
|
||||
def run_test(self):
|
||||
node = self.nodes[0]
|
||||
self.wallet = MiniWallet(node)
|
||||
|
|
@ -330,6 +375,7 @@ class MiningTest(BitcoinTestFramework):
|
|||
assert_equal(node.submitblock(hexdata=block.serialize().hex()), 'duplicate') # valid
|
||||
|
||||
self.test_blockmintxfee_parameter()
|
||||
self.test_timewarp()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ TIME_RANGE_STEP = 600 # ten-minute steps
|
|||
TIME_RANGE_MTP = TIME_GENESIS_BLOCK + (HEIGHT - 6) * TIME_RANGE_STEP
|
||||
TIME_RANGE_TIP = TIME_GENESIS_BLOCK + (HEIGHT - 1) * TIME_RANGE_STEP
|
||||
TIME_RANGE_END = TIME_GENESIS_BLOCK + HEIGHT * TIME_RANGE_STEP
|
||||
DIFFICULTY_ADJUSTMENT_INTERVAL = 2016
|
||||
DIFFICULTY_ADJUSTMENT_INTERVAL = 144
|
||||
|
||||
|
||||
class BlockchainTest(BitcoinTestFramework):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue