Browse Source

Merge branch 'debugger' into develop

cl-refactor
Gav Wood 11 years ago
parent
commit
6437a38d8a
  1. 289
      alethzero/Main.ui
  2. 141
      alethzero/MainWin.cpp
  3. 11
      alethzero/MainWin.h
  4. 163
      libethereum/State.cpp
  5. 39
      libethereum/State.h
  6. 3
      libethereum/VM.cpp
  7. 29
      libethereum/VM.h

289
alethzero/Main.ui

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>1504</width>
<height>798</height>
<width>1711</width>
<height>1138</height>
</rect>
</property>
<property name="windowTitle">
@ -83,11 +83,6 @@
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_4">
<attribute name="title">
<string>Tab 2</string>
</attribute>
</widget>
</widget>
</item>
</layout>
@ -99,7 +94,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>1504</width>
<width>1711</width>
<height>20</height>
</rect>
</property>
@ -131,9 +126,18 @@
</property>
<addaction name="about"/>
</widget>
<widget class="QMenu" name="menu_Debug">
<property name="title">
<string>&amp;Debug</string>
</property>
<addaction name="enableDebug"/>
<addaction name="debugStep"/>
<addaction name="debugContinue"/>
</widget>
<addaction name="menu_File"/>
<addaction name="menu_Network"/>
<addaction name="menu_Tools"/>
<addaction name="menu_Debug"/>
<addaction name="menu_Help"/>
</widget>
<widget class="QStatusBar" name="statusbar"/>
@ -403,7 +407,7 @@
</property>
<property name="minimumSize">
<size>
<width>442</width>
<width>510</width>
<height>360</height>
</size>
</property>
@ -437,29 +441,26 @@
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label5_2">
<property name="text">
<string>&amp;Amount</string>
</property>
<property name="buddy">
<cstring>value</cstring>
<item row="5" column="0" colspan="4">
<widget class="QSplitter" name="splitter_5">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<widget class="QPlainTextEdit" name="data"/>
<widget class="QTextEdit" name="code">
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
</widget>
</widget>
</item>
<item row="3" column="3">
<widget class="QComboBox" name="gasPriceUnits"/>
</item>
<item row="2" column="1" colspan="2">
<widget class="QSpinBox" name="value">
<property name="suffix">
<string/>
</property>
<property name="maximum">
<number>430000000</number>
<item row="3" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>&amp;Gas</string>
</property>
<property name="value">
<number>0</number>
<property name="buddy">
<cstring>gas</cstring>
</property>
</widget>
</item>
@ -479,32 +480,6 @@
</property>
</widget>
</item>
<item row="5" column="0" colspan="4">
<widget class="QSplitter" name="splitter_5">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<widget class="QPlainTextEdit" name="data"/>
<widget class="QTextEdit" name="code">
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
</widget>
</widget>
</item>
<item row="3" column="2">
<widget class="QSpinBox" name="gasPrice">
<property name="prefix">
<string>@ </string>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>430000000</number>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QSpinBox" name="gas">
<property name="suffix">
@ -521,21 +496,11 @@
</property>
</widget>
</item>
<item row="2" column="3">
<widget class="QComboBox" name="valueUnits"/>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>&amp;Gas</string>
</property>
<property name="buddy">
<cstring>gas</cstring>
</property>
</widget>
<item row="3" column="3">
<widget class="QComboBox" name="gasPriceUnits"/>
</item>
<item row="4" column="1" colspan="3">
<widget class="QLabel" name="fee">
<item row="6" column="0" colspan="3">
<widget class="QLabel" name="total">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
<horstretch>0</horstretch>
@ -545,28 +510,34 @@
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="6" column="3">
<widget class="QPushButton" name="send">
<property name="text">
<string>&amp;Send</string>
<item row="2" column="3">
<widget class="QComboBox" name="valueUnits"/>
</item>
<item row="3" column="2">
<widget class="QSpinBox" name="gasPrice">
<property name="prefix">
<string>@ </string>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>430000000</number>
</property>
</widget>
</item>
<item row="6" column="0" colspan="3">
<widget class="QLabel" name="total">
<item row="0" column="1" colspan="3">
<widget class="QLineEdit" name="destination">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string/>
<property name="placeholderText">
<string>(Create Contract)</string>
</property>
</widget>
</item>
@ -583,16 +554,49 @@
</property>
</widget>
</item>
<item row="0" column="1" colspan="3">
<widget class="QLineEdit" name="destination">
<item row="6" column="3">
<widget class="QPushButton" name="send">
<property name="text">
<string>&amp;Execute</string>
</property>
</widget>
</item>
<item row="2" column="1" colspan="2">
<widget class="QSpinBox" name="value">
<property name="suffix">
<string/>
</property>
<property name="maximum">
<number>430000000</number>
</property>
<property name="value">
<number>0</number>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label5_2">
<property name="text">
<string>&amp;Amount</string>
</property>
<property name="buddy">
<cstring>value</cstring>
</property>
</widget>
</item>
<item row="4" column="1" colspan="3">
<widget class="QLabel" name="fee">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>1</horstretch>
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="placeholderText">
<string>(Create Contract)</string>
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
@ -820,6 +824,87 @@
</layout>
</widget>
</widget>
<widget class="QDockWidget" name="dockWidget_9">
<property name="features">
<set>QDockWidget::DockWidgetFeatureMask</set>
</property>
<property name="windowTitle">
<string>Debugger</string>
</property>
<attribute name="dockWidgetArea">
<number>8</number>
</attribute>
<widget class="QWidget" name="debugPanel">
<property name="enabled">
<bool>false</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="QSplitter" name="splitter_6">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<widget class="QListWidget" name="debugCode">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
<widget class="QSplitter" name="splitter_4">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<widget class="QListWidget" name="debugStack">
<property name="selectionMode">
<enum>QAbstractItemView::NoSelection</enum>
</property>
</widget>
<widget class="QTextEdit" name="debugMemory">
<property name="readOnly">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::NoTextInteraction</set>
</property>
</widget>
<widget class="QTextEdit" name="debugStorage">
<property name="readOnly">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::NoTextInteraction</set>
</property>
</widget>
</widget>
</widget>
</item>
<item>
<widget class="QLabel" name="debugStateInfo">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
<action name="quit">
<property name="text">
<string>&amp;Quit</string>
@ -875,6 +960,36 @@
<string>&amp;Preview</string>
</property>
</action>
<action name="enableDebug">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>&amp;Debug EVM Execution</string>
</property>
</action>
<action name="debugStep">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>&amp;Single Step</string>
</property>
<property name="shortcut">
<string>F10</string>
</property>
</action>
<action name="debugContinue">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>&amp;Continue</string>
</property>
<property name="shortcut">
<string>F5</string>
</property>
</action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<customwidgets>

