Fabcoin Core  0.16.2
P2P Digital Currency
VMCalls.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 
19 #include <libethereum/ExtVM.h>
20 #include "VMConfig.h"
21 #include "VM.h"
22 using namespace std;
23 using namespace dev;
24 using namespace dev::eth;
25 
26 
27 
28 void VM::copyDataToMemory(bytesConstRef _data, u256*& _sp)
29 {
30  auto offset = static_cast<size_t>(*_sp--);
31  s512 bigIndex = *_sp--;
32  auto index = static_cast<size_t>(bigIndex);
33  auto size = static_cast<size_t>(*_sp--);
34 
35  size_t sizeToBeCopied = bigIndex + size > _data.size() ? _data.size() < bigIndex ? 0 : _data.size() - index : size;
36 
37  if (sizeToBeCopied > 0)
38  std::memcpy(m_mem.data() + offset, _data.data() + index, sizeToBeCopied);
39  if (size > sizeToBeCopied)
40  std::memset(m_mem.data() + offset + sizeToBeCopied, 0, size - sizeToBeCopied);
41 }
42 
43 
44 // consolidate exception throws to avoid spraying boost code all over interpreter
45 
46 void VM::throwOutOfGas()
47 {
48  BOOST_THROW_EXCEPTION(OutOfGas());
49 }
50 
51 void VM::throwBadInstruction()
52 {
53  BOOST_THROW_EXCEPTION(BadInstruction());
54 }
55 
56 void VM::throwBadJumpDestination()
57 {
58  BOOST_THROW_EXCEPTION(BadJumpDestination());
59 }
60 
61 void VM::throwBadStack(unsigned _size, unsigned _removed, unsigned _added)
62 {
63  if (_size < _removed)
64  {
65  if (m_onFail)
66  (this->*m_onFail)();
67  BOOST_THROW_EXCEPTION(StackUnderflow() << RequirementError((bigint)_removed, (bigint)_size));
68  }
69  if (_size - _removed + _added > 1024)
70  {
71  if (m_onFail)
72  (this->*m_onFail)();
73  BOOST_THROW_EXCEPTION(OutOfStack() << RequirementError((bigint)(_added - _removed), (bigint)_size));
74  }
75 }
76 
77 int64_t VM::verifyJumpDest(u256 const& _dest, bool _throw)
78 {
79 
80  // check for overflow
81  if (_dest <= 0x7FFFFFFFFFFFFFFF) {
82 
83  // check for within bounds and to a jump destination
84  // use binary search of array because hashtable collisions are exploitable
85  uint64_t pc = uint64_t(_dest);
86  if (std::binary_search(m_jumpDests.begin(), m_jumpDests.end(), pc))
87  return pc;
88  }
89  if (_throw)
90  throwBadJumpDestination();
91  return -1;
92 }
93 
94 
95 //
96 // interpreter cases that call out
97 //
98 
99 void VM::caseCreate()
100 {
101  m_bounce = &VM::interpretCases;
102  m_newMemSize = memNeed(*(m_SP - 1), *(m_SP - 2));
103  m_runGas = toInt63(m_schedule->createGas);
104  updateMem();
105  ON_OP();
106  updateIOGas();
107 
108  auto const& endowment = *m_SP--;
109  uint64_t initOff = (uint64_t)*m_SP--;
110  uint64_t initSize = (uint64_t)*m_SP--;
111 
112  if (endowment) BOOST_THROW_EXCEPTION(CreateWithValue());
113 
114  if (m_ext->balance(m_ext->myAddress) >= endowment && m_ext->depth < 1024)
115  {
116  *io_gas = m_io_gas;
117  u256 createGas = *io_gas;
118  if (!m_schedule->staticCallDepthLimit())
119  createGas -= createGas / 64;
120  u256 gas = createGas;
121  *++m_SP = (u160)m_ext->create(endowment, gas, bytesConstRef(m_mem.data() + initOff, initSize), m_onOp);
122  *io_gas -= (createGas - gas);
123  m_io_gas = uint64_t(*io_gas);
124  }
125  else
126  *++m_SP = 0;
127  ++m_PC;
128 }
129 
130 void VM::caseCall()
131 {
132  m_bounce = &VM::interpretCases;
133  unique_ptr<CallParameters> callParams(new CallParameters());
134  bytesRef output;
135  if (caseCallSetup(callParams.get(), output))
136  {
137  if (boost::optional<owning_bytes_ref> r = m_ext->call(*callParams))
138  {
139  r->copyTo(output);
140  *++m_SP = 1;
141  }
142  else
143  *++m_SP = 0;
144  }
145  else
146  *++m_SP = 0;
147  m_io_gas += uint64_t(callParams->gas);
148  ++m_PC;
149 }
150 
151 bool VM::caseCallSetup(CallParameters *callParams, bytesRef& o_output)
152 {
153  m_runGas = toInt63(m_schedule->callGas);
154 
155  if (m_OP == Instruction::CALL && !m_ext->exists(asAddress(*(m_SP - 1))))
156  if (*(m_SP - 2) > 0 || m_schedule->zeroValueTransferChargesNewAccountGas())
157  m_runGas += toInt63(m_schedule->callNewAccountGas);
158 
159  if (m_OP != Instruction::DELEGATECALL && *(m_SP - 2) > 0)
160  m_runGas += toInt63(m_schedule->callValueTransferGas);
161 
162  size_t sizesOffset = m_OP == Instruction::DELEGATECALL ? 3 : 4;
163  u256 inputOffset = m_stack[(1 + m_SP - m_stack) - sizesOffset];
164  u256 inputSize = m_stack[(1 + m_SP - m_stack) - sizesOffset - 1];
165  u256 outputOffset = m_stack[(1 + m_SP - m_stack) - sizesOffset - 2];
166  u256 outputSize = m_stack[(1 + m_SP - m_stack) - sizesOffset - 3];
167  uint64_t inputMemNeed = memNeed(inputOffset, inputSize);
168  uint64_t outputMemNeed = memNeed(outputOffset, outputSize);
169 
170  m_newMemSize = std::max(inputMemNeed, outputMemNeed);
171  updateMem();
172  updateIOGas();
173 
174  // "Static" costs already applied. Calculate call gas.
175  if (m_schedule->staticCallDepthLimit())
176  // With static call depth limit we just charge the provided gas amount.
177  callParams->gas = *m_SP;
178  else
179  {
180  // Apply "all but one 64th" rule.
181  u256 maxAllowedCallGas = m_io_gas - m_io_gas / 64;
182  callParams->gas = std::min(*m_SP, maxAllowedCallGas);
183  }
184 
185  m_runGas = toInt63(callParams->gas);
186  ON_OP();
187  updateIOGas();
188 
189  if (m_OP != Instruction::DELEGATECALL && *(m_SP - 2) > 0)
190  callParams->gas += m_schedule->callStipend;
191  --m_SP;
192 
193  callParams->codeAddress = asAddress(*m_SP);
194  --m_SP;
195 
196  if (m_OP == Instruction::DELEGATECALL)
197  {
198  callParams->apparentValue = m_ext->value;
199  callParams->valueTransfer = 0;
200  }
201  else
202  {
203  callParams->apparentValue = callParams->valueTransfer = *m_SP;
204  --m_SP;
205  }
206 
207  uint64_t inOff = (uint64_t)*m_SP--;
208  uint64_t inSize = (uint64_t)*m_SP--;
209  uint64_t outOff = (uint64_t)*m_SP--;
210  uint64_t outSize = (uint64_t)*m_SP--;
211 
212  if (m_ext->balance(m_ext->myAddress) >= callParams->valueTransfer && m_ext->depth < 1024)
213  {
214  callParams->onOp = m_onOp;
215  callParams->senderAddress = m_OP == Instruction::DELEGATECALL ? m_ext->caller : m_ext->myAddress;
216  callParams->receiveAddress = m_OP == Instruction::CALL ? callParams->codeAddress : m_ext->myAddress;
217  callParams->data = bytesConstRef(m_mem.data() + inOff, inSize);
218  o_output = bytesRef(m_mem.data() + outOff, outSize);
219  return true;
220  }
221  else
222  return false;
223 }
224 
Adapted from code found on http://stackoverflow.com/questions/180947/base64-decode-snippet-in-c Origi...
Definition: Arith256.cpp:15
boost::multiprecision::number< boost::multiprecision::cpp_int_backend<>> bigint
Definition: Common.h:121
std::hash for asio::adress
Definition: Common.h:323
Ran out of stack executing code of the transaction.
ExecStats::duration min
Definition: ExecStats.cpp:35
boost::multiprecision::number< boost::multiprecision::cpp_int_backend< 160, 160, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void >> u160
Definition: Common.h:127
vector_ref< byte > bytesRef
Definition: Common.h:76
#define ON_OP()
Definition: VMConfig.h:108
vector_ref< byte const > bytesConstRef
Definition: Common.h:77
boost::multiprecision::number< boost::multiprecision::cpp_int_backend< 256, 256, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void >> u256
Definition: Common.h:125
size_t size() const
Definition: vector_ref.h:55
_T * data() const
Definition: vector_ref.h:51
uint8_t const size_t const size
Definition: sha3.h:20
void * memcpy(void *a, const void *b, size_t c)
Address asAddress(u256 _item)
Definition: VM.h:39
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:69
dev::WithExisting max(dev::WithExisting _a, dev::WithExisting _b)
Definition: Common.h:326
boost::tuple< errinfo_required, errinfo_got > RequirementError
Definition: Exceptions.h:80
boost::multiprecision::number< boost::multiprecision::cpp_int_backend< 512, 512, boost::multiprecision::signed_magnitude, boost::multiprecision::unchecked, void >> s512
Definition: Common.h:130