1 // Aleth: Ethereum C++ client, tools and libraries.
2 // Copyright 2014-2019 Aleth Authors.
3 // Licensed under the GNU General Public License, Version 3.
4 
5 #include "ExtVMFace.h"
6 
7 #include <evmc/helpers.h>
8 
9 namespace dev
10 {
11 namespace eth
12 {
13 static_assert(sizeof(Address) == sizeof(evmc_address), "Address types size mismatch");
14 static_assert(alignof(Address) == alignof(evmc_address), "Address types alignment mismatch");
15 static_assert(sizeof(h256) == sizeof(evmc_uint256be), "Hash types size mismatch");
16 static_assert(alignof(h256) == alignof(evmc_uint256be), "Hash types alignment mismatch");
17 
account_exists(evmc::address const & _addr) const18 bool EvmCHost::account_exists(evmc::address const& _addr) const noexcept
19 {
20     return m_extVM.exists(fromEvmC(_addr));
21 }
22 
get_storage(evmc::address const & _addr,evmc::bytes32 const & _key) const23 evmc::bytes32 EvmCHost::get_storage(evmc::address const& _addr, evmc::bytes32 const& _key) const
24     noexcept
25 {
26     (void)_addr;
27     assert(fromEvmC(_addr) == m_extVM.myAddress);
28     return toEvmC(m_extVM.store(fromEvmC(_key)));
29 }
30 
set_storage(evmc::address const & _addr,evmc::bytes32 const & _key,evmc::bytes32 const & _value)31 evmc_storage_status EvmCHost::set_storage(
32     evmc::address const& _addr, evmc::bytes32 const& _key, evmc::bytes32 const& _value) noexcept
33 {
34     (void)_addr;
35     assert(fromEvmC(_addr) == m_extVM.myAddress);
36     u256 const index = fromEvmC(_key);
37     u256 const newValue = fromEvmC(_value);
38     u256 const currentValue = m_extVM.store(index);
39 
40     if (newValue == currentValue)
41         return EVMC_STORAGE_UNCHANGED;
42 
43     EVMSchedule const& schedule = m_extVM.evmSchedule();
44     auto status = EVMC_STORAGE_MODIFIED;
45     u256 const originalValue = m_extVM.originalStorageValue(index);
46     if (originalValue == currentValue || !schedule.sstoreNetGasMetering())
47     {
48         if (currentValue == 0)
49             status = EVMC_STORAGE_ADDED;
50         else if (newValue == 0)
51         {
52             status = EVMC_STORAGE_DELETED;
53             m_extVM.sub.refunds += schedule.sstoreRefundGas;
54         }
55     }
56     else
57     {
58         status = EVMC_STORAGE_MODIFIED_AGAIN;
59         if (originalValue != 0)
60         {
61             if (currentValue == 0)
62                 m_extVM.sub.refunds -= schedule.sstoreRefundGas;  // Can go negative.
63             if (newValue == 0)
64                 m_extVM.sub.refunds += schedule.sstoreRefundGas;
65         }
66         if (originalValue == newValue)
67         {
68             if (originalValue == 0)
69                 m_extVM.sub.refunds += schedule.sstoreSetGas - schedule.sstoreUnchangedGas;
70             else
71                 m_extVM.sub.refunds += schedule.sstoreResetGas - schedule.sstoreUnchangedGas;
72         }
73     }
74 
75     m_extVM.setStore(index, newValue);  // Interface uses native endianness
76 
77     return status;
78 }
79 
get_balance(evmc::address const & _addr) const80 evmc::uint256be EvmCHost::get_balance(evmc::address const& _addr) const noexcept
81 {
82     return toEvmC(m_extVM.balance(fromEvmC(_addr)));
83 }
84 
get_code_size(evmc::address const & _addr) const85 size_t EvmCHost::get_code_size(evmc::address const& _addr) const noexcept
86 {
87     return m_extVM.codeSizeAt(fromEvmC(_addr));
88 }
89 
get_code_hash(evmc::address const & _addr) const90 evmc::bytes32 EvmCHost::get_code_hash(evmc::address const& _addr) const noexcept
91 {
92     return toEvmC(m_extVM.codeHashAt(fromEvmC(_addr)));
93 }
94 
copy_code(evmc::address const & _addr,size_t _codeOffset,byte * _bufferData,size_t _bufferSize) const95 size_t EvmCHost::copy_code(evmc::address const& _addr, size_t _codeOffset, byte* _bufferData,
96     size_t _bufferSize) const noexcept
97 {
98     Address addr = fromEvmC(_addr);
99     bytes const& c = m_extVM.codeAt(addr);
100 
101     // Handle "big offset" edge case.
102     if (_codeOffset >= c.size())
103         return 0;
104 
105     size_t maxToCopy = c.size() - _codeOffset;
106     size_t numToCopy = std::min(maxToCopy, _bufferSize);
107     std::copy_n(&c[_codeOffset], numToCopy, _bufferData);
108     return numToCopy;
109 }
110 
selfdestruct(evmc::address const & _addr,evmc::address const & _beneficiary)111 void EvmCHost::selfdestruct(evmc::address const& _addr, evmc::address const& _beneficiary) noexcept
112 {
113     (void)_addr;
114     assert(fromEvmC(_addr) == m_extVM.myAddress);
115     m_extVM.selfdestruct(fromEvmC(_beneficiary));
116 }
117 
118 
emit_log(evmc::address const & _addr,uint8_t const * _data,size_t _dataSize,evmc::bytes32 const _topics[],size_t _numTopics)119 void EvmCHost::emit_log(evmc::address const& _addr, uint8_t const* _data, size_t _dataSize,
120     evmc::bytes32 const _topics[], size_t _numTopics) noexcept
121 {
122     (void)_addr;
123     assert(fromEvmC(_addr) == m_extVM.myAddress);
124     h256 const* pTopics = reinterpret_cast<h256 const*>(_topics);
125     m_extVM.log(h256s{pTopics, pTopics + _numTopics}, bytesConstRef{_data, _dataSize});
126 }
127 
get_tx_context() const128 evmc_tx_context EvmCHost::get_tx_context() const noexcept
129 {
130     evmc_tx_context result = {};
131     result.tx_gas_price = toEvmC(m_extVM.gasPrice);
132     result.tx_origin = toEvmC(m_extVM.origin);
133 
134     auto const& envInfo = m_extVM.envInfo();
135     result.block_coinbase = toEvmC(envInfo.author());
136     result.block_number = envInfo.number();
137     result.block_timestamp = envInfo.timestamp();
138     result.block_gas_limit = static_cast<int64_t>(envInfo.gasLimit());
139     result.block_difficulty = toEvmC(envInfo.difficulty());
140     result.chain_id = toEvmC(envInfo.chainID());
141     return result;
142 }
143 
get_block_hash(int64_t _number) const144 evmc::bytes32 EvmCHost::get_block_hash(int64_t _number) const noexcept
145 {
146     return toEvmC(m_extVM.blockHash(_number));
147 }
148 
create(evmc_message const & _msg)149 evmc::result EvmCHost::create(evmc_message const& _msg) noexcept
150 {
151     u256 gas = _msg.gas;
152     u256 value = fromEvmC(_msg.value);
153     bytesConstRef init = {_msg.input_data, _msg.input_size};
154     u256 salt = fromEvmC(_msg.create2_salt);
155     Instruction opcode = _msg.kind == EVMC_CREATE ? Instruction::CREATE : Instruction::CREATE2;
156 
157     // ExtVM::create takes the sender address from .myAddress.
158     assert(fromEvmC(_msg.sender) == m_extVM.myAddress);
159 
160     CreateResult result = m_extVM.create(value, gas, init, opcode, salt, {});
161     evmc_result evmcResult = {};
162     evmcResult.status_code = result.status;
163     evmcResult.gas_left = static_cast<int64_t>(gas);
164 
165     if (result.status == EVMC_SUCCESS)
166         evmcResult.create_address = toEvmC(result.address);
167     else
168     {
169         // Pass the output to the EVM without a copy. The EVM will delete it
170         // when finished with it.
171 
172         // First assign reference. References are not invalidated when vector
173         // of bytes is moved. See `.takeBytes()` below.
174         evmcResult.output_data = result.output.data();
175         evmcResult.output_size = result.output.size();
176 
177         // Place a new vector of bytes containing output in result's reserved memory.
178         auto* data = evmc_get_optional_storage(&evmcResult);
179         static_assert(sizeof(bytes) <= sizeof(*data), "Vector is too big");
180         new (data) bytes(result.output.takeBytes());
181         // Set the destructor to delete the vector.
182         evmcResult.release = [](evmc_result const* _result) {
183             auto* data = evmc_get_const_optional_storage(_result);
184             auto& output = reinterpret_cast<bytes const&>(*data);
185             // Explicitly call vector's destructor to release its data.
186             // This is normal pattern when placement new operator is used.
187             output.~bytes();
188         };
189     }
190     return evmc::result{evmcResult};
191 }
192 
call(evmc_message const & _msg)193 evmc::result EvmCHost::call(evmc_message const& _msg) noexcept
194 {
195     assert(_msg.gas >= 0 && "Invalid gas value");
196     assert(_msg.depth == static_cast<int>(m_extVM.depth) + 1);
197 
198     // Handle CREATE separately.
199     if (_msg.kind == EVMC_CREATE || _msg.kind == EVMC_CREATE2)
200         return create(_msg);
201 
202     CallParameters params;
203     params.gas = _msg.gas;
204     params.apparentValue = fromEvmC(_msg.value);
205     params.valueTransfer = _msg.kind == EVMC_DELEGATECALL ? 0 : params.apparentValue;
206     params.senderAddress = fromEvmC(_msg.sender);
207     params.codeAddress = fromEvmC(_msg.destination);
208     params.receiveAddress = _msg.kind == EVMC_CALL ? params.codeAddress : m_extVM.myAddress;
209     params.data = {_msg.input_data, _msg.input_size};
210     params.staticCall = (_msg.flags & EVMC_STATIC) != 0;
211     params.onOp = {};
212 
213     CallResult result = m_extVM.call(params);
214     evmc_result evmcResult = {};
215     evmcResult.status_code = result.status;
216     evmcResult.gas_left = static_cast<int64_t>(params.gas);
217 
218     // Pass the output to the EVM without a copy. The EVM will delete it
219     // when finished with it.
220 
221     // First assign reference. References are not invalidated when vector
222     // of bytes is moved. See `.takeBytes()` below.
223     evmcResult.output_data = result.output.data();
224     evmcResult.output_size = result.output.size();
225 
226     // Place a new vector of bytes containing output in result's reserved memory.
227     auto* data = evmc_get_optional_storage(&evmcResult);
228     static_assert(sizeof(bytes) <= sizeof(*data), "Vector is too big");
229     new (data) bytes(result.output.takeBytes());
230     // Set the destructor to delete the vector.
231     evmcResult.release = [](evmc_result const* _result) {
232         auto* data = evmc_get_const_optional_storage(_result);
233         auto& output = reinterpret_cast<bytes const&>(*data);
234         // Explicitly call vector's destructor to release its data.
235         // This is normal pattern when placement new operator is used.
236         output.~bytes();
237     };
238     return evmc::result{evmcResult};
239 }
240 
ExtVMFace(EnvInfo const & _envInfo,Address _myAddress,Address _caller,Address _origin,u256 _value,u256 _gasPrice,bytesConstRef _data,bytes _code,h256 const & _codeHash,u256 const & _version,unsigned _depth,bool _isCreate,bool _staticCall)241 ExtVMFace::ExtVMFace(EnvInfo const& _envInfo, Address _myAddress, Address _caller, Address _origin,
242     u256 _value, u256 _gasPrice, bytesConstRef _data, bytes _code, h256 const& _codeHash,
243     u256 const& _version, unsigned _depth, bool _isCreate, bool _staticCall)
244   : m_envInfo(_envInfo),
245     myAddress(_myAddress),
246     caller(_caller),
247     origin(_origin),
248     value(_value),
249     gasPrice(_gasPrice),
250     data(_data),
251     code(std::move(_code)),
252     codeHash(_codeHash),
253     version(_version),
254     depth(_depth),
255     isCreate(_isCreate),
256     staticCall(_staticCall)
257 {}
258 
259 }  // namespace eth
260 }  // namespace dev
261