From 07e04ab3bcd14c12ccad6dd3fa751dc05ca3fc40 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 22 Jun 2014 10:46:51 +0100 Subject: [PATCH] Make use of Serpent if available. --- CMakeLists.txt | 11 ++ alethzero/CMakeLists.txt | 4 +- alethzero/MainWin.cpp | 245 +++++++++++++++++-------------------- alethzero/MainWin.h | 1 + libqethereum/QEthereum.cpp | 1 + 5 files changed, 128 insertions(+), 134 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e77610824..e8212e5ff 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -163,6 +163,17 @@ else () link_directories(${CRYPTOPP_LIBRARIES}) endif() + find_path(SERPENT_ID NAMES serpent/funcs.h serpent/util.h PATHS . ..) + find_library(SERPENT_LS NAMES serpent PATHS ../serpent) + if ( SERPENT_ID AND SERPENT_LS ) + message(STATUS "Found serpent (headers in ${SERPENT_ID}, library ${SERPENT_LS})") + add_definitions(-DETH_SERPENT) + set( SERPENT_LIBRARIES ${SERPENT_LS} ) + else () + message(STATUS "Serpent not found. No serpent support.") + endif () + include_directories(${SERPENT_ID}) + find_path( LEVELDB_ID leveldb/db.h /usr/include /usr/local/include diff --git a/alethzero/CMakeLists.txt b/alethzero/CMakeLists.txt index 8ff762dda..afb73e77d 100644 --- a/alethzero/CMakeLists.txt +++ b/alethzero/CMakeLists.txt @@ -56,7 +56,7 @@ else () endif () qt5_use_modules(${EXECUTEABLE} Core Gui Widgets Network WebKit WebKitWidgets) -target_link_libraries(${EXECUTEABLE} qethereum ethereum secp256k1 ${CRYPTOPP_LIBRARIES}) +target_link_libraries(${EXECUTEABLE} qethereum ethereum secp256k1 ${SERPENT_LIBRARIES} ${CRYPTOPP_LIBRARIES}) if (APPLE) set_target_properties(${EXECUTEABLE} PROPERTIES MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/EthereumMacOSXBundleInfo.plist.in") @@ -103,7 +103,7 @@ elseif (${TARGET_PLATFORM} STREQUAL "w64") set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS) elseif (UNIX) else () - target_link_libraries(${EXECUTEABLE} boost_system) + target_link_libraries(${EXECUTEABLE} boost_system) target_link_libraries(${EXECUTEABLE} boost_filesystem) find_package(Threads REQUIRED) target_link_libraries(${EXECUTEABLE} ${CMAKE_THREAD_LIBS_INIT}) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 556eaf3bf..c8c1732f6 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -20,13 +20,6 @@ */ #include -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunused-parameter" -#pragma warning(push) -#pragma warning(disable:4100) -#include -#pragma GCC diagnostic pop -#pragma warning(pop) #include #include #include @@ -34,6 +27,10 @@ #include #include #include +#ifdef ETH_SERPENT +#include +#include +#endif #include #include #include @@ -100,64 +97,6 @@ static void initUnits(QComboBox* _b) Address c_config = Address("9ef0f0d81e040012600b0c1abdef7c48f720f88a"); -using namespace boost::process; - -string findSerpent() -{ - string ret; - vector paths = { ".", "..", "../cpp-ethereum", "../../cpp-ethereum", "/usr/local/bin", "/usr/bin/" }; - for (auto i: paths) - if (!ifstream(i + "/serpent_cli.py").fail()) - { - ret = i + "/serpent_cli.py"; - break; - } - if (ret.empty()) - cwarn << "Serpent compiler not found. Please install into the same path as this executable."; - return ret; -} - -bytes compileSerpent(string const& _code) -{ - static const string serpent = findSerpent(); - if (serpent.empty()) - return bytes(); - -#ifdef _WIN32 - vector args = vector({"python", serpent, "-b", "compile"}); - string exec = ""; -#else - vector args = vector({"serpent_cli.py", "-b", "compile"}); - string exec = serpent; -#endif - - context ctx; - ctx.environment = self::get_environment(); - ctx.stdin_behavior = capture_stream(); - ctx.stdout_behavior = capture_stream(); - try - { - child c = launch(exec, args, ctx); - postream& os = c.get_stdin(); - pistream& is = c.get_stdout(); - - os << _code << "\n"; - os.close(); - - string hex; - int i; - while ((i = is.get()) != -1 && i != '\r' && i != '\n') - hex.push_back(i); - - return fromHex(hex); - } - catch (boost::system::system_error&) - { - cwarn << "Serpent compiler failed to launch."; - return bytes(); - } -} - Main::Main(QWidget *parent) : QMainWindow(parent), ui(new Ui::Main) @@ -571,7 +510,7 @@ void Main::on_blockChainFilter_textChanged() s_delayed->start(200); } -static bool blockMatch(string const& _f, eth::BlockDetails const& _b, h256 _h) +static bool blockMatch(string const& _f, eth::BlockDetails const& _b, h256 _h, BlockChain const& _bc) { try { @@ -581,6 +520,10 @@ static bool blockMatch(string const& _f, eth::BlockDetails const& _b, h256 _h) catch (...) {} if (toHex(_h.ref()).find(_f) != string::npos) return true; + BlockInfo bi(_bc.block(_h)); + string info = toHex(bi.stateRoot.ref()) + " " + toHex(bi.coinbaseAddress.ref()) + " " + toHex(bi.transactionsRoot.ref()) + " " + toHex(bi.sha3Uncles.ref()); + if (info.find(_f) != string::npos) + return true; return false; } @@ -606,7 +549,7 @@ void Main::refreshBlockChain() for (auto h = bc.currentHash(); h != bc.genesisHash() && i; h = bc.details(h).parent, --i) { auto d = bc.details(h); - if (blockMatch(filter, d, h)) + if (blockMatch(filter, d, h, bc)) { QListWidgetItem* blockItem = new QListWidgetItem(QString("#%1 %2").arg(d.number).arg(h.abridged().c_str()), ui->blocks); auto hba = QByteArray((char const*)h.data(), h.size); @@ -731,6 +674,71 @@ void Main::refresh(bool _override) } } +string Main::renderDiff(eth::State const& fs, eth::State const& ts) const +{ + stringstream s; + + eth::StateDiff d = fs.diff(ts); + + s << "Pre: " << fs.rootHash() << "
"; + s << "Post: " << ts.rootHash() << ""; + + auto indent = " "; + for (auto const& i: d.accounts) + { + s << "
"; + + eth::AccountDiff const& ad = i.second; + s << "" << ad.lead() << " " << " " << render(i.first).toStdString() << ""; + if (!ad.exist.to()) + continue; + + if (ad.balance) + { + s << "
" << indent << "Balance " << std::dec << formatBalance(ad.balance.to()); + s << " " << std::showpos << (((eth::bigint)ad.balance.to()) - ((eth::bigint)ad.balance.from())) << std::noshowpos << ""; + } + if (ad.nonce) + { + s << "
" << indent << "Count #" << std::dec << ad.nonce.to(); + s << " " << std::showpos << (((eth::bigint)ad.nonce.to()) - ((eth::bigint)ad.nonce.from())) << std::noshowpos << ""; + } + if (ad.code) + { + s << "
" << indent << "Code " << std::hex << ad.code.to(); + if (ad.code.from().size()) + s << " (" << ad.code.from() << ")"; + } + + for (pair> const& i: ad.storage) + { + s << "
"; + if (!i.second.from()) + s << " + "; + else if (!i.second.to()) + s << "XXX"; + else + s << " * "; + s << " "; + + if (i.first > u256(1) << 246) + s << (h256)i.first; + else if (i.first > u160(1) << 150) + s << (h160)(u160)i.first; + else + s << std::hex << i.first; + + if (!i.second.from()) + s << ": " << std::hex << i.second.to(); + else if (!i.second.to()) + s << " (" << std::hex << i.second.from() << ")"; + else + s << ": " << std::hex << i.second.to() << " (" << i.second.from() << ")"; + } + } + return s.str(); +} + void Main::on_transactionQueue_currentItemChanged() { ui->pendingInfo->clear(); @@ -767,64 +775,7 @@ void Main::on_transactionQueue_currentItemChanged() eth::State fs = m_client->postState().fromPending(i); eth::State ts = m_client->postState().fromPending(i + 1); - eth::StateDiff d = fs.diff(ts); - - s << "Pre: " << fs.rootHash() << "
"; - s << "Post: " << ts.rootHash() << ""; - - auto indent = " "; - for (auto const& i: d.accounts) - { - s << "
"; - - eth::AccountDiff const& ad = i.second; - s << "" << ad.lead() << " " << " " << render(i.first).toStdString() << ""; - if (!ad.exist.to()) - continue; - - if (ad.balance) - { - s << "
" << indent << "Balance " << std::dec << formatBalance(ad.balance.to()); - s << " " << std::showpos << (((eth::bigint)ad.balance.to()) - ((eth::bigint)ad.balance.from())) << std::noshowpos << ""; - } - if (ad.nonce) - { - s << "
" << indent << "Count #" << std::dec << ad.nonce.to(); - s << " " << std::showpos << (((eth::bigint)ad.nonce.to()) - ((eth::bigint)ad.nonce.from())) << std::noshowpos << ""; - } - if (ad.code) - { - s << "
" << indent << "Code " << std::hex << ad.code.to(); - if (ad.code.from().size()) - s << " (" << ad.code.from() << ")"; - } - - for (pair> const& i: ad.storage) - { - s << "
"; - if (!i.second.from()) - s << " + "; - else if (!i.second.to()) - s << "XXX"; - else - s << " * "; - s << " "; - - if (i.first > u256(1) << 246) - s << (h256)i.first; - else if (i.first > u160(1) << 150) - s << (h160)(u160)i.first; - else - s << std::hex << i.first; - - if (!i.second.from()) - s << ": " << std::hex << i.second.to(); - else if (!i.second.to()) - s << " (" << std::hex << i.second.from() << ")"; - else - s << ": " << std::hex << i.second.to() << " (" << i.second.from() << ")"; - } - } + s << renderDiff(fs, ts); } ui->pendingInfo->setHtml(QString::fromStdString(s.str())); @@ -882,6 +833,7 @@ void Main::on_blocks_currentItemChanged() s << "   Minimum gas price: " << formatBalance(info.minGasPrice) << ""; s << "
Coinbase: " << pretty(info.coinbaseAddress).toStdString() << " " << info.coinbaseAddress; s << "
Nonce: " << info.nonce << ""; + s << "
Parent: " << info.parentHash << ""; s << "
Transactions: " << block[1].itemCount() << " @" << info.transactionsRoot << ""; s << "
Uncles: " << block[2].itemCount() << " @" << info.sha3Uncles << ""; s << "
Pre: " << BlockInfo(m_client->blockChain().block(info.parentHash)).stateRoot << ""; @@ -920,6 +872,13 @@ void Main::on_blocks_currentItemChanged() if (tx.data.size()) s << eth::memDump(tx.data, 16, true); } + s << "

"; +/* BlockInfo parentBlockInfo(); + eth::State s = m_client->state(); + s.resetTo(bi.); + s <<*/ + + // TODO: Make function: State::fromBlock (grabs block's parent's stateRoot, playback()'s transactions), then use State::fromPending(). Maybe even make a State::pendingDiff(). } @@ -1002,14 +961,36 @@ void Main::on_data_textChanged() { if (isCreation()) { + string src = ui->data->toPlainText().toStdString(); vector errors; - auto asmcode = eth::compileLLLToAsm(ui->data->toPlainText().toStdString(), false); - auto asmcodeopt = eth::compileLLLToAsm(ui->data->toPlainText().toStdString(), true); - m_data = compileLLL(ui->data->toPlainText().toStdString(), true, &errors); - for (auto const& i: errors) - cwarn << i; - - ui->code->setHtml("

Opt

" + QString::fromStdString(asmcodeopt).toHtmlEscaped() + "

Pre

" + QString::fromStdString(asmcode).toHtmlEscaped() + "

Code

" + QString::fromStdString(disassemble(m_data)).toHtmlEscaped()); + QString lll; + if (src.find_first_not_of("1234567890abcdefABCDEF") == string::npos && src.size() % 2 == 0) + { + m_data = fromHex(src); + } + else + { + try + { + m_data = eth::asBytes(compile(src)); + } + catch (string err) + { + errors.push_back("Serpent " + err); + auto asmcode = eth::compileLLLToAsm(src, false); + auto asmcodeopt = eth::compileLLLToAsm(ui->data->toPlainText().toStdString(), true); + m_data = compileLLL(ui->data->toPlainText().toStdString(), true, &errors); + lll = "

Opt

" + QString::fromStdString(asmcodeopt).toHtmlEscaped() + "

Pre

" + QString::fromStdString(asmcode).toHtmlEscaped() + "
"; + } + } + QString errs; + if (errors.size()) + { + errs = "

Errors

"; + for (auto const& i: errors) + errs.append("
" + QString::fromStdString(i).toHtmlEscaped() + "
"); + } + ui->code->setHtml(errs + lll + "

Code

" + QString::fromStdString(disassemble(m_data)).toHtmlEscaped()); ui->gas->setMinimum((qint64)state().createGas(m_data.size(), 0)); if (!ui->gas->isEnabled()) ui->gas->setValue(m_backupGas); diff --git a/alethzero/MainWin.h b/alethzero/MainWin.h index c81d62ae5..ea96d51be 100644 --- a/alethzero/MainWin.h +++ b/alethzero/MainWin.h @@ -131,6 +131,7 @@ private: void debugFinished(); QString render(eth::Address _a) const; eth::Address fromString(QString const& _a) const; + std::string renderDiff(eth::State const& fs, eth::State const& ts) const; eth::State const& state() const; diff --git a/libqethereum/QEthereum.cpp b/libqethereum/QEthereum.cpp index 835f7224d..25c627f54 100644 --- a/libqethereum/QEthereum.cpp +++ b/libqethereum/QEthereum.cpp @@ -333,6 +333,7 @@ QString QEthereum::balanceAt(QString _a) const QString QEthereum::storageAt(QString _a, QString _p) const { + eth::ClientGuard l(const_cast(m_client)); return toQJS(client()->postState().storage(toAddress(_a), toU256(_p))); }