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.
1251// Validate coin properties1252TransactionOutputView output = coin.GetOutput();1253uint32_t coin_height = coin.GetConfirmationHeight();1254BOOST_CHECK_EQUAL(coin_height, 143);1255BOOST_CHECK_EQUAL(output.Amount(), 3949990974);1257// Test script pubkey serialization1258auto script_pubkey = output.GetScriptPubkey();1259auto script_pubkey_bytes{script_pubkey.ToBytes()};1260BOOST_CHECK_EQUAL(script_pubkey_bytes.size(), 34);1261auto round_trip_script_pubkey{ScriptPubkey(script_pubkey_bytes)};1262BOOST_CHECK_EQUAL(round_trip_script_pubkey.ToBytes().size(), 34);1264for (const auto tx_spent_outputs : block_spent_outputs.TxsSpentOutputs()) {1265for (const auto coins : tx_spent_outputs.Coins()) {1266BOOST_CHECK_GT(coins.GetOutput().Amount(), 1);1267}1268}1270CheckRange(chain.Entries(), chain.CountEntries());1272for (const BlockTreeEntry entry : chain.Entries()) {1273std::optional<Block> block{chainman->ReadBlock(entry)};1274if (block) {1275for (const TransactionView transaction : block->Transactions()) {1276for (const TransactionOutputView output : transaction.Outputs()) {1277// skip data carrier outputs1278if ((unsigned char)output.GetScriptPubkey().ToBytes()[0] == 0x6a) {1279continue;1280}1281BOOST_CHECK_GT(output.Amount(), 1);1282}1283}1284}1285}1287int32_t count{0};1288for (const auto entry : chain.Entries()) {1289BOOST_CHECK_EQUAL(entry.GetHeight(), count);1290++count;1291}1292BOOST_CHECK_EQUAL(count, chain.CountEntries());1295fs::remove(test_directory.m_directory / "blocks" / "blk00000.dat");1296BOOST_CHECK(!chainman->ReadBlock(tip_2).has_value());1297fs::remove(test_directory.m_directory / "blocks" / "rev00000.dat");1298BOOST_CHECK_THROW(chainman->ReadBlockSpentOutputs(tip), std::runtime_error);1299}1301// -----------------------------------------------------------------------------1302// CheckTransaction tests1303//1304// Transaction hex below is copied from src/test/data/tx_invalid.json (entries1305// marked "BADTX") and tx_valid.json. CheckTransaction performs only basic context-free1306// consensus checks and can only produce two outcomes:1307// - VALID (ValidationMode::VALID, TxValidationResult::UNSET)1308// - INVALID (ValidationMode::INVALID, TxValidationResult::CONSENSUS)1309// Other TxValidationResult values are set by higher-level validation and are1310// not reachable through btck_transaction_check.1311// -----------------------------------------------------------------------------1312BOOST_AUTO_TEST_CASE(btck_transaction_check_tests)1313{1314using namespace btck;1316constexpr std::string_view valid_tx_hex{1317"01000000010001000000000000000000000000000000000000000000000000000000000000"1318"000000006a473044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b92"1319"4f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e9"1320"9e883e7a012103ba8c8b86dea131c22ab967e6dd99bdae8eff7a1f75a2c35f1f944109e3"1321"fe5e22ffffffff010000000000000000015100000000"};1322constexpr std::string_view no_outputs_tx_hex{1323"01000000010001000000000000000000000000000000000000000000000000000000000000"1324"000000006d483045022100f16703104aab4e4088317c862daec83440242411b039d14280e0"1325"3dd33b487ab802201318a7be236672c5c56083eb7a5a195bc57a40af7923ff8545016cd3b5"1326"71e2a601232103c40e5d339df3f30bf753e7e04450ae4ef76c9e45587d1d993bdc4cd06f06"1327"51c7acffffffff0000000000"};1329auto expect_valid = [](std::string_view hex) {1330Transaction tx{hex_string_to_byte_vec(hex)};1331TxValidationState st;1332BOOST_CHECK(CheckTransaction(tx, st));1333BOOST_CHECK(st.GetValidationMode() == ValidationMode::VALID);1334BOOST_CHECK(st.GetTxValidationResult() == TxValidationResult::UNSET);1335};1337auto expect_invalid = [](std::string_view hex) {1338Transaction tx{hex_string_to_byte_vec(hex)};1339TxValidationState st;1340BOOST_CHECK(!CheckTransaction(tx, st));1341BOOST_CHECK(st.GetValidationMode() == ValidationMode::INVALID);1342BOOST_CHECK(st.GetTxValidationResult() == TxValidationResult::CONSENSUS);1343};1345// Valid: simple 1-in 1-out transaction (from tx_valid.json)1346expect_valid(valid_tx_hex);1348// Valid coinbase with scriptSig size 2 (from tx_valid.json)1349expect_valid(1350"01000000010000000000000000000000000000000000000000000000000000000000000000"1351"ffffffff025151ffffffff010000000000000000015100000000");1353// No outputs (BADTX from tx_invalid.json)1354expect_invalid(no_outputs_tx_hex);1356{1357Transaction valid_tx{hex_string_to_byte_vec(valid_tx_hex)};1358Transaction invalid_tx{hex_string_to_byte_vec(no_outputs_tx_hex)};1359TxValidationState state;1361BOOST_CHECK(btck_transaction_check(valid_tx.get(), state.get()) == 1);1362BOOST_CHECK(state.GetValidationMode() == ValidationMode::VALID);1363BOOST_CHECK(state.GetTxValidationResult() == TxValidationResult::UNSET);1365BOOST_CHECK(btck_transaction_check(invalid_tx.get(), state.get()) == 0);1366BOOST_CHECK(state.GetValidationMode() == ValidationMode::INVALID);1367BOOST_CHECK(state.GetTxValidationResult() == TxValidationResult::CONSENSUS);1368}1370// Negative output (BADTX)1371expect_invalid(1372"01000000010001000000000000000000000000000000000000000000000000000000000000"1373"000000006d4830450220063222cbb128731fc09de0d7323746539166544d6c1df84d867cce"1374"a84bcc8903022100bf568e8552844de664cd41648a031554327aa8844af34b4f27397c65b9"1375"2c04de0123210243ec37dee0e2e053a9c976f43147e79bc7d9dc606ea51010af1ac80db6b0"1376"69e1acffffffff01ffffffffffffffff015100000000");1378// MAX_MONEY + 1 output (BADTX)1379expect_invalid(1380"01000000010001000000000000000000000000000000000000000000000000000000000000"1381"000000006e493046022100e1eadba00d9296c743cb6ecc703fd9ddc9b3cd12906176a226ae"1382"4c18d6b00796022100a71aef7d2874deff681ba6080f1b278bac7bb99c61b08a85f4311970"1383"ffe7f63f012321030c0588dc44d92bdcbf8e72093466766fdc265ead8db64517b0c542275b"1384"70fffbacffffffff010140075af0750700015100000000");1386// MAX_MONEY output + 1 output: sum exceeds MAX_MONEY (BADTX)1387expect_invalid(1388"01000000010001000000000000000000000000000000000000000000000000000000000000"1389"000000006d483045022027deccc14aa6668e78a8c9da3484fbcd4f9dcc9bb7d1b85146314b"1390"21b9ae4d86022100d0b43dece8cfb07348de0ca8bc5b86276fa88f7f2138381128b7c36ab2"1391"e42264012321029bb13463ddd5d2cc05da6e84e37536cb9525703cfd8f43afdb414988987a"1392"92f6acffffffff020040075af075070001510001000000000000015100000000");1394// Duplicate inputs (BADTX)1395expect_invalid(1396"01000000020001000000000000000000000000000000000000000000000000000000000000"1397"000000006c47304402204bb1197053d0d7799bf1b30cd503c44b58d6240cccbdc85b6fe76d"1398"087980208f02204beeed78200178ffc6c74237bb74b3f276bbb4098b5605d814304fe128bf"1399"1431012321039e8815e15952a7c3fada1905f8cf55419837133bd7756c0ef14fc8dfe50c0d"1400"eaacffffffff0001000000000000000000000000000000000000000000000000000000000000"1401"000000006c47304402202306489afef52a6f62e90bf750bbcdf40c06f5c6b138286e6b6b8617"1402"6bb9341802200dba98486ea68380f47ebb19a7df173b99e6bc9c681d6ccf3bde31465d1f16"1403"b3012321039e8815e15952a7c3fada1905f8cf55419837133bd7756c0ef14fc8dfe50c0dea"1404"acffffffff010000000000000000015100000000");1406// Coinbase with scriptSig size 1: too small (BADTX)1407expect_invalid(1408"01000000010000000000000000000000000000000000000000000000000000000000000000"1409"ffffffff0151ffffffff010000000000000000015100000000");1411// Coinbase with scriptSig size 101: too large (BADTX)1412expect_invalid(1413"01000000010000000000000000000000000000000000000000000000000000000000000000"1414"ffffffff6551515151515151515151515151515151515151515151515151515151515151515151"1415"515151515151515151515151515151515151515151515151515151515151515151515151515151"1416"51515151515151515151515151515151515151515151515151515151ffffffff01000000000000"1417"0000015100000000");1419// Null prevout in non-coinbase: two inputs, one is null (BADTX)1420expect_invalid(1421"01000000020000000000000000000000000000000000000000000000000000000000000000"1422"ffffffff00ffffffff000100000000000000000000000000000000000000000000000000000000"1423"00000000000000ffffffff010000000000000000015100000000");1424}1426class KernelMockTime1427{1428public:1429explicit KernelMockTime(std::chrono::seconds timestamp) { set(timestamp); }1430~KernelMockTime()1431{1432set_mock_time(std::chrono::seconds{0});1433}1435KernelMockTime(const KernelMockTime&) = delete;1436KernelMockTime& operator=(const KernelMockTime&) = delete;1438void set(std::chrono::seconds timestamp) { set_mock_time(timestamp); }1439};1441BOOST_AUTO_TEST_CASE(btck_set_mock_time_tests)1442{1443// Out-of-range timestamps throw1444BOOST_CHECK_EXCEPTION(set_mock_time(std::chrono::seconds{-1}), std::runtime_error, HasReason("timestamp out of range"));1445constexpr std::chrono::seconds max_time{std::numeric_limits<uint32_t>::max()};1446BOOST_CHECK_EXCEPTION(set_mock_time(max_time + std::chrono::seconds{1}), std::runtime_error, HasReason("timestamp out of range"));1448// Confirm the mock time actually takes effect by exercising the header future-time check1449auto test_directory{TestDirectory{"set_mock_time_test_bitcoin_kernel"}};1450auto notifications{std::make_shared<TestKernelNotifications>()};1451auto context{create_context(notifications, ChainType::REGTEST)};1452auto chainman{create_chainman(1453test_directory, /*reindex=*/false, /*wipe_chainstate=*/false,1454/*block_tree_db_in_memory=*/true, /*chainstate_db_in_memory=*/true, context)};1456Block block{hex_string_to_byte_vec(REGTEST_BLOCK_DATA[0])};1457BlockHeader header{block.GetHeader()};1458const std::chrono::seconds block_time{header.Timestamp()};1460// With the time set 3h before the header, the kernel must see the header as >2h in the future and reject it1461KernelMockTime mock_time{block_time - std::chrono::hours{3}};1462BlockValidationState future_state{chainman->ProcessBlockHeader(header)};1463BOOST_CHECK(future_state.GetValidationMode() == ValidationMode::INVALID);1464BOOST_CHECK(future_state.GetBlockValidationResult() == BlockValidationResult::TIME_FUTURE);1466// At the upper bound the header is far in the past and must be accepted; this also1467// confirms the future-time check's "now + 2h" computation doesn't overflow when now is at its max.1468mock_time.set(max_time);1469BlockValidationState ok_state{chainman->ProcessBlockHeader(header)};1470BOOST_CHECK(ok_state.GetValidationMode() == ValidationMode::VALID);1471BOOST_CHECK(ok_state.GetBlockValidationResult() == BlockValidationResult::UNSET);1472}
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.