winsvega
10 years ago
162 changed files with 7346 additions and 2474 deletions
@ -0,0 +1,59 @@ |
|||||
|
/*
|
||||
|
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 Debugger.h
|
||||
|
* @author Gav Wood <i@gavwood.com> |
||||
|
* @date 2015 |
||||
|
*/ |
||||
|
|
||||
|
#include "Context.h" |
||||
|
#include <QComboBox> |
||||
|
#include <libethcore/CommonEth.h> |
||||
|
using namespace std; |
||||
|
using namespace dev; |
||||
|
using namespace dev::eth; |
||||
|
|
||||
|
NatSpecFace::~NatSpecFace() |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
Context::~Context() |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
void initUnits(QComboBox* _b) |
||||
|
{ |
||||
|
for (auto n = (unsigned)units().size(); n-- != 0; ) |
||||
|
_b->addItem(QString::fromStdString(units()[n].second), n); |
||||
|
} |
||||
|
|
||||
|
vector<KeyPair> keysAsVector(QList<KeyPair> const& keys) |
||||
|
{ |
||||
|
auto list = keys.toStdList(); |
||||
|
return {begin(list), end(list)}; |
||||
|
} |
||||
|
|
||||
|
bool sourceIsSolidity(string const& _source) |
||||
|
{ |
||||
|
// TODO: Improve this heuristic
|
||||
|
return (_source.substr(0, 8) == "contract" || _source.substr(0, 5) == "//sol"); |
||||
|
} |
||||
|
|
||||
|
bool sourceIsSerpent(string const& _source) |
||||
|
{ |
||||
|
// TODO: Improve this heuristic
|
||||
|
return (_source.substr(0, 5) == "//ser"); |
||||
|
} |
@ -0,0 +1,68 @@ |
|||||
|
/*
|
||||
|
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 Debugger.h
|
||||
|
* @author Gav Wood <i@gavwood.com> |
||||
|
* @date 2015 |
||||
|
*/ |
||||
|
|
||||
|
#pragma once |
||||
|
|
||||
|
#include <string> |
||||
|
#include <vector> |
||||
|
#include <QString> |
||||
|
#include <QList> |
||||
|
#include <libethcore/CommonEth.h> |
||||
|
|
||||
|
class QComboBox; |
||||
|
|
||||
|
namespace dev { namespace eth { struct StateDiff; } } |
||||
|
|
||||
|
#define Small "font-size: small; " |
||||
|
#define Mono "font-family: Ubuntu Mono, Monospace, Lucida Console, Courier New; font-weight: bold; " |
||||
|
#define Div(S) "<div style=\"" S "\">" |
||||
|
#define Span(S) "<span style=\"" S "\">" |
||||
|
|
||||
|
void initUnits(QComboBox* _b); |
||||
|
|
||||
|
std::vector<dev::KeyPair> keysAsVector(QList<dev::KeyPair> const& _keys); |
||||
|
|
||||
|
bool sourceIsSolidity(std::string const& _source); |
||||
|
bool sourceIsSerpent(std::string const& _source); |
||||
|
|
||||
|
class NatSpecFace |
||||
|
{ |
||||
|
public: |
||||
|
virtual ~NatSpecFace(); |
||||
|
|
||||
|
virtual void add(dev::h256 const& _contractHash, std::string const& _doc) = 0; |
||||
|
virtual std::string retrieve(dev::h256 const& _contractHash) const = 0; |
||||
|
virtual std::string getUserNotice(std::string const& json, const dev::bytes& _transactionData) = 0; |
||||
|
virtual std::string getUserNotice(dev::h256 const& _contractHash, dev::bytes const& _transactionDacta) = 0; |
||||
|
}; |
||||
|
|
||||
|
class Context |
||||
|
{ |
||||
|
public: |
||||
|
virtual ~Context(); |
||||
|
|
||||
|
virtual QString pretty(dev::Address _a) const = 0; |
||||
|
virtual QString prettyU256(dev::u256 _n) const = 0; |
||||
|
virtual QString render(dev::Address _a) const = 0; |
||||
|
virtual dev::Address fromString(QString const& _a) const = 0; |
||||
|
virtual std::string renderDiff(dev::eth::StateDiff const& _d) const = 0; |
||||
|
}; |
||||
|
|
@ -0,0 +1,380 @@ |
|||||
|
/*
|
||||
|
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 Debugger.cpp
|
||||
|
* @author Gav Wood <i@gavwood.com> |
||||
|
* @date 2015 |
||||
|
*/ |
||||
|
|
||||
|
#include "Debugger.h" |
||||
|
|
||||
|
#include <fstream> |
||||
|
#include <QFileDialog> |
||||
|
#include <libevm/VM.h> |
||||
|
#include <libethereum/ExtVM.h> |
||||
|
#include <libethereum/Executive.h> |
||||
|
#include "ui_Debugger.h" |
||||
|
using namespace std; |
||||
|
using namespace dev; |
||||
|
using namespace dev::eth; |
||||
|
|
||||
|
Debugger::Debugger(Context* _c, QWidget* _parent): |
||||
|
QDialog(_parent), |
||||
|
ui(new Ui::Debugger), |
||||
|
m_context(_c) |
||||
|
{ |
||||
|
ui->setupUi(this); |
||||
|
} |
||||
|
|
||||
|
Debugger::~Debugger() |
||||
|
{ |
||||
|
delete ui; |
||||
|
} |
||||
|
|
||||
|
void Debugger::init() |
||||
|
{ |
||||
|
if (m_session.history.size()) |
||||
|
{ |
||||
|
alterDebugStateGroup(true); |
||||
|
ui->debugCode->setEnabled(false); |
||||
|
ui->debugTimeline->setMinimum(0); |
||||
|
ui->debugTimeline->setMaximum(m_session.history.size()); |
||||
|
ui->debugTimeline->setValue(0); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void Debugger::populate(dev::eth::Executive& _executive, dev::eth::Transaction const& _transaction) |
||||
|
{ |
||||
|
finished(); |
||||
|
if (m_session.populate(_executive, _transaction)) |
||||
|
init(); |
||||
|
update(); |
||||
|
} |
||||
|
|
||||
|
bool DebugSession::populate(dev::eth::Executive& _executive, dev::eth::Transaction const& _transaction) |
||||
|
{ |
||||
|
try { |
||||
|
if (_executive.setup(_transaction)) |
||||
|
return false; |
||||
|
} |
||||
|
catch (...) |
||||
|
{ |
||||
|
// Invalid transaction
|
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
vector<WorldState const*> levels; |
||||
|
bytes lastExtCode; |
||||
|
bytesConstRef lastData; |
||||
|
h256 lastHash; |
||||
|
h256 lastDataHash; |
||||
|
auto onOp = [&](uint64_t steps, Instruction inst, dev::bigint newMemSize, dev::bigint gasCost, VM* voidVM, ExtVMFace const* voidExt) |
||||
|
{ |
||||
|
VM& vm = *voidVM; |
||||
|
ExtVM const& ext = *static_cast<ExtVM const*>(voidExt); |
||||
|
if (ext.code != lastExtCode) |
||||
|
{ |
||||
|
lastExtCode = ext.code; |
||||
|
lastHash = sha3(lastExtCode); |
||||
|
if (!codes.count(lastHash)) |
||||
|
codes[lastHash] = ext.code; |
||||
|
} |
||||
|
if (ext.data != lastData) |
||||
|
{ |
||||
|
lastData = ext.data; |
||||
|
lastDataHash = sha3(lastData); |
||||
|
if (!codes.count(lastDataHash)) |
||||
|
codes[lastDataHash] = ext.data.toBytes(); |
||||
|
} |
||||
|
if (levels.size() < ext.depth) |
||||
|
levels.push_back(&history.back()); |
||||
|
else |
||||
|
levels.resize(ext.depth); |
||||
|
history.append(WorldState({steps, ext.myAddress, vm.curPC(), inst, newMemSize, vm.gas(), lastHash, lastDataHash, vm.stack(), vm.memory(), gasCost, ext.state().storage(ext.myAddress), levels})); |
||||
|
}; |
||||
|
_executive.go(onOp); |
||||
|
_executive.finalize(); |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
void Debugger::finished() |
||||
|
{ |
||||
|
m_session = DebugSession(); |
||||
|
ui->callStack->clear(); |
||||
|
ui->debugCode->clear(); |
||||
|
ui->debugStack->clear(); |
||||
|
ui->debugMemory->setHtml(""); |
||||
|
ui->debugStorage->setHtml(""); |
||||
|
ui->debugStateInfo->setText(""); |
||||
|
alterDebugStateGroup(false); |
||||
|
} |
||||
|
|
||||
|
void Debugger::update() |
||||
|
{ |
||||
|
if (m_session.history.size()) |
||||
|
{ |
||||
|
WorldState const& nws = m_session.history[min((int)m_session.history.size() - 1, ui->debugTimeline->value())]; |
||||
|
WorldState const& ws = ui->callStack->currentRow() > 0 ? *nws.levels[nws.levels.size() - ui->callStack->currentRow()] : nws; |
||||
|
|
||||
|
if (ui->debugTimeline->value() >= m_session.history.size()) |
||||
|
{ |
||||
|
if (ws.gasCost > ws.gas) |
||||
|
ui->debugMemory->setHtml("<h3>OUT-OF-GAS</h3>"); |
||||
|
else if (ws.inst == Instruction::RETURN && ws.stack.size() >= 2) |
||||
|
{ |
||||
|
unsigned from = (unsigned)ws.stack.back(); |
||||
|
unsigned size = (unsigned)ws.stack[ws.stack.size() - 2]; |
||||
|
unsigned o = 0; |
||||
|
bytes out(size, 0); |
||||
|
for (; o < size && from + o < ws.memory.size(); ++o) |
||||
|
out[o] = ws.memory[from + o]; |
||||
|
ui->debugMemory->setHtml("<h3>RETURN</h3>" + QString::fromStdString(dev::memDump(out, 16, true))); |
||||
|
} |
||||
|
else if (ws.inst == Instruction::STOP) |
||||
|
ui->debugMemory->setHtml("<h3>STOP</h3>"); |
||||
|
else if (ws.inst == Instruction::SUICIDE && ws.stack.size() >= 1) |
||||
|
ui->debugMemory->setHtml("<h3>SUICIDE</h3>0x" + QString::fromStdString(toString(right160(ws.stack.back())))); |
||||
|
else |
||||
|
ui->debugMemory->setHtml("<h3>EXCEPTION</h3>"); |
||||
|
|
||||
|
ostringstream ss; |
||||
|
ss << dec << "EXIT | GAS: " << dec << max<dev::bigint>(0, (dev::bigint)ws.gas - ws.gasCost); |
||||
|
ui->debugStateInfo->setText(QString::fromStdString(ss.str())); |
||||
|
ui->debugStorage->setHtml(""); |
||||
|
ui->debugCallData->setHtml(""); |
||||
|
m_session.currentData = h256(); |
||||
|
ui->callStack->clear(); |
||||
|
m_session.currentLevels.clear(); |
||||
|
ui->debugCode->clear(); |
||||
|
m_session.currentCode = h256(); |
||||
|
ui->debugStack->setHtml(""); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
if (m_session.currentLevels != nws.levels || !ui->callStack->count()) |
||||
|
{ |
||||
|
m_session.currentLevels = nws.levels; |
||||
|
ui->callStack->clear(); |
||||
|
for (unsigned i = 0; i <= nws.levels.size(); ++i) |
||||
|
{ |
||||
|
WorldState const& s = i ? *nws.levels[nws.levels.size() - i] : nws; |
||||
|
ostringstream out; |
||||
|
out << s.cur.abridged(); |
||||
|
if (i) |
||||
|
out << " " << instructionInfo(s.inst).name << " @0x" << hex << s.curPC; |
||||
|
ui->callStack->addItem(QString::fromStdString(out.str())); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if (ws.code != m_session.currentCode) |
||||
|
{ |
||||
|
m_session.currentCode = ws.code; |
||||
|
bytes const& code = m_session.codes[ws.code]; |
||||
|
QListWidget* dc = ui->debugCode; |
||||
|
dc->clear(); |
||||
|
m_session.pcWarp.clear(); |
||||
|
for (unsigned i = 0; i <= code.size(); ++i) |
||||
|
{ |
||||
|
byte b = i < code.size() ? code[i] : 0; |
||||
|
try |
||||
|
{ |
||||
|
QString s = QString::fromStdString(instructionInfo((Instruction)b).name); |
||||
|
ostringstream out; |
||||
|
out << hex << setw(4) << setfill('0') << i; |
||||
|
m_session.pcWarp[i] = dc->count(); |
||||
|
if (b >= (byte)Instruction::PUSH1 && b <= (byte)Instruction::PUSH32) |
||||
|
{ |
||||
|
unsigned bc = b - (byte)Instruction::PUSH1 + 1; |
||||
|
s = "PUSH 0x" + QString::fromStdString(toHex(bytesConstRef(&code[i + 1], bc))); |
||||
|
i += bc; |
||||
|
} |
||||
|
dc->addItem(QString::fromStdString(out.str()) + " " + s); |
||||
|
} |
||||
|
catch (...) |
||||
|
{ |
||||
|
cerr << "Unhandled exception!" << endl << boost::current_exception_diagnostic_information(); |
||||
|
break; // probably hit data segment
|
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if (ws.callData != m_session.currentData) |
||||
|
{ |
||||
|
m_session.currentData = ws.callData; |
||||
|
if (ws.callData) |
||||
|
{ |
||||
|
assert(m_session.codes.count(ws.callData)); |
||||
|
ui->debugCallData->setHtml(QString::fromStdString(dev::memDump(m_session.codes[ws.callData], 16, true))); |
||||
|
} |
||||
|
else |
||||
|
ui->debugCallData->setHtml(""); |
||||
|
} |
||||
|
|
||||
|
QString stack; |
||||
|
for (auto i: ws.stack) |
||||
|
stack.prepend("<div>" + m_context->prettyU256(i) + "</div>"); |
||||
|
ui->debugStack->setHtml(stack); |
||||
|
ui->debugMemory->setHtml(QString::fromStdString(dev::memDump(ws.memory, 16, true))); |
||||
|
assert(m_session.codes.count(ws.code)); |
||||
|
|
||||
|
if (m_session.codes[ws.code].size() >= (unsigned)ws.curPC) |
||||
|
{ |
||||
|
int l = m_session.pcWarp[(unsigned)ws.curPC]; |
||||
|
ui->debugCode->setCurrentRow(max(0, l - 5)); |
||||
|
ui->debugCode->setCurrentRow(min(ui->debugCode->count() - 1, l + 5)); |
||||
|
ui->debugCode->setCurrentRow(l); |
||||
|
} |
||||
|
else |
||||
|
cwarn << "PC (" << (unsigned)ws.curPC << ") is after code range (" << m_session.codes[ws.code].size() << ")"; |
||||
|
|
||||
|
ostringstream ss; |
||||
|
ss << dec << "STEP: " << ws.steps << " | PC: 0x" << hex << ws.curPC << " : " << instructionInfo(ws.inst).name << " | ADDMEM: " << dec << ws.newMemSize << " words | COST: " << dec << ws.gasCost << " | GAS: " << dec << ws.gas; |
||||
|
ui->debugStateInfo->setText(QString::fromStdString(ss.str())); |
||||
|
stringstream s; |
||||
|
for (auto const& i: ws.storage) |
||||
|
s << "@" << m_context->prettyU256(i.first).toStdString() << " " << m_context->prettyU256(i.second).toStdString() << "<br/>"; |
||||
|
ui->debugStorage->setHtml(QString::fromStdString(s.str())); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void Debugger::on_callStack_currentItemChanged() |
||||
|
{ |
||||
|
update(); |
||||
|
} |
||||
|
|
||||
|
void Debugger::alterDebugStateGroup(bool _enable) const |
||||
|
{ |
||||
|
ui->stepOver->setEnabled(_enable); |
||||
|
ui->stepInto->setEnabled(_enable); |
||||
|
ui->stepOut->setEnabled(_enable); |
||||
|
ui->backOver->setEnabled(_enable); |
||||
|
ui->backInto->setEnabled(_enable); |
||||
|
ui->backOut->setEnabled(_enable); |
||||
|
ui->dump->setEnabled(_enable); |
||||
|
ui->dumpStorage->setEnabled(_enable); |
||||
|
ui->dumpPretty->setEnabled(_enable); |
||||
|
} |
||||
|
|
||||
|
void Debugger::on_debugTimeline_valueChanged() |
||||
|
{ |
||||
|
update(); |
||||
|
} |
||||
|
|
||||
|
void Debugger::on_stepOver_clicked() |
||||
|
{ |
||||
|
if (ui->debugTimeline->value() < m_session.history.size()) { |
||||
|
auto l = m_session.history[ui->debugTimeline->value()].levels.size(); |
||||
|
if ((ui->debugTimeline->value() + 1) < m_session.history.size() && m_session.history[ui->debugTimeline->value() + 1].levels.size() > l) |
||||
|
{ |
||||
|
on_stepInto_clicked(); |
||||
|
if (m_session.history[ui->debugTimeline->value()].levels.size() > l) |
||||
|
on_stepOut_clicked(); |
||||
|
} |
||||
|
else |
||||
|
on_stepInto_clicked(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void Debugger::on_stepInto_clicked() |
||||
|
{ |
||||
|
ui->debugTimeline->setValue(ui->debugTimeline->value() + 1); |
||||
|
ui->callStack->setCurrentRow(0); |
||||
|
} |
||||
|
|
||||
|
void Debugger::on_stepOut_clicked() |
||||
|
{ |
||||
|
if (ui->debugTimeline->value() < m_session.history.size()) |
||||
|
{ |
||||
|
auto ls = m_session.history[ui->debugTimeline->value()].levels.size(); |
||||
|
auto l = ui->debugTimeline->value(); |
||||
|
for (; l < m_session.history.size() && m_session.history[l].levels.size() >= ls; ++l) {} |
||||
|
ui->debugTimeline->setValue(l); |
||||
|
ui->callStack->setCurrentRow(0); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void Debugger::on_backInto_clicked() |
||||
|
{ |
||||
|
ui->debugTimeline->setValue(ui->debugTimeline->value() - 1); |
||||
|
ui->callStack->setCurrentRow(0); |
||||
|
} |
||||
|
|
||||
|
void Debugger::on_backOver_clicked() |
||||
|
{ |
||||
|
auto l = m_session.history[ui->debugTimeline->value()].levels.size(); |
||||
|
if (ui->debugTimeline->value() > 0 && m_session.history[ui->debugTimeline->value() - 1].levels.size() > l) |
||||
|
{ |
||||
|
on_backInto_clicked(); |
||||
|
if (m_session.history[ui->debugTimeline->value()].levels.size() > l) |
||||
|
on_backOut_clicked(); |
||||
|
} |
||||
|
else |
||||
|
on_backInto_clicked(); |
||||
|
} |
||||
|
|
||||
|
void Debugger::on_backOut_clicked() |
||||
|
{ |
||||
|
if (ui->debugTimeline->value() > 0 && m_session.history.size() > 0) |
||||
|
{ |
||||
|
auto ls = m_session.history[min(ui->debugTimeline->value(), m_session.history.size() - 1)].levels.size(); |
||||
|
int l = ui->debugTimeline->value(); |
||||
|
for (; l > 0 && m_session.history[l].levels.size() >= ls; --l) {} |
||||
|
ui->debugTimeline->setValue(l); |
||||
|
ui->callStack->setCurrentRow(0); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void Debugger::on_dump_clicked() |
||||
|
{ |
||||
|
QString fn = QFileDialog::getSaveFileName(this, "Select file to output EVM trace"); |
||||
|
ofstream f(fn.toStdString()); |
||||
|
if (f.is_open()) |
||||
|
for (WorldState const& ws: m_session.history) |
||||
|
f << ws.cur << " " << hex << toHex(dev::toCompactBigEndian(ws.curPC, 1)) << " " << hex << toHex(dev::toCompactBigEndian((int)(byte)ws.inst, 1)) << " " << hex << toHex(dev::toCompactBigEndian((uint64_t)ws.gas, 1)) << endl; |
||||
|
} |
||||
|
|
||||
|
void Debugger::on_dumpPretty_clicked() |
||||
|
{ |
||||
|
QString fn = QFileDialog::getSaveFileName(this, "Select file to output EVM trace"); |
||||
|
ofstream f(fn.toStdString()); |
||||
|
if (f.is_open()) |
||||
|
for (WorldState const& ws: m_session.history) |
||||
|
{ |
||||
|
f << endl << " STACK" << endl; |
||||
|
for (auto i: ws.stack) |
||||
|
f << (h256)i << endl; |
||||
|
f << " MEMORY" << endl << dev::memDump(ws.memory); |
||||
|
f << " STORAGE" << endl; |
||||
|
for (auto const& i: ws.storage) |
||||
|
f << showbase << hex << i.first << ": " << i.second << endl; |
||||
|
f << dec << ws.levels.size() << " | " << ws.cur << " | #" << ws.steps << " | " << hex << setw(4) << setfill('0') << ws.curPC << " : " << instructionInfo(ws.inst).name << " | " << dec << ws.gas << " | -" << dec << ws.gasCost << " | " << ws.newMemSize << "x32"; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void Debugger::on_dumpStorage_clicked() |
||||
|
{ |
||||
|
QString fn = QFileDialog::getSaveFileName(this, "Select file to output EVM trace"); |
||||
|
ofstream f(fn.toStdString()); |
||||
|
if (f.is_open()) |
||||
|
for (WorldState const& ws: m_session.history) |
||||
|
{ |
||||
|
if (ws.inst == Instruction::STOP || ws.inst == Instruction::RETURN || ws.inst == Instruction::SUICIDE) |
||||
|
for (auto i: ws.storage) |
||||
|
f << toHex(dev::toCompactBigEndian(i.first, 1)) << " " << toHex(dev::toCompactBigEndian(i.second, 1)) << endl; |
||||
|
f << ws.cur << " " << hex << toHex(dev::toCompactBigEndian(ws.curPC, 1)) << " " << hex << toHex(dev::toCompactBigEndian((int)(byte)ws.inst, 1)) << " " << hex << toHex(dev::toCompactBigEndian((uint64_t)ws.gas, 1)) << endl; |
||||
|
} |
||||
|
} |
@ -0,0 +1,103 @@ |
|||||
|
/*
|
||||
|
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 Debugger.h
|
||||
|
* @author Gav Wood <i@gavwood.com> |
||||
|
* @date 2015 |
||||
|
*/ |
||||
|
|
||||
|
#pragma once |
||||
|
|
||||
|
#include <libdevcore/RLP.h> |
||||
|
#include <libethcore/CommonEth.h> |
||||
|
#include <libethereum/State.h> |
||||
|
#include <libethereum/Executive.h> |
||||
|
#include <QDialog> |
||||
|
#include <QMap> |
||||
|
#include <QList> |
||||
|
#include "Context.h" |
||||
|
|
||||
|
namespace Ui { class Debugger; } |
||||
|
|
||||
|
struct WorldState |
||||
|
{ |
||||
|
uint64_t steps; |
||||
|
dev::Address cur; |
||||
|
dev::u256 curPC; |
||||
|
dev::eth::Instruction inst; |
||||
|
dev::bigint newMemSize; |
||||
|
dev::u256 gas; |
||||
|
dev::h256 code; |
||||
|
dev::h256 callData; |
||||
|
dev::u256s stack; |
||||
|
dev::bytes memory; |
||||
|
dev::bigint gasCost; |
||||
|
std::map<dev::u256, dev::u256> storage; |
||||
|
std::vector<WorldState const*> levels; |
||||
|
}; |
||||
|
|
||||
|
struct DebugSession |
||||
|
{ |
||||
|
DebugSession() {} |
||||
|
|
||||
|
bool populate(dev::eth::Executive& _executive, dev::eth::Transaction const& _transaction); |
||||
|
|
||||
|
dev::h256 currentCode; |
||||
|
dev::h256 currentData; |
||||
|
std::vector<WorldState const*> currentLevels; |
||||
|
|
||||
|
QMap<unsigned, unsigned> pcWarp; |
||||
|
QList<WorldState> history; |
||||
|
|
||||
|
std::map<dev::u256, dev::bytes> codes; |
||||
|
}; |
||||
|
|
||||
|
class Debugger: public QDialog |
||||
|
{ |
||||
|
Q_OBJECT |
||||
|
|
||||
|
public: |
||||
|
explicit Debugger(Context* _context, QWidget* _parent = 0); |
||||
|
~Debugger(); |
||||
|
|
||||
|
void populate(dev::eth::Executive& _executive, dev::eth::Transaction const& _transaction); |
||||
|
|
||||
|
protected slots: |
||||
|
void on_callStack_currentItemChanged(); |
||||
|
void on_debugTimeline_valueChanged(); |
||||
|
void on_stepOver_clicked(); |
||||
|
void on_stepInto_clicked(); |
||||
|
void on_stepOut_clicked(); |
||||
|
void on_backOver_clicked(); |
||||
|
void on_backInto_clicked(); |
||||
|
void on_backOut_clicked(); |
||||
|
void on_dump_clicked(); |
||||
|
void on_dumpPretty_clicked(); |
||||
|
void on_dumpStorage_clicked(); |
||||
|
void on_close_clicked() { close(); } |
||||
|
|
||||
|
private: |
||||
|
void init(); |
||||
|
void update(); |
||||
|
void finished(); |
||||
|
|
||||
|
void alterDebugStateGroup(bool _enable) const; |
||||
|
|
||||
|
Ui::Debugger* ui; |
||||
|
|
||||
|
DebugSession m_session; |
||||
|
Context* m_context; |
||||
|
}; |
@ -0,0 +1,300 @@ |
|||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||
|
<ui version="4.0"> |
||||
|
<class>Debugger</class> |
||||
|
<widget class="QDialog" name="Debugger"> |
||||
|
<property name="geometry"> |
||||
|
<rect> |
||||
|
<x>0</x> |
||||
|
<y>0</y> |
||||
|
<width>989</width> |
||||
|
<height>690</height> |
||||
|
</rect> |
||||
|
</property> |
||||
|
<property name="windowTitle"> |
||||
|
<string>Dialog</string> |
||||
|
</property> |
||||
|
<layout class="QVBoxLayout" name="verticalLayout"> |
||||
|
<item> |
||||
|
<widget class="QFrame" name="frame"> |
||||
|
<property name="frameShape"> |
||||
|
<enum>QFrame::NoFrame</enum> |
||||
|
</property> |
||||
|
<property name="frameShadow"> |
||||
|
<enum>QFrame::Raised</enum> |
||||
|
</property> |
||||
|
<layout class="QHBoxLayout" name="horizontalLayout"> |
||||
|
<property name="leftMargin"> |
||||
|
<number>0</number> |
||||
|
</property> |
||||
|
<property name="topMargin"> |
||||
|
<number>0</number> |
||||
|
</property> |
||||
|
<property name="rightMargin"> |
||||
|
<number>0</number> |
||||
|
</property> |
||||
|
<property name="bottomMargin"> |
||||
|
<number>0</number> |
||||
|
</property> |
||||
|
<item> |
||||
|
<widget class="QToolButton" name="stepOver"> |
||||
|
<property name="text"> |
||||
|
<string>Step Over</string> |
||||
|
</property> |
||||
|
</widget> |
||||
|
</item> |
||||
|
<item> |
||||
|
<widget class="QToolButton" name="stepInto"> |
||||
|
<property name="text"> |
||||
|
<string>Step Into</string> |
||||
|
</property> |
||||
|
</widget> |
||||
|
</item> |
||||
|
<item> |
||||
|
<widget class="QToolButton" name="stepOut"> |
||||
|
<property name="text"> |
||||
|
<string>Step Out</string> |
||||
|
</property> |
||||
|
</widget> |
||||
|
</item> |
||||
|
<item> |
||||
|
<widget class="QToolButton" name="backOver"> |
||||
|
<property name="text"> |
||||
|
<string>Back Over</string> |
||||
|
</property> |
||||
|
</widget> |
||||
|
</item> |
||||
|
<item> |
||||
|
<widget class="QToolButton" name="backInto"> |
||||
|
<property name="text"> |
||||
|
<string>Back Into</string> |
||||
|
</property> |
||||
|
</widget> |
||||
|
</item> |
||||
|
<item> |
||||
|
<widget class="QToolButton" name="backOut"> |
||||
|
<property name="text"> |
||||
|
<string>Back Out</string> |
||||
|
</property> |
||||
|
</widget> |
||||
|
</item> |
||||
|
<item> |
||||
|
<spacer name="horizontalSpacer"> |
||||
|
<property name="orientation"> |
||||
|
<enum>Qt::Horizontal</enum> |
||||
|
</property> |
||||
|
<property name="sizeHint" stdset="0"> |
||||
|
<size> |
||||
|
<width>40</width> |
||||
|
<height>20</height> |
||||
|
</size> |
||||
|
</property> |
||||
|
</spacer> |
||||
|
</item> |
||||
|
</layout> |
||||
|
</widget> |
||||
|
</item> |
||||
|
<item> |
||||
|
<widget class="QSplitter" name="splitter_6"> |
||||
|
<property name="sizePolicy"> |
||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Expanding"> |
||||
|
<horstretch>0</horstretch> |
||||
|
<verstretch>0</verstretch> |
||||
|
</sizepolicy> |
||||
|
</property> |
||||
|
<property name="orientation"> |
||||
|
<enum>Qt::Horizontal</enum> |
||||
|
</property> |
||||
|
<widget class="QSplitter" name="splitter_42"> |
||||
|
<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="debugCode"> |
||||
|
<property name="sizePolicy"> |
||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Expanding"> |
||||
|
<horstretch>0</horstretch> |
||||
|
<verstretch>0</verstretch> |
||||
|
</sizepolicy> |
||||
|
</property> |
||||
|
<property name="frameShape"> |
||||
|
<enum>QFrame::NoFrame</enum> |
||||
|
</property> |
||||
|
<property name="lineWidth"> |
||||
|
<number>0</number> |
||||
|
</property> |
||||
|
</widget> |
||||
|
<widget class="QListWidget" name="callStack"> |
||||
|
<property name="font"> |
||||
|
<font> |
||||
|
<family>Ubuntu Mono</family> |
||||
|
</font> |
||||
|
</property> |
||||
|
<property name="frameShape"> |
||||
|
<enum>QFrame::NoFrame</enum> |
||||
|
</property> |
||||
|
<property name="lineWidth"> |
||||
|
<number>0</number> |
||||
|
</property> |
||||
|
</widget> |
||||
|
</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="QTextEdit" name="debugStack"> |
||||
|
<property name="frameShape"> |
||||
|
<enum>QFrame::NoFrame</enum> |
||||
|
</property> |
||||
|
<property name="lineWidth"> |
||||
|
<number>0</number> |
||||
|
</property> |
||||
|
<property name="readOnly"> |
||||
|
<bool>true</bool> |
||||
|
</property> |
||||
|
<property name="textInteractionFlags"> |
||||
|
<set>Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set> |
||||
|
</property> |
||||
|
</widget> |
||||
|
<widget class="QTextEdit" name="debugMemory"> |
||||
|
<property name="frameShape"> |
||||
|
<enum>QFrame::NoFrame</enum> |
||||
|
</property> |
||||
|
<property name="lineWidth"> |
||||
|
<number>0</number> |
||||
|
</property> |
||||
|
<property name="readOnly"> |
||||
|
<bool>true</bool> |
||||
|
</property> |
||||
|
<property name="textInteractionFlags"> |
||||
|
<set>Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set> |
||||
|
</property> |
||||
|
</widget> |
||||
|
<widget class="QTextEdit" name="debugStorage"> |
||||
|
<property name="frameShape"> |
||||
|
<enum>QFrame::NoFrame</enum> |
||||
|
</property> |
||||
|
<property name="lineWidth"> |
||||
|
<number>0</number> |
||||
|
</property> |
||||
|
<property name="readOnly"> |
||||
|
<bool>true</bool> |
||||
|
</property> |
||||
|
<property name="textInteractionFlags"> |
||||
|
<set>Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set> |
||||
|
</property> |
||||
|
</widget> |
||||
|
<widget class="QTextEdit" name="debugCallData"> |
||||
|
<property name="frameShape"> |
||||
|
<enum>QFrame::NoFrame</enum> |
||||
|
</property> |
||||
|
<property name="readOnly"> |
||||
|
<bool>true</bool> |
||||
|
</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> |
||||
|
<item> |
||||
|
<widget class="QSlider" name="debugTimeline"> |
||||
|
<property name="orientation"> |
||||
|
<enum>Qt::Horizontal</enum> |
||||
|
</property> |
||||
|
</widget> |
||||
|
</item> |
||||
|
<item> |
||||
|
<widget class="QFrame" name="frame_2"> |
||||
|
<property name="frameShape"> |
||||
|
<enum>QFrame::NoFrame</enum> |
||||
|
</property> |
||||
|
<property name="frameShadow"> |
||||
|
<enum>QFrame::Raised</enum> |
||||
|
</property> |
||||
|
<layout class="QHBoxLayout" name="horizontalLayout_2"> |
||||
|
<property name="leftMargin"> |
||||
|
<number>0</number> |
||||
|
</property> |
||||
|
<property name="topMargin"> |
||||
|
<number>0</number> |
||||
|
</property> |
||||
|
<property name="rightMargin"> |
||||
|
<number>0</number> |
||||
|
</property> |
||||
|
<property name="bottomMargin"> |
||||
|
<number>0</number> |
||||
|
</property> |
||||
|
<item> |
||||
|
<widget class="QToolButton" name="dump"> |
||||
|
<property name="text"> |
||||
|
<string>Dump</string> |
||||
|
</property> |
||||
|
</widget> |
||||
|
</item> |
||||
|
<item> |
||||
|
<widget class="QToolButton" name="dumpStorage"> |
||||
|
<property name="text"> |
||||
|
<string>Dump Storage</string> |
||||
|
</property> |
||||
|
</widget> |
||||
|
</item> |
||||
|
<item> |
||||
|
<widget class="QToolButton" name="dumpPretty"> |
||||
|
<property name="text"> |
||||
|
<string>Dump Pretty</string> |
||||
|
</property> |
||||
|
</widget> |
||||
|
</item> |
||||
|
<item> |
||||
|
<spacer name="horizontalSpacer_2"> |
||||
|
<property name="orientation"> |
||||
|
<enum>Qt::Horizontal</enum> |
||||
|
</property> |
||||
|
<property name="sizeHint" stdset="0"> |
||||
|
<size> |
||||
|
<width>577</width> |
||||
|
<height>20</height> |
||||
|
</size> |
||||
|
</property> |
||||
|
</spacer> |
||||
|
</item> |
||||
|
<item> |
||||
|
<widget class="QToolButton" name="close"> |
||||
|
<property name="text"> |
||||
|
<string>Close</string> |
||||
|
</property> |
||||
|
</widget> |
||||
|
</item> |
||||
|
</layout> |
||||
|
</widget> |
||||
|
</item> |
||||
|
</layout> |
||||
|
</widget> |
||||
|
<resources/> |
||||
|
<connections/> |
||||
|
</ui> |
@ -0,0 +1,336 @@ |
|||||
|
/*
|
||||
|
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 Transact.cpp
|
||||
|
* @author Gav Wood <i@gavwood.com> |
||||
|
* @date 2015 |
||||
|
*/ |
||||
|
|
||||
|
#include "Transact.h" |
||||
|
|
||||
|
#include <fstream> |
||||
|
#include <QFileDialog> |
||||
|
#include <QMessageBox> |
||||
|
#include <liblll/Compiler.h> |
||||
|
#include <liblll/CodeFragment.h> |
||||
|
#include <libsolidity/CompilerStack.h> |
||||
|
#include <libsolidity/Scanner.h> |
||||
|
#include <libsolidity/AST.h> |
||||
|
#include <libsolidity/SourceReferenceFormatter.h> |
||||
|
#include <libnatspec/NatspecExpressionEvaluator.h> |
||||
|
#include <libethereum/Client.h> |
||||
|
#include <libethereum/Utility.h> |
||||
|
#ifndef _MSC_VER |
||||
|
#include <libserpent/funcs.h> |
||||
|
#include <libserpent/util.h> |
||||
|
#endif |
||||
|
#include "Debugger.h" |
||||
|
#include "ui_Transact.h" |
||||
|
using namespace std; |
||||
|
using namespace dev; |
||||
|
using namespace dev::eth; |
||||
|
|
||||
|
Transact::Transact(Context* _c, QWidget* _parent): |
||||
|
QDialog(_parent), |
||||
|
ui(new Ui::Transact), |
||||
|
m_context(_c) |
||||
|
{ |
||||
|
ui->setupUi(this); |
||||
|
|
||||
|
initUnits(ui->gasPriceUnits); |
||||
|
initUnits(ui->valueUnits); |
||||
|
ui->valueUnits->setCurrentIndex(6); |
||||
|
ui->gasPriceUnits->setCurrentIndex(4); |
||||
|
ui->gasPrice->setValue(10); |
||||
|
on_destination_currentTextChanged(); |
||||
|
} |
||||
|
|
||||
|
Transact::~Transact() |
||||
|
{ |
||||
|
delete ui; |
||||
|
} |
||||
|
|
||||
|
void Transact::setEnvironment(QList<dev::KeyPair> _myKeys, dev::eth::Client* _eth, NatSpecFace* _natSpecDB) |
||||
|
{ |
||||
|
m_myKeys = _myKeys; |
||||
|
m_ethereum = _eth; |
||||
|
m_natSpecDB = _natSpecDB; |
||||
|
} |
||||
|
|
||||
|
bool Transact::isCreation() const |
||||
|
{ |
||||
|
return ui->destination->currentText().isEmpty() || ui->destination->currentText() == "(Create Contract)"; |
||||
|
} |
||||
|
|
||||
|
u256 Transact::fee() const |
||||
|
{ |
||||
|
return ui->gas->value() * gasPrice(); |
||||
|
} |
||||
|
|
||||
|
u256 Transact::value() const |
||||
|
{ |
||||
|
if (ui->valueUnits->currentIndex() == -1) |
||||
|
return 0; |
||||
|
return ui->value->value() * units()[units().size() - 1 - ui->valueUnits->currentIndex()].first; |
||||
|
} |
||||
|
|
||||
|
u256 Transact::gasPrice() const |
||||
|
{ |
||||
|
if (ui->gasPriceUnits->currentIndex() == -1) |
||||
|
return 0; |
||||
|
return ui->gasPrice->value() * units()[units().size() - 1 - ui->gasPriceUnits->currentIndex()].first; |
||||
|
} |
||||
|
|
||||
|
u256 Transact::total() const |
||||
|
{ |
||||
|
return value() + fee(); |
||||
|
} |
||||
|
|
||||
|
void Transact::updateDestination() |
||||
|
{ |
||||
|
cwatch << "updateDestination()"; |
||||
|
QString s; |
||||
|
for (auto i: ethereum()->addresses()) |
||||
|
if ((s = m_context->pretty(i)).size()) |
||||
|
// A namereg address
|
||||
|
if (ui->destination->findText(s, Qt::MatchExactly | Qt::MatchCaseSensitive) == -1) |
||||
|
ui->destination->addItem(s); |
||||
|
for (int i = 0; i < ui->destination->count(); ++i) |
||||
|
if (ui->destination->itemText(i) != "(Create Contract)" && !m_context->fromString(ui->destination->itemText(i))) |
||||
|
ui->destination->removeItem(i--); |
||||
|
} |
||||
|
|
||||
|
void Transact::updateFee() |
||||
|
{ |
||||
|
ui->fee->setText(QString("(gas sub-total: %1)").arg(formatBalance(fee()).c_str())); |
||||
|
auto totalReq = total(); |
||||
|
ui->total->setText(QString("Total: %1").arg(formatBalance(totalReq).c_str())); |
||||
|
|
||||
|
bool ok = false; |
||||
|
for (auto i: m_myKeys) |
||||
|
if (ethereum()->balanceAt(i.address()) >= totalReq) |
||||
|
{ |
||||
|
ok = true; |
||||
|
break; |
||||
|
} |
||||
|
ui->send->setEnabled(ok); |
||||
|
QPalette p = ui->total->palette(); |
||||
|
p.setColor(QPalette::WindowText, QColor(ok ? 0x00 : 0x80, 0x00, 0x00)); |
||||
|
ui->total->setPalette(p); |
||||
|
} |
||||
|
|
||||
|
string Transact::getFunctionHashes(dev::solidity::CompilerStack const& _compiler, string const& _contractName) |
||||
|
{ |
||||
|
string ret = ""; |
||||
|
auto const& contract = _compiler.getContractDefinition(_contractName); |
||||
|
auto interfaceFunctions = contract.getInterfaceFunctions(); |
||||
|
|
||||
|
for (auto const& it: interfaceFunctions) |
||||
|
{ |
||||
|
ret += it.first.abridged(); |
||||
|
ret += " :"; |
||||
|
ret += it.second->getDeclaration().getName() + "\n"; |
||||
|
} |
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
void Transact::on_destination_currentTextChanged() |
||||
|
{ |
||||
|
if (ui->destination->currentText().size() && ui->destination->currentText() != "(Create Contract)") |
||||
|
if (Address a = m_context->fromString(ui->destination->currentText())) |
||||
|
ui->calculatedName->setText(m_context->render(a)); |
||||
|
else |
||||
|
ui->calculatedName->setText("Unknown Address"); |
||||
|
else |
||||
|
ui->calculatedName->setText("Create Contract"); |
||||
|
rejigData(); |
||||
|
// updateFee();
|
||||
|
} |
||||
|
|
||||
|
void Transact::rejigData() |
||||
|
{ |
||||
|
if (isCreation()) |
||||
|
{ |
||||
|
string src = ui->data->toPlainText().toStdString(); |
||||
|
vector<string> errors; |
||||
|
QString lll; |
||||
|
QString solidity; |
||||
|
if (src.find_first_not_of("1234567890abcdefABCDEF") == string::npos && src.size() % 2 == 0) |
||||
|
{ |
||||
|
m_data = fromHex(src); |
||||
|
} |
||||
|
else if (sourceIsSolidity(src)) |
||||
|
{ |
||||
|
dev::solidity::CompilerStack compiler; |
||||
|
try |
||||
|
{ |
||||
|
// compiler.addSources(dev::solidity::StandardSources);
|
||||
|
m_data = compiler.compile(src, ui->optimize->isChecked()); |
||||
|
solidity = "<h4>Solidity</h4>"; |
||||
|
solidity += "<pre>var " + QString::fromStdString(compiler.defaultContractName()) + " = web3.eth.contractFromAbi(" + QString::fromStdString(compiler.getInterface()).replace(QRegExp("\\s"), "").toHtmlEscaped() + ");</pre>"; |
||||
|
solidity += "<pre>" + QString::fromStdString(compiler.getSolidityInterface()).toHtmlEscaped() + "</pre>"; |
||||
|
solidity += "<pre>" + QString::fromStdString(getFunctionHashes(compiler)).toHtmlEscaped() + "</pre>"; |
||||
|
} |
||||
|
catch (dev::Exception const& exception) |
||||
|
{ |
||||
|
ostringstream error; |
||||
|
solidity::SourceReferenceFormatter::printExceptionInformation(error, exception, "Error", compiler); |
||||
|
solidity = "<h4>Solidity</h4><pre>" + QString::fromStdString(error.str()).toHtmlEscaped() + "</pre>"; |
||||
|
} |
||||
|
catch (...) |
||||
|
{ |
||||
|
solidity = "<h4>Solidity</h4><pre>Uncaught exception.</pre>"; |
||||
|
} |
||||
|
} |
||||
|
#ifndef _MSC_VER |
||||
|
else if (sourceIsSerpent(src)) |
||||
|
{ |
||||
|
try |
||||
|
{ |
||||
|
m_data = dev::asBytes(::compile(src)); |
||||
|
for (auto& i: errors) |
||||
|
i = "(LLL " + i + ")"; |
||||
|
} |
||||
|
catch (string err) |
||||
|
{ |
||||
|
errors.push_back("Serpent " + err); |
||||
|
} |
||||
|
} |
||||
|
#endif |
||||
|
else |
||||
|
{ |
||||
|
m_data = compileLLL(src, ui->optimize->isChecked(), &errors); |
||||
|
if (errors.empty()) |
||||
|
{ |
||||
|
auto asmcode = compileLLLToAsm(src, false); |
||||
|
lll = "<h4>Pre</h4><pre>" + QString::fromStdString(asmcode).toHtmlEscaped() + "</pre>"; |
||||
|
if (ui->optimize->isChecked()) |
||||
|
{ |
||||
|
asmcode = compileLLLToAsm(src, true); |
||||
|
lll = "<h4>Opt</h4><pre>" + QString::fromStdString(asmcode).toHtmlEscaped() + "</pre>" + lll; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
QString errs; |
||||
|
if (errors.size()) |
||||
|
{ |
||||
|
errs = "<h4>Errors</h4>"; |
||||
|
for (auto const& i: errors) |
||||
|
errs.append("<div style=\"border-left: 6px solid #c00; margin-top: 2px\">" + QString::fromStdString(i).toHtmlEscaped() + "</div>"); |
||||
|
} |
||||
|
ui->code->setHtml(errs + lll + solidity + "<h4>Code</h4>" + QString::fromStdString(disassemble(m_data)).toHtmlEscaped() + "<h4>Hex</h4>" Div(Mono) + QString::fromStdString(toHex(m_data)) + "</div>"); |
||||
|
ui->gas->setMinimum((qint64)Interface::txGas(m_data, 0)); |
||||
|
if (!ui->gas->isEnabled()) |
||||
|
ui->gas->setValue(m_backupGas); |
||||
|
ui->gas->setEnabled(true); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
m_data = parseData(ui->data->toPlainText().toStdString()); |
||||
|
auto to = m_context->fromString(ui->destination->currentText()); |
||||
|
QString natspec; |
||||
|
if (ethereum()->codeAt(to, 0).size()) |
||||
|
{ |
||||
|
string userNotice = m_natSpecDB->getUserNotice(ethereum()->postState().codeHash(to), m_data); |
||||
|
if (userNotice.empty()) |
||||
|
natspec = "Destination contract unknown."; |
||||
|
else |
||||
|
{ |
||||
|
NatspecExpressionEvaluator evaluator; |
||||
|
natspec = evaluator.evalExpression(QString::fromStdString(userNotice)); |
||||
|
} |
||||
|
ui->gas->setMinimum((qint64)Interface::txGas(m_data, 1)); |
||||
|
if (!ui->gas->isEnabled()) |
||||
|
ui->gas->setValue(m_backupGas); |
||||
|
ui->gas->setEnabled(true); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
natspec += "Destination not a contract."; |
||||
|
if (ui->gas->isEnabled()) |
||||
|
m_backupGas = ui->gas->value(); |
||||
|
ui->gas->setValue((qint64)Interface::txGas(m_data)); |
||||
|
ui->gas->setEnabled(false); |
||||
|
} |
||||
|
ui->code->setHtml("<h3>NatSpec</h3>" + natspec + "<h3>Dump</h3>" + QString::fromStdString(dev::memDump(m_data, 8, true)) + "<h3>Hex</h3>" + Div(Mono) + QString::fromStdString(toHex(m_data)) + "</div>"); |
||||
|
} |
||||
|
updateFee(); |
||||
|
} |
||||
|
|
||||
|
void Transact::on_send_clicked() |
||||
|
{ |
||||
|
u256 totalReq = value() + fee(); |
||||
|
for (auto const& i: m_myKeys) |
||||
|
if (ethereum()->balanceAt(i.address(), 0) >= totalReq) |
||||
|
{ |
||||
|
Secret s = i.secret(); |
||||
|
if (isCreation()) |
||||
|
{ |
||||
|
// If execution is a contract creation, add Natspec to
|
||||
|
// a local Natspec LEVELDB
|
||||
|
ethereum()->transact(s, value(), m_data, ui->gas->value(), gasPrice()); |
||||
|
string src = ui->data->toPlainText().toStdString(); |
||||
|
if (sourceIsSolidity(src)) |
||||
|
try |
||||
|
{ |
||||
|
dev::solidity::CompilerStack compiler; |
||||
|
m_data = compiler.compile(src, ui->optimize->isChecked()); |
||||
|
for (string const& s: compiler.getContractNames()) |
||||
|
{ |
||||
|
h256 contractHash = compiler.getContractCodeHash(s); |
||||
|
m_natSpecDB->add(contractHash, compiler.getMetadata(s, dev::solidity::DocumentationType::NatspecUser)); |
||||
|
} |
||||
|
} |
||||
|
catch (...) |
||||
|
{ |
||||
|
} |
||||
|
close(); |
||||
|
return; |
||||
|
} |
||||
|
else |
||||
|
ethereum()->transact(s, value(), m_context->fromString(ui->destination->currentText()), m_data, ui->gas->value(), gasPrice()); |
||||
|
return; |
||||
|
} |
||||
|
QMessageBox::critical(this, "Transaction Failed", "Couldn't make transaction: no single account contains at least the required amount."); |
||||
|
} |
||||
|
|
||||
|
void Transact::on_debug_clicked() |
||||
|
{ |
||||
|
try |
||||
|
{ |
||||
|
u256 totalReq = value() + fee(); |
||||
|
for (auto i: m_myKeys) |
||||
|
if (ethereum()->balanceAt(i.address()) >= totalReq) |
||||
|
{ |
||||
|
State st(ethereum()->postState()); |
||||
|
Secret s = i.secret(); |
||||
|
Transaction t = isCreation() ? |
||||
|
Transaction(value(), gasPrice(), ui->gas->value(), m_data, st.transactionsFrom(dev::toAddress(s)), s) : |
||||
|
Transaction(value(), gasPrice(), ui->gas->value(), m_context->fromString(ui->destination->currentText()), m_data, st.transactionsFrom(dev::toAddress(s)), s); |
||||
|
Debugger dw(m_context, this); |
||||
|
Executive e(st, ethereum()->blockChain(), 0); |
||||
|
dw.populate(e, t); |
||||
|
dw.exec(); |
||||
|
return; |
||||
|
} |
||||
|
QMessageBox::critical(this, "Transaction Failed", "Couldn't make transaction: no single account contains at least the required amount."); |
||||
|
} |
||||
|
catch (dev::Exception const& _e) |
||||
|
{ |
||||
|
QMessageBox::critical(this, "Transaction Failed", "Couldn't make transaction. Low-level error: " + QString::fromStdString(diagnostic_information(_e))); |
||||
|
// this output is aimed at developers, reconsider using _e.what for more user friendly output.
|
||||
|
} |
||||
|
} |
@ -0,0 +1,82 @@ |
|||||
|
/*
|
||||
|
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 Transact.h
|
||||
|
* @author Gav Wood <i@gavwood.com> |
||||
|
* @date 2015 |
||||
|
*/ |
||||
|
|
||||
|
#pragma once |
||||
|
|
||||
|
#include <libdevcore/RLP.h> |
||||
|
#include <libethcore/CommonEth.h> |
||||
|
#include <libethereum/Transaction.h> |
||||
|
#include <QDialog> |
||||
|
#include <QMap> |
||||
|
#include <QList> |
||||
|
#include "Context.h" |
||||
|
|
||||
|
namespace Ui { class Transact; } |
||||
|
namespace dev { namespace eth { class Client; } } |
||||
|
namespace dev { namespace solidity { class CompilerStack; } } |
||||
|
|
||||
|
class Transact: public QDialog |
||||
|
{ |
||||
|
Q_OBJECT |
||||
|
|
||||
|
public: |
||||
|
explicit Transact(Context* _context, QWidget* _parent = 0); |
||||
|
~Transact(); |
||||
|
|
||||
|
void setEnvironment(QList<dev::KeyPair> _myKeys, dev::eth::Client* _eth, NatSpecFace* _natSpecDB); |
||||
|
|
||||
|
private slots: |
||||
|
void on_destination_currentTextChanged(); |
||||
|
void on_value_valueChanged() { updateFee(); } |
||||
|
void on_gas_valueChanged() { updateFee(); } |
||||
|
void on_valueUnits_currentIndexChanged() { updateFee(); } |
||||
|
void on_gasPriceUnits_currentIndexChanged() { updateFee(); } |
||||
|
void on_gasPrice_valueChanged() { updateFee(); } |
||||
|
void on_data_textChanged() { rejigData(); } |
||||
|
void on_optimize_clicked() { rejigData(); } |
||||
|
void on_send_clicked(); |
||||
|
void on_debug_clicked(); |
||||
|
void on_cancel_clicked() { close(); } |
||||
|
|
||||
|
private: |
||||
|
dev::eth::Client* ethereum() { return m_ethereum; } |
||||
|
void rejigData(); |
||||
|
|
||||
|
void updateDestination(); |
||||
|
void updateFee(); |
||||
|
bool isCreation() const; |
||||
|
dev::u256 fee() const; |
||||
|
dev::u256 total() const; |
||||
|
dev::u256 value() const; |
||||
|
dev::u256 gasPrice() const; |
||||
|
|
||||
|
std::string getFunctionHashes(dev::solidity::CompilerStack const& _compiler, std::string const& _contractName = std::string()); |
||||
|
|
||||
|
Ui::Transact* ui; |
||||
|
|
||||
|
unsigned m_backupGas; |
||||
|
dev::bytes m_data; |
||||
|
|
||||
|
QList<dev::KeyPair> m_myKeys; |
||||
|
dev::eth::Client* m_ethereum; |
||||
|
Context* m_context; |
||||
|
NatSpecFace* m_natSpecDB; |
||||
|
}; |
@ -0,0 +1,244 @@ |
|||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||
|
<ui version="4.0"> |
||||
|
<class>Transact</class> |
||||
|
<widget class="QDialog" name="Transact"> |
||||
|
<property name="geometry"> |
||||
|
<rect> |
||||
|
<x>0</x> |
||||
|
<y>0</y> |
||||
|
<width>543</width> |
||||
|
<height>695</height> |
||||
|
</rect> |
||||
|
</property> |
||||
|
<property name="windowTitle"> |
||||
|
<string>Dialog</string> |
||||
|
</property> |
||||
|
<layout class="QGridLayout" name="gridLayout"> |
||||
|
<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>&Amount</string> |
||||
|
</property> |
||||
|
<property name="buddy"> |
||||
|
<cstring>value</cstring> |
||||
|
</property> |
||||
|
</widget> |
||||
|
</item> |
||||
|
<item row="1" column="1" colspan="3"> |
||||
|
<widget class="QLineEdit" name="calculatedName"> |
||||
|
<property name="enabled"> |
||||
|
<bool>false</bool> |
||||
|
</property> |
||||
|
<property name="readOnly"> |
||||
|
<bool>true</bool> |
||||
|
</property> |
||||
|
<property name="placeholderText"> |
||||
|
<string/> |
||||
|
</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"> |
||||
|
<property name="frameShape"> |
||||
|
<enum>QFrame::NoFrame</enum> |
||||
|
</property> |
||||
|
<property name="lineWidth"> |
||||
|
<number>0</number> |
||||
|
</property> |
||||
|
</widget> |
||||
|
<widget class="QTextEdit" name="code"> |
||||
|
<property name="focusPolicy"> |
||||
|
<enum>Qt::ClickFocus</enum> |
||||
|
</property> |
||||
|
<property name="frameShape"> |
||||
|
<enum>QFrame::NoFrame</enum> |
||||
|
</property> |
||||
|
<property name="lineWidth"> |
||||
|
<number>0</number> |
||||
|
</property> |
||||
|
<property name="readOnly"> |
||||
|
<bool>true</bool> |
||||
|
</property> |
||||
|
</widget> |
||||
|
</widget> |
||||
|
</item> |
||||
|
<item row="3" column="3"> |
||||
|
<widget class="QComboBox" name="gasPriceUnits"/> |
||||
|
</item> |
||||
|
<item row="4" column="1" colspan="2"> |
||||
|
<widget class="QLabel" name="fee"> |
||||
|
<property name="sizePolicy"> |
||||
|
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred"> |
||||
|
<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> |
||||
|
<item row="0" column="0"> |
||||
|
<widget class="QLabel" name="label5"> |
||||
|
<property name="sizePolicy"> |
||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Preferred"> |
||||
|
<horstretch>0</horstretch> |
||||
|
<verstretch>0</verstretch> |
||||
|
</sizepolicy> |
||||
|
</property> |
||||
|
<property name="text"> |
||||
|
<string>&To</string> |
||||
|
</property> |
||||
|
<property name="buddy"> |
||||
|
<cstring>destination</cstring> |
||||
|
</property> |
||||
|
</widget> |
||||
|
</item> |
||||
|
<item row="2" column="3"> |
||||
|
<widget class="QComboBox" name="valueUnits"/> |
||||
|
</item> |
||||
|
<item row="7" column="2"> |
||||
|
<widget class="QPushButton" name="debug"> |
||||
|
<property name="text"> |
||||
|
<string>&Debug</string> |
||||
|
</property> |
||||
|
</widget> |
||||
|
</item> |
||||
|
<item row="7" column="3"> |
||||
|
<widget class="QPushButton" name="send"> |
||||
|
<property name="text"> |
||||
|
<string>&Execute</string> |
||||
|
</property> |
||||
|
<property name="default"> |
||||
|
<bool>false</bool> |
||||
|
</property> |
||||
|
</widget> |
||||
|
</item> |
||||
|
<item row="3" column="0"> |
||||
|
<widget class="QLabel" name="label_6"> |
||||
|
<property name="text"> |
||||
|
<string>&Gas</string> |
||||
|
</property> |
||||
|
<property name="buddy"> |
||||
|
<cstring>gas</cstring> |
||||
|
</property> |
||||
|
</widget> |
||||
|
</item> |
||||
|
<item row="3" column="1"> |
||||
|
<widget class="QSpinBox" name="gas"> |
||||
|
<property name="suffix"> |
||||
|
<string> gas</string> |
||||
|
</property> |
||||
|
<property name="minimum"> |
||||
|
<number>1</number> |
||||
|
</property> |
||||
|
<property name="maximum"> |
||||
|
<number>430000000</number> |
||||
|
</property> |
||||
|
<property name="value"> |
||||
|
<number>10000</number> |
||||
|
</property> |
||||
|
</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="4" column="3"> |
||||
|
<widget class="QCheckBox" name="optimize"> |
||||
|
<property name="text"> |
||||
|
<string>&Optimise</string> |
||||
|
</property> |
||||
|
<property name="checked"> |
||||
|
<bool>true</bool> |
||||
|
</property> |
||||
|
</widget> |
||||
|
</item> |
||||
|
<item row="4" column="0"> |
||||
|
<widget class="QLabel" name="label_2"> |
||||
|
<property name="sizePolicy"> |
||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Maximum"> |
||||
|
<horstretch>0</horstretch> |
||||
|
<verstretch>0</verstretch> |
||||
|
</sizepolicy> |
||||
|
</property> |
||||
|
<property name="text"> |
||||
|
<string>D&ata</string> |
||||
|
</property> |
||||
|
<property name="alignment"> |
||||
|
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set> |
||||
|
</property> |
||||
|
<property name="buddy"> |
||||
|
<cstring>data</cstring> |
||||
|
</property> |
||||
|
</widget> |
||||
|
</item> |
||||
|
<item row="0" column="1" colspan="3"> |
||||
|
<widget class="QComboBox" name="destination"> |
||||
|
<property name="editable"> |
||||
|
<bool>true</bool> |
||||
|
</property> |
||||
|
<item> |
||||
|
<property name="text"> |
||||
|
<string>(Create Contract)</string> |
||||
|
</property> |
||||
|
</item> |
||||
|
</widget> |
||||
|
</item> |
||||
|
<item row="6" column="0" colspan="4"> |
||||
|
<widget class="QLabel" name="total"> |
||||
|
<property name="sizePolicy"> |
||||
|
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred"> |
||||
|
<horstretch>0</horstretch> |
||||
|
<verstretch>0</verstretch> |
||||
|
</sizepolicy> |
||||
|
</property> |
||||
|
<property name="text"> |
||||
|
<string/> |
||||
|
</property> |
||||
|
</widget> |
||||
|
</item> |
||||
|
<item row="7" column="0"> |
||||
|
<widget class="QPushButton" name="cancel"> |
||||
|
<property name="text"> |
||||
|
<string>&Cancel</string> |
||||
|
</property> |
||||
|
<property name="shortcut"> |
||||
|
<string>Esc</string> |
||||
|
</property> |
||||
|
</widget> |
||||
|
</item> |
||||
|
</layout> |
||||
|
</widget> |
||||
|
<resources/> |
||||
|
<connections/> |
||||
|
</ui> |
@ -0,0 +1,47 @@ |
|||||
|
# Find microhttpd |
||||
|
# |
||||
|
# Find the microhttpd includes and library |
||||
|
# |
||||
|
# if you need to add a custom library search path, do it via via CMAKE_PREFIX_PATH |
||||
|
# |
||||
|
# This module defines |
||||
|
# MHD_INCLUDE_DIRS, where to find header, etc. |
||||
|
# MHD_LIBRARIES, the libraries needed to use jsoncpp. |
||||
|
# MHD_FOUND, If false, do not try to use jsoncpp. |
||||
|
|
||||
|
find_path( |
||||
|
MHD_INCLUDE_DIR |
||||
|
NAMES microhttpd.h |
||||
|
DOC "microhttpd include dir" |
||||
|
) |
||||
|
|
||||
|
find_library( |
||||
|
MHD_LIBRARY |
||||
|
NAMES microhttpd microhttpd-10 libmicrohttpd libmicrohttpd-dll |
||||
|
DOC "microhttpd library" |
||||
|
) |
||||
|
|
||||
|
set(MHD_INCLUDE_DIRS ${MHD_INCLUDE_DIR}) |
||||
|
set(MHD_LIBRARIES ${MHD_LIBRARY}) |
||||
|
|
||||
|
# debug library on windows |
||||
|
# same naming convention as in QT (appending debug library with d) |
||||
|
# boost is using the same "hack" as us with "optimized" and "debug" |
||||
|
# official MHD project actually uses _d suffix |
||||
|
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") |
||||
|
find_library( |
||||
|
MHD_LIBRARY_DEBUG |
||||
|
NAMES microhttpd_d microhttpd-10_d libmicrohttpd_d libmicrohttpd-dll_d |
||||
|
DOC "mhd debug library" |
||||
|
) |
||||
|
|
||||
|
set(MHD_LIBRARIES optimized ${MHD_LIBRARIES} debug ${MHD_LIBRARY_DEBUG}) |
||||
|
|
||||
|
endif() |
||||
|
|
||||
|
include(FindPackageHandleStandardArgs) |
||||
|
find_package_handle_standard_args(mhd DEFAULT_MSG |
||||
|
MHD_INCLUDE_DIR MHD_LIBRARY) |
||||
|
|
||||
|
mark_as_advanced(MHD_INCLUDE_DIR MHD_LIBRARY) |
||||
|
|
@ -1,41 +0,0 @@ |
|||||
cmake_policy(SET CMP0015 NEW) |
|
||||
# let cmake autolink dependencies on windows |
|
||||
cmake_policy(SET CMP0020 NEW) |
|
||||
# this policy was introduced in cmake 3.0 |
|
||||
# remove if, once 3.0 will be used on unix |
|
||||
if (${CMAKE_MAJOR_VERSION} GREATER 2) |
|
||||
# old policy do not use MACOSX_RPATH |
|
||||
cmake_policy(SET CMP0042 OLD) |
|
||||
cmake_policy(SET CMP0043 OLD) |
|
||||
endif() |
|
||||
|
|
||||
set(CMAKE_INCLUDE_CURRENT_DIR ON) |
|
||||
aux_source_directory(. SRC_LIST) |
|
||||
|
|
||||
include_directories(${JSON_RPC_CPP_INCLUDE_DIRS}) |
|
||||
include_directories(..) |
|
||||
|
|
||||
set(EXECUTABLE qwebthree) |
|
||||
|
|
||||
file(GLOB HEADERS "*.h") |
|
||||
|
|
||||
if(ETH_STATIC) |
|
||||
add_library(${EXECUTABLE} STATIC ${RESOURCE_ADDED} ${SRC_LIST} ${HEADERS}) |
|
||||
else() |
|
||||
add_library(${EXECUTABLE} SHARED ${RESOURCE_ADDED} ${SRC_LIST} ${HEADERS}) |
|
||||
endif() |
|
||||
|
|
||||
target_link_libraries(${EXECUTABLE} Qt5::Core) |
|
||||
target_link_libraries(${EXECUTABLE} Qt5::Gui) |
|
||||
target_link_libraries(${EXECUTABLE} Qt5::WebKit) |
|
||||
target_link_libraries(${EXECUTABLE} Qt5::WebKitWidgets) |
|
||||
target_link_libraries(${EXECUTABLE} Qt5::Widgets) |
|
||||
target_link_libraries(${EXECUTABLE} Qt5::Network) |
|
||||
target_link_libraries(${EXECUTABLE} Qt5::Quick) |
|
||||
target_link_libraries(${EXECUTABLE} Qt5::Qml) |
|
||||
target_link_libraries(${EXECUTABLE} ${JSON_RPC_CPP_SERVER_LIBRARIES}) |
|
||||
target_link_libraries(${EXECUTABLE} ethereum) |
|
||||
target_link_libraries(${EXECUTABLE} secp256k1) |
|
||||
|
|
||||
install( TARGETS ${EXECUTABLE} ARCHIVE DESTINATION lib LIBRARY DESTINATION lib ) |
|
||||
install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} ) |
|
@ -1,107 +0,0 @@ |
|||||
/*
|
|
||||
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 QWebThree.cpp
|
|
||||
* @authors: |
|
||||
* Gav Wood <i@gavwood.com> |
|
||||
* Marek Kotewicz <marek@ethdev.com> |
|
||||
* @date 2014 |
|
||||
*/ |
|
||||
|
|
||||
#include <QtCore/QtCore> |
|
||||
#include "QWebThree.h" |
|
||||
|
|
||||
using namespace std; |
|
||||
|
|
||||
QWebThree::QWebThree(QObject* _p): QObject(_p) |
|
||||
{ |
|
||||
moveToThread(_p->thread()); |
|
||||
} |
|
||||
|
|
||||
QWebThree::~QWebThree() |
|
||||
{ |
|
||||
clientDieing(); |
|
||||
} |
|
||||
|
|
||||
void QWebThree::clientDieing() |
|
||||
{ |
|
||||
this->disconnect(); |
|
||||
} |
|
||||
|
|
||||
QString QWebThree::callMethod(QString _json) |
|
||||
{ |
|
||||
emit processData(_json, ""); // it's synchronous
|
|
||||
return m_response; |
|
||||
} |
|
||||
|
|
||||
void QWebThree::onDataProcessed(QString _json, QString) |
|
||||
{ |
|
||||
QJsonObject f = QJsonDocument::fromJson(_json.toUtf8()).object(); |
|
||||
syncResponse(QString::fromUtf8(QJsonDocument(f).toJson())); |
|
||||
} |
|
||||
|
|
||||
void QWebThree::syncResponse(QString _json) |
|
||||
{ |
|
||||
m_response = _json; |
|
||||
} |
|
||||
|
|
||||
QWebThreeConnector::QWebThreeConnector() |
|
||||
{ |
|
||||
} |
|
||||
|
|
||||
QWebThreeConnector::~QWebThreeConnector() |
|
||||
{ |
|
||||
StopListening(); |
|
||||
} |
|
||||
|
|
||||
void QWebThreeConnector::setQWeb(QWebThree* _q) |
|
||||
{ |
|
||||
m_qweb = _q; |
|
||||
if (m_isListening) |
|
||||
{ |
|
||||
StopListening(); |
|
||||
StartListening(); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
bool QWebThreeConnector::StartListening() |
|
||||
{ |
|
||||
m_isListening = true; |
|
||||
if (m_qweb) |
|
||||
{ |
|
||||
connect(m_qweb, SIGNAL(processData(QString, QString)), this, SLOT(onProcessData(QString, QString))); |
|
||||
connect(this, SIGNAL(dataProcessed(QString, QString)), m_qweb, SLOT(onDataProcessed(QString, QString))); |
|
||||
} |
|
||||
return true; |
|
||||
} |
|
||||
|
|
||||
bool QWebThreeConnector::StopListening() |
|
||||
{ |
|
||||
this->disconnect(); |
|
||||
return true; |
|
||||
} |
|
||||
|
|
||||
bool QWebThreeConnector::SendResponse(std::string const& _response, void* _addInfo) |
|
||||
{ |
|
||||
emit dataProcessed(QString::fromStdString(_response), *(QString*)_addInfo); |
|
||||
return true; |
|
||||
} |
|
||||
|
|
||||
void QWebThreeConnector::onProcessData(QString const& _json, QString const& _addInfo) |
|
||||
{ |
|
||||
OnRequest(_json.toStdString(), (void*)&_addInfo); |
|
||||
} |
|
||||
|
|
@ -1,89 +0,0 @@ |
|||||
/*
|
|
||||
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 QWebThree.h
|
|
||||
* @authors: |
|
||||
* Gav Wood <i@gavwood.com> |
|
||||
* Marek Kotewicz <marek@ethdev.com> |
|
||||
* @date 2014 |
|
||||
*/ |
|
||||
|
|
||||
#pragma once |
|
||||
|
|
||||
#include <QtCore/QObject> |
|
||||
#include <QtCore/QString> |
|
||||
#include <jsonrpccpp/server.h> |
|
||||
|
|
||||
class QWebThree: public QObject |
|
||||
{ |
|
||||
Q_OBJECT |
|
||||
|
|
||||
public: |
|
||||
QWebThree(QObject* _p); |
|
||||
virtual ~QWebThree(); |
|
||||
void clientDieing(); |
|
||||
|
|
||||
Q_INVOKABLE QString callMethod(QString _json); |
|
||||
void syncResponse(QString _json); |
|
||||
|
|
||||
public slots: |
|
||||
void onDataProcessed(QString _json, QString _addInfo); |
|
||||
|
|
||||
signals: |
|
||||
void processData(QString _json, QString _addInfo); |
|
||||
void response(QString _json); |
|
||||
void onNewId(QString _id); |
|
||||
|
|
||||
private: |
|
||||
QString m_response; |
|
||||
}; |
|
||||
|
|
||||
class QWebThreeConnector: public QObject, public jsonrpc::AbstractServerConnector |
|
||||
{ |
|
||||
Q_OBJECT |
|
||||
|
|
||||
public: |
|
||||
QWebThreeConnector(); |
|
||||
virtual ~QWebThreeConnector(); |
|
||||
|
|
||||
void setQWeb(QWebThree *_q); |
|
||||
|
|
||||
virtual bool StartListening(); |
|
||||
virtual bool StopListening(); |
|
||||
virtual bool SendResponse(std::string const& _response, void* _addInfo = NULL); |
|
||||
|
|
||||
public slots: |
|
||||
void onProcessData(QString const& _json, QString const& _addInfo); |
|
||||
|
|
||||
signals: |
|
||||
void dataProcessed(QString const& _json, QString const& _addInfo); |
|
||||
|
|
||||
private: |
|
||||
QWebThree* m_qweb = nullptr; |
|
||||
bool m_isListening; |
|
||||
}; |
|
||||
|
|
||||
#define QETH_INSTALL_JS_NAMESPACE(_frame, _env, qweb) [_frame, _env, qweb]() \ |
|
||||
{ \ |
|
||||
_frame->disconnect(); \ |
|
||||
_frame->addToJavaScriptWindowObject("_web3", qweb, QWebFrame::ScriptOwnership); \ |
|
||||
_frame->addToJavaScriptWindowObject("env", _env, QWebFrame::QtOwnership); \ |
|
||||
_frame->evaluateJavaScript(contentsOfQResource(":/js/bignumber.min.js")); \ |
|
||||
_frame->evaluateJavaScript(contentsOfQResource(":/js/webthree.js")); \ |
|
||||
_frame->evaluateJavaScript(contentsOfQResource(":/js/setup.js")); \ |
|
||||
} |
|
||||
|
|
||||
|
|
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue