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
22 changes: 13 additions & 9 deletions include/bitcoin/database/impl/query/address/address_history.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,11 @@ code CLASS::get_unconfirmed_history(const stopper& cancel, histories& out,
}

uint64_t fee{};
auto height = history::unrooted_height;
if (!get_tx_fee(fee, link))
fee = history::missing_prevout;
else if (is_confirmed_all_prevouts(link))

auto height = history::unrooted_height;
if (is_confirmed_all_prevouts(link))
height = history::rooted_height;

return history{ { std::move(hash), height }, fee,
Expand Down Expand Up @@ -115,9 +116,10 @@ code CLASS::get_confirmed_history(const stopper& cancel, histories& out,
return history{};
}

uint64_t fee{};
if (!get_tx_fee(fee, link))
fee = history::missing_prevout;
// 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 };
});
Expand Down Expand Up @@ -176,10 +178,8 @@ history CLASS::get_tx_history(hash_digest&& key,
if (link.is_terminal())
return {};

uint64_t fee{};
if (!get_tx_fee(fee, link))
fee = history::missing_prevout;

// Electrum uses fees only on unconfirmed (and expensive).
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())
Expand All @@ -190,13 +190,17 @@ history CLASS::get_tx_history(hash_digest&& key,
}
else
{
if (!get_tx_fee(fee, link))
fee = history::missing_prevout;

if (is_confirmed_all_prevouts(link))
height = history::rooted_height;
}

return { { std::move(key), height }, fee, position };
}

// server/electrum
TEMPLATE
histories CLASS::get_spenders_history(
const system::chain::point& prevout) const NOEXCEPT
Expand Down
24 changes: 24 additions & 0 deletions include/bitcoin/database/impl/query/address/address_outpoints.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,30 @@ code CLASS::get_address_outpoints(const stopper& cancel, outpoints& out,
});
}

// TODO: server/native
TEMPLATE
code CLASS::get_address_outpoints(const stopper& cancel, address_link& cursor,
outpoints& out, const hash_digest& key, bool turbo) const NOEXCEPT
{
out.clear();
output_links links{};
if (const code ec = to_address_outputs(cancel, cursor, links, key))
return ec;

return parallel_outpoint_transform(cancel, turbo, out, links,
[this](const output_link& link, auto& cancel, auto& fail) NOEXCEPT
{
if (cancel || fail)
return outpoint{};

const auto point = get_outpoint(link);
if (!point.point().is_valid())
fail = true;

return point;
});
}

// utilities
// ----------------------------------------------------------------------------
// private/static
Expand Down
3 changes: 3 additions & 0 deletions include/bitcoin/database/query.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -630,6 +630,8 @@ class query
const hash_digest& key, uint64_t value, bool turbo=false) const NOEXCEPT;
code get_address_outpoints(const stopper& cancel, outpoints& out,
const hash_digest& key, bool turbo=false) const NOEXCEPT;
code get_address_outpoints(const stopper& cancel, address_link& cursor,
outpoints& out, const hash_digest& key, bool turbo=false) const NOEXCEPT;

/// Electrum queries (histories, deduped, electrum sort).
code get_unconfirmed_history(const stopper& cancel, histories& out,
Expand Down Expand Up @@ -657,6 +659,7 @@ 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;
histories get_spenders_history(const point& prevout) const NOEXCEPT;
Expand Down
2 changes: 1 addition & 1 deletion include/bitcoin/database/types/history.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ struct BCD_API history
{
static constexpr size_t rooted_height = zero;
static constexpr size_t unrooted_height = max_size_t;
static constexpr size_t missing_prevout = max_uint64;
static constexpr size_t unconfirmed_position = max_size_t;
static constexpr uint64_t missing_prevout = max_uint64;

static void filter_sort_and_dedup(std::vector<history>& history) NOEXCEPT;

Expand Down
46 changes: 23 additions & 23 deletions test/query/address/address_history.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,14 @@ BOOST_AUTO_TEST_CASE(query_address__get_history__genesis__expected)

out.clear();
BOOST_REQUIRE(!query.get_confirmed_history(cancel, out, test::genesis_address0));
BOOST_REQUIRE_EQUAL(out.at(0).fee, 0u);
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));

