diff --git a/include/bitcoin/database/impl/query/address/address_history.ipp b/include/bitcoin/database/impl/query/address/address_history.ipp index 21e66b1f..5d095586 100644 --- a/include/bitcoin/database/impl/query/address/address_history.ipp +++ b/include/bitcoin/database/impl/query/address/address_history.ipp @@ -40,12 +40,18 @@ TEMPLATE code CLASS::get_unconfirmed_history(const stopper& cancel, histories& out, const hash_digest& key, bool turbo) const NOEXCEPT { - output_links outs{}; - if (const auto ec = to_address_outputs(cancel, outs, key)) - return ec; + address_link cursor{}; + return get_unconfirmed_history(cancel, cursor, out, key, max_size_t, turbo); +} +// server/electrum +TEMPLATE +code CLASS::get_unconfirmed_history(const stopper& cancel, + address_link& cursor, histories& out, const hash_digest& key, + size_t limit, bool turbo) const NOEXCEPT +{ tx_links txs{}; - if (const auto ec = to_touched_txs(cancel, txs, outs)) + if (const auto ec = get_address_txs(cancel, cursor, txs, key, limit)) return ec; out.clear(); @@ -53,30 +59,10 @@ code CLASS::get_unconfirmed_history(const stopper& cancel, histories& out, return parallel_history_transform(cancel, turbo, out, txs, [this](const tx_link& link, auto& cancel, auto& fail) NOEXCEPT { - if (cancel || fail) - return history{}; - - // chain::checkpoint invalid in default construction (filter). - if (is_confirmed_block(find_strong(link))) - return history{}; - - auto hash = get_tx_key(link); - if (hash == system::null_hash) - { - fail = true; - return history{}; - } - - uint64_t fee{}; - if (!get_tx_fee(fee, link)) - fee = history::missing_prevout; - - auto height = history::unrooted_height; - if (is_confirmed_all_prevouts(link)) - height = history::rooted_height; - - return history{ { std::move(hash), height }, fee, - history::unconfirmed_position }; + if (cancel || fail) return history{}; + const auto out = get_tx_unconfirmed_history(link); + if (!out.confirmed() && !out.valid()) fail = true; + return out; }); } @@ -85,12 +71,18 @@ TEMPLATE code CLASS::get_confirmed_history(const stopper& cancel, histories& out, const hash_digest& key, bool turbo) const NOEXCEPT { - output_links outs{}; - if (const auto ec = to_address_outputs(cancel, outs, key)) - return ec; + address_link cursor{}; + return get_confirmed_history(cancel, cursor, out, key, max_size_t, turbo); +} +// ununsed +TEMPLATE +code CLASS::get_confirmed_history(const stopper& cancel, + address_link& cursor, histories& out, const hash_digest& key, + size_t limit, bool turbo) const NOEXCEPT +{ tx_links txs{}; - if (const auto ec = to_touched_txs(cancel, txs, outs)) + if (const auto ec = get_address_txs(cancel, cursor, txs, key, limit)) return ec; out.clear(); @@ -98,30 +90,10 @@ code CLASS::get_confirmed_history(const stopper& cancel, histories& out, return parallel_history_transform(cancel, turbo, out, txs, [this](const tx_link& link, auto& cancel, auto& fail) NOEXCEPT { - if (cancel || fail) - return history{}; - - // chain::checkpoint invalid in default construction (filter). - const auto block = find_strong(link); - if (!is_confirmed_block(block)) - return history{}; - - size_t height{}, position{}; - auto hash = get_tx_key(link); - if (hash == system::null_hash || - !get_height(height, block) || - !get_tx_position(position, link, block)) - { - fail = true; - return history{}; - } - - // Electrum uses fees only on unconfirmed (and expensive). - constexpr auto fee = history::missing_prevout; - ////if (!get_tx_fee(fee, link)) - //// fee = history::missing_prevout; - - return history{ { std::move(hash), height }, fee, position }; + if (cancel || fail) return history{}; + const auto out = get_tx_confirmed_history(link); + if (out.confirmed() && !out.valid()) fail = true; + return out; }); } @@ -140,26 +112,18 @@ code CLASS::get_history(const stopper& cancel, address_link& cursor, histories& out, const hash_digest& key, size_t limit, bool turbo) const NOEXCEPT { - output_links outs{}; - if (const auto ec = to_address_outputs(cancel, cursor, outs, key, limit)) - return ec; - - tx_links links{}; - if (const auto ec = to_touched_txs(cancel, links, outs)) + tx_links txs{}; + if (const auto ec = get_address_txs(cancel, cursor, txs, key, limit)) return ec; out.clear(); - out.resize(links.size()); - return parallel_history_transform(cancel, turbo, out, links, + out.resize(txs.size()); + return parallel_history_transform(cancel, turbo, out, txs, [this](const tx_link& link, auto& cancel, auto& fail) NOEXCEPT { - if (cancel || fail) - return history{}; - + if (cancel || fail) return history{}; const auto out = get_tx_history(link); - if (!out.valid()) - fail = true; - + if (!out.valid()) fail = true; return out; }); } @@ -173,26 +137,22 @@ history CLASS::get_tx_history(const tx_link& link) const NOEXCEPT return get_tx_history(get_tx_key(link), link); } -TEMPLATE -history CLASS::get_tx_history(const hash_digest& key) const NOEXCEPT -{ - const auto link = to_tx(key); - return get_tx_history(hash_digest{ key }, link); -} - -// private +// protected TEMPLATE history CLASS::get_tx_history(hash_digest&& key, const tx_link& link) const NOEXCEPT { + // history is invalid in default construction. if (link.is_terminal()) return {}; - // Electrum uses fees only on unconfirmed (and expensive). + // Electrum uses fees only on unconfirmed. auto fee = history::missing_prevout; auto height = history::unrooted_height; auto position = history::unconfirmed_position; - if (const auto block = find_confirmed_block(link); !block.is_terminal()) + + const auto block = find_strong(link); + if (is_confirmed_block(block)) { if (!get_height(height, block) || !get_tx_position(position, link, block)) @@ -210,6 +170,65 @@ history CLASS::get_tx_history(hash_digest&& key, return { { std::move(key), height }, fee, position }; } +TEMPLATE +history CLASS::get_tx_confirmed_history(const tx_link& link) const NOEXCEPT +{ + return get_tx_confirmed_history(get_tx_key(link), link); +} + +// protected +TEMPLATE +history CLASS::get_tx_confirmed_history(hash_digest&& key, + const tx_link& link) const NOEXCEPT +{ + // history is invalid in default construction. + if (link.is_terminal()) + return { .position = zero }; + + const auto block = find_strong(link); + + // Returns invalid (filtered) but also !confirmed(). + if (!is_confirmed_block(block)) + return { .position = history::unconfirmed_position }; + + size_t height{}, position{}; + if (!get_height(height, block) || + !get_tx_position(position, link, block)) + return { .position = zero }; + + // Electrum uses fees only on unconfirmed (expensive). + return { { std::move(key), height }, history::missing_prevout, position }; +} + +TEMPLATE +history CLASS::get_tx_unconfirmed_history(const tx_link& link) const NOEXCEPT +{ + return get_tx_unconfirmed_history(get_tx_key(link), link); +} + +// protected +TEMPLATE +history CLASS::get_tx_unconfirmed_history(hash_digest&& key, + const tx_link& link) const NOEXCEPT +{ + // history is invalid in default construction. + if (link.is_terminal()) + return { .position = history::unconfirmed_position }; + + // Returns invalid (filtered) but also confirmed(). + if (is_confirmed_block(find_strong(link))) + return { .position = zero }; + + uint64_t fee{}; + if (!get_tx_fee(fee, link)) + fee = history::missing_prevout; + + const auto height = is_confirmed_all_prevouts(link) ? + history::rooted_height : history::unrooted_height; + + return { { std::move(key), height }, fee, history::unconfirmed_position }; +} + // server/electrum TEMPLATE histories CLASS::get_spenders_history( @@ -233,8 +252,19 @@ histories CLASS::get_spenders_history(const hash_digest& key, // utilities // ---------------------------------------------------------------------------- -// private/static +TEMPLATE +code CLASS::get_address_txs(const stopper& cancel, address_link& cursor, + tx_links& out, const hash_digest& key, size_t limit) const NOEXCEPT +{ + output_links links{}; + if (const auto ec = to_address_outputs(cancel, cursor, links, key, limit)) + return ec; + + return to_touched_txs(cancel, out, links); +} + +// private/static TEMPLATE template code CLASS::parallel_history_transform(const stopper& cancel, bool turbo, diff --git a/include/bitcoin/database/query.hpp b/include/bitcoin/database/query.hpp index 89487d2d..14fee688 100644 --- a/include/bitcoin/database/query.hpp +++ b/include/bitcoin/database/query.hpp @@ -641,6 +641,14 @@ class query const hash_digest& key, bool turbo=false) const NOEXCEPT; code get_history(const stopper& cancel, histories& out, const hash_digest& key, bool turbo=false) const NOEXCEPT; + + /// Electrum queries (with limit and cursor options). + code get_unconfirmed_history(const stopper& cancel, address_link& cursor, + histories& out, const hash_digest& key, size_t limit=max_size_t, + bool turbo=false) const NOEXCEPT; + code get_confirmed_history(const stopper& cancel, address_link& cursor, + histories& out, const hash_digest& key,size_t limit=max_size_t, + bool turbo=false) const NOEXCEPT; code get_history(const stopper& cancel, address_link& cursor, histories& out, const hash_digest& key, size_t limit=max_size_t, bool turbo=false) const NOEXCEPT; @@ -663,9 +671,9 @@ class query bool turbo=false) const NOEXCEPT; /// History queries. - // TODO: add point_link cursor to new get_spenders(cursor, point) query. history get_tx_history(const tx_link& link) const NOEXCEPT; - history get_tx_history(const hash_digest& key) const NOEXCEPT; + history get_tx_confirmed_history(const tx_link& link) const NOEXCEPT; + history get_tx_unconfirmed_history(const tx_link& link) const NOEXCEPT; histories get_spenders_history(const point& prevout) const NOEXCEPT; histories get_spenders_history(const hash_digest& key, uint32_t index) const NOEXCEPT; @@ -835,6 +843,13 @@ class query history get_tx_history(hash_digest&& key, const tx_link& link) const NOEXCEPT; + history get_tx_confirmed_history(hash_digest&& key, + const tx_link& link) const NOEXCEPT; + history get_tx_unconfirmed_history(hash_digest&& key, + const tx_link& link) const NOEXCEPT; + + code get_address_txs(const stopper& cancel, address_link& cursor, + tx_links& out, const hash_digest& key, size_t limit) const NOEXCEPT; private: // This value should never be read, but may be useful in debugging. diff --git a/test/query/address/address_history.cpp b/test/query/address/address_history.cpp index 79dec478..f55ac605 100644 --- a/test/query/address/address_history.cpp +++ b/test/query/address/address_history.cpp @@ -22,8 +22,6 @@ BOOST_FIXTURE_TEST_SUITE(query_address_tests, test::directory_setup_fixture) -// get_unconfirmed_history -// get_confirmed_history // get_history BOOST_AUTO_TEST_CASE(query_address__get_history__genesis__expected) @@ -32,29 +30,126 @@ BOOST_AUTO_TEST_CASE(query_address__get_history__genesis__expected) settings.path = TEST_DIRECTORY; test::chunk_store store{ settings }; test::query_accessor query{ store }; - BOOST_REQUIRE(!store.create(test::events_handler)); - BOOST_REQUIRE(test::setup_three_block_confirmed_address_store(query)); + BOOST_CHECK(!store.create(test::events_handler)); + BOOST_CHECK(test::setup_three_block_confirmed_address_store(query)); histories out{}; const std::atomic_bool cancel{}; - BOOST_REQUIRE(!query.get_unconfirmed_history(cancel, out, test::genesis_address0)); - BOOST_REQUIRE_EQUAL(out.size(), 0u); + const auto& hash = test::genesis_address0; + BOOST_CHECK(!query.get_unconfirmed_history(cancel, out, hash)); + BOOST_CHECK_EQUAL(out.size(), 0u); out.clear(); - BOOST_REQUIRE(!query.get_confirmed_history(cancel, out, test::genesis_address0)); - BOOST_REQUIRE_EQUAL(out.at(0).fee, history::missing_prevout); - BOOST_REQUIRE_EQUAL(out.at(0).position, 0u); - BOOST_REQUIRE_EQUAL(out.at(0).tx.height(), 0u); - BOOST_REQUIRE_EQUAL(out.at(0).tx.hash(), test::genesis.transactions_ptr()->at(0)->hash(false)); + BOOST_CHECK(!query.get_confirmed_history(cancel, out, hash)); + BOOST_CHECK_EQUAL(out.at(0).fee, history::missing_prevout); + BOOST_CHECK_EQUAL(out.at(0).position, 0u); + BOOST_CHECK_EQUAL(out.at(0).tx.height(), 0u); + BOOST_CHECK_EQUAL(out.at(0).tx.hash(), test::genesis.transactions_ptr()->at(0)->hash(false)); out.clear(); - BOOST_REQUIRE(!query.get_history(cancel, out, test::genesis_address0)); - BOOST_REQUIRE_EQUAL(out.at(0).fee, history::missing_prevout); - BOOST_REQUIRE_EQUAL(out.at(0).position, 0u); - BOOST_REQUIRE_EQUAL(out.at(0).tx.height(), 0u); - BOOST_REQUIRE_EQUAL(out.at(0).tx.hash(), test::genesis.transactions_ptr()->at(0)->hash(false)); + BOOST_CHECK(!query.get_history(cancel, out, hash)); + BOOST_CHECK_EQUAL(out.at(0).fee, history::missing_prevout); + BOOST_CHECK_EQUAL(out.at(0).position, 0u); + BOOST_CHECK_EQUAL(out.at(0).tx.height(), 0u); + BOOST_CHECK_EQUAL(out.at(0).tx.hash(), test::genesis.transactions_ptr()->at(0)->hash(false)); +} + +BOOST_AUTO_TEST_CASE(query_address__get_history__turbo_block1a_address0__expected) +{ + settings settings{}; + settings.path = TEST_DIRECTORY; + test::chunk_store store{ settings }; + test::query_accessor query{ store }; + BOOST_CHECK(!store.create(test::events_handler)); + BOOST_CHECK(test::setup_three_block_confirmed_address_store(query)); + + histories out{}; + const std::atomic_bool cancel{}; + BOOST_CHECK(!query.get_history(cancel, out, test::block1a_address0, true)); + BOOST_CHECK_EQUAL(out.size(), 8u); + + // Identities (not part of sort). + BOOST_CHECK_EQUAL(out.at(0).tx.hash(), test::block1a.transactions_ptr()->at(0)->hash(false)); // tx1/tx1 (same) + BOOST_CHECK_EQUAL(out.at(1).tx.hash(), test::block2a.transactions_ptr()->at(0)->hash(false)); // tx2/tx2 (same) + BOOST_CHECK_EQUAL(out.at(2).tx.hash(), test::block2a.transactions_ptr()->at(1)->hash(false)); // tx3/tx3 (same) + BOOST_CHECK_EQUAL(out.at(3).tx.hash(), test::block3a.transactions_ptr()->at(0)->hash(false)); // tx6/tx6 (same) + BOOST_CHECK_EQUAL(out.at(4).tx.hash(), test::tx5.hash(false)); // tx5/tx4 + BOOST_CHECK_EQUAL(out.at(5).tx.hash(), test::tx4.hash(false)); // tx4/tx8 + BOOST_CHECK_EQUAL(out.at(6).tx.hash(), test::block2b.transactions_ptr()->at(0)->hash(false)); // tx8/tx5 + BOOST_CHECK_EQUAL(out.at(7).tx.hash(), test::block1b.transactions_ptr()->at(0)->hash(false)); // tx7/tx7 (same) + + // Confirmed by height ascending. + // Unconfirmed rooted before unrooted. + // NOTE: at(5) is spend exceeds value, which is returned as unrooted_height in get_unconfirmed_history() + // NOTE: but as rooted_height in get_history(). This is a consequence of the optimized processing order + // NOTE: and does not affect valid confirmed/unconfirmed txs. + BOOST_CHECK_EQUAL(out.at(0).tx.height(), 1u); // tx1 + BOOST_CHECK_EQUAL(out.at(1).tx.height(), 2u); // tx2 + BOOST_CHECK_EQUAL(out.at(2).tx.height(), 2u); // tx3 + BOOST_CHECK_EQUAL(out.at(3).tx.height(), 3u); // tx6 + BOOST_CHECK_EQUAL(out.at(4).tx.height(), history::rooted_height); // tx5/tx4 + BOOST_CHECK_EQUAL(out.at(5).tx.height(), history::rooted_height); // tx4/tx8 + BOOST_CHECK_EQUAL(out.at(6).tx.height(), history::unrooted_height); // tx8/tx5 + BOOST_CHECK_EQUAL(out.at(7).tx.height(), history::unrooted_height); // tx7 + + // Confirmed height by block position. + BOOST_CHECK_EQUAL(out.at(0).position, 0u); // tx1 + BOOST_CHECK_EQUAL(out.at(1).position, 0u); // tx2 + BOOST_CHECK_EQUAL(out.at(2).position, 1u); // tx3 + BOOST_CHECK_EQUAL(out.at(3).position, 0u); // tx6 + BOOST_CHECK_EQUAL(out.at(4).position, history::unconfirmed_position); // tx5/tx4 + BOOST_CHECK_EQUAL(out.at(5).position, history::unconfirmed_position); // tx4/tx8 + BOOST_CHECK_EQUAL(out.at(6).position, history::unconfirmed_position); // tx8/tx5 + BOOST_CHECK_EQUAL(out.at(7).position, history::unconfirmed_position); // tx7 + + // Unconfirmed system::encode_hash(hash) lexically sorted. + using namespace system; + BOOST_CHECK(encode_hash(out.at(6).tx.hash()) < encode_hash(out.at(7).tx.hash())); + + // Fee (not part of sort). + BOOST_CHECK_EQUAL(out.at(0).fee, history::missing_prevout); // tx1 + BOOST_CHECK_EQUAL(out.at(1).fee, history::missing_prevout); // tx2 + BOOST_CHECK_EQUAL(out.at(2).fee, history::missing_prevout); // tx3 + BOOST_CHECK_EQUAL(out.at(3).fee, history::missing_prevout); // tx6 + BOOST_CHECK_EQUAL(out.at(4).fee, history::missing_prevout); // tx5/tx4 + BOOST_CHECK_EQUAL(out.at(5).fee, floored_subtract(0x18u + 0x2au, 0x08u)); // tx4/tx8 + BOOST_CHECK_EQUAL(out.at(6).fee, floored_subtract(0xb1u + 0xb1u, 0xb2u)); // tx8/tx5 + BOOST_CHECK_EQUAL(out.at(7).fee, history::missing_prevout); // tx7 +} + +BOOST_AUTO_TEST_CASE(query_address__get_history__limited__limited_empty) +{ + settings settings{}; + settings.path = TEST_DIRECTORY; + test::chunk_store store{ settings }; + test::query_accessor query{ store }; + BOOST_CHECK(!store.create(test::events_handler)); + BOOST_CHECK(test::setup_three_block_confirmed_address_store(query)); + + histories out{}; + address_link cursor{}; + const std::atomic_bool cancel{}; + const auto& hash = test::block1a_address0; + + // Limited returned when limit precludes reaching the address cursor (or terminal). + BOOST_CHECK_EQUAL(query.get_history(cancel, cursor, out, hash, 0, true), error::limited); + BOOST_CHECK(out.empty()); + + cursor = address_link::terminal; + BOOST_CHECK_EQUAL(query.get_history(cancel, cursor, out, hash, 8, true), error::limited); + BOOST_CHECK(out.empty()); + + cursor = address_link::terminal; + BOOST_CHECK_EQUAL(query.get_history(cancel, cursor, out, hash, 9, true), error::success); + BOOST_CHECK_EQUAL(out.size(), 8u); + + cursor = address_link::terminal; + BOOST_CHECK_EQUAL(query.get_history(cancel, cursor, out, hash, 100, true), error::success); + BOOST_CHECK_EQUAL(out.size(), 8u); } +// ---------------------------------------------------------------------------- + // block1a_address0 has 9 instances `script{ { { opcode::pick } } }`. // 7 outputs are in individual txs, 2 are in tx bk1b0. // 4 owning txs are confirmed (bk1a/bk2a/bk3a). @@ -80,19 +175,21 @@ BOOST_AUTO_TEST_CASE(query_address__get_history__genesis__expected) // bk2atx1 owns 1c (+1c) [confirmed]. // bk3atx0 spends 1c + owns 1c (+1c) [confirmed]. +// get_unconfirmed_history + BOOST_AUTO_TEST_CASE(query_address__get_unconfirmed_history__turbo_block1a_address0__expected) { settings settings{}; settings.path = TEST_DIRECTORY; test::chunk_store store{ settings }; test::query_accessor query{ store }; - BOOST_REQUIRE(!store.create(test::events_handler)); - BOOST_REQUIRE(test::setup_three_block_confirmed_address_store(query)); + BOOST_CHECK(!store.create(test::events_handler)); + BOOST_CHECK(test::setup_three_block_confirmed_address_store(query)); histories out{}; const std::atomic_bool cancel{}; - BOOST_REQUIRE(!query.get_unconfirmed_history(cancel, out, test::block1a_address0, true)); - BOOST_REQUIRE_EQUAL(out.size(), 4u); + BOOST_CHECK(!query.get_unconfirmed_history(cancel, out, test::block1a_address0, true)); + BOOST_CHECK_EQUAL(out.size(), 4u); // Identities (not part of sort). BOOST_CHECK_EQUAL(out.at(0).tx.hash(), test::tx5.hash(false)); // tx5 @@ -126,163 +223,110 @@ BOOST_AUTO_TEST_CASE(query_address__get_unconfirmed_history__turbo_block1a_addre BOOST_CHECK_EQUAL(out.at(3).fee, 0u); // coinbase (archived with null single point). } -BOOST_AUTO_TEST_CASE(query_address__get_confirmed_history__turbo_block1a_address0__expected) +BOOST_AUTO_TEST_CASE(query_address__get_unconfirmed_history__limited__limited_empty) { settings settings{}; settings.path = TEST_DIRECTORY; test::chunk_store store{ settings }; test::query_accessor query{ store }; - BOOST_REQUIRE(!store.create(test::events_handler)); - BOOST_REQUIRE(test::setup_three_block_confirmed_address_store(query)); + BOOST_CHECK(!store.create(test::events_handler)); + BOOST_CHECK(test::setup_three_block_confirmed_address_store(query)); histories out{}; + address_link cursor{}; const std::atomic_bool cancel{}; - BOOST_REQUIRE(!query.get_confirmed_history(cancel, out, test::block1a_address0, true)); - BOOST_REQUIRE_EQUAL(out.size(), 4u); + const auto& hash = test::block1a_address0; - // Identities (not part of sort). - BOOST_REQUIRE_EQUAL(out.at(0).tx.hash(), test::block1a.transactions_ptr()->at(0)->hash(false)); // tx1 - BOOST_REQUIRE_EQUAL(out.at(1).tx.hash(), test::block2a.transactions_ptr()->at(0)->hash(false)); // tx2 - BOOST_REQUIRE_EQUAL(out.at(2).tx.hash(), test::block2a.transactions_ptr()->at(1)->hash(false)); // tx3 - BOOST_REQUIRE_EQUAL(out.at(3).tx.hash(), test::block3a.transactions_ptr()->at(0)->hash(false)); // tx6 + // Limited returned when limit precludes reaching the address cursor (or terminal). + BOOST_CHECK_EQUAL(query.get_unconfirmed_history(cancel, cursor, out, hash, 0, true), error::limited); + BOOST_CHECK(out.empty()); - // Confirmed by height ascending. - BOOST_REQUIRE_EQUAL(out.at(0).tx.height(), 1u); - BOOST_REQUIRE_EQUAL(out.at(1).tx.height(), 2u); - BOOST_REQUIRE_EQUAL(out.at(2).tx.height(), 2u); - BOOST_REQUIRE_EQUAL(out.at(3).tx.height(), 3u); - - // Unconfirmed rooted before unrooted (not part of sort). - - // Confirmed height by block position. - BOOST_REQUIRE_EQUAL(out.at(0).position, 0u); - BOOST_REQUIRE_EQUAL(out.at(1).position, 0u); - BOOST_REQUIRE_EQUAL(out.at(2).position, 1u); - BOOST_REQUIRE_EQUAL(out.at(3).position, 0u); + cursor = address_link::terminal; + BOOST_CHECK_EQUAL(query.get_unconfirmed_history(cancel, cursor, out, hash, 8, true), error::limited); + BOOST_CHECK(out.empty()); - // Unconfirmed system::encode_hash(hash) lexically sorted (not part of sort). + cursor = address_link::terminal; + BOOST_CHECK_EQUAL(query.get_unconfirmed_history(cancel, cursor, out, hash, 9, true), error::success); + BOOST_CHECK_EQUAL(out.size(), 4u); - // Fee (not part of sort). - BOOST_REQUIRE_EQUAL(out.at(0).fee, history::missing_prevout); // spend exceeds value (treated as missing prevout). - BOOST_REQUIRE_EQUAL(out.at(1).fee, history::missing_prevout); // spend exceeds value (treated as missing prevout). - BOOST_REQUIRE_EQUAL(out.at(2).fee, history::missing_prevout); // missing prevout. - BOOST_REQUIRE_EQUAL(out.at(3).fee, history::missing_prevout); // spend exceeds value (treated as missing prevout). + cursor = address_link::terminal; + BOOST_CHECK_EQUAL(query.get_unconfirmed_history(cancel, cursor, out, hash, 100, true), error::success); + BOOST_CHECK_EQUAL(out.size(), 4u); } -BOOST_AUTO_TEST_CASE(query_address__get_history__turbo_block1a_address0__expected) +// get_confirmed_history + +BOOST_AUTO_TEST_CASE(query_address__get_confirmed_history__turbo_block1a_address0__expected) { settings settings{}; settings.path = TEST_DIRECTORY; test::chunk_store store{ settings }; test::query_accessor query{ store }; - BOOST_REQUIRE(!store.create(test::events_handler)); - BOOST_REQUIRE(test::setup_three_block_confirmed_address_store(query)); + BOOST_CHECK(!store.create(test::events_handler)); + BOOST_CHECK(test::setup_three_block_confirmed_address_store(query)); histories out{}; const std::atomic_bool cancel{}; - BOOST_REQUIRE(!query.get_history(cancel, out, test::block1a_address0, true)); - BOOST_REQUIRE_EQUAL(out.size(), 8u); + BOOST_CHECK(!query.get_confirmed_history(cancel, out, test::block1a_address0, true)); + BOOST_CHECK_EQUAL(out.size(), 4u); // Identities (not part of sort). - BOOST_REQUIRE_EQUAL(out.at(0).tx.hash(), test::block1a.transactions_ptr()->at(0)->hash(false)); // tx1/tx1 (same) - BOOST_REQUIRE_EQUAL(out.at(1).tx.hash(), test::block2a.transactions_ptr()->at(0)->hash(false)); // tx2/tx2 (same) - BOOST_REQUIRE_EQUAL(out.at(2).tx.hash(), test::block2a.transactions_ptr()->at(1)->hash(false)); // tx3/tx3 (same) - BOOST_REQUIRE_EQUAL(out.at(3).tx.hash(), test::block3a.transactions_ptr()->at(0)->hash(false)); // tx6/tx6 (same) - BOOST_REQUIRE_EQUAL(out.at(4).tx.hash(), test::tx5.hash(false)); // tx5/tx4 - BOOST_REQUIRE_EQUAL(out.at(5).tx.hash(), test::tx4.hash(false)); // tx4/tx8 - BOOST_REQUIRE_EQUAL(out.at(6).tx.hash(), test::block2b.transactions_ptr()->at(0)->hash(false)); // tx8/tx5 - BOOST_REQUIRE_EQUAL(out.at(7).tx.hash(), test::block1b.transactions_ptr()->at(0)->hash(false)); // tx7/tx7 (same) + BOOST_CHECK_EQUAL(out.at(0).tx.hash(), test::block1a.transactions_ptr()->at(0)->hash(false)); // tx1/tx1 (same) + BOOST_CHECK_EQUAL(out.at(1).tx.hash(), test::block2a.transactions_ptr()->at(0)->hash(false)); // tx2/tx2 (same) + BOOST_CHECK_EQUAL(out.at(2).tx.hash(), test::block2a.transactions_ptr()->at(1)->hash(false)); // tx3/tx3 (same) + BOOST_CHECK_EQUAL(out.at(3).tx.hash(), test::block3a.transactions_ptr()->at(0)->hash(false)); // tx6/tx6 (same) // Confirmed by height ascending. - // Unconfirmed rooted before unrooted. - // NOTE: at(5) is spend exceeds value, which is returned as unrooted_height in get_unconfirmed_history() - // NOTE: but as rooted_height in get_history(). This is a consequence of the optimized processing order - // NOTE: and does not affect valid confirmed/unconfirmed txs. - BOOST_REQUIRE_EQUAL(out.at(0).tx.height(), 1u); // tx1 - BOOST_REQUIRE_EQUAL(out.at(1).tx.height(), 2u); // tx2 - BOOST_REQUIRE_EQUAL(out.at(2).tx.height(), 2u); // tx3 - BOOST_REQUIRE_EQUAL(out.at(3).tx.height(), 3u); // tx6 - BOOST_REQUIRE_EQUAL(out.at(4).tx.height(), history::rooted_height); // tx5/tx4 - BOOST_REQUIRE_EQUAL(out.at(5).tx.height(), history::rooted_height); // tx4/tx8 - BOOST_REQUIRE_EQUAL(out.at(6).tx.height(), history::unrooted_height); // tx8/tx5 - BOOST_REQUIRE_EQUAL(out.at(7).tx.height(), history::unrooted_height); // tx7 + BOOST_CHECK_EQUAL(out.at(0).tx.height(), 1u); // tx1 + BOOST_CHECK_EQUAL(out.at(1).tx.height(), 2u); // tx2 + BOOST_CHECK_EQUAL(out.at(2).tx.height(), 2u); // tx3 + BOOST_CHECK_EQUAL(out.at(3).tx.height(), 3u); // tx6 // Confirmed height by block position. - BOOST_REQUIRE_EQUAL(out.at(0).position, 0u); // tx1 - BOOST_REQUIRE_EQUAL(out.at(1).position, 0u); // tx2 - BOOST_REQUIRE_EQUAL(out.at(2).position, 1u); // tx3 - BOOST_REQUIRE_EQUAL(out.at(3).position, 0u); // tx6 - BOOST_REQUIRE_EQUAL(out.at(4).position, history::unconfirmed_position); // tx5/tx4 - BOOST_REQUIRE_EQUAL(out.at(5).position, history::unconfirmed_position); // tx4/tx8 - BOOST_REQUIRE_EQUAL(out.at(6).position, history::unconfirmed_position); // tx8/tx5 - BOOST_REQUIRE_EQUAL(out.at(7).position, history::unconfirmed_position); // tx7 - - // Unconfirmed system::encode_hash(hash) lexically sorted. - using namespace system; - BOOST_REQUIRE(encode_hash(out.at(6).tx.hash()) < encode_hash(out.at(7).tx.hash())); + BOOST_CHECK_EQUAL(out.at(0).position, 0u); // tx1 + BOOST_CHECK_EQUAL(out.at(1).position, 0u); // tx2 + BOOST_CHECK_EQUAL(out.at(2).position, 1u); // tx3 + BOOST_CHECK_EQUAL(out.at(3).position, 0u); // tx6 // Fee (not part of sort). - BOOST_REQUIRE_EQUAL(out.at(0).fee, history::missing_prevout); // tx1 - BOOST_REQUIRE_EQUAL(out.at(1).fee, history::missing_prevout); // tx2 - BOOST_REQUIRE_EQUAL(out.at(2).fee, history::missing_prevout); // tx3 - BOOST_REQUIRE_EQUAL(out.at(3).fee, history::missing_prevout); // tx6 - BOOST_REQUIRE_EQUAL(out.at(4).fee, history::missing_prevout); // tx5/tx4 - BOOST_REQUIRE_EQUAL(out.at(5).fee, floored_subtract(0x18u + 0x2au, 0x08u)); // tx4/tx8 - BOOST_REQUIRE_EQUAL(out.at(6).fee, floored_subtract(0xb1u + 0xb1u, 0xb2u)); // tx8/tx5 - BOOST_REQUIRE_EQUAL(out.at(7).fee, history::missing_prevout); // tx7 + BOOST_CHECK_EQUAL(out.at(0).fee, history::missing_prevout); // tx1 + BOOST_CHECK_EQUAL(out.at(1).fee, history::missing_prevout); // tx2 + BOOST_CHECK_EQUAL(out.at(2).fee, history::missing_prevout); // tx3 + BOOST_CHECK_EQUAL(out.at(3).fee, history::missing_prevout); // tx6 } -BOOST_AUTO_TEST_CASE(query_address__get_history__limited__limited_empty) +BOOST_AUTO_TEST_CASE(query_address__get_confirmed_history__limited__limited_empty) { settings settings{}; settings.path = TEST_DIRECTORY; test::chunk_store store{ settings }; test::query_accessor query{ store }; - BOOST_REQUIRE(!store.create(test::events_handler)); - BOOST_REQUIRE(test::setup_three_block_confirmed_address_store(query)); + BOOST_CHECK(!store.create(test::events_handler)); + BOOST_CHECK(test::setup_three_block_confirmed_address_store(query)); histories out{}; address_link cursor{}; const std::atomic_bool cancel{}; - BOOST_REQUIRE_EQUAL(query.get_history(cancel, cursor, out, test::block1a_address0, 0, true), error::limited); - BOOST_REQUIRE(out.empty()); + const auto& hash = test::block1a_address0; - cursor = address_link::terminal; - BOOST_REQUIRE_EQUAL(query.get_history(cancel, cursor, out, test::block1a_address0, 1, true), error::limited); - BOOST_REQUIRE(out.empty()); + // Limited returned when limit precludes reaching address cursor (or terminal). + BOOST_CHECK_EQUAL(query.get_confirmed_history(cancel, cursor, out, hash, 0, true), error::limited); + BOOST_CHECK(out.empty()); cursor = address_link::terminal; - BOOST_REQUIRE_EQUAL(query.get_history(cancel, cursor, out, test::block1a_address0, 7, true), error::limited); - BOOST_REQUIRE(out.empty()); + BOOST_CHECK_EQUAL(query.get_confirmed_history(cancel, cursor, out, hash, 8, true), error::limited); + BOOST_CHECK(out.empty()); cursor = address_link::terminal; - BOOST_REQUIRE_EQUAL(query.get_history(cancel, cursor, out, test::block1a_address0, 8, true), error::limited); - BOOST_REQUIRE(out.empty()); + BOOST_CHECK_EQUAL(query.get_confirmed_history(cancel, cursor, out, hash, 9, true), error::success); + BOOST_CHECK_EQUAL(out.size(), 4u); cursor = address_link::terminal; - BOOST_REQUIRE_EQUAL(query.get_history(cancel, cursor, out, test::block1a_address0, 9, true), error::success); - BOOST_REQUIRE_EQUAL(out.size(), 8u); - - cursor = address_link::terminal; - BOOST_REQUIRE_EQUAL(query.get_history(cancel, cursor, out, test::block1a_address0, 100, true), error::success); - BOOST_REQUIRE_EQUAL(out.size(), 8u); + BOOST_CHECK_EQUAL(query.get_confirmed_history(cancel, cursor, out, hash, 100, true), error::success); + BOOST_CHECK_EQUAL(out.size(), 4u); } -// get_tx_history1 -// get_tx_history2 - -BOOST_AUTO_TEST_CASE(query_address__get_tx_history__bogus__invalid) -{ - settings settings{}; - settings.path = TEST_DIRECTORY; - test::chunk_store store{ settings }; - test::query_accessor query{ store }; - BOOST_REQUIRE(!store.create(test::events_handler)); - BOOST_REQUIRE(test::setup_three_block_confirmed_address_store(query)); - - const auto history = query.get_tx_history(hash_digest{ 0x42 }); - BOOST_REQUIRE(!history.valid()); -} +// get_tx_history BOOST_AUTO_TEST_CASE(query_address__get_tx_history__genesis__expected) { @@ -290,23 +334,16 @@ BOOST_AUTO_TEST_CASE(query_address__get_tx_history__genesis__expected) settings.path = TEST_DIRECTORY; test::chunk_store store{ settings }; test::query_accessor query{ store }; - BOOST_REQUIRE(!store.create(test::events_handler)); - BOOST_REQUIRE(test::setup_three_block_confirmed_address_store(query)); + BOOST_CHECK(!store.create(test::events_handler)); + BOOST_CHECK(test::setup_three_block_confirmed_address_store(query)); const auto hash = test::genesis.transactions_ptr()->at(0)->hash(false); auto history = query.get_tx_history(0); - BOOST_REQUIRE(history.valid()); - BOOST_REQUIRE_EQUAL(history.fee, history::missing_prevout); - BOOST_REQUIRE_EQUAL(history.position, 0u); - BOOST_REQUIRE_EQUAL(history.tx.height(), 0u); - BOOST_REQUIRE_EQUAL(history.tx.hash(), hash); - - history = query.get_tx_history(hash); - BOOST_REQUIRE(history.valid()); - BOOST_REQUIRE_EQUAL(history.fee, history::missing_prevout); - BOOST_REQUIRE_EQUAL(history.position, 0u); - BOOST_REQUIRE_EQUAL(history.tx.height(), 0u); - BOOST_REQUIRE_EQUAL(history.tx.hash(), hash); + BOOST_CHECK(history.valid()); + BOOST_CHECK_EQUAL(history.fee, history::missing_prevout); + BOOST_CHECK_EQUAL(history.position, 0u); + BOOST_CHECK_EQUAL(history.tx.height(), 0u); + BOOST_CHECK_EQUAL(history.tx.hash(), hash); } BOOST_AUTO_TEST_CASE(query_address__get_tx_history__confirmed__expected) @@ -315,16 +352,16 @@ BOOST_AUTO_TEST_CASE(query_address__get_tx_history__confirmed__expected) settings.path = TEST_DIRECTORY; test::chunk_store store{ settings }; test::query_accessor query{ store }; - BOOST_REQUIRE(!store.create(test::events_handler)); - BOOST_REQUIRE(test::setup_three_block_confirmed_address_store(query)); + BOOST_CHECK(!store.create(test::events_handler)); + BOOST_CHECK(test::setup_three_block_confirmed_address_store(query)); const auto hash = test::block2a.transactions_ptr()->at(0)->hash(false); - const auto history = query.get_tx_history(hash); - BOOST_REQUIRE(history.valid()); - BOOST_REQUIRE_EQUAL(history.fee, history::missing_prevout); // spend > value - BOOST_REQUIRE_EQUAL(history.position, 0u); - BOOST_REQUIRE_EQUAL(history.tx.height(), 2u); - BOOST_REQUIRE_EQUAL(history.tx.hash(), hash); + const auto history = query.get_tx_history(query.to_tx(hash)); + BOOST_CHECK(history.valid()); + BOOST_CHECK_EQUAL(history.fee, history::missing_prevout); // spend > value + BOOST_CHECK_EQUAL(history.position, 0u); + BOOST_CHECK_EQUAL(history.tx.height(), 2u); + BOOST_CHECK_EQUAL(history.tx.hash(), hash); } BOOST_AUTO_TEST_CASE(query_address__get_tx_history__confirmed_missing_prevout__expected) @@ -333,16 +370,16 @@ BOOST_AUTO_TEST_CASE(query_address__get_tx_history__confirmed_missing_prevout__e settings.path = TEST_DIRECTORY; test::chunk_store store{ settings }; test::query_accessor query{ store }; - BOOST_REQUIRE(!store.create(test::events_handler)); - BOOST_REQUIRE(test::setup_three_block_confirmed_address_store(query)); + BOOST_CHECK(!store.create(test::events_handler)); + BOOST_CHECK(test::setup_three_block_confirmed_address_store(query)); const auto hash = test::block2a.transactions_ptr()->at(1)->hash(false); - const auto history = query.get_tx_history(hash); - BOOST_REQUIRE(history.valid()); - BOOST_REQUIRE_EQUAL(history.fee, history::missing_prevout); // missing prevout - BOOST_REQUIRE_EQUAL(history.position, 1u); - BOOST_REQUIRE_EQUAL(history.tx.height(), 2u); - BOOST_REQUIRE_EQUAL(history.tx.hash(), hash); + const auto history = query.get_tx_history(query.to_tx(hash)); + BOOST_CHECK(history.valid()); + BOOST_CHECK_EQUAL(history.fee, history::missing_prevout); // missing prevout + BOOST_CHECK_EQUAL(history.position, 1u); + BOOST_CHECK_EQUAL(history.tx.height(), 2u); + BOOST_CHECK_EQUAL(history.tx.hash(), hash); } BOOST_AUTO_TEST_CASE(query_address__get_tx_history__rooted__expected) @@ -351,17 +388,17 @@ BOOST_AUTO_TEST_CASE(query_address__get_tx_history__rooted__expected) settings.path = TEST_DIRECTORY; test::chunk_store store{ settings }; test::query_accessor query{ store }; - BOOST_REQUIRE(!store.create(test::events_handler)); - BOOST_REQUIRE(test::setup_three_block_confirmed_address_store(query)); + BOOST_CHECK(!store.create(test::events_handler)); + BOOST_CHECK(test::setup_three_block_confirmed_address_store(query)); using namespace system; const auto hash = test::tx4.hash(false); - const auto history = query.get_tx_history(hash); - BOOST_REQUIRE(history.valid()); - BOOST_REQUIRE_EQUAL(history.fee, floored_subtract(0x18u + 0x2au, 0x08u)); - BOOST_REQUIRE_EQUAL(history.position, history::unconfirmed_position); - BOOST_REQUIRE_EQUAL(history.tx.height(), history::rooted_height); - BOOST_REQUIRE_EQUAL(history.tx.hash(), hash); + const auto history = query.get_tx_history(query.to_tx(hash)); + BOOST_CHECK(history.valid()); + BOOST_CHECK_EQUAL(history.fee, floored_subtract(0x18u + 0x2au, 0x08u)); + BOOST_CHECK_EQUAL(history.position, history::unconfirmed_position); + BOOST_CHECK_EQUAL(history.tx.height(), history::rooted_height); + BOOST_CHECK_EQUAL(history.tx.hash(), hash); } BOOST_AUTO_TEST_CASE(query_address__get_tx_history__unrooted__expected) @@ -370,17 +407,17 @@ BOOST_AUTO_TEST_CASE(query_address__get_tx_history__unrooted__expected) settings.path = TEST_DIRECTORY; test::chunk_store store{ settings }; test::query_accessor query{ store }; - BOOST_REQUIRE(!store.create(test::events_handler)); - BOOST_REQUIRE(test::setup_three_block_confirmed_address_store(query)); + BOOST_CHECK(!store.create(test::events_handler)); + BOOST_CHECK(test::setup_three_block_confirmed_address_store(query)); using namespace system; const auto hash = test::block2b.transactions_ptr()->at(0)->hash(false); - const auto history = query.get_tx_history(hash); - BOOST_REQUIRE(history.valid()); - BOOST_REQUIRE_EQUAL(history.fee, floored_subtract(0xb1u + 0xb1u, 0xb2u)); - BOOST_REQUIRE_EQUAL(history.position, history::unconfirmed_position); - BOOST_REQUIRE_EQUAL(history.tx.height(), history::unrooted_height); - BOOST_REQUIRE_EQUAL(history.tx.hash(), hash); + const auto history = query.get_tx_history(query.to_tx(hash)); + BOOST_CHECK(history.valid()); + BOOST_CHECK_EQUAL(history.fee, floored_subtract(0xb1u + 0xb1u, 0xb2u)); + BOOST_CHECK_EQUAL(history.position, history::unconfirmed_position); + BOOST_CHECK_EQUAL(history.tx.height(), history::unrooted_height); + BOOST_CHECK_EQUAL(history.tx.hash(), hash); } // get_spenders_history1 @@ -392,14 +429,14 @@ BOOST_AUTO_TEST_CASE(query_address__get_spenders_history__bogus__empty) settings.path = TEST_DIRECTORY; test::chunk_store store{ settings }; test::query_accessor query{ store }; - BOOST_REQUIRE(!store.create(test::events_handler)); - BOOST_REQUIRE(test::setup_three_block_confirmed_address_store(query)); + BOOST_CHECK(!store.create(test::events_handler)); + BOOST_CHECK(test::setup_three_block_confirmed_address_store(query)); auto histories = query.get_spenders_history({ 0x42 }, 0); - BOOST_REQUIRE(histories.empty()); + BOOST_CHECK(histories.empty()); histories = query.get_spenders_history({ { 0x42 }, 0 }); - BOOST_REQUIRE(histories.empty()); + BOOST_CHECK(histories.empty()); } BOOST_AUTO_TEST_CASE(query_address__get_spenders_history__genesis__expected) @@ -408,15 +445,15 @@ BOOST_AUTO_TEST_CASE(query_address__get_spenders_history__genesis__expected) settings.path = TEST_DIRECTORY; test::chunk_store store{ settings }; test::query_accessor query{ store }; - BOOST_REQUIRE(!store.create(test::events_handler)); - BOOST_REQUIRE(test::setup_three_block_confirmed_address_store(query)); + BOOST_CHECK(!store.create(test::events_handler)); + BOOST_CHECK(test::setup_three_block_confirmed_address_store(query)); const auto hash = test::genesis.transactions_ptr()->at(0)->hash(false); auto histories = query.get_spenders_history(hash, 0); - BOOST_REQUIRE(histories.empty()); + BOOST_CHECK(histories.empty()); histories = query.get_spenders_history({ hash, 0 }); - BOOST_REQUIRE(histories.empty()); + BOOST_CHECK(histories.empty()); } BOOST_AUTO_TEST_CASE(query_address__get_spenders_history__confirmed__expected) @@ -425,37 +462,37 @@ BOOST_AUTO_TEST_CASE(query_address__get_spenders_history__confirmed__expected) settings.path = TEST_DIRECTORY; test::chunk_store store{ settings }; test::query_accessor query{ store }; - BOOST_REQUIRE(!store.create(test::events_handler)); - BOOST_REQUIRE(test::setup_three_block_confirmed_address_store(query)); + BOOST_CHECK(!store.create(test::events_handler)); + BOOST_CHECK(test::setup_three_block_confirmed_address_store(query)); using namespace system; const auto hash = test::block1a.transactions_ptr()->at(0)->hash(false); const auto histories = query.get_spenders_history(hash, 0); - BOOST_REQUIRE_EQUAL(histories.size(), 4u); - - BOOST_REQUIRE(histories.at(0).valid()); - BOOST_REQUIRE_EQUAL(histories.at(0).fee, history::missing_prevout); // spend > value - BOOST_REQUIRE_EQUAL(histories.at(0).position, 0u); - BOOST_REQUIRE_EQUAL(histories.at(0).tx.height(), 2u); - BOOST_REQUIRE_EQUAL(histories.at(0).tx.hash(), test::block2a.transactions_ptr()->at(0)->hash(false)); - - BOOST_REQUIRE(histories.at(1).valid()); - BOOST_REQUIRE_EQUAL(histories.at(1).fee, history::missing_prevout); // spend > value - BOOST_REQUIRE_EQUAL(histories.at(1).position, 0u); - BOOST_REQUIRE_EQUAL(histories.at(1).tx.height(), 3u); - BOOST_REQUIRE_EQUAL(histories.at(1).tx.hash(), test::block3a.transactions_ptr()->at(0)->hash(false)); - - BOOST_REQUIRE(histories.at(2).valid()); - BOOST_REQUIRE_EQUAL(histories.at(2).fee, history::missing_prevout); // spend > value - BOOST_REQUIRE_EQUAL(histories.at(2).position, history::unconfirmed_position); - BOOST_REQUIRE_EQUAL(histories.at(2).tx.height(), history::rooted_height); - BOOST_REQUIRE_EQUAL(histories.at(2).tx.hash(), test::tx5.hash(false)); - - BOOST_REQUIRE(histories.at(3).valid()); - BOOST_REQUIRE_EQUAL(histories.at(3).fee, floored_subtract(0x18u + 0x2au, 0x08u)); - BOOST_REQUIRE_EQUAL(histories.at(3).position, history::unconfirmed_position); - BOOST_REQUIRE_EQUAL(histories.at(3).tx.height(), history::rooted_height); - BOOST_REQUIRE_EQUAL(histories.at(3).tx.hash(), test::tx4.hash(false)); + BOOST_CHECK_EQUAL(histories.size(), 4u); + + BOOST_CHECK(histories.at(0).valid()); + BOOST_CHECK_EQUAL(histories.at(0).fee, history::missing_prevout); // spend > value + BOOST_CHECK_EQUAL(histories.at(0).position, 0u); + BOOST_CHECK_EQUAL(histories.at(0).tx.height(), 2u); + BOOST_CHECK_EQUAL(histories.at(0).tx.hash(), test::block2a.transactions_ptr()->at(0)->hash(false)); + + BOOST_CHECK(histories.at(1).valid()); + BOOST_CHECK_EQUAL(histories.at(1).fee, history::missing_prevout); // spend > value + BOOST_CHECK_EQUAL(histories.at(1).position, 0u); + BOOST_CHECK_EQUAL(histories.at(1).tx.height(), 3u); + BOOST_CHECK_EQUAL(histories.at(1).tx.hash(), test::block3a.transactions_ptr()->at(0)->hash(false)); + + BOOST_CHECK(histories.at(2).valid()); + BOOST_CHECK_EQUAL(histories.at(2).fee, history::missing_prevout); // spend > value + BOOST_CHECK_EQUAL(histories.at(2).position, history::unconfirmed_position); + BOOST_CHECK_EQUAL(histories.at(2).tx.height(), history::rooted_height); + BOOST_CHECK_EQUAL(histories.at(2).tx.hash(), test::tx5.hash(false)); + + BOOST_CHECK(histories.at(3).valid()); + BOOST_CHECK_EQUAL(histories.at(3).fee, floored_subtract(0x18u + 0x2au, 0x08u)); + BOOST_CHECK_EQUAL(histories.at(3).position, history::unconfirmed_position); + BOOST_CHECK_EQUAL(histories.at(3).tx.height(), history::rooted_height); + BOOST_CHECK_EQUAL(histories.at(3).tx.hash(), test::tx4.hash(false)); } BOOST_AUTO_TEST_SUITE_END()