Skip to content

Commit

Permalink
Merge pull request #648 from evoskuil/master
Browse files Browse the repository at this point in the history
Implement set_strong/unstrong for candidate reorgs.
  • Loading branch information
evoskuil authored Jun 19, 2024
2 parents 2a35d98 + 6749a35 commit 77fb9ac
Show file tree
Hide file tree
Showing 6 changed files with 51 additions and 55 deletions.
2 changes: 1 addition & 1 deletion include/bitcoin/node/chasers/chaser_confirm.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ class BCN_API chaser_confirm
virtual void do_validated(height_t height) NOEXCEPT;
virtual void do_organize(size_t height) NOEXCEPT;
virtual bool enqueue_block(const database::header_link& link) NOEXCEPT;
virtual void confirm_tx(const database::context& context,
virtual void confirm_tx(const database::context& ctx,
const database::tx_link& link, const race::ptr& racer) NOEXCEPT;
virtual void handle_tx(const code& ec, const database::tx_link& tx,
const race::ptr& racer) NOEXCEPT;
Expand Down
2 changes: 1 addition & 1 deletion include/bitcoin/node/chasers/chaser_organize.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ class chaser_organize

/// Store Block to database and push to top of candidate chain.
code push_block(const Block& block,
const system::chain::context& context) const NOEXCEPT;
const system::chain::context& ctx) const NOEXCEPT;

// Logging.
// ------------------------------------------------------------------------
Expand Down
2 changes: 1 addition & 1 deletion include/bitcoin/node/chasers/chaser_validate.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ class BCN_API chaser_validate
virtual void do_bump(height_t height) NOEXCEPT;