out.clear();
BOOST_REQUIRE(!query.get_history(cancel, out, test::genesis_address0));
BOOST_REQUIRE_EQUAL(out.at(0).fee, 0u);
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));
Expand Down Expand Up @@ -96,34 +96,34 @@ BOOST_AUTO_TEST_CASE(query_address__get_unconfirmed_history__turbo_block1a_addre
BOOST_REQUIRE_EQUAL(out.size(), 4u);

// Identities (not part of sort).
BOOST_REQUIRE_EQUAL(out.at(0).tx.hash(), test::tx4.hash(false)); // tx4
BOOST_REQUIRE_EQUAL(out.at(1).tx.hash(), test::block2b.transactions_ptr()->at(0)->hash(false)); // tx8
BOOST_REQUIRE_EQUAL(out.at(2).tx.hash(), test::tx5.hash(false)); // tx5
BOOST_REQUIRE_EQUAL(out.at(3).tx.hash(), test::block1b.transactions_ptr()->at(0)->hash(false)); // tx7
BOOST_CHECK_EQUAL(out.at(0).tx.hash(), test::tx5.hash(false)); // tx5
BOOST_CHECK_EQUAL(out.at(1).tx.hash(), test::tx4.hash(false)); // tx4
BOOST_CHECK_EQUAL(out.at(2).tx.hash(), test::block2b.transactions_ptr()->at(0)->hash(false)); // tx8
BOOST_CHECK_EQUAL(out.at(3).tx.hash(), test::block1b.transactions_ptr()->at(0)->hash(false)); // tx7

// Confirmed by height ascending (not part of sort).

// Unconfirmed rooted before unrooted.
BOOST_REQUIRE_EQUAL(out.at(0).tx.height(), history::rooted_height); // spends block1a (tx0 both outputs).
BOOST_REQUIRE_EQUAL(out.at(1).tx.height(), history::unrooted_height); // bk2btx0 unrooted (spends bk1).
BOOST_REQUIRE_EQUAL(out.at(2).tx.height(), history::unrooted_height); // spend exceeds value (treated as missing prevout).
BOOST_REQUIRE_EQUAL(out.at(3).tx.height(), history::unrooted_height); // bk1btx0 unrooted (missing prevouts).
BOOST_CHECK_EQUAL(out.at(0).tx.height(), history::rooted_height); // tx5 spends block1a
BOOST_CHECK_EQUAL(out.at(1).tx.height(), history::rooted_height); // tx4 spends block1a
BOOST_CHECK_EQUAL(out.at(2).tx.height(), history::unrooted_height); // block2b spends block1b
BOOST_CHECK_EQUAL(out.at(3).tx.height(), history::unrooted_height); // block1b missing prevouts

// Confirmed height by block position (not part of sort).
BOOST_REQUIRE_EQUAL(out.at(0).position, history::unconfirmed_position);
BOOST_REQUIRE_EQUAL(out.at(1).position, history::unconfirmed_position);
BOOST_REQUIRE_EQUAL(out.at(2).position, history::unconfirmed_position);
BOOST_REQUIRE_EQUAL(out.at(3).position, history::unconfirmed_position);
BOOST_CHECK_EQUAL(out.at(0).position, history::unconfirmed_position);
BOOST_CHECK_EQUAL(out.at(1).position, history::unconfirmed_position);
BOOST_CHECK_EQUAL(out.at(2).position, history::unconfirmed_position);
BOOST_CHECK_EQUAL(out.at(3).position, history::unconfirmed_position);

// Unconfirmed system::encode_hash(hash) lexically sorted.
BOOST_REQUIRE(encode_hash(out.at(1).tx.hash()) < encode_hash(out.at(2).tx.hash()));
BOOST_REQUIRE(encode_hash(out.at(2).tx.hash()) < encode_hash(out.at(3).tx.hash()));
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()));

