Inside Bitcoin
Opening the selected file…
Inside Bitcoin
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
1#!/usr/bin/env python32# Copyright (c) 2014-present The Bitcoin Core developers3# Distributed under the MIT software license, see the accompanying4# file COPYING or http://www.opensource.org/licenses/mit-license.php.5"""Test the rawtransaction RPCs.7Test the following RPCs:8- getrawtransaction9- createrawtransaction10- signrawtransactionwithwallet11- sendrawtransaction12- decoderawtransaction13"""15from collections import OrderedDict16from decimal import Decimal17from itertools import product19from test_framework.messages import (20MAX_BIP125_RBF_SEQUENCE,21COIN,22TX_MAX_STANDARD_VERSION,23TX_MIN_STANDARD_VERSION,24CTransaction,25CTxOut,26tx_from_hex,27)28from test_framework.script import (29CScript,30OP_FALSE,31OP_INVALIDOPCODE,32OP_RETURN,33)34from test_framework.test_framework import BitcoinTestFramework35from test_framework.util import (36assert_equal,37assert_greater_than,38assert_raises_rpc_error,39sync_txindex,40)41from test_framework.wallet import (42getnewdestination,43MiniWallet,44)47TXID = "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000"50class multidict(dict):51"""Dictionary that allows duplicate keys.53Constructed with a list of (key, value) tuples. When dumped by the json module,54will output invalid json with repeated keys, eg:55>>> json.dumps(multidict([(1,2),(1,2)])56'{"1": 2, "1": 2}'58Used to test calls to rpc methods with repeated keys in the json object."""60def __init__(self, x):61dict.__init__(self, x)62self.x = x64def items(self):65return self.x68class RawTransactionsTest(BitcoinTestFramework):69def set_test_params(self):70self.num_nodes = 371self.extra_args = [72["-txindex"],73[],74["-fastprune", "-prune=1"],75]76# whitelist peers to speed up tx relay / mempool sync77self.noban_tx_relay = True78self.supports_cli = False80def setup_network(self):81super().setup_network()82self.connect_nodes(0, 2)84def run_test(self):85self.wallet = MiniWallet(self.nodes[0])87self.getrawtransaction_tests()88self.createrawtransaction_tests()89self.sendrawtransaction_tests()90self.sendrawtransaction_testmempoolaccept_tests()91self.decoderawtransaction_tests()92self.transaction_version_number_tests()93self.getrawtransaction_verbosity_tests()95def getrawtransaction_tests(self):96tx = self.wallet.send_self_transfer(from_node=self.nodes[0])97self.generate(self.nodes[0], 1)98txId = tx['txid']99err_msg = (100"No such mempool transaction. Use -txindex or provide a block hash to enable"101" blockchain transaction queries. Use gettransaction for wallet transactions."102)104for n in [0, 2]:105self.log.info(f"Test getrawtransaction {'with' if n == 0 else 'without'} -txindex")107if n == 0:108sync_txindex(self, self.nodes[n])109# With -txindex.110# 1. valid parameters - only supply txid111assert_equal(self.nodes[n].getrawtransaction(txId), tx['hex'])113# 2. valid parameters - supply txid and 0 for non-verbose114assert_equal(self.nodes[n].getrawtransaction(txId, 0), tx['hex'])116# 3. valid parameters - supply txid and False for non-verbose117assert_equal(self.nodes[n].getrawtransaction(txId, False), tx['hex'])119# 4. valid parameters - supply txid and 1 for verbose.120# We only check the "hex" field of the output so we don't need to update this test every time the output format changes.121assert_equal(self.nodes[n].getrawtransaction(txId, 1)["hex"], tx['hex'])122assert_equal(self.nodes[n].getrawtransaction(txId, 2)["hex"], tx['hex'])124# 5. valid parameters - supply txid and True for non-verbose125assert_equal(self.nodes[n].getrawtransaction(txId, True)["hex"], tx['hex'])126else:127# Without -txindex, expect to raise.128for verbose in [None, 0, False, 1, True]:129assert_raises_rpc_error(-5, err_msg, self.nodes[n].getrawtransaction, txId, verbose)131# 6. invalid parameters - supply txid and invalid boolean values (strings) for verbose132for value in ["True", "False"]:133assert_raises_rpc_error(-3, "not of expected type number", self.nodes[n].getrawtransaction, txid=txId, verbose=value)134assert_raises_rpc_error(-3, "not of expected type number", self.nodes[n].getrawtransaction, txid=txId, verbosity=value)136# 7. invalid parameters - supply txid and empty array137assert_raises_rpc_error(-3, "not of expected type number", self.nodes[n].getrawtransaction, txId, [])139# 8. invalid parameters - supply txid and empty dict140assert_raises_rpc_error(-3, "not of expected type number", self.nodes[n].getrawtransaction, txId, {})142# Make a tx by sending, then generate 2 blocks; block1 has the tx in it143tx = self.wallet.send_self_transfer(from_node=self.nodes[2])['txid']144block1, block2 = self.generate(self.nodes[2], 2)145for n in [0, 2]:146self.log.info(f"Test getrawtransaction {'with' if n == 0 else 'without'} -txindex, with blockhash")147# We should be able to get the raw transaction by providing the correct block148gottx = self.nodes[n].getrawtransaction(txid=tx, verbose=True, blockhash=block1)149assert_equal(gottx['txid'], tx)150assert_equal(gottx['in_active_chain'], True)151if n == 0:152self.log.info("Test getrawtransaction with -txindex, without blockhash: 'in_active_chain' should be absent")153for v in [1,2]:154gottx = self.nodes[n].getrawtransaction(txid=tx, verbosity=v)155assert_equal(gottx['txid'], tx)156assert 'in_active_chain' not in gottx157else:158self.log.info("Test getrawtransaction without -txindex, without blockhash: expect the call to raise")159assert_raises_rpc_error(-5, err_msg, self.nodes[n].getrawtransaction, txid=tx, verbose=True)160# We should not get the tx if we provide an unrelated block161assert_raises_rpc_error(-5, "No such transaction found", self.nodes[n].getrawtransaction, txid=tx, blockhash=block2)162# An invalid block hash should raise the correct errors163assert_raises_rpc_error(-3, "JSON value of type bool is not of expected type string", self.nodes[n].getrawtransaction, txid=tx, blockhash=True)164assert_raises_rpc_error(-8, "parameter 3 must be of length 64 (not 6, for 'foobar')", self.nodes[n].getrawtransaction, txid=tx, blockhash="foobar")165assert_raises_rpc_error(-8, "parameter 3 must be of length 64 (not 8, for 'abcd1234')", self.nodes[n].getrawtransaction, txid=tx, blockhash="abcd1234")166foo = "ZZZ0000000000000000000000000000000000000000000000000000000000000"167assert_raises_rpc_error(-8, f"parameter 3 must be hexadecimal string (not '{foo}')", self.nodes[n].getrawtransaction, txid=tx, blockhash=foo)168bar = "0000000000000000000000000000000000000000000000000000000000000000"169assert_raises_rpc_error(-5, "Block hash not found", self.nodes[n].getrawtransaction, txid=tx, blockhash=bar)170# Undo the blocks and verify that "in_active_chain" is false.171self.nodes[n].invalidateblock(block1)172gottx = self.nodes[n].getrawtransaction(txid=tx, verbose=True, blockhash=block1)173assert_equal(gottx['in_active_chain'], False)174self.nodes[n].reconsiderblock(block1)175assert_equal(self.nodes[n].getbestblockhash(), block2)177self.log.info("Test getrawtransaction on genesis block coinbase returns an error")178block = self.nodes[0].getblock(self.nodes[0].getblockhash(0))179assert_raises_rpc_error(-5, "The genesis block coinbase is not considered an ordinary transaction", self.nodes[0].getrawtransaction, block['merkleroot'])181def getrawtransaction_verbosity_tests(self):182tx = self.wallet.send_self_transfer(from_node=self.nodes[1])['txid']183[block1] = self.generate(self.nodes[1], 1)184fields = [185'blockhash',186'blocktime',187'confirmations',188'hash',189'hex',190'in_active_chain',191'locktime',192'size',193'time',194'txid',195'vin',196'vout',197'vsize',198'weight',199]200prevout_fields = [201'generated',202'height',203'value',204'scriptPubKey',205]206script_pub_key_fields = [207'address',208'asm',209'hex',210'type',211]212# node 0 & 2 with verbosity 1 & 2213for n, v in product([0, 2], [1, 2]):214self.log.info(f"Test getrawtransaction_verbosity {v} {'with' if n == 0 else 'without'} -txindex, with blockhash")215gottx = self.nodes[n].getrawtransaction(txid=tx, verbosity=v, blockhash=block1)216missing_fields = set(fields).difference(gottx.keys())217if missing_fields:218raise AssertionError(f"fields {', '.join(missing_fields)} are not in transaction")220assert len(gottx['vin']) > 0221if v == 1:222assert 'fee' not in gottx223assert 'prevout' not in gottx['vin'][0]224if v == 2:225assert isinstance(gottx['fee'], Decimal)226assert 'prevout' in gottx['vin'][0]227prevout = gottx['vin'][0]['prevout']228script_pub_key = prevout['scriptPubKey']230missing_fields = set(prevout_fields).difference(prevout.keys())231if missing_fields:232raise AssertionError(f"fields {', '.join(missing_fields)} are not in transaction")234missing_fields = set(script_pub_key_fields).difference(script_pub_key.keys())235if missing_fields:236raise AssertionError(f"fields {', '.join(missing_fields)} are not in transaction")238# check verbosity 2 without blockhash but with txindex239assert 'fee' in self.nodes[0].getrawtransaction(txid=tx, verbosity=2)240# check that coinbase has no fee or does not throw any errors for verbosity 2241coin_base = self.nodes[1].getblock(block1)['tx'][0]242gottx = self.nodes[1].getrawtransaction(txid=coin_base, verbosity=2, blockhash=block1)243assert 'fee' not in gottx244# check that verbosity 2 for a mempool tx will fallback to verbosity 1245# Do this with a pruned chain, as a regression test for https://github.com/bitcoin/bitcoin/pull/29003246self.generate(self.nodes[2], 400)247assert_greater_than(self.nodes[2].pruneblockchain(250), 0)248mempool_tx = self.wallet.send_self_transfer(from_node=self.nodes[2])['txid']249gottx = self.nodes[2].getrawtransaction(txid=mempool_tx, verbosity=2)250assert 'fee' not in gottx
Independent explanations by MyBitcoinExplorer. Not affiliated with or endorsed by Bitcoin Core. Guides are educational and do not replace the source or its tests.
Bitcoin Core source © its contributors, distributed under the MIT license. Original notices and bundled third-party licenses are retained in the source tree.