def create_fund_and_spend_tx(): spendfrom = spendable_outputs.pop() script = CScript([OP_ADD]) value = spendfrom.vout[0].nValue # Fund transaction txfund = create_transaction(spendfrom, 0, b'', value, script) pad_tx(txfund) txfund.rehash() fundings.append(txfund) # Spend transaction txspend = CTransaction() txspend.vout.append(CTxOut(value - 1000, CScript([OP_TRUE]))) txspend.vin.append(CTxIn(COutPoint(txfund.sha256, 0), b'')) # Sign the transaction txspend.vin[0].scriptSig = CScript( b'\x01\x01\x51') # PUSH1(0x01) OP_1 pad_tx(txspend) txspend.rehash() return txspend
def create_fund_and_spend_tx(dummy=OP_0, sigtype='ecdsa'): spendfrom = spendable_outputs.pop() script = CScript([OP_1, public_key, OP_1, OP_CHECKMULTISIG]) value = spendfrom.vout[0].nValue # Fund transaction txfund = create_transaction(spendfrom, 0, b'', value, script) txfund.rehash() fundings.append(txfund) # Spend transaction txspend = CTransaction() txspend.vout.append(CTxOut(value - 1000, CScript([OP_TRUE]))) txspend.vin.append(CTxIn(COutPoint(txfund.sha256, 0), b'')) # Sign the transaction sighashtype = SIGHASH_ALL | SIGHASH_FORKID hashbyte = bytes([sighashtype & 0xff]) sighash = SignatureHashForkId(script, txspend, 0, sighashtype, value) if sigtype == 'schnorr': txsig = schnorr.sign(privkeybytes, sighash) + hashbyte elif sigtype == 'ecdsa': txsig = private_key.sign(sighash) + hashbyte txspend.vin[0].scriptSig = CScript([dummy, txsig]) txspend.rehash() return txspend
def test_invalid_args(self, electrum_client): from test_framework.connectrum.exc import ElectrumErrorResponse error_code = "-32602" hash_param_methods = ("blockchain.scripthash.get_balance", "blockchain.scripthash.get_history", "blockchain.scripthash.listunspent") for method in hash_param_methods: assert_raises(ElectrumErrorResponse, electrum_client.call, method, "invalidhash") try: electrum_client.call(method, "invalidhash") except Exception as e: print("ERROR:" + str(e)) assert error_code in str(e) # invalid tx try: tx = CTransaction() tx.calc_sha256() tx.vin = [CTxIn(COutPoint(0xbeef, 1))] electrum_client.call("blockchain.transaction.broadcast", ToHex(tx)) except Exception as e: print("ERROR: " + str(e)) assert error_code in str(e)
def create_segwit_fund_and_spend_tx(spend, case0=False): if not case0: # Spending from a P2SH-P2WPKH coin, # txhash:a45698363249312f8d3d93676aa714be59b0bd758e62fa054fb1ea6218480691 redeem_script0 = bytearray.fromhex( '0014fcf9969ce1c98a135ed293719721fb69f0b686cb') # Spending from a P2SH-P2WSH coin, # txhash:6b536caf727ccd02c395a1d00b752098ec96e8ec46c96bee8582be6b5060fa2f redeem_script1 = bytearray.fromhex( '0020fc8b08ed636cb23afcb425ff260b3abd03380a2333b54cfa5d51ac52d803baf4' ) else: redeem_script0 = bytearray.fromhex('51020000') redeem_script1 = bytearray.fromhex('53020080') redeem_scripts = [redeem_script0, redeem_script1] # Fund transaction to segwit addresses txfund = CTransaction() txfund.vin = [CTxIn(COutPoint(spend.tx.sha256, spend.n))] amount = (50 * COIN - 1000) // len(redeem_scripts) for redeem_script in redeem_scripts: txfund.vout.append( CTxOut( amount, CScript([OP_HASH160, hash160(redeem_script), OP_EQUAL]))) txfund.rehash() # Segwit spending transaction # We'll test if a node that checks for standardness accepts this # txn. It should fail exclusively because of the restriction in # the scriptSig (non clean stack..), so all other characteristcs # must pass standardness checks. For this reason, we create # standard P2SH outputs. txspend = CTransaction() for i in range(len(redeem_scripts)): txspend.vin.append( CTxIn(COutPoint(txfund.sha256, i), CScript([redeem_scripts[i]]))) txspend.vout = [ CTxOut( 50 * COIN - 2000, CScript( [OP_HASH160, hash160(CScript([OP_TRUE])), OP_EQUAL])) ] txspend.rehash() return txfund, txspend
def make_spend(sigcheckcount): # Add a funding tx to fundings, and return a tx spending that using # scriptsig. logging.debug("Gen tx with {} sigchecks.".format(sigcheckcount)) def get_script_with_sigcheck(count): return CScript([cds_message, cds_pubkey] + (count - 1) * [OP_3DUP, OP_CHECKDATASIGVERIFY] + [OP_CHECKDATASIG]) # get funds locked with OP_1 sourcetx = self.spendable_outputs.popleft() # make funding that forwards to scriptpubkey last_sigcheck_count = ((sigcheckcount - 1) % 30) + 1 fundtx = create_transaction( sourcetx, get_script_with_sigcheck(last_sigcheck_count)) fill_sigcheck_script = get_script_with_sigcheck(30) remaining_sigcheck = sigcheckcount while remaining_sigcheck > 30: fundtx.vout[0].nValue -= 1000 fundtx.vout.append(CTxOut(100, bytes(fill_sigcheck_script))) remaining_sigcheck -= 30 fundtx.rehash() fundings.append(fundtx) # make the spending scriptsig = CScript([cds_signature]) tx = CTransaction() tx.vin.append(CTxIn(COutPoint(fundtx.sha256, 1), scriptsig)) input_index = 2 remaining_sigcheck = sigcheckcount while remaining_sigcheck > 30: tx.vin.append( CTxIn(COutPoint(fundtx.sha256, input_index), scriptsig)) remaining_sigcheck -= 30 input_index += 1 tx.vout.append(CTxOut(0, CScript([OP_RETURN]))) pad_tx(tx) tx.rehash() return tx
def make_spend(scriptpubkey, scriptsig): # Add a funding tx to fundings, and return a tx spending that using # scriptsig. logging.debug( "Gen tx with locking script {} unlocking script {} .".format( scriptpubkey.hex(), scriptsig.hex())) # get funds locked with OP_1 sourcetx = self.spendable_outputs.popleft() # make funding that forwards to scriptpubkey fundtx = create_transaction(sourcetx, scriptpubkey) fundings.append(fundtx) # make the spending tx = CTransaction() tx.vin.append(CTxIn(COutPoint(fundtx.sha256, 1), scriptsig)) tx.vout.append(CTxOut(0, CScript([OP_RETURN]))) pad_tx(tx) tx.rehash() return tx
def create_transaction(spendfrom, custom_script, amount=None): # Fund and sign a transaction to a given output. # spendfrom should be a CTransaction with first output to OP_TRUE. # custom output will go on position 1, after position 0 which will be # OP_TRUE (so it can be reused). customout = CTxOut(0, bytes(custom_script)) # set output amount to required dust if not given customout.nValue = amount or (len(customout.serialize()) + 148) * 3 ctx = CTransaction() ctx.vin.append(CTxIn(COutPoint(spendfrom.sha256, 0), bytes([OP_TRUE]))) ctx.vout.append(CTxOut(0, bytes([OP_TRUE]))) ctx.vout.append(customout) pad_tx(ctx) fee = len(ctx.serialize()) ctx.vout[0].nValue = spendfrom.vout[0].nValue - customout.nValue - fee ctx.rehash() return ctx
def create_fund_and_spend_tx(): spend_from = spendable_outputs.pop() value = spend_from.vout[0].nValue # Reversed data data = bytes.fromhex('0123456789abcdef') rev_data = bytes(reversed(data)) # Lockscript: provide a bytestring that reverses to X script = CScript([OP_REVERSEBYTES, rev_data, OP_EQUAL]) # Fund transaction: REVERSEBYTES <reversed(x)> EQUAL tx_fund = create_tx_with_script(spend_from, 0, b'', value, script) tx_fund.rehash() # Spend transaction: <x> tx_spend = CTransaction() tx_spend.vout.append( CTxOut(value - 1000, CScript([b'x' * 100, OP_RETURN]))) tx_spend.vin.append(CTxIn(COutPoint(tx_fund.sha256, 0), b'')) tx_spend.vin[0].scriptSig = CScript([data]) tx_spend.rehash() return tx_spend, tx_fund
def create_cashaccount_tx(self, n, spend, name, address): fee = 500 tx = create_transaction( FromHex(CTransaction(), n.getrawtransaction(spend['txid'])), spend['vout'], b"", spend['satoshi'] - fee) _, _, keyhash = decode_addr(address) name = bytes(name, 'ascii') keyhash = DATATYPE_KEYHASH + keyhash cashaccount_script = CScript( [OP_RETURN, CASHACCONT_PREFIX, name, keyhash]) tx.vout.append(CTxOut(0, cashaccount_script)) tx.rehash() return n.signrawtransaction(ToHex(tx))['hex']
def __init__(self, tx=CTransaction(), n=-1): self.tx = tx self.n = n
def run_test(self): logging.info("Initializing test directory "+self.options.tmpdir) node = self.nodes[0] self.bootstrap_p2p() tip = self.get_best_block(node) logging.info("Create some blocks with OP_1 coinbase for spending.") blocks = [] for _ in range(10): tip = self.build_block(tip) blocks.append(tip) self.p2p.send_blocks_and_test(blocks, node, success=True) spendable_outputs = [block.vtx[0] for block in blocks] logging.info("Mature the blocks and get out of IBD.") node.generate(100) tip = self.get_best_block(node) logging.info( "Set up spending transactions to test and mine the funding transactions.") # Generate a key pair privkeybytes = b"xyzxyzhh" * 4 private_key = CECKey() private_key.set_secretbytes(privkeybytes) # get uncompressed public key serialization public_key = private_key.get_pubkey() # Create funding/spending transaction pair spend_from = spendable_outputs.pop() value = spend_from.vout[0].nValue # Reversed data data = bytes.fromhex('0123456789abcdef') rev_data = bytes(reversed(data)) # Lockscript: provide a bytestring that reverses to X script = CScript([OP_REVERSEBYTES, rev_data, OP_EQUAL]) # Fund transaction: REVERSEBYTES <reversed(x)> EQUAL tx_reversebytes_fund = create_tx_with_script(spend_from, 0, b'', value, script) tx_reversebytes_fund.rehash() # Spend transaction: <x> tx_reversebytes_spend = CTransaction() tx_reversebytes_spend.vout.append(CTxOut(value - 1000, CScript([b'x' * 100, OP_RETURN]))) tx_reversebytes_spend.vin.append(CTxIn(COutPoint(tx_reversebytes_fund.sha256, 0), b'')) tx_reversebytes_spend.vin[0].scriptSig = CScript([data]) tx_reversebytes_spend.rehash() # Mine funding transaction into block. Pre-upgrade output scripts can have # OP_REVERSEBYTES and still be fully valid, but they cannot spend it. tip = self.build_block(tip, [tx_reversebytes_fund]) self.p2p.send_blocks_and_test([tip], node) logging.info( "Submitting a new OP_REVERSEBYTES tx via net, and mining it in a block") # Send OP_REVERSEBYTES tx self.p2p.send_txs_and_test([tx_reversebytes_spend], node) # Verify OP_REVERSEBYTES tx is in mempool waitFor(10, lambda: set(node.getrawmempool()) == {tx_reversebytes_spend.hash}) # Mine OP_REVERSEBYTES tx into block tip = self.build_block(tip, [tx_reversebytes_spend]) self.p2p.send_blocks_and_test([tip], node)
def _zmq_test(self): """Note that this function is very picky about the exact order of generated ZMQ announcements. However, this order does not actually matter. So bitcoind code changes my break this test. """ num_blocks = 5 logging.info( "Generate {0} blocks (and {0} coinbase txes)".format(num_blocks)) # DS does not support P2PK so make sure there's a P2PKH in the wallet addr = self.nodes[0].getnewaddress() fundTx = self.nodes[0].sendtoaddress(addr, 10) # Notify of new tx zmqNotif = self.hashtx.receive().hex() assert fundTx == zmqNotif zmqNotif = self.rawtx.receive() genhashes = self.nodes[0].generate(1) # notify tx 1 zmqNotif1 = self.hashtx.receive().hex() assert fundTx == zmqNotif1 zmqNotif1r = self.rawtx.receive() # notify coinbase zmqNotif2 = self.hashtx.receive().hex() zmqNotif2r = self.rawtx.receive() assert b"/EB32/AD12" in zmqNotif2r # notify tx 1 again zmqNotif = self.hashtx.receive().hex() assert fundTx == zmqNotif zmqNotif = self.rawtx.receive() # notify the block h = self.hashblock.receive().hex() b = self.rawblock.receive() genhashes = self.nodes[0].generate(num_blocks) self.sync_all() for x in range(num_blocks): # Should receive the coinbase txid. txid = self.hashtx.receive() # Should receive the coinbase raw transaction. hex = self.rawtx.receive() tx = CTransaction() tx.deserialize(BytesIO(hex)) tx.calc_sha256() assert_equal(tx.hash, txid.hex()) # Should receive the generated block hash. hash = self.hashblock.receive().hex() assert_equal(genhashes[x], hash) # The block should only have the coinbase txid. assert_equal([txid.hex()], self.nodes[1].getblock(hash)["tx"]) # Should receive the generated raw block. block = self.rawblock.receive() assert_equal(genhashes[x], hash256(block[:80])[::-1].hex()) logging.info("Wait for tx from second node") payment_txid = self.nodes[1].sendtoaddress( self.nodes[0].getnewaddress(), 1.0) self.sync_all() # Should receive the broadcasted txid. txid = self.hashtx.receive() assert_equal(payment_txid, txid.hex()) # Should receive the broadcasted raw transaction. hex = self.rawtx.receive() assert_equal(payment_txid, hash256(hex)[::-1].hex()) if 1: # Send 2 transactions that double spend each other # If these unsubscribes fail, then you will get an assertion that a zmq topic is not correct self.hashtx.unsubscribe() self.rawtx.unsubscribe() wallet = self.nodes[0].listunspent() walletp2pkh = list(filter(lambda x : len(x["scriptPubKey"]) != 70, wallet)) # Find an input that is not P2PK t = walletp2pkh.pop() inputs = [] inputs.append({ "txid" : t["txid"], "vout" : t["vout"]}) outputs = { self.nodes[1].getnewaddress() : t["amount"] } rawtx = self.nodes[0].createrawtransaction(inputs, outputs) rawtx = self.nodes[0].signrawtransaction(rawtx) mpTx = self.nodes[0].getmempoolinfo()["size"] try: hashTxToDoubleSpend = self.nodes[1].sendrawtransaction(rawtx['hex']) except JSONRPCException as e: print(e.error['message']) assert False self.sync_all() outputs = { self.nodes[1].getnewaddress() : t["amount"] } rawtx = self.nodes[0].createrawtransaction(inputs, outputs) rawtx = self.nodes[0].signrawtransaction(rawtx) waitFor(30, lambda: self.nodes[0].getmempoolinfo()["size"] > mpTx) # make sure the original tx propagated in time try: hashtx = self.nodes[0].sendrawtransaction(rawtx['hex']) except JSONRPCException as e: assert("txn-mempool-conflict" in e.error['message']) else: assert(False) self.sync_all() # since I unsubscribed from these I don't need to load them #self.hashtx.receive() #self.rawtx.receive() # Should receive hash of a double spend proof. dsTxHash = self.hashds.receive() assert hashTxToDoubleSpend == dsTxHash.hex() ds = self.rawds.receive() assert len(ds) > 0
def run_test(self): node = self.nodes[0] self.pynode = P2PDataStore() self.connection = NodeConn('127.0.0.1', p2p_port(0), node, self.pynode) self.pynode.add_connection(self.connection) NetworkThread().start() self.pynode.wait_for_verack() # Get out of IBD node.generate(1) tip = self.getbestblock(node) logging.info("Create some blocks with OP_1 coinbase for spending.") blocks = [] for _ in range(20): tip = self.build_block(tip) blocks.append(tip) self.pynode.send_blocks_and_test(blocks, node, success=True) self.spendable_outputs = deque(block.vtx[0] for block in blocks) logging.info("Mature the blocks.") node.generate(100) tip = self.getbestblock(node) # To make compact and fast-to-verify transactions, we'll use # CHECKDATASIG over and over with the same data. # (Using the same stuff over and over again means we get to hit the # node's signature cache and don't need to make new signatures every # time.) cds_message = b'' # r=1 and s=1 ecdsa, the minimum values. cds_signature = bytes.fromhex('3006020101020101') # Recovered pubkey cds_pubkey = bytes.fromhex( '03089b476b570d66fad5a20ae6188ebbaf793a4c2a228c65f3d79ee8111d56c932' ) def minefunding2(n): """ Mine a block with a bunch of outputs that are very dense sigchecks when spent (2 sigchecks each); return the inputs that can be used to spend. """ cds_scriptpubkey = CScript([ cds_message, cds_pubkey, OP_3DUP, OP_CHECKDATASIGVERIFY, OP_CHECKDATASIGVERIFY ]) # The scriptsig is carefully padded to have size 26, which is the # shortest allowed for 2 sigchecks for mempool admission. # The resulting inputs have size 67 bytes, 33.5 bytes/sigcheck. cds_scriptsig = CScript([b'x' * 16, cds_signature]) assert_equal(len(cds_scriptsig), 26) logging.debug( "Gen {} with locking script {} unlocking script {} .".format( n, cds_scriptpubkey.hex(), cds_scriptsig.hex())) tx = self.spendable_outputs.popleft() usable_inputs = [] txes = [] for i in range(n): tx = create_transaction(tx, cds_scriptpubkey, bytes([OP_TRUE]) if i == 0 else b"") txes.append(tx) usable_inputs.append( CTxIn(COutPoint(tx.sha256, 1), cds_scriptsig)) newtip = self.build_block(tip, txes) self.pynode.send_blocks_and_test([newtip], node, timeout=10) return usable_inputs, newtip logging.info("Funding special coins that have high sigchecks") # mine 5000 funded outputs (10000 sigchecks) # will be used pre-activation and post-activation usable_inputs, tip = minefunding2(5000) # assemble them into 50 txes with 100 inputs each (200 sigchecks) submittxes_1 = [] while len(usable_inputs) >= 100: tx = CTransaction() tx.vin = [usable_inputs.pop() for _ in range(100)] tx.vout = [CTxOut(0, CScript([OP_RETURN]))] tx.rehash() submittxes_1.append(tx) # mine 5000 funded outputs (10000 sigchecks) # will be used post-activation usable_inputs, tip = minefunding2(5000) # assemble them into 50 txes with 100 inputs each (200 sigchecks) submittxes_2 = [] while len(usable_inputs) >= 100: tx = CTransaction() tx.vin = [usable_inputs.pop() for _ in range(100)] tx.vout = [CTxOut(0, CScript([OP_RETURN]))] tx.rehash() submittxes_2.append(tx) # Check high sigcheck transactions logging.info("Create transaction that have high sigchecks") fundings = [] def make_spend(sigcheckcount): # Add a funding tx to fundings, and return a tx spending that using # scriptsig. logging.debug("Gen tx with {} sigchecks.".format(sigcheckcount)) def get_script_with_sigcheck(count): return CScript([cds_message, cds_pubkey] + (count - 1) * [OP_3DUP, OP_CHECKDATASIGVERIFY] + [OP_CHECKDATASIG]) # get funds locked with OP_1 sourcetx = self.spendable_outputs.popleft() # make funding that forwards to scriptpubkey last_sigcheck_count = ((sigcheckcount - 1) % 30) + 1 fundtx = create_transaction( sourcetx, get_script_with_sigcheck(last_sigcheck_count)) fill_sigcheck_script = get_script_with_sigcheck(30) remaining_sigcheck = sigcheckcount while remaining_sigcheck > 30: fundtx.vout[0].nValue -= 1000 fundtx.vout.append(CTxOut(100, bytes(fill_sigcheck_script))) remaining_sigcheck -= 30 fundtx.rehash() fundings.append(fundtx) # make the spending scriptsig = CScript([cds_signature]) tx = CTransaction() tx.vin.append(CTxIn(COutPoint(fundtx.sha256, 1), scriptsig)) input_index = 2 remaining_sigcheck = sigcheckcount while remaining_sigcheck > 30: tx.vin.append( CTxIn(COutPoint(fundtx.sha256, input_index), scriptsig)) remaining_sigcheck -= 30 input_index += 1 tx.vout.append(CTxOut(0, CScript([OP_RETURN]))) pad_tx(tx) tx.rehash() return tx # Create transactions with many sigchecks. good_tx = make_spend(MAX_TX_SIGCHECK) bad_tx = make_spend(MAX_TX_SIGCHECK + 1) tip = self.build_block(tip, fundings) self.pynode.send_blocks_and_test([tip], node) # Both tx are accepted before the activation. pre_activation_sigcheck_block = self.build_block( tip, [good_tx, bad_tx]) self.pynode.send_blocks_and_test([pre_activation_sigcheck_block], node) node.invalidateblock(pre_activation_sigcheck_block.hash) # after block is invalidated these tx are put back into the mempool. Test uses them later so evict. waitFor(10, lambda: node.getmempoolinfo()["size"] == 2) node.evicttransaction(good_tx.hash) node.evicttransaction(bad_tx.hash) # Activation tests logging.info("Approach to just before upgrade activation") # Move our clock to the uprade time so we will accept such # future-timestamped blocks. node.setmocktime(SIGCHECKS_ACTIVATION_TIME + 10) # Mine six blocks with timestamp starting at # SIGCHECKS_ACTIVATION_TIME-1 blocks = [] for i in range(-1, 5): tip = self.build_block(tip, nTime=SIGCHECKS_ACTIVATION_TIME + i) blocks.append(tip) self.pynode.send_blocks_and_test(blocks, node, timeout=TIMEOUT) assert_equal(node.getblockchaininfo()['mediantime'], SIGCHECKS_ACTIVATION_TIME - 1) logging.info( "The next block will activate, but the activation block itself must follow old rules" ) # Send the 50 txes and get the node to mine as many as possible (it should do all) # The node is happy mining and validating a 10000 sigcheck block before # activation. self.pynode.send_txs_and_test(submittxes_1, node, timeout=TIMEOUT) [blockhash] = node.generate(1) assert_equal(set(node.getblock(blockhash, 1)["tx"][1:]), {t.hash for t in submittxes_1}) # We have activated, but let's invalidate that. assert_equal(node.getblockchaininfo()['mediantime'], SIGCHECKS_ACTIVATION_TIME) node.invalidateblock(blockhash) # Try again manually and invalidate that too goodblock = self.build_block(tip, submittxes_1) self.pynode.send_blocks_and_test([goodblock], node, timeout=TIMEOUT) node.invalidateblock(goodblock.hash) # All transactions should be back in mempool: validation is very slow in debug build waitFor( 60, lambda: set(node.getrawmempool()) == {t.hash for t in submittxes_1}) logging.info("Mine the activation block itself") tip = self.build_block(tip) self.pynode.send_blocks_and_test([tip], node, timeout=TIMEOUT) logging.info("We have activated!") assert_equal(node.getblockchaininfo()['mediantime'], SIGCHECKS_ACTIVATION_TIME) # All transactions get re-evaluated to count sigchecks, so wait for them waitFor( 60, lambda: set(node.getrawmempool()) == {t.hash for t in submittxes_1}) logging.info( "Try a block with a transaction going over the limit (limit: {})". format(MAX_TX_SIGCHECK)) bad_tx_block = self.build_block(tip, [bad_tx]) check_for_ban_on_rejected_block( self.pynode, node, bad_tx_block, reject_reason=BLOCK_SIGCHECKS_BAD_TX_SIGCHECKS) logging.info( "Try a block with a transaction just under the limit (limit: {})". format(MAX_TX_SIGCHECK)) good_tx_block = self.build_block(tip, [good_tx]) self.pynode.send_blocks_and_test([good_tx_block], node, timeout=TIMEOUT) node.invalidateblock(good_tx_block.hash) # save this tip for later # ~ upgrade_block = tip # Transactions still in pool: waitFor( 60, lambda: set(node.getrawmempool()) == {t.hash for t in submittxes_1}) logging.info( "Try sending 10000-sigcheck blocks after activation (limit: {})". format(MAXBLOCKSIZE // BLOCK_MAXBYTES_MAXSIGCHECKS_RATIO)) # Send block with same txes we just tried before activation badblock = self.build_block(tip, submittxes_1) check_for_ban_on_rejected_block( self.pynode, node, badblock, reject_reason="Invalid block due to bad-blk-sigchecks", expect_ban=True) logging.info( "There are too many sigchecks in mempool to mine in a single block. Make sure the node won't mine invalid blocks. Num tx: %s" % str(node.getmempoolinfo())) blk = node.generate(1) tip = self.getbestblock(node) # only 39 txes got mined. assert_equal(len(node.getrawmempool()), 11) logging.info( "Try sending 10000-sigcheck block with fresh transactions after activation (limit: {})" .format(MAXBLOCKSIZE // BLOCK_MAXBYTES_MAXSIGCHECKS_RATIO)) # Note: in the following tests we'll be bumping timestamp in order # to bypass any kind of 'bad block' cache on the node, and get a # fresh evaluation each time. # Try another block with 10000 sigchecks but all fresh transactions badblock = self.build_block(tip, submittxes_2, nTime=SIGCHECKS_ACTIVATION_TIME + 5) check_for_ban_on_rejected_block( self.pynode, node, badblock, reject_reason=BLOCK_SIGCHECKS_BAD_BLOCK_SIGCHECKS) # Send the same txes again with different block hash. Currently we don't # cache valid transactions in invalid blocks so nothing changes. badblock = self.build_block(tip, submittxes_2, nTime=SIGCHECKS_ACTIVATION_TIME + 6) check_for_ban_on_rejected_block( self.pynode, node, badblock, reject_reason=BLOCK_SIGCHECKS_BAD_BLOCK_SIGCHECKS) # Put all the txes in mempool, in order to get them cached: self.pynode.send_txs_and_test(submittxes_2, node, timeout=TIMEOUT) # Send them again, the node still doesn't like it. But the log # error message has now changed because the txes failed from cache. badblock = self.build_block(tip, submittxes_2, nTime=SIGCHECKS_ACTIVATION_TIME + 7) check_for_ban_on_rejected_block( self.pynode, node, badblock, reject_reason=BLOCK_SIGCHECKS_BAD_BLOCK_SIGCHECKS) logging.info( "Try sending 8000-sigcheck block after activation (limit: {})". format(MAXBLOCKSIZE // BLOCK_MAXBYTES_MAXSIGCHECKS_RATIO)) badblock = self.build_block(tip, submittxes_2[:40], nTime=SIGCHECKS_ACTIVATION_TIME + 5) check_for_ban_on_rejected_block( self.pynode, node, badblock, reject_reason=BLOCK_SIGCHECKS_BAD_BLOCK_SIGCHECKS) # redundant, but just to mirror the following test... node.set("consensus.maxBlockSigChecks=%d" % MAX_BLOCK_SIGCHECKS) logging.info( "Bump the excessiveblocksize limit by 1 byte, and send another block with same txes (new sigchecks limit: {})" .format((MAXBLOCKSIZE + 1) // BLOCK_MAXBYTES_MAXSIGCHECKS_RATIO)) node.set("consensus.maxBlockSigChecks=%d" % (MAX_BLOCK_SIGCHECKS + 1)) tip = self.build_block(tip, submittxes_2[:40], nTime=SIGCHECKS_ACTIVATION_TIME + 6) # It should succeed now since limit should be 8000. self.pynode.send_blocks_and_test([tip], node, timeout=TIMEOUT)