virtual bool enqueue_block(const database::header_link& link) NOEXCEPT;
virtual void validate_tx(const database::context& context,
virtual void validate_tx(const database::context& ctx,
const database::tx_link& link, const race::ptr& racer) NOEXCEPT;
virtual void handle_tx(const code& ec, const database::tx_link& tx,
const race::ptr& racer) NOEXCEPT;
Expand Down
29 changes: 14 additions & 15 deletions include/bitcoin/node/impl/chasers/chaser_organize.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -278,8 +278,9 @@ void CLASS::do_organize(typename Block::cptr& block_ptr,
auto index = top_candidate;
while (index > branch_point)
{
// TODO: if milestone set_unstrong.
if (!query.pop_candidate())
const auto candidate = query.to_candidate(index);
if ((is_under_milestone(index) && !query.set_unstrong(candidate)) ||
!query.pop_candidate())
{
handler(fault(error::pop_candidate), height);
return;
Expand All @@ -295,8 +296,8 @@ void CLASS::do_organize(typename Block::cptr& block_ptr,
// Push stored strong headers to candidate chain.
for (const auto& link: views_reverse(store_branch))
{
// TODO: if milestone set_strong.
if (!query.push_candidate(link))
if ((is_under_milestone(index) && !query.set_strong(link)) ||
!query.push_candidate(link))
{
handler(fault(error::push_candidate), height);
return;
Expand All @@ -309,7 +310,6 @@ void CLASS::do_organize(typename Block::cptr& block_ptr,
// Store strong tree headers and push to candidate chain.
for (const auto& key: views_reverse(tree_branch))
{
// TODO: if milestone set_strong.
if ((ec = push_block(key)))
{
handler(fault(ec), height);
Expand All @@ -323,7 +323,6 @@ void CLASS::do_organize(typename Block::cptr& block_ptr,

// Push new header as top of candidate chain.
{
// TODO: if milestone set_strong.
if ((ec = push_block(*block_ptr, state->context())))
{
handler(fault(ec), height);
Expand Down Expand Up @@ -429,8 +428,9 @@ void CLASS::do_disorganize(header_t link) NOEXCEPT
const auto top_candidate = state_->height();
for (auto index = top_candidate; index > fork_point; --index)
{
// TODO: if !milestone set_unstrong.
if (!query.pop_candidate())
const auto candidate = query.to_candidate(index);
if ((is_under_milestone(index) && !query.set_unstrong(candidate)) ||
!query.pop_candidate())
{
fault(error::pop_candidate);
return;
Expand All @@ -449,9 +449,8 @@ void CLASS::do_disorganize(header_t link) NOEXCEPT
const auto top_confirmed = query.get_top_confirmed();
for (auto index = add1(fork_point); index <= top_confirmed; ++index)
{
// TODO: if milestone set_strong.
const auto confirmed = query.to_confirmed(index);
if (!query.push_candidate(confirmed))
// Confirmed are already set_strong and must stay that way.
if (!query.push_candidate(query.to_confirmed(index)))
{
fault(error::push_candidate);
return;
Expand Down Expand Up @@ -574,15 +573,15 @@ bool CLASS::get_is_strong(bool& strong, const uint256_t& branch_work,

TEMPLATE
code CLASS::push_block(const Block& block,
const system::chain::context& context) const NOEXCEPT
const system::chain::context& ctx) const NOEXCEPT
{
// set_code invokes set_strong when checked.
const auto milestone = is_under_checkpoint(context.height);
const auto checked = is_block() && is_under_checkpoint(context.height);
const auto milestone = is_under_checkpoint(ctx.height);
const auto checked = is_block() && is_under_checkpoint(ctx.height);

auto& query = archive();
database::header_link link{};
const auto ec = query.set_code(link, block, context, milestone, checked);
const auto ec = query.set_code(link, block, ctx, milestone, checked);
if (ec)
return ec;

Expand Down
22 changes: 10 additions & 12 deletions src/chasers/chaser_confirm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -207,18 +207,18 @@ void chaser_confirm::do_organize(size_t height) NOEXCEPT
return;
}

const auto is_strong = is_under_checkpoint(height) ||
const auto checked = is_under_checkpoint(height) ||
query.is_milestone(link);

// Required for block_confirmable and all confirmed blocks.
// Checkpoint and milestone guarantee set_strong is always set.
if (!is_strong && !query.set_strong(link))
if (!checked && !query.set_strong(link))
{
fault(error::set_confirmed);
return;
}

if (ec == database::error::block_confirmable || is_strong)
if (ec == database::error::block_confirmable || checked)
{
// TODO: compute fees from validation records.
if ((ec != database::error::block_confirmable) &&
Expand All @@ -240,8 +240,6 @@ void chaser_confirm::do_organize(size_t height) NOEXCEPT
return;
}

// TODO: the quantity of work must be throttled.
// This will very rapidly pump all outstanding work into asio queue.
if (!enqueue_block(link))
{
fault(error::node_validate);
Expand All @@ -261,22 +259,22 @@ bool chaser_confirm::enqueue_block(const header_link& link) NOEXCEPT
return false;

code ec{};
const auto height = ctx.height;
if ((ec = query.unspent_duplicates(txs.front(), ctx)))
{
POST(confirm_block, ec, link, ctx.height);
POST(confirm_block, ec, link, height);
return true;
}

if (is_one(txs.size()))
{
POST(confirm_block, ec, link, ctx.height);
POST(confirm_block, ec, link, height);
return true;
}

// race_unity: last to finish with success, or first error code.
const auto racer = std::make_shared<race>(sub1(txs.size()));
racer->start(BIND(handle_txs, _1, _2, link, ctx.height));
////fire(events::block_buffered, ctx.height);
racer->start(BIND(handle_txs, _1, _2, link, height));
////fire(events::block_buffered, height);

for (auto tx = std::next(txs.begin()); tx != txs.end(); ++tx)
boost::asio::post(threadpool_.service(),
Expand All @@ -287,8 +285,8 @@ bool chaser_confirm::enqueue_block(const header_link& link) NOEXCEPT
}

// START WORK UNIT
void chaser_confirm::confirm_tx(const database::context& ctx,
const tx_link& link, const race::ptr& racer) NOEXCEPT
void chaser_confirm::confirm_tx(const context& ctx, const tx_link& link,
const race::ptr& racer) NOEXCEPT
{
const auto ec = archive().tx_confirmable(link, ctx);
POST(handle_tx, ec, link, racer);
Expand Down
49 changes: 24 additions & 25 deletions src/chasers/chaser_validate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -210,27 +210,26 @@ bool chaser_validate::enqueue_block(const header_link& link) NOEXCEPT
BC_ASSERT(stranded());
const auto& query = archive();

database::context context{};
context ctx{};
const auto txs = query.to_transactions(link);
if (txs.empty() || !query.get_context(context, link))
if (txs.empty() || !query.get_context(ctx, link))
return false;

// race_unity: last to finish with success, or first error code.
const auto racer = std::make_shared<race>(txs.size());
racer->start(BIND(handle_txs, _1, _2, link, context));
////fire(events::block_buffered, context.height);
racer->start(BIND(handle_txs, _1, _2, link, ctx));
////fire(events::block_buffered, ctx.height);

for (auto tx = txs.begin(); !closed() && tx != txs.end(); ++tx)
boost::asio::post(threadpool_.service(),
std::bind(&chaser_validate::validate_tx,
this, context, *tx, racer));
this, ctx, *tx, racer));

return true;
}

// START WORK UNIT
void chaser_validate::validate_tx(const database::context& context,
const tx_link& link, const race::ptr& racer) NOEXCEPT
void chaser_validate::validate_tx(const context& ctx, const tx_link& link,
const race::ptr& racer) NOEXCEPT
{
if (closed())
{
Expand All @@ -239,7 +238,7 @@ void chaser_validate::validate_tx(const database::context& context,
}

auto& query = archive();
auto ec = query.get_tx_state(link, context);
auto ec = query.get_tx_state(link, ctx);

// These states bypass validation.
if (ec == database::error::integrity ||
Expand All @@ -255,14 +254,14 @@ void chaser_validate::validate_tx(const database::context& context,
//// database::error::unknown_state
//// database::error::unvalidated

const chain::context ctx
const chain::context ctx_
{
context.flags, // [accept & connect]
{}, // timestamp
{}, // mtp
context.height, // [accept]
{}, // minimum_block_version
{} // work_required
ctx.flags, // [accept & connect]
{}, // timestamp
{}, // mtp
ctx.height, // [accept]
{}, // minimum_block_version
{} // work_required
};

code invalid{ system::error::missing_previous_output };
Expand All @@ -273,28 +272,28 @@ void chaser_validate::validate_tx(const database::context& context,
}
else if (!query.populate(*tx))
{
ec = query.set_tx_disconnected(link, context) ? invalid :
ec = query.set_tx_disconnected(link, ctx) ? invalid :
error::store_integrity;

fire(events::tx_invalidated, ctx.height);
}
else if (((invalid = tx->accept(ctx))) || ((invalid = tx->connect(ctx))))
else if (((invalid = tx->accept(ctx_))) || ((invalid = tx->connect(ctx_))))
{
ec = query.set_tx_disconnected(link, context) ? invalid :
ec = query.set_tx_disconnected(link, ctx) ? invalid :
error::store_integrity;

fire(events::tx_invalidated, ctx.height);
LOGR("Invalid tx [" << encode_hash(tx->hash(false)) << "] in block ("
<< ctx .height << ") " << invalid.message());
<< ctx.height << ") " << invalid.message());
}
else
{
const auto bip16 = ctx.is_enabled(chain::flags::bip16_rule);
const auto bip141 = ctx.is_enabled(chain::flags::bip141_rule);
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);

// TODO: cache fee and sigops from validation stage.
ec = query.set_tx_connected(link, context, tx->fee(), sigops) ?
ec = query.set_tx_connected(link, ctx, tx->fee(), sigops) ?
error::success : error::store_integrity;
}

Expand All @@ -319,7 +318,7 @@ void chaser_validate::handle_tx(const code& ec, const tx_link& tx,

// SYNCHRONIZE WORK UNITS
void chaser_validate::handle_txs(const code& ec, const tx_link& tx,
const header_link& link, const database::context& ctx) NOEXCEPT
const header_link& link, const context& ctx) NOEXCEPT
{
BC_ASSERT(stranded());
if (closed())
Expand All @@ -337,7 +336,7 @@ void chaser_validate::handle_txs(const code& ec, const tx_link& tx,

// SUMMARIZE WORK
void chaser_validate::validate_block(const code& ec,
const header_link& link, const database::context& ctx) NOEXCEPT
const header_link& link, const context& ctx) NOEXCEPT
{
BC_ASSERT(stranded());
auto& query = archive();
Expand Down

0 comments on commit 77fb9ac

Please sign in to comment.