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
2 changes: 2 additions & 0 deletions builds/gnu/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ include_bitcoin_database_impl_query_HEADERS = \
${srcdir}/../../include/bitcoin/database/impl/query/initialize.ipp \
${srcdir}/../../include/bitcoin/database/impl/query/locator.ipp \
${srcdir}/../../include/bitcoin/database/impl/query/merkle.ipp \
${srcdir}/../../include/bitcoin/database/impl/query/pool.ipp \
${srcdir}/../../include/bitcoin/database/impl/query/properties_block.ipp \
${srcdir}/../../include/bitcoin/database/impl/query/properties_tx.ipp \
${srcdir}/../../include/bitcoin/database/impl/query/query.ipp \
Expand Down Expand Up @@ -434,6 +435,7 @@ test_libbitcoin_database_test_SOURCES = \
${srcdir}/../../test/query/initialize.cpp \
${srcdir}/../../test/query/locator.cpp \
${srcdir}/../../test/query/merkle.cpp \
${srcdir}/../../test/query/pool.cpp \
${srcdir}/../../test/query/properties_block.cpp \
${srcdir}/../../test/query/properties_tx.cpp \
${srcdir}/../../test/query/sequences.cpp \
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,9 @@
<ClCompile Include="..\..\..\..\test\query\navigate\navigate_hashmap.cpp" />
<ClCompile Include="..\..\..\..\test\query\navigate\navigate_natural.cpp" />
<ClCompile Include="..\..\..\..\test\query\navigate\navigate_reverse.cpp" />
<ClCompile Include="..\..\..\..\test\query\pool.cpp">
<ObjectFileName>$(IntDir)test_query_pool.obj</ObjectFileName>
</ClCompile>
<ClCompile Include="..\..\..\..\test\query\properties_block.cpp" />
<ClCompile Include="..\..\..\..\test\query\properties_tx.cpp" />
<ClCompile Include="..\..\..\..\test\query\sequences.cpp" />
Expand Down Expand Up @@ -197,7 +200,9 @@
<ClCompile Include="..\..\..\..\test\tables\caches\ecdsa.cpp">
<ObjectFileName>$(IntDir)test_tables_caches_ecdsa.obj</ObjectFileName>
</ClCompile>
<ClCompile Include="..\..\..\..\test\tables\caches\pool.cpp" />
<ClCompile Include="..\..\..\..\test\tables\caches\pool.cpp">
<ObjectFileName>$(IntDir)test_tables_caches_pool.obj</ObjectFileName>
</ClCompile>
<ClCompile Include="..\..\..\..\test\tables\caches\prevalid.cpp">
<ObjectFileName>$(IntDir)test_tables_caches_prevalid.obj</ObjectFileName>
</ClCompile>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,9 @@
<ClCompile Include="..\..\..\..\test\query\navigate\navigate_reverse.cpp">
<Filter>src\query\navigate</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\test\query\pool.cpp">
<Filter>src\query</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\test\query\properties_block.cpp">
<Filter>src\query</Filter>
</ClCompile>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,7 @@
<None Include="..\..\..\..\include\bitcoin\database\impl\query\navigate\navigate_hashmap.ipp" />
<None Include="..\..\..\..\include\bitcoin\database\impl\query\navigate\navigate_natural.ipp" />
<None Include="..\..\..\..\include\bitcoin\database\impl\query\navigate\navigate_reverse.ipp" />
<None Include="..\..\..\..\include\bitcoin\database\impl\query\pool.ipp" />
<None Include="..\..\..\..\include\bitcoin\database\impl\query\properties_block.ipp" />
<None Include="..\..\..\..\include\bitcoin\database\impl\query\properties_tx.ipp" />
<None Include="..\..\..\..\include\bitcoin\database\impl\query\query.ipp" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -648,6 +648,9 @@
<None Include="..\..\..\..\include\bitcoin\database\impl\query\navigate\navigate_reverse.ipp">
<Filter>include\bitcoin\database\impl\query\navigate</Filter>
</None>
<None Include="..\..\..\..\include\bitcoin\database\impl\query\pool.ipp">
<Filter>include\bitcoin\database\impl\query</Filter>
</None>
<None Include="..\..\..\..\include\bitcoin\database\impl\query\properties_block.ipp">
<Filter>include\bitcoin\database\impl\query</Filter>
</None>
Expand Down
27 changes: 27 additions & 0 deletions include/bitcoin/database/impl/query/address/address_outpoints.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,33 @@ namespace database {
// ----------------------------------------------------------------------------
// Address table is populated during transaction archival.

// server/native
// Only unconfirmed outputs that are not spent (by an unconfirmed tx).
TEMPLATE
code CLASS::get_unconfirmed_unspent_outpoints(const stopper& cancel,
outpoints& out, const hash_digest& key, bool turbo) const NOEXCEPT
{
out.clear();
output_links links{};
if (const code ec = to_address_outputs(cancel, links, key))
return ec;

return parallel_outpoint_transform(cancel, turbo, out, links,
[this](const output_link& link, auto& cancel, auto& fail) NOEXCEPT
{
// Confirmed and spent must be filtered out. An unconfirmed output
// can only be spent by an unconfirmed tx, so is_spent() suffices.
if (cancel || fail || is_confirmed_output(link) || is_spent(link))
return outpoint{};

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

return point;
});
}

// server/native
TEMPLATE
code CLASS::get_confirmed_unspent_outpoints(const stopper& cancel,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ code CLASS::block_confirmable(const header_link& link) const NOEXCEPT
// Each non-coinbase tx is validated under its pooled context, which is
// sufficient for the block (absolute locktime is monotonic under bip113). What
// remains is the coinbase, the block checks over all txs, and the prevouts
// row, from which block_confirmable performs the chain checks.
// record, from which block_confirmable performs the chain checks.

TEMPLATE
code CLASS::validate_pooled(const header_link& link, const chain_context& ctx,
Expand Down Expand Up @@ -139,7 +139,7 @@ code CLASS::validate_pooled(const header_link& link, const chain_context& ctx,
// ========================================================================
}

// Tx records and pool rows (early, as insufficiency implies full validation).
// Tx and pool records (early, as insufficiency implies full validation).
TEMPLATE
code CLASS::get_pooled_block(pooled_block& out, const header_link& link,
const context& ctx) const NOEXCEPT
Expand Down
30 changes: 15 additions & 15 deletions include/bitcoin/database/impl/query/consensus/consensus_compact.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,14 @@ code CLASS::get_compact_links(tx_links& out,
if (!get_compact_matches(matches, positions, key))
return error::integrity;

for (const auto& [index, row]: matches)
for (const auto& [index, fk]: matches)
{
if (ambiguous.at(index))
continue;

// The columns of a row are written before its spine record.
const tx_link link{ store_.pool.get_key(row) };
if (store_.pool.first(link) != row)
// The columns of a record are written before its spine entry.
const auto link = to_pool_tx(fk);
if (link.is_terminal())
continue;

auto& found = out.at(index);
Expand Down Expand Up @@ -96,22 +96,22 @@ bool CLASS::get_compact_matches(compact_matches& out,
if (!ptr0 || !ptr1 || !ptr2 || !ptr3)
return false;

// Rows are allocated to the spine before their columns are written.
const auto rows = std::min({ ptr0.size(), ptr1.size(), ptr2.size(),
// Records are allocated to the spine before their columns are written.
const auto count = std::min({ ptr0.size(), ptr1.size(), ptr2.size(),
ptr3.size() }) / sizeof(lane_t);

const auto chunk_rows = std::max(short_id_minimum_rows,
ceilinged_divide(rows, two * cores()));
std::vector<compact_matches> found(ceilinged_divide(rows, chunk_rows));
const auto chunk_size = std::max(short_id_minimum_records,
ceilinged_divide(count, two * cores()));
std::vector<compact_matches> found(ceilinged_divide(count, chunk_size));
std::vector<size_t> chunks(found.size());
std::iota(chunks.begin(), chunks.end(), zero);
const auto policy = poolstl::execution::par_if(store_.turbo());

std::for_each(policy, chunks.cbegin(), chunks.cend(),
[&](size_t chunk) NOEXCEPT
{
const auto first = chunk * chunk_rows;
std::vector<short_id> ids(std::min(chunk_rows, rows - first));
const auto first = chunk * chunk_size;
std::vector<short_id> ids(std::min(chunk_size, count - first));

const auto column = [&](const memory& ptr) NOEXCEPT
{
Expand All @@ -128,12 +128,12 @@ bool CLASS::get_compact_matches(compact_matches& out,
});

auto& matches = found.at(chunk);
for (size_t row{}; row < ids.size(); ++row)
for (size_t index{}; index < ids.size(); ++index)
{
const auto id = bit_and(ids[row], chain::short_id::mask);
if (const auto it = positions.find(id); it != positions.end())
const auto id = bit_and(ids[index], chain::short_id::mask);
if (const auto it = positions.find(id); it != positions.cend())
matches.emplace_back(it->second,
possible_narrow_cast<link_t>(first + row));
possible_narrow_cast<link_t>(first + index));
}
});

Expand Down
191 changes: 1 addition & 190 deletions include/bitcoin/database/impl/query/consensus/consensus_states.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
namespace libbitcoin {
namespace database {

// State machine for block and tx.
// State machine for block.
// ----------------------------------------------------------------------------

TEMPLATE
Expand Down Expand Up @@ -151,105 +151,6 @@ bool CLASS::is_block_validated(code& ec, const header_link& link,
}
}

// A terminal cursor starts at the first row, and the cursor is set to end
// once the rows are exhausted.
TEMPLATE
code CLASS::get_pooled_txs(pool_link& cursor, tx_links& out,
const pool_link& end, size_t limit) const NOEXCEPT
{
out.clear();
auto row = cursor.is_terminal() ? pool_link::integer{} : cursor.value;
if (row > end.value)
return error::invalid_cursor;

if (!store_.pool.enabled())
{
cursor = end;
return error::success;
}

const auto stop = std::min(end.value, store_.pool.count().value);
for (; row < stop && out.size() < limit; ++row)
{
// The first row of a tx is its last committed, so this skips both its
// earlier rows and any uncommitted row (its key does not resolve to it).
const tx_link link{ store_.pool.get_key(row) };
if (store_.pool.first(link) != row || is_confirmed_tx(link))
continue;

out.push_back(link);
}

cursor = row == stop ? end : pool_link{ row };
return error::success;
}

TEMPLATE
code CLASS::get_pooled(pooled_tx& out, const tx_link& link,
const context& ctx) const NOEXCEPT
{
using prevout = table::prevout::slab_get;
if (!store_.pool.enabled())
return error::unvalidated;

const auto fk = store_.pool.first(link);
if (fk.is_terminal())
return error::unvalidated;

table::pool::record valid{};
if (!store_.pool.get(fk, valid))
return error::integrity;

if (!is_sufficient(ctx, valid.ctx))
return error::unvalidated;

table::spends::get_refs::parents parents(out.prevouts.size());
table::spends::get_refs run{ {}, parents };
if (!store_.spends.get(valid.spends_fk, run))
return error::integrity;

out.fee = valid.fee;
out.sigops = valid.sigops;
std::ranges::transform(parents, out.prevouts.begin(),
[](auto merged) NOEXCEPT
{
return pooled_tx::prevout
{
prevout::output_tx_fk(merged), prevout::coinbase(merged)
};
});

return error::success;
}

// protected
TEMPLATE
bool CLASS::get_pooled_fee(uint64_t& out, const tx_link& link) const NOEXCEPT
{
size_t height{};
return get_pooled_fee(out, height, link);
}

TEMPLATE
bool CLASS::get_pooled_fee(uint64_t& fee, size_t& height,
const tx_link& link) const NOEXCEPT
{
if (!store_.pool.enabled())
return false;

const auto fk = store_.pool.first(link);
if (fk.is_terminal())
return false;

table::pool::get_fee pooled{};
if (!store_.pool.get(fk, pooled))
return false;

fee = pooled.fee;
height = pooled.height;
return true;
}

// writers
// ----------------------------------------------------------------------------

Expand Down Expand Up @@ -294,96 +195,6 @@ bool CLASS::set_block_state(const header_link& link,
// ========================================================================
}

TEMPLATE
bool CLASS::set_pooled(const tx_link& link, const transaction& tx,
const chain_context& ctx) NOEXCEPT
{
return set_pooled(link, tx, context::from(ctx));
}

TEMPLATE
bool CLASS::set_pooled(const tx_link& link, const transaction& tx,
const context& ctx) NOEXCEPT
{
if (!store_.pool.enabled())
return true;

using namespace system;
using sigs = linkage<schema::sigops>;
const auto& ins = *tx.inputs_ptr();
tx_links prevouts(ins.size());

auto it = prevouts.begin();
for (const auto& in: ins)
{
tx_link parent{ in->metadata.parent_tx };
auto coinbase = in->metadata.coinbase;

// Prevouts populated from the tx's own package are not yet linked.
if (in->metadata.parent_tx == max_uint32)
{
if ((parent = to_tx(in->point().hash())).is_terminal())
return false;

coinbase = is_coinbase(parent);
}

*it++ = table::prevout::merge(coinbase, parent);
}

const auto bip16 = ctx.is_enabled(chain::flags::bip16_rule);
const auto bip141 = ctx.is_enabled(chain::flags::bip141_rule);
const auto sigops = tx.signature_operations(bip16, bip141);
using lane_t = schema::pool::witness_lane;
const auto hash = tx.get_hash(true);
const auto words = from_little_endians(array_cast<lane_t>(hash));

// ========================================================================
const auto scope = get_transactor();

// Clean single allocation failure (e.g. disk full).
table::spends::link first{};
if (!store_.spends.put_link(first, table::spends::put_refs{ {}, prevouts }))
return false;

auto& vtx = store_.pool;
const auto row = vtx.allocate(1);
if (row.is_terminal())
return false;

if (!store_.wtxid.put(row, hash))
return false;

// Column puts are unguarded, the accessor guards their rows against remap.
using word = table::pool_word;
auto guard = vtx.get_memory();
if (!guard ||
!vtx.id0.put(row, word{ {}, std::get<0>(words) }) ||
!vtx.id1.put(row, word{ {}, std::get<1>(words) }) ||
!vtx.id2.put(row, word{ {}, std::get<2>(words) }) ||
!vtx.id3.put(row, word{ {}, std::get<3>(words) }))
return false;

guard.reset();

// Commit is deferred until the columns are set.
return vtx.put(row, link, table::pool::record
{
{},
ctx,
tx.fee(),
possible_narrow_cast<sigs::integer>(sigops),
first
});
// ========================================================================
}

TEMPLATE
bool CLASS::is_pooled(const tx_link& link) const NOEXCEPT
{
return store_.pool.enabled() && !store_.pool.first(link).is_terminal();
}

} // namespace database
} // namespace libbitcoin

Expand Down
Loading
Loading