Ethereum  PoC-8
The C++ Implementation of Ethereum
LegacyVMCalls.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 "LegacyVM.h"
19 
20 using namespace std;
21 using namespace dev;
22 using namespace dev::eth;
23 
24 
25 void LegacyVM::copyDataToMemory(bytesConstRef _data, u256*_sp)
26 {
27  auto offset = static_cast<size_t>(_sp[0]);
28  s512 bigIndex = _sp[1];
29  auto index = static_cast<size_t>(bigIndex);
30  auto size = static_cast<size_t>(_sp[2]);
31 
32  size_t sizeToBeCopied = bigIndex + size > _data.size() ? _data.size() < bigIndex ? 0 : _data.size() - index : size;
33 
34  if (sizeToBeCopied > 0)
35  std::memcpy(m_mem.data() + offset, _data.data() + index, sizeToBeCopied);
36  if (size > sizeToBeCopied)
37  std::memset(m_mem.data() + offset + sizeToBeCopied, 0, size - sizeToBeCopied);
38 }
39 
40 
41 // consolidate exception throws to avoid spraying boost code all over interpreter
42 
43 void LegacyVM::throwOutOfGas()
44 {
45  BOOST_THROW_EXCEPTION(OutOfGas());
46 }
47 
48 void LegacyVM::throwBadInstruction()
49 {
50  BOOST_THROW_EXCEPTION(BadInstruction());
51 }
52 
53 void LegacyVM::throwBadJumpDestination()
54 {
55  BOOST_THROW_EXCEPTION(BadJumpDestination());
56 }
57 
58 void LegacyVM::throwDisallowedStateChange()
59 {
60  BOOST_THROW_EXCEPTION(DisallowedStateChange());
61 }
62 
63 // throwBadStack is called from fetchInstruction() -> adjustStack()
64 // its the only exception that can happen before ON_OP() log is done for an opcode case in VM.cpp
65 // so the call to m_onFail is needed here
66 void LegacyVM::throwBadStack(unsigned _removed, unsigned _added)
67 {
68  bigint size = m_stackEnd - m_SPP;
69  if (size < _removed)
70  {
71  if (m_onFail)
72  (this->*m_onFail)();
73  BOOST_THROW_EXCEPTION(StackUnderflow() << RequirementError((bigint)_removed, size));
74  }
75  else
76  {
77  if (m_onFail)
78  (this->*m_onFail)();
79  BOOST_THROW_EXCEPTION(OutOfStack() << RequirementError((bigint)(_added - _removed), size));
80  }
81 }
82 
83 void LegacyVM::throwRevertInstruction(owning_bytes_ref&& _output)
84 {
85  // We can't use BOOST_THROW_EXCEPTION here because it makes a copy of exception inside and RevertInstruction has no copy constructor
86  throw RevertInstruction(move(_output));
87 }
88 
89 void LegacyVM::throwBufferOverrun(bigint const& _endOfAccess)
90 {
91  // todo: disable this m_onFail, may result in duplicate log step in the trace
92  if (m_onFail)
93  (this->*m_onFail)();
94  BOOST_THROW_EXCEPTION(BufferOverrun() << RequirementError(_endOfAccess, bigint(m_returnData.size())));
95 }
96 
97 int64_t LegacyVM::verifyJumpDest(u256 const& _dest, bool _throw)
98 {
99  // check for overflow
100  if (_dest <= 0x7FFFFFFFFFFFFFFF) {
101 
102  // check for within bounds and to a jump destination
103  // use binary search of array because hashtable collisions are exploitable
104  uint64_t pc = uint64_t(_dest);
105  if (std::binary_search(m_jumpDests.begin(), m_jumpDests.end(), pc))
106  return pc;
107  }
108  if (_throw)
109  throwBadJumpDestination();
110  return -1;
111 }
112 
113 
114 //
115 // interpreter cases that call out
116 //
117 
118 void LegacyVM::caseCreate()
119 {
120  m_bounce = &LegacyVM::interpretCases;
121  m_runGas = toInt63(m_schedule->createGas);
122 
123  // Collect arguments.
124  u256 const endowment = m_SP[0];
125  u256 const initOff = m_SP[1];
126  u256 const initSize = m_SP[2];
127 
128  u256 salt;
129  if (m_OP == Instruction::CREATE2)
130  {
131  salt = m_SP[3];
132  // charge for hashing initCode = GSHA3WORD * ceil(len(init_code) / 32)
133  m_runGas += toInt63((u512{initSize} + 31) / 32 * m_schedule->sha3WordGas);
134  }
135 
136  updateMem(memNeed(initOff, initSize));
137  updateIOGas();
138 
139  // Clear the return data buffer. This will not free the memory.
140  m_returnData.clear();
141 
142  if (m_ext->balance(m_ext->myAddress) >= endowment && m_ext->depth < 1024)
143  {
144  *m_io_gas_p = m_io_gas;
145  u256 createGas = *m_io_gas_p;
146  if (!m_schedule->staticCallDepthLimit())
147  createGas -= createGas / 64;
148  u256 gas = createGas;
149 
150  // Get init code. Casts are safe because the memory cost has been paid.
151  auto off = static_cast<size_t>(initOff);
152  auto size = static_cast<size_t>(initSize);
153  bytesConstRef initCode{m_mem.data() + off, size};
154 
155 
156  CreateResult result = m_ext->create(endowment, gas, initCode, m_OP, salt, m_onOp);
157  m_SPP[0] = (u160)result.address; // Convert address to integer.
158  m_returnData = result.output.toBytes();
159 
160  *m_io_gas_p -= (createGas - gas);
161  m_io_gas = uint64_t(*m_io_gas_p);
162  }
163  else
164  m_SPP[0] = 0;
165  ++m_PC;
166 }
167 
168 void LegacyVM::caseCall()
169 {
170  m_bounce = &LegacyVM::interpretCases;
171 
172  // TODO: Please check if that does not actually increases the stack size.
173  // That was the case before.
174  unique_ptr<CallParameters> callParams(new CallParameters());
175 
176  // Clear the return data buffer. This will not free the memory.
177  m_returnData.clear();
178 
179  bytesRef output;
180  if (caseCallSetup(callParams.get(), output))
181  {
182  CallResult result = m_ext->call(*callParams);
183  result.output.copyTo(output);
184 
185  // Here we have 2 options:
186  // 1. Keep the whole returned memory buffer (owning_bytes_ref):
187  // higher memory footprint, no memory copy.
188  // 2. Copy only the return data from the returned memory buffer:
189  // minimal memory footprint, additional memory copy.
190  // Option 2 used:
191  m_returnData = result.output.toBytes();
192 
193  m_SPP[0] = result.status == EVMC_SUCCESS ? 1 : 0;
194  }
195  else
196  m_SPP[0] = 0;
197  m_io_gas += uint64_t(callParams->gas);
198  ++m_PC;
199 }
200 
201 bool LegacyVM::caseCallSetup(CallParameters *callParams, bytesRef& o_output)
202 {
203  // Make sure the params were properly initialized.
204  assert(callParams->valueTransfer == 0);
205  assert(callParams->apparentValue == 0);
206 
207  m_runGas = toInt63(m_schedule->callGas);
208 
209  callParams->staticCall = (m_OP == Instruction::STATICCALL || m_ext->staticCall);
210 
211  bool const haveValueArg = m_OP == Instruction::CALL || m_OP == Instruction::CALLCODE;
212 
213  Address destinationAddr = asAddress(m_SP[1]);
214  if (m_OP == Instruction::CALL && !m_ext->exists(destinationAddr))
215  if (m_SP[2] > 0 || m_schedule->zeroValueTransferChargesNewAccountGas())
216  m_runGas += toInt63(m_schedule->callNewAccountGas);
217 
218  if (haveValueArg && m_SP[2] > 0)
219  m_runGas += toInt63(m_schedule->callValueTransferGas);
220 
221  size_t const sizesOffset = haveValueArg ? 3 : 2;
222  u256 inputOffset = m_SP[sizesOffset];
223  u256 inputSize = m_SP[sizesOffset + 1];
224  u256 outputOffset = m_SP[sizesOffset + 2];
225  u256 outputSize = m_SP[sizesOffset + 3];
226  uint64_t inputMemNeed = memNeed(inputOffset, inputSize);
227  uint64_t outputMemNeed = memNeed(outputOffset, outputSize);
228 
229  m_newMemSize = std::max(inputMemNeed, outputMemNeed);
230  updateMem(m_newMemSize);
231  updateIOGas();
232 
233  // "Static" costs already applied. Calculate call gas.
234  if (m_schedule->staticCallDepthLimit())
235  {
236  // With static call depth limit we just charge the provided gas amount.
237  callParams->gas = m_SP[0];
238  }
239  else
240  {
241  // Apply "all but one 64th" rule.
242  u256 maxAllowedCallGas = m_io_gas - m_io_gas / 64;
243  callParams->gas = std::min(m_SP[0], maxAllowedCallGas);
244  }
245 
246  m_runGas = toInt63(callParams->gas);
247  updateIOGas();
248 
249  if (haveValueArg && m_SP[2] > 0)
250  callParams->gas += m_schedule->callStipend;
251 
252  callParams->codeAddress = destinationAddr;
253 
254  if (haveValueArg)
255  {
256  callParams->valueTransfer = m_SP[2];
257  callParams->apparentValue = m_SP[2];
258  }
259  else if (m_OP == Instruction::DELEGATECALL)
260  // Forward VALUE.
261  callParams->apparentValue = m_ext->value;
262 
263  uint64_t inOff = (uint64_t)inputOffset;
264  uint64_t inSize = (uint64_t)inputSize;
265  uint64_t outOff = (uint64_t)outputOffset;
266  uint64_t outSize = (uint64_t)outputSize;
267 
268  if (m_ext->balance(m_ext->myAddress) >= callParams->valueTransfer && m_ext->depth < 1024)
269  {
270  callParams->onOp = m_onOp;
271  callParams->senderAddress = m_OP == Instruction::DELEGATECALL ? m_ext->caller : m_ext->myAddress;
272  callParams->receiveAddress = (m_OP == Instruction::CALL || m_OP == Instruction::STATICCALL) ? callParams->codeAddress : m_ext->myAddress;
273  callParams->data = bytesConstRef(m_mem.data() + inOff, inSize);
274  o_output = bytesRef(m_mem.data() + outOff, outSize);
275  return true;
276  }
277  return false;
278 }
dev::eth::TransactionException::OutOfStack
@ OutOfStack
Ran out of stack executing code of the transaction.
dev::eth::TransactionException::BadInstruction
@ BadInstruction
dev::eth::CreateResult::address
h160 address
Definition: ExtVMFace.h:193
dev::vector_ref< byte const >
dev::eth::CallResult::output
owning_bytes_ref output
Definition: ExtVMFace.h:179
dev::vector_ref::copyTo
void copyTo(vector_ref< typename std::remove_const< _T >::type > _t) const
Copies the contents of this vector_ref to the contents of _t, up to the max size of _t.
Definition: vector_ref.h:67
dev::u512
boost::multiprecision::number< boost::multiprecision::cpp_int_backend< 512, 512, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void > > u512
Definition: Common.h:125
dev::eth::CallParameters::staticCall
bool staticCall
Definition: ExtVMFace.h:138
dev::eth::CallParameters::codeAddress
Address codeAddress
Definition: ExtVMFace.h:132
dev::eth::owning_bytes_ref
Definition: ExtVMFace.h:58
dev::eth
Definition: BasicAuthority.h:32
dev::FixedHash< 20 >
dev::eth::CallParameters::apparentValue
u256 apparentValue
Definition: ExtVMFace.h:135
dev::eth::CreateResult::output
owning_bytes_ref output
Definition: ExtVMFace.h:192
dev::eth::CallResult::status
evmc_status_code status
Definition: ExtVMFace.h:178
dev::vector_ref::data
_T * data() const
Definition: vector_ref.h:49
dev::u160
boost::multiprecision::number< boost::multiprecision::cpp_int_backend< 160, 160, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void > > u160
Definition: Common.h:123
dev::eth::CallParameters::valueTransfer
u256 valueTransfer
Definition: ExtVMFace.h:134
dev::vector_ref::size
size_t size() const
Definition: vector_ref.h:53
dev::eth::CallParameters::senderAddress
Address senderAddress
Definition: ExtVMFace.h:131
dev::bytesRef
vector_ref< byte > bytesRef
Definition: Common.h:73
dev::bigint
boost::multiprecision::number< boost::multiprecision::cpp_int_backend<> > bigint
Definition: Common.h:118
dev::eth::CallParameters::data
bytesConstRef data
Definition: ExtVMFace.h:137
LegacyVM.h
dev::vector_ref::toBytes
std::vector< unsigned char > toBytes() const
Definition: vector_ref.h:43
dev::eth::CallParameters
Definition: ExtVMFace.h:118
std
Definition: FixedHash.h:393
dev::eth::asAddress
Address asAddress(u256 _item)
Helpers:
Definition: VMFace.h:79
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::CreateResult
Definition: ExtVMFace.h:190
dev::eth::TransactionException::StackUnderflow
@ StackUnderflow
dev::eth::CallParameters::gas
u256 gas
Definition: ExtVMFace.h:136
dev::eth::CallParameters::onOp
OnOpFunc onOp
Definition: ExtVMFace.h:139
dev
Definition: Address.cpp:21
dev::RequirementError
boost::tuple< errinfo_required, errinfo_got > RequirementError
Definition: Exceptions.h:87
dev::eth::TransactionException::OutOfGas
@ OutOfGas
Ran out of gas executing code of the transaction.
dev::eth::CallParameters::receiveAddress
Address receiveAddress
Definition: ExtVMFace.h:133
dev::eth::RevertInstruction
Definition: VMFace.h:46
dev::s512
boost::multiprecision::number< boost::multiprecision::cpp_int_backend< 512, 512, boost::multiprecision::signed_magnitude, boost::multiprecision::unchecked, void > > s512
Definition: Common.h:126
dev::eth::CallResult
Definition: ExtVMFace.h:177