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.
251BOOST_CHECK(spent_script_pubkey.Verify(2520,253spending_tx,254precomputed_txdata,255input_index,256VERIFY_ALL_PRE_SEGWIT,257status));258BOOST_CHECK(status == ScriptVerifyStatus::OK);259}261template <typename T>262concept HasToBytes = requires(T t) {263{ t.ToBytes() } -> std::convertible_to<std::span<const std::byte>>;264};266template <typename T>267void CheckHandle(T object, T distinct_object)268{269BOOST_CHECK(object.get() != nullptr);270BOOST_CHECK(distinct_object.get() != nullptr);271BOOST_CHECK(object.get() != distinct_object.get());273if constexpr (HasToBytes<T>) {274const auto object_bytes = object.ToBytes();275const auto distinct_bytes = distinct_object.ToBytes();276BOOST_CHECK(!std::ranges::equal(object_bytes, distinct_bytes));277}279// Copy constructor280T object2(distinct_object);281BOOST_CHECK_NE(distinct_object.get(), object2.get());282if constexpr (HasToBytes<T>) {283check_equal(distinct_object.ToBytes(), object2.ToBytes());284}286// Copy assignment287T object3{distinct_object};288object2 = object3;289BOOST_CHECK_NE(object3.get(), object2.get());290if constexpr (HasToBytes<T>) {291check_equal(object3.ToBytes(), object2.ToBytes());292}294// Move constructor295auto* original_ptr = object2.get();296T object4{std::move(object2)};297BOOST_CHECK_EQUAL(object4.get(), original_ptr);298BOOST_CHECK_EQUAL(object2.get(), nullptr); // NOLINT(bugprone-use-after-move)299if constexpr (HasToBytes<T>) {300check_equal(object4.ToBytes(), object3.ToBytes());301}303// Move assignment304original_ptr = object4.get();305object2 = std::move(object4);306BOOST_CHECK_EQUAL(object2.get(), original_ptr);307BOOST_CHECK_EQUAL(object4.get(), nullptr); // NOLINT(bugprone-use-after-move)308if constexpr (HasToBytes<T>) {309check_equal(object2.ToBytes(), object3.ToBytes());310}312// Self move-assignment must not destroy the held resource.313// Use a reference to avoid -Wself-move warnings.314original_ptr = object2.get();315auto& object2_ref = object2;316object2 = std::move(object2_ref);317BOOST_CHECK_EQUAL(object2.get(), original_ptr);318if constexpr (HasToBytes<T>) {319check_equal(object2.ToBytes(), object3.ToBytes());320}321}323template <typename RangeType>324requires std::ranges::random_access_range<RangeType>325void CheckRange(const RangeType& range, size_t expected_size)326{327using value_type = std::ranges::range_value_t<RangeType>;329BOOST_CHECK_EQUAL(range.size(), expected_size);330BOOST_REQUIRE(range.size() > 0); // Some checks below assume a non-empty range331BOOST_REQUIRE(!range.empty());333BOOST_CHECK(range.begin() != range.end());334BOOST_CHECK_EQUAL(std::distance(range.begin(), range.end()), static_cast<std::ptrdiff_t>(expected_size));335BOOST_CHECK(range.cbegin() == range.begin());336BOOST_CHECK(range.cend() == range.end());338for (size_t i = 0; i < range.size(); ++i) {339BOOST_CHECK_EQUAL(range[i].get(), (*(range.begin() + i)).get());340}342BOOST_CHECK_THROW(range.at(expected_size), std::out_of_range);344BOOST_CHECK_EQUAL(range.front().get(), range[0].get());345BOOST_CHECK_EQUAL(range.back().get(), range[expected_size - 1].get());347auto it = range.begin();348auto it_copy = it;349++it;350BOOST_CHECK(it != it_copy);351--it;352BOOST_CHECK(it == it_copy);353it = range.begin();354auto old_it = it++;355BOOST_CHECK(old_it == range.begin());356BOOST_CHECK(it == range.begin() + 1);357old_it = it--;358BOOST_CHECK(old_it == range.begin() + 1);359BOOST_CHECK(it == range.begin());361it = range.begin();362it += 2;363BOOST_CHECK(it == range.begin() + 2);364it -= 2;365BOOST_CHECK(it == range.begin());367BOOST_CHECK(range.begin() < range.end());368BOOST_CHECK(range.begin() <= range.end());369BOOST_CHECK(range.end() > range.begin());370BOOST_CHECK(range.end() >= range.begin());371BOOST_CHECK(range.begin() == range.begin());373BOOST_CHECK_EQUAL(range.begin()[0].get(), range[0].get());375size_t count = 0;376for (auto rit = range.end(); rit != range.begin();) {377--rit;378++count;379}380BOOST_CHECK_EQUAL(count, expected_size);382std::vector<value_type> collected;383for (const auto& elem : range) {384collected.push_back(elem);385}386BOOST_CHECK_EQUAL(collected.size(), expected_size);388BOOST_CHECK_EQUAL(std::ranges::size(range), expected_size);390it = range.begin();391auto it2 = 1 + it;392BOOST_CHECK(it2 == it + 1);393}395BOOST_AUTO_TEST_CASE(btck_transaction_tests)396{397auto tx_data{hex_string_to_byte_vec("02000000013f7cebd65c27431a90bba7f796914fe8cc2ddfc3f2cbd6f7e5f2fc854534da95000000006b483045022100de1ac3bcdfb0332207c4a91f3832bd2c2915840165f876ab47c5f8996b971c3602201c6c053d750fadde599e6f5c4e1963df0f01fc0d97815e8157e3d59fe09ca30d012103699b464d1d8bc9e47d4fb1cdaa89a1c5783d68363c4dbc4b524ed3d857148617feffffff02836d3c01000000001976a914fc25d6d5c94003bf5b0c7b640a248e2c637fcfb088ac7ada8202000000001976a914fbed3d9b11183209a57999d54d59f67c019e756c88ac6acb0700")};398auto tx{Transaction{tx_data}};399auto tx_data_2{hex_string_to_byte_vec("02000000000101904f4ee5c87d20090b642f116e458cd6693292ad9ece23e72f15fb6c05b956210500000000fdffffff02e2010000000000002251200839a723933b56560487ec4d67dda58f09bae518ffa7e148313c5696ac837d9f10060000000000002251205826bcdae7abfb1c468204170eab00d887b61ab143464a4a09e1450bdc59a3340140f26e7af574e647355830772946356c27e7bbc773c5293688890f58983499581be84de40be7311a14e6d6422605df086620e75adae84ff06b75ce5894de5e994a00000000")};400auto tx2{Transaction{tx_data_2}};401CheckHandle(tx, tx2);403auto invalid_data = hex_string_to_byte_vec("012300");404BOOST_CHECK_THROW(Transaction{invalid_data}, std::runtime_error);405auto empty_data = hex_string_to_byte_vec("");406BOOST_CHECK_THROW(Transaction{empty_data}, std::runtime_error);408BOOST_CHECK_EQUAL(tx.CountOutputs(), 2);409BOOST_CHECK_EQUAL(tx.CountInputs(), 1);410BOOST_CHECK_EQUAL(tx.GetLocktime(), 510826);411auto broken_tx_data{std::span<std::byte>{tx_data.begin(), tx_data.begin() + 10}};412BOOST_CHECK_THROW(Transaction{broken_tx_data}, std::runtime_error);413auto input{tx.GetInput(0)};414BOOST_CHECK_EQUAL(input.GetSequence(), 0xfffffffe);415auto output{tx.GetOutput(tx.CountOutputs() - 1)};416BOOST_CHECK_EQUAL(output.Amount(), 42130042);417auto script_pubkey{output.GetScriptPubkey()};418{419auto tx_new{Transaction{tx_data}};420// This is safe, because we now use copy assignment421TransactionOutput output = tx_new.GetOutput(tx_new.CountOutputs() - 1);422ScriptPubkey script = output.GetScriptPubkey();424TransactionOutputView output2 = tx_new.GetOutput(tx_new.CountOutputs() - 1);425BOOST_CHECK_NE(output.get(), output2.get());426BOOST_CHECK_EQUAL(output.Amount(), output2.Amount());427TransactionOutput output3 = output2;428BOOST_CHECK_NE(output3.get(), output2.get());429BOOST_CHECK_EQUAL(output3.Amount(), output2.Amount());431// Non-owned view432ScriptPubkeyView script2 = output.GetScriptPubkey();433BOOST_CHECK_NE(script.get(), script2.get());434check_equal(script.ToBytes(), script2.ToBytes());436// Non-owned to owned437ScriptPubkey script3 = script2;438BOOST_CHECK_NE(script3.get(), script2.get());439check_equal(script3.ToBytes(), script2.ToBytes());440}441BOOST_CHECK_EQUAL(output.Amount(), 42130042);443auto tx_roundtrip{Transaction{tx.ToBytes()}};444check_equal(tx_roundtrip.ToBytes(), tx_data);446// The following code is unsafe, but left here to show limitations of the447// API, because we preserve the output view beyond the lifetime of the448// transaction. The view type wrapper should make this clear to the user.449// auto get_output = [&]() -> TransactionOutputView {450// auto tx{Transaction{tx_data}};451// return tx.GetOutput(0);452// };453// auto output_new = get_output();454// BOOST_CHECK_EQUAL(output_new.Amount(), 20737411);456int64_t total_amount{0};457for (const auto output : tx.Outputs()) {458total_amount += output.Amount();459}460BOOST_CHECK_EQUAL(total_amount, 62867453);462auto amount = *(tx.Outputs() | std::ranges::views::filter([](const auto& output) {463return output.Amount() == 42130042;464}) |465std::views::transform([](const auto& output) {466return output.Amount();467})).begin();468BOOST_REQUIRE(amount);469BOOST_CHECK_EQUAL(amount, 42130042);471CheckRange(tx.Outputs(), tx.CountOutputs());473ScriptPubkey script_pubkey_roundtrip{script_pubkey.ToBytes()};474check_equal(script_pubkey_roundtrip.ToBytes(), script_pubkey.ToBytes());475}477BOOST_AUTO_TEST_CASE(btck_script_pubkey)478{479auto script_data{hex_string_to_byte_vec("76a9144bfbaf6afb76cc5771bc6404810d1cc041a6933988ac")};480std::vector<std::byte> script_data_2 = script_data;481script_data_2.push_back(std::byte{0x51});482ScriptPubkey script{script_data};483ScriptPubkey script2{script_data_2};484CheckHandle(script, script2);486std::span<std::byte> empty_data{};487ScriptPubkey empty_script{empty_data};488CheckHandle(script, empty_script);489}491BOOST_AUTO_TEST_CASE(btck_transaction_output)492{493ScriptPubkey script{hex_string_to_byte_vec("76a9144bfbaf6afb76cc5771bc6404810d1cc041a6933988ac")};494TransactionOutput output{script, 1};495TransactionOutput output2{script, 2};496CheckHandle(output, output2);497}499BOOST_AUTO_TEST_CASE(btck_transaction_input)500{
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.