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/README.md b/README.md index 371b82097..d1d43815f 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,8 @@ By Gav Wood, 2014. +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) master [![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) develop +[![Stories in Ready](https://badge.waffle.io/ethereum/cpp-ethereum.png?label=ready&title=Ready)](http://waffle.io/ethereum/cpp-ethereum) + Ethereum is based on a design in an original whitepaper by Vitalik Buterin. This implementation is based on the formal specification of a refinement of that idea detailed in the 'yellow paper' by Gavin Wood. Contributors, builders and testers include Alex Leverington (Clang & Mac building, client multiplexing), Tim Hughes (MSVC compilation & Dagger testing), Caktux (ongoing CI), Christoph Jentzsch (tests), Christian Reissweiner (Solidity), Marek Kotewicz (external JS & JSON-RPC), Eric Lombrozo (MinGW32 cross-compilation), Marko Simovic (original CI), and several others. ### Building diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 8d69727f8..04a4e6bd6 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -135,15 +135,17 @@ 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()); 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; - connect(f, &QWebFrame::javaScriptWindowObjectCleared, QETH_INSTALL_JS_NAMESPACE(f, qeth, qshh, this)); + connect(f, &QWebFrame::javaScriptWindowObjectCleared, QETH_INSTALL_JS_NAMESPACE(f, this, qdev, qeth, qshh)); }); connect(ui->webView, &QWebView::loadFinished, [=]() @@ -1327,7 +1329,7 @@ void Main::on_contracts_currentItemChanged() s << "

Body Code

" << disassemble(ethereum()->codeAt(address)); ui->contractInfo->appendHtml(QString::fromStdString(s.str())); } - catch (dev::eth::InvalidTrie) + catch (dev::InvalidTrie) { ui->contractInfo->appendHtml("Corrupted trie."); } @@ -1864,7 +1866,7 @@ QString Main::prettyU256(dev::u256 _n) const s << "" << (uint64_t)_n << " (0x" << hex << (uint64_t)_n << ")"; else if (!~(_n >> 64)) s << "" << (int64_t)_n << " (0x" << hex << (int64_t)_n << ")"; - else if ((_n >> 200) == 0) + else if ((_n >> 160) == 0) { Address a = right160(_n); QString n = pretty(a); diff --git a/alethzero/MainWin.h b/alethzero/MainWin.h index 55b8b4e0a..aa5fcf572 100644 --- a/alethzero/MainWin.h +++ b/alethzero/MainWin.h @@ -247,6 +247,7 @@ private: QString m_logHistory; bool m_logChanged = true; + QDev* m_dev = nullptr; QEthereum* m_ethereum = nullptr; QWhisper* m_whisper = nullptr; }; diff --git a/eth/main.cpp b/eth/main.cpp index b5e8eb736..ff272933b 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -324,7 +324,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; @@ -700,7 +700,7 @@ int main(int argc, char** argv) cnote << "Saved" << rechex << "to" << outFile; } - catch (dev::eth::InvalidTrie) + catch (dev::InvalidTrie) { cwarn << "Corrupted trie."; } @@ -791,7 +791,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/exp/main.cpp b/exp/main.cpp index 59c622b6e..9ee26644c 100644 --- a/exp/main.cpp +++ b/exp/main.cpp @@ -29,12 +29,14 @@ #include #include #include +#include using namespace std; using namespace dev; using namespace dev::eth; using namespace dev::p2p; using namespace dev::shh; +#if 0 int main() { DownloadMan man; @@ -69,8 +71,8 @@ int main() cnote << i;*/ return 0; } +#endif -/* int main(int argc, char** argv) { g_logVerbosity = 20; @@ -102,15 +104,16 @@ int main(int argc, char** argv) ph.connect(remoteHost, remotePort); /// Only interested in the packet if the lowest bit is 1 - auto w = wh->installWatch(MessageFilter(std::vector >({{fromHex("0000000000000000000000000000000000000000000000000000000000000001"), fromHex("0000000000000000000000000000000000000000000000000000000000000001")}}))); - + auto w = wh->installWatch(MessageFilter(TopicMasks({{Topic("0000000000000000000000000000000000000000000000000000000000000001"), Topic("0000000000000000000000000000000000000000000000000000000000000001")}}))); for (int i = 0; ; ++i) { - wh->sendRaw(h256(u256(i * i)).asBytes(), h256(u256(i)).asBytes(), 1000); + wh->sendRaw(RLPStream().append(i * i).out(), Topic(u256(i)), 1000); for (auto i: wh->checkWatch(w)) - cnote << "New message:" << (u256)h256(wh->message(i).payload); + { + auto p = wh->message(i).payload; + cnote << "New message:" << RLP(p).toInt(); + } } 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/libdevcrypto/Common.cpp b/libdevcrypto/Common.cpp index 8863352a4..a9fff83c4 100644 --- a/libdevcrypto/Common.cpp +++ b/libdevcrypto/Common.cpp @@ -25,7 +25,6 @@ #include "SHA3.h" using namespace std; using namespace dev; -using namespace dev::eth; //#define ETH_ADDRESS_DEBUG 1 @@ -46,7 +45,7 @@ Address dev::toAddress(Secret _private) ok = secp256k1_ecdsa_pubkey_verify(pubkey, 65); if (!ok) return Address(); - auto ret = right160(dev::eth::sha3(bytesConstRef(&(pubkey[1]), 64))); + auto ret = right160(dev::sha3(bytesConstRef(&(pubkey[1]), 64))); #if ETH_ADDRESS_DEBUG cout << "---- ADDRESS -------------------------------" << endl; cout << "SEC: " << _private << endl; @@ -94,7 +93,7 @@ KeyPair::KeyPair(h256 _sec): m_secret = m_secret; memcpy(m_public.data(), &(pubkey[1]), 64); - m_address = right160(dev::eth::sha3(bytesConstRef(&(pubkey[1]), 64))); + m_address = right160(dev::sha3(bytesConstRef(&(pubkey[1]), 64))); #if ETH_ADDRESS_DEBUG cout << "---- ADDRESS -------------------------------" << endl; diff --git a/libdevcrypto/CryptoHeaders.h b/libdevcrypto/CryptoHeaders.h index 0361091e8..333c03a2f 100644 --- a/libdevcrypto/CryptoHeaders.h +++ b/libdevcrypto/CryptoHeaders.h @@ -29,6 +29,8 @@ #pragma GCC diagnostic ignored "-Wconversion" #pragma GCC diagnostic ignored "-Wunused-parameter" #pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wdelete-non-virtual-dtor" +#pragma GCC diagnostic ignored "-Wextra" #include #include #include diff --git a/libdevcrypto/MemoryDB.cpp b/libdevcrypto/MemoryDB.cpp index 4480417fc..4fc4ed9ad 100644 --- a/libdevcrypto/MemoryDB.cpp +++ b/libdevcrypto/MemoryDB.cpp @@ -23,12 +23,9 @@ #include "MemoryDB.h" using namespace std; using namespace dev; -using namespace dev::eth; namespace dev { -namespace eth -{ std::map MemoryDB::get() const { @@ -116,4 +113,3 @@ set MemoryDB::keys() const } } -} diff --git a/libdevcrypto/MemoryDB.h b/libdevcrypto/MemoryDB.h index 446a947ec..4b8d3b3a2 100644 --- a/libdevcrypto/MemoryDB.h +++ b/libdevcrypto/MemoryDB.h @@ -29,8 +29,6 @@ namespace dev { -namespace eth -{ struct DBChannel: public LogChannel { static const char* name() { return "TDB"; } static const int verbosity = 18; }; @@ -85,4 +83,3 @@ inline std::ostream& operator<<(std::ostream& _out, MemoryDB const& _m) } } -} diff --git a/libdevcrypto/OverlayDB.cpp b/libdevcrypto/OverlayDB.cpp index 460609fb3..8ccae6606 100644 --- a/libdevcrypto/OverlayDB.cpp +++ b/libdevcrypto/OverlayDB.cpp @@ -23,12 +23,9 @@ #include "OverlayDB.h" using namespace std; using namespace dev; -using namespace dev::eth; namespace dev { -namespace eth -{ OverlayDB::~OverlayDB() { @@ -100,4 +97,3 @@ void OverlayDB::kill(h256 _h) } } -} diff --git a/libdevcrypto/OverlayDB.h b/libdevcrypto/OverlayDB.h index 9db4eaed6..777d1e7df 100644 --- a/libdevcrypto/OverlayDB.h +++ b/libdevcrypto/OverlayDB.h @@ -34,8 +34,6 @@ namespace ldb = leveldb; namespace dev { -namespace eth -{ class OverlayDB: public MemoryDB { @@ -63,4 +61,3 @@ private: }; } -} diff --git a/libdevcrypto/SHA3.cpp b/libdevcrypto/SHA3.cpp index 58d5329ef..d72f5bbd4 100644 --- a/libdevcrypto/SHA3.cpp +++ b/libdevcrypto/SHA3.cpp @@ -24,12 +24,9 @@ using namespace std; using namespace dev; -using namespace dev::eth; namespace dev { -namespace eth -{ h256 EmptySHA3 = sha3(bytesConstRef()); @@ -118,4 +115,3 @@ bytes aesDecrypt(bytesConstRef _ivCipher, std::string const& _password, unsigned } } -} diff --git a/libdevcrypto/SHA3.h b/libdevcrypto/SHA3.h index caadfeaf9..fc2cfcfc3 100644 --- a/libdevcrypto/SHA3.h +++ b/libdevcrypto/SHA3.h @@ -29,8 +29,6 @@ namespace dev { -namespace eth -{ // SHA-3 convenience routines. @@ -69,4 +67,3 @@ void sha256(bytesConstRef _input, bytesRef _output); void ripemd160(bytesConstRef _input, bytesRef _output); } -} diff --git a/libdevcrypto/TrieCommon.cpp b/libdevcrypto/TrieCommon.cpp index bad29059e..ff44906b1 100644 --- a/libdevcrypto/TrieCommon.cpp +++ b/libdevcrypto/TrieCommon.cpp @@ -23,8 +23,6 @@ namespace dev { -namespace eth -{ /* * Hex-prefix Notation. First nibble has flags: oddness = 2^0 & termination = 2^1 @@ -127,4 +125,3 @@ byte uniqueInUse(RLP const& _orig, byte except) } } -} diff --git a/libdevcrypto/TrieCommon.h b/libdevcrypto/TrieCommon.h index ecfb4de67..8d6be8ebd 100644 --- a/libdevcrypto/TrieCommon.h +++ b/libdevcrypto/TrieCommon.h @@ -26,8 +26,6 @@ namespace dev { -namespace eth -{ inline byte nibble(bytesConstRef _data, unsigned _i) { @@ -49,10 +47,29 @@ struct NibbleSlice NibbleSlice(bytesConstRef _d = bytesConstRef(), unsigned _o = 0): data(_d), offset(_o) {} byte operator[](unsigned _index) const { return nibble(data, offset + _index); } unsigned size() const { return data.size() * 2 - offset; } + bool empty() const { return !size(); } NibbleSlice mid(unsigned _index) const { return NibbleSlice(data, offset + _index); } + void clear() { data.reset(); offset = 0; } bool contains(NibbleSlice _k) const { return shared(_k) == _k.size(); } unsigned shared(NibbleSlice _k) const { return sharedNibbles(data, offset, offset + size(), _k.data, _k.offset, _k.offset + _k.size()); } + /** + * @brief Determine if we, a full key, are situated prior to a particular key-prefix. + * @param _k The prefix. + * @return true if we are strictly prior to the prefix. + */ + bool isEarlierThan(NibbleSlice _k) const + { + unsigned i; + for (i = 0; i < _k.size() && i < size(); ++i) + if (operator[](i) < _k[i]) // Byte is lower - we're earlier.. + return true; + else if (operator[](i) > _k[i]) // Byte is higher - we're not earlier. + return false; + if (i >= _k.size()) // Ran past the end of the prefix - we're == for the entire prefix - we're not earlier. + return false; + return true; // Ran out before the prefix had finished - we're earlier. + } bool operator==(NibbleSlice _k) const { return _k.size() == size() && shared(_k) == _k.size(); } bool operator!=(NibbleSlice _s) const { return !operator==(_s); } }; @@ -102,4 +119,3 @@ inline std::string hexPrefixEncode(NibbleSlice _s1, NibbleSlice _s2, bool _leaf) } } -} diff --git a/libdevcrypto/TrieDB.cpp b/libdevcrypto/TrieDB.cpp index 3c551d2b4..168b2fdf7 100644 --- a/libdevcrypto/TrieDB.cpp +++ b/libdevcrypto/TrieDB.cpp @@ -23,10 +23,9 @@ #include "TrieDB.h" using namespace std; using namespace dev; -using namespace dev::eth; #if !ETH_LANGUAGES -const h256 dev::eth::c_shaNull = sha3(rlp("")); +const h256 dev::c_shaNull = sha3(rlp("")); #endif diff --git a/libdevcrypto/TrieDB.h b/libdevcrypto/TrieDB.h index 3dd76899a..1fca92294 100644 --- a/libdevcrypto/TrieDB.h +++ b/libdevcrypto/TrieDB.h @@ -39,8 +39,6 @@ namespace ldb = leveldb; namespace dev { -namespace eth -{ struct TrieDBChannel: public LogChannel { static const char* name() { return "-T-"; } static const int verbosity = 17; }; #define tdebug clog(TrieDBChannel) @@ -171,6 +169,7 @@ public: iterator() {} iterator(GenericTrieDB const* _db); + iterator(GenericTrieDB const* _db, bytesConstRef _key); iterator& operator++() { next(); return *this; } @@ -184,13 +183,17 @@ public: private: void next(); + void next(NibbleSlice _key); struct Node { std::string rlp; std::string key; // as hexPrefixEncoding. - byte child; // 255 -> entering + byte child; // 255 -> entering, 16 -> actually at the node, 17 -> exiting, 0-15 -> actual children. + + // 255 -> 16 -> 0 -> 1 -> ... -> 15 -> 17 + void setChild(unsigned _i) { child = _i; } void setFirstChild() { child = 16; } void incrementChild() { child = child == 16 ? 0 : child == 15 ? 17 : (child + 1); } @@ -205,6 +208,8 @@ public: iterator begin() const { return this; } iterator end() const { return iterator(); } + iterator lower_bound(bytesConstRef _key) const { return iterator(this, _key); } + private: RLPStream& streamNode(RLPStream& _s, bytes const& _b); @@ -298,6 +303,7 @@ public: iterator() {} iterator(TrieDB const* _db): Super(_db) {} + iterator(TrieDB const* _db, bytesConstRef _k): Super(_db, _k) {} value_type operator*() const { return at(); } value_type operator->() const { return at(); } @@ -307,6 +313,7 @@ public: iterator begin() const { return this; } iterator end() const { return iterator(); } + iterator lower_bound(KeyType _k) const { return iterator(this, bytesConstRef((byte const*)&_k, sizeof(KeyType))); } }; template @@ -317,14 +324,11 @@ std::ostream& operator<<(std::ostream& _out, TrieDB const& _db) return _out; } -} } // Template implementations... namespace dev { -namespace eth -{ template GenericTrieDB::iterator::iterator(GenericTrieDB const* _db) { @@ -333,6 +337,13 @@ template GenericTrieDB::iterator::iterator(GenericTrieDB const* _ next(); } +template GenericTrieDB::iterator::iterator(GenericTrieDB const* _db, bytesConstRef _fullKey) +{ + m_that = _db; + m_trail.push_back({_db->node(_db->m_root), std::string(1, '\0'), 255}); // one null byte is the HPE for the empty key. + next(_fullKey); +} + template typename GenericTrieDB::iterator::value_type GenericTrieDB::iterator::at() const { assert(m_trail.size()); @@ -341,10 +352,145 @@ template typename GenericTrieDB::iterator::value_type GenericTrie assert(!(b.key[0] & 0x10)); // should be an integer number of bytes (i.e. not an odd number of nibbles). RLP rlp(b.rlp); - if (rlp.itemCount() == 2) - return std::make_pair(bytesConstRef(b.key).cropped(1), rlp[1].payload()); - else - return std::make_pair(bytesConstRef(b.key).cropped(1), rlp[16].payload()); + return std::make_pair(bytesConstRef(b.key).cropped(1), rlp[rlp.itemCount() == 2 ? 1 : 16].payload()); +} + +template void GenericTrieDB::iterator::next(NibbleSlice _key) +{ + NibbleSlice k = _key; + while (true) + { + if (m_trail.empty()) + { + m_that = nullptr; + return; + } + + Node const& b = m_trail.back(); + RLP rlp(b.rlp); + + if (m_trail.back().child == 255) + { + // Entering. Look for first... + if (rlp.isEmpty()) + { + // Kill our search as soon as we hit an empty node. + k.clear(); + m_trail.pop_back(); + continue; + } + if (!rlp.isList() || (rlp.itemCount() != 2 && rlp.itemCount() != 17)) + { +#if ETH_PARANOIA + cwarn << "BIG FAT ERROR. STATE TRIE CORRUPTED!!!!!"; + cwarn << b.rlp.size() << toHex(b.rlp); + cwarn << rlp; + auto c = rlp.itemCount(); + cwarn << c; + BOOST_THROW_EXCEPTION(InvalidTrie()); +#else + m_that = nullptr; + return; +#endif + } + if (rlp.itemCount() == 2) + { + // Just turn it into a valid Branch + auto keyOfRLP = keyOf(rlp); + + // TODO: do something different depending on how keyOfRLP compares to k.mid(0, std::min(k.size(), keyOfRLP.size())); + // if == all is good - continue descent. + // if > discard key and continue descent. + // if < discard key and skip node. + + if (!k.contains(keyOfRLP)) + { + if (!k.isEarlierThan(keyOfRLP)) + { + k.clear(); + m_trail.pop_back(); + continue; + } + k.clear(); + } + + k = k.mid(std::min(k.size(), keyOfRLP.size())); + m_trail.back().key = hexPrefixEncode(keyOf(m_trail.back().key), keyOfRLP, false); + if (isLeaf(rlp)) + { + // leaf - exit now. + if (k.empty()) + { + m_trail.back().child = 0; + return; + } + // Still data in key we're supposed to be looking for when we're at a leaf. Go for next one. + k.clear(); + m_trail.pop_back(); + continue; + } + + // enter child. + m_trail.back().rlp = m_that->deref(rlp[1]); + // no need to set .child as 255 - it's already done. + continue; + } + else + { + // Already a branch - look for first valid. + if (k.size()) + { + m_trail.back().setChild(k[0]); + k = k.mid(1); + } + else + m_trail.back().setChild(16); + // run through to... + } + } + else + { + // Continuing/exiting. Look for next... + if (!(rlp.isList() && rlp.itemCount() == 17)) + { + k.clear(); + m_trail.pop_back(); + continue; + } + // else run through to... + m_trail.back().incrementChild(); + } + + // ...here. should only get here if we're a list. + assert(rlp.isList() && rlp.itemCount() == 17); + for (;; m_trail.back().incrementChild()) + if (m_trail.back().child == 17) + { + // finished here. + k.clear(); + m_trail.pop_back(); + break; + } + else if (!rlp[m_trail.back().child].isEmpty()) + { + if (m_trail.back().child == 16) + return; // have a value at this node - exit now. + else + { + // lead-on to another node - enter child. + // fixed so that Node passed into push_back is constructed *before* m_trail is potentially resized (which invalidates back and rlp) + Node const& back = m_trail.back(); + m_trail.push_back(Node{ + m_that->deref(rlp[back.child]), + hexPrefixEncode(keyOf(back.key), NibbleSlice(bytesConstRef(&back.child, 1), 1), false), + 255 + }); + break; + } + } + else + k.clear(); + } } template void GenericTrieDB::iterator::next() @@ -923,5 +1069,3 @@ template bytes GenericTrieDB::branch(RLP const& _orig) } } -} - diff --git a/libethcore/BlockInfo.cpp b/libethcore/BlockInfo.cpp index 536f684f2..6060ac032 100644 --- a/libethcore/BlockInfo.cpp +++ b/libethcore/BlockInfo.cpp @@ -72,7 +72,7 @@ h256 BlockInfo::headerHash(bytesConstRef _block) void BlockInfo::populateFromHeader(RLP const& _header, bool _checkNonce) { - hash = dev::eth::sha3(_header.data()); + hash = dev::sha3(_header.data()); int field = 0; try diff --git a/libethcore/CommonEth.cpp b/libethcore/CommonEth.cpp index 40a86dba4..54656173b 100644 --- a/libethcore/CommonEth.cpp +++ b/libethcore/CommonEth.cpp @@ -100,7 +100,7 @@ Address toAddress(Secret _private) ok = secp256k1_ecdsa_pubkey_verify(pubkey, 65); if (!ok) return Address(); - auto ret = right160(dev::eth::sha3(bytesConstRef(&(pubkey[1]), 64))); + auto ret = right160(dev::sha3(bytesConstRef(&(pubkey[1]), 64))); #if ETH_ADDRESS_DEBUG cout << "---- ADDRESS -------------------------------" << endl; cout << "SEC: " << _private << endl; 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/BlockChain.h b/libethereum/BlockChain.h index b723ed38d..6c96082a5 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -39,13 +39,15 @@ namespace ldb = leveldb; namespace dev { + +class OverlayDB; + namespace eth { static const h256s NullH256s; class State; -class OverlayDB; struct AlreadyHaveBlock: virtual Exception {}; struct UnknownParent: virtual 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/CommonNet.h b/libethereum/CommonNet.h index 7e4821bb4..4192c861e 100644 --- a/libethereum/CommonNet.h +++ b/libethereum/CommonNet.h @@ -30,6 +30,9 @@ namespace dev { + +class OverlayDB; + namespace eth { @@ -44,7 +47,7 @@ static const unsigned c_maxHashesAsk = 256; ///< Maximum number of hashes GetBl static const unsigned c_maxBlocks = 128; ///< Maximum number of blocks Blocks will ever send. static const unsigned c_maxBlocksAsk = 128; ///< Maximum number of blocks we ask to receive in Blocks (when using GetChain). #endif -class OverlayDB; + class BlockChain; class TransactionQueue; class EthereumHost; 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/libethereum/MessageFilter.cpp b/libethereum/MessageFilter.cpp index d88bc8a9b..951bfec98 100644 --- a/libethereum/MessageFilter.cpp +++ b/libethereum/MessageFilter.cpp @@ -36,7 +36,7 @@ h256 MessageFilter::sha3() const { RLPStream s; fillStream(s); - return dev::eth::sha3(s.out()); + return dev::sha3(s.out()); } bool MessageFilter::matches(h256 _bloom) const diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 8f2794c12..931ee2cf6 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -58,7 +58,7 @@ void ecrecoverCode(bytesConstRef _in, bytesRef _out) int pubkeylen = 65; secp256k1_start(); if (secp256k1_ecdsa_recover_compact(in.hash.data(), 32, in.r.data(), pubkey, &pubkeylen, 0, (int)(u256)in.v - 27)) - ret = dev::eth::sha3(bytesConstRef(&(pubkey[1]), 64)); + ret = dev::sha3(bytesConstRef(&(pubkey[1]), 64)); memcpy(_out.data(), &ret, min(_out.size(), sizeof(ret))); } @@ -207,6 +207,19 @@ State::~State() { } +Address State::nextActiveAddress(Address _a) const +{ + auto it = m_state.lower_bound(_a); + if ((*it).first == _a) + ++it; + if (it == m_state.end()) + // exchange comments if we want to wraparound +// it = m_state.begin(); + return Address(); + return (*it).first; +} + +// TODO: repot struct CachedAddressState { CachedAddressState(std::string const& _rlp, AddressState const* _s, OverlayDB const* _o): rS(_rlp), r(rS), s(_s), o(_o) {} diff --git a/libethereum/State.h b/libethereum/State.h index 5552ba454..dd6043c73 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -40,7 +40,8 @@ namespace dev { -namespace test{ class FakeExtVM; class FakeState;} + +namespace test { class FakeExtVM; class FakeState; } namespace eth { @@ -116,6 +117,8 @@ public: /// @returns the set containing all addresses currently in use in Ethereum. std::map addresses() const; + Address nextActiveAddress(Address _a) const; + BlockInfo const& info() const { return m_currentBlock; } /// @brief Checks that mining the current object will result in a valid block. diff --git a/libethereum/Transaction.cpp b/libethereum/Transaction.cpp index 70dae3557..bc8423bb1 100644 --- a/libethereum/Transaction.cpp +++ b/libethereum/Transaction.cpp @@ -81,7 +81,7 @@ Address Transaction::sender() const BOOST_THROW_EXCEPTION(InvalidSignature()); // TODO: check right160 is correct and shouldn't be left160. - m_sender = right160(dev::eth::sha3(bytesConstRef(&(pubkey[1]), 64))); + m_sender = right160(dev::sha3(bytesConstRef(&(pubkey[1]), 64))); #if ETH_ADDRESS_DEBUG cout << "---- RECOVER -------------------------------" << endl; diff --git a/libethereum/Transaction.h b/libethereum/Transaction.h index 5b327d96b..ecfbe24f0 100644 --- a/libethereum/Transaction.h +++ b/libethereum/Transaction.h @@ -67,8 +67,8 @@ struct Transaction void fillStream(RLPStream& _s, bool _sig = true) const; bytes rlp(bool _sig = true) const { RLPStream s; fillStream(s, _sig); return s.out(); } std::string rlpString(bool _sig = true) const { return asString(rlp(_sig)); } - h256 sha3(bool _sig = true) const { RLPStream s; fillStream(s, _sig); return dev::eth::sha3(s.out()); } - bytes sha3Bytes(bool _sig = true) const { RLPStream s; fillStream(s, _sig); return dev::eth::sha3Bytes(s.out()); } + h256 sha3(bool _sig = true) const { RLPStream s; fillStream(s, _sig); return dev::sha3(s.out()); } + bytes sha3Bytes(bool _sig = true) const { RLPStream s; fillStream(s, _sig); return dev::sha3Bytes(s.out()); } private: mutable Address m_sender; diff --git a/libevm/VM.h b/libevm/VM.h index 4cfac2783..e092bdfed 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 e85d381f8..197b5052f 100644 --- a/libqethereum/QEthereum.cpp +++ b/libqethereum/QEthereum.cpp @@ -56,10 +56,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() @@ -81,11 +82,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; @@ -96,27 +92,22 @@ QString QEthereum::lll(QString _s) const return toQJS(dev::eth::compileLLL(_s.toStdString())); } -QString QEthereum::sha3(QString _s) const -{ - return toQJS(dev::eth::sha3(toBytes(_s))); -} - -QString QEthereum::sha3(QString _s1, QString _s2) const +QString QDev::sha3(QString _s) const { - return toQJS(dev::eth::sha3(asBytes(padded(_s1, 32)) + asBytes(padded(_s2, 32)))); + return toQJS(dev::sha3(toBytes(_s))); } -QString QEthereum::sha3(QString _s1, QString _s2, QString _s3) const +QString QDev::sha3(QString _s1, QString _s2) const { - return toQJS(dev::eth::sha3(asBytes(padded(_s1, 32)) + asBytes(padded(_s2, 32)) + asBytes(padded(_s3, 32)))); + return toQJS(dev::sha3(asBytes(padded(_s1, 32)) + asBytes(padded(_s2, 32)))); } -QString QEthereum::sha3old(QString _s) const +QString QDev::sha3(QString _s1, QString _s2, QString _s3) const { - return toQJS(dev::eth::sha3(asBytes(_s))); + return toQJS(dev::sha3(asBytes(padded(_s1, 32)) + asBytes(padded(_s2, 32)) + asBytes(padded(_s3, 32)))); } -QString QEthereum::offset(QString _s, int _i) const +QString QDev::offset(QString _s, int _i) const { return toQJS(toU256(_s) + _i); } @@ -131,33 +122,11 @@ QString QEthereum::number() const return m_client ? QString::number(client()->number() + 1) : ""; } -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; } @@ -269,7 +238,7 @@ static dev::eth::MessageFilter toMessageFilter(QString _json) struct TransactionSkeleton { - Secret from; + Address from; Address to; u256 value; bytes data; @@ -283,7 +252,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")) @@ -458,26 +427,17 @@ void QEthereum::setListening(bool) client()->stopNetwork();*/ } -unsigned QEthereum::peerCount() const +void QEthereum::setAccounts(QList const& _l) { - return /*m_client ? (unsigned)client()->peerCount() :*/ 0; + m_accounts.clear(); + for (auto i: _l) + m_accounts[i.address()] = i.secret(); + keysChanged(); } -QString QEthereum::doCreate(QString _secret, QString _amount, QString _init, QString _gas, QString _gasPrice) -{ - if (!m_client) - return ""; - auto ret = toQJS(client()->transact(toSecret(_secret), toU256(_amount), toBytes(_init), toU256(_gas), toU256(_gasPrice))); - client()->flushTransactions(); - return ret; -} - -void QEthereum::doTransact(QString _secret, QString _amount, QString _dest, QString _data, QString _gas, QString _gasPrice) +unsigned QEthereum::peerCount() const { - if (!m_client) - return; - client()->transact(toSecret(_secret), toU256(_amount), toAddress(_dest), toBytes(_data), toU256(_gas), toU256(_gasPrice)); - client()->flushTransactions(); + return /*m_client ? (unsigned)client()->peerCount() :*/ 0; } QString QEthereum::doTransact(QString _json) @@ -488,18 +448,23 @@ QString QEthereum::doTransact(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(); @@ -511,15 +476,21 @@ QString QEthereum::doCall(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 94519e040..f7b978e4b 100644 --- a/libqethereum/QEthereum.h +++ b/libqethereum/QEthereum.h @@ -98,6 +98,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 @@ -112,31 +133,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; @@ -154,8 +156,6 @@ public: Q_INVOKABLE QString/*json*/ getMessages(QString _attribs/*json*/) const; - Q_INVOKABLE QString doCreate(QString _secret, QString _amount, QString _init, QString _gas, QString _gasPrice); - Q_INVOKABLE void doTransact(QString _secret, QString _amount, QString _dest, QString _data, QString _gas, QString _gasPrice); Q_INVOKABLE QString doTransact(QString _json); Q_INVOKABLE QString doCall(QString _json); @@ -172,9 +172,6 @@ public: QString/*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; unsigned peerCount() const; @@ -200,8 +197,7 @@ private: Q_PROPERTY(QString number READ number NOTIFY watchChanged) Q_PROPERTY(QString coinbase READ coinbase WRITE setCoinbase NOTIFY coinbaseChanged) 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(bool mining READ isMining WRITE setMining NOTIFY netChanged) Q_PROPERTY(bool listening READ isListening WRITE setListening NOTIFY netChanged) Q_PROPERTY(unsigned peerCount READ peerCount NOTIFY miningChanged) @@ -209,7 +205,7 @@ private: dev::eth::Interface* m_client; std::vector m_watches; - QList m_accounts; + std::map m_accounts; }; class QWhisper: public QObject @@ -251,22 +247,30 @@ private: std::vector m_watches; }; -#define QETH_INSTALL_JS_NAMESPACE(frame, eth, shh, env) [frame, eth, shh, env]() \ +// TODO: add p2p object +#define QETH_INSTALL_JS_NAMESPACE(_frame, _env, _dev, _eth, _shh) [_frame, _env, _dev, _eth, _shh]() \ { \ - frame->disconnect(); \ - frame->addToJavaScriptWindowObject("env", env, QWebFrame::QtOwnership); \ - frame->addToJavaScriptWindowObject("eth", eth, QWebFrame::ScriptOwnership); \ - frame->addToJavaScriptWindowObject("shh", eth, QWebFrame::ScriptOwnership); \ - 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->evaluateJavaScript("eth.transact = function(a, f) { var r = eth.doTransact(JSON.stringify(a)); if (f) f(r); }"); \ - frame->evaluateJavaScript("eth.call = function(a, f) { var ret = eth.doCallJson(JSON.stringify(a)); if (f) f(ret); return ret; }"); \ - frame->evaluateJavaScript("eth.messages = function(a) { return JSON.parse(eth.getMessages(JSON.stringify(a))); }"); \ - frame->evaluateJavaScript("eth.block = function(a) { return JSON.parse(eth.getBlock(a)); }"); \ - frame->evaluateJavaScript("eth.transaction = function(a) { return JSON.parse(eth.getTransaction(a)); }"); \ - frame->evaluateJavaScript("eth.uncle = function(a) { return JSON.parse(eth.getUncle(a)); }"); \ - 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->disconnect(); \ + _frame->addToJavaScriptWindowObject("env", _env, QWebFrame::QtOwnership); \ + _frame->addToJavaScriptWindowObject("dev", _dev, QWebFrame::ScriptOwnership); \ + if (_eth) \ + { \ + _frame->addToJavaScriptWindowObject("eth", _eth, QWebFrame::ScriptOwnership); \ + _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->evaluateJavaScript("eth.transact = function(a, f) { var r = eth.doTransact(JSON.stringify(a)); if (f) f(r); }"); \ + _frame->evaluateJavaScript("eth.call = function(a, f) { var ret = eth.doCallJson(JSON.stringify(a)); if (f) f(ret); return ret; }"); \ + _frame->evaluateJavaScript("eth.messages = function(a) { return JSON.parse(eth.getMessages(JSON.stringify(a))); }"); \ + _frame->evaluateJavaScript("eth.block = function(a) { return JSON.parse(eth.getBlock(a)); }"); \ + _frame->evaluateJavaScript("eth.transaction = function(a) { return JSON.parse(eth.getTransaction(a)); }"); \ + _frame->evaluateJavaScript("eth.uncle = function(a) { return JSON.parse(eth.getUncle(a)); }"); \ + } \ + 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)) }"); \ + } \ } template inline boost::multiprecision::number> toInt(QString const& _s) 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 32bbe0b31..10e965402 100644 --- a/libwebthree/WebThree.h +++ b/libwebthree/WebThree.h @@ -106,7 +106,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(); } @@ -122,10 +122,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/libwhisper/Common.h b/libwhisper/Common.h index 26e8b9da8..49405f00b 100644 --- a/libwhisper/Common.h +++ b/libwhisper/Common.h @@ -57,5 +57,7 @@ enum WhisperPacket PacketCount }; +using Topic = h256; + } } diff --git a/libwhisper/Interface.cpp b/libwhisper/Interface.cpp index e5f5cd268..beab00f3c 100644 --- a/libwhisper/Interface.cpp +++ b/libwhisper/Interface.cpp @@ -36,15 +36,8 @@ using namespace dev::shh; bool MessageFilter::matches(Message const& _m) const { - for (auto const& t: m_topicMasks) - { - if (t.first.size() != t.second.size() || _m.topic.size() < t.first.size()) - continue; - for (unsigned i = 0; i < t.first.size(); ++i) - if (((t.first[i] ^ _m.topic[i]) & t.second[i]) != 0) - goto NEXT; - return true; - NEXT:; - } + for (TopicMask const& t: m_topicMasks) + if (((t.first ^ _m.topic) & t.second) == 0) + return true; return false; } diff --git a/libwhisper/Interface.h b/libwhisper/Interface.h index e9b822cba..6bed02977 100644 --- a/libwhisper/Interface.h +++ b/libwhisper/Interface.h @@ -37,20 +37,29 @@ namespace dev namespace shh { +/*struct TopicMask +{ + Topic data; + Topic mask; +};*/ + +using TopicMask = std::pair; +using TopicMasks = std::vector; + class MessageFilter { public: MessageFilter() {} - MessageFilter(std::vector > const& _m): m_topicMasks(_m) {} - MessageFilter(RLP const& _r): m_topicMasks((std::vector>)_r) {} + MessageFilter(TopicMasks const& _m): m_topicMasks(_m) {} + MessageFilter(RLP const& _r): m_topicMasks((TopicMasks)_r) {} void fillStream(RLPStream& _s) const { _s << m_topicMasks; } - h256 sha3() const { RLPStream s; fillStream(s); return dev::eth::sha3(s.out()); } + h256 sha3() const { RLPStream s; fillStream(s); return dev::sha3(s.out()); } bool matches(Message const& _m) const; private: - std::vector > m_topicMasks; + TopicMasks m_topicMasks; }; struct InstalledFilter @@ -85,7 +94,7 @@ public: virtual Message message(h256 _m) const = 0; - virtual void sendRaw(bytes const& _payload, bytes const& _topic, unsigned _ttl) = 0; + virtual void sendRaw(bytes const& _payload, h256 _topic, unsigned _ttl) = 0; }; struct WatshhChannel: public dev::LogChannel { static const char* name() { return "shh"; } static const int verbosity = 1; }; diff --git a/libwhisper/Message.h b/libwhisper/Message.h index 952238a9b..9bc36c6a2 100644 --- a/libwhisper/Message.h +++ b/libwhisper/Message.h @@ -40,23 +40,23 @@ struct Message { unsigned expiry = 0; unsigned ttl = 0; - bytes topic; // TODO: change to h256 + Topic topic; // TODO: change to h256 bytes payload; Message() {} - Message(unsigned _exp, unsigned _ttl, bytes const& _topic, bytes const& _payload): expiry(_exp), ttl(_ttl), topic(_topic), payload(_payload) {} + Message(unsigned _exp, unsigned _ttl, Topic const& _topic, bytes const& _payload): expiry(_exp), ttl(_ttl), topic(_topic), payload(_payload) {} Message(RLP const& _m) { expiry = _m[0].toInt(); ttl = _m[1].toInt(); - topic = _m[2].toBytes(); + topic = (Topic)_m[2]; payload = _m[3].toBytes(); } operator bool () const { return !!expiry; } void streamOut(RLPStream& _s) const { _s.appendList(4) << expiry << ttl << topic << payload; } - h256 sha3() const { RLPStream s; streamOut(s); return dev::eth::sha3(s.out()); } + h256 sha3() const { RLPStream s; streamOut(s); return dev::sha3(s.out()); } }; } diff --git a/libwhisper/WhisperHost.h b/libwhisper/WhisperHost.h index 285cc1b43..081be20a1 100644 --- a/libwhisper/WhisperHost.h +++ b/libwhisper/WhisperHost.h @@ -58,7 +58,7 @@ public: virtual Message message(h256 _m) const { try { dev::ReadGuard l(x_messages); return m_messages.at(_m); } catch (...) { return Message(); } } - virtual void sendRaw(bytes const& _payload, bytes const& _topic, unsigned _ttl) { inject(Message(time(0) + _ttl, _ttl, _topic, _payload)); } + virtual void sendRaw(bytes const& _payload, Topic _topic, unsigned _ttl) { inject(Message(time(0) + _ttl, _ttl, _topic, _payload)); } private: void streamMessage(h256 _m, RLPStream& _s) const; diff --git a/neth/main.cpp b/neth/main.cpp index cac19727c..bd66743e5 100644 --- a/neth/main.cpp +++ b/neth/main.cpp @@ -805,7 +805,7 @@ int main(int argc, char** argv) cnote << "Saved" << rechex << "to" << outFile; } - catch (dev::eth::InvalidTrie const& _e) + catch (dev::InvalidTrie const& _e) { cwarn << "Corrupted trie.\n" << diagnostic_information(_e); } diff --git a/qtcreator-style.xml b/qtcreator-style.xml new file mode 100644 index 000000000..5a540f49d --- /dev/null +++ b/qtcreator-style.xml @@ -0,0 +1,39 @@ + + + + + + CodeStyleData + + false + false + true + false + false + false + true + false + true + false + false + false + true + true + false + true + false + false + false + 4 + true + false + 2 + false + 4 + + + + DisplayName + Gav + + diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 2e5366079..a764d8b6b 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) @@ -15,6 +17,11 @@ target_link_libraries(testeth secp256k1) target_link_libraries(testeth gmp) target_link_libraries(testeth ${CRYPTOPP_LS}) +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/MemTrie.cpp b/test/MemTrie.cpp index d654179f3..4879f2674 100644 --- a/test/MemTrie.cpp +++ b/test/MemTrie.cpp @@ -55,7 +55,7 @@ public: #endif /// 256-bit hash of the node - this is a SHA-3/256 hash of the RLP of the node. - h256 hash256() const { RLPStream s; makeRLP(s); return dev::eth::sha3(s.out()); } + h256 hash256() const { RLPStream s; makeRLP(s); return dev::sha3(s.out()); } bytes rlp() const { RLPStream s; makeRLP(s); return s.out(); } void mark() { m_hash256 = h256(); } @@ -200,7 +200,7 @@ void MemTrieNode::putRLP(RLPStream& _parentStream) const if (s.out().size() < 32) _parentStream.APPEND_CHILD(s.out()); else - _parentStream << dev::eth::sha3(s.out()); + _parentStream << dev::sha3(s.out()); } void TrieBranchNode::makeRLP(RLPStream& _intoStream) const diff --git a/test/TestHelperCrypto.h b/test/TestHelperCrypto.h index 6feeeb97f..cdc22ec31 100644 --- a/test/TestHelperCrypto.h +++ b/test/TestHelperCrypto.h @@ -22,11 +22,22 @@ #pragma once //#include + +#pragma warning(push) +#pragma warning(disable:4100 4244) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wdelete-non-virtual-dtor" +#pragma GCC diagnostic ignored "-Wextra" #include #include #include #include #include +#pragma warning(pop) +#pragma GCC diagnostic pop using namespace std; using namespace CryptoPP; 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/crypto.cpp b/test/crypto.cpp index 25106a77f..e71ee2285 100644 --- a/test/crypto.cpp +++ b/test/crypto.cpp @@ -307,7 +307,7 @@ int cryptoTest() int ret = secp256k1_ecdsa_recover_compact((byte const*)hmsg.data(), (int)hmsg.size(), (byte const*)sig64.data(), pubkey.data(), &pubkeylen, 0, (int)t.vrs.v - 27); pubkey.resize(pubkeylen); cout << "RECPUB: " << dec << ret << " " << pubkeylen << " " << toHex(pubkey) << endl; - cout << "SENDER: " << hex << toAddress(dev::eth::sha3(bytesConstRef(&pubkey).cropped(1))) << dec << endl; + cout << "SENDER: " << hex << toAddress(dev::sha3(bytesConstRef(&pubkey).cropped(1))) << dec << endl; } #endif return 0; diff --git a/test/hexPrefix.cpp b/test/hexPrefix.cpp index 6ced839dd..fb2fbc826 100644 --- a/test/hexPrefix.cpp +++ b/test/hexPrefix.cpp @@ -29,7 +29,6 @@ using namespace std; using namespace dev; -using namespace dev::eth; namespace js = json_spirit; BOOST_AUTO_TEST_CASE(hexPrefix_test) 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/rlp.cpp b/test/rlp.cpp index 95d40ada7..69360ad66 100644 --- a/test/rlp.cpp +++ b/test/rlp.cpp @@ -79,7 +79,7 @@ namespace dev if ( v.type() == js::str_type ) { const std::string& expectedText = v.get_str(); - if ( expectedText.front() == '#' ) + if ( !expectedText.empty() && expectedText.front() == '#' ) { // Deal with bigint instead of a raw string std::string bigIntStr = expectedText.substr(1,expectedText.length()-1); diff --git a/test/trie.cpp b/test/trie.cpp index fb74ebe20..899eb1f60 100644 --- a/test/trie.cpp +++ b/test/trie.cpp @@ -31,7 +31,6 @@ using namespace std; using namespace dev; -using namespace dev::eth; namespace js = json_spirit; @@ -236,6 +235,51 @@ BOOST_AUTO_TEST_CASE(moreTrieTests) } } +BOOST_AUTO_TEST_CASE(trieLowerBound) +{ + cnote << "Stress-testing Trie.lower_bound..."; + { + MemoryDB dm; + EnforceRefs e(dm, true); + GenericTrieDB d(&dm); + d.init(); // initialise as empty tree. + for (int a = 0; a < 20; ++a) + { + StringMap m; + for (int i = 0; i < 50; ++i) + { + auto k = randomWord(); + auto v = toString(i); + m[k] = v; + d.insert(k, v); + } + + for (auto i: d) + { + auto it = d.lower_bound(i.first); + for (auto iit = d.begin(); iit != d.end(); ++iit) + if ((*iit).first.toString() >= i.first.toString()) + { + BOOST_REQUIRE(it == iit); + break; + } + } + for (unsigned i = 0; i < 100; ++i) + { + auto k = randomWord(); + auto it = d.lower_bound(k); + for (auto iit = d.begin(); iit != d.end(); ++iit) + if ((*iit).first.toString() >= k) + { + BOOST_REQUIRE(it == iit); + break; + } + } + + } + } +} + BOOST_AUTO_TEST_CASE(trieStess) { cnote << "Stress-testing Trie..."; diff --git a/test/vm.cpp b/test/vm.cpp index cc87866df..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()); @@ -493,7 +497,6 @@ void doTests(json_spirit::mValue& v, bool _fillin) BOOST_REQUIRE(o.count("pre") > 0); BOOST_REQUIRE(o.count("exec") > 0); - VM vm; dev::test::FakeExtVM fev; fev.importEnv(o["env"].get_obj()); fev.importState(o["pre"].get_obj()); @@ -508,11 +511,13 @@ void doTests(json_spirit::mValue& v, bool _fillin) fev.code = &fev.thisTxCode; } - vm.reset(fev.gas); bytes output; + u256 gas; try { - output = vm.go(fev).toBytes(); + VM vm(fev.gas); + output = vm.go(fev).toVector(); + gas = vm.gas(); // Get the remaining gas } catch (Exception const& _e) { @@ -549,7 +554,7 @@ void doTests(json_spirit::mValue& v, bool _fillin) o["post"] = mValue(fev.exportState()); o["callcreates"] = fev.exportCallCreates(); o["out"] = "0x" + toHex(output); - fev.push(o, "gas", vm.gas()); + fev.push(o, "gas", gas); } else { @@ -573,7 +578,7 @@ void doTests(json_spirit::mValue& v, bool _fillin) else BOOST_CHECK(output == fromHex(o["out"].get_str())); - BOOST_CHECK(test.toInt(o["gas"]) == vm.gas()); + BOOST_CHECK(test.toInt(o["gas"]) == gas); BOOST_CHECK(test.addresses == fev.addresses); BOOST_CHECK(test.callcreates == fev.callcreates); } @@ -610,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) { @@ -635,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 d21077f86..d1f5938aa 100644 --- a/third/MainWin.cpp +++ b/third/MainWin.cpp @@ -105,14 +105,16 @@ 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()); QWebFrame* f = ui->webView->page()->mainFrame(); f->disconnect(SIGNAL(javaScriptWindowObjectCleared())); + auto qdev = m_dev; auto qeth = m_ethereum; auto qshh = m_whisper; - connect(f, &QWebFrame::javaScriptWindowObjectCleared, QETH_INSTALL_JS_NAMESPACE(f, qeth, qshh, this)); + connect(f, &QWebFrame::javaScriptWindowObjectCleared, QETH_INSTALL_JS_NAMESPACE(f, this, qdev, qeth, qshh)); }); connect(ui->webView, &QWebView::loadFinished, [=]() diff --git a/third/MainWin.h b/third/MainWin.h index fcb7ab304..0122cc257 100644 --- a/third/MainWin.h +++ b/third/MainWin.h @@ -132,6 +132,7 @@ private: QNetworkAccessManager m_webCtrl; + QDev* m_dev = nullptr; QEthereum* m_ethereum = nullptr; QWhisper* m_whisper = nullptr; };