diff --git a/CodingStandards.txt b/CodingStandards.txt index 672a20958..6188b9a70 100644 --- a/CodingStandards.txt +++ b/CodingStandards.txt @@ -128,6 +128,10 @@ d. Use override, final and const judiciously. e. No implementations with the class declaration, except: - template or force-inline method (though prefer implementation at bottom of header file). - one-line implementation (in which case include it in same line as declaration). +f. For a method 'foo' +- Member: m_foo; +- Getter: foo() [ also: for booleans, isFoo() ]; +- Setter: setFoo(); @@ -162,3 +166,19 @@ d. In general expressions should be roughly as important/semantically meaningful a. Comments should be doxygen-compilable, using @notation rather than \notation. +12. Include Headers + +a. Includes should go in order of lower level (STL -> boost -> libdevcore -> libdevcrypto -> libethcore -> libethereum) to higher level. Lower levels are basically dependencies to the higher levels. For example: + +#include +#include + +#include +#include +#include +#include +#include +#include + +b. The only exception to the above rule is the top of a .cpp file where its corresponding header should be located. + diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 724b231c2..0a6622e7c 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -37,7 +37,7 @@ #include #include #include -#include +#include #include #include #include @@ -48,10 +48,10 @@ #include #include #include +#include "MainWin.h" #include "DownloadView.h" #include "MiningView.h" #include "BuildInfo.h" -#include "MainWin.h" #include "OurWebThreeStubServer.h" #include "ui_Main.h" using namespace std; @@ -66,11 +66,11 @@ static void initUnits(QComboBox* _b) _b->addItem(QString::fromStdString(units()[n].second), n); } -QString Main::fromRaw(dev::h256 _n, unsigned* _inc) +QString Main::fromRaw(h256 _n, unsigned* _inc) { if (_n) { - std::string s((char const*)_n.data(), 32); + string s((char const*)_n.data(), 32); auto l = s.find_first_of('\0'); if (!l) return QString(); @@ -91,13 +91,13 @@ QString Main::fromRaw(dev::h256 _n, unsigned* _inc) return QString(); } -static std::vector keysAsVector(QList const& keys) +static vector keysAsVector(QList const& keys) { auto list = keys.toStdList(); return {begin(list), end(list)}; } -static QString contentsOfQResource(std::string const& res) +static QString contentsOfQResource(string const& res) { QFile file(QString::fromStdString(res)); if (!file.open(QFile::ReadOnly)) @@ -116,7 +116,7 @@ Main::Main(QWidget *parent) : { setWindowFlags(Qt::Window); ui->setupUi(this); - g_logPost = [=](std::string const& s, char const* c) + g_logPost = [=](string const& s, char const* c) { simpleDebugOut(s, c); m_logLock.lock(); @@ -136,8 +136,8 @@ Main::Main(QWidget *parent) : cerr << "Block Hash: " << BlockChain::genesis().hash << endl; cerr << "Block RLP: " << RLP(block) << endl; cerr << "Block Hex: " << toHex(block) << endl; - cerr << "Network protocol version: " << dev::eth::c_protocolVersion << endl; - cerr << "Client database version: " << dev::eth::c_databaseVersion << endl; + cerr << "Network protocol version: " << c_protocolVersion << endl; + cerr << "Client database version: " << c_databaseVersion << endl; ui->configDock->close(); on_verbosity_valueChanged(); @@ -158,7 +158,7 @@ Main::Main(QWidget *parent) : m_webThree.reset(new WebThreeDirect(string("AlethZero/v") + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM), getDataDir() + "/AlethZero", false, {"eth", "shh"})); m_qwebConnector.reset(new QWebThreeConnector()); - m_server.reset(new OurWebThreeStubServer(*m_qwebConnector, *web3(), keysAsVector(m_myKeys))); + m_server.reset(new OurWebThreeStubServer(*m_qwebConnector, *web3(), keysAsVector(m_myKeys), this)); connect(&*m_server, SIGNAL(onNewId(QString)), SLOT(addNewId(QString))); m_server->setIdentities(keysAsVector(owned())); m_server->StartListening(); @@ -234,7 +234,7 @@ void Main::addNewId(QString _ids) refreshWhisper(); } -dev::p2p::NetworkPreferences Main::netPrefs() const +NetworkPreferences Main::netPrefs() const { return NetworkPreferences(ui->port->value(), ui->forceAddress->text().toStdString(), ui->upnp->isChecked(), ui->localNetworking->isChecked()); } @@ -244,7 +244,7 @@ void Main::onKeysChanged() installBalancesWatch(); } -unsigned Main::installWatch(dev::eth::LogFilter const& _tf, WatchHandler const& _f) +unsigned Main::installWatch(LogFilter const& _tf, WatchHandler const& _f) { auto ret = ethereum()->installWatch(_tf); m_handlers[ret] = _f; @@ -266,10 +266,10 @@ void Main::uninstallWatch(unsigned _w) void Main::installWatches() { - installWatch(dev::eth::LogFilter().address(c_newConfig), [=](LocalisedLogEntries const&) { installNameRegWatch(); }); - installWatch(dev::eth::LogFilter().address(c_newConfig), [=](LocalisedLogEntries const&) { installCurrenciesWatch(); }); - installWatch(dev::eth::PendingChangedFilter, [=](LocalisedLogEntries const&){ onNewPending(); }); - installWatch(dev::eth::ChainChangedFilter, [=](LocalisedLogEntries const&){ onNewBlock(); }); + installWatch(LogFilter().address(c_newConfig), [=](LocalisedLogEntries const&) { installNameRegWatch(); }); + installWatch(LogFilter().address(c_newConfig), [=](LocalisedLogEntries const&) { installCurrenciesWatch(); }); + installWatch(PendingChangedFilter, [=](LocalisedLogEntries const&){ onNewPending(); }); + installWatch(ChainChangedFilter, [=](LocalisedLogEntries const&){ onNewBlock(); }); } Address Main::getNameReg() const @@ -279,24 +279,24 @@ Address Main::getNameReg() const Address Main::getCurrencies() const { - return abiOut
(ethereum()->call(c_newConfig, abiIn("lookup(uint256)", (u256)2))); + return abiOut
(ethereum()->call(c_newConfig, abiIn("lookup(uint256)", (u256)3))); } void Main::installNameRegWatch() { uninstallWatch(m_nameRegFilter); - m_nameRegFilter = installWatch(dev::eth::LogFilter().address((u160)getNameReg()), [=](LocalisedLogEntries const&){ onNameRegChange(); }); + m_nameRegFilter = installWatch(LogFilter().address((u160)getNameReg()), [=](LocalisedLogEntries const&){ onNameRegChange(); }); } void Main::installCurrenciesWatch() { uninstallWatch(m_currenciesFilter); - m_currenciesFilter = installWatch(dev::eth::LogFilter().address((u160)getCurrencies()), [=](LocalisedLogEntries const&){ onCurrenciesChange(); }); + m_currenciesFilter = installWatch(LogFilter().address((u160)getCurrencies()), [=](LocalisedLogEntries const&){ onCurrenciesChange(); }); } void Main::installBalancesWatch() { - dev::eth::LogFilter tf; + LogFilter tf; vector
altCoins; Address coinsAddr = getCurrencies(); @@ -343,6 +343,9 @@ void Main::onNewBlock() refreshBlockCount(); refreshBlockChain(); refreshAccounts(); + + // We must update balances since we can't filter updates to basic accounts. + refreshBalances(); } void Main::onNewPending() @@ -467,7 +470,7 @@ static Public stringToPublic(QString const& _a) QString Main::pretty(dev::Address _a) const { -/* static std::map s_memos; +/* static map s_memos; if (!s_memos.count(_a)) {*/ @@ -505,7 +508,7 @@ QString Main::render(dev::Address _a) const return QString::fromStdString(_a.abridged()); } -string32 fromString(std::string const& _s) +string32 fromString(string const& _s) { string32 ret; for (unsigned i = 0; i < 32 && i <= _s.size(); ++i) @@ -518,7 +521,7 @@ Address Main::fromString(QString const& _n) const if (_n == "(Create Contract)") return Address(); -/* static std::map s_memos; +/* static map s_memos; if (!s_memos.count(_n)) {*/ @@ -860,18 +863,18 @@ void Main::on_preview_triggered() void Main::refreshMining() { - dev::eth::MineProgress p = ethereum()->miningProgress(); + MineProgress p = ethereum()->miningProgress(); ui->mineStatus->setText(ethereum()->isMining() ? QString("%1s @ %2kH/s").arg(p.ms / 1000).arg(p.ms ? p.hashes / p.ms : 0) : "Not mining"); if (!ui->miningView->isVisible()) return; - list l = ethereum()->miningHistory(); + list l = ethereum()->miningHistory(); static unsigned lh = 0; if (p.hashes < lh) ui->miningView->resetStats(); lh = p.hashes; ui->miningView->appendStats(l, p); /* if (p.ms) - for (dev::eth::MineInfo const& i: l) + for (MineInfo const& i: l) cnote << i.hashes * 10 << "h/sec, need:" << i.requirement << " best:" << i.best << " best-so-far:" << p.best << " avg-speed:" << (p.hashes * 1000 / p.ms) << "h/sec"; */ } @@ -1026,10 +1029,10 @@ void Main::refreshBlockCount() cwatch << "refreshBlockCount()"; auto d = ethereum()->blockChain().details(); auto diff = BlockInfo(ethereum()->blockChain().block()).difficulty; - ui->blockCount->setText(QString("%6 #%1 @%3 T%2 PV%4 D%5").arg(d.number).arg(toLog2(d.totalDifficulty)).arg(toLog2(diff)).arg(dev::eth::c_protocolVersion).arg(dev::eth::c_databaseVersion).arg(m_privateChain.size() ? "[" + m_privateChain + "] " : "testnet")); + ui->blockCount->setText(QString("%6 #%1 @%3 T%2 PV%4 D%5").arg(d.number).arg(toLog2(d.totalDifficulty)).arg(toLog2(diff)).arg(c_protocolVersion).arg(c_databaseVersion).arg(m_privateChain.size() ? "[" + m_privateChain + "] " : "testnet")); } -static bool blockMatch(string const& _f, dev::eth::BlockDetails const& _b, h256 _h, BlockChain const& _bc) +static bool blockMatch(string const& _f, BlockDetails const& _b, h256 _h, BlockChain const& _bc) { try { @@ -1178,7 +1181,7 @@ void Main::timerEvent(QTimerEvent*) } } -string Main::renderDiff(dev::eth::StateDiff const& _d) const +string Main::renderDiff(StateDiff const& _d) const { stringstream s; @@ -1187,24 +1190,24 @@ string Main::renderDiff(dev::eth::StateDiff const& _d) const { s << "
"; - dev::eth::AccountDiff const& ad = i.second; + AccountDiff const& ad = i.second; s << "" << lead(ad.changeType()) << " " << " " << render(i.first).toStdString() << ""; if (!ad.exist.to()) continue; if (ad.balance) { - s << "
" << indent << "Balance " << std::dec << formatBalance(ad.balance.to()); - s << " " << std::showpos << (((dev::bigint)ad.balance.to()) - ((dev::bigint)ad.balance.from())) << std::noshowpos << ""; + s << "
" << indent << "Balance " << dec << formatBalance(ad.balance.to()); + s << " " << showpos << (((dev::bigint)ad.balance.to()) - ((dev::bigint)ad.balance.from())) << noshowpos << ""; } if (ad.nonce) { - s << "
" << indent << "Count #" << std::dec << ad.nonce.to(); - s << " " << std::showpos << (((dev::bigint)ad.nonce.to()) - ((dev::bigint)ad.nonce.from())) << std::noshowpos << ""; + s << "
" << indent << "Count #" << dec << ad.nonce.to(); + s << " " << showpos << (((dev::bigint)ad.nonce.to()) - ((dev::bigint)ad.nonce.from())) << noshowpos << ""; } if (ad.code) { - s << "
" << indent << "Code " << std::hex << ad.code.to().size() << " bytes"; + s << "
" << indent << "Code " << hex << ad.code.to().size() << " bytes"; if (ad.code.from().size()) s << " (" << ad.code.from().size() << " bytes)"; } @@ -1226,7 +1229,7 @@ string Main::renderDiff(dev::eth::StateDiff const& _d) const else if (i.first > u160(1) << 150) s << (h160)(u160)i.first; else - s << std::hex << i.first; + s << hex << i.first; */ if (!i.second.from()) s << ": " << prettyU256(i.second.to()).toStdString(); @@ -1479,10 +1482,10 @@ void Main::populateDebugger(dev::bytesConstRef _r) bytesConstRef lastData; h256 lastHash; h256 lastDataHash; - auto onOp = [&](uint64_t steps, Instruction inst, dev::bigint newMemSize, dev::bigint gasCost, dev::eth::VM* voidVM, dev::eth::ExtVMFace const* voidExt) + auto onOp = [&](uint64_t steps, Instruction inst, dev::bigint newMemSize, dev::bigint gasCost, VM* voidVM, ExtVMFace const* voidExt) { - dev::eth::VM& vm = *voidVM; - dev::eth::ExtVM const& ext = *static_cast(voidExt); + VM& vm = *voidVM; + ExtVM const& ext = *static_cast(voidExt); if (ext.code != lastExtCode) { lastExtCode = ext.code; @@ -1605,11 +1608,11 @@ static shh::Topic topicFromText(QString _s) { u256 v(d.cap(2).toStdString()); if (d.cap(6) == "szabo") - v *= dev::eth::szabo; + v *= szabo; else if (d.cap(5) == "finney") - v *= dev::eth::finney; + v *= finney; else if (d.cap(4) == "ether") - v *= dev::eth::ether; + v *= ether; bytes bs = dev::toCompactBigEndian(v); if (d.cap(1) != "$") for (auto i = bs.size(); i < 32; ++i) @@ -1635,6 +1638,29 @@ static shh::Topic topicFromText(QString _s) return ret; } + +bool Main::sourceIsSolidity(string const& _source) +{ + // TODO: Improve this heuristic + return (_source.substr(0, 8) == "contract" || _source.substr(0, 5) == "//sol"); +} + +string const Main::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->getName() + "\n"; + } + return ret; +} + void Main::on_data_textChanged() { m_pcWarp.clear(); @@ -1648,7 +1674,7 @@ void Main::on_data_textChanged() { m_data = fromHex(src); } - else if (src.substr(0, 8) == "contract" || src.substr(0, 5) == "//sol") // improve this heuristic + else if (sourceIsSolidity(src)) { dev::solidity::CompilerStack compiler; try @@ -1657,6 +1683,7 @@ void Main::on_data_textChanged() solidity = "

Solidity

"; solidity += "
" + QString::fromStdString(compiler.getInterface()).replace(QRegExp("\\s"), "").toHtmlEscaped() + "
"; solidity += "
" + QString::fromStdString(compiler.getSolidityInterface()).toHtmlEscaped() + "
"; + solidity += "
" + QString::fromStdString(getFunctionHashes(compiler)).toHtmlEscaped() + "
"; } catch (dev::Exception const& exception) { @@ -1671,7 +1698,7 @@ void Main::on_data_textChanged() } else { - m_data = dev::eth::compileLLL(src, m_enableOptimizer, &errors); + m_data = compileLLL(src, m_enableOptimizer, &errors); if (errors.size()) { try @@ -1687,11 +1714,11 @@ void Main::on_data_textChanged() } else { - auto asmcode = dev::eth::compileLLLToAsm(src, false); + auto asmcode = compileLLLToAsm(src, false); lll = "

Pre

" + QString::fromStdString(asmcode).toHtmlEscaped() + "
"; if (m_enableOptimizer) { - asmcode = dev::eth::compileLLLToAsm(src, true); + asmcode = compileLLLToAsm(src, true); lll = "

Opt

" + QString::fromStdString(asmcode).toHtmlEscaped() + "
" + lll; } } @@ -1872,7 +1899,28 @@ void Main::on_send_clicked() debugFinished(); 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, m_enableOptimizer); + for (string& s: compiler.getContractNames()) + { + h256 contractHash = compiler.getContractCodeHash(s); + m_natspecDB.add(contractHash, + compiler.getMetadata(s, dev::solidity::DocumentationType::NATSPEC_USER)); + } + } + catch (...) + { + statusBar()->showMessage("Couldn't compile Solidity Contract."); + } + } else ethereum()->transact(s, value(), fromString(ui->destination->currentText()), m_data, ui->gas->value(), gasPrice()); return; @@ -2008,7 +2056,7 @@ void Main::on_dumpTracePretty_triggered() 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 << " : " << dev::eth::instructionInfo(ws.inst).name << " | " << dec << ws.gas << " | -" << dec << ws.gasCost << " | " << ws.newMemSize << "x32"; + 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"; } } @@ -2095,7 +2143,9 @@ QString Main::prettyU256(dev::u256 _n) const unsigned inc = 0; QString raw; ostringstream s; - if (!(_n >> 64)) + if (_n > szabo && _n < 1000000 * ether) + s << "" << formatBalance(_n) << " (0x" << hex << (uint64_t)_n << ")"; + else if (!(_n >> 64)) s << "" << (uint64_t)_n << " (0x" << hex << (uint64_t)_n << ")"; else if (!~(_n >> 64)) s << "" << (int64_t)_n << " (0x" << hex << (int64_t)_n << ")"; @@ -2235,7 +2285,7 @@ void Main::updateDebugger() cwarn << "PC (" << (unsigned)ws.curPC << ") is after code range (" << m_codes[ws.code].size() << ")"; ostringstream ss; - ss << dec << "STEP: " << ws.steps << " | PC: 0x" << hex << ws.curPC << " : " << dev::eth::instructionInfo(ws.inst).name << " | ADDMEM: " << dec << ws.newMemSize << " words | COST: " << dec << ws.gasCost << " | GAS: " << dec << ws.gas; + 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) @@ -2257,6 +2307,16 @@ void Main::on_post_clicked() whisper()->inject(m.seal(from, topicFromText(ui->shhTopic->toPlainText()), ui->shhTtl->value(), ui->shhWork->value())); } +string Main::lookupNatSpec(dev::h256 const& _contractHash) const +{ + return m_natspecDB.retrieve(_contractHash); +} + +string Main::lookupNatSpecUserNotice(dev::h256 const& _contractHash, dev::bytes const& _transactionData) +{ + return m_natspecDB.getUserNotice(_contractHash, _transactionData); +} + void Main::refreshWhispers() { ui->whispers->clear(); diff --git a/alethzero/MainWin.h b/alethzero/MainWin.h index 18cf5113b..bcfa8a0fc 100644 --- a/alethzero/MainWin.h +++ b/alethzero/MainWin.h @@ -36,6 +36,9 @@ #include #include #include +#include + +#include "NatspecHandler.h" namespace Ui { class Main; @@ -80,7 +83,8 @@ public: dev::eth::Client* ethereum() const { return m_webThree->ethereum(); } std::shared_ptr whisper() const { return m_webThree->whisper(); } - std::string lookupNatSpec(dev::h256 const& _contractCode) const { (void)_contractCode; return ""; } // TODO: actually implement with leveldb & a UI. + std::string lookupNatSpec(dev::h256 const& _contractHash) const; + std::string lookupNatSpecUserNotice(dev::h256 const& _contractHash, dev::bytes const& _transactionData); QList owned() const { return m_myIdentities + m_myKeys; } @@ -227,6 +231,12 @@ private: void refreshBlockCount(); void refreshBalances(); + /// Attempts to infer that @c _source contains Solidity code + bool sourceIsSolidity(std::string const& _source); + /// @eturns all method hashes of a Solidity contract in a string + std::string const getFunctionHashes(dev::solidity::CompilerStack const &_compiler, + std::string const& _contractName = ""); + std::unique_ptr ui; std::unique_ptr m_webThree; @@ -269,4 +279,5 @@ private: QWebThree* m_qweb = nullptr; static QString fromRaw(dev::h256 _n, unsigned* _inc = nullptr); + NatspecHandler m_natspecDB; }; diff --git a/alethzero/NatspecHandler.cpp b/alethzero/NatspecHandler.cpp new file mode 100644 index 000000000..25cc13d4a --- /dev/null +++ b/alethzero/NatspecHandler.cpp @@ -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 . +*/ + +/** @file NatspecHandler.cpp + * @author Lefteris Karapetsas + * @date 2015 + */ +#include "NatspecHandler.h" +#include +#include + +#include +#include +#include +#include +#include +#include + +using namespace dev; +using namespace dev::eth; +using namespace std; + +NatspecHandler::NatspecHandler() +{ + string path = Defaults::dbPath(); + boost::filesystem::create_directories(path); + ldb::Options o; + o.create_if_missing = true; + ldb::DB::Open(o, path + "/natspec", &m_db); +} + +NatspecHandler::~NatspecHandler() +{ + delete m_db; +} + +void NatspecHandler::add(dev::h256 const& _contractHash, string const& _doc) +{ + bytes k = _contractHash.asBytes(); + string v = _doc; + m_db->Put(m_writeOptions, ldb::Slice((char const*)k.data(), k.size()), ldb::Slice((char const*)v.data(), v.size())); +} + +string NatspecHandler::retrieve(dev::h256 const& _contractHash) const +{ + bytes k = _contractHash.asBytes(); + string ret; + m_db->Get(m_readOptions, ldb::Slice((char const*)k.data(), k.size()), &ret); + return ret; +} + +string NatspecHandler::getUserNotice(string const& json, dev::bytes const& _transactionData) +{ + Json::Value natspec; + Json::Value userNotice; + string retStr; + m_reader.parse(json, natspec); + bytes transactionFunctionPart(_transactionData.begin(), _transactionData.begin() + 4); + FixedHash<4> transactionFunctionHash(transactionFunctionPart); + + Json::Value methods = natspec["methods"]; + for (Json::ValueIterator it = methods.begin(); it != methods.end(); ++it) + { + Json::Value keyValue = it.key(); + if (!keyValue.isString()) + BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("Illegal Natspec JSON detected")); + + string functionSig = keyValue.asString(); + FixedHash<4> functionHash(dev::sha3(functionSig)); + + if (functionHash == transactionFunctionHash) + { + Json::Value val = (*it)["notice"]; + if (!val.isString()) + BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("Illegal Natspec JSON detected")); + return val.asString(); + } + } + + // not found + return string(); +} + +string NatspecHandler::getUserNotice(dev::h256 const& _contractHash, dev::bytes const& _transactionData) +{ + return getUserNotice(retrieve(_contractHash), _transactionData); +} + + diff --git a/alethzero/NatspecHandler.h b/alethzero/NatspecHandler.h new file mode 100644 index 000000000..edd9281d7 --- /dev/null +++ b/alethzero/NatspecHandler.h @@ -0,0 +1,58 @@ +/* + 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 . +*/ + +/** @file NatspecHandler.h + * @author Lefteris Karapetsas + * @date 2015 + */ + +#pragma once + +#pragma warning(push) +#pragma warning(disable: 4100 4267) +#include +#pragma warning(pop) +#include +#include + +namespace ldb = leveldb; + +class NatspecHandler +{ + public: + NatspecHandler(); + ~NatspecHandler(); + + /// Stores locally in a levelDB a key value pair of contract code hash to natspec documentation + void add(dev::h256 const& _contractHash, std::string const& _doc); + /// Retrieves the natspec documentation as a string given a contract code hash + std::string retrieve(dev::h256 const& _contractHash) const; + + /// Given a json natspec string and the transaction data return the user notice + std::string getUserNotice(std::string const& json, const dev::bytes& _transactionData); + /// Given a contract code hash and the transaction's data retrieve the natspec documention's + /// user notice for that transaction. + /// @returns The user notice or an empty string if no natspec for the contract exists + /// or if the existing natspec does not document the @c _methodName + std::string getUserNotice(dev::h256 const& _contractHash, dev::bytes const& _transactionDacta); + + private: + ldb::ReadOptions m_readOptions; + ldb::WriteOptions m_writeOptions; + ldb::DB* m_db; + Json::Reader m_reader; +}; diff --git a/alethzero/OurWebThreeStubServer.cpp b/alethzero/OurWebThreeStubServer.cpp index 0d840e8d4..ce1f28507 100644 --- a/alethzero/OurWebThreeStubServer.cpp +++ b/alethzero/OurWebThreeStubServer.cpp @@ -22,14 +22,17 @@ #include "OurWebThreeStubServer.h" #include +#include #include #include "MainWin.h" + using namespace std; using namespace dev; using namespace dev::eth; -OurWebThreeStubServer::OurWebThreeStubServer(jsonrpc::AbstractServerConnector& _conn, dev::WebThreeDirect& _web3, std::vector const& _accounts): - WebThreeStubServer(_conn, _web3, _accounts), m_web3(&_web3) +OurWebThreeStubServer::OurWebThreeStubServer(jsonrpc::AbstractServerConnector& _conn, dev::WebThreeDirect& _web3, + std::vector const& _accounts, Main* main): + WebThreeStubServer(_conn, _web3, _accounts), m_web3(&_web3), m_main(main) {} std::string OurWebThreeStubServer::shh_newIdentity() @@ -39,36 +42,31 @@ std::string OurWebThreeStubServer::shh_newIdentity() return toJS(kp.pub()); } -bool OurWebThreeStubServer::authenticate(dev::TransactionSkeleton const& _t) const +bool OurWebThreeStubServer::showAuthenticationPopup(std::string const& _title, std::string const& _text) const { - return true; - - // To get the balance of the sender - cnote << "Sender has ETH: " << m_web3->ethereum()->postState().balance(_t.from); - - Main* main; // don't know this yet, should be a member and set at construction time by Main, who will construct us. + QMessageBox userInput; + userInput.setText(QString::fromStdString(_title)); + userInput.setInformativeText(QString::fromStdString(_text + "\n Do you wish to allow this?")); + userInput.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); + userInput.button(QMessageBox::Ok)->setText("Allow"); + userInput.button(QMessageBox::Cancel)->setText("Reject"); + userInput.setDefaultButton(QMessageBox::Cancel); + return userInput.exec() == QMessageBox::Ok; +} +bool OurWebThreeStubServer::authenticate(dev::TransactionSkeleton const& _t) const +{ h256 contractCodeHash = m_web3->ethereum()->postState().codeHash(_t.to); - if (contractCodeHash == EmptySHA3) - { // recipient has no code - nothing special about this transaction. // TODO: show basic message for value transfer. - return true; // or whatever. - } - - std::string natspecJson = main->lookupNatSpec(contractCodeHash); - - if (natspecJson.empty()) - { - // TODO: HUGE warning - we don't know what this will do! - return false; // or whatever. - } - - // otherwise it's a transaction to contract for which we have the natspec: - // determine the actual message (embellish with real data) and ask user. + return true; -// QMessageBox::question(); + std::string userNotice = m_main->lookupNatSpecUserNotice(contractCodeHash, _t.data); + if (userNotice.empty()) + return showAuthenticationPopup("Unverified Pending Transaction", + "An undocumented transaction is about to be executed."); - return true; + // otherwise it's a transaction to a contract for which we have the natspec + return showAuthenticationPopup("Pending Transaction", userNotice); } diff --git a/alethzero/OurWebThreeStubServer.h b/alethzero/OurWebThreeStubServer.h index 9ff973371..a67af0827 100644 --- a/alethzero/OurWebThreeStubServer.h +++ b/alethzero/OurWebThreeStubServer.h @@ -24,12 +24,15 @@ #include #include +class Main; + class OurWebThreeStubServer: public QObject, public WebThreeStubServer { Q_OBJECT public: - OurWebThreeStubServer(jsonrpc::AbstractServerConnector& _conn, dev::WebThreeDirect& _web3, std::vector const& _accounts); + OurWebThreeStubServer(jsonrpc::AbstractServerConnector& _conn, dev::WebThreeDirect& _web3, + std::vector const& _accounts, Main* main); virtual std::string shh_newIdentity() override; virtual bool authenticate(dev::TransactionSkeleton const& _t) const; @@ -38,5 +41,8 @@ signals: void onNewId(QString _s); private: + bool showAuthenticationPopup(std::string const& _title, std::string const& _text) const; + dev::WebThreeDirect* m_web3; + Main* m_main; }; diff --git a/evmjit/libevmjit/Compiler.cpp b/evmjit/libevmjit/Compiler.cpp index bfcb9cea1..26c78b4ca 100644 --- a/evmjit/libevmjit/Compiler.cpp +++ b/evmjit/libevmjit/Compiler.cpp @@ -644,7 +644,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode case Instruction::EXTCODESIZE: { auto addr = stack.pop(); - auto codeRef = _ext.getExtCode(addr); + auto codeRef = _ext.extcode(addr); stack.push(codeRef.size); break; } @@ -682,7 +682,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode auto srcIdx = stack.pop(); auto reqBytes = stack.pop(); - auto codeRef = _ext.getExtCode(addr); + auto codeRef = _ext.extcode(addr); _memory.copyBytes(codeRef.ptr, codeRef.size, srcIdx, destMemIdx, reqBytes); break; diff --git a/evmjit/libevmjit/Ext.cpp b/evmjit/libevmjit/Ext.cpp index f0767d9e0..aae68f43a 100644 --- a/evmjit/libevmjit/Ext.cpp +++ b/evmjit/libevmjit/Ext.cpp @@ -22,9 +22,12 @@ namespace jit Ext::Ext(RuntimeManager& _runtimeManager, Memory& _memoryMan): RuntimeHelper(_runtimeManager), - m_memoryMan(_memoryMan), + m_memoryMan(_memoryMan) +#ifdef __MSCVER + , m_funcs({}), // The only std::array initialization that works in both Visual Studio & GCC m_argAllocas({}) +#endif { m_size = m_builder.CreateAlloca(Type::Size, nullptr, "env.size"); } @@ -48,7 +51,7 @@ std::array::value> const& getEnvFuncDescs() FuncDesc{"env_call", getFunctionType(Type::Bool, {Type::EnvPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::BytePtr, Type::Size, Type::BytePtr, Type::Size, Type::WordPtr})}, FuncDesc{"env_log", getFunctionType(Type::Void, {Type::EnvPtr, Type::BytePtr, Type::Size, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr})}, FuncDesc{"env_blockhash", getFunctionType(Type::Void, {Type::EnvPtr, Type::WordPtr, Type::WordPtr})}, - FuncDesc{"env_getExtCode", getFunctionType(Type::BytePtr, {Type::EnvPtr, Type::WordPtr, Type::Size->getPointerTo()})}, + FuncDesc{"env_extcode", getFunctionType(Type::BytePtr, {Type::EnvPtr, Type::WordPtr, Type::Size->getPointerTo()})}, FuncDesc{"ext_calldataload", getFunctionType(Type::Void, {Type::RuntimeDataPtr, Type::WordPtr, Type::WordPtr})}, }}; @@ -166,10 +169,10 @@ llvm::Value* Ext::sha3(llvm::Value* _inOff, llvm::Value* _inSize) return hash; } -MemoryRef Ext::getExtCode(llvm::Value* _addr) +MemoryRef Ext::extcode(llvm::Value* _addr) { auto addr = Endianness::toBE(m_builder, _addr); - auto code = createCall(EnvFunc::getExtCode, {getRuntimeManager().getEnvPtr(), byPtr(addr), m_size}); + auto code = createCall(EnvFunc::extcode, {getRuntimeManager().getEnvPtr(), byPtr(addr), m_size}); auto codeSize = m_builder.CreateLoad(m_size); auto codeSize256 = m_builder.CreateZExt(codeSize, Type::Word); return {code, codeSize256}; diff --git a/evmjit/libevmjit/Ext.h b/evmjit/libevmjit/Ext.h index 86a8a6190..2601d32ab 100644 --- a/evmjit/libevmjit/Ext.h +++ b/evmjit/libevmjit/Ext.h @@ -34,7 +34,7 @@ enum class EnvFunc call, log, blockhash, - getExtCode, + extcode, calldataload, // Helper function, not client Env interface _size @@ -55,7 +55,7 @@ public: llvm::Value* blockhash(llvm::Value* _number); llvm::Value* sha3(llvm::Value* _inOff, llvm::Value* _inSize); - MemoryRef getExtCode(llvm::Value* _addr); + MemoryRef extcode(llvm::Value* _addr); void log(llvm::Value* _memIdx, llvm::Value* _numBytes, std::array const& _topics); diff --git a/exp/main.cpp b/exp/main.cpp index e714f29da..80f4fa37d 100644 --- a/exp/main.cpp +++ b/exp/main.cpp @@ -75,7 +75,7 @@ int main() cnote << i;*/ return 0; } -#else +#elif 0 int main() { KeyPair u = KeyPair::create(); @@ -95,5 +95,11 @@ int main() cnote << "State after transaction: " << s; cnote << before.diff(s); } +#else +int main() +{ + cnote << KeyPair(Secret("0000000000000000000000000000000000000000000000000000000000000000")).address(); + cnote << KeyPair(Secret("1111111111111111111111111111111111111111111111111111111111111111")).address(); +} #endif diff --git a/libdevcore/CommonData.h b/libdevcore/CommonData.h index 6fab67452..2573995c5 100644 --- a/libdevcore/CommonData.h +++ b/libdevcore/CommonData.h @@ -110,6 +110,9 @@ inline std::string toBigEndianString(u160 _val) { std::string ret(20, '\0'); toB inline bytes toBigEndian(u256 _val) { bytes ret(32); toBigEndian(_val, ret); return ret; } inline bytes toBigEndian(u160 _val) { bytes ret(20); toBigEndian(_val, ret); return ret; } +/// Convenience function for conversion of a u256 to hex +inline std::string toHex(u256 val) { return toHex(toBigEndian(val)); } + /// Convenience function for toBigEndian. /// @returns a byte array just big enough to represent @a _val. template diff --git a/libdevcore/CommonIO.cpp b/libdevcore/CommonIO.cpp index ec8ca605c..feb4121cb 100644 --- a/libdevcore/CommonIO.cpp +++ b/libdevcore/CommonIO.cpp @@ -26,30 +26,30 @@ using namespace std; using namespace dev; -string dev::memDump(bytes const& _b, unsigned _w, bool _html) +string dev::memDump(bytes const& _bytes, unsigned _width, bool _html) { stringstream ret; if (_html) ret << "
";
-	for (unsigned i = 0; i < _b.size(); i += _w)
+	for (unsigned i = 0; i < _bytes.size(); i += _width)
 	{
 		ret << hex << setw(4) << setfill('0') << i << " ";
-		for (unsigned j = i; j < i + _w; ++j)
-			if (j < _b.size())
-				if (_b[j] >= 32 && _b[j] < 127)
-					if ((char)_b[j] == '<' && _html)
+		for (unsigned j = i; j < i + _width; ++j)
+			if (j < _bytes.size())
+				if (_bytes[j] >= 32 && _bytes[j] < 127)
+					if ((char)_bytes[j] == '<' && _html)
 						ret << "<";
-					else if ((char)_b[j] == '&' && _html)
+					else if ((char)_bytes[j] == '&' && _html)
 						ret << "&";
 					else
-						ret << (char)_b[j];
+						ret << (char)_bytes[j];
 				else
 					ret << '?';
 			else
 				ret << ' ';
 		ret << " ";
-		for (unsigned j = i; j < i + _w && j < _b.size(); ++j)
-			ret << setfill('0') << setw(2) << hex << (unsigned)_b[j] << " ";
+		for (unsigned j = i; j < i + _width && j < _bytes.size(); ++j)
+			ret << setfill('0') << setw(2) << hex << (unsigned)_bytes[j] << " ";
 		ret << "\n";
 	}
 	if (_html)
diff --git a/libdevcore/CommonIO.h b/libdevcore/CommonIO.h
index 11422db9a..d2a67921b 100644
--- a/libdevcore/CommonIO.h
+++ b/libdevcore/CommonIO.h
@@ -47,7 +47,8 @@ bytes contents(std::string const& _file);
 void writeFile(std::string const& _file, bytes const& _data);
 
 /// Nicely renders the given bytes to a string, optionally as HTML.
-std::string memDump(bytes const& _b, unsigned _w = 8, bool _html = false);
+/// @a _bytes: bytes array to be rendered as string. @a _width of a bytes line.
+std::string memDump(bytes const& _bytes, unsigned _width = 8, bool _html = false);
 
 // Stream I/O functions.
 // Provides templated stream I/O for all STL collections so they can be shifted on to any iostream-like interface.
diff --git a/libdevcore/CommonJS.h b/libdevcore/CommonJS.h
index 4fe40ebe2..dce6d9b60 100644
--- a/libdevcore/CommonJS.h
+++ b/libdevcore/CommonJS.h
@@ -65,7 +65,7 @@ template  FixedHash jsToFixed(std::string const& _s)
 {
 	if (_s.substr(0, 2) == "0x")
 		// Hex
-		return FixedHash(_s.substr(2));
+		return FixedHash(_s.substr(2 + std::max(40, _s.size() - 2) - 40));
 	else if (_s.find_first_not_of("0123456789") == std::string::npos)
 		// Decimal
 		return (typename FixedHash::Arith)(_s);
diff --git a/libdevcrypto/CryptoPP.cpp b/libdevcrypto/CryptoPP.cpp
index acd59184f..2d0170fb9 100644
--- a/libdevcrypto/CryptoPP.cpp
+++ b/libdevcrypto/CryptoPP.cpp
@@ -199,6 +199,8 @@ bool Secp256k1::verifySecret(Secret const& _s, Public& _p)
 
 void Secp256k1::agree(Secret const& _s, Public const& _r, h256& o_s)
 {
+	(void)o_s;
+	(void)_s;
 	ECDH::Domain d(m_oid);
 	assert(d.AgreedValueLength() == sizeof(o_s));
 	byte remote[65] = {0x04};
diff --git a/libethereum/Executive.cpp b/libethereum/Executive.cpp
index c4ce543d6..4eed2b284 100644
--- a/libethereum/Executive.cpp
+++ b/libethereum/Executive.cpp
@@ -35,7 +35,7 @@ using namespace dev::eth;
 
 Executive::Executive(State& _s, BlockChain const& _bc, unsigned _level):
 	m_s(_s),
-	m_lastHashes(_s.getLastHashes(_bc)),
+	m_lastHashes(_s.getLastHashes(_bc, (unsigned)_s.info().number - 1)),
 	m_depth(_level)
 {}
 
diff --git a/libethereum/State.cpp b/libethereum/State.cpp
index 3c59bf415..9ed9a3a3a 100644
--- a/libethereum/State.cpp
+++ b/libethereum/State.cpp
@@ -418,7 +418,7 @@ TransactionReceipts State::sync(BlockChain const& _bc, TransactionQueue& _tq, bo
 	TransactionReceipts ret;
 	auto ts = _tq.transactions();
 
-	auto lh = getLastHashes(_bc);
+	auto lh = getLastHashes(_bc, _bc.number());
 
 	for (int goodTxs = 1; goodTxs;)
 	{
@@ -498,7 +498,7 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, bool _checkNonce)
 	GenericTrieDB receiptsTrie(&rm);
 	receiptsTrie.init();
 
-	LastHashes lh = getLastHashes(_bc);
+	LastHashes lh = getLastHashes(_bc, (unsigned)m_previousBlock.number);
 
 	// All ok with the block generally. Play back the transactions now...
 	unsigned i = 0;
@@ -527,7 +527,7 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, bool _checkNonce)
 		cwarn << "Bad receipts state root.";
 		cwarn << "Block:" << toHex(_block);
 		cwarn << "Block RLP:" << RLP(_block);
-		cwarn << "Want: " << receiptsTrie.root() << ", got: " << m_currentBlock.receiptsRoot;
+		cwarn << "Calculated: " << receiptsTrie.root();
 		for (unsigned j = 0; j < i; ++j)
 		{
 			RLPStream k;
@@ -538,6 +538,16 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, bool _checkNonce)
 			cwarn << "Hex: " << toHex(b);
 			cwarn << TransactionReceipt(&b);
 		}
+        cwarn << "Recorded: " << m_currentBlock.receiptsRoot;
+		auto rs = _bc.receipts(m_currentBlock.hash);
+		for (unsigned j = 0; j < rs.receipts.size(); ++j)
+		{
+			auto b = rs.receipts[j].rlp();
+			cwarn << j << ": ";
+			cwarn << "RLP: " << RLP(b);
+			cwarn << "Hex: " << toHex(b);
+			cwarn << rs.receipts[j];
+		}
 		BOOST_THROW_EXCEPTION(InvalidReceiptsStateRoot());
 	}
 
@@ -1000,19 +1010,29 @@ bool State::isTrieGood(bool _enforceRefs, bool _requireNoLeftOvers) const
 	return true;
 }
 
-LastHashes State::getLastHashes(BlockChain const& _bc) const
+LastHashes State::getLastHashes(BlockChain const& _bc, unsigned _n) const
 {
 	LastHashes ret;
 	ret.resize(256);
 	if (c_protocolVersion > 49)
 	{
-		ret[0] = _bc.currentHash();
+		ret[0] = _bc.numberHash(_n);
 		for (unsigned i = 1; i < 256; ++i)
 			ret[i] = ret[i - 1] ? _bc.details(ret[i - 1]).parent : h256();
 	}
 	return ret;
 }
 
+u256 State::execute(BlockChain const& _bc, bytes const& _rlp, bytes* o_output, bool _commit)
+{
+	return execute(getLastHashes(_bc, _bc.number()), &_rlp, o_output, _commit);
+}
+
+u256 State::execute(BlockChain const& _bc, bytesConstRef _rlp, bytes* o_output, bool _commit)
+{
+	return execute(getLastHashes(_bc, _bc.number()), _rlp, o_output, _commit);
+}
+
 // TODO: maintain node overlay revisions for stateroots -> each commit gives a stateroot + OverlayDB; allow overlay copying for rewind operations.
 u256 State::execute(LastHashes const& _lh, bytesConstRef _rlp, bytes* o_output, bool _commit)
 {
diff --git a/libethereum/State.h b/libethereum/State.h
index e7e1bbfab..85abd9366 100644
--- a/libethereum/State.h
+++ b/libethereum/State.h
@@ -147,12 +147,12 @@ public:
 	/// Like sync but only operate on _tq, killing the invalid/old ones.
 	bool cull(TransactionQueue& _tq) const;
 
-	LastHashes getLastHashes(BlockChain const& _bc) const;
+	LastHashes getLastHashes(BlockChain const& _bc, unsigned _n) const;
 
 	/// Execute a given transaction.
 	/// This will append @a _t to the transaction list and change the state accordingly.
-	u256 execute(BlockChain const& _bc, bytes const& _rlp, bytes* o_output = nullptr, bool _commit = true) { return execute(getLastHashes(_bc), &_rlp, o_output, _commit); }
-	u256 execute(BlockChain const& _bc, bytesConstRef _rlp, bytes* o_output = nullptr, bool _commit = true) { return execute(getLastHashes(_bc), _rlp, o_output, _commit); }
+	u256 execute(BlockChain const& _bc, bytes const& _rlp, bytes* o_output = nullptr, bool _commit = true);
+	u256 execute(BlockChain const& _bc, bytesConstRef _rlp, bytes* o_output = nullptr, bool _commit = true);
 	u256 execute(LastHashes const& _lh, bytes const& _rlp, bytes* o_output = nullptr, bool _commit = true) { return execute(_lh, &_rlp, o_output, _commit); }
 	u256 execute(LastHashes const& _lh, bytesConstRef _rlp, bytes* o_output = nullptr, bool _commit = true);
 
diff --git a/libjsqrc/ethereumjs/dist/ethereum.js b/libjsqrc/ethereumjs/dist/ethereum.js
index a422171be..a8ee64111 100644
--- a/libjsqrc/ethereumjs/dist/ethereum.js
+++ b/libjsqrc/ethereumjs/dist/ethereum.js
@@ -91,8 +91,8 @@ var setupInputTypes = function () {
             return value.toString(16);
         else if (typeof value === "string" && value.indexOf('0x') === 0)
             return value.substr(2);
-        else if (typeof value === "string")
-            return web3.toHex(value);
+//        else if (typeof value === "string")
+//            return web3.toHex(value);
         else
             return (+value).toString(16);
     };
diff --git a/libjsqrc/ethereumjs/dist/ethereum.js.map b/libjsqrc/ethereumjs/dist/ethereum.js.map
index 4a38cddfd..7c500f07c 100644
--- a/libjsqrc/ethereumjs/dist/ethereum.js.map
+++ b/libjsqrc/ethereumjs/dist/ethereum.js.map
@@ -17,7 +17,7 @@
   "sourceRoot": "",
   "sourcesContent": [
     "(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require==\"function\"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error(\"Cannot find module '\"+o+\"'\");throw f.code=\"MODULE_NOT_FOUND\",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require==\"function\"&&require;for(var o=0;o.\n*/\n/** @file abi.js\n * @authors:\n *   Marek Kotewicz \n *   Gav Wood \n * @date 2014\n */\n\n// TODO: is these line is supposed to be here? \nif (\"build\" !== 'build') {/*\n    var web3 = require('./web3'); // jshint ignore:line\n*/}\n\n// TODO: make these be actually accurate instead of falling back onto JS's doubles.\nvar hexToDec = function (hex) {\n    return parseInt(hex, 16).toString();\n};\n\nvar decToHex = function (dec) {\n    return parseInt(dec).toString(16);\n};\n\nvar findIndex = function (array, callback) {\n    var end = false;\n    var i = 0;\n    for (; i < array.length && !end; i++) {\n        end = callback(array[i]);\n    }\n    return end ? i - 1 : -1;\n};\n\nvar findMethodIndex = function (json, methodName) {\n    return findIndex(json, function (method) {\n        return method.name === methodName;\n    });\n};\n\nvar padLeft = function (string, chars) {\n    return new Array(chars - string.length + 1).join(\"0\") + string;\n};\n\nvar calcBitPadding = function (type, expected) {\n    var value = type.slice(expected.length);\n    if (value === \"\") {\n        return 32;\n    }\n    return parseInt(value) / 8;\n};\n\nvar calcBytePadding = function (type, expected) {\n    var value = type.slice(expected.length);\n    if (value === \"\") {\n        return 32;\n    }\n    return parseInt(value);\n};\n\nvar calcRealPadding = function (type, expected) {\n    var value = type.slice(expected.length);\n    if (value === \"\") {\n        return 32;\n    }\n    var sizes = value.split('x');\n    for (var padding = 0, i = 0; i < sizes; i++) {\n        padding += (sizes[i] / 8);\n    }\n    return padding;\n};\n\nvar setupInputTypes = function () {\n    \n    // convert from int, decimal-string, prefixed hex string whatever into a bare hex string.\n    var formatStandard = function (value) {\n        if (typeof value === \"number\")\n            return value.toString(16);\n        else if (typeof value === \"string\" && value.indexOf('0x') === 0)\n            return value.substr(2);\n        else if (typeof value === \"string\")\n            return web3.toHex(value);\n        else\n            return (+value).toString(16);\n    };\n\n    var prefixedType = function (prefix, calcPadding) {\n        return function (type, value) {\n            var expected = prefix;\n            if (type.indexOf(expected) !== 0) {\n                return false;\n            }\n\n            var padding = calcPadding(type, expected);\n            if (padding > 32)\n                return false;   // not allowed to be so big.\n            padding = 32;   // override as per the new ABI.\n\n            if (prefix === \"string\")\n                return web3.fromAscii(value, padding).substr(2);\n            return padLeft(formatStandard(value), padding * 2);\n        };\n    };\n\n    var namedType = function (name, padding, formatter) {\n        return function (type, value) {\n            if (type !== name) {\n                return false;\n            }\n\n            padding = 32;   //override as per the new ABI.\n\n            return padLeft(formatter ? formatter(value) : value, padding * 2);\n        };\n    };\n\n    var formatBool = function (value) {\n        return value ? '01' : '00';\n    };\n\n    return [\n        prefixedType('uint', calcBitPadding),\n        prefixedType('int', calcBitPadding),\n        prefixedType('hash', calcBitPadding),\n        prefixedType('string', calcBytePadding),\n        prefixedType('real', calcRealPadding),\n        prefixedType('ureal', calcRealPadding),\n        namedType('address', 20, formatStandard),\n        namedType('bool', 1, formatBool),\n    ];\n};\n\nvar inputTypes = setupInputTypes();\n\nvar toAbiInput = function (json, methodName, params) {\n    var bytes = \"\";\n    var index = findMethodIndex(json, methodName);\n\n    if (index === -1) {\n        return;\n    }\n\n    var method = json[index];\n\n    for (var i = 0; i < method.inputs.length; i++) {\n        var found = false;\n        for (var j = 0; j < inputTypes.length && !found; j++) {\n            found = inputTypes[j](method.inputs[i].type, params[i]);\n        }\n        if (!found) {\n            console.error('unsupported json type: ' + method.inputs[i].type);\n        }\n        bytes += found;\n    }\n    return bytes;\n};\n\nvar setupOutputTypes = function () {\n\n    var prefixedType = function (prefix, calcPadding) {\n        return function (type) {\n            var expected = prefix;\n            if (type.indexOf(expected) !== 0) {\n                return -1;\n            }\n\n            var padding = calcPadding(type, expected);\n            if (padding > 32)\n                return -1;   // not allowed to be so big.\n            padding = 32;  // override as per the new ABI.\n            return padding * 2;\n        };\n    };\n\n    var namedType = function (name, padding) {\n        return function (type) {\n            padding = 32;  // override as per the new ABI.\n            return name === type ? padding * 2 : -1;\n        };\n    };\n\n    var formatInt = function (value) {\n        return value.length <= 8 ? +parseInt(value, 16) : hexToDec(value);\n    };\n\n    var formatHash = function (value) {\n        return \"0x\" + value;\n    };\n\n    var formatBool = function (value) {\n        return value === '1' ? true : false;\n    };\n\n    var formatString = function (value) {\n        return web3.toAscii(value);\n    };\n\n    return [\n    { padding: prefixedType('uint', calcBitPadding), format: formatInt },\n    { padding: prefixedType('int', calcBitPadding), format: formatInt },\n    { padding: prefixedType('hash', calcBitPadding), format: formatHash },\n    { padding: prefixedType('string', calcBytePadding), format: formatString },\n    { padding: prefixedType('real', calcRealPadding), format: formatInt },\n    { padding: prefixedType('ureal', calcRealPadding), format: formatInt },\n    { padding: namedType('address', 20) },\n    { padding: namedType('bool', 1), format: formatBool }\n    ];\n};\n\nvar outputTypes = setupOutputTypes();\n\nvar fromAbiOutput = function (json, methodName, output) {\n    var index = findMethodIndex(json, methodName);\n\n    if (index === -1) {\n        return;\n    }\n\n    output = output.slice(2);\n\n    var result = [];\n    var method = json[index];\n    for (var i = 0; i < method.outputs.length; i++) {\n        var padding = -1;\n        for (var j = 0; j < outputTypes.length && padding === -1; j++) {\n            padding = outputTypes[j].padding(method.outputs[i].type);\n        }\n\n        if (padding === -1) {\n            // not found output parsing\n            continue;\n        }\n        var res = output.slice(0, padding);\n        var formatter = outputTypes[j - 1].format;\n        result.push(formatter ? formatter(res) : (\"0x\" + res));\n        output = output.slice(padding);\n    }\n\n    return result;\n};\n\nvar inputParser = function (json) {\n    var parser = {};\n    json.forEach(function (method) {\n        parser[method.name] = function () {\n            var params = Array.prototype.slice.call(arguments);\n            return toAbiInput(json, method.name, params);\n        };\n    });\n\n    return parser;\n};\n\nvar outputParser = function (json) {\n    var parser = {};\n    json.forEach(function (method) {\n        parser[method.name] = function (output) {\n            return fromAbiOutput(json, method.name, output);\n        };\n    });\n\n    return parser;\n};\n\nvar methodSignature = function (json, name) {\n    var method = json[findMethodIndex(json, name)];\n    var result = name + '(';\n    var inputTypes = method.inputs.map(function (inp) {\n        return inp.type;\n    });\n    result += inputTypes.join(',');\n    result += ')';\n\n    return web3.sha3(web3.fromAscii(result));\n};\n\nmodule.exports = {\n    inputParser: inputParser,\n    outputParser: outputParser,\n    methodSignature: methodSignature\n};\n\n",
+    "/*\n    This file is part of ethereum.js.\n\n    ethereum.js is free software: you can redistribute it and/or modify\n    it under the terms of the GNU Lesser General Public License as published by\n    the Free Software Foundation, either version 3 of the License, or\n    (at your option) any later version.\n\n    ethereum.js is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU Lesser General Public License for more details.\n\n    You should have received a copy of the GNU Lesser General Public License\n    along with ethereum.js.  If not, see .\n*/\n/** @file abi.js\n * @authors:\n *   Marek Kotewicz \n *   Gav Wood \n * @date 2014\n */\n\n// TODO: is these line is supposed to be here? \nif (\"build\" !== 'build') {/*\n    var web3 = require('./web3'); // jshint ignore:line\n*/}\n\n// TODO: make these be actually accurate instead of falling back onto JS's doubles.\nvar hexToDec = function (hex) {\n    return parseInt(hex, 16).toString();\n};\n\nvar decToHex = function (dec) {\n    return parseInt(dec).toString(16);\n};\n\nvar findIndex = function (array, callback) {\n    var end = false;\n    var i = 0;\n    for (; i < array.length && !end; i++) {\n        end = callback(array[i]);\n    }\n    return end ? i - 1 : -1;\n};\n\nvar findMethodIndex = function (json, methodName) {\n    return findIndex(json, function (method) {\n        return method.name === methodName;\n    });\n};\n\nvar padLeft = function (string, chars) {\n    return new Array(chars - string.length + 1).join(\"0\") + string;\n};\n\nvar calcBitPadding = function (type, expected) {\n    var value = type.slice(expected.length);\n    if (value === \"\") {\n        return 32;\n    }\n    return parseInt(value) / 8;\n};\n\nvar calcBytePadding = function (type, expected) {\n    var value = type.slice(expected.length);\n    if (value === \"\") {\n        return 32;\n    }\n    return parseInt(value);\n};\n\nvar calcRealPadding = function (type, expected) {\n    var value = type.slice(expected.length);\n    if (value === \"\") {\n        return 32;\n    }\n    var sizes = value.split('x');\n    for (var padding = 0, i = 0; i < sizes; i++) {\n        padding += (sizes[i] / 8);\n    }\n    return padding;\n};\n\nvar setupInputTypes = function () {\n    \n    // convert from int, decimal-string, prefixed hex string whatever into a bare hex string.\n    var formatStandard = function (value) {\n        if (typeof value === \"number\")\n            return value.toString(16);\n        else if (typeof value === \"string\" && value.indexOf('0x') === 0)\n            return value.substr(2);\n//        else if (typeof value === \"string\")\n//            return web3.toHex(value);\n        else\n            return (+value).toString(16);\n    };\n\n    var prefixedType = function (prefix, calcPadding) {\n        return function (type, value) {\n            var expected = prefix;\n            if (type.indexOf(expected) !== 0) {\n                return false;\n            }\n\n            var padding = calcPadding(type, expected);\n            if (padding > 32)\n                return false;   // not allowed to be so big.\n            padding = 32;   // override as per the new ABI.\n\n            if (prefix === \"string\")\n                return web3.fromAscii(value, padding).substr(2);\n            return padLeft(formatStandard(value), padding * 2);\n        };\n    };\n\n    var namedType = function (name, padding, formatter) {\n        return function (type, value) {\n            if (type !== name) {\n                return false;\n            }\n\n            padding = 32;   //override as per the new ABI.\n\n            return padLeft(formatter ? formatter(value) : value, padding * 2);\n        };\n    };\n\n    var formatBool = function (value) {\n        return value ? '01' : '00';\n    };\n\n    return [\n        prefixedType('uint', calcBitPadding),\n        prefixedType('int', calcBitPadding),\n        prefixedType('hash', calcBitPadding),\n        prefixedType('string', calcBytePadding),\n        prefixedType('real', calcRealPadding),\n        prefixedType('ureal', calcRealPadding),\n        namedType('address', 20, formatStandard),\n        namedType('bool', 1, formatBool),\n    ];\n};\n\nvar inputTypes = setupInputTypes();\n\nvar toAbiInput = function (json, methodName, params) {\n    var bytes = \"\";\n    var index = findMethodIndex(json, methodName);\n\n    if (index === -1) {\n        return;\n    }\n\n    var method = json[index];\n\n    for (var i = 0; i < method.inputs.length; i++) {\n        var found = false;\n        for (var j = 0; j < inputTypes.length && !found; j++) {\n            found = inputTypes[j](method.inputs[i].type, params[i]);\n        }\n        if (!found) {\n            console.error('unsupported json type: ' + method.inputs[i].type);\n        }\n        bytes += found;\n    }\n    return bytes;\n};\n\nvar setupOutputTypes = function () {\n\n    var prefixedType = function (prefix, calcPadding) {\n        return function (type) {\n            var expected = prefix;\n            if (type.indexOf(expected) !== 0) {\n                return -1;\n            }\n\n            var padding = calcPadding(type, expected);\n            if (padding > 32)\n                return -1;   // not allowed to be so big.\n            padding = 32;  // override as per the new ABI.\n            return padding * 2;\n        };\n    };\n\n    var namedType = function (name, padding) {\n        return function (type) {\n            padding = 32;  // override as per the new ABI.\n            return name === type ? padding * 2 : -1;\n        };\n    };\n\n    var formatInt = function (value) {\n        return value.length <= 8 ? +parseInt(value, 16) : hexToDec(value);\n    };\n\n    var formatHash = function (value) {\n        return \"0x\" + value;\n    };\n\n    var formatBool = function (value) {\n        return value === '1' ? true : false;\n    };\n\n    var formatString = function (value) {\n        return web3.toAscii(value);\n    };\n\n    return [\n    { padding: prefixedType('uint', calcBitPadding), format: formatInt },\n    { padding: prefixedType('int', calcBitPadding), format: formatInt },\n    { padding: prefixedType('hash', calcBitPadding), format: formatHash },\n    { padding: prefixedType('string', calcBytePadding), format: formatString },\n    { padding: prefixedType('real', calcRealPadding), format: formatInt },\n    { padding: prefixedType('ureal', calcRealPadding), format: formatInt },\n    { padding: namedType('address', 20) },\n    { padding: namedType('bool', 1), format: formatBool }\n    ];\n};\n\nvar outputTypes = setupOutputTypes();\n\nvar fromAbiOutput = function (json, methodName, output) {\n    var index = findMethodIndex(json, methodName);\n\n    if (index === -1) {\n        return;\n    }\n\n    output = output.slice(2);\n\n    var result = [];\n    var method = json[index];\n    for (var i = 0; i < method.outputs.length; i++) {\n        var padding = -1;\n        for (var j = 0; j < outputTypes.length && padding === -1; j++) {\n            padding = outputTypes[j].padding(method.outputs[i].type);\n        }\n\n        if (padding === -1) {\n            // not found output parsing\n            continue;\n        }\n        var res = output.slice(0, padding);\n        var formatter = outputTypes[j - 1].format;\n        result.push(formatter ? formatter(res) : (\"0x\" + res));\n        output = output.slice(padding);\n    }\n\n    return result;\n};\n\nvar inputParser = function (json) {\n    var parser = {};\n    json.forEach(function (method) {\n        parser[method.name] = function () {\n            var params = Array.prototype.slice.call(arguments);\n            return toAbiInput(json, method.name, params);\n        };\n    });\n\n    return parser;\n};\n\nvar outputParser = function (json) {\n    var parser = {};\n    json.forEach(function (method) {\n        parser[method.name] = function (output) {\n            return fromAbiOutput(json, method.name, output);\n        };\n    });\n\n    return parser;\n};\n\nvar methodSignature = function (json, name) {\n    var method = json[findMethodIndex(json, name)];\n    var result = name + '(';\n    var inputTypes = method.inputs.map(function (inp) {\n        return inp.type;\n    });\n    result += inputTypes.join(',');\n    result += ')';\n\n    return web3.sha3(web3.fromAscii(result));\n};\n\nmodule.exports = {\n    inputParser: inputParser,\n    outputParser: outputParser,\n    methodSignature: methodSignature\n};\n\n",
     "/*\n    This file is part of ethereum.js.\n\n    ethereum.js is free software: you can redistribute it and/or modify\n    it under the terms of the GNU Lesser General Public License as published by\n    the Free Software Foundation, either version 3 of the License, or\n    (at your option) any later version.\n\n    ethereum.js is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU Lesser General Public License for more details.\n\n    You should have received a copy of the GNU Lesser General Public License\n    along with ethereum.js.  If not, see .\n*/\n/** @file autoprovider.js\n * @authors:\n *   Marek Kotewicz \n *   Marian Oancea \n * @date 2014\n */\n\n/*\n * @brief if qt object is available, uses QtProvider,\n * if not tries to connect over websockets\n * if it fails, it uses HttpRpcProvider\n */\n\n// TODO: is these line is supposed to be here? \nif (\"build\" !== 'build') {/*\n    var WebSocket = require('ws'); // jshint ignore:line\n    var web3 = require('./web3'); // jshint ignore:line\n*/}\n\nvar AutoProvider = function (userOptions) {\n    if (web3.haveProvider()) {\n        return;\n    }\n\n    // before we determine what provider we are, we have to cache request\n    this.sendQueue = [];\n    this.onmessageQueue = [];\n\n    if (navigator.qt) {\n        this.provider = new web3.providers.QtProvider();\n        return;\n    }\n\n    userOptions = userOptions || {};\n    var options = {\n        httprpc: userOptions.httprpc || 'http://localhost:8080',\n        websockets: userOptions.websockets || 'ws://localhost:40404/eth'\n    };\n\n    var self = this;\n    var closeWithSuccess = function (success) {\n        ws.close();\n        if (success) {\n            self.provider = new web3.providers.WebSocketProvider(options.websockets);\n        } else {\n            self.provider = new web3.providers.HttpRpcProvider(options.httprpc);\n            self.poll = self.provider.poll.bind(self.provider);\n        }\n        self.sendQueue.forEach(function (payload) {\n            self.provider(payload);\n        });\n        self.onmessageQueue.forEach(function (handler) {\n            self.provider.onmessage = handler;\n        });\n    };\n\n    var ws = new WebSocket(options.websockets);\n\n    ws.onopen = function() {\n        closeWithSuccess(true);\n    };\n\n    ws.onerror = function() {\n        closeWithSuccess(false);\n    };\n};\n\nAutoProvider.prototype.send = function (payload) {\n    if (this.provider) {\n        this.provider.send(payload);\n        return;\n    }\n    this.sendQueue.push(payload);\n};\n\nObject.defineProperty(AutoProvider.prototype, 'onmessage', {\n    set: function (handler) {\n        if (this.provider) {\n            this.provider.onmessage = handler;\n            return;\n        }\n        this.onmessageQueue.push(handler);\n    }\n});\n\nmodule.exports = AutoProvider;\n",
     "/*\n    This file is part of ethereum.js.\n\n    ethereum.js is free software: you can redistribute it and/or modify\n    it under the terms of the GNU Lesser General Public License as published by\n    the Free Software Foundation, either version 3 of the License, or\n    (at your option) any later version.\n\n    ethereum.js is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU Lesser General Public License for more details.\n\n    You should have received a copy of the GNU Lesser General Public License\n    along with ethereum.js.  If not, see .\n*/\n/** @file contract.js\n * @authors:\n *   Marek Kotewicz \n * @date 2014\n */\n\n// TODO: is these line is supposed to be here? \nif (\"build\" !== 'build') {/*\n    var web3 = require('./web3'); // jshint ignore:line\n*/}\n\nvar abi = require('./abi');\n\n// method signature length in bytes\nvar ETH_METHOD_SIGNATURE_LENGTH = 4;\n\nvar contract = function (address, desc) {\n    var inputParser = abi.inputParser(desc);\n    var outputParser = abi.outputParser(desc);\n\n    var contract = {};\n\n    desc.forEach(function (method) {\n        contract[method.name] = function () {\n            var params = Array.prototype.slice.call(arguments);\n            var parsed = inputParser[method.name].apply(null, params);\n\n            var onSuccess = function (result) {\n                return outputParser[method.name](result);\n            };\n\n            return {\n                call: function (extra) {\n                    extra = extra || {};\n                    extra.to = address;\n                    return abi.methodSignature(desc, method.name).then(function (signature) {\n                        extra.data = signature.slice(0, 2 + ETH_METHOD_SIGNATURE_LENGTH * 2) + parsed;\n                        return web3.eth.call(extra).then(onSuccess);\n                    });\n                },\n                transact: function (extra) {\n                    extra = extra || {};\n                    extra.to = address;\n                    return abi.methodSignature(desc, method.name).then(function (signature) {\n                        extra.data = signature.slice(0, 2 + ETH_METHOD_SIGNATURE_LENGTH * 2) + parsed;\n                        return web3.eth.transact(extra).then(onSuccess);\n                    });\n                }\n            };\n        };\n    });\n\n    return contract;\n};\n\nmodule.exports = contract;\n",
     "/*\n    This file is part of ethereum.js.\n\n    ethereum.js is free software: you can redistribute it and/or modify\n    it under the terms of the GNU Lesser General Public License as published by\n    the Free Software Foundation, either version 3 of the License, or\n    (at your option) any later version.\n\n    ethereum.js is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU Lesser General Public License for more details.\n\n    You should have received a copy of the GNU Lesser General Public License\n    along with ethereum.js.  If not, see .\n*/\n/** @file httprpc.js\n * @authors:\n *   Marek Kotewicz \n *   Marian Oancea \n * @date 2014\n */\n\n// TODO: is these line is supposed to be here? \nif (\"build\" !== 'build') {/*\n    var XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest; // jshint ignore:line\n*/}\n\nvar HttpRpcProvider = function (host) {\n    this.handlers = [];\n    this.host = host;\n};\n\nfunction formatJsonRpcObject(object) {\n    return {\n        jsonrpc: '2.0',\n        method: object.call,\n        params: object.args,\n        id: object._id\n    };\n}\n\nfunction formatJsonRpcMessage(message) {\n    var object = JSON.parse(message);\n\n    return {\n        _id: object.id,\n        data: object.result,\n        error: object.error\n    };\n}\n\nHttpRpcProvider.prototype.sendRequest = function (payload, cb) {\n    var data = formatJsonRpcObject(payload);\n\n    var request = new XMLHttpRequest();\n    request.open(\"POST\", this.host, true);\n    request.send(JSON.stringify(data));\n    request.onreadystatechange = function () {\n        if (request.readyState === 4 && cb) {\n            cb(request);\n        }\n    };\n};\n\nHttpRpcProvider.prototype.send = function (payload) {\n    var self = this;\n    this.sendRequest(payload, function (request) {\n        self.handlers.forEach(function (handler) {\n            handler.call(self, formatJsonRpcMessage(request.responseText));\n        });\n    });\n};\n\nHttpRpcProvider.prototype.poll = function (payload, id) {\n    var self = this;\n    this.sendRequest(payload, function (request) {\n        var parsed = JSON.parse(request.responseText);\n        if (parsed.error || (parsed.result instanceof Array ? parsed.result.length === 0 : !parsed.result)) {\n            return;\n        }\n        self.handlers.forEach(function (handler) {\n            handler.call(self, {_event: payload.call, _id: id, data: parsed.result});\n        });\n    });\n};\n\nObject.defineProperty(HttpRpcProvider.prototype, \"onmessage\", {\n    set: function (handler) {\n        this.handlers.push(handler);\n    }\n});\n\nmodule.exports = HttpRpcProvider;\n",
diff --git a/libjsqrc/ethereumjs/dist/ethereum.min.js b/libjsqrc/ethereumjs/dist/ethereum.min.js
index 1eae35bd3..58ef8847e 100644
--- a/libjsqrc/ethereumjs/dist/ethereum.min.js
+++ b/libjsqrc/ethereumjs/dist/ethereum.min.js
@@ -1 +1 @@
-require=function t(e,n,r){function o(a,s){if(!n[a]){if(!e[a]){var u="function"==typeof require&&require;if(!s&&u)return u(a,!0);if(i)return i(a,!0);var c=new Error("Cannot find module '"+a+"'");throw c.code="MODULE_NOT_FOUND",c}var l=n[a]={exports:{}};e[a][0].call(l.exports,function(t){var n=e[a][1][t];return o(n?n:t)},l,l.exports,t,e,n,r)}return n[a].exports}for(var i="function"==typeof require&&require,a=0;ai;i++)o+=r[i]/8;return o},c=function(){var t=function(t){return"number"==typeof t?t.toString(16):"string"==typeof t&&0===t.indexOf("0x")?t.substr(2):"string"==typeof t?web3.toHex(t):(+t).toString(16)},e=function(e,n){return function(r,o){var a=e;if(0!==r.indexOf(a))return!1;var s=n(r,a);return s>32?!1:(s=32,"string"===e?web3.fromAscii(o,s).substr(2):i(t(o),2*s))}},n=function(t,e,n){return function(r,o){return r!==t?!1:(e=32,i(n?n(o):o,2*e))}},r=function(t){return t?"01":"00"};return[e("uint",a),e("int",a),e("hash",a),e("string",s),e("real",u),e("ureal",u),n("address",20,t),n("bool",1,r)]},l=c(),h=function(t,e,n){var r="",i=o(t,e);if(-1!==i){for(var a=t[i],s=0;s32?-1:(o=32,2*o)}},e=function(t,e){return function(n){return e=32,t===n?2*e:-1}},r=function(t){return t.length<=8?+parseInt(t,16):n(t)},o=function(t){return"0x"+t},i=function(t){return"1"===t?!0:!1},c=function(t){return web3.toAscii(t)};return[{padding:t("uint",a),format:r},{padding:t("int",a),format:r},{padding:t("hash",a),format:o},{padding:t("string",s),format:c},{padding:t("real",u),format:r},{padding:t("ureal",u),format:r},{padding:e("address",20)},{padding:e("bool",1),format:i}]},p=f(),d=function(t,e,n){var r=o(t,e);if(-1!==r){n=n.slice(2);for(var i=[],a=t[r],s=0;sn;n+=2){var o=t.charCodeAt(n);if(0===o)break;e+=String.fromCharCode(parseInt(t.substr(n,2),16))}return e},fromAscii:function(t,e){e=void 0===e?0:e;for(var n=this.toHex(t);n.length<2*e;)n+="00";return"0x"+n},toDecimal:function(t){return p(t.substring(2))},fromDecimal:function(t){return"0x"+d(t)},toEth:function(t){for(var e="string"==typeof t?0===t.indexOf("0x")?parseInt(t.substr(2),16):parseInt(t):t,n=0,r=["wei","Kwei","Mwei","Gwei","szabo","finney","ether","grand","Mether","Gether","Tether","Pether","Eether","Zether","Yether","Nether","Dether","Vether","Uether"];e>3e3&&ni;i++)o+=r[i]/8;return o},c=function(){var t=function(t){return"number"==typeof t?t.toString(16):"string"==typeof t&&0===t.indexOf("0x")?t.substr(2):(+t).toString(16)},e=function(e,n){return function(r,o){var a=e;if(0!==r.indexOf(a))return!1;var s=n(r,a);return s>32?!1:(s=32,"string"===e?web3.fromAscii(o,s).substr(2):i(t(o),2*s))}},n=function(t,e,n){return function(r,o){return r!==t?!1:(e=32,i(n?n(o):o,2*e))}},r=function(t){return t?"01":"00"};return[e("uint",a),e("int",a),e("hash",a),e("string",s),e("real",u),e("ureal",u),n("address",20,t),n("bool",1,r)]},l=c(),h=function(t,e,n){var r="",i=o(t,e);if(-1!==i){for(var a=t[i],s=0;s32?-1:(o=32,2*o)}},e=function(t,e){return function(n){return e=32,t===n?2*e:-1}},r=function(t){return t.length<=8?+parseInt(t,16):n(t)},o=function(t){return"0x"+t},i=function(t){return"1"===t?!0:!1},c=function(t){return web3.toAscii(t)};return[{padding:t("uint",a),format:r},{padding:t("int",a),format:r},{padding:t("hash",a),format:o},{padding:t("string",s),format:c},{padding:t("real",u),format:r},{padding:t("ureal",u),format:r},{padding:e("address",20)},{padding:e("bool",1),format:i}]},p=f(),d=function(t,e,n){var r=o(t,e);if(-1!==r){n=n.slice(2);for(var i=[],a=t[r],s=0;sn;n+=2){var o=t.charCodeAt(n);if(0===o)break;e+=String.fromCharCode(parseInt(t.substr(n,2),16))}return e},fromAscii:function(t,e){e=void 0===e?0:e;for(var n=this.toHex(t);n.length<2*e;)n+="00";return"0x"+n},toDecimal:function(t){return p(t.substring(2))},fromDecimal:function(t){return"0x"+d(t)},toEth:function(t){for(var e="string"==typeof t?0===t.indexOf("0x")?parseInt(t.substr(2),16):parseInt(t):t,n=0,r=["wei","Kwei","Mwei","Gwei","szabo","finney","ether","grand","Mether","Gether","Tether","Pether","Eether","Zether","Yether","Nether","Dether","Vether","Uether"];e>3e3&&n
+
+
+
+
+
+
+
+
+    

contract

+
+
+ +
+ +
+ + + diff --git a/libjsqrc/ethereumjs/lib/abi.js b/libjsqrc/ethereumjs/lib/abi.js index 1a88317bc..b964597ea 100644 --- a/libjsqrc/ethereumjs/lib/abi.js +++ b/libjsqrc/ethereumjs/lib/abi.js @@ -90,8 +90,8 @@ var setupInputTypes = function () { return value.toString(16); else if (typeof value === "string" && value.indexOf('0x') === 0) return value.substr(2); - else if (typeof value === "string") - return web3.toHex(value); +// else if (typeof value === "string") +// return web3.toHex(value); else return (+value).toString(16); }; diff --git a/libqwebthree/QWebThree.cpp b/libqwebthree/QWebThree.cpp index 891d84ffa..3f4b5c67d 100644 --- a/libqwebthree/QWebThree.cpp +++ b/libqwebthree/QWebThree.cpp @@ -140,7 +140,7 @@ void QWebThree::onDataProcessed(QString _json, QString _addInfo) for (int i = 0; i < resultsArray.size(); i++) { QJsonObject elem = resultsArray[i].toObject(); - if (elem.contains("result")) + if (elem["result"].isArray() && elem["result"].toArray().size() > 0) { QJsonObject res; res["_event"] = _addInfo; diff --git a/libsolidity/Compiler.cpp b/libsolidity/Compiler.cpp index 782a7efe2..bd6571b9a 100644 --- a/libsolidity/Compiler.cpp +++ b/libsolidity/Compiler.cpp @@ -50,10 +50,9 @@ void Compiler::compileContract(ContractDefinition const& _contract, vectoraccept(*this); // Swap the runtime context with the creation-time context - CompilerContext runtimeContext; - swap(m_context, runtimeContext); + swap(m_context, m_runtimeContext); initializeContext(_contract, _magicGlobals, _contracts); - packIntoContractCreator(_contract, runtimeContext); + packIntoContractCreator(_contract, m_runtimeContext); } void Compiler::initializeContext(ContractDefinition const& _contract, vector const& _magicGlobals, diff --git a/libsolidity/Compiler.h b/libsolidity/Compiler.h index e83d1ed3a..c229a7a8a 100644 --- a/libsolidity/Compiler.h +++ b/libsolidity/Compiler.h @@ -35,6 +35,7 @@ public: void compileContract(ContractDefinition const& _contract, std::vector const& _magicGlobals, std::map const& _contracts); bytes getAssembledBytecode() { return m_context.getAssembledBytecode(m_optimize); } + bytes getRuntimeBytecode() { return m_runtimeContext.getAssembledBytecode(m_optimize);} void streamAssembly(std::ostream& _stream) const { m_context.streamAssembly(_stream); } private: @@ -70,6 +71,7 @@ private: bool const m_optimize; CompilerContext m_context; + CompilerContext m_runtimeContext; std::vector m_breakTags; ///< tag to jump to for a "break" statement std::vector m_continueTags; ///< tag to jump to for a "continue" statement eth::AssemblyItem m_returnTag; ///< tag to jump to for a "return" statement diff --git a/libsolidity/CompilerStack.cpp b/libsolidity/CompilerStack.cpp index 904c77c5a..5532d74bc 100644 --- a/libsolidity/CompilerStack.cpp +++ b/libsolidity/CompilerStack.cpp @@ -30,6 +30,8 @@ #include #include +#include + using namespace std; namespace dev @@ -117,6 +119,7 @@ void CompilerStack::compile(bool _optimize) contractBytecode); Contract& compiledContract = m_contracts[contract->getName()]; compiledContract.bytecode = compiler->getAssembledBytecode(); + compiledContract.runtimeBytecode = compiler->getRuntimeBytecode(); compiledContract.compiler = move(compiler); contractBytecode[compiledContract.contract] = &compiledContract.bytecode; } @@ -134,6 +137,16 @@ bytes const& CompilerStack::getBytecode(string const& _contractName) const return getContract(_contractName).bytecode; } +bytes const& CompilerStack::getRuntimeBytecode(string const& _contractName) const +{ + return getContract(_contractName).runtimeBytecode; +} + +dev::h256 CompilerStack::getContractCodeHash(string const& _contractName) const +{ + return dev::sha3(getRuntimeBytecode(_contractName)); +} + void CompilerStack::streamAssembly(ostream& _outStream, string const& _contractName) const { getContract(_contractName).compiler->streamAssembly(_outStream); diff --git a/libsolidity/CompilerStack.h b/libsolidity/CompilerStack.h index afc9a5162..aa55abe50 100644 --- a/libsolidity/CompilerStack.h +++ b/libsolidity/CompilerStack.h @@ -28,6 +28,7 @@ #include #include #include +#include namespace dev { namespace solidity { @@ -75,7 +76,13 @@ public: /// @returns the compiled bytecode bytes const& compile(std::string const& _sourceCode, bool _optimize = false); + /// @returns the assembled bytecode for a contract. bytes const& getBytecode(std::string const& _contractName = "") const; + /// @returns the runtime bytecode for the contract, i.e. the code that is returned by the constructor. + bytes const& getRuntimeBytecode(std::string const& _contractName = "") const; + /// @returns hash of the runtime bytecode for the contract, i.e. the code that is returned by the constructor. + dev::h256 getContractCodeHash(std::string const& _contractName = "") const; + /// Streams a verbose version of the assembly to @a _outStream. /// Prerequisite: Successful compilation. void streamAssembly(std::ostream& _outStream, std::string const& _contractName = "") const; @@ -121,6 +128,7 @@ private: ContractDefinition const* contract = nullptr; std::shared_ptr compiler; bytes bytecode; + bytes runtimeBytecode; std::shared_ptr interfaceHandler; mutable std::unique_ptr interface; mutable std::unique_ptr solidityInterface; diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index bcb577374..2b6e53cb8 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -326,6 +326,13 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) m_context << u256(32) << u256(0) << eth::logInstruction(logNumber); break; } + case Location::BLOCKHASH: + { + arguments[0]->accept(*this); + appendTypeConversion(*arguments[0]->getType(), *function.getParameterTypes()[0], true); + m_context << eth::Instruction::BLOCKHASH; + break; + } case Location::ECRECOVER: case Location::SHA256: case Location::RIPEMD160: @@ -344,7 +351,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) return false; } -bool ExpressionCompiler::visit(NewExpression const& _newExpression) +bool ExpressionCompiler::visit(NewExpression const&) { // code is created for the function call (CREATION) only return false; diff --git a/libsolidity/InterfaceHandler.cpp b/libsolidity/InterfaceHandler.cpp index a5c6f4a1d..4c7ae5f45 100644 --- a/libsolidity/InterfaceHandler.cpp +++ b/libsolidity/InterfaceHandler.cpp @@ -106,7 +106,7 @@ std::unique_ptr InterfaceHandler::getUserDocumentation(ContractDefi if (!m_notice.empty()) {// since @notice is the only user tag if missing function should not appear user["notice"] = Json::Value(m_notice); - methods[it.second->getName()] = user; + methods[it.second->getCanonicalSignature()] = user; } } } @@ -162,7 +162,7 @@ std::unique_ptr InterfaceHandler::getDevDocumentation(ContractDefin method["return"] = m_return; if (!method.empty()) // add the function, only if we have any documentation to add - methods[it.second->getName()] = method; + methods[it.second->getCanonicalSignature()] = method; } } doc["methods"] = methods; diff --git a/libsolidity/Token.h b/libsolidity/Token.h index 2d4441d08..e5c61c7e4 100644 --- a/libsolidity/Token.h +++ b/libsolidity/Token.h @@ -47,6 +47,10 @@ #include #include +#if defined(DELETE) +#error The macro "DELETE" from windows.h conflicts with this file. Please change the order of includes. +#endif + namespace dev { namespace solidity diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index 6a1b120c9..ae87a0886 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -693,8 +693,8 @@ MagicType::MagicType(MagicType::Kind _kind): { case Kind::BLOCK: m_members = MemberList({{"coinbase", make_shared(0, IntegerType::Modifier::ADDRESS)}, - {"timestamp", make_shared(256)}, - {"prevhash", make_shared(256, IntegerType::Modifier::HASH)}, + {"timestamp", make_shared(256)}, + {"blockhash", make_shared(strings{"uint"}, strings{"hash"}, FunctionType::Location::BLOCKHASH)}, {"difficulty", make_shared(256)}, {"number", make_shared(256)}, {"gaslimit", make_shared(256)}}); diff --git a/libsolidity/Types.h b/libsolidity/Types.h index 158d58eb9..38e50acfa 100644 --- a/libsolidity/Types.h +++ b/libsolidity/Types.h @@ -354,7 +354,7 @@ public: SHA3, SUICIDE, ECRECOVER, SHA256, RIPEMD160, LOG0, LOG1, LOG2, LOG3, LOG4, - SET_GAS, SET_VALUE, + SET_GAS, SET_VALUE, BLOCKHASH, BARE }; virtual Category getCategory() const override { return Category::FUNCTION; } diff --git a/libweb3jsonrpc/WebThreeStubServerBase.cpp b/libweb3jsonrpc/WebThreeStubServerBase.cpp index 5003454f0..640ad3679 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.cpp +++ b/libweb3jsonrpc/WebThreeStubServerBase.cpp @@ -84,7 +84,7 @@ static Json::Value toJson(dev::eth::LocalisedLogEntry const& _e) static Json::Value toJson(dev::eth::LocalisedLogEntries const& _es) // commented to avoid warning. Uncomment once in use @ poC-7. { - Json::Value res; + Json::Value res(Json::arrayValue); for (dev::eth::LocalisedLogEntry const& e: _es) res.append(toJson(e)); return res; diff --git a/mix/AssemblyDebuggerControl.cpp b/mix/AssemblyDebuggerControl.cpp index f14ab8bcd..f68ddc792 100644 --- a/mix/AssemblyDebuggerControl.cpp +++ b/mix/AssemblyDebuggerControl.cpp @@ -26,8 +26,8 @@ using namespace dev::mix; -AssemblyDebuggerControl::AssemblyDebuggerControl(dev::mix::AppContext* _context): - Extension(_context, ExtensionDisplayBehavior::ModalDialog) +AssemblyDebuggerControl::AssemblyDebuggerControl(AppContext* _context): + Extension(_context, ExtensionDisplayBehavior::RightView) { connect(_context->clientModel(), &ClientModel::showDebuggerWindow, this, &AssemblyDebuggerControl::showDebugger, Qt::QueuedConnection); } @@ -48,5 +48,6 @@ void AssemblyDebuggerControl::start() const void AssemblyDebuggerControl::showDebugger() { - this->addContentOn(this); + QObject* debugPanel = m_view->findChild("debugPanel", Qt::FindChildrenRecursively); + QMetaObject::invokeMethod(debugPanel, "update"); } diff --git a/mix/AssemblyDebuggerControl.h b/mix/AssemblyDebuggerControl.h index dbe9b0676..1240b3807 100644 --- a/mix/AssemblyDebuggerControl.h +++ b/mix/AssemblyDebuggerControl.h @@ -22,13 +22,13 @@ #include #include "Extension.h" -class AppContext; - namespace dev { namespace mix { +class AppContext; + /** * @brief Extension which display transaction creation or transaction call debugging. */ @@ -44,7 +44,7 @@ public: QString contentUrl() const override; private slots: - /// Update UI with machine states result. Display a modal dialog. + /// Update UI with machine states result. Displayed in the right side tab. void showDebugger(); }; diff --git a/mix/ClientModel.cpp b/mix/ClientModel.cpp index bcbed1fac..14fcf9bfa 100644 --- a/mix/ClientModel.cpp +++ b/mix/ClientModel.cpp @@ -116,7 +116,7 @@ void ClientModel::executeSequence(std::vector const& _seque { bytes contractCode = compilerRes->bytes(); std::vector transactonData; - QFunctionDefinition* f; + QFunctionDefinition* f = nullptr; ContractCallDataEncoder c; //encode data for all transactions for (auto const& t: _sequence) diff --git a/mix/CodeEditorExtensionManager.cpp b/mix/CodeEditorExtensionManager.cpp index a123c3b7a..2b1f03ff4 100644 --- a/mix/CodeEditorExtensionManager.cpp +++ b/mix/CodeEditorExtensionManager.cpp @@ -25,7 +25,7 @@ #include #include #include -#include "ConstantCompilationControl.h" +#include "StatusPane.h" #include "AssemblyDebuggerControl.h" #include "StateListView.h" #include "AppContext.h" @@ -56,10 +56,9 @@ void CodeEditorExtensionManager::loadEditor(QQuickItem* _editor) void CodeEditorExtensionManager::initExtensions() { - std::shared_ptr output = std::make_shared(m_appContext); + std::shared_ptr output = std::make_shared(m_appContext); std::shared_ptr debug = std::make_shared(m_appContext); std::shared_ptr stateList = std::make_shared(m_appContext); - QObject::connect(m_appContext->clientModel(), &ClientModel::runFailed, output.get(), &ConstantCompilationControl::displayError); QObject::connect(m_appContext->codeModel(), &CodeModel::compilationComplete, this, &CodeEditorExtensionManager::applyCodeHighlight); initExtension(output); @@ -73,10 +72,10 @@ void CodeEditorExtensionManager::initExtension(std::shared_ptr _ext) { try { - if (_ext->getDisplayBehavior() == ExtensionDisplayBehavior::Tab) - _ext->addTabOn(m_tabView); - else if (_ext->getDisplayBehavior() == ExtensionDisplayBehavior::RightTab) - _ext->addTabOn(m_rightTabView); + if (_ext->getDisplayBehavior() == ExtensionDisplayBehavior::RightView) + _ext->addTabOn(m_rightView); + if (_ext->getDisplayBehavior() == ExtensionDisplayBehavior::HeaderView) + _ext->addTabOn(m_headerView); } catch (...) { @@ -93,13 +92,13 @@ void CodeEditorExtensionManager::applyCodeHighlight() //TODO: reimplement } -void CodeEditorExtensionManager::setRightTabView(QQuickItem* _tabView) +void CodeEditorExtensionManager::setRightView(QQuickItem* _rightView) { - m_rightTabView = _tabView; + m_rightView = _rightView; initExtensions(); //TODO: move this to a proper place } -void CodeEditorExtensionManager::setTabView(QQuickItem* _tabView) +void CodeEditorExtensionManager::setHeaderView(QQuickItem* _headerView) { - m_tabView = _tabView; + m_headerView = _headerView; } diff --git a/mix/CodeEditorExtensionManager.h b/mix/CodeEditorExtensionManager.h index 2f2a315b9..fe6fbb33a 100644 --- a/mix/CodeEditorExtensionManager.h +++ b/mix/CodeEditorExtensionManager.h @@ -26,7 +26,7 @@ #include #include #include -#include "ConstantCompilationControl.h" +#include "StatusPane.h" namespace dev { @@ -43,8 +43,8 @@ class CodeEditorExtensionManager: public QObject { Q_OBJECT - Q_PROPERTY(QQuickItem* tabView MEMBER m_tabView WRITE setTabView) - Q_PROPERTY(QQuickItem* rightTabView MEMBER m_rightTabView WRITE setRightTabView) + Q_PROPERTY(QQuickItem* headerView MEMBER m_headerView WRITE setHeaderView) + Q_PROPERTY(QQuickItem* rightView MEMBER m_rightView WRITE setRightView) public: CodeEditorExtensionManager(); @@ -54,17 +54,17 @@ public: /// Initialize extension. void initExtension(std::shared_ptr); /// Set current tab view - void setTabView(QQuickItem*); + void setHeaderView(QQuickItem*); /// Set current right tab view. - void setRightTabView(QQuickItem*); + void setRightView(QQuickItem*); private slots: void applyCodeHighlight(); private: QVector> m_features; - QQuickItem* m_tabView; - QQuickItem* m_rightTabView; + QQuickItem* m_headerView; + QQuickItem* m_rightView; AppContext* m_appContext; void loadEditor(QQuickItem* _editor); }; diff --git a/mix/CodeModel.cpp b/mix/CodeModel.cpp index 914c7e079..699e0753d 100644 --- a/mix/CodeModel.cpp +++ b/mix/CodeModel.cpp @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + 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 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. + 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 . + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . */ /** @file CodeModel.cpp * @author Arkadiy Paronyan arkadiy@ethdev.com @@ -168,7 +168,7 @@ void CodeModel::onCompilationComplete(CompilationResult*_newResult) bool CodeModel::hasContract() const { - return m_result->contract()->functionsList().size() > 0; + return m_result->successful(); } void CodeModel::updateFormatting(QTextDocument* _document) diff --git a/mix/CodeModel.h b/mix/CodeModel.h index e1a2a0fbd..0c1de2a90 100644 --- a/mix/CodeModel.h +++ b/mix/CodeModel.h @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + 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 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. + 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 . + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . */ /** @file CodeModel.h * @author Arkadiy Paronyan arkadiy@ethdev.com @@ -65,6 +65,8 @@ class CompilationResult: public QObject { Q_OBJECT Q_PROPERTY(QContractDefinition* contract READ contract) + Q_PROPERTY(QString compilerMessage READ compilerMessage CONSTANT) + Q_PROPERTY(bool successful READ successful CONSTANT) public: /// Empty compilation result constructor diff --git a/mix/ConstantCompilationControl.cpp b/mix/ConstantCompilationControl.cpp deleted file mode 100644 index 6352f070d..000000000 --- a/mix/ConstantCompilationControl.cpp +++ /dev/null @@ -1,94 +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 . -*/ -/** @file ConstantCompilationControl.cpp - * @author Yann yann@ethdev.com - * @date 2014 - * Ethereum IDE client. - */ - -#include -#include -#include -#include -#include -#include -#include -#include "ConstantCompilationControl.h" -#include "QContractDefinition.h" -#include "AppContext.h" -#include "CodeModel.h" - -using namespace dev::mix; - - -ConstantCompilationControl::ConstantCompilationControl(AppContext* _context): Extension(_context, ExtensionDisplayBehavior::Tab) -{ - connect(_context->codeModel(), &CodeModel::compilationComplete, this, &ConstantCompilationControl::update); - connect(_context->codeModel(), &CodeModel::compilationComplete, this, &ConstantCompilationControl::update); -} - -QString ConstantCompilationControl::contentUrl() const -{ - return QStringLiteral("qrc:/qml/BasicContent.qml"); -} - -QString ConstantCompilationControl::title() const -{ - return QApplication::tr("compiler"); -} - -void ConstantCompilationControl::start() const -{ -} - -void ConstantCompilationControl::update() -{ - auto result = m_ctx->codeModel()->code(); - - QObject* status = m_view->findChild("status", Qt::FindChildrenRecursively); - QObject* content = m_view->findChild("content", Qt::FindChildrenRecursively); - if (result->successful()) - { - status->setProperty("text", "succeeded"); - status->setProperty("color", "green"); - content->setProperty("text", result->assemblyCode()); - } - else - { - status->setProperty("text", "failure"); - status->setProperty("color", "red"); - content->setProperty("text", result->compilerMessage()); - } -} - -void ConstantCompilationControl::resetOutPut() -{ - QObject* status = m_view->findChild("status", Qt::FindChildrenRecursively); - QObject* content = m_view->findChild("content", Qt::FindChildrenRecursively); - status->setProperty("text", ""); - content->setProperty("text", ""); -} - - -void ConstantCompilationControl::displayError(QString const& _error) -{ - QObject* status = m_view->findChild("status", Qt::FindChildrenRecursively); - QObject* content = m_view->findChild("content", Qt::FindChildrenRecursively); - status->setProperty("text", "failure"); - status->setProperty("color", "red"); - content->setProperty("text", _error); -} diff --git a/mix/DebuggingStateWrapper.cpp b/mix/DebuggingStateWrapper.cpp index 72bb02ecd..85179e84b 100644 --- a/mix/DebuggingStateWrapper.cpp +++ b/mix/DebuggingStateWrapper.cpp @@ -66,55 +66,134 @@ std::tuple, QQMLMap*> DebuggingStateWrapper::getHumanReadableCod return std::make_tuple(codeStr, QPointer(new QQMLMap(codeMapping))); } -QString DebuggingStateWrapper::gasLeft() +QString DebuggingStateWrapper::gasCost() { std::ostringstream ss; - ss << std::dec << (m_state.gas - m_state.gasCost); + ss << std::dec << m_state.gasCost; return QString::fromStdString(ss.str()); } -QString DebuggingStateWrapper::gasCost() +QString DebuggingStateWrapper::gas() { std::ostringstream ss; - ss << std::dec << m_state.gasCost; + ss << std::dec << m_state.gas; return QString::fromStdString(ss.str()); } -QString DebuggingStateWrapper::gas() +QString DebuggingStateWrapper::newMemSize() { std::ostringstream ss; - ss << std::dec << m_state.gas; + ss << std::dec << m_state.newMemSize; return QString::fromStdString(ss.str()); } -QString DebuggingStateWrapper::debugStack() +QStringList DebuggingStateWrapper::debugStack() { - QString stack; + QStringList stack; for (auto i: m_state.stack) - stack.prepend(QString::fromStdString(prettyU256(i)) + "\n"); + stack.append(QString::fromStdString(prettyU256(i))); - return stack; + return fillList(stack, ""); } -QString DebuggingStateWrapper::debugStorage() +QStringList DebuggingStateWrapper::debugStorage() { - std::stringstream s; + QStringList storage; for (auto const& i: m_state.storage) + { + std::stringstream s; s << "@" << prettyU256(i.first) << " " << prettyU256(i.second); + storage.append(QString::fromStdString(s.str())); + } + return fillList(storage, "@ -"); +} - return QString::fromStdString(s.str()); +QVariantList DebuggingStateWrapper::debugMemory() +{ + std::vector> dump = memDumpToList(m_state.memory, 16); + QStringList filled; + filled.append(" "); + filled.append(" "); + filled.append(" "); + return fillList(qVariantDump(dump), QVariant(filled)); } -QString DebuggingStateWrapper::debugMemory() +QVariantList DebuggingStateWrapper::debugCallData() { - return QString::fromStdString(memDump(m_state.memory, 16, false)); + std::vector> dump = memDumpToList(m_data, 16); + QStringList filled; + filled.append(" "); + filled.append(" "); + filled.append(" "); + return fillList(qVariantDump(dump), QVariant(filled)); } -QString DebuggingStateWrapper::debugCallData() +std::vector> DebuggingStateWrapper::memDumpToList(bytes const& _bytes, unsigned _width) { - return QString::fromStdString(memDump(m_data, 16, false)); + std::vector> dump; + for (unsigned i = 0; i < _bytes.size(); i += _width) + { + std::stringstream ret; + std::vector dumpLine; + ret << std::hex << std::setw(4) << std::setfill('0') << i << " "; + dumpLine.push_back(ret.str()); + ret.str(std::string()); + ret.clear(); + + for (unsigned j = i; j < i + _width; ++j) + if (j < _bytes.size()) + if (_bytes[j] >= 32 && _bytes[j] < 127) + ret << (char)_bytes[j]; + else + ret << '?'; + else + ret << ' '; + dumpLine.push_back(ret.str()); + ret.str(std::string()); + ret.clear(); + + for (unsigned j = i; j < i + _width && j < _bytes.size(); ++j) + ret << std::setfill('0') << std::setw(2) << std::hex << (unsigned)_bytes[j] << " "; + dumpLine.push_back(ret.str()); + dump.push_back(dumpLine); + } + return dump; } +QVariantList DebuggingStateWrapper::qVariantDump(std::vector> const& _dump) +{ + QVariantList ret; + for (std::vector const& line: _dump) + { + QStringList qLine; + for (std::string const& cell: line) + qLine.push_back(QString::fromStdString(cell)); + ret.append(QVariant(qLine)); + } + return ret; +} + +QStringList DebuggingStateWrapper::fillList(QStringList& _list, QString const& _emptyValue) +{ + if (_list.size() < 20) + { + for (int k = _list.size(); k < 20 - _list.size(); k++) + _list.append(_emptyValue); + } + return _list; +} + +QVariantList DebuggingStateWrapper::fillList(QVariantList _list, QVariant const& _emptyValue) +{ + if (_list.size() < 20) + { + for (int k = _list.size(); k < 20 - _list.size(); k++) + _list.append(_emptyValue); + } + return _list; +} + + QStringList DebuggingStateWrapper::levels() { QStringList levelsStr; @@ -136,6 +215,11 @@ QString DebuggingStateWrapper::headerInfo() return QString::fromStdString(ss.str()); } +QString DebuggingStateWrapper::instruction() +{ + return QString::fromStdString(dev::eth::instructionInfo(m_state.inst).name); +} + QString DebuggingStateWrapper::endOfDebug() { if (m_state.gasCost > m_state.gas) diff --git a/mix/DebuggingStateWrapper.h b/mix/DebuggingStateWrapper.h index 6d1ce4220..010db9af7 100644 --- a/mix/DebuggingStateWrapper.h +++ b/mix/DebuggingStateWrapper.h @@ -83,13 +83,14 @@ class DebuggingStateWrapper: public QObject Q_PROPERTY(int curPC READ curPC CONSTANT) Q_PROPERTY(QString gasCost READ gasCost CONSTANT) Q_PROPERTY(QString gas READ gas CONSTANT) - Q_PROPERTY(QString gasLeft READ gasLeft CONSTANT) - Q_PROPERTY(QString debugStack READ debugStack CONSTANT) - Q_PROPERTY(QString debugStorage READ debugStorage CONSTANT) - Q_PROPERTY(QString debugMemory READ debugMemory CONSTANT) - Q_PROPERTY(QString debugCallData READ debugCallData CONSTANT) + Q_PROPERTY(QString instruction READ instruction CONSTANT) + Q_PROPERTY(QStringList debugStack READ debugStack CONSTANT) + Q_PROPERTY(QStringList debugStorage READ debugStorage CONSTANT) + Q_PROPERTY(QVariantList debugMemory READ debugMemory CONSTANT) + Q_PROPERTY(QVariantList debugCallData READ debugCallData CONSTANT) Q_PROPERTY(QString headerInfo READ headerInfo CONSTANT) Q_PROPERTY(QString endOfDebug READ endOfDebug CONSTANT) + Q_PROPERTY(QString newMemSize READ newMemSize CONSTANT) Q_PROPERTY(QStringList levels READ levels CONSTANT) public: @@ -105,17 +106,21 @@ public: /// Get gas used. QString gas(); /// Get stack. - QString debugStack(); + QStringList debugStack(); /// Get storage. - QString debugStorage(); + QStringList debugStorage(); /// Get memory. - QString debugMemory(); + QVariantList debugMemory(); /// Get call data. - QString debugCallData(); + QVariantList debugCallData(); /// Get info to be displayed in the header. QString headerInfo(); /// get end of debug information. QString endOfDebug(); + /// Get the new memory size. + QString newMemSize(); + /// Get current instruction + QString instruction(); /// Get all previous steps. QStringList levels(); /// Get the current processed machine state. @@ -129,6 +134,13 @@ private: MachineState m_state; bytes m_code; bytes m_data; + QStringList fillList(QStringList& _list, QString const& _emptyValue); + QVariantList fillList(QVariantList _list, QVariant const& _emptyValue); + QVariantList qVariantDump(std::vector> const& _dump); + /// Nicely renders the given bytes to a string, store the content in an array. + /// @a _bytes: bytes array to be rendered as string. @a _width of a bytes line. + std::vector> memDumpToList(bytes const& _bytes, unsigned _width); + }; } diff --git a/mix/Extension.h b/mix/Extension.h index bbd2d206b..98daf2918 100644 --- a/mix/Extension.h +++ b/mix/Extension.h @@ -33,8 +33,8 @@ class AppContext; enum ExtensionDisplayBehavior { - Tab, - RightTab, + HeaderView, + RightView, ModalDialog }; diff --git a/mix/StateListView.cpp b/mix/StateListView.cpp index 79364fdfb..835c332aa 100644 --- a/mix/StateListView.cpp +++ b/mix/StateListView.cpp @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + 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 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. + 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 . + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . */ /** @file StateListView.cpp * @author Arkadiy Paronyan arkadiy@ethdev.com @@ -29,7 +29,7 @@ using namespace dev::mix; -StateListView::StateListView(AppContext* _context): Extension(_context, ExtensionDisplayBehavior::RightTab) +StateListView::StateListView(AppContext* _context): Extension(_context, ExtensionDisplayBehavior::RightView) { } diff --git a/mix/StatusPane.cpp b/mix/StatusPane.cpp new file mode 100644 index 000000000..f74b8f22b --- /dev/null +++ b/mix/StatusPane.cpp @@ -0,0 +1,66 @@ +/* + 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 . +*/ +/** @file ConstantCompilationControl.cpp + * @author Yann yann@ethdev.com + * @date 2014 + * Ethereum IDE client. + */ + +#include +#include +#include +#include +#include +#include +#include +#include "StatusPane.h" +#include "QContractDefinition.h" +#include "AppContext.h" +#include "CodeModel.h" + +using namespace dev::mix; + +StatusPane::StatusPane(AppContext* _context): Extension(_context, ExtensionDisplayBehavior::HeaderView) +{ + connect(_context->codeModel(), &CodeModel::compilationComplete, this, &StatusPane::update); + _context->appEngine()->rootContext()->setContextProperty("statusPane", this); +} + +QString StatusPane::contentUrl() const +{ + return QStringLiteral("qrc:/qml/StatusPane.qml"); +} + +QString StatusPane::title() const +{ + return QApplication::tr("compiler"); +} + +void StatusPane::start() const +{ +} + +CompilationResult* StatusPane::result() const +{ + return m_ctx->codeModel()->code(); +} + +void StatusPane::update() +{ + QObject* ctrl = m_view->findChild("statusPane", Qt::FindChildrenRecursively); + QMetaObject::invokeMethod(ctrl, "updateStatus"); +} diff --git a/mix/ConstantCompilationControl.h b/mix/StatusPane.h similarity index 83% rename from mix/ConstantCompilationControl.h rename to mix/StatusPane.h index 227ad6080..ee65252b5 100644 --- a/mix/ConstantCompilationControl.h +++ b/mix/StatusPane.h @@ -20,6 +20,7 @@ #pragma once #include "Extension.h" +#include "CodeModel.h" namespace dev { @@ -29,23 +30,21 @@ namespace mix /** * @brief Extension which display assembly code of the contract being edited. */ -class ConstantCompilationControl: public Extension +class StatusPane: public Extension { Q_OBJECT + Q_PROPERTY(CompilationResult* result READ result CONSTANT) public: - ConstantCompilationControl(AppContext* _appContext); - ~ConstantCompilationControl() {} + StatusPane(AppContext* _appContext); + ~StatusPane() {} void start() const override; QString title() const override; QString contentUrl() const override; - -private: - void resetOutPut(); + CompilationResult* result() const; public slots: void update(); - void displayError(QString const& _error); }; } diff --git a/mix/qml.qrc b/mix/qml.qrc index 28b82865f..344fcaa22 100644 --- a/mix/qml.qrc +++ b/mix/qml.qrc @@ -10,6 +10,27 @@ qml/ProjectList.qml qml/StateDialog.qml qml/StateList.qml + qml/img/jumpintoback.png + qml/img/jumpintoforward.png + qml/img/jumpoutback.png + qml/img/jumpoutforward.png + qml/img/jumpoverback.png + qml/img/jumpoverforward.png + qml/StepActionImage.qml + qml/img/jumpintobackdisabled.png + qml/img/jumpintoforwarddisabled.png + qml/img/jumpoutbackdisabled.png + qml/img/jumpoutforwarddisabled.png + qml/img/jumpoverbackdisabled.png + qml/DebugBasicInfo.qml + qml/js/ErrorLocationFormater.js + qml/img/closedtriangleindicator.png + qml/img/opentriangleindicator.png + qml/img/bugiconactive.png + qml/img/bugiconinactive.png + qml/DebugInfoList.qml + qml/ItemDelegateDataDump.qml + qml/StatusPane.qml qml/TabStyle.qml qml/TransactionDialog.qml qml/js/Debugger.js diff --git a/mix/qml/DebugBasicInfo.qml b/mix/qml/DebugBasicInfo.qml new file mode 100644 index 000000000..3e28aa4c1 --- /dev/null +++ b/mix/qml/DebugBasicInfo.qml @@ -0,0 +1,35 @@ +import QtQuick 2.2 +import QtQuick.Controls 1.1 +import QtQuick.Layouts 1.0 +import QtQuick.Controls.Styles 1.1 + +RowLayout { + property string titleStr + width: parent.width + height: parent.height / 4 + + function update(_value) + { + currentStepValue.text = _value; + } + + Rectangle { + width: parent.width / 2 + height: parent.height + color: "#e5e5e5" + Text + { + id: title + font.pixelSize: 12 + anchors.centerIn: parent + color: "#a2a2a2" + font.family: "Sans Serif" + text: titleStr + } + } + Text + { + font.pixelSize: 13 + id: currentStepValue + } +} diff --git a/mix/qml/DebugInfoList.qml b/mix/qml/DebugInfoList.qml new file mode 100644 index 000000000..6f65cc30d --- /dev/null +++ b/mix/qml/DebugInfoList.qml @@ -0,0 +1,83 @@ +import QtQuick 2.2 +import QtQuick.Controls 1.1 +import QtQuick.Layouts 1.0 +import QtQuick.Controls.Styles 1.1 + +ColumnLayout { + property string title + property variant listModel; + property bool collapsible; + property Component itemDelegate + spacing: 0 + RowLayout { + height: 25 + id: header + Image { + source: "qrc:/qml/img/opentriangleindicator.png" + width: 15 + sourceSize.width: 15 + id: storageImgArrow + visible: collapsible + } + + Text { + anchors.left: storageImgArrow.right + color: "#8b8b8b" + text: title + id: storageListTitle + } + + MouseArea + { + enabled: collapsible + anchors.fill: parent + onClicked: { + if (storageContainer.state == "collapsed") + storageContainer.state = ""; + else + storageContainer.state = "collapsed"; + } + } + } + + RowLayout + { + height: parent.height - header.height + clip: true + Rectangle + { + height: parent.height + border.width: 3 + border.color: "#deddd9" + Layout.fillWidth: true + states: [ + State { + name: "collapsed" + PropertyChanges { + target: storageContainer.parent + height: 0 + visible: false + } + PropertyChanges { + target: storageImgArrow + source: "qrc:/qml/img/closedtriangleindicator.png" + } + } + ] + id: storageContainer + width: parent.width + ListView { + clip: true; + anchors.top: parent.top + anchors.left: parent.left + anchors.topMargin: 3 + anchors.leftMargin: 3 + width: parent.width - 3 + height: parent.height - 6 + id: storageList + model: listModel + delegate: itemDelegate + } + } + } +} diff --git a/mix/qml/Debugger.qml b/mix/qml/Debugger.qml index 056126e16..ac449065b 100644 --- a/mix/qml/Debugger.qml +++ b/mix/qml/Debugger.qml @@ -4,266 +4,505 @@ import QtQuick.Controls 1.1 import QtQuick.Dialogs 1.1 import QtQuick.Layouts 1.1 import "js/Debugger.js" as Debugger +import "js/ErrorLocationFormater.js" as ErrorLocationFormater Rectangle { + id: debugPanel + objectName: "debugPanel" anchors.fill: parent; - color: "lightgrey" - Component.onCompleted: Debugger.init(); - Rectangle { - color: "transparent" - id: headerInfo - anchors.horizontalCenter: parent.horizontalCenter - width: parent.width - height: 60 - anchors.top: parent.top - Column { - width: parent.width - height: parent.height - Rectangle { - color: "transparent" - width: parent.width - height: 30 - Label { - anchors.centerIn: parent - font.family: "Verdana" - font.pointSize: 9 - font.italic: true - id: headerInfoLabel - } - } - Rectangle { - color: "transparent" - width: parent.width - anchors.horizontalCenter: parent.horizontalCenter - height: 30 - ListView { - orientation: ListView.Horizontal - anchors.centerIn: parent; - width: parent.width - id: headerReturnList - delegate: renderDelegateReturnValues - } - Component { - id: renderDelegateReturnValues - Item { - id: wrapperItem - width: 80 - Text { - anchors.centerIn: parent - text: variable.declaration.name + " = " + variable.value - font.pointSize: 9 - } - } - } - } - } - } - - Keys.onPressed: { + color: "#ededed" + clip: true + Keys.onPressed: + { if (event.key === Qt.Key_F10) Debugger.moveSelection(1); else if (event.key === Qt.Key_F9) Debugger.moveSelection(-1); } - Rectangle { - color: "transparent" - id: stateListContainer - focus: true - anchors.topMargin: 10 - anchors.top: headerInfo.bottom - anchors.left: parent.left - height: parent.height - 70 - width: parent.width * 0.5 + function update() + { + if (statusPane.result.successful) + { + Debugger.init(); + debugScrollArea.visible = true; + compilationErrorArea.visible = false; + machineStates.visible = true; + } + else + { + debugScrollArea.visible = false; + compilationErrorArea.visible = true; + machineStates.visible = false; + var errorInfo = ErrorLocationFormater.extractErrorInfo(statusPane.result.compilerMessage, false); + errorLocation.text = errorInfo.errorLocation; + errorDetail.text = errorInfo.errorDetail; + errorLine.text = errorInfo.errorLine; + } + } + + Connections { + target: codeModel + onCompilationComplete: update() + } - ListView { + Rectangle + { + visible: false; + id: compilationErrorArea + width: parent.width - 20 + height: 500 + color: "#ededed" + anchors.left: parent.left + anchors.top: parent.top + anchors.margins: 10 + ColumnLayout + { + width: parent.width anchors.top: parent.top - height: parent.height * 0.60 - width: 200 - anchors.horizontalCenter: parent.horizontalCenter - id: statesList - model: humanReadableExecutionCode - delegate: renderDelegate - highlight: highlightBar - highlightFollowsCurrentItem: true - } + spacing: 25 + RowLayout + { + height: 100 + ColumnLayout + { + Text { + color: "red" + id: errorLocation + } + Text { + color: "#4a4a4a" + id: errorDetail + } + } + } - Component { - id: highlightBar - Rectangle { - height: statesList.currentItem.height - width: statesList.currentItem.width - border.color: "orange" - border.width: 1 - Behavior on y { SpringAnimation { spring: 2; damping: 0.1 } } + Rectangle + { + width: parent.width - 6 + height: 2 + color: "#d0d0d0" } - } - Component { - id: renderDelegate - Item { - id: wrapperItem - height: 20 - width: parent.width - Text { - anchors.centerIn: parent - text: line - font.pointSize: 9 + RowLayout + { + Text + { + color: "#4a4a4a" + id: errorLine } } } + } - Rectangle { - id: callStackPanel - anchors.top: statesList.bottom - height: parent.height * 0.35 - width: parent.width + + Flickable { + property int firstColumnWidth: 170 + property int secondColumnWidth: 250 + id: debugScrollArea + flickableDirection: Flickable.VerticalFlick + anchors.fill: parent + contentHeight: machineStates.height + 300 + contentWidth: machineStates.width + + GridLayout + { + property int sideMargin: 10 + id: machineStates + anchors.top: parent.top anchors.topMargin: 15 - color: "transparent" - Label { - id: callStackLabel - anchors.bottomMargin: 10 - horizontalAlignment: "AlignHCenter" - font.family: "Verdana" - font.pointSize: 8 - font.letterSpacing: 2 - width: parent.width - height: 15 - text: qsTr("callstack") - } + anchors.left: parent.left; + anchors.leftMargin: machineStates.sideMargin + anchors.right: parent.right; + anchors.rightMargin: machineStates.sideMargin + flow: GridLayout.TopToBottom + rowSpacing: 15 + RowLayout { + // step button + slider + spacing: machineStates.sideMargin + height: 27 + width: debugPanel.width + Rectangle + { + height: parent.height + color: "transparent" + width: debugScrollArea.firstColumnWidth + RowLayout { + anchors.horizontalCenter: parent.horizontalCenter + id: jumpButtons + spacing: 3 + StepActionImage + { + id: jumpOutBackAction; + enabledStateImg: "qrc:/qml/img/jumpoutback.png" + disableStateImg: "qrc:/qml/img/jumpoutbackdisabled.png" + onClicked: Debugger.stepOutBack() + width: 25 + height: 27 + } - ListView { - height: parent.height - 15 - width: 200 - anchors.top: callStackLabel.bottom - anchors.horizontalCenter: parent.horizontalCenter - id: levelList - delegate: Component { - Item { - Text { - font.family: "Verdana" - font.pointSize: 8 - text: modelData + StepActionImage + { + id: jumpIntoBackAction + enabledStateImg: "qrc:/qml/img/jumpintoback.png" + disableStateImg: "qrc:/qml/img/jumpintobackdisabled.png" + onClicked: Debugger.stepIntoBack() + width: 25 + height: 27 + } + + StepActionImage + { + id: jumpOverBackAction + enabledStateImg: "qrc:/qml/img/jumpoverback.png" + disableStateImg: "qrc:/qml/img/jumpoverbackdisabled.png" + onClicked: Debugger.stepOverBack() + width: 25 + height: 27 + } + + StepActionImage + { + id: jumpOverForwardAction + enabledStateImg: "qrc:/qml/img/jumpoverforward.png" + disableStateImg: "qrc:/qml/img/jumpoverforwarddisabled.png" + onClicked: Debugger.stepOverForward() + width: 25 + height: 27 + } + + StepActionImage + { + id: jumpIntoForwardAction + enabledStateImg: "qrc:/qml/img/jumpintoforward.png" + disableStateImg: "qrc:/qml/img/jumpintoforwarddisabled.png" + onClicked: Debugger.stepIntoForward() + width: 25 + height: 27 + } + + StepActionImage + { + id: jumpOutForwardAction + enabledStateImg: "qrc:/qml/img/jumpoutforward.png" + disableStateImg: "qrc:/qml/img/jumpoutforwarddisabled.png" + onClicked: Debugger.stepOutForward() + width: 25 + height: 27 + } + } + } + Rectangle { + color: "transparent" + width: debugScrollArea.secondColumnWidth + height: parent.height + Slider { + id: statesSlider + anchors.fill: parent + tickmarksEnabled: true + stepSize: 1.0 + onValueChanged: Debugger.jumpTo(value); + style: SliderStyle { + groove: Rectangle { + implicitHeight: 3 + color: "#7da4cd" + radius: 8 + } + handle: Rectangle { + anchors.centerIn: parent + color: control.pressed ? "white" : "lightgray" + border.color: "gray" + border.width: 2 + implicitWidth: 10 + implicitHeight: 10 + radius: 12 + } } } } } - } - } - Rectangle { - color: "transparent" - anchors.topMargin: 5 - anchors.bottomMargin: 10 - anchors.rightMargin: 10 - height: parent.height - 30 - width: parent.width * 0.5 - anchors.right: parent.right - anchors.top: headerInfo.bottom - anchors.bottom: parent.bottom + RowLayout { + // Assembly code + width: debugPanel.width + height: 405 + spacing: machineStates.sideMargin - Rectangle { - id: debugStack - anchors.top: parent.top - width: parent.width - height: parent.height * 0.25 - color: "transparent" - Label { - horizontalAlignment: "AlignHCenter" - font.family: "Verdana" - font.pointSize: 8 - width: parent.width - height: 15 - anchors.top : parent.top - text: qsTr("debug stack") - } - TextArea { - anchors.bottom: parent.bottom - width: parent.width - font.family: "Verdana" - font.pointSize: 8 - height: parent.height - 15 - id: debugStackTxt - readOnly: true; + Rectangle + { + width: debugScrollArea.firstColumnWidth + height: parent.height + border.width: 3 + border.color: "#deddd9" + color: "white" + anchors.top: parent.top + ListView { + anchors.fill: parent + anchors.leftMargin: 3 + anchors.rightMargin: 3 + anchors.topMargin: 3 + anchors.bottomMargin: 3 + clip: true + id: statesList + delegate: renderDelegate + highlight: highlightBar + highlightFollowsCurrentItem: true + } + + Component { + id: highlightBar + Rectangle { + radius: 4 + height: statesList.currentItem.height + width: statesList.currentItem.width; + color: "#4A90E2" + Behavior on y { SpringAnimation { spring: 2; damping: 0.1 } } + } + } + + Component { + id: renderDelegate + RowLayout { + id: wrapperItem + height: 20 + width: parent.width + spacing: 5 + Text { + anchors.left: parent.left + anchors.leftMargin: 10 + width: 15 + color: "#b2b3ae" + text: line.split(' ')[0] + font.pointSize: 9 + id: id + wrapMode: Text.NoWrap + } + Text { + wrapMode: Text.NoWrap + color: parent.ListView.isCurrentItem ? "white" : "black" + text: line.replace(line.split(' ')[0], '') + anchors.left: id.right + font.pointSize: 9 + } + } + } + } + + ColumnLayout { + width: debugScrollArea.secondColumnWidth + height: parent.height + Rectangle { + // Info + width: parent.width + id: basicInfoColumn + height: 125 + color: "transparent" + ColumnLayout { + spacing: 0 + width: parent.width + height: parent.height + DebugBasicInfo { + id: currentStep + titleStr: qsTr("Current step") + } + DebugBasicInfo { + id: mem + titleStr: qsTr("Adding memory") + } + DebugBasicInfo { + id: stepCost + titleStr: qsTr("Step cost") + } + DebugBasicInfo { + id: gasSpent + titleStr: qsTr("Total gas spent") + } + } + } + + Rectangle { + // Stack + height: 275 + width: parent.width + color: "transparent" + + DebugInfoList + { + id: stack + width: parent.width + height: parent.height + collapsible: false + title : qsTr("Stack") + itemDelegate: Item { + id: renderedItem + height: 27 + width: parent.width + RowLayout + { + anchors.fill: parent + Rectangle + { + id: indexColumn + color: "#f7f7f7" + Layout.fillWidth: true + Layout.minimumWidth: 30 + Layout.preferredWidth: 30 + Layout.maximumWidth: 30 + Layout.minimumHeight: parent.height + Text { + anchors.centerIn: parent + anchors.leftMargin: 5 + color: "#8b8b8b" + text: model.index; + font.pointSize: 9 + } + } + + Rectangle + { + anchors.left: indexColumn.right + Layout.fillWidth: true + Layout.minimumWidth: 15 + Layout.preferredWidth: 15 + Layout.maximumWidth: 60 + Layout.minimumHeight: parent.height + Text { + anchors.left: parent.left + anchors.leftMargin: 5 + anchors.verticalCenter: parent.verticalCenter + color: "#8b8b8b" + text: modelData + font.pointSize: 9 + } + } + } + + Rectangle { + id: separator + width: parent.width; + height: 1; + color: "#cccccc" + anchors.bottom: parent.bottom + } + } + } + } + } } - } - Rectangle { - id: debugMemory - anchors.top: debugStack.bottom - width: parent.width - height: parent.height * 0.25 - color: "transparent" - Label { - horizontalAlignment: "AlignHCenter" - font.family: "Verdana" - font.pointSize: 8 - width: parent.width - height: 15 - anchors.top : parent.top - text: qsTr("debug memory") + Rectangle { + width: debugPanel.width - 2 * machineStates.sideMargin + height: 2; + color: "#e3e3e3" + radius: 3 } - TextArea { - anchors.bottom: parent.bottom - width: parent.width - font.family: "Verdana" - font.pointSize: 8 - height: parent.height - 15 - id: debugMemoryTxt - readOnly: true; + + DebugInfoList + { + id: storage + width: debugPanel.width - 2 * machineStates.sideMargin + height: 223 + collapsible: true + title : qsTr("Storage") + itemDelegate: + Item { + height: 27 + width: parent.width; + RowLayout + { + id: row + width: parent.width + height: 26 + Rectangle + { + color: "#f7f7f7" + Layout.fillWidth: true + Layout.minimumWidth: parent.width / 2 + Layout.preferredWidth: parent.width / 2 + Layout.maximumWidth: parent.width / 2 + Layout.minimumHeight: parent.height + Layout.maximumHeight: parent.height + Text { + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + anchors.leftMargin: 5 + color: "#8b8b8b" + text: modelData.split(' ')[0].substring(0, 10); + font.pointSize: 9 + } + } + Rectangle + { + color: "transparent" + Layout.fillWidth: true + Layout.minimumWidth: parent.width / 2 + Layout.preferredWidth: parent.width / 2 + Layout.maximumWidth: parent.width / 2 + Layout.minimumHeight: parent.height + Layout.maximumHeight: parent.height + Text { + anchors.leftMargin: 5 + width: parent.width - 5 + wrapMode: Text.Wrap + anchors.left: parent.left + anchors.verticalCenter: parent.verticalCenter + color: "#8b8b8b" + text: modelData.split(' ')[1].substring(0, 10); + font.pointSize: 9 + } + } + } + + Rectangle { + anchors.top: row.bottom + width: parent.width; + height: 1; + color: "#cccccc" + anchors.bottom: parent.bottom + } + } } - } - Rectangle { - id: debugStorage - anchors.top: debugMemory.bottom - width: parent.width - height: parent.height * 0.25 - color: "transparent" - Label { - horizontalAlignment: "AlignHCenter" - font.family: "Verdana" - font.pointSize: 8 - width: parent.width - height: 15 - anchors.top : parent.top - text: qsTr("debug storage") + Rectangle { + width: debugPanel.width - 2 * machineStates.sideMargin + height: 2; + color: "#e3e3e3" + radius: 3 } - TextArea { - anchors.bottom: parent.bottom - width: parent.width - font.family: "Verdana" - font.pointSize: 8 - height: parent.height - 15 - id: debugStorageTxt - readOnly: true; + + DebugInfoList { + id: memoryDump + width: debugPanel.width - 2 * machineStates.sideMargin + height: 223 + collapsible: true + title: qsTr("Memory Dump") + itemDelegate: + Item { + height: 29 + width: parent.width - 3; + ItemDelegateDataDump {} + } } - } - Rectangle { - id: debugCallData - anchors.top: debugStorage.bottom - width: parent.width - height: parent.height * 0.25 - color: "transparent" - Label { - horizontalAlignment: "AlignHCenter" - font.family: "Verdana" - font.pointSize: 8 - width: parent.width - height: 15 - anchors.top : parent.top - text: qsTr("debug calldata") + Rectangle { + width: debugPanel.width - 2 * machineStates.sideMargin + height: 2; + color: "#e3e3e3" + radius: 3 } - TextArea { - anchors.bottom: parent.bottom - width: parent.width - height: parent.height - 15 - font.family: "Verdana" - font.pointSize: 8 - font.letterSpacing: 2 - id: debugCallDataTxt - readOnly: true; + + DebugInfoList { + id: callDataDump + width: debugPanel.width - 2 * machineStates.sideMargin + height: 223 + collapsible: true + title: qsTr("Call data") + itemDelegate: + Item { + height: 29 + width: parent.width - 3; + ItemDelegateDataDump {} + } } } } diff --git a/mix/qml/ItemDelegateDataDump.qml b/mix/qml/ItemDelegateDataDump.qml new file mode 100644 index 000000000..d8513ac20 --- /dev/null +++ b/mix/qml/ItemDelegateDataDump.qml @@ -0,0 +1,71 @@ +import QtQuick 2.2 +import QtQuick.Controls 1.1 +import QtQuick.Layouts 1.0 +import QtQuick.Controls.Styles 1.1 + +Rectangle { + anchors.fill: parent + RowLayout + { + id: row; + anchors.fill: parent + spacing: 2 + Rectangle + { + id: firstCol; + color: "#f7f7f7" + Layout.fillWidth: true + Layout.minimumWidth: 35 + Layout.preferredWidth: 35 + Layout.maximumWidth: 35 + Layout.minimumHeight: parent.height + Text { + anchors.centerIn: parent + anchors.leftMargin: 5 + color: "#8b8b8b" + text: modelData[0] + font.pointSize: 9; + } + } + + Rectangle + { + anchors.left: firstCol.right + Layout.fillWidth: true + Layout.minimumWidth: 90 + Layout.preferredWidth: 90 + Layout.maximumWidth: 90 + Layout.minimumHeight: parent.height + Text { + anchors.left: parent.left + anchors.leftMargin: 7 + anchors.verticalCenter: parent.verticalCenter + color: "#8b8b8b" + text: modelData[1] + font.pointSize: 9 + } + } + + Rectangle + { + Layout.fillWidth: true + Layout.minimumWidth: 50 + Layout.minimumHeight: parent.height + Text { + anchors.left: parent.left + anchors.verticalCenter: parent.verticalCenter + color: "#ededed" + font.bold: true + text: modelData[2] + font.pointSize: 10 + } + } + } + + Rectangle { + width: parent.width; + height: 1; + color: "#cccccc" + anchors.bottom: parent.bottom + } +} diff --git a/mix/qml/MainContent.qml b/mix/qml/MainContent.qml index 5376be49d..2b0b50ce5 100644 --- a/mix/qml/MainContent.qml +++ b/mix/qml/MainContent.qml @@ -5,6 +5,7 @@ import QtQuick.Controls.Styles 1.1 import CodeEditorExtensionManager 1.0 Rectangle { + objectName: "mainContent" signal keyPressed(variant event) focus: true @@ -14,59 +15,152 @@ Rectangle { root.keyPressed(event.key); } anchors.fill: parent - height: parent.height - width: parent.width; - id:root - SplitView { - orientation: Qt.Horizontal - anchors.fill: parent - - ProjectList { - width: parent.width * 0.2 - height: parent.height - Layout.minimumWidth: 200 + id: root + + function toggleRightView() + { + if (!rightView.visible) + rightView.show(); + else + rightView.hide(); + } + + function ensureRightView() + { + if (!rightView.visible) + rightView.show(); + } + + function hideRightView() + { + if (rightView.visible) + rightView.hide(); + } + + CodeEditorExtensionManager { + headerView: headerPaneTabs; + rightView: rightPaneTabs; + } + + GridLayout + { + anchors.fill: parent + rows: 2 + flow: GridLayout.TopToBottom + columnSpacing: 0 + rowSpacing: 0 + Rectangle { + width: parent.width + height: 50 + Layout.row: 0 + Layout.fillWidth: true + Layout.preferredHeight: 50 + id: headerView + Rectangle + { + gradient: Gradient { + GradientStop { position: 0.0; color: "#f1f1f1" } + GradientStop { position: 1.0; color: "#d9d7da" } + } + id: headerPaneContainer + anchors.fill: parent + TabView { + id: headerPaneTabs + tabsVisible: false + antialiasing: true + anchors.fill: parent + style: TabViewStyle { + frameOverlap: 1 + tab: Rectangle {} + frame: Rectangle { color: "transparent" } + } + } + } } - SplitView { - //anchors.fill: parent - width: parent.width * 0.6 - orientation: Qt.Vertical - CodeEditorView { - height: parent.height * 0.7 - anchors.top: parent.top - width: parent.width + SplitView { + resizing: false + Layout.row: 1 + orientation: Qt.Horizontal; + Layout.fillWidth: true + Layout.preferredHeight: root.height - headerView.height; + + ProjectList { + id: projectList + width: 200 + height: parent.height + Layout.minimumWidth: 200 + } + + Rectangle { + id: contentView + width: parent.width - projectList.width + height: parent.height + CodeEditorView { + height: parent.height + anchors.top: parent.top + width: parent.width + } } - Rectangle { - anchors.bottom: parent.bottom - id: contextualView - width: parent.width - Layout.minimumHeight: 20 - height: parent.height * 0.3 - TabView { - id: contextualTabs - antialiasing: true - anchors.fill: parent - style: TabStyle {} - } - } - } - Rectangle { - anchors.right: parent.right - id: rightPaneView - width: parent.width * 0.2 - height: parent.height - Layout.minimumWidth: 20 - TabView { - id: rightPaneTabs - antialiasing: true - anchors.fill: parent - //style: TabStyle {} - } - } - CodeEditorExtensionManager { - tabView: contextualTabs - rightTabView: rightPaneTabs - } - } + Rectangle { + visible: false; + id: rightView; + + Keys.onEscapePressed: + { + hide(); + } + + function show() { + visible = true; + contentView.width = parent.width - projectList.width - rightView.width; + } + + function hide() { + visible = false; + contentView.width = parent.width - projectList.width; + } + + height: parent.height; + width: 450 + Layout.minimumWidth: 450 + Rectangle { + anchors.fill: parent; + id: rightPaneView + TabView { + id: rightPaneTabs + tabsVisible: true + antialiasing: true + anchors.fill: parent + style: TabViewStyle { + frameOverlap: 1 + tabBar: + Rectangle { + color: "#ededed" + id: background + } + tab: Rectangle { + color: "#ededed" + implicitWidth: 80 + implicitHeight: 20 + radius: 2 + Text { + anchors.centerIn: parent + text: styleData.title + color: styleData.selected ? "#7da4cd" : "#202020" + } + } + frame: Rectangle { + } + } + } + } + } + } + } } + + + + diff --git a/mix/qml/StateList.qml b/mix/qml/StateList.qml index 12f0318d1..519e533d5 100644 --- a/mix/qml/StateList.qml +++ b/mix/qml/StateList.qml @@ -6,7 +6,7 @@ import QtQuick.Layouts 1.1 import org.ethereum.qml.ProjectModel 1.0 Rectangle { - color: "transparent" + color: "#ededed" id: stateListContainer focus: true anchors.topMargin: 10 @@ -123,7 +123,10 @@ Rectangle { ToolButton { text: qsTr("Run"); Layout.fillHeight: true - onClicked: stateListModel.runState(index); + onClicked: + { + stateListModel.runState(index) + } } } } diff --git a/mix/qml/StatusPane.qml b/mix/qml/StatusPane.qml new file mode 100644 index 000000000..af4f6949e --- /dev/null +++ b/mix/qml/StatusPane.qml @@ -0,0 +1,116 @@ +import QtQuick 2.2 +import QtQuick.Controls 1.1 +import QtQuick.Layouts 1.1 +import "js/ErrorLocationFormater.js" as ErrorLocationFormater + +Rectangle { + id: statusHeader + objectName: "statusPane" + + function updateStatus() + { + if (statusPane.result.successful) + { + status.state = ""; + status.text = qsTr("Compile without errors."); + logslink.visible = false; + } + else + { + status.state = "error"; + var errorInfo = ErrorLocationFormater.extractErrorInfo(statusPane.result.compilerMessage, true); + status.text = errorInfo.errorLocation + " " + errorInfo.errorDetail; + logslink.visible = true; + } + debugRunActionIcon.enabled = statusPane.result.successful; + } + + color: "transparent" + anchors.fill: parent + Rectangle { + id: statusContainer + anchors.horizontalCenter: parent.horizontalCenter + anchors.verticalCenter: parent.verticalCenter + radius: 3 + width: 500 + height: 30 + color: "#fcfbfc" + RowLayout { + anchors.horizontalCenter: parent.horizontalCenter + anchors.verticalCenter: parent.verticalCenter + spacing: 5 + + Text { + font.pointSize: 10 + height: 9 + font.family: "sans serif" + objectName: "status" + id: status + states:[ + State { + name: "error" + PropertyChanges { + target: status + color: "red" + } + PropertyChanges { + target: statusContainer + color: "#fffcd5" + } + } + ] + } + + Text { + visible: false + font.pointSize: 9 + height: 9 + text: qsTr("See log.") + font.family: "Monospace" + objectName: "status" + id: logslink + color: "#8c8a74" + MouseArea { + anchors.fill: parent + onClicked: { + mainContent.ensureRightView(); + } + } + } + } + } + + Rectangle + { + color: "transparent" + width: 100 + height: parent.height + anchors.top: statusHeader.top + anchors.right: statusHeader.right + RowLayout + { + anchors.fill: parent + Rectangle { + color: "transparent" + anchors.fill: parent + Button + { + anchors.right: parent.right + anchors.rightMargin: 7 + anchors.verticalCenter: parent.verticalCenter + id: debugImg + iconSource: "qrc:/qml/img/bugiconinactive.png" + action: debugRunActionIcon + } + Action { + id: debugRunActionIcon + onTriggered: { + mainContent.ensureRightView(); + clientModel.debugDeployment(); + } + enabled: false + } + } + } + } +} diff --git a/mix/qml/StepActionImage.qml b/mix/qml/StepActionImage.qml new file mode 100644 index 000000000..fd6a46521 --- /dev/null +++ b/mix/qml/StepActionImage.qml @@ -0,0 +1,39 @@ +import QtQuick 2.2 +import QtQuick.Controls 1.1 +import QtQuick.Layouts 1.0 +import QtQuick.Controls.Styles 1.1 + + +Rectangle { + id: buttonActionContainer + property string disableStateImg + property string enabledStateImg + signal clicked + + function enabled(state) + { + buttonAction.enabled = state; + if (state) + debugImg.iconSource = enabledStateImg; + else + debugImg.iconSource = disableStateImg; + } + + color: "transparent" + Button + { + anchors.fill: parent + id: debugImg + iconSource: enabledStateImg + action: buttonAction + width: buttonActionContainer.width - 3 + height: buttonActionContainer.height + } + + Action { + id: buttonAction + onTriggered: { + buttonActionContainer.clicked(); + } + } +} diff --git a/mix/qml/img/bugiconactive.png b/mix/qml/img/bugiconactive.png new file mode 100644 index 000000000..ec72938a4 Binary files /dev/null and b/mix/qml/img/bugiconactive.png differ diff --git a/mix/qml/img/bugiconinactive.png b/mix/qml/img/bugiconinactive.png new file mode 100644 index 000000000..976175b06 Binary files /dev/null and b/mix/qml/img/bugiconinactive.png differ diff --git a/mix/qml/img/closedtriangleindicator.png b/mix/qml/img/closedtriangleindicator.png new file mode 100644 index 000000000..440adb711 Binary files /dev/null and b/mix/qml/img/closedtriangleindicator.png differ diff --git a/mix/qml/img/jumpintoback.png b/mix/qml/img/jumpintoback.png new file mode 100644 index 000000000..cf5e10007 Binary files /dev/null and b/mix/qml/img/jumpintoback.png differ diff --git a/mix/qml/img/jumpintobackdisabled.png b/mix/qml/img/jumpintobackdisabled.png new file mode 100644 index 000000000..a66b5ba41 Binary files /dev/null and b/mix/qml/img/jumpintobackdisabled.png differ diff --git a/mix/qml/img/jumpintoforward.png b/mix/qml/img/jumpintoforward.png new file mode 100644 index 000000000..b47f741eb Binary files /dev/null and b/mix/qml/img/jumpintoforward.png differ diff --git a/mix/qml/img/jumpintoforwarddisabled.png b/mix/qml/img/jumpintoforwarddisabled.png new file mode 100644 index 000000000..07364cdde Binary files /dev/null and b/mix/qml/img/jumpintoforwarddisabled.png differ diff --git a/mix/qml/img/jumpoutback.png b/mix/qml/img/jumpoutback.png new file mode 100644 index 000000000..d619ff082 Binary files /dev/null and b/mix/qml/img/jumpoutback.png differ diff --git a/mix/qml/img/jumpoutbackdisabled.png b/mix/qml/img/jumpoutbackdisabled.png new file mode 100644 index 000000000..893af6998 Binary files /dev/null and b/mix/qml/img/jumpoutbackdisabled.png differ diff --git a/mix/qml/img/jumpoutforward.png b/mix/qml/img/jumpoutforward.png new file mode 100644 index 000000000..29745f756 Binary files /dev/null and b/mix/qml/img/jumpoutforward.png differ diff --git a/mix/qml/img/jumpoutforwarddisabled.png b/mix/qml/img/jumpoutforwarddisabled.png new file mode 100644 index 000000000..c7243c859 Binary files /dev/null and b/mix/qml/img/jumpoutforwarddisabled.png differ diff --git a/mix/qml/img/jumpoverback.png b/mix/qml/img/jumpoverback.png new file mode 100644 index 000000000..371e02245 Binary files /dev/null and b/mix/qml/img/jumpoverback.png differ diff --git a/mix/qml/img/jumpoverbackdisabled.png b/mix/qml/img/jumpoverbackdisabled.png new file mode 100644 index 000000000..73fc6358e Binary files /dev/null and b/mix/qml/img/jumpoverbackdisabled.png differ diff --git a/mix/qml/img/jumpoverforward.png b/mix/qml/img/jumpoverforward.png new file mode 100644 index 000000000..690d3ab49 Binary files /dev/null and b/mix/qml/img/jumpoverforward.png differ diff --git a/mix/qml/img/opentriangleindicator.png b/mix/qml/img/opentriangleindicator.png new file mode 100644 index 000000000..591a932e0 Binary files /dev/null and b/mix/qml/img/opentriangleindicator.png differ diff --git a/mix/qml/js/Debugger.js b/mix/qml/js/Debugger.js index d516abde6..43b15f27e 100644 --- a/mix/qml/js/Debugger.js +++ b/mix/qml/js/Debugger.js @@ -4,11 +4,22 @@ //statesList => ListView var currentSelectedState = null; +var jumpStartingPoint = null; function init() { + if (debugStates === undefined) + return; + + statesSlider.maximumValue = debugStates.length - 1; + statesSlider.value = 0; + statesList.model = humanReadableExecutionCode; currentSelectedState = 0; select(currentSelectedState); - displayReturnValue(); + + jumpOutBackAction.enabled(false); + jumpIntoBackAction.enabled(false); + jumpIntoForwardAction.enabled(false); + jumpOutForwardAction.enabled(false); } function moveSelection(incr) @@ -16,25 +27,34 @@ function moveSelection(incr) if (currentSelectedState + incr >= 0) { if (currentSelectedState + incr < debugStates.length) - { select(currentSelectedState + incr); - } - else - { - endOfDebug(); - } + statesSlider.value = currentSelectedState; } } function select(stateIndex) { + var codeLine = codeStr(stateIndex); var state = debugStates[stateIndex]; - var codeStr = bytesCodeMapping.getValue(state.curPC); - highlightSelection(codeStr); + highlightSelection(codeLine); currentSelectedState = stateIndex; completeCtxInformation(state); - levelList.model = state.levels; - levelList.update(); + + if (state.instruction === "JUMP") + jumpIntoForwardAction.enabled(true); + else + jumpIntoForwardAction.enabled(false); + + if (state.instruction === "JUMPDEST") + jumpIntoBackAction.enabled(true); + else + jumpIntoBackAction.enabled(false); +} + +function codeStr(stateIndex) +{ + var state = debugStates[stateIndex]; + return bytesCodeMapping.getValue(state.curPC); } function highlightSelection(index) @@ -44,21 +64,15 @@ function highlightSelection(index) function completeCtxInformation(state) { - debugStackTxt.text = state.debugStack; - debugStorageTxt.text = state.debugStorage; - debugMemoryTxt.text = state.debugMemory; - debugCallDataTxt.text = state.debugCallData; - headerInfoLabel.text = state.headerInfo -} + currentStep.update(state.step); + mem.update(state.newMemSize + " " + qsTr("words")); + stepCost.update(state.gasCost); + gasSpent.update(debugStates[0].gas - state.gas); -function endOfDebug() -{ - var state = debugStates[debugStates.length - 1]; - debugStorageTxt.text = ""; - debugCallDataTxt.text = ""; - debugStackTxt.text = ""; - debugMemoryTxt.text = state.endOfDebug; - headerInfoLabel.text = "EXIT | GAS: " + state.gasLeft; + stack.listModel = state.debugStack; + storage.listModel = state.debugStorage; + memoryDump.listModel = state.debugMemory; + callDataDump.listModel = state.debugCallData; } function displayReturnValue() @@ -66,3 +80,86 @@ function displayReturnValue() headerReturnList.model = contractCallReturnParameters; headerReturnList.update(); } + +function stepOutBack() +{ + if (jumpStartingPoint != null) + { + select(jumpStartingPoint); + jumpStartingPoint = null; + jumpOutBackAction.enabled(false); + jumpOutForwardAction.enabled(false); + } +} + +function stepIntoBack() +{ + moveSelection(-1); +} + +function stepOverBack() +{ + var state = debugStates[currentSelectedState]; + if (state.instruction === "JUMPDEST") + { + for (var k = currentSelectedState; k > 0; k--) + { + var line = bytesCodeMapping.getValue(debugStates[k].curPC); + if (line === statesList.currentIndex - 2) + { + select(k); + break; + } + } + } + else + moveSelection(-1); +} + +function stepOverForward() +{ + var state = debugStates[currentSelectedState]; + if (state.instruction === "JUMP") + { + for (var k = currentSelectedState; k < debugStates.length; k++) + { + var line = bytesCodeMapping.getValue(debugStates[k].curPC); + if (line === statesList.currentIndex + 2) + { + select(k); + break; + } + } + } + else + moveSelection(1); +} + +function stepIntoForward() +{ + var state = debugStates[currentSelectedState]; + if (state.instruction === "JUMP") + { + jumpStartingPoint = currentSelectedState; + moveSelection(1); + jumpOutBackAction.enabled(true); + jumpOutForwardAction.enabled(true); + } +} + +function stepOutForward() +{ + if (jumpStartingPoint != null) + { + stepOutBack(); + stepOverForward(); + jumpOutBackAction.enabled(false); + jumpOutForwardAction.enabled(false); + } +} + +function jumpTo(value) +{ + currentSelectedState = value; + select(currentSelectedState); +} diff --git a/mix/qml/js/ErrorLocationFormater.js b/mix/qml/js/ErrorLocationFormater.js new file mode 100644 index 000000000..8c83e6b15 --- /dev/null +++ b/mix/qml/js/ErrorLocationFormater.js @@ -0,0 +1,27 @@ +function formatLocation(raw, shortMessage) +{ + var splitted = raw.split(':'); + if (!shortMessage) + return qsTr("Error in line ") + splitted[1] + ", " + qsTr("character ") + splitted[2]; + else + return "L" + splitted[1] + "," + "C" + splitted[2]; +} + +function extractErrorInfo(raw, shortMessage) +{ + var _return = {}; + var detail = raw.split('\n')[0]; + var reg = detail.match(/:\d+:\d+:/g); + if (reg !== null) + { + _return.errorLocation = ErrorLocationFormater.formatLocation(reg[0], shortMessage); + _return.errorDetail = detail.replace(reg[0], ""); + } + else + { + _return.errorLocation = ""; + _return.errorDetail = detail; + } + _return.errorLine = raw.split('\n')[1]; + return _return; +} diff --git a/mix/qml/main.qml b/mix/qml/main.qml index 94d061639..469a6d1f4 100644 --- a/mix/qml/main.qml +++ b/mix/qml/main.qml @@ -38,13 +38,20 @@ ApplicationWindow { MenuItem { action: debugRunAction } MenuItem { action: debugResetStateAction } } + Menu { + title: qsTr("Windows") + MenuItem { action: showHideRightPanel } + } } + Component.onCompleted: { setX(Screen.width / 2 - width / 2); setY(Screen.height / 2 - height / 2); } MainContent { + id: mainContent; + anchors.fill: parent } ModalDialog { @@ -68,8 +75,11 @@ ApplicationWindow { id: debugRunAction text: "&Run" shortcut: "F5" + onTriggered: { + mainContent.ensureRightView(); + clientModel.debugDeployment(); + } enabled: codeModel.hasContract && !clientModel.running; - onTriggered: clientModel.debugDeployment(); } Action { @@ -79,6 +89,13 @@ ApplicationWindow { onTriggered: clientModel.resetState(); } + Action { + id: showHideRightPanel + text: "Show/Hide right view" + shortcut: "F7" + onTriggered: mainContent.toggleRightView(); + } + Action { id: createProjectAction text: qsTr("&New project") diff --git a/standard.js b/standard.js index 74ebc74ad..64126a278 100644 --- a/standard.js +++ b/standard.js @@ -1,10 +1,13 @@ var compile = function(name) { return web3.eth.solidity(env.contents("../../dapp-bin/" + name + "/" + name + ".sol")); }; var create = function(code) { return web3.eth.transact({ 'code': code }); }; +var createVal = function(code, val) { return web3.eth.transact(val ? { 'code': code, 'value': val } : { 'code': code }); }; var send = function(from, val, to) { return web3.eth.transact({ 'from': from, 'value': val, 'to': to }); }; var initService = function(name, dep) { return dep.then(function(){ return compile(name).then(create); }); }; +var initServiceVal = function(name, dep, val) { return dep.then(function(){ return compile(name).then(function(c) { createVal(c, val); }); }); }; var addrConfig = compile("config").then(create); var addrNameReg = initService("namereg", addrConfig); +var addrGavsino = initServiceVal("gavmble", addrNameReg, "1000000000000000000"); var abiNameReg = [{"constant":true,"inputs":[{"name":"name","type":"string32"}],"name":"addressOf","outputs":[{"name":"addr","type":"address"}]},{"constant":false,"inputs":[],"name":"kill","outputs":[]},{"constant":true,"inputs":[{"name":"addr","type":"address"}],"name":"nameOf","outputs":[{"name":"name","type":"string32"}]},{"constant":false,"inputs":[{"name":"name","type":"string32"}],"name":"register","outputs":[]},{"constant":false,"inputs":[],"name":"unregister","outputs":[]}]; var regName = function(account, name) { return web3.contract(addrNameReg, abiNameReg).register(name).transact({'from': account, 'gas': 10000}); }; @@ -26,6 +29,7 @@ addrConfig.then(function() { regName(accounts[1], 'Gav Would'); }); regName(accounts[0], 'Gav'); + // TODO: once we have the exchange. // approve(accounts[0], exchange).then(function(){ offer(accounts[0], coin, '5000', '0', '5000000000000000000'); }); // funded.then(function(){ approve(accounts[1], exchange); }); diff --git a/test/SolidityEndToEndTest.cpp b/test/SolidityEndToEndTest.cpp index 16787c8e7..b79e9c4b7 100644 --- a/test/SolidityEndToEndTest.cpp +++ b/test/SolidityEndToEndTest.cpp @@ -28,10 +28,6 @@ #include #include -#ifdef _MSC_VER -#pragma warning(disable: 4307) //integral constant overflow for high_bits_cleaning -#endif - using namespace std; namespace dev @@ -386,7 +382,8 @@ BOOST_AUTO_TEST_CASE(high_bits_cleaning) { char const* sourceCode = "contract test {\n" " function run() returns(uint256 y) {\n" - " uint32 x = uint32(0xffffffff) + 10;\n" + " uint32 t = uint32(0xffffffff);\n" + " uint32 x = t + 10;\n" " if (x >= 0xffffffff) return 0;\n" " return x;" " }\n" @@ -394,7 +391,8 @@ BOOST_AUTO_TEST_CASE(high_bits_cleaning) compileAndRun(sourceCode); auto high_bits_cleaning_cpp = []() -> u256 { - uint32_t x = uint32_t(0xffffffff) + 10; + uint32_t t = uint32_t(0xffffffff); + uint32_t x = t + 10; if (x >= 0xffffffff) return 0; return x; @@ -426,14 +424,16 @@ BOOST_AUTO_TEST_CASE(small_unsigned_types) { char const* sourceCode = "contract test {\n" " function run() returns(uint256 y) {\n" - " uint32 x = uint32(0xffffff) * 0xffffff;\n" + " uint32 t = uint32(0xffffff);\n" + " uint32 x = t * 0xffffff;\n" " return x / 0x100;" " }\n" "}\n"; compileAndRun(sourceCode); auto small_unsigned_types_cpp = []() -> u256 { - uint32_t x = uint32_t(0xffffff) * 0xffffff; + uint32_t t = uint32_t(0xffffff); + uint32_t x = t * 0xffffff; return x / 0x100; }; testSolidityAgainstCpp("run()", small_unsigned_types_cpp); diff --git a/test/SolidityNatspecJSON.cpp b/test/SolidityNatspecJSON.cpp index 7edb97a7b..d43aebc2b 100644 --- a/test/SolidityNatspecJSON.cpp +++ b/test/SolidityNatspecJSON.cpp @@ -84,7 +84,7 @@ BOOST_AUTO_TEST_CASE(user_basic_test) char const* natspec = "{" "\"methods\":{" - " \"mul\":{ \"notice\": \"Multiplies `a` by 7\"}" + " \"mul(uint256)\":{ \"notice\": \"Multiplies `a` by 7\"}" "}}"; checkNatspec(sourceCode, natspec, true); @@ -100,7 +100,7 @@ BOOST_AUTO_TEST_CASE(dev_and_user_basic_test) char const* devNatspec = "{" "\"methods\":{" - " \"mul\":{ \n" + " \"mul(uint256)\":{ \n" " \"details\": \"Multiplies a number by 7\"\n" " }\n" " }\n" @@ -108,7 +108,7 @@ BOOST_AUTO_TEST_CASE(dev_and_user_basic_test) char const* userNatspec = "{" "\"methods\":{" - " \"mul\":{ \"notice\": \"Multiplies `a` by 7\"}" + " \"mul(uint256)\":{ \"notice\": \"Multiplies `a` by 7\"}" "}}"; checkNatspec(sourceCode, devNatspec, false); @@ -128,7 +128,7 @@ BOOST_AUTO_TEST_CASE(user_multiline_comment) char const* natspec = "{" "\"methods\":{" - " \"mul_and_add\":{ \"notice\": \"Multiplies `a` by 7 and then adds `b`\"}" + " \"mul_and_add(uint256,uint256)\":{ \"notice\": \"Multiplies `a` by 7 and then adds `b`\"}" "}}"; checkNatspec(sourceCode, natspec, true); @@ -157,9 +157,9 @@ BOOST_AUTO_TEST_CASE(user_multiple_functions) char const* natspec = "{" "\"methods\":{" - " \"mul_and_add\":{ \"notice\": \"Multiplies `a` by 7 and then adds `b`\"}," - " \"divide\":{ \"notice\": \"Divides `input` by `div`\"}," - " \"sub\":{ \"notice\": \"Subtracts 3 from `input`\"}" + " \"mul_and_add(uint256,uint256)\":{ \"notice\": \"Multiplies `a` by 7 and then adds `b`\"}," + " \"divide(uint256,uint256)\":{ \"notice\": \"Divides `input` by `div`\"}," + " \"sub(int256)\":{ \"notice\": \"Subtracts 3 from `input`\"}" "}}"; checkNatspec(sourceCode, natspec, true); @@ -205,7 +205,7 @@ BOOST_AUTO_TEST_CASE(dev_desc_after_nl) char const* natspec = "{" "\"methods\":{" - " \"mul\":{ \n" + " \"mul(uint256,uint256)\":{ \n" " \"details\": \" Multiplies a number by 7 and adds second parameter\",\n" " \"params\": {\n" " \"a\": \"Documentation for the first parameter\",\n" @@ -228,7 +228,7 @@ BOOST_AUTO_TEST_CASE(dev_multiple_params) char const* natspec = "{" "\"methods\":{" - " \"mul\":{ \n" + " \"mul(uint256,uint256)\":{ \n" " \"details\": \"Multiplies a number by 7 and adds second parameter\",\n" " \"params\": {\n" " \"a\": \"Documentation for the first parameter\",\n" @@ -252,7 +252,7 @@ BOOST_AUTO_TEST_CASE(dev_mutiline_param_description) char const* natspec = "{" "\"methods\":{" - " \"mul\":{ \n" + " \"mul(uint256,uint256)\":{ \n" " \"details\": \"Multiplies a number by 7 and adds second parameter\",\n" " \"params\": {\n" " \"a\": \"Documentation for the first parameter starts here. Since it's a really complicated parameter we need 2 lines\",\n" @@ -289,21 +289,21 @@ BOOST_AUTO_TEST_CASE(dev_multiple_functions) char const* natspec = "{" "\"methods\":{" - " \"mul\":{ \n" + " \"mul(uint256,uint256)\":{ \n" " \"details\": \"Multiplies a number by 7 and adds second parameter\",\n" " \"params\": {\n" " \"a\": \"Documentation for the first parameter\",\n" " \"second\": \"Documentation for the second parameter\"\n" " }\n" " },\n" - " \"divide\":{ \n" + " \"divide(uint256,uint256)\":{ \n" " \"details\": \"Divides 2 numbers\",\n" " \"params\": {\n" " \"input\": \"Documentation for the input parameter\",\n" " \"div\": \"Documentation for the div parameter\"\n" " }\n" " },\n" - " \"sub\":{ \n" + " \"sub(int256)\":{ \n" " \"details\": \"Subtracts 3 from `input`\",\n" " \"params\": {\n" " \"input\": \"Documentation for the input parameter\"\n" @@ -327,7 +327,7 @@ BOOST_AUTO_TEST_CASE(dev_return) char const* natspec = "{" "\"methods\":{" - " \"mul\":{ \n" + " \"mul(uint256,uint256)\":{ \n" " \"details\": \"Multiplies a number by 7 and adds second parameter\",\n" " \"params\": {\n" " \"a\": \"Documentation for the first parameter starts here. Since it's a really complicated parameter we need 2 lines\",\n" @@ -353,7 +353,7 @@ BOOST_AUTO_TEST_CASE(dev_return_desc_after_nl) char const* natspec = "{" "\"methods\":{" - " \"mul\":{ \n" + " \"mul(uint256,uint256)\":{ \n" " \"details\": \"Multiplies a number by 7 and adds second parameter\",\n" " \"params\": {\n" " \"a\": \"Documentation for the first parameter starts here. Since it's a really complicated parameter we need 2 lines\",\n" @@ -381,7 +381,7 @@ BOOST_AUTO_TEST_CASE(dev_multiline_return) char const* natspec = "{" "\"methods\":{" - " \"mul\":{ \n" + " \"mul(uint256,uint256)\":{ \n" " \"details\": \"Multiplies a number by 7 and adds second parameter\",\n" " \"params\": {\n" " \"a\": \"Documentation for the first parameter starts here. Since it's a really complicated parameter we need 2 lines\",\n" @@ -410,7 +410,7 @@ BOOST_AUTO_TEST_CASE(dev_multiline_comment) char const* natspec = "{" "\"methods\":{" - " \"mul\":{ \n" + " \"mul(uint256,uint256)\":{ \n" " \"details\": \"Multiplies a number by 7 and adds second parameter\",\n" " \"params\": {\n" " \"a\": \"Documentation for the first parameter starts here. Since it's a really complicated parameter we need 2 lines\",\n" @@ -432,7 +432,7 @@ BOOST_AUTO_TEST_CASE(dev_contract_no_doc) char const* natspec = "{" " \"methods\":{" - " \"mul\":{ \n" + " \"mul(uint256,uint256)\":{ \n" " \"details\": \"Mul function\"\n" " }\n" " }\n" @@ -454,7 +454,7 @@ BOOST_AUTO_TEST_CASE(dev_contract_doc) " \"author\": \"Lefteris\"," " \"title\": \"Just a test contract\"," " \"methods\":{" - " \"mul\":{ \n" + " \"mul(uint256,uint256)\":{ \n" " \"details\": \"Mul function\"\n" " }\n" " }\n" @@ -477,7 +477,7 @@ BOOST_AUTO_TEST_CASE(dev_author_at_function) " \"author\": \"Lefteris\"," " \"title\": \"Just a test contract\"," " \"methods\":{" - " \"mul\":{ \n" + " \"mul(uint256,uint256)\":{ \n" " \"details\": \"Mul function\",\n" " \"author\": \"John Doe\",\n" " }\n" @@ -501,7 +501,7 @@ BOOST_AUTO_TEST_CASE(dev_title_at_function_error) " \"author\": \"Lefteris\"," " \"title\": \"Just a test contract\"," " \"methods\":{" - " \"mul\":{ \n" + " \"mul(uint256,uint256)\":{ \n" " \"details\": \"Mul function\"\n" " }\n" " }\n" diff --git a/test/vm.cpp b/test/vm.cpp index 7afd9de13..f15dc048a 100644 --- a/test/vm.cpp +++ b/test/vm.cpp @@ -508,23 +508,28 @@ BOOST_AUTO_TEST_CASE(vmLogTest) dev::test::executeTests("vmLogTest", "/VMTests", dev::test::doVMTests); } -BOOST_AUTO_TEST_CASE(vmPerformanceTest) +BOOST_AUTO_TEST_CASE(vmSystemOperationsTest) +{ + dev::test::executeTests("vmSystemOperationsTest", "/VMTests", dev::test::doVMTests); +} + +BOOST_AUTO_TEST_CASE(vmInputLimitsTest1) { for (int i = 1; i < boost::unit_test::framework::master_test_suite().argc; ++i) { string arg = boost::unit_test::framework::master_test_suite().argv[i]; - if (arg == "--performance") - dev::test::executeTests("vmPerformanceTest", "/VMTests", dev::test::doVMTests); + if (arg == "--inputlimits") + dev::test::executeTests("vmInputLimitsTest1", "/VMTests", dev::test::doVMTests); } } -BOOST_AUTO_TEST_CASE(vmArithPerformanceTest) +BOOST_AUTO_TEST_CASE(vmInputLimitsTest2) { for (int i = 1; i < boost::unit_test::framework::master_test_suite().argc; ++i) { string arg = boost::unit_test::framework::master_test_suite().argv[i]; - if (arg == "--performance") - dev::test::executeTests("vmArithPerformanceTest", "/VMTests", dev::test::doVMTests); + if (arg == "--inputlimits") + dev::test::executeTests("vmInputLimitsTest2", "/VMTests", dev::test::doVMTests); } } diff --git a/test/vmSystemOperationsTestFiller.json b/test/vmSystemOperationsTestFiller.json index a5cd79030..0e160bd53 100644 --- a/test/vmSystemOperationsTestFiller.json +++ b/test/vmSystemOperationsTestFiller.json @@ -12,7 +12,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "{ (MSTORE 0 0x601080600c6000396000f200600035560f6009590060203560003557) [[ 0 ]] (CREATE 23 4 28) }", + "code" : "{ (MSTORE 0 0x601080600c6000396000f3006000355415600957005b60203560003555) [[ 0 ]] (CREATE 23 3 29) }", "storage": {} } }, @@ -40,7 +40,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "100", "nonce" : 0, - "code" : "{ (MSTORE 0 0x601080600c6000396000f200600035560f6009590060203560003557) [[ 0 ]] (CREATE 230 4 28) }", + "code" : "{ (MSTORE 0 0x601080600c6000396000f3006000355415600957005b60203560003555) [[ 0 ]] (CREATE 230 3 29) }", "storage": {} } }, @@ -68,7 +68,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "100", "nonce" : 0, - "code" : "{ (MSTORE 0 0x601080600c6000396000f200600035560f6009590060203560003557) [[ 0 ]] (CREATE 23 0xfffffffffff 28) }", + "code" : "{ (MSTORE 0 0x601080600c6000396000f3006000355415600957005b60203560003555) [[ 0 ]] (CREATE 23 0xfffffffffff 29) }", "storage": {} } }, @@ -96,7 +96,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "100", "nonce" : 0, - "code" : "{ (MSTORE 0 0x601080600c6000396000f200600035560f6009590060203560003557) [[ 0 ]] (CREATE 23 4 0xffffffff) }", + "code" : "{ (MSTORE 0 0x601080600c6000396000f3006000355415600957005b60203560003555) [[ 0 ]] (CREATE 23 3 0xffffffff) }", "storage": {} } }, @@ -129,7 +129,7 @@ }, "945304eb96065b2a98b57a48a06ae28d285a71b5" : { "balance" : "23", - "code" : "0x600035560f600a59005d60203560003557", + "code" : "0x6000355415600957005b60203560003555", "nonce" : "0", "storage" : { } @@ -340,7 +340,7 @@ }, "945304eb96065b2a98b57a48a06ae28d285a71b5" : { "balance" : "23", - "code" : "0x600035560f600a59005d60203560003557", + "code" : "0x6000355415600957005b60203560003555", "nonce" : "0", "storage" : { } @@ -376,7 +376,7 @@ }, "945304eb96065b2a98b57a48a06ae28d285a71b5" : { "balance" : "23", - "code" : "0x600035560f600a59005d60203560003557", + "code" : "0x6000355415600957005b60203560003555", "nonce" : "0", "storage" : { } @@ -412,7 +412,7 @@ }, "945304eb96065b2a98b57a48a06ae28d285a71b5" : { "balance" : "23", - "code" : "0x600035560f600a59005d60203560003557", + "code" : "0x6000355415600957005b60203560003555", "nonce" : "0", "storage" : { } @@ -448,7 +448,7 @@ }, "945304eb96065b2a98b57a48a06ae28d285a71b5" : { "balance" : "23", - "code" : "0x600035560f600a59005d60203560003557", + "code" : "0x6000355415600957005b60203560003555", "nonce" : "0", "storage" : { } @@ -485,7 +485,7 @@ }, "945304eb96065b2a98b57a48a06ae28d285a71b5" : { "balance" : "23", - "code" : "0x600035560f600a59005d60203560003557", + "code" : "0x6000355415600957005b60203560003555", "nonce" : "0", "storage" : { } @@ -521,7 +521,7 @@ }, "945304eb96065b2a98b57a48a06ae28d285a71b5" : { "balance" : "23", - "code" : "0x600035560f600a59005d60203560003557", + "code" : "0x6000355415600957005b60203560003555", "nonce" : "0", "storage" : { } @@ -675,7 +675,7 @@ }, "cd1722f3947def4cf144679da39c4c32bdc35681" : { "balance" : "23", - "code" : "0x600035560f600a59005d60203560003557", + "code" : "0x6000355415600957005b60203560003555", "nonce" : "0", "storage" : { } @@ -711,7 +711,7 @@ }, "cd1722f3947def4cf144679da39c4c32bdc35681" : { "balance" : "23", - "code" : "0x600035560f600a59005d60203560003557", + "code" : "0x6000355415600957005b60203560003555", "nonce" : "0", "storage" : { } @@ -747,7 +747,7 @@ }, "cd1722f3947def4cf144679da39c4c32bdc35681" : { "balance" : "23", - "code" : "0x600035560f600a59005d60203560003557", + "code" : "0x6000355415600957005b60203560003555", "nonce" : "0", "storage" : { } @@ -873,7 +873,7 @@ }, "945304eb96065b2a98b57a48a06ae28d285a71b5" : { "balance" : "23", - "code" : "0x600035560f600a59005d60203560003557", + "code" : "0x6000355415600957005b60203560003555", "nonce" : "0", "storage" : { } @@ -909,7 +909,7 @@ }, "945304eb96065b2a98b57a48a06ae28d285a71b5" : { "balance" : "23", - "code" : "0x600035560f600a59005d60203560003557", + "code" : "0x6000355415600957005b60203560003555", "nonce" : "0", "storage" : { } @@ -945,7 +945,7 @@ }, "945304eb96065b2a98b57a48a06ae28d285a71b5" : { "balance" : "23", - "code" : "0x600035560f600a59005d60203560003557", + "code" : "0x6000355415600957005b60203560003555", "nonce" : "0", "storage" : { } @@ -976,7 +976,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x600035560f600a59005d60203560003557", + "code" : "0x6000355415600957005b60203560003555", "storage": {} } },