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
10 changes: 8 additions & 2 deletions include/bitcoin/database/impl/query/confirmed.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -161,9 +161,15 @@ bool CLASS::is_unconfirmed_spent(const output_link& link) const NOEXCEPT
TEMPLATE
bool CLASS::is_spent(const output_link& link) const NOEXCEPT
{
// *Any* tx spends the output. Note that this could even be a tx that is in
return is_spent(get_outpoint(link).point());
}

TEMPLATE
bool CLASS::is_spent(const point& prevout) const NOEXCEPT
{
// *Any* tx spends the point. Note that this could even be a tx that is in
// conflict with another long-confirmed tx, or a valid tx in invalid block.
return store_.ins.exists(get_outpoint(link).point());
return store_.ins.exists(prevout);
}

} // namespace database
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,31 +49,31 @@ bool CLASS::populate_with_metadata(const block& block,
}

TEMPLATE
bool CLASS::populate_with_metadata(const transaction& tx,
bool chain) const NOEXCEPT
bool CLASS::populate_with_metadata(const transaction& tx, bool chain,
bool pool) const NOEXCEPT
{
// This override makes the public method safe for coinbase calling.
return tx.is_coinbase() || populate_with_metadata_(tx, chain);
return tx.is_coinbase() || populate_with_metadata_(tx, chain, pool);
}

// protected
TEMPLATE
bool CLASS::populate_with_metadata_(const transaction& tx,
bool chain) const NOEXCEPT
bool CLASS::populate_with_metadata_(const transaction& tx, bool chain,
bool pool) const NOEXCEPT
{
BC_ASSERT(!tx.is_coinbase());

const auto& ins = tx.inputs_ptr();
return std::all_of(ins->begin(), ins->end(),
[this, chain](const auto& in) NOEXCEPT
[this, chain, pool](const auto& in) NOEXCEPT
{
return this->populate_with_metadata(*in, chain);
return this->populate_with_metadata(*in, chain, pool);
});
}

TEMPLATE
bool CLASS::populate_with_metadata(const input& input,
bool chain) const NOEXCEPT
bool CLASS::populate_with_metadata(const input& input, bool chain,
bool pool) const NOEXCEPT
{
// Null point would return nullptr and be interpreted as missing.
BC_ASSERT(!input.point().is_null());
Expand Down Expand Up @@ -119,7 +119,13 @@ bool CLASS::populate_with_metadata(const input& input,
metadata.median_time_past = max_uint32;
}

if (const auto height = find_strong_spender_height(input.point());
if (pool)
{
// Any spender (including duplicate tx) implies spent.
const auto spent = is_spent(input.point());
metadata.spender_height = spent ? 0_u32 : max_uint32;
}
else if (const auto height = find_strong_spender_height(input.point());
!height.is_terminal())
{
// Confirmed spender found at height.
Expand Down
12 changes: 8 additions & 4 deletions include/bitcoin/database/query.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -468,9 +468,12 @@ class query
bool populate_without_metadata(const transaction& tx) const NOEXCEPT;

/// False implies missing prevouts, node input.metadata is populated.
bool populate_with_metadata(const input& input, bool chain=false) const NOEXCEPT;
/// Pool implies free tx, where any conflict implies is spent at height 0.
bool populate_with_metadata(const input& input, bool chain=false,
bool pool=false) const NOEXCEPT;
bool populate_with_metadata(const block& block, bool chain=false) const NOEXCEPT;
bool populate_with_metadata(const transaction& tx, bool chain=false) const NOEXCEPT;
bool populate_with_metadata(const transaction& tx, bool chain=false,
bool pool=false) const NOEXCEPT;

/// Fees.
/// -----------------------------------------------------------------------
Expand Down Expand Up @@ -645,6 +648,7 @@ class query
bool is_unconfirmed_spent(const output_link& link) const NOEXCEPT;
bool is_confirmed_spent(const output_link& link) const NOEXCEPT;
bool is_spent(const output_link& link) const NOEXCEPT;
bool is_spent(const point& prevout) const NOEXCEPT;

/// Height index not used by these.
bool is_strong_tx(const tx_link& link) const NOEXCEPT;
Expand Down Expand Up @@ -923,8 +927,8 @@ class query
const header_link& link, size_t height) const NOEXCEPT;

/// Bypasses and only asserts coinbase guard (internal use).
bool populate_with_metadata_(const transaction& tx,
bool chain) const NOEXCEPT;
bool populate_with_metadata_(const transaction& tx, bool chain,
bool pool) const NOEXCEPT;

/// merkle
/// -----------------------------------------------------------------------
Expand Down
28 changes: 28 additions & 0 deletions test/query/archive/chain_reader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -852,6 +852,34 @@ BOOST_AUTO_TEST_CASE(query_chain_reader__populate_with_metadata__metadata__expec
BOOST_CHECK_EQUAL(tx4.inputs_ptr()->at(1)->metadata.parent_tx, 1u);
}

// A free tx cannot conflict, so any spender of its prevout implies spent.
BOOST_AUTO_TEST_CASE(query_chain_reader__populate_with_metadata__pool_spender__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(query.initialize(test::genesis));
BOOST_CHECK(query.set(test::block1a, test::context, false, false));

// tx5 spends the first output of the first tx of block1a, as does tx4.
const auto& unspent = clean_(test::tx5);
BOOST_CHECK(query.populate_with_metadata(unspent, true, true));
BOOST_CHECK_EQUAL(unspent.inputs_ptr()->at(0)->metadata.spender_height, max_uint32);

BOOST_CHECK(query.set(test::tx4));

const auto& spent = clean_(test::tx5);
BOOST_CHECK(query.populate_with_metadata(spent, true, true));
BOOST_CHECK_EQUAL(spent.inputs_ptr()->at(0)->metadata.spender_height, 0u);

// The spender is unassociated, so it is not a confirmed spender.
const auto& chained = clean_(test::tx5);
BOOST_CHECK(query.populate_with_metadata(chained, true, false));
BOOST_CHECK_EQUAL(chained.inputs_ptr()->at(0)->metadata.spender_height, max_uint32);
}

// populate_without_metadata
// ----------------------------------------------------------------------------

Expand Down
Loading