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.
251# sendrawtransaction should fail if the tx is in the mempool252assert_raises_rpc_error(-26, NOT_FINAL_ERROR, self.wallet.sendrawtransaction, from_node=node, tx_hex=tx.serialize().hex())253else:254# sendrawtransaction should succeed if the tx is not in the mempool255self.wallet.sendrawtransaction(from_node=node, tx_hex=tx.serialize().hex())257return tx259test_nonzero_locks(tx2, self.nodes[0], self.relayfee, use_height_lock=True)260test_nonzero_locks(tx2, self.nodes[0], self.relayfee, use_height_lock=False)262# Now mine some blocks, but make sure tx2 doesn't get mined.263# Use prioritisetransaction to lower the effective feerate to 0264self.nodes[0].prioritisetransaction(txid=tx2.txid_hex, fee_delta=int(-self.relayfee*COIN))265cur_time = int(time.time())266for _ in range(10):267self.nodes[0].setmocktime(cur_time + 600)268self.generate(self.wallet, 1, sync_fun=self.no_op)269cur_time += 600271assert tx2.txid_hex in self.nodes[0].getrawmempool()273test_nonzero_locks(tx2, self.nodes[0], self.relayfee, use_height_lock=True)274test_nonzero_locks(tx2, self.nodes[0], self.relayfee, use_height_lock=False)276# Mine tx2, and then try again277self.nodes[0].prioritisetransaction(txid=tx2.txid_hex, fee_delta=int(self.relayfee*COIN))279# Advance the time on the node so that we can test timelocks280self.nodes[0].setmocktime(cur_time+600)281# Save block template now to use for the reorg later282tmpl = self.nodes[0].getblocktemplate(NORMAL_GBT_REQUEST_PARAMS)283self.generate(self.nodes[0], 1)284assert tx2.txid_hex not in self.nodes[0].getrawmempool()286# Now that tx2 is not in the mempool, a sequence locked spend should287# succeed288tx3 = test_nonzero_locks(tx2, self.nodes[0], self.relayfee, use_height_lock=False)289assert tx3.txid_hex in self.nodes[0].getrawmempool()291self.generate(self.nodes[0], 1)292assert tx3.txid_hex not in self.nodes[0].getrawmempool()294# One more test, this time using height locks295tx4 = test_nonzero_locks(tx3, self.nodes[0], self.relayfee, use_height_lock=True)296assert tx4.txid_hex in self.nodes[0].getrawmempool()298# Now try combining confirmed and unconfirmed inputs299tx5 = test_nonzero_locks(tx4, self.nodes[0], self.relayfee, use_height_lock=True)300assert tx5.txid_hex not in self.nodes[0].getrawmempool()302utxo = self.wallet.get_utxo()303tx5.vin.append(CTxIn(COutPoint(int(utxo["txid"], 16), utxo["vout"]), nSequence=1))304tx5.vout[0].nValue += int(utxo["value"]*COIN)305self.wallet.sign_tx(tx=tx5)307assert_raises_rpc_error(-26, NOT_FINAL_ERROR, self.wallet.sendrawtransaction, from_node=self.nodes[0], tx_hex=tx5.serialize().hex())309# Test mempool-BIP68 consistency after reorg310#311# State of the transactions in the last blocks:312# ... -> [ tx2 ] -> [ tx3 ]313# tip-1 tip314# And currently tx4 is in the mempool.315#316# If we invalidate the tip, tx3 should get added to the mempool, causing317# tx4 to be removed (fails sequence-lock).318self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash())319assert tx4.txid_hex not in self.nodes[0].getrawmempool()320assert tx3.txid_hex in self.nodes[0].getrawmempool()322# Now mine 2 empty blocks to reorg out the current tip (labeled tip-1 in323# diagram above).324# This would cause tx2 to be added back to the mempool, which in turn causes325# tx3 to be removed.326for i in range(2):327block = create_block(tmpl=tmpl, ntime=cur_time)328block.solve()329tip = block.hash_int330assert_equal(None if i == 1 else 'inconclusive', self.nodes[0].submitblock(block.serialize().hex()))331tmpl = self.nodes[0].getblocktemplate(NORMAL_GBT_REQUEST_PARAMS)332tmpl['previousblockhash'] = '%x' % tip333tmpl['transactions'] = []334cur_time += 1336mempool = self.nodes[0].getrawmempool()337assert tx3.txid_hex not in mempool338assert tx2.txid_hex in mempool340# Reset the chain and get rid of the mocktimed-blocks341self.nodes[0].setmocktime(0)342self.nodes[0].invalidateblock(self.nodes[0].getblockhash(cur_height+1))343self.generate(self.wallet, 10, sync_fun=self.no_op)345# Make sure that BIP68 isn't being used to validate blocks prior to346# activation height. If more blocks are mined prior to this test347# being run, then it's possible the test has activated the soft fork, and348# this test should be moved to run earlier, or deleted.349def test_bip68_not_consensus(self):350assert not softfork_active(self.nodes[0], 'csv')352tx1 = self.wallet.send_self_transfer(from_node=self.nodes[0])["tx"]354# Make an anyone-can-spend transaction355tx2 = CTransaction()356tx2.version = 1357tx2.vin = [CTxIn(COutPoint(tx1.txid_int, 0), nSequence=0)]358tx2.vout = [CTxOut(int(tx1.vout[0].nValue - self.relayfee * COIN), SCRIPT_W0_SH_OP_TRUE)]360# sign tx2361self.wallet.sign_tx(tx=tx2)362tx2_raw = tx2.serialize().hex()363tx2 = tx_from_hex(tx2_raw)365self.wallet.sendrawtransaction(from_node=self.nodes[0], tx_hex=tx2_raw)367# Now make an invalid spend of tx2 according to BIP68368sequence_value = 100 # 100 block relative locktime370tx3 = CTransaction()371tx3.version = 2372tx3.vin = [CTxIn(COutPoint(tx2.txid_int, 0), nSequence=sequence_value)]373tx3.wit.vtxinwit = [CTxInWitness()]374tx3.wit.vtxinwit[0].scriptWitness.stack = [CScript([OP_TRUE])]375tx3.vout = [CTxOut(int(tx2.vout[0].nValue - self.relayfee * COIN), SCRIPT_W0_SH_OP_TRUE)]377assert_raises_rpc_error(-26, NOT_FINAL_ERROR, self.wallet.sendrawtransaction, from_node=self.nodes[0], tx_hex=tx3.serialize().hex())379# make a block that violates bip68; ensure that the tip updates380block = create_block(tmpl=self.nodes[0].getblocktemplate(NORMAL_GBT_REQUEST_PARAMS), txlist=[tx1, tx2, tx3])381add_witness_commitment(block)382block.solve()384assert_equal(None, self.nodes[0].submitblock(block.serialize().hex()))385assert_equal(self.nodes[0].getbestblockhash(), block.hash_hex)387def activateCSV(self):388# activation should happen at block height 432 (3 periods)389# getblockchaininfo will show CSV as active at block 431 (144 * 3 -1) since it's returning whether CSV is active for the next block.390min_activation_height = 432391height = self.nodes[0].getblockcount()392assert_greater_than(min_activation_height - height, 2)393self.generate(self.wallet, min_activation_height - height - 2, sync_fun=self.no_op)394assert not softfork_active(self.nodes[0], 'csv')395self.generate(self.wallet, 1, sync_fun=self.no_op)396assert softfork_active(self.nodes[0], 'csv')397self.sync_blocks()399# Use self.nodes[1] to test that version 2 transactions are standard.400def test_version2_relay(self):401mini_wallet = MiniWallet(self.nodes[1])402mini_wallet.send_self_transfer(from_node=self.nodes[1], version=2)405if __name__ == '__main__':406BIP68Test(__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.