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.
251self.send_blocks([b8], False, reconnect=True)253# Try to create a block that has too much fee254# genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)255# \-> b9 (4)256# \-> b3 (1) -> b4 (2)257self.log.info("Reject a block where the miner creates too much coinbase reward")258self.move_tip(6)259b9 = self.next_block(9, spend=out[4], additional_coinbase_value=1)260self.send_blocks([b9], success=False, reject_reason='bad-cb-amount', reconnect=True)262# Create a fork that ends in a block with too much fee (the one that causes the reorg)263# genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)264# \-> b10 (3) -> b11 (4)265# \-> b3 (1) -> b4 (2)266self.log.info("Reject a chain where the miner creates too much coinbase reward, even if the chain is longer")267self.move_tip(5)268b10 = self.next_block(10, spend=out[3])269self.send_blocks([b10], False)271b11 = self.next_block(11, spend=out[4], additional_coinbase_value=1)272self.send_blocks([b11], success=False, reject_reason='bad-cb-amount', reconnect=True)274# Try again, but with a valid fork first275# genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)276# \-> b12 (3) -> b13 (4) -> b14 (5)277# \-> b3 (1) -> b4 (2)278self.log.info("Reject a chain where the miner creates too much coinbase reward, even if the chain is longer (on a forked chain)")279self.move_tip(5)280b12 = self.next_block(12, spend=out[3])281self.save_spendable_output()282b13 = self.next_block(13, spend=out[4])283self.save_spendable_output()284b14 = self.next_block(14, spend=out[5], additional_coinbase_value=1)285self.send_blocks([b12, b13, b14], success=False, reject_reason='bad-cb-amount', reconnect=True)287# New tip should be b13.288assert_equal(node.getbestblockhash(), b13.hash_hex)290# Add a block with MAX_BLOCK_SIGOPS and one with one more sigop291# genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)292# \-> b12 (3) -> b13 (4) -> b15 (5) -> b16 (6)293# \-> b3 (1) -> b4 (2)294self.log.info("Accept a block with lots of checksigs")295lots_of_checksigs = CScript([OP_CHECKSIG] * (MAX_BLOCK_SIGOPS - 1))296self.move_tip(13)297b15 = self.next_block(15, spend=out[5], script=lots_of_checksigs)298self.save_spendable_output()299self.send_blocks([b15], True)301self.log.info("Reject a block with too many checksigs")302too_many_checksigs = CScript([OP_CHECKSIG] * (MAX_BLOCK_SIGOPS))303b16 = self.next_block(16, spend=out[6], script=too_many_checksigs)304self.send_blocks([b16], success=False, reject_reason='bad-blk-sigops', reconnect=True)306# Attempt to spend a transaction created on a different fork307# genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)308# \-> b12 (3) -> b13 (4) -> b15 (5) -> b17 (b3.vtx[1])309# \-> b3 (1) -> b4 (2)310self.log.info("Reject a block with a spend from a re-org'ed out tx")311self.move_tip(15)312b17 = self.next_block(17, spend=txout_b3)313self.send_blocks([b17], success=False, reject_reason='bad-txns-inputs-missingorspent', reconnect=True)315# Attempt to spend a transaction created on a different fork (on a fork this time)316# genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)317# \-> b12 (3) -> b13 (4) -> b15 (5)318# \-> b18 (b3.vtx[1]) -> b19 (6)319# \-> b3 (1) -> b4 (2)320self.log.info("Reject a block with a spend from a re-org'ed out tx (on a forked chain)")321self.move_tip(13)322b18 = self.next_block(18, spend=txout_b3)323self.send_blocks([b18], False)325b19 = self.next_block(19, spend=out[6])326self.send_blocks([b19], success=False, reject_reason='bad-txns-inputs-missingorspent', reconnect=True)328# Attempt to spend a coinbase at depth too low329# genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)330# \-> b12 (3) -> b13 (4) -> b15 (5) -> b20 (7)331# \-> b3 (1) -> b4 (2)332self.log.info("Reject a block spending an immature coinbase.")333self.move_tip(15)334b20 = self.next_block(20, spend=out[7])335self.send_blocks([b20], success=False, reject_reason='bad-txns-premature-spend-of-coinbase', reconnect=True)337# Attempt to spend a coinbase at depth too low (on a fork this time)338# genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)339# \-> b12 (3) -> b13 (4) -> b15 (5)340# \-> b21 (6) -> b22 (5)341# \-> b3 (1) -> b4 (2)342self.log.info("Reject a block spending an immature coinbase (on a forked chain)")343self.move_tip(13)344b21 = self.next_block(21, spend=out[6])345self.send_blocks([b21], False)347b22 = self.next_block(22, spend=out[5])348self.send_blocks([b22], success=False, reject_reason='bad-txns-premature-spend-of-coinbase', reconnect=True)350# Create a block on either side of MAX_BLOCK_WEIGHT and make sure its accepted/rejected351# genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)352# \-> b12 (3) -> b13 (4) -> b15 (5) -> b23 (6)353# \-> b24 (6) -> b25 (7)354# \-> b3 (1) -> b4 (2)355self.log.info("Accept a block of weight MAX_BLOCK_WEIGHT")356self.move_tip(15)357b23 = self.next_block(23, spend=out[6])358tx = CTransaction()359script_length = (MAX_BLOCK_WEIGHT - b23.get_weight() - 276) // 4360script_output = CScript([b'\x00' * script_length])361tx.vout.append(CTxOut(0, script_output))362tx.vin.append(CTxIn(COutPoint(b23.vtx[1].txid_int, 0)))363b23 = self.update_block(23, [tx])364# Make sure the math above worked out to produce a max-weighted block365assert_equal(b23.get_weight(), MAX_BLOCK_WEIGHT)366self.send_blocks([b23], True)367self.save_spendable_output()369self.log.info("Reject a block of weight MAX_BLOCK_WEIGHT + 4")370self.move_tip(15)371b24 = self.next_block(24, spend=out[6])372script_length = (MAX_BLOCK_WEIGHT - b24.get_weight() - 276) // 4373script_output = CScript([b'\x00' * (script_length + 1)])374tx.vout = [CTxOut(0, script_output)]375b24 = self.update_block(24, [tx])376assert_equal(b24.get_weight(), MAX_BLOCK_WEIGHT + 1 * 4)377self.send_blocks([b24], success=False, reject_reason='bad-blk-length', reconnect=True)379b25 = self.next_block(25, spend=out[7])380self.send_blocks([b25], False)382# Create blocks with a coinbase input script size out of range383# genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)384# \-> b12 (3) -> b13 (4) -> b15 (5) -> b23 (6) -> b30 (7)385# \-> ... (6) -> ... (7)386# \-> b3 (1) -> b4 (2)387self.log.info("Reject a block with coinbase input script size out of range")388self.move_tip(15)389b26 = self.next_block(26, spend=out[6])390b26.vtx[0].vin[0].scriptSig = b'\x00'391# update_block causes the merkle root to get updated, even with no new392# transactions, and updates the required state.393b26 = self.update_block(26, [])394self.send_blocks([b26], success=False, reject_reason='bad-cb-length', reconnect=True)396# Extend the b26 chain to make sure bitcoind isn't accepting b26397b27 = self.next_block(27, spend=out[7])398self.send_blocks([b27], False)400# Now try a too-large-coinbase script401self.move_tip(15)402b28 = self.next_block(28, spend=out[6])403b28.vtx[0].vin[0].scriptSig = b'\x00' * 101404b28 = self.update_block(28, [])405self.send_blocks([b28], success=False, reject_reason='bad-cb-length', reconnect=True)407# Extend the b28 chain to make sure bitcoind isn't accepting b28408b29 = self.next_block(29, spend=out[7])409self.send_blocks([b29], False)411# b30 has a max-sized coinbase scriptSig.412self.move_tip(23)413b30 = self.next_block(30)414b30.vtx[0].vin[0].scriptSig = bytes(b30.vtx[0].vin[0].scriptSig) # Convert CScript to raw bytes415b30.vtx[0].vin[0].scriptSig += b'\x00' * (100 - len(b30.vtx[0].vin[0].scriptSig)) # Fill with 0s416assert_equal(len(b30.vtx[0].vin[0].scriptSig), 100)417b30 = self.update_block(30, [])418self.send_blocks([b30], True)419self.save_spendable_output()421# b31 - b35 - check sigops of OP_CHECKMULTISIG / OP_CHECKMULTISIGVERIFY / OP_CHECKSIGVERIFY422#423# genesis -> ... -> b30 (7) -> b31 (8) -> b33 (9) -> b35 (10)424# \-> b36 (11)425# \-> b34 (10)426# \-> b32 (9)427#429# MULTISIG: each op code counts as 20 sigops. To create the edge case, pack another 19 sigops at the end.430self.log.info("Accept a block with the max number of OP_CHECKMULTISIG sigops")431lots_of_multisigs = CScript([OP_CHECKMULTISIG] * ((MAX_BLOCK_SIGOPS - 1) // 20) + [OP_CHECKSIG] * 19)432b31 = self.next_block(31, spend=out[8], script=lots_of_multisigs)433assert_equal(get_legacy_sigopcount_block(b31), MAX_BLOCK_SIGOPS)434self.send_blocks([b31], True)435self.save_spendable_output()437# this goes over the limit because the coinbase has one sigop438self.log.info("Reject a block with too many OP_CHECKMULTISIG sigops")439too_many_multisigs = CScript([OP_CHECKMULTISIG] * (MAX_BLOCK_SIGOPS // 20))440b32 = self.next_block(32, spend=out[9], script=too_many_multisigs)441assert_equal(get_legacy_sigopcount_block(b32), MAX_BLOCK_SIGOPS + 1)442self.send_blocks([b32], success=False, reject_reason='bad-blk-sigops', reconnect=True)444# CHECKMULTISIGVERIFY445self.log.info("Accept a block with the max number of OP_CHECKMULTISIGVERIFY sigops")446self.move_tip(31)447lots_of_multisigs = CScript([OP_CHECKMULTISIGVERIFY] * ((MAX_BLOCK_SIGOPS - 1) // 20) + [OP_CHECKSIG] * 19)448b33 = self.next_block(33, spend=out[9], script=lots_of_multisigs)449self.send_blocks([b33], True)450self.save_spendable_output()452self.log.info("Reject a block with too many OP_CHECKMULTISIGVERIFY sigops")453too_many_multisigs = CScript([OP_CHECKMULTISIGVERIFY] * (MAX_BLOCK_SIGOPS // 20))454b34 = self.next_block(34, spend=out[10], script=too_many_multisigs)455self.send_blocks([b34], success=False, reject_reason='bad-blk-sigops', reconnect=True)457# CHECKSIGVERIFY458self.log.info("Accept a block with the max number of OP_CHECKSIGVERIFY sigops")459self.move_tip(33)460lots_of_checksigs = CScript([OP_CHECKSIGVERIFY] * (MAX_BLOCK_SIGOPS - 1))461b35 = self.next_block(35, spend=out[10], script=lots_of_checksigs)462self.send_blocks([b35], True)463self.save_spendable_output()465self.log.info("Reject a block with too many OP_CHECKSIGVERIFY sigops")466too_many_checksigs = CScript([OP_CHECKSIGVERIFY] * (MAX_BLOCK_SIGOPS))467b36 = self.next_block(36, spend=out[11], script=too_many_checksigs)468self.send_blocks([b36], success=False, reject_reason='bad-blk-sigops', reconnect=True)470# Check spending of a transaction in a block which failed to connect471#472# b6 (3)473# b12 (3) -> b13 (4) -> b15 (5) -> b23 (6) -> b30 (7) -> b31 (8) -> b33 (9) -> b35 (10)474# \-> b37 (11)475# \-> b38 (11/37)476#478# save 37's spendable output, but then double-spend out11 to invalidate the block479self.log.info("Reject a block spending transaction from a block which failed to connect")480self.move_tip(35)481b37 = self.next_block(37, spend=out[11])482txout_b37 = b37.vtx[1]483tx = self.create_and_sign_transaction(out[11], 0)484b37 = self.update_block(37, [tx])485self.send_blocks([b37], success=False, reject_reason='bad-txns-inputs-missingorspent', reconnect=True)487# attempt to spend b37's first non-coinbase tx, at which point b37 was still considered valid488self.move_tip(35)489b38 = self.next_block(38, spend=txout_b37)490self.send_blocks([b38], success=False, reject_reason='bad-txns-inputs-missingorspent', reconnect=True)492# Check P2SH SigOp counting493#494#495# 13 (4) -> b15 (5) -> b23 (6) -> b30 (7) -> b31 (8) -> b33 (9) -> b35 (10) -> b39 (11) -> b41 (12)496# \-> b40 (12)497#498# b39 - create some P2SH outputs that will require 6 sigops to spend:499#500# redeem_script = COINBASE_PUBKEY, (OP_2DUP+OP_CHECKSIGVERIFY) * 5, OP_CHECKSIG
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.