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
4 changes: 2 additions & 2 deletions include/bitcoin/node/chasers/chaser_transaction.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ class BCN_API chaser_transaction
private:
static size_t to_rate(const system::chain::transaction& tx) NOEXCEPT;

code validate(size_t& index,
const system::chain::transaction_cptrs& txs) NOEXCEPT;
code validate(size_t& index, const system::chain::transaction_cptrs& txs,
const std::vector<bool>& stored) NOEXCEPT;
code validate(const system::chain::transaction& tx) NOEXCEPT;

// These are protected by strand.
Expand Down
4 changes: 3 additions & 1 deletion include/bitcoin/node/chasers/chaser_validate.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,9 @@ class BCN_API chaser_validate
const system::chain::block& block, const header_link& link,
const system::chain::context& ctx) NOEXCEPT;
virtual code populate(bool bypass, const system::chain::block& block,
const system::chain::context& ctx) NOEXCEPT;
const header_link& link, const system::chain::context& ctx) NOEXCEPT;
virtual bool populate_metadata(const system::chain::block& block,
const header_link& link, const system::chain::context& ctx) NOEXCEPT;
virtual void complete_block(const code& ec, const header_link& link,
size_t height, bool bypass, bool batched=false,
bool capturing=false) NOEXCEPT;
Expand Down
1 change: 1 addition & 0 deletions include/bitcoin/node/error.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ enum error_t : uint8_t
pooling_disabled,
insufficient_fee,
empty_package,
duplicate_transaction,
excessive_backlog,

/// fee estimation
Expand Down
1 change: 1 addition & 0 deletions include/bitcoin/node/events.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ enum events : uint8_t
ecdsa_secs, // ecdsa batch verify timespan in seconds.
schnorr_secs, // schnorr batch verify timespan in seconds.
silent_secs, // silent payment scan timespan in seconds.
validate_usecs, // block validation timespan in microseconds.

unknown
};
Expand Down
63 changes: 37 additions & 26 deletions src/chasers/chaser_transaction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -137,8 +137,16 @@ void chaser_transaction::do_submit(const transactions_cptr& txs, bool test,
return;
}

auto& query = archive();
std::vector<bool> stored(txs->size());
std::transform(txs->cbegin(), txs->cend(), stored.begin(),
[&](const auto& tx) NOEXCEPT
{
return !tx->is_coinbase() && query.is_tx(tx->get_hash(false));
});

size_t index{};
if (const auto ec = validate(index, *txs))
if (const auto ec = validate(index, *txs, stored))
{
handler(ec, index);
return;
Expand All @@ -150,10 +158,12 @@ void chaser_transaction::do_submit(const transactions_cptr& txs, bool test,
return;
}

auto& query = archive();
database::tx_links fresh(txs->size(), database::tx_link::terminal);
// Parents precede children, so a parent is archived before it is resolved.
for (index = zero; index < txs->size(); ++index)
{
if (stored.at(index))
continue;

bool pooled{};
database::tx_link link{};
const auto& tx = *txs->at(index);
Expand All @@ -165,23 +175,14 @@ void chaser_transaction::do_submit(const transactions_cptr& txs, bool test,
return;
}

if (!pooled)
fresh.at(index) = link;

fire(events::tx_archived, to_rate(tx));
notify(error::success, chases::transaction{ link });
}

// Package parents are resolved by hash, so the whole package precedes.
for (index = zero; index < txs->size(); ++index)
{
const database::tx_link link{ fresh.at(index) };
if (!link.is_terminal() && !query.set_pooled(link,
*txs->at(index), pool_))
if (!pooled && !query.set_pooled(link, tx, pool_))
{
handler(fault(error::transaction2), index);
return;
}

fire(events::tx_archived, to_rate(tx));
notify(error::success, chases::transaction{ link });
}

handler(error::success, {});
Expand All @@ -206,31 +207,41 @@ size_t chaser_transaction::to_rate(const chain::transaction& tx) NOEXCEPT
// validation
// ----------------------------------------------------------------------------

code chaser_transaction::validate(size_t& index,
const transaction_cptrs& txs) NOEXCEPT
code chaser_transaction::validate(size_t& index, const transaction_cptrs& txs,
const std::vector<bool>& stored) NOEXCEPT
{
if (txs.empty())
return error::empty_package;

if (std::ranges::all_of(stored, std::identity{}))
return error::duplicate_transaction;

if (block::is_forward_reference(txs, false))
return system::error::forward_reference;

if (block::is_internal_double_spend(txs, false))
return system::error::block_internal_double_spend;

if (const auto ec = block::populate(txs, pool_, false))
return ec;

for(const auto& tx: txs)
if (const auto ec = validate(*tx))
return ec;


uint64_t fee{}, size{};
for (const auto& tx: txs)
for (index = zero; index < txs.size(); ++index)
{
fee = ceilinged_add(fee, tx->fee());
if (stored.at(index))
continue;

const auto& tx = *txs.at(index);
if (const auto ec = validate(tx))
return ec;

fee = ceilinged_add(fee, tx.fee());
size = ceilinged_add(size, possible_wide_cast<uint64_t>(
tx->virtual_size()));
tx.virtual_size()));
}

