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.
502# Without walletrejectlongchains, we will still generate a txid503# The tx will be stored in the wallet but not accepted to the mempool504extra_txid = self.nodes[0].sendtoaddress(sending_addr, Decimal('0.0001'))505assert extra_txid not in self.nodes[0].getrawmempool()506assert extra_txid in [tx["txid"] for tx in self.nodes[0].listtransactions()]507self.nodes[0].abandontransaction(extra_txid)508total_txs = len(self.nodes[0].listtransactions("*", 99999))510# Try with walletrejectlongchains511# Double chain limit but require combining inputs, so we pass AttemptSelection512self.stop_node(0)513extra_args = ["-walletrejectlongchains", "-limitclustercount=" + str(2 * chainlimit), "-limitancestorcount=" + str(2*chainlimit)]514self.start_node(0, extra_args=extra_args)516# wait until the wallet has submitted all transactions to the mempool517self.wait_until(lambda: len(self.nodes[0].getrawmempool()) == chainlimit * 2)519# Prevent potential race condition when calling wallet RPCs right after restart520self.nodes[0].syncwithvalidationinterfacequeue()522node0_balance = self.nodes[0].getbalance()523# With walletrejectlongchains we will not create the tx and store it in our wallet.524assert_raises_rpc_error(-6, "too many unconfirmed transactions in cluster", self.nodes[0].sendtoaddress, sending_addr, node0_balance - Decimal('0.01'))526# Verify nothing new in wallet527assert_equal(total_txs, len(self.nodes[0].listtransactions("*", 99999)))529# Test getaddressinfo on external address. Note that these addresses are taken from disablewallet.py530assert_raises_rpc_error(-5, "Invalid or unsupported Base58-encoded address.", self.nodes[0].getaddressinfo, "3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy")531address_info = self.nodes[0].getaddressinfo("mneYUmWYsuk7kySiURxCi3AGxrAqZxLgPZ")532assert_equal(address_info['address'], "mneYUmWYsuk7kySiURxCi3AGxrAqZxLgPZ")533assert_equal(address_info["scriptPubKey"], "76a9144e3854046c7bd1594ac904e4793b6a45b36dea0988ac")534assert not address_info["ismine"]535assert not address_info["isscript"]536assert not address_info["ischange"]538# Test getaddressinfo 'ischange' field on change address.539self.generate(self.nodes[0], 1, sync_fun=self.no_op)540destination = self.nodes[1].getnewaddress()541txid = self.nodes[0].sendtoaddress(destination, 0.123)542tx = self.nodes[0].gettransaction(txid=txid, verbose=True)['decoded']543assert len(tx["vout"]) > 1544for vout in tx["vout"]:545address = vout['scriptPubKey']['address']546ischange = self.nodes[0].getaddressinfo(address)['ischange']547assert_equal(ischange, address != destination)548if ischange:549change = address550assert vout["ischange"]551else:552assert "ischange" not in vout553self.nodes[0].setlabel(change, 'foobar')554assert_equal(self.nodes[0].getaddressinfo(change)['ischange'], False)556# Test gettransaction response with different arguments.557self.log.info("Testing gettransaction response with different arguments...")558self.nodes[0].setlabel(change, 'baz')559baz = self.nodes[0].listtransactions(label="baz", count=1)[0]560expected_receive_vout = {"label": "baz",561"address": baz["address"],562"amount": baz["amount"],563"category": baz["category"],564"vout": baz["vout"]}565expected_fields = frozenset({'amount', 'confirmations', 'details', 'fee',566'hex', 'lastprocessedblock', 'time', 'timereceived', 'trusted', 'txid', 'wtxid', 'walletconflicts', 'mempoolconflicts',567'alternate_wtxids'})568verbose_field = "decoded"569expected_verbose_fields = expected_fields | {verbose_field}571self.log.debug("Testing gettransaction response without verbose")572tx = self.nodes[0].gettransaction(txid=txid)573assert_equal(set([*tx]), expected_fields)574assert_array_result(tx["details"], {"category": "receive"}, expected_receive_vout)576self.log.debug("Testing gettransaction response with verbose set to False")577tx = self.nodes[0].gettransaction(txid=txid, verbose=False)578assert_equal(set([*tx]), expected_fields)579assert_array_result(tx["details"], {"category": "receive"}, expected_receive_vout)581self.log.debug("Testing gettransaction response with verbose set to True")582tx = self.nodes[0].gettransaction(txid=txid, verbose=True)583assert_equal(set([*tx]), expected_verbose_fields)584assert_array_result(tx["details"], {"category": "receive"}, expected_receive_vout)585assert_equal(tx[verbose_field], self.nodes[0].decoderawtransaction(tx["hex"]))587self.log.info("Test send* RPCs with verbose=True")588address = self.nodes[0].getnewaddress("test")589txid_feeReason_one = self.nodes[2].sendtoaddress(address=address, amount=5, verbose=True)590assert_equal(txid_feeReason_one["fee_reason"], "Fallback fee")591txid_feeReason_two = self.nodes[2].sendmany(dummy='', amounts={address: 5}, verbose=True)592assert_equal(txid_feeReason_two["fee_reason"], "Fallback fee")593self.log.info("Test send* RPCs with verbose=False")594txid_feeReason_three = self.nodes[2].sendtoaddress(address=address, amount=5, verbose=False)595assert_equal(self.nodes[2].gettransaction(txid_feeReason_three)['txid'], txid_feeReason_three)596txid_feeReason_four = self.nodes[2].sendmany(dummy='', amounts={address: 5}, verbose=False)597assert_equal(self.nodes[2].gettransaction(txid_feeReason_four)['txid'], txid_feeReason_four)599self.log.info("Testing 'listunspent' outputs the parent descriptor(s) of coins")600# Create two multisig descriptors, and send a UTxO each.601multi_a = descsum_create("wsh(multi(1,tpubD6NzVbkrYhZ4YBNjUo96Jxd1u4XKWgnoc7LsA1jz3Yc2NiDbhtfBhaBtemB73n9V5vtJHwU6FVXwggTbeoJWQ1rzdz8ysDuQkpnaHyvnvzR/*,tpubD6NzVbkrYhZ4YHdDGMAYGaWxMSC1B6tPRTHuU5t3BcfcS3nrF523iFm5waFd1pP3ZvJt4Jr8XmCmsTBNx5suhcSgtzpGjGMASR3tau1hJz4/*))")602multi_b = descsum_create("wsh(multi(1,tpubD6NzVbkrYhZ4YHdDGMAYGaWxMSC1B6tPRTHuU5t3BcfcS3nrF523iFm5waFd1pP3ZvJt4Jr8XmCmsTBNx5suhcSgtzpGjGMASR3tau1hJz4/*,tpubD6NzVbkrYhZ4Y2RLiuEzNQkntjmsLpPYDm3LTRBYynUQtDtpzeUKAcb9sYthSFL3YR74cdFgF5mW8yKxv2W2CWuZDFR2dUpE5PF9kbrVXNZ/*))")603addr_a = self.nodes[0].deriveaddresses(multi_a, 0)[0]604addr_b = self.nodes[0].deriveaddresses(multi_b, 0)[0]605txid_a = self.nodes[0].sendtoaddress(addr_a, 0.01)606txid_b = self.nodes[0].sendtoaddress(addr_b, 0.01)607self.generate(self.nodes[0], 1, sync_fun=self.no_op)608# Prevent race of listunspent with outstanding TxAddedToMempool notifications609self.nodes[0].syncwithvalidationinterfacequeue()610# Now import the descriptors, make sure we can identify on which descriptor each coin was received.611self.nodes[0].createwallet(wallet_name="wo", disable_private_keys=True)612wo_wallet = self.nodes[0].get_wallet_rpc("wo")613wo_wallet.importdescriptors([614{615"desc": multi_a,616"active": False,617"timestamp": "now",618},619{620"desc": multi_b,621"active": False,622"timestamp": "now",623},624])625coins = wo_wallet.listunspent(minconf=0)626assert_equal(len(coins), 2)627coin_a = next(c for c in coins if c["txid"] == txid_a)628assert_equal(coin_a["parent_descs"][0], multi_a)629coin_b = next(c for c in coins if c["txid"] == txid_b)630assert_equal(coin_b["parent_descs"][0], multi_b)631self.nodes[0].unloadwallet("wo")633self.log.info("Test -spendzeroconfchange")634self.restart_node(0, ["-spendzeroconfchange=0"])636# create new wallet and fund it with a confirmed UTXO637self.nodes[0].createwallet(wallet_name="zeroconf", load_on_startup=True)638zeroconf_wallet = self.nodes[0].get_wallet_rpc("zeroconf")639default_wallet = self.nodes[0].get_wallet_rpc(self.default_wallet_name)640default_wallet.sendtoaddress(zeroconf_wallet.getnewaddress(), Decimal('1.0'))641self.generate(self.nodes[0], 1, sync_fun=self.no_op)642utxos = zeroconf_wallet.listunspent(minconf=0)643assert_equal(len(utxos), 1)644assert_equal(utxos[0]['confirmations'], 1)646# spend confirmed UTXO to ourselves647zeroconf_wallet.sendall(recipients=[zeroconf_wallet.getnewaddress()])648utxos = zeroconf_wallet.listunspent(minconf=0)649assert_equal(len(utxos), 1)650assert_equal(utxos[0]['confirmations'], 0)651# accounts for untrusted pending balance652bal = zeroconf_wallet.getbalances()653assert_equal(bal['mine']['trusted'], 0)654assert_equal(bal['mine']['untrusted_pending'], utxos[0]['amount'])656# spending an unconfirmed UTXO sent to ourselves should fail657assert_raises_rpc_error(-6, "Insufficient funds", zeroconf_wallet.sendtoaddress, zeroconf_wallet.getnewaddress(), Decimal('0.5'))659# check that it works again with -spendzeroconfchange set (=default)660self.restart_node(0, ["-spendzeroconfchange=1"])661# Make sure the wallet knows the tx in the mempool662self.nodes[0].syncwithvalidationinterfacequeue()664zeroconf_wallet = self.nodes[0].get_wallet_rpc("zeroconf")665utxos = zeroconf_wallet.listunspent(minconf=0)666assert_equal(len(utxos), 1)667assert_equal(utxos[0]['confirmations'], 0)668# accounts for trusted balance669bal = zeroconf_wallet.getbalances()670assert_equal(bal['mine']['trusted'], utxos[0]['amount'])671assert_equal(bal['mine']['untrusted_pending'], 0)673zeroconf_wallet.sendtoaddress(zeroconf_wallet.getnewaddress(), Decimal('0.5'))675self.test_chain_listunspent()677def test_chain_listunspent(self):678self.wallet = MiniWallet(self.nodes[0])679self.nodes[0].get_wallet_rpc(self.default_wallet_name).sendtoaddress(self.wallet.get_address(), "5")680self.generate(self.wallet, 1, sync_fun=self.no_op)681self.nodes[0].createwallet("watch_wallet", disable_private_keys=True)682watch_wallet = self.nodes[0].get_wallet_rpc("watch_wallet")683import_res = watch_wallet.importdescriptors([{"desc": self.wallet.get_descriptor(), "timestamp": "now"}])684assert_equal(import_res[0]["success"], True)686# DEFAULT_ANCESTOR_LIMIT transactions off a confirmed tx should be fine687chain = self.wallet.create_self_transfer_chain(chain_length=DEFAULT_ANCESTOR_LIMIT)688ancestor_vsize = 0689ancestor_fees = Decimal(0)691for i, t in enumerate(chain):692ancestor_vsize += t["tx"].get_vsize()693ancestor_fees += t["fee"]694self.wallet.sendrawtransaction(from_node=self.nodes[0], tx_hex=t["hex"])695# Check that listunspent ancestor{count, size, fees} yield the correct results696wallet_unspent = watch_wallet.listunspent(minconf=0)697this_unspent = next(utxo_info for utxo_info in wallet_unspent if utxo_info["txid"] == t["txid"])698assert_equal(this_unspent['ancestorcount'], i + 1)699assert_equal(this_unspent['ancestorsize'], ancestor_vsize)700assert_equal(this_unspent['ancestorfees'], ancestor_fees * COIN)703if __name__ == '__main__':704WalletTest(__file__).main()
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.