141
alethzero/MainWin.cpp

@ -9,6 +9,7 @@
#include <libethereum/Client.h>
#include <libethereum/Instruction.h>
#include <libethereum/PeerServer.h>
#include <libethereum/VM.h>
#include "BuildInfo.h"
#include "MainWin.h"
#include "ui_Main.h"
@ -31,6 +32,7 @@ using eth::PeerInfo;
using eth::RLP;
using eth::Secret;
using eth::Transaction;
using eth::Executive;
// functions
using eth::toHex;
@ -702,8 +704,8 @@ void Main::on_contracts_currentItemChanged()
auto h = h160((byte const*)hba.data(), h160::ConstructFromPointer);
stringstream s;
auto mem = state().contractStorage(h);
for (auto const& i: mem)
auto storage = state().contractStorage(h);
for (auto const& i: storage)
s << "@" << showbase << hex << i.first << "&nbsp;&nbsp;&nbsp;&nbsp;" << showbase << hex << i.second << "<br/>";
s << "<h4>Body Code</h4>" << disassemble(state().contractCode(h));
ui->contractInfo->appendHtml(QString::fromStdString(s.str()));
@ -929,11 +931,42 @@ void Main::on_send_clicked()
{
m_client->unlock();
Secret s = i.secret();
if (isCreation())
m_client->transact(s, value(), m_data, m_init, ui->gas->value(), gasPrice());
if (ui->enableDebug->isChecked())
{
m_client->lock();
m_executiveState = state();
m_client->unlock();
m_currentExecution = unique_ptr<Executive>(new Executive(m_executiveState));
Transaction t;
t.nonce = m_executiveState.transactionsFrom(toAddress(s));
t.value = value();
t.gasPrice = gasPrice();
t.gas = ui->gas->value();
t.data = m_data;
if (isCreation())
{
t.receiveAddress = Address();
t.init = m_init;
}
else
{
t.receiveAddress = fromString(ui->destination->text());
t.data = m_data;
}
t.sign(s);
auto r = t.rlp();
m_currentExecution->setup(&r);
initDebugger();
updateDebugger();
}
else
m_client->transact(s, value(), fromString(ui->destination->text()), m_data, ui->gas->value(), gasPrice());
refresh();
{
if (isCreation())
m_client->transact(s, value(), m_data, m_init, ui->gas->value(), gasPrice());
else
m_client->transact(s, value(), fromString(ui->destination->text()), m_data, ui->gas->value(), gasPrice());
refresh();
}
return;
}
m_client->unlock();
@ -946,6 +979,102 @@ void Main::on_create_triggered()
m_keysChanged = true;
}
void Main::on_enableDebug_triggered()
{
ui->debugPanel->setEnabled(ui->enableDebug->isChecked());
ui->send->setText(ui->enableDebug->isChecked() ? "D&ebug" : "&Execute");
}
void Main::on_debugStep_triggered()
{
if (!m_currentExecution)
return;
if (m_currentExecution->go(1))
debugFinished();
else
updateDebugger();
}
void Main::on_debugContinue_triggered()
{
if (!m_currentExecution)
return;
if (m_currentExecution->go())
debugFinished();
else
updateDebugger();
}
void Main::debugFinished()
{
m_currentExecution.reset();
ui->debugCode->clear();
ui->debugStack->clear();
ui->debugMemory->setHtml("");
ui->debugStorage->setHtml("");
ui->debugStateInfo->setText("");
ui->send->setEnabled(true);
ui->enableDebug->setEnabled(true);
ui->debugStep->setEnabled(false);
ui->debugContinue->setEnabled(false);
ui->debugPanel->setEnabled(false);
}
void Main::initDebugger()
{
ui->send->setEnabled(false);
ui->enableDebug->setEnabled(false);
ui->debugStep->setEnabled(true);
ui->debugContinue->setEnabled(true);
ui->debugPanel->setEnabled(true);
ui->debugCode->setEnabled(false);
QListWidget* dc = ui->debugCode;
dc->clear();
if (m_currentExecution)
{
for (unsigned i = 0; i <= m_currentExecution->ext().code.size(); ++i)
{
byte b = i < m_currentExecution->ext().code.size() ? m_currentExecution->ext().code[i] : 0;
QString s = c_instructionInfo.at((Instruction)b).name;
m_pcWarp[i] = dc->count();
ostringstream out;
out << hex << setw(4) << setfill('0') << i;
if (b >= (byte)Instruction::PUSH1 && b <= (byte)Instruction::PUSH32)
{
unsigned bc = b - (byte)Instruction::PUSH1 + 1;
s = "PUSH 0x" + QString::fromStdString(toHex(bytesConstRef(&m_currentExecution->ext().code[i + 1], bc)));
i += bc;
}
dc->addItem(QString::fromStdString(out.str()) + " " + s);
}
}
}
void Main::updateDebugger()
{
QListWidget* ds = ui->debugStack;
ds->clear();
if (m_currentExecution)
{
eth::VM const& vm = m_currentExecution->vm();
for (auto i: vm.stack())
ds->insertItem(0, QString::fromStdString(toHex(((h256)i).asArray())));
ui->debugMemory->setHtml(QString::fromStdString(htmlDump(vm.memory(), 16)));
ui->debugCode->setCurrentRow(m_pcWarp[(unsigned)vm.curPC()]);
ostringstream ss;
ss << hex << "PC: 0x" << vm.curPC() << " | GAS: 0x" << vm.gas();
ui->debugStateInfo->setText(QString::fromStdString(ss.str()));
stringstream s;
auto storage = m_currentExecution->state().contractStorage(m_currentExecution->ext().myAddress);
for (auto const& i: storage)
s << "@" << showbase << hex << i.first << "&nbsp;&nbsp;&nbsp;&nbsp;" << showbase << hex << i.second << "<br/>";
ui->debugStorage->setHtml(QString::fromStdString(s.str()));
}
}
// extra bits needed to link on VS
#ifdef _MSC_VER

