Ethereum  PoC-8
The C++ Implementation of Ethereum
ExtVM.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 */
22 #include "ExtVM.h"
23 #include "LastBlockHashesFace.h"
24 #include <boost/thread.hpp>
25 #include <exception>
26 
27 using namespace dev;
28 using namespace dev::eth;
29 
30 namespace // anonymous
31 {
32 
33 static unsigned const c_depthLimit = 1024;
34 
36 static size_t const c_singleExecutionStackSize = 100 * 1024;
37 
39 static size_t const c_defaultStackSize =
40 #if defined(__linux)
41  8 * 1024 * 1024;
42 #elif defined(_WIN32)
43  16 * 1024 * 1024;
44 #else
45  512 * 1024; // OSX and other OSs
46 #endif
47 
49 static size_t const c_entryOverhead = 128 * 1024;
50 
52 static unsigned const c_offloadPoint = (c_defaultStackSize - c_entryOverhead) / c_singleExecutionStackSize;
53 
54 void goOnOffloadedStack(Executive& _e, OnOpFunc const& _onOp)
55 {
56  // Set new stack size enouth to handle the rest of the calls up to the limit.
57  boost::thread::attributes attrs;
58  attrs.set_stack_size((c_depthLimit - c_offloadPoint) * c_singleExecutionStackSize);
59 
60  // Create new thread with big stack and join immediately.
61  // TODO: It is possible to switch the implementation to Boost.Context or similar when the API is stable.
62  boost::exception_ptr exception;
63  boost::thread{attrs, [&]{
64  try
65  {
66  _e.go(_onOp);
67  }
68  catch (...)
69  {
70  exception = boost::current_exception(); // Catch all exceptions to be rethrown in parent thread.
71  }
72  }}.join();
73  if (exception)
74  boost::rethrow_exception(exception);
75 }
76 
77 void go(unsigned _depth, Executive& _e, OnOpFunc const& _onOp)
78 {
79  // If in the offloading point we need to switch to additional separated stack space.
80  // Current stack is too small to handle more CALL/CREATE executions.
81  // It needs to be done only once as newly allocated stack space it enough to handle
82  // the rest of the calls up to the depth limit (c_depthLimit).
83 
84  if (_depth == c_offloadPoint)
85  {
86  cnote << "Stack offloading (depth: " << c_offloadPoint << ")";
87  goOnOffloadedStack(_e, _onOp);
88  }
89  else
90  _e.go(_onOp);
91 }
92 
93 evmc_status_code transactionExceptionToEvmcStatusCode(TransactionException ex) noexcept
94 {
95  switch (ex)
96  {
98  return EVMC_SUCCESS;
99 
101  return EVMC_REVERT;
102 
104  return EVMC_OUT_OF_GAS;
105 
107  return EVMC_UNDEFINED_INSTRUCTION;
108 
110  return EVMC_STACK_OVERFLOW;
111 
113  return EVMC_STACK_UNDERFLOW;
114 
115  case TransactionException ::BadJumpDestination:
116  return EVMC_BAD_JUMP_DESTINATION;
117 
118  default:
119  return EVMC_FAILURE;
120  }
121 }
122 
123 } // anonymous namespace
124 
125 
127 {
128  Executive e{m_s, envInfo(), m_sealEngine, depth + 1};
129  if (!e.call(_p, gasPrice, origin))
130  {
131  go(depth, e, _p.onOp);
132  e.accrueSubState(sub);
133  }
134  _p.gas = e.gas();
135 
136  return {transactionExceptionToEvmcStatusCode(e.getException()), e.takeOutput()};
137 }
138 
140 {
141  return m_s.codeSize(_a);
142 }
143 
145 {
146  return exists(_a) ? m_s.codeHash(_a) : h256{};
147 }
148 
150 {
151  m_s.setStorage(myAddress, _n, _v);
152 }
153 
154 CreateResult ExtVM::create(u256 _endowment, u256& io_gas, bytesConstRef _code, Instruction _op, u256 _salt, OnOpFunc const& _onOp)
155 {
156  Executive e{m_s, envInfo(), m_sealEngine, depth + 1};
157  bool result = false;
158  if (_op == Instruction::CREATE)
159  result = e.createOpcode(myAddress, _endowment, gasPrice, io_gas, _code, origin);
160  else
161  {
162  assert(_op == Instruction::CREATE2);
163  result = e.create2Opcode(myAddress, _endowment, gasPrice, io_gas, _code, origin, _salt);
164  }
165 
166  if (!result)
167  {
168  go(depth, e, _onOp);
169  e.accrueSubState(sub);
170  }
171  io_gas = e.gas();
172  return {transactionExceptionToEvmcStatusCode(e.getException()), e.takeOutput(), e.newAddress()};
173 }
174 
176 {
177  // Why transfer is not used here? That caused a consensus issue before (see Quirk #2 in
178  // http://martin.swende.se/blog/Ethereum_quirks_and_vulns.html). There is one test case
179  // witnessing the current consensus
180  // 'GeneralStateTests/stSystemOperationsTest/suicideSendEtherPostDeath.json'.
181  m_s.addBalance(_a, m_s.balance(myAddress));
182  m_s.setBalance(myAddress, 0);
183  ExtVMFace::suicide(_a);
184 }
185 
187 {
188  u256 const currentNumber = envInfo().number();
189 
190  if (_number >= currentNumber || _number < (std::max<u256>(256, currentNumber) - 256))
191  return h256();
192 
193  if (currentNumber < m_sealEngine.chainParams().experimentalForkBlock + 256)
194  {
195  h256 const parentHash = envInfo().header().parentHash();
196  h256s const lastHashes = envInfo().lastHashes().precedingHashes(parentHash);
197 
198  assert(lastHashes.size() > (unsigned)(currentNumber - 1 - _number));
199  return lastHashes[(unsigned)(currentNumber - 1 - _number)];
200  }
201 
202  u256 const nonce = m_s.getNonce(caller);
203  u256 const gas = 1000000;
204  Transaction tx(0, 0, gas, c_blockhashContractAddress, toBigEndian(_number), nonce);
205  tx.forceSender(caller);
206 
207  ExecutionResult res;
208  std::tie(res, std::ignore) = m_s.execute(envInfo(), m_sealEngine, tx, Permanence::Reverted);
209  return h256(res.output);
210 }
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::Executive::go
bool go(OnOpFunc const &_onOp=OnOpFunc())
Definition: Executive.cpp:441
dev::eth::TransactionException::OutOfStack
@ OutOfStack
Ran out of stack executing code of the transaction.
dev::eth::ExtVMFace::suicide
virtual void suicide(Address)
Suicide the associated contract and give proceeds to the given address.
Definition: ExtVMFace.h:241
dev::eth::TransactionException::BadInstruction
@ BadInstruction
dev::eth::Transaction
Encodes a transaction, ready to be exported to or freshly imported from RLP.
Definition: Transaction.h:86
dev::toBigEndian
void toBigEndian(T _val, Out &o_out)
Definition: CommonData.h:124
dev::eth::ExtVMFace::sub
SubState sub
Sub-band VM state (suicides, refund counter, logs).
Definition: ExtVMFace.h:275
dev::eth::EnvInfo::header
BlockHeader const & header() const
Definition: ExtVMFace.h:157
dev::vector_ref< byte const >
dev::eth::ExtVM::setStore
void setStore(u256 _n, u256 _v) final
Write a value in storage.
Definition: ExtVM.cpp:149
dev::eth::Instruction::CREATE
@ CREATE
create a new account with associated code
dev::eth::ChainOperationParams::experimentalForkBlock
u256 experimentalForkBlock
Definition: ChainOperationParams.h:98
dev::eth::ExtVM::suicide
void suicide(Address _a) final
Suicide the associated contract to the given address.
Definition: ExtVM.cpp:175
dev::h256
FixedHash< 32 > h256
Definition: FixedHash.h:356
dev::eth::State::getNonce
u256 getNonce(Address const &_addr) const
Definition: State.cpp:414
dev::eth
Definition: BasicAuthority.h:32
dev::eth::SealEngineFace::chainParams
ChainOperationParams const & chainParams() const
Definition: SealEngine.h:80
dev::eth::State::codeSize
size_t codeSize(Address const &_contract) const
Definition: State.cpp:534
dev::eth::State::setBalance
void setBalance(Address const &_addr, u256 const &_value)
Definition: State.cpp:385
dev::FixedHash< 20 >
dev::eth::Permanence::Reverted
@ Reverted
dev::eth::State::addBalance
void addBalance(Address const &_id, u256 const &_amount)
Definition: State.cpp:346
dev::eth::ExtVMFace::myAddress
Address myAddress
Address associated with executing code (a contract, or contract-to-be).
Definition: ExtVMFace.h:266
dev::eth::ExtVMFace::gasPrice
u256 gasPrice
Price of gas (that we already paid).
Definition: ExtVMFace.h:270
dev::eth::ExtVM::exists
bool exists(Address _a) final
Does the account exist?
Definition: ExtVM.h:88
dev::h256s
std::vector< h256 > h256s
Definition: FixedHash.h:361
cnote
#define cnote
dev::eth::TransactionException::None
@ None
ExtVM.h
dev::eth::BlockHeader::parentHash
h256 const & parentHash() const
Definition: BlockHeader.h:157
dev::eth::ExtVMFace::depth
unsigned depth
Depth of the present call.
Definition: ExtVMFace.h:276
dev::eth::EnvInfo::lastHashes
LastBlockHashesFace const & lastHashes() const
Definition: ExtVMFace.h:164
dev::eth::Executive
Message-call/contract-creation executor; useful for executing transactions.
Definition: Executive.h:104
dev::eth::c_blockhashContractAddress
const Address c_blockhashContractAddress(0xf0)
Address of the special contract for block hash storage defined in EIP96.
Definition: Common.h:34
dev::eth::TransactionException
TransactionException
Definition: Transaction.h:36
dev::eth::ExtVM::codeSizeAt
size_t codeSizeAt(Address _a) final
Definition: ExtVM.cpp:139
dev::eth::Instruction
Instruction
Virtual machine bytecode instruction.
Definition: Instruction.h:29
dev::eth::ExtVMFace::caller
Address caller
Address which sent the message (either equal to origin or a contract).
Definition: ExtVMFace.h:267
dev::eth::State::setStorage
void setStorage(Address const &_contract, u256 const &_location, u256 const &_value)
Set the value of a storage position of an account.
Definition: State.cpp:430
LastBlockHashesFace.h
dev::eth::EnvInfo::number
int64_t number() const
Definition: ExtVMFace.h:159
dev::eth::CallParameters
Definition: ExtVMFace.h:118
dev::eth::ExtVM::call
CallResult call(CallParameters &_params) final
Create a new message call.
Definition: ExtVM.cpp:126
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::ExtVM::codeHashAt
h256 codeHashAt(Address _a) final
Definition: ExtVM.cpp:144
dev::eth::CreateResult
Definition: ExtVMFace.h:190
dev::eth::TransactionException::StackUnderflow
@ StackUnderflow
dev::eth::ExtVM::blockHash
h256 blockHash(u256 _number) final
Hash of a block if within the last 256 blocks, or h256() otherwise.
Definition: ExtVM.cpp:186
dev::eth::ExtVM::create
CreateResult create(u256 _endowment, u256 &io_gas, bytesConstRef _code, Instruction _op, u256 _salt, OnOpFunc const &_onOp={}) final
Create a new contract.
Definition: ExtVM.cpp:154
dev::eth::CallParameters::gas
u256 gas
Definition: ExtVMFace.h:136
dev::eth::CallParameters::onOp
OnOpFunc onOp
Definition: ExtVMFace.h:139
dev::eth::LastBlockHashesFace::precedingHashes
virtual h256s precedingHashes(h256 const &_mostRecentHash) const =0
dev
Definition: Address.cpp:21
dev::eth::State::balance
u256 balance(Address const &_id) const
Definition: State.cpp:312
dev::eth::TransactionException::RevertInstruction
@ RevertInstruction
dev::eth::State::codeHash
h256 codeHash(Address const &_contract) const
Definition: State.cpp:526
dev::eth::ExecutionResult
Description of the result of executing a transaction.
Definition: Transaction.h:71
dev::eth::ExtVMFace::envInfo
EnvInfo const & envInfo() const
Get the execution environment information.
Definition: ExtVMFace.h:256
dev::eth::TransactionException::OutOfGas
@ OutOfGas
Ran out of gas executing code of the transaction.
dev::eth::State::execute
std::pair< ExecutionResult, TransactionReceipt > execute(EnvInfo const &_envInfo, SealEngineFace const &_sealEngine, Transaction const &_t, Permanence _p=Permanence::Committed, OnOpFunc const &_onOp=OnOpFunc())
Definition: State.cpp:598
dev::eth::TransactionBase::forceSender
void forceSender(Address const &_a)
Force the sender to a particular value. This will result in an invalid transaction RLP.
Definition: TransactionBase.h:87
dev::eth::ExecutionResult::output
bytes output
Definition: Transaction.h:75
dev::eth::CallResult
Definition: ExtVMFace.h:177
dev::eth::Instruction::CREATE2
@ CREATE2
create a new account with associated code. sha3((sender + salt + code)
dev::eth::ExtVMFace::origin
Address origin
Original transactor.
Definition: ExtVMFace.h:268