def mine_and_test_listunspent(self, script_list, ismine): utxo = find_unspent(self.nodes[0], 50) tx = CTransaction() tx.vin.append(CTxIn(COutPoint(int("0x" + utxo["txid"], 0), utxo["vout"]))) for i in script_list: tx.vout.append(CTxOut(10000000, i)) tx.rehash() signresults = self.nodes[0].signrawtransaction(bytes_to_hex_str(tx.serialize_without_witness()))["hex"] txid = self.nodes[0].sendrawtransaction(signresults, True) self.nodes[0].generate(1) sync_blocks(self.nodes) watchcount = 0 spendcount = 0 for i in self.nodes[0].listunspent(): if i["txid"] == txid: watchcount += 1 if i["spendable"] == True: spendcount += 1 if ismine == 2: assert_equal(spendcount, len(script_list)) elif ismine == 1: assert_equal(watchcount, len(script_list)) assert_equal(spendcount, 0) else: assert_equal(watchcount, 0) return txid
def mine_and_test_listunspent(self, script_list, ismine): utxo = find_spendable_utxo(self.nodes[0], 50) tx = CTransaction() tx.vin.append(CTxIn(COutPoint(int('0x'+utxo['txid'],0), utxo['vout']))) for i in script_list: tx.vout.append(CTxOut(10000000, i)) tx.rehash() signresults = self.nodes[0].signrawtransactionwithwallet(bytes_to_hex_str(tx.serialize_without_witness()))['hex'] txid = self.nodes[0].sendrawtransaction(signresults, True) self.nodes[0].generate(1) sync_blocks(self.nodes) watchcount = 0 spendcount = 0 for i in self.nodes[0].listunspent(): if (i['txid'] == txid): watchcount += 1 if (i['spendable'] == True): spendcount += 1 if (ismine == 2): assert_equal(spendcount, len(script_list)) elif (ismine == 1): assert_equal(watchcount, len(script_list)) assert_equal(spendcount, 0) else: assert_equal(watchcount, 0) return txid
def create_and_mine_tx_from_txids(self, txids, success = True): tx = CTransaction() for i in txids: txtmp = CTransaction() txraw = self.nodes[0].getrawtransaction(i) f = BytesIO(hex_str_to_bytes(txraw)) txtmp.deserialize(f) for j in range(len(txtmp.vout)): tx.vin.append(CTxIn(COutPoint(int('0x'+i,0), j))) tx.vout.append(CTxOut(0, CScript())) tx.rehash() signresults = self.nodes[0].signrawtransactionwithwallet(bytes_to_hex_str(tx.serialize_without_witness()))['hex'] self.nodes[0].sendrawtransaction(signresults, True) self.nodes[0].generate(1) sync_blocks(self.nodes)
def create_tx(self, outpoints, noutput): tx = CTransaction() total_input = 0 for parent_tx, n in outpoints: tx.vin.append( CTxIn(COutPoint(parent_tx.sha256, n), b"", 0xffffffff)) total_input += parent_tx.vout[n].nValue for _ in range(noutput): tx.vout.append( CTxOut(total_input // noutput - 1000, CScript([b"X" * 200, OP_DROP, OP_TRUE]))) tx.rehash() return tx
def create_and_mine_tx_from_txids(self, txids, success = True): tx = CTransaction() for i in txids: txtmp = CTransaction() txraw = self.nodes[0].getrawtransaction(i) f = BytesIO(hex_str_to_bytes(txraw)) txtmp.deserialize(f) for j in range(len(txtmp.vout)): tx.vin.append(CTxIn(COutPoint(int('0x'+i,0), j))) tx.vout.append(CTxOut(0, CScript())) tx.rehash() signresults = self.nodes[0].signrawtransaction(bytes_to_hex_str(tx.serialize_without_witness()))['hex'] self.nodes[0].sendrawtransaction(signresults, True) self.nodes[0].generate(1) sync_blocks(self.nodes)
def test_case(self, rpcsend=None, conn=None): # First create funding transaction that pays to output that does not require signatures. out_value = 10000 ftx = CTransaction() ftx.vout.append(CTxOut(out_value, CScript([OP_TRUE]))) ftxHex = self.nodes[0].fundrawtransaction(ToHex(ftx),{ 'changePosition' : len(ftx.vout)})['hex'] ftxHex = self.nodes[0].signrawtransaction(ftxHex)['hex'] ftx = FromHex(CTransaction(), ftxHex) ftx.rehash() # Allow coinbase to mature self.nodes[0].generate(101) # Feed in funding txn and wait for both nodes to see it self.send_txn(rpcsend, conn, ftx) wait_until(lambda: ftx.hash in self.nodes[0].getrawmempool(), timeout=5) wait_until(lambda: ftx.hash in self.nodes[1].getrawmempool(), timeout=5) # Create non-final txn. parent_txid = ftx.sha256 send_value = out_value - 500; tx = CTransaction() tx.vin.append(CTxIn(COutPoint(parent_txid, 0), b'', 0x01)) tx.vout.append(CTxOut(int(send_value), CScript([OP_TRUE]))) tx.nLockTime = int(time.time()) + 300 tx.rehash() # Send non-final txn to node0. It should be forwarded over P2P to node1. self.send_txn(rpcsend, conn, tx) wait_until(lambda: tx.hash in self.nodes[0].getrawnonfinalmempool(), timeout=5) wait_until(lambda: tx.hash in self.nodes[1].getrawnonfinalmempool(), timeout=5) assert(tx.hash not in self.nodes[0].getrawmempool()) assert(tx.hash not in self.nodes[1].getrawmempool()) # Create finalising txn. finaltx = copy.deepcopy(tx) finaltx.vin[0].nSequence = 0xFFFFFFFF; finaltx.rehash() # Send finalising txn to node0. It should be forwarded over P2P to node1. self.send_txn(rpcsend, conn, finaltx) wait_until(lambda: finaltx.hash in self.nodes[0].getrawmempool(), timeout=5) wait_until(lambda: finaltx.hash in self.nodes[1].getrawmempool(), timeout=5) assert(tx.hash not in self.nodes[0].getrawnonfinalmempool()) assert(tx.hash not in self.nodes[1].getrawnonfinalmempool())
def make_funding_transaction(node, n_outputs=30, value=100000000): ftx = CTransaction() for i in range(n_outputs): ftx.vout.append(CTxOut(value, CScript([OP_TRUE]))) # fund the transcation: ftxHex = node.fundrawtransaction(ToHex(ftx), {'changePosition': len(ftx.vout)})['hex'] ftxHex = node.signrawtransaction(ftxHex)['hex'] ftx = FromHex(CTransaction(), ftxHex) ftx.rehash() node.sendrawtransaction(ftxHex) node.generate(1) return ftx
def send_funds_to_attacker(self, node, attacker, coinbase_tx): funding_amount = int(coinbase_tx.vout[0].nValue / self.nbDoubleSpends) funding_tx = CTransaction() funding_tx.vin.append( CTxIn(COutPoint(coinbase_tx.sha256, 0), b"", 0xffffffff)) scriptPubKey = CScript([ OP_DUP, OP_HASH160, hash160(attacker.pubkey), OP_EQUALVERIFY, OP_CHECKSIG ]) for i in range(self.nbDoubleSpends): funding_tx.vout.append(CTxOut(funding_amount, scriptPubKey)) funding_tx.rehash() funding_txid = node.sendrawtransaction(ToHex(funding_tx), False, True) assert_equal(node.getrawmempool(), [funding_txid]) return funding_tx
def new_transaction(utxokey, utxo, target_tx_size): ndx, tx_to_spend = utxo padding_size = target_tx_size while True: tx = CTransaction() tx.vin.append(CTxIn(COutPoint(tx_to_spend.sha256, ndx), b'')) tx.vin[0].scriptSig = b'' tx.vout.append(CTxOut(tx_to_spend.vout[0].nValue - 2 * target_tx_size, SIMPLE_OUTPUT_SCRIPT)) tx.vout.append(CTxOut(1, CScript([OP_FALSE,OP_RETURN] + [bytes(1) * padding_size]))) sighash = SignatureHashForkId(tx_to_spend.vout[0].scriptPubKey, tx, 0, SIGHASH_ALL | SIGHASH_FORKID, tx_to_spend.vout[0].nValue) sig = utxokey.sign(sighash) + bytes(bytearray([SIGHASH_ALL | SIGHASH_FORKID])) tx.vin[0].scriptSig = CScript([sig]) tx.rehash() diff = target_tx_size - len(tx.serialize()) if diff == 0: return tx padding_size += diff
def create_and_mine_tx_from_txids(self, txids, success=True): tx = CTransaction() for txid in txids: txtmp = CTransaction() txraw = self.nodes[0].getrawtransaction(txid) f = BytesIO(hex_str_to_bytes(txraw)) txtmp.deserialize(f) for j in range(len(txtmp.vout)): tx.vin.append(CTxIn(COutPoint(int('0x' + txid, 0), j))) tx.vout.append(CTxOut(0, CScript([OP_TRUE]))) tx.rehash() signresultfull = self.nodes[0].signrawtransaction( bytes_to_hex_str(tx.serialize_without_witness())) signresult = signresultfull['hex'] assert_equal(signresultfull['complete'], True) self.nodes[0].sendrawtransaction(signresult, True) self.nodes[0].generate(1) sync_blocks(self.nodes)
def create_transaction(node, coinbase, to_address, amount, expiry_height): from_txid = node.getblock(coinbase)['tx'][0] inputs = [{"txid": from_txid, "vout": 0}] outputs = {to_address: amount} rawtx = node.createrawtransaction(inputs, outputs) tx = CTransaction() # Set the expiry height f = cStringIO.StringIO(unhexlify(rawtx)) tx.deserialize(f) tx.nExpiryHeight = expiry_height rawtx = hexlify(tx.serialize()) signresult = node.signrawtransaction(rawtx) f = cStringIO.StringIO(unhexlify(signresult['hex'])) tx.deserialize(f) tx.rehash() return tx
def spend_tx_to_data(tx_to_spend, key_for_tx_to_spend): "Create and send block with coinbase, returns conbase (tx, key) tuple" tx = CTransaction() tx.vin.append(CTxIn(COutPoint(tx_to_spend.sha256, 0), b"", 0xffffffff)) amount = tx_to_spend.vout[0].nValue - 2000 tx.vout.append(CTxOut(amount, OP_TRUE_OP_RETURN_SCRIPT)) sighash = SignatureHashForkId(tx_to_spend.vout[0].scriptPubKey, tx, 0, SIGHASH_ALL | SIGHASH_FORKID, tx_to_spend.vout[0].nValue) tx.vin[0].scriptSig = CScript([ key_for_tx_to_spend.sign(sighash) + bytes(bytearray([SIGHASH_ALL | SIGHASH_FORKID])) ]) tx.rehash() return tx
def create_children_txs(parent_tx1, keys1, parent_tx2, keys2, invalidity=None): ret = [] for n, (txout1, key1, txout2, key2) in enumerate( zip(parent_tx1.vout, keys1, parent_tx2.vout, keys2)): amount1 = txout1.nValue if invalidity == "low_fee" else int( 0.99 * txout1.nValue) amount2 = txout2.nValue if invalidity == "low_fee" else int( 0.99 * txout2.nValue) amount = amount1 + amount2 tx = CTransaction() tx.vin.append(CTxIn(COutPoint(parent_tx1.sha256, n), b"", 0xffffffff)) tx.vin.append(CTxIn(COutPoint(parent_tx2.sha256, n), b"", 0xffffffff)) k = CECKey() k.set_secretbytes(b"x" * (n + 1)) tx.vout.append(CTxOut(amount, CScript([k.get_pubkey(), OP_CHECKSIG]))) tx.calc_sha256() sighash1 = SignatureHashForkId(parent_tx1.vout[n].scriptPubKey, tx, 0, SIGHASH_ALL | SIGHASH_FORKID, parent_tx1.vout[n].nValue) tx.vin[0].scriptSig = CScript([ key1.sign(sighash1) + bytes(bytearray([SIGHASH_ALL | SIGHASH_FORKID])) ]) if invalidity == "bad_signature": sighash2 = b"\xff" * 32 else: sighash2 = SignatureHashForkId(parent_tx2.vout[n].scriptPubKey, tx, 1, SIGHASH_ALL | SIGHASH_FORKID, parent_tx2.vout[n].nValue) tx.vin[1].scriptSig = CScript([ key2.sign(sighash2) + bytes(bytearray([SIGHASH_ALL | SIGHASH_FORKID])) ]) tx.rehash() ret.append(tx) return ret
def make_utxo(node, amount, confirmed=True, script_pub_key=CScript([1])): """Create a txout with a given amount and scriptPubKey Mines coins as needed. confirmed - txouts created will be confirmed in the blockchain; unconfirmed otherwise. """ fee = 1 * COIN while node.getbalance() < satoshi_round((amount + fee) / COIN): node.generate(100) new_addr = node.getnewaddress() txid = node.sendtoaddress(new_addr, satoshi_round((amount + fee) / COIN)) tx1 = node.getrawtransaction(txid, 1) txid = int(txid, 16) i = None for i, txout in enumerate(tx1['vout']): if txout['scriptPubKey']['addresses'] == [new_addr]: break assert i is not None tx2 = CTransaction() tx2.vin = [CTxIn(COutPoint(txid, i))] tx2.vout = [CTxOut(amount, script_pub_key)] tx2.rehash() signed_tx = node.signrawtransaction(tx_to_hex(tx2)) txid = node.sendrawtransaction(signed_tx['hex'], True) # If requested, ensure txouts are confirmed. if confirmed: mempool_size = len(node.getrawmempool()) while mempool_size > 0: node.generate(1) new_size = len(node.getrawmempool()) # Error out if we have something stuck in the mempool, as this # would likely be a bug. assert (new_size < mempool_size) mempool_size = new_size return COutPoint(int(txid, 16), 0)
def test_submitbranchblockinfo(self): ''' submitbranchblockinfo "CTransaction hex data" Include branch block data to a transaction, then send to main chain :return: ''' self.log.info(sys._getframe().f_code.co_name) txid = self.node0.sendtoaddress(self.node0.getnewaddress(), 1) tx_hex = self.node0.getrawtransaction(txid) assert_raises_rpc_error(-32602, 'Invalid transaction data', self.node0.submitbranchblockinfo, tx_hex) assert_raises_rpc_error( -32602, 'This rpc api can not be called in branch chain', self.snode0.submitbranchblockinfo, tx_hex) tx = CTransaction() tx.nVersion = 9 tx.rehash() assert_raises_rpc_error(-4, 'DecodeHexTx tx hex fail', self.node0.submitbranchblockinfo, tx.hash)
def create_tx(self, outpoints, noutput, feerate, make_long_eval_script=False): """creates p2pk transaction always using the same key (created in constructor), if make_long_eval_script is set we are prepending long evaluating script to the locking script """ pre_script = MemepoolAcceptingTransactionsDuringReorg.long_eval_script if make_long_eval_script else [] tx = CTransaction() total_input = 0 for parent_tx, n in outpoints: tx.vin.append( CTxIn(COutPoint(parent_tx.sha256, n), CScript([b"0" * 72]), 0xffffffff)) total_input += parent_tx.vout[n].nValue for _ in range(noutput): tx.vout.append( CTxOut(total_input // noutput, CScript(pre_script + [self.public_key, OP_CHECKSIG]))) tx.rehash() tx_size = len(tx.serialize()) fee_per_output = int(tx_size * feerate // noutput) for output in tx.vout: output.nValue -= fee_per_output for input, (parent_tx, n) in zip(tx.vin, outpoints): sighash = SignatureHashForkId(parent_tx.vout[n].scriptPubKey, tx, 0, SIGHASH_ALL | SIGHASH_FORKID, parent_tx.vout[n].nValue) input.scriptSig = CScript([ self.private_key.sign(sighash) + bytes(bytearray([SIGHASH_ALL | SIGHASH_FORKID])) ]) tx.rehash() return tx
def create_tx(self, outpoints, noutput, feerate): tx = CTransaction() total_input = 0 for parent_tx, n in outpoints: tx.vin.append(CTxIn(COutPoint(parent_tx.sha256, n), b"", 0xffffffff)) total_input += parent_tx.vout[n].nValue for _ in range(noutput): tx.vout.append(CTxOut(total_input//noutput, CScript([b"X"*200, OP_DROP, OP_TRUE]))) tx.rehash() tx_size = len(tx.serialize()) fee_per_output = int(tx_size * feerate // noutput) for output in tx.vout: output.nValue -= fee_per_output tx.rehash() return tx
def create_tx(self, outpoints, noutput, feerate, totalSize=0, size_of_nonpayin_txs=0): tx = CTransaction() total_input = 0 for parent_tx, n in outpoints: tx.vin.append( CTxIn(COutPoint(parent_tx.sha256, n), b"", 0xffffffff)) total_input += parent_tx.vout[n].nValue for _ in range(noutput): tx.vout.append(CTxOut(total_input // noutput, CScript([OP_TRUE]))) if totalSize: tx.rehash() missingSize = totalSize - self.tx_size(tx) assert missingSize >= 0 tx.vout[0].scriptPubKey = CScript( [b"X" * (missingSize - 10), OP_DROP, OP_TRUE]) tx.rehash() overall_size = self.tx_size(tx) + size_of_nonpayin_txs fee_per_output = ceil(overall_size * feerate / noutput) for output in tx.vout: output.nValue -= fee_per_output tx.rehash() return tx
def mine_using_template(self, nodeidx=0): tmpl = self.nodes[nodeidx].getblocktemplate() assert 'proposal' in tmpl['capabilities'] assert 'coinbasetxn' not in tmpl coinbase_tx = create_coinbase(height=int(tmpl["height"])) block = CBlock() block.nVersion = int(tmpl["version"]) block.hashPrevBlock = int(tmpl["previousblockhash"], 16) block.nTime = tmpl["curtime"] block.nBits = int(tmpl["bits"], 16) block.nNonce = 0 # extended block block.nStakeDifficulty = int(tmpl["stakedifficulty"], 16) block.nVoteBits = tmpl["votebits"] block.nTicketPoolSize = tmpl["ticketpoolsize"] block.ticketLotteryState = tmpl["ticketlotterystate"] block.nVoters = tmpl["voters"] block.nFreshStake = tmpl["freshstake"] block.nRevocations = tmpl["revocations"] block.extraData = tmpl["extradata"] block.nStakeVersion = tmpl["stakeversion"] block.vtx = [coinbase_tx] for tx in tmpl["transactions"]: ctx = CTransaction() ctx.deserialize(BytesIO(hex_str_to_bytes(tx['data']))) ctx.rehash() block.vtx.append(ctx) block.hashMerkleRoot = block.calc_merkle_root() add_witness_commitment(block) block.solve() print("-------------") print("mine using template on node:", nodeidx) print('solved hash', block.hash) # print("submit for height", idx) submit_result = self.nodes[nodeidx].submitblock(ToHex(block)) print(submit_result) assert (submit_result in [None, "inconclusive"]) return block.hash
def run_test(self): self.log.info("Mining blocks...") self.nodes[0].generate(105) self.sync_all() chain_height = self.nodes[1].getblockcount() assert_equal(chain_height, 105) self.log.info("Testing transaction index...") #privkey = "cSdkPxkAjA4HDr5VHgsebAPDEh9Gyub4HK8UJr2DFGGqKKy4K5sG" #address = "mgY65WSfEmsyYaYPQaXhmXMeBhwp4EcsQW" address_hash = bytes([ 11, 47, 10, 12, 49, 191, 224, 64, 107, 12, 204, 19, 129, 253, 190, 49, 25, 70, 218, 220 ]) script_pub_key = CScript( [OP_DUP, OP_HASH160, address_hash, OP_EQUALVERIFY, OP_CHECKSIG]) unspent = self.nodes[0].listunspent() tx = CTransaction() amount = int(unspent[0]["amount"] * 10000000) tx.vin = [ CTxIn(COutPoint(int(unspent[0]["txid"], 16), unspent[0]["vout"])) ] tx.vout = [CTxOut(amount, script_pub_key)] tx.rehash() signed_tx = self.nodes[0].signrawtransaction( binascii.hexlify(tx.serialize()).decode("utf-8")) self.nodes[0].sendrawtransaction(signed_tx["hex"], True) self.nodes[0].generate(1) self.sync_all() # Check verbose raw transaction results verbose = self.nodes[3].getrawtransaction(unspent[0]["txid"], 1) assert_equal(verbose["vout"][0]["valueSat"], 500000000000) assert_equal(verbose["vout"][0]["value"], 5000) self.log.info("All Tests Passed")
def make_utxos(self): # Doesn't matter which node we use, just use node0. block = self.build_block_on_tip(self.nodes[0]) self.test_node.send_and_ping(MsgBlock(block)) assert (int(self.nodes[0].getbestblockhash(), 16) == block.sha256) self.nodes[0].generate(100) total_value = block.vtx[0].vout[0].nValue out_value = total_value // 10 tx = CTransaction() tx.vin.append(CTxIn(COutPoint(block.vtx[0].sha256, 0), b'')) for _ in range(10): tx.vout.append(CTxOut(out_value, CScript([OP_TRUE]))) tx.rehash() block2 = self.build_block_on_tip(self.nodes[0]) block2.vtx.append(tx) block2.hashMerkleRoot = block2.calc_merkle_root() block2.solve() self.test_node.send_and_ping(MsgBlock(block2)) assert_equal(int(self.nodes[0].getbestblockhash(), 16), block2.sha256) self.utxos.extend([[tx.x16r, i, out_value] for i in range(10)]) return
def spend_separator_tx(tx_sep_tx, keys_for_sep_tx): """spends Transaction with scriptPubKey in form of: <pk1> OP_CHECKSIGVERIFY OP_CODESEPARATOR <pk2> OP_CHECKSIGVERIFY OP_CODESEPARATOR ... <pk N_signings> OP_CHECKSIG """ tx = CTransaction() tx.vin.append(CTxIn(COutPoint(tx_sep_tx.sha256, 0), b"", 0xffffffff)) k = CECKey() k.set_secretbytes(b"horsebattery") amount = tx_sep_tx.vout[0].nValue - 2000 script_lists = [[]] for item in list(tx_sep_tx.vout[0].scriptPubKey): for l in script_lists: l.append(item) if item == OP_CODESEPARATOR: script_lists.append([]) tx.vout.append(CTxOut(amount, CScript([k.get_pubkey(), OP_CHECKSIG]))) flags = bytes(bytearray([SIGHASH_ALL | SIGHASH_FORKID])) sign_list = [] for sc, key in zip(script_lists, keys_for_sep_tx): sighash = SignatureHashForkId(CScript(sc), tx, 0, SIGHASH_ALL | SIGHASH_FORKID, tx_sep_tx.vout[0].nValue) sign_list.append(key.sign(sighash) + flags) tx.vin[0].scriptSig = CScript(reversed(sign_list)) tx.rehash() return tx, k
def prepare_for_test(self, height, label, coinbases, connections): transactions = [] n_generated_utxos = 0 while n_generated_utxos < self._NUMBER_OF_UTXOS_PER_HEIGHT: tx_to_spend = coinbases() tx = CTransaction() transactions.append(tx) tx.vin.append(CTxIn(COutPoint(tx_to_spend.sha256, 0), b'')) locking_key = self._UTXO_KEY cscript = CScript([locking_key.get_pubkey(), OP_CHECKSIG ]) if locking_key else CScript([OP_TRUE]) for x in range(24): coinbaseoutput = CTxOut(2 * COIN, cscript) tx.vout.append(coinbaseoutput) n_generated_utxos += 1 if self.COINBASE_KEY: tx.rehash() sighash = SignatureHashForkId(tx_to_spend.vout[0].scriptPubKey, tx, 0, SIGHASH_ALL | SIGHASH_FORKID, tx_to_spend.vout[0].nValue) sig = self._coinbase_key.sign(sighash) + bytes( bytearray([SIGHASH_ALL | SIGHASH_FORKID])) tx.vin[0].scriptSig = CScript([sig]) else: tx.vin[0].scriptSig = CScript([OP_TRUE]) tx.rehash() self.log.info( f"Created UTXO Tx {loghash(tx.hash)} with {n_generated_utxos} outputs" ) return transactions, None
def make_invalid_p2sh_tx(tx_to_spend, output_ndx): tx = CTransaction() tx.vin.append(CTxIn(COutPoint(tx_to_spend.sha256, output_ndx), b"", 0xffffffff)) tx.vout.append(CTxOut(tx_to_spend.vout[0].nValue - 2000, CScript([OP_HASH160, hash160(b'123'), OP_EQUAL]))) tx.rehash() return tx
def run_test(self): print "Mining blocks..." self.nodes[0].generate(105) self.sync_all() chain_height = self.nodes[1].getblockcount() assert_equal(chain_height, 105) assert_equal(self.nodes[1].getbalance(), 0) assert_equal(self.nodes[2].getbalance(), 0) addr1 = "zrCBKy4Uoy1X5jws6cxLqrMuE1ukuctSqfS" addr2 = "ztano5XjpquCJdSipz7VRGFgdLqNjXmV9cD" # Check that balances are correct balance0 = self.nodes[1].getaddressbalance(addr1) assert_equal(balance0["balance"], 0) # Check p2pkh and p2sh address indexes print "Testing p2pkh and p2sh address index..." txid0 = self.nodes[0].sendtoaddress(addr2, 10) self.nodes[0].generate(1) txidb0 = self.nodes[0].sendtoaddress(addr1, 10) self.nodes[0].generate(1) txid1 = self.nodes[0].sendtoaddress(addr2, 15) self.nodes[0].generate(1) txidb1 = self.nodes[0].sendtoaddress(addr1, 15) self.nodes[0].generate(1) txid2 = self.nodes[0].sendtoaddress(addr2, 20) self.nodes[0].generate(1) txidb2 = self.nodes[0].sendtoaddress(addr1, 20) self.nodes[0].generate(1) self.sync_all() txids = self.nodes[1].getaddresstxids(addr2) assert_equal(len(txids), 3) assert_equal(txids[0], txid0) assert_equal(txids[1], txid1) assert_equal(txids[2], txid2) txidsb = self.nodes[1].getaddresstxids(addr1) assert_equal(len(txidsb), 3) assert_equal(txidsb[0], txidb0) assert_equal(txidsb[1], txidb1) assert_equal(txidsb[2], txidb2) # Check that limiting by height works print "Testing querying txids by range of block heights.." height_txids = self.nodes[1].getaddresstxids({ "addresses": [addr1], "start": 105, "end": 110 }) assert_equal(len(height_txids), 2) assert_equal(height_txids[0], txidb0) assert_equal(height_txids[1], txidb1) # Check that multiple addresses works multitxids = self.nodes[1].getaddresstxids( {"addresses": [addr1, addr2]}) assert_equal(len(multitxids), 6) assert_equal(multitxids[0], txid0) assert_equal(multitxids[1], txidb0) assert_equal(multitxids[2], txid1) assert_equal(multitxids[3], txidb1) assert_equal(multitxids[4], txid2) assert_equal(multitxids[5], txidb2) # Check that balances are correct balance0 = self.nodes[1].getaddressbalance(addr1) assert_equal(balance0["balance"], 45 * 100000000) # Check that outputs with the same address will only return one txid print "Testing for txid uniqueness..." op_hash160 = "a9" op_push_20_bytes_onto_the_stack = "14" addressHash = "6349a418fc4578d10a372b54b45c280cc8c4382f" op_equal = "87" genesisCbah = "20bb1acf2c1fc1228967a611c7db30632098f0c641855180b5fe23793b72eea50d00b4" scriptPubKey = binascii.unhexlify(op_hash160 + op_push_20_bytes_onto_the_stack + addressHash + op_equal + genesisCbah) unspent = self.nodes[0].listunspent() unspent.sort(key=lambda x: x["amount"], reverse=True) tx = CTransaction() tx.vin = [ CTxIn(COutPoint(int(unspent[0]["txid"], 16), unspent[0]["vout"])) ] tx.vout = [CTxOut(10, scriptPubKey), CTxOut(11, scriptPubKey)] tx.rehash() signed_tx = self.nodes[0].signrawtransaction( binascii.hexlify(tx.serialize()).decode("utf-8")) sent_txid = self.nodes[0].sendrawtransaction(signed_tx["hex"], True) self.nodes[0].generate(1) self.sync_all() txidsmany = self.nodes[1].getaddresstxids(addr1) assert_equal(len(txidsmany), 4) assert_equal(txidsmany[3], sent_txid) # Check that balances are correct print "Testing balances..." balance0 = self.nodes[1].getaddressbalance(addr1) assert_equal(balance0["balance"], 45 * 100000000 + 21) # Check that balances are correct after spending print "Testing balances after spending..." privkey2 = "cSdkPxkAjA4HDr5VHgsebAPDEh9Gyub4HK8UJr2DFGGqKKy4K5sG" address2 = "ztUB6YWTcj2uUe5Rbucnc7oFevn7wCKyN63" op_dup = "76" addressHash2 = "0b2f0a0c31bfe0406b0ccc1381fdbe311946dadc" op_equalverify = "88" op_checksig = "ac" scriptPubKey2 = binascii.unhexlify(op_dup + op_hash160 + op_push_20_bytes_onto_the_stack + addressHash2 + op_equalverify + op_checksig + genesisCbah) self.nodes[0].importprivkey(privkey2) unspent = self.nodes[0].listunspent() unspent.sort(key=lambda x: x["amount"], reverse=True) tx = CTransaction() tx.vin = [ CTxIn(COutPoint(int(unspent[0]["txid"], 16), unspent[0]["vout"])) ] amount = unspent[0]["amount"] * 100000000 tx.vout = [CTxOut(amount, scriptPubKey2)] tx.rehash() signed_tx = self.nodes[0].signrawtransaction( binascii.hexlify(tx.serialize()).decode("utf-8")) spending_txid = self.nodes[0].sendrawtransaction( signed_tx["hex"], True) self.nodes[0].generate(1) self.sync_all() balance1 = self.nodes[1].getaddressbalance(address2) assert_equal(balance1["balance"], amount) tx = CTransaction() tx.vin = [CTxIn(COutPoint(int(spending_txid, 16), 0))] send_amount = 1 * 100000000 + 12840 change_amount = amount - send_amount - 10000 tx.vout = [ CTxOut(change_amount, scriptPubKey2), CTxOut(send_amount, scriptPubKey) ] tx.rehash() signed_tx = self.nodes[0].signrawtransaction( binascii.hexlify(tx.serialize()).decode("utf-8")) sent_txid = self.nodes[0].sendrawtransaction(signed_tx["hex"], True) self.nodes[0].generate(1) self.sync_all() balance2 = self.nodes[1].getaddressbalance(address2) assert_equal(balance2["balance"], change_amount) # Check that deltas are returned correctly deltas = self.nodes[1].getaddressdeltas({ "addresses": [address2], "start": 1, "end": 200 }) balance3 = 0 for delta in deltas: balance3 += delta["satoshis"] assert_equal(balance3, change_amount) assert_equal(deltas[0]["address"], address2) assert_equal(deltas[0]["blockindex"], 1) # Check that entire range will be queried deltasAll = self.nodes[1].getaddressdeltas({"addresses": [address2]}) assert_equal(len(deltasAll), len(deltas)) # Check that deltas can be returned from range of block heights deltas = self.nodes[1].getaddressdeltas({ "addresses": [address2], "start": 113, "end": 113 }) assert_equal(len(deltas), 1) # Check that unspent outputs can be queried print "Testing utxos..." utxos = self.nodes[1].getaddressutxos({"addresses": [address2]}) assert_equal(len(utxos), 1) assert_equal(utxos[0]["satoshis"], change_amount) # Check that indexes will be updated with a reorg print "Testing reorg..." best_hash = self.nodes[0].getbestblockhash() self.nodes[0].invalidateblock(best_hash) self.nodes[1].invalidateblock(best_hash) self.nodes[2].invalidateblock(best_hash) self.nodes[3].invalidateblock(best_hash) self.sync_all() balance4 = self.nodes[1].getaddressbalance(address2) assert_equal(balance4, balance1) utxos2 = self.nodes[1].getaddressutxos({"addresses": [address2]}) assert_equal(len(utxos2), 1) assert_equal(utxos2[0]["satoshis"], amount) # Check sorting of utxos self.nodes[2].generate(150) self.nodes[2].sendtoaddress(address2, 50) self.nodes[2].generate(1) self.nodes[2].sendtoaddress(address2, 50) self.nodes[2].generate(1) self.sync_all() utxos3 = self.nodes[1].getaddressutxos({"addresses": [address2]}) assert_equal(len(utxos3), 3) assert_equal(utxos3[0]["height"], 114) assert_equal(utxos3[1]["height"], 264) assert_equal(utxos3[2]["height"], 265) # Check mempool indexing print "Testing mempool indexing..." privKey3 = "cVfUn53hAbRrDEuMexyfgDpZPhF7KqXpS8UZevsyTDaugB7HZ3CD" address3 = "ztihzFwiPbcoMVWzvMAHf37o8jw9VSHdLtC" addressHash3 = "aa9872b5bbcdb511d89e0e11aa27da73fd2c3f50" scriptPubKey3 = binascii.unhexlify(op_dup + op_hash160 + op_push_20_bytes_onto_the_stack + addressHash3 + op_equalverify + op_checksig + genesisCbah) #address4 = "zrJgNMHvfLY26avAQCeHk8NAQxubq7CExqH" scriptPubKey4 = binascii.unhexlify(op_hash160 + op_push_20_bytes_onto_the_stack + addressHash3 + op_equal + genesisCbah) unspent = self.nodes[2].listunspent() unspent.sort(key=lambda x: x["amount"], reverse=True) tx = CTransaction() tx.vin = [ CTxIn(COutPoint(int(unspent[0]["txid"], 16), unspent[0]["vout"])) ] amount = unspent[0]["amount"] * 100000000 tx.vout = [CTxOut(amount, scriptPubKey3)] tx.rehash() signed_tx = self.nodes[2].signrawtransaction( binascii.hexlify(tx.serialize()).decode("utf-8")) memtxid1 = self.nodes[2].sendrawtransaction(signed_tx["hex"], True) time.sleep(2) tx2 = CTransaction() tx2.vin = [ CTxIn(COutPoint(int(unspent[1]["txid"], 16), unspent[1]["vout"])) ] amount = unspent[1]["amount"] * 100000000 tx2.vout = [ CTxOut(amount / 4, scriptPubKey3), CTxOut(amount / 4, scriptPubKey3), CTxOut(amount / 4, scriptPubKey4), CTxOut(amount / 4, scriptPubKey4) ] tx2.rehash() signed_tx2 = self.nodes[2].signrawtransaction( binascii.hexlify(tx2.serialize()).decode("utf-8")) memtxid2 = self.nodes[2].sendrawtransaction(signed_tx2["hex"], True) time.sleep(2) mempool = self.nodes[2].getaddressmempool({"addresses": [address3]}) assert_equal(len(mempool), 3) assert_equal(mempool[0]["txid"], memtxid1) assert_equal(mempool[0]["address"], address3) assert_equal(mempool[0]["index"], 0) assert_equal(mempool[1]["txid"], memtxid2) assert_equal(mempool[1]["index"], 0) assert_equal(mempool[2]["txid"], memtxid2) assert_equal(mempool[2]["index"], 1) self.nodes[2].generate(1) self.sync_all() mempool2 = self.nodes[2].getaddressmempool({"addresses": [address3]}) assert_equal(len(mempool2), 0) tx = CTransaction() tx.vin = [ CTxIn(COutPoint(int(memtxid2, 16), 0)), CTxIn(COutPoint(int(memtxid2, 16), 1)) ] tx.vout = [CTxOut(amount / 2 - 10000, scriptPubKey2)] tx.rehash() self.nodes[2].importprivkey(privKey3) signed_tx3 = self.nodes[2].signrawtransaction( binascii.hexlify(tx.serialize()).decode("utf-8")) self.nodes[2].sendrawtransaction(signed_tx3["hex"], True) time.sleep(2) mempool3 = self.nodes[2].getaddressmempool({"addresses": [address3]}) assert_equal(len(mempool3), 2) assert_equal(mempool3[0]["prevtxid"], memtxid2) assert_equal(mempool3[0]["prevout"], 0) assert_equal(mempool3[1]["prevtxid"], memtxid2) assert_equal(mempool3[1]["prevout"], 1) # sending and receiving to the same address privkey1 = "cQY2s58LhzUCmEXN8jtAp1Etnijx78YRZ466w4ikX1V4UpTpbsf8" address1 = "ztkoUySJkS8SMoQEjR6SkSgmDXtMB531yiw" address1hash = "c192bff751af8efec15135d42bfeedf91a6f3e34" address1script = binascii.unhexlify(op_dup + op_hash160 + op_push_20_bytes_onto_the_stack + address1hash + op_equalverify + op_checksig + genesisCbah) self.nodes[0].sendtoaddress(address1, 10) self.nodes[0].generate(1) self.sync_all() utxos = self.nodes[1].getaddressutxos({"addresses": [address1]}) assert_equal(len(utxos), 1) tx = CTransaction() tx.vin = [ CTxIn(COutPoint(int(utxos[0]["txid"], 16), utxos[0]["outputIndex"])) ] amount = utxos[0]["satoshis"] - 1000 tx.vout = [CTxOut(amount, address1script)] tx.rehash() self.nodes[0].importprivkey(privkey1) signed_tx = self.nodes[0].signrawtransaction( binascii.hexlify(tx.serialize()).decode("utf-8")) self.nodes[0].sendrawtransaction(signed_tx["hex"], True) self.sync_all() mempool_deltas = self.nodes[2].getaddressmempool( {"addresses": [address1]}) assert_equal(len(mempool_deltas), 2) # Include chaininfo in results print "Testing results with chain info..." deltas_with_info = self.nodes[1].getaddressdeltas({ "addresses": [address2], "start": 1, "end": 200, "chainInfo": True }) start_block_hash = self.nodes[1].getblockhash(1) end_block_hash = self.nodes[1].getblockhash(200) assert_equal(deltas_with_info["start"]["height"], 1) assert_equal(deltas_with_info["start"]["hash"], start_block_hash) assert_equal(deltas_with_info["end"]["height"], 200) assert_equal(deltas_with_info["end"]["hash"], end_block_hash) utxos_with_info = self.nodes[1].getaddressutxos({ "addresses": [address2], "chainInfo": True }) expected_tip_block_hash = self.nodes[1].getblockhash(267) assert_equal(utxos_with_info["height"], 267) assert_equal(utxos_with_info["hash"], expected_tip_block_hash) # Check that indexes don't get updated when checking a new block (e.g. when calling getBlockTemplate) # Initial balance is 0 and no index has been stored for addr3 addr3 = self.nodes[1].getnewaddress() addr3_balance = self.nodes[2].getaddressbalance(addr3) addr3_txs = self.nodes[2].getaddresstxids(addr3) addr3_utxos = self.nodes[2].getaddressutxos(addr3) addr3_mempool = self.nodes[2].getaddressmempool(addr3) # The initial balance must be 0 assert_equal(addr3_balance["balance"], 0) # At the beginning no address index must be stored assert_equal(addr3_txs, []) # At the beginning no unspent index must be stored assert_equal(addr3_utxos, []) # At the beginning no address mempool index must be stored assert_equal(addr3_mempool, []) # Add to mempool a transaction that sends money to addr3 addr3_amount = 0.1 addr3_txid = self.nodes[2].sendtoaddress(addr3, addr3_amount) addr3_balance = self.nodes[2].getaddressbalance(addr3) addr3_txs = self.nodes[2].getaddresstxids(addr3) addr3_utxos = self.nodes[2].getaddressutxos(addr3) addr3_mempool = self.nodes[2].getaddressmempool(addr3) # The balance must still be 0 assert_equal(addr3_balance["balance"], 0) # The address index must still be empty assert_equal(addr3_txs, []) # The unspent index must still be empty assert_equal(addr3_utxos, []) # The address mempool index must contain the new transaction assert_equal(len(addr3_mempool), 1) assert_equal(addr3_mempool[0]["txid"], addr3_txid) # Call getBlockTemplate to trigger a call to VerifyBlock() => ConnectBlock() # It should not update any index self.nodes[2].getblocktemplate() addr3_balance = self.nodes[2].getaddressbalance(addr3) addr3_txs = self.nodes[2].getaddresstxids(addr3) addr3_utxos = self.nodes[2].getaddressutxos(addr3) addr3_mempool = self.nodes[2].getaddressmempool(addr3) # The balance must still be 0 assert_equal(addr3_balance["balance"], 0) # The address index must still be empty assert_equal(addr3_txs, []) # The unspent index must still be empty assert_equal(addr3_utxos, []) # The address mempool index must still be empty assert_equal(len(addr3_mempool), 1) assert_equal(addr3_mempool[0]["txid"], addr3_txid) # Connect a new block "validating" the transaction sending money to addr3 self.nodes[2].generate(1) self.sync_all() addr3_balance = self.nodes[2].getaddressbalance(addr3) addr3_txs = self.nodes[2].getaddresstxids(addr3) addr3_utxos = self.nodes[2].getaddressutxos(addr3) addr3_mempool = self.nodes[2].getaddressmempool(addr3) # The balance must be updated assert_equal(addr3_balance["balance"], 0.1 * 1e8) # The address index must contain only the new transaction assert_equal(len(addr3_txs), 1) assert_equal(addr3_txs[0], addr3_txid) # The unspent index must contain only the new transaction assert_equal(len(addr3_utxos), 1) assert_equal(addr3_utxos[0]["txid"], addr3_txid) # The address mempool index must be empty again assert_equal(addr3_mempool, []) print "Passed\n"
def run_test(self): self.log.info("Mining blocks...") self.nodes[0].generate(105) self.sync_all() chain_height = self.nodes[1].getblockcount() assert_equal(chain_height, 105) assert_equal(self.nodes[1].getbalance(), 0) assert_equal(self.nodes[2].getbalance(), 0) # Check that balances are correct balance0 = self.nodes[1].getaddressbalance( "2N2JD6wb56AfK4tfmM6PwdVmoYk2dCKf4Br") assert_equal(balance0["balance"], 0) # Check p2pkh and p2sh address indexes self.log.info("Testing p2pkh and p2sh address index...") tx_id0 = self.nodes[0].sendtoaddress( "mo9ncXisMeAoXwqcV5EWuyncbmCcQN4rVs", 10) self.nodes[0].generate(1) tx_idb0 = self.nodes[0].sendtoaddress( "2N2JD6wb56AfK4tfmM6PwdVmoYk2dCKf4Br", 10) self.nodes[0].generate(1) tx_id1 = self.nodes[0].sendtoaddress( "mo9ncXisMeAoXwqcV5EWuyncbmCcQN4rVs", 15) self.nodes[0].generate(1) tx_idb1 = self.nodes[0].sendtoaddress( "2N2JD6wb56AfK4tfmM6PwdVmoYk2dCKf4Br", 15) self.nodes[0].generate(1) tx_id2 = self.nodes[0].sendtoaddress( "mo9ncXisMeAoXwqcV5EWuyncbmCcQN4rVs", 20) self.nodes[0].generate(1) tx_idb2 = self.nodes[0].sendtoaddress( "2N2JD6wb56AfK4tfmM6PwdVmoYk2dCKf4Br", 20) self.nodes[0].generate(1) self.sync_all() txids = self.nodes[1].getaddresstxids( "mo9ncXisMeAoXwqcV5EWuyncbmCcQN4rVs") assert_equal(len(txids), 3) assert_equal(txids[0], tx_id0) assert_equal(txids[1], tx_id1) assert_equal(txids[2], tx_id2) tx_idsb = self.nodes[1].getaddresstxids( "2N2JD6wb56AfK4tfmM6PwdVmoYk2dCKf4Br") assert_equal(len(tx_idsb), 3) assert_equal(tx_idsb[0], tx_idb0) assert_equal(tx_idsb[1], tx_idb1) assert_equal(tx_idsb[2], tx_idb2) # Check that limiting by height works self.log.info("Testing querying txids by range of block heights..") height_txids = self.nodes[1].getaddresstxids({ "addresses": ["2N2JD6wb56AfK4tfmM6PwdVmoYk2dCKf4Br"], "start": 105, "end": 110 }) assert_equal(len(height_txids), 2) assert_equal(height_txids[0], tx_idb0) assert_equal(height_txids[1], tx_idb1) # Check that multiple addresses works multi_tx_ids = self.nodes[1].getaddresstxids({ "addresses": [ "2N2JD6wb56AfK4tfmM6PwdVmoYk2dCKf4Br", "mo9ncXisMeAoXwqcV5EWuyncbmCcQN4rVs" ] }) assert_equal(len(multi_tx_ids), 6) assert_equal(multi_tx_ids[0], tx_id0) assert_equal(multi_tx_ids[1], tx_idb0) assert_equal(multi_tx_ids[2], tx_id1) assert_equal(multi_tx_ids[3], tx_idb1) assert_equal(multi_tx_ids[4], tx_id2) assert_equal(multi_tx_ids[5], tx_idb2) # Check that balances are correct balance0 = self.nodes[1].getaddressbalance( "2N2JD6wb56AfK4tfmM6PwdVmoYk2dCKf4Br") assert_equal(balance0["balance"], 45 * 100000000) # Check that outputs with the same address will only return one txid self.log.info("Testing for txid uniqueness...") address_hash = bytes([ 99, 73, 164, 24, 252, 69, 120, 209, 10, 55, 43, 84, 180, 92, 40, 12, 200, 196, 56, 47 ]) script_pub_key = CScript([OP_HASH160, address_hash, OP_EQUAL]) unspent = self.nodes[0].listunspent() tx = CTransaction() tx.vin = [ CTxIn(COutPoint(int(unspent[0]["txid"], 16), unspent[0]["vout"])) ] tx.vout = [CTxOut(10, script_pub_key), CTxOut(11, script_pub_key)] tx.rehash() signed_tx = self.nodes[0].signrawtransaction( binascii.hexlify(tx.serialize()).decode("utf-8")) sent_txid = self.nodes[0].sendrawtransaction(signed_tx["hex"], True) self.nodes[0].generate(1) self.sync_all() tx_ids_many = self.nodes[1].getaddresstxids( "2N2JD6wb56AfK4tfmM6PwdVmoYk2dCKf4Br") assert_equal(len(tx_ids_many), 4) assert_equal(tx_ids_many[3], sent_txid) # Check that balances are correct self.log.info("Testing balances...") balance0 = self.nodes[1].getaddressbalance( "2N2JD6wb56AfK4tfmM6PwdVmoYk2dCKf4Br") assert_equal(balance0["balance"], 45 * 100000000 + 21) # Check that balances are correct after spending self.log.info("Testing balances after spending...") privkey2 = "cSdkPxkAjA4HDr5VHgsebAPDEh9Gyub4HK8UJr2DFGGqKKy4K5sG" address2 = "mgY65WSfEmsyYaYPQaXhmXMeBhwp4EcsQW" address_hash2 = bytes([ 11, 47, 10, 12, 49, 191, 224, 64, 107, 12, 204, 19, 129, 253, 190, 49, 25, 70, 218, 220 ]) script_pub_key2 = CScript( [OP_DUP, OP_HASH160, address_hash2, OP_EQUALVERIFY, OP_CHECKSIG]) self.nodes[0].importprivkey(privkey2) unspent = self.nodes[0].listunspent() tx = CTransaction() tx.vin = [ CTxIn(COutPoint(int(unspent[0]["txid"], 16), unspent[0]["vout"])) ] amount = int(unspent[0]["amount"] * 100000000 - 230000) tx.vout = [CTxOut(amount, script_pub_key2)] signed_tx = self.nodes[0].signrawtransaction( binascii.hexlify(tx.serialize()).decode("utf-8")) spending_txid = self.nodes[0].sendrawtransaction( signed_tx["hex"], True) self.nodes[0].generate(1) self.sync_all() balance1 = self.nodes[1].getaddressbalance(address2) assert_equal(balance1["balance"], amount) tx = CTransaction() tx.vin = [CTxIn(COutPoint(int(spending_txid, 16), 0))] send_amount = 1 * 100000000 + 12840 change_amount = amount - send_amount - 230000 tx.vout = [ CTxOut(change_amount, script_pub_key2), CTxOut(send_amount, script_pub_key) ] tx.rehash() signed_tx = self.nodes[0].signrawtransaction( binascii.hexlify(tx.serialize()).decode("utf-8")) self.nodes[0].sendrawtransaction(signed_tx["hex"], True) self.nodes[0].generate(1) self.sync_all() balance2 = self.nodes[1].getaddressbalance(address2) assert_equal(balance2["balance"], change_amount) # Check that deltas are returned correctly deltas = self.nodes[1].getaddressdeltas({ "addresses": [address2], "start": 1, "end": 200 }) balance3 = 0 for delta in deltas: balance3 += delta["satoshis"] assert_equal(balance3, change_amount) assert_equal(deltas[0]["address"], address2) assert_equal(deltas[0]["blockindex"], 1) # Check that entire range will be queried deltas_all = self.nodes[1].getaddressdeltas({"addresses": [address2]}) assert_equal(len(deltas_all), len(deltas)) # Check that deltas can be returned from range of block heights deltas = self.nodes[1].getaddressdeltas({ "addresses": [address2], "start": 113, "end": 113 }) assert_equal(len(deltas), 1) # Check that unspent outputs can be queried self.log.info("Testing utxos...") utxos = self.nodes[1].getaddressutxos({"addresses": [address2]}) assert_equal(len(utxos), 1) assert_equal(utxos[0]["satoshis"], change_amount) # Check that indexes will be updated with a reorg self.log.info("Testing reorg...") best_hash = self.nodes[0].getbestblockhash() self.nodes[0].invalidateblock(best_hash) self.nodes[1].invalidateblock(best_hash) self.nodes[2].invalidateblock(best_hash) self.nodes[3].invalidateblock(best_hash) self.sync_all() balance4 = self.nodes[1].getaddressbalance(address2) assert_equal(balance4, balance1) utxos2 = self.nodes[1].getaddressutxos({"addresses": [address2]}) assert_equal(len(utxos2), 1) assert_equal(utxos2[0]["satoshis"], amount) # Check sorting of utxos self.nodes[2].generate(150) self.nodes[2].sendtoaddress(address2, 50) self.nodes[2].generate(1) self.nodes[2].sendtoaddress(address2, 50) self.nodes[2].generate(1) self.sync_all() utxos3 = self.nodes[1].getaddressutxos({"addresses": [address2]}) assert_equal(len(utxos3), 3) assert_equal(utxos3[0]["height"], 114) assert_equal(utxos3[1]["height"], 264) assert_equal(utxos3[2]["height"], 265) # Check mempool indexing self.log.info("Testing mempool indexing...") priv_key3 = "cVfUn53hAbRrDEuMexyfgDpZPhF7KqXpS8UZevsyTDaugB7HZ3CD" address3 = "mw4ynwhS7MmrQ27hr82kgqu7zryNDK26JB" address_hash3 = bytes([ 170, 152, 114, 181, 187, 205, 181, 17, 216, 158, 14, 17, 170, 39, 218, 115, 253, 44, 63, 80 ]) script_pub_key3 = CScript( [OP_DUP, OP_HASH160, address_hash3, OP_EQUALVERIFY, OP_CHECKSIG]) #address4 = "2N8oFVB2vThAKury4vnLquW2zVjsYjjAkYQ" script_pub_key4 = CScript([OP_HASH160, address_hash3, OP_EQUAL]) unspent = self.nodes[2].listunspent() tx = CTransaction() tx.vin = [ CTxIn(COutPoint(int(unspent[0]["txid"], 16), unspent[0]["vout"])) ] amount = int(unspent[0]["amount"] * 100000000 - 230000) tx.vout = [CTxOut(amount, script_pub_key3)] tx.rehash() signed_tx = self.nodes[2].signrawtransaction( binascii.hexlify(tx.serialize()).decode("utf-8")) mem_txid1 = self.nodes[2].sendrawtransaction(signed_tx["hex"], True) time.sleep(2) tx2 = CTransaction() tx2.vin = [ CTxIn(COutPoint(int(unspent[1]["txid"], 16), unspent[1]["vout"])) ] amount = int(unspent[1]["amount"] * 100000000 - 300000) tx2.vout = [ CTxOut(int(amount / 4), script_pub_key3), CTxOut(int(amount / 4), script_pub_key3), CTxOut(int(amount / 4), script_pub_key4), CTxOut(int(amount / 4), script_pub_key4) ] tx2.rehash() signed_tx2 = self.nodes[2].signrawtransaction( binascii.hexlify(tx2.serialize()).decode("utf-8")) mem_txid2 = self.nodes[2].sendrawtransaction(signed_tx2["hex"], True) time.sleep(2) mempool = self.nodes[2].getaddressmempool({"addresses": [address3]}) assert_equal(len(mempool), 3) assert_equal(mempool[0]["txid"], mem_txid1) assert_equal(mempool[0]["address"], address3) assert_equal(mempool[0]["index"], 0) assert_equal(mempool[1]["txid"], mem_txid2) assert_equal(mempool[1]["index"], 0) assert_equal(mempool[2]["txid"], mem_txid2) assert_equal(mempool[2]["index"], 1) self.nodes[2].generate(1) self.sync_all() mempool2 = self.nodes[2].getaddressmempool({"addresses": [address3]}) assert_equal(len(mempool2), 0) tx = CTransaction() tx.vin = [ CTxIn(COutPoint(int(mem_txid2, 16), 0)), CTxIn(COutPoint(int(mem_txid2, 16), 1)) ] tx.vout = [CTxOut(int(amount / 2 - 340000), script_pub_key2)] tx.rehash() self.nodes[2].importprivkey(priv_key3) signed_tx3 = self.nodes[2].signrawtransaction( binascii.hexlify(tx.serialize()).decode("utf-8")) self.nodes[2].sendrawtransaction(signed_tx3["hex"], True) time.sleep(2) mempool3 = self.nodes[2].getaddressmempool({"addresses": [address3]}) assert_equal(len(mempool3), 2) assert_equal(mempool3[0]["prevtxid"], mem_txid2) assert_equal(mempool3[0]["prevout"], 0) assert_equal(mempool3[1]["prevtxid"], mem_txid2) assert_equal(mempool3[1]["prevout"], 1) # sending and receiving to the same address privkey1 = "cQY2s58LhzUCmEXN8jtAp1Etnijx78YRZ466w4ikX1V4UpTpbsf8" address1 = "myAUWSHnwsQrhuMWv4Br6QsCnpB41vFwHn" address1hash = bytes([ 193, 146, 191, 247, 81, 175, 142, 254, 193, 81, 53, 212, 43, 254, 237, 249, 26, 111, 62, 52 ]) address1script = CScript( [OP_DUP, OP_HASH160, address1hash, OP_EQUALVERIFY, OP_CHECKSIG]) self.nodes[0].sendtoaddress(address1, 10) self.nodes[0].generate(1) self.sync_all() utxos = self.nodes[1].getaddressutxos({"addresses": [address1]}) assert_equal(len(utxos), 1) tx = CTransaction() tx.vin = [ CTxIn(COutPoint(int(utxos[0]["txid"], 16), utxos[0]["outputIndex"])) ] amount = int(utxos[0]["satoshis"] - 200000) tx.vout = [CTxOut(amount, address1script)] tx.rehash() self.nodes[0].importprivkey(privkey1) signed_tx = self.nodes[0].signrawtransaction( binascii.hexlify(tx.serialize()).decode("utf-8")) self.nodes[0].sendrawtransaction(signed_tx["hex"], True) self.sync_all() mempool_deltas = self.nodes[2].getaddressmempool( {"addresses": [address1]}) assert_equal(len(mempool_deltas), 2) # Include chaininfo in results self.log.info("Testing results with chain info...") deltas_with_info = self.nodes[1].getaddressdeltas({ "addresses": [address2], "start": 1, "end": 200, "chainInfo": True }) start_block_hash = self.nodes[1].getblockhash(1) end_block_hash = self.nodes[1].getblockhash(200) assert_equal(deltas_with_info["start"]["height"], 1) assert_equal(deltas_with_info["start"]["hash"], start_block_hash) assert_equal(deltas_with_info["end"]["height"], 200) assert_equal(deltas_with_info["end"]["hash"], end_block_hash) utxos_with_info = self.nodes[1].getaddressutxos({ "addresses": [address2], "chainInfo": True }) expected_tip_block_hash = self.nodes[1].getblockhash(267) assert_equal(utxos_with_info["height"], 267) assert_equal(utxos_with_info["hash"], expected_tip_block_hash) self.log.info("All Tests Passed")
def run_test(self): blocks = [] self.bl_count = 0 blocks.append(self.nodes[1].getblockhash(0)) small_target_h = 3 s = " Node1 generates %d blocks" % (CBH_DELTA + small_target_h) print(s) print self.mark_logs(s) blocks.extend(self.nodes[1].generate(CBH_DELTA + small_target_h)) self.sync_all() #------------------------------------------------------------------------------------------------------- print "Trying to send a tx with a scriptPubKey referencing a block too recent..." #------------------------------------------------------------------------------------------------------- # Create a tx having in its scriptPubKey a custom referenced block in the CHECKBLOCKATHEIGHT part # select necessary utxos for doing the PAYMENT usp = self.nodes[1].listunspent() PAYMENT = Decimal('1.0') FEE = Decimal('0.00005') amount = Decimal('0') inputs = [] print " Node1 sends %f coins to Node2" % PAYMENT for x in usp: amount += Decimal(x['amount']) inputs.append({"txid": x['txid'], "vout": x['vout']}) if amount >= PAYMENT + FEE: break outputs = { self.nodes[1].getnewaddress(): (Decimal(amount) - PAYMENT - FEE), self.nodes[2].getnewaddress(): PAYMENT } rawTx = self.nodes[1].createrawtransaction(inputs, outputs) # build an object from the raw tx in order to be able to modify it tx_01 = CTransaction() f = cStringIO.StringIO(unhexlify(rawTx)) tx_01.deserialize(f) decodedScriptOrig = self.nodes[1].decodescript( binascii.hexlify(tx_01.vout[1].scriptPubKey)) scriptOrigAsm = decodedScriptOrig['asm'] # print "Original scriptPubKey asm 1: ", scriptOrigAsm # print # store the hashed script, it is reused params = scriptOrigAsm.split() hash_script = hex_str_to_bytes(params[2]) # new referenced block height modTargetHeigth = CBH_DELTA + small_target_h - FINALITY_MIN_AGE + 5 # new referenced block hash modTargetHash = hex_str_to_bytes( self.swap_bytes(blocks[modTargetHeigth])) # build modified script modScriptPubKey = CScript([ OP_DUP, OP_HASH160, hash_script, OP_EQUALVERIFY, OP_CHECKSIG, modTargetHash, modTargetHeigth, OP_CHECKBLOCKATHEIGHT ]) tx_01.vout[1].scriptPubKey = modScriptPubKey tx_01.rehash() decodedScriptMod = self.nodes[1].decodescript( binascii.hexlify(tx_01.vout[1].scriptPubKey)) print " Modified scriptPubKey in tx 1: ", decodedScriptMod['asm'] signedRawTx = self.nodes[1].signrawtransaction(ToHex(tx_01)) h = self.nodes[1].getblockcount() assert_greater_than(FINALITY_MIN_AGE, h - modTargetHeigth) #raw_input("\npress enter to go on ..") try: txid = self.nodes[1].sendrawtransaction(signedRawTx['hex']) print " Tx sent: ", txid # should fail, therefore force test failure assert_equal(True, False) except JSONRPCException, e: print " ==> tx has been rejected as expected:" print " referenced block height=%d, chainActive.height=%d, minimumAge=%d" % ( modTargetHeigth, h, FINALITY_MIN_AGE) print
def run_test(self): self.log.info("Mining blocks...") self.nodes[0].generate(105) self.sync_all() chain_height = self.nodes[1].getblockcount() assert_equal(chain_height, 105) # Check that self.log.info("Testing spent index...") fee_satoshis = 192000 privkey = "cSdkPxkAjA4HDr5VHgsebAPDEh9Gyub4HK8UJr2DFGGqKKy4K5sG" #address = "mgY65WSfEmsyYaYPQaXhmXMeBhwp4EcsQW" address_hash = bytes([ 11, 47, 10, 12, 49, 191, 224, 64, 107, 12, 204, 19, 129, 253, 190, 49, 25, 70, 218, 220 ]) script_pub_key = CScript( [OP_DUP, OP_HASH160, address_hash, OP_EQUALVERIFY, OP_CHECKSIG]) unspent = self.nodes[0].listunspent() tx = CTransaction() amount = int(unspent[0]["amount"] * 100000000 - fee_satoshis) tx.vin = [ CTxIn(COutPoint(int(unspent[0]["txid"], 16), unspent[0]["vout"])) ] tx.vout = [CTxOut(amount, script_pub_key)] tx.rehash() signed_tx = self.nodes[0].signrawtransaction( binascii.hexlify(tx.serialize()).decode("utf-8")) txid = self.nodes[0].sendrawtransaction(signed_tx["hex"], True) self.nodes[0].generate(1) self.sync_all() self.log.info("Testing getspentinfo method...") # Check that the spentinfo works standalone info = self.nodes[1].getspentinfo({ "txid": unspent[0]["txid"], "index": unspent[0]["vout"] }) assert_equal(info["txid"], txid) assert_equal(info["index"], 0) assert_equal(info["height"], 106) self.log.info("Testing getrawtransaction method...") # Check that verbose raw transaction includes spent info tx_verbose = self.nodes[3].getrawtransaction(unspent[0]["txid"], 1) assert_equal(tx_verbose["vout"][unspent[0]["vout"]]["spentTxId"], txid) assert_equal(tx_verbose["vout"][unspent[0]["vout"]]["spentIndex"], 0) assert_equal(tx_verbose["vout"][unspent[0]["vout"]]["spentHeight"], 106) # Check that verbose raw transaction includes input values tx_verbose2 = self.nodes[3].getrawtransaction(txid, 1) assert_equal(float(tx_verbose2["vin"][0]["value"]), (amount + fee_satoshis) / 100000000) assert_equal(tx_verbose2["vin"][0]["valueSat"], amount + fee_satoshis) # Check that verbose raw transaction includes address values and input values #privkey2 = "cSdkPxkAjA4HDr5VHgsebAPDEh9Gyub4HK8UJr2DFGGqKKy4K5sG" address2 = "mgY65WSfEmsyYaYPQaXhmXMeBhwp4EcsQW" address_hash2 = bytes([ 11, 47, 10, 12, 49, 191, 224, 64, 107, 12, 204, 19, 129, 253, 190, 49, 25, 70, 218, 220 ]) script_pub_key2 = CScript( [OP_DUP, OP_HASH160, address_hash2, OP_EQUALVERIFY, OP_CHECKSIG]) tx2 = CTransaction() tx2.vin = [CTxIn(COutPoint(int(txid, 16), 0))] amount = int(amount - fee_satoshis) tx2.vout = [CTxOut(amount, script_pub_key2)] tx.rehash() self.nodes[0].importprivkey(privkey) signed_tx2 = self.nodes[0].signrawtransaction( binascii.hexlify(tx2.serialize()).decode("utf-8")) txid2 = self.nodes[0].sendrawtransaction(signed_tx2["hex"], True) # Check the mempool index self.sync_all() tx_verbose3 = self.nodes[1].getrawtransaction(txid2, 1) assert_equal(tx_verbose3["vin"][0]["address"], address2) assert_equal(tx_verbose3["vin"][0]["valueSat"], amount + fee_satoshis) assert_equal(float(tx_verbose3["vin"][0]["value"]), (amount + fee_satoshis) / 100000000) # Check the database index block_hash = self.nodes[0].generate(1) self.sync_all() tx_verbose4 = self.nodes[3].getrawtransaction(txid2, 1) assert_equal(tx_verbose4["vin"][0]["address"], address2) assert_equal(tx_verbose4["vin"][0]["valueSat"], amount + fee_satoshis) assert_equal(float(tx_verbose4["vin"][0]["value"]), (amount + fee_satoshis) / 100000000) # Check block deltas self.log.info("Testing getblockdeltas...") block = self.nodes[3].getblockdeltas(block_hash[0]) assert_equal(len(block["deltas"]), 2) assert_equal(block["deltas"][0]["index"], 0) assert_equal(len(block["deltas"][0]["inputs"]), 0) assert_equal(len(block["deltas"][0]["outputs"]), 0) assert_equal(block["deltas"][1]["index"], 1) assert_equal(block["deltas"][1]["txid"], txid2) assert_equal(block["deltas"][1]["inputs"][0]["index"], 0) assert_equal(block["deltas"][1]["inputs"][0]["address"], "mgY65WSfEmsyYaYPQaXhmXMeBhwp4EcsQW") assert_equal(block["deltas"][1]["inputs"][0]["satoshis"], (amount + fee_satoshis) * -1) assert_equal(block["deltas"][1]["inputs"][0]["prevtxid"], txid) assert_equal(block["deltas"][1]["inputs"][0]["prevout"], 0) assert_equal(block["deltas"][1]["outputs"][0]["index"], 0) assert_equal(block["deltas"][1]["outputs"][0]["address"], "mgY65WSfEmsyYaYPQaXhmXMeBhwp4EcsQW") assert_equal(block["deltas"][1]["outputs"][0]["satoshis"], amount) self.log.info("All Tests Passed")
def run_test(self): # Create a P2P connection to the first node node0 = NodeConnCB() connections = [] connections.append( NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], node0)) node0.add_connection(connections[0]) # Start up network handling in another thread. This needs to be called # after the P2P connections have been created. NetworkThread().start() # wait_for_verack ensures that the P2P connection is fully up. node0.wait_for_verack() # Out of IBD self.nodes[0].generate(1) # First create funding transaction that pays to output that does not require signatures. out_value = 10000 ftx = CTransaction() ftx.vout.append(CTxOut(out_value, CScript([OP_TRUE]))) ftxHex = self.nodes[0].fundrawtransaction( ToHex(ftx), {'changePosition': len(ftx.vout)})['hex'] ftxHex = self.nodes[0].signrawtransaction(ftxHex)['hex'] ftx = FromHex(CTransaction(), ftxHex) ftx.rehash() # Allow coinbase to mature self.nodes[0].generate(101) # Feed in funding txn and wait for both nodes to see it connections[0].send_message(msg_tx(ftx)) wait_until(lambda: ftx.hash in self.nodes[0].getrawmempool(), timeout=5) wait_until(lambda: ftx.hash in self.nodes[1].getrawmempool(), timeout=5) # Create non-final txn. parent_txid = ftx.sha256 send_value = out_value - 500 tx = CTransaction() tx.vin.append(CTxIn(COutPoint(parent_txid, 0), b'', 0x01)) tx.vout.append(CTxOut(int(send_value), CScript([OP_TRUE]))) tx.nLockTime = int(time.time()) + 300 tx.rehash() # Send non-final txn to node0. It should be forwarded over P2P to node1. connections[0].send_message(msg_tx(tx)) wait_until(lambda: tx.hash in self.nodes[0].getrawnonfinalmempool(), timeout=5) wait_until(lambda: tx.hash in self.nodes[1].getrawnonfinalmempool(), timeout=5) assert (tx.hash not in self.nodes[0].getrawmempool()) assert (tx.hash not in self.nodes[1].getrawmempool()) # Create finalising txn. finaltx = copy.deepcopy(tx) finaltx.vin[0].nSequence = 0xFFFFFFFF finaltx.rehash() # Send finalising txn to node0. It should be forwarded over P2P to node1. connections[0].send_message(msg_tx(finaltx)) wait_until(lambda: finaltx.hash in self.nodes[0].getrawmempool(), timeout=5) wait_until(lambda: finaltx.hash in self.nodes[1].getrawmempool(), timeout=5) assert (tx.hash not in self.nodes[0].getrawnonfinalmempool()) assert (tx.hash not in self.nodes[1].getrawnonfinalmempool())
def test_invalidblock(self): """ Verify situation when receiving invalid block, which is no longer considered soft rejected, via p2p """ self.nodes[0].generate(101) # create spendable tx tx_spendable = CTransaction() tx_spendable.vout = [CTxOut(4500000000, CScript([OP_TRUE]))] tx_hex_funded = self.nodes[0].fundrawtransaction( ToHex(tx_spendable), {'changePosition': len(tx_spendable.vout)})['hex'] tx_hex = self.nodes[0].signrawtransaction(tx_hex_funded)['hex'] self.nodes[0].sendrawtransaction(tx_hex, True) tx_spendable = FromHex(CTransaction(), tx_hex) tx_spendable.rehash() b1_hash = self.nodes[0].generate(1)[0] b2_hash = self.nodes[0].generate(1)[0] b3_hash = self.nodes[0].generate(1)[0] sync_blocks(self.nodes) self.nodes[0].softrejectblock(b2_hash, 1) assert_equal(self.nodes[0].getbestblockhash(), b1_hash) assert_equal(self.nodes[0].getblockcount(), 102) # Create a P2P connection to node0 that will be used to send blocks self.stop_node(0) with self.run_node_with_connections( title="test_invalidblock", node_index=0, args=["-whitelist=127.0.0.1"], # Need to whilelist localhost, so that node accepts any block number_of_connections=1) as connections: conn0 = connections[0] self.nodes[0].waitforblockheight(102) # create and send block (child of b3) with coinbase tx that pays to much coinbase_tx = create_coinbase(103) coinbase_tx.vout[0].nValue = 60 * COIN coinbase_tx.rehash() b4_invalid = create_block(int(b3_hash, 16), coinbase_tx) b4_invalid.hashMerkleRoot = b4_invalid.calc_merkle_root() b4_invalid.solve() b4_invalid.rehash() conn0.cb.send_message(msg_block(b4_invalid)) # b1 must still be at the tip self.wait_for_chain_tips(self.nodes[0], {b1_hash, b4_invalid.hash}) wait_until( lambda: self.nodes[0].getbestblockhash() == b1_hash ) # NOTE: need to wait, since reorg back to b1 can take a while even after chaintips are already as expected # create and send block b2 (child of b1) that creates a new chain b2a = create_block(int(b1_hash, 16), create_coinbase(102)) b2a.solve() b2a.rehash() conn0.cb.send_message(msg_block(b2a)) # b2a must become new tip self.wait_for_chain_tips(self.nodes[0], {b2a.hash, b4_invalid.hash}) assert_equal(self.nodes[0].getbestblockhash(), b2a.hash) # create and send block (child of b3) containing an invalid txn b4a_invalid = create_block(int(b3_hash, 16), create_coinbase(103)) b4a_invalid.vtx.append( create_transaction(tx_spendable, 0, CScript([OP_RETURN]), 100000)) # invalid unlock script b4a_invalid.hashMerkleRoot = b4a_invalid.calc_merkle_root() b4a_invalid.solve() b4a_invalid.rehash() conn0.cb.send_message(msg_block(b4a_invalid)) # b2a must still be at the tip self.wait_for_chain_tips( self.nodes[0], {b2a.hash, b4_invalid.hash, b4a_invalid.hash}) wait_until(lambda: self.nodes[0].getbestblockhash() == b2a.hash)
def make_large_invalid_tx(tx_to_spend, output_ndx): tx = CTransaction() tx.vin.append(CTxIn(COutPoint(tx_to_spend.sha256, output_ndx), b"", 0xffffffff)) tx.vout.append(CTxOut(tx_to_spend.vout[0].nValue - 2000000, CScript([bytes(1000000), OP_DROP, OP_FALSE]))) tx.rehash() return tx
def run_test(self): chain_height = self.nodes[0].getblockcount() assert_equal(chain_height, 200) self.log.debug("Mine a single block to get out of IBD") self.nodes[0].generate(1) self.sync_all() # Create funding transaction that pays to outputs that don't require signatures. out_value = 10000 ftx = CTransaction() ftx.vout.append(CTxOut(out_value, CScript([OP_TRUE]))) ftx.vout.append(CTxOut(out_value, CScript([OP_TRUE]))) ftxHex = self.nodes[2].fundrawtransaction( ToHex(ftx), {'changePosition': len(ftx.vout)})['hex'] ftxHex = self.nodes[2].signrawtransaction(ftxHex)['hex'] self.nodes[2].sendrawtransaction(ftxHex) ftx = FromHex(CTransaction(), ftxHex) ftx.rehash() # Create & send a couple of non-final txns. for i in range(2): parent_txid = ftx.sha256 send_value = out_value - 500 non_final_tx = CTransaction() non_final_tx.vin.append(CTxIn(COutPoint(parent_txid, i), b'', 0x01)) non_final_tx.vout.append( CTxOut(int(send_value), CScript([OP_TRUE]))) non_final_tx.nLockTime = int(time.time()) + 300 non_final_txHex = self.nodes[2].signrawtransaction( ToHex(non_final_tx))['hex'] self.nodes[2].sendrawtransaction(non_final_txHex) self.sync_all() self.log.debug( "Verify that all nodes have 2 transactions in their non-final mempools" ) assert_equal(len(self.nodes[0].getrawnonfinalmempool()), 2) assert_equal(len(self.nodes[1].getrawnonfinalmempool()), 2) assert_equal(len(self.nodes[2].getrawnonfinalmempool()), 2) self.log.debug( "Send another 4 transactions from node2 (to its own address)") for i in range(4): self.nodes[2].sendtoaddress(self.nodes[2].getnewaddress(), Decimal("10")) self.sync_all() self.log.debug( "Verify that all nodes have 5 transactions in their main mempools") assert_equal(len(self.nodes[0].getrawmempool()), 5) assert_equal(len(self.nodes[1].getrawmempool()), 5) assert_equal(len(self.nodes[2].getrawmempool()), 5) self.log.debug( "Stop-start node0 and node1. Verify that node0 has the transactions in its mempools and node1 does not." ) self.stop_nodes() self.start_node(0) self.start_node(1) # Give bitcoind a second to reload the mempool time.sleep(1) wait_until(lambda: len(self.nodes[0].getrawmempool()) == 5) wait_until(lambda: len(self.nodes[0].getrawnonfinalmempool()) == 2) assert_equal(len(self.nodes[1].getrawmempool()), 0) assert_equal(len(self.nodes[1].getrawnonfinalmempool()), 0) self.log.debug( "Stop-start node0 with -persistmempool=0. Verify that it doesn't load its mempool.dat file." ) self.stop_nodes() self.start_node(0, extra_args=["-persistmempool=0"]) # Give bitcoind a second to reload the mempool time.sleep(1) assert_equal(len(self.nodes[0].getrawmempool()), 0) assert_equal(len(self.nodes[0].getrawnonfinalmempool()), 0) self.log.debug( "Stop-start node0. Verify that it has the transactions in its mempool." ) self.stop_nodes() self.start_node(0) wait_until(lambda: len(self.nodes[0].getrawmempool()) == 5) wait_until(lambda: len(self.nodes[0].getrawnonfinalmempool()) == 2)
def test_prioritised_transactions(self): # Ensure that fee deltas used via prioritisetransaction are # correctly used by replacement logic # 1. Check that feeperkb uses modified fees tx0_outpoint = make_utxo(self.nodes[0], int(1.1 * COIN)) tx1a = CTransaction() tx1a.vin = [CTxIn(tx0_outpoint, n_sequence=0)] tx1a.vout = [CTxOut(1 * COIN, CScript([b'a']))] tx1a_hex = tx_to_hex(tx1a) tx1a_txid = self.nodes[0].sendrawtransaction(tx1a_hex, True) # Higher fee, but the actual fee per KB is much lower. tx1b = CTransaction() tx1b.vin = [CTxIn(tx0_outpoint, n_sequence=0)] tx1b.vout = [CTxOut(int(0.001 * COIN), CScript([b'a' * 740000]))] tx1b_hex = tx_to_hex(tx1b) # Verify tx1b cannot replace tx1a. assert_raises_rpc_error(-26, "insufficient fee", self.nodes[0].sendrawtransaction, tx1b_hex, True) # Use prioritisetransaction to set tx1a's fee to 0. self.nodes[0].prioritisetransaction(txid=tx1a_txid, fee_delta=int(-0.1 * COIN)) # Now tx1b should be able to replace tx1a tx1b_txid = self.nodes[0].sendrawtransaction(tx1b_hex, True) assert (tx1b_txid in self.nodes[0].getrawmempool()) # 2. Check that absolute fee checks use modified fee. tx1_outpoint = make_utxo(self.nodes[0], int(1.1 * COIN)) tx2a = CTransaction() tx2a.vin = [CTxIn(tx1_outpoint, n_sequence=0)] tx2a.vout = [CTxOut(1 * COIN, CScript([b'a']))] tx2a_hex = tx_to_hex(tx2a) self.nodes[0].sendrawtransaction(tx2a_hex, True) # Lower fee, but we'll prioritise it tx2b = CTransaction() tx2b.vin = [CTxIn(tx1_outpoint, n_sequence=0)] tx2b.vout = [CTxOut(int(1.01 * COIN), CScript([b'a']))] tx2b.rehash() tx2b_hex = tx_to_hex(tx2b) # Verify tx2b cannot replace tx2a. assert_raises_rpc_error(-26, "insufficient fee", self.nodes[0].sendrawtransaction, tx2b_hex, True) # Now prioritise tx2b to have a higher modified fee self.nodes[0].prioritisetransaction(txid=tx2b.hash, fee_delta=int(0.1 * COIN)) # tx2b should now be accepted tx2b_txid = self.nodes[0].sendrawtransaction(tx2b_hex, True) assert (tx2b_txid in self.nodes[0].getrawmempool())