Changeset View
Changeset View
Standalone View
Standalone View
test/functional/abc-minimaldata.py
Show All 28 Lines | |||||
) | ) | ||||
from test_framework.p2p import P2PDataStore | from test_framework.p2p import P2PDataStore | ||||
from test_framework.script import OP_ADD, OP_TRUE, CScript | from test_framework.script import OP_ADD, OP_TRUE, CScript | ||||
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_raises_rpc_error | from test_framework.util import assert_raises_rpc_error | ||||
# Minimal push violations in mempool are rejected with a bannable error. | # 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 MinimaldataTest(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 = [['-acceptnonstdtxn=1']] | self.extra_args = [["-acceptnonstdtxn=1"]] | ||||
def reconnect_p2p(self): | def reconnect_p2p(self): | ||||
"""Tear down and bootstrap the P2P connection to the node. | """Tear down and bootstrap the P2P connection to the node. | ||||
The node gets disconnected several times in this test. This helper | The node gets disconnected several times in this test. This helper | ||||
method reconnects the p2p and restarts the network thread.""" | method reconnects the p2p and restarts the network thread.""" | ||||
self.nodes[0].disconnect_p2ps() | self.nodes[0].disconnect_p2ps() | ||||
self.nodes[0].add_p2p_connection(P2PDataStore()) | self.nodes[0].add_p2p_connection(P2PDataStore()) | ||||
Show All 10 Lines | class MinimaldataTest(BitcoinTestFramework): | ||||
def build_block(self, parent, transactions=(), nTime=None): | def build_block(self, parent, transactions=(), nTime=None): | ||||
"""Make a new block with an OP_1 coinbase output. | """Make a new block with an OP_1 coinbase output. | ||||
Requires parent to have its height registered.""" | Requires parent to have its height registered.""" | ||||
parent.calc_sha256() | parent.calc_sha256() | ||||
block_height = self.block_heights[parent.sha256] + 1 | block_height = self.block_heights[parent.sha256] + 1 | ||||
block_time = (parent.nTime + 1) if nTime is None else nTime | block_time = (parent.nTime + 1) if nTime is None else nTime | ||||
block = create_block( | block = create_block(parent.sha256, create_coinbase(block_height), block_time) | ||||
parent.sha256, create_coinbase(block_height), block_time) | |||||
block.vtx.extend(transactions) | block.vtx.extend(transactions) | ||||
make_conform_to_ctor(block) | make_conform_to_ctor(block) | ||||
block.hashMerkleRoot = block.calc_merkle_root() | block.hashMerkleRoot = block.calc_merkle_root() | ||||
block.solve() | block.solve() | ||||
self.block_heights[block.sha256] = block_height | self.block_heights[block.sha256] = block_height | ||||
return block | return block | ||||
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].p2ps[0].send_txs_and_test( | self.nodes[0].p2ps[0].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_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].p2ps[0].send_blocks_and_test( | self.nodes[0].p2ps[0].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() | ||||
def run_test(self): | def run_test(self): | ||||
node, = self.nodes | (node,) = self.nodes | ||||
self.nodes[0].add_p2p_connection(P2PDataStore()) | self.nodes[0].add_p2p_connection(P2PDataStore()) | ||||
tip = self.getbestblock(node) | tip = self.getbestblock(node) | ||||
self.log.info("Create some blocks with OP_1 coinbase for spending.") | self.log.info("Create some blocks with OP_1 coinbase for spending.") | ||||
blocks = [] | blocks = [] | ||||
for _ in range(10): | for _ in range(10): | ||||
Show All 14 Lines | def run_test(self): | ||||
spendfrom = spendable_outputs.pop() | spendfrom = spendable_outputs.pop() | ||||
script = CScript([OP_ADD]) | script = CScript([OP_ADD]) | ||||
value = spendfrom.vout[0].nValue | value = spendfrom.vout[0].nValue | ||||
# Fund transaction | # Fund transaction | ||||
txfund = create_tx_with_script( | txfund = create_tx_with_script( | ||||
spendfrom, 0, b'', amount=value, script_pub_key=script) | spendfrom, 0, b"", amount=value, script_pub_key=script | ||||
) | |||||
txfund.rehash() | txfund.rehash() | ||||
fundings.append(txfund) | fundings.append(txfund) | ||||
# Spend transaction | # Spend transaction | ||||
txspend = CTransaction() | txspend = CTransaction() | ||||
txspend.vout.append( | txspend.vout.append(CTxOut(value - 1000, CScript([OP_TRUE]))) | ||||
CTxOut(value - 1000, CScript([OP_TRUE]))) | txspend.vin.append(CTxIn(COutPoint(txfund.sha256, 0), b"")) | ||||
txspend.vin.append( | |||||
CTxIn(COutPoint(txfund.sha256, 0), b'')) | |||||
# 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 | ||||
# Non minimal tx are invalid. | # Non minimal tx are invalid. | ||||
nonminimaltx = create_fund_and_spend_tx() | nonminimaltx = create_fund_and_spend_tx() | ||||
tip = self.build_block(tip, fundings) | tip = self.build_block(tip, fundings) | ||||
node.p2ps[0].send_blocks_and_test([tip], node) | node.p2ps[0].send_blocks_and_test([tip], node) | ||||
self.log.info("Trying to mine a minimaldata violation.") | self.log.info("Trying to mine a minimaldata violation.") | ||||
self.check_for_ban_on_rejected_block( | self.check_for_ban_on_rejected_block( | ||||
self.build_block(tip, [nonminimaltx]), BADINPUTS_ERROR) | self.build_block(tip, [nonminimaltx]), BADINPUTS_ERROR | ||||
self.log.info( | ) | ||||
"If we try to submit it by mempool or RPC we are banned") | self.log.info("If we try to submit it by mempool or RPC we are banned") | ||||
assert_raises_rpc_error(-26, MINIMALPUSH_ERROR, | assert_raises_rpc_error( | ||||
node.sendrawtransaction, ToHex(nonminimaltx)) | -26, MINIMALPUSH_ERROR, node.sendrawtransaction, ToHex(nonminimaltx) | ||||
self.check_for_ban_on_rejected_tx( | ) | ||||
nonminimaltx, MINIMALPUSH_ERROR) | self.check_for_ban_on_rejected_tx(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.p2ps[0].send_blocks_and_test([tip], node) | node.p2ps[0].send_blocks_and_test([tip], node) | ||||
if __name__ == '__main__': | if __name__ == "__main__": | ||||
MinimaldataTest().main() | MinimaldataTest().main() |