Ethereum  PoC-8
The C++ Implementation of Ethereum
EVMC.cpp
Go to the documentation of this file.
1 // Copyright 2018 cpp-ethereum Authors.
2 // Licensed under the GNU General Public License v3. See the LICENSE file.
3 
4 #include "EVMC.h"
5 
6 #include <libdevcore/Log.h>
7 #include <libevm/VMFactory.h>
8 
9 namespace dev
10 {
11 namespace eth
12 {
13 EVM::EVM(evmc_instance* _instance) noexcept : m_instance(_instance)
14 {
15  assert(m_instance != nullptr);
16  assert(evmc_is_abi_compatible(m_instance));
17 
18  // Set the options.
19  for (auto& pair : evmcOptions())
20  {
21  auto result = evmc_set_option(m_instance, pair.first.c_str(), pair.second.c_str());
22  switch (result)
23  {
24  case EVMC_SET_OPTION_SUCCESS:
25  break;
26  case EVMC_SET_OPTION_INVALID_NAME:
27  cwarn << "Unknown EVMC option '" << pair.first << "'";
28  break;
29  case EVMC_SET_OPTION_INVALID_VALUE:
30  cwarn << "Invalid value '" << pair.second << "' for EVMC option '" << pair.first << "'";
31  break;
32  default:
33  cwarn << "Unknown error when setting EVMC option '" << pair.first << "'";
34  }
35  }
36 }
37 
39 EVM::Result EVM::execute(ExtVMFace& _ext, int64_t gas)
40 {
41  auto mode = toRevision(_ext.evmSchedule());
42  evmc_call_kind kind = _ext.isCreate ? EVMC_CREATE : EVMC_CALL;
43  uint32_t flags = _ext.staticCall ? EVMC_STATIC : 0;
44  assert(flags != EVMC_STATIC || kind == EVMC_CALL); // STATIC implies a CALL.
45  evmc_message msg = {kind, flags, static_cast<int32_t>(_ext.depth), gas, toEvmC(_ext.myAddress),
46  toEvmC(_ext.caller), _ext.data.data(), _ext.data.size(), toEvmC(_ext.value),
47  toEvmC(0x0_cppui256)};
48  return EVM::Result{
49  evmc_execute(m_instance, &_ext, mode, &msg, _ext.code.data(), _ext.code.size())};
50 }
51 
52 owning_bytes_ref EVMC::exec(u256& io_gas, ExtVMFace& _ext, const OnOpFunc& _onOp)
53 {
54  assert(_ext.envInfo().number() >= 0);
55  assert(_ext.envInfo().timestamp() >= 0);
56 
57  constexpr int64_t int64max = std::numeric_limits<int64_t>::max();
58 
59  // TODO: The following checks should be removed by changing the types
60  // used for gas, block number and timestamp.
61  (void)int64max;
62  assert(io_gas <= int64max);
63  assert(_ext.envInfo().gasLimit() <= int64max);
64  assert(_ext.depth <= static_cast<size_t>(std::numeric_limits<int32_t>::max()));
65 
66  auto gas = static_cast<int64_t>(io_gas);
67  EVM::Result r = execute(_ext, gas);
68 
69  switch (r.status())
70  {
71  case EVMC_SUCCESS:
72  io_gas = r.gasLeft();
73  // FIXME: Copy the output for now, but copyless version possible.
74  return {r.output().toVector(), 0, r.output().size()};
75 
76  case EVMC_REVERT:
77  io_gas = r.gasLeft();
78  // FIXME: Copy the output for now, but copyless version possible.
79  throw RevertInstruction{{r.output().toVector(), 0, r.output().size()}};
80 
81  case EVMC_OUT_OF_GAS:
82  case EVMC_FAILURE:
83  BOOST_THROW_EXCEPTION(OutOfGas());
84 
85  case EVMC_INVALID_INSTRUCTION: // NOTE: this could have its own exception
86  case EVMC_UNDEFINED_INSTRUCTION:
87  BOOST_THROW_EXCEPTION(BadInstruction());
88 
89  case EVMC_BAD_JUMP_DESTINATION:
90  BOOST_THROW_EXCEPTION(BadJumpDestination());
91 
92  case EVMC_STACK_OVERFLOW:
93  BOOST_THROW_EXCEPTION(OutOfStack());
94 
95  case EVMC_STACK_UNDERFLOW:
96  BOOST_THROW_EXCEPTION(StackUnderflow());
97 
98  case EVMC_INVALID_MEMORY_ACCESS:
99  BOOST_THROW_EXCEPTION(BufferOverrun());
100 
101  case EVMC_STATIC_MODE_VIOLATION:
102  BOOST_THROW_EXCEPTION(DisallowedStateChange());
103 
104  case EVMC_REJECTED:
105  cwarn << "Execution rejected by EVMC, executing with default VM implementation";
106  return VMFactory::create(VMKind::Legacy)->exec(io_gas, _ext, _onOp);
107 
108  case EVMC_INTERNAL_ERROR:
109  default:
110  if (r.status() <= EVMC_INTERNAL_ERROR)
111  BOOST_THROW_EXCEPTION(InternalVMError{} << errinfo_evmcStatusCode(r.status()));
112  else
113  // These cases aren't really internal errors, just more specific
114  // error codes returned by the VM. Map all of them to OOG.
115  BOOST_THROW_EXCEPTION(OutOfGas());
116  }
117 }
118 
119 evmc_revision EVM::toRevision(EVMSchedule const& _schedule)
120 {
121  if (_schedule.haveCreate2)
122  return EVMC_CONSTANTINOPLE;
123  if (_schedule.haveRevert)
124  return EVMC_BYZANTIUM;
125  if (_schedule.eip158Mode)
126  return EVMC_SPURIOUS_DRAGON;
127  if (_schedule.eip150Mode)
128  return EVMC_TANGERINE_WHISTLE;
129  if (_schedule.haveDelegateCall)
130  return EVMC_HOMESTEAD;
131  return EVMC_FRONTIER;
132 }
133 } // namespace eth
134 } // namespace dev
owning_bytes_ref exec(u256 &io_gas, ExtVMFace &_ext, OnOpFunc const &_onOp) final
VM implementation.
Definition: EVMC.cpp:52
std::vector< std::pair< std::string, std::string > > & evmcOptions() noexcept
Returns the EVMC options parsed from command line.
Definition: VMFactory.cpp:136
Definition: Address.cpp:20
static VMPtr create()
Creates a VM instance of the global kind (controlled by the –vm command line option).
Definition: VMFactory.cpp:177
std::function< void(uint64_t, uint64_t, Instruction, bigint, bigint, bigint, VMFace const *, ExtVMFace const *)> OnOpFunc
Definition: ExtVMFace.h:115
u256 value
Value (in Wei) that was passed to this address.
Definition: ExtVMFace.h:269
evmc_status_code status() const
Definition: EVMC.h:54
virtual EVMSchedule const & evmSchedule() const
Return the EVM gas-price schedule for this execution context.
Definition: ExtVMFace.h:259
evmc_address toEvmC(Address const &_addr)
Definition: ExtVMFace.h:281
static evmc_revision toRevision(EVMSchedule const &_schedule)
Translate the EVMSchedule to EVMC revision.
Definition: EVMC.cpp:119
Ran out of stack executing code of the transaction.
bytesConstRef output() const
Definition: EVMC.h:64
VMKind kind
Definition: VMFactory.cpp:48
EVM(evmc_instance *_instance) noexcept
Definition: EVMC.cpp:13
int64_t gasLeft() const
Definition: EVMC.h:59
bool staticCall
Throw on state changing.
Definition: ExtVMFace.h:278
Ran out of gas executing code of the transaction.
Address caller
Address which sent the message (either equal to origin or a contract).
Definition: ExtVMFace.h:267
Result execute(ExtVMFace &_ext, int64_t gas)
Handy wrapper for evmc_execute().
Definition: EVMC.cpp:39
unsigned depth
Depth of the present call.
Definition: ExtVMFace.h:276
u256 const & gasLimit() const
Definition: ExtVMFace.h:163
#define cwarn
Interface and null implementation of the class for specifying VM externalities.
Definition: ExtVMFace.h:203
int64_t number() const
Definition: ExtVMFace.h:159
boost::multiprecision::number< boost::multiprecision::cpp_int_backend< 256, 256, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void > > u256
Definition: Common.h:121
bytes code
Current code that is executing.
Definition: ExtVMFace.h:272
Address myAddress
Address associated with executing code (a contract, or contract-to-be).
Definition: ExtVMFace.h:266
bool isCreate
Is this a CREATE call?
Definition: ExtVMFace.h:277
std::vector< mutable_value_type > toVector() const
Definition: vector_ref.h:42
boost::error_info< struct tag_evmcStatusCode, evmc_status_code > errinfo_evmcStatusCode
Error info for EVMC status code.
Definition: VMFace.h:43
size_t size() const
Definition: vector_ref.h:53
EnvInfo const & envInfo() const
Get the execution environment information.
Definition: ExtVMFace.h:256
bytesConstRef data
Current input data.
Definition: ExtVMFace.h:271
int64_t timestamp() const
Definition: ExtVMFace.h:161
_T * data() const
Definition: vector_ref.h:49