Skip to content

Commit

Permalink
Merge pull request #638 from evoskuil/master
Browse files Browse the repository at this point in the history
Revise validation chaser error handling.
  • Loading branch information
evoskuil committed Jun 5, 2024
2 parents afd881b + 8f22aa3 commit fa392c0
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 150 deletions.
185 changes: 44 additions & 141 deletions src/chasers/chaser_validate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -151,23 +151,27 @@ void chaser_validate::do_bump(height_t) NOEXCEPT
const auto link = query.to_candidate(height);
const auto ec = query.get_block_state(link);
if (ec == database::error::unassociated)
{
// Wait until the gap is filled.
return;
}

// query.is_malleable64(link) is used when there is no block instance.
if (is_under_bypass(height) && !query.is_malleable64(link))
if (ec == database::error::integrity)
{
update_neutrino(link);
fault(ec);
return;
}

if (ec == database::error::block_confirmable ||
ec == database::error::block_unconfirmable ||
ec == database::error::block_valid)
if (ec == database::error::block_unconfirmable)
{
notify(ec, chase::unconfirmable, height);
fire(events::block_unconfirmable, height);
return;
}

if (ec == error::validation_bypass ||
if (ec == database::error::block_valid ||
ec == database::error::block_confirmable ||
ec == database::error::block_valid)
(is_under_bypass(height) && !query.is_malleable64(link)))
{
update_position(height);
notify(ec, chase::valid, height);
Expand All @@ -182,87 +186,13 @@ void chaser_validate::do_bump(height_t) NOEXCEPT
fault(error::store_integrity);
return;
}
else
{
update_position(height);
}

#if defined(UNDEFINED)
// Accept/Connect block.
// ....................................................................

// neutrino_ is advanced here if successful or bypassed.
if (const auto code = validate(link, height))
{
if (code == error::validation_bypass ||
code == database::error::block_confirmable ||
code == database::error::block_valid)
{
// Advance.
++position();
notify(code, chase::valid, height);
fire(events::validate_bypassed, height);
continue;
}

if (code == error::store_integrity)
{
fault(error::node_validate);
return;
}

if (query.is_malleable(link))
{
notify(code, chase::malleated, link);
fire(events::block_malleated, height);
}
else
{
if (code != database::error::block_unconfirmable &&
!query.set_block_unconfirmable(link))
{
fault(error::set_block_unconfirmable);
return;
}

notify(code, chase::unvalid, link);
fire(events::block_unconfirmable, height);
}

LOGR("Unvalidated block [" << height << "] " << code.message());
return;
}

// Commit validation metadata.
// ....................................................................

// TODO: set fees on valid because prevout.value() populated.
// TODO: in concurrent model sum fees from each validated_tx record.
// [set_txs_connected] FOR PERFORMANCE EVALUATION ONLY.
// Tx validation/states are independent of block validation.
if (!query.set_txs_connected(link))
{
fault(error::set_txs_connected);
return;
}

if (!query.set_block_valid(link))
{
fault(error::set_block_valid);
return;
}

// Advance.
// ....................................................................

++position();
notify(error::success, chase::valid, height);
fire(events::block_validated, height);
#endif // UNDEFINED
// Retain last height in validation sequence, update neutrino.
update_position(height);
}
}

// DISTRUBUTE WORK
// DISTRUBUTE WORK UNITS
bool chaser_validate::enqueue_block(const header_link& link) NOEXCEPT
{
BC_ASSERT(stranded());
Expand All @@ -286,7 +216,7 @@ bool chaser_validate::enqueue_block(const header_link& link) NOEXCEPT
return true;
}

