def assert_tx_valid(self, tx, assert_valid=True): # Test the validity of the transaction by manually mining a block that contains the tx. block = FromHex(CBlock(), self.nodes[2].getnewblockhex()) assert len(block.vtx) > 0 block.vtx.append(tx) block.hashMerkleRoot = block.calc_merkle_root() add_witness_commitment(block) block.solve() block_hex = WitToHex(block) # First test the testproposed block RPC. if assert_valid: self.nodes[0].testproposedblock(block_hex) else: assert_raises_rpc_error(-25, "block-validation-failed", self.nodes[0].testproposedblock, block_hex) # Then try submit the block and check if it was accepted or not. pre = self.nodes[0].getblockcount() self.nodes[0].submitblock(block_hex) post = self.nodes[0].getblockcount() if assert_valid: # assert block was accepted assert pre < post else: # assert block was not accepted assert pre == post
def assert_tx_standard(self, tx, assert_standard=True): # Test the standardness of the tx by submitting it to the mempool. test_accept = self.nodes[0].testmempoolaccept([WitToHex(tx)])[0] if assert_standard: assert test_accept["allowed"], "tx was not accepted: {}".format(test_accept["reject-reason"]) else: assert not test_accept["allowed"], "tx was accepted"
def test_coinbase_witness(self): block = self.nodes[0].getnewblockhex() block_struct = FromHex(CBlock(), block) # Test vanilla block round-trip self.nodes[0].testproposedblock(WitToHex(block_struct)) # Assert there's scriptWitness in the coinbase input that is the witness nonce and nothing else assert_equal(block_struct.vtx[0].wit.vtxinwit[0].scriptWitness.stack, [b'\x00'*32]) assert_equal(block_struct.vtx[0].wit.vtxinwit[0].vchIssuanceAmountRangeproof, b'') assert_equal(block_struct.vtx[0].wit.vtxinwit[0].vchInflationKeysRangeproof, b'') assert_equal(block_struct.vtx[0].wit.vtxinwit[0].peginWitness.stack, []) # Add extra witness that isn't covered by witness merkle root, make sure blocks are still valid block_witness_stuffed = copy.deepcopy(block_struct) block_witness_stuffed.vtx[0].wit.vtxinwit[0].vchIssuanceAmountRangeproof = b'\x00' assert_raises_rpc_error(-25, "bad-cb-witness", self.nodes[0].testproposedblock, WitToHex(block_witness_stuffed)) block_witness_stuffed = copy.deepcopy(block_struct) block_witness_stuffed.vtx[0].wit.vtxinwit[0].vchInflationKeysRangeproof = b'\x00' assert_raises_rpc_error(-25, "bad-cb-witness", self.nodes[0].testproposedblock, WitToHex(block_witness_stuffed)) block_witness_stuffed = copy.deepcopy(block_struct) # Let's blow out block weight limit by adding 4MW here block_witness_stuffed.vtx[0].wit.vtxinwit[0].peginWitness.stack = [b'\x00'*4000000] assert_raises_rpc_error(-25, "bad-cb-witness", self.nodes[0].testproposedblock, WitToHex(block_witness_stuffed)) # Test that node isn't blinded to the block # Previously an over-stuffed block >4MW would have been marked permanently bad # as it already passes witness merkle and regular merkle root checks block_height = self.nodes[0].getblockcount() assert_equal(self.nodes[0].submitblock(WitToHex(block_witness_stuffed)), "bad-cb-witness") assert_equal(block_height, self.nodes[0].getblockcount()) assert_equal(self.nodes[0].submitblock(WitToHex(block_struct)), None) assert_equal(block_height+1, self.nodes[0].getblockcount()) # New block since we used the first one block_struct = FromHex(CBlock(), self.nodes[0].getnewblockhex()) block_witness_stuffed = copy.deepcopy(block_struct) # Add extra witness data that is covered by witness merkle root, make sure invalid assert_equal(block_witness_stuffed.vtx[0].wit.vtxoutwit[0].vchSurjectionproof, b'') assert_equal(block_witness_stuffed.vtx[0].wit.vtxoutwit[0].vchRangeproof, b'') block_witness_stuffed.vtx[0].wit.vtxoutwit[0].vchRangeproof = b'\x00'*100000 block_witness_stuffed.vtx[0].wit.vtxoutwit[0].vchSurjectionproof = b'\x00'*100000 assert_raises_rpc_error(-25, "bad-witness-merkle-match", self.nodes[0].testproposedblock, WitToHex(block_witness_stuffed)) witness_root_hex = block_witness_stuffed.calc_witness_merkle_root() witness_root = uint256_from_str(hex_str_to_bytes(witness_root_hex)[::-1]) block_witness_stuffed.vtx[0].vout[-1] = CTxOut(0, get_witness_script(witness_root, 0)) block_witness_stuffed.vtx[0].rehash() block_witness_stuffed.hashMerkleRoot = block_witness_stuffed.calc_merkle_root() block_witness_stuffed.rehash() assert_raises_rpc_error(-25, "bad-cb-amount", self.nodes[0].testproposedblock, WitToHex(block_witness_stuffed)) assert_greater_than(len(WitToHex(block_witness_stuffed)), 100000*4) # Make sure the witness data is actually serialized # A CTxIn that always serializes the asset issuance, even for coinbases. class AlwaysIssuanceCTxIn(CTxIn): def serialize(self): r = b'' outpoint = COutPoint() outpoint.hash = self.prevout.hash outpoint.n = self.prevout.n outpoint.n |= OUTPOINT_ISSUANCE_FLAG r += outpoint.serialize() r += ser_string(self.scriptSig) r += struct.pack("<I", self.nSequence) r += self.assetIssuance.serialize() return r # Test that issuance inputs in coinbase don't survive a serialization round-trip # (even though this can't cause issuance to occur either way due to VerifyCoinbaseAmount semantics) block_witness_stuffed = copy.deepcopy(block_struct) coinbase_orig = copy.deepcopy(block_witness_stuffed.vtx[0].vin[0]) coinbase_ser_size = len(block_witness_stuffed.vtx[0].vin[0].serialize()) block_witness_stuffed.vtx[0].vin[0] = AlwaysIssuanceCTxIn() block_witness_stuffed.vtx[0].vin[0].prevout = coinbase_orig.prevout block_witness_stuffed.vtx[0].vin[0].scriptSig = coinbase_orig.scriptSig block_witness_stuffed.vtx[0].vin[0].nSequence = coinbase_orig.nSequence block_witness_stuffed.vtx[0].vin[0].assetIssuance.nAmount.setToAmount(1) bad_coinbase_ser_size = len(block_witness_stuffed.vtx[0].vin[0].serialize()) # 32+32+9+1 should be serialized for each assetIssuance field assert_equal(bad_coinbase_ser_size, coinbase_ser_size+32+32+9+1) assert not block_witness_stuffed.vtx[0].vin[0].assetIssuance.isNull() assert_raises_rpc_error(-22, "TX decode failed", self.nodes[0].decoderawtransaction, ToHex(block_witness_stuffed.vtx[0]))