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
1 change: 1 addition & 0 deletions include/bitcoin/database/error.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ enum error_t : uint8_t
/// general
success,
canceled,
limited,
unknown_state,

/// integrity (internal fault)
Expand Down
14 changes: 12 additions & 2 deletions include/bitcoin/database/impl/query/address/address_history.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -125,13 +125,23 @@ code CLASS::get_confirmed_history(const stopper& cancel, histories& out,
});
}

// server/electrum
// ununsed
TEMPLATE
code CLASS::get_history(const stopper& cancel, histories& out,
const hash_digest& key, bool turbo) const NOEXCEPT
{
address_link cursor{};
return get_history(cancel, cursor, out, key, max_size_t, turbo);
}

// server/electrum
TEMPLATE
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, outs, key))
if (const auto ec = to_address_outputs(cancel, cursor, outs, key, limit))
return ec;

tx_links links{};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ code CLASS::to_address_outputs(const stopper& cancel, output_links& out,

TEMPLATE
code CLASS::to_address_outputs(const stopper& cancel, address_link& cursor,
output_links& out, const hash_digest& key) const NOEXCEPT
output_links& out, const hash_digest& key, size_t limit) const NOEXCEPT
{
out.clear();
const auto end = cursor;
Expand All @@ -118,6 +118,9 @@ code CLASS::to_address_outputs(const stopper& cancel, address_link& cursor,
if (it.get() == end)
return error::success;

if (is_zero(limit--))
return error::limited;

table::address::record address{};
if (!store_.address.get(it, address))
return error::integrity;
Expand Down
6 changes: 5 additions & 1 deletion include/bitcoin/database/query.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -322,7 +322,8 @@ class query
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;
output_links& out, const hash_digest& key,
size_t limit=max_size_t) const NOEXCEPT;

/// Archive reads.
/// -----------------------------------------------------------------------
Expand Down Expand Up @@ -640,6 +641,9 @@ 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;
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;

/// Electrum queries (unspents, deduped, electrum sort).
code get_unconfirmed_unspent(const stopper& cancel, unspents& out,
Expand Down
1 change: 1 addition & 0 deletions src/error.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ DEFINE_ERROR_T_MESSAGE_MAP(error)
// general
{ success, "success" },
{ canceled, "canceled" },
{ limited, "limited" },
{ unknown_state, "unknown state" },

// integrity (internal fault)
Expand Down
9 changes: 9 additions & 0 deletions test/error.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,15 @@ BOOST_AUTO_TEST_CASE(error_t__code__canceled__true_expected_message)
BOOST_REQUIRE_EQUAL(ec.message(), "canceled");
}

BOOST_AUTO_TEST_CASE(error_t__code__limited__true_expected_message)
{
constexpr auto value = error::limited;
const auto ec = code(value);
BOOST_REQUIRE(ec);
BOOST_REQUIRE(ec == value);
BOOST_REQUIRE_EQUAL(ec.message(), "limited");
}

BOOST_AUTO_TEST_CASE(error_t__code__unknown_state__true_expected_message)
{
constexpr auto value = error::unknown_state;
Expand Down
40 changes: 38 additions & 2 deletions test/query/address/address_history.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,6 @@ BOOST_AUTO_TEST_CASE(query_address__get_unconfirmed_history__turbo_block1a_addre
BOOST_REQUIRE(!store.create(test::events_handler));
BOOST_REQUIRE(test::setup_three_block_confirmed_address_store(query));

using namespace system;
histories out{};
const std::atomic_bool cancel{};
BOOST_REQUIRE(!query.get_unconfirmed_history(cancel, out, test::block1a_address0, true));
Expand All @@ -116,6 +115,7 @@ BOOST_AUTO_TEST_CASE(query_address__get_unconfirmed_history__turbo_block1a_addre
BOOST_CHECK_EQUAL(out.at(3).position, history::unconfirmed_position);

// Unconfirmed system::encode_hash(hash) lexically sorted.
using namespace system;
BOOST_CHECK(encode_hash(out.at(0).tx.hash()) < encode_hash(out.at(1).tx.hash()));
BOOST_CHECK(encode_hash(out.at(2).tx.hash()) < encode_hash(out.at(3).tx.hash()));

Expand Down Expand Up @@ -178,7 +178,6 @@ BOOST_AUTO_TEST_CASE(query_address__get_history__turbo_block1a_address0__expecte
BOOST_REQUIRE(!store.create(test::events_handler));
BOOST_REQUIRE(test::setup_three_block_confirmed_address_store(query));

using namespace system;
histories out{};
const std::atomic_bool cancel{};
BOOST_REQUIRE(!query.get_history(cancel, out, test::block1a_address0, true));
Expand Down Expand Up @@ -219,6 +218,7 @@ BOOST_AUTO_TEST_CASE(query_address__get_history__turbo_block1a_address0__expecte
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()));

// Fee (not part of sort).
Expand All @@ -232,6 +232,42 @@ BOOST_AUTO_TEST_CASE(query_address__get_history__turbo_block1a_address0__expecte
BOOST_REQUIRE_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_REQUIRE(!store.create(test::events_handler));
BOOST_REQUIRE(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());

cursor = address_link::terminal;
BOOST_REQUIRE_EQUAL(query.get_history(cancel, cursor, out, test::block1a_address0, 1, true), error::limited);
BOOST_REQUIRE(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());

cursor = address_link::terminal;
BOOST_REQUIRE_EQUAL(query.get_history(cancel, cursor, out, test::block1a_address0, 8, true), error::limited);
BOOST_REQUIRE(out.empty());

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);
}

// get_tx_history1
// get_tx_history2

Expand Down
25 changes: 25 additions & 0 deletions test/query/navigate/navigate_reverse.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,31 @@ BOOST_AUTO_TEST_CASE(query_navigate__to_address_outputs3__terminal__not_reduced)
BOOST_REQUIRE_EQUAL(out.at(5), 81u);
}

BOOST_AUTO_TEST_CASE(query_navigate__to_address_outputs3__limit__limited)
{
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_EQUAL(query.to_address_outputs(cancel, end, out, test::block1a_address0, 4), error::limited);

// The limit is applied before deduplication.
// There are 6 instances of the `script{ { { opcode::pick } } }` output, limited to 4.
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_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{};
Expand Down