11
alethzero/MainWin.h

@ -7,6 +7,7 @@
#include <QtCore/QMutex>
#include <QtWidgets/QMainWindow>
#include <libethereum/CommonEth.h>
#include <libethereum/State.h>
#include <libethereum/RLP.h>
namespace Ui {
@ -287,6 +288,9 @@ private slots:
void on_preview_triggered() { refresh(true); }
void on_quit_triggered() { close(); }
void on_urlEdit_editingFinished();
void on_debugStep_triggered();
void on_debugContinue_triggered();
void on_enableDebug_triggered();
void refresh(bool _override = false);
void refreshNetwork();
@ -297,6 +301,9 @@ signals:
private:
QString pretty(eth::Address _a) const;
void initDebugger();
void updateDebugger();
void debugFinished();
QString render(eth::Address _a) const;
eth::Address fromString(QString const& _a) const;
@ -329,6 +336,10 @@ private:
unsigned m_backupGas;
eth::State m_executiveState;
std::unique_ptr<eth::Executive> m_currentExecution;
QMap<unsigned, unsigned> m_pcWarp;
QNetworkAccessManager m_webCtrl;
QEthereum* m_ethereum;

163
libethereum/State.cpp

@ -601,6 +601,166 @@ bytes const& State::contractCode(Address _contract) const
return m_cache[_contract].code();
}
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;
if (m_t.isCreation())
gasCost = (m_t.init.size() + m_t.data.size()) * c_txDataGas + c_createGas;
else
gasCost = m_t.data.size() * c_txDataGas + c_callGas;
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, &m_t.init, 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.isContractAddress(_receiveAddress))
{
m_vm = new VM(_gas);
m_ext = new ExtVM(m_s, _receiveAddress, _senderAddress, _originAddress, _value, _gasPrice, _data, &m_s.contractCode(_receiveAddress));
}
else
m_endGas = _gas;
}
void Executive::create(Address _sender, u256 _endowment, u256 _gasPrice, u256 _gas, bytesConstRef _code, bytesConstRef _init, Address _origin)
{
m_newAddress = right160(sha3(rlpList(_sender, m_s.transactionsFrom(_sender) - 1)));
while (m_s.isContractAddress(m_newAddress) || m_s.isNormalAddress(m_newAddress))
m_newAddress = (u160)m_newAddress + 1;
// Set up new account...
m_s.m_cache[m_newAddress] = AddressState(0, 0, _code);
// Execute _init.
m_vm = new VM(_gas);
m_ext = new ExtVM(m_s, m_newAddress, _sender, _origin, _endowment, _gasPrice, bytesConstRef(), _init);
}
bool Executive::go(uint64_t _steps)
{
if (m_vm)
{
bool revert = false;
try
{
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);
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);
}
void State::execute(bytesConstRef _rlp)
{
// Entry point for a user-executed transaction.
@ -616,7 +776,7 @@ void State::execute(bytesConstRef _rlp)
throw InvalidNonce(nonceReq, 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 proce discovery protocol going.
// 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 (t.gasPrice < 10 * szabo)
{
clog(StateChat) << "Offered gas-price is too low.";
@ -671,6 +831,7 @@ void State::execute(bytesConstRef _rlp)
cnote << "Transferring" << formatBalance(gasSpent) << "to miner.";
addBalance(m_currentBlock.coinbaseAddress, feesEarned);
// !!!!!!!!!!!!!!!!!!!!! If moving to use Executive, this still needs to be done - Executive won't do it.
// Add to the user-originated transactions that we've executed.
m_transactions.push_back(t);
m_transactionSet.insert(t.sha3());

39
libethereum/State.h

@ -50,7 +50,43 @@ static const bytes EmptyBytes;
struct StateChat: public LogChannel { static const char* name() { return "=S="; } static const int verbosity = 4; };
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, bytesConstRef _init, 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();
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;
};
/**
* @brief Model of the current state of the ledger.
@ -61,10 +97,11 @@ class State
{
template <unsigned T> friend class UnitTest;
friend class ExtVM;
friend class Executive;
public:
/// Construct state object.
State(Address _coinbaseAddress, Overlay const& _db);
State(Address _coinbaseAddress = Address(), Overlay const& _db = Overlay());
/// Copy state object.
State(State const& _s);

3
libethereum/VM.cpp

@ -28,7 +28,4 @@ void VM::reset(u256 _gas)
{
m_gas = _gas;
m_curPC = 0;
m_nextPC = 1;
m_stepCount = 0;
m_runFee = 0;
}

29
libethereum/VM.h

@ -64,17 +64,17 @@ public:
void require(u256 _n) { if (m_stack.size() < _n) throw StackTooSmall(_n, m_stack.size()); }
void requireMem(unsigned _n) { if (m_temp.size() < _n) { m_temp.resize(_n); } }
u256 runFee() const { return m_runFee; }
u256 gas() const { return m_gas; }
u256 curPC() const { return m_curPC; }
bytes const& memory() const { return m_temp; }
u256s const& stack() const { return m_stack; }
private:
u256 m_gas = 0;
u256 m_curPC = 0;
u256 m_nextPC = 1;
uint64_t m_stepCount = 0;
bytes m_temp;
std::vector<u256> m_stack;
u256 m_runFee = 0;
u256s m_stack;
};
}
@ -82,10 +82,9 @@ private:
// INLINE:
template <class Ext> eth::bytesConstRef eth::VM::go(Ext& _ext, uint64_t _steps)
{
for (bool stopped = false; !stopped && _steps--; m_curPC = m_nextPC, m_nextPC = m_curPC + 1)
u256 nextPC = m_curPC + 1;
for (bool stopped = false; !stopped && _steps--; m_curPC = nextPC, nextPC = m_curPC + 1)
{
m_stepCount++;
// INSTRUCTION...
Instruction inst = (Instruction)_ext.getCode(m_curPC);
@ -310,7 +309,7 @@ template <class Ext> eth::bytesConstRef eth::VM::go(Ext& _ext, uint64_t _steps)
case Instruction::CALLDATALOAD:
{
require(1);
if ((unsigned)m_stack.back() + 32 < _ext.data.size())
if ((unsigned)m_stack.back() + 31 < _ext.data.size())
m_stack.back() = (u256)*(h256 const*)(_ext.data.data() + (unsigned)m_stack.back());
else
{
@ -379,10 +378,10 @@ template <class Ext> eth::bytesConstRef eth::VM::go(Ext& _ext, uint64_t _steps)
case Instruction::PUSH32:
{
int i = (int)inst - (int)Instruction::PUSH1 + 1;
m_nextPC = m_curPC + 1;
nextPC = m_curPC + 1;
m_stack.push_back(0);
for (; i--; m_nextPC++)
m_stack.back() = (m_stack.back() << 8) | _ext.getCode(m_nextPC);
for (; i--; nextPC++)
m_stack.back() = (m_stack.back() << 8) | _ext.getCode(nextPC);
break;
}
case Instruction::POP:
@ -456,13 +455,13 @@ template <class Ext> eth::bytesConstRef eth::VM::go(Ext& _ext, uint64_t _steps)
break;
case Instruction::JUMP:
require(1);
m_nextPC = m_stack.back();
nextPC = m_stack.back();
m_stack.pop_back();
break;
case Instruction::JUMPI:
require(2);
if (m_stack[m_stack.size() - 2])
m_nextPC = m_stack.back();
nextPC = m_stack.back();
m_stack.pop_back();
m_stack.pop_back();
break;
@ -557,7 +556,7 @@ template <class Ext> eth::bytesConstRef eth::VM::go(Ext& _ext, uint64_t _steps)
throw BadInstruction();
}
}
if (_steps == (unsigned)-1)
if (_steps == (uint64_t)-1)
throw StepsDone();
return bytesConstRef();
}

Loading…
Cancel
Save