Cleanup on block adding failure (#983)

If a block adding fails (triggering the "Block added hook signalled
failure" error message) the service node list doesn't get reset, which
immediately leads to a bad service node winner (because the winner was
already incremented and not popped off).

This updates it to call the blockchain detached hooks to do the cleanup.

It also changes around loki::defer a little bit to rename the internal
class to `deferred` and make it cancellable (by calling `.cancel()`).
`loki::defer` is repurposed as a free function to get a named `deferred`
object given a lambda, which is needed to be able to call `cancel()` on
it.  (The LOKI_DEFER macro still works as is).
This commit is contained in:
Jason Rhinelander 2019-12-15 18:49:35 -04:00 committed by Doyle
parent 78ded3af70
commit fab8ded246
2 changed files with 22 additions and 9 deletions

View file

@ -42,20 +42,27 @@ double exp2 (double);
uint64_t clamp_u64 (uint64_t val, uint64_t min, uint64_t max);
template <typename lambda_t>
struct defer
struct deferred
{
private:
lambda_t lambda;
defer(lambda_t lambda) : lambda(lambda) {}
~defer() { lambda(); }
bool cancelled = false;
public:
deferred(lambda_t lambda) : lambda(lambda) {}
void cancel() { cancelled = true; }
~deferred() { if (!cancelled) lambda(); }
};
template <typename lambda_t>
#ifdef __GNUG__
[[gnu::warn_unused_result]]
#endif
deferred<lambda_t> defer(lambda_t lambda) { return lambda; }
struct defer_helper
{
template <typename lambda_t>
defer<lambda_t> operator+(lambda_t lambda)
{
return defer<lambda_t>(lambda);
}
deferred<lambda_t> operator+(lambda_t lambda) { return lambda; }
};
#define LOKI_TOKEN_COMBINE2(x, y) x ## y

View file

@ -4024,6 +4024,13 @@ bool Blockchain::handle_block_to_main_chain(const block& bl, const crypto::hash&
LOG_ERROR("Blocks that failed verification should not reach here");
}
auto abort_block = loki::defer([&]() {
pop_block_from_blockchain();
auto old_height = m_db->height();
for (BlockchainDetachedHook* hook : m_blockchain_detached_hooks)
hook->blockchain_detached(old_height, false /*by_pop_blocks*/);
});
// TODO(loki): Not nice, making the hook take in a vector of pair<transaction,
// blobdata> messes with service_node_list::init which only constructs
// a vector of transactions and then subsequently calls block_added, so the
@ -4041,7 +4048,6 @@ bool Blockchain::handle_block_to_main_chain(const block& bl, const crypto::hash&
if (!hook->block_added(bl, only_txs, checkpoint))
{
MERROR("Block added hook signalled failure");
pop_block_from_blockchain();
return false;
}
}
@ -4065,10 +4071,10 @@ bool Blockchain::handle_block_to_main_chain(const block& bl, const crypto::hash&
if (!update_next_cumulative_weight_limit())
{
MERROR("Failed to update next cumulative weight limit");
pop_block_from_blockchain();
return false;
}
abort_block.cancel();
MINFO("+++++ BLOCK SUCCESSFULLY ADDED" << std::endl << "id:\t" << id << std::endl << "PoW:\t" << proof_of_work << std::endl << "HEIGHT " << new_height-1 << ", difficulty:\t" << current_diffic << std::endl << "block reward: " << print_money(fee_summary + base_reward) << "(" << print_money(base_reward) << " + " << print_money(fee_summary) << "), coinbase_weight: " << coinbase_weight << ", cumulative weight: " << cumulative_block_weight << ", " << block_processing_time << "(" << target_calculating_time << "/" << longhash_calculating_time << ")ms");
if(m_show_time_stats)
{