Skip to content
This repository was archived by the owner on Apr 8, 2026. It is now read-only.

Commit 9608bab

Browse files
authored
Merge pull request #217 from ethereum/cpp-host
cpp: Add evmc::host - wrapper around Host context / interface
2 parents 1b5a67c + aa3a81d commit 9608bab

File tree

4 files changed

+129
-1
lines changed

4 files changed

+129
-1
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
## [6.2.0] - Unreleased
44

5+
- Added: [[#217](https://github.com/ethereum/evmc/pull/217)]
6+
The `evmc::host` C++ wrapper for EVMC host context and interface
7+
to be used by VM implementations.
58
- Deprecated: [[#196](https://github.com/ethereum/evmc/pull/196)]
69
The `EVMC_CONSTANTINOPLE2` revision name is deprecated, replaced with `EVMC_PETERSBURG`.
710

include/evmc/evmc.hpp

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,4 +76,92 @@ class vm
7676
private:
7777
evmc_instance* const m_instance = nullptr;
7878
};
79+
80+
81+
/// Wrapper around EVMC host context / host interface.
82+
class host
83+
{
84+
evmc_context* context = nullptr;
85+
evmc_tx_context tx_context = {};
86+
87+
public:
88+
host(evmc_context* context) noexcept : context{context} {}
89+
90+
bool account_exists(const evmc_address& address) noexcept
91+
{
92+
return context->host->account_exists(context, &address);
93+
}
94+
95+
evmc_bytes32 get_storage(const evmc_address& address, const evmc_bytes32& key) noexcept
96+
{
97+
return context->host->get_storage(context, &address, &key);
98+
}
99+
100+
evmc_storage_status set_storage(const evmc_address& address,
101+
const evmc_bytes32& key,
102+
const evmc_bytes32& value) noexcept
103+
{
104+
return context->host->set_storage(context, &address, &key, &value);
105+
}
106+
107+
evmc_uint256be get_balance(const evmc_address& address) noexcept
108+
{
109+
return context->host->get_balance(context, &address);
110+
}
111+
112+
size_t get_code_size(const evmc_address& address) noexcept
113+
{
114+
return context->host->get_code_size(context, &address);
115+
}
116+
117+
evmc_bytes32 get_code_hash(const evmc_address& address) noexcept
118+
{
119+
return context->host->get_code_hash(context, &address);
120+
}
121+
122+
size_t copy_code(const evmc_address& address,
123+
size_t code_offset,
124+
uint8_t* buffer_data,
125+
size_t buffer_size) noexcept
126+
{
127+
return context->host->copy_code(context, &address, code_offset, buffer_data, buffer_size);
128+
}
129+
130+
void selfdestruct(const evmc_address& address, const evmc_address& beneficiary)
131+
{
132+
context->host->selfdestruct(context, &address, &beneficiary);
133+
}
134+
135+
result call(const evmc_message& message) noexcept
136+
{
137+
return result{context->host->call(context, &message)};
138+
}
139+
140+
/// Gets the transaction and block context from the Host.
141+
///
142+
/// The implementation caches the received transaction context
143+
/// by assuming that the block timestamp should never be zero.
144+
///
145+
/// @return Reference to the cached transaction context.
146+
const evmc_tx_context& get_tx_context() noexcept
147+
{
148+
if (tx_context.block_timestamp == 0)
149+
tx_context = context->host->get_tx_context(context);
150+
return tx_context;
151+
}
152+
153+
evmc_bytes32 get_block_hash(int64_t number) noexcept
154+
{
155+
return context->host->get_block_hash(context, number);
156+
}
157+
158+
void emit_log(const evmc_address& address,
159+
const uint8_t* data,
160+
size_t data_size,
161+
const evmc_bytes32 topics[],
162+
size_t topics_count) noexcept
163+
{
164+
context->host->emit_log(context, &address, data, data_size, topics, topics_count);
165+
}
166+
};
79167
} // namespace evmc

test/unittests/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,5 @@ add_executable(
1515
test_loader.cpp
1616
)
1717

18-
target_link_libraries(evmc-test PRIVATE loader-mocked evmc-example-vm-static instructions GTest::gtest GTest::main)
18+
target_link_libraries(evmc-test PRIVATE loader-mocked evmc-example-vm-static evmc-example-host instructions GTest::gtest GTest::main)
1919
set_target_properties(evmc-test PROPERTIES RUNTIME_OUTPUT_DIRECTORY ..)

test/unittests/test_cpp.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@
22
// Copyright 2019 The EVMC Authors.
33
// Licensed under the Apache License, Version 2.0.
44

5+
#include "../../examples/example_host.h"
56
#include "../../examples/example_vm.h"
67

78
#include <evmc/evmc.hpp>
9+
#include <evmc/helpers.hpp>
810

911
#include <gtest/gtest.h>
1012

@@ -61,3 +63,38 @@ TEST(cpp, vm_set_option)
6163
auto vm = evmc::vm{&raw_instance};
6264
EXPECT_EQ(vm.set_option("1", "2"), EVMC_SET_OPTION_INVALID_NAME);
6365
}
66+
67+
TEST(cpp, host)
68+
{
69+
// Use example host to execute all methods from the C++ host wrapper.
70+
71+
auto* host_context = example_host_create_context();
72+
auto host = evmc::host{host_context};
73+
74+
auto a = evmc_address{{1}};
75+
auto v = evmc_bytes32{{7, 7, 7}};
76+
77+
EXPECT_FALSE(host.account_exists(a));
78+
79+
EXPECT_EQ(host.set_storage(a, {}, v), EVMC_STORAGE_MODIFIED);
80+
EXPECT_EQ(host.set_storage(a, {}, v), EVMC_STORAGE_UNCHANGED);
81+
EXPECT_EQ(host.get_storage(a, {}), v);
82+
83+
EXPECT_TRUE(is_zero(host.get_balance(a)));
84+
85+
EXPECT_EQ(host.get_code_size(a), 0);
86+
EXPECT_EQ(host.get_code_hash(a), evmc_bytes32{});
87+
EXPECT_EQ(host.copy_code(a, 0, nullptr, 0), 0);
88+
89+
host.selfdestruct(a, a);
90+
EXPECT_EQ(host.call({}).gas_left, 0);
91+
92+
auto* tx = &host.get_tx_context();
93+
EXPECT_EQ(&host.get_tx_context(), tx);
94+
95+
EXPECT_EQ(host.get_block_hash(0), evmc_bytes32{});
96+
97+
host.emit_log(a, nullptr, 0, nullptr, 0);
98+
99+
example_host_destroy_context(host_context);
100+
}

0 commit comments

Comments
 (0)