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