Skip to content

Commit

Permalink
Merge pull request #1150 from AntelopeIO/GH-1145-replay-errors
Browse files Browse the repository at this point in the history
[1.1.0] Fix deferred trx processing
  • Loading branch information
heifner authored Feb 10, 2025
2 parents dcb9cc9 + 845576c commit a291a42
Show file tree
Hide file tree
Showing 6 changed files with 23 additions and 7 deletions.
3 changes: 2 additions & 1 deletion benchmark/bls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,8 @@ struct interface_in_benchmark {
timer = std::make_unique<platform_timer>();
trx_timer = std::make_unique<transaction_checktime_timer>(*timer);
trx_ctx = std::make_unique<transaction_context>(*chain->control.get(), *ptrx, ptrx->id(), std::move(*trx_timer),
action_digests_t::store_which_t::legacy);
action_digests_t::store_which_t::legacy, fc::time_point::now(),
transaction_metadata::trx_type::input);
trx_ctx->max_transaction_time_subjective = fc::microseconds::maximum();
trx_ctx->init_for_input_trx( ptrx->get_unprunable_size(), ptrx->get_prunable_size() );
trx_ctx->exec(); // this is required to generate action traces to be used by apply_context constructor
Expand Down
8 changes: 6 additions & 2 deletions libraries/chain/controller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2644,7 +2644,8 @@ struct controller_impl {

transaction_checktime_timer trx_timer(timer);
const packed_transaction trx( std::move( etrx ) );
transaction_context trx_context( self, trx, trx.id(), std::move(trx_timer), bb.action_receipt_digests().store_which(), start );
transaction_context trx_context( self, trx, trx.id(), std::move(trx_timer), bb.action_receipt_digests().store_which(),
start, transaction_metadata::trx_type::implicit );

if (auto dm_logger = get_deep_mind_logger(trx_context.is_transient())) {
dm_logger->on_onerror(etrx);
Expand Down Expand Up @@ -2690,6 +2691,8 @@ struct controller_impl {
} catch ( const boost::interprocess::bad_alloc& ) {
throw;
} catch( const fc::exception& e ) {
// apply_onerror for deferred trxs is implicit so interrupt oc not allowed
assert(e.code() != interrupt_oc_exception::code_value);
handle_exception(e);
} catch ( const std::exception& e ) {
auto wrapper = fc::std_exception_wrapper::from_current_exception(e);
Expand Down Expand Up @@ -2815,7 +2818,8 @@ struct controller_impl {
auto& bb = std::get<building_block>(pending->_block_stage);

transaction_checktime_timer trx_timer( timer );
transaction_context trx_context( self, *trx->packed_trx(), gtrx.trx_id, std::move(trx_timer), bb.action_receipt_digests().store_which() );
transaction_context trx_context( self, *trx->packed_trx(), gtrx.trx_id, std::move(trx_timer), bb.action_receipt_digests().store_which(),
start, transaction_metadata::trx_type::scheduled );
trx_context.leeway = fc::microseconds(0); // avoid stealing cpu resource
trx_context.block_deadline = block_deadline;
trx_context.max_transaction_time_subjective = max_transaction_time;
Expand Down
6 changes: 4 additions & 2 deletions libraries/chain/include/eosio/chain/transaction_context.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,8 @@ namespace eosio::chain {
const transaction_id_type& trx_id, // trx_id diff than t.id() before replace_deferred
transaction_checktime_timer&& timer,
action_digests_t::store_which_t sad,
fc::time_point start = fc::time_point::now(),
transaction_metadata::trx_type type = transaction_metadata::trx_type::input);
fc::time_point start,
transaction_metadata::trx_type type);
~transaction_context();

void init_for_implicit_trx();
Expand Down Expand Up @@ -162,6 +162,8 @@ namespace eosio::chain {
bool is_dry_run()const { return trx_type == transaction_metadata::trx_type::dry_run; };
bool is_read_only()const { return trx_type == transaction_metadata::trx_type::read_only; };
bool is_transient()const { return trx_type == transaction_metadata::trx_type::read_only || trx_type == transaction_metadata::trx_type::dry_run; };
bool is_implicit()const { return trx_type == transaction_metadata::trx_type::implicit; };
bool is_scheduled()const { return trx_type == transaction_metadata::trx_type::scheduled; };
bool has_undo()const;

int64_t set_proposed_producers(vector<producer_authority> producers);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,14 @@ struct eosvmoc_tier {
}
}
#endif
const bool allow_oc_interrupt = attempt_tierup && context.is_applying_block() && context.trx_context.has_undo();
// Do not allow oc interrupt if no undo as the transaction needs to be undone to restart it.
// Do not allow oc interrupt if implicit or scheduled. There are two implicit trxs: onblock and onerror.
// The onerror trx of deferred trxs is implicit. Interrupt needs to be disabled for deferred trxs because
// they capture all exceptions, explicitly handle undo stack, and directly call trx_context.execute_action.
// Not allowing interrupt for onblock seems rather harmless, so instead of distinguishing between onerror and
// onblock, just disallow for all implicit.
const bool allow_oc_interrupt = attempt_tierup && context.is_applying_block() &&
context.trx_context.has_undo() && !context.trx_context.is_implicit() && !context.trx_context.is_scheduled();
auto ex = fc::make_scoped_exit([&]() {
if (allow_oc_interrupt) {
eos_vm_oc_compile_interrupt = false;
Expand Down
1 change: 1 addition & 0 deletions libraries/chain/transaction_context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ namespace eosio::chain {
undo();
*trace = transaction_trace{}; // reset trace
initialize();
transaction_timer.stop();
resume_billing_timer(start);

auto sw = executed_action_receipts.store_which();
Expand Down
3 changes: 2 additions & 1 deletion libraries/chain/webassembly/runtimes/eos-vm-oc/executor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,6 @@ void executor::execute(const code_descriptor& code, memory& mem, apply_context&
syscall(SYS_mprotect, self->code_mapping, self->code_mapping_size, PROT_NONE);
self->mapping_is_executable = false;
}, this);
context.trx_context.checktime(); //catch any expiration that might have occurred before setting up callback

auto cleanup = fc::make_scoped_exit([cb, &tt=context.trx_context.transaction_timer, &mem=mem](){
cb->is_running = false;
Expand All @@ -245,6 +244,8 @@ void executor::execute(const code_descriptor& code, memory& mem, apply_context&
}
});

context.trx_context.checktime(); //catch any expiration that might have occurred before setting up callback

void(*apply_func)(uint64_t, uint64_t, uint64_t) = (void(*)(uint64_t, uint64_t, uint64_t))(cb->running_code_base + code.apply_offset);

switch(sigsetjmp(*cb->jmp, 0)) {
Expand Down

0 comments on commit a291a42

Please sign in to comment.