diff --git a/libaleth-interpreter/VM.cpp b/libaleth-interpreter/VM.cpp index f451570a85e..1658ec90589 100644 --- a/libaleth-interpreter/VM.cpp +++ b/libaleth-interpreter/VM.cpp @@ -22,87 +22,102 @@ namespace { -evmc_trace_callback g_traceCallback = nullptr; -evmc_tracer_context* g_traceContext = nullptr; - -void destroy(evmc_instance* _instance) -{ - (void)_instance; -} void delete_output(const evmc_result* result) { delete[] result->output_data; } -evmc_result execute(evmc_instance* _instance, evmc_context* _context, evmc_revision _rev, - evmc_message const* _msg, uint8_t const* _code, size_t _codeSize) noexcept +class InterpreterEvmcInstance : public evmc_instance { - (void)_instance; - std::unique_ptr vm{new dev::eth::VM}; +public: + static InterpreterEvmcInstance* create() { return new InterpreterEvmcInstance{}; } - evmc_result result = {}; - dev::eth::owning_bytes_ref output; - - try - { - output = vm->exec(_context, _rev, _msg, _code, _codeSize); - result.status_code = EVMC_SUCCESS; - result.gas_left = vm->m_io_gas; - } - catch (dev::eth::RevertInstruction& ex) - { - result.status_code = EVMC_REVERT; - result.gas_left = vm->m_io_gas; - output = ex.output(); // This moves the output from the exception! - } - catch (dev::eth::BadInstruction const&) - { - result.status_code = EVMC_UNDEFINED_INSTRUCTION; - } - catch (dev::eth::DisallowedStateChange const&) +private: + InterpreterEvmcInstance() + : evmc_instance{ + EVMC_ABI_VERSION, "interpreter", aleth_get_buildinfo()->project_version, destroy, + execute, setTracer, + nullptr, // set_option + } { - result.status_code = EVMC_STATIC_MODE_VIOLATION; } - catch (dev::eth::VMException const&) + + static void destroy(evmc_instance* _instance) { - result.status_code = EVMC_FAILURE; + delete static_cast(_instance); } - catch (...) + + static evmc_result execute(evmc_instance* _instance, evmc_context* _context, evmc_revision _rev, + evmc_message const* _msg, uint8_t const* _code, size_t _codeSize) noexcept { - result.status_code = EVMC_INTERNAL_ERROR; + std::unique_ptr vm{new dev::eth::VM}; + + evmc_result result = {}; + dev::eth::owning_bytes_ref output; + + auto evmc = static_cast(_instance); + try + { + output = vm->exec(_context, _rev, _msg, _code, _codeSize, evmc->m_traceCallback, + evmc->m_traceContext); + result.status_code = EVMC_SUCCESS; + result.gas_left = vm->m_io_gas; + } + catch (dev::eth::RevertInstruction& ex) + { + result.status_code = EVMC_REVERT; + result.gas_left = vm->m_io_gas; + output = ex.output(); // This moves the output from the exception! + } + catch (dev::eth::BadInstruction const&) + { + result.status_code = EVMC_UNDEFINED_INSTRUCTION; + } + catch (dev::eth::DisallowedStateChange const&) + { + result.status_code = EVMC_STATIC_MODE_VIOLATION; + } + catch (dev::eth::VMException const&) + { + result.status_code = EVMC_FAILURE; + } + catch (...) + { + result.status_code = EVMC_INTERNAL_ERROR; + } + + if (!output.empty()) + { + // Make a copy of the output. + auto outputData = new uint8_t[output.size()]; + std::memcpy(outputData, output.data(), output.size()); + result.output_data = outputData; + result.output_size = output.size(); + result.release = delete_output; + } + + return result; } - if (!output.empty()) + static void setTracer(evmc_instance* _instance, evmc_trace_callback _callback, + evmc_tracer_context* _context) noexcept { - // Make a copy of the output. - auto outputData = new uint8_t[output.size()]; - std::memcpy(outputData, output.data(), output.size()); - result.output_data = outputData; - result.output_size = output.size(); - result.release = delete_output; + auto evmc = static_cast(_instance); + + evmc->m_traceCallback = _callback; + evmc->m_traceContext = _context; } - return result; -} + evmc_trace_callback m_traceCallback = nullptr; + evmc_tracer_context* m_traceContext = nullptr; +}; -void setTracer(evmc_instance* /*_instance*/, evmc_trace_callback _callback, - evmc_tracer_context* _context) noexcept -{ - g_traceCallback = _callback; - g_traceContext = _context; -} } // namespace extern "C" evmc_instance* evmc_create_interpreter() noexcept { - // TODO: Allow creating multiple instances with different configurations. - static evmc_instance s_instance{ - EVMC_ABI_VERSION, "interpreter", aleth_get_buildinfo()->project_version, ::destroy, - ::execute, ::setTracer, - nullptr, // set_option - }; - return &s_instance; + return InterpreterEvmcInstance::create(); } namespace dev @@ -111,7 +126,7 @@ namespace eth { void VM::trace() noexcept { - if (g_traceCallback) + if (m_traceCallback) { auto const& metrics = c_metrics[static_cast(m_OP)]; evmc_uint256be topStackItem; @@ -121,7 +136,7 @@ void VM::trace() noexcept topStackItem = toEvmC(m_SPP[0]); pushedStackItem = &topStackItem; } - g_traceCallback(g_traceContext, m_PC, EVMC_SUCCESS, m_io_gas, m_stackEnd - m_SPP, + m_traceCallback(m_traceContext, m_PC, EVMC_SUCCESS, m_io_gas, m_stackEnd - m_SPP, pushedStackItem, m_mem.size(), 0, 0, nullptr); } } @@ -269,7 +284,8 @@ evmc_tx_context const& VM::getTxContext() // interpreter entry point owning_bytes_ref VM::exec(evmc_context* _context, evmc_revision _rev, const evmc_message* _msg, - uint8_t const* _code, size_t _codeSize) + uint8_t const* _code, size_t _codeSize, evmc_trace_callback _traceCallback, + evmc_tracer_context* _traceContext) { m_context = _context; m_rev = _rev; @@ -278,6 +294,8 @@ owning_bytes_ref VM::exec(evmc_context* _context, evmc_revision _rev, const evmc m_PC = 0; m_pCode = _code; m_codeSize = _codeSize; + m_traceCallback = _traceCallback; + m_traceContext = _traceContext; // trampoline to minimize depth of call stack when calling out m_bounce = &VM::initEntry; diff --git a/libaleth-interpreter/VM.h b/libaleth-interpreter/VM.h index 369f844e17e..f07a3d3e6f0 100644 --- a/libaleth-interpreter/VM.h +++ b/libaleth-interpreter/VM.h @@ -65,7 +65,8 @@ class VM VM() = default; owning_bytes_ref exec(evmc_context* _context, evmc_revision _rev, const evmc_message* _msg, - uint8_t const* _code, size_t _codeSize); + uint8_t const* _code, size_t _codeSize, evmc_trace_callback _traceCallback, + evmc_tracer_context* _traceContext); uint64_t m_io_gas = 0; private: @@ -114,6 +115,8 @@ class VM uint64_t m_newMemSize = 0; uint64_t m_copyMemSize = 0; + evmc_trace_callback m_traceCallback = nullptr; + evmc_tracer_context* m_traceContext = nullptr; void trace() noexcept; // initialize interpreter