diff --git a/include/bitcoin/database/impl/query/objects.ipp b/include/bitcoin/database/impl/query/objects.ipp index 91f39bb8..4739964d 100644 --- a/include/bitcoin/database/impl/query/objects.ipp +++ b/include/bitcoin/database/impl/query/objects.ipp @@ -45,7 +45,7 @@ inline bool CLASS::push_bool(std_vector& stack, TEMPLATE typename CLASS::inputs_ptr CLASS::get_inputs( - const tx_link& link) const NOEXCEPT + const tx_link& link, bool witness) const NOEXCEPT { // TODO: eliminate shared memory pointer reallocations. using namespace system; @@ -57,7 +57,7 @@ typename CLASS::inputs_ptr CLASS::get_inputs( inputs->reserve(fks.size()); for (const auto& fk: fks) - if (!push_bool(*inputs, get_input(fk))) + if (!push_bool(*inputs, get_input(fk, witness))) return {}; return inputs; @@ -85,7 +85,7 @@ typename CLASS::outputs_ptr CLASS::get_outputs( TEMPLATE typename CLASS::transactions_ptr CLASS::get_transactions( - const header_link& link) const NOEXCEPT + const header_link& link, bool witness) const NOEXCEPT { // TODO: eliminate shared memory pointer reallocations. using namespace system; @@ -97,7 +97,7 @@ typename CLASS::transactions_ptr CLASS::get_transactions( transactions->reserve(txs.size()); for (const auto& tx_fk: txs) - if (!push_bool(*transactions, get_transaction(tx_fk))) + if (!push_bool(*transactions, get_transaction(tx_fk, witness))) return {}; return transactions; @@ -133,14 +133,14 @@ typename CLASS::header::cptr CLASS::get_header( } TEMPLATE -typename CLASS::block::cptr CLASS::get_block( - const header_link& link) const NOEXCEPT +typename CLASS::block::cptr CLASS::get_block(const header_link& link, + bool witness) const NOEXCEPT { const auto header = get_header(link); if (!header) return {}; - const auto transactions = get_transactions(link); + const auto transactions = get_transactions(link, witness); if (!transactions) return {}; @@ -152,8 +152,8 @@ typename CLASS::block::cptr CLASS::get_block( } TEMPLATE -typename CLASS::transaction::cptr CLASS::get_transaction( - const tx_link& link) const NOEXCEPT +typename CLASS::transaction::cptr CLASS::get_transaction(const tx_link& link, + bool witness) const NOEXCEPT { using namespace system; table::transaction::only_with_sk tx{}; @@ -172,7 +172,7 @@ typename CLASS::transaction::cptr CLASS::get_transaction( // Points are allocated contiguously. for (auto fk = tx.point_fk; fk < (tx.point_fk + tx.ins_count); ++fk) - if (!push_bool(*inputs, get_input(fk))) + if (!push_bool(*inputs, get_input(fk, witness))) return {}; for (const auto& fk: outs.out_fks) @@ -217,11 +217,11 @@ typename CLASS::point::cptr CLASS::make_point(hash_digest&& hash, } TEMPLATE -typename CLASS::input::cptr CLASS::get_input( - const point_link& link) const NOEXCEPT +typename CLASS::input::cptr CLASS::get_input(const point_link& link, + bool witness) const NOEXCEPT { using namespace system; - table::input::get_ptrs in{}; + table::input::get_ptrs in{ {}, witness }; table::ins::get_input ins{}; table::point::record point{}; if (!store_.ins.get(link, ins) || @@ -255,7 +255,7 @@ typename CLASS::point CLASS::get_point( TEMPLATE typename CLASS::inputs_ptr CLASS::get_spenders( - const output_link& link) const NOEXCEPT + const output_link& link, bool witness) const NOEXCEPT { using namespace system; const auto point_fks = to_spenders(link); @@ -264,7 +264,7 @@ typename CLASS::inputs_ptr CLASS::get_spenders( // TODO: eliminate shared memory pointer reallocation. for (const auto& point_fk: point_fks) - if (!push_bool(*inputs, get_input(point_fk))) + if (!push_bool(*inputs, get_input(point_fk, witness))) return {}; return inputs; @@ -272,9 +272,9 @@ typename CLASS::inputs_ptr CLASS::get_spenders( TEMPLATE typename CLASS::input::cptr CLASS::get_input(const tx_link& link, - uint32_t input_index) const NOEXCEPT + uint32_t input_index, bool witness) const NOEXCEPT { - return get_input(to_point(link, input_index)); + return get_input(to_point(link, input_index), witness); } TEMPLATE @@ -285,10 +285,10 @@ typename CLASS::output::cptr CLASS::get_output(const tx_link& link, } TEMPLATE -typename CLASS::inputs_ptr CLASS::get_spenders(const tx_link& link, - uint32_t output_index) const NOEXCEPT +typename CLASS::inputs_ptr CLASS::get_spenders_index(const tx_link& link, + uint32_t output_index, bool witness) const NOEXCEPT { - return get_spenders(to_output(link, output_index)); + return get_spenders(to_output(link, output_index), witness); } // Populate prevout objects. diff --git a/include/bitcoin/database/query.hpp b/include/bitcoin/database/query.hpp index c8eee53b..75e260a1 100644 --- a/include/bitcoin/database/query.hpp +++ b/include/bitcoin/database/query.hpp @@ -364,24 +364,26 @@ class query /// Objects. /// ----------------------------------------------------------------------- - inputs_ptr get_inputs(const tx_link& link) const NOEXCEPT; + inputs_ptr get_inputs(const tx_link& link, bool witness) const NOEXCEPT; outputs_ptr get_outputs(const tx_link& link) const NOEXCEPT; - transactions_ptr get_transactions(const header_link& link) const NOEXCEPT; + transactions_ptr get_transactions(const header_link& link, + bool witness) const NOEXCEPT; header::cptr get_header(const header_link& link) const NOEXCEPT; - block::cptr get_block(const header_link& link) const NOEXCEPT; - transaction::cptr get_transaction(const tx_link& link) const NOEXCEPT; + block::cptr get_block(const header_link& link, bool witness) const NOEXCEPT; + transaction::cptr get_transaction(const tx_link& link, bool witness) const NOEXCEPT; + input::cptr get_input(const point_link& link, bool witness) const NOEXCEPT; output::cptr get_output(const output_link& link) const NOEXCEPT; - input::cptr get_input(const point_link& link) const NOEXCEPT; - inputs_ptr get_spenders(const output_link& link) const NOEXCEPT; + inputs_ptr get_spenders(const output_link& link, + bool witness) const NOEXCEPT; input::cptr get_input(const tx_link& link, - uint32_t input_index) const NOEXCEPT; + uint32_t input_index, bool witness) const NOEXCEPT; output::cptr get_output(const tx_link& link, uint32_t output_index) const NOEXCEPT; point get_point(const point_link& link) const NOEXCEPT; - inputs_ptr get_spenders(const tx_link& link, - uint32_t output_index) const NOEXCEPT; + inputs_ptr get_spenders_index(const tx_link& link, + uint32_t output_index, bool witness) const NOEXCEPT; /// False implies missing prevouts, node input.metadata is populated. bool populate_with_metadata(const input& input) const NOEXCEPT; diff --git a/include/bitcoin/database/tables/archives/input.hpp b/include/bitcoin/database/tables/archives/input.hpp index 72b5ffa7..fadde0fe 100644 --- a/include/bitcoin/database/tables/archives/input.hpp +++ b/include/bitcoin/database/tables/archives/input.hpp @@ -89,10 +89,13 @@ struct input { using namespace system; script = std::make_shared(source, true); - witness = std::make_shared(source, true); + witness = witnessed ? + std::make_shared(source, true) : + std::make_shared(); return source; } + bool witnessed{}; system::chain::script::cptr script{}; system::chain::witness::cptr witness{}; }; diff --git a/test/query/archive_write.cpp b/test/query/archive_write.cpp index 801c1617..ed132f8f 100644 --- a/test/query/archive_write.cpp +++ b/test/query/archive_write.cpp @@ -437,7 +437,7 @@ BOOST_AUTO_TEST_CASE(query_archive_write__set_tx__get_tx__expected) BOOST_REQUIRE(query.set(tx)); BOOST_REQUIRE(query.is_tx(tx.hash(false))); - const auto pointer1 = query.get_transaction(query.to_tx(tx_hash)); + const auto pointer1 = query.get_transaction(query.to_tx(tx_hash), false); BOOST_REQUIRE(pointer1); //// BOOST_REQUIRE(*pointer1 == tx); BOOST_REQUIRE_EQUAL(pointer1->hash(false), tx_hash); @@ -599,7 +599,7 @@ BOOST_AUTO_TEST_CASE(query_archive_write__set_block__get_block__expected) //// BOOST_REQUIRE_EQUAL(store.spend_body(), genesis_spend_body); BOOST_REQUIRE_EQUAL(store.txs_body(), genesis_txs_body); - const auto pointer1 = query.get_block(query.to_header(test::genesis.hash())); + const auto pointer1 = query.get_block(query.to_header(test::genesis.hash()), false); BOOST_REQUIRE(pointer1); //// BOOST_REQUIRE(*pointer1 == test::genesis); @@ -753,7 +753,7 @@ BOOST_AUTO_TEST_CASE(query_archive_write__set_block_txs__get_block__expected) //// BOOST_REQUIRE_EQUAL(store.spend_body(), genesis_spend_body); BOOST_REQUIRE_EQUAL(store.txs_body(), genesis_txs_body); - const auto pointer1 = query.get_block(query.to_header(test::genesis.hash())); + const auto pointer1 = query.get_block(query.to_header(test::genesis.hash()), false); BOOST_REQUIRE(pointer1); //// BOOST_REQUIRE(*pointer1 == test::genesis); @@ -1392,7 +1392,7 @@ BOOST_AUTO_TEST_CASE(query_archive_write__get_input__not_found__nullptr) test::chunk_store store{ settings }; test::query_accessor query{ store }; BOOST_REQUIRE(!store.create(events_handler)); - BOOST_REQUIRE(!query.get_input(query.to_tx(system::null_hash), 0u)); + BOOST_REQUIRE(!query.get_input(query.to_tx(system::null_hash), 0u, false)); BOOST_REQUIRE(!store.close(events_handler)); } @@ -1422,7 +1422,7 @@ BOOST_AUTO_TEST_CASE(query_archive_write__get_inputs__tx_not_found__nullptr) test::query_accessor query{ store }; BOOST_REQUIRE(!store.create(events_handler)); BOOST_REQUIRE(query.initialize(test::genesis)); - BOOST_REQUIRE(!query.get_inputs(1)); + BOOST_REQUIRE(!query.get_inputs(1, false)); } BOOST_AUTO_TEST_CASE(query_archive_write__get_inputs__found__expected) @@ -1434,7 +1434,7 @@ BOOST_AUTO_TEST_CASE(query_archive_write__get_inputs__found__expected) BOOST_REQUIRE(!store.create(events_handler)); BOOST_REQUIRE(query.initialize(test::genesis)); BOOST_REQUIRE(query.set(test::tx4)); - BOOST_REQUIRE_EQUAL(query.get_inputs(1)->size(), 2u); + BOOST_REQUIRE_EQUAL(query.get_inputs(1, false)->size(), 2u); } BOOST_AUTO_TEST_CASE(query_archive_write__get_output__not_found__nullptr) @@ -1501,7 +1501,7 @@ BOOST_AUTO_TEST_CASE(query_archive_write__get_transactions__tx_not_found__nullpt BOOST_REQUIRE(!store.create(events_handler)); BOOST_REQUIRE(query.initialize(test::genesis)); BOOST_REQUIRE(query.set(test::tx4)); - BOOST_REQUIRE(!query.get_transactions(3)); + BOOST_REQUIRE(!query.get_transactions(3, false)); } BOOST_AUTO_TEST_CASE(query_archive_write__get_transactions__found__expected) @@ -1515,9 +1515,9 @@ BOOST_AUTO_TEST_CASE(query_archive_write__get_transactions__found__expected) BOOST_REQUIRE(query.set(test::block1a, test::context, false, false)); BOOST_REQUIRE(query.set(test::block2a, test::context, false, false)); BOOST_REQUIRE(query.set(test::tx4)); - BOOST_REQUIRE_EQUAL(query.get_transactions(0)->size(), 1u); - BOOST_REQUIRE_EQUAL(query.get_transactions(1)->size(), 1u); - BOOST_REQUIRE_EQUAL(query.get_transactions(2)->size(), 2u); + BOOST_REQUIRE_EQUAL(query.get_transactions(0, false)->size(), 1u); + BOOST_REQUIRE_EQUAL(query.get_transactions(1, false)->size(), 1u); + BOOST_REQUIRE_EQUAL(query.get_transactions(2, false)->size(), 2u); } BOOST_AUTO_TEST_CASE(query_archive_write__get_spenders__unspent_or_not_found__expected) @@ -1533,29 +1533,29 @@ BOOST_AUTO_TEST_CASE(query_archive_write__get_spenders__unspent_or_not_found__ex BOOST_REQUIRE(query.set(test::block3, test::context, false, false)); // Caller should always test for nullptr. - BOOST_REQUIRE(query.get_spenders(output_link::terminal)->empty()); - BOOST_REQUIRE(query.get_spenders(tx_link::terminal, 0)->empty()); - BOOST_REQUIRE(query.get_spenders(tx_link::terminal, 1)->empty()); - - BOOST_REQUIRE(query.get_spenders(query.to_output(0, 0))->empty()); - BOOST_REQUIRE(query.get_spenders(query.to_output(0, 1))->empty()); - BOOST_REQUIRE(query.get_spenders(0, 0)->empty()); - BOOST_REQUIRE(query.get_spenders(0, 1)->empty()); - - BOOST_REQUIRE(query.get_spenders(query.to_output(1, 0))->empty()); - BOOST_REQUIRE(query.get_spenders(query.to_output(1, 1))->empty()); - BOOST_REQUIRE(query.get_spenders(1, 0)->empty()); - BOOST_REQUIRE(query.get_spenders(1, 1)->empty()); - - BOOST_REQUIRE(query.get_spenders(query.to_output(2, 0))->empty()); - BOOST_REQUIRE(query.get_spenders(query.to_output(2, 1))->empty()); - BOOST_REQUIRE(query.get_spenders(2, 0)->empty()); - BOOST_REQUIRE(query.get_spenders(2, 1)->empty()); - - BOOST_REQUIRE(query.get_spenders(query.to_output(3, 0))->empty()); - BOOST_REQUIRE(query.get_spenders(query.to_output(3, 1))->empty()); - BOOST_REQUIRE(query.get_spenders(3, 0)->empty()); - BOOST_REQUIRE(query.get_spenders(3, 1)->empty()); + BOOST_REQUIRE(query.get_spenders(output_link::terminal, true)->empty()); + BOOST_REQUIRE(query.get_spenders_index(tx_link::terminal, 0, true)->empty()); + BOOST_REQUIRE(query.get_spenders_index(tx_link::terminal, 1, true)->empty()); + + BOOST_REQUIRE(query.get_spenders(query.to_output(0, 0), true)->empty()); + BOOST_REQUIRE(query.get_spenders(query.to_output(0, 1), true)->empty()); + BOOST_REQUIRE(query.get_spenders_index(0, 0, true)->empty()); + BOOST_REQUIRE(query.get_spenders_index(0, 1, true)->empty()); + + BOOST_REQUIRE(query.get_spenders(query.to_output(1, 0), true)->empty()); + BOOST_REQUIRE(query.get_spenders(query.to_output(1, 1), true)->empty()); + BOOST_REQUIRE(query.get_spenders_index(1, 0, true)->empty()); + BOOST_REQUIRE(query.get_spenders_index(1, 1, true)->empty()); + + BOOST_REQUIRE(query.get_spenders(query.to_output(2, 0), true)->empty()); + BOOST_REQUIRE(query.get_spenders(query.to_output(2, 1), true)->empty()); + BOOST_REQUIRE(query.get_spenders_index(2, 0, true)->empty()); + BOOST_REQUIRE(query.get_spenders_index(2, 1, true)->empty()); + + BOOST_REQUIRE(query.get_spenders(query.to_output(3, 0), true)->empty()); + BOOST_REQUIRE(query.get_spenders(query.to_output(3, 1), true)->empty()); + BOOST_REQUIRE(query.get_spenders_index(3, 0, true)->empty()); + BOOST_REQUIRE(query.get_spenders_index(3, 1, true)->empty()); } ////BOOST_AUTO_TEST_CASE(query_archive_write__get_spenders__found_and_spent__expected) @@ -1568,50 +1568,50 @@ BOOST_AUTO_TEST_CASE(query_archive_write__get_spenders__unspent_or_not_found__ex //// BOOST_REQUIRE(query.initialize(test::genesis)); //// //// // Neither of the two block1a outputs spent yet. -//// BOOST_REQUIRE(query.set(test::block1a, test::context)); -//// BOOST_REQUIRE(query.get_spenders(query.to_output(1, 0))->empty()); -//// BOOST_REQUIRE(query.get_spenders(query.to_output(1, 1))->empty()); -//// BOOST_REQUIRE(query.get_spenders(query.to_output(1, 2))->empty()); -//// BOOST_REQUIRE(query.get_spenders(1, 0)->empty()); -//// BOOST_REQUIRE(query.get_spenders(1, 1)->empty()); -//// BOOST_REQUIRE(query.get_spenders(1, 2)->empty()); +//// BOOST_REQUIRE(query.set(test::block1a, test::context, false, false)); +//// BOOST_REQUIRE(query.get_spenders(query.to_output(1, 0), true)->empty()); +//// BOOST_REQUIRE(query.get_spenders(query.to_output(1, 1), true)->empty()); +//// BOOST_REQUIRE(query.get_spenders(query.to_output(1, 2), true)->empty()); +//// BOOST_REQUIRE(query.get_spenders_index(1, 0, true)->empty()); +//// BOOST_REQUIRE(query.get_spenders_index(1, 1, true)->empty()); +//// BOOST_REQUIRE(query.get_spenders_index(1, 2, true)->empty()); //// //// // Each of the two outputs of block1a spent once. -//// BOOST_REQUIRE(query.set(test::block2a, test::context)); +//// BOOST_REQUIRE(query.set(test::block2a, test::context, false, false)); //// -//// BOOST_REQUIRE_EQUAL(query.get_spenders(query.to_output(1, 0))->size(), 1u); -//// BOOST_REQUIRE_EQUAL(query.get_spenders(query.to_output(1, 1))->size(), 1u); -//// BOOST_REQUIRE(query.get_spenders(query.to_output(1, 2))->empty()); -//// BOOST_REQUIRE_EQUAL(query.get_spenders(1, 0)->size(), 1u); -//// BOOST_REQUIRE_EQUAL(query.get_spenders(1, 1)->size(), 1u); -//// BOOST_REQUIRE_EQUAL(query.get_spenders(1, 2)->size(), 0u); +//// BOOST_REQUIRE_EQUAL(query.get_spenders(query.to_output(1, 0), true)->size(), 1u); +//// BOOST_REQUIRE_EQUAL(query.get_spenders(query.to_output(1, 1), true)->size(), 1u); +//// BOOST_REQUIRE(query.get_spenders(query.to_output(1, 2), true)->empty()); +//// BOOST_REQUIRE_EQUAL(query.get_spenders_index(1, 0, true)->size(), 1u); +//// BOOST_REQUIRE_EQUAL(query.get_spenders_index(1, 1, true)->size(), 1u); +//// BOOST_REQUIRE_EQUAL(query.get_spenders_index(1, 2, true)->size(), 0u); //// //// // Match the two spenders. //// const auto block_inputs = test::block2a.transactions_ptr()->front()->inputs_ptr(); -//// BOOST_REQUIRE(*query.get_spenders(query.to_output(1, 0))->front() == *(*block_inputs).front()); -//// BOOST_REQUIRE(*query.get_spenders(query.to_output(1, 1))->front() == *(*block_inputs).back()); +//// BOOST_REQUIRE(*query.get_spenders(query.to_output(1, 0), true)->front() == *(*block_inputs).front()); +//// BOOST_REQUIRE(*query.get_spenders(query.to_output(1, 1), true)->front() == *(*block_inputs).back()); //// BOOST_REQUIRE(*query.get_spenders(1, 0)->front() == *(*block_inputs).front()); //// BOOST_REQUIRE(*query.get_spenders(1, 1)->front() == *(*block_inputs).back()); //// //// // Each of the two outputs of block1a spent twice (two unconfirmed double spends). //// BOOST_REQUIRE(query.set(test::tx4)); -//// BOOST_REQUIRE_EQUAL(query.get_spenders(query.to_output(1, 0))->size(), 2u); -//// BOOST_REQUIRE_EQUAL(query.get_spenders(query.to_output(1, 1))->size(), 2u); -//// BOOST_REQUIRE(query.get_spenders(query.to_output(1, 2))->empty()); -//// BOOST_REQUIRE_EQUAL(query.get_spenders(1, 0)->size(), 2u); -//// BOOST_REQUIRE_EQUAL(query.get_spenders(1, 1)->size(), 2u); -//// BOOST_REQUIRE_EQUAL(query.get_spenders(1, 2)->size(), 0u); +//// BOOST_REQUIRE_EQUAL(query.get_spenders(query.to_output(1, 0), true)->size(), 2u); +//// BOOST_REQUIRE_EQUAL(query.get_spenders(query.to_output(1, 1), true)->size(), 2u); +//// BOOST_REQUIRE(query.get_spenders(query.to_output(1, 2), true)->empty()); +//// BOOST_REQUIRE_EQUAL(query.get_spenders_index(1, 0, true)->size(), 2u); +//// BOOST_REQUIRE_EQUAL(query.get_spenders_index(1, 1, true)->size(), 2u); +//// BOOST_REQUIRE_EQUAL(query.get_spenders_index(1, 2, true)->size(), 0u); //// //// // Match the four spenders. //// const auto tx_inputs = test::tx4.inputs_ptr(); -//// BOOST_REQUIRE(*query.get_spenders(query.to_output(1, 0))->front() == *(*tx_inputs).front()); -//// BOOST_REQUIRE(*query.get_spenders(query.to_output(1, 1))->front() == *(*tx_inputs).back()); -//// BOOST_REQUIRE(*query.get_spenders(query.to_output(1, 0))->back() == *(*block_inputs).front()); -//// BOOST_REQUIRE(*query.get_spenders(query.to_output(1, 1))->back() == *(*block_inputs).back()); -//// BOOST_REQUIRE(*query.get_spenders(1, 0)->front() == *(*tx_inputs).front()); -//// BOOST_REQUIRE(*query.get_spenders(1, 1)->front() == *(*tx_inputs).back()); -//// BOOST_REQUIRE(*query.get_spenders(1, 0)->back() == *(*block_inputs).front()); -//// BOOST_REQUIRE(*query.get_spenders(1, 1)->back() == *(*block_inputs).back()); +//// BOOST_REQUIRE(*query.get_spenders(query.to_output(1, 0), true)->front() == *(*tx_inputs).front()); +//// BOOST_REQUIRE(*query.get_spenders(query.to_output(1, 1), true)->front() == *(*tx_inputs).back()); +//// BOOST_REQUIRE(*query.get_spenders(query.to_output(1, 0), true)->back() == *(*block_inputs).front()); +//// BOOST_REQUIRE(*query.get_spenders(query.to_output(1, 1), true)->back() == *(*block_inputs).back()); +//// BOOST_REQUIRE(*query.get_spenders_index(1, 0, true)->front() == *(*tx_inputs).front()); +//// BOOST_REQUIRE(*query.get_spenders_index(1, 1, true)->front() == *(*tx_inputs).back()); +//// BOOST_REQUIRE(*query.get_spenders_index(1, 0, true)->back() == *(*block_inputs).front()); +//// BOOST_REQUIRE(*query.get_spenders_index(1, 1, true)->back() == *(*block_inputs).back()); ////} BOOST_AUTO_TEST_CASE(query_archive_write__get_value__genesis__expected)