Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[1.1.0] Fix deferred trx processing #1150

Merged
merged 6 commits into from
Feb 10, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 );
linh2931 marked this conversation as resolved.
Show resolved Hide resolved

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();
linh2931 marked this conversation as resolved.
Show resolved Hide resolved
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();
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was not needed. The undo() call above calls transaction_timer.stop(). I can remove it, but having it here makes it more obvious that it is being called.

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