1 /* EVMC: Ethereum Client-VM Connector API.
2 * Copyright 2016-2019 The EVMC Authors.
3 * Licensed under the Apache License, Version 2.0.
4 */
5
6 /// @file
7 /// Example implementation of an EVMC Host.
8
9 #include "example_host.h"
10
11 #include <evmc/evmc.hpp>
12
13 #include <algorithm>
14 #include <map>
15 #include <vector>
16
17 using namespace evmc::literals;
18
19 namespace evmc
20 {
21 struct account
22 {
23 evmc::uint256be balance = {};
24 std::vector<uint8_t> code;
25 std::map<evmc::bytes32, evmc::bytes32> storage;
26
code_hashevmc::account27 virtual evmc::bytes32 code_hash() const
28 {
29 // Extremely dumb "hash" function.
30 evmc::bytes32 ret{};
31 for (std::vector<uint8_t>::size_type i = 0; i != code.size(); i++)
32 {
33 auto v = code[i];
34 ret.bytes[v % sizeof(ret.bytes)] ^= v;
35 }
36 return ret;
37 }
38 };
39
40 using accounts = std::map<evmc::address, account>;
41
42 } // namespace evmc
43
44 class ExampleHost : public evmc::Host
45 {
46 evmc::accounts accounts;
47 evmc_tx_context tx_context{};
48
49 public:
50 ExampleHost() = default;
ExampleHost(evmc_tx_context & _tx_context)51 explicit ExampleHost(evmc_tx_context& _tx_context) noexcept : tx_context{_tx_context} {};
ExampleHost(evmc_tx_context & _tx_context,evmc::accounts & _accounts)52 ExampleHost(evmc_tx_context& _tx_context, evmc::accounts& _accounts) noexcept
53 : accounts{_accounts}, tx_context{_tx_context} {};
54
account_exists(const evmc::address & addr) const55 bool account_exists(const evmc::address& addr) const noexcept final
56 {
57 return accounts.find(addr) != accounts.end();
58 }
59
get_storage(const evmc::address & addr,const evmc::bytes32 & key) const60 evmc::bytes32 get_storage(const evmc::address& addr, const evmc::bytes32& key) const
61 noexcept final
62 {
63 const auto account_iter = accounts.find(addr);
64 if (account_iter == accounts.end())
65 return {};
66
67 const auto storage_iter = account_iter->second.storage.find(key);
68 if (storage_iter != account_iter->second.storage.end())
69 return storage_iter->second;
70 return {};
71 }
72
set_storage(const evmc::address & addr,const evmc::bytes32 & key,const evmc::bytes32 & value)73 evmc_storage_status set_storage(const evmc::address& addr,
74 const evmc::bytes32& key,
75 const evmc::bytes32& value) noexcept final
76 {
77 auto& account = accounts[addr];
78 auto prev_value = account.storage[key];
79 account.storage[key] = value;
80
81 return (prev_value == value) ? EVMC_STORAGE_UNCHANGED : EVMC_STORAGE_MODIFIED;
82 }
83
get_balance(const evmc::address & addr) const84 evmc::uint256be get_balance(const evmc::address& addr) const noexcept final
85 {
86 auto it = accounts.find(addr);
87 if (it != accounts.end())
88 return it->second.balance;
89 return {};
90 }
91
get_code_size(const evmc::address & addr) const92 size_t get_code_size(const evmc::address& addr) const noexcept final
93 {
94 auto it = accounts.find(addr);
95 if (it != accounts.end())
96 return it->second.code.size();
97 return 0;
98 }
99
get_code_hash(const evmc::address & addr) const100 evmc::bytes32 get_code_hash(const evmc::address& addr) const noexcept final
101 {
102 auto it = accounts.find(addr);
103 if (it != accounts.end())
104 return it->second.code_hash();
105 return {};
106 }
107
copy_code(const evmc::address & addr,size_t code_offset,uint8_t * buffer_data,size_t buffer_size) const108 size_t copy_code(const evmc::address& addr,
109 size_t code_offset,
110 uint8_t* buffer_data,
111 size_t buffer_size) const noexcept final
112 {
113 const auto it = accounts.find(addr);
114 if (it == accounts.end())
115 return 0;
116
117 const auto& code = it->second.code;
118
119 if (code_offset >= code.size())
120 return 0;
121
122 const auto n = std::min(buffer_size, code.size() - code_offset);
123
124 if (n > 0)
125 std::copy_n(&code[code_offset], n, buffer_data);
126 return n;
127 }
128
selfdestruct(const evmc::address & addr,const evmc::address & beneficiary)129 void selfdestruct(const evmc::address& addr, const evmc::address& beneficiary) noexcept final
130 {
131 (void)addr;
132 (void)beneficiary;
133 }
134
call(const evmc_message & msg)135 evmc::result call(const evmc_message& msg) noexcept final
136 {
137 return {EVMC_REVERT, msg.gas, msg.input_data, msg.input_size};
138 }
139
get_tx_context() const140 evmc_tx_context get_tx_context() const noexcept final { return tx_context; }
141
get_block_hash(int64_t number) const142 evmc::bytes32 get_block_hash(int64_t number) const noexcept final
143 {
144 const int64_t current_block_number = get_tx_context().block_number;
145
146 return (number < current_block_number && number >= current_block_number - 256) ?
147 0xb10c8a5fb10c8a5fb10c8a5fb10c8a5fb10c8a5fb10c8a5fb10c8a5fb10c8a5f_bytes32 :
148 0_bytes32;
149 }
150
emit_log(const evmc::address & addr,const uint8_t * data,size_t data_size,const evmc::bytes32 topics[],size_t topics_count)151 void emit_log(const evmc::address& addr,
152 const uint8_t* data,
153 size_t data_size,
154 const evmc::bytes32 topics[],
155 size_t topics_count) noexcept final
156 {
157 (void)addr;
158 (void)data;
159 (void)data_size;
160 (void)topics;
161 (void)topics_count;
162 }
163 };
164
165
166 extern "C" {
167
example_host_get_interface()168 const evmc_host_interface* example_host_get_interface()
169 {
170 return &evmc::Host::get_interface();
171 }
172
example_host_create_context(evmc_tx_context tx_context)173 evmc_host_context* example_host_create_context(evmc_tx_context tx_context)
174 {
175 auto host = new ExampleHost{tx_context};
176 return host->to_context();
177 }
178
example_host_destroy_context(evmc_host_context * context)179 void example_host_destroy_context(evmc_host_context* context)
180 {
181 delete evmc::Host::from_context<ExampleHost>(context);
182 }
183 }
184