diff --git a/CodingStandards.txt b/CodingStandards.txt index 79403af2f..e1313e2fd 100644 --- a/CodingStandards.txt +++ b/CodingStandards.txt @@ -1,7 +1,7 @@ 0. Formatting a. Use tabs for indentation! -- 1 tab is 4 spaces wide. +- tab stops are every 4 characters. - One indentation level -> exactly one byte (i.e. a tab character) in the source file. b. Line widths: - Don't worry about having lines of code > 80-char wide. @@ -11,8 +11,9 @@ d. Never place condition bodies on same line as condition. e. Space between first paren and keyword, but *not* following first paren or preceeding final paren. f. No spaces when fewer than intra-expression three parens together; when three or more, space according to clarity. g. No spaces for subscripting. -h. Space all other operators. -i. Braces, when used, always have their own lines and are at same indentation level as "parent" scope. +h. No space before ':' but one after it, except in the ternary operator: one on both sides. +i. Space all other operators. +j. Braces, when used, always have their own lines and are at same indentation level as "parent" scope. (WRONG) if( a==b[ i ] ) { printf ("Hello\n"); } @@ -147,8 +148,17 @@ e. A dictionary and thesaurus are your friends. - Find short, memorable & (at least semi-) descriptive names for commonly used classes or name-fragments. +10. Type-definitions -10. Commenting +a. Prefer using to typedef. e.g. using ints = std::vector; rather than typedef std::vector ints; +b. Generally avoid shortening a standard form that already includes all important information: +- e.g. stick to shared_ptr rather than shortening to ptr. +c. Where there are exceptions to this (due to excessive use and clear meaning), note the change prominently and use it consistently. +- e.g. using Guard = boost::lock_guard; ///< Guard is used throughout the codebase since it's clear in meaning and used commonly. +d. In general expressions should be roughly as important/semantically meaningful as the space they occupy. + + +11. Commenting a. Comments should be doxygen-compilable, using @notation rather than \notation. diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 774eab64b..aa3f8db6b 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -135,6 +135,7 @@ Main::Main(QWidget *parent) : connect(ui->webView, &QWebView::loadStarted, [this]() { // NOTE: no need to delete as QETH_INSTALL_JS_NAMESPACE adopts it. + m_dev = new QDev(this); m_ethereum = new QEthereum(this, ethereum(), owned()); m_whisper = new QWhisper(this, whisper()); m_p2p = new QPeer2Peer(this, peer2peer()); @@ -142,10 +143,11 @@ Main::Main(QWidget *parent) : QWebSettings::globalSettings()->setAttribute(QWebSettings::DeveloperExtrasEnabled, true); QWebFrame* f = ui->webView->page()->mainFrame(); f->disconnect(SIGNAL(javaScriptWindowObjectCleared())); + auto qdev = m_dev; auto qeth = m_ethereum; auto qshh = m_whisper; auto qp2p = m_p2p; - connect(f, &QWebFrame::javaScriptWindowObjectCleared, QETH_INSTALL_JS_NAMESPACE(f, qeth, qshh, qp2p, this)); + connect(f, &QWebFrame::javaScriptWindowObjectCleared, QETH_INSTALL_JS_NAMESPACE(f, this, qdev, qeth, qshh, qp2p)); }); connect(ui->webView, &QWebView::loadFinished, [=]() diff --git a/alethzero/MainWin.h b/alethzero/MainWin.h index eaba4d685..cd2899aec 100644 --- a/alethzero/MainWin.h +++ b/alethzero/MainWin.h @@ -248,6 +248,7 @@ private: QString m_logHistory; bool m_logChanged = true; + QDev* m_dev = nullptr; QEthereum* m_ethereum = nullptr; QWhisper* m_whisper = nullptr; QPeer2Peer* m_p2p = nullptr; diff --git a/eth/main.cpp b/eth/main.cpp index d83d7efdf..1516478a5 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -325,7 +325,7 @@ int main(int argc, char** argv) c->setAddress(coinbase); } - auto nodesState = contents(dbPath + "/nodeState.rlp"); + auto nodesState = contents((dbPath.size() ? dbPath : getDataDir()) + "/nodeState.rlp"); web3.restoreNodes(&nodesState); cout << "Address: " << endl << toHex(us.address().asArray()) << endl; @@ -792,7 +792,7 @@ int main(int argc, char** argv) while (!g_exit) this_thread::sleep_for(chrono::milliseconds(1000)); - writeFile(dbPath + "/nodeState.rlp", web3.saveNodes()); + writeFile((dbPath.size() ? dbPath : getDataDir()) + "/nodeState.rlp", web3.saveNodes()); return 0; } diff --git a/libdevcore/Common.cpp b/libdevcore/Common.cpp index 335e2b387..d9192c79f 100644 --- a/libdevcore/Common.cpp +++ b/libdevcore/Common.cpp @@ -27,7 +27,7 @@ using namespace dev; namespace dev { -char const* Version = "0.7.4"; +char const* Version = "0.7.5"; } diff --git a/libdevcore/Exceptions.h b/libdevcore/Exceptions.h index 1a54814c6..74315ff26 100644 --- a/libdevcore/Exceptions.h +++ b/libdevcore/Exceptions.h @@ -44,6 +44,6 @@ struct FileError: virtual Exception {}; // error information to be added to exceptions typedef boost::error_info errinfo_invalidSymbol; -typedef boost::error_info errinfo_wrongAddress; +typedef boost::error_info errinfo_wrongAddress; typedef boost::error_info errinfo_comment; } diff --git a/libdevcore/Worker.cpp b/libdevcore/Worker.cpp index 29ff766d7..b2660305a 100644 --- a/libdevcore/Worker.cpp +++ b/libdevcore/Worker.cpp @@ -38,6 +38,7 @@ void Worker::startWorking() m_work.reset(new thread([&]() { setThreadName(m_name.c_str()); + startedWorking(); while (!m_stop) { this_thread::sleep_for(chrono::milliseconds(30)); diff --git a/libdevcore/Worker.h b/libdevcore/Worker.h index 8f0baaf60..a4a998dd7 100644 --- a/libdevcore/Worker.h +++ b/libdevcore/Worker.h @@ -46,6 +46,7 @@ protected: void startWorking(); void stopWorking(); bool isWorking() const { Guard l(x_work); return !!m_work; } + virtual void startedWorking() {} virtual void doWork() = 0; virtual void doneWorking() {} diff --git a/libethcore/Exceptions.h b/libethcore/Exceptions.h index 8a4723696..8e4fcb2d2 100644 --- a/libethcore/Exceptions.h +++ b/libethcore/Exceptions.h @@ -44,26 +44,26 @@ struct FeeTooSmall: virtual dev::Exception {}; struct TooMuchGasUsed: virtual dev::Exception {}; struct ExtraDataTooBig: virtual dev::Exception {}; struct InvalidSignature: virtual dev::Exception {}; -class InvalidBlockFormat: public dev::Exception { public: InvalidBlockFormat(int _f, bytesConstRef _d): m_f(_f), m_d(_d.toBytes()) {} int m_f; bytes m_d; virtual const char* what() const noexcept; }; +class InvalidBlockFormat: virtual public dev::Exception { public: InvalidBlockFormat(int _f, bytesConstRef _d): m_f(_f), m_d(_d.toBytes()) {} int m_f; bytes m_d; virtual const char* what() const noexcept; }; struct InvalidUnclesHash: virtual dev::Exception {}; struct InvalidUncle: virtual dev::Exception {}; struct UncleTooOld: virtual dev::Exception {}; -class UncleInChain: public dev::Exception { public: UncleInChain(h256Set _uncles, h256 _block): m_uncles(_uncles), m_block(_block) {} h256Set m_uncles; h256 m_block; virtual const char* what() const noexcept; }; +class UncleInChain: virtual public dev::Exception { public: UncleInChain(h256Set _uncles, h256 _block): m_uncles(_uncles), m_block(_block) {} h256Set m_uncles; h256 m_block; virtual const char* what() const noexcept; }; struct DuplicateUncleNonce: virtual dev::Exception {}; struct InvalidStateRoot: virtual dev::Exception {}; -class InvalidTransactionsHash: public dev::Exception { public: InvalidTransactionsHash(h256 _head, h256 _real): m_head(_head), m_real(_real) {} h256 m_head; h256 m_real; virtual const char* what() const noexcept; }; +class InvalidTransactionsHash: virtual public dev::Exception { public: InvalidTransactionsHash(h256 _head, h256 _real): m_head(_head), m_real(_real) {} h256 m_head; h256 m_real; virtual const char* what() const noexcept; }; struct InvalidTransaction: virtual dev::Exception {}; struct InvalidDifficulty: virtual dev::Exception {}; -class InvalidGasLimit: public dev::Exception { public: InvalidGasLimit(u256 _provided = 0, u256 _valid = 0): provided(_provided), valid(_valid) {} u256 provided; u256 valid; virtual const char* what() const noexcept; }; -class InvalidMinGasPrice: public dev::Exception { public: InvalidMinGasPrice(u256 _provided = 0, u256 _limit = 0): provided(_provided), limit(_limit) {} u256 provided; u256 limit; virtual const char* what() const noexcept; }; +class InvalidGasLimit: virtual public dev::Exception { public: InvalidGasLimit(u256 _provided = 0, u256 _valid = 0): provided(_provided), valid(_valid) {} u256 provided; u256 valid; virtual const char* what() const noexcept; }; +class InvalidMinGasPrice: virtual public dev::Exception { public: InvalidMinGasPrice(u256 _provided = 0, u256 _limit = 0): provided(_provided), limit(_limit) {} u256 provided; u256 limit; virtual const char* what() const noexcept; }; struct InvalidTransactionGasUsed: virtual dev::Exception {}; struct InvalidTransactionStateRoot: virtual dev::Exception {}; struct InvalidTimestamp: virtual dev::Exception {}; -class InvalidNonce: public dev::Exception { public: InvalidNonce(u256 _required = 0, u256 _candidate = 0): required(_required), candidate(_candidate) {} u256 required; u256 candidate; virtual const char* what() const noexcept; }; -class InvalidBlockNonce: public dev::Exception { public: InvalidBlockNonce(h256 _h = h256(), h256 _n = h256(), u256 _d = 0): h(_h), n(_n), d(_d) {} h256 h; h256 n; u256 d; virtual const char* what() const noexcept; }; +class InvalidNonce: virtual public dev::Exception { public: InvalidNonce(u256 _required = 0, u256 _candidate = 0): required(_required), candidate(_candidate) {} u256 required; u256 candidate; virtual const char* what() const noexcept; }; +class InvalidBlockNonce: virtual public dev::Exception { public: InvalidBlockNonce(h256 _h = h256(), h256 _n = h256(), u256 _d = 0): h(_h), n(_n), d(_d) {} h256 h; h256 n; u256 d; virtual const char* what() const noexcept; }; struct InvalidParentHash: virtual dev::Exception {}; struct InvalidNumber: virtual dev::Exception {}; -struct InvalidContractAddress: virtual dev::Exception {}; +struct InvalidContractAddress: virtual public dev::Exception {}; } } diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 717e2684c..ecce7406d 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -88,8 +88,19 @@ void Client::setNetworkId(u256 _n) h->setNetworkId(_n); } -DownloadMan const* Client::downloadMan() const { if (auto h = m_host.lock()) return &(h->downloadMan()); return nullptr; } -bool Client::isSyncing() const { if (auto h = m_host.lock()) return h->isSyncing(); return false; } +DownloadMan const* Client::downloadMan() const +{ + if (auto h = m_host.lock()) + return &(h->downloadMan()); + return nullptr; +} + +bool Client::isSyncing() const +{ + if (auto h = m_host.lock()) + return h->isSyncing(); + return false; +} void Client::doneWorking() { diff --git a/libethereum/Client.h b/libethereum/Client.h index 8ec65c199..cabc9ac23 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -285,7 +285,7 @@ private: State m_preMine; ///< The present state of the client. State m_postMine; ///< The state of the client which we're mining (i.e. it'll have all the rewards added). - std::weak_ptr m_host; ///< Our Ethereum Host. Don't do anything if we can't lock. + std::weak_ptr m_host; ///< Our Ethereum Host. Don't do anything if we can't lock. std::vector m_miners; mutable boost::shared_mutex x_miners; diff --git a/libethereum/EthereumHost.cpp b/libethereum/EthereumHost.cpp index 5daf67fb9..94ef9d35c 100644 --- a/libethereum/EthereumHost.cpp +++ b/libethereum/EthereumHost.cpp @@ -86,6 +86,11 @@ void EthereumHost::noteNeedsSyncing(EthereumPeer* _who) void EthereumHost::changeSyncer(EthereumPeer* _syncer) { + if (_syncer) + clog(NetAllDetail) << "Changing syncer to" << _syncer->session()->socketId(); + else + clog(NetAllDetail) << "Clearing syncer."; + m_syncer = _syncer; if (isSyncing()) { diff --git a/libethereum/EthereumPeer.cpp b/libethereum/EthereumPeer.cpp index 24b400c1d..b204546d4 100644 --- a/libethereum/EthereumPeer.cpp +++ b/libethereum/EthereumPeer.cpp @@ -142,7 +142,6 @@ void EthereumPeer::transition(Asking _a, bool _force) host()->m_man.resetToChain(m_syncingNeededBlocks); host()->m_latestBlockSent = m_syncingLatestHash; - } else { @@ -156,7 +155,7 @@ void EthereumPeer::transition(Asking _a, bool _force) if (m_asking == Asking::Nothing || m_asking == Asking::Hashes || m_asking == Asking::Blocks) { // Looks like it's the best yet for total difficulty. Set to download. - setAsking(Asking::Blocks, true); // will kick off other peers to help if available. + setAsking(Asking::Blocks, isSyncing()); // will kick off other peers to help if available. auto blocks = m_sub.nextFetch(c_maxBlocksAsk); if (blocks.size()) { diff --git a/libevm/VM.h b/libevm/VM.h index 401e30baf..2eb34ed04 100644 --- a/libevm/VM.h +++ b/libevm/VM.h @@ -41,7 +41,7 @@ struct BreakPointHit: virtual VMException {}; struct BadInstruction: virtual VMException {}; struct BadJumpDestination: virtual VMException {}; struct OutOfGas: virtual VMException {}; -class StackTooSmall: public VMException { public: StackTooSmall(u256 _req, u256 _got): req(_req), got(_got) {} u256 req; u256 got; }; +class StackTooSmall: virtual public VMException { public: StackTooSmall(u256 _req, u256 _got): req(_req), got(_got) {} u256 req; u256 got; }; // Convert from a 256-bit integer stack/memory entry into a 160-bit Address hash. // Currently we just pull out the right (low-order in BE) 160-bits. diff --git a/libp2p/Common.h b/libp2p/Common.h index 7c2c61156..0df7f14fe 100644 --- a/libp2p/Common.h +++ b/libp2p/Common.h @@ -127,5 +127,7 @@ struct PeerInfo std::map notes; }; +using PeerInfos = std::vector; + } } diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index ea89b5613..415ff467a 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -61,8 +61,9 @@ Host::Host(std::string const& _clientVersion, NetworkPreferences const& _n, bool Worker("p2p"), m_clientVersion(_clientVersion), m_netPrefs(_n), - m_acceptor(m_ioService), - m_socket(m_ioService), + m_ioService(new ba::io_service), + m_acceptor(*m_ioService), + m_socket(*m_ioService), m_key(KeyPair::create()) { populateAddresses(); @@ -73,11 +74,15 @@ Host::Host(std::string const& _clientVersion, NetworkPreferences const& _n, bool Host::~Host() { - stop(); + quit(); } void Host::start() { + // if there's no ioService, it means we've had quit() called - bomb out - we're not allowed in here. + if (!m_ioService) + return; + if (isWorking()) stop(); @@ -105,14 +110,6 @@ void Host::start() } } - determinePublic(m_netPrefs.publicIP, m_netPrefs.upnp); - ensureAccepting(); - - if (!m_public.address().is_unspecified() && (m_nodes.empty() || m_nodes[m_nodesList[0]]->id != id())) - noteNode(id(), m_public, Origin::Perfect, false); - - clog(NetNote) << "Id:" << id().abridged(); - for (auto const& h: m_capabilities) h.second->onStarting(); @@ -137,7 +134,18 @@ void Host::stop() m_socket.close(); disconnectPeers(); + if (!!m_ioService) + { + m_ioService->stop(); + m_ioService->reset(); + } +} + +void Host::quit() +{ + stop(); m_ioService.reset(); + // m_acceptor & m_socket are DANGEROUS now. } unsigned Host::protocolVersion() const @@ -168,6 +176,10 @@ void Host::registerPeer(std::shared_ptr _s, CapDescs const& _caps) void Host::disconnectPeers() { + // if there's no ioService, it means we've had quit() called - bomb out - we're not allowed in here. + if (!m_ioService) + return; + for (unsigned n = 0;; n = 0) { { @@ -181,7 +193,7 @@ void Host::disconnectPeers() } if (!n) break; - m_ioService.poll(); + m_ioService->poll(); this_thread::sleep_for(chrono::milliseconds(100)); } @@ -204,6 +216,10 @@ void Host::seal(bytes& _b) void Host::determinePublic(string const& _publicAddress, bool _upnp) { + // if there's no ioService, it means we've had quit() called - bomb out - we're not allowed in here. + if (!m_ioService) + return; + if (_upnp) try { @@ -211,7 +227,7 @@ void Host::determinePublic(string const& _publicAddress, bool _upnp) } catch (NoUPnPDevice) {} // let m_upnp continue as null - we handle it properly. - bi::tcp::resolver r(m_ioService); + bi::tcp::resolver r(*m_ioService); if (m_upnp && m_upnp->isValid() && m_peerAddresses.size()) { clog(NetNote) << "External addr:" << m_upnp->externalIP(); @@ -249,6 +265,10 @@ void Host::determinePublic(string const& _publicAddress, bool _upnp) void Host::populateAddresses() { + // if there's no ioService, it means we've had quit() called - bomb out - we're not allowed in here. + if (!m_ioService) + return; + #ifdef _WIN32 WSAData wsaData; if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0) @@ -289,7 +309,7 @@ void Host::populateAddresses() if (getifaddrs(&ifaddr) == -1) BOOST_THROW_EXCEPTION(NoNetworking()); - bi::tcp::resolver r(m_ioService); + bi::tcp::resolver r(*m_ioService); for (ifaddrs* ifa = ifaddr; ifa; ifa = ifa->ifa_next) { @@ -349,7 +369,7 @@ shared_ptr Host::noteNode(NodeId _id, bi::tcp::endpoint _a, Origin _o, boo if (_a.port() < 30300 && _a.port() > 30303) cwarn << "Wierd port being recorded!"; - if (_a.port() >= 49152) + if (_a.port() >= /*49152*/32768) { cwarn << "Private port being recorded - setting to 0"; _a = bi::tcp::endpoint(_a.address(), 0); @@ -422,6 +442,10 @@ Nodes Host::potentialPeers(RangeMask const& _known) void Host::ensureAccepting() { + // if there's no ioService, it means we've had quit() called - bomb out - we're not allowed in here. + if (!m_ioService) + return; + if (!m_accepting) { clog(NetConnect) << "Listening on local port " << m_listenPort << " (public: " << m_public << ")"; @@ -465,13 +489,17 @@ string Host::pocHost() void Host::connect(std::string const& _addr, unsigned short _port) noexcept { + // if there's no ioService, it means we've had quit() called - bomb out - we're not allowed in here. + if (!m_ioService) + return; + for (int i = 0; i < 2; ++i) { try { if (i == 0) { - bi::tcp::resolver r(m_ioService); + bi::tcp::resolver r(*m_ioService); connect(r.resolve({_addr, toString(_port)})->endpoint()); } else @@ -493,8 +521,12 @@ void Host::connect(std::string const& _addr, unsigned short _port) noexcept void Host::connect(bi::tcp::endpoint const& _ep) { + // if there's no ioService, it means we've had quit() called - bomb out - we're not allowed in here. + if (!m_ioService) + return; + clog(NetConnect) << "Attempting single-shot connection to " << _ep; - bi::tcp::socket* s = new bi::tcp::socket(m_ioService); + bi::tcp::socket* s = new bi::tcp::socket(*m_ioService); s->async_connect(_ep, [=](boost::system::error_code const& ec) { if (ec) @@ -509,27 +541,31 @@ void Host::connect(bi::tcp::endpoint const& _ep) }); } -void Node::connect(Host* _h) +void Host::connect(std::shared_ptr const& _n) { - clog(NetConnect) << "Attempting connection to node" << id.abridged() << "@" << address << "from" << _h->id().abridged(); - lastAttempted = std::chrono::system_clock::now(); - failedAttempts++; - _h->m_ready -= index; - bi::tcp::socket* s = new bi::tcp::socket(_h->m_ioService); - s->async_connect(address, [=](boost::system::error_code const& ec) + // if there's no ioService, it means we've had quit() called - bomb out - we're not allowed in here. + if (!m_ioService) + return; + + clog(NetConnect) << "Attempting connection to node" << _n->id.abridged() << "@" << _n->address << "from" << id().abridged(); + _n->lastAttempted = std::chrono::system_clock::now(); + _n->failedAttempts++; + m_ready -= _n->index; + bi::tcp::socket* s = new bi::tcp::socket(*m_ioService); + s->async_connect(_n->address, [=](boost::system::error_code const& ec) { if (ec) { - clog(NetConnect) << "Connection refused to node" << id.abridged() << "@" << address << "(" << ec.message() << ")"; - lastDisconnect = TCPError; - lastAttempted = std::chrono::system_clock::now(); - _h->m_ready += index; + clog(NetConnect) << "Connection refused to node" << _n->id.abridged() << "@" << _n->address << "(" << ec.message() << ")"; + _n->lastDisconnect = TCPError; + _n->lastAttempted = std::chrono::system_clock::now(); + m_ready += _n->index; } else { - clog(NetConnect) << "Connected to" << id.abridged() << "@" << address; - lastConnected = std::chrono::system_clock::now(); - auto p = make_shared(_h, std::move(*s), _h->node(id), true); // true because we don't care about ids matched for now. Once we have permenant IDs this will matter a lot more and we can institute a safer mechanism. + clog(NetConnect) << "Connected to" << _n->id.abridged() << "@" << _n->address; + _n->lastConnected = std::chrono::system_clock::now(); + auto p = make_shared(this, std::move(*s), node(_n->id), true); // true because we don't care about ids matched for now. Once we have permenant IDs this will matter a lot more and we can institute a safer mechanism. p->start(); } delete s; @@ -594,7 +630,7 @@ void Host::growPeers() if (ns.size()) for (Node const& i: ns) { - m_nodes[i.id]->connect(this); + connect(m_nodes[i.id]); if (!--morePeers) return; } @@ -640,8 +676,12 @@ void Host::prunePeers() i = m_peers.erase(i); } -std::vector Host::peers(bool _updatePing) const +PeerInfos Host::peers(bool _updatePing) const { + // if there's no ioService, it means we've had quit() called - bomb out - we're not allowed in here. + if (!m_ioService) + return PeerInfos(); + RecursiveGuard l(x_peers); if (_updatePing) { @@ -656,8 +696,23 @@ std::vector Host::peers(bool _updatePing) const return ret; } +void Host::startedWorking() +{ + determinePublic(m_netPrefs.publicIP, m_netPrefs.upnp); + ensureAccepting(); + + if (!m_public.address().is_unspecified() && (m_nodes.empty() || m_nodes[m_nodesList[0]]->id != id())) + noteNode(id(), m_public, Origin::Perfect, false); + + clog(NetNote) << "Id:" << id().abridged(); +} + void Host::doWork() { + // if there's no ioService, it means we've had quit() called - bomb out - we're not allowed in here. + if (asserts(!!m_ioService)) + return; + growPeers(); prunePeers(); @@ -679,7 +734,7 @@ void Host::doWork() pingAll(); } - m_ioService.poll(); + m_ioService->poll(); } void Host::pingAll() @@ -701,7 +756,7 @@ bytes Host::saveNodes() const { Node const& n = *(i.second); // TODO: PoC-7: Figure out why it ever shares these ports.//n.address.port() >= 30300 && n.address.port() <= 30305 && - if (!n.dead && n.address.port() > 0 && n.address.port() < 49152 && n.id != id() && !isPrivateAddress(n.address.address())) + if (!n.dead && n.address.port() > 0 && n.address.port() < /*49152*/32768 && n.id != id() && !isPrivateAddress(n.address.address())) { nodes.appendList(10); if (n.address.address().is_v4()) diff --git a/libp2p/Host.h b/libp2p/Host.h index c981edc29..34179a3b4 100644 --- a/libp2p/Host.h +++ b/libp2p/Host.h @@ -97,8 +97,6 @@ struct Node else return score < _n.score; } - - void connect(Host* _h); }; using Nodes = std::vector; @@ -147,6 +145,7 @@ public: static std::string pocHost(); void connect(std::string const& _addr, unsigned short _port = 30303) noexcept; void connect(bi::tcp::endpoint const& _ep); + void connect(std::shared_ptr const& _n); /// @returns true iff we have the a peer of the given id. bool havePeer(NodeId _id) const; @@ -155,7 +154,7 @@ public: void setIdealPeerCount(unsigned _n) { m_idealPeerCount = _n; } /// Get peer information. - std::vector peers(bool _updatePing = false) const; + PeerInfos peers(bool _updatePing = false) const; /// Get number of peers connected; equivalent to, but faster than, peers().size(). size_t peerCount() const { RecursiveGuard l(x_peers); return m_peers.size(); } @@ -174,12 +173,14 @@ public: Nodes nodes() const { RecursiveGuard l(x_peers); Nodes ret; for (auto const& i: m_nodes) ret.push_back(*i.second); return ret; } - void setNetworkPreferences(NetworkPreferences const& _p) { stop(); m_netPrefs = _p; start(); } + void setNetworkPreferences(NetworkPreferences const& _p) { auto had = isStarted(); if (had) stop(); m_netPrefs = _p; if (had) start(); } void start(); void stop(); bool isStarted() const { return isWorking(); } + void quit(); + NodeId id() const { return m_key.pub(); } void registerPeer(std::shared_ptr _s, CapDescs const& _caps); @@ -195,6 +196,8 @@ private: void growPeers(); void prunePeers(); + virtual void startedWorking(); + /// Conduct I/O, polling, syncing, whatever. /// Ideally all time-consuming I/O is done in a background thread or otherwise asynchronously, but you get this call every 100ms or so anyway. /// This won't touch alter the blockchain. @@ -210,7 +213,7 @@ private: static const int NetworkStopped = -1; ///< The value meaning we're not actually listening. int m_listenPort = NetworkStopped; ///< What port are we listening on? - ba::io_service m_ioService; ///< IOService for network stuff. + std::unique_ptr m_ioService; ///< IOService for network stuff. bi::tcp::acceptor m_acceptor; ///< Listening acceptor. bi::tcp::socket m_socket; ///< Listening socket. diff --git a/libp2p/Session.cpp b/libp2p/Session.cpp index 5a66064f8..beb6f161d 100644 --- a/libp2p/Session.cpp +++ b/libp2p/Session.cpp @@ -335,7 +335,7 @@ bool Session::interpret(RLP const& _r) if (!ep.port()) goto CONTINUE; // Zero port? Don't think so. - if (ep.port() >= 49152) + if (ep.port() >= /*49152*/32768) goto CONTINUE; // Private port according to IANA. // TODO: PoC-7: @@ -582,7 +582,7 @@ void Session::doRead() // error - bad protocol clogS(NetWarn) << "Couldn't interpret packet." << RLP(r); // Just wasting our bandwidth - perhaps reduce rating? - return; + //return; } } memmove(m_incoming.data(), m_incoming.data() + tlen, m_incoming.size() - tlen); diff --git a/libp2p/UPnP.h b/libp2p/UPnP.h index 0031298a6..4d53a998b 100644 --- a/libp2p/UPnP.h +++ b/libp2p/UPnP.h @@ -25,6 +25,7 @@ #include #include #include +#include struct UPNPUrls; struct IGDdatas; @@ -46,6 +47,7 @@ public: bool isValid() const { return m_ok; } +private: std::set m_reg; bool m_ok; std::shared_ptr m_urls; diff --git a/libqethereum/QEthereum.cpp b/libqethereum/QEthereum.cpp index bf00fd6ef..ca11f557b 100644 --- a/libqethereum/QEthereum.cpp +++ b/libqethereum/QEthereum.cpp @@ -57,10 +57,11 @@ QString unpadded(QString _s) } QEthereum::QEthereum(QObject* _p, eth::Interface* _c, QList _accounts): - QObject(_p), m_client(_c), m_accounts(_accounts) + QObject(_p), m_client(_c) { // required to prevent crash on osx when performing addto/evaluatejavascript calls moveToThread(_p->thread()); + setAccounts(_accounts); } QEthereum::~QEthereum() @@ -82,11 +83,6 @@ void QEthereum::clearWatches() m_watches.clear(); } -QString QEthereum::secretToAddress(QString _s) const -{ - return toQJS(KeyPair(toSecret(_s)).address()); -} - eth::Interface* QEthereum::client() const { return m_client; @@ -97,27 +93,22 @@ QString QEthereum::lll(QString _s) const return toQJS(dev::eth::compileLLL(_s.toStdString())); } -QString QEthereum::sha3(QString _s) const +QString QDev::sha3(QString _s) const { return toQJS(dev::sha3(toBytes(_s))); } -QString QEthereum::sha3(QString _s1, QString _s2) const +QString QDev::sha3(QString _s1, QString _s2) const { return toQJS(dev::sha3(asBytes(padded(_s1, 32)) + asBytes(padded(_s2, 32)))); } -QString QEthereum::sha3(QString _s1, QString _s2, QString _s3) const +QString QDev::sha3(QString _s1, QString _s2, QString _s3) const { return toQJS(dev::sha3(asBytes(padded(_s1, 32)) + asBytes(padded(_s2, 32)) + asBytes(padded(_s3, 32)))); } -QString QEthereum::sha3old(QString _s) const -{ - return toQJS(dev::sha3(asBytes(_s))); -} - -QString QEthereum::offset(QString _s, int _i) const +QString QDev::offset(QString _s, int _i) const { return toQJS(toU256(_s) + _i); } @@ -132,33 +123,11 @@ unsigned QEthereum::number() const return client() ? client()->number() + 1 : 0; } -QString QEthereum::account() const -{ - if (m_accounts.empty()) - return toQJS(Address()); - return toQJS(m_accounts[0].address()); -} - QStringList QEthereum::accounts() const { QStringList ret; for (auto i: m_accounts) - ret.push_back(toQJS(i.address())); - return ret; -} - -QString QEthereum::key() const -{ - if (m_accounts.empty()) - return toQJS(KeyPair().sec()); - return toQJS(m_accounts[0].sec()); -} - -QStringList QEthereum::keys() const -{ - QStringList ret; - for (auto i: m_accounts) - ret.push_back(toQJS(i.sec())); + ret.push_back(toQJS(i.first)); return ret; } @@ -270,7 +239,7 @@ static dev::eth::MessageFilter toMessageFilter(QString _json) struct TransactionSkeleton { - Secret from; + Address from; Address to; u256 value; bytes data; @@ -284,7 +253,7 @@ static TransactionSkeleton toTransaction(QString _json) QJsonObject f = QJsonDocument::fromJson(_json.toUtf8()).object(); if (f.contains("from")) - ret.from = toSecret(f["from"].toString()); + ret.from = toAddress(f["from"].toString()); if (f.contains("to")) ret.to = toAddress(f["to"].toString()); if (f.contains("value")) @@ -459,6 +428,14 @@ void QEthereum::setMiningImpl(bool _l) } } +void QEthereum::setAccounts(QList const& _l) +{ + m_accounts.clear(); + for (auto i: _l) + m_accounts[i.address()] = i.secret(); + keysChanged(); +} + QString QEthereum::doTransactImpl(QString _json) { QString ret; @@ -467,18 +444,23 @@ QString QEthereum::doTransactImpl(QString _json) TransactionSkeleton t = toTransaction(_json); if (!t.from && m_accounts.size()) { - auto b = m_accounts.first(); + auto b = m_accounts.begin()->first; for (auto a: m_accounts) - if (client()->balanceAt(KeyPair(a).address()) > client()->balanceAt(KeyPair(b).address())) - b = a; - t.from = b.secret(); + if (client()->balanceAt(a.first) > client()->balanceAt(b)) + b = a.first; + t.from = b; } + if (!m_accounts.count(t.from)) + return QString(); if (!t.gasPrice) t.gasPrice = 10 * dev::eth::szabo; if (!t.gas) - t.gas = min(client()->gasLimitRemaining(), client()->balanceAt(KeyPair(t.from).address()) / t.gasPrice); + t.gas = min(client()->gasLimitRemaining(), client()->balanceAt(t.from) / t.gasPrice); + + cwarn << "Silently signing transaction from address" << t.from.abridged() << ": User validation hook goes here."; if (t.to) - client()->transact(t.from, t.value, t.to, t.data, t.gas, t.gasPrice); + // TODO: insert validification hook here. + client()->transact(m_accounts[t.from].secret(), t.value, t.to, t.data, t.gas, t.gasPrice); else ret = toQJS(client()->transact(t.from, t.value, t.data, t.gas, t.gasPrice)); client()->flushTransactions(); @@ -490,15 +472,21 @@ QString QEthereum::doCallImpl(QString _json) if (!m_client) return QString(); TransactionSkeleton t = toTransaction(_json); - if (!t.to) - return QString(); if (!t.from && m_accounts.size()) - t.from = m_accounts[0].secret(); + { + auto b = m_accounts.begin()->first; + for (auto a: m_accounts) + if (client()->balanceAt(a.first) > client()->balanceAt(b)) + b = a.first; + t.from = b; + } + if (!m_accounts.count(t.from)) + return QString(); if (!t.gasPrice) t.gasPrice = 10 * dev::eth::szabo; if (!t.gas) - t.gas = client()->balanceAt(KeyPair(t.from).address()) / t.gasPrice; - bytes out = client()->call(t.from, t.value, t.to, t.data, t.gas, t.gasPrice); + t.gas = min(client()->gasLimitRemaining(), client()->balanceAt(t.from) / t.gasPrice); + bytes out = client()->call(m_accounts[t.from].secret(), t.value, t.to, t.data, t.gas, t.gasPrice); return asQString(out); } diff --git a/libqethereum/QEthereum.h b/libqethereum/QEthereum.h index c4ff710b9..13008fb9b 100644 --- a/libqethereum/QEthereum.h +++ b/libqethereum/QEthereum.h @@ -106,6 +106,27 @@ inline QString fromBinary(QString const& _s, unsigned _padding = 32) return fromBinary(asBytes(_s), _padding); } +class QDev: public QObject +{ + Q_OBJECT + +public: + QDev(QObject* _p): QObject(_p) {} + virtual ~QDev() {} + + Q_INVOKABLE QString sha3(QString _s) const; + Q_INVOKABLE QString sha3(QString _s1, QString _s2) const; + Q_INVOKABLE QString sha3(QString _s1, QString _s2, QString _s3) const; + Q_INVOKABLE QString offset(QString _s, int _offset) const; + + Q_INVOKABLE QString toAscii(QString _s) const { return ::toBinary(_s); } + Q_INVOKABLE QString fromAscii(QString _s) const { return ::fromBinary(_s, 32); } + Q_INVOKABLE QString fromAscii(QString _s, unsigned _padding) const { return ::fromBinary(_s, _padding); } + Q_INVOKABLE QString toDecimal(QString _s) const { return ::toDecimal(_s); } + Q_INVOKABLE double fromFixed(QString _s) const { return ::fromFixed(_s); } + Q_INVOKABLE QString toFixed(double _d) const { return ::toFixed(_d); } +}; + class QEthereum: public QObject { Q_OBJECT @@ -120,31 +141,12 @@ public: /// Call when the client() is going to be deleted to make this object useless but safe. void clientDieing(); - void setAccounts(QList _l) { m_accounts = _l; keysChanged(); } + void setAccounts(QList const& _l); - Q_INVOKABLE QString ethTest() const { return "Hello world!"; } Q_INVOKABLE QEthereum* self() { return this; } - Q_INVOKABLE QString secretToAddress(QString _s) const; Q_INVOKABLE QString lll(QString _s) const; - Q_INVOKABLE QString sha3(QString _s) const; - Q_INVOKABLE QString sha3(QString _s1, QString _s2) const; - Q_INVOKABLE QString sha3(QString _s1, QString _s2, QString _s3) const; - Q_INVOKABLE QString sha3old(QString _s) const; - Q_INVOKABLE QString offset(QString _s, int _offset) const; - - Q_INVOKABLE QString pad(QString _s, unsigned _l) const { return padded(_s, _l); } - Q_INVOKABLE QString pad(QString _s, unsigned _l, unsigned _r) const { return padded(_s, _l, _r); } - Q_INVOKABLE QString unpad(QString _s) const { return unpadded(_s); } - - Q_INVOKABLE QString toAscii(QString _s) const { return ::toBinary(_s); } - Q_INVOKABLE QString fromAscii(QString _s) const { return ::fromBinary(_s, 32); } - Q_INVOKABLE QString fromAscii(QString _s, unsigned _padding) const { return ::fromBinary(_s, _padding); } - Q_INVOKABLE QString toDecimal(QString _s) const { return ::toDecimal(_s); } - Q_INVOKABLE double fromFixed(QString _s) const { return ::fromFixed(_s); } - Q_INVOKABLE QString toFixed(double _d) const { return ::toFixed(_d); } - // [NEW API] - Use this instead. Q_INVOKABLE QString/*dev::u256*/ balanceAt(QString/*dev::Address*/ _a, int _block) const; Q_INVOKABLE double countAt(QString/*dev::Address*/ _a, int _block) const; @@ -176,9 +178,6 @@ public: unsigned/*dev::u256*/ number() const; int getDefault() const; - QString/*dev::KeyPair*/ key() const; - QStringList/*list of dev::KeyPair*/ keys() const; - QString/*dev::Address*/ account() const; QStringList/*list of dev::Address*/ accounts() const; public slots: @@ -200,14 +199,13 @@ private: Q_PROPERTY(QString coinbase READ coinbase WRITE setCoinbaseImpl NOTIFY coinbaseChanged) Q_PROPERTY(bool mining READ isMining WRITE setMiningImpl NOTIFY netChanged) Q_PROPERTY(QString gasPrice READ gasPrice) - Q_PROPERTY(QString key READ key NOTIFY keysChanged) - Q_PROPERTY(QStringList keys READ keys NOTIFY keysChanged) + Q_PROPERTY(QStringList accounts READ accounts NOTIFY keysChanged) Q_PROPERTY(int defaultBlock READ getDefault WRITE setDefault) Q_PROPERTY(unsigned number READ number NOTIFY watchChanged) dev::eth::Interface* m_client; std::vector m_watches; - QList m_accounts; + std::map m_accounts; }; class QPeer2Peer : public QObject @@ -272,52 +270,52 @@ private: }; // TODO: p2p object condition -#define QETH_INSTALL_JS_NAMESPACE(frame, eth, shh, p2p, env) [frame, eth, shh, p2p, env]() \ +#define QETH_INSTALL_JS_NAMESPACE(_frame, _env, _dev, _eth, _shh, _p2p) [_frame, _env, _dev, _eth, _shh, _p2p]() \ { \ - frame->disconnect(); \ - frame->addToJavaScriptWindowObject("env", env, QWebFrame::QtOwnership); \ - if (eth) \ + _frame->disconnect(); \ + _frame->addToJavaScriptWindowObject("env", _env, QWebFrame::QtOwnership); \ + _frame->addToJavaScriptWindowObject("dev", _dev, QWebFrame::ScriptOwnership); \ + if (_eth) \ { \ - frame->addToJavaScriptWindowObject("eth", eth, QWebFrame::ScriptOwnership); \ - frame->addToJavaScriptWindowObject("p2p", p2p, QWebFrame::ScriptOwnership); \ - frame->evaluateJavaScript("eth.setCoinbase = function(a, f) { window.setTimeout(function () { eth.coinbase = a; if (f) {f(true);}}, 0); }"); \ - frame->evaluateJavaScript("eth.getCoinbase = function(f) { window.setTimeout(function () { if (f) {f(eth.coinbase);}}, 0); }"); \ - frame->evaluateJavaScript("eth.listening = {get listening() {return p2p.listening}, set listening(l) {p2p.listening = l}}"); \ - frame->evaluateJavaScript("eth.setListening = function(a, f) { window.setTimeout(function () { eth.listening = a; if (f) {f(true);}}, 0); }"); \ - frame->evaluateJavaScript("eth.getListening = function(f) { window.setTimeout(function () { if (f) {f(eth.listening);}}, 0); }"); \ - frame->evaluateJavaScript("eth.setMining = function(a, f) { window.setTimeout(function () { eth.mining = a; if (f) {f(true);}}, 0); }"); \ - frame->evaluateJavaScript("eth.getMining = function(f) { window.setTimeout(function () { if (f) { f(eth.mining);}}, 0); }"); \ - frame->evaluateJavaScript("eth.getGasPrice = function(f) { window.setTimeout(function () { if (f) {f(eth.gasPrice);}}, 0); }"); \ - frame->evaluateJavaScript("eth.getKey = function(f) { window.setTimeout(function () { if(f) {f(eth.key);}}, 0); }"); \ - frame->evaluateJavaScript("eth.getKeys = function(f) { window.setTimeout(function () { if (f) {f(eth.keys);}}, 0); }"); \ - frame->evaluateJavaScript("eth.peerCount = {get peerCount() {return p2p.peerCount}}"); \ - frame->evaluateJavaScript("eth.getPeerCount = function(f) { window.setTimeout(function () { if (f) {f(eth.peerCount);}}, 0); }"); \ - frame->evaluateJavaScript("eth.getDefaultBlock = function(f) { window.setTimeout(function () { if (f) {f(eth.defaultBlock);}}, 0); }"); \ - frame->evaluateJavaScript("eth.getNumber = function(f) { window.setTimeout(function () { if (f) {f(eth.number);}}, 0); }"); \ - frame->evaluateJavaScript("eth.messages = function(a) { return JSON.parse(eth.getMessagesImpl(JSON.stringify(a))); }"); \ - frame->evaluateJavaScript("eth.getMessages = function(a, f) { window.setTimeout(function () { if (f) { f(JSON.parse(eth.getMessagesImpl(JSON.stringify(a)))); }}, 0);}"); \ - frame->evaluateJavaScript("eth.getBalanceAt = function() { var args = Array.prototype.slice.call(arguments, 0, -1); f = arguments[arguments.length - 1]; window.setTimeout(function () { if (f) { f(eth.balanceAt.apply(null, args)); }},0);}"); \ - frame->evaluateJavaScript("eth.getStateAt = function() { var args = Array.prototype.slice.call(arguments, 0, -1); f = arguments[arguments.length - 1]; window.setTimeout(function () { if (f) { f(eth.stateAt.apply(null, args)); }},0);}"); \ - frame->evaluateJavaScript("eth.getCountAt = function() { var args = Array.prototype.slice.call(arguments, 0, -1); f = arguments[arguments.length - 1]; window.setTimeout(function () { if (f) { f(eth.countAt.apply(null, args)); }},0);}"); \ - frame->evaluateJavaScript("eth.getCodeAt = function() { var args = Array.prototype.slice.call(arguments, 0, -1); f = arguments[arguments.length - 1]; window.setTimeout(function () { if (f) { f(eth.codeAt.apply(null, args)); }},0);}"); \ - frame->evaluateJavaScript("eth.transact = function(a) { var ret = eth.doTransactImpl(JSON.stringify(a)); return ret; }"); \ - frame->evaluateJavaScript("eth.doTransact = function() { var args = Array.prototype.slice.call(arguments, 0, -1); f = arguments[arguments.length - 1]; window.setTimeout(function () { if (f) { f(eth.transact.apply(null, args)); }},0);}"); \ - frame->evaluateJavaScript("eth.call = function(a) { var ret = eth.doCallImpl(JSON.stringify(a)); return ret; }"); \ - frame->evaluateJavaScript("eth.doCall = function() { var args = Array.prototype.slice.call(arguments, 0, -1); f = arguments[arguments.length - 1]; window.setTimeout(function () { if (f) { f(eth.call.apply(null, args)); }},0);}"); \ - frame->evaluateJavaScript("eth.block = function(a) { return JSON.parse(eth.getBlockImpl(JSON.stringify(a))); }"); \ - frame->evaluateJavaScript("eth.getBlock = function() { var args = Array.prototype.slice.call(arguments, 0, -1); f = arguments[arguments.length - 1]; window.setTimeout(function () { if (f) { f(eth.block.apply(null, args)); }},0);}"); \ - frame->evaluateJavaScript("eth.transaction = function(a, i) { return JSON.parse(eth.getTransactionImpl(JSON.stringify(a), i)); }"); \ - frame->evaluateJavaScript("eth.getTransaction = function() { var args = Array.prototype.slice.call(arguments, 0, -1); f = arguments[arguments.length - 1]; window.setTimeout(function () { if (f) { f(eth.transaction.apply(null, args)); }},0);}"); \ - frame->evaluateJavaScript("eth.uncle = function(a, i) { return JSON.parse(eth.getUncleImpl(JSON.stringify(a), i)); }"); \ - frame->evaluateJavaScript("eth.getUncle = function() { var args = Array.prototype.slice.call(arguments, 0, -1); f = arguments[arguments.length - 1]; window.setTimeout(function () { if (f) { f(eth.uncle.apply(null, args)); }},0);}"); \ - frame->evaluateJavaScript("eth.makeWatch = function(a) { var ww = eth.newWatch(a); var ret = { w: ww }; ret.uninstall = function() { eth.killWatch(w); }; ret.changed = function(f) { eth.watchChanged.connect(function(nw) { if (nw == ww) f() }); }; ret.messages = function() { return JSON.parse(eth.watchMessages(this.w)) }; return ret; }"); \ - frame->evaluateJavaScript("eth.watch = function(a) { return eth.makeWatch(JSON.stringify(a)) }"); \ + _frame->addToJavaScriptWindowObject("eth", _eth, QWebFrame::ScriptOwnership); \ + _frame->addToJavaScriptWindowObject("p2p", _p2p, QWebFrame::ScriptOwnership); \ + _frame->evaluateJavaScript("eth.setCoinbase = function(a, f) { window.setTimeout(function () { eth.coinbase = a; if (f) {f(true);}}, 0); }"); \ + _frame->evaluateJavaScript("eth.getCoinbase = function(f) { window.setTimeout(function () { if (f) {f(eth.coinbase);}}, 0); }"); \ + _frame->evaluateJavaScript("eth.listening = {get listening() {return p2p.listening}, set listening(l) {p2p.listening = l}}"); \ + _frame->evaluateJavaScript("eth.setListening = function(a, f) { window.setTimeout(function () { eth.listening = a; if (f) {f(true);}}, 0); }"); \ + _frame->evaluateJavaScript("eth.getListening = function(f) { window.setTimeout(function () { if (f) {f(eth.listening);}}, 0); }"); \ + _frame->evaluateJavaScript("eth.setMining = function(a, f) { window.setTimeout(function () { eth.mining = a; if (f) {f(true);}}, 0); }"); \ + _frame->evaluateJavaScript("eth.getMining = function(f) { window.setTimeout(function () { if (f) { f(eth.mining);}}, 0); }"); \ + _frame->evaluateJavaScript("eth.getGasPrice = function(f) { window.setTimeout(function () { if (f) {f(eth.gasPrice);}}, 0); }"); \ + _frame->evaluateJavaScript("eth.getAccounts = function(f) { window.setTimeout(function () { if (f) {f(eth.accounts);}}, 0); }"); \ + _frame->evaluateJavaScript("eth.peerCount = {get peerCount() {return p2p.peerCount}}"); \ + _frame->evaluateJavaScript("eth.getPeerCount = function(f) { window.setTimeout(function () { if (f) {f(eth.peerCount);}}, 0); }"); \ + _frame->evaluateJavaScript("eth.getDefaultBlock = function(f) { window.setTimeout(function () { if (f) {f(eth.defaultBlock);}}, 0); }"); \ + _frame->evaluateJavaScript("eth.getNumber = function(f) { window.setTimeout(function () { if (f) {f(eth.number);}}, 0); }"); \ + _frame->evaluateJavaScript("eth.messages = function(a) { return JSON.parse(eth.getMessagesImpl(JSON.stringify(a))); }"); \ + _frame->evaluateJavaScript("eth.getMessages = function(a, f) { window.setTimeout(function () { if (f) { f(JSON.parse(eth.getMessagesImpl(JSON.stringify(a)))); }}, 0);}"); \ + _frame->evaluateJavaScript("eth.getBalanceAt = function() { var args = Array.prototype.slice.call(arguments, 0, -1); f = arguments[arguments.length - 1]; window.setTimeout(function () { if (f) { f(eth.balanceAt.apply(null, args)); }},0);}"); \ + _frame->evaluateJavaScript("eth.getStateAt = function() { var args = Array.prototype.slice.call(arguments, 0, -1); f = arguments[arguments.length - 1]; window.setTimeout(function () { if (f) { f(eth.stateAt.apply(null, args)); }},0);}"); \ + _frame->evaluateJavaScript("eth.getCountAt = function() { var args = Array.prototype.slice.call(arguments, 0, -1); f = arguments[arguments.length - 1]; window.setTimeout(function () { if (f) { f(eth.countAt.apply(null, args)); }},0);}"); \ + _frame->evaluateJavaScript("eth.getCodeAt = function() { var args = Array.prototype.slice.call(arguments, 0, -1); f = arguments[arguments.length - 1]; window.setTimeout(function () { if (f) { f(eth.codeAt.apply(null, args)); }},0);}"); \ + _frame->evaluateJavaScript("eth.transact = function(a) { var ret = eth.doTransactImpl(JSON.stringify(a)); return ret; }"); \ + _frame->evaluateJavaScript("eth.doTransact = function() { var args = Array.prototype.slice.call(arguments, 0, -1); f = arguments[arguments.length - 1]; window.setTimeout(function () { if (f) { f(eth.transact.apply(null, args)); }},0);}"); \ + _frame->evaluateJavaScript("eth.call = function(a) { var ret = eth.doCallImpl(JSON.stringify(a)); return ret; }"); \ + _frame->evaluateJavaScript("eth.doCall = function() { var args = Array.prototype.slice.call(arguments, 0, -1); f = arguments[arguments.length - 1]; window.setTimeout(function () { if (f) { f(eth.call.apply(null, args)); }},0);}"); \ + _frame->evaluateJavaScript("eth.block = function(a) { return JSON.parse(eth.getBlockImpl(JSON.stringify(a))); }"); \ + _frame->evaluateJavaScript("eth.getBlock = function() { var args = Array.prototype.slice.call(arguments, 0, -1); f = arguments[arguments.length - 1]; window.setTimeout(function () { if (f) { f(eth.block.apply(null, args)); }},0);}"); \ + _frame->evaluateJavaScript("eth.transaction = function(a, i) { return JSON.parse(eth.getTransactionImpl(JSON.stringify(a), i)); }"); \ + _frame->evaluateJavaScript("eth.getTransaction = function() { var args = Array.prototype.slice.call(arguments, 0, -1); f = arguments[arguments.length - 1]; window.setTimeout(function () { if (f) { f(eth.transaction.apply(null, args)); }},0);}"); \ + _frame->evaluateJavaScript("eth.uncle = function(a, i) { return JSON.parse(eth.getUncleImpl(JSON.stringify(a), i)); }"); \ + _frame->evaluateJavaScript("eth.getUncle = function() { var args = Array.prototype.slice.call(arguments, 0, -1); f = arguments[arguments.length - 1]; window.setTimeout(function () { if (f) { f(eth.uncle.apply(null, args)); }},0);}"); \ + _frame->evaluateJavaScript("eth.makeWatch = function(a) { var ww = eth.newWatch(a); var ret = { w: ww }; ret.uninstall = function() { eth.killWatch(w); }; ret.changed = function(f) { eth.watchChanged.connect(function(nw) { if (nw == ww) f() }); }; ret.messages = function() { return JSON.parse(eth.watchMessages(this.w)) }; return ret; }"); \ + _frame->evaluateJavaScript("eth.watch = function(a) { return eth.makeWatch(JSON.stringify(a)) }"); \ } \ - if (shh) \ + if (_shh) \ { \ - frame->addToJavaScriptWindowObject("shh", shh, QWebFrame::ScriptOwnership); \ - frame->evaluateJavaScript("shh.makeWatch = function(a) { var ww = shh.newWatch(a); var ret = { w: ww }; ret.uninstall = function() { shh.killWatch(w); }; ret.changed = function(f) { shh.watchChanged.connect(function(nw) { if (nw == ww) f() }); }; ret.messages = function() { return JSON.parse(shh.watchMessages(this.w)) }; return ret; }"); \ - frame->evaluateJavaScript("shh.watch = function(a) { return shh.makeWatch(JSON.stringify(a)) }"); \ + _frame->addToJavaScriptWindowObject("shh", _shh, QWebFrame::ScriptOwnership); \ + _frame->evaluateJavaScript("shh.makeWatch = function(a) { var ww = shh.newWatch(a); var ret = { w: ww }; ret.uninstall = function() { shh.killWatch(w); }; ret.changed = function(f) { shh.watchChanged.connect(function(nw) { if (nw == ww) f() }); }; ret.messages = function() { return JSON.parse(shh.watchMessages(this.w)) }; return ret; }"); \ + _frame->evaluateJavaScript("shh.watch = function(a) { return shh.makeWatch(JSON.stringify(a)) }"); \ } \ } diff --git a/libwebthree/WebThree.cpp b/libwebthree/WebThree.cpp index 1515a8707..b5256ac22 100644 --- a/libwebthree/WebThree.cpp +++ b/libwebthree/WebThree.cpp @@ -51,6 +51,28 @@ WebThreeDirect::WebThreeDirect(std::string const& _clientVersion, std::string co WebThreeDirect::~WebThreeDirect() { + // Utterly horrible right now - WebThree owns everything (good), but: + // m_net (Host) owns the eth::EthereumHost via a shared_ptr. + // The eth::EthereumHost depends on eth::Client (it maintains a reference to the BlockChain field of Client). + // eth::Client (owned by us via a unique_ptr) uses eth::EthereumHost (via a weak_ptr). + // Really need to work out a clean way of organising ownership and guaranteeing startup/shutdown is perfect. + + // Have to call quit here to get the Host to kill its io_service otherwise we end up with left-over reads, + // still referencing Sessions getting deleted *after* m_ethereum is reset, causing bad things to happen, since + // the guarantee is that m_ethereum is only reset *after* all sessions have ended (sessions are allowed to + // use bits of data owned by m_ethereum). + m_net.quit(); + m_ethereum.reset(); +} + +void WebThreeDirect::setNetworkPreferences(p2p::NetworkPreferences const& _n) +{ + auto had = haveNetwork(); + if (had) + stopNetwork(); + m_net.setNetworkPreferences(_n); + if (had) + startNetwork(); } std::vector WebThreeDirect::peers() diff --git a/libwebthree/WebThree.h b/libwebthree/WebThree.h index a61c23244..b42b9775a 100644 --- a/libwebthree/WebThree.h +++ b/libwebthree/WebThree.h @@ -107,7 +107,7 @@ public: bool haveNetwork() const { return m_net.isStarted(); } - void setNetworkPreferences(p2p::NetworkPreferences const& _n) { auto had = haveNetwork(); if (had) stopNetwork(); m_net.setNetworkPreferences(_n); if (had) startNetwork(); } + void setNetworkPreferences(p2p::NetworkPreferences const& _n); p2p::NodeId id() const { return m_net.id(); } @@ -126,10 +126,10 @@ public: private: std::string m_clientVersion; ///< Our end-application client's name/version. - std::unique_ptr m_ethereum; ///< Main interface for Ethereum ("eth") protocol. - std::weak_ptr m_whisper; ///< Main interface for Whisper ("shh") protocol. - p2p::Host m_net; ///< Should run in background and send us events when blocks found and allow us to send blocks as required. + + std::unique_ptr m_ethereum; ///< Main interface for Ethereum ("eth") protocol. + std::weak_ptr m_whisper; ///< Main interface for Whisper ("shh") protocol. }; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 066c38aeb..2a6ee0c86 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,6 +1,7 @@ cmake_policy(SET CMP0015 NEW) aux_source_directory(. SRC_LIST) +list(REMOVE_ITEM SRC_LIST "./createRandomTest.cpp") include_directories(..) link_directories(../libethcore) @@ -8,6 +9,7 @@ link_directories(../libethereum) file(GLOB HEADERS "*.h") add_executable(testeth ${SRC_LIST} ${HEADERS}) +add_executable(createRandomTest createRandomTest.cpp vm.cpp) target_link_libraries(testeth ethereum) target_link_libraries(testeth ethcore) @@ -20,6 +22,11 @@ if(JSONRPC_LS) target_link_libraries(testeth ethrpc) endif() +target_link_libraries(createRandomTest ethereum) +target_link_libraries(createRandomTest ethcore) +target_link_libraries(createRandomTest boost_chrono) +target_link_libraries(createRandomTest boost_unit_test_framework) + if ("${TARGET_PLATFORM}" STREQUAL "w64") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-libgcc -static-libstdc++") target_link_libraries(testeth boost_system-mt-s) diff --git a/test/createRandomTest.cpp b/test/createRandomTest.cpp new file mode 100644 index 000000000..874869a5c --- /dev/null +++ b/test/createRandomTest.cpp @@ -0,0 +1,152 @@ +/* + 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 createRandomTest.cpp + * @author Christoph Jentzsch + * @date 2014 + * Creating a random virtual machine test. + */ + +#include +#include +#include +#include +#include +#pragma GCC diagnostic ignored "-Wunused-parameter" +#include +#include +#include +#include +#include +#include +#include "vm.h" + +using namespace std; +using namespace json_spirit; +using namespace dev; + +void doMyTests(json_spirit::mValue& v); + +int main(int argc, char *argv[]) +{ + if (argc != 2) + { + cout << "usage: createRandomTest \n"; + return 0; + } + + // create random code + + boost::random::mt19937 gen; + + auto now = chrono::steady_clock::now().time_since_epoch(); + auto timeSinceEpoch = chrono::duration_cast(now).count(); + gen.seed(static_cast(timeSinceEpoch)); + boost::random::uniform_int_distribution<> lengthOfCodeDist(2, 16); + boost::random::uniform_int_distribution<> opcodeDist(0, 255); + boost::random::variate_generator > randGen(gen, opcodeDist); + + int lengthOfCode = lengthOfCodeDist(gen); + string randomCode; + + for (int i = 0; i < lengthOfCode; ++i) + randomCode += toHex(toCompactBigEndian(randGen())); + + // read template test file + + mValue v; + boost::filesystem::path p(__FILE__); + boost::filesystem::path dir = p.parent_path(); + string s = asString(contents(dir.string() + "/randomTestFiller.json")); + read_string(s, v); + + // insert new random code + v.get_obj().find("randomVMtest")->second.get_obj().find("pre")->second.get_obj().begin()->second.get_obj()["code"] = "0x" + randomCode; + + // execute code in vm + doMyTests(v); + + // write new test + string filename = argv[1]; + writeFile(filename, asBytes(json_spirit::write_string(v, true))); + + return 0; +} + +void doMyTests(json_spirit::mValue& v) +{ + for (auto& i: v.get_obj()) + { + mObject& o = i.second.get_obj(); + + assert(o.count("env") > 0); + assert(o.count("pre") > 0); + assert(o.count("exec") > 0); + + eth::VM vm; + test::FakeExtVM fev; + fev.importEnv(o["env"].get_obj()); + fev.importState(o["pre"].get_obj()); + + o["pre"] = mValue(fev.exportState()); + + fev.importExec(o["exec"].get_obj()); + if (!fev.code) + { + fev.thisTxCode = get<3>(fev.addresses.at(fev.myAddress)); + fev.code = &fev.thisTxCode; + } + + vm.reset(fev.gas); + bytes output; + try + { + output = vm.go(fev).toBytes(); + } + catch (Exception const& _e) + { + cnote << "VM did throw an exception: " << diagnostic_information(_e); + } + catch (std::exception const& _e) + { + cnote << "VM did throw an exception: " << _e.what(); + } + + // delete null entries in storage for the sake of comparison + + for (auto &a: fev.addresses) + { + vector keystoDelete; + for (auto &s: get<2>(a.second)) + { + if (s.second == 0) + keystoDelete.push_back(s.first); + } + for (auto const key: keystoDelete ) + { + get<2>(a.second).erase(key); + } + } + + o["env"] = mValue(fev.exportEnv()); + o["exec"] = mValue(fev.exportExec()); + o["post"] = mValue(fev.exportState()); + o["callcreates"] = fev.exportCallCreates(); + o["out"] = "0x" + toHex(output); + fev.push(o, "gas", vm.gas()); + } +} diff --git a/test/randomTestFiller.json b/test/randomTestFiller.json new file mode 100644 index 000000000..065a21b34 --- /dev/null +++ b/test/randomTestFiller.json @@ -0,0 +1,29 @@ +{ + "randomVMtest": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "random", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + } +} diff --git a/test/vm.cpp b/test/vm.cpp index d77906731..7306ef32d 100644 --- a/test/vm.cpp +++ b/test/vm.cpp @@ -22,6 +22,7 @@ #include "vm.h" #include +#include #define FILL_TESTS @@ -97,7 +98,7 @@ bool FakeExtVM::call(Address _receiveAddress, u256 _value, bytesConstRef _data, { cnote << "not able to call to : " << myAddress << "\n"; cnote << "in FakeExtVM you can only make a call to " << na << "\n"; - BOOST_THROW_EXCEPTION(FakeExtVMFailure() << errinfo_comment("Address not callable in FakeExtVM\n") << errinfo_wrongAddress(myAddress)); + BOOST_THROW_EXCEPTION(FakeExtVMFailure() << errinfo_comment("Address not callable in FakeExtVM\n") << errinfo_wrongAddress(toString(myAddress))); return false; } } @@ -123,7 +124,7 @@ bool FakeExtVM::call(Address _receiveAddress, u256 _value, bytesConstRef _data, { cnote << "not able to call to : " << (_codeAddressOverride ? _codeAddressOverride : _receiveAddress) << "\n"; cnote << "in FakeExtVM you can only make a call to " << na << "\n"; - BOOST_THROW_EXCEPTION(FakeExtVMFailure() << errinfo_comment("Address not callable in FakeExtVM\n") << errinfo_wrongAddress(_codeAddressOverride ? _codeAddressOverride : _receiveAddress)); + BOOST_THROW_EXCEPTION(FakeExtVMFailure() << errinfo_comment("Address not callable in FakeExtVM\n") << errinfo_wrongAddress(toString(_codeAddressOverride ? _codeAddressOverride : _receiveAddress))); return false; } } @@ -251,12 +252,13 @@ mObject FakeExtVM::exportEnv() void FakeExtVM::importEnv(mObject& _o) { - BOOST_REQUIRE(_o.count("previousHash") > 0); - BOOST_REQUIRE(_o.count("currentGasLimit") > 0); - BOOST_REQUIRE(_o.count("currentDifficulty") > 0); - BOOST_REQUIRE(_o.count("currentTimestamp") > 0); - BOOST_REQUIRE(_o.count("currentCoinbase") > 0); - BOOST_REQUIRE(_o.count("currentNumber") > 0); + // cant use BOOST_REQUIRE, because this function is used outside boost test (createRandomTest) + assert(_o.count("previousHash") > 0); + assert(_o.count("currentGasLimit") > 0); + assert(_o.count("currentDifficulty") > 0); + assert(_o.count("currentTimestamp") > 0); + assert(_o.count("currentCoinbase") > 0); + assert(_o.count("currentNumber") > 0); previousBlock.hash = h256(_o["previousHash"].get_str()); currentBlock.number = toInt(_o["currentNumber"]); @@ -293,10 +295,11 @@ void FakeExtVM::importState(mObject& _object) for (auto const& i: _object) { mObject o = i.second.get_obj(); - BOOST_REQUIRE(o.count("balance") > 0); - BOOST_REQUIRE(o.count("nonce") > 0); - BOOST_REQUIRE(o.count("storage") > 0); - BOOST_REQUIRE(o.count("code") > 0); + // cant use BOOST_REQUIRE, because this function is used outside boost test (createRandomTest) + assert(o.count("balance") > 0); + assert(o.count("nonce") > 0); + assert(o.count("storage") > 0); + assert(o.count("code") > 0); auto& a = addresses[Address(i.first)]; get<0>(a) = toInt(o["balance"]); @@ -334,13 +337,14 @@ mObject FakeExtVM::exportExec() void FakeExtVM::importExec(mObject& _o) { - BOOST_REQUIRE(_o.count("address")> 0); - BOOST_REQUIRE(_o.count("caller") > 0); - BOOST_REQUIRE(_o.count("origin") > 0); - BOOST_REQUIRE(_o.count("value") > 0); - BOOST_REQUIRE(_o.count("data") > 0); - BOOST_REQUIRE(_o.count("gasPrice") > 0); - BOOST_REQUIRE(_o.count("gas") > 0); + // cant use BOOST_REQUIRE, because this function is used outside boost test (createRandomTest) + assert(_o.count("address")> 0); + assert(_o.count("caller") > 0); + assert(_o.count("origin") > 0); + assert(_o.count("value") > 0); + assert(_o.count("data") > 0); + assert(_o.count("gasPrice") > 0); + assert(_o.count("gas") > 0); myAddress = Address(_o["address"].get_str()); caller = Address(_o["caller"].get_str()); @@ -611,16 +615,29 @@ void doTests(json_spirit::mValue& v, bool _fillin) void executeTests(const string& _name) { + const char* ptestPath = getenv("ETHEREUM_TEST_PATH"); + string testPath; + + if (ptestPath == NULL) + { + cnote << " could not find environment variable ETHEREUM_TEST_PATH \n"; + testPath = "../../../tests/vmtests"; + } + else + testPath = ptestPath; + #ifdef FILL_TESTS try { cnote << "Populating VM tests..."; json_spirit::mValue v; - string s = asString(contents("../../../cpp-ethereum/test/" + _name + "Filler.json")); + boost::filesystem::path p(__FILE__); + boost::filesystem::path dir = p.parent_path(); + string s = asString(contents(dir.string() + "/" + _name + "Filler.json")); BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of " + _name + "Filler.json is empty."); json_spirit::read_string(s, v); dev::test::doTests(v, true); - writeFile("../../../tests/vmtests/" + _name + ".json", asBytes(json_spirit::write_string(v, true))); + writeFile(testPath + "/" + _name + ".json", asBytes(json_spirit::write_string(v, true))); } catch (Exception const& _e) { @@ -636,8 +653,8 @@ void executeTests(const string& _name) { cnote << "Testing VM..." << _name; json_spirit::mValue v; - string s = asString(contents("../../../tests/vmtests/" + _name + ".json")); - BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of " + _name + ".json is empty. Have you cloned the 'tests' repo branch develop?"); + string s = asString(contents(testPath + "/" + _name + ".json")); + BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of " + _name + ".json is empty. Have you cloned the 'tests' repo branch develop and set ETHEREUM_TEST_PATH to its path?"); json_spirit::read_string(s, v); dev::test::doTests(v, false); } diff --git a/test/vmArithmeticTestFiller.json b/test/vmArithmeticTestFiller.json index d7826d198..9e9538386 100644 --- a/test/vmArithmeticTestFiller.json +++ b/test/vmArithmeticTestFiller.json @@ -281,6 +281,91 @@ } }, + "mul4": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (* 0x8000000000000000000000000000000000000000000000000000000000000000 115792089237316195423570985008687907853269984665640564039457584007913129639935) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "mul5": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (* 0x8000000000000000000000000000000000000000000000000000000000000000 0x8000000000000000000000000000000000000000000000000000000000000000) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "mul6": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (* 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "sub0": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", diff --git a/test/vmIOandFlowOperationsTestFiller.json b/test/vmIOandFlowOperationsTestFiller.json index e214a2d53..79d162c8d 100644 --- a/test/vmIOandFlowOperationsTestFiller.json +++ b/test/vmIOandFlowOperationsTestFiller.json @@ -530,6 +530,61 @@ "gas" : "10000" } }, + "jump0_jumpdest0": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "0x602360085860015d600257", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "jump0_jumpdest1": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "0x602360075860015d600257", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, "jumpi0": { "env" : { @@ -559,6 +614,34 @@ } }, + "jumpi1_jumpdest": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "0x60236001600a5960015d600257", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + "jumpi1": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", diff --git a/test/vmSystemOperationsTestFiller.json b/test/vmSystemOperationsTestFiller.json index de8a3ad1a..c948f0436 100644 --- a/test/vmSystemOperationsTestFiller.json +++ b/test/vmSystemOperationsTestFiller.json @@ -129,7 +129,7 @@ }, "945304eb96065b2a98b57a48a06ae28d285a71b5" : { "balance" : "23", - "code" : "0x600035560f6009590060203560003557", + "code" : "0x600035560f600a59005d60203560003557", "nonce" : "0", "storage" : { } @@ -255,6 +255,42 @@ } }, + "callcodeToReturn1": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (MSTORE 32 0xaaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffaa ) [[ 0 ]] (CALLCODE 500 0x945304eb96065b2a98b57a48a06ae28d285a71b5 23 0 64 0 2 ) }", + "storage": {} + }, + "945304eb96065b2a98b57a48a06ae28d285a71b5" : { + "balance" : "23", + "code" : "0x6001600157603760005560026000f2", + "nonce" : "0", + "storage" : { + } + } + + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "100000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000000000000" + } + }, + "CallToNameRegistratorOutOfGas": { "env" : { @@ -274,7 +310,7 @@ }, "945304eb96065b2a98b57a48a06ae28d285a71b5" : { "balance" : "23", - "code" : "0x600035560f6009590060203560003557", + "code" : "0x600035560f600a59005d60203560003557", "nonce" : "0", "storage" : { } @@ -310,7 +346,7 @@ }, "945304eb96065b2a98b57a48a06ae28d285a71b5" : { "balance" : "23", - "code" : "0x600035560f6009590060203560003557", + "code" : "0x600035560f600a59005d60203560003557", "nonce" : "0", "storage" : { } @@ -346,7 +382,7 @@ }, "945304eb96065b2a98b57a48a06ae28d285a71b5" : { "balance" : "23", - "code" : "0x600035560f6009590060203560003557", + "code" : "0x600035560f600a59005d60203560003557", "nonce" : "0", "storage" : { } @@ -382,7 +418,7 @@ }, "945304eb96065b2a98b57a48a06ae28d285a71b5" : { "balance" : "23", - "code" : "0x600035560f6009590060203560003557", + "code" : "0x600035560f600a59005d60203560003557", "nonce" : "0", "storage" : { } @@ -419,7 +455,7 @@ }, "945304eb96065b2a98b57a48a06ae28d285a71b5" : { "balance" : "23", - "code" : "0x600035560f6009590060203560003557", + "code" : "0x600035560f600a59005d60203560003557", "nonce" : "0", "storage" : { } @@ -455,7 +491,7 @@ }, "945304eb96065b2a98b57a48a06ae28d285a71b5" : { "balance" : "23", - "code" : "0x600035560f6009590060203560003557", + "code" : "0x600035560f600a59005d60203560003557", "nonce" : "0", "storage" : { } @@ -525,7 +561,7 @@ }, "cd1722f3947def4cf144679da39c4c32bdc35681" : { "balance" : "23", - "code" : "0x600035560f6009590060203560003557", + "code" : "0x600035560f600a59005d60203560003557", "nonce" : "0", "storage" : { } @@ -561,7 +597,7 @@ }, "cd1722f3947def4cf144679da39c4c32bdc35681" : { "balance" : "23", - "code" : "0x600035560f6009590060203560003557", + "code" : "0x600035560f600a59005d60203560003557", "nonce" : "0", "storage" : { } @@ -597,7 +633,7 @@ }, "cd1722f3947def4cf144679da39c4c32bdc35681" : { "balance" : "23", - "code" : "0x600035560f6009590060203560003557", + "code" : "0x600035560f600a59005d60203560003557", "nonce" : "0", "storage" : { } @@ -723,7 +759,7 @@ }, "945304eb96065b2a98b57a48a06ae28d285a71b5" : { "balance" : "23", - "code" : "0x600035560f6009590060203560003557", + "code" : "0x600035560f600a59005d60203560003557", "nonce" : "0", "storage" : { } @@ -759,7 +795,43 @@ }, "945304eb96065b2a98b57a48a06ae28d285a71b5" : { "balance" : "23", - "code" : "0x600035560f6009590060203560003557", + "code" : "0x600035560f600a59005d60203560003557", + "nonce" : "0", + "storage" : { + } + } + + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "100000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000000000000" + } + }, + + "callcodeToNameRegistrator0": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (MSTORE 32 0xaaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffaa ) [[ 0 ]] (CALLCODE 1000000 0x945304eb96065b2a98b57a48a06ae28d285a71b5 23 0 64 64 0) }", + "storage": {} + }, + "945304eb96065b2a98b57a48a06ae28d285a71b5" : { + "balance" : "23", + "code" : "0x600035560f600a59005d60203560003557", "nonce" : "0", "storage" : { } @@ -790,7 +862,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x600035560f6009590060203560003557", + "code" : "0x600035560f600a59005d60203560003557", "storage": {} } }, @@ -841,7 +913,7 @@ } }, - "ABAcalls0": { + "ABAcalls1": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", diff --git a/third/MainWin.cpp b/third/MainWin.cpp index 5e53a06a7..4fe58a9a9 100644 --- a/third/MainWin.cpp +++ b/third/MainWin.cpp @@ -105,16 +105,18 @@ Main::Main(QWidget *parent) : connect(ui->webView, &QWebView::loadStarted, [this]() { // NOTE: no need to delete as QETH_INSTALL_JS_NAMESPACE adopts it. + m_dev = new QDev(this); m_ethereum = new QEthereum(this, ethereum(), owned()); m_whisper = new QWhisper(this, whisper()); m_p2p = new QPeer2Peer(this, peer2peer()); QWebFrame* f = ui->webView->page()->mainFrame(); f->disconnect(SIGNAL(javaScriptWindowObjectCleared())); + auto qdev = m_dev; auto qeth = m_ethereum; auto qshh = m_whisper; auto qp2p = m_p2p; - connect(f, &QWebFrame::javaScriptWindowObjectCleared, QETH_INSTALL_JS_NAMESPACE(f, qeth, qshh, qp2p, this)); + connect(f, &QWebFrame::javaScriptWindowObjectCleared, QETH_INSTALL_JS_NAMESPACE(f, this, qdev, qeth, qshh, qp2p)); }); connect(ui->webView, &QWebView::loadFinished, [=]() diff --git a/third/MainWin.h b/third/MainWin.h index 3bd937283..5d6577d42 100644 --- a/third/MainWin.h +++ b/third/MainWin.h @@ -133,6 +133,7 @@ private: QNetworkAccessManager m_webCtrl; + QDev* m_dev = nullptr; QEthereum* m_ethereum = nullptr; QWhisper* m_whisper = nullptr; QPeer2Peer* m_p2p = nullptr;