diff options
author | Sjors Provoost <sjors@sprovoost.nl> | 2024-08-20 18:49:59 +0200 |
---|---|---|
committer | Sjors Provoost <sjors@sprovoost.nl> | 2024-08-20 18:49:59 +0200 |
commit | e929054e12210353812f440c685a23329e7040f7 (patch) | |
tree | 1b3bafc1b14f16c2b45604117f6d67ffa3f7ebcd /test | |
parent | e85f386c4b157b7d1ac16aface9bd2c614e62b46 (diff) |
Add timewarp attack mitigation test
Diffstat (limited to 'test')
-rwxr-xr-x | test/functional/mining_basic.py | 44 |
1 files changed, 44 insertions, 0 deletions
diff --git a/test/functional/mining_basic.py b/test/functional/mining_basic.py index 6a364a4815..b183023b2f 100755 --- a/test/functional/mining_basic.py +++ b/test/functional/mining_basic.py @@ -34,6 +34,9 @@ from test_framework.util import ( 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 = 1000 # default `-blockmintxfee` setting [sat/kvB] @@ -115,6 +118,46 @@ 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) + assert_raises_rpc_error(-1, "time-timewarp-attack, block's timestamp is too early on diff adjustment block", + lambda: node.getblocktemplate(NORMAL_GBT_REQUEST_PARAMS)) + + # Create template with an acceptable timestamp and then modify it + self.nodes[0].setmocktime(t + MAX_FUTURE_BLOCK_TIME) + tmpl = node.getblocktemplate(NORMAL_GBT_REQUEST_PARAMS) + + block = CBlock() + block.nVersion = tmpl["version"] + block.hashPrevBlock = int(tmpl["previousblockhash"], 16) + block.nTime = t + block.nBits = int(tmpl["bits"], 16) + block.nNonce = 0 + block.vtx = [create_coinbase(height=int(tmpl["height"]))] + block.solve() + + self.nodes[0].setmocktime(t) + assert_raises_rpc_error(-25, 'time-timewarp-attack', lambda: node.submitheader(hexdata=CBlockHeader(block).serialize().hex())) + def run_test(self): node = self.nodes[0] self.wallet = MiniWallet(node) @@ -322,6 +365,7 @@ class MiningTest(BitcoinTestFramework): assert_equal(node.submitblock(hexdata=block.serialize().hex()), 'duplicate') # valid self.test_blockmintxfee_parameter() + self.test_timewarp() if __name__ == '__main__': |