From e3b84b8b48a36b0d7099a49a48cf71b87090e31a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 31 Oct 2019 10:38:17 +0100 Subject: [PATCH 1/6] Move evmc_host_interface out of evmc_host_context --- examples/example.c | 5 +- examples/example_host.cpp | 10 +- examples/example_host.h | 2 + .../example_precompiles_vm.cpp | 5 +- examples/example_vm/example_vm.c | 13 ++- include/evmc/evmc.h | 30 ++--- include/evmc/evmc.hpp | 103 ++++++++++++------ include/evmc/helpers.h | 3 +- test/unittests/test_cpp.cpp | 10 +- test/vmtester/tests.cpp | 8 +- 10 files changed, 115 insertions(+), 74 deletions(-) diff --git a/examples/example.c b/examples/example.c index 863d536..3ee30af 100644 --- a/examples/example.c +++ b/examples/example.c @@ -48,6 +48,7 @@ int main(int argc, char* argv[]) tx_context.block_number = 42; tx_context.block_timestamp = 66; tx_context.block_gas_limit = gas * 2; + const struct evmc_host_interface* host = example_host_get_interface(); struct evmc_host_context* ctx = example_host_create_context(tx_context); struct evmc_message msg; msg.kind = EVMC_CALL; @@ -58,7 +59,7 @@ int main(int argc, char* argv[]) msg.input_size = sizeof(input); msg.gas = gas; msg.depth = 0; - struct evmc_result result = evmc_execute(vm, ctx, EVMC_HOMESTEAD, &msg, code, code_size); + struct evmc_result result = evmc_execute(vm, host, ctx, EVMC_HOMESTEAD, &msg, code, code_size); printf("Execution result:\n"); int exit_code = 0; if (result.status_code != EVMC_SUCCESS) @@ -77,7 +78,7 @@ int main(int argc, char* argv[]) printf("%02x", result.output_data[i]); printf("\n"); const evmc_bytes32 storage_key = {{0}}; - evmc_bytes32 storage_value = ctx->host->get_storage(ctx, &msg.destination, &storage_key); + evmc_bytes32 storage_value = host->get_storage(ctx, &msg.destination, &storage_key); printf(" Storage at 0x00..00: "); for (i = 0; i < sizeof(storage_value.bytes) / sizeof(storage_value.bytes[0]); i++) printf("%02x", storage_value.bytes[i]); diff --git a/examples/example_host.cpp b/examples/example_host.cpp index 08df029..64545a0 100644 --- a/examples/example_host.cpp +++ b/examples/example_host.cpp @@ -160,13 +160,19 @@ public: extern "C" { +const evmc_host_interface* example_host_get_interface() +{ + return evmc::Host::get_interface(); +} + evmc_host_context* example_host_create_context(evmc_tx_context tx_context) { - return new ExampleHost(tx_context); + auto host = new ExampleHost{tx_context}; + return host->to_context(); } void example_host_destroy_context(evmc_host_context* context) { - delete static_cast(context); + delete evmc::Host::from_context(context); } } diff --git a/examples/example_host.h b/examples/example_host.h index 6c54920..9f76c19 100644 --- a/examples/example_host.h +++ b/examples/example_host.h @@ -9,6 +9,8 @@ extern "C" { #endif +const struct evmc_host_interface* example_host_get_interface(); + struct evmc_host_context* example_host_create_context(struct evmc_tx_context tx_context); void example_host_destroy_context(struct evmc_host_context* context); diff --git a/examples/example_precompiles_vm/example_precompiles_vm.cpp b/examples/example_precompiles_vm/example_precompiles_vm.cpp index 233cf3c..52fd1c2 100644 --- a/examples/example_precompiles_vm/example_precompiles_vm.cpp +++ b/examples/example_precompiles_vm/example_precompiles_vm.cpp @@ -48,8 +48,9 @@ static evmc_result not_implemented() return result; } -static evmc_result execute(evmc_vm*, - evmc_host_context*, +static evmc_result execute(evmc_vm* /*unused*/, + const evmc_host_interface* /*unused*/, + evmc_host_context* /*unused*/, enum evmc_revision rev, const evmc_message* msg, const uint8_t*, diff --git a/examples/example_vm/example_vm.c b/examples/example_vm/example_vm.c index 4574782..de3003a 100644 --- a/examples/example_vm/example_vm.c +++ b/examples/example_vm/example_vm.c @@ -75,6 +75,7 @@ static void free_result_output_data(const struct evmc_result* result) /// The example implementation of the evmc_vm::execute() method. static struct evmc_result execute(struct evmc_vm* instance, + const struct evmc_host_interface* host, struct evmc_host_context* context, enum evmc_revision rev, const struct evmc_message* msg, @@ -142,16 +143,16 @@ static struct evmc_result execute(struct evmc_vm* instance, strncmp((const char*)code, counter, code_size) == 0) { const evmc_bytes32 key = {{0}}; - evmc_bytes32 value = context->host->get_storage(context, &msg->destination, &key); + evmc_bytes32 value = host->get_storage(context, &msg->destination, &key); value.bytes[31]++; - context->host->set_storage(context, &msg->destination, &key, &value); + host->set_storage(context, &msg->destination, &key, &value); ret.status_code = EVMC_SUCCESS; return ret; } else if (code_size == (sizeof(return_block_number) - 1) && strncmp((const char*)code, return_block_number, code_size) == 0) { - const struct evmc_tx_context tx_context = context->host->get_tx_context(context); + const struct evmc_tx_context tx_context = host->get_tx_context(context); const size_t output_size = 20; uint8_t* output_data = (uint8_t*)calloc(1, output_size); @@ -166,7 +167,7 @@ static struct evmc_result execute(struct evmc_vm* instance, else if (code_size == (sizeof(save_return_block_number) - 1) && strncmp((const char*)code, save_return_block_number, code_size) == 0) { - const struct evmc_tx_context tx_context = context->host->get_tx_context(context); + const struct evmc_tx_context tx_context = host->get_tx_context(context); const size_t output_size = 20; // Store block number. @@ -174,7 +175,7 @@ static struct evmc_result execute(struct evmc_vm* instance, evmc_bytes32 value = {{0}}; // NOTE: assume block number is <= 255 value.bytes[31] = (uint8_t)tx_context.block_number; - context->host->set_storage(context, &msg->destination, &key, &value); + host->set_storage(context, &msg->destination, &key, &value); // Return block number. uint8_t* output_data = (uint8_t*)calloc(1, output_size); @@ -195,7 +196,7 @@ static struct evmc_result execute(struct evmc_vm* instance, call_msg.depth = msg->depth + 1; call_msg.gas = msg->gas - (msg->gas / 64); call_msg.sender = msg->destination; - return context->host->call(context, &call_msg); + return host->call(context, &call_msg); } ret.status_code = EVMC_FAILURE; diff --git a/include/evmc/evmc.h b/include/evmc/evmc.h index a3afa51..fe950d3 100644 --- a/include/evmc/evmc.h +++ b/include/evmc/evmc.h @@ -156,6 +156,11 @@ struct evmc_tx_context evmc_uint256be chain_id; /**< The blockchain's ChainID. */ }; +/** + * @struct evmc_host_context + * The opaque data type representing the Host execution context. + * @see evmc_execute_fn(). + */ struct evmc_host_context; /** @@ -653,22 +658,6 @@ struct evmc_host_interface }; -/** - * Execution context managed by the Host. - * - * The Host MUST pass the pointer to the execution context to ::evmc_execute_fn. - * The VM MUST pass the same pointer back to the Host in every callback function. - * The context MUST contain at least the function table defining - * the context callback interface. - * Optionally, the Host MAY include in the context additional data. - */ -struct evmc_host_context -{ - /** The Host interface. */ - const struct evmc_host_interface* host; -}; - - /* Forward declaration. */ struct evmc_vm; @@ -791,10 +780,12 @@ enum evmc_revision * This function MAY be invoked multiple times for a single VM instance. * * @param vm The VM instance. This argument MUST NOT be NULL. - * @param context The pointer to the Host execution context to be passed - * to the Host interface methods (::evmc_host_interface). - * This argument MUST NOT be NULL unless + * @param host The Host interface. This argument MUST NOT be NULL unless * the @p vm has the ::EVMC_CAPABILITY_PRECOMPILES capability. + * @param context The opaque pointer to the Host execution context. + * This argument MAY be NULL. The VM MUST pass the same + * pointer to the methods of the @p host interface. + * The VM MUST NOT dereference the pointer. * @param rev The requested EVM specification revision. * @param msg The call parameters. See ::evmc_message. This argument MUST NOT be NULL. * @param code The reference to the code to be executed. This argument MAY be NULL. @@ -802,6 +793,7 @@ enum evmc_revision * @return The execution result. */ typedef struct evmc_result (*evmc_execute_fn)(struct evmc_vm* vm, + const struct evmc_host_interface* host, struct evmc_host_context* context, enum evmc_revision rev, const struct evmc_message* msg, diff --git a/include/evmc/evmc.hpp b/include/evmc/evmc.hpp index a159569..d2c29f2 100644 --- a/include/evmc/evmc.hpp +++ b/include/evmc/evmc.hpp @@ -398,13 +398,14 @@ public: } /// @copydoc evmc_execute() - result execute(evmc_host_context& ctx, + result execute(const evmc_host_interface& host, + evmc_host_context* ctx, evmc_revision rev, const evmc_message& msg, const uint8_t* code, size_t code_size) noexcept { - return result{m_instance->execute(m_instance, &ctx, rev, &msg, code, code_size)}; + return result{m_instance->execute(m_instance, &host, ctx, rev, &msg, code, code_size)}; } private: @@ -478,43 +479,46 @@ public: /// To be used by VM implementations as better alternative to using ::evmc_host_context directly. class HostContext : public HostInterface { + const evmc_host_interface* host = nullptr; evmc_host_context* context = nullptr; evmc_tx_context tx_context = {}; public: /// Implicit converting constructor from evmc_host_context. - HostContext(evmc_host_context* ctx) noexcept : context{ctx} {} // NOLINT + HostContext(const evmc_host_interface* interface, evmc_host_context* ctx) noexcept + : host{interface}, context{ctx} + {} bool account_exists(const address& address) noexcept final { - return context->host->account_exists(context, &address); + return host->account_exists(context, &address); } bytes32 get_storage(const address& address, const bytes32& key) noexcept final { - return context->host->get_storage(context, &address, &key); + return host->get_storage(context, &address, &key); } evmc_storage_status set_storage(const address& address, const bytes32& key, const bytes32& value) noexcept final { - return context->host->set_storage(context, &address, &key, &value); + return host->set_storage(context, &address, &key, &value); } uint256be get_balance(const address& address) noexcept final { - return context->host->get_balance(context, &address); + return host->get_balance(context, &address); } size_t get_code_size(const address& address) noexcept final { - return context->host->get_code_size(context, &address); + return host->get_code_size(context, &address); } bytes32 get_code_hash(const address& address) noexcept final { - return context->host->get_code_hash(context, &address); + return host->get_code_hash(context, &address); } size_t copy_code(const address& address, @@ -522,17 +526,17 @@ public: uint8_t* buffer_data, size_t buffer_size) noexcept final { - return context->host->copy_code(context, &address, code_offset, buffer_data, buffer_size); + return host->copy_code(context, &address, code_offset, buffer_data, buffer_size); } void selfdestruct(const address& addr, const address& beneficiary) noexcept final { - context->host->selfdestruct(context, &addr, &beneficiary); + host->selfdestruct(context, &addr, &beneficiary); } result call(const evmc_message& message) noexcept final { - return result{context->host->call(context, &message)}; + return result{host->call(context, &message)}; } /// @copydoc HostInterface::get_tx_context() @@ -544,13 +548,13 @@ public: evmc_tx_context get_tx_context() noexcept final { if (tx_context.block_timestamp == 0) - tx_context = context->host->get_tx_context(context); + tx_context = host->get_tx_context(context); return tx_context; } bytes32 get_block_hash(int64_t number) noexcept final { - return context->host->get_block_hash(context, number); + return host->get_block_hash(context, number); } void emit_log(const address& addr, @@ -559,7 +563,7 @@ public: const bytes32 topics[], size_t topics_count) noexcept final { - context->host->emit_log(context, &addr, data, data_size, topics, topics_count); + host->emit_log(context, &addr, data, data_size, topics, topics_count); } }; @@ -567,43 +571,63 @@ public: /// /// When implementing EVMC Host, you can directly inherit from the evmc::Host class. /// This way your implementation will be simpler by avoiding manual handling -/// of the ::evmc_host_context and the ::evmc_host_context::host. -class Host : public HostInterface, public evmc_host_context +/// of the ::evmc_host_context and the ::evmc_host_interface. +class Host : public HostInterface { public: - inline Host() noexcept; + /// Provides access to the global host interface. + /// @returns Pointer to the host interface object. + static const evmc_host_interface* get_interface() noexcept; + + /// Converts the Host object to the opaque host context pointer. + /// @returns Pointer to evmc_host_context. + evmc_host_context* to_context() noexcept { return reinterpret_cast(this); } + + /// Converts the opaque host context pointer back to the original Host object. + /// @tparam DerivedClass The class derived from the Host class. + /// @param context The opaque host context pointer. + /// @returns The pointer to DerivedClass. + template + static DerivedClass* from_context(evmc_host_context* context) noexcept + { + // Get pointer of the Host base class. + auto* h = reinterpret_cast(context); + + // Additional downcast, only possible if DerivedClass inherits from Host. + return static_cast(h); + } }; namespace internal { inline bool account_exists(evmc_host_context* h, const evmc_address* addr) noexcept { - return static_cast(h)->account_exists(*addr); + return reinterpret_cast(h)->account_exists(*addr); } inline evmc_bytes32 get_storage(evmc_host_context* h, const evmc_address* addr, const evmc_bytes32* key) noexcept { - return static_cast(h)->get_storage(*addr, *key); + return reinterpret_cast(h)->get_storage(*addr, *key); } inline evmc_storage_status set_storage(evmc_host_context* h, const evmc_address* addr, const evmc_bytes32* key, const evmc_bytes32* value) noexcept { - return static_cast(h)->set_storage(*addr, *key, *value); + return reinterpret_cast(h)->set_storage(*addr, *key, *value); } inline evmc_uint256be get_balance(evmc_host_context* h, const evmc_address* addr) noexcept { - return static_cast(h)->get_balance(*addr); + return reinterpret_cast(h)->get_balance(*addr); } inline size_t get_code_size(evmc_host_context* h, const evmc_address* addr) noexcept { - return static_cast(h)->get_code_size(*addr); + return reinterpret_cast(h)->get_code_size(*addr); } inline evmc_bytes32 get_code_hash(evmc_host_context* h, const evmc_address* addr) noexcept { - return static_cast(h)->get_code_hash(*addr); + return reinterpret_cast(h)->get_code_hash(*addr); } inline size_t copy_code(evmc_host_context* h, const evmc_address* addr, @@ -611,25 +635,25 @@ inline size_t copy_code(evmc_host_context* h, uint8_t* buffer_data, size_t buffer_size) noexcept { - return static_cast(h)->copy_code(*addr, code_offset, buffer_data, buffer_size); + return reinterpret_cast(h)->copy_code(*addr, code_offset, buffer_data, buffer_size); } inline void selfdestruct(evmc_host_context* h, const evmc_address* addr, const evmc_address* beneficiary) noexcept { - static_cast(h)->selfdestruct(*addr, *beneficiary); + reinterpret_cast(h)->selfdestruct(*addr, *beneficiary); } inline evmc_result call(evmc_host_context* h, const evmc_message* msg) noexcept { - return static_cast(h)->call(*msg).release_raw(); + return reinterpret_cast(h)->call(*msg).release_raw(); } inline evmc_tx_context get_tx_context(evmc_host_context* h) noexcept { - return static_cast(h)->get_tx_context(); + return reinterpret_cast(h)->get_tx_context(); } inline evmc_bytes32 get_block_hash(evmc_host_context* h, int64_t block_number) noexcept { - return static_cast(h)->get_block_hash(block_number); + return reinterpret_cast(h)->get_block_hash(block_number); } inline void emit_log(evmc_host_context* h, const evmc_address* addr, @@ -638,16 +662,25 @@ inline void emit_log(evmc_host_context* h, const evmc_bytes32 topics[], size_t num_topics) noexcept { - static_cast(h)->emit_log(*addr, data, data_size, static_cast(topics), - num_topics); + reinterpret_cast(h)->emit_log(*addr, data, data_size, + static_cast(topics), num_topics); } -constexpr evmc_host_interface interface{ - account_exists, get_storage, set_storage, get_balance, get_code_size, get_code_hash, - copy_code, selfdestruct, call, get_tx_context, get_block_hash, emit_log}; + } // namespace internal -inline Host::Host() noexcept : evmc_host_context{&evmc::internal::interface} {} +inline const evmc_host_interface* Host::get_interface() noexcept +{ + static constexpr evmc_host_interface interface{ + ::evmc::internal::account_exists, ::evmc::internal::get_storage, + ::evmc::internal::set_storage, ::evmc::internal::get_balance, + ::evmc::internal::get_code_size, ::evmc::internal::get_code_hash, + ::evmc::internal::copy_code, ::evmc::internal::selfdestruct, + ::evmc::internal::call, ::evmc::internal::get_tx_context, + ::evmc::internal::get_block_hash, ::evmc::internal::emit_log}; + return &interface; +} + } // namespace evmc diff --git a/include/evmc/helpers.h b/include/evmc/helpers.h index 5c05be5..36febfd 100644 --- a/include/evmc/helpers.h +++ b/include/evmc/helpers.h @@ -85,13 +85,14 @@ static inline enum evmc_set_option_result evmc_set_option(struct evmc_vm* vm, * @see evmc_execute_fn. */ static inline struct evmc_result evmc_execute(struct evmc_vm* vm, + const struct evmc_host_interface* host, struct evmc_host_context* context, enum evmc_revision rev, const struct evmc_message* msg, uint8_t const* code, size_t code_size) { - return vm->execute(vm, context, rev, msg, code, code_size); + return vm->execute(vm, host, context, rev, msg, code, code_size); } /// The evmc_result release function using free() for releasing the memory. diff --git a/test/unittests/test_cpp.cpp b/test/unittests/test_cpp.cpp index 1ec8c19..5e2cbf4 100644 --- a/test/unittests/test_cpp.cpp +++ b/test/unittests/test_cpp.cpp @@ -268,8 +268,8 @@ TEST(cpp, vm) EXPECT_EQ(vm.name(), std::string{"example_vm"}); EXPECT_NE(vm.version()[0], 0); - auto ctx = evmc_host_context{}; - auto res = vm.execute(ctx, EVMC_MAX_REVISION, {}, nullptr, 0); + const auto host = evmc_host_interface{}; + auto res = vm.execute(host, nullptr, EVMC_MAX_REVISION, {}, nullptr, 0); EXPECT_EQ(res.status_code, EVMC_FAILURE); EXPECT_TRUE(vm.get_capabilities() & EVMC_CAPABILITY_EVM1); @@ -348,8 +348,9 @@ TEST(cpp, host) { // Use example host to execute all methods from the C++ host wrapper. + auto* host_interface = example_host_get_interface(); auto* host_context = example_host_create_context(evmc_tx_context{}); - auto host = evmc::HostContext{host_context}; + auto host = evmc::HostContext{host_interface, host_context}; const auto a = evmc::address{{{1}}}; const auto v = evmc::bytes32{{{7, 7, 7}}}; @@ -382,8 +383,9 @@ TEST(cpp, host_call) { // Use example host to test Host::call() method. + auto* host_interface = example_host_get_interface(); auto* host_context = example_host_create_context(evmc_tx_context{}); - auto host = evmc::HostContext{host_context}; + auto host = evmc::HostContext{host_interface, host_context}; EXPECT_EQ(host.call({}).gas_left, 0); diff --git a/test/vmtester/tests.cpp b/test/vmtester/tests.cpp index 32ebac9..1064d3c 100644 --- a/test/vmtester/tests.cpp +++ b/test/vmtester/tests.cpp @@ -59,12 +59,13 @@ TEST_F(evmc_vm_test, capabilities) TEST_F(evmc_vm_test, execute_call) { + const evmc_host_interface* host = example_host_get_interface(); evmc_host_context* context = example_host_create_context(evmc_tx_context{}); evmc_message msg{}; std::array code = {{0xfe, 0x00}}; evmc_result result = - vm->execute(vm, context, EVMC_MAX_REVISION, &msg, code.data(), code.size()); + vm->execute(vm, host, context, EVMC_MAX_REVISION, &msg, code.data(), code.size()); // Validate some constraints if (result.status_code != EVMC_SUCCESS && result.status_code != EVMC_REVERT) @@ -92,6 +93,7 @@ TEST_F(evmc_vm_test, execute_call) TEST_F(evmc_vm_test, execute_create) { + const evmc_host_interface* host = example_host_get_interface(); evmc_host_context* context = example_host_create_context(evmc_tx_context{}); evmc_message msg{ EVMC_CREATE, 0, 0, 65536, evmc_address{}, evmc_address{}, nullptr, 0, evmc_uint256be{}, @@ -99,7 +101,7 @@ TEST_F(evmc_vm_test, execute_create) std::array code = {{0xfe, 0x00}}; evmc_result result = - vm->execute(vm, context, EVMC_MAX_REVISION, &msg, code.data(), code.size()); + vm->execute(vm, host, context, EVMC_MAX_REVISION, &msg, code.data(), code.size()); // Validate some constraints if (result.status_code != EVMC_SUCCESS && result.status_code != EVMC_REVERT) @@ -181,7 +183,7 @@ TEST_F(evmc_vm_test, precompile_test) EVMC_CALL, 0, 0, 65536, destination, evmc_address{}, nullptr, 0, evmc_uint256be{}, evmc_bytes32{}}; - evmc_result result = vm->execute(vm, nullptr, EVMC_MAX_REVISION, &msg, nullptr, 0); + evmc_result result = vm->execute(vm, nullptr, nullptr, EVMC_MAX_REVISION, &msg, nullptr, 0); // Validate some constraints From cbd068a9793f085fc53c7fa139c64f078dd28ffa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 31 Oct 2019 10:46:47 +0100 Subject: [PATCH 2/6] cpp: Reuse from_context() to implement evmc_host_interface --- include/evmc/evmc.hpp | 43 +++++++++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/include/evmc/evmc.hpp b/include/evmc/evmc.hpp index d2c29f2..e161c03 100644 --- a/include/evmc/evmc.hpp +++ b/include/evmc/evmc.hpp @@ -587,7 +587,7 @@ public: /// @tparam DerivedClass The class derived from the Host class. /// @param context The opaque host context pointer. /// @returns The pointer to DerivedClass. - template + template static DerivedClass* from_context(evmc_host_context* context) noexcept { // Get pointer of the Host base class. @@ -602,59 +602,70 @@ namespace internal { inline bool account_exists(evmc_host_context* h, const evmc_address* addr) noexcept { - return reinterpret_cast(h)->account_exists(*addr); + return Host::from_context(h)->account_exists(*addr); } + inline evmc_bytes32 get_storage(evmc_host_context* h, const evmc_address* addr, const evmc_bytes32* key) noexcept { - return reinterpret_cast(h)->get_storage(*addr, *key); + return Host::from_context(h)->get_storage(*addr, *key); } + inline evmc_storage_status set_storage(evmc_host_context* h, const evmc_address* addr, const evmc_bytes32* key, const evmc_bytes32* value) noexcept { - return reinterpret_cast(h)->set_storage(*addr, *key, *value); + return Host::from_context(h)->set_storage(*addr, *key, *value); } + inline evmc_uint256be get_balance(evmc_host_context* h, const evmc_address* addr) noexcept { - return reinterpret_cast(h)->get_balance(*addr); + return Host::from_context(h)->get_balance(*addr); } + inline size_t get_code_size(evmc_host_context* h, const evmc_address* addr) noexcept { - return reinterpret_cast(h)->get_code_size(*addr); + return Host::from_context(h)->get_code_size(*addr); } + inline evmc_bytes32 get_code_hash(evmc_host_context* h, const evmc_address* addr) noexcept { - return reinterpret_cast(h)->get_code_hash(*addr); + return Host::from_context(h)->get_code_hash(*addr); } + inline size_t copy_code(evmc_host_context* h, const evmc_address* addr, size_t code_offset, uint8_t* buffer_data, size_t buffer_size) noexcept { - return reinterpret_cast(h)->copy_code(*addr, code_offset, buffer_data, buffer_size); + return Host::from_context(h)->copy_code(*addr, code_offset, buffer_data, buffer_size); } + inline void selfdestruct(evmc_host_context* h, const evmc_address* addr, const evmc_address* beneficiary) noexcept { - reinterpret_cast(h)->selfdestruct(*addr, *beneficiary); + Host::from_context(h)->selfdestruct(*addr, *beneficiary); } + inline evmc_result call(evmc_host_context* h, const evmc_message* msg) noexcept { - return reinterpret_cast(h)->call(*msg).release_raw(); + return Host::from_context(h)->call(*msg).release_raw(); } + inline evmc_tx_context get_tx_context(evmc_host_context* h) noexcept { - return reinterpret_cast(h)->get_tx_context(); + return Host::from_context(h)->get_tx_context(); } + inline evmc_bytes32 get_block_hash(evmc_host_context* h, int64_t block_number) noexcept { - return reinterpret_cast(h)->get_block_hash(block_number); + return Host::from_context(h)->get_block_hash(block_number); } + inline void emit_log(evmc_host_context* h, const evmc_address* addr, const uint8_t* data, @@ -662,11 +673,9 @@ inline void emit_log(evmc_host_context* h, const evmc_bytes32 topics[], size_t num_topics) noexcept { - reinterpret_cast(h)->emit_log(*addr, data, data_size, - static_cast(topics), num_topics); + Host::from_context(h)->emit_log(*addr, data, data_size, static_cast(topics), + num_topics); } - - } // namespace internal inline const evmc_host_interface* Host::get_interface() noexcept @@ -680,8 +689,6 @@ inline const evmc_host_interface* Host::get_interface() noexcept ::evmc::internal::get_block_hash, ::evmc::internal::emit_log}; return &interface; } - - } // namespace evmc From e0ab5b1d539b11224cd29cf18f32a821e4e5b563 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 20 Sep 2019 14:16:27 +0200 Subject: [PATCH 3/6] Update Go bindings --- bindings/go/evmc/evmc.go | 24 +++++++++-------------- bindings/go/evmc/host.go | 42 ++++++++++++---------------------------- 2 files changed, 21 insertions(+), 45 deletions(-) diff --git a/bindings/go/evmc/evmc.go b/bindings/go/evmc/evmc.go index e3063fa..db72bf3 100644 --- a/bindings/go/evmc/evmc.go +++ b/bindings/go/evmc/evmc.go @@ -23,16 +23,10 @@ static inline enum evmc_set_option_result set_option(struct evmc_vm* vm, char* n return ret; } -struct extended_context -{ - struct evmc_host_context context; - int64_t index; -}; - extern const struct evmc_host_interface evmc_go_host; static struct evmc_result execute_wrapper(struct evmc_vm* vm, - int64_t context_index, enum evmc_revision rev, + uintptr_t context_index, enum evmc_revision rev, enum evmc_call_kind kind, uint32_t flags, int32_t depth, int64_t gas, const evmc_address* destination, const evmc_address* sender, const uint8_t* input_data, size_t input_size, const evmc_uint256be* value, @@ -51,8 +45,8 @@ static struct evmc_result execute_wrapper(struct evmc_vm* vm, *create2_salt, }; - struct extended_context ctx = {{&evmc_go_host}, context_index}; - return evmc_execute(vm, &ctx.context, rev, &msg, code, code_size); + struct evmc_host_context* context = (struct evmc_host_context*)context_index; + return evmc_execute(vm, &evmc_go_host, context, rev, &msg, code, code_size); } */ import "C" @@ -242,7 +236,7 @@ func (vm *VM) Execute(ctx HostContext, rev Revision, evmcSender := evmcAddress(sender) evmcValue := evmcBytes32(value) evmcCreate2Salt := evmcBytes32(create2Salt) - result := C.execute_wrapper(vm.handle, C.int64_t(ctxId), uint32(rev), + result := C.execute_wrapper(vm.handle, C.uintptr_t(ctxId), uint32(rev), C.enum_evmc_call_kind(kind), flags, C.int32_t(depth), C.int64_t(gas), &evmcDestination, &evmcSender, bytesPtr(input), C.size_t(len(input)), &evmcValue, bytesPtr(code), C.size_t(len(code)), &evmcCreate2Salt) @@ -262,12 +256,12 @@ func (vm *VM) Execute(ctx HostContext, rev Revision, } var ( - hostContextCounter int - hostContextMap = map[int]HostContext{} + hostContextCounter uintptr + hostContextMap = map[uintptr]HostContext{} hostContextMapMu sync.Mutex ) -func addHostContext(ctx HostContext) int { +func addHostContext(ctx HostContext) uintptr { hostContextMapMu.Lock() id := hostContextCounter hostContextCounter++ @@ -276,13 +270,13 @@ func addHostContext(ctx HostContext) int { return id } -func removeHostContext(id int) { +func removeHostContext(id uintptr) { hostContextMapMu.Lock() delete(hostContextMap, id) hostContextMapMu.Unlock() } -func getHostContext(idx int) HostContext { +func getHostContext(idx uintptr) HostContext { hostContextMapMu.Lock() ctx := hostContextMap[idx] hostContextMapMu.Unlock() diff --git a/bindings/go/evmc/host.go b/bindings/go/evmc/host.go index 3b1ee97..478ac5c 100644 --- a/bindings/go/evmc/host.go +++ b/bindings/go/evmc/host.go @@ -10,12 +10,6 @@ package evmc #include #include -struct extended_context -{ - struct evmc_host_context context; - int64_t index; -}; - */ import "C" import ( @@ -99,50 +93,43 @@ type HostContext interface { //export accountExists func accountExists(pCtx unsafe.Pointer, pAddr *C.evmc_address) C.bool { - idx := int((*C.struct_extended_context)(pCtx).index) - ctx := getHostContext(idx) + ctx := getHostContext(uintptr(pCtx)) return C.bool(ctx.AccountExists(goAddress(*pAddr))) } //export getStorage func getStorage(pCtx unsafe.Pointer, pAddr *C.struct_evmc_address, pKey *C.evmc_bytes32) C.evmc_bytes32 { - idx := int((*C.struct_extended_context)(pCtx).index) - ctx := getHostContext(idx) + ctx := getHostContext(uintptr(pCtx)) return evmcBytes32(ctx.GetStorage(goAddress(*pAddr), goHash(*pKey))) } //export setStorage func setStorage(pCtx unsafe.Pointer, pAddr *C.evmc_address, pKey *C.evmc_bytes32, pVal *C.evmc_bytes32) C.enum_evmc_storage_status { - idx := int((*C.struct_extended_context)(pCtx).index) - ctx := getHostContext(idx) + ctx := getHostContext(uintptr(pCtx)) return C.enum_evmc_storage_status(ctx.SetStorage(goAddress(*pAddr), goHash(*pKey), goHash(*pVal))) } //export getBalance func getBalance(pCtx unsafe.Pointer, pAddr *C.evmc_address) C.evmc_uint256be { - idx := int((*C.struct_extended_context)(pCtx).index) - ctx := getHostContext(idx) + ctx := getHostContext(uintptr(pCtx)) return evmcBytes32(ctx.GetBalance(goAddress(*pAddr))) } //export getCodeSize func getCodeSize(pCtx unsafe.Pointer, pAddr *C.evmc_address) C.size_t { - idx := int((*C.struct_extended_context)(pCtx).index) - ctx := getHostContext(idx) + ctx := getHostContext(uintptr(pCtx)) return C.size_t(ctx.GetCodeSize(goAddress(*pAddr))) } //export getCodeHash func getCodeHash(pCtx unsafe.Pointer, pAddr *C.evmc_address) C.evmc_bytes32 { - idx := int((*C.struct_extended_context)(pCtx).index) - ctx := getHostContext(idx) + ctx := getHostContext(uintptr(pCtx)) return evmcBytes32(ctx.GetCodeHash(goAddress(*pAddr))) } //export copyCode func copyCode(pCtx unsafe.Pointer, pAddr *C.evmc_address, offset C.size_t, p *C.uint8_t, size C.size_t) C.size_t { - idx := int((*C.struct_extended_context)(pCtx).index) - ctx := getHostContext(idx) + ctx := getHostContext(uintptr(pCtx)) code := ctx.GetCode(goAddress(*pAddr)) length := C.size_t(len(code)) @@ -162,15 +149,13 @@ func copyCode(pCtx unsafe.Pointer, pAddr *C.evmc_address, offset C.size_t, p *C. //export selfdestruct func selfdestruct(pCtx unsafe.Pointer, pAddr *C.evmc_address, pBeneficiary *C.evmc_address) { - idx := int((*C.struct_extended_context)(pCtx).index) - ctx := getHostContext(idx) + ctx := getHostContext(uintptr(pCtx)) ctx.Selfdestruct(goAddress(*pAddr), goAddress(*pBeneficiary)) } //export getTxContext func getTxContext(pCtx unsafe.Pointer) C.struct_evmc_tx_context { - idx := int((*C.struct_extended_context)(pCtx).index) - ctx := getHostContext(idx) + ctx := getHostContext(uintptr(pCtx)) txContext := ctx.GetTxContext() @@ -188,15 +173,13 @@ func getTxContext(pCtx unsafe.Pointer) C.struct_evmc_tx_context { //export getBlockHash func getBlockHash(pCtx unsafe.Pointer, number int64) C.evmc_bytes32 { - idx := int((*C.struct_extended_context)(pCtx).index) - ctx := getHostContext(idx) + ctx := getHostContext(uintptr(pCtx)) return evmcBytes32(ctx.GetBlockHash(number)) } //export emitLog func emitLog(pCtx unsafe.Pointer, pAddr *C.evmc_address, pData unsafe.Pointer, dataSize C.size_t, pTopics unsafe.Pointer, topicsCount C.size_t) { - idx := int((*C.struct_extended_context)(pCtx).index) - ctx := getHostContext(idx) + ctx := getHostContext(uintptr(pCtx)) // FIXME: Optimize memory copy data := C.GoBytes(pData, C.int(dataSize)) @@ -213,8 +196,7 @@ func emitLog(pCtx unsafe.Pointer, pAddr *C.evmc_address, pData unsafe.Pointer, d //export call func call(pCtx unsafe.Pointer, msg *C.struct_evmc_message) C.struct_evmc_result { - idx := int((*C.struct_extended_context)(pCtx).index) - ctx := getHostContext(idx) + ctx := getHostContext(uintptr(pCtx)) kind := CallKind(msg.kind) output, gasLeft, createAddr, err := ctx.Call(kind, goAddress(msg.destination), goAddress(msg.sender), goHash(msg.value).Big(), From 8c00cdacb4119d7ac9f86fb8e817bbaa01b9e211 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Tue, 24 Sep 2019 16:03:57 +0100 Subject: [PATCH 4/6] Update Rust bindings --- bindings/rust/evmc-declare/src/lib.rs | 8 +- bindings/rust/evmc-sys/build.rs | 1 + bindings/rust/evmc-sys/src/lib.rs | 6 ++ bindings/rust/evmc-vm/src/container.rs | 11 +- bindings/rust/evmc-vm/src/lib.rs | 135 +++++++++++-------------- 5 files changed, 79 insertions(+), 82 deletions(-) diff --git a/bindings/rust/evmc-declare/src/lib.rs b/bindings/rust/evmc-declare/src/lib.rs index 9e08ab7..77e10bc 100644 --- a/bindings/rust/evmc-declare/src/lib.rs +++ b/bindings/rust/evmc-declare/src/lib.rs @@ -335,6 +335,7 @@ fn build_execute_fn(names: &VMNameSet) -> proc_macro2::TokenStream { quote! { extern "C" fn __evmc_execute( instance: *mut ::evmc_vm::ffi::evmc_vm, + host: *const ::evmc_vm::ffi::evmc_host_interface, context: *mut ::evmc_vm::ffi::evmc_host_context, revision: ::evmc_vm::ffi::evmc_revision, msg: *const ::evmc_vm::ffi::evmc_message, @@ -345,7 +346,7 @@ fn build_execute_fn(names: &VMNameSet) -> proc_macro2::TokenStream { use evmc_vm::EvmcVm; // TODO: context is optional in case of the "precompiles" capability - if instance.is_null() || context.is_null() || msg.is_null() || (code.is_null() && code_size != 0) { + if instance.is_null() || host.is_null() || context.is_null() || msg.is_null() || (code.is_null() && code_size != 0) { // These are irrecoverable errors that violate the EVMC spec. std::process::abort(); } @@ -376,7 +377,10 @@ fn build_execute_fn(names: &VMNameSet) -> proc_macro2::TokenStream { let result = ::std::panic::catch_unwind(|| { let mut execution_context = unsafe { - ::evmc_vm::ExecutionContext::new(context.as_mut().expect("EVMC context is null")) + ::evmc_vm::ExecutionContext::new( + host.as_ref().expect("EVMC host is null"), + context.as_mut().expect("EVMC context is null") + ) }; container.execute(revision, code_ref, &execution_message, &mut execution_context) }); diff --git a/bindings/rust/evmc-sys/build.rs b/bindings/rust/evmc-sys/build.rs index 3521047..c74e188 100644 --- a/bindings/rust/evmc-sys/build.rs +++ b/bindings/rust/evmc-sys/build.rs @@ -22,6 +22,7 @@ fn gen_bindings() { .rustified_enum("*") // force deriving the Hash trait on basic types (address, bytes32) .derive_hash(true) + .opaque_type("evmc_host_context") .generate() .expect("Unable to generate bindings"); diff --git a/bindings/rust/evmc-sys/src/lib.rs b/bindings/rust/evmc-sys/src/lib.rs index 6a545ff..3ec49d9 100644 --- a/bindings/rust/evmc-sys/src/lib.rs +++ b/bindings/rust/evmc-sys/src/lib.rs @@ -36,6 +36,12 @@ impl Default for evmc_bytes32 { } } +impl Default for evmc_host_context { + fn default() -> Self { + evmc_host_context { _unused: [0u8; 0] } + } +} + #[cfg(test)] mod tests { use std::mem::size_of; diff --git a/bindings/rust/evmc-vm/src/container.rs b/bindings/rust/evmc-vm/src/container.rs index 8082089..ff0001b 100644 --- a/bindings/rust/evmc-vm/src/container.rs +++ b/bindings/rust/evmc-vm/src/container.rs @@ -59,6 +59,7 @@ mod tests { use crate::{ExecutionContext, ExecutionMessage, ExecutionResult}; struct TestVm {} + impl EvmcVm for TestVm { fn init() -> Self { TestVm {} @@ -131,9 +132,9 @@ mod tests { get_block_hash: None, emit_log: None, }; - let mut backing_context = ::evmc_sys::evmc_host_context { host: &host }; + let mut host_context = ::evmc_sys::evmc_host_context::default(); - let mut context = ExecutionContext::new(&mut backing_context); + let mut context = ExecutionContext::new(&host, &mut host_context); let container = EvmcContainer::::new(instance); assert_eq!( container @@ -141,7 +142,7 @@ mod tests { evmc_sys::evmc_revision::EVMC_PETERSBURG, &code, &message, - &mut context + &mut context, ) .status_code(), ::evmc_sys::evmc_status_code::EVMC_FAILURE @@ -149,7 +150,7 @@ mod tests { let ptr = unsafe { EvmcContainer::into_ffi_pointer(container) }; - let mut context = ExecutionContext::new(&mut backing_context); + let mut context = ExecutionContext::new(&host, &mut host_context); let container = unsafe { EvmcContainer::::from_ffi_pointer(ptr) }; assert_eq!( container @@ -157,7 +158,7 @@ mod tests { evmc_sys::evmc_revision::EVMC_PETERSBURG, &code, &message, - &mut context + &mut context, ) .status_code(), ::evmc_sys::evmc_status_code::EVMC_FAILURE diff --git a/bindings/rust/evmc-vm/src/lib.rs b/bindings/rust/evmc-vm/src/lib.rs index a13c067..52b5679 100644 --- a/bindings/rust/evmc-vm/src/lib.rs +++ b/bindings/rust/evmc-vm/src/lib.rs @@ -58,6 +58,7 @@ pub type ExecutionTxContext = ffi::evmc_tx_context; /// EVMC context structure. Exposes the EVMC host functions, message data, and transaction context /// to the executing VM. pub struct ExecutionContext<'a> { + host: &'a ffi::evmc_host_interface, context: &'a mut ffi::evmc_host_context, tx_context: ExecutionTxContext, } @@ -194,14 +195,17 @@ impl ExecutionMessage { } impl<'a> ExecutionContext<'a> { - pub fn new(_context: &'a mut ffi::evmc_host_context) -> Self { - assert!(_context.host != std::ptr::null()); + pub fn new( + host: &'a ffi::evmc_host_interface, + _context: &'a mut ffi::evmc_host_context, + ) -> Self { let _tx_context = unsafe { - assert!((*(_context.host)).get_tx_context.is_some()); - (*(_context.host)).get_tx_context.unwrap()(_context as *mut ffi::evmc_host_context) + assert!((*host).get_tx_context.is_some()); + (*host).get_tx_context.unwrap()(_context as *mut ffi::evmc_host_context) }; ExecutionContext { + host: host, context: _context, tx_context: _tx_context, } @@ -215,8 +219,8 @@ impl<'a> ExecutionContext<'a> { /// Check if an account exists. pub fn account_exists(&mut self, address: &Address) -> bool { unsafe { - assert!((*self.context.host).account_exists.is_some()); - (*self.context.host).account_exists.unwrap()( + assert!((*self.host).account_exists.is_some()); + (*self.host).account_exists.unwrap()( self.context as *mut ffi::evmc_host_context, address as *const Address, ) @@ -226,8 +230,8 @@ impl<'a> ExecutionContext<'a> { /// Read from a storage key. pub fn get_storage(&mut self, address: &Address, key: &Bytes32) -> Bytes32 { unsafe { - assert!((*self.context.host).get_storage.is_some()); - (*self.context.host).get_storage.unwrap()( + assert!((*self.host).get_storage.is_some()); + (*self.host).get_storage.unwrap()( self.context as *mut ffi::evmc_host_context, address as *const Address, key as *const Bytes32, @@ -243,8 +247,8 @@ impl<'a> ExecutionContext<'a> { value: &Bytes32, ) -> ffi::evmc_storage_status { unsafe { - assert!((*self.context.host).set_storage.is_some()); - (*self.context.host).set_storage.unwrap()( + assert!((*self.host).set_storage.is_some()); + (*self.host).set_storage.unwrap()( self.context as *mut ffi::evmc_host_context, address as *const Address, key as *const Bytes32, @@ -256,8 +260,8 @@ impl<'a> ExecutionContext<'a> { /// Get balance of an account. pub fn get_balance(&mut self, address: &Address) -> Uint256 { unsafe { - assert!((*self.context.host).get_balance.is_some()); - (*self.context.host).get_balance.unwrap()( + assert!((*self.host).get_balance.is_some()); + (*self.host).get_balance.unwrap()( self.context as *mut ffi::evmc_host_context, address as *const Address, ) @@ -267,8 +271,8 @@ impl<'a> ExecutionContext<'a> { /// Get code size of an account. pub fn get_code_size(&mut self, address: &Address) -> usize { unsafe { - assert!((*self.context.host).get_code_size.is_some()); - (*self.context.host).get_code_size.unwrap()( + assert!((*self.host).get_code_size.is_some()); + (*self.host).get_code_size.unwrap()( self.context as *mut ffi::evmc_host_context, address as *const Address, ) @@ -278,8 +282,8 @@ impl<'a> ExecutionContext<'a> { /// Get code hash of an account. pub fn get_code_hash(&mut self, address: &Address) -> Bytes32 { unsafe { - assert!((*self.context.host).get_code_size.is_some()); - (*self.context.host).get_code_hash.unwrap()( + assert!((*self.host).get_code_size.is_some()); + (*self.host).get_code_hash.unwrap()( self.context as *mut ffi::evmc_host_context, address as *const Address, ) @@ -289,8 +293,8 @@ impl<'a> ExecutionContext<'a> { /// Copy code of an account. pub fn copy_code(&mut self, address: &Address, code_offset: usize, buffer: &mut [u8]) -> usize { unsafe { - assert!((*self.context.host).copy_code.is_some()); - (*self.context.host).copy_code.unwrap()( + assert!((*self.host).copy_code.is_some()); + (*self.host).copy_code.unwrap()( self.context as *mut ffi::evmc_host_context, address as *const Address, code_offset, @@ -304,8 +308,8 @@ impl<'a> ExecutionContext<'a> { /// Self-destruct the current account. pub fn selfdestruct(&mut self, address: &Address, beneficiary: &Address) { unsafe { - assert!((*self.context.host).selfdestruct.is_some()); - (*self.context.host).selfdestruct.unwrap()( + assert!((*self.host).selfdestruct.is_some()); + (*self.host).selfdestruct.unwrap()( self.context as *mut ffi::evmc_host_context, address as *const Address, beneficiary as *const Address, @@ -343,8 +347,8 @@ impl<'a> ExecutionContext<'a> { create2_salt: *message.create2_salt(), }; unsafe { - assert!((*self.context.host).call.is_some()); - (*self.context.host).call.unwrap()( + assert!((*self.host).call.is_some()); + (*self.host).call.unwrap()( self.context as *mut ffi::evmc_host_context, &message as *const ffi::evmc_message, ) @@ -355,19 +359,16 @@ impl<'a> ExecutionContext<'a> { /// Get block hash of an account. pub fn get_block_hash(&mut self, num: i64) -> Bytes32 { unsafe { - assert!((*self.context.host).get_block_hash.is_some()); - (*self.context.host).get_block_hash.unwrap()( - self.context as *mut ffi::evmc_host_context, - num, - ) + assert!((*self.host).get_block_hash.is_some()); + (*self.host).get_block_hash.unwrap()(self.context as *mut ffi::evmc_host_context, num) } } /// Emit a log. pub fn emit_log(&mut self, address: &Address, data: &[u8], topics: &[Bytes32]) { unsafe { - assert!((*self.context.host).emit_log.is_some()); - (*self.context.host).emit_log.unwrap()( + assert!((*self.host).emit_log.is_some()); + (*self.host).emit_log.unwrap()( self.context as *mut ffi::evmc_host_context, address as *const Address, // FIXME: ensure that alignment of the array elements is OK @@ -801,74 +802,61 @@ mod tests { } // Update these when needed for tests - fn get_dummy_context() -> ffi::evmc_host_context { - ffi::evmc_host_context { - host: Box::into_raw(Box::new(ffi::evmc_host_interface { - account_exists: None, - get_storage: None, - set_storage: None, - get_balance: None, - get_code_size: Some(get_dummy_code_size), - get_code_hash: None, - copy_code: None, - selfdestruct: None, - call: Some(execute_call), - get_tx_context: Some(get_dummy_tx_context), - get_block_hash: None, - emit_log: None, - })), - } - } - - // Helper to safely dispose of the dummy context, and not bring up false positives in the - // sanitizers. - fn dummy_context_dispose(context: ffi::evmc_host_context) { - unsafe { - Box::from_raw(context.host as *mut ffi::evmc_host_interface); + fn get_dummy_host_interface() -> ffi::evmc_host_interface { + ffi::evmc_host_interface { + account_exists: None, + get_storage: None, + set_storage: None, + get_balance: None, + get_code_size: Some(get_dummy_code_size), + get_code_hash: None, + copy_code: None, + selfdestruct: None, + call: Some(execute_call), + get_tx_context: Some(get_dummy_tx_context), + get_block_hash: None, + emit_log: None, } } #[test] fn execution_context() { - let mut context_raw = get_dummy_context(); - // Make a copy here so we don't let get_dummy_context() go out of scope when called again - // in get_dummy_tx_context() and cause LLVM - // sanitizers to complain - let mut context_raw_copy = context_raw.clone(); - - let exe_context = ExecutionContext::new(&mut context_raw); + let mut host_context = ffi::evmc_host_context::default(); + let mut host_context_copy = host_context.clone(); + let host_interface = get_dummy_host_interface(); + let exe_context = ExecutionContext::new(&host_interface, &mut host_context); let a = exe_context.get_tx_context(); + let b = - unsafe { get_dummy_tx_context(&mut context_raw_copy as *mut ffi::evmc_host_context) }; + unsafe { get_dummy_tx_context(&mut host_context_copy as *mut ffi::evmc_host_context) }; assert_eq!(a.block_gas_limit, b.block_gas_limit); assert_eq!(a.block_timestamp, b.block_timestamp); assert_eq!(a.block_number, b.block_number); - - dummy_context_dispose(context_raw); } #[test] fn get_code_size() { // This address is useless. Just a dummy parameter for the interface function. let test_addr = Address { bytes: [0u8; 20] }; - let mut context_raw = get_dummy_context(); - let mut exe_context = ExecutionContext::new(&mut context_raw); + let host = get_dummy_host_interface(); + let mut host_context = ffi::evmc_host_context::default(); + + let mut exe_context = ExecutionContext::new(&host, &mut host_context); let a: usize = 105023; let b = exe_context.get_code_size(&test_addr); assert_eq!(a, b); - - dummy_context_dispose(context_raw); } #[test] fn test_call_empty_data() { // This address is useless. Just a dummy parameter for the interface function. let test_addr = ffi::evmc_address { bytes: [0u8; 20] }; - let mut context_raw = get_dummy_context(); - let mut exe_context = ExecutionContext::new(&mut context_raw); + let host = get_dummy_host_interface(); + let mut host_context = ffi::evmc_host_context::default(); + let mut exe_context = ExecutionContext::new(&host, &mut host_context); let message = ExecutionMessage::new( ffi::evmc_call_kind::EVMC_CALL, @@ -889,16 +877,15 @@ mod tests { assert!(b.output().is_none()); assert!(b.create_address().is_some()); assert_eq!(b.create_address().unwrap(), &ffi::evmc_address::default()); - - dummy_context_dispose(context_raw); } #[test] fn test_call_with_data() { // This address is useless. Just a dummy parameter for the interface function. let test_addr = ffi::evmc_address { bytes: [0u8; 20] }; - let mut context_raw = get_dummy_context(); - let mut exe_context = ExecutionContext::new(&mut context_raw); + let host = get_dummy_host_interface(); + let mut host_context = ffi::evmc_host_context::default(); + let mut exe_context = ExecutionContext::new(&host, &mut host_context); let data = vec![0xc0, 0xff, 0xfe]; @@ -922,7 +909,5 @@ mod tests { assert_eq!(b.output().unwrap(), &data); assert!(b.create_address().is_some()); assert_eq!(b.create_address().unwrap(), &ffi::evmc_address::default()); - - dummy_context_dispose(context_raw); } } From 077bcb3e2961facd5c13254c35caad902b118f6e Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Tue, 5 Nov 2019 10:24:00 +0000 Subject: [PATCH 5/6] Update Rust bindings to consider host_context as an opaque pointer --- bindings/rust/evmc-declare/src/lib.rs | 8 +-- bindings/rust/evmc-sys/src/lib.rs | 6 --- bindings/rust/evmc-vm/src/container.rs | 6 +-- bindings/rust/evmc-vm/src/lib.rs | 67 +++++++++----------------- 4 files changed, 30 insertions(+), 57 deletions(-) diff --git a/bindings/rust/evmc-declare/src/lib.rs b/bindings/rust/evmc-declare/src/lib.rs index 77e10bc..506a2ce 100644 --- a/bindings/rust/evmc-declare/src/lib.rs +++ b/bindings/rust/evmc-declare/src/lib.rs @@ -346,14 +346,14 @@ fn build_execute_fn(names: &VMNameSet) -> proc_macro2::TokenStream { use evmc_vm::EvmcVm; // TODO: context is optional in case of the "precompiles" capability - if instance.is_null() || host.is_null() || context.is_null() || msg.is_null() || (code.is_null() && code_size != 0) { + if instance.is_null() || host.is_null() || msg.is_null() || (code.is_null() && code_size != 0) { // These are irrecoverable errors that violate the EVMC spec. std::process::abort(); } assert!(!instance.is_null()); - // TODO: context is optional in case of the "precompiles" capability - assert!(!context.is_null()); + // TODO: host is optional in case of the "precompiles" capability + assert!(!host.is_null()); assert!(!msg.is_null()); let execution_message: ::evmc_vm::ExecutionMessage = unsafe { @@ -379,7 +379,7 @@ fn build_execute_fn(names: &VMNameSet) -> proc_macro2::TokenStream { let mut execution_context = unsafe { ::evmc_vm::ExecutionContext::new( host.as_ref().expect("EVMC host is null"), - context.as_mut().expect("EVMC context is null") + context, ) }; container.execute(revision, code_ref, &execution_message, &mut execution_context) diff --git a/bindings/rust/evmc-sys/src/lib.rs b/bindings/rust/evmc-sys/src/lib.rs index 3ec49d9..6a545ff 100644 --- a/bindings/rust/evmc-sys/src/lib.rs +++ b/bindings/rust/evmc-sys/src/lib.rs @@ -36,12 +36,6 @@ impl Default for evmc_bytes32 { } } -impl Default for evmc_host_context { - fn default() -> Self { - evmc_host_context { _unused: [0u8; 0] } - } -} - #[cfg(test)] mod tests { use std::mem::size_of; diff --git a/bindings/rust/evmc-vm/src/container.rs b/bindings/rust/evmc-vm/src/container.rs index ff0001b..4155d36 100644 --- a/bindings/rust/evmc-vm/src/container.rs +++ b/bindings/rust/evmc-vm/src/container.rs @@ -132,9 +132,9 @@ mod tests { get_block_hash: None, emit_log: None, }; - let mut host_context = ::evmc_sys::evmc_host_context::default(); + let host_context = std::ptr::null_mut(); - let mut context = ExecutionContext::new(&host, &mut host_context); + let mut context = ExecutionContext::new(&host, host_context); let container = EvmcContainer::::new(instance); assert_eq!( container @@ -150,7 +150,7 @@ mod tests { let ptr = unsafe { EvmcContainer::into_ffi_pointer(container) }; - let mut context = ExecutionContext::new(&host, &mut host_context); + let mut context = ExecutionContext::new(&host, host_context); let container = unsafe { EvmcContainer::::from_ffi_pointer(ptr) }; assert_eq!( container diff --git a/bindings/rust/evmc-vm/src/lib.rs b/bindings/rust/evmc-vm/src/lib.rs index 52b5679..e14a91d 100644 --- a/bindings/rust/evmc-vm/src/lib.rs +++ b/bindings/rust/evmc-vm/src/lib.rs @@ -59,7 +59,7 @@ pub type ExecutionTxContext = ffi::evmc_tx_context; /// to the executing VM. pub struct ExecutionContext<'a> { host: &'a ffi::evmc_host_interface, - context: &'a mut ffi::evmc_host_context, + context: *mut ffi::evmc_host_context, tx_context: ExecutionTxContext, } @@ -195,13 +195,10 @@ impl ExecutionMessage { } impl<'a> ExecutionContext<'a> { - pub fn new( - host: &'a ffi::evmc_host_interface, - _context: &'a mut ffi::evmc_host_context, - ) -> Self { + pub fn new(host: &'a ffi::evmc_host_interface, _context: *mut ffi::evmc_host_context) -> Self { let _tx_context = unsafe { assert!((*host).get_tx_context.is_some()); - (*host).get_tx_context.unwrap()(_context as *mut ffi::evmc_host_context) + (*host).get_tx_context.unwrap()(_context) }; ExecutionContext { @@ -220,10 +217,7 @@ impl<'a> ExecutionContext<'a> { pub fn account_exists(&mut self, address: &Address) -> bool { unsafe { assert!((*self.host).account_exists.is_some()); - (*self.host).account_exists.unwrap()( - self.context as *mut ffi::evmc_host_context, - address as *const Address, - ) + (*self.host).account_exists.unwrap()(self.context, address as *const Address) } } @@ -232,7 +226,7 @@ impl<'a> ExecutionContext<'a> { unsafe { assert!((*self.host).get_storage.is_some()); (*self.host).get_storage.unwrap()( - self.context as *mut ffi::evmc_host_context, + self.context, address as *const Address, key as *const Bytes32, ) @@ -249,7 +243,7 @@ impl<'a> ExecutionContext<'a> { unsafe { assert!((*self.host).set_storage.is_some()); (*self.host).set_storage.unwrap()( - self.context as *mut ffi::evmc_host_context, + self.context, address as *const Address, key as *const Bytes32, value as *const Bytes32, @@ -261,10 +255,7 @@ impl<'a> ExecutionContext<'a> { pub fn get_balance(&mut self, address: &Address) -> Uint256 { unsafe { assert!((*self.host).get_balance.is_some()); - (*self.host).get_balance.unwrap()( - self.context as *mut ffi::evmc_host_context, - address as *const Address, - ) + (*self.host).get_balance.unwrap()(self.context, address as *const Address) } } @@ -272,10 +263,7 @@ impl<'a> ExecutionContext<'a> { pub fn get_code_size(&mut self, address: &Address) -> usize { unsafe { assert!((*self.host).get_code_size.is_some()); - (*self.host).get_code_size.unwrap()( - self.context as *mut ffi::evmc_host_context, - address as *const Address, - ) + (*self.host).get_code_size.unwrap()(self.context, address as *const Address) } } @@ -283,10 +271,7 @@ impl<'a> ExecutionContext<'a> { pub fn get_code_hash(&mut self, address: &Address) -> Bytes32 { unsafe { assert!((*self.host).get_code_size.is_some()); - (*self.host).get_code_hash.unwrap()( - self.context as *mut ffi::evmc_host_context, - address as *const Address, - ) + (*self.host).get_code_hash.unwrap()(self.context, address as *const Address) } } @@ -295,7 +280,7 @@ impl<'a> ExecutionContext<'a> { unsafe { assert!((*self.host).copy_code.is_some()); (*self.host).copy_code.unwrap()( - self.context as *mut ffi::evmc_host_context, + self.context, address as *const Address, code_offset, // FIXME: ensure that alignment of the array elements is OK @@ -310,7 +295,7 @@ impl<'a> ExecutionContext<'a> { unsafe { assert!((*self.host).selfdestruct.is_some()); (*self.host).selfdestruct.unwrap()( - self.context as *mut ffi::evmc_host_context, + self.context, address as *const Address, beneficiary as *const Address, ) @@ -348,11 +333,7 @@ impl<'a> ExecutionContext<'a> { }; unsafe { assert!((*self.host).call.is_some()); - (*self.host).call.unwrap()( - self.context as *mut ffi::evmc_host_context, - &message as *const ffi::evmc_message, - ) - .into() + (*self.host).call.unwrap()(self.context, &message as *const ffi::evmc_message).into() } } @@ -360,7 +341,7 @@ impl<'a> ExecutionContext<'a> { pub fn get_block_hash(&mut self, num: i64) -> Bytes32 { unsafe { assert!((*self.host).get_block_hash.is_some()); - (*self.host).get_block_hash.unwrap()(self.context as *mut ffi::evmc_host_context, num) + (*self.host).get_block_hash.unwrap()(self.context, num) } } @@ -369,7 +350,7 @@ impl<'a> ExecutionContext<'a> { unsafe { assert!((*self.host).emit_log.is_some()); (*self.host).emit_log.unwrap()( - self.context as *mut ffi::evmc_host_context, + self.context, address as *const Address, // FIXME: ensure that alignment of the array elements is OK data.as_ptr(), @@ -821,14 +802,12 @@ mod tests { #[test] fn execution_context() { - let mut host_context = ffi::evmc_host_context::default(); - let mut host_context_copy = host_context.clone(); + let host_context = std::ptr::null_mut(); let host_interface = get_dummy_host_interface(); - let exe_context = ExecutionContext::new(&host_interface, &mut host_context); + let exe_context = ExecutionContext::new(&host_interface, host_context); let a = exe_context.get_tx_context(); - let b = - unsafe { get_dummy_tx_context(&mut host_context_copy as *mut ffi::evmc_host_context) }; + let b = unsafe { get_dummy_tx_context(host_context) }; assert_eq!(a.block_gas_limit, b.block_gas_limit); assert_eq!(a.block_timestamp, b.block_timestamp); @@ -840,9 +819,9 @@ mod tests { // This address is useless. Just a dummy parameter for the interface function. let test_addr = Address { bytes: [0u8; 20] }; let host = get_dummy_host_interface(); - let mut host_context = ffi::evmc_host_context::default(); + let host_context = std::ptr::null_mut(); - let mut exe_context = ExecutionContext::new(&host, &mut host_context); + let mut exe_context = ExecutionContext::new(&host, host_context); let a: usize = 105023; let b = exe_context.get_code_size(&test_addr); @@ -855,8 +834,8 @@ mod tests { // This address is useless. Just a dummy parameter for the interface function. let test_addr = ffi::evmc_address { bytes: [0u8; 20] }; let host = get_dummy_host_interface(); - let mut host_context = ffi::evmc_host_context::default(); - let mut exe_context = ExecutionContext::new(&host, &mut host_context); + let host_context = std::ptr::null_mut(); + let mut exe_context = ExecutionContext::new(&host, host_context); let message = ExecutionMessage::new( ffi::evmc_call_kind::EVMC_CALL, @@ -884,8 +863,8 @@ mod tests { // This address is useless. Just a dummy parameter for the interface function. let test_addr = ffi::evmc_address { bytes: [0u8; 20] }; let host = get_dummy_host_interface(); - let mut host_context = ffi::evmc_host_context::default(); - let mut exe_context = ExecutionContext::new(&host, &mut host_context); + let host_context = std::ptr::null_mut(); + let mut exe_context = ExecutionContext::new(&host, host_context); let data = vec![0xc0, 0xff, 0xfe]; From 4645d97ef6ec7e5bc128cc2331a0cc2ced2a3e4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 4 Nov 2019 22:03:50 +0100 Subject: [PATCH 6/6] Update CHANGELOG --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 35edeeb..6f42d7d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,9 @@ and this project adheres to [Semantic Versioning]. [[#430](https://github.com/ethereum/evmc/pull/430)] - The `evmc_context` renamed to `evmc_host_context`. [[#426](https://github.com/ethereum/evmc/pull/426)] +- The `evmc_host_interface` is now separated from `evmc_host_context`. + This simplifies language bindings which implement the `evmc_host_interface`. + [[#427](https://github.com/ethereum/evmc/pull/427)] - The `evmc::vm` renamed to `evmc::VM` in C++ API. [[#252](https://github.com/ethereum/evmc/pull/252)] - Previously deprecated `helpers.hpp` header file has been removed.