Gav Wood
11 years ago
7 changed files with 817 additions and 599 deletions
@ -0,0 +1,49 @@ |
|||
/*
|
|||
This file is part of cpp-ethereum. |
|||
|
|||
cpp-ethereum is free software: you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation, either version 3 of the License, or |
|||
(at your option) any later version. |
|||
|
|||
cpp-ethereum is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
|||
*/ |
|||
/** @file FeeStructure.cpp
|
|||
* @author Gav Wood <i@gavwood.com> |
|||
* @date 2014 |
|||
*/ |
|||
|
|||
#include "FeeStructure.h" |
|||
|
|||
using namespace std; |
|||
using namespace eth; |
|||
|
|||
u256 const c_stepFee = 1; |
|||
u256 const c_dataFee = 20; |
|||
u256 const c_memoryFee = 0;//5; memoryFee is 0 for PoC-3
|
|||
u256 const c_extroFee = 40; |
|||
u256 const c_cryptoFee = 20; |
|||
u256 const c_newContractFee = 100; |
|||
u256 const c_txFee = 100; |
|||
|
|||
void FeeStructure::setMultiplier(u256 _x) |
|||
{ |
|||
m_stepFee = c_stepFee * _x; |
|||
m_dataFee = c_dataFee * _x; |
|||
m_memoryFee = c_memoryFee * _x; |
|||
m_extroFee = c_extroFee * _x; |
|||
m_cryptoFee = c_cryptoFee * _x; |
|||
m_newContractFee = c_newContractFee * _x; |
|||
m_txFee = c_txFee * _x; |
|||
} |
|||
|
|||
u256 FeeStructure::multiplier() const |
|||
{ |
|||
return m_stepFee / c_stepFee; |
|||
} |
@ -0,0 +1,43 @@ |
|||
/*
|
|||
This file is part of cpp-ethereum. |
|||
|
|||
cpp-ethereum is free software: you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation, either version 3 of the License, or |
|||
(at your option) any later version. |
|||
|
|||
cpp-ethereum is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
|||
*/ |
|||
/** @file FeeStructure.h
|
|||
* @author Gav Wood <i@gavwood.com> |
|||
* @date 2014 |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
#include "Common.h" |
|||
|
|||
namespace eth |
|||
{ |
|||
|
|||
struct FeeStructure |
|||
{ |
|||
/// The fee structure. Values yet to be agreed on...
|
|||
void setMultiplier(u256 _x); ///< The current block multiplier.
|
|||
u256 multiplier() const; |
|||
u256 m_stepFee; |
|||
u256 m_dataFee; |
|||
u256 m_memoryFee; |
|||
u256 m_extroFee; |
|||
u256 m_cryptoFee; |
|||
u256 m_newContractFee; |
|||
u256 m_txFee; |
|||
}; |
|||
|
|||
} |
@ -0,0 +1,60 @@ |
|||
/*
|
|||
This file is part of cpp-ethereum. |
|||
|
|||
cpp-ethereum is free software: you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation, either version 3 of the License, or |
|||
(at your option) any later version. |
|||
|
|||
cpp-ethereum is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
|||
*/ |
|||
/** @file VM.cpp
|
|||
* @author Gav Wood <i@gavwood.com> |
|||
* @date 2014 |
|||
*/ |
|||
|
|||
#include "VM.h" |
|||
|
|||
#include <secp256k1.h> |
|||
#include <boost/filesystem.hpp> |
|||
#if WIN32 |
|||
#pragma warning(push) |
|||
#pragma warning(disable:4244) |
|||
#else |
|||
#pragma GCC diagnostic ignored "-Wunused-function" |
|||
#endif |
|||
#include <sha.h> |
|||
#include <sha3.h> |
|||
#include <ripemd.h> |
|||
#if WIN32 |
|||
#pragma warning(pop) |
|||
#else |
|||
#endif |
|||
#include <ctime> |
|||
#include <random> |
|||
#include "BlockChain.h" |
|||
#include "Instruction.h" |
|||
#include "Exceptions.h" |
|||
#include "Dagger.h" |
|||
#include "Defaults.h" |
|||
using namespace std; |
|||
using namespace eth; |
|||
|
|||
VM::VM() |
|||
{ |
|||
reset(); |
|||
} |
|||
|
|||
void VM::reset() |
|||
{ |
|||
m_curPC = 0; |
|||
m_nextPC = 1; |
|||
m_stepCount = 0; |
|||
m_runFee = 0; |
|||
} |
@ -0,0 +1,592 @@ |
|||
/*
|
|||
This file is part of cpp-ethereum. |
|||
|
|||
cpp-ethereum is free software: you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation, either version 3 of the License, or |
|||
(at your option) any later version. |
|||
|
|||
cpp-ethereum is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
|||
*/ |
|||
/** @file VM.h
|
|||
* @author Gav Wood <i@gavwood.com> |
|||
* @date 2014 |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
#include <unordered_map> |
|||
#include <secp256k1.h> |
|||
#if WIN32 |
|||
#pragma warning(push) |
|||
#pragma warning(disable:4244) |
|||
#else |
|||
#pragma GCC diagnostic ignored "-Wunused-function" |
|||
#endif |
|||
#include <sha.h> |
|||
#include <sha3.h> |
|||
#include <ripemd.h> |
|||
#if WIN32 |
|||
#pragma warning(pop) |
|||
#else |
|||
#endif |
|||
#include "Common.h" |
|||
#include "Exceptions.h" |
|||
#include "FeeStructure.h" |
|||
#include "Instruction.h" |
|||
#include "BlockInfo.h" |
|||
#include "ExtVMFace.h" |
|||
|
|||
namespace eth |
|||
{ |
|||
|
|||
// Convert from a 256-bit integer stack/memory entry into a 160-bit Address hash.
|
|||
// Currently we just pull out the right (low-order in BE) 160-bits.
|
|||
inline Address asAddress(u256 _item) |
|||
{ |
|||
return right160(h256(_item)); |
|||
} |
|||
|
|||
inline u256 fromAddress(Address _a) |
|||
{ |
|||
return (u160)_a; |
|||
} |
|||
|
|||
/**
|
|||
*/ |
|||
class VM |
|||
{ |
|||
template <unsigned T> friend class UnitTest; |
|||
|
|||
public: |
|||
/// Construct VM object.
|
|||
VM(); |
|||
|
|||
void reset(); |
|||
|
|||
template <class Ext> |
|||
void go(Ext& _ext, uint64_t _steps = (uint64_t)-1); |
|||
|
|||
void require(u256 _n) { if (m_stack.size() < _n) throw StackTooSmall(_n, m_stack.size()); } |
|||
u256 runFee() const { return m_runFee; } |
|||
|
|||
private: |
|||
u256 m_curPC = 0; |
|||
u256 m_nextPC = 1; |
|||
uint64_t m_stepCount = 0; |
|||
std::map<u256, u256> m_temp; |
|||
std::vector<u256> m_stack; |
|||
u256 m_runFee = 0; |
|||
}; |
|||
|
|||
} |
|||
|
|||
// INLINE:
|
|||
template <class Ext> void eth::VM::go(Ext& _ext, uint64_t _steps) |
|||
{ |
|||
for (bool stopped = false; !stopped && _steps--; m_curPC = m_nextPC, m_nextPC = m_curPC + 1) |
|||
{ |
|||
m_stepCount++; |
|||
|
|||
// INSTRUCTION...
|
|||
auto rawInst = _ext.store(m_curPC); |
|||
if (rawInst > 0xff) |
|||
throw BadInstruction(); |
|||
Instruction inst = (Instruction)(uint8_t)rawInst; |
|||
|
|||
// FEES...
|
|||
bigint runFee = m_stepCount > 16 ? _ext.fees.m_stepFee : 0; |
|||
bigint storeCostDelta = 0; |
|||
switch (inst) |
|||
{ |
|||
case Instruction::SSTORE: |
|||
require(2); |
|||
if (!_ext.store(m_stack.back()) && m_stack[m_stack.size() - 2]) |
|||
storeCostDelta += _ext.fees.m_memoryFee; |
|||
if (_ext.store(m_stack.back()) && !m_stack[m_stack.size() - 2]) |
|||
storeCostDelta -= _ext.fees.m_memoryFee; |
|||
// continue on to...
|
|||
case Instruction::SLOAD: |
|||
runFee += _ext.fees.m_dataFee; |
|||
break; |
|||
|
|||
case Instruction::EXTRO: |
|||
case Instruction::BALANCE: |
|||
runFee += _ext.fees.m_extroFee; |
|||
break; |
|||
|
|||
case Instruction::MKTX: |
|||
runFee += _ext.fees.m_txFee; |
|||
break; |
|||
|
|||
case Instruction::SHA256: |
|||
case Instruction::RIPEMD160: |
|||
case Instruction::ECMUL: |
|||
case Instruction::ECADD: |
|||
case Instruction::ECSIGN: |
|||
case Instruction::ECRECOVER: |
|||
case Instruction::ECVALID: |
|||
runFee += _ext.fees.m_cryptoFee; |
|||
break; |
|||
default: |
|||
break; |
|||
} |
|||
_ext.payFee(runFee + storeCostDelta); |
|||
m_runFee += (u256)runFee; |
|||
|
|||
// EXECUTE...
|
|||
switch (inst) |
|||
{ |
|||
case Instruction::ADD: |
|||
//pops two items and pushes S[-1] + S[-2] mod 2^256.
|
|||
require(2); |
|||
m_stack[m_stack.size() - 2] += m_stack.back(); |
|||
m_stack.pop_back(); |
|||
break; |
|||
case Instruction::MUL: |
|||
//pops two items and pushes S[-1] * S[-2] mod 2^256.
|
|||
require(2); |
|||
m_stack[m_stack.size() - 2] *= m_stack.back(); |
|||
m_stack.pop_back(); |
|||
break; |
|||
case Instruction::SUB: |
|||
require(2); |
|||
m_stack[m_stack.size() - 2] = m_stack.back() - m_stack[m_stack.size() - 2]; |
|||
m_stack.pop_back(); |
|||
break; |
|||
case Instruction::DIV: |
|||
require(2); |
|||
m_stack[m_stack.size() - 2] = m_stack.back() / m_stack[m_stack.size() - 2]; |
|||
m_stack.pop_back(); |
|||
break; |
|||
case Instruction::SDIV: |
|||
require(2); |
|||
(s256&)m_stack[m_stack.size() - 2] = (s256&)m_stack.back() / (s256&)m_stack[m_stack.size() - 2]; |
|||
m_stack.pop_back(); |
|||
break; |
|||
case Instruction::MOD: |
|||
require(2); |
|||
m_stack[m_stack.size() - 2] = m_stack.back() % m_stack[m_stack.size() - 2]; |
|||
m_stack.pop_back(); |
|||
break; |
|||
case Instruction::SMOD: |
|||
require(2); |
|||
(s256&)m_stack[m_stack.size() - 2] = (s256&)m_stack.back() % (s256&)m_stack[m_stack.size() - 2]; |
|||
m_stack.pop_back(); |
|||
break; |
|||
case Instruction::EXP: |
|||
{ |
|||
// TODO: better implementation?
|
|||
require(2); |
|||
auto n = m_stack.back(); |
|||
auto x = m_stack[m_stack.size() - 2]; |
|||
m_stack.pop_back(); |
|||
for (u256 i = 0; i < x; ++i) |
|||
n *= n; |
|||
m_stack.back() = n; |
|||
break; |
|||
} |
|||
case Instruction::NEG: |
|||
require(1); |
|||
m_stack.back() = ~(m_stack.back() - 1); |
|||
break; |
|||
case Instruction::LT: |
|||
require(2); |
|||
m_stack[m_stack.size() - 2] = m_stack.back() < m_stack[m_stack.size() - 2] ? 1 : 0; |
|||
m_stack.pop_back(); |
|||
break; |
|||
case Instruction::LE: |
|||
require(2); |
|||
m_stack[m_stack.size() - 2] = m_stack.back() <= m_stack[m_stack.size() - 2] ? 1 : 0; |
|||
m_stack.pop_back(); |
|||
break; |
|||
case Instruction::GT: |
|||
require(2); |
|||
m_stack[m_stack.size() - 2] = m_stack.back() > m_stack[m_stack.size() - 2] ? 1 : 0; |
|||
m_stack.pop_back(); |
|||
break; |
|||
case Instruction::GE: |
|||
require(2); |
|||
m_stack[m_stack.size() - 2] = m_stack.back() >= m_stack[m_stack.size() - 2] ? 1 : 0; |
|||
m_stack.pop_back(); |
|||
break; |
|||
case Instruction::EQ: |
|||
require(2); |
|||
m_stack[m_stack.size() - 2] = m_stack.back() == m_stack[m_stack.size() - 2] ? 1 : 0; |
|||
m_stack.pop_back(); |
|||
break; |
|||
case Instruction::NOT: |
|||
require(1); |
|||
m_stack.back() = m_stack.back() ? 0 : 1; |
|||
m_stack.pop_back(); |
|||
break; |
|||
case Instruction::MYADDRESS: |
|||
m_stack.push_back(fromAddress(_ext.myAddress)); |
|||
break; |
|||
case Instruction::TXSENDER: |
|||
m_stack.push_back(fromAddress(_ext.txSender)); |
|||
break; |
|||
case Instruction::TXVALUE: |
|||
m_stack.push_back(_ext.txValue); |
|||
break; |
|||
case Instruction::TXDATAN: |
|||
m_stack.push_back(_ext.txData.size()); |
|||
break; |
|||
case Instruction::TXDATA: |
|||
require(1); |
|||
m_stack.back() = m_stack.back() < _ext.txData.size() ? _ext.txData[(uint)m_stack.back()] : 0; |
|||
break; |
|||
case Instruction::BLK_PREVHASH: |
|||
m_stack.push_back(_ext.previousBlock.hash); |
|||
break; |
|||
case Instruction::BLK_COINBASE: |
|||
m_stack.push_back((u160)_ext.currentBlock.coinbaseAddress); |
|||
break; |
|||
case Instruction::BLK_TIMESTAMP: |
|||
m_stack.push_back(_ext.currentBlock.timestamp); |
|||
break; |
|||
case Instruction::BLK_NUMBER: |
|||
m_stack.push_back(_ext.currentNumber); |
|||
break; |
|||
case Instruction::BLK_DIFFICULTY: |
|||
m_stack.push_back(_ext.currentBlock.difficulty); |
|||
break; |
|||
case Instruction::BLK_NONCE: |
|||
m_stack.push_back(_ext.previousBlock.nonce); |
|||
break; |
|||
case Instruction::BASEFEE: |
|||
m_stack.push_back(_ext.fees.multiplier()); |
|||
break; |
|||
case Instruction::SHA256: |
|||
{ |
|||
uint s = (uint)std::min(m_stack.back(), (u256)(m_stack.size() - 1) * 32); |
|||
m_stack.pop_back(); |
|||
|
|||
CryptoPP::SHA256 digest; |
|||
uint i = 0; |
|||
for (; s; s = (s >= 32 ? s - 32 : 0), i += 32) |
|||
{ |
|||
bytes b = toBigEndian(m_stack.back()); |
|||
digest.Update(b.data(), (int)std::min<u256>(32, s)); // b.size() == 32
|
|||
m_stack.pop_back(); |
|||
} |
|||
std::array<byte, 32> final; |
|||
digest.TruncatedFinal(final.data(), 32); |
|||
m_stack.push_back(fromBigEndian<u256>(final)); |
|||
break; |
|||
} |
|||
case Instruction::RIPEMD160: |
|||
{ |
|||
uint s = (uint)std::min(m_stack.back(), (u256)(m_stack.size() - 1) * 32); |
|||
m_stack.pop_back(); |
|||
|
|||
CryptoPP::RIPEMD160 digest; |
|||
uint i = 0; |
|||
for (; s; s = (s >= 32 ? s - 32 : 0), i += 32) |
|||
{ |
|||
bytes b = toBigEndian(m_stack.back()); |
|||
digest.Update(b.data(), (int)std::min<u256>(32, s)); // b.size() == 32
|
|||
m_stack.pop_back(); |
|||
} |
|||
std::array<byte, 20> final; |
|||
digest.TruncatedFinal(final.data(), 20); |
|||
// NOTE: this aligns to right of 256-bit container (low-order bytes).
|
|||
// This won't work if they're treated as byte-arrays and thus left-aligned in a 256-bit container.
|
|||
m_stack.push_back((u256)fromBigEndian<u160>(final)); |
|||
break; |
|||
} |
|||
case Instruction::ECMUL: |
|||
{ |
|||
// ECMUL - pops three items.
|
|||
// If (S[-2],S[-1]) are a valid point in secp256k1, including both coordinates being less than P, pushes (S[-1],S[-2]) * S[-3], using (0,0) as the point at infinity.
|
|||
// Otherwise, pushes (0,0).
|
|||
require(3); |
|||
|
|||
bytes pub(1, 4); |
|||
pub += toBigEndian(m_stack[m_stack.size() - 2]); |
|||
pub += toBigEndian(m_stack.back()); |
|||
m_stack.pop_back(); |
|||
m_stack.pop_back(); |
|||
|
|||
bytes x = toBigEndian(m_stack.back()); |
|||
m_stack.pop_back(); |
|||
|
|||
if (secp256k1_ecdsa_pubkey_verify(pub.data(), (int)pub.size())) // TODO: Check both are less than P.
|
|||
{ |
|||
secp256k1_ecdsa_pubkey_tweak_mul(pub.data(), (int)pub.size(), x.data()); |
|||
m_stack.push_back(fromBigEndian<u256>(bytesConstRef(&pub).cropped(1, 32))); |
|||
m_stack.push_back(fromBigEndian<u256>(bytesConstRef(&pub).cropped(33, 32))); |
|||
} |
|||
else |
|||
{ |
|||
m_stack.push_back(0); |
|||
m_stack.push_back(0); |
|||
} |
|||
break; |
|||
} |
|||
case Instruction::ECADD: |
|||
{ |
|||
// ECADD - pops four items and pushes (S[-4],S[-3]) + (S[-2],S[-1]) if both points are valid, otherwise (0,0).
|
|||
require(4); |
|||
|
|||
bytes pub(1, 4); |
|||
pub += toBigEndian(m_stack[m_stack.size() - 2]); |
|||
pub += toBigEndian(m_stack.back()); |
|||
m_stack.pop_back(); |
|||
m_stack.pop_back(); |
|||
|
|||
bytes tweak(1, 4); |
|||
tweak += toBigEndian(m_stack[m_stack.size() - 2]); |
|||
tweak += toBigEndian(m_stack.back()); |
|||
m_stack.pop_back(); |
|||
m_stack.pop_back(); |
|||
|
|||
if (secp256k1_ecdsa_pubkey_verify(pub.data(),(int) pub.size()) && secp256k1_ecdsa_pubkey_verify(tweak.data(),(int) tweak.size())) |
|||
{ |
|||
secp256k1_ecdsa_pubkey_tweak_add(pub.data(), (int)pub.size(), tweak.data()); |
|||
m_stack.push_back(fromBigEndian<u256>(bytesConstRef(&pub).cropped(1, 32))); |
|||
m_stack.push_back(fromBigEndian<u256>(bytesConstRef(&pub).cropped(33, 32))); |
|||
} |
|||
else |
|||
{ |
|||
m_stack.push_back(0); |
|||
m_stack.push_back(0); |
|||
} |
|||
break; |
|||
} |
|||
case Instruction::ECSIGN: |
|||
{ |
|||
require(2); |
|||
bytes sig(64); |
|||
int v = 0; |
|||
|
|||
u256 msg = m_stack.back(); |
|||
m_stack.pop_back(); |
|||
u256 priv = m_stack.back(); |
|||
m_stack.pop_back(); |
|||
bytes nonce = toBigEndian(Transaction::kFromMessage(msg, priv)); |
|||
|
|||
if (!secp256k1_ecdsa_sign_compact(toBigEndian(msg).data(), 64, sig.data(), toBigEndian(priv).data(), nonce.data(), &v)) |
|||
throw InvalidSignature(); |
|||
|
|||
m_stack.push_back(v + 27); |
|||
m_stack.push_back(fromBigEndian<u256>(bytesConstRef(&sig).cropped(0, 32))); |
|||
m_stack.push_back(fromBigEndian<u256>(bytesConstRef(&sig).cropped(32))); |
|||
break; |
|||
} |
|||
case Instruction::ECRECOVER: |
|||
{ |
|||
require(4); |
|||
|
|||
bytes sig = toBigEndian(m_stack[m_stack.size() - 2]) + toBigEndian(m_stack.back()); |
|||
m_stack.pop_back(); |
|||
m_stack.pop_back(); |
|||
int v = (int)m_stack.back(); |
|||
m_stack.pop_back(); |
|||
bytes msg = toBigEndian(m_stack.back()); |
|||
m_stack.pop_back(); |
|||
|
|||
byte pubkey[65]; |
|||
int pubkeylen = 65; |
|||
if (secp256k1_ecdsa_recover_compact(msg.data(), (int)msg.size(), sig.data(), pubkey, &pubkeylen, 0, v - 27)) |
|||
{ |
|||
m_stack.push_back(0); |
|||
m_stack.push_back(0); |
|||
} |
|||
else |
|||
{ |
|||
m_stack.push_back(fromBigEndian<u256>(bytesConstRef(&pubkey[1], 32))); |
|||
m_stack.push_back(fromBigEndian<u256>(bytesConstRef(&pubkey[33], 32))); |
|||
} |
|||
break; |
|||
} |
|||
case Instruction::ECVALID: |
|||
{ |
|||
require(2); |
|||
bytes pub(1, 4); |
|||
pub += toBigEndian(m_stack[m_stack.size() - 2]); |
|||
pub += toBigEndian(m_stack.back()); |
|||
m_stack.pop_back(); |
|||
m_stack.pop_back(); |
|||
|
|||
m_stack.back() = secp256k1_ecdsa_pubkey_verify(pub.data(), (int)pub.size()) ? 1 : 0; |
|||
break; |
|||
} |
|||
case Instruction::SHA3: |
|||
{ |
|||
uint s = (uint)std::min(m_stack.back(), (u256)(m_stack.size() - 1) * 32); |
|||
m_stack.pop_back(); |
|||
|
|||
CryptoPP::SHA3_256 digest; |
|||
uint i = 0; |
|||
for (; s; s = (s >= 32 ? s - 32 : 0), i += 32) |
|||
{ |
|||
bytes b = toBigEndian(m_stack.back()); |
|||
digest.Update(b.data(), (int)std::min<u256>(32, s)); // b.size() == 32
|
|||
m_stack.pop_back(); |
|||
} |
|||
std::array<byte, 32> final; |
|||
digest.TruncatedFinal(final.data(), 32); |
|||
m_stack.push_back(fromBigEndian<u256>(final)); |
|||
break; |
|||
} |
|||
case Instruction::PUSH: |
|||
{ |
|||
m_stack.push_back(_ext.store(m_curPC + 1)); |
|||
m_nextPC = m_curPC + 2; |
|||
break; |
|||
} |
|||
case Instruction::POP: |
|||
require(1); |
|||
m_stack.pop_back(); |
|||
break; |
|||
case Instruction::DUP: |
|||
require(1); |
|||
m_stack.push_back(m_stack.back()); |
|||
break; |
|||
/*case Instruction::DUPN:
|
|||
{ |
|||
auto s = store(curPC + 1); |
|||
if (s == 0 || s > stack.size()) |
|||
throw OperandOutOfRange(1, stack.size(), s); |
|||
stack.push_back(stack[stack.size() - (uint)s]); |
|||
nextPC = curPC + 2; |
|||
break; |
|||
}*/ |
|||
case Instruction::SWAP: |
|||
{ |
|||
require(2); |
|||
auto d = m_stack.back(); |
|||
m_stack.back() = m_stack[m_stack.size() - 2]; |
|||
m_stack[m_stack.size() - 2] = d; |
|||
break; |
|||
} |
|||
/*case Instruction::SWAPN:
|
|||
{ |
|||
require(1); |
|||
auto d = stack.back(); |
|||
auto s = store(curPC + 1); |
|||
if (s == 0 || s > stack.size()) |
|||
throw OperandOutOfRange(1, stack.size(), s); |
|||
stack.back() = stack[stack.size() - (uint)s]; |
|||
stack[stack.size() - (uint)s] = d; |
|||
nextPC = curPC + 2; |
|||
break; |
|||
}*/ |
|||
case Instruction::MLOAD: |
|||
{ |
|||
require(1); |
|||
#ifdef __clang__ |
|||
auto mFinder = tempMem.find(stack.back()); |
|||
if (mFinder != tempMem.end()) |
|||
stack.back() = mFinder->second; |
|||
else |
|||
stack.back() = 0; |
|||
#else |
|||
m_stack.back() = m_temp[m_stack.back()]; |
|||
#endif |
|||
break; |
|||
} |
|||
case Instruction::MSTORE: |
|||
{ |
|||
require(2); |
|||
#ifdef __clang__ |
|||
auto mFinder = tempMem.find(stack.back()); |
|||
if (mFinder == tempMem.end()) |
|||
tempMem.insert(make_pair(stack.back(), stack[stack.size() - 2])); |
|||
else |
|||
mFinder->second = stack[stack.size() - 2]; |
|||
#else |
|||
m_temp[m_stack.back()] = m_stack[m_stack.size() - 2]; |
|||
#endif |
|||
m_stack.pop_back(); |
|||
m_stack.pop_back(); |
|||
break; |
|||
} |
|||
case Instruction::SLOAD: |
|||
require(1); |
|||
m_stack.back() = _ext.store(m_stack.back()); |
|||
break; |
|||
case Instruction::SSTORE: |
|||
require(2); |
|||
_ext.setStore(m_stack.back(), m_stack[m_stack.size() - 2]); |
|||
m_stack.pop_back(); |
|||
m_stack.pop_back(); |
|||
break; |
|||
case Instruction::JMP: |
|||
require(1); |
|||
m_nextPC = m_stack.back(); |
|||
m_stack.pop_back(); |
|||
break; |
|||
case Instruction::JMPI: |
|||
require(2); |
|||
if (m_stack.back()) |
|||
m_nextPC = m_stack[m_stack.size() - 2]; |
|||
m_stack.pop_back(); |
|||
m_stack.pop_back(); |
|||
break; |
|||
case Instruction::IND: |
|||
m_stack.push_back(m_curPC); |
|||
break; |
|||
case Instruction::EXTRO: |
|||
{ |
|||
require(2); |
|||
auto memoryAddress = m_stack.back(); |
|||
m_stack.pop_back(); |
|||
Address contractAddress = asAddress(m_stack.back()); |
|||
m_stack.back() = _ext.extro(contractAddress, memoryAddress); |
|||
break; |
|||
} |
|||
case Instruction::BALANCE: |
|||
{ |
|||
require(1); |
|||
m_stack.back() = _ext.balance(asAddress(m_stack.back())); |
|||
break; |
|||
} |
|||
case Instruction::MKTX: |
|||
{ |
|||
require(3); |
|||
|
|||
Transaction t; |
|||
t.receiveAddress = asAddress(m_stack.back()); |
|||
m_stack.pop_back(); |
|||
t.value = m_stack.back(); |
|||
m_stack.pop_back(); |
|||
|
|||
auto itemCount = m_stack.back(); |
|||
m_stack.pop_back(); |
|||
if (m_stack.size() < itemCount) |
|||
throw OperandOutOfRange(0, m_stack.size(), itemCount); |
|||
t.data.reserve((uint)itemCount); |
|||
for (auto i = 0; i < itemCount; ++i) |
|||
{ |
|||
t.data.push_back(m_stack.back()); |
|||
m_stack.pop_back(); |
|||
} |
|||
|
|||
_ext.mktx(t); |
|||
break; |
|||
} |
|||
case Instruction::SUICIDE: |
|||
{ |
|||
require(1); |
|||
Address dest = asAddress(m_stack.back()); |
|||
_ext.suicide(dest); |
|||
// ...follow through to...
|
|||
} |
|||
case Instruction::STOP: |
|||
return; |
|||
default: |
|||
throw BadInstruction(); |
|||
} |
|||
} |
|||
if (_steps == (unsigned)-1) |
|||
throw StepsDone(); |
|||
} |
|||
|
Loading…
Reference in new issue