From c9d4276443be3e46ed94a4eda0a7e8b87c02050a Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Wed, 15 Jan 2025 12:56:07 -0600 Subject: [PATCH 1/8] GH-1091 Attempt to make interrupt of trx more common --- tests/nodeos_high_transaction_test.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/nodeos_high_transaction_test.py b/tests/nodeos_high_transaction_test.py index 6f99cc6348..5516f08032 100755 --- a/tests/nodeos_high_transaction_test.py +++ b/tests/nodeos_high_transaction_test.py @@ -112,6 +112,9 @@ nonProdNodes.append(node) else: prodNodes.append(node) + if not args.send_duplicates: + # want to test sending to a node that is configured as a producer but not producing + nonProdNodes.append(cluster.biosNode) nonProdNodeCount = len(nonProdNodes) # *** delegate bandwidth to accounts *** From 1a2a0c91836f8456e2ff8b5d3d5f86cd355cc209 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Wed, 15 Jan 2025 14:52:09 -0600 Subject: [PATCH 2/8] GH-1095 Additional use of bios node to test using a configured producer node that is not producing for trx execution --- tests/nodeos_retry_transaction_test.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/nodeos_retry_transaction_test.py b/tests/nodeos_retry_transaction_test.py index 561fe6f6fc..60979e69e2 100755 --- a/tests/nodeos_retry_transaction_test.py +++ b/tests/nodeos_retry_transaction_test.py @@ -130,7 +130,7 @@ apiNodeCount = len(apiNodes) - node=apiNodes[0] + node=cluster.biosNode # use biosNode to test configured as a producer but not producing checkTransIds = [] startTime = time.perf_counter() Print("Create new accounts via %s" % (cluster.eosioAccount.name)) @@ -155,6 +155,7 @@ Print("Transfer funds took %s sec" % (nextTime - startTime)) startTime = nextTime + node=apiNodes[0] Print("Delegate Bandwidth to new accounts") for account in accounts: trans=node.delegatebw(account, 200.0000, 200.0000, waitForTransBlock=False, exitOnError=True, reportStatus=False) From 11f1e9ab031550fdf51096518c6a18ae39274154 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Thu, 16 Jan 2025 11:56:00 -0600 Subject: [PATCH 3/8] GH-1095 Refactor platform_timer and transaction_checktime_timer to use an enum for timer state instead of a bool expired. This allows differentiation between timer expired and interruption. --- libraries/chain/controller.cpp | 2 +- .../include/eosio/chain/platform_timer.hpp | 16 ++++++++--- .../eosio/chain/transaction_context.hpp | 3 ++- .../eosio/chain/wasm_interface_private.hpp | 7 ++--- libraries/chain/platform_timer_accuracy.cpp | 3 ++- libraries/chain/platform_timer_posix.cpp | 27 ++++++++++++------- libraries/chain/transaction_context.cpp | 8 +++--- .../chain/webassembly/runtimes/eos-vm.cpp | 3 ++- 8 files changed, 42 insertions(+), 27 deletions(-) diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index 226a68fe4c..1c44610637 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -4533,7 +4533,7 @@ struct controller_impl { // validated. if (applying_block) { ilog("Interrupting apply block"); - main_thread_timer.expire_now(); + main_thread_timer.interrupt_timer(); } } diff --git a/libraries/chain/include/eosio/chain/platform_timer.hpp b/libraries/chain/include/eosio/chain/platform_timer.hpp index 72fb8d1fef..88aed7fa97 100644 --- a/libraries/chain/include/eosio/chain/platform_timer.hpp +++ b/libraries/chain/include/eosio/chain/platform_timer.hpp @@ -7,8 +7,6 @@ #include -#include - namespace eosio { namespace chain { struct platform_timer { @@ -17,7 +15,8 @@ struct platform_timer { void start(fc::time_point tp); void stop(); - void expire_now(); + void interrupt_timer(); + void _expire_now(); // called by internal timer /* Sets a callback for when timer expires. Be aware this could might fire from a signal handling context and/or on any particular thread. Only a single callback can be registered at once; trying to register more will @@ -35,9 +34,18 @@ struct platform_timer { _expiration_callback_data = user; } - std::atomic_bool expired = true; + enum class state_t { + running, + timed_out, + interrupted, + stopped + }; + state_t timer_state() const { return _state; } private: + std::atomic _state = state_t::stopped; + + struct impl; constexpr static size_t fwd_size = 8; fc::fwd my; diff --git a/libraries/chain/include/eosio/chain/transaction_context.hpp b/libraries/chain/include/eosio/chain/transaction_context.hpp index c8fa1ed0bc..44f3c26dbd 100644 --- a/libraries/chain/include/eosio/chain/transaction_context.hpp +++ b/libraries/chain/include/eosio/chain/transaction_context.hpp @@ -20,12 +20,13 @@ namespace eosio::chain { void start(fc::time_point tp); void stop(); + platform_timer::state_t timer_state() const { return _timer.timer_state(); } + /* Sets a callback for when timer expires. Be aware this could might fire from a signal handling context and/or on any particular thread. Only a single callback can be registered at once; trying to register more will result in an exception. Use nullptr to disable a previously set callback. */ void set_expiration_callback(void(*func)(void*), void* user); - std::atomic_bool& expired; private: platform_timer& _timer; diff --git a/libraries/chain/include/eosio/chain/wasm_interface_private.hpp b/libraries/chain/include/eosio/chain/wasm_interface_private.hpp index f038f2e30f..8b608a1b22 100644 --- a/libraries/chain/include/eosio/chain/wasm_interface_private.hpp +++ b/libraries/chain/include/eosio/chain/wasm_interface_private.hpp @@ -124,8 +124,7 @@ struct eosvmoc_tier { return; if (executing_code_hash.load() == code_id) { ilog("EOS VM OC tier up interrupting ${id}", ("id", code_id)); - eos_vm_oc_compile_interrupt = true; - main_thread_timer.expire_now(); + main_thread_timer.interrupt_timer(); } }); } @@ -172,7 +171,6 @@ struct eosvmoc_tier { const bool allow_oc_interrupt = attempt_tierup && context.is_applying_block() && context.trx_context.has_undo(); auto ex = fc::make_scoped_exit([&]() { if (allow_oc_interrupt) { - eos_vm_oc_compile_interrupt = false; executing_code_hash.store({}); // indicate no longer executing } }); @@ -181,7 +179,7 @@ struct eosvmoc_tier { try { get_instantiated_module(code_hash, vm_type, vm_version, context.trx_context)->apply(context); } catch (const interrupt_exception& e) { - if (allow_oc_interrupt && eos_vm_oc_compile_interrupt) { + if (allow_oc_interrupt && main_thread_timer.timer_state() == platform_timer::state_t::interrupted) { ++eos_vm_oc_compile_interrupt_count; dlog("EOS VM OC compile complete interrupt of ${r} <= ${a}::${act} code ${h}, interrupt #${c}", ("r", context.get_receiver())("a", context.get_action().account) @@ -310,7 +308,6 @@ struct eosvmoc_tier { const wasm_interface::vm_type wasm_runtime_time; const wasm_interface::vm_oc_enable eosvmoc_tierup; large_atomic executing_code_hash{}; - std::atomic eos_vm_oc_compile_interrupt{false}; uint32_t eos_vm_oc_compile_interrupt_count{0}; // for testing #ifdef EOSIO_EOS_VM_OC_RUNTIME_ENABLED diff --git a/libraries/chain/platform_timer_accuracy.cpp b/libraries/chain/platform_timer_accuracy.cpp index 94a69c8944..8634bd4f17 100644 --- a/libraries/chain/platform_timer_accuracy.cpp +++ b/libraries/chain/platform_timer_accuracy.cpp @@ -39,9 +39,10 @@ void compute_and_print_timer_accuracy(platform_timer& timer) { for(unsigned int i = 0; i < loops; ++i) { auto start = std::chrono::high_resolution_clock::now(); timer.start(fc::time_point(fc::time_point::now().time_since_epoch() + fc::microseconds(interval))); - while(!timer.expired) {} + while(timer.timer_state() == platform_timer::state_t::running) {} auto end = std::chrono::high_resolution_clock::now(); int timer_slop = std::chrono::duration_cast(end-start).count() - interval; + timer.stop(); //since more samples are run for the shorter expirations, weigh the longer expirations accordingly. This //helps to make a few results more fair. Two such examples: AWS c4&i5 xen instances being rather stable diff --git a/libraries/chain/platform_timer_posix.cpp b/libraries/chain/platform_timer_posix.cpp index 4388fa18b9..6ccbe46571 100644 --- a/libraries/chain/platform_timer_posix.cpp +++ b/libraries/chain/platform_timer_posix.cpp @@ -21,7 +21,7 @@ struct platform_timer::impl { static void sig_handler(int, siginfo_t* si, void*) { platform_timer* self = (platform_timer*)si->si_value.sival_ptr; - self->expire_now(); + self->_expire_now(); } }; @@ -56,35 +56,42 @@ platform_timer::~platform_timer() { void platform_timer::start(fc::time_point tp) { if(tp == fc::time_point::maximum()) { - expired = false; + _state = state_t::running; return; } fc::microseconds x = tp.time_since_epoch() - fc::time_point::now().time_since_epoch(); if(x.count() <= 0) - expired = true; + _state = state_t::timed_out; else { time_t secs = x.count() / 1000000; long nsec = (x.count() - (secs*1000000)) * 1000; struct itimerspec enable = {{0, 0}, {secs, nsec}}; - expired = false; + _state = state_t::running; if(timer_settime(my->timerid, 0, &enable, NULL) != 0) - expired = true; + _state = state_t::timed_out; } } -void platform_timer::expire_now() { - bool expected = false; - if (expired.compare_exchange_strong(expected, true)) { +void platform_timer::_expire_now() { + state_t expected = state_t::running; + if (_state.compare_exchange_strong(expected, state_t::timed_out)) { + call_expiration_callback(); + } +} + +void platform_timer::interrupt_timer() { + state_t expected = state_t::running; + if (_state.compare_exchange_strong(expected, state_t::interrupted)) { call_expiration_callback(); } } void platform_timer::stop() { - if(expired) + if(_state == state_t::stopped) return; struct itimerspec disable = {{0, 0}, {0, 0}}; timer_settime(my->timerid, 0, &disable, NULL); - expired = true; + _state = state_t::stopped; } } diff --git a/libraries/chain/transaction_context.cpp b/libraries/chain/transaction_context.cpp index 33ad785a5d..c95afa17c8 100644 --- a/libraries/chain/transaction_context.cpp +++ b/libraries/chain/transaction_context.cpp @@ -14,8 +14,7 @@ namespace eosio::chain { transaction_checktime_timer::transaction_checktime_timer(platform_timer& timer) - : expired(timer.expired), _timer(timer) { - expired = 0; + : _timer(timer) { } void transaction_checktime_timer::start(fc::time_point tp) { @@ -489,11 +488,12 @@ namespace eosio::chain { } void transaction_context::checktime()const { - if(BOOST_LIKELY(transaction_timer.expired == false)) + platform_timer::state_t expired = transaction_timer.timer_state(); + if(BOOST_LIKELY(expired == platform_timer::state_t::running)) return; auto now = fc::time_point::now(); - if (explicit_billed_cpu_time && block_deadline > now) { + if (expired == platform_timer::state_t::interrupted) { EOS_THROW( interrupt_exception, "interrupt signaled, ran ${bt}us, start ${s}", ("bt", now - pseudo_start)("s", start) ); } else if( explicit_billed_cpu_time || deadline_exception_code == deadline_exception::code_value ) { diff --git a/libraries/chain/webassembly/runtimes/eos-vm.cpp b/libraries/chain/webassembly/runtimes/eos-vm.cpp index 5325382049..253dabdb49 100644 --- a/libraries/chain/webassembly/runtimes/eos-vm.cpp +++ b/libraries/chain/webassembly/runtimes/eos-vm.cpp @@ -29,7 +29,8 @@ namespace { guard(transaction_checktime_timer& timer, F&& func) : _timer(timer), _func(std::forward(func)) { _timer.set_expiration_callback(&callback, this); - if(_timer.expired) { + platform_timer::state_t expired = _timer.timer_state(); + if(expired == platform_timer::state_t::timed_out || expired == platform_timer::state_t::interrupted) { _func(); // it's harmless if _func is invoked twice } } From 8ad83f22069f6583edfbedf76b60ea8a9e6d331d Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Thu, 16 Jan 2025 13:49:12 -0600 Subject: [PATCH 4/8] GH-1095 Revert removal of eos_vm_oc_compile_interrupt flag, as it is still needed. --- .../chain/include/eosio/chain/wasm_interface_private.hpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libraries/chain/include/eosio/chain/wasm_interface_private.hpp b/libraries/chain/include/eosio/chain/wasm_interface_private.hpp index 8b608a1b22..d60a06ff5e 100644 --- a/libraries/chain/include/eosio/chain/wasm_interface_private.hpp +++ b/libraries/chain/include/eosio/chain/wasm_interface_private.hpp @@ -124,6 +124,7 @@ struct eosvmoc_tier { return; if (executing_code_hash.load() == code_id) { ilog("EOS VM OC tier up interrupting ${id}", ("id", code_id)); + eos_vm_oc_compile_interrupt = true; main_thread_timer.interrupt_timer(); } }); @@ -171,6 +172,7 @@ struct eosvmoc_tier { const bool allow_oc_interrupt = attempt_tierup && context.is_applying_block() && context.trx_context.has_undo(); auto ex = fc::make_scoped_exit([&]() { if (allow_oc_interrupt) { + eos_vm_oc_compile_interrupt = false; executing_code_hash.store({}); // indicate no longer executing } }); @@ -179,7 +181,7 @@ struct eosvmoc_tier { try { get_instantiated_module(code_hash, vm_type, vm_version, context.trx_context)->apply(context); } catch (const interrupt_exception& e) { - if (allow_oc_interrupt && main_thread_timer.timer_state() == platform_timer::state_t::interrupted) { + if (allow_oc_interrupt && eos_vm_oc_compile_interrupt && main_thread_timer.timer_state() == platform_timer::state_t::interrupted) { ++eos_vm_oc_compile_interrupt_count; dlog("EOS VM OC compile complete interrupt of ${r} <= ${a}::${act} code ${h}, interrupt #${c}", ("r", context.get_receiver())("a", context.get_action().account) @@ -308,6 +310,7 @@ struct eosvmoc_tier { const wasm_interface::vm_type wasm_runtime_time; const wasm_interface::vm_oc_enable eosvmoc_tierup; large_atomic executing_code_hash{}; + std::atomic eos_vm_oc_compile_interrupt{false}; uint32_t eos_vm_oc_compile_interrupt_count{0}; // for testing #ifdef EOSIO_EOS_VM_OC_RUNTIME_ENABLED From 1a50b7bd46782afb83a1ada007e3ef50b06d84c3 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Thu, 16 Jan 2025 14:09:43 -0600 Subject: [PATCH 5/8] GH-1095 Update to use the new _state like platform_timer_posix --- .../chain/platform_timer_asio_fallback.cpp | 25 ++++++++++++------- libraries/chain/platform_timer_kqueue.cpp | 19 +++++++++----- 2 files changed, 29 insertions(+), 15 deletions(-) diff --git a/libraries/chain/platform_timer_asio_fallback.cpp b/libraries/chain/platform_timer_asio_fallback.cpp index 547bc5dcc7..d5c355e850 100644 --- a/libraries/chain/platform_timer_asio_fallback.cpp +++ b/libraries/chain/platform_timer_asio_fallback.cpp @@ -57,36 +57,43 @@ platform_timer::~platform_timer() { void platform_timer::start(fc::time_point tp) { if(tp == fc::time_point::maximum()) { - expired = false; + _state = state_t::running; return; } fc::microseconds x = tp.time_since_epoch() - fc::time_point::now().time_since_epoch(); if(x.count() <= 0) - expired = true; + _state = state_t::timed_out; else { - expired = false; + _state = state_t::running; my->timer->expires_after(std::chrono::microseconds(x.count())); my->timer->async_wait([this](const boost::system::error_code& ec) { if(ec) return; - expire_now(); + _expire_now(); }); } } -void platform_timer::expire_now() { - bool expected = false; - if (expired.compare_exchange_strong(expected, true)) { +void platform_timer::_expire_now() { + state_t expected = state_t::running; + if (_state.compare_exchange_strong(expected, state_t::timed_out)) { + call_expiration_callback(); + } +} + +void platform_timer::interrupt_timer() { + state_t expected = state_t::running; + if (_state.compare_exchange_strong(expected, state_t::interrupted)) { call_expiration_callback(); } } void platform_timer::stop() { - if(expired) + if(_state == state_t::stopped) return; my->timer->cancel(); - expired = true; + _state = state_t::stopped; } }} diff --git a/libraries/chain/platform_timer_kqueue.cpp b/libraries/chain/platform_timer_kqueue.cpp index 16f076a0cb..ed64b4b352 100644 --- a/libraries/chain/platform_timer_kqueue.cpp +++ b/libraries/chain/platform_timer_kqueue.cpp @@ -58,7 +58,7 @@ platform_timer::platform_timer() { if(c == 1 && anEvent.filter == EVFILT_TIMER) { platform_timer* self = (platform_timer*)anEvent.udata; - self->expire_now(); + self->_expire_now(); } else if(c == 1 && anEvent.filter == EVFILT_USER) return; @@ -105,21 +105,28 @@ void platform_timer::start(fc::time_point tp) { } } -void platform_timer::expire_now() { - bool expected = false; - if (expired.compare_exchange_strong(expected, true)) { +void platform_timer::_expire_now() { + state_t expected = state_t::running; + if (_state.compare_exchange_strong(expected, state_t::timed_out)) { + call_expiration_callback(); + } +} + +void platform_timer::interrupt_timer() { + state_t expected = state_t::running; + if (_state.compare_exchange_strong(expected, state_t::interrupted)) { call_expiration_callback(); } } void platform_timer::stop() { - if(expired) + if(_state == state_t::stopped) return; struct kevent64_s stop_timer_event; EV_SET64(&stop_timer_event, my->timerid, EVFILT_TIMER, EV_DELETE, 0, 0, 0, 0, 0); kevent64(kqueue_fd, &stop_timer_event, 1, NULL, 0, KEVENT_FLAG_IMMEDIATE, NULL); - expired = true; + _state = state_t::stopped; } }} From 0f4fbb4385af4e94cecf585a2f942a2b8531556f Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Thu, 16 Jan 2025 14:48:26 -0600 Subject: [PATCH 6/8] GH-1095 Allow interrupted transaction to be retried --- plugins/producer_plugin/producer_plugin.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/producer_plugin/producer_plugin.cpp b/plugins/producer_plugin/producer_plugin.cpp index 2339772958..ed74756ac8 100644 --- a/plugins/producer_plugin/producer_plugin.cpp +++ b/plugins/producer_plugin/producer_plugin.cpp @@ -93,6 +93,7 @@ bool exception_is_exhausted(const fc::exception& e) { return (code == block_cpu_usage_exceeded::code_value) || (code == block_net_usage_exceeded::code_value) || (code == deadline_exception::code_value) || + (code == interrupt_exception::code_value) || // allow interrupted trxs to be retried (code == ro_trx_vm_oc_compile_temporary_failure::code_value); } } // namespace From d072fcd763329e884a5e3fbe2c5aaa5218c25c06 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Thu, 16 Jan 2025 16:18:12 -0600 Subject: [PATCH 7/8] GH-1095 Make expire_now() private --- libraries/chain/include/eosio/chain/platform_timer.hpp | 4 ++-- libraries/chain/platform_timer_asio_fallback.cpp | 4 ++-- libraries/chain/platform_timer_kqueue.cpp | 4 ++-- libraries/chain/platform_timer_posix.cpp | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/libraries/chain/include/eosio/chain/platform_timer.hpp b/libraries/chain/include/eosio/chain/platform_timer.hpp index 88aed7fa97..253c35b13d 100644 --- a/libraries/chain/include/eosio/chain/platform_timer.hpp +++ b/libraries/chain/include/eosio/chain/platform_timer.hpp @@ -16,7 +16,6 @@ struct platform_timer { void start(fc::time_point tp); void stop(); void interrupt_timer(); - void _expire_now(); // called by internal timer /* Sets a callback for when timer expires. Be aware this could might fire from a signal handling context and/or on any particular thread. Only a single callback can be registered at once; trying to register more will @@ -43,8 +42,9 @@ struct platform_timer { state_t timer_state() const { return _state; } private: - std::atomic _state = state_t::stopped; + void expire_now(); + std::atomic _state = state_t::stopped; struct impl; constexpr static size_t fwd_size = 8; diff --git a/libraries/chain/platform_timer_asio_fallback.cpp b/libraries/chain/platform_timer_asio_fallback.cpp index d5c355e850..96ae98bfd4 100644 --- a/libraries/chain/platform_timer_asio_fallback.cpp +++ b/libraries/chain/platform_timer_asio_fallback.cpp @@ -69,12 +69,12 @@ void platform_timer::start(fc::time_point tp) { my->timer->async_wait([this](const boost::system::error_code& ec) { if(ec) return; - _expire_now(); + expire_now(); }); } } -void platform_timer::_expire_now() { +void platform_timer::expire_now() { state_t expected = state_t::running; if (_state.compare_exchange_strong(expected, state_t::timed_out)) { call_expiration_callback(); diff --git a/libraries/chain/platform_timer_kqueue.cpp b/libraries/chain/platform_timer_kqueue.cpp index ed64b4b352..53a2804d84 100644 --- a/libraries/chain/platform_timer_kqueue.cpp +++ b/libraries/chain/platform_timer_kqueue.cpp @@ -58,7 +58,7 @@ platform_timer::platform_timer() { if(c == 1 && anEvent.filter == EVFILT_TIMER) { platform_timer* self = (platform_timer*)anEvent.udata; - self->_expire_now(); + self->expire_now(); } else if(c == 1 && anEvent.filter == EVFILT_USER) return; @@ -105,7 +105,7 @@ void platform_timer::start(fc::time_point tp) { } } -void platform_timer::_expire_now() { +void platform_timer::expire_now() { state_t expected = state_t::running; if (_state.compare_exchange_strong(expected, state_t::timed_out)) { call_expiration_callback(); diff --git a/libraries/chain/platform_timer_posix.cpp b/libraries/chain/platform_timer_posix.cpp index 6ccbe46571..aac36a5cd7 100644 --- a/libraries/chain/platform_timer_posix.cpp +++ b/libraries/chain/platform_timer_posix.cpp @@ -21,7 +21,7 @@ struct platform_timer::impl { static void sig_handler(int, siginfo_t* si, void*) { platform_timer* self = (platform_timer*)si->si_value.sival_ptr; - self->_expire_now(); + self->expire_now(); } }; @@ -72,7 +72,7 @@ void platform_timer::start(fc::time_point tp) { } } -void platform_timer::_expire_now() { +void platform_timer::expire_now() { state_t expected = state_t::running; if (_state.compare_exchange_strong(expected, state_t::timed_out)) { call_expiration_callback(); From 848f90eb0ab90642273219de99f3062ace6eef8e Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Fri, 17 Jan 2025 13:48:43 -0600 Subject: [PATCH 8/8] GH-1092 Add assert that start() only called after stop(). Fix transaction_context to call stop() on undo/squash --- libraries/chain/platform_timer_posix.cpp | 1 + libraries/chain/transaction_context.cpp | 2 ++ 2 files changed, 3 insertions(+) diff --git a/libraries/chain/platform_timer_posix.cpp b/libraries/chain/platform_timer_posix.cpp index aac36a5cd7..c968ccbd60 100644 --- a/libraries/chain/platform_timer_posix.cpp +++ b/libraries/chain/platform_timer_posix.cpp @@ -55,6 +55,7 @@ platform_timer::~platform_timer() { } void platform_timer::start(fc::time_point tp) { + assert(_state == state_t::stopped); if(tp == fc::time_point::maximum()) { _state = state_t::running; return; diff --git a/libraries/chain/transaction_context.cpp b/libraries/chain/transaction_context.cpp index c95afa17c8..3276aef1b4 100644 --- a/libraries/chain/transaction_context.cpp +++ b/libraries/chain/transaction_context.cpp @@ -440,10 +440,12 @@ namespace eosio::chain { void transaction_context::squash() { if (undo_session) undo_session->squash(); control.apply_trx_block_context(trx_blk_context); + transaction_timer.stop(); } void transaction_context::undo() { if (undo_session) undo_session->undo(); + transaction_timer.stop(); } void transaction_context::check_net_usage()const {