10 changed files with 374 additions and 257 deletions
@ -0,0 +1,187 @@ |
|||
/*
|
|||
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 Executive.cpp
|
|||
* @author Gav Wood <i@gavwood.com> |
|||
* @date 2014 |
|||
*/ |
|||
|
|||
#include "Executive.h" |
|||
#include "State.h" |
|||
#include "ExtVM.h" |
|||
#include "VM.h" |
|||
using namespace std; |
|||
using namespace eth; |
|||
|
|||
Executive::~Executive() |
|||
{ |
|||
// TODO: Make safe.
|
|||
delete m_ext; |
|||
delete m_vm; |
|||
} |
|||
|
|||
void Executive::setup(bytesConstRef _rlp) |
|||
{ |
|||
// Entry point for a user-executed transaction.
|
|||
m_t = Transaction(_rlp); |
|||
|
|||
auto sender = m_t.sender(); |
|||
|
|||
// Avoid invalid transactions.
|
|||
auto nonceReq = m_s.transactionsFrom(sender); |
|||
if (m_t.nonce != nonceReq) |
|||
{ |
|||
clog(StateChat) << "Invalid Nonce."; |
|||
throw InvalidNonce(nonceReq, m_t.nonce); |
|||
} |
|||
|
|||
// Don't like transactions whose gas price is too low. NOTE: this won't stay here forever - it's just until we get a proper gas price discovery protocol going.
|
|||
if (m_t.gasPrice < 10 * szabo) |
|||
{ |
|||
clog(StateChat) << "Offered gas-price is too low."; |
|||
throw GasPriceTooLow(); |
|||
} |
|||
|
|||
// Check gas cost is enough.
|
|||
u256 gasCost = m_t.data.size() * c_txDataGas + c_txGas; |
|||
|
|||
if (m_t.gas < gasCost) |
|||
{ |
|||
clog(StateChat) << "Not enough gas to pay for the transaction."; |
|||
throw OutOfGas(); |
|||
} |
|||
|
|||
m_startGas = m_t.gas; |
|||
|
|||
u256 cost = m_t.value + m_t.gas * m_t.gasPrice; |
|||
|
|||
// Avoid unaffordable transactions.
|
|||
if (m_s.balance(sender) < cost) |
|||
{ |
|||
clog(StateChat) << "Not enough cash."; |
|||
throw NotEnoughCash(); |
|||
} |
|||
|
|||
// Increment associated nonce for sender.
|
|||
m_s.noteSending(sender); |
|||
|
|||
// Pay...
|
|||
// cnote << "Paying" << formatBalance(cost) << "from sender (includes" << m_t.gas << "gas at" << formatBalance(m_t.gasPrice) << ")";
|
|||
m_s.subBalance(sender, cost); |
|||
|
|||
if (m_t.isCreation()) |
|||
create(sender, m_t.value, m_t.gasPrice, m_t.gas - gasCost, &m_t.data, sender); |
|||
else |
|||
call(m_t.receiveAddress, sender, m_t.value, m_t.gasPrice, bytesConstRef(&m_t.data), m_t.gas - gasCost, sender); |
|||
} |
|||
|
|||
void Executive::call(Address _receiveAddress, Address _senderAddress, u256 _value, u256 _gasPrice, bytesConstRef _data, u256 _gas, Address _originAddress) |
|||
{ |
|||
// cnote << "Transferring" << formatBalance(_value) << "to receiver.";
|
|||
m_s.addBalance(_receiveAddress, _value); |
|||
|
|||
if (m_s.addressHasCode(_receiveAddress)) |
|||
{ |
|||
m_vm = new VM(_gas); |
|||
m_ext = new ExtVM(m_s, _receiveAddress, _senderAddress, _originAddress, _value, _gasPrice, _data, &m_s.code(_receiveAddress)); |
|||
} |
|||
else |
|||
m_endGas = _gas; |
|||
} |
|||
|
|||
void Executive::create(Address _sender, u256 _endowment, u256 _gasPrice, u256 _gas, bytesConstRef _init, Address _origin) |
|||
{ |
|||
m_newAddress = right160(sha3(rlpList(_sender, m_s.transactionsFrom(_sender) - 1))); |
|||
while (m_s.addressInUse(m_newAddress)) |
|||
m_newAddress = (u160)m_newAddress + 1; |
|||
|
|||
// Set up new account...
|
|||
m_s.m_cache[m_newAddress] = AddressState(0, 0, h256(), h256()); |
|||
|
|||
// Execute _init.
|
|||
m_vm = new VM(_gas); |
|||
m_ext = new ExtVM(m_s, m_newAddress, _sender, _origin, _endowment, _gasPrice, _init, _init); |
|||
} |
|||
|
|||
bool Executive::go(uint64_t _steps) |
|||
{ |
|||
if (m_vm) |
|||
{ |
|||
bool revert = false; |
|||
try |
|||
{ |
|||
m_out = m_vm->go(*m_ext, _steps); |
|||
m_endGas = m_vm->gas(); |
|||
} |
|||
catch (StepsDone const&) |
|||
{ |
|||
return false; |
|||
} |
|||
catch (OutOfGas const& /*_e*/) |
|||
{ |
|||
clog(StateChat) << "Out of Gas! Reverting."; |
|||
revert = true; |
|||
} |
|||
catch (VMException const& _e) |
|||
{ |
|||
clog(StateChat) << "VM Exception: " << _e.description(); |
|||
} |
|||
catch (Exception const& _e) |
|||
{ |
|||
clog(StateChat) << "Exception in VM: " << _e.description(); |
|||
} |
|||
catch (std::exception const& _e) |
|||
{ |
|||
clog(StateChat) << "std::exception in VM: " << _e.what(); |
|||
} |
|||
|
|||
// Write state out only in the case of a non-excepted transaction.
|
|||
if (revert) |
|||
{ |
|||
m_ext->revert(); |
|||
if (m_newAddress) |
|||
{ |
|||
m_s.m_cache.erase(m_newAddress); |
|||
m_newAddress = Address(); |
|||
} |
|||
} |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
u256 Executive::gas() const |
|||
{ |
|||
return m_vm->gas(); |
|||
} |
|||
|
|||
void Executive::finalize() |
|||
{ |
|||
// cnote << "Refunding" << formatBalance(m_endGas * m_ext->gasPrice) << "to origin (=" << m_endGas << "*" << formatBalance(m_ext->gasPrice) << ")";
|
|||
m_s.addBalance(m_ext->origin, m_endGas * m_ext->gasPrice); |
|||
|
|||
if (m_t.isCreation() && m_newAddress && m_out.size()) |
|||
// non-reverted creation - put code in place.
|
|||
m_s.m_cache[m_newAddress].setCode(m_out); |
|||
|
|||
u256 gasSpent = (m_startGas - m_endGas) * m_ext->gasPrice; |
|||
/* unsigned c_feesKept = 8;
|
|||
u256 feesEarned = gasSpent - (gasSpent / c_feesKept); |
|||
cnote << "Transferring" << (100.0 - 100.0 / c_feesKept) << "% of" << formatBalance(gasSpent) << "=" << formatBalance(feesEarned) << "to miner (" << formatBalance(gasSpent - feesEarned) << "is burnt)."; |
|||
*/ |
|||
u256 feesEarned = gasSpent; |
|||
// cnote << "Transferring" << formatBalance(gasSpent) << "to miner.";
|
|||
m_s.addBalance(m_s.m_currentBlock.coinbaseAddress, feesEarned); |
|||
} |
@ -0,0 +1,70 @@ |
|||
/*
|
|||
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 Executive.h
|
|||
* @author Gav Wood <i@gavwood.com> |
|||
* @date 2014 |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
#include "CommonEth.h" |
|||
#include "Transaction.h" |
|||
|
|||
namespace eth |
|||
{ |
|||
|
|||
class VM; |
|||
class ExtVM; |
|||
class State; |
|||
|
|||
class Executive |
|||
{ |
|||
public: |
|||
Executive(State& _s): m_s(_s) {} |
|||
~Executive(); |
|||
|
|||
void setup(bytesConstRef _transaction); |
|||
void create(Address _txSender, u256 _endowment, u256 _gasPrice, u256 _gas, bytesConstRef _code, Address _originAddress); |
|||
void call(Address _myAddress, Address _txSender, u256 _txValue, u256 _gasPrice, bytesConstRef _txData, u256 _gas, Address _originAddress); |
|||
bool go(uint64_t _steps = (unsigned)-1); |
|||
void finalize(); |
|||
|
|||
Transaction const& t() const { return m_t; } |
|||
|
|||
u256 gas() const; |
|||
|
|||
bytesConstRef out() const { return m_out; } |
|||
h160 newAddress() const { return m_newAddress; } |
|||
|
|||
VM const& vm() const { return *m_vm; } |
|||
State const& state() const { return m_s; } |
|||
ExtVM const& ext() const { return *m_ext; } |
|||
|
|||
private: |
|||
State& m_s; |
|||
ExtVM* m_ext = nullptr; // TODO: make safe.
|
|||
VM* m_vm = nullptr; |
|||
bytesConstRef m_out; |
|||
Address m_newAddress; |
|||
|
|||
Transaction m_t; |
|||
|
|||
u256 m_startGas; |
|||
u256 m_endGas; |
|||
}; |
|||
|
|||
} |
@ -0,0 +1,22 @@ |
|||
/*
|
|||
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 ExtVM.cpp
|
|||
* @author Gav Wood <i@gavwood.com> |
|||
* @date 2014 |
|||
*/ |
|||
|
|||
#include "ExtVM.h" |
@ -0,0 +1,86 @@ |
|||
/*
|
|||
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 ExtVM.h
|
|||
* @author Gav Wood <i@gavwood.com> |
|||
* @date 2014 |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
#include <map> |
|||
#include "CommonEth.h" |
|||
#include "State.h" |
|||
#include "ExtVMFace.h" |
|||
|
|||
namespace eth |
|||
{ |
|||
|
|||
// TODO: Document
|
|||
class ExtVM: public ExtVMFace |
|||
{ |
|||
public: |
|||
ExtVM(State& _s, Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytesConstRef _code): |
|||
ExtVMFace(_myAddress, _caller, _origin, _value, _gasPrice, _data, _code, _s.m_previousBlock, _s.m_currentBlock, _s.m_currentNumber), m_s(_s), m_origCache(_s.m_cache) |
|||
{ |
|||
m_s.ensureCached(_myAddress, true, true); |
|||
} |
|||
|
|||
u256 store(u256 _n) |
|||
{ |
|||
return m_s.storage(myAddress, _n); |
|||
} |
|||
void setStore(u256 _n, u256 _v) |
|||
{ |
|||
m_s.setStorage(myAddress, _n, _v); |
|||
} |
|||
|
|||
h160 create(u256 _endowment, u256* _gas, bytesConstRef _code) |
|||
{ |
|||
// Increment associated nonce for sender.
|
|||
m_s.noteSending(myAddress); |
|||
|
|||
return m_s.create(myAddress, _endowment, gasPrice, _gas, _code, origin); |
|||
} |
|||
|
|||
bool call(Address _receiveAddress, u256 _txValue, bytesConstRef _txData, u256* _gas, bytesRef _out) |
|||
{ |
|||
return m_s.call(_receiveAddress, myAddress, _txValue, gasPrice, _txData, _gas, _out, origin); |
|||
} |
|||
|
|||
u256 balance(Address _a) { return m_s.balance(_a); } |
|||
void subBalance(u256 _a) { m_s.subBalance(myAddress, _a); } |
|||
u256 txCount(Address _a) { return m_s.transactionsFrom(_a); } |
|||
void suicide(Address _a) |
|||
{ |
|||
m_s.addBalance(_a, m_s.balance(myAddress)); |
|||
m_s.m_cache[myAddress].kill(); |
|||
} |
|||
|
|||
void revert() |
|||
{ |
|||
m_s.m_cache = m_origCache; |
|||
} |
|||
|
|||
private: |
|||
State& m_s; |
|||
std::map<Address, AddressState> m_origCache; |
|||
std::map<u256, u256>* m_store; |
|||
}; |
|||
|
|||
} |
|||
|
|||
|
Loading…
Reference in new issue