// Fee (not part of sort).
BOOST_REQUIRE_EQUAL(out.at(0).fee, floored_subtract(0x18u + 0x2au, 0x08u));
BOOST_REQUIRE_EQUAL(out.at(1).fee, floored_subtract(0xb1u + 0xb1u, 0xb2u));
BOOST_REQUIRE_EQUAL(out.at(2).fee, history::missing_prevout); // spend exceeds value (treated as missing prevout).
BOOST_REQUIRE_EQUAL(out.at(3).fee, 0u); // coinbase (archived with null single point).
BOOST_CHECK_EQUAL(out.at(0).fee, history::missing_prevout); // spend exceeds value (treated as missing prevout).
BOOST_CHECK_EQUAL(out.at(1).fee, floored_subtract(0x18u + 0x2au, 0x08u));
BOOST_CHECK_EQUAL(out.at(2).fee, floored_subtract(0xb1u + 0xb1u, 0xb2u));
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)
Expand Down Expand Up @@ -229,7 +229,7 @@ BOOST_AUTO_TEST_CASE(query_address__get_history__turbo_block1a_address0__expecte
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, 0u); // tx7
BOOST_REQUIRE_EQUAL(out.at(7).fee, history::missing_prevout); // tx7
}

// get_tx_history1
Expand Down Expand Up @@ -260,14 +260,14 @@ BOOST_AUTO_TEST_CASE(query_address__get_tx_history__genesis__expected)
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, 0u);
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, 0u);
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);
Expand Down
30 changes: 26 additions & 4 deletions test/query/address/address_outpoints.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -124,9 +124,9 @@ BOOST_AUTO_TEST_CASE(query_address__get_minimum_unspent_outpoints__below__includ
BOOST_REQUIRE(*out.begin() == query.get_outpoint(query.to_output(0, 0)));
}

// get_address_outpoints
// get_address_outpoints1

BOOST_AUTO_TEST_CASE(query_address__get_address_outpoints__turbo_genesis__expected)
BOOST_AUTO_TEST_CASE(query_address__get_address_outpoints1__turbo_genesis__expected)
{
settings settings{};
settings.path = TEST_DIRECTORY;
Expand All @@ -142,7 +142,7 @@ BOOST_AUTO_TEST_CASE(query_address__get_address_outpoints__turbo_genesis__expect
BOOST_REQUIRE(*out.begin() == query.get_outpoint(query.to_output(0, 0)));
}

BOOST_AUTO_TEST_CASE(query_address__get_address_outpoints__genesis__expected)
BOOST_AUTO_TEST_CASE(query_address__get_address_outpoints1__genesis__expected)
{
settings settings{};
settings.path = TEST_DIRECTORY;
Expand All @@ -158,7 +158,7 @@ BOOST_AUTO_TEST_CASE(query_address__get_address_outpoints__genesis__expected)
BOOST_REQUIRE(*out.begin() == query.get_outpoint(query.to_output(0, 0)));
}

BOOST_AUTO_TEST_CASE(query_address__get_address_outpoints__cancel__canceled_false)
BOOST_AUTO_TEST_CASE(query_address__get_address_outpoints1__cancel__canceled_false)
{
settings settings{};
settings.path = TEST_DIRECTORY;
Expand All @@ -173,4 +173,26 @@ BOOST_AUTO_TEST_CASE(query_address__get_address_outpoints__cancel__canceled_fals
BOOST_REQUIRE(out.empty());
}

// get_address_outpoints2

BOOST_AUTO_TEST_CASE(query_address__get_address_outpoints2__progressive_cursor__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(query.initialize(test::genesis));

outpoints out{};
address_link cursor{};
const std::atomic_bool cancel{};
BOOST_REQUIRE(!query.get_address_outpoints(cancel, cursor, out, test::genesis_address0));
BOOST_REQUIRE_EQUAL(out.size(), 1u);
BOOST_REQUIRE_EQUAL(cursor, 0u);
BOOST_REQUIRE(*out.begin() == query.get_outpoint(query.to_output(0, 0)));

// TODO: add same tx again.
}

BOOST_AUTO_TEST_SUITE_END()