Skip to content
This repository was archived by the owner on Aug 2, 2022. It is now read-only.

Commit

Permalink
Merge pull request #10332 from EOSIO/huangminghuang/state-history-exi…
Browse files Browse the repository at this point in the history
…t-on-write-failure-2.0.x

state-history-exit-on-write-failure-2.0.x
  • Loading branch information
huangminghuang authored May 6, 2021
2 parents e3524f1 + b2a83f8 commit ffce82f
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 30 deletions.
2 changes: 2 additions & 0 deletions libraries/chain/include/eosio/chain/exceptions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -480,6 +480,8 @@ namespace eosio { namespace chain {
3140000, "Exceptions that are allowed to bubble out of emit calls in controller" )
FC_DECLARE_DERIVED_EXCEPTION( checkpoint_exception, controller_emit_signal_exception,
3140001, "Block does not match checkpoint" )
FC_DECLARE_DERIVED_EXCEPTION( state_history_write_exception, controller_emit_signal_exception,
3140002, "State history write error" )


FC_DECLARE_DERIVED_EXCEPTION( abi_exception, chain_exception,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
#include <eosio/chain/types.hpp>
#include <fc/log/logger.hpp>
#include <fc/io/cfile.hpp>

#include <appbase/application.hpp>
namespace eosio {

/*
Expand Down Expand Up @@ -87,39 +87,52 @@ class state_history_log {

template <typename F>
void write_entry(const state_history_log_header& header, const chain::block_id_type& prev_id, F write_payload) {
auto block_num = chain::block_header::num_from_id(header.block_id);
EOS_ASSERT(_begin_block == _end_block || block_num <= _end_block, chain::plugin_exception,
"missed a block in ${name}.log", ("name", name));
try {
auto block_num = chain::block_header::num_from_id(header.block_id);
EOS_ASSERT(_begin_block == _end_block || block_num <= _end_block, chain::plugin_exception,
"missed a block in ${name}.log", ("name", name));

if (_begin_block != _end_block && block_num > _begin_block) {
if (block_num == _end_block) {
EOS_ASSERT(prev_id == last_block_id, chain::plugin_exception, "missed a fork change in ${name}.log",
("name", name));
} else {
state_history_log_header prev;
get_entry(block_num - 1, prev);
EOS_ASSERT(prev_id == prev.block_id, chain::plugin_exception, "missed a fork change in ${name}.log",
("name", name));
if (_begin_block != _end_block && block_num > _begin_block) {
if (block_num == _end_block) {
EOS_ASSERT(prev_id == last_block_id, chain::plugin_exception, "missed a fork change in ${name}.log",
("name", name));
} else {
state_history_log_header prev;
get_entry(block_num - 1, prev);
EOS_ASSERT(prev_id == prev.block_id, chain::plugin_exception, "missed a fork change in ${name}.log",
("name", name));
}
}
}

if (block_num < _end_block)
truncate(block_num);
log.seek_end(0);
uint64_t pos = log.tellp();
write_header(header);
write_payload(log);
uint64_t end = log.tellp();
EOS_ASSERT(end == pos + state_history_log_header_serial_size + header.payload_size, chain::plugin_exception,
"wrote payload with incorrect size to ${name}.log", ("name", name));
log.write((char*)&pos, sizeof(pos));
if (block_num < _end_block)
truncate(block_num);
log.seek_end(0);
uint64_t pos = log.tellp();
write_header(header);
write_payload(log);
uint64_t end = log.tellp();
EOS_ASSERT(end == pos + state_history_log_header_serial_size + header.payload_size, chain::plugin_exception,
"wrote payload with incorrect size to ${name}.log", ("name", name));
log.write((char*)&pos, sizeof(pos));

index.seek_end(0);
index.write((char*)&pos, sizeof(pos));
if (_begin_block == _end_block)
_begin_block = block_num;
_end_block = block_num + 1;
last_block_id = header.block_id;
index.seek_end(0);
index.write((char*)&pos, sizeof(pos));
if (_begin_block == _end_block)
_begin_block = block_num;
_end_block = block_num + 1;
last_block_id = header.block_id;
}
catch(const chain::plugin_exception& e) {
elog( "chain::plugin_exception: ${details}", ("details", e.to_detail_string()) );
// Both app().quit() and exception throwing are required. Without app().quit(),
// the exception would be caught and drop before reaching main(). The exception is
// to ensure the block won't be commited.
appbase::app().quit();
EOS_THROW(
chain::state_history_write_exception,
"State history encountered an Error which it cannot recover from. Please resolve the error and relaunch "
"the process");
}
}

// returns cfile positioned at payload
Expand Down

0 comments on commit ffce82f

Please sign in to comment.