Ethereum  PoC-8
The C++ Implementation of Ethereum
ExtVMFace.cpp
Go to the documentation of this file.
1 /*
2  This file is part of cpp-ethereum.
3 
4  cpp-ethereum is free software: you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation, either version 3 of the License, or
7  (at your option) any later version.
8 
9  cpp-ethereum is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
16 */
17 
18 #include "ExtVMFace.h"
19 
20 #include <evmc/helpers.h>
21 
22 namespace dev
23 {
24 namespace eth
25 {
26 namespace
27 {
28 
29 static_assert(sizeof(Address) == sizeof(evmc_address), "Address types size mismatch");
30 static_assert(alignof(Address) == alignof(evmc_address), "Address types alignment mismatch");
31 static_assert(sizeof(h256) == sizeof(evmc_uint256be), "Hash types size mismatch");
32 static_assert(alignof(h256) == alignof(evmc_uint256be), "Hash types alignment mismatch");
33 
34 bool accountExists(evmc_context* _context, evmc_address const* _addr) noexcept
35 {
36  auto& env = static_cast<ExtVMFace&>(*_context);
37  Address addr = fromEvmC(*_addr);
38  return env.exists(addr);
39 }
40 
41 evmc_bytes32 getStorage(
42  evmc_context* _context, evmc_address const* _addr, evmc_uint256be const* _key) noexcept
43 {
44  (void) _addr;
45  auto& env = static_cast<ExtVMFace&>(*_context);
46  assert(fromEvmC(*_addr) == env.myAddress);
47  u256 key = fromEvmC(*_key);
48  return toEvmC(env.store(key));
49 }
50 
51 evmc_storage_status setStorage(evmc_context* _context, evmc_address const* _addr,
52  evmc_uint256be const* _key, evmc_uint256be const* _value) noexcept
53 {
54  (void)_addr;
55  auto& env = static_cast<ExtVMFace&>(*_context);
56  assert(fromEvmC(*_addr) == env.myAddress);
57  u256 const index = fromEvmC(*_key);
58  u256 const newValue = fromEvmC(*_value);
59  u256 const currentValue = env.store(index);
60 
61  if (newValue == currentValue)
62  return EVMC_STORAGE_UNCHANGED;
63 
64  EVMSchedule const& schedule = env.evmSchedule();
65  auto status = EVMC_STORAGE_MODIFIED;
66  u256 const originalValue = env.originalStorageValue(index);
67  if (originalValue == currentValue || !schedule.eip1283Mode)
68  {
69  if (currentValue == 0)
70  status = EVMC_STORAGE_ADDED;
71  else if (newValue == 0)
72  {
73  status = EVMC_STORAGE_DELETED;
74  env.sub.refunds += schedule.sstoreRefundGas;
75  }
76  }
77  else
78  {
79  status = EVMC_STORAGE_MODIFIED_AGAIN;
80  if (originalValue != 0)
81  {
82  if (currentValue == 0)
83  env.sub.refunds -= schedule.sstoreRefundGas; // Can go negative.
84  if (newValue == 0)
85  env.sub.refunds += schedule.sstoreRefundGas;
86  }
87  if (originalValue == newValue)
88  {
89  if (originalValue == 0)
90  env.sub.refunds += schedule.sstoreRefundGas + schedule.sstoreRefundNonzeroGas;
91  else
92  env.sub.refunds += schedule.sstoreRefundNonzeroGas;
93  }
94  }
95 
96  env.setStore(index, newValue); // Interface uses native endianness
97 
98  return status;
99 }
100 
101 evmc_uint256be getBalance(evmc_context* _context, evmc_address const* _addr) noexcept
102 {
103  auto& env = static_cast<ExtVMFace&>(*_context);
104  return toEvmC(env.balance(fromEvmC(*_addr)));
105 }
106 
107 size_t getCodeSize(evmc_context* _context, evmc_address const* _addr)
108 {
109  auto& env = static_cast<ExtVMFace&>(*_context);
110  return env.codeSizeAt(fromEvmC(*_addr));
111 }
112 
113 evmc_bytes32 getCodeHash(evmc_context* _context, evmc_address const* _addr)
114 {
115  auto& env = static_cast<ExtVMFace&>(*_context);
116  return toEvmC(env.codeHashAt(fromEvmC(*_addr)));
117 }
118 
119 size_t copyCode(evmc_context* _context, evmc_address const* _addr, size_t _codeOffset,
120  byte* _bufferData, size_t _bufferSize)
121 {
122  auto& env = static_cast<ExtVMFace&>(*_context);
123  Address addr = fromEvmC(*_addr);
124  bytes const& code = env.codeAt(addr);
125 
126  // Handle "big offset" edge case.
127  if (_codeOffset >= code.size())
128  return 0;
129 
130  size_t maxToCopy = code.size() - _codeOffset;
131  size_t numToCopy = std::min(maxToCopy, _bufferSize);
132  std::copy_n(&code[_codeOffset], numToCopy, _bufferData);
133  return numToCopy;
134 }
135 
136 void selfdestruct(
137  evmc_context* _context,
138  evmc_address const* _addr,
139  evmc_address const* _beneficiary
140 ) noexcept
141 {
142  (void) _addr;
143  auto& env = static_cast<ExtVMFace&>(*_context);
144  assert(fromEvmC(*_addr) == env.myAddress);
145  env.suicide(fromEvmC(*_beneficiary));
146 }
147 
148 
149 void log(
150  evmc_context* _context,
151  evmc_address const* _addr,
152  uint8_t const* _data,
153  size_t _dataSize,
154  evmc_uint256be const _topics[],
155  size_t _numTopics
156 ) noexcept
157 {
158  (void) _addr;
159  auto& env = static_cast<ExtVMFace&>(*_context);
160  assert(fromEvmC(*_addr) == env.myAddress);
161  h256 const* pTopics = reinterpret_cast<h256 const*>(_topics);
162  env.log(h256s{pTopics, pTopics + _numTopics},
163  bytesConstRef{_data, _dataSize});
164 }
165 
166 evmc_tx_context getTxContext(evmc_context* _context) noexcept
167 {
168  auto& env = static_cast<ExtVMFace&>(*_context);
169  evmc_tx_context result = {};
170  result.tx_gas_price = toEvmC(env.gasPrice);
171  result.tx_origin = toEvmC(env.origin);
172  result.block_coinbase = toEvmC(env.envInfo().author());
173  result.block_number = static_cast<int64_t>(env.envInfo().number());
174  result.block_timestamp = static_cast<int64_t>(env.envInfo().timestamp());
175  result.block_gas_limit = static_cast<int64_t>(env.envInfo().gasLimit());
176  result.block_difficulty = toEvmC(env.envInfo().difficulty());
177  return result;
178 }
179 
180 evmc_bytes32 getBlockHash(evmc_context* _envPtr, int64_t _number)
181 {
182  auto& env = static_cast<ExtVMFace&>(*_envPtr);
183  return toEvmC(env.blockHash(_number));
184 }
185 
186 evmc_result create(ExtVMFace& _env, evmc_message const* _msg) noexcept
187 {
188  u256 gas = _msg->gas;
189  u256 value = fromEvmC(_msg->value);
190  bytesConstRef init = {_msg->input_data, _msg->input_size};
191  u256 salt = fromEvmC(_msg->create2_salt);
192  Instruction opcode = _msg->kind == EVMC_CREATE ? Instruction::CREATE : Instruction::CREATE2;
193 
194  // ExtVM::create takes the sender address from .myAddress.
195  assert(fromEvmC(_msg->sender) == _env.myAddress);
196 
197  CreateResult result = _env.create(value, gas, init, opcode, salt, {});
198  evmc_result evmcResult = {};
199  evmcResult.status_code = result.status;
200  evmcResult.gas_left = static_cast<int64_t>(gas);
201 
202  if (result.status == EVMC_SUCCESS)
203  evmcResult.create_address = toEvmC(result.address);
204  else
205  {
206  // Pass the output to the EVM without a copy. The EVM will delete it
207  // when finished with it.
208 
209  // First assign reference. References are not invalidated when vector
210  // of bytes is moved. See `.takeBytes()` below.
211  evmcResult.output_data = result.output.data();
212  evmcResult.output_size = result.output.size();
213 
214  // Place a new vector of bytes containing output in result's reserved memory.
215  auto* data = evmc_get_optional_storage(&evmcResult);
216  static_assert(sizeof(bytes) <= sizeof(*data), "Vector is too big");
217  new(data) bytes(result.output.takeBytes());
218  // Set the destructor to delete the vector.
219  evmcResult.release = [](evmc_result const* _result)
220  {
221  auto* data = evmc_get_const_optional_storage(_result);
222  auto& output = reinterpret_cast<bytes const&>(*data);
223  // Explicitly call vector's destructor to release its data.
224  // This is normal pattern when placement new operator is used.
225  output.~bytes();
226  };
227  }
228  return evmcResult;
229 }
230 
231 evmc_result call(evmc_context* _context, evmc_message const* _msg) noexcept
232 {
233  assert(_msg->gas >= 0 && "Invalid gas value");
234  auto& env = static_cast<ExtVMFace&>(*_context);
235 
236  // Handle CREATE separately.
237  if (_msg->kind == EVMC_CREATE || _msg->kind == EVMC_CREATE2)
238  return create(env, _msg);
239 
240  CallParameters params;
241  params.gas = _msg->gas;
242  params.apparentValue = fromEvmC(_msg->value);
243  params.valueTransfer =
244  _msg->kind == EVMC_DELEGATECALL ? 0 : params.apparentValue;
245  params.senderAddress = fromEvmC(_msg->sender);
246  params.codeAddress = fromEvmC(_msg->destination);
247  params.receiveAddress =
248  _msg->kind == EVMC_CALL ? params.codeAddress : env.myAddress;
249  params.data = {_msg->input_data, _msg->input_size};
250  params.staticCall = (_msg->flags & EVMC_STATIC) != 0;
251  params.onOp = {};
252 
253  CallResult result = env.call(params);
254  evmc_result evmcResult = {};
255  evmcResult.status_code = result.status;
256  evmcResult.gas_left = static_cast<int64_t>(params.gas);
257 
258  // Pass the output to the EVM without a copy. The EVM will delete it
259  // when finished with it.
260 
261  // First assign reference. References are not invalidated when vector
262  // of bytes is moved. See `.takeBytes()` below.
263  evmcResult.output_data = result.output.data();
264  evmcResult.output_size = result.output.size();
265 
266  // Place a new vector of bytes containing output in result's reserved memory.
267  auto* data = evmc_get_optional_storage(&evmcResult);
268  static_assert(sizeof(bytes) <= sizeof(*data), "Vector is too big");
269  new(data) bytes(result.output.takeBytes());
270  // Set the destructor to delete the vector.
271  evmcResult.release = [](evmc_result const* _result)
272  {
273  auto* data = evmc_get_const_optional_storage(_result);
274  auto& output = reinterpret_cast<bytes const&>(*data);
275  // Explicitly call vector's destructor to release its data.
276  // This is normal pattern when placement new operator is used.
277  output.~bytes();
278  };
279  return evmcResult;
280 }
281 
282 evmc_host_interface const hostInterface = {
283  accountExists,
284  getStorage,
285  setStorage,
286  getBalance,
287  getCodeSize,
288  getCodeHash,
289  copyCode,
290  selfdestruct,
291  eth::call,
292  getTxContext,
293  getBlockHash,
294  eth::log,
295 };
296 }
297 
298 ExtVMFace::ExtVMFace(EnvInfo const& _envInfo, Address _myAddress, Address _caller, Address _origin,
299  u256 _value, u256 _gasPrice, bytesConstRef _data, bytes _code, h256 const& _codeHash,
300  unsigned _depth, bool _isCreate, bool _staticCall)
301  : evmc_context{&hostInterface},
302  m_envInfo(_envInfo),
303  myAddress(_myAddress),
304  caller(_caller),
305  origin(_origin),
306  value(_value),
307  gasPrice(_gasPrice),
308  data(_data),
309  code(std::move(_code)),
310  codeHash(_codeHash),
311  depth(_depth),
312  isCreate(_isCreate),
313  staticCall(_staticCall)
314 {}
315 
316 }
317 }
dev::vector_ref< byte const >
dev::eth::Instruction::CREATE
@ CREATE
create a new account with associated code
dev::h256
FixedHash< 32 > h256
Definition: FixedHash.h:356
dev::eth::fromEvmC
u256 fromEvmC(evmc_uint256be const &_n)
Definition: ExtVMFace.h:291
dev::FixedHash< 20 >
dev::eth::toEvmC
evmc_address toEvmC(Address const &_addr)
Definition: ExtVMFace.h:281
ExtVMFace.h
dev::h256s
std::vector< h256 > h256s
Definition: FixedHash.h:361
dev::eth::ExtVMFace::ExtVMFace
ExtVMFace(EnvInfo const &_envInfo, Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytes _code, h256 const &_codeHash, unsigned _depth, bool _isCreate, bool _staticCall)
Full constructor.
Definition: ExtVMFace.cpp:298
dev::bytes
std::vector< byte > bytes
Definition: Common.h:72
dev::bytesConstRef
vector_ref< byte const > bytesConstRef
Definition: Common.h:74
dev::eth::Instruction
Instruction
Virtual machine bytecode instruction.
Definition: Instruction.h:29
dev::u256
boost::multiprecision::number< boost::multiprecision::cpp_int_backend< 256, 256, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void > > u256
Definition: Common.h:121
dev
Definition: Address.cpp:21
dev::eth::EnvInfo
Definition: ExtVMFace.h:143
dev::Address
h160 Address
Definition: Address.h:30
dev::eth::Instruction::CREATE2
@ CREATE2
create a new account with associated code. sha3((sender + salt + code)