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