// CONCURRENT WORK
// START WORK UNIT
void chaser_validate::validate_tx(const database::context& context,
const tx_link& link, const race::ptr& racer) NOEXCEPT
{
Expand Down Expand Up @@ -369,6 +299,7 @@ void chaser_validate::validate_tx(const database::context& context,
POST(handle_tx, ec, link, racer);
}

// FINISH WORK UNIT
void chaser_validate::handle_tx(const code& ec, const tx_link& tx,
const race::ptr& racer) NOEXCEPT
{
Expand All @@ -384,7 +315,7 @@ void chaser_validate::handle_tx(const code& ec, const tx_link& tx,
racer->finish(ec, tx);
}

// SYNCHRONIZE WORK
// SYNCHRONIZE WORK UNITS
void chaser_validate::handle_txs(const code& ec, const tx_link& tx,
const header_link& link, const database::context& ctx) NOEXCEPT
{
Expand All @@ -407,71 +338,43 @@ void chaser_validate::validate_block(const code& ec,
const header_link& link, const database::context& ctx) NOEXCEPT
{
BC_ASSERT(stranded());
const auto& query = archive();
if (ec && query.is_malleable64(link))
auto& query = archive();

if (ec)
{
notify(ec, chase::malleated, link);
fire(events::block_malleated, ctx.height);
const auto malleable64 = query.is_malleable64(link);

// Must be malleable64 if failed under checkpoint.
// Transactions are set strong upon archive when under bypass.
if (is_under_bypass(ctx.height) &&
(!malleable64 || query.set_unstrong(link)))
{
fault(error::store_integrity);
return;
}

if (malleable64)
{
// TODO: log malleated64 block with ec.
notify(ec, chase::malleated, link);
fire(events::block_malleated, ctx.height);
return;
}

// TODO: log block is unconfirmable.
notify(ec, chase::unconfirmable, link);
fire(events::block_unconfirmable, ctx.height);
return;
}

// TODO:
// If ec (other than store_integrity) block is unconfirmable.
// Collect up tx fees and sigops, etc. for block validation with no block.
// Collect up tx fees and sigops, etc. for block validate with no block.

// fire event first so that log is ordered.
fire(events::block_validated, ctx.height);
notify(ec, chase::valid, ctx.height);
}

#if defined (UNDEFINED)
code chaser_validate::validate(const header_link& link,
size_t height) NOEXCEPT
{
code ec{};
const auto& query = archive();

// query.is_malleable64(link) is used when there is no block instance.
if (is_under_bypass(height) && !query.is_malleable64(link))
return update_neutrino(link) ? error::validation_bypass :
error::store_integrity;

ec = query.get_block_state(link);
if (ec == database::error::block_confirmable ||
ec == database::error::block_unconfirmable ||
ec == database::error::block_valid)
return ec;

database::context context{};
const auto block_ptr = query.get_block(link);
if (!block_ptr || !query.get_context(context, link))
return error::store_integrity;

const auto& block = *block_ptr;
if (!query.populate(block))
return system::error::missing_previous_output;

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

if ((ec = block.accept(ctx, subsidy_interval_blocks_, initial_subsidy_)))
return ec;

if ((ec = block.connect(ctx)))
return ec;

// This can only fail if block missing or prevouts are not fully populated.
return update_neutrino(link, block) ? ec : error::store_integrity;
}
#endif // UNDEFINED

// neutrino
// ----------------------------------------------------------------------------

Expand Down
13 changes: 4 additions & 9 deletions src/protocols/protocol_block_in_31800.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,8 @@ bool protocol_block_in_31800::handle_receive_block(const code& ec,
return true;
}

if (query.is_malleated64(*block_ptr))
const auto malleable64 = block_ptr->is_malleable64();
if (malleable64 && query.is_malleated64(*block_ptr))
{
// Disallow known block malleation, drop peer and keep trying.
// Malleation is assumed (and archived) when malleable64 is invalid.
Expand All @@ -318,8 +319,7 @@ bool protocol_block_in_31800::handle_receive_block(const code& ec,

// Transaction/witness commitments are required under checkpoint.
// This ensures that the block/header hash represents expected txs.
const auto bypass = is_under_bypass(ctx.height) &&
!block_ptr->is_malleable64();
const auto bypass = is_under_bypass(ctx.height) && !malleable64;

// Performs full check if block is mally64 (mally32 caught either way).
if (const auto code = check(*block_ptr, ctx, bypass))
Expand Down Expand Up @@ -372,12 +372,7 @@ bool protocol_block_in_31800::handle_receive_block(const code& ec,
const auto size = block_ptr->serialized_size(true);
const chain::transactions_cptr txs_ptr{ block_ptr->transactions_ptr() };

// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
// TODO: ensure that when a mally64 is caught under bypass that tx
// confirmations are reverted when the block is sequentially invalidated.
// Query: A strong_tx may be in a not-yet-confirmed block.
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

// Transactions are set strong when bypass is true.
if (const auto code = query.set_code(*txs_ptr, link, size, bypass))
{
LOGF("Failure storing block [" << encode_hash(hash) << ":"
Expand Down

0 comments on commit fa392c0

Please sign in to comment.