Paweł Bylica
10 years ago
249 changed files with 13186 additions and 5872 deletions
@ -0,0 +1,7 @@ |
|||
#pragma once |
|||
|
|||
#define ETH_COMMIT_HASH @ETH_COMMIT_HASH@ |
|||
#define ETH_CLEAN_REPO @ETH_CLEAN_REPO@ |
|||
#define ETH_BUILD_TYPE @ETH_BUILD_TYPE@ |
|||
#define ETH_BUILD_PLATFORM @ETH_BUILD_PLATFORM@ |
|||
|
@ -1,55 +0,0 @@ |
|||
CURRENT_SOURCE_DIR=$1 |
|||
CURRENT_BINARY_DIR=$2 |
|||
BUILD_TYPE=$3 |
|||
BUILD_PLATFORM=$4 |
|||
|
|||
echo "Current source dir: $CURRENT_SOURCE_DIR" |
|||
echo "Current binary dir: $CURRENT_BINARY_DIR" |
|||
echo "Build type: $BUILD_TYPE" |
|||
echo "Build platform: $BUILD_PLATFORM" |
|||
|
|||
if [[ -e "$CURRENT_SOURCE_DIR/BuildInfo.h" ]] |
|||
then |
|||
echo "Using existing BuildInfo.h" |
|||
cp $CURRENT_SOURCE_DIR/BuildInfo.h $CURRENT_BINARY_DIR/BuildInfo.h.tmp |
|||
else |
|||
if [[ -e "$CURRENT_SOURCE_DIR/.git" ]] |
|||
then |
|||
ETH_COMMIT_HASH=$(git --git-dir=$CURRENT_SOURCE_DIR/.git --work-tree=$CURRENT_SOURCE_DIR rev-parse HEAD) |
|||
ETH_LOCAL_CHANGES=$(git --git-dir=$CURRENT_SOURCE_DIR/.git --work-tree=$CURRENT_SOURCE_DIR diff --shortstat) |
|||
if [[ -z "$ETH_LOCAL_CHANGES" ]] |
|||
then |
|||
ETH_CLEAN_REPO=1 |
|||
else |
|||
ETH_CLEAN_REPO=0 |
|||
fi |
|||
|
|||
echo "Commit hash: ${ETH_COMMIT_HASH} (Clean: ${ETH_CLEAN_REPO} - ${ETH_LOCAL_CHANGES})" |
|||
else |
|||
echo "Unknown repo." |
|||
ETH_COMMIT_HASH=0 |
|||
ETH_CLEAN_REPO=1 |
|||
fi |
|||
|
|||
echo "// This file was automatically generated by cmake" > $CURRENT_BINARY_DIR/BuildInfo.h.tmp |
|||
echo "" >> $CURRENT_BINARY_DIR/BuildInfo.h.tmp |
|||
echo "#pragma once" >> $CURRENT_BINARY_DIR/BuildInfo.h.tmp |
|||
echo "" >> $CURRENT_BINARY_DIR/BuildInfo.h.tmp |
|||
echo "#define ETH_COMMIT_HASH $ETH_COMMIT_HASH" >> $CURRENT_BINARY_DIR/BuildInfo.h.tmp |
|||
echo "#define ETH_CLEAN_REPO $ETH_CLEAN_REPO" >> $CURRENT_BINARY_DIR/BuildInfo.h.tmp |
|||
echo "#define ETH_BUILD_TYPE $BUILD_TYPE" >> $CURRENT_BINARY_DIR/BuildInfo.h.tmp |
|||
echo "#define ETH_BUILD_PLATFORM $BUILD_PLATFORM" >> $CURRENT_BINARY_DIR/BuildInfo.h.tmp |
|||
fi |
|||
|
|||
if [[ -e "$CURRENT_BINARY_DIR/BuildInfo.h" ]] |
|||
then |
|||
DIFF=$(diff $CURRENT_BINARY_DIR/BuildInfo.h $CURRENT_BINARY_DIR/BuildInfo.h.tmp) |
|||
if [[ -z "$DIFF" ]] |
|||
then |
|||
rm $CURRENT_BINARY_DIR/BuildInfo.h.tmp |
|||
else |
|||
mv $CURRENT_BINARY_DIR/BuildInfo.h.tmp $CURRENT_BINARY_DIR/BuildInfo.h |
|||
fi |
|||
else |
|||
mv $CURRENT_BINARY_DIR/BuildInfo.h.tmp $CURRENT_BINARY_DIR/BuildInfo.h |
|||
fi |
@ -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,24 @@ |
|||
# |
|||
# renames the file if it is different from its destination |
|||
include(CMakeParseArguments) |
|||
# |
|||
macro(replace_if_different SOURCE DST) |
|||
set(extra_macro_args ${ARGN}) |
|||
set(options CREATE) |
|||
set(one_value_args) |
|||
set(multi_value_args) |
|||
cmake_parse_arguments(REPLACE_IF_DIFFERENT "${options}" "${one_value_args}" "${multi_value_args}" "${extra_macro_args}") |
|||
|
|||
if (REPLACE_IF_DIFFERENT_CREATE AND (NOT (EXISTS "${DST}"))) |
|||
file(WRITE "${DST}" "") |
|||
endif() |
|||
|
|||
execute_process(COMMAND ${CMAKE_COMMAND} -E compare_files "${SOURCE}" "${DST}" RESULT_VARIABLE DIFFERENT) |
|||
|
|||
if (DIFFERENT) |
|||
execute_process(COMMAND ${CMAKE_COMMAND} -E rename "${SOURCE}" "${DST}") |
|||
else() |
|||
execute_process(COMMAND ${CMAKE_COMMAND} -E remove "${SOURCE}") |
|||
endif() |
|||
endmacro() |
|||
|
@ -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) |
|||
|
@ -0,0 +1,48 @@ |
|||
# generates BuildInfo.h |
|||
# |
|||
# this module expects |
|||
# ETH_SOURCE_DIR - main CMAKE_SOURCE_DIR |
|||
# ETH_DST_DIR - main CMAKE_BINARY_DIR |
|||
# ETH_BUILD_TYPE |
|||
# ETH_BUILD_PLATFORM |
|||
# |
|||
# example usage: |
|||
# cmake -DETH_SOURCE_DIR=. -DETH_DST_DIR=build -DETH_BUILD_TYPE=Debug -DETH_BUILD_PLATFORM=mac -P scripts/buildinfo.cmake |
|||
|
|||
if (NOT ETH_BUILD_TYPE) |
|||
set(ETH_BUILD_TYPE "unknown") |
|||
endif() |
|||
|
|||
if (NOT ETH_BUILD_PLATFORM) |
|||
set(ETH_BUILD_PLATFORM "unknown") |
|||
endif() |
|||
|
|||
execute_process( |
|||
COMMAND git --git-dir=${ETH_SOURCE_DIR}/.git --work-tree=${ETH_SOURCE_DIR} rev-parse HEAD |
|||
OUTPUT_VARIABLE ETH_COMMIT_HASH OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_QUIET |
|||
) |
|||
|
|||
if (NOT ETH_COMMIT_HASH) |
|||
set(ETH_COMMIT_HASH 0) |
|||
endif() |
|||
|
|||
execute_process( |
|||
COMMAND git --git-dir=${ETH_SOURCE_DIR}/.git --work-tree=${ETH_SOURCE_DIR} diff --shortstat |
|||
OUTPUT_VARIABLE ETH_LOCAL_CHANGES OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_QUIET |
|||
) |
|||
|
|||
if (ETH_LOCAL_CHANGES) |
|||
set(ETH_CLEAN_REPO 0) |
|||
else() |
|||
set(ETH_CLEAN_REPO 1) |
|||
endif() |
|||
|
|||
set(INFILE "${ETH_SOURCE_DIR}/BuildInfo.h.in") |
|||
set(TMPFILE "${ETH_DST_DIR}/BuildInfo.h.tmp") |
|||
set(OUTFILE "${ETH_DST_DIR}/BuildInfo.h") |
|||
|
|||
configure_file("${INFILE}" "${TMPFILE}") |
|||
|
|||
include("${ETH_SOURCE_DIR}/cmake/EthUtils.cmake") |
|||
replace_if_different("${TMPFILE}" "${OUTFILE}" CREATE) |
|||
|
@ -0,0 +1,14 @@ |
|||
# adds possibility to run configure_file as buildstep |
|||
# reference: |
|||
# http://www.cmake.org/pipermail/cmake/2012-May/050227.html |
|||
# |
|||
# This module expects |
|||
# INFILE |
|||
# OUTFILE |
|||
# other custom vars |
|||
# |
|||
# example usage: |
|||
# cmake -DINFILE=blah.in -DOUTFILE=blah.out -Dvar1=value1 -Dvar2=value2 -P scripts/configure.cmake |
|||
|
|||
configure_file(${INFILE} ${OUTFILE}) |
|||
|
@ -0,0 +1,45 @@ |
|||
# generates JSONRPC Stub Server && Client |
|||
# |
|||
# this script expects |
|||
# ETH_SOURCE_DIR - main CMAKE_SOURCE_DIR |
|||
# ETH_SPEC_PATH |
|||
# ETH_SERVER_DIR |
|||
# ETH_CLIENT_DIR |
|||
# ETH_SERVER_NAME |
|||
# ETH_CLIENT_NAME |
|||
# ETH_JSON_RPC_STUB |
|||
# |
|||
# example usage: |
|||
# cmake -DETH_SPEC_PATH=spec.json -DETH_SERVER_DIR=libweb3jsonrpc -DETH_CLIENT_DIR=test |
|||
# -DETH_SERVER_NAME=AbstractWebThreeStubServer -DETH_CLIENT_NAME=WebThreeStubClient -DETH_JSON_RPC_STUB=/usr/local/bin/jsonrpcstub |
|||
|
|||
# by default jsonrpcstub produces files in lowercase, we want to stick to this |
|||
string(TOLOWER ${ETH_SERVER_NAME} ETH_SERVER_NAME_LOWER) |
|||
string(TOLOWER ${ETH_CLIENT_NAME} ETH_CLIENT_NAME_LOWER) |
|||
|
|||
# setup names |
|||
set(SERVER_TMPFILE "${ETH_SERVER_DIR}/${ETH_SERVER_NAME_LOWER}.h.tmp") |
|||
set(SERVER_OUTFILE "${ETH_SERVER_DIR}/${ETH_SERVER_NAME_LOWER}.h") |
|||
set(CLIENT_TMPFILE "${ETH_CLIENT_DIR}/${ETH_CLIENT_NAME_LOWER}.h.tmp") |
|||
set(CLIENT_OUTFILE "${ETH_CLIENT_DIR}/${ETH_CLIENT_NAME_LOWER}.h") |
|||
|
|||
# create tmp files |
|||
execute_process( |
|||
COMMAND ${ETH_JSON_RPC_STUB} ${ETH_SPEC_PATH} |
|||
--cpp-server=${ETH_SERVER_NAME} --cpp-server-file=${SERVER_TMPFILE} |
|||
--cpp-client=${ETH_CLIENT_NAME} --cpp-client-file=${CLIENT_TMPFILE} |
|||
OUTPUT_VARIABLE ERR ERROR_QUIET |
|||
) |
|||
|
|||
# don't throw fatal error on jsonrpcstub error, someone might have old version of jsonrpcstub, |
|||
# he does not need to upgrade it if he is not working on JSON RPC |
|||
# show him warning instead |
|||
if (ERR) |
|||
message(WARNING "Your version of jsonrcpstub tool is not supported. Please upgrade it.") |
|||
message(WARNING "${ERR}") |
|||
else() |
|||
include("${ETH_SOURCE_DIR}/cmake/EthUtils.cmake") |
|||
replace_if_different("${SERVER_TMPFILE}" "${SERVER_OUTFILE}") |
|||
replace_if_different("${CLIENT_TMPFILE}" "${CLIENT_OUTFILE}") |
|||
endif() |
|||
|
@ -0,0 +1,83 @@ |
|||
/*
|
|||
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 Peer.cpp
|
|||
* @author Alex Leverington <nessence@gmail.com> |
|||
* @author Gav Wood <i@gavwood.com> |
|||
* @date 2014 |
|||
*/ |
|||
|
|||
#include "Peer.h" |
|||
using namespace std; |
|||
using namespace dev; |
|||
using namespace dev::p2p; |
|||
|
|||
namespace dev |
|||
{ |
|||
|
|||
namespace p2p |
|||
{ |
|||
|
|||
bool Peer::shouldReconnect() const |
|||
{ |
|||
return chrono::system_clock::now() > m_lastAttempted + chrono::seconds(fallbackSeconds()); |
|||
} |
|||
|
|||
unsigned Peer::fallbackSeconds() const |
|||
{ |
|||
switch (m_lastDisconnect) |
|||
{ |
|||
case BadProtocol: |
|||
return 30 * (m_failedAttempts + 1); |
|||
case UselessPeer: |
|||
case TooManyPeers: |
|||
case ClientQuit: |
|||
return 15 * (m_failedAttempts + 1); |
|||
case NoDisconnect: |
|||
default: |
|||
if (m_failedAttempts < 5) |
|||
return m_failedAttempts ? m_failedAttempts * 5 : 5; |
|||
else if (m_failedAttempts < 15) |
|||
return 25 + (m_failedAttempts - 5) * 10; |
|||
else |
|||
return 25 + 100 + (m_failedAttempts - 15) * 20; |
|||
} |
|||
} |
|||
|
|||
bool Peer::operator<(Peer const& _p) const |
|||
{ |
|||
if (isOffline() != _p.isOffline()) |
|||
return isOffline(); |
|||
else if (isOffline()) |
|||
if (m_lastAttempted == _p.m_lastAttempted) |
|||
return m_failedAttempts < _p.m_failedAttempts; |
|||
else |
|||
return m_lastAttempted < _p.m_lastAttempted; |
|||
else |
|||
if (m_score == _p.m_score) |
|||
if (m_rating == _p.m_rating) |
|||
if (m_failedAttempts == _p.m_failedAttempts) |
|||
return id < _p.id; |
|||
else |
|||
return m_failedAttempts < _p.m_failedAttempts; |
|||
else |
|||
return m_rating < _p.m_rating; |
|||
else |
|||
return m_score < _p.m_score; |
|||
} |
|||
|
|||
} |
|||
} |
@ -0,0 +1,97 @@ |
|||
/*
|
|||
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 Peer.h
|
|||
* @author Alex Leverington <nessence@gmail.com> |
|||
* @author Gav Wood <i@gavwood.com> |
|||
* @date 2014 |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
#include "Common.h" |
|||
|
|||
namespace dev |
|||
{ |
|||
|
|||
namespace p2p |
|||
{ |
|||
|
|||
/**
|
|||
* @brief Representation of connectivity state and all other pertinent Peer metadata. |
|||
* A Peer represents connectivity between two nodes, which in this case, are the host |
|||
* and remote nodes. |
|||
* |
|||
* State information necessary for loading network topology is maintained by NodeTable. |
|||
* |
|||
* @todo Implement 'bool required' |
|||
* @todo reputation: Move score, rating to capability-specific map (&& remove friend class) |
|||
* @todo reputation: implement via origin-tagged events |
|||
* @todo Populate metadata upon construction; save when destroyed. |
|||
* @todo Metadata for peers needs to be handled via a storage backend. |
|||
* Specifically, peers can be utilized in a variety of |
|||
* many-to-many relationships while also needing to modify shared instances of |
|||
* those peers. Modifying these properties via a storage backend alleviates |
|||
* Host of the responsibility. (&& remove save/restoreNetwork) |
|||
* @todo reimplement recording of historical session information on per-transport basis |
|||
* @todo rebuild nodetable when localNetworking is enabled/disabled |
|||
* @todo move attributes into protected |
|||
*/ |
|||
class Peer: public Node |
|||
{ |
|||
friend class Session; /// Allows Session to update score and rating.
|
|||
friend class Host; /// For Host: saveNetwork(), restoreNetwork()
|
|||
|
|||
public: |
|||
bool isOffline() const { return !m_session.lock(); } |
|||
|
|||
bi::tcp::endpoint const& peerEndpoint() const { return endpoint.tcp; } |
|||
|
|||
virtual bool operator<(Peer const& _p) const; |
|||
|
|||
/// WIP: Returns current peer rating.
|
|||
int rating() const { return m_rating; } |
|||
|
|||
/// Return true if connection attempt should be made to this peer or false if
|
|||
bool shouldReconnect() const; |
|||
|
|||
/// Number of times connection has been attempted to peer.
|
|||
int failedAttempts() const { return m_failedAttempts; } |
|||
|
|||
/// Reason peer was previously disconnected.
|
|||
DisconnectReason lastDisconnect() const { return m_lastDisconnect; } |
|||
|
|||
protected: |
|||
/// Returns number of seconds to wait until attempting connection, based on attempted connection history.
|
|||
unsigned fallbackSeconds() const; |
|||
|
|||
int m_score = 0; ///< All time cumulative.
|
|||
int m_rating = 0; ///< Trending.
|
|||
|
|||
/// Network Availability
|
|||
|
|||
std::chrono::system_clock::time_point m_lastConnected; |
|||
std::chrono::system_clock::time_point m_lastAttempted; |
|||
unsigned m_failedAttempts = 0; |
|||
DisconnectReason m_lastDisconnect = NoDisconnect; ///< Reason for disconnect that happened last.
|
|||
|
|||
/// Used by isOffline() and (todo) for peer to emit session information.
|
|||
std::weak_ptr<Session> m_session; |
|||
}; |
|||
using Peers = std::vector<Peer>; |
|||
|
|||
} |
|||
} |
@ -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