index = zero;

// Compared in satoshis per virtual kilobyte.
const auto rate = node_settings().minimum_fee_rate_();
return ceilinged_multiply(fee, 1'000_u64) < ceilinged_multiply(rate, size) ?
Expand Down
41 changes: 38 additions & 3 deletions src/chasers/chaser_validate_parallel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ namespace node {

using namespace system;
using namespace database;
using namespace std::chrono;

// Parallel execution path (concurrent by block).
// ----------------------------------------------------------------------------
Expand All @@ -40,6 +41,7 @@ void chaser_validate::validate_block(const header_link& link,
chain::context ctx{};
bool batched{}, capturing{};
auto& query = archive();
const auto start = network::logger::now();

// TODO: implement allocator parameter resulting in full allocation to
// shared_ptr<block>, to optimize deallocate (12% of milestone/filter).
Expand All @@ -53,7 +55,7 @@ void chaser_validate::validate_block(const header_link& link,
{
ec = error::validate3;
}
else if ((ec = populate(bypass, *block, ctx)))
else if ((ec = populate(bypass, *block, link, ctx)))
{
if (!query.set_block_unconfirmable(link))
ec = error::validate4;
Expand All @@ -65,6 +67,13 @@ void chaser_validate::validate_block(const header_link& link,
ec = error::validate5;
}

if (!ec && !bypass)
{
const auto elapsed = network::logger::now() - start;
fire(events::validate_usecs,
duration_cast<microseconds>(elapsed).count());
}

--validate_backlog_;
complete_block(ec, link, ctx.height, bypass, batched, capturing);
}
Expand All @@ -73,7 +82,7 @@ void chaser_validate::validate_block(const header_link& link,
// ----------------------------------------------------------------------------

code chaser_validate::populate(bool bypass, const chain::block& block,
const chain::context& ctx) NOEXCEPT
const header_link& link, const chain::context& ctx) NOEXCEPT
{
const auto& query = archive();

Expand All @@ -92,13 +101,39 @@ code chaser_validate::populate(bool bypass, const chain::block& block,
return ec;

// Metadata identifies internal spends allowing confirmation bypass.
if (!query.populate_with_metadata(block))
if (!populate_metadata(block, link, ctx))
return system::error::missing_previous_output;
}

return error::success;
}

// A tx pooled under a sufficient context takes its metadata from the pool.
bool chaser_validate::populate_metadata(const chain::block& block,
const header_link& link, const chain::context& ctx) NOEXCEPT
{
const auto& query = archive();
const auto& txs = *block.transactions_ptr();
const auto links = query.to_transactions(link);
if (links.size() != txs.size())
return query.populate_with_metadata(block);

pooled_tx pooled{};
const auto pool = database::context::from(ctx);
for (auto index = one; index < txs.size(); ++index)
{
const auto& tx = *txs.at(index);
const auto populated = query.populate_pooled(pooled, tx,
links.at(index), pool) ? query.populate_with_metadata(tx) :
query.populate_without_metadata(tx);

if (!populated)
return false;
}

return true;
}

code chaser_validate::validate(bool& batched, bool& capturing, bool bypass,
const chain::block& block, const header_link& link,
const chain::context& ctx) NOEXCEPT
Expand Down
1 change: 1 addition & 0 deletions src/error.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ DEFINE_ERROR_T_MESSAGE_MAP(error)
{ pooling_disabled, "pooling disabled" },
{ insufficient_fee, "insufficient fee" },
{ empty_package, "empty package" },
{ duplicate_transaction, "duplicate transaction" },
{ excessive_backlog, "excessive transaction backlog" },

// fee estimation
Expand Down
4 changes: 3 additions & 1 deletion src/protocols/protocol_transaction_in_106.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,8 @@ void protocol_transaction_in_106::do_handle_submit(const code& ec,
return;

// A conflict with an unconfirmed tx is not misbehavior, as the peer
// cannot know what is held here. An unknown prevout is not misbehavior,
// cannot know what is held here, and a requested tx may be archived from
// another peer before it arrives. An unknown prevout is not misbehavior,
// as announcement order is not constrained and orphans are not pooled.
// A locked tx is final to a peer one block ahead, as locks are evaluated
// against the presumed next block, so neither lock is misbehavior.
Expand All @@ -180,6 +181,7 @@ void protocol_transaction_in_106::do_handle_submit(const code& ec,
if (ec &&
(ec != error::pooling_disabled) &&
(ec != error::insufficient_fee) &&
(ec != error::duplicate_transaction) &&
(ec != system::error::double_spend) &&
(ec != system::error::absolute_time_locked) &&
(ec != system::error::relative_time_locked) &&
Expand Down
Loading