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