diff --git a/README.md b/README.md index 14e37b879..6cd9c7adf 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,12 @@ ## Ethereum C++ Client. -By Gav Wood, 2014. +By Gav Wood et al, 2013, 2014, 2015. | Linux | OSX | Windows ----------|---------|-----|-------- -develop | [![Build+Status](http://build.ethdev.com/buildstatusimage?builder=Linux%20C%2B%2B%20develop%20branch)](http://build.ethdev.com/builders/Linux%20C%2B%2B%20develop%20branch/builds/-1) | [![Build+Status](http://build.ethdev.com/buildstatusimage?builder=OSX%20C%2B%2B%20develop%20branch)](http://build.ethdev.com/builders/OSX%20C%2B%2B%20develop%20branch/builds/-1) | [![Build+Status](http://build.ethdev.com/buildstatusimage?builder=Windows%20C%2B%2B%20develop%20branch)](http://build.ethdev.com/builders/Windows%20C%2B%2B%20develop%20branch/builds/-1) -master | [![Build+Status](http://build.ethdev.com/buildstatusimage?builder=Linux%20C%2B%2B%20master%20branch)](http://build.ethdev.com/builders/Linux%20C%2B%2B%20master%20branch/builds/-1) | [![Build+Status](http://build.ethdev.com/buildstatusimage?builder=OSX%20C%2B%2B%20master%20branch)](http://build.ethdev.com/builders/OSX%20C%2B%2B%20master%20branch/builds/-1) | [![Build+Status](http://build.ethdev.com/buildstatusimage?builder=Windows%20C%2B%2B%20master%20branch)](http://build.ethdev.com/builders/Windows%20C%2B%2B%20master%20branch/builds/-1) -evmjit | [![Build+Status](http://build.ethdev.com/buildstatusimage?builder=Linux%20C%2B%2B%20develop%20evmjit)](http://build.ethdev.com/builders/Linux%20C%2B%2B%20develop%20evmjit/builds/-1) | [![Build+Status](http://build.ethdev.com/buildstatusimage?builder=OSX%20C%2B%2B%20develop%20evmjit)](http://build.ethdev.com/builders/OSX%20C%2B%2B%20develop%20evmjit/builds/-1) | N/A +develop | [![Build+Status](https://build.ethdev.com/buildstatusimage?builder=Linux%20C%2B%2B%20develop%20branch)](https://build.ethdev.com/builders/Linux%20C%2B%2B%20develop%20branch/builds/-1) | [![Build+Status](https://build.ethdev.com/buildstatusimage?builder=OSX%20C%2B%2B%20develop%20branch)](https://build.ethdev.com/builders/OSX%20C%2B%2B%20develop%20branch/builds/-1) | [![Build+Status](https://build.ethdev.com/buildstatusimage?builder=Windows%20C%2B%2B%20develop%20branch)](https://build.ethdev.com/builders/Windows%20C%2B%2B%20develop%20branch/builds/-1) +master | [![Build+Status](https://build.ethdev.com/buildstatusimage?builder=Linux%20C%2B%2B%20master%20branch)](https://build.ethdev.com/builders/Linux%20C%2B%2B%20master%20branch/builds/-1) | [![Build+Status](https://build.ethdev.com/buildstatusimage?builder=OSX%20C%2B%2B%20master%20branch)](https://build.ethdev.com/builders/OSX%20C%2B%2B%20master%20branch/builds/-1) | [![Build+Status](https://build.ethdev.com/buildstatusimage?builder=Windows%20C%2B%2B%20master%20branch)](https://build.ethdev.com/builders/Windows%20C%2B%2B%20master%20branch/builds/-1) +evmjit | [![Build+Status](https://build.ethdev.com/buildstatusimage?builder=Linux%20C%2B%2B%20develop%20evmjit)](https://build.ethdev.com/builders/Linux%20C%2B%2B%20develop%20evmjit/builds/-1) | [![Build+Status](https://build.ethdev.com/buildstatusimage?builder=OSX%20C%2B%2B%20develop%20evmjit)](https://build.ethdev.com/builders/OSX%20C%2B%2B%20develop%20evmjit/builds/-1) | N/A [![Stories in Ready](https://badge.waffle.io/ethereum/cpp-ethereum.png?label=ready&title=Ready)](http://waffle.io/ethereum/cpp-ethereum) @@ -24,7 +24,6 @@ To run the tests, make sure you clone the tests repository from github.com/ether See [TODO](https://github.com/ethereum/cpp-ethereum/wiki/TODO) - ### License See [LICENSE](LICENSE) diff --git a/alethzero/GraphParameters.h b/alethzero/GraphParameters.h index e73061335..e1669bd21 100644 --- a/alethzero/GraphParameters.h +++ b/alethzero/GraphParameters.h @@ -37,8 +37,11 @@ static T graphParameters(T _min, T _max, unsigned _divisions, T* o_from = 0, T* T uMax = _max / _divisor; if (uMax == uMin || !_divisions) { - *o_from = 0; - *o_delta = 1; + if (o_delta && o_from) + { + *o_from = 0; + *o_delta = 1; + } return 1; } long double l10 = std::log10((uMax - uMin) / T(_divisions) * 5.5f); diff --git a/alethzero/Grapher.h b/alethzero/Grapher.h index 0f7ccd642..564fe6654 100644 --- a/alethzero/Grapher.h +++ b/alethzero/Grapher.h @@ -76,24 +76,24 @@ public: void labelYOrderedPoints(std::map const& _translatedData, int _maxCount = 20, float _minFactor = .01f) const; protected: - QPainter* p; + QPainter* p = nullptr; QRect active; std::pair xRange; std::pair yRange; - float xM; - float xC; - float yM; - float yC; + float xM = 0; + float xC = 0; + float yM = 0; + float yC = 0; - float dx; - float dy; + float dx = 0; + float dy = 0; std::function xLabel; std::function yLabel; std::function pLabel; - float fontPixelSize; + float fontPixelSize = 0; // Translate from raw indexed data into x/y graph units. Only relevant for indexed data. float xT(float _dataIndex) const { return _dataIndex * xM + xC; } diff --git a/alethzero/Main.ui b/alethzero/Main.ui index b7c4f6c96..9025aa846 100644 --- a/alethzero/Main.ui +++ b/alethzero/Main.ui @@ -163,6 +163,7 @@ &Special + @@ -1652,6 +1653,17 @@ font-size: 14pt New &Transaction... + + + true + + + true + + + &NatSpec Enabled + + diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 00fb29e2d..c40e8f6a0 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -201,6 +201,11 @@ Main::~Main() g_logPost = simpleDebugOut; } +bool Main::confirm() const +{ + return ui->natSpec->isChecked(); +} + void Main::on_newIdentity_triggered() { KeyPair kp = KeyPair::create(); @@ -651,6 +656,7 @@ void Main::writeSettings() s.setValue("localNetworking", ui->localNetworking->isChecked()); s.setValue("forceMining", ui->forceMining->isChecked()); s.setValue("paranoia", ui->paranoia->isChecked()); + s.setValue("natSpec", ui->natSpec->isChecked()); s.setValue("showAll", ui->showAll->isChecked()); s.setValue("showAllAccounts", ui->showAllAccounts->isChecked()); s.setValue("clientName", ui->clientName->text()); @@ -662,7 +668,7 @@ void Main::writeSettings() s.setValue("jitvm", ui->jitvm->isChecked()); bytes d = m_webThree->saveNetwork(); - if (d.size()) + if (!d.empty()) m_networkConfig = QByteArray((char*)d.data(), (int)d.size()); s.setValue("peers", m_networkConfig); s.setValue("nameReg", ui->nameReg->text()); @@ -720,6 +726,7 @@ void Main::readSettings(bool _skipGeometry) ui->forceMining->setChecked(s.value("forceMining", false).toBool()); on_forceMining_triggered(); ui->paranoia->setChecked(s.value("paranoia", false).toBool()); + ui->natSpec->setChecked(s.value("natSpec", true).toBool()); ui->showAll->setChecked(s.value("showAll", false).toBool()); ui->showAllAccounts->setChecked(s.value("showAllAccounts", false).toBool()); ui->clientName->setText(s.value("clientName", "").toString()); @@ -1160,6 +1167,7 @@ void Main::timerEvent(QTimerEvent*) interval = 0; refreshNetwork(); refreshWhispers(); + poll(); } else interval += 100; diff --git a/alethzero/MainWin.h b/alethzero/MainWin.h index 6c4a97301..52b98d293 100644 --- a/alethzero/MainWin.h +++ b/alethzero/MainWin.h @@ -72,6 +72,7 @@ public: dev::eth::Client* ethereum() const { return m_webThree->ethereum(); } std::shared_ptr whisper() const { return m_webThree->whisper(); } + bool confirm() const; NatSpecFace* natSpec() { return &m_natSpecDB; } QVariant evalRaw(QString const& _js); diff --git a/alethzero/MiningView.cpp b/alethzero/MiningView.cpp index fa6da737b..63d1fcf99 100644 --- a/alethzero/MiningView.cpp +++ b/alethzero/MiningView.cpp @@ -48,7 +48,6 @@ string sL(float _x, float _y) { return toString(round(_x * 1000)) + "s (" + toSt MiningView::MiningView(QWidget* _p): QWidget(_p) { - } void MiningView::appendStats(list const& _i, MineProgress const& _p) @@ -86,10 +85,10 @@ void MiningView::appendStats(list const& _i, MineProgress const& _p) for (auto& i: m_resets) i -= o; - remove_if(m_resets.begin(), m_resets.end(), [](int i){return i < 0;}); + m_resets.erase(remove_if(m_resets.begin(), m_resets.end(), [](int i){return i < 0;}), m_resets.end()); for (auto& i: m_completes) i -= o; - remove_if(m_completes.begin(), m_completes.end(), [](int i){return i < 0;}); + m_completes.erase(remove_if(m_completes.begin(), m_completes.end(), [](int i){return i < 0;}), m_completes.end()); m_progress = _p; update(); diff --git a/alethzero/NatspecHandler.cpp b/alethzero/NatspecHandler.cpp index bfdbaa178..27cf00341 100644 --- a/alethzero/NatspecHandler.cpp +++ b/alethzero/NatspecHandler.cpp @@ -66,7 +66,6 @@ string NatspecHandler::getUserNotice(string const& json, dev::bytes const& _tran { Json::Value natspec; Json::Value userNotice; - string retStr; m_reader.parse(json, natspec); FixedHash<4> transactionFunctionHash((bytesConstRef(&_transactionData).cropped(0, 4).toBytes())); diff --git a/alethzero/NatspecHandler.h b/alethzero/NatspecHandler.h index 15ceb7b0b..7aeafec41 100644 --- a/alethzero/NatspecHandler.h +++ b/alethzero/NatspecHandler.h @@ -54,6 +54,6 @@ class NatspecHandler: public NatSpecFace private: ldb::ReadOptions m_readOptions; ldb::WriteOptions m_writeOptions; - ldb::DB* m_db; + ldb::DB* m_db = nullptr; Json::Reader m_reader; }; diff --git a/alethzero/OurWebThreeStubServer.cpp b/alethzero/OurWebThreeStubServer.cpp index 2d1dd0481..da588ba3e 100644 --- a/alethzero/OurWebThreeStubServer.cpp +++ b/alethzero/OurWebThreeStubServer.cpp @@ -33,9 +33,11 @@ using namespace dev; using namespace dev::eth; OurWebThreeStubServer::OurWebThreeStubServer(jsonrpc::AbstractServerConnector& _conn, WebThreeDirect& _web3, - vector const& _accounts, Main* main): - WebThreeStubServer(_conn, _web3, _accounts), m_web3(&_web3), m_main(main) -{} + vector const& _accounts, Main* _main): + WebThreeStubServer(_conn, _web3, _accounts), m_web3(&_web3), m_main(_main) +{ + connect(_main, SIGNAL(poll()), this, SLOT(doValidations())); +} string OurWebThreeStubServer::shh_newIdentity() { @@ -44,29 +46,44 @@ string OurWebThreeStubServer::shh_newIdentity() return toJS(kp.pub()); } -bool OurWebThreeStubServer::showAuthenticationPopup(string const& _title, string const& _text) const +bool OurWebThreeStubServer::showAuthenticationPopup(string const& _title, string const& _text) { - int button; - QMetaObject::invokeMethod(m_main, "authenticate", Qt::BlockingQueuedConnection, Q_RETURN_ARG(int, button), Q_ARG(QString, QString::fromStdString(_title)), Q_ARG(QString, QString::fromStdString(_text))); - return button == QMessageBox::Ok; + if (!m_main->confirm()) + { + cnote << "Skipping confirmation step for: " << _title << "\n" << _text; + return true; + } + + QMessageBox userInput; + userInput.setText(QString::fromStdString(_title)); + userInput.setInformativeText(QString::fromStdString(_text)); + 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; + //QMetaObject::invokeMethod(m_main, "authenticate", Qt::BlockingQueuedConnection, Q_RETURN_ARG(int, button), Q_ARG(QString, QString::fromStdString(_title)), Q_ARG(QString, QString::fromStdString(_text))); + //return button == QMessageBox::Ok; } -bool OurWebThreeStubServer::showCreationNotice(TransactionSkeleton const& _t) const +bool OurWebThreeStubServer::showCreationNotice(TransactionSkeleton const& _t, bool _toProxy) { - return showAuthenticationPopup("Contract Creation Transaction", "ÐApp is attemping to create a contract; to be endowed with " + formatBalance(_t.value) + ", with additional network fees of up to " + formatBalance(_t.gas * _t.gasPrice) + ".\n\nMaximum total cost is " + formatBalance(_t.value + _t.gas * _t.gasPrice) + "."); + return showAuthenticationPopup("Contract Creation Transaction", string("ÐApp is attemping to create a contract; ") + (_toProxy ? "(this transaction is not executed directly, but forwarded to another ÐApp) " : "") + "to be endowed with " + formatBalance(_t.value) + ", with additional network fees of up to " + formatBalance(_t.gas * _t.gasPrice) + ".\n\nMaximum total cost is " + formatBalance(_t.value + _t.gas * _t.gasPrice) + "."); } -bool OurWebThreeStubServer::showSendNotice(TransactionSkeleton const& _t) const +bool OurWebThreeStubServer::showSendNotice(TransactionSkeleton const& _t, bool _toProxy) { - return showAuthenticationPopup("Fund Transfer Transaction", "ÐApp is attempting to send " + formatBalance(_t.value) + " to a recipient " + m_main->pretty(_t.to).toStdString() + ", with additional network fees of up to " + formatBalance(_t.gas * _t.gasPrice) + ".\n\nMaximum total cost is " + formatBalance(_t.value + _t.gas * _t.gasPrice) + "."); + return showAuthenticationPopup("Fund Transfer Transaction", "ÐApp is attempting to send " + formatBalance(_t.value) + " to a recipient " + m_main->pretty(_t.to).toStdString() + (_toProxy ? " (this transaction is not executed directly, but forwarded to another ÐApp)" : "") + +", with additional network fees of up to " + formatBalance(_t.gas * _t.gasPrice) + ".\n\nMaximum total cost is " + formatBalance(_t.value + _t.gas * _t.gasPrice) + "."); } -bool OurWebThreeStubServer::showUnknownCallNotice(TransactionSkeleton const& _t) const +bool OurWebThreeStubServer::showUnknownCallNotice(TransactionSkeleton const& _t, bool _toProxy) { return showAuthenticationPopup("DANGEROUS! Unknown Contract Transaction!", "ÐApp is attempting to call into an unknown contract at address " + - m_main->pretty(_t.to).toStdString() + - ".\n\nCall involves sending " + + m_main->pretty(_t.to).toStdString() + ".\n\n" + + (_toProxy ? "This transaction is not executed directly, but forwarded to another ÐApp.\n\n" : "") + + "Call involves sending " + formatBalance(_t.value) + " to the recipient, with additional network fees of up to " + formatBalance(_t.gas * _t.gasPrice) + "However, this also does other stuff which we don't understand, and does so in your name.\n\n" + @@ -76,25 +93,43 @@ bool OurWebThreeStubServer::showUnknownCallNotice(TransactionSkeleton const& _t) "REJECT UNLESS YOU REALLY KNOW WHAT YOU ARE DOING!"); } -bool OurWebThreeStubServer::authenticate(TransactionSkeleton const& _t) +void OurWebThreeStubServer::authenticate(TransactionSkeleton const& _t, bool _toProxy) +{ + Guard l(x_queued); + m_queued.push(make_pair(_t, _toProxy)); +} + +void OurWebThreeStubServer::doValidations() +{ + Guard l(x_queued); + while (!m_queued.empty()) + { + auto q = m_queued.front(); + m_queued.pop(); + if (validateTransaction(q.first, q.second)) + WebThreeStubServerBase::authenticate(q.first, q.second); + } +} + +bool OurWebThreeStubServer::validateTransaction(TransactionSkeleton const& _t, bool _toProxy) { if (_t.creation) { - // recipient has no code - nothing special about this transaction, show basic value transfer info - return showCreationNotice(_t); + // show notice concerning the creation code. TODO: this needs entering into natspec. + return showCreationNotice(_t, _toProxy); } h256 contractCodeHash = m_web3->ethereum()->postState().codeHash(_t.to); if (contractCodeHash == EmptySHA3) { // recipient has no code - nothing special about this transaction, show basic value transfer info - return showSendNotice(_t); + return showSendNotice(_t, _toProxy); } string userNotice = m_main->natSpec()->getUserNotice(contractCodeHash, _t.data); if (userNotice.empty()) - return showUnknownCallNotice(_t); + return showUnknownCallNotice(_t, _toProxy); NatspecExpressionEvaluator evaluator; userNotice = evaluator.evalExpression(QString::fromStdString(userNotice)).toStdString(); @@ -104,11 +139,12 @@ bool OurWebThreeStubServer::authenticate(TransactionSkeleton const& _t) "ÐApp attempting to conduct contract interaction with " + m_main->pretty(_t.to).toStdString() + ": " + userNotice + ".\n\n" + + (_toProxy ? "This transaction is not executed directly, but forwarded to another ÐApp.\n\n" : "") + (_t.value > 0 ? "In addition, ÐApp is attempting to send " + formatBalance(_t.value) + " to said recipient, with additional network fees of up to " + - formatBalance(_t.gas * _t.gasPrice) + " = " + - formatBalance(_t.value + _t.gas * _t.gasPrice) + "." + formatBalance(_t.gas * _t.gasPrice) + " = " + + formatBalance(_t.value + _t.gas * _t.gasPrice) + "." : "Additional network fees are at most" + formatBalance(_t.gas * _t.gasPrice) + ".") diff --git a/alethzero/OurWebThreeStubServer.h b/alethzero/OurWebThreeStubServer.h index fbdae7d03..95cf70438 100644 --- a/alethzero/OurWebThreeStubServer.h +++ b/alethzero/OurWebThreeStubServer.h @@ -19,7 +19,9 @@ * @date 2014 */ +#include #include +#include #include #include #include @@ -35,16 +37,24 @@ public: std::vector const& _accounts, Main* main); virtual std::string shh_newIdentity() override; - virtual bool authenticate(dev::eth::TransactionSkeleton const& _t); + virtual void authenticate(dev::eth::TransactionSkeleton const& _t, bool _toProxy); signals: void onNewId(QString _s); +public slots: + void doValidations(); + private: - bool showAuthenticationPopup(std::string const& _title, std::string const& _text) const; - bool showCreationNotice(dev::eth::TransactionSkeleton const& _t) const; - bool showSendNotice(dev::eth::TransactionSkeleton const& _t) const; - bool showUnknownCallNotice(dev::eth::TransactionSkeleton const& _t) const; + bool showAuthenticationPopup(std::string const& _title, std::string const& _text); + bool showCreationNotice(dev::eth::TransactionSkeleton const& _t, bool _toProxy); + bool showSendNotice(dev::eth::TransactionSkeleton const& _t, bool _toProxy); + bool showUnknownCallNotice(dev::eth::TransactionSkeleton const& _t, bool _toProxy); + + bool validateTransaction(dev::eth::TransactionSkeleton const& _t, bool _toProxy); + + std::queue> m_queued; + dev::Mutex x_queued; dev::WebThreeDirect* m_web3; Main* m_main; diff --git a/alethzero/Transact.cpp b/alethzero/Transact.cpp index bfeb41d9a..1b9a62a2d 100644 --- a/alethzero/Transact.cpp +++ b/alethzero/Transact.cpp @@ -202,7 +202,7 @@ void Transact::rejigData() for (auto& i: errors) i = "(LLL " + i + ")"; } - catch (string err) + catch (string const& err) { errors.push_back("Serpent " + err); } diff --git a/cmake/EthDependencies.cmake b/cmake/EthDependencies.cmake index fb6b09bb8..3f6cbcd77 100644 --- a/cmake/EthDependencies.cmake +++ b/cmake/EthDependencies.cmake @@ -128,6 +128,11 @@ if (NOT HEADLESS) set (MACDEPLOYQT_APP ${Qt5Core_DIR}/../../../bin/macdeployqt) message(" - macdeployqt path: ${MACDEPLOYQT_APP}") endif() + # we need to find path to windeployqt on windows + if (WIN32) + set (WINDEPLOYQT_APP ${Qt5Core_DIR}/../../../bin/windeployqt) + message(" - windeployqt path: ${WINDEPLOYQT_APP}") + endif() # TODO check node && npm version find_program(ETH_NODE node) diff --git a/cmake/EthExecutableHelper.cmake b/cmake/EthExecutableHelper.cmake index 427e0a9c4..c6e0210de 100644 --- a/cmake/EthExecutableHelper.cmake +++ b/cmake/EthExecutableHelper.cmake @@ -63,7 +63,7 @@ macro(eth_install_executable EXECUTABLE) if (APPLE) set(eth_qml_dir "-qmldir=${ETH_INSTALL_EXECUTABLE_QMLDIR}") elseif (WIN32) - set(eth_qml_dir --qmldir ${ETH_INSTALL_EXECUTABLE_QMLDIR}) + set(eth_qml_dir "--qmldir ${ETH_INSTALL_EXECUTABLE_QMLDIR}") endif() message(STATUS "${EXECUTABLE} qmldir: ${eth_qml_dir}") endif() @@ -88,49 +88,17 @@ macro(eth_install_executable EXECUTABLE) set(BU_CHMOD_BUNDLE_ITEMS 1) verify_app(\"${APP_BUNDLE_PATH}\") " COMPONENT RUNTIME ) - elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") - - # copy all dlls to executable directory - # TODO improve that by copying only required dlls - file (GLOB DLLS ${ETH_DEPENDENCY_INSTALL_DIR}/bin/*.dll) - - foreach(DLL ${DLLS}) - add_custom_command(TARGET ${EXECUTABLE} POST_BUILD - COMMAND cmake -E copy "${DLL}" "$" - ) - endforeach() + elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") add_custom_command(TARGET ${EXECUTABLE} POST_BUILD - COMMAND cmake -E copy_directory - "${ETH_DEPENDENCY_INSTALL_DIR}/plugins/platforms" - $/platforms + COMMAND cmd /C "set PATH=${Qt5Core_DIR}/../../../bin;%PATH% && ${WINDEPLOYQT_APP} ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${EXECUTABLE}.exe ${eth_qml_dir}" + WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} ) - - # ugly way, improve that + #workaround for https://bugreports.qt.io/browse/QTBUG-42083 add_custom_command(TARGET ${EXECUTABLE} POST_BUILD - COMMAND cmake -E copy_directory - "${ETH_DEPENDENCY_INSTALL_DIR}/qml" - $ - ) - - install( FILES ${DLLS} - DESTINATION bin - COMPONENT ${EXECUTABLE} - ) - - install( DIRECTORY ${ETH_DEPENDENCY_INSTALL_DIR}/plugins/platforms - DESTINATION bin - COMPONENT ${EXECUTABLE} + COMMAND cmd /C "(echo [Paths] & echo.Prefix=.)" > "qt.conf" + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR} VERBATIM ) - - file (GLOB QMLS ${ETH_DEPENDENCY_INSTALL_DIR}/qml/*) - foreach(QML ${QMLS}) - install( DIRECTORY ${QML} - DESTINATION bin - COMPONENT ${EXECUTABLE} - ) - endforeach() - install( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin COMPONENT ${EXECUTABLE} diff --git a/eth/main.cpp b/eth/main.cpp index f17817fbf..5051580a5 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -749,7 +749,7 @@ int main(int argc, char** argv) else if (format == "standard+") oof = [&](uint64_t, Instruction instr, bigint, bigint, dev::eth::VM* vvm, dev::eth::ExtVMFace const* vextVM) { - dev::eth::VM* vm = (VM*)vvm; + dev::eth::VM* vm = vvm; dev::eth::ExtVM const* ext = static_cast(vextVM); if (instr == Instruction::STOP || instr == Instruction::RETURN || instr == Instruction::SUICIDE) for (auto const& i: ext->state().storage(ext->myAddress)) @@ -898,7 +898,9 @@ int main(int argc, char** argv) while (!g_exit) this_thread::sleep_for(chrono::milliseconds(1000)); - writeFile((dbPath.size() ? dbPath : getDataDir()) + "/network.rlp", web3.saveNetwork()); + auto netData = web3.saveNetwork(); + if (!netData.empty()) + writeFile((dbPath.size() ? dbPath : getDataDir()) + "/network.rlp", netData); return 0; } diff --git a/evmjit/CMakeLists.txt b/evmjit/CMakeLists.txt index a449f9a60..14fca2cde 100644 --- a/evmjit/CMakeLists.txt +++ b/evmjit/CMakeLists.txt @@ -3,13 +3,14 @@ cmake_minimum_required(VERSION 2.8.12) project(evmjit) set_property(GLOBAL PROPERTY USE_FOLDERS ON) +set(CMAKE_AUTOMOC OFF) -if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") +if(${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC") else() - set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -Wno-unknown-pragmas -Wextra -fPIC") + set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -Wextra -Wconversion -Wno-unknown-pragmas") endif() -if(CMAKE_SYSTEM_NAME STREQUAL "Linux") +if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") # Do not allow unresovled symbols in shared library (default on linux) set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--no-undefined") endif() diff --git a/evmjit/LICENSE.md b/evmjit/LICENSE.md new file mode 100644 index 000000000..630157f98 --- /dev/null +++ b/evmjit/LICENSE.md @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 Paweł Bylica + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/evmjit/README.md b/evmjit/README.md new file mode 100644 index 000000000..a480e83dc --- /dev/null +++ b/evmjit/README.md @@ -0,0 +1,43 @@ +# The Ethereum EVM JIT + +EVM JIT is a library for just-in-time compilation of Ethereum EVM code. +It can be used to substitute classic interpreter-like EVM Virtual Machine in Ethereum client. + +## Build + +### Linux / Ubuntu + +1. Install llvm-3.5-dev package + 1. For Ubuntu 14.04 using LLVM deb packages source: http://llvm.org/apt + 2. For Ubuntu 14.10 using Ubuntu packages +2. Build library with cmake + 1. `mkdir build && cd $_` + 2. `cmake .. && make` +3. Install library + 1. `sudo make install` + 2. `sudo ldconfig` + +### OSX + +1. Install llvm35 + 1. `brew install llvm35 --disable-shared --HEAD` +2. Build library with cmake + 1. `mkdir build && cd $_` + 2. `cmake -DLLVM_DIR=/usr/local/lib/llvm-3.5/share/llvm/cmake .. && make` +3. Install library + 1. `make install` (with admin rights?) + +### Windows + +Ask me. + +## Options + +Options to evmjit library can be passed by environmental variables, e.g. `EVMJIT_CACHE=0 testeth --jit`. + +Option | Default value | Description +------------- | ------------- | ---------------------------------------------- +EVMJIT_CACHE | 1 | Enables on disk cache for compiled EVM objects +EVMJIT_DUMP | 0 | Dumps generated LLVM module to standard output + + diff --git a/evmjit/libevmjit-cpp/CMakeLists.txt b/evmjit/libevmjit-cpp/CMakeLists.txt index 58375e4ee..53448332b 100644 --- a/evmjit/libevmjit-cpp/CMakeLists.txt +++ b/evmjit/libevmjit-cpp/CMakeLists.txt @@ -9,6 +9,11 @@ set(SOURCES ) source_group("" FILES ${SOURCES}) +if(${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC") +else() + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC") # add PIC for archive +endif() + add_library(${TARGET_NAME} ${SOURCES}) set_property(TARGET ${TARGET_NAME} PROPERTY FOLDER "libs") diff --git a/evmjit/libevmjit-cpp/Env.cpp b/evmjit/libevmjit-cpp/Env.cpp index f89897792..11882d79d 100644 --- a/evmjit/libevmjit-cpp/Env.cpp +++ b/evmjit/libevmjit-cpp/Env.cpp @@ -1,4 +1,5 @@ +#pragma GCC diagnostic ignored "-Wconversion" #include #include #include @@ -46,23 +47,22 @@ extern "C" *o_hash = _env->blockhash(llvm2eth(*_number)); } - EXPORT void env_create(ExtVMFace* _env, i256* io_gas, i256* _endowment, byte* _initBeg, uint64_t _initSize, h256* o_address) + EXPORT void env_create(ExtVMFace* _env, int64_t* io_gas, i256* _endowment, byte* _initBeg, uint64_t _initSize, h256* o_address) { auto endowment = llvm2eth(*_endowment); if (_env->balance(_env->myAddress) >= endowment && _env->depth < 1024) { _env->subBalance(endowment); - auto gas = llvm2eth(*io_gas); - OnOpFunc onOp {}; // TODO: Handle that thing - h256 address(_env->create(endowment, gas, {_initBeg, _initSize}, onOp), h256::AlignRight); - *io_gas = eth2llvm(gas); + u256 gas = *io_gas; + h256 address(_env->create(endowment, gas, {_initBeg, _initSize}, {}), h256::AlignRight); + *io_gas = static_cast(gas); *o_address = address; } else *o_address = {}; } - EXPORT bool env_call(ExtVMFace* _env, i256* io_gas, h256* _receiveAddress, i256* _value, byte* _inBeg, uint64_t _inSize, byte* _outBeg, uint64_t _outSize, h256* _codeAddress) + EXPORT bool env_call(ExtVMFace* _env, int64_t* io_gas, h256* _receiveAddress, i256* _value, byte* _inBeg, uint64_t _inSize, byte* _outBeg, uint64_t _outSize, h256* _codeAddress) { auto value = llvm2eth(*_value); if (_env->balance(_env->myAddress) >= value && _env->depth < 1024) @@ -70,12 +70,11 @@ extern "C" _env->subBalance(value); auto receiveAddress = right160(*_receiveAddress); auto inRef = bytesConstRef{_inBeg, _inSize}; - auto outRef = bytesConstRef{_outBeg, _outSize}; - OnOpFunc onOp {}; // TODO: Handle that thing + auto outRef = bytesRef{_outBeg, _outSize}; auto codeAddress = right160(*_codeAddress); - auto gas = llvm2eth(*io_gas); - auto ret = _env->call(receiveAddress, value, inRef, gas, outRef, onOp, {}, codeAddress); - *io_gas = eth2llvm(gas); + u256 gas = *io_gas; + auto ret = _env->call(receiveAddress, value, inRef, gas, outRef, {}, {}, codeAddress); + *io_gas = static_cast(gas); return ret; } diff --git a/evmjit/libevmjit-cpp/JitVM.cpp b/evmjit/libevmjit-cpp/JitVM.cpp index 413525e5a..55dcd94f8 100644 --- a/evmjit/libevmjit-cpp/JitVM.cpp +++ b/evmjit/libevmjit-cpp/JitVM.cpp @@ -1,6 +1,9 @@ +#pragma GCC diagnostic ignored "-Wconversion" #include "JitVM.h" #include +#include +#include #include #include "Utils.h" @@ -11,22 +14,26 @@ namespace eth extern "C" void env_sload(); // fake declaration for linker symbol stripping workaround, see a call below -bytesConstRef JitVM::go(ExtVMFace& _ext, OnOpFunc const&, uint64_t) +bytesConstRef JitVM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _step) { using namespace jit; - if (m_gas > std::numeric_limits::max()) - BOOST_THROW_EXCEPTION(OutOfGas()); // Do not accept requests with gas > 2^63 (int64 max) // TODO: Return "not accepted" exception to allow interpreted handle that - - if (_ext.gasPrice > std::numeric_limits::max()) - BOOST_THROW_EXCEPTION(OutOfGas()); - - if (_ext.currentBlock.number > std::numeric_limits::max()) - BOOST_THROW_EXCEPTION(OutOfGas()); - - if (_ext.currentBlock.timestamp > std::numeric_limits::max()) - BOOST_THROW_EXCEPTION(OutOfGas()); + auto rejected = false; + // TODO: Rejecting transactions with gas limit > 2^63 can be used by attacker to take JIT out of scope + rejected |= m_gas > std::numeric_limits::max(); // Do not accept requests with gas > 2^63 (int64 max) + rejected |= _ext.gasPrice > std::numeric_limits::max(); + rejected |= _ext.currentBlock.number > std::numeric_limits::max(); + rejected |= _ext.currentBlock.timestamp > std::numeric_limits::max(); + if (rejected) + { + UNTESTED; + std::cerr << "Rejected\n"; + VMFactory::setKind(VMKind::Interpreter); + m_fallbackVM = VMFactory::create(m_gas); + VMFactory::setKind(VMKind::JIT); + return m_fallbackVM->go(_ext, _onOp, _step); + } m_data.gas = static_cast(m_gas); m_data.gasPrice = static_cast(_ext.gasPrice); @@ -43,9 +50,10 @@ bytesConstRef JitVM::go(ExtVMFace& _ext, OnOpFunc const&, uint64_t) m_data.timestamp = static_cast(_ext.currentBlock.timestamp); m_data.code = _ext.code.data(); m_data.codeSize = _ext.code.size(); + m_data.codeHash = eth2llvm(sha3(_ext.code)); auto env = reinterpret_cast(&_ext); - auto exitCode = m_engine.run(_ext.code, &m_data, env); + auto exitCode = m_engine.run(&m_data, env); switch (exitCode) { case ReturnCode::Suicide: diff --git a/evmjit/libevmjit-cpp/JitVM.h b/evmjit/libevmjit-cpp/JitVM.h index 90855127e..58caa3648 100644 --- a/evmjit/libevmjit-cpp/JitVM.h +++ b/evmjit/libevmjit-cpp/JitVM.h @@ -12,15 +12,13 @@ class JitVM: public VMFace { virtual bytesConstRef go(ExtVMFace& _ext, OnOpFunc const& _onOp = {}, uint64_t _steps = (uint64_t)-1) override final; - enum Kind: bool { Interpreter, JIT }; - static std::unique_ptr create(Kind, u256 _gas = 0); - private: friend class VMFactory; explicit JitVM(u256 _gas = 0) : VMFace(_gas) {} jit::RuntimeData m_data; jit::ExecutionEngine m_engine; + std::unique_ptr m_fallbackVM; ///< VM used in case of input data rejected by JIT }; diff --git a/evmjit/libevmjit/Arith256.cpp b/evmjit/libevmjit/Arith256.cpp index 99ca63ea6..ddf06b463 100644 --- a/evmjit/libevmjit/Arith256.cpp +++ b/evmjit/libevmjit/Arith256.cpp @@ -1,11 +1,14 @@ #include "Arith256.h" -#include "Runtime.h" -#include "Type.h" -#include "Endianness.h" -#include -#include #include +#include + +#include "preprocessor/llvm_includes_start.h" +#include +#include "preprocessor/llvm_includes_end.h" + +#include "Type.h" +#include "Endianness.h" namespace dev { @@ -16,29 +19,102 @@ namespace jit Arith256::Arith256(llvm::IRBuilder<>& _builder) : CompilerHelper(_builder) -{ - using namespace llvm; +{} - m_result = m_builder.CreateAlloca(Type::Word, nullptr, "arith.result"); - m_arg1 = m_builder.CreateAlloca(Type::Word, nullptr, "arith.arg1"); - m_arg2 = m_builder.CreateAlloca(Type::Word, nullptr, "arith.arg2"); - m_arg3 = m_builder.CreateAlloca(Type::Word, nullptr, "arith.arg3"); +void Arith256::debug(llvm::Value* _value, char _c) +{ + if (!m_debug) + { + llvm::Type* argTypes[] = {Type::Word, m_builder.getInt8Ty()}; + m_debug = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::ExternalLinkage, "debug", getModule()); + } + createCall(m_debug, {m_builder.CreateZExtOrTrunc(_value, Type::Word), m_builder.getInt8(_c)}); +} - using Linkage = GlobalValue::LinkageTypes; +llvm::Function* Arith256::getMulFunc() +{ + auto& func = m_mul; + if (!func) + { + llvm::Type* argTypes[] = {Type::Word, Type::Word}; + func = llvm::Function::Create(llvm::FunctionType::get(Type::Word, argTypes, false), llvm::Function::PrivateLinkage, "mul", getModule()); - llvm::Type* arg2Types[] = {Type::WordPtr, Type::WordPtr, Type::WordPtr}; + auto x = &func->getArgumentList().front(); + x->setName("x"); + auto y = x->getNextNode(); + y->setName("y"); - m_mul = Function::Create(FunctionType::get(Type::Void, arg2Types, false), Linkage::ExternalLinkage, "arith_mul", getModule()); + InsertPointGuard guard{m_builder}; + auto bb = llvm::BasicBlock::Create(m_builder.getContext(), {}, func); + m_builder.SetInsertPoint(bb); + auto i64 = Type::Size; + auto i128 = m_builder.getIntNTy(128); + auto i256 = Type::Word; + auto x_lo = m_builder.CreateTrunc(x, i64, "x.lo"); + auto y_lo = m_builder.CreateTrunc(y, i64, "y.lo"); + auto x_mi = m_builder.CreateTrunc(m_builder.CreateLShr(x, Constant::get(64)), i64); + auto y_mi = m_builder.CreateTrunc(m_builder.CreateLShr(y, Constant::get(64)), i64); + auto x_hi = m_builder.CreateTrunc(m_builder.CreateLShr(x, Constant::get(128)), i128); + auto y_hi = m_builder.CreateTrunc(m_builder.CreateLShr(y, Constant::get(128)), i128); + + auto t1 = m_builder.CreateMul(m_builder.CreateZExt(x_lo, i128), m_builder.CreateZExt(y_lo, i128)); + auto t2 = m_builder.CreateMul(m_builder.CreateZExt(x_lo, i128), m_builder.CreateZExt(y_mi, i128)); + auto t3 = m_builder.CreateMul(m_builder.CreateZExt(x_lo, i128), y_hi); + auto t4 = m_builder.CreateMul(m_builder.CreateZExt(x_mi, i128), m_builder.CreateZExt(y_lo, i128)); + auto t5 = m_builder.CreateMul(m_builder.CreateZExt(x_mi, i128), m_builder.CreateZExt(y_mi, i128)); + auto t6 = m_builder.CreateMul(m_builder.CreateZExt(x_mi, i128), y_hi); + auto t7 = m_builder.CreateMul(x_hi, m_builder.CreateZExt(y_lo, i128)); + auto t8 = m_builder.CreateMul(x_hi, m_builder.CreateZExt(y_mi, i128)); + + auto p = m_builder.CreateZExt(t1, i256); + p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t2, i256), Constant::get(64))); + p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t3, i256), Constant::get(128))); + p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t4, i256), Constant::get(64))); + p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t5, i256), Constant::get(128))); + p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t6, i256), Constant::get(192))); + p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t7, i256), Constant::get(128))); + p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t8, i256), Constant::get(192))); + m_builder.CreateRet(p); + } + return func; } -void Arith256::debug(llvm::Value* _value, char _c) +llvm::Function* Arith256::getMul512Func() { - if (!m_debug) + auto& func = m_mul512; + if (!func) { - llvm::Type* argTypes[] = {Type::Word, m_builder.getInt8Ty()}; - m_debug = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::ExternalLinkage, "debug", getModule()); + auto i512 = m_builder.getIntNTy(512); + llvm::Type* argTypes[] = {Type::Word, Type::Word}; + func = llvm::Function::Create(llvm::FunctionType::get(i512, argTypes, false), llvm::Function::PrivateLinkage, "mul512", getModule()); + + auto x = &func->getArgumentList().front(); + x->setName("x"); + auto y = x->getNextNode(); + y->setName("y"); + + InsertPointGuard guard{m_builder}; + auto bb = llvm::BasicBlock::Create(m_builder.getContext(), {}, func); + m_builder.SetInsertPoint(bb); + auto i128 = m_builder.getIntNTy(128); + auto i256 = Type::Word; + auto x_lo = m_builder.CreateZExt(m_builder.CreateTrunc(x, i128, "x.lo"), i256); + auto y_lo = m_builder.CreateZExt(m_builder.CreateTrunc(y, i128, "y.lo"), i256); + auto x_hi = m_builder.CreateZExt(m_builder.CreateTrunc(m_builder.CreateLShr(x, Constant::get(128)), i128, "x.hi"), i256); + auto y_hi = m_builder.CreateZExt(m_builder.CreateTrunc(m_builder.CreateLShr(y, Constant::get(128)), i128, "y.hi"), i256); + + auto t1 = createCall(getMulFunc(), {x_lo, y_lo}); + auto t2 = createCall(getMulFunc(), {x_lo, y_hi}); + auto t3 = createCall(getMulFunc(), {x_hi, y_lo}); + auto t4 = createCall(getMulFunc(), {x_hi, y_hi}); + + auto p = m_builder.CreateZExt(t1, i512); + p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t2, i512), m_builder.getIntN(512, 128))); + p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t3, i512), m_builder.getIntN(512, 128))); + p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t4, i512), m_builder.getIntN(512, 256))); + m_builder.CreateRet(p); } - createCall(m_debug, {_value, m_builder.getInt8(_c)}); + return func; } llvm::Function* Arith256::getDivFunc(llvm::Type* _type) @@ -85,6 +161,15 @@ llvm::Function* Arith256::getDivFunc(llvm::Type* _type) auto i0 = m_builder.CreateNUWSub(yLz, rLz, "i0"); auto shlBy0 = m_builder.CreateICmpEQ(i0, zero); auto y0 = m_builder.CreateShl(yArg, i0); + if (_type == m_builder.getIntNTy(512)) // Workaround for shl bug for long shifts + { + const auto treshold = m_builder.getIntN(512, 128); + auto highShift = m_builder.CreateICmpUGT(i0, treshold); + auto s = m_builder.CreateNUWSub(i0, treshold); + auto yhs = m_builder.CreateShl(yArg, treshold); + yhs = m_builder.CreateShl(yhs, s); + y0 = m_builder.CreateSelect(highShift, yhs, y0); + } y0 = m_builder.CreateSelect(shlBy0, yArg, y0, "y0"); // Workaround for LLVM bug: shl by 0 produces wrong result m_builder.CreateBr(loopBB); @@ -135,7 +220,7 @@ llvm::Function* Arith256::getExpFunc() if (!m_exp) { llvm::Type* argTypes[] = {Type::Word, Type::Word}; - m_exp = llvm::Function::Create(llvm::FunctionType::get(Type::Word, argTypes, false), llvm::Function::PrivateLinkage, "arith.exp", getModule()); + m_exp = llvm::Function::Create(llvm::FunctionType::get(Type::Word, argTypes, false), llvm::Function::PrivateLinkage, "exp", getModule()); auto base = &m_exp->getArgumentList().front(); base->setName("base"); @@ -159,9 +244,6 @@ llvm::Function* Arith256::getExpFunc() auto returnBB = llvm::BasicBlock::Create(m_builder.getContext(), "Return", m_exp); m_builder.SetInsertPoint(entryBB); - auto a1 = m_builder.CreateAlloca(Type::Word, nullptr, "a1"); - auto a2 = m_builder.CreateAlloca(Type::Word, nullptr, "a2"); - auto a3 = m_builder.CreateAlloca(Type::Word, nullptr, "a3"); m_builder.CreateBr(headerBB); m_builder.SetInsertPoint(headerBB); @@ -176,20 +258,14 @@ llvm::Function* Arith256::getExpFunc() m_builder.CreateCondBr(eOdd, updateBB, continueBB); m_builder.SetInsertPoint(updateBB); - m_builder.CreateStore(r, a1); - m_builder.CreateStore(b, a2); - createCall(m_mul, {a1, a2, a3}); - auto r0 = m_builder.CreateLoad(a3, "r0"); + auto r0 = createCall(getMulFunc(), {r, b}); m_builder.CreateBr(continueBB); m_builder.SetInsertPoint(continueBB); auto r1 = m_builder.CreatePHI(Type::Word, 2, "r1"); r1->addIncoming(r, bodyBB); r1->addIncoming(r0, updateBB); - m_builder.CreateStore(b, a1); - m_builder.CreateStore(b, a2); - createCall(m_mul, {a1, a2, a3}); - auto b1 = m_builder.CreateLoad(a3, "b1"); + auto b1 = createCall(getMulFunc(), {b, b}); auto e1 = m_builder.CreateLShr(e, Constant::get(1), "e1"); m_builder.CreateBr(headerBB); @@ -244,9 +320,6 @@ llvm::Function* Arith256::getMulModFunc() m_mulmod = llvm::Function::Create(llvm::FunctionType::get(Type::Word, argTypes, false), llvm::Function::PrivateLinkage, "mulmod", getModule()); auto i512Ty = m_builder.getIntNTy(512); - llvm::Type* mul512ArgTypes[] = {Type::WordPtr, Type::WordPtr, i512Ty->getPointerTo()}; - auto mul512 = llvm::Function::Create(llvm::FunctionType::get(Type::Void, mul512ArgTypes, false), llvm::Function::ExternalLinkage, "arith_mul512", getModule()); - auto x = &m_mulmod->getArgumentList().front(); x->setName("x"); auto y = x->getNextNode(); @@ -258,32 +331,19 @@ llvm::Function* Arith256::getMulModFunc() auto entryBB = llvm::BasicBlock::Create(m_builder.getContext(), {}, m_mulmod); m_builder.SetInsertPoint(entryBB); - auto a1 = m_builder.CreateAlloca(Type::Word); - auto a2 = m_builder.CreateAlloca(Type::Word); - auto a3 = m_builder.CreateAlloca(i512Ty); - m_builder.CreateStore(x, a1); - m_builder.CreateStore(y, a2); - createCall(mul512, {a1, a2, a3}); - auto p = m_builder.CreateLoad(a3, "p"); + auto p = createCall(getMul512Func(), {x, y}); auto m = m_builder.CreateZExt(mod, i512Ty, "m"); auto d = createCall(getDivFunc(i512Ty), {p, m}); auto r = m_builder.CreateExtractValue(d, 1, "r"); - m_builder.CreateRet(m_builder.CreateTrunc(r, Type::Word)); + r = m_builder.CreateTrunc(r, Type::Word); + m_builder.CreateRet(r); } return m_mulmod; } -llvm::Value* Arith256::binaryOp(llvm::Function* _op, llvm::Value* _arg1, llvm::Value* _arg2) -{ - m_builder.CreateStore(_arg1, m_arg1); - m_builder.CreateStore(_arg2, m_arg2); - m_builder.CreateCall3(_op, m_arg1, m_arg2, m_result); - return m_builder.CreateLoad(m_result); -} - llvm::Value* Arith256::mul(llvm::Value* _arg1, llvm::Value* _arg2) { - return binaryOp(m_mul, _arg1, _arg2); + return createCall(getMulFunc(), {_arg1, _arg2}); } std::pair Arith256::div(llvm::Value* _arg1, llvm::Value* _arg2) @@ -331,157 +391,6 @@ llvm::Value* Arith256::mulmod(llvm::Value* _arg1, llvm::Value* _arg2, llvm::Valu return createCall(getMulModFunc(), {_arg1, _arg2, _arg3}); } -namespace -{ -#ifdef __SIZEOF_INT128__ - using uint128 = __uint128_t; -#else - struct uint128 - { - uint64_t lo = 0; - uint64_t hi = 0; - - uint128(uint64_t lo) : lo(lo) {} - - uint128 operator+(uint128 a) - { - uint128 r = 0; - bool overflow = lo > std::numeric_limits::max() - a.lo; - r.lo = lo + a.lo; - r.hi = hi + a.hi + overflow; - return r; - } - - uint128 operator>>(int s) - { - assert(s == 64); - return hi; - } - - uint128 operator<<(int s) - { - assert(s == 64); - uint128 r = 0; - r.hi = lo; - return r; - } - - explicit operator uint64_t() { return lo; } - - static uint128 mul(uint64_t a, uint64_t b) - { - auto x_lo = 0xFFFFFFFF & a; - auto y_lo = 0xFFFFFFFF & b; - auto x_hi = a >> 32; - auto y_hi = b >> 32; - - auto t1 = x_lo * y_lo; - auto t2 = x_lo * y_hi; - auto t3 = x_hi * y_lo; - auto t4 = x_hi * y_hi; - - auto lo = (uint32_t)t1; - auto mid = (uint64_t)(t1 >> 32) + (uint32_t)t2 + (uint32_t)t3; - auto hi = (uint64_t)(t2 >> 32) + (t3 >> 32) + t4 + (mid >> 32); - - uint128 r = 0; - r.lo = (uint64_t)lo + (mid << 32); - r.hi = hi; - return r; - } - - uint128 operator*(uint128 a) - { - auto t1 = mul(lo, a.lo); - auto t2 = mul(lo, a.hi); - auto t3 = mul(hi, a.lo); - return t1 + (t2 << 64) + (t3 << 64); - } - }; -#endif - - struct uint256 - { - uint64_t lo = 0; - uint64_t mid = 0; - uint128 hi = 0; - - uint256(uint64_t lo, uint64_t mid, uint128 hi): lo(lo), mid(mid), hi(hi) {} - uint256(uint128 n) - { - lo = (uint64_t) n; - mid = (uint64_t) (n >> 64); - } - - explicit operator uint128() - { - uint128 r = lo; - r = (r + ((uint128) mid)) << 64; - return r; - } - - uint256 operator+(uint256 a) - { - auto _lo = (uint128) lo + a.lo; - auto _mid = (uint128) mid + a.mid + (_lo >> 64); - auto _hi = hi + a.hi + (_mid >> 64); - return {(uint64_t)_lo, (uint64_t)_mid, _hi}; - } - - uint256 lo2hi() - { - hi = (uint128)*this; - lo = 0; - mid = 0; - return *this; - } - }; - - struct uint512 - { - uint128 lo; - uint128 mid; - uint256 hi; - }; - - uint256 mul(uint256 x, uint256 y) - { - auto t1 = (uint128) x.lo * y.lo; - auto t2 = (uint128) x.lo * y.mid; - auto t3 = (uint128) x.lo * y.hi; - auto t4 = (uint128) x.mid * y.lo; - auto t5 = (uint128) x.mid * y.mid; - auto t6 = (uint128) x.mid * y.hi; - auto t7 = x.hi * y.lo; - auto t8 = x.hi * y.mid; - - auto lo = (uint64_t) t1; - auto m1 = (t1 >> 64) + (uint64_t) t2; - auto m2 = (uint64_t) m1; - auto mid = (uint128) m2 + (uint64_t) t4; - auto hi = (t2 >> 64) + t3 + (t4 >> 64) + t5 + (t6 << 64) + t7 - + (t8 << 64) + (m1 >> 64) + (mid >> 64); - - return {lo, (uint64_t)mid, hi}; - } - - uint512 mul512(uint256 x, uint256 y) - { - auto x_lo = (uint128) x; - auto y_lo = (uint128) y; - - auto t1 = mul(x_lo, y_lo); - auto t2 = mul(x_lo, y.hi); - auto t3 = mul(x.hi, y_lo); - auto t4 = mul(x.hi, y.hi); - - auto lo = (uint128) t1; - auto mid = (uint256) t1.hi + (uint128) t2 + (uint128) t3; - auto hi = (uint256)t2.hi + t3.hi + t4 + mid.hi; - - return {lo, (uint128)mid, hi}; - } -} } } @@ -489,20 +398,9 @@ namespace extern "C" { - using namespace dev::eth::jit; - EXPORT void debug(uint64_t a, uint64_t b, uint64_t c, uint64_t d, char z) { - std::cerr << "DEBUG " << z << ": " << d << c << b << a << std::endl; - } - - EXPORT void arith_mul(uint256* _arg1, uint256* _arg2, uint256* o_result) - { - *o_result = mul(*_arg1, *_arg2); - } - - EXPORT void arith_mul512(uint256* _arg1, uint256* _arg2, uint512* o_result) - { - *o_result = mul512(*_arg1, *_arg2); + std::cerr << "DEBUG " << std::dec << z << ": " //<< d << c << b << a + << " [" << std::hex << std::setfill('0') << std::setw(16) << d << std::setw(16) << c << std::setw(16) << b << std::setw(16) << a << "]\n"; } } diff --git a/evmjit/libevmjit/Arith256.h b/evmjit/libevmjit/Arith256.h index 5852137f8..2513ca568 100644 --- a/evmjit/libevmjit/Arith256.h +++ b/evmjit/libevmjit/Arith256.h @@ -24,26 +24,21 @@ public: void debug(llvm::Value* _value, char _c); private: + llvm::Function* getMulFunc(); + llvm::Function* getMul512Func(); llvm::Function* getDivFunc(llvm::Type* _type); llvm::Function* getExpFunc(); llvm::Function* getAddModFunc(); llvm::Function* getMulModFunc(); - llvm::Value* binaryOp(llvm::Function* _op, llvm::Value* _arg1, llvm::Value* _arg2); - - llvm::Function* m_mul; - + llvm::Function* m_mul = nullptr; + llvm::Function* m_mul512 = nullptr; llvm::Function* m_div = nullptr; llvm::Function* m_div512 = nullptr; llvm::Function* m_exp = nullptr; llvm::Function* m_addmod = nullptr; llvm::Function* m_mulmod = nullptr; llvm::Function* m_debug = nullptr; - - llvm::Value* m_arg1; - llvm::Value* m_arg2; - llvm::Value* m_arg3; - llvm::Value* m_result; }; diff --git a/evmjit/libevmjit/BasicBlock.cpp b/evmjit/libevmjit/BasicBlock.cpp index 5868c0f43..c9e71be9a 100644 --- a/evmjit/libevmjit/BasicBlock.cpp +++ b/evmjit/libevmjit/BasicBlock.cpp @@ -1,13 +1,14 @@ - #include "BasicBlock.h" #include +#include "preprocessor/llvm_includes_start.h" #include #include #include #include #include +#include "preprocessor/llvm_includes_end.h" #include "Type.h" @@ -18,13 +19,14 @@ namespace eth namespace jit { -const char* BasicBlock::NamePrefix = "Instr."; +static const char* jumpDestName = "JmpDst."; +static const char* basicBlockName = "Instr."; -BasicBlock::BasicBlock(bytes::const_iterator _begin, bytes::const_iterator _end, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest) : +BasicBlock::BasicBlock(instr_idx _firstInstrIdx, code_iterator _begin, code_iterator _end, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest) : + m_firstInstrIdx{_firstInstrIdx}, m_begin(_begin), m_end(_end), - // TODO: Add begin index to name - m_llvmBB(llvm::BasicBlock::Create(_mainFunc->getContext(), NamePrefix, _mainFunc)), + m_llvmBB(llvm::BasicBlock::Create(_mainFunc->getContext(), {isJumpDest ? jumpDestName : basicBlockName, std::to_string(_firstInstrIdx)}, _mainFunc)), m_stack(*this), m_builder(_builder), m_isJumpDest(isJumpDest) @@ -43,6 +45,7 @@ BasicBlock::LocalStack::LocalStack(BasicBlock& _owner) : void BasicBlock::LocalStack::push(llvm::Value* _value) { + assert(_value->getType() == Type::Word); m_bblock.m_currentStack.push_back(_value); m_bblock.m_tosOffset += 1; } @@ -139,7 +142,7 @@ void BasicBlock::synchronizeLocalStack(Stack& _evmStack) auto endIter = m_currentStack.end(); // Update (emit set()) changed values - for (int idx = m_currentStack.size() - 1 - m_tosOffset; + for (int idx = (int)m_currentStack.size() - 1 - m_tosOffset; currIter < endIter && idx >= 0; ++currIter, --idx) { @@ -306,7 +309,7 @@ void BasicBlock::linkLocalStacks(std::vector basicBlocks, llvm::IRB auto& initialStack = bblock.m_initialStack; initialStack.erase(initialStack.begin(), initialStack.begin() + info.inputItems); // Initial stack shrinks, so the size difference grows: - bblock.m_tosOffset += info.inputItems; + bblock.m_tosOffset += (int)info.inputItems; } // We must account for the items that were pushed directly to successor @@ -319,7 +322,7 @@ void BasicBlock::linkLocalStacks(std::vector basicBlocks, llvm::IRB auto& exitStack = bblock.m_currentStack; exitStack.erase(exitStack.end() - info.outputItems, exitStack.end()); - bblock.m_tosOffset -= info.outputItems; + bblock.m_tosOffset -= (int)info.outputItems; // FIXME: Fix types } } diff --git a/evmjit/libevmjit/BasicBlock.h b/evmjit/libevmjit/BasicBlock.h index cda4f89bd..7469b7b69 100644 --- a/evmjit/libevmjit/BasicBlock.h +++ b/evmjit/libevmjit/BasicBlock.h @@ -1,6 +1,7 @@ #pragma once + #include -#include + #include "Common.h" #include "Stack.h" @@ -11,7 +12,7 @@ namespace eth namespace jit { -using ProgramCounter = uint64_t; // TODO: Rename +using instr_idx = uint64_t; class BasicBlock { @@ -50,10 +51,7 @@ public: BasicBlock& m_bblock; }; - /// Basic block name prefix. The rest is instruction index. - static const char* NamePrefix; - - explicit BasicBlock(bytes::const_iterator _begin, bytes::const_iterator _end, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest); + explicit BasicBlock(instr_idx _firstInstrIdx, code_iterator _begin, code_iterator _end, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest); explicit BasicBlock(std::string _name, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest); BasicBlock(const BasicBlock&) = delete; @@ -61,8 +59,9 @@ public: llvm::BasicBlock* llvm() { return m_llvmBB; } - bytes::const_iterator begin() { return m_begin; } - bytes::const_iterator end() { return m_end; } + instr_idx firstInstrIdx() const { return m_firstInstrIdx; } + code_iterator begin() const { return m_begin; } + code_iterator end() const { return m_end; } bool isJumpDest() const { return m_isJumpDest; } @@ -84,8 +83,9 @@ public: void dump(std::ostream& os, bool _dotOutput = false); private: - bytes::const_iterator const m_begin; - bytes::const_iterator const m_end; + instr_idx const m_firstInstrIdx = 0; ///< Code index of first instruction in the block + code_iterator const m_begin = {}; ///< Iterator pointing code beginning of the block + code_iterator const m_end = {}; ///< Iterator pointing code end of the block llvm::BasicBlock* const m_llvmBB; diff --git a/evmjit/libevmjit/BuildInfo.h.in b/evmjit/libevmjit/BuildInfo.h.in new file mode 100644 index 000000000..204b4d89b --- /dev/null +++ b/evmjit/libevmjit/BuildInfo.h.in @@ -0,0 +1,10 @@ + +#define EVMJIT_VERSION "${EVMJIT_VERSION}" +#define EVMJIT_VERSION_MAJOR ${EVMJIT_VERSION_MAJOR} +#define EVMJIT_VERSION_MINOR ${EVMJIT_VERSION_MINOR} +#define EVMJIT_VERSION_PATCH ${EVMJIT_VERSION_PATCH} +#define EVMJIT_VERSION_PRERELEASE "${EVMJIT_VERSION_PRERELEASE}" +#define EVMJIT_VERSION_FULL "${EVMJIT_VERSION_FULL}" + +#define LLVM_VERSION "${LLVM_PACKAGE_VERSION}" +#define LLVM_ASSERTIONS "${LLVM_ENABLE_ASSERTIONS}" diff --git a/evmjit/libevmjit/CMakeLists.txt b/evmjit/libevmjit/CMakeLists.txt index 545e55344..943c64e42 100644 --- a/evmjit/libevmjit/CMakeLists.txt +++ b/evmjit/libevmjit/CMakeLists.txt @@ -6,30 +6,63 @@ set(INTERFACE_HEADERS interface.h) source_group("" FILES ${HEADERS}) source_group("" FILES ${SOURCES}) -if (NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") - # Disable rtti for Cache as LLVM has no rtti - set_source_files_properties(Cache.cpp PROPERTIES COMPILE_FLAGS -fno-rtti) +if(${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC") +else() + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti") endif() -find_package(Git) -if(GIT_FOUND) - execute_process(COMMAND ${GIT_EXECUTABLE} -C ${CMAKE_CURRENT_SOURCE_DIR} describe --dirty --always - OUTPUT_VARIABLE EVMJIT_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE) + +set(EVMJIT_VERSION "0.0.0") +set(EVMJIT_VERSION_MAJOR 0) +set(EVMJIT_VERSION_MINOR 0) +set(EVMJIT_VERSION_PATCH 0) +set(EVMJIT_VERSION_FULL "v0.0.0-nogit") + +find_package(Git) +if(GIT_FOUND) + execute_process(COMMAND ${GIT_EXECUTABLE} -C ${CMAKE_CURRENT_SOURCE_DIR} describe --dirty --always --match v* + OUTPUT_VARIABLE EVMJIT_VERSION_FULL OUTPUT_STRIP_TRAILING_WHITESPACE) +endif() + +if(${EVMJIT_VERSION_FULL} MATCHES "^v[0-9]+\\.[0-9]+") + string(SUBSTRING ${EVMJIT_VERSION_FULL} 1 -1 EVMJIT_VERSION_FULL) # skip "v" + string(REPLACE "-" ";" VERSION_COMPONENTS ${EVMJIT_VERSION_FULL}) + list(LENGTH VERSION_COMPONENTS NUM_VERSION_COMPONENTS) + list(GET VERSION_COMPONENTS 0 EVMJIT_VERSION) + string(REPLACE "." ";" VERSION_NUMBERS ${EVMJIT_VERSION}) + list(LENGTH VERSION_NUMBERS NUM_VERSION_NUMBERS) + list(GET VERSION_NUMBERS 0 EVMJIT_VERSION_MAJOR) + list(GET VERSION_NUMBERS 1 EVMJIT_VERSION_MINOR) + if(${NUM_VERSION_NUMBERS} GREATER 2) + list(GET VERSION_NUMBERS 2 EVMJIT_VERSION_PATCH) # patch number is optional + endif() + if(${NUM_VERSION_COMPONENTS} GREATER 1) + list(GET VERSION_COMPONENTS 1 VERSION_PRERELEASE_CANDIDATE) + string(REGEX MATCH "^[a-zA-Z]+.*" EVMJIT_VERSION_PRERELEASE ${VERSION_PRERELEASE_CANDIDATE}) # prerelease starts with letter + endif() endif() -if(NOT EVMJIT_VERSION) - set(EVMJIT_VERSION "unknown") + +if(${EVMJIT_VERSION_MAJOR} EQUAL 0) + set(EVMJIT_SOVERSION "0.${EVMJIT_VERSION_MINOR}") +else() + set(EVMJIT_SOVERSION ${EVMJIT_VERSION_MAJOR}) endif() -message("EVM JIT version: ${EVMJIT_VERSION}") +configure_file(BuildInfo.h.in ${CMAKE_CURRENT_BINARY_DIR}/gen/BuildInfo.gen.h) + +message(STATUS "EVM JIT version: ${EVMJIT_VERSION_MAJOR}.${EVMJIT_VERSION_MINOR}.${EVMJIT_VERSION_PATCH} ${EVMJIT_VERSION_PRERELEASE} (${EVMJIT_VERSION_FULL})") -add_library(${TARGET_NAME} SHARED ${SOURCES} ${HEADERS}) -set_target_properties(${TARGET_NAME} PROPERTIES VERSION ${EVMJIT_VERSION} FOLDER "libs") +add_library(${TARGET_NAME} SHARED ${SOURCES} ${HEADERS} gen/BuildInfo.gen.h) +set_target_properties(${TARGET_NAME} PROPERTIES + VERSION ${EVMJIT_VERSION} SOVERSION ${EVMJIT_SOVERSION} + FOLDER "libs") include_directories(${LLVM_INCLUDE_DIRS}) +include_directories(${CMAKE_CURRENT_BINARY_DIR}/gen) target_link_libraries(${TARGET_NAME} PRIVATE ${LLVM_LIBS}) #set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti") install(TARGETS ${TARGET_NAME} LIBRARY DESTINATION lib ARCHIVE DESTINATION lib RUNTIME DESTINATION bin) -#install(FILES ${INTERFACE_HEADERS} DESTINATION include/${TARGET_NAME}) +#install(FILES ${INTERFACE_HEADERS} DESTINATION include/${TARGET_NAME}) \ No newline at end of file diff --git a/evmjit/libevmjit/Cache.cpp b/evmjit/libevmjit/Cache.cpp index 0e6fb517a..fe226eefb 100644 --- a/evmjit/libevmjit/Cache.cpp +++ b/evmjit/libevmjit/Cache.cpp @@ -1,12 +1,19 @@ #include "Cache.h" -#include -#include + #include +#include + +#include "preprocessor/llvm_includes_start.h" #include #include +#include #include #include #include +#include "preprocessor/llvm_includes_end.h" + +#include "ExecutionEngine.h" +#include "Utils.h" namespace dev { @@ -15,23 +22,31 @@ namespace eth namespace jit { -//#define LOG(...) std::cerr << "CACHE " -#define LOG(...) std::ostream(nullptr) +//#define CACHE_LOG std::cerr << "CACHE " +#define CACHE_LOG std::ostream(nullptr) -ObjectCache* Cache::getObjectCache() +namespace { - static ObjectCache objectCache; - return &objectCache; + llvm::MemoryBuffer* g_lastObject; + ExecutionEngineListener* g_listener; } -namespace +ObjectCache* Cache::getObjectCache(ExecutionEngineListener* _listener) { - llvm::MemoryBuffer* lastObject; + static ObjectCache objectCache; + g_listener = _listener; + return &objectCache; } std::unique_ptr Cache::getObject(std::string const& id) { - assert(!lastObject); + if (g_listener) + g_listener->stateChanged(ExecState::CacheLoad); + + CACHE_LOG << id << ": search\n"; + if (!CHECK(!g_lastObject)) + g_lastObject = nullptr; + llvm::SmallString<256> cachePath; llvm::sys::path::system_temp_directory(false, cachePath); llvm::sys::path::append(cachePath, "evm_objs", id); @@ -51,22 +66,31 @@ std::unique_ptr Cache::getObject(std::string const& id) #endif if (auto r = llvm::MemoryBuffer::getFile(cachePath.str(), -1, false)) - lastObject = llvm::MemoryBuffer::getMemBufferCopy(r.get()->getBuffer()); + g_lastObject = llvm::MemoryBuffer::getMemBufferCopy(r.get()->getBuffer()); else if (r.getError() != std::make_error_code(std::errc::no_such_file_or_directory)) std::cerr << r.getError().message(); // TODO: Add log - if (lastObject) // if object found create fake module + if (g_lastObject) // if object found create fake module { - auto module = std::unique_ptr(new llvm::Module(id, llvm::getGlobalContext())); - auto mainFuncType = llvm::FunctionType::get(llvm::IntegerType::get(llvm::getGlobalContext(), 32), {}, false); - llvm::Function::Create(mainFuncType, llvm::Function::ExternalLinkage, id, module.get()); + CACHE_LOG << id << ": found\n"; + auto&& context = llvm::getGlobalContext(); + auto module = std::unique_ptr(new llvm::Module(id, context)); + auto mainFuncType = llvm::FunctionType::get(llvm::Type::getVoidTy(context), {}, false); + auto mainFunc = llvm::Function::Create(mainFuncType, llvm::Function::ExternalLinkage, id, module.get()); + auto bb = llvm::BasicBlock::Create(context, {}, mainFunc); + bb->getInstList().push_back(new llvm::UnreachableInst{context}); + return module; } + CACHE_LOG << id << ": not found\n"; return nullptr; } void ObjectCache::notifyObjectCompiled(llvm::Module const* _module, llvm::MemoryBuffer const* _object) { + if (g_listener) + g_listener->stateChanged(ExecState::CacheWrite); + auto&& id = _module->getModuleIdentifier(); llvm::SmallString<256> cachePath; llvm::sys::path::system_temp_directory(false, cachePath); @@ -77,15 +101,17 @@ void ObjectCache::notifyObjectCompiled(llvm::Module const* _module, llvm::Memory llvm::sys::path::append(cachePath, id); + CACHE_LOG << id << ": write\n"; std::string error; llvm::raw_fd_ostream cacheFile(cachePath.c_str(), error, llvm::sys::fs::F_None); cacheFile << _object->getBuffer(); } -llvm::MemoryBuffer* ObjectCache::getObject(llvm::Module const*) +llvm::MemoryBuffer* ObjectCache::getObject(llvm::Module const* _module) { - auto o = lastObject; - lastObject = nullptr; + CACHE_LOG << _module->getModuleIdentifier() << ": use\n"; + auto o = g_lastObject; + g_lastObject = nullptr; return o; } diff --git a/evmjit/libevmjit/Cache.h b/evmjit/libevmjit/Cache.h index 1cad537cd..e8f01d38d 100644 --- a/evmjit/libevmjit/Cache.h +++ b/evmjit/libevmjit/Cache.h @@ -1,9 +1,8 @@ #pragma once #include -#include -#include +#include namespace dev { @@ -11,6 +10,7 @@ namespace eth { namespace jit { +class ExecutionEngineListener; class ObjectCache : public llvm::ObjectCache { @@ -23,16 +23,13 @@ public: /// not available. The caller owns both the MemoryBuffer returned by this /// and the memory it references. virtual llvm::MemoryBuffer* getObject(llvm::Module const* _module) final override; - -private: - std::unordered_map> m_map; }; class Cache { public: - static ObjectCache* getObjectCache(); + static ObjectCache* getObjectCache(ExecutionEngineListener* _listener); static std::unique_ptr getObject(std::string const& id); }; diff --git a/evmjit/libevmjit/Common.h b/evmjit/libevmjit/Common.h index d629f25ad..62731292f 100644 --- a/evmjit/libevmjit/Common.h +++ b/evmjit/libevmjit/Common.h @@ -20,25 +20,30 @@ namespace jit using byte = uint8_t; using bytes = std::vector; using bytes_ref = std::tuple; +using code_iterator = byte const*; struct NoteChannel {}; // FIXME: Use some log library? enum class ReturnCode { - Stop = 0, - Return = 1, + // Success codes + Stop = 0, + Return = 1, Suicide = 2, - OutOfGas = -1, - BadJumpDestination = -2, - StackTooSmall = -3, - BadInstruction = -4, + // Standard error codes + OutOfGas = -1, + StackTooSmall = -2, + BadJumpDestination = -3, + BadInstruction = -4, + Rejected = -5, ///< Input data (code, gas, block info, etc.) does not meet JIT requirement and execution request has been rejected - LLVMConfigError = -5, - LLVMCompileError = -6, - LLVMLinkError = -7, + // Internal error codes + LLVMConfigError = -101, + LLVMCompileError = -102, + LLVMLinkError = -103, - UnexpectedException = -8, + UnexpectedException = -111, LinkerWorkaround = -299, }; diff --git a/evmjit/libevmjit/Compiler.cpp b/evmjit/libevmjit/Compiler.cpp index ad8a14fc7..de48e8ef9 100644 --- a/evmjit/libevmjit/Compiler.cpp +++ b/evmjit/libevmjit/Compiler.cpp @@ -1,4 +1,3 @@ - #include "Compiler.h" #include @@ -6,13 +5,15 @@ #include #include +#include "preprocessor/llvm_includes_start.h" #include #include #include #include - +#include #include #include +#include "preprocessor/llvm_includes_end.h" #include "Instruction.h" #include "Type.h" @@ -39,10 +40,10 @@ Compiler::Compiler(Options const& _options): Type::init(m_builder.getContext()); } -void Compiler::createBasicBlocks(bytes const& _bytecode) +void Compiler::createBasicBlocks(code_iterator _codeBegin, code_iterator _codeEnd) { /// Helper function that skips push data and finds next iterator (can be the end) - auto skipPushDataAndGetNext = [](bytes::const_iterator _curr, bytes::const_iterator _end) + auto skipPushDataAndGetNext = [](code_iterator _curr, code_iterator _end) { static const auto push1 = static_cast(Instruction::PUSH1); static const auto push32 = static_cast(Instruction::PUSH32); @@ -52,11 +53,11 @@ void Compiler::createBasicBlocks(bytes const& _bytecode) return _curr + offset; }; - auto begin = _bytecode.begin(); + auto begin = _codeBegin; // begin of current block bool nextJumpDest = false; - for (auto curr = begin, next = begin; curr != _bytecode.end(); curr = next) + for (auto curr = begin, next = begin; curr != _codeEnd; curr = next) { - next = skipPushDataAndGetNext(curr, _bytecode.end()); + next = skipPushDataAndGetNext(curr, _codeEnd); bool isEnd = false; switch (Instruction(*curr)) @@ -77,22 +78,19 @@ void Compiler::createBasicBlocks(bytes const& _bytecode) break; } - assert(next <= _bytecode.end()); - if (next == _bytecode.end() || Instruction(*next) == Instruction::JUMPDEST) + assert(next <= _codeEnd); + if (next == _codeEnd || Instruction(*next) == Instruction::JUMPDEST) isEnd = true; if (isEnd) { - auto beginIdx = begin - _bytecode.begin(); + auto beginIdx = begin - _codeBegin; m_basicBlocks.emplace(std::piecewise_construct, std::forward_as_tuple(beginIdx), - std::forward_as_tuple(begin, next, m_mainFunc, m_builder, nextJumpDest)); + std::forward_as_tuple(beginIdx, begin, next, m_mainFunc, m_builder, nextJumpDest)); nextJumpDest = false; begin = next; } } - - // TODO: Create Stop basic block on demand - m_stopBB = llvm::BasicBlock::Create(m_mainFunc->getContext(), "Stop", m_mainFunc); } llvm::BasicBlock* Compiler::getJumpTableBlock() @@ -125,7 +123,7 @@ llvm::BasicBlock* Compiler::getBadJumpBlock() return m_badJumpBlock->llvm(); } -std::unique_ptr Compiler::compile(bytes const& _bytecode, std::string const& _id) +std::unique_ptr Compiler::compile(code_iterator _begin, code_iterator _end, std::string const& _id) { auto compilationStartTime = std::chrono::high_resolution_clock::now(); auto module = std::unique_ptr(new llvm::Module(_id, m_builder.getContext())); @@ -135,21 +133,40 @@ std::unique_ptr Compiler::compile(bytes const& _bytecode, std::str m_mainFunc = llvm::Function::Create(mainFuncType, llvm::Function::ExternalLinkage, _id, module.get()); m_mainFunc->getArgumentList().front().setName("rt"); - // Create the basic blocks. - auto entryBlock = llvm::BasicBlock::Create(m_builder.getContext(), "entry", m_mainFunc); + // Create entry basic block + auto entryBlock = llvm::BasicBlock::Create(m_builder.getContext(), {}, m_mainFunc); m_builder.SetInsertPoint(entryBlock); - createBasicBlocks(_bytecode); + auto jmpBufWords = m_builder.CreateAlloca(Type::BytePtr, m_builder.getInt64(3), "jmpBuf.words"); + auto frameaddress = llvm::Intrinsic::getDeclaration(module.get(), llvm::Intrinsic::frameaddress); + auto fp = m_builder.CreateCall(frameaddress, m_builder.getInt32(0), "fp"); + m_builder.CreateStore(fp, jmpBufWords); + auto stacksave = llvm::Intrinsic::getDeclaration(module.get(), llvm::Intrinsic::stacksave); + auto sp = m_builder.CreateCall(stacksave, "sp"); + auto jmpBufSp = m_builder.CreateConstInBoundsGEP1_64(jmpBufWords, 2, "jmpBuf.sp"); + m_builder.CreateStore(sp, jmpBufSp); + auto setjmp = llvm::Intrinsic::getDeclaration(module.get(), llvm::Intrinsic::eh_sjlj_setjmp); + auto jmpBuf = m_builder.CreateBitCast(jmpBufWords, Type::BytePtr, "jmpBuf"); + auto r = m_builder.CreateCall(setjmp, jmpBuf); + auto normalFlow = m_builder.CreateICmpEQ(r, m_builder.getInt32(0)); + + createBasicBlocks(_begin, _end); // Init runtime structures. - RuntimeManager runtimeManager(m_builder); + RuntimeManager runtimeManager(m_builder, jmpBuf, _begin, _end); GasMeter gasMeter(m_builder, runtimeManager); Memory memory(runtimeManager, gasMeter); Ext ext(runtimeManager, memory); Stack stack(m_builder, runtimeManager); Arith256 arith(m_builder); - m_builder.CreateBr(m_basicBlocks.empty() ? m_stopBB : m_basicBlocks.begin()->second.llvm()); + // TODO: Create Stop basic block on demand + m_stopBB = llvm::BasicBlock::Create(m_mainFunc->getContext(), "Stop", m_mainFunc); + auto abortBB = llvm::BasicBlock::Create(m_mainFunc->getContext(), "Abort", m_mainFunc); + + auto firstBB = m_basicBlocks.empty() ? m_stopBB : m_basicBlocks.begin()->second.llvm(); + auto expectTrue = llvm::MDBuilder{m_builder.getContext()}.createBranchWeights(1, 0); + m_builder.CreateCondBr(normalFlow, firstBB, abortBB, expectTrue); for (auto basicBlockPairIt = m_basicBlocks.begin(); basicBlockPairIt != m_basicBlocks.end(); ++basicBlockPairIt) { @@ -157,7 +174,7 @@ std::unique_ptr Compiler::compile(bytes const& _bytecode, std::str auto iterCopy = basicBlockPairIt; ++iterCopy; auto nextBasicBlock = (iterCopy != m_basicBlocks.end()) ? iterCopy->second.llvm() : nullptr; - compileBasicBlock(basicBlock, _bytecode, runtimeManager, arith, memory, ext, gasMeter, nextBasicBlock); + compileBasicBlock(basicBlock, runtimeManager, arith, memory, ext, gasMeter, nextBasicBlock); } // Code for special blocks: @@ -165,6 +182,9 @@ std::unique_ptr Compiler::compile(bytes const& _bytecode, std::str m_builder.SetInsertPoint(m_stopBB); m_builder.CreateRet(Constant::get(ReturnCode::Stop)); + m_builder.SetInsertPoint(abortBB); + m_builder.CreateRet(Constant::get(ReturnCode::OutOfGas)); + removeDeadBlocks(); // Link jump table target index @@ -224,7 +244,7 @@ std::unique_ptr Compiler::compile(bytes const& _bytecode, std::str } -void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode, RuntimeManager& _runtimeManager, +void Compiler::compileBasicBlock(BasicBlock& _basicBlock, RuntimeManager& _runtimeManager, Arith256& _arith, Memory& _memory, Ext& _ext, GasMeter& _gasMeter, llvm::BasicBlock* _nextBasicBlock) { if (!_nextBasicBlock) // this is the last block in the code @@ -623,7 +643,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode case Instruction::PC: { - auto value = Constant::get(it - _bytecode.begin()); + auto value = Constant::get(it - _basicBlock.begin() + _basicBlock.firstInstrIdx()); stack.push(value); break; } @@ -631,7 +651,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode case Instruction::GAS: { _gasMeter.commitCostBlock(); - stack.push(_runtimeManager.getGas()); + stack.push(m_builder.CreateZExt(_runtimeManager.getGas(), Type::Word)); break; } @@ -741,10 +761,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode _memory.require(initOff, initSize); _gasMeter.commitCostBlock(); - - auto gas = _runtimeManager.getGas(); - auto address = _ext.create(gas, endowment, initOff, initSize); - _runtimeManager.setGas(gas); + auto address = _ext.create(endowment, initOff, initSize); stack.push(address); break; } @@ -752,7 +769,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode case Instruction::CALL: case Instruction::CALLCODE: { - auto gas = stack.pop(); + auto callGas256 = stack.pop(); auto codeAddress = stack.pop(); auto value = stack.pop(); auto inOff = stack.pop(); @@ -770,9 +787,13 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode if (inst == Instruction::CALLCODE) receiveAddress = _runtimeManager.get(RuntimeData::Address); - _gasMeter.count(gas); - auto ret = _ext.call(gas, receiveAddress, value, inOff, inSize, outOff, outSize, codeAddress); - _gasMeter.giveBack(gas); + auto gas = _runtimeManager.getGas(); + _gasMeter.count(callGas256); + auto callGas = m_builder.CreateTrunc(callGas256, Type::Gas); + auto gasLeft = m_builder.CreateNSWSub(gas, callGas); + _runtimeManager.setGas(callGas); + auto ret = _ext.call(receiveAddress, value, inOff, inSize, outOff, outSize, codeAddress); + _gasMeter.giveBack(gasLeft); stack.push(ret); break; } @@ -825,12 +846,9 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode break; } - default: // Invalid instruction - runtime exception - { - // TODO: Replace with return statement - _runtimeManager.raiseException(ReturnCode::BadInstruction); - } - + default: // Invalid instruction - abort + m_builder.CreateRet(Constant::get(ReturnCode::BadInstruction)); + it = _basicBlock.end() - 1; // finish block compilation } } diff --git a/evmjit/libevmjit/Compiler.h b/evmjit/libevmjit/Compiler.h index 720a48cf9..c9795fb99 100644 --- a/evmjit/libevmjit/Compiler.h +++ b/evmjit/libevmjit/Compiler.h @@ -1,8 +1,5 @@ - #pragma once -#include - #include "Common.h" #include "BasicBlock.h" @@ -33,13 +30,13 @@ public: Compiler(Options const& _options); - std::unique_ptr compile(bytes const& _bytecode, std::string const& _id); + std::unique_ptr compile(code_iterator _begin, code_iterator _end, std::string const& _id); private: - void createBasicBlocks(bytes const& _bytecode); + void createBasicBlocks(code_iterator _begin, code_iterator _end); - void compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode, class RuntimeManager& _runtimeManager, class Arith256& _arith, class Memory& _memory, class Ext& _ext, class GasMeter& _gasMeter, llvm::BasicBlock* _nextBasicBlock); + void compileBasicBlock(BasicBlock& _basicBlock, class RuntimeManager& _runtimeManager, class Arith256& _arith, class Memory& _memory, class Ext& _ext, class GasMeter& _gasMeter, llvm::BasicBlock* _nextBasicBlock); llvm::BasicBlock* getJumpTableBlock(); diff --git a/evmjit/libevmjit/CompilerHelper.cpp b/evmjit/libevmjit/CompilerHelper.cpp index 9cccecd79..5c8ee8574 100644 --- a/evmjit/libevmjit/CompilerHelper.cpp +++ b/evmjit/libevmjit/CompilerHelper.cpp @@ -1,8 +1,8 @@ - #include "CompilerHelper.h" -#include +#include "preprocessor/llvm_includes_start.h" #include +#include "preprocessor/llvm_includes_end.h" #include "RuntimeManager.h" diff --git a/evmjit/libevmjit/CompilerHelper.h b/evmjit/libevmjit/CompilerHelper.h index 62733ca72..cd6d09a58 100644 --- a/evmjit/libevmjit/CompilerHelper.h +++ b/evmjit/libevmjit/CompilerHelper.h @@ -1,7 +1,8 @@ - #pragma once +#include "preprocessor/llvm_includes_start.h" #include +#include "preprocessor/llvm_includes_end.h" namespace dev @@ -19,7 +20,7 @@ protected: CompilerHelper(llvm::IRBuilder<>& _builder); CompilerHelper(const CompilerHelper&) = delete; - void operator=(CompilerHelper) = delete; + CompilerHelper& operator=(CompilerHelper) = delete; /// Reference to the IR module being compiled llvm::Module* getModule(); diff --git a/evmjit/libevmjit/Endianness.cpp b/evmjit/libevmjit/Endianness.cpp index db7edfdc9..38f71560c 100644 --- a/evmjit/libevmjit/Endianness.cpp +++ b/evmjit/libevmjit/Endianness.cpp @@ -1,7 +1,8 @@ - #include "Endianness.h" +#include "preprocessor/llvm_includes_start.h" #include +#include "preprocessor/llvm_includes_end.h" #include "Type.h" diff --git a/evmjit/libevmjit/Endianness.h b/evmjit/libevmjit/Endianness.h index 8a1f41085..19fd8fc58 100644 --- a/evmjit/libevmjit/Endianness.h +++ b/evmjit/libevmjit/Endianness.h @@ -1,7 +1,8 @@ - #pragma once +#include "preprocessor/llvm_includes_start.h" #include +#include "preprocessor/llvm_includes_end.h" namespace dev { diff --git a/evmjit/libevmjit/ExecStats.cpp b/evmjit/libevmjit/ExecStats.cpp new file mode 100644 index 000000000..684f6d39a --- /dev/null +++ b/evmjit/libevmjit/ExecStats.cpp @@ -0,0 +1,97 @@ +#include "ExecStats.h" + +#include +#include +#include + +#include "Utils.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +void ExecStats::stateChanged(ExecState _state) +{ + if (!CHECK(m_state != ExecState::Finished)) + return; + + auto now = clock::now(); + if (_state != ExecState::Started) + { + assert(time[(int)m_state] == ExecStats::duration::zero()); + time[(int)m_state] = now - m_tp; + } + m_state = _state; + m_tp = now; +} + +namespace +{ +struct StatsAgg +{ + using unit = std::chrono::microseconds; + ExecStats::duration tot = ExecStats::duration::zero(); + ExecStats::duration min = ExecStats::duration::max(); + ExecStats::duration max = ExecStats::duration::zero(); + size_t count = 0; + + void update(ExecStats::duration _d) + { + ++count; + tot += _d; + min = _d < min ? _d : min; + max = _d > max ? _d : max; + } + + void output(char const* _name, std::ostream& _os) + { + auto avg = tot / count; + _os << std::setfill(' ') + << std::setw(12) << std::left << _name + << std::setw(10) << std::right << std::chrono::duration_cast(tot).count() + << std::setw(10) << std::right << std::chrono::duration_cast(avg).count() + << std::setw(10) << std::right << std::chrono::duration_cast(min).count() + << std::setw(10) << std::right << std::chrono::duration_cast(max).count() + << std::endl; + } +}; + +char const* getExecStateName(ExecState _state) +{ + switch (_state) + { + case ExecState::Started: return "Start"; + case ExecState::CacheLoad: return "CacheLoad"; + case ExecState::CacheWrite: return "CacheWrite"; + case ExecState::Compilation: return "Compilation"; + case ExecState::CodeGen: return "CodeGen"; + case ExecState::Execution: return "Execution"; + case ExecState::Return: return "Return"; + case ExecState::Finished: return "Finish"; + } + return nullptr; +} +} + +StatsCollector::~StatsCollector() +{ + if (stats.empty()) + return; + + std::cout << " [us] total avg min max\n"; + for (int i = 0; i < (int)ExecState::Finished; ++i) + { + StatsAgg agg; + for (auto&& s : stats) + agg.update(s->time[i]); + + agg.output(getExecStateName(ExecState(i)), std::cout); + } +} + +} +} +} diff --git a/evmjit/libevmjit/ExecStats.h b/evmjit/libevmjit/ExecStats.h new file mode 100644 index 000000000..498e21341 --- /dev/null +++ b/evmjit/libevmjit/ExecStats.h @@ -0,0 +1,43 @@ +#pragma once + +#include + +#include "ExecutionEngine.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +class ExecStats : public ExecutionEngineListener +{ +public: + using clock = std::chrono::high_resolution_clock; + using duration = clock::duration; + using time_point = clock::time_point; + + std::string id; + duration time[(int)ExecState::Finished] = {}; + + void stateChanged(ExecState _state) override; + +private: + ExecState m_state = {}; + time_point m_tp = {}; + +}; + + +class StatsCollector +{ +public: + std::vector> stats; + + ~StatsCollector(); +}; + +} +} +} diff --git a/evmjit/libevmjit/ExecutionEngine.cpp b/evmjit/libevmjit/ExecutionEngine.cpp index aae5349d8..1d2ff91b1 100644 --- a/evmjit/libevmjit/ExecutionEngine.cpp +++ b/evmjit/libevmjit/ExecutionEngine.cpp @@ -1,24 +1,25 @@ #include "ExecutionEngine.h" -#include +#include #include // env options +#include +#include "preprocessor/llvm_includes_start.h" #include #include -#pragma warning(push) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunused-parameter" #include #include -#pragma warning(pop) -#pragma GCC diagnostic pop #include #include #include +#include "preprocessor/llvm_includes_end.h" #include "Runtime.h" #include "Compiler.h" #include "Cache.h" +#include "ExecStats.h" +#include "Utils.h" +#include "BuildInfo.gen.h" namespace dev { @@ -31,34 +32,20 @@ namespace { using EntryFuncPtr = ReturnCode(*)(Runtime*); -ReturnCode runEntryFunc(EntryFuncPtr _mainFunc, Runtime* _runtime) +std::string codeHash(i256 const& _hash) { - // That function uses long jumps to handle "execeptions". - // Do not create any non-POD objects here - - ReturnCode returnCode{}; - auto sj = setjmp(_runtime->getJmpBuf()); - if (sj == 0) - returnCode = _mainFunc(_runtime); - else - returnCode = static_cast(sj); - - return returnCode; -} - -std::string codeHash(bytes const& _code) -{ - uint32_t hash = 0; - for (auto b : _code) + static const auto size = sizeof(_hash); + static const auto hexChars = "0123456789abcdef"; + std::string str; + str.resize(size * 2); + auto outIt = str.rbegin(); // reverse for BE + auto& arr = *(std::array*)&_hash; + for (auto b : arr) { - hash += b; - hash += (hash << 10); - hash ^= (hash >> 6); + *(outIt++) = hexChars[b & 0xf]; + *(outIt++) = hexChars[b >> 4]; } - hash += (hash << 3); - hash ^= (hash >> 11); - hash += (hash << 15); - return std::to_string(hash); + return str; } bool getEnvOption(char const* _name, bool _default) @@ -69,82 +56,94 @@ bool getEnvOption(char const* _name, bool _default) return std::strtol(var, nullptr, 10) != 0; } +bool showInfo() +{ + auto show = getEnvOption("EVMJIT_INFO", false); + if (show) + { + std::cout << "The Ethereum EVM JIT " EVMJIT_VERSION_FULL " LLVM " LLVM_VERSION << std::endl; + } + return show; } -ReturnCode ExecutionEngine::run(bytes const& _code, RuntimeData* _data, Env* _env) +} + +ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) { - static std::unique_ptr ee; // TODO: Use Managed Objects from LLVM? static auto debugDumpModule = getEnvOption("EVMJIT_DUMP", false); static auto objectCacheEnabled = getEnvOption("EVMJIT_CACHE", true); + static auto statsCollectingEnabled = getEnvOption("EVMJIT_STATS", false); + static auto infoShown = showInfo(); + (void) infoShown; - auto mainFuncName = codeHash(_code); - EntryFuncPtr entryFuncPtr{}; - Runtime runtime(_data, _env); // TODO: I don't know why but it must be created before getFunctionAddress() calls + std::unique_ptr listener{new ExecStats}; + listener->stateChanged(ExecState::Started); - if (ee && (entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName))) + auto objectCache = objectCacheEnabled ? Cache::getObjectCache(listener.get()) : nullptr; + + static std::unique_ptr ee; + if (!ee) { + llvm::InitializeNativeTarget(); + llvm::InitializeNativeTargetAsmPrinter(); + + auto module = std::unique_ptr(new llvm::Module({}, llvm::getGlobalContext())); + llvm::EngineBuilder builder(module.get()); + builder.setEngineKind(llvm::EngineKind::JIT); + builder.setUseMCJIT(true); + builder.setOptLevel(llvm::CodeGenOpt::None); + + auto triple = llvm::Triple(llvm::sys::getProcessTriple()); + if (triple.getOS() == llvm::Triple::OSType::Win32) + triple.setObjectFormat(llvm::Triple::ObjectFormatType::ELF); // MCJIT does not support COFF format + module->setTargetTriple(triple.str()); + + ee.reset(builder.create()); + if (!CHECK(ee)) + return ReturnCode::LLVMConfigError; + module.release(); // Successfully created llvm::ExecutionEngine takes ownership of the module + ee->setObjectCache(objectCache); } - else + + static StatsCollector statsCollector; + + auto mainFuncName = codeHash(_data->codeHash); + Runtime runtime(_data, _env); // TODO: I don't know why but it must be created before getFunctionAddress() calls + + auto entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName); + if (!entryFuncPtr) { - auto objectCache = objectCacheEnabled ? Cache::getObjectCache() : nullptr; - std::unique_ptr module; - if (objectCache) - module = Cache::getObject(mainFuncName); + auto module = objectCache ? Cache::getObject(mainFuncName) : nullptr; if (!module) - module = Compiler({}).compile(_code, mainFuncName); - if (debugDumpModule) - module->dump(); - if (!ee) - { - llvm::InitializeNativeTarget(); - llvm::InitializeNativeTargetAsmPrinter(); - - llvm::EngineBuilder builder(module.get()); - builder.setEngineKind(llvm::EngineKind::JIT); - builder.setUseMCJIT(true); - std::unique_ptr memoryManager(new llvm::SectionMemoryManager); - builder.setMCJITMemoryManager(memoryManager.get()); - builder.setOptLevel(llvm::CodeGenOpt::None); - - auto triple = llvm::Triple(llvm::sys::getProcessTriple()); - if (triple.getOS() == llvm::Triple::OSType::Win32) - triple.setObjectFormat(llvm::Triple::ObjectFormatType::ELF); // MCJIT does not support COFF format - module->setTargetTriple(triple.str()); - - ee.reset(builder.create()); - if (!ee) - return ReturnCode::LLVMConfigError; - - module.release(); // Successfully created llvm::ExecutionEngine takes ownership of the module - memoryManager.release(); // and memory manager - - if (objectCache) - ee->setObjectCache(objectCache); - entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName); - } - else { - if (!entryFuncPtr) - { - ee->addModule(module.get()); - module.release(); - entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName); - } + listener->stateChanged(ExecState::Compilation); + assert(_data->code || !_data->codeSize); //TODO: Is it good idea to execute empty code? + module = Compiler({}).compile(_data->code, _data->code + _data->codeSize, mainFuncName); } + if (debugDumpModule) + module->dump(); + + ee->addModule(module.get()); + module.release(); + listener->stateChanged(ExecState::CodeGen); + entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName); } - assert(entryFuncPtr); + if (!CHECK(entryFuncPtr)) + return ReturnCode::LLVMLinkError; - auto executionStartTime = std::chrono::high_resolution_clock::now(); + listener->stateChanged(ExecState::Execution); + auto returnCode = entryFuncPtr(&runtime); + listener->stateChanged(ExecState::Return); - auto returnCode = runEntryFunc(entryFuncPtr, &runtime); if (returnCode == ReturnCode::Return) { returnData = runtime.getReturnData(); // Save reference to return data std::swap(m_memory, runtime.getMemory()); // Take ownership of memory } + listener->stateChanged(ExecState::Finished); - auto executionEndTime = std::chrono::high_resolution_clock::now(); - clog(JIT) << " + " << std::chrono::duration_cast(executionEndTime - executionStartTime).count() << " ms\n"; + if (statsCollectingEnabled) + statsCollector.stats.push_back(std::move(listener)); return returnCode; } diff --git a/evmjit/libevmjit/ExecutionEngine.h b/evmjit/libevmjit/ExecutionEngine.h index e8d1e1c05..4c2965e58 100644 --- a/evmjit/libevmjit/ExecutionEngine.h +++ b/evmjit/libevmjit/ExecutionEngine.h @@ -1,5 +1,7 @@ #pragma once +#include + #include "RuntimeData.h" namespace dev @@ -9,14 +11,40 @@ namespace eth namespace jit { +enum class ExecState +{ + Started, + CacheLoad, + CacheWrite, + Compilation, + CodeGen, + Execution, + Return, + Finished +}; + +class ExecutionEngineListener +{ +public: + ExecutionEngineListener() = default; + ExecutionEngineListener(ExecutionEngineListener const&) = delete; + ExecutionEngineListener& operator=(ExecutionEngineListener) = delete; + virtual ~ExecutionEngineListener() {} + + virtual void executionStarted() {} + virtual void executionEnded() {} + + virtual void stateChanged(ExecState) {} +}; + class ExecutionEngine { public: ExecutionEngine() = default; ExecutionEngine(ExecutionEngine const&) = delete; - void operator=(ExecutionEngine) = delete; + ExecutionEngine& operator=(ExecutionEngine) = delete; - EXPORT ReturnCode run(bytes const& _code, RuntimeData* _data, Env* _env); + EXPORT ReturnCode run(RuntimeData* _data, Env* _env); /// Reference to returned data (RETURN opcode used) bytes_ref returnData; diff --git a/evmjit/libevmjit/Ext.cpp b/evmjit/libevmjit/Ext.cpp index a37a6fe99..38deef214 100644 --- a/evmjit/libevmjit/Ext.cpp +++ b/evmjit/libevmjit/Ext.cpp @@ -1,9 +1,8 @@ - #include "Ext.h" -#include -#include +#include "preprocessor/llvm_includes_start.h" #include +#include "preprocessor/llvm_includes_end.h" #include "RuntimeManager.h" #include "Memory.h" @@ -41,8 +40,8 @@ std::array::value> const& getEnvFuncDescs() FuncDesc{"env_sstore", getFunctionType(Type::Void, {Type::EnvPtr, Type::WordPtr, Type::WordPtr})}, FuncDesc{"env_sha3", getFunctionType(Type::Void, {Type::BytePtr, Type::Size, Type::WordPtr})}, FuncDesc{"env_balance", getFunctionType(Type::Void, {Type::EnvPtr, Type::WordPtr, Type::WordPtr})}, - FuncDesc{"env_create", getFunctionType(Type::Void, {Type::EnvPtr, Type::WordPtr, Type::WordPtr, Type::BytePtr, Type::Size, Type::WordPtr})}, - 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_create", getFunctionType(Type::Void, {Type::EnvPtr, Type::GasPtr, Type::WordPtr, Type::BytePtr, Type::Size, Type::WordPtr})}, + FuncDesc{"env_call", getFunctionType(Type::Bool, {Type::EnvPtr, Type::GasPtr, 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_extcode", getFunctionType(Type::BytePtr, {Type::EnvPtr, Type::WordPtr, Type::Size->getPointerTo()})}, @@ -60,14 +59,16 @@ llvm::Function* createFunc(EnvFunc _id, llvm::Module* _module) llvm::Value* Ext::getArgAlloca() { - auto& a = m_argAllocas[m_argCounter++]; + auto& a = m_argAllocas[m_argCounter]; if (!a) { - // FIXME: Improve order and names InsertPointGuard g{getBuilder()}; - getBuilder().SetInsertPoint(getMainFunction()->front().getFirstNonPHI()); - a = getBuilder().CreateAlloca(Type::Word, nullptr, "arg"); + auto allocaIt = getMainFunction()->front().begin(); + std::advance(allocaIt, m_argCounter); // Skip already created allocas + getBuilder().SetInsertPoint(allocaIt); + a = getBuilder().CreateAlloca(Type::Word, nullptr, {"a.", std::to_string(m_argCounter)}); } + ++m_argCounter; return a; } @@ -124,30 +125,26 @@ llvm::Value* Ext::blockhash(llvm::Value* _number) return Endianness::toNative(getBuilder(), hash); } -llvm::Value* Ext::create(llvm::Value*& _gas, llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* _initSize) +llvm::Value* Ext::create(llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* _initSize) { - auto gas = byPtr(_gas); auto ret = getArgAlloca(); auto begin = m_memoryMan.getBytePtr(_initOff); auto size = m_builder.CreateTrunc(_initSize, Type::Size, "size"); - createCall(EnvFunc::create, {getRuntimeManager().getEnvPtr(), gas, byPtr(_endowment), begin, size, ret}); - _gas = m_builder.CreateLoad(gas); // Return gas + createCall(EnvFunc::create, {getRuntimeManager().getEnvPtr(), getRuntimeManager().getGasPtr(), byPtr(_endowment), begin, size, ret}); llvm::Value* address = m_builder.CreateLoad(ret); address = Endianness::toNative(m_builder, address); return address; } -llvm::Value* Ext::call(llvm::Value*& _gas, llvm::Value* _receiveAddress, llvm::Value* _value, llvm::Value* _inOff, llvm::Value* _inSize, llvm::Value* _outOff, llvm::Value* _outSize, llvm::Value* _codeAddress) +llvm::Value* Ext::call(llvm::Value* _receiveAddress, llvm::Value* _value, llvm::Value* _inOff, llvm::Value* _inSize, llvm::Value* _outOff, llvm::Value* _outSize, llvm::Value* _codeAddress) { - auto gas = byPtr(_gas); auto receiveAddress = Endianness::toBE(m_builder, _receiveAddress); auto inBeg = m_memoryMan.getBytePtr(_inOff); auto inSize = m_builder.CreateTrunc(_inSize, Type::Size, "in.size"); auto outBeg = m_memoryMan.getBytePtr(_outOff); auto outSize = m_builder.CreateTrunc(_outSize, Type::Size, "out.size"); auto codeAddress = Endianness::toBE(m_builder, _codeAddress); - auto ret = createCall(EnvFunc::call, {getRuntimeManager().getEnvPtr(), gas, byPtr(receiveAddress), byPtr(_value), inBeg, inSize, outBeg, outSize, byPtr(codeAddress)}); - _gas = m_builder.CreateLoad(gas); // Return gas + auto ret = createCall(EnvFunc::call, {getRuntimeManager().getEnvPtr(), getRuntimeManager().getGasPtr(), byPtr(receiveAddress), byPtr(_value), inBeg, inSize, outBeg, outSize, byPtr(codeAddress)}); return m_builder.CreateZExt(ret, Type::Word, "ret"); } diff --git a/evmjit/libevmjit/Ext.h b/evmjit/libevmjit/Ext.h index 2601d32ab..1c0c0fc56 100644 --- a/evmjit/libevmjit/Ext.h +++ b/evmjit/libevmjit/Ext.h @@ -1,7 +1,7 @@ - #pragma once #include + #include "CompilerHelper.h" namespace dev @@ -50,8 +50,8 @@ public: llvm::Value* balance(llvm::Value* _address); llvm::Value* calldataload(llvm::Value* _index); - llvm::Value* create(llvm::Value*& _gas, llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* _initSize); - llvm::Value* call(llvm::Value*& _gas, llvm::Value* _receiveAddress, llvm::Value* _value, llvm::Value* _inOff, llvm::Value* _inSize, llvm::Value* _outOff, llvm::Value* _outSize, llvm::Value* _codeAddress); + llvm::Value* create(llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* _initSize); + llvm::Value* call(llvm::Value* _receiveAddress, llvm::Value* _value, llvm::Value* _inOff, llvm::Value* _inSize, llvm::Value* _outOff, llvm::Value* _outSize, llvm::Value* _codeAddress); llvm::Value* blockhash(llvm::Value* _number); llvm::Value* sha3(llvm::Value* _inOff, llvm::Value* _inSize); diff --git a/evmjit/libevmjit/GasMeter.cpp b/evmjit/libevmjit/GasMeter.cpp index 4aa6a738d..ca21714e0 100644 --- a/evmjit/libevmjit/GasMeter.cpp +++ b/evmjit/libevmjit/GasMeter.cpp @@ -1,11 +1,9 @@ - #include "GasMeter.h" -#include -#include +#include "preprocessor/llvm_includes_start.h" #include +#include "preprocessor/llvm_includes_end.h" -#include "Type.h" #include "Ext.h" #include "RuntimeManager.h" @@ -19,29 +17,29 @@ namespace jit namespace // Helper functions { -uint64_t const c_stepGas = 1; -uint64_t const c_balanceGas = 20; -uint64_t const c_sha3Gas = 10; -uint64_t const c_sha3WordGas = 10; -uint64_t const c_sloadGas = 20; -uint64_t const c_sstoreSetGas = 300; -uint64_t const c_sstoreResetGas = 100; -uint64_t const c_sstoreRefundGas = 100; -uint64_t const c_createGas = 100; -uint64_t const c_createDataGas = 5; -uint64_t const c_callGas = 20; -uint64_t const c_expGas = 1; -uint64_t const c_expByteGas = 1; -uint64_t const c_memoryGas = 1; -uint64_t const c_txDataZeroGas = 1; -uint64_t const c_txDataNonZeroGas = 5; -uint64_t const c_txGas = 500; -uint64_t const c_logGas = 32; -uint64_t const c_logDataGas = 1; -uint64_t const c_logTopicGas = 32; -uint64_t const c_copyGas = 1; - -uint64_t getStepCost(Instruction inst) +int64_t const c_stepGas = 1; +int64_t const c_balanceGas = 20; +int64_t const c_sha3Gas = 10; +int64_t const c_sha3WordGas = 10; +int64_t const c_sloadGas = 20; +int64_t const c_sstoreSetGas = 300; +int64_t const c_sstoreResetGas = 100; +int64_t const c_sstoreRefundGas = 100; +int64_t const c_createGas = 100; +int64_t const c_createDataGas = 5; +int64_t const c_callGas = 20; +int64_t const c_expGas = 1; +int64_t const c_expByteGas = 1; +int64_t const c_memoryGas = 1; +int64_t const c_txDataZeroGas = 1; +int64_t const c_txDataNonZeroGas = 5; +int64_t const c_txGas = 500; +int64_t const c_logGas = 32; +int64_t const c_logDataGas = 1; +int64_t const c_logTopicGas = 32; +int64_t const c_copyGas = 1; + +int64_t getStepCost(Instruction inst) { switch (inst) { @@ -72,7 +70,7 @@ uint64_t getStepCost(Instruction inst) case Instruction::LOG3: case Instruction::LOG4: { - auto numTopics = static_cast(inst) - static_cast(Instruction::LOG0); + auto numTopics = static_cast(inst) - static_cast(Instruction::LOG0); return c_logGas + numTopics * c_logTopicGas; } } @@ -86,7 +84,7 @@ GasMeter::GasMeter(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager) { auto module = getModule(); - llvm::Type* gasCheckArgs[] = {Type::RuntimePtr, Type::Word}; + llvm::Type* gasCheckArgs[] = {Type::RuntimePtr, Type::Gas}; m_gasCheckFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Void, gasCheckArgs, false), llvm::Function::PrivateLinkage, "gas.check", module); InsertPointGuard guard(m_builder); @@ -94,22 +92,22 @@ GasMeter::GasMeter(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager) auto outOfGasBB = llvm::BasicBlock::Create(_builder.getContext(), "OutOfGas", m_gasCheckFunc); auto updateBB = llvm::BasicBlock::Create(_builder.getContext(), "Update", m_gasCheckFunc); + auto rt = &m_gasCheckFunc->getArgumentList().front(); + rt->setName("rt"); + auto cost = rt->getNextNode(); + cost->setName("cost"); + m_builder.SetInsertPoint(checkBB); - auto arg = m_gasCheckFunc->arg_begin(); - arg->setName("rt"); - ++arg; - arg->setName("cost"); - auto cost = arg; auto gas = m_runtimeManager.getGas(); - auto isOutOfGas = m_builder.CreateICmpUGT(cost, gas, "isOutOfGas"); + gas = m_builder.CreateNSWSub(gas, cost, "gasUpdated"); + auto isOutOfGas = m_builder.CreateICmpSLT(gas, m_builder.getInt64(0), "isOutOfGas"); // gas < 0, with gas == 0 we can still do 0 cost instructions m_builder.CreateCondBr(isOutOfGas, outOfGasBB, updateBB); m_builder.SetInsertPoint(outOfGasBB); - m_runtimeManager.raiseException(ReturnCode::OutOfGas); + m_runtimeManager.abort(); m_builder.CreateUnreachable(); m_builder.SetInsertPoint(updateBB); - gas = m_builder.CreateSub(gas, cost); m_runtimeManager.setGas(gas); m_builder.CreateRetVoid(); } @@ -119,7 +117,7 @@ void GasMeter::count(Instruction _inst) if (!m_checkCall) { // Create gas check call with mocked block cost at begining of current cost-block - m_checkCall = createCall(m_gasCheckFunc, {m_runtimeManager.getRuntimePtr(), llvm::UndefValue::get(Type::Word)}); + m_checkCall = createCall(m_gasCheckFunc, {m_runtimeManager.getRuntimePtr(), llvm::UndefValue::get(Type::Gas)}); } m_blockCost += getStepCost(_inst); @@ -127,6 +125,15 @@ void GasMeter::count(Instruction _inst) void GasMeter::count(llvm::Value* _cost) { + if (_cost->getType() == Type::Word) + { + auto gasMax256 = m_builder.CreateZExt(Constant::gasMax, Type::Word); + auto tooHigh = m_builder.CreateICmpUGT(_cost, gasMax256, "costTooHigh"); + auto cost64 = m_builder.CreateTrunc(_cost, Type::Gas); + _cost = m_builder.CreateSelect(tooHigh, Constant::gasMax, cost64, "cost"); + } + + assert(_cost->getType() == Type::Gas); createCall(m_gasCheckFunc, {m_runtimeManager.getRuntimePtr(), _cost}); } @@ -136,12 +143,13 @@ void GasMeter::countExp(llvm::Value* _exponent) // lz - leading zeros // cost = ((256 - lz) + 7) / 8 - // OPT: All calculations can be done on 32/64 bits + // OPT: Can gas update be done in exp algorithm? auto ctlz = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::ctlz, Type::Word); - auto lz = m_builder.CreateCall2(ctlz, _exponent, m_builder.getInt1(false)); - auto sigBits = m_builder.CreateSub(Constant::get(256), lz); - auto sigBytes = m_builder.CreateUDiv(m_builder.CreateAdd(sigBits, Constant::get(7)), Constant::get(8)); + auto lz256 = m_builder.CreateCall2(ctlz, _exponent, m_builder.getInt1(false)); + auto lz = m_builder.CreateTrunc(lz256, Type::Gas, "lz"); + auto sigBits = m_builder.CreateSub(m_builder.getInt64(256), lz, "sigBits"); + auto sigBytes = m_builder.CreateUDiv(m_builder.CreateAdd(sigBits, m_builder.getInt64(7)), m_builder.getInt64(8)); count(sigBytes); } @@ -154,8 +162,8 @@ void GasMeter::countSStore(Ext& _ext, llvm::Value* _index, llvm::Value* _newValu auto newValueIsntZero = m_builder.CreateICmpNE(_newValue, Constant::get(0), "newValueIsntZero"); auto isInsert = m_builder.CreateAnd(oldValueIsZero, newValueIsntZero, "isInsert"); auto isDelete = m_builder.CreateAnd(oldValueIsntZero, newValueIsZero, "isDelete"); - auto cost = m_builder.CreateSelect(isInsert, Constant::get(c_sstoreSetGas), Constant::get(c_sstoreResetGas), "cost"); - cost = m_builder.CreateSelect(isDelete, Constant::get(0), cost, "cost"); + auto cost = m_builder.CreateSelect(isInsert, m_builder.getInt64(c_sstoreSetGas), m_builder.getInt64(c_sstoreResetGas), "cost"); + cost = m_builder.CreateSelect(isDelete, m_builder.getInt64(0), cost, "cost"); count(cost); } @@ -173,17 +181,16 @@ void GasMeter::countSha3Data(llvm::Value* _dataLength) assert(m_blockCost > 0); // SHA3 instruction is already counted // TODO: This round ups to 32 happens in many places - // FIXME: 64-bit arith used, but not verified static_assert(c_sha3WordGas != 1, "SHA3 data cost has changed. Update GasMeter"); - auto dataLength64 = getBuilder().CreateTrunc(_dataLength, Type::lowPrecision); - auto words64 = m_builder.CreateUDiv(m_builder.CreateAdd(dataLength64, getBuilder().getInt64(31)), getBuilder().getInt64(32)); + auto dataLength64 = getBuilder().CreateTrunc(_dataLength, Type::Gas); + auto words64 = m_builder.CreateUDiv(m_builder.CreateNUWAdd(dataLength64, getBuilder().getInt64(31)), getBuilder().getInt64(32)); auto cost64 = m_builder.CreateNUWMul(getBuilder().getInt64(c_sha3WordGas), words64); - auto cost = getBuilder().CreateZExt(cost64, Type::Word); - count(cost); + count(cost64); } void GasMeter::giveBack(llvm::Value* _gas) { + assert(_gas->getType() == Type::Gas); m_runtimeManager.setGas(m_builder.CreateAdd(m_runtimeManager.getGas(), _gas)); } @@ -199,7 +206,7 @@ void GasMeter::commitCostBlock() return; } - m_checkCall->setArgOperand(1, Constant::get(m_blockCost)); // Update block cost in gas check call + m_checkCall->setArgOperand(1, m_builder.getInt64(m_blockCost)); // Update block cost in gas check call m_checkCall = nullptr; // End cost-block m_blockCost = 0; } diff --git a/evmjit/libevmjit/GasMeter.h b/evmjit/libevmjit/GasMeter.h index 56da6eb9f..4056cd64d 100644 --- a/evmjit/libevmjit/GasMeter.h +++ b/evmjit/libevmjit/GasMeter.h @@ -1,4 +1,3 @@ - #pragma once #include "CompilerHelper.h" @@ -50,7 +49,7 @@ public: private: /// Cumulative gas cost of a block of instructions /// @TODO Handle overflow - uint64_t m_blockCost = 0; + int64_t m_blockCost = 0; llvm::CallInst* m_checkCall = nullptr; llvm::Function* m_gasCheckFunc = nullptr; diff --git a/evmjit/libevmjit/Instruction.cpp b/evmjit/libevmjit/Instruction.cpp index fdc40d043..f70b020f8 100644 --- a/evmjit/libevmjit/Instruction.cpp +++ b/evmjit/libevmjit/Instruction.cpp @@ -1,6 +1,8 @@ - #include "Instruction.h" + +#include "preprocessor/llvm_includes_start.h" #include +#include "preprocessor/llvm_includes_end.h" namespace dev { @@ -9,7 +11,7 @@ namespace eth namespace jit { -llvm::APInt readPushData(bytes::const_iterator& _curr, bytes::const_iterator _end) +llvm::APInt readPushData(code_iterator& _curr, code_iterator _end) { auto pushInst = *_curr; assert(Instruction(pushInst) >= Instruction::PUSH1 && Instruction(pushInst) <= Instruction::PUSH32); @@ -26,7 +28,7 @@ llvm::APInt readPushData(bytes::const_iterator& _curr, bytes::const_iterator _en return value; } -void skipPushData(bytes::const_iterator& _curr, bytes::const_iterator _end) +void skipPushData(code_iterator& _curr, code_iterator _end) { auto pushInst = *_curr; assert(Instruction(pushInst) >= Instruction::PUSH1 && Instruction(pushInst) <= Instruction::PUSH32); diff --git a/evmjit/libevmjit/Instruction.h b/evmjit/libevmjit/Instruction.h index 158490dee..6785213d6 100644 --- a/evmjit/libevmjit/Instruction.h +++ b/evmjit/libevmjit/Instruction.h @@ -161,11 +161,11 @@ enum class Instruction: uint8_t /// Reads PUSH data from pointed fragment of bytecode and constructs number out of it /// Reading out of bytecode means reading 0 /// @param _curr is updated and points the last real byte read -llvm::APInt readPushData(bytes::const_iterator& _curr, bytes::const_iterator _end); +llvm::APInt readPushData(code_iterator& _curr, code_iterator _end); /// Skips PUSH data in pointed fragment of bytecode. /// @param _curr is updated and points the last real byte skipped -void skipPushData(bytes::const_iterator& _curr, bytes::const_iterator _end); +void skipPushData(code_iterator& _curr, code_iterator _end); #define ANY_PUSH PUSH1: \ case Instruction::PUSH2: \ diff --git a/evmjit/libevmjit/Memory.cpp b/evmjit/libevmjit/Memory.cpp index c6f8a9ec0..647c5f26a 100644 --- a/evmjit/libevmjit/Memory.cpp +++ b/evmjit/libevmjit/Memory.cpp @@ -1,239 +1,260 @@ -#include "Memory.h" - -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "Type.h" -#include "Runtime.h" -#include "GasMeter.h" -#include "Endianness.h" -#include "RuntimeManager.h" - -namespace dev -{ -namespace eth -{ -namespace jit -{ - -Memory::Memory(RuntimeManager& _runtimeManager, GasMeter& _gasMeter): - RuntimeHelper(_runtimeManager), // TODO: RuntimeHelper not needed - m_gasMeter(_gasMeter) -{ - llvm::Type* resizeArgs[] = {Type::RuntimePtr, Type::WordPtr}; - m_resize = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, resizeArgs, false), llvm::Function::ExternalLinkage, "mem_resize", getModule()); - llvm::AttrBuilder attrBuilder; - attrBuilder.addAttribute(llvm::Attribute::NoAlias).addAttribute(llvm::Attribute::NoCapture).addAttribute(llvm::Attribute::NonNull).addAttribute(llvm::Attribute::ReadOnly); - m_resize->setAttributes(llvm::AttributeSet::get(m_resize->getContext(), 1, attrBuilder)); - - m_require = createRequireFunc(_gasMeter); - m_loadWord = createFunc(false, Type::Word, _gasMeter); - m_storeWord = createFunc(true, Type::Word, _gasMeter); - m_storeByte = createFunc(true, Type::Byte, _gasMeter); -} - -llvm::Function* Memory::createRequireFunc(GasMeter& _gasMeter) -{ - llvm::Type* argTypes[] = {Type::RuntimePtr, Type::Word, Type::Word}; - auto func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::PrivateLinkage, "mem.require", getModule()); - auto rt = func->arg_begin(); - rt->setName("rt"); - auto offset = rt->getNextNode(); - offset->setName("offset"); - auto size = offset->getNextNode(); - size->setName("size"); - - auto preBB = llvm::BasicBlock::Create(func->getContext(), "Pre", func); - auto checkBB = llvm::BasicBlock::Create(func->getContext(), "Check", func); - auto resizeBB = llvm::BasicBlock::Create(func->getContext(), "Resize", func); - auto returnBB = llvm::BasicBlock::Create(func->getContext(), "Return", func); - - InsertPointGuard guard(m_builder); // Restores insert point at function exit - - // BB "Pre": Ignore checks with size 0 - m_builder.SetInsertPoint(preBB); - auto sizeIsZero = m_builder.CreateICmpEQ(size, Constant::get(0)); - m_builder.CreateCondBr(sizeIsZero, returnBB, checkBB); - - // BB "Check" - m_builder.SetInsertPoint(checkBB); - auto uaddWO = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::uadd_with_overflow, Type::Word); - auto uaddRes = m_builder.CreateCall2(uaddWO, offset, size, "res"); - auto sizeRequired = m_builder.CreateExtractValue(uaddRes, 0, "sizeReq"); - auto overflow1 = m_builder.CreateExtractValue(uaddRes, 1, "overflow1"); - auto rtPtr = getRuntimeManager().getRuntimePtr(); - auto sizePtr = m_builder.CreateStructGEP(rtPtr, 4); - auto currSize = m_builder.CreateLoad(sizePtr, "currSize"); - auto tooSmall = m_builder.CreateICmpULE(currSize, sizeRequired, "tooSmall"); - auto resizeNeeded = m_builder.CreateOr(tooSmall, overflow1, "resizeNeeded"); - m_builder.CreateCondBr(resizeNeeded, resizeBB, returnBB); // OPT branch weights? - - // BB "Resize" - m_builder.SetInsertPoint(resizeBB); - // Check gas first - uaddRes = m_builder.CreateCall2(uaddWO, sizeRequired, Constant::get(31), "res"); - auto wordsRequired = m_builder.CreateExtractValue(uaddRes, 0); - auto overflow2 = m_builder.CreateExtractValue(uaddRes, 1, "overflow2"); - auto overflow = m_builder.CreateOr(overflow1, overflow2, "overflow"); - wordsRequired = m_builder.CreateSelect(overflow, Constant::get(-1), wordsRequired); - wordsRequired = m_builder.CreateUDiv(wordsRequired, Constant::get(32), "wordsReq"); - sizeRequired = m_builder.CreateMul(wordsRequired, Constant::get(32), "roundedSizeReq"); - auto words = m_builder.CreateUDiv(currSize, Constant::get(32), "words"); // size is always 32*k - auto newWords = m_builder.CreateSub(wordsRequired, words, "addtionalWords"); - _gasMeter.countMemory(newWords); - // Resize - m_builder.CreateStore(sizeRequired, sizePtr); - auto newData = m_builder.CreateCall2(m_resize, rt, sizePtr, "newData"); - auto dataPtr = m_builder.CreateStructGEP(rtPtr, 3); - m_builder.CreateStore(newData, dataPtr); - m_builder.CreateBr(returnBB); - - // BB "Return" - m_builder.SetInsertPoint(returnBB); - m_builder.CreateRetVoid(); - return func; -} - -llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType, GasMeter&) -{ - auto isWord = _valueType == Type::Word; - - llvm::Type* storeArgs[] = {Type::RuntimePtr, Type::Word, _valueType}; - llvm::Type* loadArgs[] = {Type::RuntimePtr, Type::Word}; - auto name = _isStore ? isWord ? "mstore" : "mstore8" : "mload"; - auto funcType = _isStore ? llvm::FunctionType::get(Type::Void, storeArgs, false) : llvm::FunctionType::get(Type::Word, loadArgs, false); - auto func = llvm::Function::Create(funcType, llvm::Function::PrivateLinkage, name, getModule()); - - InsertPointGuard guard(m_builder); // Restores insert point at function exit - - m_builder.SetInsertPoint(llvm::BasicBlock::Create(func->getContext(), {}, func)); - auto rt = func->arg_begin(); - rt->setName("rt"); - auto index = rt->getNextNode(); - index->setName("index"); - - auto valueSize = _valueType->getPrimitiveSizeInBits() / 8; - this->require(index, Constant::get(valueSize)); - auto ptr = getBytePtr(index); - if (isWord) - ptr = m_builder.CreateBitCast(ptr, Type::WordPtr, "wordPtr"); - if (_isStore) - { - llvm::Value* value = index->getNextNode(); - value->setName("value"); - if (isWord) - value = Endianness::toBE(m_builder, value); - m_builder.CreateStore(value, ptr); - m_builder.CreateRetVoid(); - } - else - { - llvm::Value* ret = m_builder.CreateLoad(ptr); - ret = Endianness::toNative(m_builder, ret); - m_builder.CreateRet(ret); - } - - return func; -} - - -llvm::Value* Memory::loadWord(llvm::Value* _addr) -{ - return createCall(m_loadWord, {getRuntimeManager().getRuntimePtr(), _addr}); -} - -void Memory::storeWord(llvm::Value* _addr, llvm::Value* _word) -{ - createCall(m_storeWord, {getRuntimeManager().getRuntimePtr(), _addr, _word}); -} - -void Memory::storeByte(llvm::Value* _addr, llvm::Value* _word) -{ - auto byte = m_builder.CreateTrunc(_word, Type::Byte, "byte"); - createCall(m_storeByte, {getRuntimeManager().getRuntimePtr(), _addr, byte}); -} - -llvm::Value* Memory::getData() -{ - auto rtPtr = getRuntimeManager().getRuntimePtr(); - auto dataPtr = m_builder.CreateStructGEP(rtPtr, 3); - return m_builder.CreateLoad(dataPtr, "data"); -} - -llvm::Value* Memory::getSize() -{ - auto rtPtr = getRuntimeManager().getRuntimePtr(); - auto sizePtr = m_builder.CreateStructGEP(rtPtr, 4); - return m_builder.CreateLoad(sizePtr, "size"); -} - -llvm::Value* Memory::getBytePtr(llvm::Value* _index) -{ - auto idx = m_builder.CreateTrunc(_index, Type::Size, "idx"); // Never allow memory index be a type bigger than i64 - return m_builder.CreateGEP(getData(), idx, "ptr"); -} - -void Memory::require(llvm::Value* _offset, llvm::Value* _size) -{ - createCall(m_require, {getRuntimeManager().getRuntimePtr(), _offset, _size}); -} - -void Memory::copyBytes(llvm::Value* _srcPtr, llvm::Value* _srcSize, llvm::Value* _srcIdx, - llvm::Value* _destMemIdx, llvm::Value* _reqBytes) -{ - require(_destMemIdx, _reqBytes); - - // Additional copy cost - // TODO: This round ups to 32 happens in many places - auto copyWords = m_builder.CreateUDiv(m_builder.CreateAdd(_reqBytes, Constant::get(31)), Constant::get(32)); - m_gasMeter.countCopy(copyWords); - - // Algorithm: - // isOutsideData = idx256 >= size256 - // idx64 = trunc idx256 - // size64 = trunc size256 - // dataLeftSize = size64 - idx64 // safe if not isOutsideData - // reqBytes64 = trunc _reqBytes // require() handles large values - // bytesToCopy0 = select(reqBytes64 > dataLeftSize, dataSizeLeft, reqBytes64) // min - // bytesToCopy = select(isOutsideData, 0, bytesToCopy0) - - auto isOutsideData = m_builder.CreateICmpUGE(_srcIdx, _srcSize); - auto idx64 = m_builder.CreateTrunc(_srcIdx, Type::lowPrecision); - auto size64 = m_builder.CreateTrunc(_srcSize, Type::lowPrecision); - auto dataLeftSize = m_builder.CreateNUWSub(size64, idx64); - auto reqBytes64 = m_builder.CreateTrunc(_reqBytes, Type::lowPrecision); - auto outOfBound = m_builder.CreateICmpUGT(reqBytes64, dataLeftSize); - auto bytesToCopyInner = m_builder.CreateSelect(outOfBound, dataLeftSize, reqBytes64); - auto zero64 = llvm::ConstantInt::get(Type::lowPrecision, 0); // TODO: Cache common constants - auto bytesToCopy = m_builder.CreateSelect(isOutsideData, zero64, bytesToCopyInner); - - auto src = m_builder.CreateGEP(_srcPtr, idx64, "src"); - auto dstIdx = m_builder.CreateTrunc(_destMemIdx, Type::Size, "dstIdx"); // Never allow memory index be a type bigger than i64 - auto dst = m_builder.CreateGEP(getData(), dstIdx, "dst"); - m_builder.CreateMemCpy(dst, src, bytesToCopy, 0); -} - -} -} -} - - -extern "C" -{ - using namespace dev::eth::jit; - - EXPORT byte* mem_resize(Runtime* _rt, i256* _size) // TODO: Use uint64 as size OR use realloc in LLVM IR - { - auto size = _size->a; // Trunc to 64-bit - auto& memory = _rt->getMemory(); - memory.resize(size); - return memory.data(); - } -} +#include "Memory.h" + +#include "preprocessor/llvm_includes_start.h" +#include +#include "preprocessor/llvm_includes_end.h" + +#include "Type.h" +#include "Runtime.h" +#include "GasMeter.h" +#include "Endianness.h" +#include "RuntimeManager.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +Memory::Memory(RuntimeManager& _runtimeManager, GasMeter& _gasMeter): + RuntimeHelper(_runtimeManager), // TODO: RuntimeHelper not needed + m_gasMeter(_gasMeter) +{} + +llvm::Function* Memory::getRequireFunc() +{ + auto& func = m_require; + if (!func) + { + llvm::Type* argTypes[] = {Type::RuntimePtr, Type::Word, Type::Word}; + func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::PrivateLinkage, "mem.require", getModule()); + auto rt = func->arg_begin(); + rt->setName("rt"); + auto offset = rt->getNextNode(); + offset->setName("offset"); + auto size = offset->getNextNode(); + size->setName("size"); + + llvm::Type* resizeArgs[] = {Type::RuntimePtr, Type::WordPtr}; + auto resize = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, resizeArgs, false), llvm::Function::ExternalLinkage, "mem_resize", getModule()); + llvm::AttrBuilder attrBuilder; + attrBuilder.addAttribute(llvm::Attribute::NoAlias).addAttribute(llvm::Attribute::NoCapture).addAttribute(llvm::Attribute::NonNull).addAttribute(llvm::Attribute::ReadOnly); + resize->setAttributes(llvm::AttributeSet::get(resize->getContext(), 1, attrBuilder)); + + auto preBB = llvm::BasicBlock::Create(func->getContext(), "Pre", func); + auto checkBB = llvm::BasicBlock::Create(func->getContext(), "Check", func); + auto resizeBB = llvm::BasicBlock::Create(func->getContext(), "Resize", func); + auto returnBB = llvm::BasicBlock::Create(func->getContext(), "Return", func); + + InsertPointGuard guard(m_builder); // Restores insert point at function exit + + // BB "Pre": Ignore checks with size 0 + m_builder.SetInsertPoint(preBB); + auto sizeIsZero = m_builder.CreateICmpEQ(size, Constant::get(0)); + m_builder.CreateCondBr(sizeIsZero, returnBB, checkBB); + + // BB "Check" + m_builder.SetInsertPoint(checkBB); + auto uaddWO = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::uadd_with_overflow, Type::Word); + auto uaddRes = m_builder.CreateCall2(uaddWO, offset, size, "res"); + auto sizeRequired = m_builder.CreateExtractValue(uaddRes, 0, "sizeReq"); + auto overflow1 = m_builder.CreateExtractValue(uaddRes, 1, "overflow1"); + auto rtPtr = getRuntimeManager().getRuntimePtr(); + auto sizePtr = m_builder.CreateStructGEP(rtPtr, 4); + auto currSize = m_builder.CreateLoad(sizePtr, "currSize"); + auto tooSmall = m_builder.CreateICmpULE(currSize, sizeRequired, "tooSmall"); + auto resizeNeeded = m_builder.CreateOr(tooSmall, overflow1, "resizeNeeded"); + m_builder.CreateCondBr(resizeNeeded, resizeBB, returnBB); // OPT branch weights? + + // BB "Resize" + m_builder.SetInsertPoint(resizeBB); + // Check gas first + uaddRes = m_builder.CreateCall2(uaddWO, sizeRequired, Constant::get(31), "res"); + auto wordsRequired = m_builder.CreateExtractValue(uaddRes, 0); + auto overflow2 = m_builder.CreateExtractValue(uaddRes, 1, "overflow2"); + auto overflow = m_builder.CreateOr(overflow1, overflow2, "overflow"); + wordsRequired = m_builder.CreateSelect(overflow, Constant::get(-1), wordsRequired); + wordsRequired = m_builder.CreateUDiv(wordsRequired, Constant::get(32), "wordsReq"); + sizeRequired = m_builder.CreateMul(wordsRequired, Constant::get(32), "roundedSizeReq"); + auto words = m_builder.CreateUDiv(currSize, Constant::get(32), "words"); // size is always 32*k + auto newWords = m_builder.CreateSub(wordsRequired, words, "addtionalWords"); + m_gasMeter.countMemory(newWords); + // Resize + m_builder.CreateStore(sizeRequired, sizePtr); + auto newData = m_builder.CreateCall2(resize, rt, sizePtr, "newData"); + auto dataPtr = m_builder.CreateStructGEP(rtPtr, 3); + m_builder.CreateStore(newData, dataPtr); + m_builder.CreateBr(returnBB); + + // BB "Return" + m_builder.SetInsertPoint(returnBB); + m_builder.CreateRetVoid(); + } + return func; +} + +llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType, GasMeter&) +{ + auto isWord = _valueType == Type::Word; + + llvm::Type* storeArgs[] = {Type::RuntimePtr, Type::Word, _valueType}; + llvm::Type* loadArgs[] = {Type::RuntimePtr, Type::Word}; + auto name = _isStore ? isWord ? "mstore" : "mstore8" : "mload"; + auto funcType = _isStore ? llvm::FunctionType::get(Type::Void, storeArgs, false) : llvm::FunctionType::get(Type::Word, loadArgs, false); + auto func = llvm::Function::Create(funcType, llvm::Function::PrivateLinkage, name, getModule()); + + InsertPointGuard guard(m_builder); // Restores insert point at function exit + + m_builder.SetInsertPoint(llvm::BasicBlock::Create(func->getContext(), {}, func)); + auto rt = func->arg_begin(); + rt->setName("rt"); + auto index = rt->getNextNode(); + index->setName("index"); + + auto valueSize = _valueType->getPrimitiveSizeInBits() / 8; + this->require(index, Constant::get(valueSize)); + auto ptr = getBytePtr(index); + if (isWord) + ptr = m_builder.CreateBitCast(ptr, Type::WordPtr, "wordPtr"); + if (_isStore) + { + llvm::Value* value = index->getNextNode(); + value->setName("value"); + if (isWord) + value = Endianness::toBE(m_builder, value); + m_builder.CreateStore(value, ptr); + m_builder.CreateRetVoid(); + } + else + { + llvm::Value* ret = m_builder.CreateLoad(ptr); + ret = Endianness::toNative(m_builder, ret); + m_builder.CreateRet(ret); + } + + return func; +} + +llvm::Function* Memory::getLoadWordFunc() +{ + auto& func = m_loadWord; + if (!func) + func = createFunc(false, Type::Word, m_gasMeter); + return func; +} + +llvm::Function* Memory::getStoreWordFunc() +{ + auto& func = m_storeWord; + if (!func) + func = createFunc(true, Type::Word, m_gasMeter); + return func; +} + +llvm::Function* Memory::getStoreByteFunc() +{ + auto& func = m_storeByte; + if (!func) + func = createFunc(true, Type::Byte, m_gasMeter); + return func; +} + + +llvm::Value* Memory::loadWord(llvm::Value* _addr) +{ + return createCall(getLoadWordFunc(), {getRuntimeManager().getRuntimePtr(), _addr}); +} + +void Memory::storeWord(llvm::Value* _addr, llvm::Value* _word) +{ + createCall(getStoreWordFunc(), {getRuntimeManager().getRuntimePtr(), _addr, _word}); +} + +void Memory::storeByte(llvm::Value* _addr, llvm::Value* _word) +{ + auto byte = m_builder.CreateTrunc(_word, Type::Byte, "byte"); + createCall(getStoreByteFunc(), {getRuntimeManager().getRuntimePtr(), _addr, byte}); +} + +llvm::Value* Memory::getData() +{ + auto rtPtr = getRuntimeManager().getRuntimePtr(); + auto dataPtr = m_builder.CreateStructGEP(rtPtr, 3); + return m_builder.CreateLoad(dataPtr, "data"); +} + +llvm::Value* Memory::getSize() +{ + auto rtPtr = getRuntimeManager().getRuntimePtr(); + auto sizePtr = m_builder.CreateStructGEP(rtPtr, 4); + return m_builder.CreateLoad(sizePtr, "size"); +} + +llvm::Value* Memory::getBytePtr(llvm::Value* _index) +{ + auto idx = m_builder.CreateTrunc(_index, Type::Size, "idx"); // Never allow memory index be a type bigger than i64 + return m_builder.CreateGEP(getData(), idx, "ptr"); +} + +void Memory::require(llvm::Value* _offset, llvm::Value* _size) +{ + if (auto constant = llvm::dyn_cast(_size)) + { + if (!constant->getValue()) + return; + } + createCall(getRequireFunc(), {getRuntimeManager().getRuntimePtr(), _offset, _size}); +} + +void Memory::copyBytes(llvm::Value* _srcPtr, llvm::Value* _srcSize, llvm::Value* _srcIdx, + llvm::Value* _destMemIdx, llvm::Value* _reqBytes) +{ + require(_destMemIdx, _reqBytes); + + // Additional copy cost + // TODO: This round ups to 32 happens in many places + auto reqBytes = m_builder.CreateTrunc(_reqBytes, Type::Gas); + auto copyWords = m_builder.CreateUDiv(m_builder.CreateNUWAdd(reqBytes, m_builder.getInt64(31)), m_builder.getInt64(32)); + m_gasMeter.countCopy(copyWords); + + // Algorithm: + // isOutsideData = idx256 >= size256 + // idx64 = trunc idx256 + // size64 = trunc size256 + // dataLeftSize = size64 - idx64 // safe if not isOutsideData + // reqBytes64 = trunc _reqBytes // require() handles large values + // bytesToCopy0 = select(reqBytes64 > dataLeftSize, dataSizeLeft, reqBytes64) // min + // bytesToCopy = select(isOutsideData, 0, bytesToCopy0) + + auto isOutsideData = m_builder.CreateICmpUGE(_srcIdx, _srcSize); + auto idx64 = m_builder.CreateTrunc(_srcIdx, Type::Size); + auto size64 = m_builder.CreateTrunc(_srcSize, Type::Size); + auto dataLeftSize = m_builder.CreateNUWSub(size64, idx64); + auto outOfBound = m_builder.CreateICmpUGT(reqBytes, dataLeftSize); + auto bytesToCopyInner = m_builder.CreateSelect(outOfBound, dataLeftSize, reqBytes); + auto bytesToCopy = m_builder.CreateSelect(isOutsideData, m_builder.getInt64(0), bytesToCopyInner); + + auto src = m_builder.CreateGEP(_srcPtr, idx64, "src"); + auto dstIdx = m_builder.CreateTrunc(_destMemIdx, Type::Size, "dstIdx"); // Never allow memory index be a type bigger than i64 + auto dst = m_builder.CreateGEP(getData(), dstIdx, "dst"); + m_builder.CreateMemCpy(dst, src, bytesToCopy, 0); +} + +} +} +} + + +extern "C" +{ + using namespace dev::eth::jit; + + EXPORT byte* mem_resize(Runtime* _rt, i256* _size) // TODO: Use uint64 as size OR use realloc in LLVM IR + { + auto size = _size->a; // Trunc to 64-bit + auto& memory = _rt->getMemory(); + memory.resize(size); + return memory.data(); + } +} diff --git a/evmjit/libevmjit/Memory.h b/evmjit/libevmjit/Memory.h index ed9c51805..e8edce735 100644 --- a/evmjit/libevmjit/Memory.h +++ b/evmjit/libevmjit/Memory.h @@ -31,13 +31,16 @@ private: GasMeter& m_gasMeter; llvm::Function* createFunc(bool _isStore, llvm::Type* _type, GasMeter& _gasMeter); - llvm::Function* createRequireFunc(GasMeter& _gasMeter); - llvm::Function* m_resize; - llvm::Function* m_require; - llvm::Function* m_loadWord; - llvm::Function* m_storeWord; - llvm::Function* m_storeByte; + llvm::Function* getRequireFunc(); + llvm::Function* getLoadWordFunc(); + llvm::Function* getStoreWordFunc(); + llvm::Function* getStoreByteFunc(); + + llvm::Function* m_require = nullptr; + llvm::Function* m_loadWord = nullptr; + llvm::Function* m_storeWord = nullptr; + llvm::Function* m_storeByte = nullptr; }; } diff --git a/evmjit/libevmjit/Runtime.cpp b/evmjit/libevmjit/Runtime.cpp index eb70e01d1..69937368c 100644 --- a/evmjit/libevmjit/Runtime.cpp +++ b/evmjit/libevmjit/Runtime.cpp @@ -1,9 +1,6 @@ - #include "Runtime.h" -#include -#include -#include +#include namespace dev { @@ -14,8 +11,7 @@ namespace jit Runtime::Runtime(RuntimeData* _data, Env* _env) : m_data(*_data), - m_env(*_env), - m_currJmpBuf(m_jmpBuf) + m_env(*_env) {} bytes_ref Runtime::getReturnData() const diff --git a/evmjit/libevmjit/Runtime.h b/evmjit/libevmjit/Runtime.h index 20cf56984..82be4a0c8 100644 --- a/evmjit/libevmjit/Runtime.h +++ b/evmjit/libevmjit/Runtime.h @@ -1,46 +1,40 @@ - -#pragma once - -#include -#include "RuntimeData.h" - -namespace dev -{ -namespace eth -{ -namespace jit -{ - -using StackImpl = std::vector; -using MemoryImpl = bytes; -using jmp_buf_ref = decltype(&std::jmp_buf{}[0]); - -class Runtime -{ -public: - Runtime(RuntimeData* _data, Env* _env); - - Runtime(const Runtime&) = delete; - Runtime& operator=(const Runtime&) = delete; - - StackImpl& getStack() { return m_stack; } - MemoryImpl& getMemory() { return m_memory; } - Env* getEnvPtr() { return &m_env; } - - bytes_ref getReturnData() const; - jmp_buf_ref getJmpBuf() { return m_jmpBuf; } - -private: - RuntimeData& m_data; ///< Pointer to data. Expected by compiled contract. - Env& m_env; ///< Pointer to environment proxy. Expected by compiled contract. - jmp_buf_ref m_currJmpBuf; ///< Pointer to jump buffer. Expected by compiled contract. - byte* m_memoryData = nullptr; - i256 m_memorySize; - std::jmp_buf m_jmpBuf; - StackImpl m_stack; - MemoryImpl m_memory; -}; - -} -} -} +#pragma once + +#include "RuntimeData.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +using StackImpl = std::vector; +using MemoryImpl = bytes; + +class Runtime +{ +public: + Runtime(RuntimeData* _data, Env* _env); + + Runtime(const Runtime&) = delete; + Runtime& operator=(const Runtime&) = delete; + + StackImpl& getStack() { return m_stack; } + MemoryImpl& getMemory() { return m_memory; } + + bytes_ref getReturnData() const; + +private: + RuntimeData& m_data; ///< Pointer to data. Expected by compiled contract. + Env& m_env; ///< Pointer to environment proxy. Expected by compiled contract. + void* m_currJmpBuf = nullptr; ///< Pointer to jump buffer. Expected by compiled contract. + byte* m_memoryData = nullptr; + i256 m_memorySize; + StackImpl m_stack; + MemoryImpl m_memory; +}; + +} +} +} diff --git a/evmjit/libevmjit/RuntimeData.h b/evmjit/libevmjit/RuntimeData.h index 58d68db8a..cc081cc58 100644 --- a/evmjit/libevmjit/RuntimeData.h +++ b/evmjit/libevmjit/RuntimeData.h @@ -1,7 +1,6 @@ #pragma once -#include "Utils.h" - +#include "Common.h" namespace dev { @@ -50,6 +49,7 @@ struct RuntimeData int64_t timestamp = 0; byte const* code = nullptr; uint64_t codeSize = 0; + i256 codeHash; }; /// VM Environment (ExtVM) opaque type diff --git a/evmjit/libevmjit/RuntimeManager.cpp b/evmjit/libevmjit/RuntimeManager.cpp index 408f2dee3..0b5762fa2 100644 --- a/evmjit/libevmjit/RuntimeManager.cpp +++ b/evmjit/libevmjit/RuntimeManager.cpp @@ -1,12 +1,8 @@ - #include "RuntimeManager.h" -#include -#include -#include - -#include "RuntimeData.h" -#include "Instruction.h" +#include "preprocessor/llvm_includes_start.h" +#include +#include "preprocessor/llvm_includes_end.h" namespace dev { @@ -87,9 +83,17 @@ llvm::Twine getName(RuntimeData::Index _index) } } -RuntimeManager::RuntimeManager(llvm::IRBuilder<>& _builder): CompilerHelper(_builder) +RuntimeManager::RuntimeManager(llvm::IRBuilder<>& _builder, llvm::Value* _jmpBuf, code_iterator _codeBegin, code_iterator _codeEnd): + CompilerHelper(_builder), + m_jmpBuf(_jmpBuf), + m_codeBegin(_codeBegin), + m_codeEnd(_codeEnd) { - m_longjmp = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::longjmp); + m_longjmp = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::eh_sjlj_longjmp); + + // save jmpBuf to be used in helper functions + auto ptr = m_builder.CreateStructGEP(getRuntimePtr(), 2); + m_builder.CreateStore(m_jmpBuf, ptr, "jmpBufExt"); // Unpack data auto rtPtr = getRuntimePtr(); @@ -161,9 +165,10 @@ void RuntimeManager::registerSuicide(llvm::Value* _balanceAddress) set(RuntimeData::SuicideDestAddress, _balanceAddress); } -void RuntimeManager::raiseException(ReturnCode _returnCode) +void RuntimeManager::abort(llvm::Value* _jmpBuf) { - m_builder.CreateCall2(m_longjmp, getJmpBuf(), Constant::get(_returnCode)); + auto longjmp = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::eh_sjlj_longjmp); + createCall(longjmp, {_jmpBuf}); } llvm::Value* RuntimeManager::get(Instruction _inst) @@ -191,14 +196,14 @@ llvm::Value* RuntimeManager::getCallData() llvm::Value* RuntimeManager::getCode() { - return get(RuntimeData::Code); + // OPT Check what is faster + //return get(RuntimeData::Code); + return m_builder.CreateGlobalStringPtr({reinterpret_cast(m_codeBegin), static_cast(m_codeEnd - m_codeBegin)}, "code"); } llvm::Value* RuntimeManager::getCodeSize() { - auto value = get(RuntimeData::CodeSize); - assert(value->getType() == Type::Size); - return getBuilder().CreateZExt(value, Type::Word); + return Constant::get(m_codeEnd - m_codeBegin); } llvm::Value* RuntimeManager::getCallDataSize() @@ -208,23 +213,28 @@ llvm::Value* RuntimeManager::getCallDataSize() return getBuilder().CreateZExt(value, Type::Word); } -llvm::Value* RuntimeManager::getJmpBuf() +llvm::Value* RuntimeManager::getJmpBufExt() { - auto ptr = getBuilder().CreateStructGEP(getRuntimePtr(), 2, "jmpbufPtr"); - return getBuilder().CreateLoad(ptr, "jmpbuf"); + auto ptr = getBuilder().CreateStructGEP(getRuntimePtr(), 2); + return getBuilder().CreateLoad(ptr, "jmpBufExt"); } llvm::Value* RuntimeManager::getGas() { - auto value = get(RuntimeData::Gas); - assert(value->getType() == Type::Size); - return getBuilder().CreateZExt(value, Type::Word); + auto gas = get(RuntimeData::Gas); + assert(gas->getType() == Type::Gas); + return gas; +} + +llvm::Value* RuntimeManager::getGasPtr() +{ + return getPtr(RuntimeData::Gas); } void RuntimeManager::setGas(llvm::Value* _gas) { - auto newGas = getBuilder().CreateTrunc(_gas, Type::Size); - set(RuntimeData::Gas, newGas); + assert(_gas->getType() == Type::Gas); + set(RuntimeData::Gas, _gas); } } diff --git a/evmjit/libevmjit/RuntimeManager.h b/evmjit/libevmjit/RuntimeManager.h index b5f3ca657..30c69ec88 100644 --- a/evmjit/libevmjit/RuntimeManager.h +++ b/evmjit/libevmjit/RuntimeManager.h @@ -15,25 +15,28 @@ namespace jit class RuntimeManager: public CompilerHelper { public: - RuntimeManager(llvm::IRBuilder<>& _builder); + RuntimeManager(llvm::IRBuilder<>& _builder, llvm::Value* _jmpBuf, code_iterator _codeBegin, code_iterator _codeEnd); llvm::Value* getRuntimePtr(); llvm::Value* getDataPtr(); - llvm::Value* getEnvPtr(); // TODO: Can we make it const? + llvm::Value* getEnvPtr(); llvm::Value* get(RuntimeData::Index _index); llvm::Value* get(Instruction _inst); - llvm::Value* getGas(); // TODO: Remove + llvm::Value* getGas(); + llvm::Value* getGasPtr(); llvm::Value* getCallData(); llvm::Value* getCode(); llvm::Value* getCodeSize(); llvm::Value* getCallDataSize(); + llvm::Value* getJmpBuf() { return m_jmpBuf; } void setGas(llvm::Value* _gas); void registerReturnData(llvm::Value* _index, llvm::Value* _size); void registerSuicide(llvm::Value* _balanceAddress); - void raiseException(ReturnCode _returnCode); + void abort(llvm::Value* _jmpBuf); + void abort() { abort(getJmpBufExt()); } static llvm::StructType* getRuntimeType(); static llvm::StructType* getRuntimeDataType(); @@ -41,11 +44,15 @@ public: private: llvm::Value* getPtr(RuntimeData::Index _index); void set(RuntimeData::Index _index, llvm::Value* _value); - llvm::Value* getJmpBuf(); + llvm::Value* getJmpBufExt(); llvm::Function* m_longjmp = nullptr; + llvm::Value* const m_jmpBuf; llvm::Value* m_dataPtr = nullptr; llvm::Value* m_envPtr = nullptr; + + code_iterator m_codeBegin = {}; + code_iterator m_codeEnd = {}; }; } diff --git a/evmjit/libevmjit/Stack.cpp b/evmjit/libevmjit/Stack.cpp index 44f1c21c1..81a954991 100644 --- a/evmjit/libevmjit/Stack.cpp +++ b/evmjit/libevmjit/Stack.cpp @@ -1,10 +1,11 @@ #include "Stack.h" -#include "RuntimeManager.h" -#include "Runtime.h" -#include "Type.h" +#include "preprocessor/llvm_includes_start.h" #include -#include +#include "preprocessor/llvm_includes_end.h" + +#include "RuntimeManager.h" +#include "Runtime.h" namespace dev { @@ -27,18 +28,87 @@ Stack::Stack(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager): llvm::Type* pushArgTypes[] = {Type::RuntimePtr, Type::WordPtr}; m_push = Function::Create(FunctionType::get(Type::Void, pushArgTypes, false), Linkage::ExternalLinkage, "stack_push", module); - llvm::Type* popArgTypes[] = {Type::RuntimePtr, Type::Size}; - m_pop = Function::Create(FunctionType::get(Type::Void, popArgTypes, false), Linkage::ExternalLinkage, "stack_pop", module); - llvm::Type* getSetArgTypes[] = {Type::RuntimePtr, Type::Size, Type::WordPtr}; - m_get = Function::Create(FunctionType::get(Type::Void, getSetArgTypes, false), Linkage::ExternalLinkage, "stack_get", module); m_set = Function::Create(FunctionType::get(Type::Void, getSetArgTypes, false), Linkage::ExternalLinkage, "stack_set", module); } +llvm::Function* Stack::getPopFunc() +{ + auto& func = m_pop; + if (!func) + { + llvm::Type* argTypes[] = {Type::RuntimePtr, Type::Size, Type::BytePtr}; + func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::ExternalLinkage, "stack.pop", getModule()); + llvm::Type* extArgTypes[] = {Type::RuntimePtr, Type::Size}; + auto extPopFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Bool, extArgTypes, false), llvm::Function::ExternalLinkage, "stack_pop", getModule()); + + auto rt = &func->getArgumentList().front(); + rt->setName("rt"); + auto index = rt->getNextNode(); + index->setName("index"); + auto jmpBuf = index->getNextNode(); + jmpBuf->setName("jmpBuf"); + + InsertPointGuard guard{m_builder}; + auto entryBB = llvm::BasicBlock::Create(m_builder.getContext(), {}, func); + auto underflowBB = llvm::BasicBlock::Create(m_builder.getContext(), "Underflow", func); + auto returnBB = llvm::BasicBlock::Create(m_builder.getContext(), "Return", func); + + m_builder.SetInsertPoint(entryBB); + auto ok = createCall(extPopFunc, {rt, index}); + m_builder.CreateCondBr(ok, returnBB, underflowBB); //TODO: Add branch weight + + m_builder.SetInsertPoint(underflowBB); + m_runtimeManager.abort(jmpBuf); + m_builder.CreateUnreachable(); + + m_builder.SetInsertPoint(returnBB); + m_builder.CreateRetVoid(); + } + return func; +} + +llvm::Function* Stack::getGetFunc() +{ + auto& func = m_get; + if (!func) + { + llvm::Type* argTypes[] = {Type::RuntimePtr, Type::Size, Type::BytePtr}; + func = llvm::Function::Create(llvm::FunctionType::get(Type::WordPtr, argTypes, false), llvm::Function::ExternalLinkage, "stack.get", getModule()); + llvm::Type* extArgTypes[] = {Type::RuntimePtr, Type::Size}; + auto extGetFunc = llvm::Function::Create(llvm::FunctionType::get(Type::WordPtr, extArgTypes, false), llvm::Function::ExternalLinkage, "stack_get", getModule()); + + auto rt = &func->getArgumentList().front(); + rt->setName("rt"); + auto index = rt->getNextNode(); + index->setName("index"); + auto jmpBuf = index->getNextNode(); + jmpBuf->setName("jmpBuf"); + + InsertPointGuard guard{m_builder}; + auto entryBB = llvm::BasicBlock::Create(m_builder.getContext(), {}, func); + auto underflowBB = llvm::BasicBlock::Create(m_builder.getContext(), "Underflow", func); + auto returnBB = llvm::BasicBlock::Create(m_builder.getContext(), "Return", func); + + m_builder.SetInsertPoint(entryBB); + auto valuePtr = createCall(extGetFunc, {rt, index}); + auto ok = m_builder.CreateICmpNE(valuePtr, llvm::ConstantPointerNull::get(Type::WordPtr)); + m_builder.CreateCondBr(ok, returnBB, underflowBB); //TODO: Add branch weight + + m_builder.SetInsertPoint(underflowBB); + m_runtimeManager.abort(jmpBuf); + m_builder.CreateUnreachable(); + + m_builder.SetInsertPoint(returnBB); + m_builder.CreateRet(valuePtr); + } + return func; +} + llvm::Value* Stack::get(size_t _index) { - m_builder.CreateCall3(m_get, m_runtimeManager.getRuntimePtr(), llvm::ConstantInt::get(Type::Size, _index, false), m_arg); - return m_builder.CreateLoad(m_arg); + auto valuePtr = createCall(getGetFunc(), {m_runtimeManager.getRuntimePtr(), m_builder.getInt64(_index), m_runtimeManager.getJmpBuf()}); + return m_builder.CreateLoad(valuePtr); } void Stack::set(size_t _index, llvm::Value* _value) @@ -49,7 +119,7 @@ void Stack::set(size_t _index, llvm::Value* _value) void Stack::pop(size_t _count) { - m_builder.CreateCall2(m_pop, m_runtimeManager.getRuntimePtr(), llvm::ConstantInt::get(Type::Size, _count, false)); + createCall(getPopFunc(), {m_runtimeManager.getRuntimePtr(), m_builder.getInt64(_count), m_runtimeManager.getJmpBuf()}); } void Stack::push(llvm::Value* _value) @@ -69,13 +139,14 @@ extern "C" { using namespace dev::eth::jit; - EXPORT void stack_pop(Runtime* _rt, uint64_t _count) + EXPORT bool stack_pop(Runtime* _rt, uint64_t _count) { auto& stack = _rt->getStack(); if (stack.size() < _count) - longjmp(_rt->getJmpBuf(), static_cast(ReturnCode::StackTooSmall)); + return false; stack.erase(stack.end() - _count, stack.end()); + return true; } EXPORT void stack_push(Runtime* _rt, i256 const* _word) @@ -87,22 +158,18 @@ extern "C" Stack::maxStackSize = stack.size(); } - EXPORT void stack_get(Runtime* _rt, uint64_t _index, i256* o_ret) + EXPORT i256* stack_get(Runtime* _rt, uint64_t _index) { auto& stack = _rt->getStack(); - // TODO: encode _index and stack size in the return code - if (stack.size() <= _index) - longjmp(_rt->getJmpBuf(), static_cast(ReturnCode::StackTooSmall)); - - *o_ret = *(stack.rbegin() + _index); + return _index < stack.size() ? &*(stack.rbegin() + _index) : nullptr; } EXPORT void stack_set(Runtime* _rt, uint64_t _index, i256 const* _word) { auto& stack = _rt->getStack(); - // TODO: encode _index and stack size in the return code - if (stack.size() <= _index) - longjmp(_rt->getJmpBuf(), static_cast(ReturnCode::StackTooSmall)); + assert(_index < stack.size()); + if (_index >= stack.size()) + return; *(stack.rbegin() + _index) = *_word; } diff --git a/evmjit/libevmjit/Stack.h b/evmjit/libevmjit/Stack.h index 3e8881e4f..4b6fa374f 100644 --- a/evmjit/libevmjit/Stack.h +++ b/evmjit/libevmjit/Stack.h @@ -2,8 +2,6 @@ #include "CompilerHelper.h" -#include - namespace dev { namespace eth @@ -25,11 +23,14 @@ public: static size_t maxStackSize; private: + llvm::Function* getPopFunc(); + llvm::Function* getGetFunc(); + RuntimeManager& m_runtimeManager; + llvm::Function* m_pop = nullptr; llvm::Function* m_push; - llvm::Function* m_pop; - llvm::Function* m_get; + llvm::Function* m_get = nullptr; llvm::Function* m_set; llvm::Value* m_arg; diff --git a/evmjit/libevmjit/Type.cpp b/evmjit/libevmjit/Type.cpp index 22ccea12e..8e2bc13fc 100644 --- a/evmjit/libevmjit/Type.cpp +++ b/evmjit/libevmjit/Type.cpp @@ -1,8 +1,4 @@ - #include "Type.h" - -#include - #include "RuntimeManager.h" namespace dev @@ -17,6 +13,8 @@ llvm::PointerType* Type::WordPtr; llvm::IntegerType* Type::lowPrecision; llvm::IntegerType* Type::Bool; llvm::IntegerType* Type::Size; +llvm::IntegerType* Type::Gas; +llvm::PointerType* Type::GasPtr; llvm::IntegerType* Type::Byte; llvm::PointerType* Type::BytePtr; llvm::Type* Type::Void; @@ -24,6 +22,7 @@ llvm::IntegerType* Type::MainReturn; llvm::PointerType* Type::EnvPtr; llvm::PointerType* Type::RuntimeDataPtr; llvm::PointerType* Type::RuntimePtr; +llvm::ConstantInt* Constant::gasMax; void Type::init(llvm::LLVMContext& _context) { @@ -35,6 +34,8 @@ void Type::init(llvm::LLVMContext& _context) // TODO: Size should be architecture-dependent Bool = llvm::Type::getInt1Ty(_context); Size = llvm::Type::getInt64Ty(_context); + Gas = Size; + GasPtr = Gas->getPointerTo(); Byte = llvm::Type::getInt8Ty(_context); BytePtr = Byte->getPointerTo(); Void = llvm::Type::getVoidTy(_context); @@ -43,6 +44,8 @@ void Type::init(llvm::LLVMContext& _context) EnvPtr = llvm::StructType::create(_context, "Env")->getPointerTo(); RuntimeDataPtr = RuntimeManager::getRuntimeDataType()->getPointerTo(); RuntimePtr = RuntimeManager::getRuntimeType()->getPointerTo(); + + Constant::gasMax = llvm::ConstantInt::getSigned(Type::Gas, std::numeric_limits::max()); } } diff --git a/evmjit/libevmjit/Type.h b/evmjit/libevmjit/Type.h index d4804ee59..b8a4a09eb 100644 --- a/evmjit/libevmjit/Type.h +++ b/evmjit/libevmjit/Type.h @@ -1,8 +1,10 @@ - #pragma once +#include "preprocessor/llvm_includes_start.h" #include -#include +#include +#include "preprocessor/llvm_includes_end.h" + #include "Common.h" namespace dev @@ -23,6 +25,8 @@ struct Type static llvm::IntegerType* Bool; static llvm::IntegerType* Size; + static llvm::IntegerType* Gas; + static llvm::PointerType* GasPtr; static llvm::IntegerType* Byte; static llvm::PointerType* BytePtr; @@ -41,6 +45,8 @@ struct Type struct Constant { + static llvm::ConstantInt* gasMax; + /// Returns word-size constant static llvm::ConstantInt* get(int64_t _n); static llvm::ConstantInt* get(llvm::APInt const& _n); diff --git a/evmjit/libevmjit/Utils.cpp b/evmjit/libevmjit/Utils.cpp index 5f7f75bfd..bf3bf93b3 100644 --- a/evmjit/libevmjit/Utils.cpp +++ b/evmjit/libevmjit/Utils.cpp @@ -1,4 +1,3 @@ - #include "Utils.h" namespace dev diff --git a/evmjit/libevmjit/Utils.h b/evmjit/libevmjit/Utils.h index 7e6133ced..aad975f5b 100644 --- a/evmjit/libevmjit/Utils.h +++ b/evmjit/libevmjit/Utils.h @@ -16,6 +16,9 @@ struct JIT: public NoteChannel { static const char* name() { return "JIT"; } }; //#define clog(CHANNEL) std::cerr #define clog(CHANNEL) std::ostream(nullptr) +// The same as assert, but expression is always evaluated and result returned +#define CHECK(expr) (assert(expr), expr) + } } } diff --git a/evmjit/libevmjit/interface.cpp b/evmjit/libevmjit/interface.cpp index 6b0992dd4..645f3d150 100644 --- a/evmjit/libevmjit/interface.cpp +++ b/evmjit/libevmjit/interface.cpp @@ -12,6 +12,7 @@ using namespace dev::eth::jit; EXPORT void* evmjit_create() noexcept { + // TODO: Make sure ExecutionEngine constructor does not throw return new(std::nothrow) ExecutionEngine; } @@ -22,14 +23,12 @@ EXPORT void evmjit_destroy(ExecutionEngine* _engine) noexcept EXPORT int evmjit_run(ExecutionEngine* _engine, RuntimeData* _data, Env* _env) noexcept { + if (!_engine || !_data) + return static_cast(ReturnCode::UnexpectedException); + try { - auto codePtr = _data->code; - auto codeSize = _data->codeSize; - bytes bytecode; - bytecode.insert(bytecode.end(), codePtr, codePtr + codeSize); - - auto returnCode = _engine->run(bytecode, _data, _env); + auto returnCode = _engine->run(_data, _env); return static_cast(returnCode); } catch(...) diff --git a/evmjit/libevmjit/preprocessor/llvm_includes_end.h b/evmjit/libevmjit/preprocessor/llvm_includes_end.h new file mode 100644 index 000000000..023c8021e --- /dev/null +++ b/evmjit/libevmjit/preprocessor/llvm_includes_end.h @@ -0,0 +1,5 @@ +#if defined(_MSC_VER) + #pragma warning(pop) +#else + #pragma GCC diagnostic pop +#endif diff --git a/evmjit/libevmjit/preprocessor/llvm_includes_start.h b/evmjit/libevmjit/preprocessor/llvm_includes_start.h new file mode 100644 index 000000000..bf34ade99 --- /dev/null +++ b/evmjit/libevmjit/preprocessor/llvm_includes_start.h @@ -0,0 +1,8 @@ +#if defined(_MSC_VER) + #pragma warning(push) + #pragma warning(disable: 4267 4244 4800) +#else + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wunused-parameter" + #pragma GCC diagnostic ignored "-Wconversion" +#endif diff --git a/exp/main.cpp b/exp/main.cpp index 80f4fa37d..23c907ed1 100644 --- a/exp/main.cpp +++ b/exp/main.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -33,11 +34,13 @@ #include #include #include +#include using namespace std; using namespace dev; using namespace dev::eth; using namespace dev::p2p; using namespace dev::shh; +namespace js = json_spirit; #if 0 int main() @@ -98,8 +101,7 @@ int main() #else int main() { - cnote << KeyPair(Secret("0000000000000000000000000000000000000000000000000000000000000000")).address(); - cnote << KeyPair(Secret("1111111111111111111111111111111111111111111111111111111111111111")).address(); + return 0; } #endif diff --git a/libdevcore/Common.cpp b/libdevcore/Common.cpp index 365f65202..431a95580 100644 --- a/libdevcore/Common.cpp +++ b/libdevcore/Common.cpp @@ -27,7 +27,7 @@ using namespace dev; namespace dev { -char const* Version = "0.8.1"; +char const* Version = "0.8.2"; } diff --git a/libdevcore/Worker.h b/libdevcore/Worker.h index f73a0f4aa..40bc118aa 100644 --- a/libdevcore/Worker.h +++ b/libdevcore/Worker.h @@ -64,7 +64,7 @@ protected: private: std::string m_name; - unsigned m_idleWaitMs; + unsigned m_idleWaitMs = 0; mutable Mutex x_work; ///< Lock for the network existance. std::unique_ptr m_work; ///< The network thread. diff --git a/libdevcore/vector_ref.h b/libdevcore/vector_ref.h index 9039c3149..42633f6f1 100644 --- a/libdevcore/vector_ref.h +++ b/libdevcore/vector_ref.h @@ -19,7 +19,7 @@ public: vector_ref(): m_data(nullptr), m_count(0) {} vector_ref(_T* _data, size_t _count): m_data(_data), m_count(_count) {} - vector_ref(typename std::conditional::value, std::string const*, std::string*>::type _data): m_data((_T*)_data->data()), m_count(_data->size() / sizeof(_T)) {} + vector_ref(typename std::conditional::value, std::string const*, std::string*>::type _data): m_data(reinterpret_cast<_T*>(_data->data())), m_count(_data->size() / sizeof(_T)) {} vector_ref(typename std::conditional::value, std::vector::type> const*, std::vector<_T>*>::type _data): m_data(_data->data()), m_count(_data->size()) {} vector_ref(typename std::conditional::value, std::string const&, std::string&>::type _data): m_data((_T*)_data.data()), m_count(_data.size() / sizeof(_T)) {} #ifdef STORAGE_LEVELDB_INCLUDE_DB_H_ @@ -29,9 +29,10 @@ public: bool contentsEqual(std::vector const& _c) const { return _c.size() == m_count && !memcmp(_c.data(), m_data, m_count); } std::vector toVector() const { return std::vector(m_data, m_data + m_count); } - std::vector toBytes() const { return std::vector((unsigned char const*)m_data, (unsigned char const*)m_data + m_count * sizeof(_T)); } + std::vector toBytes() const { return std::vector(reinterpret_cast(m_data), reinterpret_cast(m_data) + m_count * sizeof(_T)); } std::string toString() const { return std::string((char const*)m_data, ((char const*)m_data) + m_count * sizeof(_T)); } - template operator vector_ref<_T2>() const { assert(m_count * sizeof(_T) / sizeof(_T2) * sizeof(_T2) / sizeof(_T) == m_count); return vector_ref<_T2>((_T2*)m_data, m_count * sizeof(_T) / sizeof(_T2)); } + template explicit operator vector_ref<_T2>() const { assert(m_count * sizeof(_T) / sizeof(_T2) * sizeof(_T2) / sizeof(_T) == m_count); return vector_ref<_T2>(reinterpret_cast<_T2*>(m_data), m_count * sizeof(_T) / sizeof(_T2)); } + operator vector_ref<_T const>() const { return vector_ref<_T const>(m_data, m_count); } _T* data() const { return m_data; } size_t count() const { return m_count; } diff --git a/libdevcrypto/Common.cpp b/libdevcrypto/Common.cpp index 0a94662c8..048134de8 100644 --- a/libdevcrypto/Common.cpp +++ b/libdevcrypto/Common.cpp @@ -44,6 +44,8 @@ bool dev::SignatureStruct::isValid() const return true; } +Address dev::ZeroAddress = Address(); + Public dev::toPublic(Secret const& _secret) { Public p; diff --git a/libdevcrypto/Common.h b/libdevcrypto/Common.h index e91df2526..ccbd0953b 100644 --- a/libdevcrypto/Common.h +++ b/libdevcrypto/Common.h @@ -62,6 +62,9 @@ struct SignatureStruct /// @NOTE This is not endian-specific; it's just a bunch of bytes. using Address = h160; +/// The zero address. +extern Address ZeroAddress; + /// A vector of Ethereum addresses. using Addresses = h160s; diff --git a/libdevcrypto/TrieDB.h b/libdevcrypto/TrieDB.h index 3da63edf4..f5b7ff9c9 100644 --- a/libdevcrypto/TrieDB.h +++ b/libdevcrypto/TrieDB.h @@ -161,7 +161,7 @@ public: std::string at(bytesConstRef _key) const; void insert(bytesConstRef _key, bytesConstRef _value); void remove(bytesConstRef _key); - void contains(bytesConstRef _key) { return !at(_key).empty(); } + bool contains(bytesConstRef _key) { return !at(_key).empty(); } class iterator { @@ -809,7 +809,10 @@ template bytes GenericTrieDB::deleteAt(RLP const& _orig, NibbleSl // exactly our node - return null. if (k == _k && isLeaf(_orig)) + { + killNode(_orig); return RLPNull; + } // partial key is our key - move down. if (_k.contains(k)) @@ -917,7 +920,6 @@ template bytes GenericTrieDB::place(RLP const& _orig, NibbleSlice tdebug << "place " << _orig << _k; #endif - killNode(_orig); if (_orig.isEmpty()) return (RLPStream(2) << hexPrefixEncode(_k, true) << _s).out(); diff --git a/libethcore/CommonEth.cpp b/libethcore/CommonEth.cpp index e07eb04ba..2264e6ec9 100644 --- a/libethcore/CommonEth.cpp +++ b/libethcore/CommonEth.cpp @@ -32,7 +32,7 @@ namespace dev namespace eth { -const unsigned c_protocolVersion = 53; +const unsigned c_protocolVersion = 54; const unsigned c_databaseVersion = 5; vector> const& units() diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 11ab08ce6..29095076f 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -22,6 +22,7 @@ #include "BlockChain.h" #include +#include #include #include #include @@ -29,11 +30,13 @@ #include #include #include +#include "GenesisInfo.h" #include "State.h" #include "Defaults.h" using namespace std; using namespace dev; using namespace dev::eth; +namespace js = json_spirit; #define ETH_CATCH 1 diff --git a/libethereum/BlockQueue.cpp b/libethereum/BlockQueue.cpp index bb5055104..01c8c796c 100644 --- a/libethereum/BlockQueue.cpp +++ b/libethereum/BlockQueue.cpp @@ -59,7 +59,6 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc) catch (Exception const& _e) { cwarn << "Ignoring malformed block: " << diagnostic_information(_e); - return false; return ImportResult::Malformed; } #endif @@ -128,7 +127,7 @@ void BlockQueue::drain(std::vector& o_out) void BlockQueue::noteReadyWithoutWriteGuard(h256 _good) { list goodQueue(1, _good); - while (goodQueue.size()) + while (!goodQueue.empty()) { auto r = m_unknown.equal_range(goodQueue.front()); goodQueue.pop_front(); diff --git a/libethereum/CanonBlockChain.cpp b/libethereum/CanonBlockChain.cpp index fc7107154..b0fe90a78 100644 --- a/libethereum/CanonBlockChain.cpp +++ b/libethereum/CanonBlockChain.cpp @@ -21,6 +21,7 @@ #include "CanonBlockChain.h" +#include #include #include #include @@ -29,11 +30,13 @@ #include #include #include +#include "GenesisInfo.h" #include "State.h" #include "Defaults.h" using namespace std; using namespace dev; using namespace dev::eth; +namespace js = json_spirit; #define ETH_CATCH 1 @@ -42,18 +45,23 @@ std::map const& dev::eth::genesisState() static std::map s_ret; if (s_ret.empty()) { - // Initialise. - for (auto i: vector({ - "dbdbdb2cbd23b783741e8d7fcf51e459b497e4a6", - "e6716f9544a56c530d868e4bfbacb172315bdead", - "b9c015918bdaba24b4ff057a92a3873d6eb201be", - "1a26338f0d905e295fccb71fa9ea849ffa12aaf4", - "2ef47100e0787b915105fd5e3f4ff6752079d5cb", - "cd2a3d9f938e13cd947ec05abc7fe734df8dd826", - "6c386a4b26f73c802f34673f7248bb118f97424a", - "e4157b34ea9615cfbde6b4fda419828124b70c78" - })) - s_ret[Address(fromHex(i))] = Account(u256(1) << 200, Account::NormalCreation); + js::mValue val; + json_spirit::read_string(c_genesisInfo, val); + for (auto account: val.get_obj()) + { + u256 balance; + if (account.second.get_obj().count("wei")) + balance = u256(account.second.get_obj()["wei"].get_str()); + else + balance = u256(account.second.get_obj()["finney"].get_str()) * finney; + if (account.second.get_obj().count("code")) + { + s_ret[Address(fromHex(account.first))] = Account(balance, Account::ContractConception); + s_ret[Address(fromHex(account.first))].setCode(fromHex(account.second.get_obj()["code"].get_str())); + } + else + s_ret[Address(fromHex(account.first))] = Account(balance, Account::NormalCreation); + } } return s_ret; } diff --git a/libethereum/Client.h b/libethereum/Client.h index f4ab5ce76..7cd520ab6 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -127,7 +127,7 @@ template struct ABIDeserialiser {}; template struct ABIDeserialiser> { static FixedHash deserialise(bytesConstRef& io_t) { static_assert(N <= 32, "Parameter sizes must be at most 32 bytes."); FixedHash ret; io_t.cropped(32 - N, N).populate(ret.ref()); io_t = io_t.cropped(32); return ret; } }; template <> struct ABIDeserialiser { static u256 deserialise(bytesConstRef& io_t) { u256 ret = fromBigEndian(io_t.cropped(0, 32)); io_t = io_t.cropped(32); return ret; } }; template <> struct ABIDeserialiser { static u160 deserialise(bytesConstRef& io_t) { u160 ret = fromBigEndian(io_t.cropped(12, 20)); io_t = io_t.cropped(32); return ret; } }; -template <> struct ABIDeserialiser { static string32 deserialise(bytesConstRef& io_t) { string32 ret; io_t.cropped(0, 32).populate(vector_ref(ret.data(), 32)); io_t = io_t.cropped(32); return ret; } }; +template <> struct ABIDeserialiser { static string32 deserialise(bytesConstRef& io_t) { string32 ret; io_t.cropped(0, 32).populate(bytesRef((byte*)ret.data(), 32)); io_t = io_t.cropped(32); return ret; } }; template T abiOut(bytes const& _data) { diff --git a/libethereum/GenesisInfo.cpp b/libethereum/GenesisInfo.cpp new file mode 100644 index 000000000..b9b45d4b4 --- /dev/null +++ b/libethereum/GenesisInfo.cpp @@ -0,0 +1,40 @@ +/* + 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 GenesisInfo.cpp + * @author Gav Wood + * @date 2014 + */ + +#include "GenesisInfo.h" + +std::string const dev::eth::c_genesisInfo = +R"ETHEREUM( +{ + "dbdbdb2cbd23b783741e8d7fcf51e459b497e4a6": { "wei": "1606938044258990275541962092341162602522202993782792835301376" }, + "e6716f9544a56c530d868e4bfbacb172315bdead": { "wei": "1606938044258990275541962092341162602522202993782792835301376" }, + "b9c015918bdaba24b4ff057a92a3873d6eb201be": { "wei": "1606938044258990275541962092341162602522202993782792835301376" }, + "1a26338f0d905e295fccb71fa9ea849ffa12aaf4": { "wei": "1606938044258990275541962092341162602522202993782792835301376" }, + "2ef47100e0787b915105fd5e3f4ff6752079d5cb": { "wei": "1606938044258990275541962092341162602522202993782792835301376" }, + "cd2a3d9f938e13cd947ec05abc7fe734df8dd826": { "wei": "1606938044258990275541962092341162602522202993782792835301376" }, + "6c386a4b26f73c802f34673f7248bb118f97424a": { "wei": "1606938044258990275541962092341162602522202993782792835301376" }, + "e4157b34ea9615cfbde6b4fda419828124b70c78": { "wei": "1606938044258990275541962092341162602522202993782792835301376" }, + "b0afc46d9ce366d06ab4952ca27db1d9557ae9fd": { "finney": "154162184" }, + "f6b1e9dc460d4d62cc22ec5f987d726929c0f9f0": { "finney": "102774789" }, + "cc45122d8b7fa0b1eaa6b29e0fb561422a9239d0": { "finney": "51387394" }, + "b7576e9d314df41ec5506494293afb1bd5d3f65d": { "finney": "69423399" }, +} +)ETHEREUM"; diff --git a/libethereum/GenesisInfo.h b/libethereum/GenesisInfo.h new file mode 100644 index 000000000..7775da9e8 --- /dev/null +++ b/libethereum/GenesisInfo.h @@ -0,0 +1,32 @@ +/* + 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 GenesisInfo.h + * @author Gav Wood + * @date 2014 + */ + +#pragma once + +#include + +namespace dev { +namespace eth { + +extern std::string const c_genesisInfo; + +} +} diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 5b9da0cdd..76ad1f269 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -537,7 +537,7 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, bool _checkNonce) cwarn << "Hex: " << toHex(b); cwarn << TransactionReceipt(&b); } - cwarn << "Recorded: " << m_currentBlock.receiptsRoot; + cwarn << "Recorded: " << m_currentBlock.receiptsRoot; auto rs = _bc.receipts(m_currentBlock.hash); for (unsigned j = 0; j < rs.receipts.size(); ++j) { @@ -1199,11 +1199,11 @@ std::ostream& dev::eth::operator<<(std::ostream& _out, State const& _s) else if (j.second) cached.insert(j.first); } - if (delta.size()) + if (!delta.empty()) lead = (lead == " . ") ? "*.* " : "*** "; contout << " @:"; - if (delta.size()) + if (!delta.empty()) contout << "???"; else contout << r[2].toHash(); diff --git a/libevm/VM.cpp b/libevm/VM.cpp index 9274628fb..a7ca91533 100644 --- a/libevm/VM.cpp +++ b/libevm/VM.cpp @@ -34,7 +34,13 @@ void VM::reset(u256 _gas) noexcept bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _steps) { - auto memNeed = [](dev::u256 _offset, dev::u256 _size) { return _size ? (bigint)_offset + _size : (bigint)0; }; + auto memNeed = [](u256 _offset, dev::u256 _size) { return _size ? (bigint)_offset + _size : (bigint)0; }; + auto gasForMem = [](bigint _size) -> bigint + { + bigint s = _size / 32; +// return (bigint)c_memoryGas * (s + s * s / 1024); + return (bigint)c_memoryGas * s; + }; if (m_jumpDests.empty()) for (unsigned i = 0; i < _ext.code.size(); ++i) @@ -297,7 +303,7 @@ bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _steps) newTempSize = (newTempSize + 31) / 32 * 32; if (newTempSize > m_temp.size()) - runGas += c_memoryGas * (newTempSize - m_temp.size()) / 32; + runGas += gasForMem(newTempSize) - gasForMem(m_temp.size()); runGas += c_copyGas * (copySize + 31) / 32; onOperation(); @@ -529,7 +535,7 @@ bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _steps) m_stack.push_back(_ext.currentBlock.difficulty); break; case Instruction::GASLIMIT: - m_stack.push_back(1000000); + m_stack.push_back(_ext.currentBlock.gasLimit); break; case Instruction::PUSH1: case Instruction::PUSH2: diff --git a/libevm/VMFace.h b/libevm/VMFace.h index 44ae03868..f8c20feb1 100644 --- a/libevm/VMFace.h +++ b/libevm/VMFace.h @@ -40,7 +40,7 @@ public: explicit VMFace(u256 _gas): m_gas(_gas) {} virtual ~VMFace() = default; VMFace(VMFace const&) = delete; - void operator=(VMFace const&) = delete; + VMFace& operator=(VMFace const&) = delete; virtual void reset(u256 _gas = 0) noexcept { m_gas = _gas; } u256 gas() const noexcept { return m_gas; } diff --git a/libevm/VMFactory.cpp b/libevm/VMFactory.cpp index b6549ba04..40f8a3500 100644 --- a/libevm/VMFactory.cpp +++ b/libevm/VMFactory.cpp @@ -39,7 +39,7 @@ void VMFactory::setKind(VMKind _kind) std::unique_ptr VMFactory::create(u256 _gas) { #if ETH_EVMJIT - return std::unique_ptr(g_kind == VMKind::JIT ? (VMFace*)new JitVM(_gas) : new VM(_gas)); + return std::unique_ptr(g_kind == VMKind::JIT ? static_cast(new JitVM(_gas)) : static_cast(new VM(_gas))); #else asserts(g_kind == VMKind::Interpreter && "JIT disabled in build configuration"); return std::unique_ptr(new VM(_gas)); diff --git a/libevmcore/Assembly.cpp b/libevmcore/Assembly.cpp index 889865d9f..37c3ff18d 100644 --- a/libevmcore/Assembly.cpp +++ b/libevmcore/Assembly.cpp @@ -214,7 +214,7 @@ ostream& Assembly::streamRLP(ostream& _out, string const& _prefix) const BOOST_THROW_EXCEPTION(InvalidOpcode()); } - if (m_data.size() || m_subs.size()) + if (!m_data.empty() || !m_subs.empty()) { _out << _prefix << ".data:" << endl; for (auto const& i: m_data) @@ -441,7 +441,7 @@ Assembly& Assembly::optimise(bool _enable) if (i.type() == PushTag) tags.erase(i.data()); - if (tags.size()) + if (!tags.empty()) { auto t = *tags.begin(); unsigned i = t.second; @@ -567,7 +567,7 @@ bytes Assembly::assemble() const toBigEndian(tagPos[i.second], r); } - if (m_data.size()) + if (!m_data.empty()) { ret.push_back(0); for (auto const& i: m_data) diff --git a/libevmcore/Assembly.h b/libevmcore/Assembly.h index 9d9e4093c..ffe13b34d 100644 --- a/libevmcore/Assembly.h +++ b/libevmcore/Assembly.h @@ -72,6 +72,8 @@ inline std::ostream& operator<<(std::ostream& _out, AssemblyItems const& _i) { r class Assembly { public: + Assembly() {} + AssemblyItem newTag() { return AssemblyItem(Tag, m_usedTags++); } AssemblyItem newPushTag() { return AssemblyItem(PushTag, m_usedTags++); } AssemblyItem newData(bytes const& _data) { h256 h = (u256)std::hash()(asString(_data)); m_data[h] = _data; return AssemblyItem(PushData, h); } diff --git a/libjsqrc/ethereumjs/.gitignore b/libjsqrc/ethereumjs/.gitignore index 399b6dc88..c2dd6b86d 100644 --- a/libjsqrc/ethereumjs/.gitignore +++ b/libjsqrc/ethereumjs/.gitignore @@ -5,6 +5,7 @@ # git config --global core.excludesfile ~/.gitignore_global *.swp +/coverage /tmp */**/*un~ *un~ diff --git a/libjsqrc/ethereumjs/.travis.yml b/libjsqrc/ethereumjs/.travis.yml index 83b21d840..558fd1537 100644 --- a/libjsqrc/ethereumjs/.travis.yml +++ b/libjsqrc/ethereumjs/.travis.yml @@ -9,5 +9,5 @@ script: - "jshint *.js lib" after_script: - npm run-script build - - npm test + - npm run-script test-coveralls diff --git a/libjsqrc/ethereumjs/README.md b/libjsqrc/ethereumjs/README.md index 02988fe73..0a8bd092d 100644 --- a/libjsqrc/ethereumjs/README.md +++ b/libjsqrc/ethereumjs/README.md @@ -3,7 +3,7 @@ This is the Ethereum compatible [JavaScript API](https://github.com/ethereum/wiki/wiki/JavaScript-API) which implements the [Generic JSON RPC](https://github.com/ethereum/wiki/wiki/Generic-JSON-RPC) spec. It's available on npm as a node module and also for bower and component as an embeddable js -[![NPM version][npm-image]][npm-url] [![Build Status][travis-image]][travis-url] [![dependency status][dep-image]][dep-url] [![dev dependency status][dep-dev-image]][dep-dev-url] +[![NPM version][npm-image]][npm-url] [![Build Status][travis-image]][travis-url] [![dependency status][dep-image]][dep-url] [![dev dependency status][dep-dev-image]][dep-dev-url][![Coverage Status][coveralls-image]][coveralls-url] @@ -30,9 +30,9 @@ Require the library: var web3 = require('web3'); -Set a provider (QtProvider, WebSocketProvider, HttpRpcProvider) +Set a provider (QtSyncProvider, HttpSyncProvider) - var web3.setProvider(new web3.providers.WebSocketProvider('ws://localhost:40404/eth')); + web3.setProvider(new web3.providers.HttpSyncProvider()); There you go, now you can use it: @@ -93,4 +93,6 @@ ethereum -ws -loglevel=4 [dep-url]: https://david-dm.org/ethereum/ethereum.js [dep-dev-image]: https://david-dm.org/ethereum/ethereum.js/dev-status.svg [dep-dev-url]: https://david-dm.org/ethereum/ethereum.js#info=devDependencies +[coveralls-image]: https://coveralls.io/repos/ethereum/ethereum.js/badge.svg?branch=master +[coveralls-url]: https://coveralls.io/r/ethereum/ethereum.js?branch=master diff --git a/libjsqrc/ethereumjs/bower.json b/libjsqrc/ethereumjs/bower.json index 168f1b39a..b9a048718 100644 --- a/libjsqrc/ethereumjs/bower.json +++ b/libjsqrc/ethereumjs/bower.json @@ -1,7 +1,7 @@ { "name": "ethereum.js", "namespace": "ethereum", - "version": "0.0.13", + "version": "0.0.15", "description": "Ethereum Compatible JavaScript API", "main": ["./dist/ethereum.js", "./dist/ethereum.min.js"], "dependencies": { diff --git a/libjsqrc/ethereumjs/dist/ethereum.js b/libjsqrc/ethereumjs/dist/ethereum.js index 4c36a7c71..1662ddf91 100644 --- a/libjsqrc/ethereumjs/dist/ethereum.js +++ b/libjsqrc/ethereumjs/dist/ethereum.js @@ -210,7 +210,7 @@ module.exports = { }; -},{"./const":2,"./formatters":6,"./types":11,"./utils":12,"./web3":13}],2:[function(require,module,exports){ +},{"./const":2,"./formatters":8,"./types":14,"./utils":15,"./web3":17}],2:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -264,7 +264,8 @@ module.exports = { ETH_PADDING: 32, ETH_SIGNATURE_LENGTH: 4, ETH_UNITS: ETH_UNITS, - ETH_BIGNUMBER_ROUNDING_MODE: { ROUNDING_MODE: BigNumber.ROUND_DOWN } + ETH_BIGNUMBER_ROUNDING_MODE: { ROUNDING_MODE: BigNumber.ROUND_DOWN }, + ETH_POLLING_TIMEOUT: 1000 }; @@ -295,6 +296,7 @@ var web3 = require('./web3'); var abi = require('./abi'); var utils = require('./utils'); var eventImpl = require('./event'); +var filter = require('./filter'); var exportNatspecGlobals = function (vars) { // it's used byt natspec.js @@ -416,11 +418,11 @@ var addEventsToContract = function (contract, desc, address) { var signature = abi.eventSignatureFromAscii(e.name); var event = eventImpl.inputParser(address, signature, e); var o = event.apply(null, params); - o._onWatchEventResult = function (data) { + var outputFormatter = function (data) { var parser = eventImpl.outputParser(e); return parser(data); }; - return web3.eth.watch(o); + return web3.eth.watch(o, undefined, undefined, outputFormatter); }; // this property should be used by eth.filter to check if object is an event @@ -487,7 +489,131 @@ var contract = function (address, desc) { module.exports = contract; -},{"./abi":1,"./event":4,"./utils":12,"./web3":13}],4:[function(require,module,exports){ +},{"./abi":1,"./event":6,"./filter":7,"./utils":15,"./web3":17}],4:[function(require,module,exports){ +/* + This file is part of ethereum.js. + + ethereum.js is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ethereum.js 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with ethereum.js. If not, see . +*/ +/** @file db.js + * @authors: + * Marek Kotewicz + * @date 2015 + */ + +/// @returns an array of objects describing web3.db api methods +var methods = function () { + return [ + { name: 'put', call: 'db_put' }, + { name: 'get', call: 'db_get' }, + { name: 'putString', call: 'db_putString' }, + { name: 'getString', call: 'db_getString' } + ]; +}; + +module.exports = { + methods: methods +}; + +},{}],5:[function(require,module,exports){ +/* + This file is part of ethereum.js. + + ethereum.js is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ethereum.js 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with ethereum.js. If not, see . +*/ +/** @file eth.js + * @authors: + * Marek Kotewicz + * @date 2015 + */ + +/// @returns an array of objects describing web3.eth api methods +var methods = function () { + var blockCall = function (args) { + return typeof args[0] === "string" ? "eth_blockByHash" : "eth_blockByNumber"; + }; + + var transactionCall = function (args) { + return typeof args[0] === "string" ? 'eth_transactionByHash' : 'eth_transactionByNumber'; + }; + + var uncleCall = function (args) { + return typeof args[0] === "string" ? 'eth_uncleByHash' : 'eth_uncleByNumber'; + }; + + var transactionCountCall = function (args) { + return typeof args[0] === "string" ? 'eth_transactionCountByHash' : 'eth_transactionCountByNumber'; + }; + + var uncleCountCall = function (args) { + return typeof args[0] === "string" ? 'eth_uncleCountByHash' : 'eth_uncleCountByNumber'; + }; + + return [ + { name: 'balanceAt', call: 'eth_balanceAt' }, + { name: 'stateAt', call: 'eth_stateAt' }, + { name: 'storageAt', call: 'eth_storageAt' }, + { name: 'countAt', call: 'eth_countAt'}, + { name: 'codeAt', call: 'eth_codeAt' }, + { name: 'transact', call: 'eth_transact' }, + { name: 'call', call: 'eth_call' }, + { name: 'block', call: blockCall }, + { name: 'transaction', call: transactionCall }, + { name: 'uncle', call: uncleCall }, + { name: 'compilers', call: 'eth_compilers' }, + { name: 'flush', call: 'eth_flush' }, + { name: 'lll', call: 'eth_lll' }, + { name: 'solidity', call: 'eth_solidity' }, + { name: 'serpent', call: 'eth_serpent' }, + { name: 'logs', call: 'eth_logs' }, + { name: 'transactionCount', call: transactionCountCall }, + { name: 'uncleCount', call: uncleCountCall } + ]; +}; + +/// @returns an array of objects describing web3.eth api properties +var properties = function () { + return [ + { name: 'coinbase', getter: 'eth_coinbase', setter: 'eth_setCoinbase' }, + { name: 'listening', getter: 'eth_listening', setter: 'eth_setListening' }, + { name: 'mining', getter: 'eth_mining', setter: 'eth_setMining' }, + { name: 'gasPrice', getter: 'eth_gasPrice' }, + { name: 'accounts', getter: 'eth_accounts' }, + { name: 'peerCount', getter: 'eth_peerCount' }, + { name: 'defaultBlock', getter: 'eth_defaultBlock', setter: 'eth_setDefaultBlock' }, + { name: 'number', getter: 'eth_number'} + ]; +}; + +module.exports = { + methods: methods, + properties: properties +}; + + +},{}],6:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -589,6 +715,7 @@ var outputParser = function (event) { args: {} }; + output.topics = output.topic; // fallback for go-ethereum if (!output.topic) { return result; } @@ -624,7 +751,7 @@ module.exports = { }; -},{"./abi":1,"./utils":12}],5:[function(require,module,exports){ +},{"./abi":1,"./utils":15}],7:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -650,84 +777,96 @@ module.exports = { * @date 2014 */ -var web3 = require('./web3'); // jshint ignore:line - -/// should be used when we want to watch something -/// it's using inner polling mechanism and is notified about changes -/// TODO: change 'options' name cause it may be not the best matching one, since we have events -var Filter = function(options, impl) { - - if (typeof options !== "string") { - - // topics property is deprecated, warn about it! - if (options.topics) { - console.warn('"topics" is deprecated, use "topic" instead'); - } - - this._onWatchResult = options._onWatchEventResult; - - // evaluate lazy properties - options = { - to: options.to, - topic: options.topic, - earliest: options.earliest, - latest: options.latest, - max: options.max, - skip: options.skip, - address: options.address - }; - +/// Should be called to check if filter implementation is valid +/// @returns true if it is, otherwise false +var implementationIsValid = function (i) { + return !!i && + typeof i.newFilter === 'function' && + typeof i.getMessages === 'function' && + typeof i.uninstallFilter === 'function' && + typeof i.startPolling === 'function' && + typeof i.stopPolling === 'function'; +}; + +/// This method should be called on options object, to verify deprecated properties && lazy load dynamic ones +/// @param should be string or object +/// @returns options string or object +var getOptions = function (options) { + if (typeof options === 'string') { + return options; + } + + options = options || {}; + + if (options.topics) { + console.warn('"topics" is deprecated, is "topic" instead'); } - - this.impl = impl; - this.callbacks = []; - this.id = impl.newFilter(options); - web3.provider.startPolling({method: impl.changed, params: [this.id]}, this.id, this.trigger.bind(this)); + // evaluate lazy properties + return { + to: options.to, + topic: options.topic, + earliest: options.earliest, + latest: options.latest, + max: options.max, + skip: options.skip, + address: options.address + }; }; -/// alias for changed* -Filter.prototype.arrived = function(callback) { - this.changed(callback); -}; -Filter.prototype.happened = function(callback) { - this.changed(callback); -}; +/// Should be used when we want to watch something +/// it's using inner polling mechanism and is notified about changes +/// @param options are filter options +/// @param implementation, an abstract polling implementation +/// @param formatter (optional), callback function which formats output before 'real' callback +var filter = function(options, implementation, formatter) { + if (!implementationIsValid(implementation)) { + console.error('filter implemenation is invalid'); + return; + } -/// gets called when there is new eth/shh message -Filter.prototype.changed = function(callback) { - this.callbacks.push(callback); -}; + options = getOptions(options); + var callbacks = []; + var filterId = implementation.newFilter(options); + var onMessages = function (messages) { + messages.forEach(function (message) { + message = formatter ? formatter(message) : message; + callbacks.forEach(function (callback) { + callback(message); + }); + }); + }; -/// trigger calling new message from people -Filter.prototype.trigger = function(messages) { - for (var i = 0; i < this.callbacks.length; i++) { - for (var j = 0; j < messages.length; j++) { - var message = this._onWatchResult ? this._onWatchResult(messages[j]) : messages[j]; - this.callbacks[i].call(this, message); - } - } -}; + implementation.startPolling(filterId, onMessages, implementation.uninstallFilter); -/// should be called to uninstall current filter -Filter.prototype.uninstall = function() { - this.impl.uninstallFilter(this.id); - web3.provider.stopPolling(this.id); -}; + var changed = function (callback) { + callbacks.push(callback); + }; -/// should be called to manually trigger getting latest messages from the client -Filter.prototype.messages = function() { - return this.impl.getMessages(this.id); -}; + var messages = function () { + return implementation.getMessages(filterId); + }; + + var uninstall = function (callback) { + implementation.stopPolling(filterId); + implementation.uninstallFilter(filterId); + callbacks = []; + }; -/// alias for messages -Filter.prototype.logs = function () { - return this.messages(); + return { + changed: changed, + arrived: changed, + happened: changed, + messages: messages, + logs: messages, + uninstall: uninstall + }; }; -module.exports = Filter; +module.exports = filter; + -},{"./web3":13}],6:[function(require,module,exports){ +},{}],8:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -883,7 +1022,7 @@ module.exports = { }; -},{"./const":2,"./utils":12}],7:[function(require,module,exports){ +},{"./const":2,"./utils":15}],9:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -913,25 +1052,27 @@ if ("build" !== 'build') {/* var HttpSyncProvider = function (host) { this.handlers = []; - this.host = host || 'http://localhost:8080'; + this.host = host || 'http://127.0.0.1:8080'; }; HttpSyncProvider.prototype.send = function (payload) { //var data = formatJsonRpcObject(payload); - + var request = new XMLHttpRequest(); request.open('POST', this.host, false); request.send(JSON.stringify(payload)); - - // check request.status + var result = request.responseText; + // check request.status + if(request.status !== 200) + return; return JSON.parse(result); }; module.exports = HttpSyncProvider; -},{}],8:[function(require,module,exports){ +},{}],10:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -998,7 +1139,42 @@ module.exports = { -},{}],9:[function(require,module,exports){ +},{}],11:[function(require,module,exports){ +/* + This file is part of ethereum.js. + + ethereum.js is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ethereum.js 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with ethereum.js. If not, see . +*/ +/** @file qtsync.js + * @authors: + * Marek Kotewicz + * Marian Oancea + * @date 2014 + */ + +var QtSyncProvider = function () { +}; + +QtSyncProvider.prototype.send = function (payload) { + var result = navigator.qt.callMethod(JSON.stringify(payload)); + return JSON.parse(result); +}; + +module.exports = QtSyncProvider; + + +},{}],12:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -1015,7 +1191,7 @@ module.exports = { You should have received a copy of the GNU Lesser General Public License along with ethereum.js. If not, see . */ -/** @file providermanager.js +/** @file requestmanager.js * @authors: * Jeffrey Wilcke * Marek Kotewicz @@ -1024,85 +1200,86 @@ module.exports = { * @date 2014 */ -var web3 = require('./web3'); var jsonrpc = require('./jsonrpc'); - +var c = require('./const'); /** - * Provider manager object prototype * It's responsible for passing messages to providers - * If no provider is set it's responsible for queuing requests * It's also responsible for polling the ethereum node for incoming messages - * Default poll timeout is 12 seconds - * If we are running ethereum.js inside ethereum browser, there are backend based tools responsible for polling, - * and provider manager polling mechanism is not used + * Default poll timeout is 1 second */ -var ProviderManager = function() { - this.polls = []; - this.provider = undefined; +var requestManager = function() { + var polls = []; + var provider; - var self = this; - var poll = function () { - self.polls.forEach(function (data) { - var result = self.send(data.data); - - if (!(result instanceof Array) || result.length === 0) { - return; - } + var send = function (data) { + var payload = jsonrpc.toPayload(data.method, data.params); + + if (!provider) { + console.error('provider is not set'); + return null; + } - data.callback(result); - }); + var result = provider.send(payload); - setTimeout(poll, 1000); + if (!jsonrpc.isValidResponse(result)) { + console.log(result); + return null; + } + + return result.result; }; - poll(); -}; - -/// sends outgoing requests -/// @params data - an object with at least 'method' property -ProviderManager.prototype.send = function(data) { - var payload = jsonrpc.toPayload(data.method, data.params); - - if (this.provider === undefined) { - console.error('provider is not set'); - return null; - } - var result = this.provider.send(payload); + var setProvider = function (p) { + provider = p; + }; - if (!jsonrpc.isValidResponse(result)) { - console.log(result); - return null; - } + var startPolling = function (data, pollId, callback, uninstall) { + polls.push({data: data, id: pollId, callback: callback, uninstall: uninstall}); + }; - return result.result; -}; + var stopPolling = function (pollId) { + for (var i = polls.length; i--;) { + var poll = polls[i]; + if (poll.id === pollId) { + polls.splice(i, 1); + } + } + }; -/// setups provider, which will be used for sending messages -ProviderManager.prototype.set = function(provider) { - this.provider = provider; -}; + var reset = function () { + polls.forEach(function (poll) { + poll.uninstall(poll.id); + }); + polls = []; + }; -/// this method is only used, when we do not have native qt bindings and have to do polling on our own -/// should be callled, on start watching for eth/shh changes -ProviderManager.prototype.startPolling = function (data, pollId, callback) { - this.polls.push({data: data, id: pollId, callback: callback}); -}; + var poll = function () { + polls.forEach(function (data) { + var result = send(data.data); + if (!(result instanceof Array) || result.length === 0) { + return; + } + data.callback(result); + }); + setTimeout(poll, c.ETH_POLLING_TIMEOUT); + }; + + poll(); -/// should be called to stop polling for certain watch changes -ProviderManager.prototype.stopPolling = function (pollId) { - for (var i = this.polls.length; i--;) { - var poll = this.polls[i]; - if (poll.id === pollId) { - this.polls.splice(i, 1); - } - } + return { + send: send, + setProvider: setProvider, + startPolling: startPolling, + stopPolling: stopPolling, + reset: reset + }; }; -module.exports = ProviderManager; +module.exports = requestManager; -},{"./jsonrpc":8,"./web3":13}],10:[function(require,module,exports){ +},{"./const":2,"./jsonrpc":10}],13:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -1119,25 +1296,29 @@ module.exports = ProviderManager; You should have received a copy of the GNU Lesser General Public License along with ethereum.js. If not, see . */ -/** @file qtsync.js +/** @file shh.js * @authors: * Marek Kotewicz - * Marian Oancea - * @date 2014 + * @date 2015 */ -var QtSyncProvider = function () { +/// @returns an array of objects describing web3.shh api methods +var methods = function () { + return [ + { name: 'post', call: 'shh_post' }, + { name: 'newIdentity', call: 'shh_newIdentity' }, + { name: 'haveIdentity', call: 'shh_haveIdentity' }, + { name: 'newGroup', call: 'shh_newGroup' }, + { name: 'addToGroup', call: 'shh_addToGroup' } + ]; }; -QtSyncProvider.prototype.send = function (payload) { - var result = navigator.qt.callMethod(JSON.stringify(payload)); - return JSON.parse(result); +module.exports = { + methods: methods }; -module.exports = QtSyncProvider; - -},{}],11:[function(require,module,exports){ +},{}],14:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -1218,7 +1399,7 @@ module.exports = { }; -},{"./formatters":6}],12:[function(require,module,exports){ +},{"./formatters":8}],15:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -1362,7 +1543,7 @@ module.exports = { }; -},{"./const":2}],13:[function(require,module,exports){ +},{"./const":2}],16:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -1379,100 +1560,14 @@ module.exports = { You should have received a copy of the GNU Lesser General Public License along with ethereum.js. If not, see . */ -/** @file web3.js +/** @file watches.js * @authors: - * Jeffrey Wilcke * Marek Kotewicz - * Marian Oancea - * Gav Wood - * @date 2014 + * @date 2015 */ -if ("build" !== 'build') {/* - var BigNumber = require('bignumber.js'); -*/} - -var utils = require('./utils'); - -/// @returns an array of objects describing web3 api methods -var web3Methods = function () { - return [ - { name: 'sha3', call: 'web3_sha3' } - ]; -}; - -/// @returns an array of objects describing web3.eth api methods -var ethMethods = function () { - var blockCall = function (args) { - return typeof args[0] === "string" ? "eth_blockByHash" : "eth_blockByNumber"; - }; - - var transactionCall = function (args) { - return typeof args[0] === "string" ? 'eth_transactionByHash' : 'eth_transactionByNumber'; - }; - - var uncleCall = function (args) { - return typeof args[0] === "string" ? 'eth_uncleByHash' : 'eth_uncleByNumber'; - }; - - var methods = [ - { name: 'balanceAt', call: 'eth_balanceAt' }, - { name: 'stateAt', call: 'eth_stateAt' }, - { name: 'storageAt', call: 'eth_storageAt' }, - { name: 'countAt', call: 'eth_countAt'}, - { name: 'codeAt', call: 'eth_codeAt' }, - { name: 'transact', call: 'eth_transact' }, - { name: 'call', call: 'eth_call' }, - { name: 'block', call: blockCall }, - { name: 'transaction', call: transactionCall }, - { name: 'uncle', call: uncleCall }, - { name: 'compilers', call: 'eth_compilers' }, - { name: 'flush', call: 'eth_flush' }, - { name: 'lll', call: 'eth_lll' }, - { name: 'solidity', call: 'eth_solidity' }, - { name: 'serpent', call: 'eth_serpent' }, - { name: 'logs', call: 'eth_logs' } - ]; - return methods; -}; - -/// @returns an array of objects describing web3.eth api properties -var ethProperties = function () { - return [ - { name: 'coinbase', getter: 'eth_coinbase', setter: 'eth_setCoinbase' }, - { name: 'listening', getter: 'eth_listening', setter: 'eth_setListening' }, - { name: 'mining', getter: 'eth_mining', setter: 'eth_setMining' }, - { name: 'gasPrice', getter: 'eth_gasPrice' }, - { name: 'accounts', getter: 'eth_accounts' }, - { name: 'peerCount', getter: 'eth_peerCount' }, - { name: 'defaultBlock', getter: 'eth_defaultBlock', setter: 'eth_setDefaultBlock' }, - { name: 'number', getter: 'eth_number'} - ]; -}; - -/// @returns an array of objects describing web3.db api methods -var dbMethods = function () { - return [ - { name: 'put', call: 'db_put' }, - { name: 'get', call: 'db_get' }, - { name: 'putString', call: 'db_putString' }, - { name: 'getString', call: 'db_getString' } - ]; -}; - -/// @returns an array of objects describing web3.shh api methods -var shhMethods = function () { - return [ - { name: 'post', call: 'shh_post' }, - { name: 'newIdentity', call: 'shh_newIdentity' }, - { name: 'haveIdentity', call: 'shh_haveIdentity' }, - { name: 'newGroup', call: 'shh_newGroup' }, - { name: 'addToGroup', call: 'shh_addToGroup' } - ]; -}; - /// @returns an array of objects describing web3.eth.watch api methods -var ethWatchMethods = function () { +var eth = function () { var newFilter = function (args) { return typeof args[0] === 'string' ? 'eth_newFilterString' : 'eth_newFilter'; }; @@ -1485,7 +1580,7 @@ var ethWatchMethods = function () { }; /// @returns an array of objects describing web3.shh.watch api methods -var shhWatchMethods = function () { +var shh = function () { return [ { name: 'newFilter', call: 'shh_newFilter' }, { name: 'uninstallFilter', call: 'shh_uninstallFilter' }, @@ -1493,6 +1588,57 @@ var shhWatchMethods = function () { ]; }; +module.exports = { + eth: eth, + shh: shh +}; + + +},{}],17:[function(require,module,exports){ +/* + This file is part of ethereum.js. + + ethereum.js is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ethereum.js 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with ethereum.js. If not, see . +*/ +/** @file web3.js + * @authors: + * Jeffrey Wilcke + * Marek Kotewicz + * Marian Oancea + * Gav Wood + * @date 2014 + */ + +if ("build" !== 'build') {/* + var BigNumber = require('bignumber.js'); +*/} + +var eth = require('./eth'); +var db = require('./db'); +var shh = require('./shh'); +var watches = require('./watches'); +var filter = require('./filter'); +var utils = require('./utils'); +var requestManager = require('./requestmanager'); + +/// @returns an array of objects describing web3 api methods +var web3Methods = function () { + return [ + { name: 'sha3', call: 'web3_sha3' } + ]; +}; + /// creates methods in a given object based on method description on input /// setups api calls for these methods var setupMethods = function (obj, methods) { @@ -1500,7 +1646,7 @@ var setupMethods = function (obj, methods) { obj[method.name] = function () { var args = Array.prototype.slice.call(arguments); var call = typeof method.call === 'function' ? method.call(args) : method.call; - return web3.provider.send({ + return web3.manager.send({ method: call, params: args }); @@ -1514,14 +1660,14 @@ var setupProperties = function (obj, properties) { properties.forEach(function (property) { var proto = {}; proto.get = function () { - return web3.provider.send({ + return web3.manager.send({ method: property.getter }); }; if (property.setter) { proto.set = function (val) { - return web3.provider.send({ + return web3.manager.send({ method: property.setter, params: [val] }); @@ -1531,10 +1677,30 @@ var setupProperties = function (obj, properties) { }); }; +var startPolling = function (method, id, callback, uninstall) { + web3.manager.startPolling({ + method: method, + params: [id] + }, id, callback, uninstall); +}; + +var stopPolling = function (id) { + web3.manager.stopPolling(id); +}; + +var ethWatch = { + startPolling: startPolling.bind(null, 'eth_changed'), + stopPolling: stopPolling +}; + +var shhWatch = { + startPolling: startPolling.bind(null, 'shh_changed'), + stopPolling: stopPolling +}; + /// setups web3 object, and it's in-browser executed methods var web3 = { - _callbacks: {}, - _events: {}, + manager: requestManager(), providers: {}, /// @returns ascii string representation of hex value prefixed with 0x @@ -1573,11 +1739,12 @@ var web3 = { /// @param filter may be a string, object or event /// @param indexed is optional, this is an object with optional event indexed params /// @param options is optional, this is an object with optional event options ('max'...) - watch: function (filter, indexed, options) { - if (filter._isEvent) { - return filter(indexed, options); + /// TODO: fix it, 4 params? no way + watch: function (fil, indexed, options, formatter) { + if (fil._isEvent) { + return fil(indexed, options); } - return new web3.filter(filter, ethWatch); + return filter(fil, ethWatch, formatter); } }, @@ -1586,54 +1753,44 @@ var web3 = { /// shh object prototype shh: { - /// @param filter may be a string, object or event - watch: function (filter, indexed) { - return new web3.filter(filter, shhWatch); + watch: function (fil) { + return filter(fil, shhWatch); } }, + setProvider: function (provider) { + web3.manager.setProvider(provider); + }, + + /// Should be called to reset state of web3 object + /// Resets everything except manager + reset: function () { + web3.manager.reset(); + } }; /// setups all api methods setupMethods(web3, web3Methods()); -setupMethods(web3.eth, ethMethods()); -setupProperties(web3.eth, ethProperties()); -setupMethods(web3.db, dbMethods()); -setupMethods(web3.shh, shhMethods()); - -var ethWatch = { - changed: 'eth_changed' -}; - -setupMethods(ethWatch, ethWatchMethods()); - -var shhWatch = { - changed: 'shh_changed' -}; - -setupMethods(shhWatch, shhWatchMethods()); - -web3.setProvider = function(provider) { - web3.provider.set(provider); -}; +setupMethods(web3.eth, eth.methods()); +setupProperties(web3.eth, eth.properties()); +setupMethods(web3.db, db.methods()); +setupMethods(web3.shh, shh.methods()); +setupMethods(ethWatch, watches.eth()); +setupMethods(shhWatch, watches.shh()); module.exports = web3; -},{"./utils":12}],"web3":[function(require,module,exports){ +},{"./db":4,"./eth":5,"./filter":7,"./requestmanager":12,"./shh":13,"./utils":15,"./watches":16}],"web3":[function(require,module,exports){ var web3 = require('./lib/web3'); -var ProviderManager = require('./lib/providermanager'); -web3.provider = new ProviderManager(); -web3.filter = require('./lib/filter'); web3.providers.HttpSyncProvider = require('./lib/httpsync'); web3.providers.QtSyncProvider = require('./lib/qtsync'); web3.eth.contract = require('./lib/contract'); web3.abi = require('./lib/abi'); - module.exports = web3; -},{"./lib/abi":1,"./lib/contract":3,"./lib/filter":5,"./lib/httpsync":7,"./lib/providermanager":9,"./lib/qtsync":10,"./lib/web3":13}]},{},["web3"]) +},{"./lib/abi":1,"./lib/contract":3,"./lib/httpsync":9,"./lib/qtsync":11,"./lib/web3":17}]},{},["web3"]) //# sourceMappingURL=ethereum.js.map \ No newline at end of file diff --git a/libjsqrc/ethereumjs/dist/ethereum.js.map b/libjsqrc/ethereumjs/dist/ethereum.js.map index e441da86c..d9f613c6a 100644 --- a/libjsqrc/ethereumjs/dist/ethereum.js.map +++ b/libjsqrc/ethereumjs/dist/ethereum.js.map @@ -5,37 +5,45 @@ "lib/abi.js", "lib/const.js", "lib/contract.js", + "lib/db.js", + "lib/eth.js", "lib/event.js", "lib/filter.js", "lib/formatters.js", "lib/httpsync.js", "lib/jsonrpc.js", - "lib/providermanager.js", "lib/qtsync.js", + "lib/requestmanager.js", + "lib/shh.js", "lib/types.js", "lib/utils.js", + "lib/watches.js", "lib/web3.js", "index.js" ], "names": [], - "mappings": "AAAA;ACAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AClNA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACxDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACzNA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACvIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACrGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC1JA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC9CA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACjEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACtGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACjCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC/EA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC9IA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AChQA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA", + "mappings": "AAAA;ACAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AClNA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACzDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC1NA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACnCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACrFA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACxIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACjHA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC1JA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AChDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACjEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACjCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACvGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACrCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC/EA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC9IA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACjDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACzLA;AACA;AACA;AACA;AACA;AACA;AACA;AACA", "file": "generated.js", "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\nvar web3 = require('./web3'); \nvar utils = require('./utils');\nvar types = require('./types');\nvar c = require('./const');\nvar f = require('./formatters');\n\nvar displayTypeError = function (type) {\n console.error('parser does not support type: ' + type);\n};\n\n/// This method should be called if we want to check if givent type is an array type\n/// @returns true if it is, otherwise false\nvar arrayType = function (type) {\n return type.slice(-2) === '[]';\n};\n\nvar dynamicTypeBytes = function (type, value) {\n // TODO: decide what to do with array of strings\n if (arrayType(type) || type === 'string') // only string itself that is dynamic; stringX is static length.\n return f.formatInputInt(value.length); \n return \"\";\n};\n\nvar inputTypes = types.inputTypes(); \n\n/// Formats input params to bytes\n/// @param abi contract method inputs\n/// @param array of params that will be formatted to bytes\n/// @returns bytes representation of input params\nvar formatInput = function (inputs, params) {\n var bytes = \"\";\n var padding = c.ETH_PADDING * 2;\n\n /// first we iterate in search for dynamic \n inputs.forEach(function (input, index) {\n bytes += dynamicTypeBytes(input.type, params[index]);\n });\n\n inputs.forEach(function (input, i) {\n var typeMatch = false;\n for (var j = 0; j < inputTypes.length && !typeMatch; j++) {\n typeMatch = inputTypes[j].type(inputs[i].type, params[i]);\n }\n if (!typeMatch) {\n displayTypeError(inputs[i].type);\n }\n\n var formatter = inputTypes[j - 1].format;\n var toAppend = \"\";\n\n if (arrayType(inputs[i].type))\n toAppend = params[i].reduce(function (acc, curr) {\n return acc + formatter(curr);\n }, \"\");\n else\n toAppend = formatter(params[i]);\n\n bytes += toAppend; \n });\n return bytes;\n};\n\nvar dynamicBytesLength = function (type) {\n if (arrayType(type) || type === 'string') // only string itself that is dynamic; stringX is static length.\n return c.ETH_PADDING * 2;\n return 0;\n};\n\nvar outputTypes = types.outputTypes(); \n\n/// Formats output bytes back to param list\n/// @param contract abi method outputs\n/// @param bytes representtion of output \n/// @returns array of output params \nvar formatOutput = function (outs, output) {\n \n output = output.slice(2);\n var result = [];\n var padding = c.ETH_PADDING * 2;\n\n var dynamicPartLength = outs.reduce(function (acc, curr) {\n return acc + dynamicBytesLength(curr.type);\n }, 0);\n \n var dynamicPart = output.slice(0, dynamicPartLength);\n output = output.slice(dynamicPartLength);\n\n outs.forEach(function (out, i) {\n var typeMatch = false;\n for (var j = 0; j < outputTypes.length && !typeMatch; j++) {\n typeMatch = outputTypes[j].type(outs[i].type);\n }\n\n if (!typeMatch) {\n displayTypeError(outs[i].type);\n }\n\n var formatter = outputTypes[j - 1].format;\n if (arrayType(outs[i].type)) {\n var size = f.formatOutputUInt(dynamicPart.slice(0, padding));\n dynamicPart = dynamicPart.slice(padding);\n var array = [];\n for (var k = 0; k < size; k++) {\n array.push(formatter(output.slice(0, padding))); \n output = output.slice(padding);\n }\n result.push(array);\n }\n else if (types.prefixedType('string')(outs[i].type)) {\n dynamicPart = dynamicPart.slice(padding); \n result.push(formatter(output.slice(0, padding)));\n output = output.slice(padding);\n } else {\n result.push(formatter(output.slice(0, padding)));\n output = output.slice(padding);\n }\n });\n\n return result;\n};\n\n/// @param json abi for contract\n/// @returns input parser object for given json abi\n/// TODO: refactor creating the parser, do not double logic from contract\nvar inputParser = function (json) {\n var parser = {};\n json.forEach(function (method) {\n var displayName = utils.extractDisplayName(method.name); \n var typeName = utils.extractTypeName(method.name);\n\n var impl = function () {\n var params = Array.prototype.slice.call(arguments);\n return formatInput(method.inputs, params);\n };\n \n if (parser[displayName] === undefined) {\n parser[displayName] = impl;\n }\n\n parser[displayName][typeName] = impl;\n });\n\n return parser;\n};\n\n/// @param json abi for contract\n/// @returns output parser for given json abi\nvar outputParser = function (json) {\n var parser = {};\n json.forEach(function (method) {\n\n var displayName = utils.extractDisplayName(method.name); \n var typeName = utils.extractTypeName(method.name);\n\n var impl = function (output) {\n return formatOutput(method.outputs, output);\n };\n\n if (parser[displayName] === undefined) {\n parser[displayName] = impl;\n }\n\n parser[displayName][typeName] = impl;\n });\n\n return parser;\n};\n\n/// @param function/event name for which we want to get signature\n/// @returns signature of function/event with given name\nvar signatureFromAscii = function (name) {\n return web3.sha3(web3.fromAscii(name)).slice(0, 2 + c.ETH_SIGNATURE_LENGTH * 2);\n};\n\nvar eventSignatureFromAscii = function (name) {\n return web3.sha3(web3.fromAscii(name));\n};\n\nmodule.exports = {\n inputParser: inputParser,\n outputParser: outputParser,\n formatInput: formatInput,\n formatOutput: formatOutput,\n signatureFromAscii: signatureFromAscii,\n eventSignatureFromAscii: eventSignatureFromAscii\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 const.js\n * @authors:\n * Marek Kotewicz \n * @date 2015\n */\n\n/// required to define ETH_BIGNUMBER_ROUNDING_MODE\nif (\"build\" !== 'build') {/*\n var BigNumber = require('bignumber.js'); // jshint ignore:line\n*/}\n\nvar ETH_UNITS = [ \n 'wei', \n 'Kwei', \n 'Mwei', \n 'Gwei', \n 'szabo', \n 'finney', \n 'ether', \n 'grand', \n 'Mether', \n 'Gether', \n 'Tether', \n 'Pether', \n 'Eether', \n 'Zether', \n 'Yether', \n 'Nether', \n 'Dether', \n 'Vether', \n 'Uether' \n];\n\nmodule.exports = {\n ETH_PADDING: 32,\n ETH_SIGNATURE_LENGTH: 4,\n ETH_UNITS: ETH_UNITS,\n ETH_BIGNUMBER_ROUNDING_MODE: { ROUNDING_MODE: BigNumber.ROUND_DOWN }\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 contract.js\n * @authors:\n * Marek Kotewicz \n * @date 2014\n */\n\nvar web3 = require('./web3'); \nvar abi = require('./abi');\nvar utils = require('./utils');\nvar eventImpl = require('./event');\n\nvar exportNatspecGlobals = function (vars) {\n // it's used byt natspec.js\n // TODO: figure out better way to solve this\n web3._currentContractAbi = vars.abi;\n web3._currentContractAddress = vars.address;\n web3._currentContractMethodName = vars.method;\n web3._currentContractMethodParams = vars.params;\n};\n\nvar addFunctionRelatedPropertiesToContract = function (contract) {\n \n contract.call = function (options) {\n contract._isTransact = false;\n contract._options = options;\n return contract;\n };\n\n contract.transact = function (options) {\n contract._isTransact = true;\n contract._options = options;\n return contract;\n };\n\n contract._options = {};\n ['gas', 'gasPrice', 'value', 'from'].forEach(function(p) {\n contract[p] = function (v) {\n contract._options[p] = v;\n return contract;\n };\n });\n\n};\n\nvar addFunctionsToContract = function (contract, desc, address) {\n var inputParser = abi.inputParser(desc);\n var outputParser = abi.outputParser(desc);\n\n // create contract functions\n utils.filterFunctions(desc).forEach(function (method) {\n\n var displayName = utils.extractDisplayName(method.name);\n var typeName = utils.extractTypeName(method.name);\n\n var impl = function () {\n var params = Array.prototype.slice.call(arguments);\n var signature = abi.signatureFromAscii(method.name);\n var parsed = inputParser[displayName][typeName].apply(null, params);\n\n var options = contract._options || {};\n options.to = address;\n options.data = signature + parsed;\n \n var isTransact = contract._isTransact === true || (contract._isTransact !== false && !method.constant);\n var collapse = options.collapse !== false;\n \n // reset\n contract._options = {};\n contract._isTransact = null;\n\n if (isTransact) {\n \n exportNatspecGlobals({\n abi: desc,\n address: address,\n method: method.name,\n params: params\n });\n\n // transactions do not have any output, cause we do not know, when they will be processed\n web3.eth.transact(options);\n return;\n }\n \n var output = web3.eth.call(options);\n var ret = outputParser[displayName][typeName](output);\n if (collapse)\n {\n if (ret.length === 1)\n ret = ret[0];\n else if (ret.length === 0)\n ret = null;\n }\n return ret;\n };\n\n if (contract[displayName] === undefined) {\n contract[displayName] = impl;\n }\n\n contract[displayName][typeName] = impl;\n });\n};\n\nvar addEventRelatedPropertiesToContract = function (contract, desc, address) {\n contract.address = address;\n contract._onWatchEventResult = function (data) {\n var matchingEvent = event.getMatchingEvent(utils.filterEvents(desc));\n var parser = eventImpl.outputParser(matchingEvent);\n return parser(data);\n };\n \n Object.defineProperty(contract, 'topic', {\n get: function() {\n return utils.filterEvents(desc).map(function (e) {\n return abi.eventSignatureFromAscii(e.name);\n });\n }\n });\n\n};\n\nvar addEventsToContract = function (contract, desc, address) {\n // create contract events\n utils.filterEvents(desc).forEach(function (e) {\n\n var impl = function () {\n var params = Array.prototype.slice.call(arguments);\n var signature = abi.eventSignatureFromAscii(e.name);\n var event = eventImpl.inputParser(address, signature, e);\n var o = event.apply(null, params);\n o._onWatchEventResult = function (data) {\n var parser = eventImpl.outputParser(e);\n return parser(data);\n };\n return web3.eth.watch(o); \n };\n \n // this property should be used by eth.filter to check if object is an event\n impl._isEvent = true;\n\n var displayName = utils.extractDisplayName(e.name);\n var typeName = utils.extractTypeName(e.name);\n\n if (contract[displayName] === undefined) {\n contract[displayName] = impl;\n }\n\n contract[displayName][typeName] = impl;\n\n });\n};\n\n\n/**\n * This method should be called when we want to call / transact some solidity method from javascript\n * it returns an object which has same methods available as solidity contract description\n * usage example: \n *\n * var abi = [{\n * name: 'myMethod',\n * inputs: [{ name: 'a', type: 'string' }],\n * outputs: [{name: 'd', type: 'string' }]\n * }]; // contract abi\n *\n * var myContract = web3.eth.contract('0x0123123121', abi); // creation of contract object\n *\n * myContract.myMethod('this is test string param for call'); // myMethod call (implicit, default)\n * myContract.call().myMethod('this is test string param for call'); // myMethod call (explicit)\n * myContract.transact().myMethod('this is test string param for transact'); // myMethod transact\n *\n * @param address - address of the contract, which should be called\n * @param desc - abi json description of the contract, which is being created\n * @returns contract object\n */\n\nvar contract = function (address, desc) {\n\n // workaround for invalid assumption that method.name is the full anonymous prototype of the method.\n // it's not. it's just the name. the rest of the code assumes it's actually the anonymous\n // prototype, so we make it so as a workaround.\n // TODO: we may not want to modify input params, maybe use copy instead?\n desc.forEach(function (method) {\n if (method.name.indexOf('(') === -1) {\n var displayName = method.name;\n var typeName = method.inputs.map(function(i){return i.type; }).join();\n method.name = displayName + '(' + typeName + ')';\n }\n });\n\n var result = {};\n addFunctionRelatedPropertiesToContract(result);\n addFunctionsToContract(result, desc, address);\n addEventRelatedPropertiesToContract(result, desc, address);\n addEventsToContract(result, desc, address);\n\n return result;\n};\n\nmodule.exports = contract;\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 event.js\n * @authors:\n * Marek Kotewicz \n * @date 2014\n */\n\nvar abi = require('./abi');\nvar utils = require('./utils');\n\n/// filter inputs array && returns only indexed (or not) inputs\n/// @param inputs array\n/// @param bool if result should be an array of indexed params on not\n/// @returns array of (not?) indexed params\nvar filterInputs = function (inputs, indexed) {\n return inputs.filter(function (current) {\n return current.indexed === indexed;\n });\n};\n\nvar inputWithName = function (inputs, name) {\n var index = utils.findIndex(inputs, function (input) {\n return input.name === name;\n });\n \n if (index === -1) {\n console.error('indexed param with name ' + name + ' not found');\n return undefined;\n }\n return inputs[index];\n};\n\nvar indexedParamsToTopics = function (event, indexed) {\n // sort keys?\n return Object.keys(indexed).map(function (key) {\n var inputs = [inputWithName(filterInputs(event.inputs, true), key)];\n\n var value = indexed[key];\n if (value instanceof Array) {\n return value.map(function (v) {\n return abi.formatInput(inputs, [v]);\n }); \n }\n return abi.formatInput(inputs, [value]);\n });\n};\n\nvar inputParser = function (address, signature, event) {\n \n // valid options are 'earliest', 'latest', 'offset' and 'max', as defined for 'eth.watch'\n return function (indexed, options) {\n var o = options || {};\n o.address = address;\n o.topic = [];\n o.topic.push(signature);\n if (indexed) {\n o.topic = o.topic.concat(indexedParamsToTopics(event, indexed));\n }\n return o;\n };\n};\n\nvar getArgumentsObject = function (inputs, indexed, notIndexed) {\n var indexedCopy = indexed.slice();\n var notIndexedCopy = notIndexed.slice();\n return inputs.reduce(function (acc, current) {\n var value;\n if (current.indexed)\n value = indexed.splice(0, 1)[0];\n else\n value = notIndexed.splice(0, 1)[0];\n\n acc[current.name] = value;\n return acc;\n }, {}); \n};\n \nvar outputParser = function (event) {\n \n return function (output) {\n var result = {\n event: utils.extractDisplayName(event.name),\n number: output.number,\n args: {}\n };\n\n if (!output.topic) {\n return result;\n }\n \n var indexedOutputs = filterInputs(event.inputs, true);\n var indexedData = \"0x\" + output.topic.slice(1, output.topic.length).map(function (topic) { return topic.slice(2); }).join(\"\");\n var indexedRes = abi.formatOutput(indexedOutputs, indexedData);\n\n var notIndexedOutputs = filterInputs(event.inputs, false);\n var notIndexedRes = abi.formatOutput(notIndexedOutputs, output.data);\n\n result.args = getArgumentsObject(event.inputs, indexedRes, notIndexedRes);\n\n return result;\n };\n};\n\nvar getMatchingEvent = function (events, payload) {\n for (var i = 0; i < events.length; i++) {\n var signature = abi.eventSignatureFromAscii(events[i].name); \n if (signature === payload.topic[0]) {\n return events[i];\n }\n }\n return undefined;\n};\n\n\nmodule.exports = {\n inputParser: inputParser,\n outputParser: outputParser,\n getMatchingEvent: getMatchingEvent\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 filter.js\n * @authors:\n * Jeffrey Wilcke \n * Marek Kotewicz \n * Marian Oancea \n * Gav Wood \n * @date 2014\n */\n\nvar web3 = require('./web3'); // jshint ignore:line\n\n/// should be used when we want to watch something\n/// it's using inner polling mechanism and is notified about changes\n/// TODO: change 'options' name cause it may be not the best matching one, since we have events\nvar Filter = function(options, impl) {\n\n if (typeof options !== \"string\") {\n\n // topics property is deprecated, warn about it!\n if (options.topics) {\n console.warn('\"topics\" is deprecated, use \"topic\" instead');\n }\n \n this._onWatchResult = options._onWatchEventResult;\n\n // evaluate lazy properties\n options = {\n to: options.to,\n topic: options.topic,\n earliest: options.earliest,\n latest: options.latest,\n max: options.max,\n skip: options.skip,\n address: options.address\n };\n\n }\n \n this.impl = impl;\n this.callbacks = [];\n\n this.id = impl.newFilter(options);\n web3.provider.startPolling({method: impl.changed, params: [this.id]}, this.id, this.trigger.bind(this));\n};\n\n/// alias for changed*\nFilter.prototype.arrived = function(callback) {\n this.changed(callback);\n};\nFilter.prototype.happened = function(callback) {\n this.changed(callback);\n};\n\n/// gets called when there is new eth/shh message\nFilter.prototype.changed = function(callback) {\n this.callbacks.push(callback);\n};\n\n/// trigger calling new message from people\nFilter.prototype.trigger = function(messages) {\n for (var i = 0; i < this.callbacks.length; i++) {\n for (var j = 0; j < messages.length; j++) {\n var message = this._onWatchResult ? this._onWatchResult(messages[j]) : messages[j];\n this.callbacks[i].call(this, message);\n }\n }\n};\n\n/// should be called to uninstall current filter\nFilter.prototype.uninstall = function() {\n this.impl.uninstallFilter(this.id);\n web3.provider.stopPolling(this.id);\n};\n\n/// should be called to manually trigger getting latest messages from the client\nFilter.prototype.messages = function() {\n return this.impl.getMessages(this.id);\n};\n\n/// alias for messages\nFilter.prototype.logs = function () {\n return this.messages();\n};\n\nmodule.exports = Filter;\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 const.js\n * @authors:\n * Marek Kotewicz \n * @date 2015\n */\n\n/// required to define ETH_BIGNUMBER_ROUNDING_MODE\nif (\"build\" !== 'build') {/*\n var BigNumber = require('bignumber.js'); // jshint ignore:line\n*/}\n\nvar ETH_UNITS = [ \n 'wei', \n 'Kwei', \n 'Mwei', \n 'Gwei', \n 'szabo', \n 'finney', \n 'ether', \n 'grand', \n 'Mether', \n 'Gether', \n 'Tether', \n 'Pether', \n 'Eether', \n 'Zether', \n 'Yether', \n 'Nether', \n 'Dether', \n 'Vether', \n 'Uether' \n];\n\nmodule.exports = {\n ETH_PADDING: 32,\n ETH_SIGNATURE_LENGTH: 4,\n ETH_UNITS: ETH_UNITS,\n ETH_BIGNUMBER_ROUNDING_MODE: { ROUNDING_MODE: BigNumber.ROUND_DOWN },\n ETH_POLLING_TIMEOUT: 1000\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 contract.js\n * @authors:\n * Marek Kotewicz \n * @date 2014\n */\n\nvar web3 = require('./web3'); \nvar abi = require('./abi');\nvar utils = require('./utils');\nvar eventImpl = require('./event');\nvar filter = require('./filter');\n\nvar exportNatspecGlobals = function (vars) {\n // it's used byt natspec.js\n // TODO: figure out better way to solve this\n web3._currentContractAbi = vars.abi;\n web3._currentContractAddress = vars.address;\n web3._currentContractMethodName = vars.method;\n web3._currentContractMethodParams = vars.params;\n};\n\nvar addFunctionRelatedPropertiesToContract = function (contract) {\n \n contract.call = function (options) {\n contract._isTransact = false;\n contract._options = options;\n return contract;\n };\n\n contract.transact = function (options) {\n contract._isTransact = true;\n contract._options = options;\n return contract;\n };\n\n contract._options = {};\n ['gas', 'gasPrice', 'value', 'from'].forEach(function(p) {\n contract[p] = function (v) {\n contract._options[p] = v;\n return contract;\n };\n });\n\n};\n\nvar addFunctionsToContract = function (contract, desc, address) {\n var inputParser = abi.inputParser(desc);\n var outputParser = abi.outputParser(desc);\n\n // create contract functions\n utils.filterFunctions(desc).forEach(function (method) {\n\n var displayName = utils.extractDisplayName(method.name);\n var typeName = utils.extractTypeName(method.name);\n\n var impl = function () {\n var params = Array.prototype.slice.call(arguments);\n var signature = abi.signatureFromAscii(method.name);\n var parsed = inputParser[displayName][typeName].apply(null, params);\n\n var options = contract._options || {};\n options.to = address;\n options.data = signature + parsed;\n \n var isTransact = contract._isTransact === true || (contract._isTransact !== false && !method.constant);\n var collapse = options.collapse !== false;\n \n // reset\n contract._options = {};\n contract._isTransact = null;\n\n if (isTransact) {\n \n exportNatspecGlobals({\n abi: desc,\n address: address,\n method: method.name,\n params: params\n });\n\n // transactions do not have any output, cause we do not know, when they will be processed\n web3.eth.transact(options);\n return;\n }\n \n var output = web3.eth.call(options);\n var ret = outputParser[displayName][typeName](output);\n if (collapse)\n {\n if (ret.length === 1)\n ret = ret[0];\n else if (ret.length === 0)\n ret = null;\n }\n return ret;\n };\n\n if (contract[displayName] === undefined) {\n contract[displayName] = impl;\n }\n\n contract[displayName][typeName] = impl;\n });\n};\n\nvar addEventRelatedPropertiesToContract = function (contract, desc, address) {\n contract.address = address;\n contract._onWatchEventResult = function (data) {\n var matchingEvent = event.getMatchingEvent(utils.filterEvents(desc));\n var parser = eventImpl.outputParser(matchingEvent);\n return parser(data);\n };\n \n Object.defineProperty(contract, 'topic', {\n get: function() {\n return utils.filterEvents(desc).map(function (e) {\n return abi.eventSignatureFromAscii(e.name);\n });\n }\n });\n\n};\n\nvar addEventsToContract = function (contract, desc, address) {\n // create contract events\n utils.filterEvents(desc).forEach(function (e) {\n\n var impl = function () {\n var params = Array.prototype.slice.call(arguments);\n var signature = abi.eventSignatureFromAscii(e.name);\n var event = eventImpl.inputParser(address, signature, e);\n var o = event.apply(null, params);\n var outputFormatter = function (data) {\n var parser = eventImpl.outputParser(e);\n return parser(data);\n };\n return web3.eth.watch(o, undefined, undefined, outputFormatter);\n };\n \n // this property should be used by eth.filter to check if object is an event\n impl._isEvent = true;\n\n var displayName = utils.extractDisplayName(e.name);\n var typeName = utils.extractTypeName(e.name);\n\n if (contract[displayName] === undefined) {\n contract[displayName] = impl;\n }\n\n contract[displayName][typeName] = impl;\n\n });\n};\n\n\n/**\n * This method should be called when we want to call / transact some solidity method from javascript\n * it returns an object which has same methods available as solidity contract description\n * usage example: \n *\n * var abi = [{\n * name: 'myMethod',\n * inputs: [{ name: 'a', type: 'string' }],\n * outputs: [{name: 'd', type: 'string' }]\n * }]; // contract abi\n *\n * var myContract = web3.eth.contract('0x0123123121', abi); // creation of contract object\n *\n * myContract.myMethod('this is test string param for call'); // myMethod call (implicit, default)\n * myContract.call().myMethod('this is test string param for call'); // myMethod call (explicit)\n * myContract.transact().myMethod('this is test string param for transact'); // myMethod transact\n *\n * @param address - address of the contract, which should be called\n * @param desc - abi json description of the contract, which is being created\n * @returns contract object\n */\n\nvar contract = function (address, desc) {\n\n // workaround for invalid assumption that method.name is the full anonymous prototype of the method.\n // it's not. it's just the name. the rest of the code assumes it's actually the anonymous\n // prototype, so we make it so as a workaround.\n // TODO: we may not want to modify input params, maybe use copy instead?\n desc.forEach(function (method) {\n if (method.name.indexOf('(') === -1) {\n var displayName = method.name;\n var typeName = method.inputs.map(function(i){return i.type; }).join();\n method.name = displayName + '(' + typeName + ')';\n }\n });\n\n var result = {};\n addFunctionRelatedPropertiesToContract(result);\n addFunctionsToContract(result, desc, address);\n addEventRelatedPropertiesToContract(result, desc, address);\n addEventsToContract(result, desc, address);\n\n return result;\n};\n\nmodule.exports = contract;\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 db.js\n * @authors:\n * Marek Kotewicz \n * @date 2015\n */\n\n/// @returns an array of objects describing web3.db api methods\nvar methods = function () {\n return [\n { name: 'put', call: 'db_put' },\n { name: 'get', call: 'db_get' },\n { name: 'putString', call: 'db_putString' },\n { name: 'getString', call: 'db_getString' }\n ];\n};\n\nmodule.exports = {\n methods: methods\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 eth.js\n * @authors:\n * Marek Kotewicz \n * @date 2015\n */\n\n/// @returns an array of objects describing web3.eth api methods\nvar methods = function () {\n var blockCall = function (args) {\n return typeof args[0] === \"string\" ? \"eth_blockByHash\" : \"eth_blockByNumber\";\n };\n\n var transactionCall = function (args) {\n return typeof args[0] === \"string\" ? 'eth_transactionByHash' : 'eth_transactionByNumber';\n };\n\n var uncleCall = function (args) {\n return typeof args[0] === \"string\" ? 'eth_uncleByHash' : 'eth_uncleByNumber';\n };\n\n var transactionCountCall = function (args) {\n return typeof args[0] === \"string\" ? 'eth_transactionCountByHash' : 'eth_transactionCountByNumber';\n };\n\n var uncleCountCall = function (args) {\n return typeof args[0] === \"string\" ? 'eth_uncleCountByHash' : 'eth_uncleCountByNumber';\n };\n\n return [\n { name: 'balanceAt', call: 'eth_balanceAt' },\n { name: 'stateAt', call: 'eth_stateAt' },\n { name: 'storageAt', call: 'eth_storageAt' },\n { name: 'countAt', call: 'eth_countAt'},\n { name: 'codeAt', call: 'eth_codeAt' },\n { name: 'transact', call: 'eth_transact' },\n { name: 'call', call: 'eth_call' },\n { name: 'block', call: blockCall },\n { name: 'transaction', call: transactionCall },\n { name: 'uncle', call: uncleCall },\n { name: 'compilers', call: 'eth_compilers' },\n { name: 'flush', call: 'eth_flush' },\n { name: 'lll', call: 'eth_lll' },\n { name: 'solidity', call: 'eth_solidity' },\n { name: 'serpent', call: 'eth_serpent' },\n { name: 'logs', call: 'eth_logs' },\n { name: 'transactionCount', call: transactionCountCall },\n { name: 'uncleCount', call: uncleCountCall }\n ];\n};\n\n/// @returns an array of objects describing web3.eth api properties\nvar properties = function () {\n return [\n { name: 'coinbase', getter: 'eth_coinbase', setter: 'eth_setCoinbase' },\n { name: 'listening', getter: 'eth_listening', setter: 'eth_setListening' },\n { name: 'mining', getter: 'eth_mining', setter: 'eth_setMining' },\n { name: 'gasPrice', getter: 'eth_gasPrice' },\n { name: 'accounts', getter: 'eth_accounts' },\n { name: 'peerCount', getter: 'eth_peerCount' },\n { name: 'defaultBlock', getter: 'eth_defaultBlock', setter: 'eth_setDefaultBlock' },\n { name: 'number', getter: 'eth_number'}\n ];\n};\n\nmodule.exports = {\n methods: methods,\n properties: properties\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 event.js\n * @authors:\n * Marek Kotewicz \n * @date 2014\n */\n\nvar abi = require('./abi');\nvar utils = require('./utils');\n\n/// filter inputs array && returns only indexed (or not) inputs\n/// @param inputs array\n/// @param bool if result should be an array of indexed params on not\n/// @returns array of (not?) indexed params\nvar filterInputs = function (inputs, indexed) {\n return inputs.filter(function (current) {\n return current.indexed === indexed;\n });\n};\n\nvar inputWithName = function (inputs, name) {\n var index = utils.findIndex(inputs, function (input) {\n return input.name === name;\n });\n \n if (index === -1) {\n console.error('indexed param with name ' + name + ' not found');\n return undefined;\n }\n return inputs[index];\n};\n\nvar indexedParamsToTopics = function (event, indexed) {\n // sort keys?\n return Object.keys(indexed).map(function (key) {\n var inputs = [inputWithName(filterInputs(event.inputs, true), key)];\n\n var value = indexed[key];\n if (value instanceof Array) {\n return value.map(function (v) {\n return abi.formatInput(inputs, [v]);\n }); \n }\n return abi.formatInput(inputs, [value]);\n });\n};\n\nvar inputParser = function (address, signature, event) {\n \n // valid options are 'earliest', 'latest', 'offset' and 'max', as defined for 'eth.watch'\n return function (indexed, options) {\n var o = options || {};\n o.address = address;\n o.topic = [];\n o.topic.push(signature);\n if (indexed) {\n o.topic = o.topic.concat(indexedParamsToTopics(event, indexed));\n }\n return o;\n };\n};\n\nvar getArgumentsObject = function (inputs, indexed, notIndexed) {\n var indexedCopy = indexed.slice();\n var notIndexedCopy = notIndexed.slice();\n return inputs.reduce(function (acc, current) {\n var value;\n if (current.indexed)\n value = indexed.splice(0, 1)[0];\n else\n value = notIndexed.splice(0, 1)[0];\n\n acc[current.name] = value;\n return acc;\n }, {}); \n};\n \nvar outputParser = function (event) {\n \n return function (output) {\n var result = {\n event: utils.extractDisplayName(event.name),\n number: output.number,\n args: {}\n };\n\n output.topics = output.topic; // fallback for go-ethereum\n if (!output.topic) {\n return result;\n }\n \n var indexedOutputs = filterInputs(event.inputs, true);\n var indexedData = \"0x\" + output.topic.slice(1, output.topic.length).map(function (topic) { return topic.slice(2); }).join(\"\");\n var indexedRes = abi.formatOutput(indexedOutputs, indexedData);\n\n var notIndexedOutputs = filterInputs(event.inputs, false);\n var notIndexedRes = abi.formatOutput(notIndexedOutputs, output.data);\n\n result.args = getArgumentsObject(event.inputs, indexedRes, notIndexedRes);\n\n return result;\n };\n};\n\nvar getMatchingEvent = function (events, payload) {\n for (var i = 0; i < events.length; i++) {\n var signature = abi.eventSignatureFromAscii(events[i].name); \n if (signature === payload.topic[0]) {\n return events[i];\n }\n }\n return undefined;\n};\n\n\nmodule.exports = {\n inputParser: inputParser,\n outputParser: outputParser,\n getMatchingEvent: getMatchingEvent\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 filter.js\n * @authors:\n * Jeffrey Wilcke \n * Marek Kotewicz \n * Marian Oancea \n * Gav Wood \n * @date 2014\n */\n\n/// Should be called to check if filter implementation is valid\n/// @returns true if it is, otherwise false\nvar implementationIsValid = function (i) {\n return !!i && \n typeof i.newFilter === 'function' && \n typeof i.getMessages === 'function' && \n typeof i.uninstallFilter === 'function' &&\n typeof i.startPolling === 'function' &&\n typeof i.stopPolling === 'function';\n};\n\n/// This method should be called on options object, to verify deprecated properties && lazy load dynamic ones\n/// @param should be string or object\n/// @returns options string or object\nvar getOptions = function (options) {\n if (typeof options === 'string') {\n return options;\n } \n\n options = options || {};\n\n if (options.topics) {\n console.warn('\"topics\" is deprecated, is \"topic\" instead');\n }\n\n // evaluate lazy properties\n return {\n to: options.to,\n topic: options.topic,\n earliest: options.earliest,\n latest: options.latest,\n max: options.max,\n skip: options.skip,\n address: options.address\n };\n};\n\n/// Should be used when we want to watch something\n/// it's using inner polling mechanism and is notified about changes\n/// @param options are filter options\n/// @param implementation, an abstract polling implementation\n/// @param formatter (optional), callback function which formats output before 'real' callback \nvar filter = function(options, implementation, formatter) {\n if (!implementationIsValid(implementation)) {\n console.error('filter implemenation is invalid');\n return;\n }\n\n options = getOptions(options);\n var callbacks = [];\n var filterId = implementation.newFilter(options);\n var onMessages = function (messages) {\n messages.forEach(function (message) {\n message = formatter ? formatter(message) : message;\n callbacks.forEach(function (callback) {\n callback(message);\n });\n });\n };\n\n implementation.startPolling(filterId, onMessages, implementation.uninstallFilter);\n\n var changed = function (callback) {\n callbacks.push(callback);\n };\n\n var messages = function () {\n return implementation.getMessages(filterId);\n };\n \n var uninstall = function (callback) {\n implementation.stopPolling(filterId);\n implementation.uninstallFilter(filterId);\n callbacks = [];\n };\n\n return {\n changed: changed,\n arrived: changed,\n happened: changed,\n messages: messages,\n logs: messages,\n uninstall: uninstall\n };\n};\n\nmodule.exports = filter;\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 formatters.js\n * @authors:\n * Marek Kotewicz \n * @date 2015\n */\n\nif (\"build\" !== 'build') {/*\n var BigNumber = require('bignumber.js'); // jshint ignore:line\n*/}\n\nvar utils = require('./utils');\nvar c = require('./const');\n\n/// @param string string to be padded\n/// @param number of characters that result string should have\n/// @param sign, by default 0\n/// @returns right aligned string\nvar padLeft = function (string, chars, sign) {\n return new Array(chars - string.length + 1).join(sign ? sign : \"0\") + string;\n};\n\n/// Formats input value to byte representation of int\n/// If value is negative, return it's two's complement\n/// If the value is floating point, round it down\n/// @returns right-aligned byte representation of int\nvar formatInputInt = function (value) {\n var padding = c.ETH_PADDING * 2;\n if (value instanceof BigNumber || typeof value === 'number') {\n if (typeof value === 'number')\n value = new BigNumber(value);\n BigNumber.config(c.ETH_BIGNUMBER_ROUNDING_MODE);\n value = value.round();\n\n if (value.lessThan(0)) \n value = new BigNumber(\"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\", 16).plus(value).plus(1);\n value = value.toString(16);\n }\n else if (value.indexOf('0x') === 0)\n value = value.substr(2);\n else if (typeof value === 'string')\n value = formatInputInt(new BigNumber(value));\n else\n value = (+value).toString(16);\n return padLeft(value, padding);\n};\n\n/// Formats input value to byte representation of string\n/// @returns left-algined byte representation of string\nvar formatInputString = function (value) {\n return utils.fromAscii(value, c.ETH_PADDING).substr(2);\n};\n\n/// Formats input value to byte representation of bool\n/// @returns right-aligned byte representation bool\nvar formatInputBool = function (value) {\n return '000000000000000000000000000000000000000000000000000000000000000' + (value ? '1' : '0');\n};\n\n/// Formats input value to byte representation of real\n/// Values are multiplied by 2^m and encoded as integers\n/// @returns byte representation of real\nvar formatInputReal = function (value) {\n return formatInputInt(new BigNumber(value).times(new BigNumber(2).pow(128))); \n};\n\n\n/// Check if input value is negative\n/// @param value is hex format\n/// @returns true if it is negative, otherwise false\nvar signedIsNegative = function (value) {\n return (new BigNumber(value.substr(0, 1), 16).toString(2).substr(0, 1)) === '1';\n};\n\n/// Formats input right-aligned input bytes to int\n/// @returns right-aligned input bytes formatted to int\nvar formatOutputInt = function (value) {\n value = value || \"0\";\n // check if it's negative number\n // it it is, return two's complement\n if (signedIsNegative(value)) {\n return new BigNumber(value, 16).minus(new BigNumber('ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff', 16)).minus(1);\n }\n return new BigNumber(value, 16);\n};\n\n/// Formats big right-aligned input bytes to uint\n/// @returns right-aligned input bytes formatted to uint\nvar formatOutputUInt = function (value) {\n value = value || \"0\";\n return new BigNumber(value, 16);\n};\n\n/// @returns input bytes formatted to real\nvar formatOutputReal = function (value) {\n return formatOutputInt(value).dividedBy(new BigNumber(2).pow(128)); \n};\n\n/// @returns input bytes formatted to ureal\nvar formatOutputUReal = function (value) {\n return formatOutputUInt(value).dividedBy(new BigNumber(2).pow(128)); \n};\n\n/// @returns right-aligned input bytes formatted to hex\nvar formatOutputHash = function (value) {\n return \"0x\" + value;\n};\n\n/// @returns right-aligned input bytes formatted to bool\nvar formatOutputBool = function (value) {\n return value === '0000000000000000000000000000000000000000000000000000000000000001' ? true : false;\n};\n\n/// @returns left-aligned input bytes formatted to ascii string\nvar formatOutputString = function (value) {\n return utils.toAscii(value);\n};\n\n/// @returns right-aligned input bytes formatted to address\nvar formatOutputAddress = function (value) {\n return \"0x\" + value.slice(value.length - 40, value.length);\n};\n\n\nmodule.exports = {\n formatInputInt: formatInputInt,\n formatInputString: formatInputString,\n formatInputBool: formatInputBool,\n formatInputReal: formatInputReal,\n formatOutputInt: formatOutputInt,\n formatOutputUInt: formatOutputUInt,\n formatOutputReal: formatOutputReal,\n formatOutputUReal: formatOutputUReal,\n formatOutputHash: formatOutputHash,\n formatOutputBool: formatOutputBool,\n formatOutputString: formatOutputString,\n formatOutputAddress: formatOutputAddress\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 httpsync.js\n * @authors:\n * Marek Kotewicz \n * Marian Oancea \n * @date 2014\n */\n\nif (\"build\" !== 'build') {/*\n var XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest; // jshint ignore:line\n*/}\n\nvar HttpSyncProvider = function (host) {\n this.handlers = [];\n this.host = host || 'http://localhost:8080';\n};\n\nHttpSyncProvider.prototype.send = function (payload) {\n //var data = formatJsonRpcObject(payload);\n \n var request = new XMLHttpRequest();\n request.open('POST', this.host, false);\n request.send(JSON.stringify(payload));\n \n // check request.status\n var result = request.responseText;\n return JSON.parse(result);\n};\n\nmodule.exports = HttpSyncProvider;\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 httpsync.js\n * @authors:\n * Marek Kotewicz \n * Marian Oancea \n * @date 2014\n */\n\nif (\"build\" !== 'build') {/*\n var XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest; // jshint ignore:line\n*/}\n\nvar HttpSyncProvider = function (host) {\n this.handlers = [];\n this.host = host || 'http://127.0.0.1:8080';\n};\n\nHttpSyncProvider.prototype.send = function (payload) {\n //var data = formatJsonRpcObject(payload);\n\n var request = new XMLHttpRequest();\n request.open('POST', this.host, false);\n request.send(JSON.stringify(payload));\n\n var result = request.responseText;\n // check request.status\n if(request.status !== 200)\n return;\n return JSON.parse(result);\n};\n\nmodule.exports = HttpSyncProvider;\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 jsonrpc.js\n * @authors:\n * Marek Kotewicz \n * @date 2015\n */\n\nvar messageId = 1;\n\n/// Should be called to valid json create payload object\n/// @param method of jsonrpc call, required\n/// @param params, an array of method params, optional\n/// @returns valid jsonrpc payload object\nvar toPayload = function (method, params) {\n if (!method)\n console.error('jsonrpc method should be specified!');\n\n return {\n jsonrpc: '2.0',\n method: method,\n params: params || [],\n id: messageId++\n }; \n};\n\n/// Should be called to check if jsonrpc response is valid\n/// @returns true if response is valid, otherwise false \nvar isValidResponse = function (response) {\n return !!response &&\n !response.error &&\n response.jsonrpc === '2.0' &&\n typeof response.id === 'number' &&\n response.result !== undefined; // only undefined is not valid json object\n};\n\n/// Should be called to create batch payload object\n/// @param messages, an array of objects with method (required) and params (optional) fields\nvar toBatchPayload = function (messages) {\n return messages.map(function (message) {\n return toPayload(message.method, message.params);\n }); \n};\n\nmodule.exports = {\n toPayload: toPayload,\n isValidResponse: isValidResponse,\n toBatchPayload: toBatchPayload\n};\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 providermanager.js\n * @authors:\n * Jeffrey Wilcke \n * Marek Kotewicz \n * Marian Oancea \n * Gav Wood \n * @date 2014\n */\n\nvar web3 = require('./web3'); \nvar jsonrpc = require('./jsonrpc');\n\n\n/**\n * Provider manager object prototype\n * It's responsible for passing messages to providers\n * If no provider is set it's responsible for queuing requests\n * It's also responsible for polling the ethereum node for incoming messages\n * Default poll timeout is 12 seconds\n * If we are running ethereum.js inside ethereum browser, there are backend based tools responsible for polling,\n * and provider manager polling mechanism is not used\n */\nvar ProviderManager = function() {\n this.polls = [];\n this.provider = undefined;\n\n var self = this;\n var poll = function () {\n self.polls.forEach(function (data) {\n var result = self.send(data.data);\n\n if (!(result instanceof Array) || result.length === 0) {\n return;\n }\n\n data.callback(result);\n });\n\n setTimeout(poll, 1000);\n };\n poll();\n};\n\n/// sends outgoing requests\n/// @params data - an object with at least 'method' property\nProviderManager.prototype.send = function(data) {\n var payload = jsonrpc.toPayload(data.method, data.params);\n\n if (this.provider === undefined) {\n console.error('provider is not set');\n return null; \n }\n\n var result = this.provider.send(payload);\n\n if (!jsonrpc.isValidResponse(result)) {\n console.log(result);\n return null;\n }\n\n return result.result;\n};\n\n/// setups provider, which will be used for sending messages\nProviderManager.prototype.set = function(provider) {\n this.provider = provider;\n};\n\n/// this method is only used, when we do not have native qt bindings and have to do polling on our own\n/// should be callled, on start watching for eth/shh changes\nProviderManager.prototype.startPolling = function (data, pollId, callback) {\n this.polls.push({data: data, id: pollId, callback: callback});\n};\n\n/// should be called to stop polling for certain watch changes\nProviderManager.prototype.stopPolling = function (pollId) {\n for (var i = this.polls.length; i--;) {\n var poll = this.polls[i];\n if (poll.id === pollId) {\n this.polls.splice(i, 1);\n }\n }\n};\n\nmodule.exports = ProviderManager;\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 qtsync.js\n * @authors:\n * Marek Kotewicz \n * Marian Oancea \n * @date 2014\n */\n\nvar QtSyncProvider = function () {\n};\n\nQtSyncProvider.prototype.send = function (payload) {\n var result = navigator.qt.callMethod(JSON.stringify(payload));\n return JSON.parse(result);\n};\n\nmodule.exports = QtSyncProvider;\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 requestmanager.js\n * @authors:\n * Jeffrey Wilcke \n * Marek Kotewicz \n * Marian Oancea \n * Gav Wood \n * @date 2014\n */\n\nvar jsonrpc = require('./jsonrpc');\nvar c = require('./const');\n\n/**\n * It's responsible for passing messages to providers\n * It's also responsible for polling the ethereum node for incoming messages\n * Default poll timeout is 1 second\n */\nvar requestManager = function() {\n var polls = [];\n var provider;\n\n var send = function (data) {\n var payload = jsonrpc.toPayload(data.method, data.params);\n \n if (!provider) {\n console.error('provider is not set');\n return null;\n }\n\n var result = provider.send(payload);\n\n if (!jsonrpc.isValidResponse(result)) {\n console.log(result);\n return null;\n }\n \n return result.result;\n };\n\n var setProvider = function (p) {\n provider = p;\n };\n\n var startPolling = function (data, pollId, callback, uninstall) {\n polls.push({data: data, id: pollId, callback: callback, uninstall: uninstall});\n };\n\n var stopPolling = function (pollId) {\n for (var i = polls.length; i--;) {\n var poll = polls[i];\n if (poll.id === pollId) {\n polls.splice(i, 1);\n }\n }\n };\n\n var reset = function () {\n polls.forEach(function (poll) {\n poll.uninstall(poll.id); \n });\n polls = [];\n };\n\n var poll = function () {\n polls.forEach(function (data) {\n var result = send(data.data);\n if (!(result instanceof Array) || result.length === 0) {\n return;\n }\n data.callback(result);\n });\n setTimeout(poll, c.ETH_POLLING_TIMEOUT);\n };\n \n poll();\n\n return {\n send: send,\n setProvider: setProvider,\n startPolling: startPolling,\n stopPolling: stopPolling,\n reset: reset\n };\n};\n\nmodule.exports = requestManager;\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 shh.js\n * @authors:\n * Marek Kotewicz \n * @date 2015\n */\n\n/// @returns an array of objects describing web3.shh api methods\nvar methods = function () {\n return [\n { name: 'post', call: 'shh_post' },\n { name: 'newIdentity', call: 'shh_newIdentity' },\n { name: 'haveIdentity', call: 'shh_haveIdentity' },\n { name: 'newGroup', call: 'shh_newGroup' },\n { name: 'addToGroup', call: 'shh_addToGroup' }\n ];\n};\n\nmodule.exports = {\n methods: methods\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 types.js\n * @authors:\n * Marek Kotewicz \n * @date 2015\n */\n\nvar f = require('./formatters');\n\n/// @param expected type prefix (string)\n/// @returns function which checks if type has matching prefix. if yes, returns true, otherwise false\nvar prefixedType = function (prefix) {\n return function (type) {\n return type.indexOf(prefix) === 0;\n };\n};\n\n/// @param expected type name (string)\n/// @returns function which checks if type is matching expected one. if yes, returns true, otherwise false\nvar namedType = function (name) {\n return function (type) {\n return name === type;\n };\n};\n\n/// Setups input formatters for solidity types\n/// @returns an array of input formatters \nvar inputTypes = function () {\n \n return [\n { type: prefixedType('uint'), format: f.formatInputInt },\n { type: prefixedType('int'), format: f.formatInputInt },\n { type: prefixedType('hash'), format: f.formatInputInt },\n { type: prefixedType('string'), format: f.formatInputString }, \n { type: prefixedType('real'), format: f.formatInputReal },\n { type: prefixedType('ureal'), format: f.formatInputReal },\n { type: namedType('address'), format: f.formatInputInt },\n { type: namedType('bool'), format: f.formatInputBool }\n ];\n};\n\n/// Setups output formaters for solidity types\n/// @returns an array of output formatters\nvar outputTypes = function () {\n\n return [\n { type: prefixedType('uint'), format: f.formatOutputUInt },\n { type: prefixedType('int'), format: f.formatOutputInt },\n { type: prefixedType('hash'), format: f.formatOutputHash },\n { type: prefixedType('string'), format: f.formatOutputString },\n { type: prefixedType('real'), format: f.formatOutputReal },\n { type: prefixedType('ureal'), format: f.formatOutputUReal },\n { type: namedType('address'), format: f.formatOutputAddress },\n { type: namedType('bool'), format: f.formatOutputBool }\n ];\n};\n\nmodule.exports = {\n prefixedType: prefixedType,\n namedType: namedType,\n inputTypes: inputTypes,\n outputTypes: outputTypes\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 utils.js\n * @authors:\n * Marek Kotewicz \n * @date 2015\n */\n\nvar c = require('./const');\n\n/// Finds first index of array element matching pattern\n/// @param array\n/// @param callback pattern\n/// @returns index of element\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\n/// @returns ascii string representation of hex value prefixed with 0x\nvar toAscii = function(hex) {\n// Find termination\n var str = \"\";\n var i = 0, l = hex.length;\n if (hex.substring(0, 2) === '0x') {\n i = 2;\n }\n for (; i < l; i+=2) {\n var code = parseInt(hex.substr(i, 2), 16);\n if (code === 0) {\n break;\n }\n\n str += String.fromCharCode(code);\n }\n\n return str;\n};\n \nvar toHex = function(str) {\n var hex = \"\";\n for(var i = 0; i < str.length; i++) {\n var n = str.charCodeAt(i).toString(16);\n hex += n.length < 2 ? '0' + n : n;\n }\n\n return hex;\n};\n\n/// @returns hex representation (prefixed by 0x) of ascii string\nvar fromAscii = function(str, pad) {\n pad = pad === undefined ? 0 : pad;\n var hex = toHex(str);\n while (hex.length < pad*2)\n hex += \"00\";\n return \"0x\" + hex;\n};\n\n/// @returns display name for function/event eg. multiply(uint256) -> multiply\nvar extractDisplayName = function (name) {\n var length = name.indexOf('('); \n return length !== -1 ? name.substr(0, length) : name;\n};\n\n/// @returns overloaded part of function/event name\nvar extractTypeName = function (name) {\n /// TODO: make it invulnerable\n var length = name.indexOf('(');\n return length !== -1 ? name.substr(length + 1, name.length - 1 - (length + 1)).replace(' ', '') : \"\";\n};\n\n/// Filters all function from input abi\n/// @returns abi array with filtered objects of type 'function'\nvar filterFunctions = function (json) {\n return json.filter(function (current) {\n return current.type === 'function'; \n }); \n};\n\n/// Filters all events form input abi\n/// @returns abi array with filtered objects of type 'event'\nvar filterEvents = function (json) {\n return json.filter(function (current) {\n return current.type === 'event';\n });\n};\n\n/// used to transform value/string to eth string\n/// TODO: use BigNumber.js to parse int\n/// TODO: add tests for it!\nvar toEth = function (str) {\n var val = typeof str === \"string\" ? str.indexOf('0x') === 0 ? parseInt(str.substr(2), 16) : parseInt(str) : str;\n var unit = 0;\n var units = c.ETH_UNITS;\n while (val > 3000 && unit < units.length - 1)\n {\n val /= 1000;\n unit++;\n }\n var s = val.toString().length < val.toFixed(2).length ? val.toString() : val.toFixed(2);\n var replaceFunction = function($0, $1, $2) {\n return $1 + ',' + $2;\n };\n\n while (true) {\n var o = s;\n s = s.replace(/(\\d)(\\d\\d\\d[\\.\\,])/, replaceFunction);\n if (o === s)\n break;\n }\n return s + ' ' + units[unit];\n};\n\nmodule.exports = {\n findIndex: findIndex,\n toAscii: toAscii,\n fromAscii: fromAscii,\n extractDisplayName: extractDisplayName,\n extractTypeName: extractTypeName,\n filterFunctions: filterFunctions,\n filterEvents: filterEvents,\n toEth: toEth\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 web3.js\n * @authors:\n * Jeffrey Wilcke \n * Marek Kotewicz \n * Marian Oancea \n * Gav Wood \n * @date 2014\n */\n\nif (\"build\" !== 'build') {/*\n var BigNumber = require('bignumber.js');\n*/}\n\nvar utils = require('./utils');\n\n/// @returns an array of objects describing web3 api methods\nvar web3Methods = function () {\n return [\n { name: 'sha3', call: 'web3_sha3' }\n ];\n};\n\n/// @returns an array of objects describing web3.eth api methods\nvar ethMethods = function () {\n var blockCall = function (args) {\n return typeof args[0] === \"string\" ? \"eth_blockByHash\" : \"eth_blockByNumber\";\n };\n\n var transactionCall = function (args) {\n return typeof args[0] === \"string\" ? 'eth_transactionByHash' : 'eth_transactionByNumber';\n };\n\n var uncleCall = function (args) {\n return typeof args[0] === \"string\" ? 'eth_uncleByHash' : 'eth_uncleByNumber';\n };\n\n var methods = [\n { name: 'balanceAt', call: 'eth_balanceAt' },\n { name: 'stateAt', call: 'eth_stateAt' },\n { name: 'storageAt', call: 'eth_storageAt' },\n { name: 'countAt', call: 'eth_countAt'},\n { name: 'codeAt', call: 'eth_codeAt' },\n { name: 'transact', call: 'eth_transact' },\n { name: 'call', call: 'eth_call' },\n { name: 'block', call: blockCall },\n { name: 'transaction', call: transactionCall },\n { name: 'uncle', call: uncleCall },\n { name: 'compilers', call: 'eth_compilers' },\n { name: 'flush', call: 'eth_flush' },\n { name: 'lll', call: 'eth_lll' },\n { name: 'solidity', call: 'eth_solidity' },\n { name: 'serpent', call: 'eth_serpent' },\n { name: 'logs', call: 'eth_logs' }\n ];\n return methods;\n};\n\n/// @returns an array of objects describing web3.eth api properties\nvar ethProperties = function () {\n return [\n { name: 'coinbase', getter: 'eth_coinbase', setter: 'eth_setCoinbase' },\n { name: 'listening', getter: 'eth_listening', setter: 'eth_setListening' },\n { name: 'mining', getter: 'eth_mining', setter: 'eth_setMining' },\n { name: 'gasPrice', getter: 'eth_gasPrice' },\n { name: 'accounts', getter: 'eth_accounts' },\n { name: 'peerCount', getter: 'eth_peerCount' },\n { name: 'defaultBlock', getter: 'eth_defaultBlock', setter: 'eth_setDefaultBlock' },\n { name: 'number', getter: 'eth_number'}\n ];\n};\n\n/// @returns an array of objects describing web3.db api methods\nvar dbMethods = function () {\n return [\n { name: 'put', call: 'db_put' },\n { name: 'get', call: 'db_get' },\n { name: 'putString', call: 'db_putString' },\n { name: 'getString', call: 'db_getString' }\n ];\n};\n\n/// @returns an array of objects describing web3.shh api methods\nvar shhMethods = function () {\n return [\n { name: 'post', call: 'shh_post' },\n { name: 'newIdentity', call: 'shh_newIdentity' },\n { name: 'haveIdentity', call: 'shh_haveIdentity' },\n { name: 'newGroup', call: 'shh_newGroup' },\n { name: 'addToGroup', call: 'shh_addToGroup' }\n ];\n};\n\n/// @returns an array of objects describing web3.eth.watch api methods\nvar ethWatchMethods = function () {\n var newFilter = function (args) {\n return typeof args[0] === 'string' ? 'eth_newFilterString' : 'eth_newFilter';\n };\n\n return [\n { name: 'newFilter', call: newFilter },\n { name: 'uninstallFilter', call: 'eth_uninstallFilter' },\n { name: 'getMessages', call: 'eth_filterLogs' }\n ];\n};\n\n/// @returns an array of objects describing web3.shh.watch api methods\nvar shhWatchMethods = function () {\n return [\n { name: 'newFilter', call: 'shh_newFilter' },\n { name: 'uninstallFilter', call: 'shh_uninstallFilter' },\n { name: 'getMessages', call: 'shh_getMessages' }\n ];\n};\n\n/// creates methods in a given object based on method description on input\n/// setups api calls for these methods\nvar setupMethods = function (obj, methods) {\n methods.forEach(function (method) {\n obj[method.name] = function () {\n var args = Array.prototype.slice.call(arguments);\n var call = typeof method.call === 'function' ? method.call(args) : method.call;\n return web3.provider.send({\n method: call,\n params: args\n });\n };\n });\n};\n\n/// creates properties in a given object based on properties description on input\n/// setups api calls for these properties\nvar setupProperties = function (obj, properties) {\n properties.forEach(function (property) {\n var proto = {};\n proto.get = function () {\n return web3.provider.send({\n method: property.getter\n });\n };\n\n if (property.setter) {\n proto.set = function (val) {\n return web3.provider.send({\n method: property.setter,\n params: [val]\n });\n };\n }\n Object.defineProperty(obj, property.name, proto);\n });\n};\n\n/// setups web3 object, and it's in-browser executed methods\nvar web3 = {\n _callbacks: {},\n _events: {},\n providers: {},\n\n /// @returns ascii string representation of hex value prefixed with 0x\n toAscii: utils.toAscii,\n\n /// @returns hex representation (prefixed by 0x) of ascii string\n fromAscii: utils.fromAscii,\n\n /// @returns decimal representaton of hex value prefixed by 0x\n toDecimal: function (val) {\n // remove 0x and place 0, if it's required\n val = val.length > 2 ? val.substring(2) : \"0\";\n return (new BigNumber(val, 16).toString(10));\n },\n\n /// @returns hex representation (prefixed by 0x) of decimal value\n fromDecimal: function (val) {\n return \"0x\" + (new BigNumber(val).toString(16));\n },\n\n /// used to transform value/string to eth string\n toEth: utils.toEth,\n\n /// eth object prototype\n eth: {\n contractFromAbi: function (abi) {\n return function(addr) {\n // Default to address of Config. TODO: rremove prior to genesis.\n addr = addr || '0xc6d9d2cd449a754c494264e1809c50e34d64562b';\n var ret = web3.eth.contract(addr, abi);\n ret.address = addr;\n return ret;\n };\n },\n\n /// @param filter may be a string, object or event\n /// @param indexed is optional, this is an object with optional event indexed params\n /// @param options is optional, this is an object with optional event options ('max'...)\n watch: function (filter, indexed, options) {\n if (filter._isEvent) {\n return filter(indexed, options);\n }\n return new web3.filter(filter, ethWatch);\n }\n },\n\n /// db object prototype\n db: {},\n\n /// shh object prototype\n shh: {\n \n /// @param filter may be a string, object or event\n watch: function (filter, indexed) {\n return new web3.filter(filter, shhWatch);\n }\n },\n};\n\n/// setups all api methods\nsetupMethods(web3, web3Methods());\nsetupMethods(web3.eth, ethMethods());\nsetupProperties(web3.eth, ethProperties());\nsetupMethods(web3.db, dbMethods());\nsetupMethods(web3.shh, shhMethods());\n\nvar ethWatch = {\n changed: 'eth_changed'\n};\n\nsetupMethods(ethWatch, ethWatchMethods());\n\nvar shhWatch = {\n changed: 'shh_changed'\n};\n\nsetupMethods(shhWatch, shhWatchMethods());\n\nweb3.setProvider = function(provider) {\n web3.provider.set(provider);\n};\n\nmodule.exports = web3;\n\n", - "var web3 = require('./lib/web3');\nvar ProviderManager = require('./lib/providermanager');\nweb3.provider = new ProviderManager();\nweb3.filter = require('./lib/filter');\nweb3.providers.HttpSyncProvider = require('./lib/httpsync');\nweb3.providers.QtSyncProvider = require('./lib/qtsync');\nweb3.eth.contract = require('./lib/contract');\nweb3.abi = require('./lib/abi');\n\n\nmodule.exports = web3;\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 watches.js\n * @authors:\n * Marek Kotewicz \n * @date 2015\n */\n\n/// @returns an array of objects describing web3.eth.watch api methods\nvar eth = function () {\n var newFilter = function (args) {\n return typeof args[0] === 'string' ? 'eth_newFilterString' : 'eth_newFilter';\n };\n\n return [\n { name: 'newFilter', call: newFilter },\n { name: 'uninstallFilter', call: 'eth_uninstallFilter' },\n { name: 'getMessages', call: 'eth_filterLogs' }\n ];\n};\n\n/// @returns an array of objects describing web3.shh.watch api methods\nvar shh = function () {\n return [\n { name: 'newFilter', call: 'shh_newFilter' },\n { name: 'uninstallFilter', call: 'shh_uninstallFilter' },\n { name: 'getMessages', call: 'shh_getMessages' }\n ];\n};\n\nmodule.exports = {\n eth: eth,\n shh: shh\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 web3.js\n * @authors:\n * Jeffrey Wilcke \n * Marek Kotewicz \n * Marian Oancea \n * Gav Wood \n * @date 2014\n */\n\nif (\"build\" !== 'build') {/*\n var BigNumber = require('bignumber.js');\n*/}\n\nvar eth = require('./eth');\nvar db = require('./db');\nvar shh = require('./shh');\nvar watches = require('./watches');\nvar filter = require('./filter');\nvar utils = require('./utils');\nvar requestManager = require('./requestmanager');\n\n/// @returns an array of objects describing web3 api methods\nvar web3Methods = function () {\n return [\n { name: 'sha3', call: 'web3_sha3' }\n ];\n};\n\n/// creates methods in a given object based on method description on input\n/// setups api calls for these methods\nvar setupMethods = function (obj, methods) {\n methods.forEach(function (method) {\n obj[method.name] = function () {\n var args = Array.prototype.slice.call(arguments);\n var call = typeof method.call === 'function' ? method.call(args) : method.call;\n return web3.manager.send({\n method: call,\n params: args\n });\n };\n });\n};\n\n/// creates properties in a given object based on properties description on input\n/// setups api calls for these properties\nvar setupProperties = function (obj, properties) {\n properties.forEach(function (property) {\n var proto = {};\n proto.get = function () {\n return web3.manager.send({\n method: property.getter\n });\n };\n\n if (property.setter) {\n proto.set = function (val) {\n return web3.manager.send({\n method: property.setter,\n params: [val]\n });\n };\n }\n Object.defineProperty(obj, property.name, proto);\n });\n};\n\nvar startPolling = function (method, id, callback, uninstall) {\n web3.manager.startPolling({\n method: method, \n params: [id]\n }, id, callback, uninstall); \n};\n\nvar stopPolling = function (id) {\n web3.manager.stopPolling(id);\n};\n\nvar ethWatch = {\n startPolling: startPolling.bind(null, 'eth_changed'), \n stopPolling: stopPolling\n};\n\nvar shhWatch = {\n startPolling: startPolling.bind(null, 'shh_changed'), \n stopPolling: stopPolling\n};\n\n/// setups web3 object, and it's in-browser executed methods\nvar web3 = {\n manager: requestManager(),\n providers: {},\n\n /// @returns ascii string representation of hex value prefixed with 0x\n toAscii: utils.toAscii,\n\n /// @returns hex representation (prefixed by 0x) of ascii string\n fromAscii: utils.fromAscii,\n\n /// @returns decimal representaton of hex value prefixed by 0x\n toDecimal: function (val) {\n // remove 0x and place 0, if it's required\n val = val.length > 2 ? val.substring(2) : \"0\";\n return (new BigNumber(val, 16).toString(10));\n },\n\n /// @returns hex representation (prefixed by 0x) of decimal value\n fromDecimal: function (val) {\n return \"0x\" + (new BigNumber(val).toString(16));\n },\n\n /// used to transform value/string to eth string\n toEth: utils.toEth,\n\n /// eth object prototype\n eth: {\n contractFromAbi: function (abi) {\n return function(addr) {\n // Default to address of Config. TODO: rremove prior to genesis.\n addr = addr || '0xc6d9d2cd449a754c494264e1809c50e34d64562b';\n var ret = web3.eth.contract(addr, abi);\n ret.address = addr;\n return ret;\n };\n },\n\n /// @param filter may be a string, object or event\n /// @param indexed is optional, this is an object with optional event indexed params\n /// @param options is optional, this is an object with optional event options ('max'...)\n /// TODO: fix it, 4 params? no way\n watch: function (fil, indexed, options, formatter) {\n if (fil._isEvent) {\n return fil(indexed, options);\n }\n return filter(fil, ethWatch, formatter);\n }\n },\n\n /// db object prototype\n db: {},\n\n /// shh object prototype\n shh: {\n /// @param filter may be a string, object or event\n watch: function (fil) {\n return filter(fil, shhWatch);\n }\n },\n setProvider: function (provider) {\n web3.manager.setProvider(provider);\n },\n \n /// Should be called to reset state of web3 object\n /// Resets everything except manager\n reset: function () {\n web3.manager.reset(); \n }\n};\n\n/// setups all api methods\nsetupMethods(web3, web3Methods());\nsetupMethods(web3.eth, eth.methods());\nsetupProperties(web3.eth, eth.properties());\nsetupMethods(web3.db, db.methods());\nsetupMethods(web3.shh, shh.methods());\nsetupMethods(ethWatch, watches.eth());\nsetupMethods(shhWatch, watches.shh());\n\nmodule.exports = web3;\n\n", + "var web3 = require('./lib/web3');\nweb3.providers.HttpSyncProvider = require('./lib/httpsync');\nweb3.providers.QtSyncProvider = require('./lib/qtsync');\nweb3.eth.contract = require('./lib/contract');\nweb3.abi = require('./lib/abi');\n\nmodule.exports = web3;\n" ] } \ No newline at end of file diff --git a/libjsqrc/ethereumjs/dist/ethereum.min.js b/libjsqrc/ethereumjs/dist/ethereum.min.js index df408d3e4..92748f48a 100644 --- a/libjsqrc/ethereumjs/dist/ethereum.min.js +++ b/libjsqrc/ethereumjs/dist/ethereum.min.js @@ -1 +1 @@ -require=function t(e,n,r){function i(a,u){if(!n[a]){if(!e[a]){var s="function"==typeof require&&require;if(!u&&s)return s(a,!0);if(o)return o(a,!0);var f=new Error("Cannot find module '"+a+"'");throw f.code="MODULE_NOT_FOUND",f}var c=n[a]={exports:{}};e[a][0].call(c.exports,function(t){var n=e[a][1][t];return i(n?n:t)},c,c.exports,t,e,n,r)}return n[a].exports}for(var o="function"==typeof require&&require,a=0;av;v++)g.push(h(e.slice(0,r))),e=e.slice(r);n.push(g)}else i.prefixedType("string")(t[f].type)?(c=c.slice(r),n.push(h(e.slice(0,r))),e=e.slice(r)):(n.push(h(e.slice(0,r))),e=e.slice(r))}),n},d=function(t){var e={};return t.forEach(function(t){var n=r.extractDisplayName(t.name),i=r.extractTypeName(t.name),o=function(){var e=Array.prototype.slice.call(arguments);return l(t.inputs,e)};void 0===e[n]&&(e[n]=o),e[n][i]=o}),e},g=function(t){var e={};return t.forEach(function(t){var n=r.extractDisplayName(t.name),i=r.extractTypeName(t.name),o=function(e){return h(t.outputs,e)};void 0===e[n]&&(e[n]=o),e[n][i]=o}),e},v=function(t){return n.sha3(n.fromAscii(t)).slice(0,2+2*o.ETH_SIGNATURE_LENGTH)},y=function(t){return n.sha3(n.fromAscii(t))};e.exports={inputParser:d,outputParser:g,formatInput:l,formatOutput:h,signatureFromAscii:v,eventSignatureFromAscii:y}},{"./const":2,"./formatters":6,"./types":11,"./utils":12,"./web3":13}],2:[function(t,e){var n=["wei","Kwei","Mwei","Gwei","szabo","finney","ether","grand","Mether","Gether","Tether","Pether","Eether","Zether","Yether","Nether","Dether","Vether","Uether"];e.exports={ETH_PADDING:32,ETH_SIGNATURE_LENGTH:4,ETH_UNITS:n,ETH_BIGNUMBER_ROUNDING_MODE:{ROUNDING_MODE:BigNumber.ROUND_DOWN}}},{}],3:[function(t,e){var n=t("./web3"),r=t("./abi"),i=t("./utils"),o=t("./event"),a=function(t){n._currentContractAbi=t.abi,n._currentContractAddress=t.address,n._currentContractMethodName=t.method,n._currentContractMethodParams=t.params},u=function(t){t.call=function(e){return t._isTransact=!1,t._options=e,t},t.transact=function(e){return t._isTransact=!0,t._options=e,t},t._options={},["gas","gasPrice","value","from"].forEach(function(e){t[e]=function(n){return t._options[e]=n,t}})},s=function(t,e,o){var u=r.inputParser(e),s=r.outputParser(e);i.filterFunctions(e).forEach(function(f){var c=i.extractDisplayName(f.name),l=i.extractTypeName(f.name),p=function(){var i=Array.prototype.slice.call(arguments),p=r.signatureFromAscii(f.name),m=u[c][l].apply(null,i),h=t._options||{};h.to=o,h.data=p+m;var d=t._isTransact===!0||t._isTransact!==!1&&!f.constant,g=h.collapse!==!1;if(t._options={},t._isTransact=null,d)return a({abi:e,address:o,method:f.name,params:i}),void n.eth.transact(h);var v=n.eth.call(h),y=s[c][l](v);return g&&(1===y.length?y=y[0]:0===y.length&&(y=null)),y};void 0===t[c]&&(t[c]=p),t[c][l]=p})},f=function(t,e,n){t.address=n,t._onWatchEventResult=function(t){var n=event.getMatchingEvent(i.filterEvents(e)),r=o.outputParser(n);return r(t)},Object.defineProperty(t,"topic",{get:function(){return i.filterEvents(e).map(function(t){return r.eventSignatureFromAscii(t.name)})}})},c=function(t,e,a){i.filterEvents(e).forEach(function(e){var u=function(){var t=Array.prototype.slice.call(arguments),i=r.eventSignatureFromAscii(e.name),u=o.inputParser(a,i,e),s=u.apply(null,t);return s._onWatchEventResult=function(t){var n=o.outputParser(e);return n(t)},n.eth.watch(s)};u._isEvent=!0;var s=i.extractDisplayName(e.name),f=i.extractTypeName(e.name);void 0===t[s]&&(t[s]=u),t[s][f]=u})},l=function(t,e){e.forEach(function(t){if(-1===t.name.indexOf("(")){var e=t.name,n=t.inputs.map(function(t){return t.type}).join();t.name=e+"("+n+")"}});var n={};return u(n),s(n,e,t),f(n,e,t),c(n,e,t),n};e.exports=l},{"./abi":1,"./event":4,"./utils":12,"./web3":13}],4:[function(t,e){var n=t("./abi"),r=t("./utils"),i=function(t,e){return t.filter(function(t){return t.indexed===e})},o=function(t,e){var n=r.findIndex(t,function(t){return t.name===e});return-1===n?void console.error("indexed param with name "+e+" not found"):t[n]},a=function(t,e){return Object.keys(e).map(function(r){var a=[o(i(t.inputs,!0),r)],u=e[r];return u instanceof Array?u.map(function(t){return n.formatInput(a,[t])}):n.formatInput(a,[u])})},u=function(t,e,n){return function(r,i){var o=i||{};return o.address=t,o.topic=[],o.topic.push(e),r&&(o.topic=o.topic.concat(a(n,r))),o}},s=function(t,e,n){e.slice(),n.slice();return t.reduce(function(t,r){var i;return i=r.indexed?e.splice(0,1)[0]:n.splice(0,1)[0],t[r.name]=i,t},{})},f=function(t){return function(e){var o={event:r.extractDisplayName(t.name),number:e.number,args:{}};if(!e.topic)return o;var a=i(t.inputs,!0),u="0x"+e.topic.slice(1,e.topic.length).map(function(t){return t.slice(2)}).join(""),f=n.formatOutput(a,u),c=i(t.inputs,!1),l=n.formatOutput(c,e.data);return o.args=s(t.inputs,f,l),o}},c=function(t,e){for(var r=0;rn;n+=2){var i=parseInt(t.substr(n,2),16);if(0===i)break;e+=String.fromCharCode(i)}return e},o=function(t){for(var e="",n=0;n3e3&&r2?t.substring(2):"0",new BigNumber(t,16).toString(10)},fromDecimal:function(t){return"0x"+new BigNumber(t).toString(16)},toEth:n.toEth,eth:{contractFromAbi:function(t){return function(e){e=e||"0xc6d9d2cd449a754c494264e1809c50e34d64562b";var n=p.eth.contract(e,t);return n.address=e,n}},watch:function(t,e,n){return t._isEvent?t(e,n):new p.filter(t,m)}},db:{},shh:{watch:function(t){return new p.filter(t,h)}}};c(p,r()),c(p.eth,i()),l(p.eth,o()),c(p.db,a()),c(p.shh,u());var m={changed:"eth_changed"};c(m,s());var h={changed:"shh_changed"};c(h,f()),p.setProvider=function(t){p.provider.set(t)},e.exports=p},{"./utils":12}],web3:[function(t,e){var n=t("./lib/web3"),r=t("./lib/providermanager");n.provider=new r,n.filter=t("./lib/filter"),n.providers.HttpSyncProvider=t("./lib/httpsync"),n.providers.QtSyncProvider=t("./lib/qtsync"),n.eth.contract=t("./lib/contract"),n.abi=t("./lib/abi"),e.exports=n},{"./lib/abi":1,"./lib/contract":3,"./lib/filter":5,"./lib/httpsync":7,"./lib/providermanager":9,"./lib/qtsync":10,"./lib/web3":13}]},{},["web3"]); \ No newline at end of file +require=function t(n,e,r){function o(i,u){if(!e[i]){if(!n[i]){var f="function"==typeof require&&require;if(!u&&f)return f(i,!0);if(a)return a(i,!0);var s=new Error("Cannot find module '"+i+"'");throw s.code="MODULE_NOT_FOUND",s}var c=e[i]={exports:{}};n[i][0].call(c.exports,function(t){var e=n[i][1][t];return o(e?e:t)},c,c.exports,t,n,e,r)}return e[i].exports}for(var a="function"==typeof require&&require,i=0;iv;v++)g.push(h(n.slice(0,r))),n=n.slice(r);e.push(g)}else o.prefixedType("string")(t[s].type)?(c=c.slice(r),e.push(h(n.slice(0,r))),n=n.slice(r)):(e.push(h(n.slice(0,r))),n=n.slice(r))}),e},d=function(t){var n={};return t.forEach(function(t){var e=r.extractDisplayName(t.name),o=r.extractTypeName(t.name),a=function(){var n=Array.prototype.slice.call(arguments);return l(t.inputs,n)};void 0===n[e]&&(n[e]=a),n[e][o]=a}),n},g=function(t){var n={};return t.forEach(function(t){var e=r.extractDisplayName(t.name),o=r.extractTypeName(t.name),a=function(n){return h(t.outputs,n)};void 0===n[e]&&(n[e]=a),n[e][o]=a}),n},v=function(t){return e.sha3(e.fromAscii(t)).slice(0,2+2*a.ETH_SIGNATURE_LENGTH)},y=function(t){return e.sha3(e.fromAscii(t))};n.exports={inputParser:d,outputParser:g,formatInput:l,formatOutput:h,signatureFromAscii:v,eventSignatureFromAscii:y}},{"./const":2,"./formatters":8,"./types":14,"./utils":15,"./web3":17}],2:[function(t,n){var e=["wei","Kwei","Mwei","Gwei","szabo","finney","ether","grand","Mether","Gether","Tether","Pether","Eether","Zether","Yether","Nether","Dether","Vether","Uether"];n.exports={ETH_PADDING:32,ETH_SIGNATURE_LENGTH:4,ETH_UNITS:e,ETH_BIGNUMBER_ROUNDING_MODE:{ROUNDING_MODE:BigNumber.ROUND_DOWN},ETH_POLLING_TIMEOUT:1e3}},{}],3:[function(t,n){var e=t("./web3"),r=t("./abi"),o=t("./utils"),a=t("./event"),i=(t("./filter"),function(t){e._currentContractAbi=t.abi,e._currentContractAddress=t.address,e._currentContractMethodName=t.method,e._currentContractMethodParams=t.params}),u=function(t){t.call=function(n){return t._isTransact=!1,t._options=n,t},t.transact=function(n){return t._isTransact=!0,t._options=n,t},t._options={},["gas","gasPrice","value","from"].forEach(function(n){t[n]=function(e){return t._options[n]=e,t}})},f=function(t,n,a){var u=r.inputParser(n),f=r.outputParser(n);o.filterFunctions(n).forEach(function(s){var c=o.extractDisplayName(s.name),l=o.extractTypeName(s.name),p=function(){var o=Array.prototype.slice.call(arguments),p=r.signatureFromAscii(s.name),m=u[c][l].apply(null,o),h=t._options||{};h.to=a,h.data=p+m;var d=t._isTransact===!0||t._isTransact!==!1&&!s.constant,g=h.collapse!==!1;if(t._options={},t._isTransact=null,d)return i({abi:n,address:a,method:s.name,params:o}),void e.eth.transact(h);var v=e.eth.call(h),y=f[c][l](v);return g&&(1===y.length?y=y[0]:0===y.length&&(y=null)),y};void 0===t[c]&&(t[c]=p),t[c][l]=p})},s=function(t,n,e){t.address=e,t._onWatchEventResult=function(t){var e=event.getMatchingEvent(o.filterEvents(n)),r=a.outputParser(e);return r(t)},Object.defineProperty(t,"topic",{get:function(){return o.filterEvents(n).map(function(t){return r.eventSignatureFromAscii(t.name)})}})},c=function(t,n,i){o.filterEvents(n).forEach(function(n){var u=function(){var t=Array.prototype.slice.call(arguments),o=r.eventSignatureFromAscii(n.name),u=a.inputParser(i,o,n),f=u.apply(null,t),s=function(t){var e=a.outputParser(n);return e(t)};return e.eth.watch(f,void 0,void 0,s)};u._isEvent=!0;var f=o.extractDisplayName(n.name),s=o.extractTypeName(n.name);void 0===t[f]&&(t[f]=u),t[f][s]=u})},l=function(t,n){n.forEach(function(t){if(-1===t.name.indexOf("(")){var n=t.name,e=t.inputs.map(function(t){return t.type}).join();t.name=n+"("+e+")"}});var e={};return u(e),f(e,n,t),s(e,n,t),c(e,n,t),e};n.exports=l},{"./abi":1,"./event":6,"./filter":7,"./utils":15,"./web3":17}],4:[function(t,n){var e=function(){return[{name:"put",call:"db_put"},{name:"get",call:"db_get"},{name:"putString",call:"db_putString"},{name:"getString",call:"db_getString"}]};n.exports={methods:e}},{}],5:[function(t,n){var e=function(){var t=function(t){return"string"==typeof t[0]?"eth_blockByHash":"eth_blockByNumber"},n=function(t){return"string"==typeof t[0]?"eth_transactionByHash":"eth_transactionByNumber"},e=function(t){return"string"==typeof t[0]?"eth_uncleByHash":"eth_uncleByNumber"},r=function(t){return"string"==typeof t[0]?"eth_transactionCountByHash":"eth_transactionCountByNumber"},o=function(t){return"string"==typeof t[0]?"eth_uncleCountByHash":"eth_uncleCountByNumber"};return[{name:"balanceAt",call:"eth_balanceAt"},{name:"stateAt",call:"eth_stateAt"},{name:"storageAt",call:"eth_storageAt"},{name:"countAt",call:"eth_countAt"},{name:"codeAt",call:"eth_codeAt"},{name:"transact",call:"eth_transact"},{name:"call",call:"eth_call"},{name:"block",call:t},{name:"transaction",call:n},{name:"uncle",call:e},{name:"compilers",call:"eth_compilers"},{name:"flush",call:"eth_flush"},{name:"lll",call:"eth_lll"},{name:"solidity",call:"eth_solidity"},{name:"serpent",call:"eth_serpent"},{name:"logs",call:"eth_logs"},{name:"transactionCount",call:r},{name:"uncleCount",call:o}]},r=function(){return[{name:"coinbase",getter:"eth_coinbase",setter:"eth_setCoinbase"},{name:"listening",getter:"eth_listening",setter:"eth_setListening"},{name:"mining",getter:"eth_mining",setter:"eth_setMining"},{name:"gasPrice",getter:"eth_gasPrice"},{name:"accounts",getter:"eth_accounts"},{name:"peerCount",getter:"eth_peerCount"},{name:"defaultBlock",getter:"eth_defaultBlock",setter:"eth_setDefaultBlock"},{name:"number",getter:"eth_number"}]};n.exports={methods:e,properties:r}},{}],6:[function(t,n){var e=t("./abi"),r=t("./utils"),o=function(t,n){return t.filter(function(t){return t.indexed===n})},a=function(t,n){var e=r.findIndex(t,function(t){return t.name===n});return-1===e?void console.error("indexed param with name "+n+" not found"):t[e]},i=function(t,n){return Object.keys(n).map(function(r){var i=[a(o(t.inputs,!0),r)],u=n[r];return u instanceof Array?u.map(function(t){return e.formatInput(i,[t])}):e.formatInput(i,[u])})},u=function(t,n,e){return function(r,o){var a=o||{};return a.address=t,a.topic=[],a.topic.push(n),r&&(a.topic=a.topic.concat(i(e,r))),a}},f=function(t,n,e){n.slice(),e.slice();return t.reduce(function(t,r){var o;return o=r.indexed?n.splice(0,1)[0]:e.splice(0,1)[0],t[r.name]=o,t},{})},s=function(t){return function(n){var a={event:r.extractDisplayName(t.name),number:n.number,args:{}};if(n.topics=n.topic,!n.topic)return a;var i=o(t.inputs,!0),u="0x"+n.topic.slice(1,n.topic.length).map(function(t){return t.slice(2)}).join(""),s=e.formatOutput(i,u),c=o(t.inputs,!1),l=e.formatOutput(c,n.data);return a.args=f(t.inputs,s,l),a}},c=function(t,n){for(var r=0;re;e+=2){var o=parseInt(t.substr(e,2),16);if(0===o)break;n+=String.fromCharCode(o)}return n},a=function(t){for(var n="",e=0;e3e3&&r2?t.substring(2):"0",new BigNumber(t,16).toString(10)},fromDecimal:function(t){return"0x"+new BigNumber(t).toString(16)},toEth:u.toEth,eth:{contractFromAbi:function(t){return function(n){n=n||"0xc6d9d2cd449a754c494264e1809c50e34d64562b";var e=g.eth.contract(n,t);return e.address=n,e}},watch:function(t,n,e,r){return t._isEvent?t(n,e):i(t,h,r)}},db:{},shh:{watch:function(t){return i(t,d)}},setProvider:function(t){g.manager.setProvider(t)},reset:function(){g.manager.reset()}};c(g,s()),c(g.eth,e.methods()),l(g.eth,e.properties()),c(g.db,r.methods()),c(g.shh,o.methods()),c(h,a.eth()),c(d,a.shh()),n.exports=g},{"./db":4,"./eth":5,"./filter":7,"./requestmanager":12,"./shh":13,"./utils":15,"./watches":16}],web3:[function(t,n){var e=t("./lib/web3");e.providers.HttpSyncProvider=t("./lib/httpsync"),e.providers.QtSyncProvider=t("./lib/qtsync"),e.eth.contract=t("./lib/contract"),e.abi=t("./lib/abi"),n.exports=e},{"./lib/abi":1,"./lib/contract":3,"./lib/httpsync":9,"./lib/qtsync":11,"./lib/web3":17}]},{},["web3"]); \ No newline at end of file diff --git a/libjsqrc/ethereumjs/gulpfile.js b/libjsqrc/ethereumjs/gulpfile.js index f8f6c96ce..61f7c9ebc 100644 --- a/libjsqrc/ethereumjs/gulpfile.js +++ b/libjsqrc/ethereumjs/gulpfile.js @@ -15,90 +15,55 @@ var unreach = require('unreachable-branch-transform'); var source = require('vinyl-source-stream'); var exorcist = require('exorcist'); var bower = require('bower'); +var streamify = require('gulp-streamify'); var DEST = './dist/'; - -var build = function(src, dst, ugly) { - var result = browserify({ - debug: true, - insert_global_vars: false, - detectGlobals: false, - bundleExternal: false - }) - .require('./' + src + '.js', {expose: 'web3'}) - .add('./' + src + '.js') - .transform('envify', { - NODE_ENV: 'build' - }) - .transform('unreachable-branch-transform'); - - if (ugly) { - result = result.transform('uglifyify', { - mangle: false, - compress: { - dead_code: false, - conditionals: true, - unused: false, - hoist_funs: true, - hoist_vars: true, - negate_iife: false - }, - beautify: true, - warnings: true - }); - } - - return result.bundle() - .pipe(exorcist(path.join( DEST, dst + '.js.map'))) - .pipe(source(dst + '.js')) - .pipe(gulp.dest( DEST )); -}; - -var uglifyFile = function(file) { - return gulp.src( DEST + file + '.js') - .pipe(uglify()) - .pipe(rename(file + '.min.js')) - .pipe(gulp.dest( DEST )); +var src = 'index'; +var dst = 'ethereum'; + +var browserifyOptions = { + debug: true, + insert_global_vars: false, + detectGlobals: false, + bundleExternal: false }; gulp.task('bower', function(cb){ - bower.commands.install().on('end', function (installed){ - console.log(installed); - cb(); - }); + bower.commands.install().on('end', function (installed){ + console.log(installed); + cb(); + }); }); gulp.task('clean', ['lint'], function(cb) { - del([ DEST ], cb); + del([ DEST ], cb); }); gulp.task('lint', function(){ - return gulp.src(['./*.js', './lib/*.js']) - .pipe(jshint()) - .pipe(jshint.reporter('default')); + return gulp.src(['./*.js', './lib/*.js']) + .pipe(jshint()) + .pipe(jshint.reporter('default')); }); gulp.task('build', ['clean'], function () { - return build('index', 'ethereum', true); -}); - -gulp.task('buildDev', ['clean'], function () { - return build('index', 'ethereum', false); -}); - -gulp.task('uglify', ['build'], function(){ - return uglifyFile('ethereum'); -}); - -gulp.task('uglifyDev', ['buildDev'], function(){ - return uglifyFile('ethereum'); + return browserify(browserifyOptions) + .require('./' + src + '.js', {expose: 'web3'}) + .add('./' + src + '.js') + .transform('envify', { NODE_ENV: 'build' }) + .transform('unreachable-branch-transform') + .bundle() + .pipe(exorcist(path.join( DEST, dst + '.js.map'))) + .pipe(source(dst + '.js')) + .pipe(gulp.dest( DEST )) + .pipe(streamify(uglify())) + .pipe(rename(dst + '.min.js')) + .pipe(gulp.dest( DEST )); }); gulp.task('watch', function() { - gulp.watch(['./lib/*.js'], ['lint', 'prepare', 'build']); + gulp.watch(['./lib/*.js'], ['lint', 'build']); }); -gulp.task('release', ['bower', 'lint', 'build', 'uglify']); -gulp.task('dev', ['bower', 'lint', 'buildDev', 'uglifyDev']); +gulp.task('dev', ['bower', 'lint', 'build']); gulp.task('default', ['dev']); diff --git a/libjsqrc/ethereumjs/index.js b/libjsqrc/ethereumjs/index.js index 76c923722..67c500fb7 100644 --- a/libjsqrc/ethereumjs/index.js +++ b/libjsqrc/ethereumjs/index.js @@ -1,11 +1,7 @@ var web3 = require('./lib/web3'); -var ProviderManager = require('./lib/providermanager'); -web3.provider = new ProviderManager(); -web3.filter = require('./lib/filter'); web3.providers.HttpSyncProvider = require('./lib/httpsync'); web3.providers.QtSyncProvider = require('./lib/qtsync'); web3.eth.contract = require('./lib/contract'); web3.abi = require('./lib/abi'); - module.exports = web3; diff --git a/libjsqrc/ethereumjs/lib/const.js b/libjsqrc/ethereumjs/lib/const.js index 8a17b794d..f7ccc9e28 100644 --- a/libjsqrc/ethereumjs/lib/const.js +++ b/libjsqrc/ethereumjs/lib/const.js @@ -51,6 +51,7 @@ module.exports = { ETH_PADDING: 32, ETH_SIGNATURE_LENGTH: 4, ETH_UNITS: ETH_UNITS, - ETH_BIGNUMBER_ROUNDING_MODE: { ROUNDING_MODE: BigNumber.ROUND_DOWN } + ETH_BIGNUMBER_ROUNDING_MODE: { ROUNDING_MODE: BigNumber.ROUND_DOWN }, + ETH_POLLING_TIMEOUT: 1000 }; diff --git a/libjsqrc/ethereumjs/lib/contract.js b/libjsqrc/ethereumjs/lib/contract.js index a0525bd9d..4b2cd5f65 100644 --- a/libjsqrc/ethereumjs/lib/contract.js +++ b/libjsqrc/ethereumjs/lib/contract.js @@ -24,6 +24,7 @@ var web3 = require('./web3'); var abi = require('./abi'); var utils = require('./utils'); var eventImpl = require('./event'); +var filter = require('./filter'); var exportNatspecGlobals = function (vars) { // it's used byt natspec.js @@ -145,11 +146,11 @@ var addEventsToContract = function (contract, desc, address) { var signature = abi.eventSignatureFromAscii(e.name); var event = eventImpl.inputParser(address, signature, e); var o = event.apply(null, params); - o._onWatchEventResult = function (data) { + var outputFormatter = function (data) { var parser = eventImpl.outputParser(e); return parser(data); }; - return web3.eth.watch(o); + return web3.eth.watch(o, undefined, undefined, outputFormatter); }; // this property should be used by eth.filter to check if object is an event diff --git a/libjsqrc/ethereumjs/lib/db.js b/libjsqrc/ethereumjs/lib/db.js new file mode 100644 index 000000000..5f5ebc2b1 --- /dev/null +++ b/libjsqrc/ethereumjs/lib/db.js @@ -0,0 +1,35 @@ +/* + This file is part of ethereum.js. + + ethereum.js is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ethereum.js 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with ethereum.js. If not, see . +*/ +/** @file db.js + * @authors: + * Marek Kotewicz + * @date 2015 + */ + +/// @returns an array of objects describing web3.db api methods +var methods = function () { + return [ + { name: 'put', call: 'db_put' }, + { name: 'get', call: 'db_get' }, + { name: 'putString', call: 'db_putString' }, + { name: 'getString', call: 'db_getString' } + ]; +}; + +module.exports = { + methods: methods +}; diff --git a/libjsqrc/ethereumjs/lib/eth.js b/libjsqrc/ethereumjs/lib/eth.js new file mode 100644 index 000000000..58ed5fa11 --- /dev/null +++ b/libjsqrc/ethereumjs/lib/eth.js @@ -0,0 +1,85 @@ +/* + This file is part of ethereum.js. + + ethereum.js is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ethereum.js 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with ethereum.js. If not, see . +*/ +/** @file eth.js + * @authors: + * Marek Kotewicz + * @date 2015 + */ + +/// @returns an array of objects describing web3.eth api methods +var methods = function () { + var blockCall = function (args) { + return typeof args[0] === "string" ? "eth_blockByHash" : "eth_blockByNumber"; + }; + + var transactionCall = function (args) { + return typeof args[0] === "string" ? 'eth_transactionByHash' : 'eth_transactionByNumber'; + }; + + var uncleCall = function (args) { + return typeof args[0] === "string" ? 'eth_uncleByHash' : 'eth_uncleByNumber'; + }; + + var transactionCountCall = function (args) { + return typeof args[0] === "string" ? 'eth_transactionCountByHash' : 'eth_transactionCountByNumber'; + }; + + var uncleCountCall = function (args) { + return typeof args[0] === "string" ? 'eth_uncleCountByHash' : 'eth_uncleCountByNumber'; + }; + + return [ + { name: 'balanceAt', call: 'eth_balanceAt' }, + { name: 'stateAt', call: 'eth_stateAt' }, + { name: 'storageAt', call: 'eth_storageAt' }, + { name: 'countAt', call: 'eth_countAt'}, + { name: 'codeAt', call: 'eth_codeAt' }, + { name: 'transact', call: 'eth_transact' }, + { name: 'call', call: 'eth_call' }, + { name: 'block', call: blockCall }, + { name: 'transaction', call: transactionCall }, + { name: 'uncle', call: uncleCall }, + { name: 'compilers', call: 'eth_compilers' }, + { name: 'flush', call: 'eth_flush' }, + { name: 'lll', call: 'eth_lll' }, + { name: 'solidity', call: 'eth_solidity' }, + { name: 'serpent', call: 'eth_serpent' }, + { name: 'logs', call: 'eth_logs' }, + { name: 'transactionCount', call: transactionCountCall }, + { name: 'uncleCount', call: uncleCountCall } + ]; +}; + +/// @returns an array of objects describing web3.eth api properties +var properties = function () { + return [ + { name: 'coinbase', getter: 'eth_coinbase', setter: 'eth_setCoinbase' }, + { name: 'listening', getter: 'eth_listening', setter: 'eth_setListening' }, + { name: 'mining', getter: 'eth_mining', setter: 'eth_setMining' }, + { name: 'gasPrice', getter: 'eth_gasPrice' }, + { name: 'accounts', getter: 'eth_accounts' }, + { name: 'peerCount', getter: 'eth_peerCount' }, + { name: 'defaultBlock', getter: 'eth_defaultBlock', setter: 'eth_setDefaultBlock' }, + { name: 'number', getter: 'eth_number'} + ]; +}; + +module.exports = { + methods: methods, + properties: properties +}; + diff --git a/libjsqrc/ethereumjs/lib/event.js b/libjsqrc/ethereumjs/lib/event.js index 0c41e0a39..f8b61f3f9 100644 --- a/libjsqrc/ethereumjs/lib/event.js +++ b/libjsqrc/ethereumjs/lib/event.js @@ -99,6 +99,7 @@ var outputParser = function (event) { args: {} }; + output.topics = output.topic; // fallback for go-ethereum if (!output.topic) { return result; } diff --git a/libjsqrc/ethereumjs/lib/filter.js b/libjsqrc/ethereumjs/lib/filter.js index 6ab2b7edc..cf04b44f1 100644 --- a/libjsqrc/ethereumjs/lib/filter.js +++ b/libjsqrc/ethereumjs/lib/filter.js @@ -23,79 +23,91 @@ * @date 2014 */ -var web3 = require('./web3'); // jshint ignore:line - -/// should be used when we want to watch something -/// it's using inner polling mechanism and is notified about changes -/// TODO: change 'options' name cause it may be not the best matching one, since we have events -var Filter = function(options, impl) { - - if (typeof options !== "string") { - - // topics property is deprecated, warn about it! - if (options.topics) { - console.warn('"topics" is deprecated, use "topic" instead'); - } - - this._onWatchResult = options._onWatchEventResult; - - // evaluate lazy properties - options = { - to: options.to, - topic: options.topic, - earliest: options.earliest, - latest: options.latest, - max: options.max, - skip: options.skip, - address: options.address - }; - - } - - this.impl = impl; - this.callbacks = []; - - this.id = impl.newFilter(options); - web3.provider.startPolling({method: impl.changed, params: [this.id]}, this.id, this.trigger.bind(this)); +/// Should be called to check if filter implementation is valid +/// @returns true if it is, otherwise false +var implementationIsValid = function (i) { + return !!i && + typeof i.newFilter === 'function' && + typeof i.getMessages === 'function' && + typeof i.uninstallFilter === 'function' && + typeof i.startPolling === 'function' && + typeof i.stopPolling === 'function'; }; -/// alias for changed* -Filter.prototype.arrived = function(callback) { - this.changed(callback); -}; -Filter.prototype.happened = function(callback) { - this.changed(callback); -}; +/// This method should be called on options object, to verify deprecated properties && lazy load dynamic ones +/// @param should be string or object +/// @returns options string or object +var getOptions = function (options) { + if (typeof options === 'string') { + return options; + } -/// gets called when there is new eth/shh message -Filter.prototype.changed = function(callback) { - this.callbacks.push(callback); -}; + options = options || {}; -/// trigger calling new message from people -Filter.prototype.trigger = function(messages) { - for (var i = 0; i < this.callbacks.length; i++) { - for (var j = 0; j < messages.length; j++) { - var message = this._onWatchResult ? this._onWatchResult(messages[j]) : messages[j]; - this.callbacks[i].call(this, message); - } + if (options.topics) { + console.warn('"topics" is deprecated, is "topic" instead'); } -}; -/// should be called to uninstall current filter -Filter.prototype.uninstall = function() { - this.impl.uninstallFilter(this.id); - web3.provider.stopPolling(this.id); + // evaluate lazy properties + return { + to: options.to, + topic: options.topic, + earliest: options.earliest, + latest: options.latest, + max: options.max, + skip: options.skip, + address: options.address + }; }; -/// should be called to manually trigger getting latest messages from the client -Filter.prototype.messages = function() { - return this.impl.getMessages(this.id); -}; +/// Should be used when we want to watch something +/// it's using inner polling mechanism and is notified about changes +/// @param options are filter options +/// @param implementation, an abstract polling implementation +/// @param formatter (optional), callback function which formats output before 'real' callback +var filter = function(options, implementation, formatter) { + if (!implementationIsValid(implementation)) { + console.error('filter implemenation is invalid'); + return; + } -/// alias for messages -Filter.prototype.logs = function () { - return this.messages(); + options = getOptions(options); + var callbacks = []; + var filterId = implementation.newFilter(options); + var onMessages = function (messages) { + messages.forEach(function (message) { + message = formatter ? formatter(message) : message; + callbacks.forEach(function (callback) { + callback(message); + }); + }); + }; + + implementation.startPolling(filterId, onMessages, implementation.uninstallFilter); + + var changed = function (callback) { + callbacks.push(callback); + }; + + var messages = function () { + return implementation.getMessages(filterId); + }; + + var uninstall = function (callback) { + implementation.stopPolling(filterId); + implementation.uninstallFilter(filterId); + callbacks = []; + }; + + return { + changed: changed, + arrived: changed, + happened: changed, + messages: messages, + logs: messages, + uninstall: uninstall + }; }; -module.exports = Filter; +module.exports = filter; + diff --git a/libjsqrc/ethereumjs/lib/httpsync.js b/libjsqrc/ethereumjs/lib/httpsync.js index 06e410ca8..b90fa746e 100644 --- a/libjsqrc/ethereumjs/lib/httpsync.js +++ b/libjsqrc/ethereumjs/lib/httpsync.js @@ -27,18 +27,20 @@ if (process.env.NODE_ENV !== 'build') { var HttpSyncProvider = function (host) { this.handlers = []; - this.host = host || 'http://localhost:8080'; + this.host = host || 'http://127.0.0.1:8080'; }; HttpSyncProvider.prototype.send = function (payload) { //var data = formatJsonRpcObject(payload); - + var request = new XMLHttpRequest(); request.open('POST', this.host, false); request.send(JSON.stringify(payload)); - - // check request.status + var result = request.responseText; + // check request.status + if(request.status !== 200) + return; return JSON.parse(result); }; diff --git a/libjsqrc/ethereumjs/lib/providermanager.js b/libjsqrc/ethereumjs/lib/providermanager.js deleted file mode 100644 index 55b072634..000000000 --- a/libjsqrc/ethereumjs/lib/providermanager.js +++ /dev/null @@ -1,102 +0,0 @@ -/* - This file is part of ethereum.js. - - ethereum.js is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - ethereum.js 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 Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with ethereum.js. If not, see . -*/ -/** @file providermanager.js - * @authors: - * Jeffrey Wilcke - * Marek Kotewicz - * Marian Oancea - * Gav Wood - * @date 2014 - */ - -var web3 = require('./web3'); -var jsonrpc = require('./jsonrpc'); - - -/** - * Provider manager object prototype - * It's responsible for passing messages to providers - * If no provider is set it's responsible for queuing requests - * It's also responsible for polling the ethereum node for incoming messages - * Default poll timeout is 12 seconds - * If we are running ethereum.js inside ethereum browser, there are backend based tools responsible for polling, - * and provider manager polling mechanism is not used - */ -var ProviderManager = function() { - this.polls = []; - this.provider = undefined; - - var self = this; - var poll = function () { - self.polls.forEach(function (data) { - var result = self.send(data.data); - - if (!(result instanceof Array) || result.length === 0) { - return; - } - - data.callback(result); - }); - - setTimeout(poll, 1000); - }; - poll(); -}; - -/// sends outgoing requests -/// @params data - an object with at least 'method' property -ProviderManager.prototype.send = function(data) { - var payload = jsonrpc.toPayload(data.method, data.params); - - if (this.provider === undefined) { - console.error('provider is not set'); - return null; - } - - var result = this.provider.send(payload); - - if (!jsonrpc.isValidResponse(result)) { - console.log(result); - return null; - } - - return result.result; -}; - -/// setups provider, which will be used for sending messages -ProviderManager.prototype.set = function(provider) { - this.provider = provider; -}; - -/// this method is only used, when we do not have native qt bindings and have to do polling on our own -/// should be callled, on start watching for eth/shh changes -ProviderManager.prototype.startPolling = function (data, pollId, callback) { - this.polls.push({data: data, id: pollId, callback: callback}); -}; - -/// should be called to stop polling for certain watch changes -ProviderManager.prototype.stopPolling = function (pollId) { - for (var i = this.polls.length; i--;) { - var poll = this.polls[i]; - if (poll.id === pollId) { - this.polls.splice(i, 1); - } - } -}; - -module.exports = ProviderManager; - diff --git a/libjsqrc/ethereumjs/lib/requestmanager.js b/libjsqrc/ethereumjs/lib/requestmanager.js new file mode 100644 index 000000000..6162b5f38 --- /dev/null +++ b/libjsqrc/ethereumjs/lib/requestmanager.js @@ -0,0 +1,103 @@ +/* + This file is part of ethereum.js. + + ethereum.js is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ethereum.js 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with ethereum.js. If not, see . +*/ +/** @file requestmanager.js + * @authors: + * Jeffrey Wilcke + * Marek Kotewicz + * Marian Oancea + * Gav Wood + * @date 2014 + */ + +var jsonrpc = require('./jsonrpc'); +var c = require('./const'); + +/** + * It's responsible for passing messages to providers + * It's also responsible for polling the ethereum node for incoming messages + * Default poll timeout is 1 second + */ +var requestManager = function() { + var polls = []; + var provider; + + var send = function (data) { + var payload = jsonrpc.toPayload(data.method, data.params); + + if (!provider) { + console.error('provider is not set'); + return null; + } + + var result = provider.send(payload); + + if (!jsonrpc.isValidResponse(result)) { + console.log(result); + return null; + } + + return result.result; + }; + + var setProvider = function (p) { + provider = p; + }; + + var startPolling = function (data, pollId, callback, uninstall) { + polls.push({data: data, id: pollId, callback: callback, uninstall: uninstall}); + }; + + var stopPolling = function (pollId) { + for (var i = polls.length; i--;) { + var poll = polls[i]; + if (poll.id === pollId) { + polls.splice(i, 1); + } + } + }; + + var reset = function () { + polls.forEach(function (poll) { + poll.uninstall(poll.id); + }); + polls = []; + }; + + var poll = function () { + polls.forEach(function (data) { + var result = send(data.data); + if (!(result instanceof Array) || result.length === 0) { + return; + } + data.callback(result); + }); + setTimeout(poll, c.ETH_POLLING_TIMEOUT); + }; + + poll(); + + return { + send: send, + setProvider: setProvider, + startPolling: startPolling, + stopPolling: stopPolling, + reset: reset + }; +}; + +module.exports = requestManager; + diff --git a/libjsqrc/ethereumjs/lib/shh.js b/libjsqrc/ethereumjs/lib/shh.js new file mode 100644 index 000000000..563e71d27 --- /dev/null +++ b/libjsqrc/ethereumjs/lib/shh.js @@ -0,0 +1,37 @@ +/* + This file is part of ethereum.js. + + ethereum.js is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ethereum.js 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with ethereum.js. If not, see . +*/ +/** @file shh.js + * @authors: + * Marek Kotewicz + * @date 2015 + */ + +/// @returns an array of objects describing web3.shh api methods +var methods = function () { + return [ + { name: 'post', call: 'shh_post' }, + { name: 'newIdentity', call: 'shh_newIdentity' }, + { name: 'haveIdentity', call: 'shh_haveIdentity' }, + { name: 'newGroup', call: 'shh_newGroup' }, + { name: 'addToGroup', call: 'shh_addToGroup' } + ]; +}; + +module.exports = { + methods: methods +}; + diff --git a/libjsqrc/ethereumjs/lib/watches.js b/libjsqrc/ethereumjs/lib/watches.js new file mode 100644 index 000000000..84ff38922 --- /dev/null +++ b/libjsqrc/ethereumjs/lib/watches.js @@ -0,0 +1,49 @@ +/* + This file is part of ethereum.js. + + ethereum.js is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ethereum.js 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with ethereum.js. If not, see . +*/ +/** @file watches.js + * @authors: + * Marek Kotewicz + * @date 2015 + */ + +/// @returns an array of objects describing web3.eth.watch api methods +var eth = function () { + var newFilter = function (args) { + return typeof args[0] === 'string' ? 'eth_newFilterString' : 'eth_newFilter'; + }; + + return [ + { name: 'newFilter', call: newFilter }, + { name: 'uninstallFilter', call: 'eth_uninstallFilter' }, + { name: 'getMessages', call: 'eth_filterLogs' } + ]; +}; + +/// @returns an array of objects describing web3.shh.watch api methods +var shh = function () { + return [ + { name: 'newFilter', call: 'shh_newFilter' }, + { name: 'uninstallFilter', call: 'shh_uninstallFilter' }, + { name: 'getMessages', call: 'shh_getMessages' } + ]; +}; + +module.exports = { + eth: eth, + shh: shh +}; + diff --git a/libjsqrc/ethereumjs/lib/web3.js b/libjsqrc/ethereumjs/lib/web3.js index 41df75051..1d8d0fba8 100644 --- a/libjsqrc/ethereumjs/lib/web3.js +++ b/libjsqrc/ethereumjs/lib/web3.js @@ -27,7 +27,13 @@ if (process.env.NODE_ENV !== 'build') { var BigNumber = require('bignumber.js'); } +var eth = require('./eth'); +var db = require('./db'); +var shh = require('./shh'); +var watches = require('./watches'); +var filter = require('./filter'); var utils = require('./utils'); +var requestManager = require('./requestmanager'); /// @returns an array of objects describing web3 api methods var web3Methods = function () { @@ -36,98 +42,6 @@ var web3Methods = function () { ]; }; -/// @returns an array of objects describing web3.eth api methods -var ethMethods = function () { - var blockCall = function (args) { - return typeof args[0] === "string" ? "eth_blockByHash" : "eth_blockByNumber"; - }; - - var transactionCall = function (args) { - return typeof args[0] === "string" ? 'eth_transactionByHash' : 'eth_transactionByNumber'; - }; - - var uncleCall = function (args) { - return typeof args[0] === "string" ? 'eth_uncleByHash' : 'eth_uncleByNumber'; - }; - - var methods = [ - { name: 'balanceAt', call: 'eth_balanceAt' }, - { name: 'stateAt', call: 'eth_stateAt' }, - { name: 'storageAt', call: 'eth_storageAt' }, - { name: 'countAt', call: 'eth_countAt'}, - { name: 'codeAt', call: 'eth_codeAt' }, - { name: 'transact', call: 'eth_transact' }, - { name: 'call', call: 'eth_call' }, - { name: 'block', call: blockCall }, - { name: 'transaction', call: transactionCall }, - { name: 'uncle', call: uncleCall }, - { name: 'compilers', call: 'eth_compilers' }, - { name: 'flush', call: 'eth_flush' }, - { name: 'lll', call: 'eth_lll' }, - { name: 'solidity', call: 'eth_solidity' }, - { name: 'serpent', call: 'eth_serpent' }, - { name: 'logs', call: 'eth_logs' } - ]; - return methods; -}; - -/// @returns an array of objects describing web3.eth api properties -var ethProperties = function () { - return [ - { name: 'coinbase', getter: 'eth_coinbase', setter: 'eth_setCoinbase' }, - { name: 'listening', getter: 'eth_listening', setter: 'eth_setListening' }, - { name: 'mining', getter: 'eth_mining', setter: 'eth_setMining' }, - { name: 'gasPrice', getter: 'eth_gasPrice' }, - { name: 'accounts', getter: 'eth_accounts' }, - { name: 'peerCount', getter: 'eth_peerCount' }, - { name: 'defaultBlock', getter: 'eth_defaultBlock', setter: 'eth_setDefaultBlock' }, - { name: 'number', getter: 'eth_number'} - ]; -}; - -/// @returns an array of objects describing web3.db api methods -var dbMethods = function () { - return [ - { name: 'put', call: 'db_put' }, - { name: 'get', call: 'db_get' }, - { name: 'putString', call: 'db_putString' }, - { name: 'getString', call: 'db_getString' } - ]; -}; - -/// @returns an array of objects describing web3.shh api methods -var shhMethods = function () { - return [ - { name: 'post', call: 'shh_post' }, - { name: 'newIdentity', call: 'shh_newIdentity' }, - { name: 'haveIdentity', call: 'shh_haveIdentity' }, - { name: 'newGroup', call: 'shh_newGroup' }, - { name: 'addToGroup', call: 'shh_addToGroup' } - ]; -}; - -/// @returns an array of objects describing web3.eth.watch api methods -var ethWatchMethods = function () { - var newFilter = function (args) { - return typeof args[0] === 'string' ? 'eth_newFilterString' : 'eth_newFilter'; - }; - - return [ - { name: 'newFilter', call: newFilter }, - { name: 'uninstallFilter', call: 'eth_uninstallFilter' }, - { name: 'getMessages', call: 'eth_filterLogs' } - ]; -}; - -/// @returns an array of objects describing web3.shh.watch api methods -var shhWatchMethods = function () { - return [ - { name: 'newFilter', call: 'shh_newFilter' }, - { name: 'uninstallFilter', call: 'shh_uninstallFilter' }, - { name: 'getMessages', call: 'shh_getMessages' } - ]; -}; - /// creates methods in a given object based on method description on input /// setups api calls for these methods var setupMethods = function (obj, methods) { @@ -135,7 +49,7 @@ var setupMethods = function (obj, methods) { obj[method.name] = function () { var args = Array.prototype.slice.call(arguments); var call = typeof method.call === 'function' ? method.call(args) : method.call; - return web3.provider.send({ + return web3.manager.send({ method: call, params: args }); @@ -149,14 +63,14 @@ var setupProperties = function (obj, properties) { properties.forEach(function (property) { var proto = {}; proto.get = function () { - return web3.provider.send({ + return web3.manager.send({ method: property.getter }); }; if (property.setter) { proto.set = function (val) { - return web3.provider.send({ + return web3.manager.send({ method: property.setter, params: [val] }); @@ -166,10 +80,30 @@ var setupProperties = function (obj, properties) { }); }; +var startPolling = function (method, id, callback, uninstall) { + web3.manager.startPolling({ + method: method, + params: [id] + }, id, callback, uninstall); +}; + +var stopPolling = function (id) { + web3.manager.stopPolling(id); +}; + +var ethWatch = { + startPolling: startPolling.bind(null, 'eth_changed'), + stopPolling: stopPolling +}; + +var shhWatch = { + startPolling: startPolling.bind(null, 'shh_changed'), + stopPolling: stopPolling +}; + /// setups web3 object, and it's in-browser executed methods var web3 = { - _callbacks: {}, - _events: {}, + manager: requestManager(), providers: {}, /// @returns ascii string representation of hex value prefixed with 0x @@ -208,11 +142,12 @@ var web3 = { /// @param filter may be a string, object or event /// @param indexed is optional, this is an object with optional event indexed params /// @param options is optional, this is an object with optional event options ('max'...) - watch: function (filter, indexed, options) { - if (filter._isEvent) { - return filter(indexed, options); + /// TODO: fix it, 4 params? no way + watch: function (fil, indexed, options, formatter) { + if (fil._isEvent) { + return fil(indexed, options); } - return new web3.filter(filter, ethWatch); + return filter(fil, ethWatch, formatter); } }, @@ -221,36 +156,30 @@ var web3 = { /// shh object prototype shh: { - /// @param filter may be a string, object or event - watch: function (filter, indexed) { - return new web3.filter(filter, shhWatch); + watch: function (fil) { + return filter(fil, shhWatch); } }, + setProvider: function (provider) { + web3.manager.setProvider(provider); + }, + + /// Should be called to reset state of web3 object + /// Resets everything except manager + reset: function () { + web3.manager.reset(); + } }; /// setups all api methods setupMethods(web3, web3Methods()); -setupMethods(web3.eth, ethMethods()); -setupProperties(web3.eth, ethProperties()); -setupMethods(web3.db, dbMethods()); -setupMethods(web3.shh, shhMethods()); - -var ethWatch = { - changed: 'eth_changed' -}; - -setupMethods(ethWatch, ethWatchMethods()); - -var shhWatch = { - changed: 'shh_changed' -}; - -setupMethods(shhWatch, shhWatchMethods()); - -web3.setProvider = function(provider) { - web3.provider.set(provider); -}; +setupMethods(web3.eth, eth.methods()); +setupProperties(web3.eth, eth.properties()); +setupMethods(web3.db, db.methods()); +setupMethods(web3.shh, shh.methods()); +setupMethods(ethWatch, watches.eth()); +setupMethods(shhWatch, watches.shh()); module.exports = web3; diff --git a/libjsqrc/ethereumjs/package.json b/libjsqrc/ethereumjs/package.json index 8102a2592..40b3349e5 100644 --- a/libjsqrc/ethereumjs/package.json +++ b/libjsqrc/ethereumjs/package.json @@ -1,38 +1,42 @@ { "name": "ethereum.js", "namespace": "ethereum", - "version": "0.0.13", + "version": "0.0.15", "description": "Ethereum Compatible JavaScript API", "main": "./index.js", "directories": { "lib": "./lib" }, "dependencies": { + "bignumber.js": ">=2.0.0", "ws": "*", - "xmlhttprequest": "*", - "bignumber.js": ">=2.0.0" + "xmlhttprequest": "*" }, "devDependencies": { "bower": ">=1.3.0", "browserify": ">=6.0", + "coveralls": "^2.11.2", "del": ">=0.1.1", "envify": "^3.0.0", "exorcist": "^0.1.6", "gulp": ">=3.4.0", "gulp-jshint": ">=1.5.0", "gulp-rename": ">=1.2.0", + "gulp-streamify": "0.0.5", "gulp-uglify": ">=1.0.0", + "istanbul": "^0.3.5", "jshint": ">=2.5.0", - "uglifyify": "^2.6.0", + "mocha": ">=2.1.0", + "mocha-lcov-reporter": "0.0.1", "unreachable-branch-transform": "^0.1.0", - "vinyl-source-stream": "^1.0.0", - "mocha": ">=2.1.0" + "vinyl-source-stream": "^1.0.0" }, "scripts": { "build": "gulp", "watch": "gulp watch", "lint": "gulp lint", - "test": "mocha" + "test": "mocha", + "test-coveralls": "istanbul cover _mocha -- -R spec && cat coverage/lcov.info | coveralls --verbose" }, "repository": { "type": "git", diff --git a/libjsqrc/ethereumjs/test/eth.methods.js b/libjsqrc/ethereumjs/test/eth.methods.js index 8f10b441d..9ea0ad59a 100644 --- a/libjsqrc/ethereumjs/test/eth.methods.js +++ b/libjsqrc/ethereumjs/test/eth.methods.js @@ -19,6 +19,8 @@ describe('web3', function() { u.methodExists(web3.eth, 'solidity'); u.methodExists(web3.eth, 'serpent'); u.methodExists(web3.eth, 'logs'); + u.methodExists(web3.eth, 'transactionCount'); + u.methodExists(web3.eth, 'uncleCount'); u.propertyExists(web3.eth, 'coinbase'); u.propertyExists(web3.eth, 'listening'); diff --git a/libjsqrc/ethereumjs/test/filter.methods.js b/libjsqrc/ethereumjs/test/filter.methods.js new file mode 100644 index 000000000..9f81ec38f --- /dev/null +++ b/libjsqrc/ethereumjs/test/filter.methods.js @@ -0,0 +1,27 @@ +var assert = require('assert'); +var filter = require('../lib/filter'); +var u = require('./test.utils.js'); + +var empty = function () {}; +var implementation = { + newFilter: empty, + getMessages: empty, + uninstallFilter: empty, + startPolling: empty, + stopPolling: empty, +}; + +describe('web3', function () { + describe('eth', function () { + describe('filter', function () { + var f = filter({}, implementation); + + u.methodExists(f, 'arrived'); + u.methodExists(f, 'happened'); + u.methodExists(f, 'changed'); + u.methodExists(f, 'messages'); + u.methodExists(f, 'logs'); + u.methodExists(f, 'uninstall'); + }); + }); +}); diff --git a/libjsqrc/ethereumjs/test/web3.methods.js b/libjsqrc/ethereumjs/test/web3.methods.js index 06de41da4..8dcc61101 100644 --- a/libjsqrc/ethereumjs/test/web3.methods.js +++ b/libjsqrc/ethereumjs/test/web3.methods.js @@ -6,5 +6,16 @@ describe('web3', function() { u.methodExists(web3, 'sha3'); u.methodExists(web3, 'toAscii'); u.methodExists(web3, 'fromAscii'); + u.methodExists(web3, 'toDecimal'); + u.methodExists(web3, 'fromDecimal'); + u.methodExists(web3, 'toEth'); + u.methodExists(web3, 'setProvider'); + u.methodExists(web3, 'reset'); + + u.propertyExists(web3, 'manager'); + u.propertyExists(web3, 'providers'); + u.propertyExists(web3, 'eth'); + u.propertyExists(web3, 'db'); + u.propertyExists(web3, 'shh'); }); diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index f117df37a..44a17fcb5 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -630,6 +630,9 @@ void Host::disconnectLatePeers() bytes Host::saveNetwork() const { + if (!m_nodeTable) + return bytes(); + std::list peers; { RecursiveGuard l(x_sessions); @@ -665,17 +668,20 @@ bytes Host::saveNetwork() const } } - auto state = m_nodeTable->snapshot(); - state.sort(); - for (auto const& s: state) + if (!!m_nodeTable) { - network.appendList(3); - if (s.endpoint.tcp.address().is_v4()) - network << s.endpoint.tcp.address().to_v4().to_bytes(); - else - network << s.endpoint.tcp.address().to_v6().to_bytes(); - network << s.endpoint.tcp.port() << s.id; - count++; + auto state = m_nodeTable->snapshot(); + state.sort(); + for (auto const& s: state) + { + network.appendList(3); + if (s.endpoint.tcp.address().is_v4()) + network << s.endpoint.tcp.address().to_v4().to_bytes(); + else + network << s.endpoint.tcp.address().to_v6().to_bytes(); + network << s.endpoint.tcp.port() << s.id; + count++; + } } RLPStream ret(3); diff --git a/libp2p/UDP.cpp b/libp2p/UDP.cpp index e27b6e57a..5d9cdab79 100644 --- a/libp2p/UDP.cpp +++ b/libp2p/UDP.cpp @@ -38,9 +38,9 @@ h256 RLPXDatagramFace::sign(Secret const& _k) Signature sig = dev::sign(_k, sighash); // S(H(type||data)) data.resize(h256::size + Signature::size + rlpx.size()); - bytesConstRef rlpxHash(&data[0], h256::size); - bytesConstRef rlpxSig(&data[h256::size], Signature::size); - bytesConstRef rlpxPayload(&data[h256::size + Signature::size], rlpx.size()); + bytesRef rlpxHash(&data[0], h256::size); + bytesRef rlpxSig(&data[h256::size], Signature::size); + bytesRef rlpxPayload(&data[h256::size + Signature::size], rlpx.size()); sig.ref().copyTo(rlpxSig); rlpx.copyTo(rlpxPayload); diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index c6d8f5c58..a18785ae1 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -77,6 +77,9 @@ void ContractDefinition::checkTypeRequirements() for (ASTPointer const& function: getDefinedFunctions()) function->checkTypeRequirements(); + for (ASTPointer const& variable: m_stateVariables) + variable->checkTypeRequirements(); + // check for hash collisions in function signatures set> hashes; for (auto const& it: getInterfaceFunctionList()) @@ -274,15 +277,6 @@ TypePointer FunctionDefinition::getType(ContractDefinition const*) const void FunctionDefinition::checkTypeRequirements() { - // change all byte arrays parameters to point to calldata - if (getVisibility() == Visibility::External) - for (ASTPointer const& var: getParameters()) - { - auto const& type = var->getType(); - solAssert(!!type, ""); - if (auto const* byteArrayType = dynamic_cast(type.get())) - var->setType(byteArrayType->copyForLocation(ByteArrayType::Location::CallData)); - } for (ASTPointer const& var: getParameters() + getReturnParameters()) if (!var->getType()->canLiveOutsideStorage()) BOOST_THROW_EXCEPTION(var->createTypeError("Type is required to live outside storage.")); @@ -299,16 +293,20 @@ string FunctionDefinition::getCanonicalSignature() const bool VariableDeclaration::isLValue() const { - if (auto const* function = dynamic_cast(getScope())) - if (function->getVisibility() == Declaration::Visibility::External && isFunctionParameter()) - return false; - return true; + // External function parameters are Read-Only + return !isExternalFunctionParameter(); } -bool VariableDeclaration::isFunctionParameter() const +void VariableDeclaration::checkTypeRequirements() +{ + if (m_value) + m_value->checkTypeRequirements(); +} + +bool VariableDeclaration::isExternalFunctionParameter() const { auto const* function = dynamic_cast(getScope()); - if (!function) + if (!function || function->getVisibility() != Declaration::Visibility::External) return false; for (auto const& variable: function->getParameters()) if (variable.get() == this) @@ -401,26 +399,26 @@ void Return::checkTypeRequirements() m_expression->expectType(*m_returnParameters->getParameters().front()->getType()); } -void VariableDefinition::checkTypeRequirements() +void VariableDeclarationStatement::checkTypeRequirements() { // Variables can be declared without type (with "var"), in which case the first assignment // sets the type. // Note that assignments before the first declaration are legal because of the special scoping // rules inherited from JavaScript. - if (m_value) + if (m_variable->getValue()) { if (m_variable->getType()) - m_value->expectType(*m_variable->getType()); + m_variable->getValue()->expectType(*m_variable->getType()); else { // no type declared and no previous assignment, infer the type - m_value->checkTypeRequirements(); - TypePointer type = m_value->getType(); + m_variable->getValue()->checkTypeRequirements(); + TypePointer type = m_variable->getValue()->getType(); if (type->getCategory() == Type::Category::IntegerConstant) { auto intType = dynamic_pointer_cast(type)->getIntegerType(); if (!intType) - BOOST_THROW_EXCEPTION(m_value->createTypeError("Invalid integer constant " + type->toString())); + BOOST_THROW_EXCEPTION(m_variable->getValue()->createTypeError("Invalid integer constant " + type->toString())); type = intType; } else if (type->getCategory() == Type::Category::Void) @@ -429,7 +427,6 @@ void VariableDefinition::checkTypeRequirements() } } } - void Assignment::checkTypeRequirements() { m_leftHandSide->checkTypeRequirements(); diff --git a/libsolidity/AST.h b/libsolidity/AST.h index 62855bc7a..064457d3b 100644 --- a/libsolidity/AST.h +++ b/libsolidity/AST.h @@ -432,14 +432,17 @@ class VariableDeclaration: public Declaration { public: VariableDeclaration(Location const& _location, ASTPointer const& _type, - ASTPointer const& _name, Visibility _visibility, - bool _isStateVar = false, bool _isIndexed = false): - Declaration(_location, _name, _visibility), m_typeName(_type), - m_isStateVariable(_isStateVar), m_isIndexed(_isIndexed) {} + ASTPointer const& _name, ASTPointer _value, + Visibility _visibility, + bool _isStateVar = false, bool _isIndexed = false): + Declaration(_location, _name, _visibility), + m_typeName(_type), m_value(_value), + m_isStateVariable(_isStateVar), m_isIndexed(_isIndexed) {} virtual void accept(ASTVisitor& _visitor) override; virtual void accept(ASTConstVisitor& _visitor) const override; TypeName const* getTypeName() const { return m_typeName.get(); } + ASTPointer const& getValue() const { return m_value; } /// Returns the declared or inferred type. Can be an empty pointer if no type was explicitly /// declared and there is no assignment to the variable that fixes the type. @@ -447,8 +450,11 @@ public: void setType(std::shared_ptr const& _type) { m_type = _type; } virtual bool isLValue() const override; + + /// Calls checkTypeRequirments for all state variables. + void checkTypeRequirements(); bool isLocalVariable() const { return !!dynamic_cast(getScope()); } - bool isFunctionParameter() const; + bool isExternalFunctionParameter() const; bool isStateVariable() const { return m_isStateVariable; } bool isIndexed() const { return m_isIndexed; } @@ -457,6 +463,7 @@ protected: private: ASTPointer m_typeName; ///< can be empty ("var") + ASTPointer m_value; ///< the assigned value, can be missing bool m_isStateVariable; ///< Whether or not this is a contract state variable bool m_isIndexed; ///< Whether this is an indexed variable (used by events). @@ -833,22 +840,20 @@ private: * also be "var") but the actual assignment can be missing. * Examples: var a = 2; uint256 a; */ -class VariableDefinition: public Statement +class VariableDeclarationStatement: public Statement { public: - VariableDefinition(Location const& _location, ASTPointer _variable, - ASTPointer _value): - Statement(_location), m_variable(_variable), m_value(_value) {} + VariableDeclarationStatement(Location const& _location, ASTPointer _variable): + Statement(_location), m_variable(_variable) {} virtual void accept(ASTVisitor& _visitor) override; virtual void accept(ASTConstVisitor& _visitor) const override; virtual void checkTypeRequirements() override; VariableDeclaration const& getDeclaration() const { return *m_variable; } - Expression const* getExpression() const { return m_value.get(); } + Expression const* getExpression() const { return m_variable->getValue().get(); } private: ASTPointer m_variable; - ASTPointer m_value; ///< the assigned value, can be missing }; /** diff --git a/libsolidity/ASTForward.h b/libsolidity/ASTForward.h index 0b6817e45..3a151b63e 100644 --- a/libsolidity/ASTForward.h +++ b/libsolidity/ASTForward.h @@ -63,7 +63,7 @@ class ForStatement; class Continue; class Break; class Return; -class VariableDefinition; +class VariableDeclarationStatement; class ExpressionStatement; class Expression; class Assignment; diff --git a/libsolidity/ASTJsonConverter.cpp b/libsolidity/ASTJsonConverter.cpp index 04feafe2f..c30e4ca2b 100644 --- a/libsolidity/ASTJsonConverter.cpp +++ b/libsolidity/ASTJsonConverter.cpp @@ -198,7 +198,7 @@ bool ASTJsonConverter::visit(Return const&) return true; } -bool ASTJsonConverter::visit(VariableDefinition const&) +bool ASTJsonConverter::visit(VariableDeclarationStatement const&) { addJsonNode("VariableDefinition", {}, true); return true; @@ -394,7 +394,7 @@ void ASTJsonConverter::endVisit(Return const&) goUp(); } -void ASTJsonConverter::endVisit(VariableDefinition const&) +void ASTJsonConverter::endVisit(VariableDeclarationStatement const&) { goUp(); } diff --git a/libsolidity/ASTJsonConverter.h b/libsolidity/ASTJsonConverter.h index 466801e9c..30a92e66c 100644 --- a/libsolidity/ASTJsonConverter.h +++ b/libsolidity/ASTJsonConverter.h @@ -64,7 +64,7 @@ public: bool visit(Continue const& _node) override; bool visit(Break const& _node) override; bool visit(Return const& _node) override; - bool visit(VariableDefinition const& _node) override; + bool visit(VariableDeclarationStatement const& _node) override; bool visit(ExpressionStatement const& _node) override; bool visit(Expression const& _node) override; bool visit(Assignment const& _node) override; @@ -98,7 +98,7 @@ public: void endVisit(Continue const&) override; void endVisit(Break const&) override; void endVisit(Return const&) override; - void endVisit(VariableDefinition const&) override; + void endVisit(VariableDeclarationStatement const&) override; void endVisit(ExpressionStatement const&) override; void endVisit(Expression const&) override; void endVisit(Assignment const&) override; diff --git a/libsolidity/ASTPrinter.cpp b/libsolidity/ASTPrinter.cpp index d380b0029..209bb73e6 100644 --- a/libsolidity/ASTPrinter.cpp +++ b/libsolidity/ASTPrinter.cpp @@ -225,9 +225,9 @@ bool ASTPrinter::visit(Return const& _node) return goDeeper(); } -bool ASTPrinter::visit(VariableDefinition const& _node) +bool ASTPrinter::visit(VariableDeclarationStatement const& _node) { - writeLine("VariableDefinition"); + writeLine("VariableDeclarationStatement"); printSourcePart(_node); return goDeeper(); } @@ -469,7 +469,7 @@ void ASTPrinter::endVisit(Return const&) m_indentation--; } -void ASTPrinter::endVisit(VariableDefinition const&) +void ASTPrinter::endVisit(VariableDeclarationStatement const&) { m_indentation--; } diff --git a/libsolidity/ASTPrinter.h b/libsolidity/ASTPrinter.h index d9072aacc..7a0ef5a65 100644 --- a/libsolidity/ASTPrinter.h +++ b/libsolidity/ASTPrinter.h @@ -68,7 +68,7 @@ public: bool visit(Continue const& _node) override; bool visit(Break const& _node) override; bool visit(Return const& _node) override; - bool visit(VariableDefinition const& _node) override; + bool visit(VariableDeclarationStatement const& _node) override; bool visit(ExpressionStatement const& _node) override; bool visit(Expression const& _node) override; bool visit(Assignment const& _node) override; @@ -109,7 +109,7 @@ public: void endVisit(Continue const&) override; void endVisit(Break const&) override; void endVisit(Return const&) override; - void endVisit(VariableDefinition const&) override; + void endVisit(VariableDeclarationStatement const&) override; void endVisit(ExpressionStatement const&) override; void endVisit(Expression const&) override; void endVisit(Assignment const&) override; diff --git a/libsolidity/ASTVisitor.h b/libsolidity/ASTVisitor.h index a7fa6b1cf..2ecfbe4b1 100644 --- a/libsolidity/ASTVisitor.h +++ b/libsolidity/ASTVisitor.h @@ -69,7 +69,7 @@ public: virtual bool visit(Continue&) { return true; } virtual bool visit(Break&) { return true; } virtual bool visit(Return&) { return true; } - virtual bool visit(VariableDefinition&) { return true; } + virtual bool visit(VariableDeclarationStatement&) { return true; } virtual bool visit(ExpressionStatement&) { return true; } virtual bool visit(Expression&) { return true; } virtual bool visit(Assignment&) { return true; } @@ -112,7 +112,7 @@ public: virtual void endVisit(Continue&) { } virtual void endVisit(Break&) { } virtual void endVisit(Return&) { } - virtual void endVisit(VariableDefinition&) { } + virtual void endVisit(VariableDeclarationStatement&) { } virtual void endVisit(ExpressionStatement&) { } virtual void endVisit(Expression&) { } virtual void endVisit(Assignment&) { } @@ -159,7 +159,7 @@ public: virtual bool visit(Continue const&) { return true; } virtual bool visit(Break const&) { return true; } virtual bool visit(Return const&) { return true; } - virtual bool visit(VariableDefinition const&) { return true; } + virtual bool visit(VariableDeclarationStatement const&) { return true; } virtual bool visit(ExpressionStatement const&) { return true; } virtual bool visit(Expression const&) { return true; } virtual bool visit(Assignment const&) { return true; } @@ -202,7 +202,7 @@ public: virtual void endVisit(Continue const&) { } virtual void endVisit(Break const&) { } virtual void endVisit(Return const&) { } - virtual void endVisit(VariableDefinition const&) { } + virtual void endVisit(VariableDeclarationStatement const&) { } virtual void endVisit(ExpressionStatement const&) { } virtual void endVisit(Expression const&) { } virtual void endVisit(Assignment const&) { } diff --git a/libsolidity/AST_accept.h b/libsolidity/AST_accept.h index b71e103df..5bd6993db 100644 --- a/libsolidity/AST_accept.h +++ b/libsolidity/AST_accept.h @@ -196,16 +196,24 @@ void FunctionDefinition::accept(ASTConstVisitor& _visitor) const void VariableDeclaration::accept(ASTVisitor& _visitor) { if (_visitor.visit(*this)) + { if (m_typeName) m_typeName->accept(_visitor); + if (m_value) + m_value->accept(_visitor); + } _visitor.endVisit(*this); } void VariableDeclaration::accept(ASTConstVisitor& _visitor) const { if (_visitor.visit(*this)) + { if (m_typeName) m_typeName->accept(_visitor); + if (m_value) + m_value->accept(_visitor); + } _visitor.endVisit(*this); } @@ -475,25 +483,17 @@ void ExpressionStatement::accept(ASTConstVisitor& _visitor) const _visitor.endVisit(*this); } -void VariableDefinition::accept(ASTVisitor& _visitor) +void VariableDeclarationStatement::accept(ASTVisitor& _visitor) { if (_visitor.visit(*this)) - { m_variable->accept(_visitor); - if (m_value) - m_value->accept(_visitor); - } _visitor.endVisit(*this); } -void VariableDefinition::accept(ASTConstVisitor& _visitor) const +void VariableDeclarationStatement::accept(ASTConstVisitor& _visitor) const { if (_visitor.visit(*this)) - { m_variable->accept(_visitor); - if (m_value) - m_value->accept(_visitor); - } _visitor.endVisit(*this); } diff --git a/libsolidity/Compiler.cpp b/libsolidity/Compiler.cpp index 14acc0113..23014da6c 100644 --- a/libsolidity/Compiler.cpp +++ b/libsolidity/Compiler.cpp @@ -73,7 +73,7 @@ void Compiler::packIntoContractCreator(ContractDefinition const& _contract, Comp for (ASTPointer const& base: contract->getBaseContracts()) { ContractDefinition const* baseContract = dynamic_cast( - base->getName()->getReferencedDeclaration()); + base->getName()->getReferencedDeclaration()); solAssert(baseContract, ""); if (baseArguments.count(baseContract) == 0) baseArguments[baseContract] = &base->getArguments(); @@ -85,12 +85,14 @@ void Compiler::packIntoContractCreator(ContractDefinition const& _contract, Comp { ContractDefinition const* base = bases[bases.size() - i]; solAssert(base, ""); + initializeStateVariables(*base); FunctionDefinition const* baseConstructor = base->getConstructor(); if (!baseConstructor) continue; solAssert(baseArguments[base], ""); appendBaseConstructorCall(*baseConstructor, *baseArguments[base]); } + initializeStateVariables(_contract); if (_contract.getConstructor()) appendConstructorCall(*_contract.getConstructor()); @@ -247,6 +249,13 @@ void Compiler::registerStateVariables(ContractDefinition const& _contract) m_context.addStateVariable(*variable); } +void Compiler::initializeStateVariables(ContractDefinition const& _contract) +{ + for (ASTPointer const& variable: _contract.getStateVariables()) + if (variable->getValue()) + ExpressionCompiler::appendStateVariableInitialization(m_context, *variable); +} + bool Compiler::visit(VariableDeclaration const& _variableDeclaration) { solAssert(_variableDeclaration.isStateVariable(), "Compiler visit to non-state variable declaration."); @@ -429,7 +438,7 @@ bool Compiler::visit(Return const& _return) return false; } -bool Compiler::visit(VariableDefinition const& _variableDefinition) +bool Compiler::visit(VariableDeclarationStatement const& _variableDefinition) { if (Expression const* expression = _variableDefinition.getExpression()) { diff --git a/libsolidity/Compiler.h b/libsolidity/Compiler.h index 1aeaee88f..0838512ee 100644 --- a/libsolidity/Compiler.h +++ b/libsolidity/Compiler.h @@ -59,6 +59,7 @@ private: void appendReturnValuePacker(TypePointers const& _typeParameters); void registerStateVariables(ContractDefinition const& _contract); + void initializeStateVariables(ContractDefinition const& _contract); virtual bool visit(VariableDeclaration const& _variableDeclaration) override; virtual bool visit(FunctionDefinition const& _function) override; @@ -68,7 +69,7 @@ private: virtual bool visit(Continue const& _continue) override; virtual bool visit(Break const& _break) override; virtual bool visit(Return const& _return) override; - virtual bool visit(VariableDefinition const& _variableDefinition) override; + virtual bool visit(VariableDeclarationStatement const& _variableDefinition) override; virtual bool visit(ExpressionStatement const& _expressionStatement) override; virtual bool visit(PlaceholderStatement const&) override; diff --git a/libsolidity/CompilerStack.cpp b/libsolidity/CompilerStack.cpp index ca9c75bcd..69dbced00 100644 --- a/libsolidity/CompilerStack.cpp +++ b/libsolidity/CompilerStack.cpp @@ -58,21 +58,22 @@ CompilerStack::CompilerStack(bool _addStandardSources): m_addStandardSources(_addStandardSources), m_parseSuccessful(false) { if (m_addStandardSources) - addSources(StandardSources); + addSources(StandardSources, true); // add them as libraries } -bool CompilerStack::addSource(string const& _name, string const& _content) +bool CompilerStack::addSource(string const& _name, string const& _content, bool _isLibrary) { bool existed = m_sources.count(_name) != 0; reset(true); - m_sources[_name].scanner = make_shared(CharStream(expanded(_content)), _name); + m_sources[_name].scanner = make_shared(CharStream(_content), _name); + m_sources[_name].isLibrary = _isLibrary; return existed; } void CompilerStack::setSource(string const& _sourceCode) { reset(); - addSource("", expanded(_sourceCode)); + addSource("", _sourceCode); } void CompilerStack::parse() @@ -126,57 +127,6 @@ vector CompilerStack::getContractNames() const return contractNames; } -////// BEGIN: TEMPORARY ONLY -/// -/// NOTE: THIS INVALIDATES SOURCE POINTERS AND CAN CRASH THE COMPILER -/// -/// remove once import works properly and we have genesis contracts - -string CompilerStack::expanded(string const& _sourceCode) -{ - const map c_standardSources = map{ - { "Config", "contract Config{function lookup(uint256 service)constant returns(address a){}function kill(){}function unregister(uint256 id){}function register(uint256 id,address service){}}" }, - { "Coin", "contract Coin{function isApprovedFor(address _target,address _proxy)constant returns(bool _r){}function isApproved(address _proxy)constant returns(bool _r){}function sendCoinFrom(address _from,uint256 _val,address _to){}function coinBalanceOf(address _a)constant returns(uint256 _r){}function sendCoin(uint256 _val,address _to){}function coinBalance()constant returns(uint256 _r){}function approve(address _a){}}"}, - { "CoinReg", "contract CoinReg{function count()constant returns(uint256 r){}function info(uint256 i)constant returns(address addr,string3 name,uint256 denom){}function register(string3 name,uint256 denom){}function unregister(){}}" }, - { "coin", "#require CoinReg\ncontract coin {function coin(string3 name, uint denom) {CoinReg(Config().lookup(3)).register(name, denom);}}" }, - { "service", "#require Config\ncontract service{function service(uint _n){Config().register(_n, this);}}" }, - { "owned", "contract owned{function owned(){owner = msg.sender;}modifier onlyowner(){if(msg.sender==owner)_}address owner;}" }, - { "mortal", "#require owned\ncontract mortal is owned {function kill() { if (msg.sender == owner) suicide(owner); }}" }, - { "NameReg", "contract NameReg{function register(string32 name){}function addressOf(string32 name)constant returns(address addr){}function unregister(){}function nameOf(address addr)constant returns(string32 name){}}" }, - { "named", "#require Config NameReg\ncontract named {function named(string32 name) {NameReg(Config().lookup(1)).register(name);}}" }, - { "std", "#require owned mortal Config NameReg named" }, - }; - - string sub; - set got; - function localExpanded; - localExpanded = [&](string const& s) -> string - { - string ret = s; - for (size_t p = 0; p != string::npos;) - if ((p = ret.find("#require ")) != string::npos) - { - string n = ret.substr(p + 9, ret.find_first_of('\n', p + 9) - p - 9); - ret.replace(p, n.size() + 9, ""); - vector rs; - boost::split(rs, n, boost::is_any_of(" \t,"), boost::token_compress_on); - for (auto const& r: rs) - if (!got.count(r)) - { - if (c_standardSources.count(r)) - sub.append("\n" + localExpanded(c_standardSources.at(r)) + "\n"); - got.insert(r); - } - } - // TODO: remove once we have genesis contracts. - else if ((p = ret.find("Config()")) != string::npos) - ret.replace(p, 8, "Config(0xc6d9d2cd449a754c494264e1809c50e34d64562b)"); - return ret; - }; - return sub + localExpanded(_sourceCode); -} - -////// END: TEMPORARY ONLY void CompilerStack::compile(bool _optimize) { @@ -328,7 +278,8 @@ void CompilerStack::resolveImports() }; for (auto const& sourcePair: m_sources) - toposort(&sourcePair.second); + if (!sourcePair.second.isLibrary) + toposort(&sourcePair.second); swap(m_sourceOrder, sourceOrder); } diff --git a/libsolidity/CompilerStack.h b/libsolidity/CompilerStack.h index cb4770cd3..8f77ef68a 100644 --- a/libsolidity/CompilerStack.h +++ b/libsolidity/CompilerStack.h @@ -64,8 +64,8 @@ public: /// Adds a source object (e.g. file) to the parser. After this, parse has to be called again. /// @returns true if a source object by the name already existed and was replaced. - void addSources(std::map const& _nameContents) { for (auto const& i: _nameContents) addSource(i.first, i.second); } - bool addSource(std::string const& _name, std::string const& _content); + void addSources(std::map const& _nameContents, bool _isLibrary = false) { for (auto const& i: _nameContents) addSource(i.first, i.second, _isLibrary); } + bool addSource(std::string const& _name, std::string const& _content, bool _isLibrary = false); void setSource(std::string const& _sourceCode); /// Parses all source units that were added void parse(); @@ -125,7 +125,8 @@ private: std::shared_ptr scanner; std::shared_ptr ast; std::string interface; - void reset() { scanner.reset(); ast.reset(); interface.clear(); } + bool isLibrary = false; + void reset() { scanner.reset(); ast.reset(); interface.clear(); isLibrary = false;} }; struct Contract @@ -143,10 +144,6 @@ private: Contract(); }; - /// Expand source code with preprocessor-like includes. - /// @todo Replace with better framework. - std::string expanded(std::string const& _sourceCode); - void reset(bool _keepSources = false); void resolveImports(); diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index a8bc53e0f..461dfef14 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -56,6 +56,23 @@ void ExpressionCompiler::appendStateVariableAccessor(CompilerContext& _context, compiler.appendStateVariableAccessor(_varDecl); } +void ExpressionCompiler::appendStateVariableInitialization(CompilerContext& _context, VariableDeclaration const& _varDecl, bool _optimize) +{ + compileExpression(_context, *(_varDecl.getValue()), _optimize); + if (_varDecl.getValue()->getType()) + appendTypeConversion(_context, *(_varDecl.getValue())->getType(), *(_varDecl.getValue())->getType()); + + ExpressionCompiler compiler(_context, _optimize); + compiler.appendStateVariableInitialization(_varDecl); +} + +void ExpressionCompiler::appendStateVariableInitialization(VariableDeclaration const& _varDecl) +{ + LValue var = LValue(m_context); + var.fromDeclaration(_varDecl, _varDecl.getValue()->getLocation()); + var.storeValue(*_varDecl.getType(), _varDecl.getLocation()); +} + bool ExpressionCompiler::visit(Assignment const& _assignment) { _assignment.getRightHandSide().accept(*this); @@ -77,7 +94,6 @@ bool ExpressionCompiler::visit(Assignment const& _assignment) } m_currentLValue.storeValue(*_assignment.getRightHandSide().getType(), _assignment.getLocation()); m_currentLValue.reset(); - return false; } @@ -572,7 +588,7 @@ void ExpressionCompiler::endVisit(Identifier const& _identifier) m_context << m_context.getVirtualFunctionEntryLabel(*functionDef).pushTag(); else if (dynamic_cast(declaration)) { - m_currentLValue.fromIdentifier(_identifier, *declaration); + m_currentLValue.fromDeclaration(*declaration, _identifier.getLocation()); m_currentLValue.retrieveValueIfLValueNotRequested(_identifier); } else if (dynamic_cast(declaration)) @@ -1002,12 +1018,12 @@ ExpressionCompiler::LValue::LValue(CompilerContext& _compilerContext, LValueType m_size = unsigned(m_dataType->getSizeOnStack()); } -void ExpressionCompiler::LValue::fromIdentifier(Identifier const& _identifier, Declaration const& _declaration) +void ExpressionCompiler::LValue::fromDeclaration(Declaration const& _declaration, Location const& _location) { if (m_context->isLocalVariable(&_declaration)) { m_type = LValueType::Stack; - m_dataType = _identifier.getType(); + m_dataType = _declaration.getType(); m_size = m_dataType->getSizeOnStack(); m_baseStackOffset = m_context->getBaseStackOffsetOfVariable(_declaration); } @@ -1015,12 +1031,13 @@ void ExpressionCompiler::LValue::fromIdentifier(Identifier const& _identifier, D { *m_context << m_context->getStorageLocationOfVariable(_declaration); m_type = LValueType::Storage; - m_dataType = _identifier.getType(); + m_dataType = _declaration.getType(); solAssert(m_dataType->getStorageSize() <= numeric_limits::max(), "The storage size of " + m_dataType->toString() + " should fit in an unsigned"); - m_size = unsigned(m_dataType->getStorageSize()); } + m_size = unsigned(m_dataType->getStorageSize()); + } else - BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_sourceLocation(_identifier.getLocation()) + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_sourceLocation(_location) << errinfo_comment("Identifier type not supported or identifier not found.")); } @@ -1117,7 +1134,7 @@ void ExpressionCompiler::LValue::storeValue(Type const& _sourceType, Location co } else { - solAssert(_sourceType.getCategory() == m_dataType->getCategory(), ""); + solAssert(_sourceType.getCategory() == m_dataType->getCategory(), "Wrong type conversation for assignment."); if (m_dataType->getCategory() == Type::Category::ByteArray) { CompilerUtils(*m_context).copyByteArrayToStorage( diff --git a/libsolidity/ExpressionCompiler.h b/libsolidity/ExpressionCompiler.h index 471d81865..889c58b19 100644 --- a/libsolidity/ExpressionCompiler.h +++ b/libsolidity/ExpressionCompiler.h @@ -59,6 +59,9 @@ public: /// Appends code for a State Variable accessor function static void appendStateVariableAccessor(CompilerContext& _context, VariableDeclaration const& _varDecl, bool _optimize = false); + /// Appends code for a State Variable Initialization function + static void appendStateVariableInitialization(CompilerContext& _context, VariableDeclaration const& _varDecl, bool _optimize = false); + private: explicit ExpressionCompiler(CompilerContext& _compilerContext, bool _optimize = false): m_optimize(_optimize), m_context(_compilerContext), m_currentLValue(m_context) {} @@ -111,6 +114,9 @@ private: /// Appends code for a State Variable accessor function void appendStateVariableAccessor(VariableDeclaration const& _varDecl); + /// Appends code for a State Variable initialization + void appendStateVariableInitialization(VariableDeclaration const& _varDecl); + /** * Helper class to store and retrieve lvalues to and from various locations. * All types except STACK store a reference in a slot on the stack, STACK just @@ -126,8 +132,9 @@ private: std::shared_ptr const& _dataType, unsigned _baseStackOffset = 0); /// Set type according to the declaration and retrieve the reference. - /// @a _expression is the current expression - void fromIdentifier(Identifier const& _identifier, Declaration const& _declaration); + /// @a _location is the current location + void fromDeclaration(Declaration const& _declaration, Location const& _location); + void reset() { m_type = LValueType::None; m_dataType.reset(); m_baseStackOffset = 0; m_size = 0; } bool isValid() const { return m_type != LValueType::None; } diff --git a/libsolidity/NameAndTypeResolver.cpp b/libsolidity/NameAndTypeResolver.cpp index ea70b65b4..15e1ac6f5 100644 --- a/libsolidity/NameAndTypeResolver.cpp +++ b/libsolidity/NameAndTypeResolver.cpp @@ -267,12 +267,12 @@ void DeclarationRegistrationHelper::endVisit(ModifierDefinition&) closeCurrentScope(); } -void DeclarationRegistrationHelper::endVisit(VariableDefinition& _variableDefinition) +void DeclarationRegistrationHelper::endVisit(VariableDeclarationStatement& _variableDeclarationStatement) { // Register the local variables with the function // This does not fit here perfectly, but it saves us another AST visit. - solAssert(m_currentFunction, "Variable definition without function."); - m_currentFunction->addLocalVariable(_variableDefinition.getDeclaration()); + solAssert(m_currentFunction, "Variable declaration without function."); + m_currentFunction->addLocalVariable(_variableDeclarationStatement.getDeclaration()); } bool DeclarationRegistrationHelper::visit(VariableDeclaration& _declaration) @@ -333,7 +333,13 @@ void ReferencesResolver::endVisit(VariableDeclaration& _variable) // or mapping if (_variable.getTypeName()) { - _variable.setType(_variable.getTypeName()->toType()); + TypePointer type = _variable.getTypeName()->toType(); + // All byte array parameter types should point to call data + if (_variable.isExternalFunctionParameter()) + if (auto const* byteArrayType = dynamic_cast(type.get())) + type = byteArrayType->copyForLocation(ByteArrayType::Location::CallData); + _variable.setType(type); + if (!_variable.getType()) BOOST_THROW_EXCEPTION(_variable.getTypeName()->createTypeError("Invalid type name")); } diff --git a/libsolidity/NameAndTypeResolver.h b/libsolidity/NameAndTypeResolver.h index d9ac98ce5..63b8ab637 100644 --- a/libsolidity/NameAndTypeResolver.h +++ b/libsolidity/NameAndTypeResolver.h @@ -105,7 +105,7 @@ private: void endVisit(FunctionDefinition& _function) override; bool visit(ModifierDefinition& _modifier) override; void endVisit(ModifierDefinition& _modifier) override; - void endVisit(VariableDefinition& _variableDefinition) override; + void endVisit(VariableDeclarationStatement& _variableDeclarationStatement) override; bool visit(VariableDeclaration& _declaration) override; bool visit(EventDefinition& _event) override; void endVisit(EventDefinition& _event) override; diff --git a/libsolidity/Parser.cpp b/libsolidity/Parser.cpp index 72334c6cc..9940fb8d9 100644 --- a/libsolidity/Parser.cpp +++ b/libsolidity/Parser.cpp @@ -148,6 +148,7 @@ ASTPointer Parser::parseContractDefinition() { VarDeclParserOptions options; options.isStateVariable = true; + options.allowInitialValue = true; stateVariables.push_back(parseVariableDeclaration(options)); expectToken(Token::Semicolon); } @@ -324,9 +325,19 @@ ASTPointer Parser::parseVariableDeclaration(VarDeclParserOp } else identifier = expectIdentifierToken(); - return nodeFactory.createNode(type, identifier, - visibility, _options.isStateVariable, - isIndexed); + ASTPointer value; + if (_options.allowInitialValue) + { + if (m_scanner->getCurrentToken() == Token::Assign) + { + m_scanner->next(); + value = parseExpression(); + nodeFactory.setEndPositionFromNode(value); + } + } + return nodeFactory.createNode(type, identifier, value, + visibility, _options.isStateVariable, + isIndexed); } ASTPointer Parser::parseModifierDefinition() @@ -519,7 +530,7 @@ ASTPointer Parser::parseStatement() } // fall-through default: - statement = parseVarDefOrExprStmt(); + statement = parseVarDeclOrExprStmt(); } expectToken(Token::Semicolon); return statement; @@ -568,7 +579,7 @@ ASTPointer Parser::parseForStatement() // LTODO: Maybe here have some predicate like peekExpression() instead of checking for semicolon and RParen? if (m_scanner->getCurrentToken() != Token::Semicolon) - initExpression = parseVarDefOrExprStmt(); + initExpression = parseVarDeclOrExprStmt(); expectToken(Token::Semicolon); if (m_scanner->getCurrentToken() != Token::Semicolon) @@ -587,30 +598,22 @@ ASTPointer Parser::parseForStatement() body); } -ASTPointer Parser::parseVarDefOrExprStmt() +ASTPointer Parser::parseVarDeclOrExprStmt() { - if (peekVariableDefinition()) - return parseVariableDefinition(); + if (peekVariableDeclarationStatement()) + return parseVariableDeclarationStatement(); else return parseExpressionStatement(); } -ASTPointer Parser::parseVariableDefinition() +ASTPointer Parser::parseVariableDeclarationStatement() { ASTNodeFactory nodeFactory(*this); VarDeclParserOptions options; options.allowVar = true; + options.allowInitialValue = true; ASTPointer variable = parseVariableDeclaration(options); - ASTPointer value; - if (m_scanner->getCurrentToken() == Token::Assign) - { - m_scanner->next(); - value = parseExpression(); - nodeFactory.setEndPositionFromNode(value); - } - else - nodeFactory.setEndPositionFromNode(variable); - return nodeFactory.createNode(variable, value); + return nodeFactory.createNode(variable); } ASTPointer Parser::parseExpressionStatement() @@ -822,11 +825,11 @@ pair>, vector>> Parser::pars } -bool Parser::peekVariableDefinition() +bool Parser::peekVariableDeclarationStatement() { - // distinguish between variable definition (and potentially assignment) and expression statement + // distinguish between variable declaration (and potentially assignment) and expression statement // (which include assignments to other expressions and pre-declared variables) - // We have a variable definition if we get a keyword that specifies a type name, or + // We have a variable declaration if we get a keyword that specifies a type name, or // in the case of a user-defined type, we have two identifiers following each other. return (m_scanner->getCurrentToken() == Token::Mapping || m_scanner->getCurrentToken() == Token::Var || diff --git a/libsolidity/Parser.h b/libsolidity/Parser.h index 1bb4ea977..4034aec85 100644 --- a/libsolidity/Parser.h +++ b/libsolidity/Parser.h @@ -51,6 +51,7 @@ private: bool isStateVariable = false; bool allowIndexed = false; bool allowEmptyName = false; + bool allowInitialValue = false; }; ///@{ @@ -76,8 +77,8 @@ private: ASTPointer parseIfStatement(); ASTPointer parseWhileStatement(); ASTPointer parseForStatement(); - ASTPointer parseVarDefOrExprStmt(); - ASTPointer parseVariableDefinition(); + ASTPointer parseVarDeclOrExprStmt(); + ASTPointer parseVariableDeclarationStatement(); ASTPointer parseExpressionStatement(); ASTPointer parseExpression(); ASTPointer parseBinaryExpression(int _minPrecedence = 4); @@ -91,8 +92,8 @@ private: ///@{ ///@name Helper functions - /// Peeks ahead in the scanner to determine if a variable definition is going to follow - bool peekVariableDefinition(); + /// Peeks ahead in the scanner to determine if a variable declaration statement is going to follow + bool peekVariableDeclarationStatement(); /// If current token value is not _value, throw exception otherwise advance token. void expectToken(Token::Value _value); diff --git a/libsolidity/Token.h b/libsolidity/Token.h index e9765e5eb..4aa000475 100644 --- a/libsolidity/Token.h +++ b/libsolidity/Token.h @@ -372,7 +372,7 @@ public: static Value AssignmentToBinaryOp(Value op) { solAssert(isAssignmentOp(op) && op != Assign, ""); - return Token::Value(op + (BitOr - AssignBitOr)); + return Value(op + (BitOr - AssignBitOr)); } static bool isBitOp(Value op) { return (BitOr <= op && op <= SHR) || op == BitNot; } diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index a9c480176..55dedd921 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -653,7 +653,7 @@ MemberList const& StructType::getMembers() const // We need to lazy-initialize it because of recursive references. if (!m_members) { - vector> members; + MemberList::MemberMap members; for (ASTPointer const& variable: m_struct.getMembers()) members.push_back(make_pair(variable->getName(), variable->getType())); m_members.reset(new MemberList(members)); diff --git a/libsolidity/Types.h b/libsolidity/Types.h index d529d8d08..af64f1cb5 100644 --- a/libsolidity/Types.h +++ b/libsolidity/Types.h @@ -430,12 +430,21 @@ public: Location _location = Location::Internal, bool _arbitraryParameters = false): FunctionType(parseElementaryTypeVector(_parameterTypes), parseElementaryTypeVector(_returnParameterTypes), _location, _arbitraryParameters) {} - FunctionType(TypePointers const& _parameterTypes, TypePointers const& _returnParameterTypes, - Location _location = Location::Internal, - bool _arbitraryParameters = false, bool _gasSet = false, bool _valueSet = false): - m_parameterTypes(_parameterTypes), m_returnParameterTypes(_returnParameterTypes), - m_location(_location), - m_arbitraryParameters(_arbitraryParameters), m_gasSet(_gasSet), m_valueSet(_valueSet) {} + FunctionType( + TypePointers const& _parameterTypes, + TypePointers const& _returnParameterTypes, + Location _location = Location::Internal, + bool _arbitraryParameters = false, + bool _gasSet = false, + bool _valueSet = false + ): + m_parameterTypes (_parameterTypes), + m_returnParameterTypes (_returnParameterTypes), + m_location (_location), + m_arbitraryParameters (_arbitraryParameters), + m_gasSet (_gasSet), + m_valueSet (_valueSet) + {} TypePointers const& getParameterTypes() const { return m_parameterTypes; } std::vector const& getParameterNames() const { return m_parameterNames; } @@ -490,7 +499,7 @@ private: bool const m_arbitraryParameters = false; bool const m_gasSet = false; ///< true iff the gas value to be used is on the stack bool const m_valueSet = false; ///< true iff the value to be sent is on the stack - bool m_isConstant; + bool m_isConstant = false; mutable std::unique_ptr m_members; Declaration const* m_declaration = nullptr; }; diff --git a/libweb3jsonrpc/AccountHolder.cpp b/libweb3jsonrpc/AccountHolder.cpp new file mode 100644 index 000000000..b88397953 --- /dev/null +++ b/libweb3jsonrpc/AccountHolder.cpp @@ -0,0 +1,108 @@ +/* + 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 AccountHolder.cpp + * @authors: + * Christian R + * Lefteris Karapetsas + * @date 2015 + */ + +#include "AccountHolder.h" +#include +#include +#include +#include + +using namespace std; +using namespace dev; +using namespace dev::eth; + +vector g_emptyQueue; +static std::mt19937 g_randomNumberGenerator(time(0)); +static Mutex x_rngMutex; + +void AccountHolder::setAccounts(vector const& _accounts) +{ + m_accounts.clear(); + for (auto const& keyPair: _accounts) + { + m_accounts.push_back(keyPair.address()); + m_keyPairs[keyPair.address()] = keyPair; + } +} + +vector
AccountHolder::getAllAccounts() const +{ + vector
accounts = m_accounts; + for (auto const& pair: m_proxyAccounts) + if (!isRealAccount(pair.first)) + accounts.push_back(pair.first); + return accounts; +} + +Address const& AccountHolder::getDefaultTransactAccount() const +{ + if (m_accounts.empty()) + return ZeroAddress; + Address const* bestMatch = &m_accounts.front(); + for (auto const& account: m_accounts) + if (m_client()->balanceAt(account) > m_client()->balanceAt(*bestMatch)) + bestMatch = &account; + return *bestMatch; +} + +int AccountHolder::addProxyAccount(const Address& _account) +{ + Guard g(x_rngMutex); + int id = std::uniform_int_distribution(1)(g_randomNumberGenerator); + id = int(u256(FixedHash<32>(sha3(bytesConstRef((byte*)(&id), sizeof(int) / sizeof(byte)))))); + if (isProxyAccount(_account) || id == 0 || m_transactionQueues.count(id)) + return 0; + m_proxyAccounts.insert(make_pair(_account, id)); + m_transactionQueues[id].first = _account; + return id; +} + +bool AccountHolder::removeProxyAccount(unsigned _id) +{ + if (!m_transactionQueues.count(_id)) + return false; + m_proxyAccounts.erase(m_transactionQueues[_id].first); + m_transactionQueues.erase(_id); + return true; +} + +void AccountHolder::queueTransaction(TransactionSkeleton const& _transaction) +{ + if (!m_proxyAccounts.count(_transaction.from)) + return; + int id = m_proxyAccounts[_transaction.from]; + m_transactionQueues[id].second.push_back(_transaction); +} + +vector const& AccountHolder::getQueuedTransactions(int _id) const +{ + if (!m_transactionQueues.count(_id)) + return g_emptyQueue; + return m_transactionQueues.at(_id).second; +} + +void AccountHolder::clearQueue(int _id) +{ + if (m_transactionQueues.count(_id)) + m_transactionQueues.at(_id).second.clear(); +} diff --git a/libweb3jsonrpc/AccountHolder.h b/libweb3jsonrpc/AccountHolder.h new file mode 100644 index 000000000..52005b51f --- /dev/null +++ b/libweb3jsonrpc/AccountHolder.h @@ -0,0 +1,74 @@ +/* + 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 AccountHolder.h + * @authors: + * Christian R + * Lefteris Karapetsas + * @date 2015 + */ + +#pragma once + +#include +#include +#include +#include +#include + +namespace dev +{ +namespace eth +{ +class Interface; +} + +/** + * Manages real accounts (where we know the secret key) and proxy accounts (where transactions + * to be sent from these accounts are forwarded to a proxy on the other side). + */ +class AccountHolder +{ +public: + explicit AccountHolder(std::function const& _client): m_client(_client) {} + + /// Sets or resets the list of real accounts. + void setAccounts(std::vector const& _accounts); + std::vector
const& getRealAccounts() const { return m_accounts; } + bool isRealAccount(Address const& _account) const { return m_keyPairs.count(_account) > 0; } + bool isProxyAccount(Address const& _account) const { return m_proxyAccounts.count(_account) > 0; } + Secret const& secretKey(Address const& _account) const { return m_keyPairs.at(_account).secret(); } + std::vector
getAllAccounts() const; + Address const& getDefaultTransactAccount() const; + + int addProxyAccount(Address const& _account); + bool removeProxyAccount(unsigned _id); + void queueTransaction(eth::TransactionSkeleton const& _transaction); + + std::vector const& getQueuedTransactions(int _id) const; + void clearQueue(int _id); + +private: + using TransactionQueue = std::vector; + + std::map m_keyPairs; + std::vector
m_accounts; + std::map m_proxyAccounts; + std::map> m_transactionQueues; + std::function m_client; +}; + +} diff --git a/libweb3jsonrpc/WebThreeStubServerBase.cpp b/libweb3jsonrpc/WebThreeStubServerBase.cpp index 8e0b30366..6ab701899 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.cpp +++ b/libweb3jsonrpc/WebThreeStubServerBase.cpp @@ -35,11 +35,13 @@ #include #endif #include "WebThreeStubServerBase.h" +#include "AccountHolder.h" using namespace std; using namespace dev; using namespace dev::eth; + static Json::Value toJson(dev::eth::BlockInfo const& _bi) { Json::Value res; @@ -72,6 +74,18 @@ static Json::Value toJson(dev::eth::Transaction const& _t) return res; } +static Json::Value toJson(dev::eth::TransactionSkeleton const& _t) +{ + Json::Value res; + res["to"] = toJS(_t.to); + res["from"] = toJS(_t.from); + res["gas"] = toJS(_t.gas); + res["gasPrice"] = toJS(_t.gasPrice); + res["value"] = toJS(_t.value); + res["data"] = jsFromBinary(_t.data); + return res; +} + static Json::Value toJson(dev::eth::LocalisedLogEntry const& _e) { Json::Value res; @@ -212,19 +226,9 @@ static Json::Value toJson(h256 const& _h, shh::Envelope const& _e, shh::Message } WebThreeStubServerBase::WebThreeStubServerBase(jsonrpc::AbstractServerConnector& _conn, std::vector const& _accounts): - AbstractWebThreeStubServer(_conn) -{ - setAccounts(_accounts); -} - -void WebThreeStubServerBase::setAccounts(std::vector const& _accounts) + AbstractWebThreeStubServer(_conn), m_accounts(make_shared(std::bind(&WebThreeStubServerBase::client, this))) { - m_accounts.clear(); - for (auto const& i: _accounts) - { - m_accounts.push_back(i.address()); - m_accountsLookup[i.address()] = i; - } + m_accounts->setAccounts(_accounts); } void WebThreeStubServerBase::setIdentities(std::vector const& _ids) @@ -242,7 +246,7 @@ std::string WebThreeStubServerBase::web3_sha3(std::string const& _param1) Json::Value WebThreeStubServerBase::eth_accounts() { Json::Value ret(Json::arrayValue); - for (auto const& i: m_accounts) + for (auto const& i: m_accounts->getAllAccounts()) ret.append(toJS(i)); return ret; } @@ -326,21 +330,15 @@ std::string WebThreeStubServerBase::eth_call(Json::Value const& _json) { std::string ret; TransactionSkeleton t = toTransaction(_json); - if (!t.from && m_accounts.size()) - { - auto b = m_accounts.front(); - for (auto const& a: m_accounts) - if (client()->balanceAt(a) > client()->balanceAt(b)) - b = a; - t.from = b; - } - if (!m_accountsLookup.count(t.from)) + if (!t.from) + t.from = m_accounts->getDefaultTransactAccount(); + if (!m_accounts->isRealAccount(t.from)) return ret; if (!t.gasPrice) t.gasPrice = 10 * dev::eth::szabo; if (!t.gas) t.gas = min(client()->gasLimitRemaining(), client()->balanceAt(t.from) / t.gasPrice); - ret = toJS(client()->call(m_accountsLookup[t.from].secret(), t.value, t.to, t.data, t.gas, t.gasPrice)); + ret = toJS(client()->call(m_accounts->secretKey(t.from), t.value, t.to, t.data, t.gas, t.gasPrice)); return ret; } @@ -464,6 +462,25 @@ bool WebThreeStubServerBase::eth_submitWork(std::string const& _nonce) return client()->submitNonce(jsToFixed<32>(_nonce)); } +int WebThreeStubServerBase::eth_register(std::string const& _address) +{ + return m_accounts->addProxyAccount(jsToAddress(_address)); +} + +bool WebThreeStubServerBase::eth_unregister(int _id) +{ + return m_accounts->removeProxyAccount(_id); +} + +Json::Value WebThreeStubServerBase::eth_queuedTransactions(int _id) +{ + Json::Value ret(Json::arrayValue); + for (TransactionSkeleton const& t: m_accounts->getQueuedTransactions(_id)) + ret.append(toJson(t)); + m_accounts->clearQueue(_id); + return ret; +} + std::string WebThreeStubServerBase::shh_newGroup(std::string const& _id, std::string const& _who) { (void)_id; @@ -684,36 +701,31 @@ std::string WebThreeStubServerBase::eth_transact(Json::Value const& _json) { std::string ret; TransactionSkeleton t = toTransaction(_json); - if (!t.from && m_accounts.size()) - { - auto b = m_accounts.front(); - for (auto const& a: m_accounts) - if (client()->balanceAt(a) > client()->balanceAt(b)) - b = a; - t.from = b; - } - if (!m_accountsLookup.count(t.from)) - return ret; + if (t.creation) + ret = right160(sha3(rlpList(t.from, client()->countAt(t.from))));; + if (!t.from) + t.from = m_accounts->getDefaultTransactAccount(); if (!t.gasPrice) t.gasPrice = 10 * dev::eth::szabo; if (!t.gas) t.gas = min(client()->gasLimitRemaining(), client()->balanceAt(t.from) / t.gasPrice); - if (authenticate(t)) - { - if (t.to) - // TODO: from qethereum, insert validification hook here. - client()->transact(m_accountsLookup[t.from].secret(), t.value, t.to, t.data, t.gas, t.gasPrice); - else - ret = toJS(client()->transact(m_accountsLookup[t.from].secret(), t.value, t.data, t.gas, t.gasPrice)); - client()->flushTransactions(); - } + + if (m_accounts->isRealAccount(t.from)) + authenticate(t, false); + else if (m_accounts->isProxyAccount(t.from)) + authenticate(t, true); + return ret; } -bool WebThreeStubServerBase::authenticate(TransactionSkeleton const& _t) +void WebThreeStubServerBase::authenticate(TransactionSkeleton const& _t, bool _toProxy) { - cwarn << "Silently signing transaction from address" << _t.from.abridged() << ": User validation hook goes here."; - return true; + if (_toProxy) + m_accounts->queueTransaction(_t); + else if (_t.to) + client()->transact(m_accounts->secretKey(_t.from), _t.value, _t.to, _t.data, _t.gas, _t.gasPrice); + else + client()->transact(m_accounts->secretKey(_t.from), _t.value, _t.data, _t.gas, _t.gasPrice); } Json::Value WebThreeStubServerBase::eth_transactionByHash(std::string const& _hash, int _i) @@ -742,3 +754,7 @@ bool WebThreeStubServerBase::eth_uninstallFilter(int _id) return true; } +void WebThreeStubServerBase::setAccounts(const std::vector& _accounts) +{ + m_accounts->setAccounts(_accounts); +} diff --git a/libweb3jsonrpc/WebThreeStubServerBase.h b/libweb3jsonrpc/WebThreeStubServerBase.h index ec83c9797..9535c33a0 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.h +++ b/libweb3jsonrpc/WebThreeStubServerBase.h @@ -23,6 +23,7 @@ #pragma once +#include #include #include #include @@ -35,6 +36,7 @@ namespace dev { class WebThreeNetworkFace; +class AccountHolder; class KeyPair; namespace eth { @@ -110,6 +112,10 @@ public: virtual Json::Value eth_getWork(); virtual bool eth_submitWork(std::string const& _nonce); + virtual int eth_register(std::string const& _address); + virtual bool eth_unregister(int _id); + virtual Json::Value eth_queuedTransactions(int _id); + virtual std::string db_get(std::string const& _name, std::string const& _key); virtual std::string db_getString(std::string const& _name, std::string const& _key); virtual bool db_put(std::string const& _name, std::string const& _key, std::string const& _value); @@ -130,7 +136,7 @@ public: std::map const& ids() const { return m_ids; } protected: - virtual bool authenticate(dev::eth::TransactionSkeleton const& _t); + virtual void authenticate(dev::eth::TransactionSkeleton const& _t, bool _toProxy); protected: virtual dev::eth::Interface* client() = 0; @@ -138,11 +144,9 @@ protected: virtual dev::WebThreeNetworkFace* network() = 0; virtual dev::WebThreeStubDatabaseFace* db() = 0; - std::map m_accountsLookup; - std::vector m_accounts; - std::map m_ids; std::map m_shhWatches; + std::shared_ptr m_accounts; }; } //namespace dev diff --git a/libweb3jsonrpc/abstractwebthreestubserver.h b/libweb3jsonrpc/abstractwebthreestubserver.h index 53d7f856d..e40c68acd 100644 --- a/libweb3jsonrpc/abstractwebthreestubserver.h +++ b/libweb3jsonrpc/abstractwebthreestubserver.h @@ -55,6 +55,9 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServerbindAndAddMethod(jsonrpc::Procedure("eth_logs", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, "param1",jsonrpc::JSON_OBJECT, NULL), &AbstractWebThreeStubServer::eth_logsI); this->bindAndAddMethod(jsonrpc::Procedure("eth_getWork", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, NULL), &AbstractWebThreeStubServer::eth_getWorkI); this->bindAndAddMethod(jsonrpc::Procedure("eth_submitWork", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_submitWorkI); + this->bindAndAddMethod(jsonrpc::Procedure("eth_register", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_INTEGER, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_registerI); + this->bindAndAddMethod(jsonrpc::Procedure("eth_unregister", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::eth_unregisterI); + this->bindAndAddMethod(jsonrpc::Procedure("eth_queuedTransactions", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::eth_queuedTransactionsI); this->bindAndAddMethod(jsonrpc::Procedure("db_put", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING,"param3",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::db_putI); this->bindAndAddMethod(jsonrpc::Procedure("db_get", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::db_getI); this->bindAndAddMethod(jsonrpc::Procedure("db_putString", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING,"param3",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::db_putStringI); @@ -253,6 +256,18 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServereth_submitWork(request[0u].asString()); } + inline virtual void eth_registerI(const Json::Value &request, Json::Value &response) + { + response = this->eth_register(request[0u].asString()); + } + inline virtual void eth_unregisterI(const Json::Value &request, Json::Value &response) + { + response = this->eth_unregister(request[0u].asInt()); + } + inline virtual void eth_queuedTransactionsI(const Json::Value &request, Json::Value &response) + { + response = this->eth_queuedTransactions(request[0u].asInt()); + } inline virtual void db_putI(const Json::Value &request, Json::Value &response) { response = this->db_put(request[0u].asString(), request[1u].asString(), request[2u].asString()); @@ -349,6 +364,9 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServerqml/StateDialog.qml qml/StateList.qml qml/StateListModel.qml + qml/img/dappProjectIcon.png 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/img/jumpoverforwarddisabled.png qml/StepActionImage.qml qml/img/jumpintobackdisabled.png qml/img/jumpintoforwarddisabled.png diff --git a/neth/main.cpp b/neth/main.cpp index 27da7e89b..ca25b8d11 100644 --- a/neth/main.cpp +++ b/neth/main.cpp @@ -433,7 +433,6 @@ int main(int argc, char** argv) clientName += "/"; cout << credits(); - NetworkPreferences netPrefs(listenPort, publicIP, upnp, useLocal); auto nodesState = contents((dbPath.size() ? dbPath : getDataDir()) + "/network.rlp"); dev::WebThreeDirect web3( @@ -455,6 +454,7 @@ int main(int argc, char** argv) } cout << "Address: " << endl << toHex(us.address().asArray()) << endl; + web3.startNetwork(); if (bootstrap) diff --git a/standard.js b/standard.js index 0f9cf6fa4..f51828cbe 100644 --- a/standard.js +++ b/standard.js @@ -10,6 +10,7 @@ var addrNameReg = initService("namereg"); var addrGavsino = initServiceVal("gavmble", "1000000000000000000"); var addrCoinReg = initService("coins"); var addrGavCoin = initService("coin"); + var addrRegistrar = initService("registrar"); var abiNameReg = [{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"getName","outputs":[{"name":"o_name","type":"string32"}]},{"constant":false,"inputs":[{"name":"name","type":"string32"}],"name":"register","outputs":[]},{"constant":true,"inputs":[{"name":"name","type":"string32"}],"name":"addressOf","outputs":[{"name":"addr","type":"address"}]},{"constant":true,"inputs":[{"name":"_name","type":"string32"}],"name":"getAddress","outputs":[{"name":"o_owner","type":"address"}]},{"constant":false,"inputs":[],"name":"unregister","outputs":[]},{"constant":true,"inputs":[{"name":"addr","type":"address"}],"name":"nameOf","outputs":[{"name":"name","type":"string32"}]}]; diff --git a/test/AccountHolder.cpp b/test/AccountHolder.cpp new file mode 100644 index 000000000..e8e42ff18 --- /dev/null +++ b/test/AccountHolder.cpp @@ -0,0 +1,74 @@ +/* + 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 . + */ +/** + * @author Christian R + * @date 2015 + * Unit tests for the account holder used by the WebThreeStubServer. + */ + +#include +#include + +namespace dev +{ +namespace test +{ + +BOOST_AUTO_TEST_SUITE(AccountHolderTest) + +BOOST_AUTO_TEST_CASE(ProxyAccountUseCase) +{ + AccountHolder h = AccountHolder(std::function()); + BOOST_CHECK(h.getAllAccounts().empty()); + BOOST_CHECK(h.getRealAccounts().empty()); + Address addr("abababababababababababababababababababab"); + Address addr2("abababababababababababababababababababab"); + int id = h.addProxyAccount(addr); + BOOST_CHECK(h.getQueuedTransactions(id).empty()); + // register it again + int secondID = h.addProxyAccount(addr); + BOOST_CHECK(h.getQueuedTransactions(secondID).empty()); + + eth::TransactionSkeleton t1; + eth::TransactionSkeleton t2; + t1.from = addr; + t1.data = fromHex("12345678"); + t2.from = addr; + t2.data = fromHex("abcdef"); + BOOST_CHECK(h.getQueuedTransactions(id).empty()); + h.queueTransaction(t1); + BOOST_CHECK_EQUAL(1, h.getQueuedTransactions(id).size()); + h.queueTransaction(t2); + BOOST_REQUIRE_EQUAL(2, h.getQueuedTransactions(id).size()); + + // second proxy should not see transactions + BOOST_CHECK(h.getQueuedTransactions(secondID).empty()); + + BOOST_CHECK(h.getQueuedTransactions(id)[0].data == t1.data); + BOOST_CHECK(h.getQueuedTransactions(id)[1].data == t2.data); + + h.clearQueue(id); + BOOST_CHECK(h.getQueuedTransactions(id).empty()); + // removing fails because it never existed + BOOST_CHECK(!h.removeProxyAccount(secondID)); + BOOST_CHECK(h.removeProxyAccount(id)); +} + +BOOST_AUTO_TEST_SUITE_END() + +} +} diff --git a/test/SolidityEndToEndTest.cpp b/test/SolidityEndToEndTest.cpp index 8c87db2d8..1f80b1017 100644 --- a/test/SolidityEndToEndTest.cpp +++ b/test/SolidityEndToEndTest.cpp @@ -2570,6 +2570,61 @@ BOOST_AUTO_TEST_CASE(constructing_enums_from_ints) BOOST_CHECK(callContractFunction("test()") == encodeArgs(1)); } +BOOST_AUTO_TEST_CASE(inline_member_init) +{ + char const* sourceCode = R"( + contract test { + function test(){ + m_b = 6; + m_c = 8; + } + uint m_a = 5; + uint m_b; + uint m_c = 7; + function get() returns (uint a, uint b, uint c){ + a = m_a; + b = m_b; + c = m_c; + } + })"; + compileAndRun(sourceCode); + BOOST_CHECK(callContractFunction("get()") == encodeArgs(5, 6, 8)); +} + +BOOST_AUTO_TEST_CASE(inline_member_init_inheritence) +{ + char const* sourceCode = R"( + contract Base { + function Base(){} + uint m_base = 5; + function getBMember() returns (uint i) { return m_base; } + } + contract Derived is Base { + function Derived(){} + uint m_derived = 6; + function getDMember() returns (uint i) { return m_derived; } + })"; + compileAndRun(sourceCode); + BOOST_CHECK(callContractFunction("getBMember()") == encodeArgs(5)); + BOOST_CHECK(callContractFunction("getDMember()") == encodeArgs(6)); +} + +BOOST_AUTO_TEST_CASE(inline_member_init_inheritence_without_constructor) +{ + char const* sourceCode = R"( + contract Base { + uint m_base = 5; + function getBMember() returns (uint i) { return m_base; } + } + contract Derived is Base { + uint m_derived = 6; + function getDMember() returns (uint i) { return m_derived; } + })"; + compileAndRun(sourceCode); + BOOST_CHECK(callContractFunction("getBMember()") == encodeArgs(5)); + BOOST_CHECK(callContractFunction("getDMember()") == encodeArgs(6)); +} + BOOST_AUTO_TEST_CASE(external_function) { char const* sourceCode = R"( diff --git a/test/SolidityNameAndTypeResolution.cpp b/test/SolidityNameAndTypeResolution.cpp index bfef873c4..da6c2a88a 100644 --- a/test/SolidityNameAndTypeResolution.cpp +++ b/test/SolidityNameAndTypeResolution.cpp @@ -1163,6 +1163,19 @@ BOOST_AUTO_TEST_CASE(external_argument_delete) BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError); } +BOOST_AUTO_TEST_CASE(test_for_bug_override_function_with_bytearray_type) +{ + char const* sourceCode = R"( + contract Vehicle { + function f(bytes _a) external returns (uint256 r) {r = 1;} + } + contract Bike is Vehicle { + function f(bytes _a) external returns (uint256 r) {r = 42;} + } + )"; + BOOST_CHECK_NO_THROW(parseTextAndResolveNamesWithChecks(sourceCode)); +} + BOOST_AUTO_TEST_SUITE_END() } diff --git a/test/stInitCodeTestFiller.json b/test/stInitCodeTestFiller.json index 134d75198..ea5467df8 100644 --- a/test/stInitCodeTestFiller.json +++ b/test/stInitCodeTestFiller.json @@ -267,7 +267,7 @@ { "095e7baea6a6c7c4c2dfeb977efac326af552d87": { "balance": "0", - "nonce": "0", + "nonce": "40", "code": "{[[ 2 ]](ADDRESS)(CODECOPY 0 0 32)(CREATE 0 0 32)}", "storage": {} }, @@ -489,5 +489,83 @@ "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", "value" : "0" } + }, + + "ReturnTest" : { + "env" : { + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentDifficulty" : "45678256", + "currentGasLimit" : "10000000", + "currentNumber" : "0", + "currentTimestamp" : 1, + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "pre" : + { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "100000", + "code" : "{(CALL 2000 0xb94f5374fce5edbc8e2a8697c15331677e6ebf0b 0 30 1 31 1) (RETURN 30 2)}", + "nonce" : "0", + "storage" : { + } + }, + + "b94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "100000", + "code" : "{(MSTORE 0 0x15) (RETURN 31 1)}", + "nonce" : "0", + "storage" : { + } + } + }, + "transaction" : + { + "data" : "", + "gasLimit" : "5000", + "gasPrice" : "1", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "a94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "value" : "1" + } + }, + + "ReturnTest2" : { + "env" : { + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentDifficulty" : "45678256", + "currentGasLimit" : "100000000", + "currentNumber" : "0", + "currentTimestamp" : 1, + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "pre" : + { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "100000", + "code" : "{(MSTORE 0 0x15)(CALL 7000 0xb94f5374fce5edbc8e2a8697c15331677e6ebf0b 0 0 32 32 32) (RETURN 0 64)}", + "nonce" : "0", + "storage" : { + } + }, + + "b94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "100000", + "code" : "{(MSTORE 0 (MUL 3 (CALLDATALOAD 0)))(RETURN 0 32)}", + "nonce" : "0", + "storage" : { + } + } + }, + "transaction" : + { + "data" : "", + "gasLimit" : "15000", + "gasPrice" : "1", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "a94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "value" : "1" + } } } diff --git a/test/stSolidityTestFiller.json b/test/stSolidityTestFiller.json index fc0770c5e..973c52a8d 100644 --- a/test/stSolidityTestFiller.json +++ b/test/stSolidityTestFiller.json @@ -73,6 +73,9 @@ "//" : " if (!testStructuresAndVariabless()) ", "//" : " res = hash(int(res) + int(0x0000f00000000000000000000000000000000000000000000000000000000000)); ", "//" : " ", + "//" : " if (!testCryptographicFunctions()) ", + "//" : " res = hash(int(res) + int(0x00000f0000000000000000000000000000000000000000000000000000000000)); ", + "//" : " ", "//" : " //Tested 27.01.2015 ", "//" : " //should run out of gas ", "//" : " //if (!testInfiniteLoop()) ", @@ -83,6 +86,21 @@ "//" : " // res = hash(int(res) + int(0x0000000000000000000000000000000000000000000000000000000000000000)); ", "//" : " } ", "//" : " ", + "//" : " function testCryptographicFunctions() returns (bool res) ", + "//" : " { ", + "//" : " res = true; ", + "//" : " if (sha3('teststring') != 0x43c4b4524adb81e4e9a5c4648a98e9d320e3908ac5b6c889144b642cd08ae16d) ", + "//" : " return false; ", + "//" : " ", + "//" : " if (sha256('teststring') != 0x3c8727e019a42b444667a587b6001251becadabbb36bfed8087a92c18882d111) ", + "//" : " return false; ", + "//" : " ", + "//" : " if (ripemd160('teststring') != 0xcd566972b5e50104011a92b59fa8e0b1234851ae) ", + "//" : " return false; ", + "//" : " ", + "//" : " //ecrecover ", + "//" : " } ", + "//" : " ", "//" : " function testStructuresAndVariabless() returns (bool res) ", "//" : " { ", "//" : " res = true; ", @@ -112,8 +130,8 @@ "//" : " return false; ", "//" : " ", "//" : " //for some reason does not work 27.01.2015 ", - "//" : " //if (block.gaslimit != 1000000000000000000000) ", - "//" : " // return false; ", + "//" : " if (block.gaslimit != 1000000000000000000000) ", + "//" : " return false; ", "//" : " ", "//" : " if (block.number != 120) ", "//" : " return false; ", @@ -213,7 +231,7 @@ "//" : " a = new TestContract(); ", "//" : " } ", "//" : "} ", - "code" : "0x60e060020a6000350480630c4c9a8014610078578063296df0df1461008a5780632a9afb831461009c578063380e4396146100ae5780634893d88a146100c05780637ee17e12146100ce578063981a3165146100dc578063a60eedda146100ee578063e97384dc14610100578063ed973fe91461011257005b610080610431565b8060005260206000f35b6100926103f7565b8060005260206000f35b6100a46105d1565b8060005260206000f35b6100b6610220565b8060005260206000f35b6100c8610426565b60006000f35b6100d66102df565b60006000f35b6100e4610411565b8060005260206000f35b6100f6610124565b8060005260206000f35b6101086102f5565b8060005260206000f35b61011a6101be565b8060005260206000f35b60006000605f6106be600039605f60006000f0905080600160a060020a031662f55d9d8060e060020a0260005241600160a060020a0316600452600060006024600060008660155a03f150505080600160a060020a031663b9c3d0a58060e060020a02600052602060006004600060008660155a03f150505060005160e1146101ac576101b5565b600191506101ba565b600091505b5090565b60006000605f6106be600039605f60006000f0905080600160a060020a031663b9c3d0a58060e060020a02600052602060006004600060008660155a03f150505060005160e11461020e57610217565b6001915061021c565b600091505b5090565b60006000600060009150600092508160001461023b576102bf565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe78213156102b5575b600a82121561027a578180600101925050610264565b81600a14610287576102b0565b600a90505b60008160ff1611156102af5781806001900392505080806001900391505061028c565b5b6102be565b600092506102da565b5b816000146102cc576102d5565b600192506102da565b600092505b505090565b6000605f6106be600039605f60006000f0905090565b60006001905041600160a060020a0316732adc25665018aa1fe0e6bc666dac8fc2697ff9ba14156103255761032e565b600090506103f4565b446302b8feb0141561033f57610348565b600090506103f4565b43607814156103565761035f565b600090506103f4565b33600160a060020a031673a94f5374fce5edbc8e2a8697c15331677e6ebf0b141561038957610392565b600090506103f4565b34606414156103a0576103a9565b600090506103f4565b3a600114156103b7576103c0565b600090506103f4565b32600160a060020a031673a94f5374fce5edbc8e2a8697c15331677e6ebf0b14156103ea576103f3565b600090506103f4565b5b90565b6000600090505b60011561040a576103fe565b6001905090565b60006000905061041f610426565b6001905090565b61042e610411565b50565b60006000905061043f6102df565b50610448610220565b1561045257610478565b7ff000000000000000000000000000000000000000000000000000000000000000810190505b6104806101be565b1561048a576104b0565b7f0f00000000000000000000000000000000000000000000000000000000000000810190505b6104b8610124565b156104c2576104e7565b7ef0000000000000000000000000000000000000000000000000000000000000810190505b6104ef6102f5565b156104f95761051e565b7e0f000000000000000000000000000000000000000000000000000000000000810190505b60ff60008190555073a94f5374fce5edbc8e2a8697c15331677e6ebf0b60018190555060ff6002819055507f676c6f62616c2064617461203332206c656e67746820737472696e670000000060038190555073a94f5374fce5edbc8e2a8697c15331677e6ebf0b600460006000526020526040600020819055506105a06105d1565b156105aa576105ce565b7df00000000000000000000000000000000000000000000000000000000000810190505b90565b60006001905060005460ff14156105e7576105f0565b600090506106ba565b60025460005414156106015761060a565b600090506106ba565b600154600160a060020a031673a94f5374fce5edbc8e2a8697c15331677e6ebf0b14156106365761063f565b600090506106ba565b6003547f676c6f62616c2064617461203332206c656e67746820737472696e6700000000141561066e57610677565b600090506106ba565b60046000600052602052604060002054600160a060020a031673a94f5374fce5edbc8e2a8697c15331677e6ebf0b14156106b0576106b9565b600090506106ba565b5b905600605380600c6000396000f30060e060020a600035048062f55d9d14601d578063b9c3d0a514602c57005b60266004356045565b60006000f35b6032603c565b8060005260206000f35b600060e1905090565b80600160a060020a0316ff5056", + "code" : "0x60003560e060020a900480630c4c9a8014610084578063296df0df146100965780632a9afb83146100a8578063380e4396146100ba5780634893d88a146100cc5780637ee17e12146100da578063981a3165146100e8578063a60eedda146100fa578063e0a9fd281461010c578063e97384dc1461011e578063ed973fe91461013057005b61008c6102c0565b8060005260206000f35b61009e61067b565b8060005260206000f35b6100b06101ba565b8060005260206000f35b6100c261049b565b8060005260206000f35b6100d461087d565b60006000f35b6100e26101a4565b60006000f35b6100f06102ab565b8060005260206000f35b610102610695565b8060005260206000f35b610114610732565b8060005260206000f35b61012661055a565b8060005260206000f35b610138610142565b8060005260206000f35b600060006060610889600039606060006000f0905080600160a060020a031663b9c3d0a5602060008260e060020a026000526004600060008660155a03f150505060005160e1146101925761019b565b600191506101a0565b600091505b5090565b60006060610889600039606060006000f0905090565b60006001905060005460ff14156101d0576101d9565b600090506102a8565b60025460005414156101ea576101f3565b600090506102a8565b600154600160a060020a031673a94f5374fce5edbc8e2a8697c15331677e6ebf0b141561021f57610228565b600090506102a8565b6003547f676c6f62616c2064617461203332206c656e67746820737472696e6700000000141561025757610260565b600090506102a8565b600460006000815260200190815260200160002054600160a060020a031673a94f5374fce5edbc8e2a8697c15331677e6ebf0b141561029e576102a7565b600090506102a8565b5b90565b6000600090506102b961087d565b6001905090565b6000600090506102ce6101a4565b506102d761049b565b156102e157610307565b7ff000000000000000000000000000000000000000000000000000000000000000810190505b61030f610142565b156103195761033f565b7f0f00000000000000000000000000000000000000000000000000000000000000810190505b610347610695565b1561035157610376565b7ef0000000000000000000000000000000000000000000000000000000000000810190505b61037e61055a565b15610388576103ad565b7e0f000000000000000000000000000000000000000000000000000000000000810190505b60ff60008190555073a94f5374fce5edbc8e2a8697c15331677e6ebf0b60018190555060ff6002819055507f676c6f62616c2064617461203332206c656e67746820737472696e670000000060038190555073a94f5374fce5edbc8e2a8697c15331677e6ebf0b6004600060008152602001908152602001600020819055506104346101ba565b1561043e57610462565b7df00000000000000000000000000000000000000000000000000000000000810190505b61046a610732565b1561047457610498565b7d0f0000000000000000000000000000000000000000000000000000000000810190505b90565b6000600060006000915060009250816000146104b65761053a565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7821315610530575b600a8212156104f55781806001019250506104df565b81600a146105025761052b565b600a90505b60008160ff16111561052a57818060019003925050808060019003915050610507565b5b610539565b60009250610555565b5b8160001461054757610550565b60019250610555565b600092505b505090565b60006001905041600160a060020a0316732adc25665018aa1fe0e6bc666dac8fc2697ff9ba141561058a57610593565b60009050610678565b446302b8feb014156105a4576105ad565b60009050610678565b45683635c9adc5dea0000014156105c3576105cc565b60009050610678565b43607814156105da576105e3565b60009050610678565b33600160a060020a031673a94f5374fce5edbc8e2a8697c15331677e6ebf0b141561060d57610616565b60009050610678565b34606414156106245761062d565b60009050610678565b3a6001141561063b57610644565b60009050610678565b32600160a060020a031673a94f5374fce5edbc8e2a8697c15331677e6ebf0b141561066e57610677565b60009050610678565b5b90565b6000600090505b60011561068e57610682565b6001905090565b60006000600191506060610889600039606060006000f0905080600160a060020a031662f55d9d600060008260e060020a02600052600441600160a060020a03168152602001600060008660155a03f150505080600160a060020a031663b9c3d0a5602060008260e060020a026000526004600060008660155a03f150505060005160e114156107245761072d565b6000915061072e565b5b5090565b60006001905060007f74657374737472696e67000000000000000000000000000000000000000000008152600a016000207f43c4b4524adb81e4e9a5c4648a98e9d320e3908ac5b6c889144b642cd08ae16d141561078f57610798565b6000905061087a565b60026020600060007f74657374737472696e67000000000000000000000000000000000000000000008152600a01600060008560155a03f150506000517f3c8727e019a42b444667a587b6001251becadabbb36bfed8087a92c18882d11114156108015761080a565b6000905061087a565b60036020600060007f74657374737472696e67000000000000000000000000000000000000000000008152600a01600060008560155a03f15050600051600160a060020a031673cd566972b5e50104011a92b59fa8e0b1234851ae141561087057610879565b6000905061087a565b5b90565b6108856102ab565b505600605480600c6000396000f30060003560e060020a90048062f55d9d14601e578063b9c3d0a514602d57005b60276004356046565b60006000f35b6033603d565b8060005260206000f35b600060e1905090565b80600160a060020a0316ff5056", "nonce" : "0", "storage" : { } @@ -233,5 +251,260 @@ "to" : "d94f5374fce5edbc8e2a8697c15331677e6ebf0b", "value" : "100" } + }, + + "CallLowLevelCreatesSolidity" : { + "env" : { + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentDifficulty" : "45678256", + "currentGasLimit" : "100000000", + "currentNumber" : "0", + "currentTimestamp" : 1, + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "pre" : + { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "100000", + "//": "contract subcaller ", + "//": "{ ", + "//": " function init(address a) ", + "//": " { ", + "//": " main(a).setdata(225); ", + "//": " } ", + "//": "} ", + "//": " ", + "//": "contract main ", + "//": "{ ", + "//": " uint data; ", + "//": " function run() returns (uint) ", + "//": " { ", + "//": " data = 1; ", + "//": " subcaller a = new subcaller(); ", + "//": " a.init(msg.sender); ", + "//": " return data; ", + "//": " } ", + "//": " ", + "//": " function setdata(uint _data) ", + "//": " { ", + "//": " data = _data; ", + "//": " } ", + "//": "}", + "code" : "0x60e060020a60003504806330debb4214610020578063c04062261461003157005b61002b6004356100a4565b60006000f35b610039610043565b8060005260206000f35b60006000600160008190555060656100af600039606560006000f0905080600160a060020a03166319ab453c600060008260e060020a02600052600433600160a060020a03168152602001600060008660155a03f150505060005491505090565b80600081905550505600605980600c6000396000f30060e060020a60003504806319ab453c14601457005b601d6004356023565b60006000f35b80600160a060020a03166330debb42600060008260e060020a02600052600460e18152602001600060008660155a03f15050505056", + "nonce" : "0", + "storage" : { + } + } + }, + "transaction" : + { + "//" : "run()", + "data" : "0xc0406226", + "gasLimit" : "15000", + "gasPrice" : "1", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "a94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "value" : "1" + } + }, + + "CallRecursiveMethods" : { + "env" : { + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentDifficulty" : "45678256", + "currentGasLimit" : "100000000", + "currentNumber" : "0", + "currentTimestamp" : 1, + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "pre" : + { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "100000", + "//" : "contract recursiveMethods ", + "//" : "{ ", + "//" : " function testInfiniteLoop() ", + "//" : " { ", + "//" : " while(true){} ", + "//" : " } ", + "//" : " ", + "//" : " function testRecursiveMethods() ", + "//" : " { ", + "//" : " testRecursiveMethods2(); ", + "//" : " } ", + "//" : " ", + "//" : " function testRecursiveMethods2() ", + "//" : " { ", + "//" : " testRecursiveMethods(); ", + "//" : " } ", + "//" : "}", + "code" : "0x60e060020a600035048063296df0df1460285780634893d88a146034578063981a316514604057005b602e604c565b60006000f35b603a6061565b60006000f35b60466059565b60006000f35b5b600115605757604d565b565b605f6061565b565b60676059565b56", + "nonce" : "0", + "storage" : { + } + } + }, + "transaction" : + { + "//" : "testRecursiveMethods()", + "data" : "0x981a3165", + "gasLimit" : "7000", + "gasPrice" : "1", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "a94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "value" : "1" + } + }, + + "CallInfiniteLoop" : { + "env" : { + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentDifficulty" : "45678256", + "currentGasLimit" : "100000000", + "currentNumber" : "0", + "currentTimestamp" : 1, + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "pre" : + { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "100000", + "//" : "contract recursiveMethods ", + "//" : "{ ", + "//" : " function testInfiniteLoop() ", + "//" : " { ", + "//" : " while(true){} ", + "//" : " } ", + "//" : " ", + "//" : " function testRecursiveMethods() ", + "//" : " { ", + "//" : " testRecursiveMethods2(); ", + "//" : " } ", + "//" : " ", + "//" : " function testRecursiveMethods2() ", + "//" : " { ", + "//" : " testRecursiveMethods(); ", + "//" : " } ", + "//" : "}", + "code" : "0x60e060020a600035048063296df0df1460285780634893d88a146034578063981a316514604057005b602e604c565b60006000f35b603a6061565b60006000f35b60466059565b60006000f35b5b600115605757604d565b565b605f6061565b565b60676059565b56", + "nonce" : "0", + "storage" : { + } + } + }, + "transaction" : + { + "//" : "testInfiniteLoop()", + "data" : "0x296df0df", + "gasLimit" : "10000", + "gasPrice" : "1", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "a94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "value" : "1" + } + }, + + "RecursiveCreateContracts" : { + "env" : { + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentDifficulty" : "45678256", + "currentGasLimit" : "100000000", + "currentNumber" : "0", + "currentTimestamp" : 1, + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "pre" : + { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000", + "//" : "contract recursiveCreate1 ", + "//" : "{ ", + "//" : " function recursiveCreate1(address a, uint depth) ", + "//" : " { ", + "//" : " depth = depth - 1; ", + "//" : " if(depth > 0) ", + "//" : " main(a).create2(depth); ", + "//" : " } ", + "//" : "} ", + "//" : " ", + "//" : "contract recursiveCreate2 ", + "//" : "{ ", + "//" : " function recursiveCreate2(address a, uint depth) ", + "//" : " { ", + "//" : " depth = depth - 1; ", + "//" : " if(depth > 0) ", + "//" : " recursiveCreate1 rec1 = new recursiveCreate1(a, depth); ", + "//" : " } ", + "//" : "} ", + "//" : " ", + "//" : "contract main ", + "//" : "{ ", + "//" : " address maincontract; ", + "//" : " uint depp; ", + "//" : " function run(uint depth) ", + "//" : " { ", + "//" : " maincontract = msg.sender; ", + "//" : " depp = depth; ", + "//" : " recursiveCreate1 rec1 = new recursiveCreate1(maincontract, depth); ", + "//" : " } ", + "//" : " ", + "//" : " function create2(uint depth) ", + "//" : " { ", + "//" : " recursiveCreate2 rec2 = new recursiveCreate2(maincontract, depth); ", + "//" : " address(rec2).send(2); ", + "//" : " } ", + "//" : "}", + "code" : "0x60003560e060020a90048063820b13f614610021578063a444f5e91461003257005b61002c600435610043565b60006000f35b61003d60043561008f565b60006000f35b600060c66100cc60003960c6600054600160a060020a0316815260200182815260200160006000f0905080600160a060020a0316600060026000600060006000848787f1505050505050565b6000336000819055508160018190555060686101926000396068600054600160a060020a0316815260200182815260200160006000f09050505056006012604060c6600439600451602451601e565b60018060c56000396000f35b6000600182039150600082116031576057565b6068605d600039606883600160a060020a0316815260200182815260200160006000f090505b5050505600601260406068600439600451602451601e565b60018060676000396000f35b60018103905060008111602f576062565b81600160a060020a031663820b13f6600060008260e060020a026000526004858152602001600060008660155a03f15050505b505056000000601260406068600439600451602451601e565b60018060676000396000f35b60018103905060008111602f576062565b81600160a060020a031663820b13f6600060008260e060020a026000526004858152602001600060008660155a03f15050505b5050560000", + "nonce" : "0", + "storage" : { + } + } + }, + "transaction" : + { + "//" : "run(uint256)", + "data" : "0xa444f5e900000000000000000000000000000000000000000000000000000000000204", + "gasLimit" : "10000", + "gasPrice" : "1", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "a94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "value" : "1" + } + }, + + "AmbigiousMethod" : { + "env" : { + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentDifficulty" : "45678256", + "currentGasLimit" : "100000000", + "currentNumber" : "0", + "currentTimestamp" : 1, + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "pre" : + { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "100000", + "code" : "0x60003560e060020a90048063c040622614601557005b601b6021565b60006000f35b61014f60008190555056", + "nonce" : "0", + "storage" : { + } + } + }, + "transaction" : + { + "//" : "run()", + "data" : "0xc0406226", + "gasLimit" : "10000", + "gasPrice" : "1", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "a94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "value" : "1" + } } } diff --git a/test/stTransactionTestFiller.json b/test/stTransactionTestFiller.json index 214a0ae7c..73026608d 100644 --- a/test/stTransactionTestFiller.json +++ b/test/stTransactionTestFiller.json @@ -208,7 +208,7 @@ } }, - "b94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "b94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "balance" : "1000000", "code" : "{ (CALL 5000 0xc94f5374fce5edbc8e2a8697c15331677e6ebf0b 1 0 0 0 0) }", "nonce" : "0", @@ -216,7 +216,7 @@ } }, - "c94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "c94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "balance" : "0", "code" : "{[[1]]55}", "nonce" : "0", @@ -523,6 +523,232 @@ } }, + "SuicidesAndInternlCallSuicidesOOG" : { + "env" : { + "currentCoinbase" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "currentDifficulty" : "45678256", + "currentGasLimit" : "10000", + "currentNumber" : "0", + "currentTimestamp" : 1, + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "pre" : + { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "7000", + "code" : "", + "nonce" : "0", + "storage" : { + } + }, + + "c94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "10", + "code" : "{(CALL 0 0 1 0 0 0 0) (SUICIDE 0)}", + "nonce" : "0", + "storage" : { + } + }, + + "0000000000000000000000000000000000000000" : { + "balance" : "0", + "code" : "{(SUICIDE 1)}", + "nonce" : "0", + "storage" : { + } + } + + }, + + "transaction" : + { + "data" : "", + "gasLimit" : "700", + "gasPrice" : "1", + "nonce" : "", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "c94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "value" : "10" + } + }, + + "SuicidesAndInternlCallSuicides" : { + "env" : { + "currentCoinbase" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "currentDifficulty" : "45678256", + "currentGasLimit" : "10000", + "currentNumber" : "0", + "currentTimestamp" : 1, + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "pre" : + { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "7000", + "code" : "", + "nonce" : "0", + "storage" : { + } + }, + + "c94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "10", + "code" : "{(CALL 20 0 1 0 0 0 0) (SUICIDE 0)}", + "nonce" : "0", + "storage" : { + } + }, + + "0000000000000000000000000000000000000000" : { + "balance" : "0", + "code" : "{(SUICIDE 1)}", + "nonce" : "0", + "storage" : { + } + } + + }, + + "transaction" : + { + "data" : "", + "gasLimit" : "700", + "gasPrice" : "1", + "nonce" : "", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "c94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "value" : "10" + } + }, + + "SuicidesStopAfterSuicide" : { + "env" : { + "currentCoinbase" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "currentDifficulty" : "45678256", + "currentGasLimit" : "100000", + "currentNumber" : "0", + "currentTimestamp" : 1, + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "pre" : + { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "7000", + "code" : "", + "nonce" : "0", + "storage" : { + } + }, + + "c94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "10000", + "code" : "{(SUICIDE 0) (CALL 0 2000 0 0 0 0 0) }", + "nonce" : "0", + "storage" : { + } + }, + + "0000000000000000000000000000000000000000" : { + "balance" : "1110", + "code" : "{(SUICIDE 1)}", + "nonce" : "0", + "storage" : { + } + } + }, + + "transaction" : + { + "data" : "", + "gasLimit" : "3700", + "gasPrice" : "1", + "nonce" : "", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "c94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "value" : "10" + } + }, + + "SuicidesAndSendMoneyToItselfEtherDestroyed" : { + "env" : { + "currentCoinbase" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "currentDifficulty" : "45678256", + "currentGasLimit" : "10000", + "currentNumber" : "0", + "currentTimestamp" : 1, + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "pre" : + { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "7000", + "code" : "", + "nonce" : "0", + "storage" : { + } + }, + + "c94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000", + "code" : "{(SUICIDE 0xc94f5374fce5edbc8e2a8697c15331677e6ebf0b)}", + "nonce" : "0", + "storage" : { + } + } + }, + + "transaction" : + { + "data" : "", + "gasLimit" : "1700", + "gasPrice" : "1", + "nonce" : "", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "c94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "value" : "10" + } + }, + + "SuicidesMixingCoinbase" : { + "env" : { + "currentCoinbase" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "currentDifficulty" : "45678256", + "currentGasLimit" : "10000", + "currentNumber" : "0", + "currentTimestamp" : 1, + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "pre" : + { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "7000", + "code" : "", + "nonce" : "0", + "storage" : { + } + }, + + "b94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000", + "code" : "{(SUICIDE 0xc94f5374fce5edbc8e2a8697c15331677e6ebf0b)}", + "nonce" : "0", + "storage" : { + } + } + }, + + "transaction" : + { + "data" : "", + "gasLimit" : "1700", + "gasPrice" : "1", + "nonce" : "", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "value" : "10" + } + }, + "TransactionNonceCheck" : { "env" : { "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", @@ -994,7 +1220,7 @@ } }, - "b94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "b94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "balance" : "0", "code" : "{(MSTORE 0 0x600c600055) (CREATE 0 27 5)}", "nonce" : "0", diff --git a/test/ttTransactionTestFiller.json b/test/ttTransactionTestFiller.json index e9ae27188..78615bb45 100644 --- a/test/ttTransactionTestFiller.json +++ b/test/ttTransactionTestFiller.json @@ -241,21 +241,6 @@ } }, - "WrongAddress" : { - "transaction" : - { - "data" : "", - "gasLimit" : "", - "gasPrice" : "", - "nonce" : "", - "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d8v", - "value" : "", - "v" : "27", - "r" : "0x48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353", - "s" : "0xefffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804" - } - }, - "AddressMoreThan20" : { "transaction" : { diff --git a/test/webthreestubclient.h b/test/webthreestubclient.h index ee175b058..70aa9db99 100644 --- a/test/webthreestubclient.h +++ b/test/webthreestubclient.h @@ -447,6 +447,36 @@ class WebThreeStubClient : public jsonrpc::Client else throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); } + int eth_register(const std::string& param1) throw (jsonrpc::JsonRpcException) + { + Json::Value p; + p.append(param1); + Json::Value result = this->CallMethod("eth_register",p); + if (result.isInt()) + return result.asInt(); + else + throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); + } + bool eth_unregister(int param1) throw (jsonrpc::JsonRpcException) + { + Json::Value p; + p.append(param1); + Json::Value result = this->CallMethod("eth_unregister",p); + if (result.isBool()) + return result.asBool(); + else + throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); + } + Json::Value eth_queuedTransactions(int param1) throw (jsonrpc::JsonRpcException) + { + Json::Value p; + p.append(param1); + Json::Value result = this->CallMethod("eth_queuedTransactions",p); + if (result.isArray()) + return result; + else + throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); + } bool db_put(const std::string& param1, const std::string& param2, const std::string& param3) throw (jsonrpc::JsonRpcException) { Json::Value p; diff --git a/test/whisperTopic.cpp b/test/whisperTopic.cpp index be93174ec..4609c957d 100644 --- a/test/whisperTopic.cpp +++ b/test/whisperTopic.cpp @@ -30,6 +30,7 @@ using namespace dev::shh; BOOST_AUTO_TEST_SUITE(whisper) +#if ALEX_HASH_FIXED_NETWORKING BOOST_AUTO_TEST_CASE(topic) { cnote << "Testing Whisper..."; @@ -293,5 +294,6 @@ BOOST_AUTO_TEST_CASE(asyncforwarding) BOOST_REQUIRE_EQUAL(result, 1); } +#endif BOOST_AUTO_TEST_SUITE_END()