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.
1001BOOST_CHECK(bad_merkle_block.Check(consensus_params, BlockCheckFlags::BASE, state));1002BOOST_CHECK(state.GetValidationMode() == ValidationMode::VALID);1004auto bad_pow_block_data = raw_block;1005bad_pow_block_data[NBITS_OFFSET + 3] = std::byte{0x1c};1006Block bad_pow_block{bad_pow_block_data};1008BOOST_CHECK(!bad_pow_block.Check(consensus_params, BlockCheckFlags::POW, state));1009BOOST_CHECK(state.GetValidationMode() == ValidationMode::INVALID);1010BOOST_CHECK(state.GetBlockValidationResult() == BlockValidationResult::INVALID_HEADER);1012BOOST_CHECK(bad_pow_block.Check(consensus_params, BlockCheckFlags::MERKLE, state));1013BOOST_CHECK(state.GetValidationMode() == ValidationMode::VALID);1015auto bad_base_block_data = raw_block;1016bad_base_block_data[COINBASE_PREVOUT_N_OFFSET] = std::byte{0x00};1017Block bad_base_block{bad_base_block_data};1019BOOST_CHECK(!bad_base_block.Check(consensus_params, BlockCheckFlags::BASE, state));1020BOOST_CHECK(state.GetValidationMode() == ValidationMode::INVALID);1021BOOST_CHECK(state.GetBlockValidationResult() == BlockValidationResult::CONSENSUS);1023// Test with invalid truncated block data.1024auto truncated_block_data = hex_string_to_byte_vec("010000006fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000982051fd1e4ba744bbbe680e1fee14677ba1a3c3540bf7b1cdb606e857233e0e61bc6649ffff001d01e36299");1025BOOST_CHECK_EXCEPTION(Block{truncated_block_data}, std::runtime_error,1026HasReason{"failed to instantiate btck object"});1027}1029BOOST_AUTO_TEST_CASE(btck_chainman_mainnet_tests)1030{1031auto test_directory{TestDirectory{"mainnet_test_bitcoin_kernel"}};1032chainman_mainnet_validation_test(test_directory);1033chainman_reindex_test(test_directory);1034chainman_reindex_chainstate_test(test_directory);1035}1037BOOST_AUTO_TEST_CASE(btck_block_hash_tests)1038{1039std::array<std::byte, 32> test_hash;1040std::array<std::byte, 32> test_hash_2;1041for (int i = 0; i < 32; ++i) {1042test_hash[i] = static_cast<std::byte>(i);1043test_hash_2[i] = static_cast<std::byte>(i + 1);1044}1045BlockHash block_hash{test_hash};1046BlockHash block_hash_2{test_hash_2};1047BOOST_CHECK(block_hash != block_hash_2);1048BOOST_CHECK(block_hash == block_hash);1049CheckHandle(block_hash, block_hash_2);1050}1052BOOST_AUTO_TEST_CASE(btck_block_tree_entry_tests)1053{1054auto test_directory{TestDirectory{"block_tree_entry_test_bitcoin_kernel"}};1055auto notifications{std::make_shared<TestKernelNotifications>()};1056auto context{create_context(notifications, ChainType::REGTEST)};1057auto chainman{create_chainman(1058test_directory,1059/*reindex=*/false,1060/*wipe_chainstate=*/false,1061/*block_tree_db_in_memory=*/true,1062/*chainstate_db_in_memory=*/true,1063context)};1065// Process a couple of blocks1066for (size_t i{0}; i < 3; i++) {1067Block block{hex_string_to_byte_vec(REGTEST_BLOCK_DATA[i])};1068bool new_block{false};1069chainman->ProcessBlock(block, &new_block);1070BOOST_CHECK(new_block);1071}1073auto chain{chainman->GetChain()};1074auto entry_0{chain.GetByHeight(0)};1075auto entry_1{chain.GetByHeight(1)};1076auto entry_2{chain.GetByHeight(2)};1078// Test inequality1079BOOST_CHECK(entry_0 != entry_1);1080BOOST_CHECK(entry_1 != entry_2);1081BOOST_CHECK(entry_0 != entry_2);1083// Test equality with same entry1084BOOST_CHECK(entry_0 == chain.GetByHeight(0));1085BOOST_CHECK(entry_0 == BlockTreeEntry{entry_0});1086BOOST_CHECK(entry_1 == entry_1);1088// Test GetPrevious1089auto prev{entry_1.GetPrevious()};1090BOOST_CHECK(prev.has_value());1091BOOST_CHECK(prev.value() == entry_0);1093// Test GetAncestor1094BOOST_CHECK(entry_2.GetAncestor(2) == entry_2);1095BOOST_CHECK(entry_2.GetAncestor(1) == entry_1);1096BOOST_CHECK(entry_2.GetAncestor(0) == entry_0);1097}1099BOOST_AUTO_TEST_CASE(btck_chainman_in_memory_tests)1100{1101auto in_memory_test_directory{TestDirectory{"in-memory_test_bitcoin_kernel"}};1103auto notifications{std::make_shared<TestKernelNotifications>()};1104auto context{create_context(notifications, ChainType::REGTEST)};1105auto chainman{create_chainman(1106in_memory_test_directory, /*reindex=*/false, /*wipe_chainstate=*/false,1107/*block_tree_db_in_memory=*/true, /*chainstate_db_in_memory=*/true, context)};1109for (auto& raw_block : REGTEST_BLOCK_DATA) {1110Block block{hex_string_to_byte_vec(raw_block)};1111bool new_block{false};1112chainman->ProcessBlock(block, &new_block);1113BOOST_CHECK(new_block);1114}1116BOOST_CHECK(fs::exists(in_memory_test_directory.m_directory / "blocks"));1117BOOST_CHECK(!fs::exists(in_memory_test_directory.m_directory / "blocks" / "index"));1118BOOST_CHECK(!fs::exists(in_memory_test_directory.m_directory / "chainstate"));1120BOOST_CHECK(context.interrupt());1121}1123BOOST_AUTO_TEST_CASE(btck_chainman_regtest_tests)1124{1125auto test_directory{TestDirectory{"regtest_test_bitcoin_kernel"}};1127auto notifications{std::make_shared<TestKernelNotifications>()};1128auto context{create_context(notifications, ChainType::REGTEST)};1130{1131auto chainman{create_chainman(1132test_directory, /*reindex=*/false, /*wipe_chainstate=*/false,1133/*block_tree_db_in_memory=*/false, /*chainstate_db_in_memory=*/false, context)};1134for (const auto& data : REGTEST_BLOCK_DATA) {1135Block block{hex_string_to_byte_vec(data)};1136BlockHeader header = block.GetHeader();1137BlockValidationState state = chainman->ProcessBlockHeader(header);1138BOOST_CHECK(state.GetValidationMode() == ValidationMode::VALID);1139BOOST_CHECK(state.GetBlockValidationResult() == BlockValidationResult::UNSET);1140BlockTreeEntry entry{*chainman->GetBlockTreeEntry(header.Hash())};1141BOOST_CHECK(!chainman->GetChain().Contains(entry));1142BlockTreeEntry best_entry{chainman->GetBestEntry()};1143BlockHash hash{entry.GetHash()};1144BOOST_CHECK(hash == best_entry.GetHeader().Hash());1145}1146}1148// Validate 206 regtest blocks in total.1149// Stop halfway to check that it is possible to continue validating starting1150// from prior state.1151const size_t mid{REGTEST_BLOCK_DATA.size() / 2};1153{1154auto chainman{create_chainman(1155test_directory, /*reindex=*/false, /*wipe_chainstate=*/false,1156/*block_tree_db_in_memory=*/false, /*chainstate_db_in_memory=*/false, context)};1157for (size_t i{0}; i < mid; i++) {1158Block block{hex_string_to_byte_vec(REGTEST_BLOCK_DATA[i])};1159bool new_block{false};1160BOOST_CHECK(chainman->ProcessBlock(block, &new_block));1161BOOST_CHECK(new_block);1162}1163}1165auto chainman{create_chainman(1166test_directory, /*reindex=*/false, /*wipe_chainstate=*/false,1167/*block_tree_db_in_memory=*/false, /*chainstate_db_in_memory=*/false, context)};1169for (size_t i{mid}; i < REGTEST_BLOCK_DATA.size(); i++) {1170Block block{hex_string_to_byte_vec(REGTEST_BLOCK_DATA[i])};1171bool new_block{false};1172BOOST_CHECK(chainman->ProcessBlock(block, &new_block));1173BOOST_CHECK(new_block);1174}1176auto chain = chainman->GetChain();1177auto tip = chain.Entries().back();1178auto read_block = chainman->ReadBlock(tip).value();1179check_equal(read_block.ToBytes(), hex_string_to_byte_vec(REGTEST_BLOCK_DATA[REGTEST_BLOCK_DATA.size() - 1]));1181auto tip_2 = tip.GetPrevious().value();1182auto read_block_2 = chainman->ReadBlock(tip_2).value();1183check_equal(read_block_2.ToBytes(), hex_string_to_byte_vec(REGTEST_BLOCK_DATA[REGTEST_BLOCK_DATA.size() - 2]));1185Txid txid = read_block.Transactions()[0].Txid();1186Txid txid_2 = read_block_2.Transactions()[0].Txid();1187BOOST_CHECK(txid != txid_2);1188BOOST_CHECK(txid == txid);1189CheckHandle(txid, txid_2);1191auto find_transaction = [&chainman](const TxidView& target_txid) -> std::optional<Transaction> {1192auto chain = chainman->GetChain();1193for (const auto block_tree_entry : chain.Entries()) {1194auto block{chainman->ReadBlock(block_tree_entry)};1195for (const TransactionView transaction : block->Transactions()) {1196if (transaction.Txid() == target_txid) {1197return Transaction{transaction};1198}1199}1200}1201return std::nullopt;1202};1204for (const auto block_tree_entry : chain.Entries()) {1205auto block{chainman->ReadBlock(block_tree_entry)};1206for (const auto transaction : block->Transactions()) {1207std::vector<TransactionInput> inputs;1208std::vector<TransactionOutput> spent_outputs;1209for (const auto input : transaction.Inputs()) {1210OutPointView point = input.OutPoint();1211if (point.index() == std::numeric_limits<uint32_t>::max()) {1212continue;1213}1214inputs.emplace_back(input);1215BOOST_CHECK(point.Txid() != transaction.Txid());1216std::optional<Transaction> tx = find_transaction(point.Txid());1217BOOST_CHECK(tx.has_value());1218BOOST_CHECK(point.Txid() == tx->Txid());1219spent_outputs.emplace_back(tx->GetOutput(point.index()));1220}1221BOOST_CHECK(inputs.size() == spent_outputs.size());1222ScriptVerifyStatus status = ScriptVerifyStatus::OK;1223const PrecomputedTransactionData precomputed_txdata{transaction, spent_outputs};1224for (size_t i{0}; i < inputs.size(); ++i) {1225BOOST_CHECK(spent_outputs[i].GetScriptPubkey().Verify(spent_outputs[i].Amount(), transaction, &precomputed_txdata, i, ScriptVerificationFlags::ALL, status));1226}1227}1228}1230// Read spent outputs for current tip and its previous block1231BlockSpentOutputs block_spent_outputs{chainman->ReadBlockSpentOutputs(tip)};1232BlockSpentOutputs block_spent_outputs_prev{chainman->ReadBlockSpentOutputs(*tip.GetPrevious())};1233CheckHandle(block_spent_outputs, block_spent_outputs_prev);1234CheckRange(block_spent_outputs_prev.TxsSpentOutputs(), block_spent_outputs_prev.Count());1235BOOST_CHECK_EQUAL(block_spent_outputs.Count(), 1);1237// Get transaction spent outputs from the last transaction in the two blocks1238TransactionSpentOutputsView transaction_spent_outputs{block_spent_outputs.GetTxSpentOutputs(block_spent_outputs.Count() - 1)};1239TransactionSpentOutputs owned_transaction_spent_outputs{transaction_spent_outputs};1240TransactionSpentOutputs owned_transaction_spent_outputs_prev{block_spent_outputs_prev.GetTxSpentOutputs(block_spent_outputs_prev.Count() - 1)};1241CheckHandle(owned_transaction_spent_outputs, owned_transaction_spent_outputs_prev);1242CheckRange(transaction_spent_outputs.Coins(), transaction_spent_outputs.Count());1244// Get the last coin from the transaction spent outputs1245CoinView coin{transaction_spent_outputs.GetCoin(transaction_spent_outputs.Count() - 1)};1246BOOST_CHECK(!coin.IsCoinbase());1247Coin owned_coin{coin};1248Coin owned_coin_prev{owned_transaction_spent_outputs_prev.GetCoin(owned_transaction_spent_outputs_prev.Count() - 1)};1249CheckHandle(owned_coin, owned_coin_prev);
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.