Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

set_strong in parallel, style. #498

Merged
merged 7 commits into from
Jun 22, 2024
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
8 changes: 4 additions & 4 deletions include/bitcoin/database/error.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,8 @@ enum error_t : uint8_t
tx_point_put,
tx_spend_set,
tx_output_put,
tx_tx_set,
tx_puts_put,
tx_tx_set,
tx_spend_commit,
tx_address_put,
tx_tx_commit,
Expand All @@ -121,10 +121,10 @@ enum error_t : uint8_t
header_put,

/// txs archive
txs_empty,
txs_header,
txs_txs_put,
txs_confirm
txs_empty,
txs_confirm,
txs_txs_put
};

// No current need for error_code equivalence mapping.
Expand Down
4 changes: 2 additions & 2 deletions include/bitcoin/database/impl/primitives/hashmap.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -376,8 +376,8 @@ Link CLASS::first(const memory_ptr& ptr, Link link, const Key& key) NOEXCEPT
return {};

// element key matches (found)
const auto key_ptr = std::next(offset, Link::size);
if (is_zero(std::memcmp(key.data(), key_ptr, array_count<Key>)))
if (is_zero(std::memcmp(key.data(), std::next(offset, Link::size),
array_count<Key>)))
return link;

// set next element link (loop)
Expand Down
12 changes: 9 additions & 3 deletions include/bitcoin/database/impl/query/archive.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -302,13 +302,13 @@ TEMPLATE
bool CLASS::get_tx_position(size_t& out, const tx_link& link) const NOEXCEPT
{
// to_block is strong but not necessarily confirmed.
const auto block_fk = to_block(link);
if (!is_confirmed_block(block_fk))
const auto fk = to_block(link);
if (!is_confirmed_block(fk))
return false;

// False return below implies an integrity error (tx should be indexed).
table::txs::get_position txs{ {}, link };
if (!store_.txs.find(block_fk, txs))
if (!store_.txs.find(fk, txs))
return false;

out = txs.position;
Expand Down Expand Up @@ -356,6 +356,7 @@ TEMPLATE
typename CLASS::inputs_ptr CLASS::get_inputs(
const tx_link& link) const NOEXCEPT
{
// TODO: eliminate shared memory pointer reallcations.
using namespace system;
const auto fks = to_tx_spends(link);
if (fks.empty())
Expand All @@ -375,6 +376,7 @@ TEMPLATE
typename CLASS::outputs_ptr CLASS::get_outputs(
const tx_link& link) const NOEXCEPT
{
// TODO: eliminate shared memory pointer reallcations.
using namespace system;
const auto fks = to_tx_outputs(link);
if (fks.empty())
Expand All @@ -394,6 +396,7 @@ TEMPLATE
typename CLASS::transactions_ptr CLASS::get_transactions(
const header_link& link) const NOEXCEPT
{
// TODO: eliminate shared memory pointer reallcations.
using namespace system;
const auto txs = to_transactions(link);
if (txs.empty())
Expand Down Expand Up @@ -502,6 +505,7 @@ TEMPLATE
typename CLASS::transaction::cptr CLASS::get_transaction(
const tx_link& link) const NOEXCEPT
{
// TODO: eliminate shared memory pointer reallcations.
using namespace system;
table::transaction::only_with_sk tx{};
if (!store_.tx.get(link, tx))
Expand Down Expand Up @@ -601,6 +605,7 @@ typename CLASS::inputs_ptr CLASS::get_spenders(
const auto spenders = to_shared<chain::input_cptrs>();
spenders->reserve(spend_fks.size());

// TODO: eliminate shared memory pointer reallcation.
for (const auto& spend_fk: spend_fks)
if (!push_bool(*spenders, get_input(spend_fk)))
return {};
Expand Down Expand Up @@ -676,6 +681,7 @@ code CLASS::set_code(tx_link& out_fk, const transaction& tx) NOEXCEPT
std_vector<foreign_point> spends{};
spends.reserve(ins.size());

// TODO: eliminate shared memory pointer reallcations.
// ========================================================================
const auto scope = store_.get_transactor();

Expand Down
145 changes: 100 additions & 45 deletions include/bitcoin/database/impl/query/confirm.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#define LIBBITCOIN_DATABASE_QUERY_CONFIRM_IPP

#include <algorithm>
#include <atomic>
#include <bitcoin/system.hpp>
#include <bitcoin/database/define.hpp>
#include <bitcoin/database/error.hpp>
Expand Down Expand Up @@ -136,14 +137,14 @@ bool CLASS::is_spent(const spend_link& link) const NOEXCEPT
if (spend.is_null())
return false;

return !!spent_prevout(spend.prevout(), spend.parent_fk);
return is_spent_prevout(spend.prevout(), spend.parent_fk);
}

// unused
TEMPLATE
bool CLASS::is_strong_spend(const spend_link& link) const NOEXCEPT
{
return !to_block(to_spend_tx(link)).is_terminal();
return is_strong_tx(to_spend_tx(link));
}

// unused
Expand Down Expand Up @@ -235,14 +236,23 @@ code CLASS::locked_prevout(const point_link& link, uint32_t sequence,

// protected
TEMPLATE
code CLASS::spent_prevout(tx_link link, index index) const NOEXCEPT
bool CLASS::is_spent_prevout(const tx_link& link, index index) const NOEXCEPT
{
return spent_prevout(table::spend::compose(link, index), tx_link::terminal);
const auto fp = table::spend::compose(link, index);
return is_spent_prevout(fp, tx_link::terminal);
}

// protected
TEMPLATE
code CLASS::spent_prevout(const foreign_point& point,
bool CLASS::is_spent_prevout(const foreign_point& point,
const tx_link& self) const NOEXCEPT
{
return spent_prevout(point, self) != error::success;
}

// protected
TEMPLATE
error::error_t CLASS::spent_prevout(const foreign_point& point,
const tx_link& self) const NOEXCEPT
{
auto it = store_.spend.it(point);
Expand All @@ -255,8 +265,6 @@ code CLASS::spent_prevout(const foreign_point& point,
if (!store_.spend.get(it, spend))
return error::integrity;

// Skip current spend, which is the only one if not double spent.
// If strong spender exists then prevout is confirmed double spent.
if ((spend.parent_fk != self) && is_strong_tx(spend.parent_fk))
return error::confirmed_double_spend;
}
Expand All @@ -266,11 +274,10 @@ code CLASS::spent_prevout(const foreign_point& point,

// protected
TEMPLATE
code CLASS::unspendable_prevout(const point_link& link,
error::error_t CLASS::unspendable_prevout(const point_link& link,
uint32_t sequence, uint32_t version, const context& ctx) const NOEXCEPT
{
const auto key = get_point_key(link);
const auto strong = to_strong(key);
const auto strong = to_strong(get_point_key(link));

if (strong.block.is_terminal())
return strong.tx.is_terminal() ? error::missing_previous_output :
Expand Down Expand Up @@ -311,29 +318,31 @@ code CLASS::unspent_duplicates(const tx_link& coinbase,
size_t unspent{};
for (const auto& tx: coinbases)
for (index out{}; out < output_count(tx); ++out)
if (!spent_prevout(tx, out) && is_one(unspent++))
if (!is_spent_prevout(tx, out) && is_one(unspent++))
return error::unspent_coinbase_collision;

return is_zero(unspent) ? error::integrity : error::success;
}

// protected
TEMPLATE
code CLASS::tx_confirmable(const tx_link& link,
const context& ctx) const NOEXCEPT
spend_sets CLASS::to_spend_sets(const header_link& link) const NOEXCEPT
{
code ec{};
const auto set = to_spend_set(link);
for (const auto& spend: set.spends)
const auto txs = to_transactions(link);
if (txs.size() <= one)
return {};

spend_sets out{ sub1(txs.size()) };
const auto to_set = [this](const auto& tx) NOEXCEPT
{
if ((ec = unspendable_prevout(spend.point_fk, spend.sequence,
set.version, ctx)))
return ec;
return to_spend_set(tx);
};

if ((ec = spent_prevout(spend.prevout(), link)))
return ec;
}
// C++17 incomplete on GCC/CLang, so presently parallel only on MSVC++.
std_transform(bc::par_unseq, std::next(txs.begin()), txs.end(),
out.begin(), to_set);

return error::success;
return out;
}

// split(3) 219 secs for 400k-410k; split(2) 255 and split(0) 456 (not shown).
Expand All @@ -348,41 +357,86 @@ code CLASS::block_confirmable(const header_link& link) const NOEXCEPT
if ((ec = unspent_duplicates(to_coinbase(link), ctx)))
return ec;

const auto is_unspendable = [&ctx, this] (const auto& set) NOEXCEPT
std::atomic<error::error_t> fault{ error::success };
const auto is_unspendable = [this, &ctx, &fault](const auto& set) NOEXCEPT
{
error::error_t ec{};
for (const auto& spend: set.spends)
if (unspendable_prevout(spend.point_fk, spend.sequence,
set.version, ctx))
if ((ec = unspendable_prevout(spend.point_fk, spend.sequence,
set.version, ctx)))
{
fault.store(ec);
return true;
}

return false;
};

const auto is_spent = [this](const auto& set) NOEXCEPT
const auto is_spent = [this, &fault](const auto& set) NOEXCEPT
{
error::error_t ec{};
for (const auto& spend: set.spends)
if (spent_prevout(spend.prevout(), set.tx))
if ((ec = spent_prevout(spend.prevout(), set.tx)))
{
fault.store(ec);
return true;
}

return false;
};

// C++17 incomplete on GCC/CLang, so presently parallel only on MSVC++.
const auto sets = to_non_coinbase_spends(link);
const auto sets = to_spend_sets(link);

// C++17 incomplete on GCC/CLang, so presently parallel only on MSVC++.
if (std_any_of(bc::par_unseq, sets.begin(), sets.end(), is_unspendable))
return error::integrity;
return { fault.load() };

// C++17 incomplete on GCC/CLang, so presently parallel only on MSVC++.
if (std_any_of(bc::par_unseq, sets.begin(), sets.end(), is_spent))
return error::integrity;
return error::success;
return { fault.load() };

return ec;
}

#if defined(UNDEFINED)

// protected
TEMPLATE
spend_sets CLASS::to_spend_sets(
const header_link& link) const NOEXCEPT
{
const auto txs = to_transactions(link);
if (txs.size() <= one)
return {};

spend_sets sets{};
sets.reserve(sub1(txs.size()));
for (auto tx = std::next(txs.begin()); tx != txs.end(); ++tx)
sets.push_back(to_spend_set(*tx));

return sets;
}

TEMPLATE
code CLASS::tx_confirmable(const tx_link& link,
const context& ctx) const NOEXCEPT
{
code ec{};
const auto set = to_spend_set(link);
for (const auto& spend : set.spends)
{
if ((ec = unspendable_prevout(spend.point_fk, spend.sequence,
set.version, ctx)))
return ec;

if (is_spent_prevout(spend.prevout(), link))
return error::confirmed_double_spend;
}

return error::success;
}

// split(0) 403 secs for 400k-410k
TEMPLATE
code CLASS::block_confirmable(const header_link& link) const NOEXCEPT
Expand Down Expand Up @@ -418,7 +472,7 @@ code CLASS::block_confirmable(const header_link& link) const NOEXCEPT
if ((ec = unspent_duplicates(to_coinbase(link), ctx)))
return ec;

const auto sets = to_non_coinbase_spends(link);
const auto sets = to_spend_sets(link);
for (const auto& set: sets)
{
for (const auto& spend: set.spends)
Expand All @@ -427,8 +481,8 @@ code CLASS::block_confirmable(const header_link& link) const NOEXCEPT
set.version, ctx)))
return ec;

if ((ec = spent_prevout(spend.prevout(), set.tx)))
return ec;
if (is_spent_prevout(spend.prevout(), set.tx))
return error::confirmed_double_spend;
}
}

Expand All @@ -447,7 +501,7 @@ code CLASS::block_confirmable(const header_link& link) const NOEXCEPT
if ((ec = unspent_duplicates(to_coinbase(link), ctx)))
return ec;

const auto sets = to_non_coinbase_spends(link);
const auto sets = to_spend_sets(link);
for (const auto& set: sets)
for (const auto& spend: set.spends)
if ((ec = unspendable_prevout(spend.point_fk, spend.sequence,
Expand All @@ -458,8 +512,8 @@ code CLASS::block_confirmable(const header_link& link) const NOEXCEPT

for (const auto& set: sets)
for (const auto& spend: set.spends)
if ((ec = spent_prevout(spend.prevout(), set.tx)))
return ec;
if (is_spent_prevout(spend.prevout(), set.tx))
return error::confirmed_double_spend;

return ec;
}
Expand All @@ -471,18 +525,19 @@ TEMPLATE
bool CLASS::set_strong(const header_link& link, const tx_links& txs,
bool positive) NOEXCEPT
{
return std::all_of(txs.begin(), txs.end(), [&](const tx_link& fk) NOEXCEPT
const auto set = [this, &link, positive](const tx_link& tx) NOEXCEPT
{
// If under checkpoint txs is set later, so under fault will reoccur.
// Otherwise confirmed by height is set later so will also reoccur.
// Confirmation by height always sequential so can be no inconsistency.
return store_.strong_tx.put(fk, table::strong_tx::record
// TODO: eliminate shared memory pointer reallcation.
return store_.strong_tx.put(tx, table::strong_tx::record
{
{},
link,
positive
});
});
};

// C++17 incomplete on GCC/CLang, so presently parallel only on MSVC++.
return std_all_of(bc::par_unseq, txs.begin(), txs.end(), set);
}

TEMPLATE
Expand Down
Loading
Loading