|
| 1 | +#!/usr/bin/env python3 |
| 2 | +# Copyright (c) 2014-2022 The Bitcoin Core developers |
| 3 | +# Distributed under the MIT software license, see the accompanying |
| 4 | +# file COPYING or http://www.opensource.org/licenses/mit-license.php. |
| 5 | +"""Test RPCs that retrieve information from the mempool.""" |
| 6 | + |
| 7 | +from test_framework.blocktools import COINBASE_MATURITY |
| 8 | +from test_framework.test_framework import BitcoinTestFramework |
| 9 | +from test_framework.util import ( |
| 10 | + assert_equal, |
| 11 | + assert_raises_rpc_error, |
| 12 | +) |
| 13 | +from test_framework.wallet import MiniWallet |
| 14 | + |
| 15 | + |
| 16 | +class RPCMempoolInfoTest(BitcoinTestFramework): |
| 17 | + def set_test_params(self): |
| 18 | + self.num_nodes = 1 |
| 19 | + |
| 20 | + def run_test(self): |
| 21 | + self.wallet = MiniWallet(self.nodes[0]) |
| 22 | + self.generate(self.wallet, COINBASE_MATURITY + 1) |
| 23 | + self.wallet.rescan_utxos() |
| 24 | + confirmed_utxo = self.wallet.get_utxo() |
| 25 | + |
| 26 | + # Create a tree of unconfirmed transactions in the mempool: |
| 27 | + # txA |
| 28 | + # / \ |
| 29 | + # / \ |
| 30 | + # / \ |
| 31 | + # / \ |
| 32 | + # / \ |
| 33 | + # txB txC |
| 34 | + # / \ / \ |
| 35 | + # / \ / \ |
| 36 | + # txD txE txF txG |
| 37 | + # \ / |
| 38 | + # \ / |
| 39 | + # txH |
| 40 | + |
| 41 | + def create_tx(**kwargs): |
| 42 | + return self.wallet.send_self_transfer_multi( |
| 43 | + from_node=self.nodes[0], |
| 44 | + **kwargs, |
| 45 | + ) |
| 46 | + |
| 47 | + txA = create_tx(utxos_to_spend=[confirmed_utxo], num_outputs=2) |
| 48 | + txB = create_tx(utxos_to_spend=[txA["new_utxos"][0]], num_outputs=2) |
| 49 | + txC = create_tx(utxos_to_spend=[txA["new_utxos"][1]], num_outputs=2) |
| 50 | + txD = create_tx(utxos_to_spend=[txB["new_utxos"][0]], num_outputs=1) |
| 51 | + txE = create_tx(utxos_to_spend=[txB["new_utxos"][1]], num_outputs=1) |
| 52 | + txF = create_tx(utxos_to_spend=[txC["new_utxos"][0]], num_outputs=2) |
| 53 | + txG = create_tx(utxos_to_spend=[txC["new_utxos"][1]], num_outputs=1) |
| 54 | + txH = create_tx(utxos_to_spend=[txE["new_utxos"][0],txF["new_utxos"][0]], num_outputs=1) |
| 55 | + txidA, txidB, txidC, txidD, txidE, txidF, txidG, txidH = [ |
| 56 | + tx["txid"] for tx in [txA, txB, txC, txD, txE, txF, txG, txH] |
| 57 | + ] |
| 58 | + |
| 59 | + mempool = self.nodes[0].getrawmempool() |
| 60 | + assert_equal(len(mempool), 8) |
| 61 | + for txid in [txidA, txidB, txidC, txidD, txidE, txidF, txidG, txidH]: |
| 62 | + assert_equal(txid in mempool, True) |
| 63 | + |
| 64 | + self.log.info("Find transactions spending outputs") |
| 65 | + result = self.nodes[0].gettxspendingprevout([ {'txid' : confirmed_utxo['txid'], 'vout' : 0}, {'txid' : txidA, 'vout' : 1} ]) |
| 66 | + assert_equal(result, [ {'txid' : confirmed_utxo['txid'], 'vout' : 0, 'spendingtxid' : txidA}, {'txid' : txidA, 'vout' : 1, 'spendingtxid' : txidC} ]) |
| 67 | + |
| 68 | + self.log.info("Find transaction spending multiple outputs") |
| 69 | + result = self.nodes[0].gettxspendingprevout([ {'txid' : txidE, 'vout' : 0}, {'txid' : txidF, 'vout' : 0} ]) |
| 70 | + assert_equal(result, [ {'txid' : txidE, 'vout' : 0, 'spendingtxid' : txidH}, {'txid' : txidF, 'vout' : 0, 'spendingtxid' : txidH} ]) |
| 71 | + |
| 72 | + self.log.info("Find no transaction when output is unspent") |
| 73 | + result = self.nodes[0].gettxspendingprevout([ {'txid' : txidH, 'vout' : 0} ]) |
| 74 | + assert_equal(result, [ {'txid' : txidH, 'vout' : 0} ]) |
| 75 | + result = self.nodes[0].gettxspendingprevout([ {'txid' : txidA, 'vout' : 5} ]) |
| 76 | + assert_equal(result, [ {'txid' : txidA, 'vout' : 5} ]) |
| 77 | + |
| 78 | + self.log.info("Mixed spent and unspent outputs") |
| 79 | + result = self.nodes[0].gettxspendingprevout([ {'txid' : txidB, 'vout' : 0}, {'txid' : txidG, 'vout' : 3} ]) |
| 80 | + assert_equal(result, [ {'txid' : txidB, 'vout' : 0, 'spendingtxid' : txidD}, {'txid' : txidG, 'vout' : 3} ]) |
| 81 | + |
| 82 | + self.log.info("Unknown input fields") |
| 83 | + assert_raises_rpc_error(-3, "Unexpected key unknown", self.nodes[0].gettxspendingprevout, [{'txid' : txidC, 'vout' : 1, 'unknown' : 42}]) |
| 84 | + |
| 85 | + self.log.info("Invalid vout provided") |
| 86 | + assert_raises_rpc_error(-8, "Invalid parameter, vout cannot be negative", self.nodes[0].gettxspendingprevout, [{'txid' : txidA, 'vout' : -1}]) |
| 87 | + |
| 88 | + self.log.info("Invalid txid provided") |
| 89 | + assert_raises_rpc_error(-3, "Expected type string for txid, got number", self.nodes[0].gettxspendingprevout, [{'txid' : 42, 'vout' : 0}]) |
| 90 | + |
| 91 | + self.log.info("Missing outputs") |
| 92 | + assert_raises_rpc_error(-8, "Invalid parameter, outputs are missing", self.nodes[0].gettxspendingprevout, []) |
| 93 | + |
| 94 | + self.log.info("Missing vout") |
| 95 | + assert_raises_rpc_error(-3, "Missing vout", self.nodes[0].gettxspendingprevout, [{'txid' : txidA}]) |
| 96 | + |
| 97 | + self.log.info("Missing txid") |
| 98 | + assert_raises_rpc_error(-3, "Missing txid", self.nodes[0].gettxspendingprevout, [{'vout' : 3}]) |
| 99 | + |
| 100 | + |
| 101 | +if __name__ == '__main__': |
| 102 | + RPCMempoolInfoTest().main() |
0 commit comments