Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 15 additions & 3 deletions include/bitcoin/database/impl/query/navigate/navigate_reverse.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -99,21 +99,33 @@ TEMPLATE
code CLASS::to_address_outputs(const stopper& cancel, output_links& out,
const hash_digest& key) const NOEXCEPT
{
// Pushing into the vector is more efficient than precomputation of size.
address_link cursor{};
return to_address_outputs(cancel, cursor, out, key);
}

TEMPLATE
code CLASS::to_address_outputs(const stopper& cancel, address_link& cursor,
output_links& out, const hash_digest& key) const NOEXCEPT
{
out.clear();
for (auto it = store_.address.it(key); it; ++it)
const auto end = cursor;
auto it = store_.address.it(key);
for (cursor = it.get(); it; ++it)
{
if (cancel)
return error::canceled;

if (it.get() == end)
return error::success;

table::address::record address{};
if (!store_.address.get(it, address))
return error::integrity;

out.push_back(address.output_fk);
}

return error::success;
return end.is_terminal() ? error::success : error::not_found;
}

// input|output|prevout->tx[parent]
Expand Down
2 changes: 2 additions & 0 deletions include/bitcoin/database/query.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,8 @@ class query
const hash_digest& key) const NOEXCEPT;
code to_address_outputs(const stopper& cancel, output_links& out,
const hash_digest& key) const NOEXCEPT;
code to_address_outputs(const stopper& cancel, address_link& cursor,
output_links& out, const hash_digest& key) const NOEXCEPT;

/// Archive reads.
/// -----------------------------------------------------------------------
Expand Down
121 changes: 121 additions & 0 deletions test/query/navigate/navigate_reverse.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,127 @@ BOOST_AUTO_TEST_CASE(query_navigate__to_address_outputs2__always__expected)
BOOST_REQUIRE_EQUAL(out.at(5), 81u);
}

// to_address_outputs3

BOOST_AUTO_TEST_CASE(query_navigate__to_address_outputs3__terminal__not_reduced)
{
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(setup_three_block_unconfirmed_address_store(query));

output_links out{};
address_link end{};
const std::atomic_bool cancel{};
BOOST_REQUIRE(!query.to_address_outputs(cancel, end, out, test::block1a_address0));

// There are 6 instances of the `script{ { { opcode::pick } } }` output.
BOOST_REQUIRE_EQUAL(out.size(), 6u);
BOOST_REQUIRE_EQUAL(out.at(0), 123u);
BOOST_REQUIRE_EQUAL(out.at(1), 116u);
BOOST_REQUIRE_EQUAL(out.at(2), 109u);
BOOST_REQUIRE_EQUAL(out.at(3), 102u);
BOOST_REQUIRE_EQUAL(out.at(4), 95u);
BOOST_REQUIRE_EQUAL(out.at(5), 81u);
}

BOOST_AUTO_TEST_CASE(query_navigate__to_address_outputs3__stop_mismatch__populated_not_found)
{
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(setup_three_block_unconfirmed_address_store(query));

output_links out{};
address_link cursor{ 4242 };
const std::atomic_bool cancel{};
const auto ec = query.to_address_outputs(cancel, cursor, out, test::block1a_address0);
BOOST_REQUIRE_EQUAL(ec, error::not_found);

// The end was not found but the full list is returned.
BOOST_REQUIRE_EQUAL(out.size(), 6u);
BOOST_REQUIRE_EQUAL(out.at(0), 123u);
BOOST_REQUIRE_EQUAL(out.at(1), 116u);
BOOST_REQUIRE_EQUAL(out.at(2), 109u);
BOOST_REQUIRE_EQUAL(out.at(3), 102u);
BOOST_REQUIRE_EQUAL(out.at(4), 95u);
BOOST_REQUIRE_EQUAL(out.at(5), 81u);
}

BOOST_AUTO_TEST_CASE(query_navigate__to_address_outputs3__stop_match__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(setup_three_block_unconfirmed_address_store(query));

output_links out{};
address_link cursor{ 3 };
const std::atomic_bool cancel{};
BOOST_REQUIRE(!query.to_address_outputs(cancel, cursor, out, test::block1a_address0));
BOOST_REQUIRE_EQUAL(cursor.value, 7u);

// The stop was found so partial list is returned.
BOOST_REQUIRE_EQUAL(out.size(), 4u);
BOOST_REQUIRE_EQUAL(out.at(0), 123u);
BOOST_REQUIRE_EQUAL(out.at(1), 116u);
BOOST_REQUIRE_EQUAL(out.at(2), 109u);
BOOST_REQUIRE_EQUAL(out.at(3), 102u);
}

BOOST_AUTO_TEST_CASE(query_navigate__to_address_outputs3__progression__expected)
{
settings settings{};
settings.path = TEST_DIRECTORY;
test::chunk_store store{ settings };
test::query_accessor query{ store };
BOOST_REQUIRE(!store.create(test::events_handler));

output_links out{};
address_link cursor{};
const std::atomic_bool cancel{};

// Add three unconfirmed blocks and two txs, with 7 outputs, 6 matching address.
BOOST_REQUIRE(setup_three_block_unconfirmed_address_store(query));
BOOST_REQUIRE(!query.to_address_outputs(cancel, cursor, out, test::block1a_address0));
BOOST_REQUIRE_EQUAL(cursor.value, 7u);
BOOST_REQUIRE_EQUAL(out.size(), 6u);
BOOST_REQUIRE_EQUAL(out.at(0), 123u);
BOOST_REQUIRE_EQUAL(out.at(1), 116u);
BOOST_REQUIRE_EQUAL(out.at(2), 109u);
BOOST_REQUIRE_EQUAL(out.at(3), 102u);
BOOST_REQUIRE_EQUAL(out.at(4), 95u);
BOOST_REQUIRE_EQUAL(out.at(5), 81u);

// Add two unconfirmed blocks with 3 outputs, all matching address.
BOOST_REQUIRE(query.set(test::block1b, database::context{ 0, 1, 0 }, false, false));
BOOST_REQUIRE(query.set(test::block2b, database::context{ 0, 2, 0 }, false, false));
BOOST_REQUIRE(!query.to_address_outputs(cancel, cursor, out, test::block1a_address0));
BOOST_REQUIRE_EQUAL(cursor.value, 10u);
BOOST_REQUIRE_EQUAL(out.size(), 3u);
BOOST_REQUIRE_EQUAL(out.at(0), 144u);
BOOST_REQUIRE_EQUAL(out.at(1), 137u);
BOOST_REQUIRE_EQUAL(out.at(2), 130u);

// Add one tx with one output, matching address.
BOOST_REQUIRE(query.set(test::tx2b));
BOOST_REQUIRE(!query.to_address_outputs(cancel, cursor, out, test::block1a_address0));
BOOST_REQUIRE_EQUAL(cursor.value, 11u);
BOOST_REQUIRE_EQUAL(out.size(), 1u);
BOOST_REQUIRE_EQUAL(out.at(0), 151u);

// No changes to this address since cursor.
BOOST_REQUIRE(!query.to_address_outputs(cancel, cursor, out, test::block1a_address0));
BOOST_REQUIRE_EQUAL(cursor.value, 11u);
BOOST_REQUIRE(out.empty());
}

// to_input_tx
// to_output_tx

Expand Down