Fabcoin Core  0.16.2
P2P Digital Currency
JitVM.cpp
Go to the documentation of this file.
1 #include "JitVM.h"
2 
3 #include <libdevcore/Log.h>
4 #include <libevm/VM.h>
5 #include <libevm/VMFactory.h>
6 
7 namespace dev
8 {
9 namespace eth
10 {
11 namespace
12 {
13 
14 static_assert(sizeof(Address) == sizeof(evm_uint160be),
15  "Address types size mismatch");
16 static_assert(alignof(Address) == alignof(evm_uint160be),
17  "Address types alignment mismatch");
18 
19 inline evm_uint160be toEvmC(Address _addr)
20 {
21  return *reinterpret_cast<evm_uint160be*>(&_addr);
22 }
23 
24 inline Address fromEvmC(evm_uint160be _addr)
25 {
26  return *reinterpret_cast<Address*>(&_addr);
27 }
28 
29 static_assert(sizeof(h256) == sizeof(evm_uint256be), "Hash types size mismatch");
30 static_assert(alignof(h256) == alignof(evm_uint256be), "Hash types alignment mismatch");
31 
32 inline evm_uint256be toEvmC(h256 _h)
33 {
34  return *reinterpret_cast<evm_uint256be*>(&_h);
35 }
36 
37 inline u256 asUint(evm_uint256be _n)
38 {
39  return fromBigEndian<u256>(_n.bytes);
40 }
41 
42 inline h256 asHash(evm_uint256be _n)
43 {
44  return h256(&_n.bytes[0], h256::ConstructFromPointer);
45 }
46 
47 void evm_query(
48  evm_variant* o_result,
49  evm_env* _opaqueEnv,
50  evm_query_key _key,
51  evm_variant const* _arg
52 ) noexcept
53 {
54  auto &env = *reinterpret_cast<ExtVMFace*>(_opaqueEnv);
55  switch (_key)
56  {
57  case EVM_ADDRESS:
58  o_result->address = toEvmC(env.myAddress);
59  break;
60  case EVM_CALLER:
61  o_result->address = toEvmC(env.caller);
62  break;
63  case EVM_ORIGIN:
64  o_result->address = toEvmC(env.origin);
65  break;
66  case EVM_GAS_PRICE:
67  o_result->uint256be = toEvmC(env.gasPrice);
68  break;
69  case EVM_COINBASE:
70  o_result->address = toEvmC(env.envInfo().author());
71  break;
72  case EVM_DIFFICULTY:
73  o_result->uint256be = toEvmC(env.envInfo().difficulty());
74  break;
75  case EVM_GAS_LIMIT:
76  o_result->int64 = env.envInfo().gasLimit();
77  break;
78  case EVM_NUMBER:
79  // TODO: Handle overflow / exception
80  o_result->int64 = static_cast<int64_t>(env.envInfo().number());
81  break;
82  case EVM_TIMESTAMP:
83  // TODO: Handle overflow / exception
84  o_result->int64 = static_cast<int64_t>(env.envInfo().timestamp());
85  break;
87  {
88  auto addr = fromEvmC(_arg->address);
89  auto &code = env.codeAt(addr);
90  o_result->data = code.data();
91  o_result->data_size = code.size();
92  break;
93  }
94  case EVM_CODE_SIZE:
95  {
96  auto addr = fromEvmC(_arg->address);
97  o_result->int64 = env.codeSizeAt(addr);
98  break;
99  }
100  case EVM_BALANCE:
101  {
102  auto addr = fromEvmC(_arg->address);
103  o_result->uint256be = toEvmC(env.balance(addr));
104  break;
105  }
106  case EVM_BLOCKHASH:
107  o_result->uint256be = toEvmC(env.blockHash(_arg->int64));
108  break;
109  case EVM_SLOAD:
110  {
111  auto key = asUint(_arg->uint256be);
112  o_result->uint256be = toEvmC(env.store(key));
113  break;
114  }
115  case EVM_ACCOUNT_EXISTS:
116  {
117  auto addr = fromEvmC(_arg->address);
118  o_result->int64 = env.exists(addr);
119  break;
120  }
121  case EVM_CALL_DEPTH:
122  o_result->int64 = env.depth;
123  break;
124  }
125 }
126 
127 void evm_update(
128  evm_env* _opaqueEnv,
129  evm_update_key _key,
130  evm_variant const* _arg1,
131  evm_variant const* _arg2
132 ) noexcept
133 {
134  auto &env = *reinterpret_cast<ExtVMFace*>(_opaqueEnv);
135  switch (_key)
136  {
137  case EVM_SSTORE:
138  {
139  auto index = asUint(_arg1->uint256be);
140  auto value = asUint(_arg2->uint256be);
141  if (value == 0 && env.store(index) != 0) // If delete
142  env.sub.refunds += env.evmSchedule().sstoreRefundGas; // Increase refund counter
143 
144  env.setStore(index, value); // Interface uses native endianness
145  break;
146  }
147  case EVM_LOG:
148  {
149  size_t numTopics = _arg2->data_size / sizeof(h256);
150  h256 const* pTopics = reinterpret_cast<h256 const*>(_arg2->data);
151  env.log({pTopics, pTopics + numTopics}, {_arg1->data, _arg1->data_size});
152  break;
153  }
154  case EVM_SELFDESTRUCT:
155  // Register selfdestruction beneficiary.
156  env.suicide(fromEvmC(_arg1->address));
157  break;
158  }
159 }
160 
161 int64_t evm_call(
162  evm_env* _opaqueEnv,
163  evm_call_kind _kind,
164  int64_t _gas,
165  evm_uint160be const* _address,
166  evm_uint256be const* _value,
167  uint8_t const* _inputData,
168  size_t _inputSize,
169  uint8_t* _outputData,
170  size_t _outputSize
171 ) noexcept
172 {
173  assert(_gas >= 0 && "Invalid gas value");
174  auto &env = *reinterpret_cast<ExtVMFace*>(_opaqueEnv);
175  auto value = asUint(*_value);
176  bytesConstRef input{_inputData, _inputSize};
177 
178  if (_kind == EVM_CREATE)
179  {
180  assert(_outputSize == 20);
181  u256 gas = _gas;
182  auto addr = env.create(value, gas, input, {});
183  auto gasLeft = static_cast<decltype(_gas)>(gas);
184  if (addr)
185  std::memcpy(_outputData, addr.data(), 20);
186  else
187  gasLeft |= EVM_CALL_FAILURE;
188  return gasLeft;
189  }
190 
191  CallParameters params;
192  params.gas = _gas;
193  params.apparentValue = _kind == EVM_DELEGATECALL ? env.value : value;
194  params.valueTransfer = _kind == EVM_DELEGATECALL ? 0 : params.apparentValue;
195  params.senderAddress = _kind == EVM_DELEGATECALL ? env.caller : env.myAddress;
196  params.codeAddress = fromEvmC(*_address);
197  params.receiveAddress = _kind == EVM_CALL ? params.codeAddress : env.myAddress;
198  params.data = input;
199  params.onOp = {};
200 
201  auto output = env.call(params);
202  auto gasLeft = static_cast<int64_t>(params.gas);
203 
204  if (output)
205  output->copyTo({_outputData, _outputSize});
206  else
207  // Add failure indicator.
208  gasLeft |= EVM_CALL_FAILURE;
209 
210  return gasLeft;
211 }
212 
213 
215 class EVM
216 {
217 public:
218  EVM(evm_query_fn _queryFn, evm_update_fn _updateFn, evm_call_fn _callFn)
219  {
220  auto factory = evmjit_get_factory();
221  m_instance = factory.create(_queryFn, _updateFn, _callFn);
222  }
223 
224  ~EVM()
225  {
227  }
228 
229  EVM(EVM const&) = delete;
230  EVM& operator=(EVM) = delete;
231 
232  class Result
233  {
234  public:
235  explicit Result(evm_result const& _result):
236  m_result(_result)
237  {}
238 
239  ~Result()
240  {
241  if (m_result.release)
243  }
244 
245  Result(Result&& _other):
246  m_result(_other.m_result)
247  {
248  // Disable releaser of the rvalue object.
249  _other.m_result.release = nullptr;
250  }
251 
252  Result(Result const&) = delete;
253  Result& operator=(Result const&) = delete;
254 
255  evm_result_code code() const
256  {
257  return m_result.code;
258  }
259 
260  int64_t gasLeft() const
261  {
262  return m_result.gas_left;
263  }
264 
265  bytesConstRef output() const
266  {
268  }
269 
270  private:
272  };
273 
275  Result execute(ExtVMFace& _ext, int64_t gas)
276  {
277  auto env = reinterpret_cast<evm_env*>(&_ext);
278  auto mode = JitVM::scheduleToMode(_ext.evmSchedule());
279  return Result{m_instance->execute(
280  m_instance, env, mode, toEvmC(_ext.codeHash), _ext.code.data(),
281  _ext.code.size(), gas, _ext.data.data(), _ext.data.size(),
282  toEvmC(_ext.value)
283  )};
284  }
285 
286  bool isCodeReady(evm_mode _mode, h256 _codeHash)
287  {
288  return m_instance->get_code_status(m_instance, _mode, toEvmC(_codeHash)) == EVM_READY;
289  }
290 
291  void compile(evm_mode _mode, bytesConstRef _code, h256 _codeHash)
292  {
294  m_instance, _mode, toEvmC(_codeHash), _code.data(), _code.size()
295  );
296  }
297 
298 private:
301 };
302 
303 EVM& getJit()
304 {
305  // Create EVM JIT instance by using EVM-C interface.
306  static EVM jit(evm_query, evm_update, evm_call);
307  return jit;
308 }
309 
310 }
311 
312 owning_bytes_ref JitVM::exec(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp)
313 {
314  auto rejected = false;
315  // TODO: Rejecting transactions with gas limit > 2^63 can be used by attacker to take JIT out of scope
316  rejected |= io_gas > std::numeric_limits<int64_t>::max(); // Do not accept requests with gas > 2^63 (int64 max)
317  rejected |= _ext.envInfo().number() > std::numeric_limits<int64_t>::max();
318  rejected |= _ext.envInfo().timestamp() > std::numeric_limits<int64_t>::max();
319  rejected |= _ext.envInfo().gasLimit() > std::numeric_limits<int64_t>::max();
320  if (rejected)
321  {
322  cwarn << "Execution rejected by EVM JIT (gas limit: " << io_gas << "), executing with interpreter";
323  return VMFactory::create(VMKind::Interpreter)->exec(io_gas, _ext, _onOp);
324  }
325 
326  auto gas = static_cast<int64_t>(io_gas);
327  auto r = getJit().execute(_ext, gas);
328 
329  // TODO: Add EVM-C result codes mapping with exception types.
330  if (r.code() != EVM_SUCCESS)
331  BOOST_THROW_EXCEPTION(OutOfGas());
332 
333  io_gas = r.gasLeft();
334  auto output = r.output();
335  // FIXME: Copy the output for now, but copyless version possible.
336  return {output.toVector(), 0, output.size()};
337 }
338 
340 {
341  if (_schedule.eip158Mode)
342  return EVM_CLEARING;
343  if (_schedule.eip150Mode)
344  return EVM_ANTI_DOS;
345  return _schedule.haveDelegateCall ? EVM_HOMESTEAD : EVM_FRONTIER;
346 }
347 
348 bool JitVM::isCodeReady(evm_mode _mode, h256 _codeHash)
349 {
350  return getJit().isCodeReady(_mode, _codeHash);
351 }
352 
353 void JitVM::compile(evm_mode _mode, bytesConstRef _code, h256 _codeHash)
354 {
355  getJit().compile(_mode, _code, _codeHash);
356 }
357 
358 }
359 }
Adapted from code found on http://stackoverflow.com/questions/180947/base64-decode-snippet-in-c Origi...
Definition: Arith256.cpp:15
uint8_t bytes[32]
The 32 bytes of the big-endian integer or hash.
Definition: evm.h:38
owning_bytes_ref exec(u256 &io_gas, ExtVMFace &_ext, OnOpFunc const &_onOp) overridefinal
VM implementation.
Definition: JitVM.cpp:312
evm_get_code_status_fn get_code_status
Optional pointer to function returning a status of a code.
Definition: evm.h:439
u256 const & timestamp() const
Definition: ExtVMFace.h:239
Big-endian 256-bit integer.
Definition: evm.h:36
Update storage entry.
Definition: evm.h:239
int64_t gasLimit() const
Definition: ExtVMFace.h:241
uint8_t const * output_data
The reference to output data.
Definition: evm.h:82
h160 Address
An Ethereum address: 20 bytes.
Definition: Common.h:62
evm_mode mode
Definition: SmartVM.cpp:47
Current block difficulty for DIFFICULTY.
Definition: evm.h:116
EnvInfo const & envInfo() const
Get the execution environment information.
Definition: ExtVMFace.h:313
int64_t gas_left
The amount of gas left after the execution.
Definition: evm.h:78
Current block number for NUMBER.
Definition: evm.h:118
assert(len-trim+(2 *lenIndices)<=WIDTH)
static void compile(evm_mode _mode, bytesConstRef _code, h256 _codeHash)
Definition: JitVM.cpp:353
evm_release_result_fn release
The pointer to the result release implementation.
Definition: evm.h:92
static std::unique_ptr< VMFace > create()
Creates a VM instance of global kind (controlled by setKind() function).
Definition: VMFactory.cpp:41
Execution finished with success.
Definition: evm.h:49
u256 const & number() const
Definition: ExtVMFace.h:237
evm_prepare_code_fn prepare_code
Optional pointer to function compiling a code.
Definition: evm.h:444
Transaction gas price for GASPRICE.
Definition: evm.h:114
bytes code
Definition: SmartVM.cpp:45
The code has been compiled and is available in memory.
Definition: evm.h:404
Address of the contract for ADDRESS.
Definition: evm.h:111
Request CREATE. Semantic of some params changes.
Definition: evm.h:281
Message sender address for CALLER.
Definition: evm.h:112
Ran out of gas executing code of the transaction.
evm_update_key
The update callback key.
Definition: evm.h:238
Variant type to represent possible types of values used in EVM.
Definition: evm.h:138
EXPORT struct evm_factory evmjit_get_factory(void)
Get EVMJIT instance.
Definition: JIT.cpp:389
enum evm_result_code code
The execution result code.
Definition: evm.h:73
Current call depth.
Definition: evm.h:125
size_t output_size
The size of the output data.
Definition: evm.h:85
Current block timestamp for TIMESTAMP.
Definition: evm.h:119
Balance of a given address for BALANCE.
Definition: evm.h:122
ExecStats::duration max
Definition: ExecStats.cpp:36
evm_destroy_fn destroy
Pointer to function destroying the EVM instance.
Definition: evm.h:431
Request CALL.
Definition: evm.h:278
Transaction origin address for ORIGIN.
Definition: evm.h:113
Big-endian 160-bit hash suitable for keeping an Ethereum address.
Definition: evm.h:42
The EVM instance.
Definition: evm.h:429
vector_ref< byte const > bytesConstRef
Definition: Common.h:77
evm_call_kind
The kind of call-like instruction.
Definition: evm.h:277
Current block miner address for COINBASE.
Definition: evm.h:115
std::function< void(uint64_t, uint64_t, Instruction, bigint, bigint, bigint, VM *, ExtVMFace const *)> OnOpFunc
Definition: ExtVMFace.h:193
Block hash of by block number for BLOCKHASH.
Definition: evm.h:123
FixedHash< 32 > h256
Definition: FixedHash.h:340
#define cwarn
Definition: Log.h:304
Check if an account exists.
Definition: evm.h:124
boost::multiprecision::number< boost::multiprecision::cpp_int_backend< 256, 256, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void >> u256
Definition: Common.h:125
evm_mode
EVM compatibility mode aka chain mode.
Definition: evm.h:359
Request DELEGATECALL. The value param ignored.
Definition: evm.h:279
Code by an address for EXTCODECOPY.
Definition: evm.h:120
evm_execute_fn execute
Pointer to function executing a code by the EVM instance.
Definition: evm.h:434
The EVM code execution result.
Definition: evm.h:71
evm_result_code
The execution result code.
Definition: evm.h:48
Interface and null implementation of the class for specifying VM externalities.
Definition: ExtVMFace.h:265
Storage value of a given key for SLOAD.
Definition: evm.h:110
static bool isCodeReady(evm_mode _mode, h256 _codeHash)
Definition: JitVM.cpp:348
Reference to a slice of buffer that also owns the buffer.
Definition: ExtVMFace.h:56
void(* evm_update_fn)(struct evm_env *env, enum evm_update_key key, const union evm_variant *arg1, const union evm_variant *arg2)
Update callback function.
Definition: evm.h:271
void * memcpy(void *a, const void *b, size_t c)
Mark contract as selfdestructed and set beneficiary address.
Definition: evm.h:241
Code size by an address for EXTCODESIZE.
Definition: evm.h:121
Log.
Definition: evm.h:240
evm_instance * m_instance
The VM instance created with m_interface.create().
Definition: JitVM.cpp:300
static evm_mode scheduleToMode(EVMSchedule const &_schedule)
Definition: JitVM.cpp:339
void(* evm_query_fn)(union evm_variant *result, struct evm_env *env, enum evm_query_key key, const union evm_variant *arg)
Query callback function.
Definition: evm.h:232
Current block gas limit for GASLIMIT.
Definition: evm.h:117
evm_query_key
The query callback key.
Definition: evm.h:109
int64_t(* evm_call_fn)(struct evm_env *env, enum evm_call_kind kind, int64_t gas, const struct evm_uint160be *address, const struct evm_uint256be *value, uint8_t const *input, size_t input_size, uint8_t *output, size_t output_size)
Pointer to the callback function supporting EVM calls.
Definition: evm.h:308
evm_result m_result
Definition: JitVM.cpp:271