Changeset View
Changeset View
Standalone View
Standalone View
test/functional/abc-minimaldata-activation.py
#!/usr/bin/env python3 | #!/usr/bin/env python3 | ||||
# Copyright (c) 2019 The Bitcoin developers | # Copyright (c) 2019 The Bitcoin developers | ||||
# Distributed under the MIT software license, see the accompanying | # Distributed under the MIT software license, see the accompanying | ||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php. | # file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||||
""" | """ | ||||
This tests the activation of MINIMALDATA rule to consensus (from standard). | This tests the MINIMALDATA consensus rule. | ||||
- test rejection in mempool, with error changing before/after activation. | - test rejection in mempool, with error changing before/after activation. | ||||
- test acceptance in blocks before activation, and rejection after. | - test acceptance in blocks before activation, and rejection after. | ||||
- check non-banning for peers who send invalid txns that would have been valid | - check non-banning for peers who send invalid txns that would have been valid | ||||
on the other side of the upgrade. | on the other side of the upgrade. | ||||
Derived from abc-schnorr.py | Derived from abc-schnorr.py | ||||
""" | """ | ||||
Show All 17 Lines | |||||
) | ) | ||||
from test_framework.script import ( | from test_framework.script import ( | ||||
CScript, | CScript, | ||||
OP_ADD, | OP_ADD, | ||||
OP_TRUE, | OP_TRUE, | ||||
) | ) | ||||
from test_framework.test_framework import BitcoinTestFramework | from test_framework.test_framework import BitcoinTestFramework | ||||
from test_framework.txtools import pad_tx | from test_framework.txtools import pad_tx | ||||
from test_framework.util import assert_equal, assert_raises_rpc_error | from test_framework.util import assert_raises_rpc_error | ||||
# the upgrade activation time, which we artificially set far into the future | # Minimal push violations in mempool are rejected with a bannable error. | ||||
GRAVITON_START_TIME = 2000000000 | |||||
# If we don't do this, autoreplay protection will activate before graviton and | |||||
# all our sigs will mysteriously fail. | |||||
REPLAY_PROTECTION_START_TIME = GRAVITON_START_TIME * 2 | |||||
# Both before and after the upgrade, minimal push violations in mempool are | |||||
# rejected with a bannable error. | |||||
MINIMALPUSH_ERROR = 'mandatory-script-verify-flag-failed (Data push larger than necessary)' | MINIMALPUSH_ERROR = 'mandatory-script-verify-flag-failed (Data push larger than necessary)' | ||||
# Blocks with invalid scripts give this error: | # Blocks with invalid scripts give this error: | ||||
BADINPUTS_ERROR = 'blk-bad-inputs' | BADINPUTS_ERROR = 'blk-bad-inputs' | ||||
class SchnorrTest(BitcoinTestFramework): | class MinimaldataTest(BitcoinTestFramework): | ||||
def set_test_params(self): | def set_test_params(self): | ||||
self.num_nodes = 1 | self.num_nodes = 1 | ||||
self.block_heights = {} | self.block_heights = {} | ||||
self.extra_args = [["-gravitonactivationtime={}".format( | |||||
GRAVITON_START_TIME), | |||||
"-replayprotectionactivationtime={}".format( | |||||
REPLAY_PROTECTION_START_TIME)]] | |||||
def bootstrap_p2p(self, *, num_connections=1): | def bootstrap_p2p(self, *, num_connections=1): | ||||
"""Add a P2P connection to the node. | """Add a P2P connection to the node. | ||||
Helper to connect and wait for version handshake.""" | Helper to connect and wait for version handshake.""" | ||||
for _ in range(num_connections): | for _ in range(num_connections): | ||||
self.nodes[0].add_p2p_connection(P2PDataStore()) | self.nodes[0].add_p2p_connection(P2PDataStore()) | ||||
Show All 34 Lines | class MinimaldataTest(BitcoinTestFramework): | ||||
def check_for_ban_on_rejected_tx(self, tx, reject_reason=None): | def check_for_ban_on_rejected_tx(self, tx, reject_reason=None): | ||||
"""Check we are disconnected when sending a txn that the node rejects. | """Check we are disconnected when sending a txn that the node rejects. | ||||
(Can't actually get banned, since bitcoind won't ban local peers.)""" | (Can't actually get banned, since bitcoind won't ban local peers.)""" | ||||
self.nodes[0].p2p.send_txs_and_test( | self.nodes[0].p2p.send_txs_and_test( | ||||
[tx], self.nodes[0], success=False, expect_disconnect=True, reject_reason=reject_reason) | [tx], self.nodes[0], success=False, expect_disconnect=True, reject_reason=reject_reason) | ||||
self.reconnect_p2p() | self.reconnect_p2p() | ||||
def check_for_no_ban_on_rejected_tx(self, tx, reject_reason): | |||||
"""Check we are not disconnected when sending a txn that the node rejects.""" | |||||
self.nodes[0].p2p.send_txs_and_test( | |||||
[tx], self.nodes[0], success=False, reject_reason=reject_reason) | |||||
def check_for_ban_on_rejected_block(self, block, reject_reason=None): | def check_for_ban_on_rejected_block(self, block, reject_reason=None): | ||||
"""Check we are disconnected when sending a block that the node rejects. | """Check we are disconnected when sending a block that the node rejects. | ||||
(Can't actually get banned, since bitcoind won't ban local peers.)""" | (Can't actually get banned, since bitcoind won't ban local peers.)""" | ||||
self.nodes[0].p2p.send_blocks_and_test( | self.nodes[0].p2p.send_blocks_and_test( | ||||
[block], self.nodes[0], success=False, reject_reason=reject_reason, expect_disconnect=True) | [block], self.nodes[0], success=False, reject_reason=reject_reason, expect_disconnect=True) | ||||
self.reconnect_p2p() | self.reconnect_p2p() | ||||
▲ Show 20 Lines • Show All 42 Lines • ▼ Show 20 Lines | def run_test(self): | ||||
# Sign the transaction | # Sign the transaction | ||||
txspend.vin[0].scriptSig = CScript( | txspend.vin[0].scriptSig = CScript( | ||||
b'\x01\x01\x51') # PUSH1(0x01) OP_1 | b'\x01\x01\x51') # PUSH1(0x01) OP_1 | ||||
pad_tx(txspend) | pad_tx(txspend) | ||||
txspend.rehash() | txspend.rehash() | ||||
return txspend | return txspend | ||||
# make a few of these, which are nonstandard before upgrade and invalid after. | # Non minimal tx are invalid. | ||||
nonminimaltx = create_fund_and_spend_tx() | nonminimaltx = create_fund_and_spend_tx() | ||||
nonminimaltx_2 = create_fund_and_spend_tx() | |||||
nonminimaltx_3 = create_fund_and_spend_tx() | |||||
tip = self.build_block(tip, fundings) | tip = self.build_block(tip, fundings) | ||||
node.p2p.send_blocks_and_test([tip], node) | node.p2p.send_blocks_and_test([tip], node) | ||||
self.log.info("Start preupgrade tests") | self.log.info("Trying to mine a minimaldata violation.") | ||||
self.log.info("Sending rejected transactions via RPC") | |||||
assert_raises_rpc_error(-26, MINIMALPUSH_ERROR, | |||||
node.sendrawtransaction, ToHex(nonminimaltx)) | |||||
assert_raises_rpc_error(-26, MINIMALPUSH_ERROR, | |||||
node.sendrawtransaction, ToHex(nonminimaltx_2)) | |||||
assert_raises_rpc_error(-26, MINIMALPUSH_ERROR, | |||||
node.sendrawtransaction, ToHex(nonminimaltx_3)) | |||||
self.log.info( | |||||
"Sending rejected transactions via net (banning)") | |||||
self.check_for_ban_on_rejected_tx( | |||||
nonminimaltx, MINIMALPUSH_ERROR) | |||||
self.check_for_ban_on_rejected_tx( | |||||
nonminimaltx_2, MINIMALPUSH_ERROR) | |||||
self.check_for_ban_on_rejected_tx( | |||||
nonminimaltx_3, MINIMALPUSH_ERROR) | |||||
assert_equal(node.getrawmempool(), []) | |||||
self.log.info("Successfully mine nonstandard transaction") | |||||
tip = self.build_block(tip, [nonminimaltx]) | |||||
node.p2p.send_blocks_and_test([tip], node) | |||||
# Activation tests | |||||
self.log.info("Approach to just before upgrade activation") | |||||
# Move our clock to the uprade time so we will accept such future-timestamped blocks. | |||||
node.setmocktime(GRAVITON_START_TIME) | |||||
# Mine six blocks with timestamp starting at GRAVITON_START_TIME-1 | |||||
blocks = [] | |||||
for i in range(-1, 5): | |||||
tip = self.build_block(tip, nTime=GRAVITON_START_TIME + i) | |||||
blocks.append(tip) | |||||
node.p2p.send_blocks_and_test(blocks, node) | |||||
assert_equal(node.getblockchaininfo()[ | |||||
'mediantime'], GRAVITON_START_TIME - 1) | |||||
self.log.info( | |||||
"Mine the activation block itself, including a minimaldata violation at the last possible moment") | |||||
tip = self.build_block(tip, [nonminimaltx_2]) | |||||
node.p2p.send_blocks_and_test([tip], node) | |||||
self.log.info("We have activated!") | |||||
assert_equal(node.getblockchaininfo()[ | |||||
'mediantime'], GRAVITON_START_TIME) | |||||
self.log.info( | |||||
"Trying to mine a minimaldata violation, but we are just barely too late") | |||||
self.check_for_ban_on_rejected_block( | self.check_for_ban_on_rejected_block( | ||||
self.build_block(tip, [nonminimaltx_3]), BADINPUTS_ERROR) | self.build_block(tip, [nonminimaltx]), BADINPUTS_ERROR) | ||||
self.log.info( | self.log.info( | ||||
"If we try to submit it by mempool or RPC we still aren't banned") | "If we try to submit it by mempool or RPC we are banned") | ||||
assert_raises_rpc_error(-26, MINIMALPUSH_ERROR, | assert_raises_rpc_error(-26, MINIMALPUSH_ERROR, | ||||
node.sendrawtransaction, ToHex(nonminimaltx_3)) | node.sendrawtransaction, ToHex(nonminimaltx)) | ||||
self.check_for_ban_on_rejected_tx( | self.check_for_ban_on_rejected_tx( | ||||
nonminimaltx_3, MINIMALPUSH_ERROR) | nonminimaltx, MINIMALPUSH_ERROR) | ||||
self.log.info("Mine a normal block") | self.log.info("Mine a normal block") | ||||
tip = self.build_block(tip) | tip = self.build_block(tip) | ||||
node.p2p.send_blocks_and_test([tip], node) | node.p2p.send_blocks_and_test([tip], node) | ||||
if __name__ == '__main__': | if __name__ == '__main__': | ||||
SchnorrTest().main() | MinimaldataTest().main() |