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.
1001self.move_tip(65)1002self.next_block(67)1003tx1 = self.create_and_sign_transaction(out[20], out[20].vout[0].nValue)1004tx2 = self.create_and_sign_transaction(tx1, 1)1005tx3 = self.create_and_sign_transaction(tx1, 2)1006b67 = self.update_block(67, [tx1, tx2, tx3])1007self.send_blocks([b67], success=False, reject_reason='bad-txns-inputs-missingorspent', reconnect=True)1009# More tests of block subsidy1010#1011# -> b64 (18) -> b65 (19) -> b69 (20)1012# \-> b68 (20)1013#1014# b68 - coinbase with an extra 10 satoshis,1015# creates a tx that has 9 satoshis from out[20] go to fees1016# this fails because the coinbase is trying to claim 1 satoshi too much in fees1017#1018# b69 - coinbase with extra 10 satoshis, and a tx that gives a 10 satoshi fee1019# this succeeds1020#1021self.log.info("Reject a block trying to claim too much subsidy in the coinbase transaction")1022self.move_tip(65)1023self.next_block(68, additional_coinbase_value=10)1024tx = self.create_and_sign_transaction(out[20], out[20].vout[0].nValue - 9)1025b68 = self.update_block(68, [tx])1026self.send_blocks([b68], success=False, reject_reason='bad-cb-amount', reconnect=True)1028self.log.info("Accept a block claiming the correct subsidy in the coinbase transaction")1029self.move_tip(65)1030b69 = self.next_block(69, additional_coinbase_value=10)1031tx = self.create_and_sign_transaction(out[20], out[20].vout[0].nValue - 10)1032self.update_block(69, [tx])1033self.send_blocks([b69], True)1034self.save_spendable_output()1036# Test spending the outpoint of a non-existent transaction1037#1038# -> b65 (19) -> b69 (20)1039# \-> b70 (21)1040#1041self.log.info("Reject a block containing a transaction spending from a non-existent input")1042self.move_tip(69)1043self.next_block(70, spend=out[21])1044bogus_txid_int = uint256_from_str(b"23c70ed7c0506e9178fc1a987f40a33946d4ad4c962b5ae3a52546da53af0c5c")1045tx = CTransaction()1046tx.vin.append(CTxIn(COutPoint(bogus_txid_int, 0), b"", SEQUENCE_FINAL))1047tx.vout.append(CTxOut(1, b""))1048b70 = self.update_block(70, [tx])1049self.send_blocks([b70], success=False, reject_reason='bad-txns-inputs-missingorspent', reconnect=True)1051# Test accepting an invalid block which has the same hash as a valid one (via merkle tree tricks)1052#1053# -> b65 (19) -> b69 (20) -> b72 (21)1054# \-> b71 (21)1055#1056# b72 is a good block.1057# b71 is a copy of 72, but re-adds one of its transactions. However, it has the same hash as b72.1058self.log.info("Reject a block containing a duplicate transaction but with the same Merkle root (Merkle tree malleability")1059self.move_tip(69)1060self.next_block(72)1061tx1 = self.create_and_sign_transaction(out[21], 2)1062tx2 = self.create_and_sign_transaction(tx1, 1)1063b72 = self.update_block(72, [tx1, tx2]) # now tip is 721064b71 = copy.deepcopy(b72)1065b71.vtx.append(tx2) # add duplicate tx21066self.block_heights[b71.hash_int] = self.block_heights[b69.hash_int] + 1 # b71 builds off b691067self.blocks[71] = b711069assert_equal(len(b71.vtx), 4)1070assert_equal(len(b72.vtx), 3)1071assert_equal(b72.hash_int, b71.hash_int)1073self.move_tip(71)1074self.send_blocks([b71], success=False, reject_reason='bad-txns-duplicate', reconnect=True)1076self.move_tip(72)1077self.send_blocks([b72], True)1078self.save_spendable_output()1080# Test some invalid scripts and MAX_BLOCK_SIGOPS1081#1082# -> b69 (20) -> b72 (21)1083# \-> b** (22)1084#1086# b73 - tx with excessive sigops that are placed after an excessively large script element.1087# The purpose of the test is to make sure those sigops are counted.1088#1089# script is a bytearray of size 20,5261090#1091# bytearray[0-19,998] : OP_CHECKSIG1092# bytearray[19,999] : OP_PUSHDATA41093# bytearray[20,000-20,003]: 521 (max_script_element_size+1, in little-endian format)1094# bytearray[20,004-20,525]: unread data (script_element)1095# bytearray[20,526] : OP_CHECKSIG (this puts us over the limit)1096self.log.info("Reject a block containing too many sigops after a large script element")1097self.move_tip(72)1098self.next_block(73)1099size = MAX_BLOCK_SIGOPS - 1 + MAX_SCRIPT_ELEMENT_SIZE + 1 + 5 + 11100a = bytearray([OP_CHECKSIG] * size)1101a[MAX_BLOCK_SIGOPS - 1] = int("4e", 16) # OP_PUSHDATA41103element_size = MAX_SCRIPT_ELEMENT_SIZE + 11104a[MAX_BLOCK_SIGOPS] = element_size % 2561105a[MAX_BLOCK_SIGOPS + 1] = element_size // 2561106a[MAX_BLOCK_SIGOPS + 2] = 01107a[MAX_BLOCK_SIGOPS + 3] = 01109tx = self.create_and_sign_transaction(out[22], 1, CScript(a))1110b73 = self.update_block(73, [tx])1111assert_equal(get_legacy_sigopcount_block(b73), MAX_BLOCK_SIGOPS + 1)1112self.send_blocks([b73], success=False, reject_reason='bad-blk-sigops', reconnect=True)1114# b74/75 - if we push an invalid script element, all previous sigops are counted,1115# but sigops after the element are not counted.1116#1117# The invalid script element is that the push_data indicates that1118# there will be a large amount of data (0xffffff bytes), but we only1119# provide a much smaller number. These bytes are CHECKSIGS so they would1120# cause b75 to fail for excessive sigops, if those bytes were counted.1121#1122# b74 fails because we put MAX_BLOCK_SIGOPS+1 before the element1123# b75 succeeds because we put MAX_BLOCK_SIGOPS before the element1124self.log.info("Check sigops are counted correctly after an invalid script element")1125self.move_tip(72)1126self.next_block(74)1127size = MAX_BLOCK_SIGOPS - 1 + MAX_SCRIPT_ELEMENT_SIZE + 42 # total = 20,5611128a = bytearray([OP_CHECKSIG] * size)1129a[MAX_BLOCK_SIGOPS] = 0x4e1130a[MAX_BLOCK_SIGOPS + 1] = 0xfe1131a[MAX_BLOCK_SIGOPS + 2] = 0xff1132a[MAX_BLOCK_SIGOPS + 3] = 0xff1133a[MAX_BLOCK_SIGOPS + 4] = 0xff1134tx = self.create_and_sign_transaction(out[22], 1, CScript(a))1135b74 = self.update_block(74, [tx])1136self.send_blocks([b74], success=False, reject_reason='bad-blk-sigops', reconnect=True)1138self.move_tip(72)1139self.next_block(75)1140size = MAX_BLOCK_SIGOPS - 1 + MAX_SCRIPT_ELEMENT_SIZE + 421141a = bytearray([OP_CHECKSIG] * size)1142a[MAX_BLOCK_SIGOPS - 1] = 0x4e1143a[MAX_BLOCK_SIGOPS] = 0xff1144a[MAX_BLOCK_SIGOPS + 1] = 0xff1145a[MAX_BLOCK_SIGOPS + 2] = 0xff1146a[MAX_BLOCK_SIGOPS + 3] = 0xff1147tx = self.create_and_sign_transaction(out[22], 1, CScript(a))1148b75 = self.update_block(75, [tx])1149self.send_blocks([b75], True)1150self.save_spendable_output()1152# Check that if we push an element filled with CHECKSIGs, they are not counted1153self.move_tip(75)1154self.next_block(76)1155size = MAX_BLOCK_SIGOPS - 1 + MAX_SCRIPT_ELEMENT_SIZE + 1 + 51156a = bytearray([OP_CHECKSIG] * size)1157a[MAX_BLOCK_SIGOPS - 1] = 0x4e # PUSHDATA4, but leave the following bytes as just checksigs1158tx = self.create_and_sign_transaction(out[23], 1, CScript(a))1159b76 = self.update_block(76, [tx])1160self.send_blocks([b76], True)1161self.save_spendable_output()1163# Test transaction resurrection1164#1165# -> b77 (24) -> b78 (25) -> b79 (26)1166# \-> b80 (25) -> b81 (26) -> b82 (27)1167#1168# b78 creates a tx, which is spent in b79. After b82, both should be in mempool1169#1170# The resurrected transactions must pass the node's mempool policy, so create1171# and spend standard outputs (P2PK using the coinbase pubkey to keep it simple).1172self.log.info("Test transaction resurrection during a re-org")1173standard_output_script = key_to_p2pk_script(self.coinbase_pubkey)1174self.move_tip(76)1175self.next_block(77)1176tx77 = self.create_and_sign_transaction(out[24], 10 * COIN, standard_output_script)1177b77 = self.update_block(77, [tx77])1178self.send_blocks([b77], True)1179self.save_spendable_output()1181self.next_block(78)1182tx78 = self.create_and_sign_transaction(tx77, 9 * COIN, standard_output_script)1183b78 = self.update_block(78, [tx78])1184self.send_blocks([b78], True)1186self.next_block(79)1187tx79 = self.create_and_sign_transaction(tx78, 8 * COIN, standard_output_script)1188b79 = self.update_block(79, [tx79])1189self.send_blocks([b79], True)1191# mempool should be empty1192assert_equal(len(self.nodes[0].getrawmempool()), 0)1194self.move_tip(77)1195b80 = self.next_block(80, spend=out[25])1196self.send_blocks([b80], False, force_send=True)1197self.save_spendable_output()1199b81 = self.next_block(81, spend=out[26])1200self.send_blocks([b81], False, force_send=True) # other chain is same length1201self.save_spendable_output()1203b82 = self.next_block(82, spend=out[27])1204self.send_blocks([b82], True) # now this chain is longer, triggers re-org1205self.save_spendable_output()1207# now check that tx78 and tx79 have been put back into the peer's mempool1208mempool = self.nodes[0].getrawmempool()1209assert_equal(len(mempool), 2)1210assert tx78.txid_hex in mempool1211assert tx79.txid_hex in mempool1213# Test invalid opcodes in dead execution paths.1214#1215# -> b81 (26) -> b82 (27) -> b83 (28)1216#1217self.log.info("Accept a block with invalid opcodes in dead execution paths")1218self.next_block(83)1219op_codes = [OP_IF, OP_INVALIDOPCODE, OP_ELSE, OP_TRUE, OP_ENDIF]1220script = CScript(op_codes)1221tx1 = self.create_and_sign_transaction(out[28], out[28].vout[0].nValue, script)1223tx2 = self.create_and_sign_transaction(tx1, 0, CScript([OP_TRUE]))1224tx2.vin[0].scriptSig = CScript([OP_FALSE])1226b83 = self.update_block(83, [tx1, tx2])1227self.send_blocks([b83], True)1228self.save_spendable_output()1230# Reorg on/off blocks that have OP_RETURN in them (and try to spend them)1231#1232# -> b81 (26) -> b82 (27) -> b83 (28) -> b84 (29) -> b87 (30) -> b88 (31)1233# \-> b85 (29) -> b86 (30) \-> b89a (32)1234#1235self.log.info("Test re-orging blocks with OP_RETURN in them")1236self.next_block(84)1237tx1 = self.create_tx(out[29], 0, 0, CScript([OP_RETURN]))1238tx1.vout.append(CTxOut(0, CScript([OP_TRUE])))1239tx1.vout.append(CTxOut(0, CScript([OP_TRUE])))1240tx1.vout.append(CTxOut(0, CScript([OP_TRUE])))1241tx1.vout.append(CTxOut(0, CScript([OP_TRUE])))1242self.sign_tx(tx1, out[29])1243tx2 = self.create_tx(tx1, 1, 0, CScript([OP_RETURN]))1244tx2.vout.append(CTxOut(0, CScript([OP_RETURN])))1245tx3 = self.create_tx(tx1, 2, 0, CScript([OP_RETURN]))1246tx3.vout.append(CTxOut(0, CScript([OP_TRUE])))1247tx4 = self.create_tx(tx1, 3, 0, CScript([OP_TRUE]))1248tx4.vout.append(CTxOut(0, CScript([OP_RETURN])))1249tx5 = self.create_tx(tx1, 4, 0, CScript([OP_RETURN]))
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.