From 446b02be00251650cecf3e9c1db5a3eb57f0760f Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Thu, 11 Dec 2014 23:36:23 +0100 Subject: [PATCH 001/111] fix trie test# --- test/trie.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/test/trie.cpp b/test/trie.cpp index 67f706917..e2117228e 100644 --- a/test/trie.cpp +++ b/test/trie.cpp @@ -67,9 +67,14 @@ BOOST_AUTO_TEST_CASE(trie_tests) cnote << i.first; js::mObject& o = i.second.get_obj(); vector> ss; - for (auto i: o["in"].get_obj()) + for (auto i: o["in"].get_array()) { - ss.push_back(make_pair(i.first, i.second.get_str())); + vector values; + for (auto s: i.get_array()) + values.push_back(s.get_str()); + + assert(values.size() == 2); + ss.push_back(make_pair(values[0], values[1])); if (!ss.back().first.find("0x")) ss.back().first = asString(fromHex(ss.back().first.substr(2))); if (!ss.back().second.find("0x")) @@ -88,7 +93,9 @@ BOOST_AUTO_TEST_CASE(trie_tests) BOOST_REQUIRE(t.check(true)); } BOOST_REQUIRE(!o["root"].is_null()); - BOOST_CHECK_EQUAL(o["root"].get_str(), toHex(t.root().asArray())); + BOOST_CHECK_EQUAL(o["root"].get_str(), "0x" + toHex(t.root().asArray())); + if (o["root"].get_str() != "0x" + toHex(t.root().asArray())) + break; } } } From 605b5ab816c1ec13da7779e983ca01077baf0f92 Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Fri, 12 Dec 2014 09:05:39 +0100 Subject: [PATCH 002/111] remove permuatations in trietest (order is critical for test) --- test/trie.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/test/trie.cpp b/test/trie.cpp index e2117228e..203994312 100644 --- a/test/trie.cpp +++ b/test/trie.cpp @@ -82,7 +82,6 @@ BOOST_AUTO_TEST_CASE(trie_tests) } for (unsigned j = 0; j < min(1000u, dev::test::fac((unsigned)ss.size())); ++j) { - next_permutation(ss.begin(), ss.end()); MemoryDB m; GenericTrieDB t(&m); t.init(); From 98eb72dc142e53e0869592a4163c373d0b1f688e Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Fri, 12 Dec 2014 09:10:17 +0100 Subject: [PATCH 003/111] efficiency, use reference instead of copy --- test/trie.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/trie.cpp b/test/trie.cpp index 203994312..b300de337 100644 --- a/test/trie.cpp +++ b/test/trie.cpp @@ -67,10 +67,10 @@ BOOST_AUTO_TEST_CASE(trie_tests) cnote << i.first; js::mObject& o = i.second.get_obj(); vector> ss; - for (auto i: o["in"].get_array()) + for (auto& i: o["in"].get_array()) { vector values; - for (auto s: i.get_array()) + for (auto& s: i.get_array()) values.push_back(s.get_str()); assert(values.size() == 2); From 30e69503ec2215cb709e2e0adae2e6d046cb35b5 Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Fri, 12 Dec 2014 21:07:47 +0100 Subject: [PATCH 004/111] include original trie test --- test/trie.cpp.orig | 374 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 374 insertions(+) create mode 100644 test/trie.cpp.orig diff --git a/test/trie.cpp.orig b/test/trie.cpp.orig new file mode 100644 index 000000000..7a9461ce2 --- /dev/null +++ b/test/trie.cpp.orig @@ -0,0 +1,374 @@ +/* + 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 trie.cpp + * @author Gav Wood + * @date 2014 + * Trie test functions. + */ + +#include +#include +#include "JsonSpiritHeaders.h" +#include +#include +#include "TrieHash.h" +#include "MemTrie.h" +#include +#include "TestHelper.h" + +using namespace std; +using namespace dev; + +namespace js = json_spirit; + +namespace dev +{ +namespace test +{ + +static unsigned fac(unsigned _i) +{ + return _i > 2 ? _i * fac(_i - 1) : _i; +} + +} +} + +BOOST_AUTO_TEST_SUITE(TrieTests) + +BOOST_AUTO_TEST_CASE(trie_tests) +{ + string testPath = test::getTestPath(); + + + testPath += "/TrieTests"; + + cnote << "Testing Trie..."; + js::mValue v; + string s = asString(contents(testPath + "/trieanyorder.json")); + BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of 'trieanyorder.json' is empty. Have you cloned the 'tests' repo branch develop?"); + js::read_string(s, v); + for (auto& i: v.get_obj()) + { + cnote << i.first; + js::mObject& o = i.second.get_obj(); + vector> ss; + for (auto& i: o["in"].get_array()) + { + vector values; + for (auto& s: i.get_array()) + values.push_back(s.get_str()); + + assert(values.size() == 2); + ss.push_back(make_pair(values[0], values[1])); + if (!ss.back().first.find("0x")) + ss.back().first = asString(fromHex(ss.back().first.substr(2))); + if (!ss.back().second.find("0x")) + ss.back().second = asString(fromHex(ss.back().second.substr(2))); + } + for (unsigned j = 0; j < min(1000u, dev::test::fac((unsigned)ss.size())); ++j) + { + MemoryDB m; + GenericTrieDB t(&m); + t.init(); + BOOST_REQUIRE(t.check(true)); + for (auto const& k: ss) + { + t.insert(k.first, k.second); + BOOST_REQUIRE(t.check(true)); + } + BOOST_REQUIRE(!o["root"].is_null()); + BOOST_CHECK_EQUAL(o["root"].get_str(), "0x" + toHex(t.root().asArray())); +<<<<<<< HEAD + if (o["root"].get_str() != "0x" + toHex(t.root().asArray())) + break; +======= +>>>>>>> upstream/develop + } + } +} + +inline h256 stringMapHash256(StringMap const& _s) +{ + return hash256(_s); +} + +BOOST_AUTO_TEST_CASE(moreTrieTests) +{ + cnote << "Testing Trie more..."; +#if 0 + // More tests... + { + MemoryDB m; + GenericTrieDB t(&m); + t.init(); // initialise as empty tree. + cout << t; + cout << m; + cout << t.root() << endl; + cout << hash256(StringMap()) << endl; + + t.insert(string("tesz"), string("test")); + cout << t; + cout << m; + cout << t.root() << endl; + cout << stringMapHash256({{"test", "test"}}) << endl; + + t.insert(string("tesa"), string("testy")); + cout << t; + cout << m; + cout << t.root() << endl; + cout << stringMapHash256({{"test", "test"}, {"te", "testy"}}) << endl; + cout << t.at(string("test")) << endl; + cout << t.at(string("te")) << endl; + cout << t.at(string("t")) << endl; + + t.remove(string("te")); + cout << m; + cout << t.root() << endl; + cout << stringMapHash256({{"test", "test"}}) << endl; + + t.remove(string("test")); + cout << m; + cout << t.root() << endl; + cout << hash256(StringMap()) << endl; + } + { + MemoryDB m; + GenericTrieDB t(&m); + t.init(); // initialise as empty tree. + t.insert(string("a"), string("A")); + t.insert(string("b"), string("B")); + cout << t; + cout << m; + cout << t.root() << endl; + cout << stringMapHash256({{"b", "B"}, {"a", "A"}}) << endl; + cout << RLP(rlp256({{"b", "B"}, {"a", "A"}})) << endl; + } + { + MemTrie t; + t.insert("dog", "puppy"); + cout << hex << t.hash256() << endl; + cout << RLP(t.rlp()) << endl; + } + { + MemTrie t; + t.insert("bed", "d"); + t.insert("be", "e"); + cout << hex << t.hash256() << endl; + cout << RLP(t.rlp()) << endl; + } + { + cout << hex << stringMapHash256({{"dog", "puppy"}, {"doe", "reindeer"}}) << endl; + MemTrie t; + t.insert("dog", "puppy"); + t.insert("doe", "reindeer"); + cout << hex << t.hash256() << endl; + cout << RLP(t.rlp()) << endl; + cout << toHex(t.rlp()) << endl; + } +#endif + { + MemoryDB m; + GenericTrieDB d(&m); + d.init(); // initialise as empty tree. + MemTrie t; + StringMap s; + + auto add = [&](char const* a, char const* b) + { + d.insert(string(a), string(b)); + t.insert(a, b); + s[a] = b; + + /*cout << endl << "-------------------------------" << endl; + cout << a << " -> " << b << endl; + cout << d; + cout << m; + cout << d.root() << endl; + cout << hash256(s) << endl;*/ + + BOOST_REQUIRE(d.check(true)); + BOOST_REQUIRE_EQUAL(t.hash256(), hash256(s)); + BOOST_REQUIRE_EQUAL(d.root(), hash256(s)); + for (auto const& i: s) + { + (void)i; + BOOST_REQUIRE_EQUAL(t.at(i.first), i.second); + BOOST_REQUIRE_EQUAL(d.at(i.first), i.second); + } + }; + + auto remove = [&](char const* a) + { + s.erase(a); + t.remove(a); + d.remove(string(a)); + + /*cout << endl << "-------------------------------" << endl; + cout << "X " << a << endl; + cout << d; + cout << m; + cout << d.root() << endl; + cout << hash256(s) << endl;*/ + + BOOST_REQUIRE(d.check(true)); + BOOST_REQUIRE(t.at(a).empty()); + BOOST_REQUIRE(d.at(string(a)).empty()); + BOOST_REQUIRE_EQUAL(t.hash256(), hash256(s)); + BOOST_REQUIRE_EQUAL(d.root(), hash256(s)); + for (auto const& i: s) + { + (void)i; + BOOST_REQUIRE_EQUAL(t.at(i.first), i.second); + BOOST_REQUIRE_EQUAL(d.at(i.first), i.second); + } + }; + + add("dogglesworth", "cat"); + add("doe", "reindeer"); + remove("dogglesworth"); + add("horse", "stallion"); + add("do", "verb"); + add("doge", "coin"); + remove("horse"); + remove("do"); + remove("doge"); + remove("doe"); + } +} + +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..."; + { + MemoryDB m; + MemoryDB dm; + EnforceRefs e(dm, true); + GenericTrieDB d(&dm); + d.init(); // initialise as empty tree. + MemTrie t; + BOOST_REQUIRE(d.check(true)); + 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; + t.insert(k, v); + d.insert(k, v); + BOOST_REQUIRE_EQUAL(hash256(m), t.hash256()); + BOOST_REQUIRE_EQUAL(hash256(m), d.root()); + BOOST_REQUIRE(d.check(true)); + } + while (!m.empty()) + { + auto k = m.begin()->first; + auto v = m.begin()->second; + d.remove(k); + t.remove(k); + m.erase(k); + if (!d.check(true)) + { + // cwarn << m; + for (auto i: d) + cwarn << i.first.toString() << i.second.toString(); + + MemoryDB dm2; + EnforceRefs e2(dm2, true); + GenericTrieDB d2(&dm2); + d2.init(); // initialise as empty tree. + for (auto i: d) + d2.insert(i.first, i.second); + + cwarn << "Good:" << d2.root(); +// for (auto i: dm2.get()) +// cwarn << i.first.abridged() << ": " << RLP(i.second); + d2.debugStructure(cerr); + cwarn << "Broken:" << d.root(); // Leaves an extension -> extension (3c1... -> 742...) +// for (auto i: dm.get()) +// cwarn << i.first.abridged() << ": " << RLP(i.second); + d.debugStructure(cerr); + + d2.insert(k, v); + cwarn << "Pres:" << d2.root(); +// for (auto i: dm2.get()) +// cwarn << i.first.abridged() << ": " << RLP(i.second); + d2.debugStructure(cerr); + g_logVerbosity = 99; + d2.remove(k); + g_logVerbosity = 4; + + cwarn << "Good?" << d2.root(); + } + BOOST_REQUIRE(d.check(true)); + BOOST_REQUIRE_EQUAL(hash256(m), t.hash256()); + BOOST_REQUIRE_EQUAL(hash256(m), d.root()); + } + } + } +} + +BOOST_AUTO_TEST_SUITE_END() + + From 31c7875a3b745cfeb26def72446ba5c917b556fe Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Fri, 12 Dec 2014 21:09:23 +0100 Subject: [PATCH 005/111] include original trie test --- test/trie.cpp | 46 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/test/trie.cpp b/test/trie.cpp index 3f072a6d1..6c9f6877d 100644 --- a/test/trie.cpp +++ b/test/trie.cpp @@ -50,7 +50,7 @@ static unsigned fac(unsigned _i) BOOST_AUTO_TEST_SUITE(TrieTests) -BOOST_AUTO_TEST_CASE(trie_tests) +BOOST_AUTO_TEST_CASE(trie_test_anyorder) { string testPath = test::getTestPath(); @@ -93,6 +93,50 @@ BOOST_AUTO_TEST_CASE(trie_tests) } } +BOOST_AUTO_TEST_CASE(trie_tests_ordered) +{ + string testPath = test::getTestPath(); + + testPath += "/TrieTests"; + + cnote << "Testing Trie..."; + js::mValue v; + string s = asString(contents(testPath + "/trietest.json")); + BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of 'trietest.json' is empty. Have you cloned the 'tests' repo branch develop?"); + js::read_string(s, v); + for (auto& i: v.get_obj()) + { + cnote << i.first; + js::mObject& o = i.second.get_obj(); + vector> ss; + for (auto& i: o["in"].get_array()) + { + vector values; + for (auto& s: i.get_array()) + values.push_back(s.get_str()); + + assert(values.size() == 2); + ss.push_back(make_pair(values[0], values[1])); + if (!ss.back().first.find("0x")) + ss.back().first = asString(fromHex(ss.back().first.substr(2))); + if (!ss.back().second.find("0x")) + ss.back().second = asString(fromHex(ss.back().second.substr(2))); + } + + MemoryDB m; + GenericTrieDB t(&m); + t.init(); + BOOST_REQUIRE(t.check(true)); + for (auto const& k: ss) + { + t.insert(k.first, k.second); + BOOST_REQUIRE(t.check(true)); + } + BOOST_REQUIRE(!o["root"].is_null()); + BOOST_CHECK_EQUAL(o["root"].get_str(), "0x" + toHex(t.root().asArray())); + } +} + inline h256 stringMapHash256(StringMap const& _s) { return hash256(_s); From 71bf6e7eded7e17cc64b82f6a9fd8d89458a4f85 Mon Sep 17 00:00:00 2001 From: subtly Date: Tue, 16 Dec 2014 22:01:39 +0100 Subject: [PATCH 006/111] udp != tcp. history-commit. --- libp2p/Host.cpp | 30 +++++----- libp2p/Host.h | 6 +- libp2p/Network.cpp | 8 ++- libp2p/Network.h | 102 +++++++++++++++++++++++++++++++++- libp2p/Session.cpp | 2 +- libp2p/Session.h | 4 +- test/kademlia.cpp | 33 +++++++++++ test/{network.cpp => net.cpp} | 0 8 files changed, 160 insertions(+), 25 deletions(-) create mode 100644 test/kademlia.cpp rename test/{network.cpp => net.cpp} (100%) diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index 93a6ce672..4a99ac90f 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -43,7 +43,7 @@ Host::Host(std::string const& _clientVersion, NetworkPreferences const& _n, bool m_netPrefs(_n), m_ifAddresses(Network::getInterfaceAddresses()), m_ioService(2), - m_acceptorV4(m_ioService), + m_tcp4Acceptor(m_ioService), m_key(KeyPair::create()) { for (auto address: m_ifAddresses) @@ -95,9 +95,9 @@ void Host::doneWorking() m_ioService.reset(); // shutdown acceptor - m_acceptorV4.cancel(); - if (m_acceptorV4.is_open()) - m_acceptorV4.close(); + m_tcp4Acceptor.cancel(); + if (m_tcp4Acceptor.is_open()) + m_tcp4Acceptor.close(); // There maybe an incoming connection which started but hasn't finished. // Wait for acceptor to end itself instead of assuming it's complete. @@ -280,7 +280,7 @@ void Host::determinePublic(string const& _publicAddress, bool _upnp) { if (!m_peerAddresses.count(reqpublicaddr)) m_peerAddresses.insert(reqpublicaddr); - m_public = reqpublic; + m_tcpPublic = reqpublic; return; } @@ -288,7 +288,7 @@ void Host::determinePublic(string const& _publicAddress, bool _upnp) for (auto addr: m_peerAddresses) if (addr.is_v4() && !isPrivateAddress(addr)) { - m_public = bi::tcp::endpoint(*m_peerAddresses.begin(), m_listenPort); + m_tcpPublic = bi::tcp::endpoint(*m_peerAddresses.begin(), m_listenPort); return; } @@ -301,7 +301,7 @@ void Host::determinePublic(string const& _publicAddress, bool _upnp) { if (!m_peerAddresses.count(upnpep.address())) m_peerAddresses.insert(upnpep.address()); - m_public = upnpep; + m_tcpPublic = upnpep; return; } } @@ -312,12 +312,12 @@ void Host::determinePublic(string const& _publicAddress, bool _upnp) for (auto addr: m_peerAddresses) if (addr.is_v4() && isPrivateAddress(addr)) { - m_public = bi::tcp::endpoint(addr, m_listenPort); + m_tcpPublic = bi::tcp::endpoint(addr, m_listenPort); return; } // otherwise address is unspecified - m_public = bi::tcp::endpoint(bi::address(), m_listenPort); + m_tcpPublic = bi::tcp::endpoint(bi::address(), m_listenPort); } void Host::runAcceptor() @@ -326,10 +326,10 @@ void Host::runAcceptor() if (m_run && !m_accepting) { - clog(NetConnect) << "Listening on local port " << m_listenPort << " (public: " << m_public << ")"; + clog(NetConnect) << "Listening on local port " << m_listenPort << " (public: " << m_tcpPublic << ")"; m_accepting = true; m_socket.reset(new bi::tcp::socket(m_ioService)); - m_acceptorV4.async_accept(*m_socket, [=](boost::system::error_code ec) + m_tcp4Acceptor.async_accept(*m_socket, [=](boost::system::error_code ec) { bool success = false; if (!ec) @@ -656,7 +656,7 @@ void Host::startedWorking() } // try to open acceptor (todo: ipv6) - m_listenPort = Network::listen4(m_acceptorV4, m_netPrefs.listenPort); + m_listenPort = Network::tcp4Listen(m_tcp4Acceptor, m_netPrefs.listenPort); // start capability threads for (auto const& h: m_capabilities) @@ -674,8 +674,8 @@ void Host::startedWorking() // if m_public address is valid then add us to node list // todo: abstract empty() and emplace logic - if (!m_public.address().is_unspecified() && (m_nodes.empty() || m_nodes[m_nodesList[0]]->id != id())) - noteNode(id(), m_public, Origin::Perfect, false); + if (!m_tcpPublic.address().is_unspecified() && (m_nodes.empty() || m_nodes[m_nodesList[0]]->id != id())) + noteNode(id(), m_tcpPublic, Origin::Perfect, false); clog(NetNote) << "Id:" << id().abridged(); @@ -739,7 +739,7 @@ void Host::restoreNodes(bytesConstRef _b) { auto oldId = id(); m_key = KeyPair(r[1].toHash()); - noteNode(id(), m_public, Origin::Perfect, false, oldId); + noteNode(id(), m_tcpPublic, Origin::Perfect, false, oldId); for (auto i: r[2]) { diff --git a/libp2p/Host.h b/libp2p/Host.h index a146d6a66..8ed25f2ae 100644 --- a/libp2p/Host.h +++ b/libp2p/Host.h @@ -152,7 +152,7 @@ public: void pingAll(); /// Get the port we're listening on currently. - unsigned short listenPort() const { return m_public.port(); } + unsigned short listenPort() const { return m_tcpPublic.port(); } /// Serialise the set of known peers. bytes saveNodes() const; @@ -219,7 +219,7 @@ private: int m_listenPort = -1; ///< What port are we listening on. -1 means binding failed or acceptor hasn't been initialized. ba::io_service m_ioService; ///< IOService for network stuff. - bi::tcp::acceptor m_acceptorV4; ///< Listening acceptor. + bi::tcp::acceptor m_tcp4Acceptor; ///< Listening acceptor. std::unique_ptr m_socket; ///< Listening socket. std::unique_ptr m_timer; ///< Timer which, when network is running, calls scheduler() every c_timerInterval ms. @@ -229,7 +229,7 @@ private: std::set m_pendingNodeConns; /// Used only by connect(Node&) to limit concurrently connecting to same node. See connect(shared_ptrconst&). Mutex x_pendingNodeConns; - bi::tcp::endpoint m_public; ///< Our public listening endpoint. + bi::tcp::endpoint m_tcpPublic; ///< Our public listening endpoint. KeyPair m_key; ///< Our unique ID. bool m_hadNewNodes = false; diff --git a/libp2p/Network.cpp b/libp2p/Network.cpp index 8ca8dd135..94413e93f 100644 --- a/libp2p/Network.cpp +++ b/libp2p/Network.cpp @@ -38,6 +38,12 @@ using namespace std; using namespace dev; using namespace dev::p2p; +template +Socket::Socket(SocketEventFace* _seface): m_eventDelegate(_seface), m_socket(m_eventDelegate->ioService()) {} + +template +Socket::Socket(SocketEventFace* _seface, endpointType _endpoint): m_eventDelegate(_seface), m_socket(m_eventDelegate->ioService(), _endpoint) {} + std::vector Network::getInterfaceAddresses() { std::vector addresses; @@ -111,7 +117,7 @@ std::vector Network::getInterfaceAddresses() return std::move(addresses); } -int Network::listen4(bi::tcp::acceptor& _acceptor, unsigned short _listenPort) +int Network::tcp4Listen(bi::tcp::acceptor& _acceptor, unsigned short _listenPort) { int retport = -1; for (unsigned i = 0; i < 2; ++i) diff --git a/libp2p/Network.h b/libp2p/Network.h index 944d390c8..3f96fd457 100644 --- a/libp2p/Network.h +++ b/libp2p/Network.h @@ -22,13 +22,17 @@ #pragma once +#include #include +#include +#include +#include +#include "Common.h" namespace ba = boost::asio; namespace bi = ba::ip; namespace dev { - namespace p2p { @@ -42,6 +46,98 @@ struct NetworkPreferences bool localNetworking = false; }; +struct Packet +{ + bytes payload() const { return s.out(); } + + bool required = false; + RLPStream s; +}; + +class SocketFace +{ + virtual void send(Packet const& _msg) = 0; +}; +class SocketEventFace; + +/** + * @brief Generic Socket Interface + * Owners of sockets must outlive the socket. + * Boost ASIO uses lowercase template for udp/tcp, which is adopted here. + */ +template +class Socket: SocketFace, public std::enable_shared_from_this> +{ +public: + using socketType = typename T::socket; + using endpointType = typename T::endpoint; + Socket(SocketEventFace* _seface); + Socket(SocketEventFace* _seface, endpointType _endpoint); + +protected: + void send(Packet const& _msg) + { + if (!m_started) + return; + + Guard l(x_sendQ); + sendQ.push_back(_msg.payload()); + if (sendQ.size() == 1 && !m_stopped) + doWrite(); + } + + void doWrite() + { + const bytes& bytes = sendQ[0]; + auto self(Socket::shared_from_this()); +// boost::asio::async_write(m_socket, boost::asio::buffer(bytes), [this, self](boost::system::error_code _ec, std::size_t /*length*/) +// { +// if (_ec) +// return stopWithError(_ec); +// else +// { +// Guard l(x_sendQ); +// sendQ.pop_front(); +// if (sendQ.empty()) +// return; +// } +// doWrite(); +// }); + } + + void stopWithError(boost::system::error_code _ec); + + std::atomic m_stopped; ///< Set when connection is stopping or stopped. Handshake cannot occur unless m_stopped is true. + std::atomic m_started; ///< Atomically ensure connection is started once. Start cannot occur unless m_started is false. Managed by start() and shutdown(bool). + + SocketEventFace* m_eventDelegate = nullptr; + + Mutex x_sendQ; + std::deque sendQ; + bytes recvBuffer; + size_t recvdBytes = 0; + socketType m_socket; + + Mutex x_socketError; ///< Mutex for error which can occur from host or IO thread. + boost::system::error_code socketError; ///< Set when shut down due to error. +}; + +class SocketEventFace +{ +public: + virtual ba::io_service& ioService() = 0; + virtual void onStopped(SocketFace*) = 0; + virtual void onReceive(SocketFace*, Packet&) = 0; +}; + +struct UDPSocket: public Socket +{ + UDPSocket(ba::io_service& _io, unsigned _port): Socket(nullptr, bi::udp::endpoint(bi::udp::v4(), _port)) {} + ~UDPSocket() { boost::system::error_code ec; m_socket.shutdown(bi::udp::socket::shutdown_both, ec); m_socket.close(); } + +// bi::udp::socket m_socket; +}; + /** * @brief Network Class * Static network operations and interface(s). @@ -53,8 +149,8 @@ public: static std::vector getInterfaceAddresses(); /// Try to bind and listen on _listenPort, else attempt net-allocated port. - static int listen4(bi::tcp::acceptor& _acceptor, unsigned short _listenPort); - + static int tcp4Listen(bi::tcp::acceptor& _acceptor, unsigned short _listenPort); + /// Return public endpoint of upnp interface. If successful o_upnpifaddr will be a private interface address and endpoint will contain public address and port. static bi::tcp::endpoint traverseNAT(std::vector const& _ifAddresses, unsigned short _listenPort, bi::address& o_upnpifaddr); }; diff --git a/libp2p/Session.cpp b/libp2p/Session.cpp index cb0a60a92..3a0dcf1cf 100644 --- a/libp2p/Session.cpp +++ b/libp2p/Session.cpp @@ -522,7 +522,7 @@ void Session::start() << m_server->protocolVersion() << m_server->m_clientVersion << m_server->caps() - << m_server->m_public.port() + << m_server->m_tcpPublic.port() << m_server->id(); sealAndSend(s); ping(); diff --git a/libp2p/Session.h b/libp2p/Session.h index cd2dbf5a7..cabef2cbf 100644 --- a/libp2p/Session.h +++ b/libp2p/Session.h @@ -107,8 +107,8 @@ private: mutable bi::tcp::socket m_socket; ///< Socket for the peer's connection. Mutable to ask for native_handle(). Mutex x_writeQueue; ///< Mutex for the write queue. std::deque m_writeQueue; ///< The write queue. - std::array m_data; ///< Data buffer for the write queue. - bytes m_incoming; ///< The incoming read queue of bytes. + std::array m_data; ///< Buffer for ingress packet data. + bytes m_incoming; ///< Read buffer for ingress bytes. PeerInfo m_info; ///< Dynamic information about this peer. diff --git a/test/kademlia.cpp b/test/kademlia.cpp new file mode 100644 index 000000000..21c28cb87 --- /dev/null +++ b/test/kademlia.cpp @@ -0,0 +1,33 @@ +/* + 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 kademlia.cpp + * @author Alex Leverington + * @date 2014 + * Basic networking tests + */ + +#include +#include +using namespace std; +using namespace dev; +using namespace dev::p2p; + +BOOST_AUTO_TEST_CASE(host_listen_udp4) +{ + +} + diff --git a/test/network.cpp b/test/net.cpp similarity index 100% rename from test/network.cpp rename to test/net.cpp From cef5c1a843a1f691ed9225fb92bf3319c3557b84 Mon Sep 17 00:00:00 2001 From: subtly Date: Thu, 18 Dec 2014 08:35:12 +0100 Subject: [PATCH 007/111] initial interface for udp. test sending/receiving udp. --- libp2p/Network.cpp | 6 -- libp2p/Network.h | 93 +---------------------- libp2p/UDP.cpp | 20 +++++ libp2p/UDP.h | 181 +++++++++++++++++++++++++++++++++++++++++++++ test/kademlia.cpp | 12 --- test/net.cpp | 86 ++++++++++++++------- 6 files changed, 262 insertions(+), 136 deletions(-) create mode 100644 libp2p/UDP.cpp create mode 100644 libp2p/UDP.h diff --git a/libp2p/Network.cpp b/libp2p/Network.cpp index 94413e93f..d0276d67e 100644 --- a/libp2p/Network.cpp +++ b/libp2p/Network.cpp @@ -38,12 +38,6 @@ using namespace std; using namespace dev; using namespace dev::p2p; -template -Socket::Socket(SocketEventFace* _seface): m_eventDelegate(_seface), m_socket(m_eventDelegate->ioService()) {} - -template -Socket::Socket(SocketEventFace* _seface, endpointType _endpoint): m_eventDelegate(_seface), m_socket(m_eventDelegate->ioService(), _endpoint) {} - std::vector Network::getInterfaceAddresses() { std::vector addresses; diff --git a/libp2p/Network.h b/libp2p/Network.h index 3f96fd457..aeeabf329 100644 --- a/libp2p/Network.h +++ b/libp2p/Network.h @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include "Common.h" @@ -46,98 +47,6 @@ struct NetworkPreferences bool localNetworking = false; }; -struct Packet -{ - bytes payload() const { return s.out(); } - - bool required = false; - RLPStream s; -}; - -class SocketFace -{ - virtual void send(Packet const& _msg) = 0; -}; -class SocketEventFace; - -/** - * @brief Generic Socket Interface - * Owners of sockets must outlive the socket. - * Boost ASIO uses lowercase template for udp/tcp, which is adopted here. - */ -template -class Socket: SocketFace, public std::enable_shared_from_this> -{ -public: - using socketType = typename T::socket; - using endpointType = typename T::endpoint; - Socket(SocketEventFace* _seface); - Socket(SocketEventFace* _seface, endpointType _endpoint); - -protected: - void send(Packet const& _msg) - { - if (!m_started) - return; - - Guard l(x_sendQ); - sendQ.push_back(_msg.payload()); - if (sendQ.size() == 1 && !m_stopped) - doWrite(); - } - - void doWrite() - { - const bytes& bytes = sendQ[0]; - auto self(Socket::shared_from_this()); -// boost::asio::async_write(m_socket, boost::asio::buffer(bytes), [this, self](boost::system::error_code _ec, std::size_t /*length*/) -// { -// if (_ec) -// return stopWithError(_ec); -// else -// { -// Guard l(x_sendQ); -// sendQ.pop_front(); -// if (sendQ.empty()) -// return; -// } -// doWrite(); -// }); - } - - void stopWithError(boost::system::error_code _ec); - - std::atomic m_stopped; ///< Set when connection is stopping or stopped. Handshake cannot occur unless m_stopped is true. - std::atomic m_started; ///< Atomically ensure connection is started once. Start cannot occur unless m_started is false. Managed by start() and shutdown(bool). - - SocketEventFace* m_eventDelegate = nullptr; - - Mutex x_sendQ; - std::deque sendQ; - bytes recvBuffer; - size_t recvdBytes = 0; - socketType m_socket; - - Mutex x_socketError; ///< Mutex for error which can occur from host or IO thread. - boost::system::error_code socketError; ///< Set when shut down due to error. -}; - -class SocketEventFace -{ -public: - virtual ba::io_service& ioService() = 0; - virtual void onStopped(SocketFace*) = 0; - virtual void onReceive(SocketFace*, Packet&) = 0; -}; - -struct UDPSocket: public Socket -{ - UDPSocket(ba::io_service& _io, unsigned _port): Socket(nullptr, bi::udp::endpoint(bi::udp::v4(), _port)) {} - ~UDPSocket() { boost::system::error_code ec; m_socket.shutdown(bi::udp::socket::shutdown_both, ec); m_socket.close(); } - -// bi::udp::socket m_socket; -}; - /** * @brief Network Class * Static network operations and interface(s). diff --git a/libp2p/UDP.cpp b/libp2p/UDP.cpp new file mode 100644 index 000000000..9fc65b7c3 --- /dev/null +++ b/libp2p/UDP.cpp @@ -0,0 +1,20 @@ +/* + 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 UDP.cpp + * @author Alex Leverington + * @date 2014 + */ diff --git a/libp2p/UDP.h b/libp2p/UDP.h new file mode 100644 index 000000000..ff94df2ac --- /dev/null +++ b/libp2p/UDP.h @@ -0,0 +1,181 @@ +/* + 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 UDP.h + * @author Alex Leverington + * @date 2014 + */ + +#pragma once + +#include +#include +#include +#include +#include +#include "Common.h" +namespace ba = boost::asio; +namespace bi = ba::ip; + +namespace dev +{ +namespace p2p +{ + +struct UDPDatagram +{ + bi::udp::endpoint to; + bytes data; +}; + +struct UDPSocketFace +{ + virtual void send(UDPDatagram const& _msg) = 0; + virtual void disconnect() = 0; +}; + +struct UDPSocketEvents +{ + virtual void onDisconnected(UDPSocketFace*) {}; + virtual void onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytesConstRef _packetData) = 0; +}; + +/** + * @brief UDP Interface + * Handler must implement UDPSocketEvents. S is maximum data size (bytes) of UDP datagram. + */ +template +class UDPSocket: UDPSocketFace, public std::enable_shared_from_this> +{ +public: + static constexpr unsigned datagramSize = S; + static_assert(datagramSize < 65507, "UDP datagrams cannot be larger than 65507 bytes"); + + /// Construct open socket to endpoint. + UDPSocket(ba::io_service& _io, Handler& _host, unsigned _port): m_host(_host), m_socket(_io, bi::udp::endpoint(bi::udp::v4(), _port)) {}; + virtual ~UDPSocket() { disconnect(); } + + void connect() + { + bool no = false; + if (!m_started.compare_exchange_strong(no, true)) + return; + m_closed = false; + doRead(); + } + + void send(UDPDatagram const& _datagram) + { + if (!m_started) + return; + + Guard l(x_sendQ); + sendQ.push_back(_datagram); + if (sendQ.size() == 1 && !m_closed) + doWrite(); + } + + void disconnect() { disconnectWithError(boost::asio::error::connection_reset); } + +protected: + void doRead() + { + auto self(UDPSocket::shared_from_this()); + m_socket.async_receive_from(boost::asio::buffer(recvData), recvEndpoint, [this, self](boost::system::error_code _ec, size_t _len) + { + if (_ec) + return disconnectWithError(_ec); + + assert(_len); + m_host.onReceived(this, recvEndpoint, bytesConstRef(recvData.data(), _len)); + if (!m_closed) + doRead(); + }); + } + + void doWrite() + { + const UDPDatagram& datagram = sendQ[0]; + auto self(UDPSocket::shared_from_this()); + m_socket.async_send_to(boost::asio::buffer(datagram.data), datagram.to, [this, self](boost::system::error_code _ec, std::size_t) + { + if (_ec) + return disconnectWithError(_ec); + else + { + Guard l(x_sendQ); + sendQ.pop_front(); + if (sendQ.empty()) + return; + } + doWrite(); + }); + } + + void disconnectWithError(boost::system::error_code _ec) + { + // If !started and already stopped, shutdown has already occured. (EOF or Operation canceled) + if (!m_started && m_closed) + return; + + assert(_ec); + { + // disconnect-operation following prior non-zero errors are ignored + Guard l(x_socketError); + if (socketError != boost::system::error_code()) + return; + socketError = _ec; + } + // TODO: (if non-zero error) schedule high-priority writes + + // prevent concurrent disconnect + bool yes = true; + if (!m_started.compare_exchange_strong(yes, false)) + return; + + // set m_closed to true to prevent undeliverable egress messages + bool wasClosed = m_closed; + m_closed = true; + + // close sockets + boost::system::error_code ec; + m_socket.shutdown(bi::udp::socket::shutdown_both, ec); + m_socket.close(); + + // socket never started if it never left stopped-state (pre-handshake) + if (wasClosed) + return; + + m_host.onDisconnected(this); + } + + std::atomic m_closed; ///< Set when connection is stopping or stopped. Handshake cannot occur unless m_closed is true. + std::atomic m_started; ///< Atomically ensure connection is started once. Start cannot occur unless m_started is false. Managed by start and disconnectWithError. + + Handler& m_host; ///< Interface which owns this socket. + + Mutex x_sendQ; + std::deque sendQ; + std::array recvData; ///< Buffer for ingress datagrams. + bi::udp::endpoint recvEndpoint; ///< Endpoint data was received from. + bi::udp::socket m_socket; + + Mutex x_socketError; ///< Mutex for error which can occur from host or IO thread. + boost::system::error_code socketError; ///< Set when shut down due to error. +}; + +} +} \ No newline at end of file diff --git a/test/kademlia.cpp b/test/kademlia.cpp index 21c28cb87..a9d7701cf 100644 --- a/test/kademlia.cpp +++ b/test/kademlia.cpp @@ -17,17 +17,5 @@ /** @file kademlia.cpp * @author Alex Leverington * @date 2014 - * Basic networking tests */ -#include -#include -using namespace std; -using namespace dev; -using namespace dev::p2p; - -BOOST_AUTO_TEST_CASE(host_listen_udp4) -{ - -} - diff --git a/test/net.cpp b/test/net.cpp index acdd649d9..e52654411 100644 --- a/test/net.cpp +++ b/test/net.cpp @@ -14,42 +14,76 @@ You should have received a copy of the GNU General Public License along with cpp-ethereum. If not, see . */ -/** @file network.cpp - * @author Marko Simovic +/** @file net.cpp + * @author Alex Leverington * @date 2014 - * Basic networking tests */ #include -#include -#include -#include -#include -#include "TestHelper.h" +#include +#include using namespace std; using namespace dev; -using namespace dev::eth; +using namespace dev::p2p; +namespace ba = boost::asio; +namespace bi = ba::ip; -// Disabled since tests shouldn't block (not the worst offender, but timeout should be reduced anyway). -/* -BOOST_AUTO_TEST_CASE(listen_port_busy) +class TestA: UDPSocketEvents, public Worker { - short port = 20000; +public: + TestA(): Worker("test",0), m_io(), m_socket(new UDPSocket(m_io, *this, 30300)) {} + ~TestA() { m_io.stop(); stopWorking(); } + + void start() { startWorking(); } + void doWork() { m_io.run(); } + + void onDisconnected(UDPSocketFace*) {}; + void onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytesConstRef _packet) { if(_packet.toString() == "AAAA") success = true; }; - //make use of the port ahead of our client - ba::io_service ioService; - bi::tcp::endpoint endPoint(bi::tcp::v4(), port); - bi::tcp::acceptor acceptor(ioService, endPoint); - acceptor.listen(10); + ba::io_service m_io; + shared_ptr> m_socket; + + bool success = false; +}; - //prepare client and try to listen on same, used, port - Client c1("TestClient1", KeyPair::create().address(), - (boost::filesystem::temp_directory_path() / boost::filesystem::unique_path()).string()); +//struct TestBProtocol: UDPSocketEvents +//{ +// void onDisconnected(UDPSocketFace*) {}; +// void onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytesConstRef _packet) { cout << "received TestBProtocol" << endl; }; +//}; +// +//class TestB: TestBProtocol +//{ +//public: +// TestB(): m_io(), m_socket(m_io, *this, 30300) {} +////private: +// ba::io_service m_io; +// UDPSocket m_socket; +//}; +// +//class TestC +//{ +//public: +// TestC(): m_io(), m_socket(m_io, m_rpc, 30300) {} +////private: +// ba::io_service m_io; +// TestBProtocol m_rpc; +// UDPSocket m_socket; +//}; - c1.startNetwork(port); +BOOST_AUTO_TEST_SUITE(p2p) - BOOST_REQUIRE(c1.haveNetwork()); - BOOST_REQUIRE(c1.peerServer()->listenPort() != 0); - BOOST_REQUIRE(c1.peerServer()->listenPort() != port); +BOOST_AUTO_TEST_CASE(test) +{ + UDPDatagram d; + d.to = boost::asio::ip::udp::endpoint(boost::asio::ip::address::from_string("127.0.0.1"), 30300); + d.data = bytes({65,65,65,65}); + + TestA a; a.start(); a.m_socket->connect(); + a.m_socket->send(d); + sleep(1); + BOOST_REQUIRE_EQUAL(true, a.success); } -*/ + +BOOST_AUTO_TEST_SUITE_END() + From ecccc68e306b8a52feb36595f825d43afdf25c7d Mon Sep 17 00:00:00 2001 From: subtly Date: Thu, 18 Dec 2014 17:21:06 +0100 Subject: [PATCH 008/111] spacing --- test/net.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/net.cpp b/test/net.cpp index e52654411..0b3208302 100644 --- a/test/net.cpp +++ b/test/net.cpp @@ -38,7 +38,7 @@ public: void doWork() { m_io.run(); } void onDisconnected(UDPSocketFace*) {}; - void onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytesConstRef _packet) { if(_packet.toString() == "AAAA") success = true; }; + void onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytesConstRef _packet) { if (_packet.toString() == "AAAA") success = true; } ba::io_service m_io; shared_ptr> m_socket; @@ -73,7 +73,7 @@ public: BOOST_AUTO_TEST_SUITE(p2p) -BOOST_AUTO_TEST_CASE(test) +BOOST_AUTO_TEST_CASE(test_txrx_one) { UDPDatagram d; d.to = boost::asio::ip::udp::endpoint(boost::asio::ip::address::from_string("127.0.0.1"), 30300); From d1aa994f8e77b87b0bab9907e7431fbf41fbf98b Mon Sep 17 00:00:00 2001 From: subtly Date: Thu, 18 Dec 2014 20:25:36 +0100 Subject: [PATCH 009/111] stash --- libp2p/UDP.h | 2 ++ test/net.cpp | 15 +++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/libp2p/UDP.h b/libp2p/UDP.h index ff94df2ac..74499da11 100644 --- a/libp2p/UDP.h +++ b/libp2p/UDP.h @@ -68,11 +68,13 @@ public: UDPSocket(ba::io_service& _io, Handler& _host, unsigned _port): m_host(_host), m_socket(_io, bi::udp::endpoint(bi::udp::v4(), _port)) {}; virtual ~UDPSocket() { disconnect(); } + /// Socket will begin listening for and delivering packets void connect() { bool no = false; if (!m_started.compare_exchange_strong(no, true)) return; + m_closed = false; doRead(); } diff --git a/test/net.cpp b/test/net.cpp index 0b3208302..1e8d20c54 100644 --- a/test/net.cpp +++ b/test/net.cpp @@ -28,6 +28,21 @@ using namespace dev::p2p; namespace ba = boost::asio; namespace bi = ba::ip; +class Kademlia: UDPSocketEvents +{ +public: + Kademlia(): Worker("test",0), m_io(), m_socket(new UDPSocket(m_io, *this, 30300)) {} + ~Kademlia() { m_io.stop(); stopWorking(); } + + void onDisconnected(UDPSocketFace*) {}; + void onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytesConstRef _packet) { if (_packet.toString() == "AAAA") success = true; } + + ba::io_service m_io; + shared_ptr> m_socket; + + bool success = false; +}; + class TestA: UDPSocketEvents, public Worker { public: From 31f1c73a188d649760d0075bd008bcb082e56e1c Mon Sep 17 00:00:00 2001 From: winsvega Date: Fri, 19 Dec 2014 01:57:21 +0300 Subject: [PATCH 010/111] Cteate Contract From Contract Init Code Test --- test/stInitCodeTestFiller.json | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/test/stInitCodeTestFiller.json b/test/stInitCodeTestFiller.json index 76d8f7957..1ac0a11ad 100644 --- a/test/stInitCodeTestFiller.json +++ b/test/stInitCodeTestFiller.json @@ -276,20 +276,19 @@ "095e7baea6a6c7c4c2dfeb977efac326af552d87": { "balance": "10000", "nonce": 0, - "code": "{[[ 2 ]](ADDRESS)(CODECOPY 0 0 32)(CREATE 0 0 32)}", + "code": "{(MSTORE 0 0x601080600c6000396000f20060003554156009570060203560003555) [[ 0 ]] (CREATE 23 4 28)}", "storage": {} - }, + }, - "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { - "balance" : "100000", - "code" : "", - "nonce" : "0", - "storage" : { - } - } + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b": { + "balance" : "100000", + "code" : "", + "nonce" : "0", + "storage" : {} + } }, "transaction" : - { + { "data" : "0x00", "gasLimit" : "10000", "gasPrice" : "1", From 6e363446324a7eb5704b3b3ed595cc7ca59df673 Mon Sep 17 00:00:00 2001 From: Christian Date: Thu, 18 Dec 2014 18:53:43 +0100 Subject: [PATCH 011/111] Possibility for binary operators to yield types different from their operands'. --- libsolidity/AST.cpp | 35 ++++++++++++---------------- libsolidity/Types.cpp | 52 ++++++++++++++++++++++++++++++++++-------- libsolidity/Types.h | 53 ++++++++++++++++++++++++++++++++++--------- 3 files changed, 99 insertions(+), 41 deletions(-) diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index 1fa6d8f6f..c7d617b4f 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -180,12 +180,18 @@ void Assignment::checkTypeRequirements() //@todo later, assignments to structs might be possible, but not to mappings if (!m_leftHandSide->getType()->isValueType() && !m_leftHandSide->isLocalLValue()) BOOST_THROW_EXCEPTION(createTypeError("Assignment to non-local non-value lvalue.")); - m_rightHandSide->expectType(*m_leftHandSide->getType()); m_type = m_leftHandSide->getType(); - if (m_assigmentOperator != Token::ASSIGN) + if (m_assigmentOperator == Token::ASSIGN) + m_rightHandSide->expectType(*m_type); + else + { // compound assignment - if (!m_type->acceptsBinaryOperator(Token::AssignmentToBinaryOp(m_assigmentOperator))) + m_rightHandSide->checkTypeRequirements(); + TypePointer resultType = Type::binaryOperatorResult(Token::AssignmentToBinaryOp(m_assigmentOperator), + m_type, m_rightHandSide->getType()); + if (!resultType || *resultType != *m_type) BOOST_THROW_EXCEPTION(createTypeError("Operator not compatible with type.")); + } } void ExpressionStatement::checkTypeRequirements() @@ -225,24 +231,13 @@ void BinaryOperation::checkTypeRequirements() { m_left->checkTypeRequirements(); m_right->checkTypeRequirements(); - if (m_right->getType()->isImplicitlyConvertibleTo(*m_left->getType())) - m_commonType = m_left->getType(); - else if (m_left->getType()->isImplicitlyConvertibleTo(*m_right->getType())) - m_commonType = m_right->getType(); - else - BOOST_THROW_EXCEPTION(createTypeError("No common type found in binary operation: " + - m_left->getType()->toString() + " vs. " + + m_commonType = Type::binaryOperatorResult(m_operator, m_left->getType(), m_right->getType()); + if (!m_commonType) + BOOST_THROW_EXCEPTION(createTypeError("Operator " + string(Token::toString(m_operator)) + + " not compatible with types " + + m_left->getType()->toString() + " and " + m_right->getType()->toString())); - if (Token::isCompareOp(m_operator)) - m_type = make_shared(); - else - { - m_type = m_commonType; - if (!m_commonType->acceptsBinaryOperator(m_operator)) - BOOST_THROW_EXCEPTION(createTypeError("Operator " + string(Token::toString(m_operator)) + - " not compatible with type " + - m_commonType->toString())); - } + m_type = Token::isCompareOp(m_operator) ? make_shared() : m_commonType; } void FunctionCall::checkTypeRequirements() diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index 71319c3ac..664b56ff6 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -100,6 +100,16 @@ shared_ptr Type::forLiteral(Literal const& _literal) } } +TypePointer Type::commonType(TypePointer const& _a, TypePointer const& _b) +{ + if (_b->isImplicitlyConvertibleTo(*_a)) + return _a; + else if (_a->isImplicitlyConvertibleTo(*_b)) + return _b; + else + return TypePointer(); +} + const MemberList Type::EmptyMemberList = MemberList(); shared_ptr IntegerType::smallestTypeForLiteral(string const& _literal) @@ -146,16 +156,6 @@ bool IntegerType::isExplicitlyConvertibleTo(Type const& _convertTo) const return _convertTo.getCategory() == getCategory() || _convertTo.getCategory() == Category::CONTRACT; } -bool IntegerType::acceptsBinaryOperator(Token::Value _operator) const -{ - if (isAddress()) - return Token::isCompareOp(_operator); - else if (isHash()) - return Token::isCompareOp(_operator) || Token::isBitOp(_operator); - else - return true; -} - bool IntegerType::acceptsUnaryOperator(Token::Value _operator) const { if (_operator == Token::DELETE) @@ -192,6 +192,28 @@ u256 IntegerType::literalValue(Literal const& _literal) const return u256(value); } +TypePointer IntegerType::binaryOperatorResultImpl(Token::Value _operator, TypePointer const& _this, TypePointer const& _other) const +{ + if (getCategory() != _other->getCategory()) + return TypePointer(); + auto commonType = dynamic_pointer_cast(Type::commonType(_this, _other)); + + if (!commonType) + return TypePointer(); + + if (commonType->isAddress()) + { + if (!Token::isCompareOp(_operator)) + return TypePointer(); + } + else if (commonType->isHash()) + { + if (!(Token::isCompareOp(_operator) || Token::isBitOp(_operator))) + return TypePointer(); + } + return commonType; +} + const MemberList IntegerType::AddressMemberList = MemberList({{"balance", make_shared(256)}, @@ -266,6 +288,16 @@ u256 BoolType::literalValue(Literal const& _literal) const BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Bool type constructed from non-boolean literal.")); } +TypePointer BoolType::binaryOperatorResultImpl(Token::Value _operator, TypePointer const& _this, TypePointer const& _other) const +{ + if (getCategory() != _other->getCategory()) + return TypePointer(); + if (Token::isCompareOp(_operator) || _operator == Token::AND || _operator == Token::OR) + return _this; + else + return TypePointer(); +} + bool ContractType::isExplicitlyConvertibleTo(Type const& _convertTo) const { if (isImplicitlyConvertibleTo(_convertTo)) diff --git a/libsolidity/Types.h b/libsolidity/Types.h index 48539a1d7..0afa0ccd3 100644 --- a/libsolidity/Types.h +++ b/libsolidity/Types.h @@ -81,15 +81,23 @@ public: ///@{ ///@name Factory functions /// Factory functions that convert an AST @ref TypeName to a Type. - static std::shared_ptr fromElementaryTypeName(Token::Value _typeToken); - static std::shared_ptr fromUserDefinedTypeName(UserDefinedTypeName const& _typeName); - static std::shared_ptr fromMapping(Mapping const& _typeName); - static std::shared_ptr fromFunction(FunctionDefinition const& _function); + static TypePointer fromElementaryTypeName(Token::Value _typeToken); + static TypePointer fromUserDefinedTypeName(UserDefinedTypeName const& _typeName); + static TypePointer fromMapping(Mapping const& _typeName); + static TypePointer fromFunction(FunctionDefinition const& _function); /// @} /// Auto-detect the proper type for a literal. @returns an empty pointer if the literal does /// not fit any type. - static std::shared_ptr forLiteral(Literal const& _literal); + static TypePointer forLiteral(Literal const& _literal); + /// @returns a pointer to _a or _b if the other is implicitly convertible to it or nullptr otherwise + static TypePointer commonType(TypePointer const& _a, TypePointer const& _b); + /// @returns the resulting type of applying the given operator or an empty pointer if this is not possible. + /// The default implementation allows comparison operators if a common type exists + static TypePointer binaryOperatorResult(Token::Value _operator, TypePointer const& _a, TypePointer const& _b) + { + return _a->binaryOperatorResultImpl(_operator, _a, _b); + } virtual Category getCategory() const = 0; virtual bool isImplicitlyConvertibleTo(Type const& _other) const { return *this == _other; } @@ -97,7 +105,6 @@ public: { return isImplicitlyConvertibleTo(_convertTo); } - virtual bool acceptsBinaryOperator(Token::Value) const { return false; } virtual bool acceptsUnaryOperator(Token::Value) const { return false; } virtual bool operator==(Type const& _other) const { return getCategory() == _other.getCategory(); } @@ -131,6 +138,11 @@ public: } protected: + virtual TypePointer binaryOperatorResultImpl(Token::Value _operator, TypePointer const& _a, TypePointer const& _b) const + { + return Token::isCompareOp(_operator) ? commonType(_a, _b) : TypePointer(); + } + /// Convenience object used when returning an empty member list. static const MemberList EmptyMemberList; }; @@ -155,7 +167,6 @@ public: virtual bool isImplicitlyConvertibleTo(Type const& _convertTo) const override; virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const override; - virtual bool acceptsBinaryOperator(Token::Value _operator) const override; virtual bool acceptsUnaryOperator(Token::Value _operator) const override; virtual bool operator==(Type const& _other) const override; @@ -173,6 +184,9 @@ public: bool isAddress() const { return m_modifier == Modifier::ADDRESS; } int isSigned() const { return m_modifier == Modifier::SIGNED; } +protected: + virtual TypePointer binaryOperatorResultImpl(Token::Value _operator, TypePointer const& _this, TypePointer const& _other) const override; + private: int m_bits; Modifier m_modifier; @@ -217,10 +231,6 @@ public: BoolType() {} virtual Category getCategory() const { return Category::BOOL; } virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const override; - virtual bool acceptsBinaryOperator(Token::Value _operator) const override - { - return _operator == Token::AND || _operator == Token::OR; - } virtual bool acceptsUnaryOperator(Token::Value _operator) const override { return _operator == Token::NOT || _operator == Token::DELETE; @@ -231,6 +241,9 @@ public: virtual std::string toString() const override { return "bool"; } virtual u256 literalValue(Literal const& _literal) const override; + +protected: + virtual TypePointer binaryOperatorResultImpl(Token::Value _operator, TypePointer const& _this, TypePointer const& _other) const override; }; /** @@ -369,6 +382,12 @@ public: virtual u256 getStorageSize() const override { BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Storage size of non-storable void type requested.")); } virtual bool canLiveOutsideStorage() const override { return false; } virtual unsigned getSizeOnStack() const override { return 0; } + +protected: + virtual TypePointer binaryOperatorResultImpl(Token::Value _operator, TypePointer const& _this, TypePointer const& _other) const override + { + return TypePointer(); + } }; /** @@ -389,6 +408,12 @@ public: virtual bool canLiveOutsideStorage() const override { return false; } virtual std::string toString() const override { return "type(" + m_actualType->toString() + ")"; } +protected: + virtual TypePointer binaryOperatorResultImpl(Token::Value _operator, TypePointer const& _this, TypePointer const& _other) const override + { + return TypePointer(); + } + private: TypePointer m_actualType; }; @@ -413,6 +438,12 @@ public: virtual std::string toString() const override; +protected: + virtual TypePointer binaryOperatorResultImpl(Token::Value _operator, TypePointer const& _this, TypePointer const& _other) const override + { + return TypePointer(); + } + private: Kind m_kind; From 27d79a2f17f3140258d1b9b89914dc9b166aef1d Mon Sep 17 00:00:00 2001 From: subtly Date: Fri, 19 Dec 2014 22:14:11 +0100 Subject: [PATCH 012/111] initialize atomics so udp messages are delivered on linux #656 --- libp2p/UDP.h | 10 +++++----- test/net.cpp | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/libp2p/UDP.h b/libp2p/UDP.h index 74499da11..fd48aa59d 100644 --- a/libp2p/UDP.h +++ b/libp2p/UDP.h @@ -65,16 +65,16 @@ public: static_assert(datagramSize < 65507, "UDP datagrams cannot be larger than 65507 bytes"); /// Construct open socket to endpoint. - UDPSocket(ba::io_service& _io, Handler& _host, unsigned _port): m_host(_host), m_socket(_io, bi::udp::endpoint(bi::udp::v4(), _port)) {}; + UDPSocket(ba::io_service& _io, UDPSocketEvents& _host, unsigned _port): m_host(_host), m_socket(_io, bi::udp::endpoint(bi::udp::v4(), _port)) { m_started.store(false); m_closed.store(true); }; virtual ~UDPSocket() { disconnect(); } /// Socket will begin listening for and delivering packets void connect() { - bool no = false; - if (!m_started.compare_exchange_strong(no, true)) + bool expect = false; + if (!m_started.compare_exchange_strong(expect, true)) return; - + m_closed = false; doRead(); } @@ -86,7 +86,7 @@ public: Guard l(x_sendQ); sendQ.push_back(_datagram); - if (sendQ.size() == 1 && !m_closed) + if (sendQ.size() == 1 && !m_closed.load()) doWrite(); } diff --git a/test/net.cpp b/test/net.cpp index 1e8d20c54..34b20ccc7 100644 --- a/test/net.cpp +++ b/test/net.cpp @@ -94,7 +94,7 @@ BOOST_AUTO_TEST_CASE(test_txrx_one) d.to = boost::asio::ip::udp::endpoint(boost::asio::ip::address::from_string("127.0.0.1"), 30300); d.data = bytes({65,65,65,65}); - TestA a; a.start(); a.m_socket->connect(); + TestA a; a.m_socket->connect(); a.start(); a.m_socket->send(d); sleep(1); BOOST_REQUIRE_EQUAL(true, a.success); From 46a286f6e7c8f29bab408b0766693b2bf8e86fbb Mon Sep 17 00:00:00 2001 From: subtly Date: Fri, 19 Dec 2014 22:40:44 +0100 Subject: [PATCH 013/111] fix the fix --- libp2p/UDP.h | 4 +++- test/net.cpp | 16 +--------------- 2 files changed, 4 insertions(+), 16 deletions(-) diff --git a/libp2p/UDP.h b/libp2p/UDP.h index fd48aa59d..31ec170f6 100644 --- a/libp2p/UDP.h +++ b/libp2p/UDP.h @@ -37,6 +37,8 @@ namespace p2p struct UDPDatagram { + UDPDatagram() = default; + UDPDatagram(bi::udp::endpoint _ep, bytes _data): to(_ep), data(std::move(_data)) {} bi::udp::endpoint to; bytes data; }; @@ -167,7 +169,7 @@ protected: std::atomic m_closed; ///< Set when connection is stopping or stopped. Handshake cannot occur unless m_closed is true. std::atomic m_started; ///< Atomically ensure connection is started once. Start cannot occur unless m_started is false. Managed by start and disconnectWithError. - Handler& m_host; ///< Interface which owns this socket. + UDPSocketEvents& m_host; ///< Interface which owns this socket. Mutex x_sendQ; std::deque sendQ; diff --git a/test/net.cpp b/test/net.cpp index 34b20ccc7..6e9efff16 100644 --- a/test/net.cpp +++ b/test/net.cpp @@ -20,6 +20,7 @@ */ #include +#include #include #include using namespace std; @@ -28,21 +29,6 @@ using namespace dev::p2p; namespace ba = boost::asio; namespace bi = ba::ip; -class Kademlia: UDPSocketEvents -{ -public: - Kademlia(): Worker("test",0), m_io(), m_socket(new UDPSocket(m_io, *this, 30300)) {} - ~Kademlia() { m_io.stop(); stopWorking(); } - - void onDisconnected(UDPSocketFace*) {}; - void onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytesConstRef _packet) { if (_packet.toString() == "AAAA") success = true; } - - ba::io_service m_io; - shared_ptr> m_socket; - - bool success = false; -}; - class TestA: UDPSocketEvents, public Worker { public: From ae66da681c1196d4cefed4273bf065dff006a355 Mon Sep 17 00:00:00 2001 From: winsvega Date: Sat, 20 Dec 2014 19:12:52 +0300 Subject: [PATCH 014/111] Contract Creation Init Codes --- test/stInitCodeTestFiller.json | 188 ++++++++++++++++++++++++++++++--- 1 file changed, 175 insertions(+), 13 deletions(-) diff --git a/test/stInitCodeTestFiller.json b/test/stInitCodeTestFiller.json index 1ac0a11ad..55f5567af 100644 --- a/test/stInitCodeTestFiller.json +++ b/test/stInitCodeTestFiller.json @@ -262,11 +262,11 @@ } }, - "CallTheContractToCreateContractWithInitCode" : { + "CallContractToCreateContractWhichWouldCreateContractInInitCode" : { "env" : { "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", "currentDifficulty" : "45678256", - "currentGasLimit" : "1000000", + "currentGasLimit" : "100000000", "currentNumber" : "0", "currentTimestamp" : 1, "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" @@ -274,28 +274,190 @@ "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87": { - "balance": "10000", + "balance": "1", "nonce": 0, - "code": "{(MSTORE 0 0x601080600c6000396000f20060003554156009570060203560003555) [[ 0 ]] (CREATE 23 4 28)}", + "comment": "{[[0]] 12 (CREATE 0 64 32)}", + "code": "{(MSTORE 0 0x600c600055602060406000f0)(CREATE 0 20 12)}", "storage": {} - }, + }, - "a94f5374fce5edbc8e2a8697c15331677e6ebf0b": { - "balance" : "100000", - "code" : "", - "nonce" : "0", - "storage" : {} - } + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "100000000", + "code" : "", + "nonce" : "0", + "storage" : { + } + } }, "transaction" : + { + "data" : "0x00", + "gasLimit" : "20000000", + "gasPrice" : "1", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "0" + } + }, + + "CallContractToCreateContractWhichWouldCreateContractIfCalled" : { + "env" : { + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentDifficulty" : "45678256", + "currentGasLimit" : "100000000", + "currentNumber" : "0", + "currentTimestamp" : 1, + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87": { + "balance": "1000", + "nonce": 0, + "comment": "(CREATE 0 64 32)", + "comment": "{[[0]] 12 (MSTORE 32 0x602060406000f0)(RETURN 57 7)}", + "code": "{(MSTORE 0 0x600c60005566602060406000f060205260076039f3)[[0]](CREATE 1 11 21)(CALL 500 (SLOAD 0) 1 0 0 0 0)}", + "storage": {} + }, + + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "100000000", + "code" : "", + "nonce" : "0", + "storage" : { + } + } + }, + "transaction" : + { "data" : "0x00", - "gasLimit" : "10000", + "gasLimit" : "20000000", "gasPrice" : "1", "nonce" : "0", "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", - "value" : "1" + "value" : "0" + } + }, + + "CallContractToCreateContractOOG" : { + "env" : { + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentDifficulty" : "45678256", + "currentGasLimit" : "100000000", + "currentNumber" : "0", + "currentTimestamp" : 1, + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "pre" : + { + "095e7baea6a6c7c4c2dfeb977efac326af552d87": { + "balance": "0", + "nonce": 0, + "comment": "(CREATE 0 64 32)", + "comment": "{[[0]] 12 (MSTORE 32 0x602060406000f0)(RETURN 57 7)}", + "code": "{(MSTORE 0 0x600c60005566602060406000f060205260076039f3)[[0]](CREATE 1 11 21)(CALL 0 (SLOAD 0) 0 0 0 0 0)}", + "storage": {} + }, + + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "100000000", + "code" : "", + "nonce" : "0", + "storage" : { + } + } + }, + "transaction" : + { + "data" : "0x00", + "gasLimit" : "20000000", + "gasPrice" : "1", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "0" + } + }, + + "CallContractToCreateContractAndCallItOOG" : { + "env" : { + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentDifficulty" : "45678256", + "currentGasLimit" : "100000000", + "currentNumber" : "0", + "currentTimestamp" : 1, + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "pre" : + { + "095e7baea6a6c7c4c2dfeb977efac326af552d87": { + "balance": "1000", + "nonce": 0, + "comment": "(CREATE 0 64 32)", + "comment": "{[[0]] 12 (MSTORE 32 0x602060406000f0)(RETURN 57 7)}", + "code": "{(MSTORE 0 0x600c60005566602060406000f060205260076039f3)[[0]](CREATE 1 11 21)(CALL 0 (SLOAD 0) 1 0 0 0 0)}", + "storage": {} + }, + + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "100000000", + "code" : "", + "nonce" : "0", + "storage" : { + } + } + }, + "transaction" : + { + "data" : "0x00", + "gasLimit" : "20000000", + "gasPrice" : "1", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "0" + } + }, + + "CallContractToCreateContractNoCash" : { + "env" : { + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentDifficulty" : "45678256", + "currentGasLimit" : "100000000", + "currentNumber" : "0", + "currentTimestamp" : 1, + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "pre" : + { + "095e7baea6a6c7c4c2dfeb977efac326af552d87": { + "balance": "1000", + "nonce": 0, + "comment": "(CREATE 0 64 32)", + "comment": "{[[0]] 12 (MSTORE 32 0x602060406000f0)(RETURN 57 7)}", + "code": "{(MSTORE 0 0x600c60005566602060406000f060205260076039f3)[[0]](CREATE 1001 11 21)}", + "storage": {} + }, + + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "100000000", + "code" : "", + "nonce" : "0", + "storage" : { + } + } + }, + "transaction" : + { + "data" : "0x00", + "gasLimit" : "20000000", + "gasPrice" : "1", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "0" } } } From dd4c7152b4a6f45f5709d96085fb8a71ebe520d0 Mon Sep 17 00:00:00 2001 From: subtly Date: Sun, 21 Dec 2014 09:11:57 +0100 Subject: [PATCH 015/111] socket is created in disconnected state. socket can't be created in open state because shared_ptr methods aren't available to doRead until after class has been constructed and the socket is dependent on ioservice running. --- libp2p/UDP.h | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/libp2p/UDP.h b/libp2p/UDP.h index 31ec170f6..ec491288b 100644 --- a/libp2p/UDP.h +++ b/libp2p/UDP.h @@ -57,17 +57,17 @@ struct UDPSocketEvents /** * @brief UDP Interface - * Handler must implement UDPSocketEvents. S is maximum data size (bytes) of UDP datagram. + * Handler must implement UDPSocketEvents. */ -template -class UDPSocket: UDPSocketFace, public std::enable_shared_from_this> +template +class UDPSocket: UDPSocketFace, public std::enable_shared_from_this> { public: - static constexpr unsigned datagramSize = S; - static_assert(datagramSize < 65507, "UDP datagrams cannot be larger than 65507 bytes"); + static constexpr unsigned maxDatagramSize = MaxDatagramSize; + static_assert(maxDatagramSize < 65507, "UDP datagrams cannot be larger than 65507 bytes"); /// Construct open socket to endpoint. - UDPSocket(ba::io_service& _io, UDPSocketEvents& _host, unsigned _port): m_host(_host), m_socket(_io, bi::udp::endpoint(bi::udp::v4(), _port)) { m_started.store(false); m_closed.store(true); }; + UDPSocket(ba::io_service& _io, UDPSocketEvents& _host, unsigned _port): m_host(_host), m_endpoint(bi::udp::v4(), _port), m_socket(_io) { m_started.store(false); m_closed.store(true); }; virtual ~UDPSocket() { disconnect(); } /// Socket will begin listening for and delivering packets @@ -76,6 +76,9 @@ public: bool expect = false; if (!m_started.compare_exchange_strong(expect, true)) return; + + m_socket.open(bi::udp::v4()); + m_socket.bind(m_endpoint); m_closed = false; doRead(); @@ -83,7 +86,7 @@ public: void send(UDPDatagram const& _datagram) { - if (!m_started) + if (m_closed) return; Guard l(x_sendQ); @@ -91,13 +94,15 @@ public: if (sendQ.size() == 1 && !m_closed.load()) doWrite(); } + + bool isOpen() { return !m_closed; } void disconnect() { disconnectWithError(boost::asio::error::connection_reset); } protected: void doRead() { - auto self(UDPSocket::shared_from_this()); + auto self(UDPSocket::shared_from_this()); m_socket.async_receive_from(boost::asio::buffer(recvData), recvEndpoint, [this, self](boost::system::error_code _ec, size_t _len) { if (_ec) @@ -113,7 +118,7 @@ protected: void doWrite() { const UDPDatagram& datagram = sendQ[0]; - auto self(UDPSocket::shared_from_this()); + auto self(UDPSocket::shared_from_this()); m_socket.async_send_to(boost::asio::buffer(datagram.data), datagram.to, [this, self](boost::system::error_code _ec, std::size_t) { if (_ec) @@ -132,7 +137,7 @@ protected: void disconnectWithError(boost::system::error_code _ec) { // If !started and already stopped, shutdown has already occured. (EOF or Operation canceled) - if (!m_started && m_closed) + if (!m_started && m_closed && !m_socket.is_open()) return; assert(_ec); @@ -146,8 +151,8 @@ protected: // TODO: (if non-zero error) schedule high-priority writes // prevent concurrent disconnect - bool yes = true; - if (!m_started.compare_exchange_strong(yes, false)) + bool expected = true; + if (!m_started.compare_exchange_strong(expected, false)) return; // set m_closed to true to prevent undeliverable egress messages @@ -170,10 +175,11 @@ protected: std::atomic m_started; ///< Atomically ensure connection is started once. Start cannot occur unless m_started is false. Managed by start and disconnectWithError. UDPSocketEvents& m_host; ///< Interface which owns this socket. + bi::udp::endpoint m_endpoint; ///< Endpoint which we listen to. Mutex x_sendQ; std::deque sendQ; - std::array recvData; ///< Buffer for ingress datagrams. + std::array recvData; ///< Buffer for ingress datagrams. bi::udp::endpoint recvEndpoint; ///< Endpoint data was received from. bi::udp::socket m_socket; From 7ab02cf4874ad7cd90c75be908e6ac6ce93ee43f Mon Sep 17 00:00:00 2001 From: subtly Date: Mon, 22 Dec 2014 01:51:19 +0100 Subject: [PATCH 016/111] move some things for udp. added a class for kademlia. --- libp2p/UDP.h | 37 +++- test/net.cpp | 567 +++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 562 insertions(+), 42 deletions(-) diff --git a/libp2p/UDP.h b/libp2p/UDP.h index ec491288b..a28646369 100644 --- a/libp2p/UDP.h +++ b/libp2p/UDP.h @@ -26,6 +26,9 @@ #include #include #include +#include +#include +#include #include "Common.h" namespace ba = boost::asio; namespace bi = ba::ip; @@ -40,12 +43,30 @@ struct UDPDatagram UDPDatagram() = default; UDPDatagram(bi::udp::endpoint _ep, bytes _data): to(_ep), data(std::move(_data)) {} bi::udp::endpoint to; + bytes data; }; + +struct RLPDatagram: UDPDatagram +{ + void seal(Secret const& _k) + { + RLPStream packet; + streamRLP(packet); + bytes b(packet.out()); + Signature sig = dev::sign(_k, dev::sha3(b)); + data.resize(data.size() + Signature::size); + sig.ref().copyTo(&data); + memcpy(data.data()+sizeof(Signature),b.data(),b.size()); + } + +protected: + virtual void streamRLP(RLPStream& _s) const {}; +}; struct UDPSocketFace { - virtual void send(UDPDatagram const& _msg) = 0; + virtual bool send(UDPDatagram const& _msg) = 0; virtual void disconnect() = 0; }; @@ -80,19 +101,25 @@ public: m_socket.open(bi::udp::v4()); m_socket.bind(m_endpoint); + // clear write queue so reconnect doesn't send stale messages + Guard l(x_sendQ); + sendQ.clear(); + m_closed = false; doRead(); } - void send(UDPDatagram const& _datagram) + bool send(UDPDatagram const& _datagram) { if (m_closed) - return; + return false; Guard l(x_sendQ); sendQ.push_back(_datagram); - if (sendQ.size() == 1 && !m_closed.load()) + if (sendQ.size() == 1) doWrite(); + + return true; } bool isOpen() { return !m_closed; } @@ -137,7 +164,7 @@ protected: void disconnectWithError(boost::system::error_code _ec) { // If !started and already stopped, shutdown has already occured. (EOF or Operation canceled) - if (!m_started && m_closed && !m_socket.is_open()) + if (!m_started && m_closed && !m_socket.is_open() /* todo: veirfy this logic*/) return; assert(_ec); diff --git a/test/net.cpp b/test/net.cpp index 6e9efff16..0a22a7e63 100644 --- a/test/net.cpp +++ b/test/net.cpp @@ -20,8 +20,8 @@ */ #include -#include #include +#include #include using namespace std; using namespace dev; @@ -29,58 +29,551 @@ using namespace dev::p2p; namespace ba = boost::asio; namespace bi = ba::ip; -class TestA: UDPSocketEvents, public Worker +/** + * Ping packet: Check if node is alive. + * PingNode is cached and regenerated after expiration - t, where t is timeout. + * + * signature: Signature of message. + * ipAddress: Our IP address. + * port: Our port. + * expiration: Triggers regeneration of packet. May also provide control over synchronization. + * + * Ping is used to implement evict. When a new node is seen for + * a given bucket which is full, the least-responsive node is pinged. + * If the pinged node doesn't respond then it is removed and the new + * node is inserted. + */ +struct PingNode: RLPDatagram +{ + bytes ipAddress; + uint16_t port; + uint64_t expiration; + + Signature signature; + +// void streamRLP(RLPStream& _s) const { _s.appendList(3); _s << ipAddress << port << expiration; } +}; + +struct Pong: RLPDatagram { + // todo: weak-signed pong + Address from; + uint64_t replyTo; /// expiration from PingNode + + void streamRLP(RLPStream& _s) const { _s.appendList(2); _s << from << replyTo; } +}; + +/** + * FindNeighbors Packet: Request k-nodes, closest to the target. + * FindNeighbors is cached and regenerated after expiration - t, where t is timeout. + * + * signature: Signature of message. + * target: Address of NodeId. The responding node will send back nodes closest to the target. + * expiration: Triggers regeneration of packet. May also provide control over synchronization. + * + */ +struct FindNeighbors: RLPDatagram +{ + h160 target; + uint64_t expiration; + + Signature signature; + + void streamRLP(RLPStream& _s) const { _s.appendList(2); _s << target << expiration; } +}; + +/** + * Node Packet: Multiple node packets are sent in response to FindNeighbors. + */ +struct Neighbors: RLPDatagram +{ + struct Node + { + bytes ipAddress; + uint16_t port; + NodeId node; +// void streamRLP(RLPStream& _s) const { _s.appendList(3); _s << ipAddress << port << node; } + }; + + std::set nodes; + h256 nonce; + + Signature signature; + +// void streamRLP(RLPStream& _s) const { _s.appendList(2); _s.appendList(nodes.size()); for (auto& n: nodes) n.streamRLP(_s); _s << nonce; } +}; + +/** + * NodeTable using S/Kademlia system for node discovery and preference. + * untouched buckets are refreshed if they have not been touched within an hour + * + * Thread-safety is ensured by modifying NodeEntry details via + * shared_ptr replacement instead of mutating values. + * + * @todo don't try to evict node if node isRequired. (support for makeRequired) + * @todo optimize (use tree for state (or set w/custom compare for cache)) + * @todo constructor support for m_node, m_secret + * @todo use s_bitsPerStep for find and refresh/ping + * @todo exclude bucket from refresh if we have node as peer + * @todo restore nodes + */ +class NodeTable: UDPSocketEvents, public std::enable_shared_from_this +{ + using nodeSocket = UDPSocket; + using timePoint = std::chrono::steady_clock::time_point; + + static unsigned const s_bucketSize = 16; // Denoted by k in [Kademlia]. Number of nodes stored in each bucket. +// const unsigned s_bitsPerStep = 5; // @todo Denoted by b in [Kademlia]. Bits by which address space will be divided for find responses. + static unsigned const s_alpha = 3; // Denoted by \alpha in [Kademlia]. Number of concurrent FindNeighbors requests. + const unsigned s_findTimout = 300; // How long to wait between find queries. +// const unsigned s_siblings = 5; // @todo Denoted by s in [S/Kademlia]. User-defined by sub-protocols. + const unsigned s_bucketRefresh = 3600; // Refresh interval prevents bucket from becoming stale. [Kademlia] + const unsigned s_bits = sizeof(Address); // Denoted by n. + const unsigned s_buckets = 8 * s_bits - 1; + const unsigned s_evictionCheckInterval = 75; // Interval by which eviction timeouts are checked. + const unsigned s_pingTimeout = 500; + static size_t const s_tableSize = Address::size * 8 - 1; // Address::size + +public: + static unsigned dist(Address const& _a, Address const& _b) { u160 d = _a ^ _b; unsigned ret; for (ret = 0; d >>= 1; ++ret) {}; return ret; } + +protected: + struct NodeDefaultEndpoint + { + NodeDefaultEndpoint(bi::udp::endpoint _udp): udp(_udp) {} + bi::udp::endpoint udp; + }; + + struct NodeEntry + { + NodeEntry(Address _id, Public _pubk, bi::udp::endpoint _udp): id(_id), pubk(_pubk), endpoint(NodeDefaultEndpoint(_udp)), distance(0) {} + NodeEntry(NodeEntry _src, Address _id, Public _pubk, bi::udp::endpoint _udp): id(_id), pubk(_pubk), endpoint(NodeDefaultEndpoint(_udp)), distance(dist(_src.id,_id)) {} + NodeEntry(NodeEntry _src, Address _id, Public _pubk, NodeDefaultEndpoint _gw): id(_id), pubk(_pubk), endpoint(_gw), distance(dist(_src.id,_id)) {} + Address id; + Public pubk; + NodeDefaultEndpoint endpoint; ///< How we've previously connected to this node. (must match node's reported endpoint) + const unsigned distance; + timePoint activePing; + }; + + struct NodeBucket + { + unsigned distance; + timePoint modified; + std::list> nodes; + }; + + using EvictionTimeout = std::pair,Address>; + public: - TestA(): Worker("test",0), m_io(), m_socket(new UDPSocket(m_io, *this, 30300)) {} - ~TestA() { m_io.stop(); stopWorking(); } + NodeTable(ba::io_service& _io): + m_node(NodeEntry(Address(), Public(), bi::udp::endpoint())), + m_socket(new nodeSocket(_io, *this, 30300)), + m_socketPtr(m_socket.get()), + m_io(_io), + m_bucketRefreshTimer(m_io), + m_evictionCheckTimer(m_io) + { + for (unsigned i = 0; i < s_buckets; i++) + m_state[i].distance = i, m_state[i].modified = chrono::steady_clock::now() - chrono::seconds(1); + doRefreshBuckets(boost::system::error_code()); + } + + ~NodeTable() { + m_evictionCheckTimer.cancel(); + m_bucketRefreshTimer.cancel(); + m_socketPtr->disconnect(); + } + + void join() { doFindNode(m_node.id); } + + std::list
nodes() const + { + std::list
nodes; + Guard l(x_nodes); + for (auto& i: m_nodes) + nodes.push_back(i.second->id); + return std::move(nodes); + } + + NodeEntry operator[](Address _id) + { + Guard l(x_nodes); + return *m_nodes[_id]; + } + +protected: + void requestNeighbors(NodeEntry const& _node, Address _target) const + { + FindNeighbors p; + p.target = _target; + + p.to = _node.endpoint.udp; + p.seal(m_secret); + m_socketPtr->send(p); + } + + /// Dispatches udp requests in order to populate node table to be as close as possible to _node. + void doFindNode(Address _node, unsigned _round = 0, std::shared_ptr>> _tried = std::shared_ptr>>()) + { + if (!m_socketPtr->isOpen() || _round == 7) + return; + + auto nearest = findNearest(_node); + std::list> tried; + for (unsigned i = 0; i < nearest.size() && tried.size() < s_alpha; i++) + if (!_tried->count(nearest[i])) + { + tried.push_back(nearest[i]); + requestNeighbors(*nearest[i], _node); + } + else + continue; + + while (auto n = tried.front()) + { + _tried->insert(n); + tried.pop_front(); + } + + auto self(shared_from_this()); + m_evictionCheckTimer.expires_from_now(boost::posix_time::milliseconds(s_findTimout)); + m_evictionCheckTimer.async_wait([this, self, _node, _round, _tried](boost::system::error_code const& _ec) + { + if (_ec) + return; + doFindNode(_node, _round + 1, _tried); + }); + } + + std::vector> findNearest(Address _target) + { + // send s_alpha FindNeighbors packets to nodes we know, closest to target + unsigned head = dist(m_node.id, _target); + unsigned tail = (head - 1) % (s_tableSize - 1); + + // todo: optimize with tree + std::map>> found; + unsigned count = 0; + + // if d is 0, then we roll look forward, if last, we reverse, else, spread from d + if (head != 0 && tail != s_tableSize) + while (head != tail && count < s_bucketSize) + { + Guard l(x_state); + for (auto& n: m_state[head].nodes) + if (auto p = n.lock()) + { + if (count < s_bucketSize) + found[dist(_target, p->id)].push_back(p); + else + break; + } + + if (count < s_bucketSize && head) + for (auto& n: m_state[tail].nodes) + if (auto p = n.lock()) + { + if (count < s_bucketSize) + found[dist(_target, p->id)].push_back(p); + else + break; + } + head++; + tail = (tail - 1) % (s_tableSize - 1); + } + else if (head == 0) + while (head < s_bucketSize && count < s_bucketSize) + { + Guard l(x_state); + for (auto& n: m_state[head].nodes) + if (auto p = n.lock()) + { + if (count < s_bucketSize) + found[dist(_target, p->id)].push_back(p); + else + break; + } + head--; + } + else if (tail == s_tableSize - 1) + while (tail > 0 && count < s_bucketSize) + { + Guard l(x_state); + for (auto& n: m_state[tail].nodes) + if (auto p = n.lock()) + { + if (count < s_bucketSize) + found[dist(_target, p->id)].push_back(p); + else + break; + } + tail--; + } + + std::vector> ret; + for (auto& nodes: found) + for (auto& n: nodes.second) + ret.push_back(n); + return std::move(ret); + } + + void ping(bi::address _address, unsigned _port) const + { + PingNode p; + string ip = m_node.endpoint.udp.address().to_string(); + p.ipAddress = asBytes(ip); + p.port = m_node.endpoint.udp.port(); +// p.expiration; + p.seal(m_secret); + m_socketPtr->send(p); + } + + void ping(NodeEntry* _n) const + { + if (_n && _n->endpoint.udp.address().is_v4()) + ping(_n->endpoint.udp.address(), _n->endpoint.udp.port()); + } + + void evict(std::shared_ptr _leastSeen, std::shared_ptr _new) + { + if (!m_socketPtr->isOpen()) + return; + + Guard l(x_evictions); + m_evictions.push_back(EvictionTimeout(make_pair(_leastSeen->id,chrono::steady_clock::now()), _new->id)); + if (m_evictions.size() == 1) + doCheckEvictions(boost::system::error_code()); + + m_evictions.push_back(EvictionTimeout(make_pair(_leastSeen->id,chrono::steady_clock::now()), _new->id)); + ping(_leastSeen.get()); + } + void noteNode(Public _pubk, bi::udp::endpoint _endpoint) + { + Address id = right160(sha3(_pubk)); + std::shared_ptr node; + { + Guard l(x_nodes); + auto n = m_nodes.find(id); + if (n == m_nodes.end()) + { + m_nodes[id] = std::shared_ptr(new NodeEntry(m_node, id, _pubk, _endpoint)); + node = m_nodes[id]; + } + else + node = n->second; + } + + noteNode(node); + } + + void noteNode(std::shared_ptr _n) + { + std::shared_ptr contested; + { + NodeBucket s = bucket(_n.get()); + Guard l(x_state); + s.nodes.remove_if([&_n](std::weak_ptr n) + { + auto p = n.lock(); + if (!p || p == _n) + return true; + return false; + }); + + if (s.nodes.size() >= s_bucketSize) + { + contested = s.nodes.front().lock(); + if (!contested) + { + s.nodes.pop_front(); + s.nodes.push_back(_n); + } + } + else + s.nodes.push_back(_n); + } + + if (contested) + evict(contested, _n); + } + + void dropNode(std::shared_ptr _n) + { + NodeBucket s = bucket(_n.get()); + { + Guard l(x_state); + s.nodes.remove_if([&_n](std::weak_ptr n) { return n.lock() == _n; }); + } + Guard l(x_nodes); + m_nodes.erase(_n->id); + } + + NodeBucket const& bucket(NodeEntry* _n) const + { + return m_state[_n->distance]; + } + + void onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytesConstRef _packet) + { + RLP rlp(_packet); + + + // whenever a pong is received, first check if it's in m_evictions, if so, remove it + Guard l(x_evictions); + } + + void onDisconnected(UDPSocketFace*) + { + + } + + void doCheckEvictions(boost::system::error_code const& _ec) + { + if (_ec || !m_socketPtr->isOpen()) + return; + + m_evictionCheckTimer.expires_from_now(boost::posix_time::milliseconds(s_evictionCheckInterval)); + auto self(shared_from_this()); + m_evictionCheckTimer.async_wait([this, self](boost::system::error_code const& _ec) + { + if (_ec) + return; + + bool evictionsRemain = false; + std::list> drop; + { + Guard l(x_evictions); + for (auto& e: m_evictions) + if (chrono::steady_clock::now() - e.first.second > chrono::milliseconds(s_pingTimeout)) + { + Guard l(x_nodes); + drop.push_back(m_nodes[e.second]); + } + evictionsRemain = m_evictions.size() - drop.size() > 0; + } + + for (auto& n: drop) + dropNode(n); + + if (evictionsRemain) + doCheckEvictions(boost::system::error_code()); + }); + } + + void doRefreshBuckets(boost::system::error_code const& _ec) + { + cout << "refreshing buckets" << endl; + if (_ec) + return; + + // first check if there are any pending evictions + + + bool connected = m_socketPtr->isOpen(); + bool refreshed = false; + if (connected) + { + Guard l(x_state); + for (auto& d: m_state) + if (chrono::steady_clock::now() - d.modified > chrono::seconds(s_bucketRefresh)) + while (!d.nodes.empty()) + { + auto n = d.nodes.front(); + if (auto p = n.lock()) + { + refreshed = true; + ping(p.get()); + break; + } + d.nodes.pop_front(); + } + } + + unsigned nextRefresh = connected ? (refreshed ? 200 : s_bucketRefresh*1000) : 10000; + auto runcb = [this](boost::system::error_code const& error) -> void { doRefreshBuckets(error); }; + m_bucketRefreshTimer.expires_from_now(boost::posix_time::milliseconds(nextRefresh)); + m_bucketRefreshTimer.async_wait(runcb); + } + +private: + NodeEntry m_node; ///< This node. + Secret m_secret; ///< This nodes secret key. + + mutable Mutex x_nodes; ///< Mutable for thread-safe copy in nodes() const. + std::map> m_nodes; ///< Address -> Node table (most common lookup path) + + Mutex x_state; + std::array m_state; ///< State table; logbinned nodes. + + Mutex x_evictions; + std::deque m_evictions; ///< Eviction timeouts. + + shared_ptr m_socket; ///< Shared pointer for our UDPSocket; ASIO requires shared_ptr. + nodeSocket* m_socketPtr; ///< Set to m_socket.get(). + ba::io_service& m_io; ///< Used by bucket refresh timer. + boost::asio::deadline_timer m_bucketRefreshTimer; ///< Timer which schedules and enacts bucket refresh. + boost::asio::deadline_timer m_evictionCheckTimer; ///< Timer for handling node evictions. +}; + +/** + * Only used for testing. Not useful beyond tests. + */ +class TestHost: public Worker +{ +public: + TestHost(): Worker("test",0), m_io() {}; + ~TestHost() { m_io.stop(); stopWorking(); } + void start() { startWorking(); } + void doWork() { m_io.run(); } + +protected: + ba::io_service m_io; +}; + +/** + * Only used for testing. Not useful beyond tests. + */ +class TestNodeHost: public TestHost +{ +public: + TestNodeHost(): m_nodes(m_io) {}; + ~TestNodeHost() { m_io.stop(); stopWorking(); } + void start() { startWorking(); } + void doWork() { m_io.run(); } + + NodeTable m_nodes; +}; + +class TestUDPSocket: UDPSocketEvents, public TestHost +{ +public: + TestUDPSocket(): m_socket(new UDPSocket(m_io, *this, 30300)) {} + ~TestUDPSocket() { m_io.stop(); stopWorking(); } void start() { startWorking(); } void doWork() { m_io.run(); } void onDisconnected(UDPSocketFace*) {}; - void onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytesConstRef _packet) { if (_packet.toString() == "AAAA") success = true; } + void onReceived(UDPSocketFace*, bi::udp::endpoint const&, bytesConstRef _packet) { if (_packet.toString() == "AAAA") success = true; } - ba::io_service m_io; - shared_ptr> m_socket; + shared_ptr> m_socket; bool success = false; }; -//struct TestBProtocol: UDPSocketEvents -//{ -// void onDisconnected(UDPSocketFace*) {}; -// void onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytesConstRef _packet) { cout << "received TestBProtocol" << endl; }; -//}; -// -//class TestB: TestBProtocol -//{ -//public: -// TestB(): m_io(), m_socket(m_io, *this, 30300) {} -////private: -// ba::io_service m_io; -// UDPSocket m_socket; -//}; -// -//class TestC -//{ -//public: -// TestC(): m_io(), m_socket(m_io, m_rpc, 30300) {} -////private: -// ba::io_service m_io; -// TestBProtocol m_rpc; -// UDPSocket m_socket; -//}; - BOOST_AUTO_TEST_SUITE(p2p) -BOOST_AUTO_TEST_CASE(test_txrx_one) +BOOST_AUTO_TEST_CASE(kademlia) { - UDPDatagram d; - d.to = boost::asio::ip::udp::endpoint(boost::asio::ip::address::from_string("127.0.0.1"), 30300); - d.data = bytes({65,65,65,65}); + TestNodeHost nodeHost; - TestA a; a.m_socket->connect(); a.start(); +} + +BOOST_AUTO_TEST_CASE(test_txrx_one) +{ + UDPDatagram d(bi::udp::endpoint(boost::asio::ip::address::from_string("127.0.0.1"), 30300), bytes({65,65,65,65})); + TestUDPSocket a; a.m_socket->connect(); a.start(); a.m_socket->send(d); sleep(1); BOOST_REQUIRE_EQUAL(true, a.success); From 5da56314000ef5ca77a5ba98145350623835a9a5 Mon Sep 17 00:00:00 2001 From: subtly Date: Mon, 22 Dec 2014 03:56:07 +0100 Subject: [PATCH 017/111] repot. --- libp2p/UDP.cpp | 15 ++ libp2p/UDP.h | 236 ++++++++++++------------ test/net.cpp | 489 +------------------------------------------------ 3 files changed, 138 insertions(+), 602 deletions(-) diff --git a/libp2p/UDP.cpp b/libp2p/UDP.cpp index 9fc65b7c3..a398eb1fa 100644 --- a/libp2p/UDP.cpp +++ b/libp2p/UDP.cpp @@ -18,3 +18,18 @@ * @author Alex Leverington * @date 2014 */ + +#include "UDP.h" +using namespace dev; +using namespace dev::p2p; + +void RLPDatagram::seal(Secret const& _k) +{ + RLPStream packet; + streamRLP(packet); + bytes b(packet.out()); + Signature sig = dev::sign(_k, dev::sha3(b)); + data.resize(data.size() + Signature::size); + sig.ref().copyTo(&data); + memcpy(data.data()+sizeof(Signature),b.data(),b.size()); +} diff --git a/libp2p/UDP.h b/libp2p/UDP.h index a28646369..0f4499c84 100644 --- a/libp2p/UDP.h +++ b/libp2p/UDP.h @@ -43,23 +43,12 @@ struct UDPDatagram UDPDatagram() = default; UDPDatagram(bi::udp::endpoint _ep, bytes _data): to(_ep), data(std::move(_data)) {} bi::udp::endpoint to; - bytes data; }; - + struct RLPDatagram: UDPDatagram { - void seal(Secret const& _k) - { - RLPStream packet; - streamRLP(packet); - bytes b(packet.out()); - Signature sig = dev::sign(_k, dev::sha3(b)); - data.resize(data.size() + Signature::size); - sig.ref().copyTo(&data); - memcpy(data.data()+sizeof(Signature),b.data(),b.size()); - } - + virtual void seal(Secret const& _k); protected: virtual void streamRLP(RLPStream& _s) const {}; }; @@ -92,127 +81,146 @@ public: virtual ~UDPSocket() { disconnect(); } /// Socket will begin listening for and delivering packets - void connect() - { - bool expect = false; - if (!m_started.compare_exchange_strong(expect, true)) - return; - - m_socket.open(bi::udp::v4()); - m_socket.bind(m_endpoint); - - // clear write queue so reconnect doesn't send stale messages - Guard l(x_sendQ); - sendQ.clear(); - - m_closed = false; - doRead(); - } + void connect(); - bool send(UDPDatagram const& _datagram) - { - if (m_closed) - return false; - - Guard l(x_sendQ); - sendQ.push_back(_datagram); - if (sendQ.size() == 1) - doWrite(); - - return true; - } + /// Send datagram. + bool send(UDPDatagram const& _datagram); + /// Returns if socket is open. bool isOpen() { return !m_closed; } + /// Disconnect socket. void disconnect() { disconnectWithError(boost::asio::error::connection_reset); } protected: - void doRead() - { - auto self(UDPSocket::shared_from_this()); - m_socket.async_receive_from(boost::asio::buffer(recvData), recvEndpoint, [this, self](boost::system::error_code _ec, size_t _len) - { - if (_ec) - return disconnectWithError(_ec); - - assert(_len); - m_host.onReceived(this, recvEndpoint, bytesConstRef(recvData.data(), _len)); - if (!m_closed) - doRead(); - }); - } - void doWrite() + void doRead(); + + void doWrite(); + + void disconnectWithError(boost::system::error_code _ec); + + std::atomic m_started; ///< Atomically ensure connection is started once. Start cannot occur unless m_started is false. Managed by start and disconnectWithError. + std::atomic m_closed; ///< Connection availability. + + UDPSocketEvents& m_host; ///< Interface which owns this socket. + bi::udp::endpoint m_endpoint; ///< Endpoint which we listen to. + + Mutex x_sendQ; + std::deque sendQ; ///< Queue for egress data. + std::array recvData; ///< Buffer for ingress data. + bi::udp::endpoint recvEndpoint; ///< Endpoint data was received from. + bi::udp::socket m_socket; ///< Boost asio udp socket. + + Mutex x_socketError; ///< Mutex for error which can be set from host or IO thread. + boost::system::error_code socketError; ///< Set when shut down due to error. +}; + +template +void UDPSocket::connect() +{ + bool expect = false; + if (!m_started.compare_exchange_strong(expect, true)) + return; + + m_socket.open(bi::udp::v4()); + m_socket.bind(m_endpoint); + + // clear write queue so reconnect doesn't send stale messages + Guard l(x_sendQ); + sendQ.clear(); + + m_closed = false; + doRead(); +} + +template +bool UDPSocket::send(UDPDatagram const& _datagram) +{ + if (m_closed) + return false; + + Guard l(x_sendQ); + sendQ.push_back(_datagram); + if (sendQ.size() == 1) + doWrite(); + + return true; +} + +template +void UDPSocket::doRead() +{ + auto self(UDPSocket::shared_from_this()); + m_socket.async_receive_from(boost::asio::buffer(recvData), recvEndpoint, [this, self](boost::system::error_code _ec, size_t _len) { - const UDPDatagram& datagram = sendQ[0]; - auto self(UDPSocket::shared_from_this()); - m_socket.async_send_to(boost::asio::buffer(datagram.data), datagram.to, [this, self](boost::system::error_code _ec, std::size_t) - { - if (_ec) - return disconnectWithError(_ec); - else - { - Guard l(x_sendQ); - sendQ.pop_front(); - if (sendQ.empty()) - return; - } - doWrite(); - }); - } + if (_ec) + return disconnectWithError(_ec); + + assert(_len); + m_host.onReceived(this, recvEndpoint, bytesConstRef(recvData.data(), _len)); + if (!m_closed) + doRead(); + }); +} - void disconnectWithError(boost::system::error_code _ec) +template +void UDPSocket::doWrite() +{ + const UDPDatagram& datagram = sendQ[0]; + auto self(UDPSocket::shared_from_this()); + m_socket.async_send_to(boost::asio::buffer(datagram.data), datagram.to, [this, self](boost::system::error_code _ec, std::size_t) { - // If !started and already stopped, shutdown has already occured. (EOF or Operation canceled) - if (!m_started && m_closed && !m_socket.is_open() /* todo: veirfy this logic*/) - return; - - assert(_ec); + if (_ec) + return disconnectWithError(_ec); + else { - // disconnect-operation following prior non-zero errors are ignored - Guard l(x_socketError); - if (socketError != boost::system::error_code()) + Guard l(x_sendQ); + sendQ.pop_front(); + if (sendQ.empty()) return; - socketError = _ec; } - // TODO: (if non-zero error) schedule high-priority writes + doWrite(); + }); +} - // prevent concurrent disconnect - bool expected = true; - if (!m_started.compare_exchange_strong(expected, false)) - return; - - // set m_closed to true to prevent undeliverable egress messages - bool wasClosed = m_closed; - m_closed = true; - - // close sockets - boost::system::error_code ec; - m_socket.shutdown(bi::udp::socket::shutdown_both, ec); - m_socket.close(); - - // socket never started if it never left stopped-state (pre-handshake) - if (wasClosed) - return; +template +void UDPSocket::disconnectWithError(boost::system::error_code _ec) +{ + // If !started and already stopped, shutdown has already occured. (EOF or Operation canceled) + if (!m_started && m_closed && !m_socket.is_open() /* todo: veirfy this logic*/) + return; - m_host.onDisconnected(this); + assert(_ec); + { + // disconnect-operation following prior non-zero errors are ignored + Guard l(x_socketError); + if (socketError != boost::system::error_code()) + return; + socketError = _ec; } + // TODO: (if non-zero error) schedule high-priority writes - std::atomic m_closed; ///< Set when connection is stopping or stopped. Handshake cannot occur unless m_closed is true. - std::atomic m_started; ///< Atomically ensure connection is started once. Start cannot occur unless m_started is false. Managed by start and disconnectWithError. - - UDPSocketEvents& m_host; ///< Interface which owns this socket. - bi::udp::endpoint m_endpoint; ///< Endpoint which we listen to. + // prevent concurrent disconnect + bool expected = true; + if (!m_started.compare_exchange_strong(expected, false)) + return; - Mutex x_sendQ; - std::deque sendQ; - std::array recvData; ///< Buffer for ingress datagrams. - bi::udp::endpoint recvEndpoint; ///< Endpoint data was received from. - bi::udp::socket m_socket; + // set m_closed to true to prevent undeliverable egress messages + bool wasClosed = m_closed; + m_closed = true; - Mutex x_socketError; ///< Mutex for error which can occur from host or IO thread. - boost::system::error_code socketError; ///< Set when shut down due to error. -}; + // close sockets + boost::system::error_code ec; + m_socket.shutdown(bi::udp::socket::shutdown_both, ec); + m_socket.close(); + + // socket never started if it never left stopped-state (pre-handshake) + if (wasClosed) + return; + + m_host.onDisconnected(this); +} } } \ No newline at end of file diff --git a/test/net.cpp b/test/net.cpp index 0a22a7e63..3d2e08eb6 100644 --- a/test/net.cpp +++ b/test/net.cpp @@ -23,500 +23,13 @@ #include #include #include +#include using namespace std; using namespace dev; using namespace dev::p2p; namespace ba = boost::asio; namespace bi = ba::ip; -/** - * Ping packet: Check if node is alive. - * PingNode is cached and regenerated after expiration - t, where t is timeout. - * - * signature: Signature of message. - * ipAddress: Our IP address. - * port: Our port. - * expiration: Triggers regeneration of packet. May also provide control over synchronization. - * - * Ping is used to implement evict. When a new node is seen for - * a given bucket which is full, the least-responsive node is pinged. - * If the pinged node doesn't respond then it is removed and the new - * node is inserted. - */ -struct PingNode: RLPDatagram -{ - bytes ipAddress; - uint16_t port; - uint64_t expiration; - - Signature signature; - -// void streamRLP(RLPStream& _s) const { _s.appendList(3); _s << ipAddress << port << expiration; } -}; - -struct Pong: RLPDatagram -{ - // todo: weak-signed pong - Address from; - uint64_t replyTo; /// expiration from PingNode - - void streamRLP(RLPStream& _s) const { _s.appendList(2); _s << from << replyTo; } -}; - -/** - * FindNeighbors Packet: Request k-nodes, closest to the target. - * FindNeighbors is cached and regenerated after expiration - t, where t is timeout. - * - * signature: Signature of message. - * target: Address of NodeId. The responding node will send back nodes closest to the target. - * expiration: Triggers regeneration of packet. May also provide control over synchronization. - * - */ -struct FindNeighbors: RLPDatagram -{ - h160 target; - uint64_t expiration; - - Signature signature; - - void streamRLP(RLPStream& _s) const { _s.appendList(2); _s << target << expiration; } -}; - -/** - * Node Packet: Multiple node packets are sent in response to FindNeighbors. - */ -struct Neighbors: RLPDatagram -{ - struct Node - { - bytes ipAddress; - uint16_t port; - NodeId node; -// void streamRLP(RLPStream& _s) const { _s.appendList(3); _s << ipAddress << port << node; } - }; - - std::set nodes; - h256 nonce; - - Signature signature; - -// void streamRLP(RLPStream& _s) const { _s.appendList(2); _s.appendList(nodes.size()); for (auto& n: nodes) n.streamRLP(_s); _s << nonce; } -}; - -/** - * NodeTable using S/Kademlia system for node discovery and preference. - * untouched buckets are refreshed if they have not been touched within an hour - * - * Thread-safety is ensured by modifying NodeEntry details via - * shared_ptr replacement instead of mutating values. - * - * @todo don't try to evict node if node isRequired. (support for makeRequired) - * @todo optimize (use tree for state (or set w/custom compare for cache)) - * @todo constructor support for m_node, m_secret - * @todo use s_bitsPerStep for find and refresh/ping - * @todo exclude bucket from refresh if we have node as peer - * @todo restore nodes - */ -class NodeTable: UDPSocketEvents, public std::enable_shared_from_this -{ - using nodeSocket = UDPSocket; - using timePoint = std::chrono::steady_clock::time_point; - - static unsigned const s_bucketSize = 16; // Denoted by k in [Kademlia]. Number of nodes stored in each bucket. -// const unsigned s_bitsPerStep = 5; // @todo Denoted by b in [Kademlia]. Bits by which address space will be divided for find responses. - static unsigned const s_alpha = 3; // Denoted by \alpha in [Kademlia]. Number of concurrent FindNeighbors requests. - const unsigned s_findTimout = 300; // How long to wait between find queries. -// const unsigned s_siblings = 5; // @todo Denoted by s in [S/Kademlia]. User-defined by sub-protocols. - const unsigned s_bucketRefresh = 3600; // Refresh interval prevents bucket from becoming stale. [Kademlia] - const unsigned s_bits = sizeof(Address); // Denoted by n. - const unsigned s_buckets = 8 * s_bits - 1; - const unsigned s_evictionCheckInterval = 75; // Interval by which eviction timeouts are checked. - const unsigned s_pingTimeout = 500; - static size_t const s_tableSize = Address::size * 8 - 1; // Address::size - -public: - static unsigned dist(Address const& _a, Address const& _b) { u160 d = _a ^ _b; unsigned ret; for (ret = 0; d >>= 1; ++ret) {}; return ret; } - -protected: - struct NodeDefaultEndpoint - { - NodeDefaultEndpoint(bi::udp::endpoint _udp): udp(_udp) {} - bi::udp::endpoint udp; - }; - - struct NodeEntry - { - NodeEntry(Address _id, Public _pubk, bi::udp::endpoint _udp): id(_id), pubk(_pubk), endpoint(NodeDefaultEndpoint(_udp)), distance(0) {} - NodeEntry(NodeEntry _src, Address _id, Public _pubk, bi::udp::endpoint _udp): id(_id), pubk(_pubk), endpoint(NodeDefaultEndpoint(_udp)), distance(dist(_src.id,_id)) {} - NodeEntry(NodeEntry _src, Address _id, Public _pubk, NodeDefaultEndpoint _gw): id(_id), pubk(_pubk), endpoint(_gw), distance(dist(_src.id,_id)) {} - Address id; - Public pubk; - NodeDefaultEndpoint endpoint; ///< How we've previously connected to this node. (must match node's reported endpoint) - const unsigned distance; - timePoint activePing; - }; - - struct NodeBucket - { - unsigned distance; - timePoint modified; - std::list> nodes; - }; - - using EvictionTimeout = std::pair,Address>; - -public: - NodeTable(ba::io_service& _io): - m_node(NodeEntry(Address(), Public(), bi::udp::endpoint())), - m_socket(new nodeSocket(_io, *this, 30300)), - m_socketPtr(m_socket.get()), - m_io(_io), - m_bucketRefreshTimer(m_io), - m_evictionCheckTimer(m_io) - { - for (unsigned i = 0; i < s_buckets; i++) - m_state[i].distance = i, m_state[i].modified = chrono::steady_clock::now() - chrono::seconds(1); - doRefreshBuckets(boost::system::error_code()); - } - - ~NodeTable() { - m_evictionCheckTimer.cancel(); - m_bucketRefreshTimer.cancel(); - m_socketPtr->disconnect(); - } - - void join() { doFindNode(m_node.id); } - - std::list
nodes() const - { - std::list
nodes; - Guard l(x_nodes); - for (auto& i: m_nodes) - nodes.push_back(i.second->id); - return std::move(nodes); - } - - NodeEntry operator[](Address _id) - { - Guard l(x_nodes); - return *m_nodes[_id]; - } - -protected: - void requestNeighbors(NodeEntry const& _node, Address _target) const - { - FindNeighbors p; - p.target = _target; - - p.to = _node.endpoint.udp; - p.seal(m_secret); - m_socketPtr->send(p); - } - - /// Dispatches udp requests in order to populate node table to be as close as possible to _node. - void doFindNode(Address _node, unsigned _round = 0, std::shared_ptr>> _tried = std::shared_ptr>>()) - { - if (!m_socketPtr->isOpen() || _round == 7) - return; - - auto nearest = findNearest(_node); - std::list> tried; - for (unsigned i = 0; i < nearest.size() && tried.size() < s_alpha; i++) - if (!_tried->count(nearest[i])) - { - tried.push_back(nearest[i]); - requestNeighbors(*nearest[i], _node); - } - else - continue; - - while (auto n = tried.front()) - { - _tried->insert(n); - tried.pop_front(); - } - - auto self(shared_from_this()); - m_evictionCheckTimer.expires_from_now(boost::posix_time::milliseconds(s_findTimout)); - m_evictionCheckTimer.async_wait([this, self, _node, _round, _tried](boost::system::error_code const& _ec) - { - if (_ec) - return; - doFindNode(_node, _round + 1, _tried); - }); - } - - std::vector> findNearest(Address _target) - { - // send s_alpha FindNeighbors packets to nodes we know, closest to target - unsigned head = dist(m_node.id, _target); - unsigned tail = (head - 1) % (s_tableSize - 1); - - // todo: optimize with tree - std::map>> found; - unsigned count = 0; - - // if d is 0, then we roll look forward, if last, we reverse, else, spread from d - if (head != 0 && tail != s_tableSize) - while (head != tail && count < s_bucketSize) - { - Guard l(x_state); - for (auto& n: m_state[head].nodes) - if (auto p = n.lock()) - { - if (count < s_bucketSize) - found[dist(_target, p->id)].push_back(p); - else - break; - } - - if (count < s_bucketSize && head) - for (auto& n: m_state[tail].nodes) - if (auto p = n.lock()) - { - if (count < s_bucketSize) - found[dist(_target, p->id)].push_back(p); - else - break; - } - head++; - tail = (tail - 1) % (s_tableSize - 1); - } - else if (head == 0) - while (head < s_bucketSize && count < s_bucketSize) - { - Guard l(x_state); - for (auto& n: m_state[head].nodes) - if (auto p = n.lock()) - { - if (count < s_bucketSize) - found[dist(_target, p->id)].push_back(p); - else - break; - } - head--; - } - else if (tail == s_tableSize - 1) - while (tail > 0 && count < s_bucketSize) - { - Guard l(x_state); - for (auto& n: m_state[tail].nodes) - if (auto p = n.lock()) - { - if (count < s_bucketSize) - found[dist(_target, p->id)].push_back(p); - else - break; - } - tail--; - } - - std::vector> ret; - for (auto& nodes: found) - for (auto& n: nodes.second) - ret.push_back(n); - return std::move(ret); - } - - void ping(bi::address _address, unsigned _port) const - { - PingNode p; - string ip = m_node.endpoint.udp.address().to_string(); - p.ipAddress = asBytes(ip); - p.port = m_node.endpoint.udp.port(); -// p.expiration; - p.seal(m_secret); - m_socketPtr->send(p); - } - - void ping(NodeEntry* _n) const - { - if (_n && _n->endpoint.udp.address().is_v4()) - ping(_n->endpoint.udp.address(), _n->endpoint.udp.port()); - } - - void evict(std::shared_ptr _leastSeen, std::shared_ptr _new) - { - if (!m_socketPtr->isOpen()) - return; - - Guard l(x_evictions); - m_evictions.push_back(EvictionTimeout(make_pair(_leastSeen->id,chrono::steady_clock::now()), _new->id)); - if (m_evictions.size() == 1) - doCheckEvictions(boost::system::error_code()); - - m_evictions.push_back(EvictionTimeout(make_pair(_leastSeen->id,chrono::steady_clock::now()), _new->id)); - ping(_leastSeen.get()); - } - - void noteNode(Public _pubk, bi::udp::endpoint _endpoint) - { - Address id = right160(sha3(_pubk)); - std::shared_ptr node; - { - Guard l(x_nodes); - auto n = m_nodes.find(id); - if (n == m_nodes.end()) - { - m_nodes[id] = std::shared_ptr(new NodeEntry(m_node, id, _pubk, _endpoint)); - node = m_nodes[id]; - } - else - node = n->second; - } - - noteNode(node); - } - - void noteNode(std::shared_ptr _n) - { - std::shared_ptr contested; - { - NodeBucket s = bucket(_n.get()); - Guard l(x_state); - s.nodes.remove_if([&_n](std::weak_ptr n) - { - auto p = n.lock(); - if (!p || p == _n) - return true; - return false; - }); - - if (s.nodes.size() >= s_bucketSize) - { - contested = s.nodes.front().lock(); - if (!contested) - { - s.nodes.pop_front(); - s.nodes.push_back(_n); - } - } - else - s.nodes.push_back(_n); - } - - if (contested) - evict(contested, _n); - } - - void dropNode(std::shared_ptr _n) - { - NodeBucket s = bucket(_n.get()); - { - Guard l(x_state); - s.nodes.remove_if([&_n](std::weak_ptr n) { return n.lock() == _n; }); - } - Guard l(x_nodes); - m_nodes.erase(_n->id); - } - - NodeBucket const& bucket(NodeEntry* _n) const - { - return m_state[_n->distance]; - } - - void onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytesConstRef _packet) - { - RLP rlp(_packet); - - - // whenever a pong is received, first check if it's in m_evictions, if so, remove it - Guard l(x_evictions); - } - - void onDisconnected(UDPSocketFace*) - { - - } - - void doCheckEvictions(boost::system::error_code const& _ec) - { - if (_ec || !m_socketPtr->isOpen()) - return; - - m_evictionCheckTimer.expires_from_now(boost::posix_time::milliseconds(s_evictionCheckInterval)); - auto self(shared_from_this()); - m_evictionCheckTimer.async_wait([this, self](boost::system::error_code const& _ec) - { - if (_ec) - return; - - bool evictionsRemain = false; - std::list> drop; - { - Guard l(x_evictions); - for (auto& e: m_evictions) - if (chrono::steady_clock::now() - e.first.second > chrono::milliseconds(s_pingTimeout)) - { - Guard l(x_nodes); - drop.push_back(m_nodes[e.second]); - } - evictionsRemain = m_evictions.size() - drop.size() > 0; - } - - for (auto& n: drop) - dropNode(n); - - if (evictionsRemain) - doCheckEvictions(boost::system::error_code()); - }); - } - - void doRefreshBuckets(boost::system::error_code const& _ec) - { - cout << "refreshing buckets" << endl; - if (_ec) - return; - - // first check if there are any pending evictions - - - bool connected = m_socketPtr->isOpen(); - bool refreshed = false; - if (connected) - { - Guard l(x_state); - for (auto& d: m_state) - if (chrono::steady_clock::now() - d.modified > chrono::seconds(s_bucketRefresh)) - while (!d.nodes.empty()) - { - auto n = d.nodes.front(); - if (auto p = n.lock()) - { - refreshed = true; - ping(p.get()); - break; - } - d.nodes.pop_front(); - } - } - - unsigned nextRefresh = connected ? (refreshed ? 200 : s_bucketRefresh*1000) : 10000; - auto runcb = [this](boost::system::error_code const& error) -> void { doRefreshBuckets(error); }; - m_bucketRefreshTimer.expires_from_now(boost::posix_time::milliseconds(nextRefresh)); - m_bucketRefreshTimer.async_wait(runcb); - } - -private: - NodeEntry m_node; ///< This node. - Secret m_secret; ///< This nodes secret key. - - mutable Mutex x_nodes; ///< Mutable for thread-safe copy in nodes() const. - std::map> m_nodes; ///< Address -> Node table (most common lookup path) - - Mutex x_state; - std::array m_state; ///< State table; logbinned nodes. - - Mutex x_evictions; - std::deque m_evictions; ///< Eviction timeouts. - - shared_ptr m_socket; ///< Shared pointer for our UDPSocket; ASIO requires shared_ptr. - nodeSocket* m_socketPtr; ///< Set to m_socket.get(). - ba::io_service& m_io; ///< Used by bucket refresh timer. - boost::asio::deadline_timer m_bucketRefreshTimer; ///< Timer which schedules and enacts bucket refresh. - boost::asio::deadline_timer m_evictionCheckTimer; ///< Timer for handling node evictions. -}; - /** * Only used for testing. Not useful beyond tests. */ From 6131bd62d665b293809759e5acd2141faed2f3a3 Mon Sep 17 00:00:00 2001 From: subtly Date: Mon, 22 Dec 2014 03:56:22 +0100 Subject: [PATCH 018/111] NodeTable into own files. --- libp2p/NodeTable.cpp | 351 +++++++++++++++++++++++++++++++++++++++++++ libp2p/NodeTable.h | 226 ++++++++++++++++++++++++++++ 2 files changed, 577 insertions(+) create mode 100644 libp2p/NodeTable.cpp create mode 100644 libp2p/NodeTable.h diff --git a/libp2p/NodeTable.cpp b/libp2p/NodeTable.cpp new file mode 100644 index 000000000..0011e0e45 --- /dev/null +++ b/libp2p/NodeTable.cpp @@ -0,0 +1,351 @@ +/* + 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 NodeTable.cpp + * @author Alex Leverington + * @date 2014 + */ + +#include "NodeTable.h" +using namespace std; +using namespace dev; +using namespace dev::p2p; + +NodeTable::NodeTable(ba::io_service& _io): + m_node(NodeEntry(Address(), Public(), bi::udp::endpoint())), + m_socket(new nodeSocket(_io, *this, 30300)), + m_socketPtr(m_socket.get()), + m_io(_io), + m_bucketRefreshTimer(m_io), + m_evictionCheckTimer(m_io) + { + for (unsigned i = 0; i < s_bins; i++) + m_state[i].distance = i, m_state[i].modified = chrono::steady_clock::now() - chrono::seconds(1); + doRefreshBuckets(boost::system::error_code()); + } + +NodeTable::~NodeTable() +{ + m_evictionCheckTimer.cancel(); + m_bucketRefreshTimer.cancel(); + m_socketPtr->disconnect(); +} + + void NodeTable::join() +{ + doFindNode(m_node.id); +} + +std::list
NodeTable::nodes() const +{ + std::list
nodes; + Guard l(x_nodes); + for (auto& i: m_nodes) + nodes.push_back(i.second->id); + return std::move(nodes); +} + +NodeTable::NodeEntry NodeTable::operator[](Address _id) +{ + Guard l(x_nodes); + return *m_nodes[_id]; +} + +void NodeTable::requestNeighbors(NodeEntry const& _node, Address _target) const +{ + FindNeighbors p; + p.target = _target; + + p.to = _node.endpoint.udp; + p.seal(m_secret); + m_socketPtr->send(p); +} + +void NodeTable::doFindNode(Address _node, unsigned _round, std::shared_ptr>> _tried) +{ + if (!m_socketPtr->isOpen() || _round == 7) + return; + + auto nearest = findNearest(_node); + std::list> tried; + for (unsigned i = 0; i < nearest.size() && tried.size() < s_alpha; i++) + if (!_tried->count(nearest[i])) + { + tried.push_back(nearest[i]); + requestNeighbors(*nearest[i], _node); + } + else + continue; + + while (auto n = tried.front()) + { + _tried->insert(n); + tried.pop_front(); + } + + auto self(shared_from_this()); + m_evictionCheckTimer.expires_from_now(boost::posix_time::milliseconds(s_findTimout)); + m_evictionCheckTimer.async_wait([this, self, _node, _round, _tried](boost::system::error_code const& _ec) + { + if (_ec) + return; + doFindNode(_node, _round + 1, _tried); + }); +} + +std::vector> NodeTable::findNearest(Address _target) +{ + // send s_alpha FindNeighbors packets to nodes we know, closest to target + unsigned head = dist(m_node.id, _target); + unsigned tail = (head - 1) % (s_bits - 1); + + // todo: optimize with tree + std::map>> found; + unsigned count = 0; + + // if d is 0, then we roll look forward, if last, we reverse, else, spread from d + if (head != 0 && tail != s_bits) + while (head != tail && count < s_bucketSize) + { + Guard l(x_state); + for (auto& n: m_state[head].nodes) + if (auto p = n.lock()) + { + if (count < s_bucketSize) + found[dist(_target, p->id)].push_back(p); + else + break; + } + + if (count < s_bucketSize && head) + for (auto& n: m_state[tail].nodes) + if (auto p = n.lock()) + { + if (count < s_bucketSize) + found[dist(_target, p->id)].push_back(p); + else + break; + } + head++; + tail = (tail - 1) % (s_bits - 1); + } + else if (head == 0) + while (head < s_bucketSize && count < s_bucketSize) + { + Guard l(x_state); + for (auto& n: m_state[head].nodes) + if (auto p = n.lock()) + { + if (count < s_bucketSize) + found[dist(_target, p->id)].push_back(p); + else + break; + } + head--; + } + else if (tail == s_bits - 1) + while (tail > 0 && count < s_bucketSize) + { + Guard l(x_state); + for (auto& n: m_state[tail].nodes) + if (auto p = n.lock()) + { + if (count < s_bucketSize) + found[dist(_target, p->id)].push_back(p); + else + break; + } + tail--; + } + + std::vector> ret; + for (auto& nodes: found) + for (auto& n: nodes.second) + ret.push_back(n); + return std::move(ret); +} + +void NodeTable::ping(bi::address _address, unsigned _port) const +{ + PingNode p; + string ip = m_node.endpoint.udp.address().to_string(); + p.ipAddress = asBytes(ip); + p.port = m_node.endpoint.udp.port(); +// p.expiration; + p.seal(m_secret); + m_socketPtr->send(p); +} + +void NodeTable::ping(NodeEntry* _n) const +{ + if (_n && _n->endpoint.udp.address().is_v4()) + ping(_n->endpoint.udp.address(), _n->endpoint.udp.port()); +} + +void NodeTable::evict(std::shared_ptr _leastSeen, std::shared_ptr _new) +{ + if (!m_socketPtr->isOpen()) + return; + + Guard l(x_evictions); + m_evictions.push_back(EvictionTimeout(make_pair(_leastSeen->id,chrono::steady_clock::now()), _new->id)); + if (m_evictions.size() == 1) + doCheckEvictions(boost::system::error_code()); + + m_evictions.push_back(EvictionTimeout(make_pair(_leastSeen->id,chrono::steady_clock::now()), _new->id)); + ping(_leastSeen.get()); +} + +void NodeTable::noteNode(Public _pubk, bi::udp::endpoint _endpoint) +{ + Address id = right160(sha3(_pubk)); + std::shared_ptr node; + { + Guard l(x_nodes); + auto n = m_nodes.find(id); + if (n == m_nodes.end()) + { + m_nodes[id] = std::shared_ptr(new NodeEntry(m_node, id, _pubk, _endpoint)); + node = m_nodes[id]; + } + else + node = n->second; + } + + noteNode(node); +} + +void NodeTable::noteNode(std::shared_ptr _n) +{ + std::shared_ptr contested; + { + NodeBucket s = bucket(_n.get()); + Guard l(x_state); + s.nodes.remove_if([&_n](std::weak_ptr n) + { + auto p = n.lock(); + if (!p || p == _n) + return true; + return false; + }); + + if (s.nodes.size() >= s_bucketSize) + { + contested = s.nodes.front().lock(); + if (!contested) + { + s.nodes.pop_front(); + s.nodes.push_back(_n); + } + } + else + s.nodes.push_back(_n); + } + + if (contested) + evict(contested, _n); +} + +void NodeTable::dropNode(std::shared_ptr _n) +{ + NodeBucket s = bucket(_n.get()); + { + Guard l(x_state); + s.nodes.remove_if([&_n](std::weak_ptr n) { return n.lock() == _n; }); + } + Guard l(x_nodes); + m_nodes.erase(_n->id); +} + +NodeTable::NodeBucket const& NodeTable::bucket(NodeEntry* _n) const +{ + return m_state[_n->distance]; +} + +void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytesConstRef _packet) +{ + RLP rlp(_packet); + + + // whenever a pong is received, first check if it's in m_evictions, if so, remove it + Guard l(x_evictions); +} + +void NodeTable::doCheckEvictions(boost::system::error_code const& _ec) +{ + if (_ec || !m_socketPtr->isOpen()) + return; + + m_evictionCheckTimer.expires_from_now(boost::posix_time::milliseconds(s_evictionCheckInterval)); + auto self(shared_from_this()); + m_evictionCheckTimer.async_wait([this, self](boost::system::error_code const& _ec) + { + if (_ec) + return; + + bool evictionsRemain = false; + std::list> drop; + { + Guard l(x_evictions); + for (auto& e: m_evictions) + if (chrono::steady_clock::now() - e.first.second > chrono::milliseconds(s_pingTimeout)) + { + Guard l(x_nodes); + drop.push_back(m_nodes[e.second]); + } + evictionsRemain = m_evictions.size() - drop.size() > 0; + } + + for (auto& n: drop) + dropNode(n); + + if (evictionsRemain) + doCheckEvictions(boost::system::error_code()); + }); +} + +void NodeTable::doRefreshBuckets(boost::system::error_code const& _ec) +{ + cout << "refreshing buckets" << endl; + if (_ec) + return; + + bool connected = m_socketPtr->isOpen(); + bool refreshed = false; + if (connected) + { + Guard l(x_state); + for (auto& d: m_state) + if (chrono::steady_clock::now() - d.modified > chrono::seconds(s_bucketRefresh)) + while (!d.nodes.empty()) + { + auto n = d.nodes.front(); + if (auto p = n.lock()) + { + refreshed = true; + ping(p.get()); + break; + } + d.nodes.pop_front(); + } + } + + unsigned nextRefresh = connected ? (refreshed ? 200 : s_bucketRefresh*1000) : 10000; + auto runcb = [this](boost::system::error_code const& error) -> void { doRefreshBuckets(error); }; + m_bucketRefreshTimer.expires_from_now(boost::posix_time::milliseconds(nextRefresh)); + m_bucketRefreshTimer.async_wait(runcb); +} + diff --git a/libp2p/NodeTable.h b/libp2p/NodeTable.h new file mode 100644 index 000000000..1f15540bf --- /dev/null +++ b/libp2p/NodeTable.h @@ -0,0 +1,226 @@ +/* + 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 NodeTable.h + * @author Alex Leverington + * @date 2014 + */ + +#pragma once + +#include +#include + +namespace dev +{ +namespace p2p +{ + +/** + * Ping packet: Check if node is alive. + * PingNode is cached and regenerated after expiration - t, where t is timeout. + * + * signature: Signature of message. + * ipAddress: Our IP address. + * port: Our port. + * expiration: Triggers regeneration of packet. May also provide control over synchronization. + * + * Ping is used to implement evict. When a new node is seen for + * a given bucket which is full, the least-responsive node is pinged. + * If the pinged node doesn't respond then it is removed and the new + * node is inserted. + */ +struct PingNode: RLPDatagram +{ + bytes ipAddress; + uint16_t port; + uint64_t expiration; + + Signature signature; + + void streamRLP(RLPStream& _s) const { _s.appendList(3); _s << ipAddress << port << expiration; } +}; + +struct Pong: RLPDatagram +{ + // todo: weak-signed pong + Address from; + uint64_t replyTo; /// expiration from PingNode + + void streamRLP(RLPStream& _s) const { _s.appendList(2); _s << from << replyTo; } +}; + +/** + * FindNeighbors Packet: Request k-nodes, closest to the target. + * FindNeighbors is cached and regenerated after expiration - t, where t is timeout. + * + * signature: Signature of message. + * target: Address of NodeId. The responding node will send back nodes closest to the target. + * expiration: Triggers regeneration of packet. May also provide control over synchronization. + * + */ +struct FindNeighbors: RLPDatagram +{ + h160 target; + uint64_t expiration; + + Signature signature; + + void streamRLP(RLPStream& _s) const { _s.appendList(2); _s << target << expiration; } +}; + +/** + * Node Packet: Multiple node packets are sent in response to FindNeighbors. + */ +struct Neighbors: RLPDatagram +{ + struct Node + { + bytes ipAddress; + uint16_t port; + NodeId node; + void streamRLP(RLPStream& _s) const { _s.appendList(3); _s << ipAddress << port << node; } + }; + + std::set nodes; + h256 nonce; + + Signature signature; + + void streamRLP(RLPStream& _s) const { _s.appendList(2); _s.appendList(nodes.size()); for (auto& n: nodes) n.streamRLP(_s); _s << nonce; } +}; + +/** + * NodeTable using S/Kademlia system for node discovery and preference. + * untouched buckets are refreshed if they have not been touched within an hour + * + * Thread-safety is ensured by modifying NodeEntry details via + * shared_ptr replacement instead of mutating values. + * + * @todo don't try to evict node if node isRequired. (support for makeRequired) + * @todo optimize (use tree for state (or set w/custom compare for cache)) + * @todo constructor support for m_node, m_secret + * @todo use s_bitsPerStep for find and refresh/ping + * @todo exclude bucket from refresh if we have node as peer + * @todo restore nodes + */ +class NodeTable: UDPSocketEvents, public std::enable_shared_from_this +{ + using nodeSocket = UDPSocket; + using timePoint = std::chrono::steady_clock::time_point; + + static unsigned const s_bucketSize = 16; // Denoted by k in [Kademlia]. Number of nodes stored in each bucket. +// const unsigned s_bitsPerStep = 5; // @todo Denoted by b in [Kademlia]. Bits by which address space will be divided for find responses. + static unsigned const s_alpha = 3; // Denoted by \alpha in [Kademlia]. Number of concurrent FindNeighbors requests. + const unsigned s_findTimout = 300; // How long to wait between find queries. +// const unsigned s_siblings = 5; // @todo Denoted by s in [S/Kademlia]. User-defined by sub-protocols. + const unsigned s_bucketRefresh = 3600; // Refresh interval prevents bucket from becoming stale. [Kademlia] + static unsigned const s_bits = 8 * Address::size; // Denoted by n. + static unsigned const s_bins = s_bits - 1; // + const unsigned s_evictionCheckInterval = 75; // Interval by which eviction timeouts are checked. + const unsigned s_pingTimeout = 500; + +public: + static unsigned dist(Address const& _a, Address const& _b) { u160 d = _a ^ _b; unsigned ret; for (ret = 0; d >>= 1; ++ret) {}; return ret; } + + struct NodeDefaultEndpoint + { + NodeDefaultEndpoint(bi::udp::endpoint _udp): udp(_udp) {} + bi::udp::endpoint udp; + }; + + struct NodeEntry + { + NodeEntry(Address _id, Public _pubk, bi::udp::endpoint _udp): id(_id), pubk(_pubk), endpoint(NodeDefaultEndpoint(_udp)), distance(0) {} + NodeEntry(NodeEntry _src, Address _id, Public _pubk, bi::udp::endpoint _udp): id(_id), pubk(_pubk), endpoint(NodeDefaultEndpoint(_udp)), distance(dist(_src.id,_id)) {} + NodeEntry(NodeEntry _src, Address _id, Public _pubk, NodeDefaultEndpoint _gw): id(_id), pubk(_pubk), endpoint(_gw), distance(dist(_src.id,_id)) {} + Address id; + Public pubk; + NodeDefaultEndpoint endpoint; ///< How we've previously connected to this node. (must match node's reported endpoint) + const unsigned distance; + timePoint activePing; + }; + + struct NodeBucket + { + unsigned distance; + timePoint modified; + std::list> nodes; + }; + + using EvictionTimeout = std::pair,Address>; + + NodeTable(ba::io_service& _io); + ~NodeTable(); + + void join(); + + std::list
nodes() const; + + NodeEntry operator[](Address _id); + +protected: + void requestNeighbors(NodeEntry const& _node, Address _target) const; + + /// Sends requests to other nodes requesting nodes "near" to us in order to populate node table such that connected nodes form centrality. + void doFindNode(Address _node, unsigned _round = 0, std::shared_ptr>> _tried = std::shared_ptr>>()); + + std::vector> findNearest(Address _target); + + void ping(bi::address _address, unsigned _port) const; + + void ping(NodeEntry* _n) const; + + void evict(std::shared_ptr _leastSeen, std::shared_ptr _new); + + void noteNode(Public _pubk, bi::udp::endpoint _endpoint); + + void noteNode(std::shared_ptr _n); + + void dropNode(std::shared_ptr _n); + + NodeBucket const& bucket(NodeEntry* _n) const; + + void onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytesConstRef _packet); + + void onDisconnected(UDPSocketFace*) {}; + + void doCheckEvictions(boost::system::error_code const& _ec); + + void doRefreshBuckets(boost::system::error_code const& _ec); + +private: + NodeEntry m_node; ///< This node. + Secret m_secret; ///< This nodes secret key. + + mutable Mutex x_nodes; ///< Mutable for thread-safe copy in nodes() const. + std::map> m_nodes; ///< Address -> Node table (most common lookup path) + + Mutex x_state; + std::array m_state; ///< State table of binned nodes. + + Mutex x_evictions; + std::deque m_evictions; ///< Eviction timeouts. + + std::shared_ptr m_socket; ///< Shared pointer for our UDPSocket; ASIO requires shared_ptr. + nodeSocket* m_socketPtr; ///< Set to m_socket.get(). + ba::io_service& m_io; ///< Used by bucket refresh timer. + boost::asio::deadline_timer m_bucketRefreshTimer; ///< Timer which schedules and enacts bucket refresh. + boost::asio::deadline_timer m_evictionCheckTimer; ///< Timer for handling node evictions. +}; + +} +} \ No newline at end of file From 1174c7168dc08be1b574807b499fcc4502f7c135 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 22 Dec 2014 17:24:06 +0100 Subject: [PATCH 019/111] Update evmjit --- evmjit | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/evmjit b/evmjit index 1b490244b..66d5a2b5c 160000 --- a/evmjit +++ b/evmjit @@ -1 +1 @@ -Subproject commit 1b490244bf4864b96448d56a7cd20f3d5b0a0b9b +Subproject commit 66d5a2b5cdf1361dcf0205b191dd12be090ed224 From fd61f9f45280b71b0e272e71587ddd39dfdc7f8d Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 22 Dec 2014 17:24:38 +0100 Subject: [PATCH 020/111] git ignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index c18d5a01d..6fde7ca22 100644 --- a/.gitignore +++ b/.gitignore @@ -64,3 +64,5 @@ profile DerivedData project.pbxproj + +evmjit From d910918492645f17e4f41f00c85fe74c315501c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 23 Dec 2014 00:54:55 +0100 Subject: [PATCH 021/111] Update evmjit submodule. JIT passes all VM & State tests. --- evmjit | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/evmjit b/evmjit index 1b490244b..69930b9bc 160000 --- a/evmjit +++ b/evmjit @@ -1 +1 @@ -Subproject commit 1b490244bf4864b96448d56a7cd20f3d5b0a0b9b +Subproject commit 69930b9bcd27bb46d24890889bc1a4bdb2742271 From 2aa1933b1b9ac7b94231da291a2d8d010bb6a6fc Mon Sep 17 00:00:00 2001 From: wanderer Date: Mon, 22 Dec 2014 23:58:04 -0500 Subject: [PATCH 022/111] added stackUnder Flow test --- test/stInitCodeTestFiller.json | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/test/stInitCodeTestFiller.json b/test/stInitCodeTestFiller.json index 76d8f7957..52f674098 100644 --- a/test/stInitCodeTestFiller.json +++ b/test/stInitCodeTestFiller.json @@ -92,6 +92,36 @@ "value" : "1" } }, + "StackUnderFlowContractCreation" : { + "env" : { + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentDifficulty" : "45678256", + "currentGasLimit" : "1000000", + "currentNumber" : "0", + "currentTimestamp" : 1, + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "pre" : + { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "10000", + "code" : "", + "nonce" : "0", + "storage" : { + } + } + }, + "transaction" : + { + "data" : "0x6000f1", + "gasLimit" : "1000", + "gasPrice" : "1", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "", + "value" : "0" + } + }, "TransactionSuicideInitCode" : { "env" : { From da5acab432b1639a9a58e594e7fadd0af7140391 Mon Sep 17 00:00:00 2001 From: subtly Date: Tue, 23 Dec 2014 08:56:56 +0100 Subject: [PATCH 023/111] refactor constants to be determined during compile. added RLPXDatagram. constructors and updates to datagram constructors. docs and logging. WIP tests and host/harness for NodeTable. --- libp2p/NodeTable.cpp | 91 ++++++++++++------------ libp2p/NodeTable.h | 162 +++++++++++++++++++++++++++++-------------- libp2p/UDP.cpp | 8 ++- libp2p/UDP.h | 46 +++++++++--- test/net.cpp | 71 ++++++++++++++----- 5 files changed, 251 insertions(+), 127 deletions(-) diff --git a/libp2p/NodeTable.cpp b/libp2p/NodeTable.cpp index 0011e0e45..0bc024b03 100644 --- a/libp2p/NodeTable.cpp +++ b/libp2p/NodeTable.cpp @@ -24,18 +24,19 @@ using namespace std; using namespace dev; using namespace dev::p2p; -NodeTable::NodeTable(ba::io_service& _io): - m_node(NodeEntry(Address(), Public(), bi::udp::endpoint())), - m_socket(new nodeSocket(_io, *this, 30300)), - m_socketPtr(m_socket.get()), - m_io(_io), - m_bucketRefreshTimer(m_io), - m_evictionCheckTimer(m_io) - { - for (unsigned i = 0; i < s_bins; i++) - m_state[i].distance = i, m_state[i].modified = chrono::steady_clock::now() - chrono::seconds(1); - doRefreshBuckets(boost::system::error_code()); - } +NodeTable::NodeTable(ba::io_service& _io, uint16_t _port): + m_node(Node(Address(), Public(), bi::udp::endpoint())), + m_socket(new nodeSocket(_io, *this, _port)), + m_socketPtr(m_socket.get()), + m_io(_io), + m_bucketRefreshTimer(m_io), + m_evictionCheckTimer(m_io) +{ + for (unsigned i = 0; i < s_bins; i++) + m_state[i].distance = i, m_state[i].modified = chrono::steady_clock::now() - chrono::seconds(1); + doRefreshBuckets(boost::system::error_code()); + m_socketPtr->connect(); +} NodeTable::~NodeTable() { @@ -44,7 +45,7 @@ NodeTable::~NodeTable() m_socketPtr->disconnect(); } - void NodeTable::join() +void NodeTable::join() { doFindNode(m_node.id); } @@ -66,17 +67,14 @@ NodeTable::NodeEntry NodeTable::operator[](Address _id) void NodeTable::requestNeighbors(NodeEntry const& _node, Address _target) const { - FindNeighbors p; - p.target = _target; - - p.to = _node.endpoint.udp; - p.seal(m_secret); + FindNode p(_node.endpoint.udp, _target); + p.sign(m_secret); m_socketPtr->send(p); } void NodeTable::doFindNode(Address _node, unsigned _round, std::shared_ptr>> _tried) { - if (!m_socketPtr->isOpen() || _round == 7) + if (!m_socketPtr->isOpen() || _round == s_maxSteps) return; auto nearest = findNearest(_node); @@ -84,20 +82,27 @@ void NodeTable::doFindNode(Address _node, unsigned _round, std::shared_ptrcount(nearest[i])) { - tried.push_back(nearest[i]); - requestNeighbors(*nearest[i], _node); + auto r = nearest[i]; + tried.push_back(r); + FindNode p(r->endpoint.udp, _node); + p.sign(m_secret); + m_socketPtr->send(p); } - else - continue; - while (auto n = tried.front()) + if (tried.empty()) { - _tried->insert(n); + clog(NodeTableWarn) << "Terminating doFindNode after " << _round << " rounds."; + return; + } + + while (!tried.empty()) + { + _tried->insert(tried.front()); tried.pop_front(); } auto self(shared_from_this()); - m_evictionCheckTimer.expires_from_now(boost::posix_time::milliseconds(s_findTimout)); + m_evictionCheckTimer.expires_from_now(boost::posix_time::milliseconds(c_reqTimeout.count())); m_evictionCheckTimer.async_wait([this, self, _node, _round, _tried](boost::system::error_code const& _ec) { if (_ec) @@ -108,15 +113,16 @@ void NodeTable::doFindNode(Address _node, unsigned _round, std::shared_ptr> NodeTable::findNearest(Address _target) { - // send s_alpha FindNeighbors packets to nodes we know, closest to target + // send s_alpha FindNode packets to nodes we know, closest to target unsigned head = dist(m_node.id, _target); - unsigned tail = (head - 1) % (s_bits - 1); + unsigned tail = (head - 1) % s_bins; // todo: optimize with tree std::map>> found; unsigned count = 0; // if d is 0, then we roll look forward, if last, we reverse, else, spread from d +#pragma warning TODO: This should probably be s_bins instead of s_bits. if (head != 0 && tail != s_bits) while (head != tail && count < s_bucketSize) { @@ -140,7 +146,7 @@ std::vector> NodeTable::findNearest(Addres break; } head++; - tail = (tail - 1) % (s_bits - 1); + tail = (tail - 1) % s_bins; } else if (head == 0) while (head < s_bucketSize && count < s_bucketSize) @@ -156,7 +162,7 @@ std::vector> NodeTable::findNearest(Addres } head--; } - else if (tail == s_bits - 1) + else if (tail == s_bins) while (tail > 0 && count < s_bucketSize) { Guard l(x_state); @@ -178,21 +184,17 @@ std::vector> NodeTable::findNearest(Addres return std::move(ret); } -void NodeTable::ping(bi::address _address, unsigned _port) const +void NodeTable::ping(bi::udp::endpoint _to) const { - PingNode p; - string ip = m_node.endpoint.udp.address().to_string(); - p.ipAddress = asBytes(ip); - p.port = m_node.endpoint.udp.port(); -// p.expiration; - p.seal(m_secret); + PingNode p(_to, m_node.endpoint.udp.address().to_string(), m_node.endpoint.udp.port()); + p.sign(m_secret); m_socketPtr->send(p); } void NodeTable::ping(NodeEntry* _n) const { - if (_n && _n->endpoint.udp.address().is_v4()) - ping(_n->endpoint.udp.address(), _n->endpoint.udp.port()); + if (_n) + ping(_n->endpoint.udp); } void NodeTable::evict(std::shared_ptr _leastSeen, std::shared_ptr _new) @@ -279,6 +281,7 @@ void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytes { RLP rlp(_packet); + clog(NodeTableNote) << "Received message from " << _from.address().to_string() << ":" << _from.port(); // whenever a pong is received, first check if it's in m_evictions, if so, remove it Guard l(x_evictions); @@ -289,8 +292,8 @@ void NodeTable::doCheckEvictions(boost::system::error_code const& _ec) if (_ec || !m_socketPtr->isOpen()) return; - m_evictionCheckTimer.expires_from_now(boost::posix_time::milliseconds(s_evictionCheckInterval)); auto self(shared_from_this()); + m_evictionCheckTimer.expires_from_now(boost::posix_time::milliseconds(s_evictionCheckInterval)); m_evictionCheckTimer.async_wait([this, self](boost::system::error_code const& _ec) { if (_ec) @@ -301,7 +304,7 @@ void NodeTable::doCheckEvictions(boost::system::error_code const& _ec) { Guard l(x_evictions); for (auto& e: m_evictions) - if (chrono::steady_clock::now() - e.first.second > chrono::milliseconds(s_pingTimeout)) + if (chrono::steady_clock::now() - e.first.second > c_reqTimeout) { Guard l(x_nodes); drop.push_back(m_nodes[e.second]); @@ -319,7 +322,7 @@ void NodeTable::doCheckEvictions(boost::system::error_code const& _ec) void NodeTable::doRefreshBuckets(boost::system::error_code const& _ec) { - cout << "refreshing buckets" << endl; + clog(NodeTableNote) << "refreshing buckets"; if (_ec) return; @@ -329,7 +332,7 @@ void NodeTable::doRefreshBuckets(boost::system::error_code const& _ec) { Guard l(x_state); for (auto& d: m_state) - if (chrono::steady_clock::now() - d.modified > chrono::seconds(s_bucketRefresh)) + if (chrono::steady_clock::now() - d.modified > c_bucketRefresh) while (!d.nodes.empty()) { auto n = d.nodes.front(); @@ -343,7 +346,7 @@ void NodeTable::doRefreshBuckets(boost::system::error_code const& _ec) } } - unsigned nextRefresh = connected ? (refreshed ? 200 : s_bucketRefresh*1000) : 10000; + unsigned nextRefresh = connected ? (refreshed ? 200 : c_bucketRefresh.count()*1000) : 10000; auto runcb = [this](boost::system::error_code const& error) -> void { doRefreshBuckets(error); }; m_bucketRefreshTimer.expires_from_now(boost::posix_time::milliseconds(nextRefresh)); m_bucketRefreshTimer.async_wait(runcb); diff --git a/libp2p/NodeTable.h b/libp2p/NodeTable.h index 1f15540bf..b29cffe7d 100644 --- a/libp2p/NodeTable.h +++ b/libp2p/NodeTable.h @@ -21,6 +21,7 @@ #pragma once +#include #include #include @@ -42,51 +43,58 @@ namespace p2p * a given bucket which is full, the least-responsive node is pinged. * If the pinged node doesn't respond then it is removed and the new * node is inserted. + * + * @todo uint128_t for ip address (<->integer ipv4/6, asio-address, asio-endpoint) + * */ -struct PingNode: RLPDatagram +struct PingNode: RLPXDatagram { - bytes ipAddress; + using RLPXDatagram::RLPXDatagram; + PingNode(bi::udp::endpoint _to, std::string _src, uint16_t _srcPort, std::chrono::seconds _expiration = std::chrono::seconds(60)): RLPXDatagram(_to), ipAddress(_src), port(_srcPort), expiration(fromNow(_expiration)) {} + + std::string ipAddress; uint16_t port; uint64_t expiration; - Signature signature; - void streamRLP(RLPStream& _s) const { _s.appendList(3); _s << ipAddress << port << expiration; } }; -struct Pong: RLPDatagram +struct Pong: RLPXDatagram { - // todo: weak-signed pong - Address from; - uint64_t replyTo; /// expiration from PingNode + using RLPXDatagram::RLPXDatagram; + + h256 replyTo; /// TBD - void streamRLP(RLPStream& _s) const { _s.appendList(2); _s << from << replyTo; } + void streamRLP(RLPStream& _s) const { _s.appendList(1); _s << replyTo; } }; /** - * FindNeighbors Packet: Request k-nodes, closest to the target. - * FindNeighbors is cached and regenerated after expiration - t, where t is timeout. + * FindNode Packet: Request k-nodes, closest to the target. + * FindNode is cached and regenerated after expiration - t, where t is timeout. + * FindNode implicitly results in finding neighbors of a given node. * - * signature: Signature of message. * target: Address of NodeId. The responding node will send back nodes closest to the target. * expiration: Triggers regeneration of packet. May also provide control over synchronization. * */ -struct FindNeighbors: RLPDatagram +struct FindNode: RLPXDatagram { + using RLPXDatagram::RLPXDatagram; + FindNode(bi::udp::endpoint _to, Address _target, std::chrono::seconds _expiration = std::chrono::seconds(30)): RLPXDatagram(_to), target(_target), expiration(fromNow(_expiration)) {} + h160 target; uint64_t expiration; - - Signature signature; - + void streamRLP(RLPStream& _s) const { _s.appendList(2); _s << target << expiration; } }; /** - * Node Packet: Multiple node packets are sent in response to FindNeighbors. + * Node Packet: Multiple node packets are sent in response to FindNode. */ -struct Neighbors: RLPDatagram +struct Neighbors: RLPXDatagram { + using RLPXDatagram::RLPXDatagram; + struct Node { bytes ipAddress; @@ -110,31 +118,32 @@ struct Neighbors: RLPDatagram * Thread-safety is ensured by modifying NodeEntry details via * shared_ptr replacement instead of mutating values. * - * @todo don't try to evict node if node isRequired. (support for makeRequired) - * @todo optimize (use tree for state (or set w/custom compare for cache)) + * [Interface] * @todo constructor support for m_node, m_secret - * @todo use s_bitsPerStep for find and refresh/ping - * @todo exclude bucket from refresh if we have node as peer + * @todo don't try to evict node if node isRequired. (support for makeRequired) + * @todo exclude bucket from refresh if we have node as peer (support for makeRequired) * @todo restore nodes + * @todo std::shared_ptr m_cachedPingPacket; + * @todo std::shared_ptr m_cachedFindSelfPacket; + * + * [Networking] + * @todo use eth/stun/ice/whatever for public-discovery + * + * [Protocol] + * @todo optimize knowledge at opposite edges; eg, s_bitsPerStep lookups. (Can be done via pointers to NodeBucket) + * @todo ^ s_bitsPerStep = 5; // Denoted by b in [Kademlia]. Bits by which address space is divided. + * @todo optimize (use tree for state and/or custom compare for cache) + * @todo reputation (aka universal siblings lists) + * @todo dht (aka siblings) + * + * [Maintenance] + * @todo pretty logs */ class NodeTable: UDPSocketEvents, public std::enable_shared_from_this { - using nodeSocket = UDPSocket; + using nodeSocket = UDPSocket; using timePoint = std::chrono::steady_clock::time_point; - - static unsigned const s_bucketSize = 16; // Denoted by k in [Kademlia]. Number of nodes stored in each bucket. -// const unsigned s_bitsPerStep = 5; // @todo Denoted by b in [Kademlia]. Bits by which address space will be divided for find responses. - static unsigned const s_alpha = 3; // Denoted by \alpha in [Kademlia]. Number of concurrent FindNeighbors requests. - const unsigned s_findTimout = 300; // How long to wait between find queries. -// const unsigned s_siblings = 5; // @todo Denoted by s in [S/Kademlia]. User-defined by sub-protocols. - const unsigned s_bucketRefresh = 3600; // Refresh interval prevents bucket from becoming stale. [Kademlia] - static unsigned const s_bits = 8 * Address::size; // Denoted by n. - static unsigned const s_bins = s_bits - 1; // - const unsigned s_evictionCheckInterval = 75; // Interval by which eviction timeouts are checked. - const unsigned s_pingTimeout = 500; - -public: - static unsigned dist(Address const& _a, Address const& _b) { u160 d = _a ^ _b; unsigned ret; for (ret = 0; d >>= 1; ++ret) {}; return ret; } + using EvictionTimeout = std::pair,Address>; struct NodeDefaultEndpoint { @@ -142,16 +151,29 @@ public: bi::udp::endpoint udp; }; - struct NodeEntry + struct Node { - NodeEntry(Address _id, Public _pubk, bi::udp::endpoint _udp): id(_id), pubk(_pubk), endpoint(NodeDefaultEndpoint(_udp)), distance(0) {} - NodeEntry(NodeEntry _src, Address _id, Public _pubk, bi::udp::endpoint _udp): id(_id), pubk(_pubk), endpoint(NodeDefaultEndpoint(_udp)), distance(dist(_src.id,_id)) {} - NodeEntry(NodeEntry _src, Address _id, Public _pubk, NodeDefaultEndpoint _gw): id(_id), pubk(_pubk), endpoint(_gw), distance(dist(_src.id,_id)) {} + Node(Address _id, Public _pubk, NodeDefaultEndpoint _udp): id(_id), pubk(_pubk), endpoint(_udp) {} + Node(Address _id, Public _pubk, bi::udp::endpoint _udp): Node(_id, _pubk, NodeDefaultEndpoint(_udp)) {} + + virtual Address const& address() const { return id; } + virtual Public const& publicKey() const { return pubk; } + Address id; Public pubk; - NodeDefaultEndpoint endpoint; ///< How we've previously connected to this node. (must match node's reported endpoint) - const unsigned distance; - timePoint activePing; + NodeDefaultEndpoint endpoint; + }; + + /** + * NodeEntry + * @todo Type of id will become template parameter. + */ + struct NodeEntry: public Node + { + NodeEntry(Node _src, Address _id, Public _pubk, NodeDefaultEndpoint _gw): Node(_id, _pubk, _gw), distance(dist(_src.id,_id)) {} + NodeEntry(Node _src, Address _id, Public _pubk, bi::udp::endpoint _udp): Node(_id, _pubk, NodeDefaultEndpoint(_udp)), distance(dist(_src.id,_id)) {} + + const unsigned distance; ///< Node's distance from _src (see constructor). }; struct NodeBucket @@ -161,9 +183,30 @@ public: std::list> nodes; }; - using EvictionTimeout = std::pair,Address>; +public: + + /// Constants for Kademlia, mostly derived from address space. + + static constexpr unsigned s_addressByteSize = sizeof(NodeEntry::id); ///< Size of address type in bytes. + static constexpr unsigned s_bits = 8 * s_addressByteSize; ///< Denoted by n in [Kademlia]. + static constexpr unsigned s_bins = s_bits - 1; ///< Size of m_state (excludes root, which is us). + static constexpr unsigned s_maxSteps = boost::static_log2::value; ///< Max iterations of discovery. (doFindNode) + + /// Chosen constants + + static constexpr unsigned s_bucketSize = 16; ///< Denoted by k in [Kademlia]. Number of nodes stored in each bucket. + static constexpr unsigned s_alpha = 3; ///< Denoted by \alpha in [Kademlia]. Number of concurrent FindNode requests. + static constexpr uint16_t s_defaultPort = 30300; ///< Default port to listen on. + + /// Intervals + + static constexpr unsigned s_evictionCheckInterval = 75; ///< Interval at which eviction timeouts are checked. + std::chrono::milliseconds const c_reqTimeout = std::chrono::milliseconds(300); ///< How long to wait for requests (evict, find iterations). + std::chrono::seconds const c_bucketRefresh = std::chrono::seconds(3600); ///< Refresh interval prevents bucket from becoming stale. [Kademlia] + + static unsigned dist(Address const& _a, Address const& _b) { u160 d = _a ^ _b; unsigned ret; for (ret = 0; d >>= 1; ++ret) {}; return ret; } - NodeTable(ba::io_service& _io); + NodeTable(ba::io_service& _io, uint16_t _port = s_defaultPort); ~NodeTable(); void join(); @@ -173,14 +216,13 @@ public: NodeEntry operator[](Address _id); protected: - void requestNeighbors(NodeEntry const& _node, Address _target) const; - - /// Sends requests to other nodes requesting nodes "near" to us in order to populate node table such that connected nodes form centrality. + /// Repeatedly sends s_alpha concurrent requests to nodes nearest to target, for nodes nearest to target, up to . void doFindNode(Address _node, unsigned _round = 0, std::shared_ptr>> _tried = std::shared_ptr>>()); + /// Returns nodes nearest to target. std::vector> findNearest(Address _target); - void ping(bi::address _address, unsigned _port) const; + void ping(bi::udp::endpoint _to) const; void ping(NodeEntry* _n) const; @@ -194,16 +236,27 @@ protected: NodeBucket const& bucket(NodeEntry* _n) const; + /// Network Events + void onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytesConstRef _packet); void onDisconnected(UDPSocketFace*) {}; + /// Tasks + void doCheckEvictions(boost::system::error_code const& _ec); void doRefreshBuckets(boost::system::error_code const& _ec); - + +#ifndef BOOST_AUTO_TEST_SUITE private: - NodeEntry m_node; ///< This node. +#else +protected: +#endif + /// Sends s_alpha concurrent FindNeighbor requests to nodes closest to target until + void requestNeighbors(NodeEntry const& _node, Address _target) const; + + Node m_node; ///< This node. Secret m_secret; ///< This nodes secret key. mutable Mutex x_nodes; ///< Mutable for thread-safe copy in nodes() const. @@ -215,12 +268,15 @@ private: Mutex x_evictions; std::deque m_evictions; ///< Eviction timeouts. - std::shared_ptr m_socket; ///< Shared pointer for our UDPSocket; ASIO requires shared_ptr. + std::shared_ptr m_socket; ///< Shared pointer for our UDPSocket; ASIO requires shared_ptr. nodeSocket* m_socketPtr; ///< Set to m_socket.get(). ba::io_service& m_io; ///< Used by bucket refresh timer. boost::asio::deadline_timer m_bucketRefreshTimer; ///< Timer which schedules and enacts bucket refresh. boost::asio::deadline_timer m_evictionCheckTimer; ///< Timer for handling node evictions. }; + +struct NodeTableWarn: public LogChannel { static const char* name() { return "!P!"; } static const int verbosity = 0; }; +struct NodeTableNote: public LogChannel { static const char* name() { return "*P*"; } static const int verbosity = 1; }; } } \ No newline at end of file diff --git a/libp2p/UDP.cpp b/libp2p/UDP.cpp index a398eb1fa..9af74c10f 100644 --- a/libp2p/UDP.cpp +++ b/libp2p/UDP.cpp @@ -23,13 +23,15 @@ using namespace dev; using namespace dev::p2p; -void RLPDatagram::seal(Secret const& _k) +h256 RLPXDatagram::sign(Secret const& _k) { RLPStream packet; streamRLP(packet); bytes b(packet.out()); - Signature sig = dev::sign(_k, dev::sha3(b)); + h256 h(dev::sha3(b)); + Signature sig = dev::sign(_k, h); data.resize(data.size() + Signature::size); sig.ref().copyTo(&data); - memcpy(data.data()+sizeof(Signature),b.data(),b.size()); + memcpy(data.data() + sizeof(Signature), b.data(), b.size()); + return std::move(h); } diff --git a/libp2p/UDP.h b/libp2p/UDP.h index 0f4499c84..878c21906 100644 --- a/libp2p/UDP.h +++ b/libp2p/UDP.h @@ -38,27 +38,49 @@ namespace dev namespace p2p { -struct UDPDatagram +/** + * UDP Datagram + * @todo make data private + */ +class UDPDatagram { - UDPDatagram() = default; - UDPDatagram(bi::udp::endpoint _ep, bytes _data): to(_ep), data(std::move(_data)) {} - bi::udp::endpoint to; +public: + UDPDatagram(bi::udp::endpoint _ep): locus(_ep) {} + UDPDatagram(bi::udp::endpoint _ep, bytes _data): data(_data), locus(_ep) {} + bi::udp::endpoint const& endpoint() const { return locus; } + bytes data; +protected: + bi::udp::endpoint locus; }; -struct RLPDatagram: UDPDatagram +/** + * @brief RLPX Datagram which can be signed. + */ +struct RLPXDatagram: public UDPDatagram { - virtual void seal(Secret const& _k); -protected: - virtual void streamRLP(RLPStream& _s) const {}; + static uint64_t fromNow(std::chrono::milliseconds _ms) { return std::chrono::duration_cast((std::chrono::system_clock::now() + _ms).time_since_epoch()).count(); } + static uint64_t fromNow(std::chrono::seconds _sec) { return std::chrono::duration_cast((std::chrono::system_clock::now() + _sec).time_since_epoch()).count(); } + + RLPXDatagram(bi::udp::endpoint _ep): UDPDatagram(_ep) {} + + virtual h256 sign(Secret const& _from); + virtual void streamRLP(RLPStream&) const = 0; + Signature signature; }; +/** + * @brief Interface which UDPSocket will implement. + */ struct UDPSocketFace { virtual bool send(UDPDatagram const& _msg) = 0; virtual void disconnect() = 0; }; +/** + * @brief Interface which a UDPSocket's owner must implement. + */ struct UDPSocketEvents { virtual void onDisconnected(UDPSocketFace*) {}; @@ -68,6 +90,9 @@ struct UDPSocketEvents /** * @brief UDP Interface * Handler must implement UDPSocketEvents. + * + * @todo multiple endpoints (we cannot advertise 0.0.0.0) + * @todo decouple deque from UDPDatagram and add ref() to datagram for fire&forget */ template class UDPSocket: UDPSocketFace, public std::enable_shared_from_this> @@ -76,7 +101,6 @@ public: static constexpr unsigned maxDatagramSize = MaxDatagramSize; static_assert(maxDatagramSize < 65507, "UDP datagrams cannot be larger than 65507 bytes"); - /// Construct open socket to endpoint. UDPSocket(ba::io_service& _io, UDPSocketEvents& _host, unsigned _port): m_host(_host), m_endpoint(bi::udp::v4(), _port), m_socket(_io) { m_started.store(false); m_closed.store(true); }; virtual ~UDPSocket() { disconnect(); } @@ -142,6 +166,7 @@ bool UDPSocket::send(UDPDatagram const& _datagram) Guard l(x_sendQ); sendQ.push_back(_datagram); + clog(NoteChannel) << "qued datagram"; if (sendQ.size() == 1) doWrite(); @@ -169,7 +194,7 @@ void UDPSocket::doWrite() { const UDPDatagram& datagram = sendQ[0]; auto self(UDPSocket::shared_from_this()); - m_socket.async_send_to(boost::asio::buffer(datagram.data), datagram.to, [this, self](boost::system::error_code _ec, std::size_t) + m_socket.async_send_to(boost::asio::buffer(datagram.data), datagram.endpoint(), [this, self](boost::system::error_code _ec, std::size_t) { if (_ec) return disconnectWithError(_ec); @@ -180,6 +205,7 @@ void UDPSocket::doWrite() if (sendQ.empty()) return; } + clog(NoteChannel) << "sent datagram"; doWrite(); }); } diff --git a/test/net.cpp b/test/net.cpp index 3d2e08eb6..886e17a47 100644 --- a/test/net.cpp +++ b/test/net.cpp @@ -30,6 +30,8 @@ using namespace dev::p2p; namespace ba = boost::asio; namespace bi = ba::ip; +BOOST_AUTO_TEST_SUITE(p2p) + /** * Only used for testing. Not useful beyond tests. */ @@ -37,7 +39,7 @@ class TestHost: public Worker { public: TestHost(): Worker("test",0), m_io() {}; - ~TestHost() { m_io.stop(); stopWorking(); } + virtual ~TestHost() { m_io.stop(); stopWorking(); } void start() { startWorking(); } void doWork() { m_io.run(); } @@ -45,28 +47,62 @@ protected: ba::io_service m_io; }; +struct TestNodeTable: public NodeTable +{ + void generateTestNodes(int _count = 10) + { + asserts(_count < 1000); + static uint16_t s_basePort = 30500; + + m_testNodes.clear(); + for (auto i = 0; i < _count; i++) + m_testNodes.push_back(make_pair(KeyPair::create(),s_basePort++)); + } + std::vector> m_testNodes; // keypair and port + + /// Constructor + using NodeTable::NodeTable; + + void setup() + { + /// Phase 1 test: populate with pings + /// Phase 2 test: pre-populate *expected* ping-responses, send pings + + bi::address ourIp = bi::address::from_string("127.0.0.1"); + uint16_t ourPort = 30300; + bi::udp::endpoint ourEndpoint(ourIp, ourPort); + + generateTestNodes(); + for (auto& n: m_testNodes) + ping(bi::udp::endpoint(ourIp, n.second)); + + // wait 1ms between each send + // send PingNode for each s_bootstrapNodes + // wait until nodecount is s_testNodes.count() + + } + + void reset() + { + Guard l(x_state); + for (auto& n: m_state) n.nodes.clear(); + } +}; + /** * Only used for testing. Not useful beyond tests. */ -class TestNodeHost: public TestHost +struct TestNodeTableHost: public TestHost { -public: - TestNodeHost(): m_nodes(m_io) {}; - ~TestNodeHost() { m_io.stop(); stopWorking(); } - void start() { startWorking(); } - void doWork() { m_io.run(); } - - NodeTable m_nodes; + TestNodeTableHost(): nodeTable(new TestNodeTable(m_io)) {}; + shared_ptr nodeTable; }; class TestUDPSocket: UDPSocketEvents, public TestHost { public: TestUDPSocket(): m_socket(new UDPSocket(m_io, *this, 30300)) {} - ~TestUDPSocket() { m_io.stop(); stopWorking(); } - void start() { startWorking(); } - void doWork() { m_io.run(); } - + void onDisconnected(UDPSocketFace*) {}; void onReceived(UDPSocketFace*, bi::udp::endpoint const&, bytesConstRef _packet) { if (_packet.toString() == "AAAA") success = true; } @@ -75,12 +111,13 @@ public: bool success = false; }; -BOOST_AUTO_TEST_SUITE(p2p) - BOOST_AUTO_TEST_CASE(kademlia) { - TestNodeHost nodeHost; - +// TestNodeTableHost node; +// node.start(); +// node.nodeTable->join(); // ideally, joining with empty node table logs warning we can check for +// node.nodeTable->setup(); +// sleep(1); } BOOST_AUTO_TEST_CASE(test_txrx_one) From 2a1ea35f7fb770e24ae7d0a3132ec4a0e0c8ea9a Mon Sep 17 00:00:00 2001 From: subtly Date: Tue, 23 Dec 2014 09:25:36 +0100 Subject: [PATCH 024/111] send/receive messages (not yet interepreted) --- libp2p/NodeTable.cpp | 13 ++++++----- libp2p/NodeTable.h | 14 ++++++------ libp2p/UDP.h | 1 - test/net.cpp | 52 +++++++++++++++++++++++++++----------------- 4 files changed, 46 insertions(+), 34 deletions(-) diff --git a/libp2p/NodeTable.cpp b/libp2p/NodeTable.cpp index 0bc024b03..b3c31b56b 100644 --- a/libp2p/NodeTable.cpp +++ b/libp2p/NodeTable.cpp @@ -24,9 +24,10 @@ using namespace std; using namespace dev; using namespace dev::p2p; -NodeTable::NodeTable(ba::io_service& _io, uint16_t _port): - m_node(Node(Address(), Public(), bi::udp::endpoint())), - m_socket(new nodeSocket(_io, *this, _port)), +NodeTable::NodeTable(ba::io_service& _io, KeyPair _alias, uint16_t _listenPort): + m_node(Node(_alias.address(), _alias.pub(), bi::udp::endpoint())), + m_secret(_alias.sec()), + m_socket(new NodeSocket(_io, *this, _listenPort)), m_socketPtr(m_socket.get()), m_io(_io), m_bucketRefreshTimer(m_io), @@ -281,7 +282,7 @@ void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytes { RLP rlp(_packet); - clog(NodeTableNote) << "Received message from " << _from.address().to_string() << ":" << _from.port(); + clog(NodeTableNote) << "Received X from " << _from.address().to_string() << ":" << _from.port(); // whenever a pong is received, first check if it's in m_evictions, if so, remove it Guard l(x_evictions); @@ -322,10 +323,10 @@ void NodeTable::doCheckEvictions(boost::system::error_code const& _ec) void NodeTable::doRefreshBuckets(boost::system::error_code const& _ec) { - clog(NodeTableNote) << "refreshing buckets"; if (_ec) return; - + + clog(NodeTableNote) << "refreshing buckets"; bool connected = m_socketPtr->isOpen(); bool refreshed = false; if (connected) diff --git a/libp2p/NodeTable.h b/libp2p/NodeTable.h index b29cffe7d..a27811b0b 100644 --- a/libp2p/NodeTable.h +++ b/libp2p/NodeTable.h @@ -141,9 +141,9 @@ struct Neighbors: RLPXDatagram */ class NodeTable: UDPSocketEvents, public std::enable_shared_from_this { - using nodeSocket = UDPSocket; - using timePoint = std::chrono::steady_clock::time_point; - using EvictionTimeout = std::pair,Address>; + using NodeSocket = UDPSocket; + using TimePoint = std::chrono::steady_clock::time_point; + using EvictionTimeout = std::pair,Address>; struct NodeDefaultEndpoint { @@ -179,7 +179,7 @@ class NodeTable: UDPSocketEvents, public std::enable_shared_from_this struct NodeBucket { unsigned distance; - timePoint modified; + TimePoint modified; std::list> nodes; }; @@ -206,7 +206,7 @@ public: static unsigned dist(Address const& _a, Address const& _b) { u160 d = _a ^ _b; unsigned ret; for (ret = 0; d >>= 1; ++ret) {}; return ret; } - NodeTable(ba::io_service& _io, uint16_t _port = s_defaultPort); + NodeTable(ba::io_service& _io, KeyPair _alias, uint16_t _port = s_defaultPort); ~NodeTable(); void join(); @@ -268,8 +268,8 @@ protected: Mutex x_evictions; std::deque m_evictions; ///< Eviction timeouts. - std::shared_ptr m_socket; ///< Shared pointer for our UDPSocket; ASIO requires shared_ptr. - nodeSocket* m_socketPtr; ///< Set to m_socket.get(). + std::shared_ptr m_socket; ///< Shared pointer for our UDPSocket; ASIO requires shared_ptr. + NodeSocket* m_socketPtr; ///< Set to m_socket.get(). ba::io_service& m_io; ///< Used by bucket refresh timer. boost::asio::deadline_timer m_bucketRefreshTimer; ///< Timer which schedules and enacts bucket refresh. boost::asio::deadline_timer m_evictionCheckTimer; ///< Timer for handling node evictions. diff --git a/libp2p/UDP.h b/libp2p/UDP.h index 878c21906..0db491272 100644 --- a/libp2p/UDP.h +++ b/libp2p/UDP.h @@ -166,7 +166,6 @@ bool UDPSocket::send(UDPDatagram const& _datagram) Guard l(x_sendQ); sendQ.push_back(_datagram); - clog(NoteChannel) << "qued datagram"; if (sendQ.size() == 1) doWrite(); diff --git a/test/net.cpp b/test/net.cpp index 886e17a47..d3aaae53d 100644 --- a/test/net.cpp +++ b/test/net.cpp @@ -49,21 +49,10 @@ protected: struct TestNodeTable: public NodeTable { - void generateTestNodes(int _count = 10) - { - asserts(_count < 1000); - static uint16_t s_basePort = 30500; - - m_testNodes.clear(); - for (auto i = 0; i < _count; i++) - m_testNodes.push_back(make_pair(KeyPair::create(),s_basePort++)); - } - std::vector> m_testNodes; // keypair and port - /// Constructor using NodeTable::NodeTable; - void setup() + void setup(std::vector> const& _testNodes) { /// Phase 1 test: populate with pings /// Phase 2 test: pre-populate *expected* ping-responses, send pings @@ -72,8 +61,7 @@ struct TestNodeTable: public NodeTable uint16_t ourPort = 30300; bi::udp::endpoint ourEndpoint(ourIp, ourPort); - generateTestNodes(); - for (auto& n: m_testNodes) + for (auto& n: _testNodes) ping(bi::udp::endpoint(ourIp, n.second)); // wait 1ms between each send @@ -94,8 +82,32 @@ struct TestNodeTable: public NodeTable */ struct TestNodeTableHost: public TestHost { - TestNodeTableHost(): nodeTable(new TestNodeTable(m_io)) {}; + TestNodeTableHost(): m_alias(KeyPair::create()), nodeTable(new TestNodeTable(m_io, m_alias)) {}; + + void generateTestNodes(int _count = 10) + { + asserts(_count < 1000); + static uint16_t s_basePort = 30500; + + m_testNodes.clear(); + for (auto i = 0; i < _count; i++) + { + KeyPair k = KeyPair::create(); + m_testNodes.push_back(make_pair(k,s_basePort+i)); + testNodes.push_back(make_shared(m_io,k,s_basePort+i)); + } + } + std::vector> m_testNodes; // keypair and port + + void setup() + { + generateTestNodes(); + nodeTable->setup(m_testNodes); + } + + KeyPair m_alias; shared_ptr nodeTable; + std::vector> testNodes; }; class TestUDPSocket: UDPSocketEvents, public TestHost @@ -113,11 +125,11 @@ public: BOOST_AUTO_TEST_CASE(kademlia) { -// TestNodeTableHost node; -// node.start(); -// node.nodeTable->join(); // ideally, joining with empty node table logs warning we can check for -// node.nodeTable->setup(); -// sleep(1); + TestNodeTableHost node; + node.start(); + node.nodeTable->join(); // ideally, joining with empty node table logs warning we can check for + node.setup(); + sleep(1); } BOOST_AUTO_TEST_CASE(test_txrx_one) From 82d40b6ff8fb643023afd9ac0d9059dd64e49232 Mon Sep 17 00:00:00 2001 From: subtly Date: Tue, 23 Dec 2014 11:11:07 +0100 Subject: [PATCH 025/111] more implementating of packets --- libp2p/NodeTable.cpp | 47 +++++++++++++++++++++++++++++--- libp2p/NodeTable.h | 65 +++++++++++++++++++++++++++++++++++--------- libp2p/UDP.cpp | 2 +- libp2p/UDP.h | 6 ++-- 4 files changed, 100 insertions(+), 20 deletions(-) diff --git a/libp2p/NodeTable.cpp b/libp2p/NodeTable.cpp index b3c31b56b..c6cf24b71 100644 --- a/libp2p/NodeTable.cpp +++ b/libp2p/NodeTable.cpp @@ -280,12 +280,51 @@ NodeTable::NodeBucket const& NodeTable::bucket(NodeEntry* _n) const void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytesConstRef _packet) { - RLP rlp(_packet); + if (_packet.size() < 69) + { + clog(NodeTableMessageSummary) << "Invalid Message received from " << _from.address().to_string() << ":" << _from.port(); + return; + } - clog(NodeTableNote) << "Received X from " << _from.address().to_string() << ":" << _from.port(); + /// 3 items is PingNode, 2 items w/no lists is FindNode, 2 items w/first item as list is Neighbors, 1 item is Pong + RLP rlp(bytesConstRef(_packet.cropped(65, _packet.size() - 65))); + unsigned itemCount = rlp.itemCount(); - // whenever a pong is received, first check if it's in m_evictions, if so, remove it - Guard l(x_evictions); +// bytesConstRef sig(_packet.cropped(0, 65)); // verify signature (deferred) + + switch (itemCount) { + case 1: + { + clog(NodeTableMessageSummary) << "Received Pong from " << _from.address().to_string() << ":" << _from.port(); + // whenever a pong is received, first check if it's in m_evictions, if so, remove it + Guard l(x_evictions); + break; + } + + case 2: + if (rlp[0].isList()) + { + clog(NodeTableMessageSummary) << "Received Neighbors from " << _from.address().to_string() << ":" << _from.port(); + } + else + { + clog(NodeTableMessageSummary) << "Received FindNode from " << _from.address().to_string() << ":" << _from.port(); + } + break; + + case 3: + { + clog(NodeTableMessageSummary) << "Received PingNode from " << _from.address().to_string() << ":" << _from.port(); + // todo: if we know the node, send a pong. otherwise ignore him. + // let's send a pong! + + break; + } + + default: + clog(NodeTableMessageSummary) << "Invalid Message received from " << _from.address().to_string() << ":" << _from.port(); + return; + } } void NodeTable::doCheckEvictions(boost::system::error_code const& _ec) diff --git a/libp2p/NodeTable.h b/libp2p/NodeTable.h index a27811b0b..36ca0fd7d 100644 --- a/libp2p/NodeTable.h +++ b/libp2p/NodeTable.h @@ -34,6 +34,10 @@ namespace p2p * Ping packet: Check if node is alive. * PingNode is cached and regenerated after expiration - t, where t is timeout. * + * RLP Encoded Items: 3 + * Minimum Encoded Size: 18 bytes + * Maximum Encoded Size: bytes // todo after u128 addresses + * * signature: Signature of message. * ipAddress: Our IP address. * port: Our port. @@ -47,25 +51,39 @@ namespace p2p * @todo uint128_t for ip address (<->integer ipv4/6, asio-address, asio-endpoint) * */ -struct PingNode: RLPXDatagram +struct PingNode: public RLPXDatagram { + friend class NodeTable; using RLPXDatagram::RLPXDatagram; PingNode(bi::udp::endpoint _to, std::string _src, uint16_t _srcPort, std::chrono::seconds _expiration = std::chrono::seconds(60)): RLPXDatagram(_to), ipAddress(_src), port(_srcPort), expiration(fromNow(_expiration)) {} - std::string ipAddress; - uint16_t port; - uint64_t expiration; - + std::string ipAddress; // rlp encoded bytes min: 16 + uint16_t port; // rlp encoded bytes min: 1 max: 3 + uint64_t expiration; // rlp encoded bytes min: 1 max: 9 + +protected: void streamRLP(RLPStream& _s) const { _s.appendList(3); _s << ipAddress << port << expiration; } + void interpretRLP(bytesConstRef _bytes) { RLP r(_bytes); ipAddress = (std::string)r[0]; port = (uint16_t)r[1]; expiration = (uint64_t)r[2]; } }; +/** + * Pong packet: response to ping + * + * RLP Encoded Items: 1 + * Minimum Encoded Size: 33 bytes + * Maximum Encoded Size: 33 bytes + * + * @todo value of replyTo + */ struct Pong: RLPXDatagram { + friend class NodeTable; using RLPXDatagram::RLPXDatagram; - h256 replyTo; /// TBD + h256 replyTo; void streamRLP(RLPStream& _s) const { _s.appendList(1); _s << replyTo; } + void interpretRLP(bytesConstRef _bytes) { RLP r(_bytes); replyTo = (h256)r[0]; } }; /** @@ -73,12 +91,17 @@ struct Pong: RLPXDatagram * FindNode is cached and regenerated after expiration - t, where t is timeout. * FindNode implicitly results in finding neighbors of a given node. * - * target: Address of NodeId. The responding node will send back nodes closest to the target. + * RLP Encoded Items: 2 + * Minimum Encoded Size: 21 bytes + * Maximum Encoded Size: 30 bytes + * + * target: Address of node. The responding node will send back nodes closest to the target. * expiration: Triggers regeneration of packet. May also provide control over synchronization. * */ struct FindNode: RLPXDatagram { + friend class NodeTable; using RLPXDatagram::RLPXDatagram; FindNode(bi::udp::endpoint _to, Address _target, std::chrono::seconds _expiration = std::chrono::seconds(30)): RLPXDatagram(_to), target(_target), expiration(fromNow(_expiration)) {} @@ -86,29 +109,37 @@ struct FindNode: RLPXDatagram uint64_t expiration; void streamRLP(RLPStream& _s) const { _s.appendList(2); _s << target << expiration; } + void interpretRLP(bytesConstRef _bytes) { RLP r(_bytes); target = (h160)r[0]; expiration = (uint64_t)r[1]; } }; /** * Node Packet: Multiple node packets are sent in response to FindNode. + * + * RLP Encoded Items: 2 (first item is list) + * Minimum Encoded Size: 10 bytes + * */ struct Neighbors: RLPXDatagram { + friend class NodeTable; using RLPXDatagram::RLPXDatagram; struct Node { - bytes ipAddress; + Node() = default; + Node(bytesConstRef _bytes) { interpretRLP(_bytes); } + std::string ipAddress; uint16_t port; NodeId node; void streamRLP(RLPStream& _s) const { _s.appendList(3); _s << ipAddress << port << node; } + void interpretRLP(bytesConstRef _bytes) { RLP r(_bytes); ipAddress = r[0].toString(); port = (uint16_t)r[1]; node = (h512)r[2]; } }; - std::set nodes; + std::list nodes; h256 nonce; - - Signature signature; - + void streamRLP(RLPStream& _s) const { _s.appendList(2); _s.appendList(nodes.size()); for (auto& n: nodes) n.streamRLP(_s); _s << nonce; } + void interpretRLP(bytesConstRef _bytes) { RLP r(_bytes); for (auto n: r[0]) nodes.push_back(Node(n.toBytesConstRef())); nonce = (h256)r[1]; } }; /** @@ -274,9 +305,17 @@ protected: boost::asio::deadline_timer m_bucketRefreshTimer; ///< Timer which schedules and enacts bucket refresh. boost::asio::deadline_timer m_evictionCheckTimer; ///< Timer for handling node evictions. }; - + struct NodeTableWarn: public LogChannel { static const char* name() { return "!P!"; } static const int verbosity = 0; }; struct NodeTableNote: public LogChannel { static const char* name() { return "*P*"; } static const int verbosity = 1; }; +struct NodeTableMessageSummary: public LogChannel { static const char* name() { return "-P-"; } static const int verbosity = 2; }; +struct NodeTableConnect: public LogChannel { static const char* name() { return "+P+"; } static const int verbosity = 10; }; +struct NodeTableMessageDetail: public LogChannel { static const char* name() { return "=P="; } static const int verbosity = 5; }; +struct NodeTableTriviaSummary: public LogChannel { static const char* name() { return "-P-"; } static const int verbosity = 10; }; +struct NodeTableTriviaDetail: public LogChannel { static const char* name() { return "=P="; } static const int verbosity = 11; }; +struct NodeTableAllDetail: public LogChannel { static const char* name() { return "=P="; } static const int verbosity = 13; }; +struct NodeTableEgress: public LogChannel { static const char* name() { return ">>P"; } static const int verbosity = 14; }; +struct NodeTableIngress: public LogChannel { static const char* name() { return "<((std::chrono::system_clock::now() + _sec).time_since_epoch()).count(); } RLPXDatagram(bi::udp::endpoint _ep): UDPDatagram(_ep) {} - virtual h256 sign(Secret const& _from); - virtual void streamRLP(RLPStream&) const = 0; + +protected: + virtual void streamRLP(RLPStream&) const =0; + virtual void interpretRLP(bytesConstRef _bytes) =0; Signature signature; }; From c06054f63ed5135cbf13a4ff95ccf055fba8b3e1 Mon Sep 17 00:00:00 2001 From: subtly Date: Tue, 23 Dec 2014 13:44:52 +0100 Subject: [PATCH 026/111] basic implementation of packets --- libp2p/NodeTable.cpp | 79 +++++++++----- libp2p/NodeTable.h | 240 ++++++++++++++++++++++--------------------- libp2p/UDP.cpp | 13 --- libp2p/UDP.h | 37 +++++-- test/net.cpp | 6 -- 5 files changed, 204 insertions(+), 171 deletions(-) diff --git a/libp2p/NodeTable.cpp b/libp2p/NodeTable.cpp index c6cf24b71..6c1a4cda0 100644 --- a/libp2p/NodeTable.cpp +++ b/libp2p/NodeTable.cpp @@ -287,43 +287,66 @@ void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytes } /// 3 items is PingNode, 2 items w/no lists is FindNode, 2 items w/first item as list is Neighbors, 1 item is Pong - RLP rlp(bytesConstRef(_packet.cropped(65, _packet.size() - 65))); + bytesConstRef rlpBytes(_packet.cropped(65, _packet.size() - 65)); + RLP rlp(rlpBytes); unsigned itemCount = rlp.itemCount(); // bytesConstRef sig(_packet.cropped(0, 65)); // verify signature (deferred) - switch (itemCount) { - case 1: - { - clog(NodeTableMessageSummary) << "Received Pong from " << _from.address().to_string() << ":" << _from.port(); - // whenever a pong is received, first check if it's in m_evictions, if so, remove it - Guard l(x_evictions); - break; - } - - case 2: - if (rlp[0].isList()) + try { + switch (itemCount) { + case 1: { - clog(NodeTableMessageSummary) << "Received Neighbors from " << _from.address().to_string() << ":" << _from.port(); + clog(NodeTableMessageSummary) << "Received Pong from " << _from.address().to_string() << ":" << _from.port(); + Pong in = Pong::fromBytesConstRef(_from, rlpBytes); + + // whenever a pong is received, first check if it's in m_evictions, if so, remove it + // otherwise check if we're expecting a pong. if we weren't, blacklist IP for 300 seconds + + break; } - else + + case 2: + if (rlp[0].isList()) + { + clog(NodeTableMessageSummary) << "Received Neighbors from " << _from.address().to_string() << ":" << _from.port(); + Neighbors in = Neighbors::fromBytesConstRef(_from, rlpBytes); + for (auto n: in.nodes) + noteNode(n.node, bi::udp::endpoint(bi::address::from_string(n.ipAddress), n.port)); + } + else + { + clog(NodeTableMessageSummary) << "Received FindNode from " << _from.address().to_string() << ":" << _from.port(); + FindNode in = FindNode::fromBytesConstRef(_from, rlpBytes); + + std::vector> nearest = findNearest(in.target); + Neighbors out(_from, nearest); + out.sign(m_secret); + m_socketPtr->send(out); + } + break; + + case 3: { - clog(NodeTableMessageSummary) << "Received FindNode from " << _from.address().to_string() << ":" << _from.port(); + clog(NodeTableMessageSummary) << "Received PingNode from " << _from.address().to_string() << ":" << _from.port(); + // todo: if we know the node, reply, otherwise ignore. + PingNode in = PingNode::fromBytesConstRef(_from, rlpBytes); + + Pong p(_from); + p.replyTo = sha3(rlpBytes); + p.sign(m_secret); + m_socketPtr->send(p); + break; } - break; - - case 3: - { - clog(NodeTableMessageSummary) << "Received PingNode from " << _from.address().to_string() << ":" << _from.port(); - // todo: if we know the node, send a pong. otherwise ignore him. - // let's send a pong! - - break; + + default: + clog(NodeTableMessageSummary) << "Invalid Message received from " << _from.address().to_string() << ":" << _from.port(); + return; } - - default: - clog(NodeTableMessageSummary) << "Invalid Message received from " << _from.address().to_string() << ":" << _from.port(); - return; + } + catch (...) + { + } } diff --git a/libp2p/NodeTable.h b/libp2p/NodeTable.h index 36ca0fd7d..a5dd41f07 100644 --- a/libp2p/NodeTable.h +++ b/libp2p/NodeTable.h @@ -30,118 +30,6 @@ namespace dev namespace p2p { -/** - * Ping packet: Check if node is alive. - * PingNode is cached and regenerated after expiration - t, where t is timeout. - * - * RLP Encoded Items: 3 - * Minimum Encoded Size: 18 bytes - * Maximum Encoded Size: bytes // todo after u128 addresses - * - * signature: Signature of message. - * ipAddress: Our IP address. - * port: Our port. - * expiration: Triggers regeneration of packet. May also provide control over synchronization. - * - * Ping is used to implement evict. When a new node is seen for - * a given bucket which is full, the least-responsive node is pinged. - * If the pinged node doesn't respond then it is removed and the new - * node is inserted. - * - * @todo uint128_t for ip address (<->integer ipv4/6, asio-address, asio-endpoint) - * - */ -struct PingNode: public RLPXDatagram -{ - friend class NodeTable; - using RLPXDatagram::RLPXDatagram; - PingNode(bi::udp::endpoint _to, std::string _src, uint16_t _srcPort, std::chrono::seconds _expiration = std::chrono::seconds(60)): RLPXDatagram(_to), ipAddress(_src), port(_srcPort), expiration(fromNow(_expiration)) {} - - std::string ipAddress; // rlp encoded bytes min: 16 - uint16_t port; // rlp encoded bytes min: 1 max: 3 - uint64_t expiration; // rlp encoded bytes min: 1 max: 9 - -protected: - void streamRLP(RLPStream& _s) const { _s.appendList(3); _s << ipAddress << port << expiration; } - void interpretRLP(bytesConstRef _bytes) { RLP r(_bytes); ipAddress = (std::string)r[0]; port = (uint16_t)r[1]; expiration = (uint64_t)r[2]; } -}; - -/** - * Pong packet: response to ping - * - * RLP Encoded Items: 1 - * Minimum Encoded Size: 33 bytes - * Maximum Encoded Size: 33 bytes - * - * @todo value of replyTo - */ -struct Pong: RLPXDatagram -{ - friend class NodeTable; - using RLPXDatagram::RLPXDatagram; - - h256 replyTo; - - void streamRLP(RLPStream& _s) const { _s.appendList(1); _s << replyTo; } - void interpretRLP(bytesConstRef _bytes) { RLP r(_bytes); replyTo = (h256)r[0]; } -}; - -/** - * FindNode Packet: Request k-nodes, closest to the target. - * FindNode is cached and regenerated after expiration - t, where t is timeout. - * FindNode implicitly results in finding neighbors of a given node. - * - * RLP Encoded Items: 2 - * Minimum Encoded Size: 21 bytes - * Maximum Encoded Size: 30 bytes - * - * target: Address of node. The responding node will send back nodes closest to the target. - * expiration: Triggers regeneration of packet. May also provide control over synchronization. - * - */ -struct FindNode: RLPXDatagram -{ - friend class NodeTable; - using RLPXDatagram::RLPXDatagram; - FindNode(bi::udp::endpoint _to, Address _target, std::chrono::seconds _expiration = std::chrono::seconds(30)): RLPXDatagram(_to), target(_target), expiration(fromNow(_expiration)) {} - - h160 target; - uint64_t expiration; - - void streamRLP(RLPStream& _s) const { _s.appendList(2); _s << target << expiration; } - void interpretRLP(bytesConstRef _bytes) { RLP r(_bytes); target = (h160)r[0]; expiration = (uint64_t)r[1]; } -}; - -/** - * Node Packet: Multiple node packets are sent in response to FindNode. - * - * RLP Encoded Items: 2 (first item is list) - * Minimum Encoded Size: 10 bytes - * - */ -struct Neighbors: RLPXDatagram -{ - friend class NodeTable; - using RLPXDatagram::RLPXDatagram; - - struct Node - { - Node() = default; - Node(bytesConstRef _bytes) { interpretRLP(_bytes); } - std::string ipAddress; - uint16_t port; - NodeId node; - void streamRLP(RLPStream& _s) const { _s.appendList(3); _s << ipAddress << port << node; } - void interpretRLP(bytesConstRef _bytes) { RLP r(_bytes); ipAddress = r[0].toString(); port = (uint16_t)r[1]; node = (h512)r[2]; } - }; - - std::list nodes; - h256 nonce; - - void streamRLP(RLPStream& _s) const { _s.appendList(2); _s.appendList(nodes.size()); for (auto& n: nodes) n.streamRLP(_s); _s << nonce; } - void interpretRLP(bytesConstRef _bytes) { RLP r(_bytes); for (auto n: r[0]) nodes.push_back(Node(n.toBytesConstRef())); nonce = (h256)r[1]; } -}; - /** * NodeTable using S/Kademlia system for node discovery and preference. * untouched buckets are refreshed if they have not been touched within an hour @@ -158,20 +46,20 @@ struct Neighbors: RLPXDatagram * @todo std::shared_ptr m_cachedFindSelfPacket; * * [Networking] - * @todo use eth/stun/ice/whatever for public-discovery + * @todo use eth/upnp/natpmp/stun/ice/etc for public-discovery + * @todo firewall * * [Protocol] + * @todo ping newly added nodes for eviction * @todo optimize knowledge at opposite edges; eg, s_bitsPerStep lookups. (Can be done via pointers to NodeBucket) * @todo ^ s_bitsPerStep = 5; // Denoted by b in [Kademlia]. Bits by which address space is divided. * @todo optimize (use tree for state and/or custom compare for cache) * @todo reputation (aka universal siblings lists) * @todo dht (aka siblings) - * - * [Maintenance] - * @todo pretty logs */ class NodeTable: UDPSocketEvents, public std::enable_shared_from_this { + friend struct Neighbors; using NodeSocket = UDPSocket; using TimePoint = std::chrono::steady_clock::time_point; using EvictionTimeout = std::pair,Address>; @@ -305,6 +193,126 @@ protected: boost::asio::deadline_timer m_bucketRefreshTimer; ///< Timer which schedules and enacts bucket refresh. boost::asio::deadline_timer m_evictionCheckTimer; ///< Timer for handling node evictions. }; + +/** + * Ping packet: Check if node is alive. + * PingNode is cached and regenerated after expiration - t, where t is timeout. + * + * RLP Encoded Items: 3 + * Minimum Encoded Size: 18 bytes + * Maximum Encoded Size: bytes // todo after u128 addresses + * + * signature: Signature of message. + * ipAddress: Our IP address. + * port: Our port. + * expiration: Triggers regeneration of packet. May also provide control over synchronization. + * + * Ping is used to implement evict. When a new node is seen for + * a given bucket which is full, the least-responsive node is pinged. + * If the pinged node doesn't respond then it is removed and the new + * node is inserted. + * + * @todo uint128_t for ip address (<->integer ipv4/6, asio-address, asio-endpoint) + * + */ +struct PingNode: RLPXDatagram +{ + using RLPXDatagram::RLPXDatagram; + PingNode(bi::udp::endpoint _ep, std::string _src, uint16_t _srcPort, std::chrono::seconds _expiration = std::chrono::seconds(60)): RLPXDatagram(_ep), ipAddress(_src), port(_srcPort), expiration(futureFromEpoch(_expiration)) {} + + std::string ipAddress; // rlp encoded bytes min: 16 + uint16_t port; // rlp encoded bytes min: 1 max: 3 + uint64_t expiration; // rlp encoded bytes min: 1 max: 9 + + void streamRLP(RLPStream& _s) const { _s.appendList(3); _s << ipAddress << port << expiration; } + void interpretRLP(bytesConstRef _bytes) { RLP r(_bytes); ipAddress = (std::string)r[0]; port = (uint16_t)r[1]; expiration = (uint64_t)r[2]; } +}; + +/** + * Pong packet: response to ping + * + * RLP Encoded Items: 1 + * Minimum Encoded Size: 33 bytes + * Maximum Encoded Size: 33 bytes + * + * @todo value of replyTo + * @todo create from PingNode (reqs RLPXDatagram verify flag) + */ +struct Pong: RLPXDatagram +{ + using RLPXDatagram::RLPXDatagram; + + h256 replyTo; // hash of rlp of PingNode + + void streamRLP(RLPStream& _s) const { _s.appendList(1); _s << replyTo; } + void interpretRLP(bytesConstRef _bytes) { RLP r(_bytes); replyTo = (h256)r[0]; } +}; + +/** + * FindNode Packet: Request k-nodes, closest to the target. + * FindNode is cached and regenerated after expiration - t, where t is timeout. + * FindNode implicitly results in finding neighbors of a given node. + * + * RLP Encoded Items: 2 + * Minimum Encoded Size: 21 bytes + * Maximum Encoded Size: 30 bytes + * + * target: Address of node. The responding node will send back nodes closest to the target. + * expiration: Triggers regeneration of packet. May also provide control over synchronization. + * + */ +struct FindNode: RLPXDatagram +{ + using RLPXDatagram::RLPXDatagram; + FindNode(bi::udp::endpoint _ep, Address _target, std::chrono::seconds _expiration = std::chrono::seconds(30)): RLPXDatagram(_ep), target(_target), expiration(futureFromEpoch(_expiration)) {} + + h160 target; + uint64_t expiration; + + void streamRLP(RLPStream& _s) const { _s.appendList(2); _s << target << expiration; } + void interpretRLP(bytesConstRef _bytes) { RLP r(_bytes); target = (h160)r[0]; expiration = (uint64_t)r[1]; } +}; + +/** + * Node Packet: Multiple node packets are sent in response to FindNode. + * + * RLP Encoded Items: 2 (first item is list) + * Minimum Encoded Size: 10 bytes + * + * @todo nonce + */ +struct Neighbors: RLPXDatagram +{ + struct Node + { + Node() = default; + Node(bytesConstRef _bytes) { interpretRLP(_bytes); } + std::string ipAddress; + uint16_t port; + NodeId node; + void streamRLP(RLPStream& _s) const { _s.appendList(3); _s << ipAddress << port << node; } + void interpretRLP(bytesConstRef _bytes) { RLP r(_bytes); ipAddress = r[0].toString(); port = (uint16_t)r[1]; node = (h512)r[2]; } + }; + + using RLPXDatagram::RLPXDatagram; + Neighbors(bi::udp::endpoint _to, std::vector> const& _nearest): RLPXDatagram(_to), nonce(h256()) + { + for (auto& n: _nearest) + { + Node node; + node.ipAddress = n->endpoint.udp.address().to_string(); + node.port = n->endpoint.udp.port(); + node.node = n->publicKey(); + nodes.push_back(node); + } + } + + std::list nodes; + h256 nonce; + + void streamRLP(RLPStream& _s) const { _s.appendList(2); _s.appendList(nodes.size()); for (auto& n: nodes) n.streamRLP(_s); _s << nonce; } + void interpretRLP(bytesConstRef _bytes) { RLP r(_bytes); for (auto n: r[0]) nodes.push_back(Node(n.toBytesConstRef())); nonce = (h256)r[1]; } +}; struct NodeTableWarn: public LogChannel { static const char* name() { return "!P!"; } static const int verbosity = 0; }; struct NodeTableNote: public LogChannel { static const char* name() { return "*P*"; } static const int verbosity = 1; }; diff --git a/libp2p/UDP.cpp b/libp2p/UDP.cpp index ea5845da7..f98c31e09 100644 --- a/libp2p/UDP.cpp +++ b/libp2p/UDP.cpp @@ -22,16 +22,3 @@ #include "UDP.h" using namespace dev; using namespace dev::p2p; - -h256 RLPXDatagram::sign(Secret const& _k) -{ - RLPStream packet; - streamRLP(packet); - bytes b(packet.out()); - h256 h(dev::sha3(b)); - Signature sig = dev::sign(_k, h); - data.resize(b.size() + Signature::size); - sig.ref().copyTo(&data); - memcpy(data.data() + sizeof(Signature), b.data(), b.size()); - return std::move(h); -} diff --git a/libp2p/UDP.h b/libp2p/UDP.h index ab694fba5..5de8053a0 100644 --- a/libp2p/UDP.h +++ b/libp2p/UDP.h @@ -40,13 +40,13 @@ namespace p2p /** * UDP Datagram - * @todo make data private + * @todo make data protected/functional */ class UDPDatagram { public: - UDPDatagram(bi::udp::endpoint _ep): locus(_ep) {} - UDPDatagram(bi::udp::endpoint _ep, bytes _data): data(_data), locus(_ep) {} + UDPDatagram(bi::udp::endpoint const& _ep): locus(_ep) {} + UDPDatagram(bi::udp::endpoint const& _ep, bytes _data): data(_data), locus(_ep) {} bi::udp::endpoint const& endpoint() const { return locus; } bytes data; @@ -56,20 +56,41 @@ protected: /** * @brief RLPX Datagram which can be signed. + * @todo compact templates + * @todo make data private/functional (see UDPDatagram) + * @todo valid=true/false (based on signature) */ +template struct RLPXDatagram: public UDPDatagram { - static uint64_t fromNow(std::chrono::milliseconds _ms) { return std::chrono::duration_cast((std::chrono::system_clock::now() + _ms).time_since_epoch()).count(); } - static uint64_t fromNow(std::chrono::seconds _sec) { return std::chrono::duration_cast((std::chrono::system_clock::now() + _sec).time_since_epoch()).count(); } - - RLPXDatagram(bi::udp::endpoint _ep): UDPDatagram(_ep) {} + static T fromBytesConstRef(bi::udp::endpoint const& _ep, bytesConstRef _bytes) { T t(_ep); t.interpretRLP(_bytes); return std::move(t); } + static uint64_t futureFromEpoch(std::chrono::milliseconds _ms) { return std::chrono::duration_cast((std::chrono::system_clock::now() + _ms).time_since_epoch()).count(); } + static uint64_t futureFromEpoch(std::chrono::seconds _sec) { return std::chrono::duration_cast((std::chrono::system_clock::now() + _sec).time_since_epoch()).count(); } + + RLPXDatagram(bi::udp::endpoint const& _ep): UDPDatagram(_ep) {} virtual h256 sign(Secret const& _from); -protected: virtual void streamRLP(RLPStream&) const =0; virtual void interpretRLP(bytesConstRef _bytes) =0; + +protected: Signature signature; }; + +template +h256 RLPXDatagram::sign(Secret const& _k) +{ + RLPStream packet; + streamRLP(packet); + bytes b(packet.out()); + h256 h(dev::sha3(b)); + Signature sig = dev::sign(_k, h); + data.resize(b.size() + Signature::size); + sig.ref().copyTo(&data); + memcpy(data.data() + sizeof(Signature), b.data(), b.size()); + return std::move(h); +} + /** * @brief Interface which UDPSocket will implement. diff --git a/test/net.cpp b/test/net.cpp index d3aaae53d..8277c1f70 100644 --- a/test/net.cpp +++ b/test/net.cpp @@ -54,7 +54,6 @@ struct TestNodeTable: public NodeTable void setup(std::vector> const& _testNodes) { - /// Phase 1 test: populate with pings /// Phase 2 test: pre-populate *expected* ping-responses, send pings bi::address ourIp = bi::address::from_string("127.0.0.1"); @@ -63,11 +62,6 @@ struct TestNodeTable: public NodeTable for (auto& n: _testNodes) ping(bi::udp::endpoint(ourIp, n.second)); - - // wait 1ms between each send - // send PingNode for each s_bootstrapNodes - // wait until nodecount is s_testNodes.count() - } void reset() From 74b085efea90dbce18a7320ff05cda0de0bd99d5 Mon Sep 17 00:00:00 2001 From: Joris Bontje Date: Tue, 23 Dec 2014 15:03:57 +0100 Subject: [PATCH 027/111] use Ethereum PPA for cryptopp and jsonrpc dependencies --- docker/Dockerfile | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index c183f03b9..9c76549cb 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -7,6 +7,7 @@ RUN apt-get upgrade -y # Ethereum dependencies RUN apt-get install -qy build-essential g++-4.8 git cmake libboost-all-dev libcurl4-openssl-dev wget RUN apt-get install -qy automake unzip libgmp-dev libtool libleveldb-dev yasm libminiupnpc-dev libreadline-dev scons +RUN apt-get install -qy libjsoncpp-dev libargtable2-dev # NCurses based GUI (not optional though for a succesful compilation, see https://github.com/ethereum/cpp-ethereum/issues/452 ) RUN apt-get install -qy libncurses5-dev @@ -14,15 +15,11 @@ RUN apt-get install -qy libncurses5-dev # Qt-based GUI # RUN apt-get install -qy qtbase5-dev qt5-default qtdeclarative5-dev libqt5webkit5-dev -# Cryptopp -RUN git clone --depth=1 https://github.com/mmoss/cryptopp.git -RUN cd cryptopp && scons --shared --prefix=/usr - -# JSONRPC (version 0.2.1, see https://github.com/ethereum/cpp-ethereum/issues/453 ) -RUN apt-get install -qy libjsoncpp-dev libargtable2-dev -RUN git clone --depth=1 --branch=0.2.1 https://github.com/cinemast/libjson-rpc-cpp.git -RUN mkdir -p libjson-rpc-cpp/build -RUN cd libjson-rpc-cpp/build && cmake .. && make && make install +# Ethereum PPA +RUN apt-get install -qy software-properties-common +RUN add-apt-repository ppa:ethereum/ethereum +RUN apt-get update +RUN apt-get install -qy libcryptopp-dev libjson-rpc-cpp-dev # Build Ethereum (HEADLESS) RUN git clone --depth=1 https://github.com/ethereum/cpp-ethereum From c1d8aa7551792405c856c1814b13ad244c4861f3 Mon Sep 17 00:00:00 2001 From: winsvega Date: Tue, 23 Dec 2014 23:38:44 +0300 Subject: [PATCH 028/111] comments in json --- test/stInitCodeTestFiller.json | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/test/stInitCodeTestFiller.json b/test/stInitCodeTestFiller.json index 55f5567af..501b1ff21 100644 --- a/test/stInitCodeTestFiller.json +++ b/test/stInitCodeTestFiller.json @@ -276,7 +276,7 @@ "095e7baea6a6c7c4c2dfeb977efac326af552d87": { "balance": "1", "nonce": 0, - "comment": "{[[0]] 12 (CREATE 0 64 32)}", + "//": "{[[0]] 12 (CREATE 0 64 32)}", "code": "{(MSTORE 0 0x600c600055602060406000f0)(CREATE 0 20 12)}", "storage": {} }, @@ -315,8 +315,8 @@ "095e7baea6a6c7c4c2dfeb977efac326af552d87": { "balance": "1000", "nonce": 0, - "comment": "(CREATE 0 64 32)", - "comment": "{[[0]] 12 (MSTORE 32 0x602060406000f0)(RETURN 57 7)}", + "//": "(CREATE 0 64 32)", + "//": "{[[0]] 12 (MSTORE 32 0x602060406000f0)(RETURN 57 7)}", "code": "{(MSTORE 0 0x600c60005566602060406000f060205260076039f3)[[0]](CREATE 1 11 21)(CALL 500 (SLOAD 0) 1 0 0 0 0)}", "storage": {} }, @@ -355,8 +355,8 @@ "095e7baea6a6c7c4c2dfeb977efac326af552d87": { "balance": "0", "nonce": 0, - "comment": "(CREATE 0 64 32)", - "comment": "{[[0]] 12 (MSTORE 32 0x602060406000f0)(RETURN 57 7)}", + "//": "(CREATE 0 64 32)", + "//": "{[[0]] 12 (MSTORE 32 0x602060406000f0)(RETURN 57 7)}", "code": "{(MSTORE 0 0x600c60005566602060406000f060205260076039f3)[[0]](CREATE 1 11 21)(CALL 0 (SLOAD 0) 0 0 0 0 0)}", "storage": {} }, @@ -395,8 +395,8 @@ "095e7baea6a6c7c4c2dfeb977efac326af552d87": { "balance": "1000", "nonce": 0, - "comment": "(CREATE 0 64 32)", - "comment": "{[[0]] 12 (MSTORE 32 0x602060406000f0)(RETURN 57 7)}", + "//": "(CREATE 0 64 32)", + "//": "{[[0]] 12 (MSTORE 32 0x602060406000f0)(RETURN 57 7)}", "code": "{(MSTORE 0 0x600c60005566602060406000f060205260076039f3)[[0]](CREATE 1 11 21)(CALL 0 (SLOAD 0) 1 0 0 0 0)}", "storage": {} }, @@ -435,8 +435,8 @@ "095e7baea6a6c7c4c2dfeb977efac326af552d87": { "balance": "1000", "nonce": 0, - "comment": "(CREATE 0 64 32)", - "comment": "{[[0]] 12 (MSTORE 32 0x602060406000f0)(RETURN 57 7)}", + "//": "(CREATE 0 64 32)", + "//": "{[[0]] 12 (MSTORE 32 0x602060406000f0)(RETURN 57 7)}", "code": "{(MSTORE 0 0x600c60005566602060406000f060205260076039f3)[[0]](CREATE 1001 11 21)}", "storage": {} }, From 4216162fc17cf2f2d3092beee28937f940fc1761 Mon Sep 17 00:00:00 2001 From: subtly Date: Wed, 24 Dec 2014 10:22:27 +0100 Subject: [PATCH 029/111] message signing and verification. shutdown io/thread before dealloc in nodetable/testnodetables. --- libp2p/NodeTable.cpp | 65 +++++++++++++++++++++++++++----------------- libp2p/NodeTable.h | 33 +++++++++++++++------- libp2p/UDP.cpp | 21 ++++++++++++++ libp2p/UDP.h | 38 +++++++++++--------------- test/net.cpp | 34 +++++++++++++++++------ 5 files changed, 125 insertions(+), 66 deletions(-) diff --git a/libp2p/NodeTable.cpp b/libp2p/NodeTable.cpp index 6c1a4cda0..3799a4eef 100644 --- a/libp2p/NodeTable.cpp +++ b/libp2p/NodeTable.cpp @@ -45,7 +45,7 @@ NodeTable::~NodeTable() m_bucketRefreshTimer.cancel(); m_socketPtr->disconnect(); } - + void NodeTable::join() { doFindNode(m_node.id); @@ -60,6 +60,16 @@ std::list
NodeTable::nodes() const return std::move(nodes); } +list NodeTable::state() const +{ + list ret; + Guard l(x_state); + for (auto s: m_state) + for (auto n: s.nodes) + ret.push_back(*n.lock()); + return move(ret); +} + NodeTable::NodeEntry NodeTable::operator[](Address _id) { Guard l(x_nodes); @@ -115,17 +125,16 @@ void NodeTable::doFindNode(Address _node, unsigned _round, std::shared_ptr> NodeTable::findNearest(Address _target) { // send s_alpha FindNode packets to nodes we know, closest to target + static unsigned lastBin = s_bins - 1; unsigned head = dist(m_node.id, _target); - unsigned tail = (head - 1) % s_bins; + unsigned tail = head == 0 ? lastBin : (head - 1) % s_bins; - // todo: optimize with tree std::map>> found; unsigned count = 0; // if d is 0, then we roll look forward, if last, we reverse, else, spread from d -#pragma warning TODO: This should probably be s_bins instead of s_bits. - if (head != 0 && tail != s_bits) - while (head != tail && count < s_bucketSize) + if (head > 1 && tail != lastBin) + while (head != tail && head < s_bins && count < s_bucketSize) { Guard l(x_state); for (auto& n: m_state[head].nodes) @@ -137,7 +146,7 @@ std::vector> NodeTable::findNearest(Addres break; } - if (count < s_bucketSize && head) + if (count < s_bucketSize && tail) for (auto& n: m_state[tail].nodes) if (auto p = n.lock()) { @@ -146,11 +155,13 @@ std::vector> NodeTable::findNearest(Addres else break; } + head++; - tail = (tail - 1) % s_bins; + if (tail) + tail--; } - else if (head == 0) - while (head < s_bucketSize && count < s_bucketSize) + else if (head < 2) + while (head < s_bins && count < s_bucketSize) { Guard l(x_state); for (auto& n: m_state[head].nodes) @@ -161,9 +172,9 @@ std::vector> NodeTable::findNearest(Addres else break; } - head--; + head++; } - else if (tail == s_bins) + else while (tail > 0 && count < s_bucketSize) { Guard l(x_state); @@ -221,8 +232,8 @@ void NodeTable::noteNode(Public _pubk, bi::udp::endpoint _endpoint) auto n = m_nodes.find(id); if (n == m_nodes.end()) { - m_nodes[id] = std::shared_ptr(new NodeEntry(m_node, id, _pubk, _endpoint)); - node = m_nodes[id]; + node.reset(new NodeEntry(m_node, id, _pubk, _endpoint)); + m_nodes[id] = node; } else node = n->second; @@ -235,12 +246,11 @@ void NodeTable::noteNode(std::shared_ptr _n) { std::shared_ptr contested; { - NodeBucket s = bucket(_n.get()); + NodeBucket& s = bucket(_n.get()); Guard l(x_state); s.nodes.remove_if([&_n](std::weak_ptr n) { - auto p = n.lock(); - if (!p || p == _n) + if (n.lock() == _n) return true; return false; }); @@ -264,7 +274,7 @@ void NodeTable::noteNode(std::shared_ptr _n) void NodeTable::dropNode(std::shared_ptr _n) { - NodeBucket s = bucket(_n.get()); + NodeBucket &s = bucket(_n.get()); { Guard l(x_state); s.nodes.remove_if([&_n](std::weak_ptr n) { return n.lock() == _n; }); @@ -273,9 +283,9 @@ void NodeTable::dropNode(std::shared_ptr _n) m_nodes.erase(_n->id); } -NodeTable::NodeBucket const& NodeTable::bucket(NodeEntry* _n) const +NodeTable::NodeBucket& NodeTable::bucket(NodeEntry const* _n) { - return m_state[_n->distance]; + return m_state[_n->distance - 1]; } void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytesConstRef _packet) @@ -286,12 +296,19 @@ void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytes return; } - /// 3 items is PingNode, 2 items w/no lists is FindNode, 2 items w/first item as list is Neighbors, 1 item is Pong + // 3 items is PingNode, 2 items w/no lists is FindNode, 2 items w/first item as list is Neighbors, 1 item is Pong bytesConstRef rlpBytes(_packet.cropped(65, _packet.size() - 65)); RLP rlp(rlpBytes); unsigned itemCount = rlp.itemCount(); -// bytesConstRef sig(_packet.cropped(0, 65)); // verify signature (deferred) + bytesConstRef sigBytes(_packet.cropped(0, 65)); + Public nodeid(dev::recover(*(Signature const*)sigBytes.data(), sha3(rlpBytes))); + if (!nodeid) + { + clog(NodeTableMessageSummary) << "Invalid Message Signature from " << _from.address().to_string() << ":" << _from.port(); + return; + } + noteNode(nodeid, _from); try { switch (itemCount) { @@ -300,8 +317,7 @@ void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytes clog(NodeTableMessageSummary) << "Received Pong from " << _from.address().to_string() << ":" << _from.port(); Pong in = Pong::fromBytesConstRef(_from, rlpBytes); - // whenever a pong is received, first check if it's in m_evictions, if so, remove it - // otherwise check if we're expecting a pong. if we weren't, blacklist IP for 300 seconds + // whenever a pong is received, first check if it's in m_evictions break; } @@ -329,7 +345,6 @@ void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytes case 3: { clog(NodeTableMessageSummary) << "Received PingNode from " << _from.address().to_string() << ":" << _from.port(); - // todo: if we know the node, reply, otherwise ignore. PingNode in = PingNode::fromBytesConstRef(_from, rlpBytes); Pong p(_from); diff --git a/libp2p/NodeTable.h b/libp2p/NodeTable.h index a5dd41f07..89456b4fd 100644 --- a/libp2p/NodeTable.h +++ b/libp2p/NodeTable.h @@ -38,19 +38,20 @@ namespace p2p * shared_ptr replacement instead of mutating values. * * [Interface] - * @todo constructor support for m_node, m_secret - * @todo don't try to evict node if node isRequired. (support for makeRequired) - * @todo exclude bucket from refresh if we have node as peer (support for makeRequired) - * @todo restore nodes + * @todo restore nodes: affects refreshbuckets + * @todo TCP endpoints + * @todo makeRequired: don't try to evict node if node isRequired. + * @todo makeRequired: exclude bucket from refresh if we have node as peer. * @todo std::shared_ptr m_cachedPingPacket; * @todo std::shared_ptr m_cachedFindSelfPacket; * * [Networking] - * @todo use eth/upnp/natpmp/stun/ice/etc for public-discovery + * @todo TCP endpoints + * @todo eth/upnp/natpmp/stun/ice/etc for public-discovery * @todo firewall * * [Protocol] - * @todo ping newly added nodes for eviction + * @todo post-eviction pong * @todo optimize knowledge at opposite edges; eg, s_bitsPerStep lookups. (Can be done via pointers to NodeBucket) * @todo ^ s_bitsPerStep = 5; // Denoted by b in [Kademlia]. Bits by which address space is divided. * @todo optimize (use tree for state and/or custom compare for cache) @@ -130,10 +131,13 @@ public: void join(); + NodeEntry root() const { return NodeEntry(m_node, m_node.address(), m_node.publicKey(), m_node.endpoint.udp); } std::list
nodes() const; + std::list state() const; NodeEntry operator[](Address _id); + protected: /// Repeatedly sends s_alpha concurrent requests to nodes nearest to target, for nodes nearest to target, up to . void doFindNode(Address _node, unsigned _round = 0, std::shared_ptr>> _tried = std::shared_ptr>>()); @@ -153,9 +157,9 @@ protected: void dropNode(std::shared_ptr _n); - NodeBucket const& bucket(NodeEntry* _n) const; - - /// Network Events + NodeBucket& bucket(NodeEntry const* _n); + + /// General Network Events void onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytesConstRef _packet); @@ -181,7 +185,7 @@ protected: mutable Mutex x_nodes; ///< Mutable for thread-safe copy in nodes() const. std::map> m_nodes; ///< Address -> Node table (most common lookup path) - Mutex x_state; + mutable Mutex x_state; std::array m_state; ///< State table of binned nodes. Mutex x_evictions; @@ -194,6 +198,15 @@ protected: boost::asio::deadline_timer m_evictionCheckTimer; ///< Timer for handling node evictions. }; +std::ostream& operator<<(std::ostream& _out, NodeTable const& _nodeTable) +{ + _out << _nodeTable.root().address() << "\t" << "0\t" << _nodeTable.root().endpoint.udp.address() << ":" << _nodeTable.root().endpoint.udp.port() << std::endl; + auto s = _nodeTable.state(); + for (auto n: s) + _out << n.address() << "\t" << n.distance << "\t" << n.endpoint.udp.address() << ":" << n.endpoint.udp.port() << std::endl; + return _out; +} + /** * Ping packet: Check if node is alive. * PingNode is cached and regenerated after expiration - t, where t is timeout. diff --git a/libp2p/UDP.cpp b/libp2p/UDP.cpp index f98c31e09..42f5e4cab 100644 --- a/libp2p/UDP.cpp +++ b/libp2p/UDP.cpp @@ -22,3 +22,24 @@ #include "UDP.h" using namespace dev; using namespace dev::p2p; + +//template +h256 RLPXDatagramFace::sign(Secret const& _k) +{ + RLPStream packet; + streamRLP(packet); + bytes b(packet.out()); + h256 h(dev::sha3(b)); + Signature sig = dev::sign(_k, h); + data.resize(b.size() + Signature::size); + sig.ref().copyTo(&data); + memcpy(data.data() + sizeof(Signature), b.data(), b.size()); + return std::move(h); +}; + +//template +Public RLPXDatagramFace::authenticate(bytesConstRef _sig, bytesConstRef _rlp) +{ + Signature const& sig = *(Signature const*)_sig.data(); + return std::move(dev::recover(sig, sha3(_rlp))); +}; \ No newline at end of file diff --git a/libp2p/UDP.h b/libp2p/UDP.h index 5de8053a0..498d37f0c 100644 --- a/libp2p/UDP.h +++ b/libp2p/UDP.h @@ -58,39 +58,28 @@ protected: * @brief RLPX Datagram which can be signed. * @todo compact templates * @todo make data private/functional (see UDPDatagram) - * @todo valid=true/false (based on signature) */ -template -struct RLPXDatagram: public UDPDatagram +//template +struct RLPXDatagramFace: public UDPDatagram { - static T fromBytesConstRef(bi::udp::endpoint const& _ep, bytesConstRef _bytes) { T t(_ep); t.interpretRLP(_bytes); return std::move(t); } +// static T fromBytesConstRef(bi::udp::endpoint const& _ep, bytesConstRef _bytes) { T t(_ep); t.interpretRLP(_bytes); return std::move(t); } static uint64_t futureFromEpoch(std::chrono::milliseconds _ms) { return std::chrono::duration_cast((std::chrono::system_clock::now() + _ms).time_since_epoch()).count(); } static uint64_t futureFromEpoch(std::chrono::seconds _sec) { return std::chrono::duration_cast((std::chrono::system_clock::now() + _sec).time_since_epoch()).count(); } + static Public authenticate(bytesConstRef _sig, bytesConstRef _rlp); - RLPXDatagram(bi::udp::endpoint const& _ep): UDPDatagram(_ep) {} + RLPXDatagramFace(bi::udp::endpoint const& _ep): UDPDatagram(_ep) {} virtual h256 sign(Secret const& _from); virtual void streamRLP(RLPStream&) const =0; virtual void interpretRLP(bytesConstRef _bytes) =0; - -protected: - Signature signature; }; template -h256 RLPXDatagram::sign(Secret const& _k) +struct RLPXDatagram: public RLPXDatagramFace { - RLPStream packet; - streamRLP(packet); - bytes b(packet.out()); - h256 h(dev::sha3(b)); - Signature sig = dev::sign(_k, h); - data.resize(b.size() + Signature::size); - sig.ref().copyTo(&data); - memcpy(data.data() + sizeof(Signature), b.data(), b.size()); - return std::move(h); -} - + static T fromBytesConstRef(bi::udp::endpoint const& _ep, bytesConstRef _bytes) { T t(_ep); t.interpretRLP(_bytes); return std::move(t); } + using RLPXDatagramFace::RLPXDatagramFace; +}; /** * @brief Interface which UDPSocket will implement. @@ -198,6 +187,9 @@ bool UDPSocket::send(UDPDatagram const& _datagram) template void UDPSocket::doRead() { + if (m_closed) + return; + auto self(UDPSocket::shared_from_this()); m_socket.async_receive_from(boost::asio::buffer(recvData), recvEndpoint, [this, self](boost::system::error_code _ec, size_t _len) { @@ -206,14 +198,16 @@ void UDPSocket::doRead() assert(_len); m_host.onReceived(this, recvEndpoint, bytesConstRef(recvData.data(), _len)); - if (!m_closed) - doRead(); + doRead(); }); } template void UDPSocket::doWrite() { + if (m_closed) + return; + const UDPDatagram& datagram = sendQ[0]; auto self(UDPSocket::shared_from_this()); m_socket.async_send_to(boost::asio::buffer(datagram.data), datagram.endpoint(), [this, self](boost::system::error_code _ec, std::size_t) diff --git a/test/net.cpp b/test/net.cpp index 8277c1f70..274f729c6 100644 --- a/test/net.cpp +++ b/test/net.cpp @@ -42,6 +42,7 @@ public: virtual ~TestHost() { m_io.stop(); stopWorking(); } void start() { startWorking(); } void doWork() { m_io.run(); } + void doneWorking() { m_io.reset(); m_io.poll(); m_io.reset(); } protected: ba::io_service m_io; @@ -52,18 +53,20 @@ struct TestNodeTable: public NodeTable /// Constructor using NodeTable::NodeTable; - void setup(std::vector> const& _testNodes) + void pingAll(std::vector> const& _testNodes) { - /// Phase 2 test: pre-populate *expected* ping-responses, send pings - bi::address ourIp = bi::address::from_string("127.0.0.1"); - uint16_t ourPort = 30300; - bi::udp::endpoint ourEndpoint(ourIp, ourPort); - for (auto& n: _testNodes) ping(bi::udp::endpoint(ourIp, n.second)); } + void populate(std::vector> const& _testNodes) + { + bi::address ourIp = bi::address::from_string("127.0.0.1"); + for (auto& n: _testNodes) + noteNode(n.first.pub(), bi::udp::endpoint(ourIp, n.second)); + } + void reset() { Guard l(x_state); @@ -77,8 +80,9 @@ struct TestNodeTable: public NodeTable struct TestNodeTableHost: public TestHost { TestNodeTableHost(): m_alias(KeyPair::create()), nodeTable(new TestNodeTable(m_io, m_alias)) {}; + ~TestNodeTableHost() { m_io.stop(); stopWorking(); } - void generateTestNodes(int _count = 10) + void generateTestNodes(int _count = 30) { asserts(_count < 1000); static uint16_t s_basePort = 30500; @@ -96,7 +100,16 @@ struct TestNodeTableHost: public TestHost void setup() { generateTestNodes(); - nodeTable->setup(m_testNodes); + } + + void pingAll() + { + nodeTable->pingAll(m_testNodes); + } + + void populate() + { + nodeTable->populate(m_testNodes); } KeyPair m_alias; @@ -123,7 +136,10 @@ BOOST_AUTO_TEST_CASE(kademlia) node.start(); node.nodeTable->join(); // ideally, joining with empty node table logs warning we can check for node.setup(); - sleep(1); + node.pingAll(); + this_thread::sleep_for(chrono::milliseconds(500)); + + cout << "NodeTable:\n" << *node.nodeTable.get() << endl; } BOOST_AUTO_TEST_CASE(test_txrx_one) From ac583f503fd06a280edab8a913b4aba8825a9ab5 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 24 Dec 2014 11:36:08 +0100 Subject: [PATCH 030/111] Implemented 256-long history for PREVHASH, though still optional. --- alethzero/MainWin.cpp | 4 +-- eth/main.cpp | 2 +- exp/main.cpp | 4 +-- libethereum/Client.cpp | 4 +-- libethereum/Executive.cpp | 11 +++++-- libethereum/Executive.h | 6 +++- libethereum/ExtVM.cpp | 4 +-- libethereum/ExtVM.h | 4 +-- libethereum/State.cpp | 48 +++++++++++++++++++------------ libethereum/State.h | 14 +++++---- libevm/ExtVMFace.cpp | 3 +- libevm/ExtVMFace.h | 10 +++++-- libevm/VM.h | 12 ++++++-- libp2p/Session.cpp | 2 +- mix/AssemblyDebuggerModel.cpp | 2 +- test/solidityExecutionFramework.h | 2 +- test/state.cpp | 2 +- test/stateOriginal.cpp | 2 +- test/vm.cpp | 2 +- 19 files changed, 88 insertions(+), 50 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index e25db4137..9cc651e4a 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -1350,7 +1350,7 @@ void Main::on_debugCurrent_triggered() { unsigned txi = item->data(Qt::UserRole + 1).toInt(); m_executiveState = ethereum()->state(txi + 1, h); - m_currentExecution = unique_ptr(new Executive(m_executiveState, 0)); + m_currentExecution = unique_ptr(new Executive(m_executiveState, ethereum()->blockChain(), 0)); Transaction t = m_executiveState.pending()[txi]; m_executiveState = m_executiveState.fromPending(txi); auto r = t.rlp(); @@ -1803,7 +1803,7 @@ void Main::on_debug_clicked() { Secret s = i.secret(); m_executiveState = ethereum()->postState(); - m_currentExecution = unique_ptr(new Executive(m_executiveState, 0)); + m_currentExecution = unique_ptr(new Executive(m_executiveState, ethereum()->blockChain(), 0)); Transaction t = isCreation() ? Transaction(value(), gasPrice(), ui->gas->value(), m_data, m_executiveState.transactionsFrom(dev::toAddress(s)), s) : Transaction(value(), gasPrice(), ui->gas->value(), fromString(ui->destination->currentText()), m_data, m_executiveState.transactionsFrom(dev::toAddress(s)), s); diff --git a/eth/main.cpp b/eth/main.cpp index 1520e86c4..1d139faa7 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -619,7 +619,7 @@ int main(int argc, char** argv) dev::eth::State state =c->state(index + 1,c->blockChain().numberHash(block)); if (index < state.pending().size()) { - Executive e(state, 0); + Executive e(state, c->blockChain(), 0); Transaction t = state.pending()[index]; state = state.fromPending(index); bytes r = t.rlp(); diff --git a/exp/main.cpp b/exp/main.cpp index 27707decb..e714f29da 100644 --- a/exp/main.cpp +++ b/exp/main.cpp @@ -21,13 +21,13 @@ */ #include #include +#include #include #include #include #include #include #include -#include #include #include #include @@ -91,7 +91,7 @@ int main() Transaction t(0, 10000, 10000, c, bytes(), 0, u.secret()); cnote << "Transaction: " << t; cnote << s.balance(c); - s.execute(t.rlp()); + s.execute(LastHashes(), t.rlp()); cnote << "State after transaction: " << s; cnote << before.diff(s); } diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index e3346754b..02ef2d3be 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -343,7 +343,7 @@ bytes Client::call(Secret _secret, u256 _value, Address _dest, bytes const& _dat n = temp.transactionsFrom(toAddress(_secret)); } Transaction t(_value, _gasPrice, _gas, _dest, _data, n, _secret); - u256 gasUsed = temp.execute(t.rlp(), &out, false); + u256 gasUsed = temp.execute(m_bc, t.rlp(), &out, false); (void)gasUsed; // TODO: do something with gasused which it returns. } catch (...) @@ -442,7 +442,7 @@ void Client::doWork() // returns h256s as blooms, once for each transaction. cwork << "postSTATE <== TQ"; - h512s newPendingBlooms = m_postMine.sync(m_tq); + h512s newPendingBlooms = m_postMine.sync(m_bc, m_tq); if (newPendingBlooms.size()) { for (auto i: newPendingBlooms) diff --git a/libethereum/Executive.cpp b/libethereum/Executive.cpp index d16cf794c..3bc6ea93e 100644 --- a/libethereum/Executive.cpp +++ b/libethereum/Executive.cpp @@ -29,12 +29,19 @@ #include "State.h" #include "ExtVM.h" #include "Precompiled.h" +#include "BlockChain.h" using namespace std; using namespace dev; using namespace dev::eth; #define ETH_VMTRACE 1 +Executive::Executive(State& _s, BlockChain const& _bc, unsigned _level): + m_s(_s), + m_lastHashes(_s.getLastHashes(_bc)), + m_depth(_level) +{} + u256 Executive::gasUsed() const { return m_t.gas() - m_endGas; @@ -123,7 +130,7 @@ bool Executive::call(Address _receiveAddress, Address _codeAddress, Address _sen { m_vm = VMFactory::create(_gas); bytes const& c = m_s.code(_codeAddress); - m_ext = make_shared(m_s, _receiveAddress, _senderAddress, _originAddress, _value, _gasPrice, _data, &c, m_depth); + m_ext = make_shared(m_s, m_lastHashes, _receiveAddress, _senderAddress, _originAddress, _value, _gasPrice, _data, &c, m_depth); } else m_endGas = _gas; @@ -143,7 +150,7 @@ bool Executive::create(Address _sender, u256 _endowment, u256 _gasPrice, u256 _g // Execute _init. m_vm = VMFactory::create(_gas); - m_ext = make_shared(m_s, m_newAddress, _sender, _origin, _endowment, _gasPrice, bytesConstRef(), _init, m_depth); + m_ext = make_shared(m_s, m_lastHashes, m_newAddress, _sender, _origin, _endowment, _gasPrice, bytesConstRef(), _init, m_depth); return _init.empty(); } diff --git a/libethereum/Executive.h b/libethereum/Executive.h index 8ccccddf8..0b154b4b5 100644 --- a/libethereum/Executive.h +++ b/libethereum/Executive.h @@ -34,6 +34,7 @@ namespace eth { class State; +class BlockChain; class ExtVM; struct Manifest; @@ -52,7 +53,9 @@ class Executive { public: /// Basic constructor. - Executive(State& _s, unsigned _level): m_s(_s), m_depth(_level) {} + Executive(State& _s, LastHashes const& _lh, unsigned _level): m_s(_s), m_lastHashes(_lh), m_depth(_level) {} + /// Basic constructor. + Executive(State& _s, BlockChain const& _bc, unsigned _level); /// Basic destructor. ~Executive() = default; @@ -102,6 +105,7 @@ public: private: State& m_s; ///< The state to which this operation/transaction is applied. + LastHashes m_lastHashes; std::shared_ptr m_ext; ///< The VM externality object for the VM execution or null if no VM is required. std::unique_ptr m_vm; ///< The VM object or null if no VM is required. bytes m_precompiledOut; ///< Used for the output when there is no VM for a contract (i.e. precompiled). diff --git a/libethereum/ExtVM.cpp b/libethereum/ExtVM.cpp index a005a030b..a8eba5a50 100644 --- a/libethereum/ExtVM.cpp +++ b/libethereum/ExtVM.cpp @@ -28,7 +28,7 @@ using namespace dev::eth; bool ExtVM::call(Address _receiveAddress, u256 _txValue, bytesConstRef _txData, u256& io_gas, bytesRef _out, OnOpFunc const& _onOp, Address _myAddressOverride, Address _codeAddressOverride) { - Executive e(m_s, depth + 1); + Executive e(m_s, lastHashes, depth + 1); if (!e.call(_receiveAddress, _codeAddressOverride ? _codeAddressOverride : _receiveAddress, _myAddressOverride ? _myAddressOverride : myAddress, _txValue, gasPrice, _txData, io_gas, origin)) { e.go(_onOp); @@ -45,7 +45,7 @@ h160 ExtVM::create(u256 _endowment, u256& io_gas, bytesConstRef _code, OnOpFunc // Increment associated nonce for sender. m_s.noteSending(myAddress); - Executive e(m_s, depth + 1); + Executive e(m_s, lastHashes, depth + 1); if (!e.create(myAddress, _endowment, gasPrice, io_gas, _code, origin)) { e.go(_onOp); diff --git a/libethereum/ExtVM.h b/libethereum/ExtVM.h index cfe40874f..30cbf1a5a 100644 --- a/libethereum/ExtVM.h +++ b/libethereum/ExtVM.h @@ -39,8 +39,8 @@ class ExtVM: public ExtVMFace { public: /// Full constructor. - ExtVM(State& _s, Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytesConstRef _code, unsigned _depth = 0): - ExtVMFace(_myAddress, _caller, _origin, _value, _gasPrice, _data, _code.toBytes(), _s.m_previousBlock, _s.m_currentBlock, _depth), m_s(_s), m_origCache(_s.m_cache) + ExtVM(State& _s, LastHashes const& _lh, Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytesConstRef _code, unsigned _depth = 0): + ExtVMFace(_myAddress, _caller, _origin, _value, _gasPrice, _data, _code.toBytes(), _s.m_previousBlock, _s.m_currentBlock, _lh, _depth), m_s(_s), m_origCache(_s.m_cache) { m_s.ensureCached(_myAddress, true, true); } diff --git a/libethereum/State.cpp b/libethereum/State.cpp index e02b06bcd..e5d31d863 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -114,7 +114,7 @@ State::State(OverlayDB const& _db, BlockChain const& _bc, h256 _h): m_ourAddress = bi.coinbaseAddress; sync(_bc, bi.parentHash, bip); - enact(&b); + enact(&b, _bc); } State::State(State const& _s): @@ -319,7 +319,7 @@ bool State::sync(BlockChain const& _bc, h256 _block, BlockInfo const& _bi) for (auto it = chain.rbegin(); it != chain.rend(); ++it) { auto b = _bc.block(*it); - enact(&b); + enact(&b, _bc); cleanup(true); } } @@ -348,7 +348,7 @@ u256 State::enactOn(bytesConstRef _block, BlockInfo const& _bi, BlockChain const sync(_bc, _bi.parentHash); resetCurrent(); m_previousBlock = biParent; - return enact(_block, &_bc); + return enact(_block, _bc); } map State::addresses() const @@ -412,12 +412,14 @@ bool State::cull(TransactionQueue& _tq) const return ret; } -h512s State::sync(TransactionQueue& _tq, bool* o_transactionQueueChanged) +h512s State::sync(BlockChain const& _bc, TransactionQueue& _tq, bool* o_transactionQueueChanged) { // TRANSACTIONS h512s ret; auto ts = _tq.transactions(); + auto lh = getLastHashes(_bc); + for (int goodTxs = 1; goodTxs;) { goodTxs = 0; @@ -429,7 +431,7 @@ h512s State::sync(TransactionQueue& _tq, bool* o_transactionQueueChanged) { uncommitToMine(); // boost::timer t; - execute(i.second); + execute(lh, i.second); ret.push_back(m_receipts.back().bloom()); _tq.noteGood(i); ++goodTxs; @@ -467,7 +469,7 @@ h512s State::sync(TransactionQueue& _tq, bool* o_transactionQueueChanged) return ret; } -u256 State::enact(bytesConstRef _block, BlockChain const* _bc, bool _checkNonce) +u256 State::enact(bytesConstRef _block, BlockChain const& _bc, bool _checkNonce) { // m_currentBlock is assumed to be prepopulated and reset. @@ -496,6 +498,8 @@ u256 State::enact(bytesConstRef _block, BlockChain const* _bc, bool _checkNonce) GenericTrieDB receiptsTrie(&rm); receiptsTrie.init(); + LastHashes lh = getLastHashes(_bc); + // All ok with the block generally. Play back the transactions now... unsigned i = 0; for (auto const& tr: RLP(_block)[1]) @@ -507,7 +511,7 @@ u256 State::enact(bytesConstRef _block, BlockChain const* _bc, bool _checkNonce) // cnote << m_state.root() << m_state; // cnote << *this; - execute(tr.data()); + execute(lh, tr.data()); RLPStream receiptrlp; m_receipts.back().streamRLP(receiptrlp); @@ -551,7 +555,7 @@ u256 State::enact(bytesConstRef _block, BlockChain const* _bc, bool _checkNonce) // Check uncles & apply their rewards to state. set nonces = { m_currentBlock.nonce }; Addresses rewarded; - set knownUncles = _bc ? _bc->allUnclesFrom(m_currentBlock.parentHash) : set(); + set knownUncles = _bc.allUnclesFrom(m_currentBlock.parentHash); for (auto const& i: RLP(_block)[2]) { if (knownUncles.count(sha3(i.data()))) @@ -560,13 +564,11 @@ u256 State::enact(bytesConstRef _block, BlockChain const* _bc, bool _checkNonce) BlockInfo uncle = BlockInfo::fromHeader(i.data()); if (nonces.count(uncle.nonce)) BOOST_THROW_EXCEPTION(DuplicateUncleNonce()); - if (_bc) - { - BlockInfo uncleParent(_bc->block(uncle.parentHash)); - if ((bigint)uncleParent.number < (bigint)m_currentBlock.number - 6) - BOOST_THROW_EXCEPTION(UncleTooOld()); - uncle.verifyParent(uncleParent); - } + + BlockInfo uncleParent(_bc.block(uncle.parentHash)); + if ((bigint)uncleParent.number < (bigint)m_currentBlock.number - 6) + BOOST_THROW_EXCEPTION(UncleTooOld()); + uncle.verifyParent(uncleParent); nonces.insert(uncle.nonce); tdIncrease += uncle.difficulty; @@ -648,7 +650,7 @@ bool State::amIJustParanoid(BlockChain const& _bc) cnote << "PARANOIA root:" << s.rootHash(); // s.m_currentBlock.populate(&block.out(), false); // s.m_currentBlock.verifyInternals(&block.out()); - s.enact(&block.out(), &_bc, false); // don't check nonce for this since we haven't mined it yet. + s.enact(&block.out(), _bc, false); // don't check nonce for this since we haven't mined it yet. s.cleanup(false); return true; } @@ -993,9 +995,17 @@ bool State::isTrieGood(bool _enforceRefs, bool _requireNoLeftOvers) const return true; } -// TODO: maintain node overlay revisions for stateroots -> each commit gives a stateroot + OverlayDB; allow overlay copying for rewind operations. +LastHashes State::getLastHashes(BlockChain const& _bc) const +{ + LastHashes ret; + unsigned n = (unsigned)m_previousBlock.number; + for (unsigned i = 0; i < 256; ++i) + ret[i] = _bc.numberHash(n - i); + return ret; +} -u256 State::execute(bytesConstRef _rlp, bytes* o_output, bool _commit) +// TODO: maintain node overlay revisions for stateroots -> each commit gives a stateroot + OverlayDB; allow overlay copying for rewind operations. +u256 State::execute(LastHashes const& _lh, bytesConstRef _rlp, bytes* o_output, bool _commit) { #ifndef ETH_RELEASE commit(); // get an updated hash @@ -1008,7 +1018,7 @@ u256 State::execute(bytesConstRef _rlp, bytes* o_output, bool _commit) auto h = rootHash(); #endif - Executive e(*this, 0); + Executive e(*this, _lh, 0); e.setup(_rlp); u256 startGasUsed = gasUsed(); diff --git a/libethereum/State.h b/libethereum/State.h index 763a67451..0473893c4 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -143,14 +143,18 @@ public: /// @returns a list of bloom filters one for each transaction placed from the queue into the state. /// @a o_transactionQueueChanged boolean pointer, the value of which will be set to true if the transaction queue /// changed and the pointer is non-null - h512s sync(TransactionQueue& _tq, bool* o_transactionQueueChanged = nullptr); + h512s sync(BlockChain const& _bc, TransactionQueue& _tq, bool* o_transactionQueueChanged = nullptr); /// Like sync but only operate on _tq, killing the invalid/old ones. bool cull(TransactionQueue& _tq) const; + LastHashes getLastHashes(BlockChain const& _bc) const; + /// Execute a given transaction. /// This will append @a _t to the transaction list and change the state accordingly. - u256 execute(bytes const& _rlp, bytes* o_output = nullptr, bool _commit = true) { return execute(&_rlp, o_output, _commit); } - u256 execute(bytesConstRef _rlp, bytes* o_output = nullptr, bool _commit = true); + u256 execute(BlockChain const& _bc, bytes const& _rlp, bytes* o_output = nullptr, bool _commit = true) { return execute(getLastHashes(_bc), &_rlp, o_output, _commit); } + u256 execute(BlockChain const& _bc, bytesConstRef _rlp, bytes* o_output = nullptr, bool _commit = true) { return execute(getLastHashes(_bc), _rlp, o_output, _commit); } + u256 execute(LastHashes const& _lh, bytes const& _rlp, bytes* o_output = nullptr, bool _commit = true) { return execute(_lh, &_rlp, o_output, _commit); } + u256 execute(LastHashes const& _lh, bytesConstRef _rlp, bytes* o_output = nullptr, bool _commit = true); /// Get the remaining gas limit in this block. u256 gasLimitRemaining() const { return m_currentBlock.gasLimit - gasUsed(); } @@ -268,9 +272,9 @@ private: /// Retrieve all information about a given address into a cache. void ensureCached(std::map& _cache, Address _a, bool _requireCode, bool _forceCreate) const; - /// Execute the given block, assuming it corresponds to m_currentBlock. If _bc is passed, it will be used to check the uncles. + /// Execute the given block, assuming it corresponds to m_currentBlock. /// Throws on failure. - u256 enact(bytesConstRef _block, BlockChain const* _bc = nullptr, bool _checkNonce = true); + u256 enact(bytesConstRef _block, BlockChain const& _bc, bool _checkNonce = true); /// Finalise the block, applying the earned rewards. void applyRewards(Addresses const& _uncleAddresses); diff --git a/libevm/ExtVMFace.cpp b/libevm/ExtVMFace.cpp index 8a08a290c..ebef1fdb0 100644 --- a/libevm/ExtVMFace.cpp +++ b/libevm/ExtVMFace.cpp @@ -25,7 +25,7 @@ using namespace std; using namespace dev; using namespace dev::eth; -ExtVMFace::ExtVMFace(Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytes const& _code, BlockInfo const& _previousBlock, BlockInfo const& _currentBlock, unsigned _depth): +ExtVMFace::ExtVMFace(Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytes const& _code, BlockInfo const& _previousBlock, BlockInfo const& _currentBlock, LastHashes const& _lh, unsigned _depth): myAddress(_myAddress), caller(_caller), origin(_origin), @@ -33,6 +33,7 @@ ExtVMFace::ExtVMFace(Address _myAddress, Address _caller, Address _origin, u256 gasPrice(_gasPrice), data(_data), code(_code), + lastHashes(_lh), previousBlock(_previousBlock), currentBlock(_currentBlock), depth(_depth) diff --git a/libevm/ExtVMFace.h b/libevm/ExtVMFace.h index 84dee4272..2c5e9400c 100644 --- a/libevm/ExtVMFace.h +++ b/libevm/ExtVMFace.h @@ -93,6 +93,8 @@ struct SubState class ExtVMFace; class VM; +using LastHashes = std::array; + using OnOpFunc = std::function; /** @@ -105,7 +107,7 @@ public: ExtVMFace() = default; /// Full constructor. - ExtVMFace(Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytes const& _code, BlockInfo const& _previousBlock, BlockInfo const& _currentBlock, unsigned _depth); + ExtVMFace(Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytes const& _code, BlockInfo const& _previousBlock, BlockInfo const& _currentBlock, LastHashes const& _lh, unsigned _depth); virtual ~ExtVMFace() = default; @@ -145,6 +147,9 @@ public: /// Revert any changes made (by any of the other calls). virtual void revert() {} + /// Hash of a block if within the last 256 blocks, or h256() otherwise. + h256 prevhash(u256 _number) { return _number < currentBlock.number && _number > (std::max(257, currentBlock.number) - 257) ? lastHashes[(unsigned)(currentBlock.number - 1 - _number)] : h256(); } // TODO: CHECK!!! + /// Get the code at the given location in code ROM. byte getCode(u256 _n) const { return _n < code.size() ? code[(size_t)_n] : 0; } @@ -155,7 +160,8 @@ public: u256 gasPrice; ///< Price of gas (that we already paid). bytesConstRef data; ///< Current input data. bytes code; ///< Current code that is executing. - BlockInfo previousBlock; ///< The previous block's information. + LastHashes lastHashes; ///< Most recent 256 blocks' hashes. + BlockInfo previousBlock; ///< The previous block's information. TODO: PoC-8: REMOVE BlockInfo currentBlock; ///< The current block's information. SubState sub; ///< Sub-band VM state (suicides, refund counter, logs). unsigned depth = 0; ///< Depth of the present call. diff --git a/libevm/VM.h b/libevm/VM.h index 1f3fc17d5..64353e2db 100644 --- a/libevm/VM.h +++ b/libevm/VM.h @@ -198,7 +198,6 @@ inline bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _st require(1); runGas = c_balanceGas; break; - case Instruction::LOG0: case Instruction::LOG1: case Instruction::LOG2: @@ -240,6 +239,11 @@ inline bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _st break; } + case Instruction::PREVHASH: + if (c_protocolVersion > 49) + require(1); + break; + case Instruction::PC: case Instruction::MSIZE: case Instruction::GAS: @@ -251,7 +255,6 @@ inline bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _st case Instruction::CALLDATASIZE: case Instruction::CODESIZE: case Instruction::GASPRICE: - case Instruction::PREVHASH: case Instruction::COINBASE: case Instruction::TIMESTAMP: case Instruction::NUMBER: @@ -581,7 +584,10 @@ inline bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _st m_stack.push_back(_ext.gasPrice); break; case Instruction::PREVHASH: - m_stack.push_back(_ext.previousBlock.hash); + if (c_protocolVersion > 49) + m_stack.back() = (u256)_ext.prevhash(m_stack.back()); + else + m_stack.push_back(_ext.previousBlock.hash); break; case Instruction::COINBASE: m_stack.push_back((u160)_ext.currentBlock.coinbaseAddress); diff --git a/libp2p/Session.cpp b/libp2p/Session.cpp index cb0a60a92..bf08cfe00 100644 --- a/libp2p/Session.cpp +++ b/libp2p/Session.cpp @@ -195,7 +195,7 @@ bool Session::interpret(RLP const& _r) // "'operator<<' should be declared prior to the call site or in an associated namespace of one of its arguments" stringstream capslog; for (auto cap: caps) - capslog << "(" << hex << cap.first << "," << hex << cap.second << ")"; + capslog << "(" << cap.first << "," << dec << cap.second << ")"; clogS(NetMessageSummary) << "Hello: " << clientVersion << "V[" << m_protocolVersion << "]" << id.abridged() << showbase << capslog.str() << dec << listenPort; diff --git a/mix/AssemblyDebuggerModel.cpp b/mix/AssemblyDebuggerModel.cpp index 1e07760e1..17abf5700 100644 --- a/mix/AssemblyDebuggerModel.cpp +++ b/mix/AssemblyDebuggerModel.cpp @@ -38,7 +38,7 @@ AssemblyDebuggerModel::AssemblyDebuggerModel(): m_baseState(Address(), m_overlayDB, BaseState::Empty) { m_baseState.addBalance(m_userAccount.address(), 10000000 * ether); - m_currentExecution = std::unique_ptr(new Executive(m_executiveState, 0)); + m_currentExecution = std::unique_ptr(new Executive(m_executiveState, LastHashes(), 0)); } DebuggingContent AssemblyDebuggerModel::getContractInitiationDebugStates(dev::bytesConstRef _rawTransaction) diff --git a/test/solidityExecutionFramework.h b/test/solidityExecutionFramework.h index 91ee7ad6a..9f25b3725 100644 --- a/test/solidityExecutionFramework.h +++ b/test/solidityExecutionFramework.h @@ -117,7 +117,7 @@ private: void sendMessage(bytes const& _data, bool _isCreation, u256 const& _value = 0) { m_state.addBalance(m_sender, _value); // just in case - eth::Executive executive(m_state, 0); + eth::Executive executive(m_state, eth::LastHashes(), 0); eth::Transaction t = _isCreation ? eth::Transaction(_value, m_gasPrice, m_gas, _data, 0, KeyPair::create().sec()) : eth::Transaction(_value, m_gasPrice, m_gas, m_contractAddress, _data, 0, KeyPair::create().sec()); bytes transactionRLP = t.rlp(); diff --git a/test/state.cpp b/test/state.cpp index b1ad8d44e..133468226 100644 --- a/test/state.cpp +++ b/test/state.cpp @@ -62,7 +62,7 @@ void doStateTests(json_spirit::mValue& v, bool _fillin) try { - theState.execute(tx, &output); + theState.execute(LastHashes(), tx, &output); } catch (Exception const& _e) { diff --git a/test/stateOriginal.cpp b/test/stateOriginal.cpp index 8344894f4..a49c55061 100644 --- a/test/stateOriginal.cpp +++ b/test/stateOriginal.cpp @@ -69,7 +69,7 @@ int stateTest() assert(t.sender() == myMiner.address()); tx = t.rlp(); } - s.execute(tx); + s.execute(bc, tx); cout << s; diff --git a/test/vm.cpp b/test/vm.cpp index 920f0582c..18bf57977 100644 --- a/test/vm.cpp +++ b/test/vm.cpp @@ -33,7 +33,7 @@ using namespace dev::eth; using namespace dev::test; FakeExtVM::FakeExtVM(eth::BlockInfo const& _previousBlock, eth::BlockInfo const& _currentBlock, unsigned _depth): /// TODO: XXX: remove the default argument & fix. - ExtVMFace(Address(), Address(), Address(), 0, 1, bytesConstRef(), bytes(), _previousBlock, _currentBlock, _depth) {} + ExtVMFace(Address(), Address(), Address(), 0, 1, bytesConstRef(), bytes(), _previousBlock, _currentBlock, LastHashes(), _depth) {} h160 FakeExtVM::create(u256 _endowment, u256& io_gas, bytesConstRef _init, OnOpFunc const&) { From ba455270c09cdf4202c8d23bf5d3eedce9a05f45 Mon Sep 17 00:00:00 2001 From: subtly Date: Wed, 24 Dec 2014 14:48:47 +0100 Subject: [PATCH 031/111] memory --- libp2p/NodeTable.cpp | 44 +++++++++++++++++++++++++++++--------------- libp2p/NodeTable.h | 36 +++++++++++++++++++++--------------- libp2p/UDP.h | 1 - test/net.cpp | 43 ++++++++++++++++++++++++++++++++++++------- 4 files changed, 86 insertions(+), 38 deletions(-) diff --git a/libp2p/NodeTable.cpp b/libp2p/NodeTable.cpp index 3799a4eef..b5b261321 100644 --- a/libp2p/NodeTable.cpp +++ b/libp2p/NodeTable.cpp @@ -35,8 +35,8 @@ NodeTable::NodeTable(ba::io_service& _io, KeyPair _alias, uint16_t _listenPort): { for (unsigned i = 0; i < s_bins; i++) m_state[i].distance = i, m_state[i].modified = chrono::steady_clock::now() - chrono::seconds(1); - doRefreshBuckets(boost::system::error_code()); m_socketPtr->connect(); + doRefreshBuckets(boost::system::error_code()); } NodeTable::~NodeTable() @@ -87,7 +87,15 @@ void NodeTable::doFindNode(Address _node, unsigned _round, std::shared_ptrisOpen() || _round == s_maxSteps) return; - + + if (_round == s_maxSteps) + { + clog(NodeTableWarn) << "Terminating doFindNode after " << _round << " rounds."; + return; + } + else + _tried.reset(new std::set>()); + auto nearest = findNearest(_node); std::list> tried; for (unsigned i = 0; i < nearest.size() && tried.size() < s_alpha; i++) @@ -137,7 +145,7 @@ std::vector> NodeTable::findNearest(Addres while (head != tail && head < s_bins && count < s_bucketSize) { Guard l(x_state); - for (auto& n: m_state[head].nodes) + for (auto n: m_state[head].nodes) if (auto p = n.lock()) { if (count < s_bucketSize) @@ -147,7 +155,7 @@ std::vector> NodeTable::findNearest(Addres } if (count < s_bucketSize && tail) - for (auto& n: m_state[tail].nodes) + for (auto n: m_state[tail].nodes) if (auto p = n.lock()) { if (count < s_bucketSize) @@ -164,7 +172,7 @@ std::vector> NodeTable::findNearest(Addres while (head < s_bins && count < s_bucketSize) { Guard l(x_state); - for (auto& n: m_state[head].nodes) + for (auto n: m_state[head].nodes) if (auto p = n.lock()) { if (count < s_bucketSize) @@ -178,7 +186,7 @@ std::vector> NodeTable::findNearest(Addres while (tail > 0 && count < s_bucketSize) { Guard l(x_state); - for (auto& n: m_state[tail].nodes) + for (auto n: m_state[tail].nodes) if (auto p = n.lock()) { if (count < s_bucketSize) @@ -191,7 +199,7 @@ std::vector> NodeTable::findNearest(Addres std::vector> ret; for (auto& nodes: found) - for (auto& n: nodes.second) + for (auto n: nodes.second) ret.push_back(n); return std::move(ret); } @@ -223,9 +231,14 @@ void NodeTable::evict(std::shared_ptr _leastSeen, std::shared_ptr node; { Guard l(x_nodes); @@ -325,6 +338,7 @@ void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytes case 2: if (rlp[0].isList()) { + // todo: chunk neighbors packet clog(NodeTableMessageSummary) << "Received Neighbors from " << _from.address().to_string() << ":" << _from.port(); Neighbors in = Neighbors::fromBytesConstRef(_from, rlpBytes); for (auto n: in.nodes) @@ -371,7 +385,7 @@ void NodeTable::doCheckEvictions(boost::system::error_code const& _ec) return; auto self(shared_from_this()); - m_evictionCheckTimer.expires_from_now(boost::posix_time::milliseconds(s_evictionCheckInterval)); + m_evictionCheckTimer.expires_from_now(c_evictionCheckInterval); m_evictionCheckTimer.async_wait([this, self](boost::system::error_code const& _ec) { if (_ec) @@ -380,17 +394,17 @@ void NodeTable::doCheckEvictions(boost::system::error_code const& _ec) bool evictionsRemain = false; std::list> drop; { - Guard l(x_evictions); + Guard le(x_evictions); + Guard ln(x_nodes); for (auto& e: m_evictions) if (chrono::steady_clock::now() - e.first.second > c_reqTimeout) - { - Guard l(x_nodes); - drop.push_back(m_nodes[e.second]); - } + if (auto n = m_nodes[e.second]) + drop.push_back(n); evictionsRemain = m_evictions.size() - drop.size() > 0; } - for (auto& n: drop) + drop.unique(); + for (auto n: drop) dropNode(n); if (evictionsRemain) diff --git a/libp2p/NodeTable.h b/libp2p/NodeTable.h index 89456b4fd..fe925fea8 100644 --- a/libp2p/NodeTable.h +++ b/libp2p/NodeTable.h @@ -120,9 +120,9 @@ public: /// Intervals - static constexpr unsigned s_evictionCheckInterval = 75; ///< Interval at which eviction timeouts are checked. - std::chrono::milliseconds const c_reqTimeout = std::chrono::milliseconds(300); ///< How long to wait for requests (evict, find iterations). - std::chrono::seconds const c_bucketRefresh = std::chrono::seconds(3600); ///< Refresh interval prevents bucket from becoming stale. [Kademlia] + boost::posix_time::milliseconds const c_evictionCheckInterval = boost::posix_time::milliseconds(75); ///< Interval at which eviction timeouts are checked. + std::chrono::milliseconds const c_reqTimeout = std::chrono::milliseconds(300); ///< How long to wait for requests (evict, find iterations). + std::chrono::seconds const c_bucketRefresh = std::chrono::seconds(3600); ///< Refresh interval prevents bucket from becoming stale. [Kademlia] static unsigned dist(Address const& _a, Address const& _b) { u160 d = _a ^ _b; unsigned ret; for (ret = 0; d >>= 1; ++ret) {}; return ret; } @@ -151,7 +151,7 @@ protected: void evict(std::shared_ptr _leastSeen, std::shared_ptr _new); - void noteNode(Public _pubk, bi::udp::endpoint _endpoint); + void noteNode(Public const& _pubk, bi::udp::endpoint const& _endpoint); void noteNode(std::shared_ptr _n); @@ -234,11 +234,11 @@ struct PingNode: RLPXDatagram PingNode(bi::udp::endpoint _ep, std::string _src, uint16_t _srcPort, std::chrono::seconds _expiration = std::chrono::seconds(60)): RLPXDatagram(_ep), ipAddress(_src), port(_srcPort), expiration(futureFromEpoch(_expiration)) {} std::string ipAddress; // rlp encoded bytes min: 16 - uint16_t port; // rlp encoded bytes min: 1 max: 3 - uint64_t expiration; // rlp encoded bytes min: 1 max: 9 + unsigned port; // rlp encoded bytes min: 1 max: 3 + unsigned expiration; // rlp encoded bytes min: 1 max: 9 void streamRLP(RLPStream& _s) const { _s.appendList(3); _s << ipAddress << port << expiration; } - void interpretRLP(bytesConstRef _bytes) { RLP r(_bytes); ipAddress = (std::string)r[0]; port = (uint16_t)r[1]; expiration = (uint64_t)r[2]; } + void interpretRLP(bytesConstRef _bytes) { RLP r(_bytes); ipAddress = r[0].toString(); port = r[1].toInt(); expiration = r[2].toInt(); } }; /** @@ -280,10 +280,10 @@ struct FindNode: RLPXDatagram FindNode(bi::udp::endpoint _ep, Address _target, std::chrono::seconds _expiration = std::chrono::seconds(30)): RLPXDatagram(_ep), target(_target), expiration(futureFromEpoch(_expiration)) {} h160 target; - uint64_t expiration; + unsigned expiration; void streamRLP(RLPStream& _s) const { _s.appendList(2); _s << target << expiration; } - void interpretRLP(bytesConstRef _bytes) { RLP r(_bytes); target = (h160)r[0]; expiration = (uint64_t)r[1]; } + void interpretRLP(bytesConstRef _bytes) { RLP r(_bytes); target = r[0].toHash(); expiration = r[1].toInt(); } }; /** @@ -299,12 +299,16 @@ struct Neighbors: RLPXDatagram struct Node { Node() = default; - Node(bytesConstRef _bytes) { interpretRLP(_bytes); } + Node(RLP const& _r) { interpretRLP(_r); } std::string ipAddress; - uint16_t port; + unsigned port; NodeId node; - void streamRLP(RLPStream& _s) const { _s.appendList(3); _s << ipAddress << port << node; } - void interpretRLP(bytesConstRef _bytes) { RLP r(_bytes); ipAddress = r[0].toString(); port = (uint16_t)r[1]; node = (h512)r[2]; } + void streamRLP(RLPStream& _s) const { + _s.appendList(3); _s << ipAddress << port << node; + } + void interpretRLP(RLP const& _r) { + ipAddress = _r[0].toString(); port = _r[1].toInt(); node = h512(_r[2].toBytes()); + } }; using RLPXDatagram::RLPXDatagram; @@ -323,8 +327,10 @@ struct Neighbors: RLPXDatagram std::list nodes; h256 nonce; - void streamRLP(RLPStream& _s) const { _s.appendList(2); _s.appendList(nodes.size()); for (auto& n: nodes) n.streamRLP(_s); _s << nonce; } - void interpretRLP(bytesConstRef _bytes) { RLP r(_bytes); for (auto n: r[0]) nodes.push_back(Node(n.toBytesConstRef())); nonce = (h256)r[1]; } + void streamRLP(RLPStream& _s) const { _s.appendList(2); _s.appendList(nodes.size()); for (auto& n: nodes) n.streamRLP(_s); _s << 1; } + void interpretRLP(bytesConstRef _bytes) { + RLP r(_bytes); for (auto n: r[0]) nodes.push_back(Node(n)); nonce = (h256)r[1]; + } }; struct NodeTableWarn: public LogChannel { static const char* name() { return "!P!"; } static const int verbosity = 0; }; diff --git a/libp2p/UDP.h b/libp2p/UDP.h index 498d37f0c..82b89b9c8 100644 --- a/libp2p/UDP.h +++ b/libp2p/UDP.h @@ -221,7 +221,6 @@ void UDPSocket::doWrite() if (sendQ.empty()) return; } - clog(NoteChannel) << "sent datagram"; doWrite(); }); } diff --git a/test/net.cpp b/test/net.cpp index 274f729c6..d5113b8b4 100644 --- a/test/net.cpp +++ b/test/net.cpp @@ -57,14 +57,23 @@ struct TestNodeTable: public NodeTable { bi::address ourIp = bi::address::from_string("127.0.0.1"); for (auto& n: _testNodes) + { ping(bi::udp::endpoint(ourIp, n.second)); + this_thread::sleep_for(chrono::milliseconds(5)); + } } - void populate(std::vector> const& _testNodes) + void populate(std::vector> const& _testNodes, size_t _count = 0) { + if (!_count) + _count = _testNodes.size(); + bi::address ourIp = bi::address::from_string("127.0.0.1"); for (auto& n: _testNodes) - noteNode(n.first.pub(), bi::udp::endpoint(ourIp, n.second)); + if (_count--) + noteNode(n.first.pub(), bi::udp::endpoint(ourIp, n.second)); + else + break; } void reset() @@ -82,7 +91,7 @@ struct TestNodeTableHost: public TestHost TestNodeTableHost(): m_alias(KeyPair::create()), nodeTable(new TestNodeTable(m_io, m_alias)) {}; ~TestNodeTableHost() { m_io.stop(); stopWorking(); } - void generateTestNodes(int _count = 30) + void generateTestNodes(int _count = 16) { asserts(_count < 1000); static uint16_t s_basePort = 30500; @@ -105,11 +114,13 @@ struct TestNodeTableHost: public TestHost void pingAll() { nodeTable->pingAll(m_testNodes); +// for (auto& n: testNodes) +// n->pingAll(m_testNodes); } - void populate() + void populate(size_t _count = 0) { - nodeTable->populate(m_testNodes); + nodeTable->populate(m_testNodes, _count); } KeyPair m_alias; @@ -130,6 +141,13 @@ public: bool success = false; }; +BOOST_AUTO_TEST_CASE(test_findnode_neighbors) +{ + // Executing findNode should result in a list which is serialized + // into Neighbors packet. Neighbors packet should then be deserialized + // into the same list of nearest nodes. +} + BOOST_AUTO_TEST_CASE(kademlia) { TestNodeTableHost node; @@ -137,12 +155,23 @@ BOOST_AUTO_TEST_CASE(kademlia) node.nodeTable->join(); // ideally, joining with empty node table logs warning we can check for node.setup(); node.pingAll(); + clog << "NodeTable:\n" << *node.nodeTable.get() << endl; + this_thread::sleep_for(chrono::milliseconds(10000)); + + node.nodeTable->reset(); + clog << "NodeTable:\n" << *node.nodeTable.get() << endl; + + node.populate(2); + clog << "NodeTable:\n" << *node.nodeTable.get() << endl; this_thread::sleep_for(chrono::milliseconds(500)); - cout << "NodeTable:\n" << *node.nodeTable.get() << endl; +// node.nodeTable->join(); +// this_thread::sleep_for(chrono::milliseconds(2000)); +// +// clog << "NodeTable:\n" << *node.nodeTable.get() << endl; } -BOOST_AUTO_TEST_CASE(test_txrx_one) +BOOST_AUTO_TEST_CASE(test_udp_once) { UDPDatagram d(bi::udp::endpoint(boost::asio::ip::address::from_string("127.0.0.1"), 30300), bytes({65,65,65,65})); TestUDPSocket a; a.m_socket->connect(); a.start(); From d8323bbd09e3eec0a94e3ac8f1f56d2f6fd4ba34 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 25 Dec 2014 10:34:11 +0000 Subject: [PATCH 032/111] Simple ABI in/out and new Solidity-based Config/NameReg integration. --- alethzero/MainWin.cpp | 25 ++++++ libdevcore/Common.h | 3 + libdevcore/CommonData.cpp | 180 ++------------------------------------ libdevcore/CommonData.h | 3 + libdevcore/vector_ref.h | 2 +- libethereum/Client.cpp | 26 ++++++ libethereum/Client.h | 33 +++++++ libethereum/State.cpp | 9 +- 8 files changed, 102 insertions(+), 179 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 9cc651e4a..324868022 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -106,6 +106,8 @@ static QString contentsOfQResource(std::string const& res) } Address c_config = Address("661005d2720d855f1d9976f88bb10c1a3398c77f"); +Address c_newConfig = Address("d5f9d8d94886e70b06e474c3fb14fd43e2f23970"); +Address c_nameReg = Address("ddd1cea741d548f90d86fb87a3ae6492e18c03a1"); Main::Main(QWidget *parent) : QMainWindow(parent), @@ -450,6 +452,29 @@ static Public stringToPublic(QString const& _a) QString Main::pretty(dev::Address _a) const { + static std::map s_memos; + + if (!s_memos.count(_a)) + { + static Address s_newNameReg; + + if (!s_newNameReg) + s_newNameReg = abiOut
(ethereum()->call(c_newConfig, abiIn(1, (u256)1))); + + if (s_newNameReg) + { + QString s = QString::fromStdString(toString(abiOut(ethereum()->call(s_newNameReg, abiIn(2, _a))))); + if (s.size()) + { + s_memos[_a] = s; + return s; + } + } + } + else + if (s_memos[_a].size()) + return s_memos[_a]; + h256 n; if (h160 nameReg = (u160)ethereum()->stateAt(c_config, 0)) diff --git a/libdevcore/Common.h b/libdevcore/Common.h index 198119f24..11bee7aa5 100644 --- a/libdevcore/Common.h +++ b/libdevcore/Common.h @@ -74,6 +74,9 @@ using StringMap = std::map; using u256Map = std::map; using HexMap = std::map; +// Fixed-length string types. +using string32 = std::array; + // Null/Invalid values for convenience. static const u256 Invalid256 = ~(u256)0; static const bytes NullBytes; diff --git a/libdevcore/CommonData.cpp b/libdevcore/CommonData.cpp index fc3910cfe..b3abe4300 100644 --- a/libdevcore/CommonData.cpp +++ b/libdevcore/CommonData.cpp @@ -123,180 +123,10 @@ bytes dev::asNibbles(std::string const& _s) return ret; } -#if 0 - -/* Following code is copyright 2012-2014 Luke Dashjr - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the standard MIT license. See COPYING for more details. - */ - -#include -#include -#include -#include - -static const int8_t b58digits_map[] = { - -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, - -1, 0, 1, 2, 3, 4, 5, 6, 7, 8,-1,-1,-1,-1,-1,-1, - -1, 9,10,11,12,13,14,15, 16,-1,17,18,19,20,21,-1, - 22,23,24,25,26,27,28,29, 30,31,32,-1,-1,-1,-1,-1, - -1,33,34,35,36,37,38,39, 40,41,42,43,-1,44,45,46, - 47,48,49,50,51,52,53,54, 55,56,57,-1,-1,-1,-1,-1, -}; - -bool b58tobin(void *bin, size_t *binszp, const char *b58, size_t b58sz) -{ - size_t binsz = *binszp; - const unsigned char *b58u = (void*)b58; - unsigned char *binu = bin; - size_t outisz = (binsz + 3) / 4; - uint32_t outi[outisz]; - uint64_t t; - uint32_t c; - size_t i, j; - uint8_t bytesleft = binsz % 4; - uint32_t zeromask = bytesleft ? (0xffffffff << (bytesleft * 8)) : 0; - unsigned zerocount = 0; - - if (!b58sz) - b58sz = strlen(b58); - - memset(outi, 0, outisz * sizeof(*outi)); - - // Leading zeros, just count - for (i = 0; i < b58sz && !b58digits_map[b58u[i]]; ++i) - ++zerocount; - - for ( ; i < b58sz; ++i) - { - if (b58u[i] & 0x80) - // High-bit set on invalid digit - return false; - if (b58digits_map[b58u[i]] == -1) - // Invalid base58 digit - return false; - c = (unsigned)b58digits_map[b58u[i]]; - for (j = outisz; j--; ) - { - t = ((uint64_t)outi[j]) * 58 + c; - c = (t & 0x3f00000000) >> 32; - outi[j] = t & 0xffffffff; - } - if (c) - // Output number too big (carry to the next int32) - return false; - if (outi[0] & zeromask) - // Output number too big (last int32 filled too far) - return false; - } - - j = 0; - switch (bytesleft) { - case 3: - *(binu++) = (outi[0] & 0xff0000) >> 16; - case 2: - *(binu++) = (outi[0] & 0xff00) >> 8; - case 1: - *(binu++) = (outi[0] & 0xff); - ++j; - default: - break; - } - - for (; j < outisz; ++j) - { - *(binu++) = (outi[j] >> 0x18) & 0xff; - *(binu++) = (outi[j] >> 0x10) & 0xff; - *(binu++) = (outi[j] >> 8) & 0xff; - *(binu++) = (outi[j] >> 0) & 0xff; - } - - // Count canonical base58 byte count - binu = bin; - for (i = 0; i < binsz; ++i) - { - if (binu[i]) - break; - --*binszp; - } - *binszp += zerocount; - - return true; -} - -static -bool my_dblsha256(void *hash, const void *data, size_t datasz) +std::string dev::toString(string32 const& _s) { - uint8_t buf[0x20]; - return b58_sha256_impl(buf, data, datasz) && b58_sha256_impl(hash, buf, sizeof(buf)); -} - -int b58check(const void *bin, size_t binsz, const char *base58str, size_t b58sz) -{ - unsigned char buf[32]; - const uint8_t *binc = bin; - unsigned i; - if (binsz < 4) - return -4; - if (!my_dblsha256(buf, bin, binsz - 4)) - return -2; - if (memcmp(&binc[binsz - 4], buf, 4)) - return -1; - - // Check number of zeros is correct AFTER verifying checksum (to avoid possibility of accessing base58str beyond the end) - for (i = 0; binc[i] == '\0' && base58str[i] == '1'; ++i) - {} // Just finding the end of zeros, nothing to do in loop - if (binc[i] == '\0' || base58str[i] == '1') - return -3; - - return binc[0]; -} - -static const char b58digits_ordered[] = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; - -bool b58enc(char *b58, size_t *b58sz, const void *data, size_t binsz) -{ - const uint8_t *bin = data; - int carry; - size_t i, j, high, zcount = 0; - size_t size; - - while (zcount < binsz && !bin[zcount]) - ++zcount; - - size = (binsz - zcount) * 138 / 100 + 1; - uint8_t buf[size]; - memset(buf, 0, size); - - for (i = zcount, high = size - 1; i < binsz; ++i, high = j) - { - for (carry = bin[i], j = size - 1; (j > high) || carry; --j) - { - carry += 256 * buf[j]; - buf[j] = carry % 58; - carry /= 58; - } - } - - for (j = 0; j < size && !buf[j]; ++j); - - if (*b58sz <= zcount + size - j) - { - *b58sz = zcount + size - j + 1; - return false; - } - - if (zcount) - memset(b58, '1', zcount); - for (i = zcount; j < size; ++i, ++j) - b58[i] = b58digits_ordered[buf[j]]; - b58[i] = '\0'; - *b58sz = i + 1; - - return true; + std::string ret; + for (unsigned i = 0; i < 32 && _s[i]; ++i) + ret.push_back(_s[i]); + return ret; } - -#endif diff --git a/libdevcore/CommonData.h b/libdevcore/CommonData.h index 87d2f5e28..6fab67452 100644 --- a/libdevcore/CommonData.h +++ b/libdevcore/CommonData.h @@ -236,4 +236,7 @@ inline std::set<_T> operator+(std::set<_T> const& _a, std::set<_T> const& _b) return ret += _b; } +/// Make normal string from fixed-length string. +std::string toString(string32 const& _s); + } diff --git a/libdevcore/vector_ref.h b/libdevcore/vector_ref.h index db46d62f6..714c53b8c 100644 --- a/libdevcore/vector_ref.h +++ b/libdevcore/vector_ref.h @@ -40,7 +40,7 @@ public: vector_ref<_T> cropped(size_t _begin, size_t _count = ~size_t(0)) const { if (m_data && _begin + std::max(size_t(0), _count) <= m_count) return vector_ref<_T>(m_data + _begin, _count == ~size_t(0) ? m_count - _begin : _count); else return vector_ref<_T>(); } void retarget(_T const* _d, size_t _s) { m_data = _d; m_count = _s; } void retarget(std::vector<_T> const& _t) { m_data = _t.data(); m_count = _t.size(); } - void copyTo(vector_ref::type> _t) const { memcpy(_t.data(), m_data, std::min(_t.size(), m_count) * sizeof(_T)); } + void copyTo(vector_ref::type> _t) const { memcpy(_t.data(), m_data, std::min(_t.size(), m_count) * sizeof(_T)); memset(_t.data() + m_count, 0, std::max(_t.size(), m_count) - m_count); } _T* begin() { return m_data; } _T* end() { return m_data + m_count; } diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 02ef2d3be..c7ed4500c 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -353,6 +353,32 @@ bytes Client::call(Secret _secret, u256 _value, Address _dest, bytes const& _dat return out; } +bytes Client::call(Address _dest, bytes const& _data, u256 _gas, u256 _value, u256 _gasPrice) +{ + bytes out; + try + { + u256 n; + State temp; + KeyPair k = KeyPair::create(); + // cdebug << "Nonce at " << toAddress(_secret) << " pre:" << m_preMine.transactionsFrom(toAddress(_secret)) << " post:" << m_postMine.transactionsFrom(toAddress(_secret)); + { + ReadGuard l(x_stateDB); + temp = m_postMine; + temp.addBalance(k.address(), _gas * _gasPrice + _value); + n = temp.transactionsFrom(k.address()); + } + Transaction t(_value, _gasPrice, _gas, _dest, _data, n, k.secret()); + u256 gasUsed = temp.execute(m_bc, t.rlp(), &out, false); + (void)gasUsed; // TODO: do something with gasused which it returns. + } + catch (...) + { + // TODO: Some sort of notification of failure. + } + return out; +} + Address Client::transact(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas, u256 _gasPrice) { startWorking(); diff --git a/libethereum/Client.h b/libethereum/Client.h index e8c460093..a68a3ecd8 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -25,6 +25,8 @@ #include #include #include +#include +#include #include #include #include @@ -105,6 +107,34 @@ struct WorkChannel: public LogChannel { static const char* name() { return "-W-" #define cworkin dev::LogOutputStream() #define cworkout dev::LogOutputStream() +template struct ABISerialiser {}; +template struct ABISerialiser> { static bytes serialise(FixedHash const& _t) { return _t.asBytes(); } }; +template <> struct ABISerialiser { static bytes serialise(u256 const& _t) { return h256(_t).asBytes(); } }; +template <> struct ABISerialiser { static bytes serialise(u160 const& _t) { return h160(_t).asBytes(); } }; + +inline bytes abiInAux() { return {}; } +template bytes abiInAux(T const& _t, U const& ... _u) +{ + return ABISerialiser::serialise(_t) + abiInAux(_u ...); +} + +template bytes abiIn(byte _id, T const& ... _t) +{ + return bytes(1, _id) + abiInAux(_t ...); +} + +template struct ABIDeserialiser {}; +template struct ABIDeserialiser> { static FixedHash deserialise(bytesConstRef& io_t) { FixedHash ret(io_t.cropped(0, N).toBytes()); io_t = io_t.cropped(N); return ret; } }; +template <> struct ABIDeserialiser { static u256 deserialise(bytesConstRef& io_t) { u256 ret = fromBigEndian(io_t.cropped(0, 32)); io_t = io_t.cropped(32); return ret; } }; +template <> struct ABIDeserialiser { static u256 deserialise(bytesConstRef& io_t) { u160 ret = fromBigEndian(io_t.cropped(0, 20)); io_t = io_t.cropped(20); return ret; } }; +template <> struct ABIDeserialiser { static string32 deserialise(bytesConstRef& io_t) { string32 ret; io_t.cropped(0, 32).copyTo(vector_ref(ret.data(), 32)); io_t = io_t.cropped(32); return ret; } }; + +template T abiOut(bytes const& _data) +{ + bytesConstRef o(&_data); + return ABIDeserialiser::deserialise(o); +} + /** * @brief Main API hub for interfacing with Ethereum. */ @@ -135,6 +165,9 @@ public: /// Makes the given call. Nothing is recorded into the state. virtual bytes call(Secret _secret, u256 _value, Address _dest, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo); + /// Makes the given call. Nothing is recorded into the state. This cheats by creating a null address and endowing it with a lot of ETH. + virtual bytes call(Address _dest, bytes const& _data = bytes(), u256 _gas = 125000, u256 _value = 0, u256 _gasPrice = 1 * ether); + // Informational stuff // [NEW API] diff --git a/libethereum/State.cpp b/libethereum/State.cpp index e5d31d863..ecdf2dab3 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -998,9 +998,12 @@ bool State::isTrieGood(bool _enforceRefs, bool _requireNoLeftOvers) const LastHashes State::getLastHashes(BlockChain const& _bc) const { LastHashes ret; - unsigned n = (unsigned)m_previousBlock.number; - for (unsigned i = 0; i < 256; ++i) - ret[i] = _bc.numberHash(n - i); + if (c_protocolVersion > 49) + { + unsigned n = (unsigned)m_previousBlock.number; + for (unsigned i = 0; i < 256; ++i) + ret[i] = _bc.numberHash(n - i); + } return ret; } From 15afb23e5ad044bd4a5c1a60c7380ab4a574ca41 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 25 Dec 2014 11:36:55 +0000 Subject: [PATCH 033/111] More integration with SolNameReg --- alethzero/MainWin.cpp | 57 +++++++++++++++++++++++++++++++------------ libethereum/Client.h | 1 + 2 files changed, 43 insertions(+), 15 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 324868022..dbcd0f493 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -450,25 +450,23 @@ static Public stringToPublic(QString const& _a) return Public(); } +static Address g_newNameReg; + QString Main::pretty(dev::Address _a) const { static std::map s_memos; if (!s_memos.count(_a)) { - static Address s_newNameReg; - - if (!s_newNameReg) - s_newNameReg = abiOut
(ethereum()->call(c_newConfig, abiIn(1, (u256)1))); + if (!g_newNameReg) + g_newNameReg = abiOut
(ethereum()->call(c_newConfig, abiIn(1, (u256)1))); - if (s_newNameReg) + if (g_newNameReg) { - QString s = QString::fromStdString(toString(abiOut(ethereum()->call(s_newNameReg, abiIn(2, _a))))); + QString s = QString::fromStdString(toString(abiOut(ethereum()->call(g_newNameReg, abiIn(2, _a))))); + s_memos[_a] = s; if (s.size()) - { - s_memos[_a] = s; return s; - } } } else @@ -494,19 +492,47 @@ QString Main::render(dev::Address _a) const return QString::fromStdString(_a.abridged()); } -Address Main::fromString(QString const& _a) const +string32 fromString(std::string const& _s) +{ + string32 ret; + for (unsigned i = 0; i < 32 && i <= _s.size(); ++i) + ret[i] = i < _s.size() ? _s[i] : 0; + return ret; +} + +Address Main::fromString(QString const& _n) const { - if (_a == "(Create Contract)") + if (_n == "(Create Contract)") return Address(); - string sn = _a.toStdString(); + static std::map s_memos; + + if (!s_memos.count(_n)) + { + if (!g_newNameReg) + g_newNameReg = abiOut
(ethereum()->call(c_newConfig, abiIn(1, (u256)1))); + + if (g_newNameReg) + { + Address a = abiOut
(ethereum()->call(g_newNameReg, abiIn(0, ::fromString(_n.toStdString())))); + s_memos[_n] = a; + if (a) + return a; + } + } + else + if (s_memos[_n]) + return s_memos[_n]; + + string sn = _n.toStdString(); if (sn.size() > 32) sn.resize(32); h256 n; memcpy(n.data(), sn.data(), sn.size()); memset(n.data() + sn.size(), 0, 32 - sn.size()); - if (_a.size()) + if (_n.size()) { + if (h160 nameReg = (u160)ethereum()->stateAt(c_config, 0)) if (h256 a = ethereum()->stateAt(nameReg, n)) return right160(a); @@ -514,8 +540,9 @@ Address Main::fromString(QString const& _a) const if (h256 a = ethereum()->stateAt(m_nameReg, n)) return right160(a); } - if (_a.size() == 40) - return Address(fromHex(_a.toStdString())); + + if (_n.size() == 40) + return Address(fromHex(_n.toStdString())); else return Address(); } diff --git a/libethereum/Client.h b/libethereum/Client.h index a68a3ecd8..06c504355 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -111,6 +111,7 @@ template struct ABISerialiser {}; template struct ABISerialiser> { static bytes serialise(FixedHash const& _t) { return _t.asBytes(); } }; template <> struct ABISerialiser { static bytes serialise(u256 const& _t) { return h256(_t).asBytes(); } }; template <> struct ABISerialiser { static bytes serialise(u160 const& _t) { return h160(_t).asBytes(); } }; +template <> struct ABISerialiser { static bytes serialise(string32 const& _t) { return bytesConstRef((byte const*)_t.data(), 32).toBytes(); } }; inline bytes abiInAux() { return {}; } template bytes abiInAux(T const& _t, U const& ... _u) From 0a46ee464b5c1e6b4d1e942c694d1dd6b068c350 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 25 Dec 2014 11:45:10 +0000 Subject: [PATCH 034/111] Speed up basic calls. --- libethereum/Client.cpp | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index c7ed4500c..edad31c6d 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -27,6 +27,7 @@ #include #include #include "Defaults.h" +#include "Executive.h" #include "EthereumHost.h" using namespace std; using namespace dev; @@ -355,28 +356,24 @@ bytes Client::call(Secret _secret, u256 _value, Address _dest, bytes const& _dat bytes Client::call(Address _dest, bytes const& _data, u256 _gas, u256 _value, u256 _gasPrice) { - bytes out; try { - u256 n; State temp; - KeyPair k = KeyPair::create(); - // cdebug << "Nonce at " << toAddress(_secret) << " pre:" << m_preMine.transactionsFrom(toAddress(_secret)) << " post:" << m_postMine.transactionsFrom(toAddress(_secret)); +// cdebug << "Nonce at " << toAddress(_secret) << " pre:" << m_preMine.transactionsFrom(toAddress(_secret)) << " post:" << m_postMine.transactionsFrom(toAddress(_secret)); { ReadGuard l(x_stateDB); temp = m_postMine; - temp.addBalance(k.address(), _gas * _gasPrice + _value); - n = temp.transactionsFrom(k.address()); } - Transaction t(_value, _gasPrice, _gas, _dest, _data, n, k.secret()); - u256 gasUsed = temp.execute(m_bc, t.rlp(), &out, false); - (void)gasUsed; // TODO: do something with gasused which it returns. + Executive e(temp, LastHashes(), 0); + e.call(_dest, _dest, Address(), _value, _gasPrice, &_data, _gas, Address()); + e.go(); + return e.out().toBytes(); } catch (...) { // TODO: Some sort of notification of failure. } - return out; + return bytes(); } Address Client::transact(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas, u256 _gasPrice) From bf05c50c7855b25b73733b1abeb89892d7eb4509 Mon Sep 17 00:00:00 2001 From: subtly Date: Fri, 26 Dec 2014 00:56:50 +0100 Subject: [PATCH 035/111] test encoding/decoding neighbors. add MAC. --- libp2p/NodeTable.cpp | 21 ++++++--- libp2p/NodeTable.h | 24 +++++----- libp2p/UDP.cpp | 33 +++++++++----- test/net.cpp | 101 ++++++++++++++++++++++++++----------------- 4 files changed, 110 insertions(+), 69 deletions(-) diff --git a/libp2p/NodeTable.cpp b/libp2p/NodeTable.cpp index b5b261321..8024f0151 100644 --- a/libp2p/NodeTable.cpp +++ b/libp2p/NodeTable.cpp @@ -235,7 +235,7 @@ void NodeTable::noteNode(Public const& _pubk, bi::udp::endpoint const& _endpoint { Address id = right160(sha3(_pubk)); - // Don't add ourself (would result in -1 bucket lookup) + // Don't add ourself if (id == m_node.address()) return; @@ -303,18 +303,27 @@ NodeTable::NodeBucket& NodeTable::bucket(NodeEntry const* _n) void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytesConstRef _packet) { - if (_packet.size() < 69) + // h256 + Signature + RLP + if (_packet.size() < 100) { - clog(NodeTableMessageSummary) << "Invalid Message received from " << _from.address().to_string() << ":" << _from.port(); + clog(NodeTableMessageSummary) << "Invalid Message size received from " << _from.address().to_string() << ":" << _from.port(); + return; + } + + bytesConstRef signedBytes(_packet.cropped(h256::size, _packet.size() - h256::size)); + h256 hashSigned(sha3(signedBytes)); + if (!_packet.cropped(0, h256::size).contentsEqual(hashSigned.asBytes())) + { + clog(NodeTableMessageSummary) << "Invalid Message hash received from " << _from.address().to_string() << ":" << _from.port(); return; } // 3 items is PingNode, 2 items w/no lists is FindNode, 2 items w/first item as list is Neighbors, 1 item is Pong - bytesConstRef rlpBytes(_packet.cropped(65, _packet.size() - 65)); + bytesConstRef rlpBytes(signedBytes.cropped(Signature::size, signedBytes.size() - Signature::size)); RLP rlp(rlpBytes); unsigned itemCount = rlp.itemCount(); - bytesConstRef sigBytes(_packet.cropped(0, 65)); + bytesConstRef sigBytes(_packet.cropped(h256::size, Signature::size)); Public nodeid(dev::recover(*(Signature const*)sigBytes.data(), sha3(rlpBytes))); if (!nodeid) { @@ -339,8 +348,8 @@ void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytes if (rlp[0].isList()) { // todo: chunk neighbors packet - clog(NodeTableMessageSummary) << "Received Neighbors from " << _from.address().to_string() << ":" << _from.port(); Neighbors in = Neighbors::fromBytesConstRef(_from, rlpBytes); + clog(NodeTableMessageSummary) << "Received " << in.nodes.size() << " Neighbors from " << _from.address().to_string() << ":" << _from.port(); for (auto n: in.nodes) noteNode(n.node, bi::udp::endpoint(bi::address::from_string(n.ipAddress), n.port)); } diff --git a/libp2p/NodeTable.h b/libp2p/NodeTable.h index fe925fea8..399b48eaa 100644 --- a/libp2p/NodeTable.h +++ b/libp2p/NodeTable.h @@ -104,6 +104,8 @@ class NodeTable: UDPSocketEvents, public std::enable_shared_from_this }; public: + NodeTable(ba::io_service& _io, KeyPair _alias, uint16_t _port = 30300); + ~NodeTable(); /// Constants for Kademlia, mostly derived from address space. @@ -116,7 +118,6 @@ public: static constexpr unsigned s_bucketSize = 16; ///< Denoted by k in [Kademlia]. Number of nodes stored in each bucket. static constexpr unsigned s_alpha = 3; ///< Denoted by \alpha in [Kademlia]. Number of concurrent FindNode requests. - static constexpr uint16_t s_defaultPort = 30300; ///< Default port to listen on. /// Intervals @@ -125,9 +126,6 @@ public: std::chrono::seconds const c_bucketRefresh = std::chrono::seconds(3600); ///< Refresh interval prevents bucket from becoming stale. [Kademlia] static unsigned dist(Address const& _a, Address const& _b) { u160 d = _a ^ _b; unsigned ret; for (ret = 0; d >>= 1; ++ret) {}; return ret; } - - NodeTable(ba::io_service& _io, KeyPair _alias, uint16_t _port = s_defaultPort); - ~NodeTable(); void join(); @@ -233,9 +231,9 @@ struct PingNode: RLPXDatagram using RLPXDatagram::RLPXDatagram; PingNode(bi::udp::endpoint _ep, std::string _src, uint16_t _srcPort, std::chrono::seconds _expiration = std::chrono::seconds(60)): RLPXDatagram(_ep), ipAddress(_src), port(_srcPort), expiration(futureFromEpoch(_expiration)) {} - std::string ipAddress; // rlp encoded bytes min: 16 - unsigned port; // rlp encoded bytes min: 1 max: 3 - unsigned expiration; // rlp encoded bytes min: 1 max: 9 + std::string ipAddress; + unsigned port; + unsigned expiration; void streamRLP(RLPStream& _s) const { _s.appendList(3); _s << ipAddress << port << expiration; } void interpretRLP(bytesConstRef _bytes) { RLP r(_bytes); ipAddress = r[0].toString(); port = r[1].toInt(); expiration = r[2].toInt(); } @@ -248,6 +246,7 @@ struct PingNode: RLPXDatagram * Minimum Encoded Size: 33 bytes * Maximum Encoded Size: 33 bytes * + * @todo expiration * @todo value of replyTo * @todo create from PingNode (reqs RLPXDatagram verify flag) */ @@ -256,6 +255,7 @@ struct Pong: RLPXDatagram using RLPXDatagram::RLPXDatagram; h256 replyTo; // hash of rlp of PingNode + unsigned expiration; void streamRLP(RLPStream& _s) const { _s.appendList(1); _s << replyTo; } void interpretRLP(bytesConstRef _bytes) { RLP r(_bytes); replyTo = (h256)r[0]; } @@ -292,7 +292,7 @@ struct FindNode: RLPXDatagram * RLP Encoded Items: 2 (first item is list) * Minimum Encoded Size: 10 bytes * - * @todo nonce + * @todo nonce: Should be replaced with expiration. */ struct Neighbors: RLPXDatagram { @@ -312,7 +312,7 @@ struct Neighbors: RLPXDatagram }; using RLPXDatagram::RLPXDatagram; - Neighbors(bi::udp::endpoint _to, std::vector> const& _nearest): RLPXDatagram(_to), nonce(h256()) + Neighbors(bi::udp::endpoint _to, std::vector> const& _nearest): RLPXDatagram(_to) { for (auto& n: _nearest) { @@ -325,11 +325,11 @@ struct Neighbors: RLPXDatagram } std::list nodes; - h256 nonce; + unsigned expiration = 1; - void streamRLP(RLPStream& _s) const { _s.appendList(2); _s.appendList(nodes.size()); for (auto& n: nodes) n.streamRLP(_s); _s << 1; } + void streamRLP(RLPStream& _s) const { _s.appendList(2); _s.appendList(nodes.size()); for (auto& n: nodes) n.streamRLP(_s); _s << expiration; } void interpretRLP(bytesConstRef _bytes) { - RLP r(_bytes); for (auto n: r[0]) nodes.push_back(Node(n)); nonce = (h256)r[1]; + RLP r(_bytes); for (auto n: r[0]) nodes.push_back(Node(n)); expiration = r[1].toInt(); } }; diff --git a/libp2p/UDP.cpp b/libp2p/UDP.cpp index 42f5e4cab..8b60196e9 100644 --- a/libp2p/UDP.cpp +++ b/libp2p/UDP.cpp @@ -23,23 +23,32 @@ using namespace dev; using namespace dev::p2p; -//template h256 RLPXDatagramFace::sign(Secret const& _k) { - RLPStream packet; - streamRLP(packet); - bytes b(packet.out()); - h256 h(dev::sha3(b)); - Signature sig = dev::sign(_k, h); - data.resize(b.size() + Signature::size); - sig.ref().copyTo(&data); - memcpy(data.data() + sizeof(Signature), b.data(), b.size()); - return std::move(h); + RLPStream rlpstream; + streamRLP(rlpstream); + bytes rlpBytes(rlpstream.out()); + + bytesConstRef rlp(&rlpBytes); + h256 hash(dev::sha3(rlp)); + Signature sig = dev::sign(_k, hash); + + data.resize(h256::size + Signature::size + rlp.size()); + bytesConstRef packetHash(&data[0], h256::size); + bytesConstRef signedPayload(&data[h256::size], Signature::size + rlp.size()); + bytesConstRef payloadSig(&data[h256::size], Signature::size); + bytesConstRef payload(&data[h256::size+Signature::size], rlp.size()); + + sig.ref().copyTo(payloadSig); + rlp.copyTo(payload); + dev::sha3(signedPayload).ref().copyTo(packetHash); + + return std::move(hash); }; -//template Public RLPXDatagramFace::authenticate(bytesConstRef _sig, bytesConstRef _rlp) { Signature const& sig = *(Signature const*)_sig.data(); return std::move(dev::recover(sig, sha3(_rlp))); -}; \ No newline at end of file +}; + diff --git a/test/net.cpp b/test/net.cpp index d5113b8b4..4c45475f3 100644 --- a/test/net.cpp +++ b/test/net.cpp @@ -53,7 +53,23 @@ struct TestNodeTable: public NodeTable /// Constructor using NodeTable::NodeTable; - void pingAll(std::vector> const& _testNodes) + static std::vector> createTestNodes(int _count = 16) + { + std::vector> ret; + asserts(_count < 1000); + static uint16_t s_basePort = 30500; + + ret.clear(); + for (auto i = 0; i < _count; i++) + { + KeyPair k = KeyPair::create(); + ret.push_back(make_pair(k,s_basePort+i)); + } + + return std::move(ret); + } + + void pingTestNodes(std::vector> const& _testNodes) { bi::address ourIp = bi::address::from_string("127.0.0.1"); for (auto& n: _testNodes) @@ -63,7 +79,7 @@ struct TestNodeTable: public NodeTable } } - void populate(std::vector> const& _testNodes, size_t _count = 0) + void populateTestNodes(std::vector> const& _testNodes, size_t _count = 0) { if (!_count) _count = _testNodes.size(); @@ -88,44 +104,19 @@ struct TestNodeTable: public NodeTable */ struct TestNodeTableHost: public TestHost { - TestNodeTableHost(): m_alias(KeyPair::create()), nodeTable(new TestNodeTable(m_io, m_alias)) {}; + TestNodeTableHost(): m_alias(KeyPair::create()), nodeTable(new TestNodeTable(m_io, m_alias)), testNodes(TestNodeTable::createTestNodes()) {}; ~TestNodeTableHost() { m_io.stop(); stopWorking(); } - - void generateTestNodes(int _count = 16) - { - asserts(_count < 1000); - static uint16_t s_basePort = 30500; - - m_testNodes.clear(); - for (auto i = 0; i < _count; i++) - { - KeyPair k = KeyPair::create(); - m_testNodes.push_back(make_pair(k,s_basePort+i)); - testNodes.push_back(make_shared(m_io,k,s_basePort+i)); - } - } - std::vector> m_testNodes; // keypair and port - void setup() - { - generateTestNodes(); - } + void setup() { for (auto n: testNodes) nodeTables.push_back(make_shared(m_io,n.first,n.second)); } - void pingAll() - { - nodeTable->pingAll(m_testNodes); -// for (auto& n: testNodes) -// n->pingAll(m_testNodes); - } + void pingAll() { for (auto& t: nodeTables) t->pingTestNodes(testNodes); } - void populate(size_t _count = 0) - { - nodeTable->populate(m_testNodes, _count); - } + void populate(size_t _count = 0) { nodeTable->populateTestNodes(testNodes, _count); } KeyPair m_alias; shared_ptr nodeTable; - std::vector> testNodes; + std::vector> testNodes; // keypair and port + std::vector> nodeTables; }; class TestUDPSocket: UDPSocketEvents, public TestHost @@ -141,6 +132,36 @@ public: bool success = false; }; +BOOST_AUTO_TEST_CASE(test_neighbors_packet) +{ + KeyPair k = KeyPair::create(); + std::vector> testNodes(TestNodeTable::createTestNodes()); + bi::udp::endpoint to(boost::asio::ip::address::from_string("127.0.0.1"), 30000); + + Neighbors out(to); + for (auto n: testNodes) + { + Neighbors::Node node; + node.ipAddress = boost::asio::ip::address::from_string("127.0.0.1").to_string(); + node.port = n.second; + node.node = n.first.pub(); + out.nodes.push_back(node); + } + out.sign(k.sec()); + + bytesConstRef packet(out.data.data(), out.data.size()); + bytesConstRef rlpBytes(packet.cropped(97, packet.size() - 97)); + Neighbors in = Neighbors::fromBytesConstRef(to, rlpBytes); + int count = 0; + for (auto n: in.nodes) + { + BOOST_REQUIRE_EQUAL(testNodes[count].second, n.port); + BOOST_REQUIRE_EQUAL(testNodes[count].first.pub(), n.node); + BOOST_REQUIRE_EQUAL(sha3(testNodes[count].first.pub()), sha3(n.node)); + count++; + } +} + BOOST_AUTO_TEST_CASE(test_findnode_neighbors) { // Executing findNode should result in a list which is serialized @@ -154,21 +175,23 @@ BOOST_AUTO_TEST_CASE(kademlia) node.start(); node.nodeTable->join(); // ideally, joining with empty node table logs warning we can check for node.setup(); + node.populate(); + clog << "NodeTable:\n" << *node.nodeTable.get() << endl; + node.pingAll(); + this_thread::sleep_for(chrono::milliseconds(4000)); clog << "NodeTable:\n" << *node.nodeTable.get() << endl; - this_thread::sleep_for(chrono::milliseconds(10000)); node.nodeTable->reset(); clog << "NodeTable:\n" << *node.nodeTable.get() << endl; node.populate(2); - clog << "NodeTable:\n" << *node.nodeTable.get() << endl; this_thread::sleep_for(chrono::milliseconds(500)); + clog << "NodeTable:\n" << *node.nodeTable.get() << endl; -// node.nodeTable->join(); -// this_thread::sleep_for(chrono::milliseconds(2000)); -// -// clog << "NodeTable:\n" << *node.nodeTable.get() << endl; + node.nodeTable->join(); + this_thread::sleep_for(chrono::milliseconds(2000)); + clog << "NodeTable:\n" << *node.nodeTable.get() << endl; } BOOST_AUTO_TEST_CASE(test_udp_once) From d5f0679fb378f37e517c82dcf40977253eb94edf Mon Sep 17 00:00:00 2001 From: subtly Date: Fri, 26 Dec 2014 02:35:31 +0100 Subject: [PATCH 036/111] send multiple neighbors packets when size is over datagram size limit. --- libp2p/NodeTable.cpp | 22 ++++++++++++---------- libp2p/NodeTable.h | 33 ++++++++++++++++++++++----------- libp2p/UDP.h | 2 +- 3 files changed, 35 insertions(+), 22 deletions(-) diff --git a/libp2p/NodeTable.cpp b/libp2p/NodeTable.cpp index 8024f0151..64aabc2bb 100644 --- a/libp2p/NodeTable.cpp +++ b/libp2p/NodeTable.cpp @@ -306,7 +306,7 @@ void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytes // h256 + Signature + RLP if (_packet.size() < 100) { - clog(NodeTableMessageSummary) << "Invalid Message size received from " << _from.address().to_string() << ":" << _from.port(); + clog(NodeTableMessageSummary) << "Invalid Message size from " << _from.address().to_string() << ":" << _from.port(); return; } @@ -314,11 +314,10 @@ void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytes h256 hashSigned(sha3(signedBytes)); if (!_packet.cropped(0, h256::size).contentsEqual(hashSigned.asBytes())) { - clog(NodeTableMessageSummary) << "Invalid Message hash received from " << _from.address().to_string() << ":" << _from.port(); + clog(NodeTableMessageSummary) << "Invalid Message hash from " << _from.address().to_string() << ":" << _from.port(); return; } - - // 3 items is PingNode, 2 items w/no lists is FindNode, 2 items w/first item as list is Neighbors, 1 item is Pong + bytesConstRef rlpBytes(signedBytes.cropped(Signature::size, signedBytes.size() - Signature::size)); RLP rlp(rlpBytes); unsigned itemCount = rlp.itemCount(); @@ -327,7 +326,7 @@ void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytes Public nodeid(dev::recover(*(Signature const*)sigBytes.data(), sha3(rlpBytes))); if (!nodeid) { - clog(NodeTableMessageSummary) << "Invalid Message Signature from " << _from.address().to_string() << ":" << _from.port(); + clog(NodeTableMessageSummary) << "Invalid Message signature from " << _from.address().to_string() << ":" << _from.port(); return; } noteNode(nodeid, _from); @@ -347,7 +346,6 @@ void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytes case 2: if (rlp[0].isList()) { - // todo: chunk neighbors packet Neighbors in = Neighbors::fromBytesConstRef(_from, rlpBytes); clog(NodeTableMessageSummary) << "Received " << in.nodes.size() << " Neighbors from " << _from.address().to_string() << ":" << _from.port(); for (auto n: in.nodes) @@ -359,9 +357,13 @@ void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytes FindNode in = FindNode::fromBytesConstRef(_from, rlpBytes); std::vector> nearest = findNearest(in.target); - Neighbors out(_from, nearest); - out.sign(m_secret); - m_socketPtr->send(out); + static unsigned const nlimit = (m_socketPtr->maxDatagramSize - 11) / 86; + for (unsigned offset = 0; offset < nearest.size(); offset += nlimit) + { + Neighbors out(_from, nearest, offset, nlimit); + out.sign(m_secret); + m_socketPtr->send(out); + } } break; @@ -384,7 +386,7 @@ void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytes } catch (...) { - + // likely culprit is invalid rlp encoding } } diff --git a/libp2p/NodeTable.h b/libp2p/NodeTable.h index 399b48eaa..d8e886c31 100644 --- a/libp2p/NodeTable.h +++ b/libp2p/NodeTable.h @@ -21,6 +21,7 @@ #pragma once +#include #include #include #include @@ -109,15 +110,15 @@ public: /// Constants for Kademlia, mostly derived from address space. - static constexpr unsigned s_addressByteSize = sizeof(NodeEntry::id); ///< Size of address type in bytes. - static constexpr unsigned s_bits = 8 * s_addressByteSize; ///< Denoted by n in [Kademlia]. - static constexpr unsigned s_bins = s_bits - 1; ///< Size of m_state (excludes root, which is us). - static constexpr unsigned s_maxSteps = boost::static_log2::value; ///< Max iterations of discovery. (doFindNode) + static unsigned const s_addressByteSize = sizeof(NodeEntry::id); ///< Size of address type in bytes. + static unsigned const s_bits = 8 * s_addressByteSize; ///< Denoted by n in [Kademlia]. + static unsigned const s_bins = s_bits - 1; ///< Size of m_state (excludes root, which is us). + static unsigned const s_maxSteps = boost::static_log2::value; ///< Max iterations of discovery. (doFindNode) /// Chosen constants - static constexpr unsigned s_bucketSize = 16; ///< Denoted by k in [Kademlia]. Number of nodes stored in each bucket. - static constexpr unsigned s_alpha = 3; ///< Denoted by \alpha in [Kademlia]. Number of concurrent FindNode requests. + static unsigned const s_bucketSize = 16; ///< Denoted by k in [Kademlia]. Number of nodes stored in each bucket. + static unsigned const s_alpha = 3; ///< Denoted by \alpha in [Kademlia]. Number of concurrent FindNode requests. /// Intervals @@ -312,16 +313,26 @@ struct Neighbors: RLPXDatagram }; using RLPXDatagram::RLPXDatagram; - Neighbors(bi::udp::endpoint _to, std::vector> const& _nearest): RLPXDatagram(_to) + Neighbors(bi::udp::endpoint _to, std::vector> const& _nearest, unsigned _offset = 0, unsigned _limit = 0): RLPXDatagram(_to) { - for (auto& n: _nearest) + auto limit = _limit ? std::min(_nearest.size(), (size_t)(_offset + _limit)) : _nearest.size(); + for (auto i = _offset; i < limit; i++) { Node node; - node.ipAddress = n->endpoint.udp.address().to_string(); - node.port = n->endpoint.udp.port(); - node.node = n->publicKey(); + node.ipAddress = _nearest[i]->endpoint.udp.address().to_string(); + node.port = _nearest[i]->endpoint.udp.port(); + node.node = _nearest[i]->publicKey(); nodes.push_back(node); } + +// for (auto& n: _nearest) +// { +// Node node; +// node.ipAddress = n->endpoint.udp.address().to_string(); // 16 +// node.port = n->endpoint.udp.port(); // 3 +// node.node = n->publicKey();// 67 +// nodes.push_back(node); +// } } std::list nodes; diff --git a/libp2p/UDP.h b/libp2p/UDP.h index 82b89b9c8..6efe1908d 100644 --- a/libp2p/UDP.h +++ b/libp2p/UDP.h @@ -110,7 +110,7 @@ template class UDPSocket: UDPSocketFace, public std::enable_shared_from_this> { public: - static constexpr unsigned maxDatagramSize = MaxDatagramSize; + enum { maxDatagramSize = MaxDatagramSize }; static_assert(maxDatagramSize < 65507, "UDP datagrams cannot be larger than 65507 bytes"); UDPSocket(ba::io_service& _io, UDPSocketEvents& _host, unsigned _port): m_host(_host), m_endpoint(bi::udp::v4(), _port), m_socket(_io) { m_started.store(false); m_closed.store(true); }; From cffc27417a37fc2d737f69b19ea2895ca5a2a2c9 Mon Sep 17 00:00:00 2001 From: subtly Date: Fri, 26 Dec 2014 05:38:27 +0100 Subject: [PATCH 037/111] inline << operator, mute logging --- libp2p/NodeTable.cpp | 16 +++++++++++----- libp2p/NodeTable.h | 4 ++-- test/net.cpp | 14 +++++++------- 3 files changed, 20 insertions(+), 14 deletions(-) diff --git a/libp2p/NodeTable.cpp b/libp2p/NodeTable.cpp index 64aabc2bb..4cae6af0b 100644 --- a/libp2p/NodeTable.cpp +++ b/libp2p/NodeTable.cpp @@ -247,12 +247,18 @@ void NodeTable::noteNode(Public const& _pubk, bi::udp::endpoint const& _endpoint { node.reset(new NodeEntry(m_node, id, _pubk, _endpoint)); m_nodes[id] = node; +// clog(NodeTableMessageSummary) << "Adding node to cache: " << id; } else + { node = n->second; +// clog(NodeTableMessageSummary) << "Found node in cache: " << id; + } } - noteNode(node); + // todo: why is this necessary? + if (!!node) + noteNode(node); } void NodeTable::noteNode(std::shared_ptr _n) @@ -335,7 +341,7 @@ void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytes switch (itemCount) { case 1: { - clog(NodeTableMessageSummary) << "Received Pong from " << _from.address().to_string() << ":" << _from.port(); +// clog(NodeTableMessageSummary) << "Received Pong from " << _from.address().to_string() << ":" << _from.port(); Pong in = Pong::fromBytesConstRef(_from, rlpBytes); // whenever a pong is received, first check if it's in m_evictions @@ -347,13 +353,13 @@ void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytes if (rlp[0].isList()) { Neighbors in = Neighbors::fromBytesConstRef(_from, rlpBytes); - clog(NodeTableMessageSummary) << "Received " << in.nodes.size() << " Neighbors from " << _from.address().to_string() << ":" << _from.port(); +// clog(NodeTableMessageSummary) << "Received " << in.nodes.size() << " Neighbors from " << _from.address().to_string() << ":" << _from.port(); for (auto n: in.nodes) noteNode(n.node, bi::udp::endpoint(bi::address::from_string(n.ipAddress), n.port)); } else { - clog(NodeTableMessageSummary) << "Received FindNode from " << _from.address().to_string() << ":" << _from.port(); +// clog(NodeTableMessageSummary) << "Received FindNode from " << _from.address().to_string() << ":" << _from.port(); FindNode in = FindNode::fromBytesConstRef(_from, rlpBytes); std::vector> nearest = findNearest(in.target); @@ -369,7 +375,7 @@ void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytes case 3: { - clog(NodeTableMessageSummary) << "Received PingNode from " << _from.address().to_string() << ":" << _from.port(); +// clog(NodeTableMessageSummary) << "Received PingNode from " << _from.address().to_string() << ":" << _from.port(); PingNode in = PingNode::fromBytesConstRef(_from, rlpBytes); Pong p(_from); diff --git a/libp2p/NodeTable.h b/libp2p/NodeTable.h index d8e886c31..32a700d73 100644 --- a/libp2p/NodeTable.h +++ b/libp2p/NodeTable.h @@ -197,7 +197,7 @@ protected: boost::asio::deadline_timer m_evictionCheckTimer; ///< Timer for handling node evictions. }; -std::ostream& operator<<(std::ostream& _out, NodeTable const& _nodeTable) +inline std::ostream& operator<<(std::ostream& _out, NodeTable const& _nodeTable) { _out << _nodeTable.root().address() << "\t" << "0\t" << _nodeTable.root().endpoint.udp.address() << ":" << _nodeTable.root().endpoint.udp.port() << std::endl; auto s = _nodeTable.state(); @@ -205,7 +205,7 @@ std::ostream& operator<<(std::ostream& _out, NodeTable const& _nodeTable) _out << n.address() << "\t" << n.distance << "\t" << n.endpoint.udp.address() << ":" << n.endpoint.udp.port() << std::endl; return _out; } - + /** * Ping packet: Check if node is alive. * PingNode is cached and regenerated after expiration - t, where t is timeout. diff --git a/test/net.cpp b/test/net.cpp index 4c45475f3..d9b5d1579 100644 --- a/test/net.cpp +++ b/test/net.cpp @@ -53,14 +53,14 @@ struct TestNodeTable: public NodeTable /// Constructor using NodeTable::NodeTable; - static std::vector> createTestNodes(int _count = 16) + static std::vector> createTestNodes(unsigned _count) { std::vector> ret; asserts(_count < 1000); static uint16_t s_basePort = 30500; ret.clear(); - for (auto i = 0; i < _count; i++) + for (unsigned i = 0; i < _count; i++) { KeyPair k = KeyPair::create(); ret.push_back(make_pair(k,s_basePort+i)); @@ -75,7 +75,7 @@ struct TestNodeTable: public NodeTable for (auto& n: _testNodes) { ping(bi::udp::endpoint(ourIp, n.second)); - this_thread::sleep_for(chrono::milliseconds(5)); + this_thread::sleep_for(chrono::milliseconds(2)); } } @@ -104,7 +104,7 @@ struct TestNodeTable: public NodeTable */ struct TestNodeTableHost: public TestHost { - TestNodeTableHost(): m_alias(KeyPair::create()), nodeTable(new TestNodeTable(m_io, m_alias)), testNodes(TestNodeTable::createTestNodes()) {}; + TestNodeTableHost(unsigned _count = 8): m_alias(KeyPair::create()), nodeTable(new TestNodeTable(m_io, m_alias)), testNodes(TestNodeTable::createTestNodes(_count)) {}; ~TestNodeTableHost() { m_io.stop(); stopWorking(); } void setup() { for (auto n: testNodes) nodeTables.push_back(make_shared(m_io,n.first,n.second)); } @@ -135,7 +135,7 @@ public: BOOST_AUTO_TEST_CASE(test_neighbors_packet) { KeyPair k = KeyPair::create(); - std::vector> testNodes(TestNodeTable::createTestNodes()); + std::vector> testNodes(TestNodeTable::createTestNodes(16)); bi::udp::endpoint to(boost::asio::ip::address::from_string("127.0.0.1"), 30000); Neighbors out(to); @@ -171,7 +171,7 @@ BOOST_AUTO_TEST_CASE(test_findnode_neighbors) BOOST_AUTO_TEST_CASE(kademlia) { - TestNodeTableHost node; + TestNodeTableHost node(12); node.start(); node.nodeTable->join(); // ideally, joining with empty node table logs warning we can check for node.setup(); @@ -179,7 +179,7 @@ BOOST_AUTO_TEST_CASE(kademlia) clog << "NodeTable:\n" << *node.nodeTable.get() << endl; node.pingAll(); - this_thread::sleep_for(chrono::milliseconds(4000)); + this_thread::sleep_for(chrono::milliseconds(1000)); clog << "NodeTable:\n" << *node.nodeTable.get() << endl; node.nodeTable->reset(); From cf4c63a066b3c2a44e1d9c8594223d6361f7f5a4 Mon Sep 17 00:00:00 2001 From: subtly Date: Fri, 26 Dec 2014 06:56:05 +0100 Subject: [PATCH 038/111] try to fix windows build --- libp2p/NodeTable.h | 18 +++++++++++------- libp2p/UDP.h | 1 + 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/libp2p/NodeTable.h b/libp2p/NodeTable.h index 32a700d73..8457555d3 100644 --- a/libp2p/NodeTable.h +++ b/libp2p/NodeTable.h @@ -38,11 +38,16 @@ namespace p2p * Thread-safety is ensured by modifying NodeEntry details via * shared_ptr replacement instead of mutating values. * - * [Interface] + * [Integration] + * @todo deadline-timer which maintains tcp/peer connections * @todo restore nodes: affects refreshbuckets * @todo TCP endpoints * @todo makeRequired: don't try to evict node if node isRequired. * @todo makeRequired: exclude bucket from refresh if we have node as peer. + * + * [Optimization] + * @todo Pong to include ip:port where ping was received + * @todo expiration and sha3(id) 'to' for messages which are replies (prevents replay) * @todo std::shared_ptr m_cachedPingPacket; * @todo std::shared_ptr m_cachedFindSelfPacket; * @@ -57,7 +62,6 @@ namespace p2p * @todo ^ s_bitsPerStep = 5; // Denoted by b in [Kademlia]. Bits by which address space is divided. * @todo optimize (use tree for state and/or custom compare for cache) * @todo reputation (aka universal siblings lists) - * @todo dht (aka siblings) */ class NodeTable: UDPSocketEvents, public std::enable_shared_from_this { @@ -110,7 +114,7 @@ public: /// Constants for Kademlia, mostly derived from address space. - static unsigned const s_addressByteSize = sizeof(NodeEntry::id); ///< Size of address type in bytes. + static unsigned const s_addressByteSize = sizeof(Node::id); ///< Size of address type in bytes. static unsigned const s_bits = 8 * s_addressByteSize; ///< Denoted by n in [Kademlia]. static unsigned const s_bins = s_bits - 1; ///< Size of m_state (excludes root, which is us). static unsigned const s_maxSteps = boost::static_log2::value; ///< Max iterations of discovery. (doFindNode) @@ -229,7 +233,7 @@ inline std::ostream& operator<<(std::ostream& _out, NodeTable const& _nodeTable) */ struct PingNode: RLPXDatagram { - using RLPXDatagram::RLPXDatagram; + using RLPXDatagram::RLPXDatagram; PingNode(bi::udp::endpoint _ep, std::string _src, uint16_t _srcPort, std::chrono::seconds _expiration = std::chrono::seconds(60)): RLPXDatagram(_ep), ipAddress(_src), port(_srcPort), expiration(futureFromEpoch(_expiration)) {} std::string ipAddress; @@ -253,7 +257,7 @@ struct PingNode: RLPXDatagram */ struct Pong: RLPXDatagram { - using RLPXDatagram::RLPXDatagram; + using RLPXDatagram::RLPXDatagram; h256 replyTo; // hash of rlp of PingNode unsigned expiration; @@ -277,7 +281,7 @@ struct Pong: RLPXDatagram */ struct FindNode: RLPXDatagram { - using RLPXDatagram::RLPXDatagram; + using RLPXDatagram::RLPXDatagram; FindNode(bi::udp::endpoint _ep, Address _target, std::chrono::seconds _expiration = std::chrono::seconds(30)): RLPXDatagram(_ep), target(_target), expiration(futureFromEpoch(_expiration)) {} h160 target; @@ -312,7 +316,7 @@ struct Neighbors: RLPXDatagram } }; - using RLPXDatagram::RLPXDatagram; + using RLPXDatagram::RLPXDatagram; Neighbors(bi::udp::endpoint _to, std::vector> const& _nearest, unsigned _offset = 0, unsigned _limit = 0): RLPXDatagram(_to) { auto limit = _limit ? std::min(_nearest.size(), (size_t)(_offset + _limit)) : _nearest.size(); diff --git a/libp2p/UDP.h b/libp2p/UDP.h index 6efe1908d..cc8e58b9f 100644 --- a/libp2p/UDP.h +++ b/libp2p/UDP.h @@ -21,6 +21,7 @@ #pragma once +#include #include #include #include From 50a1edb23bf75970fc6324250834b77d2e2f3d97 Mon Sep 17 00:00:00 2001 From: arkpar Date: Sat, 27 Dec 2014 14:53:34 +0100 Subject: [PATCH 039/111] improved debugging model --- mix/AssemblyDebuggerControl.cpp | 172 +++++++++++++++-------------- mix/AssemblyDebuggerControl.h | 33 +++--- mix/AssemblyDebuggerModel.cpp | 27 ++--- mix/AssemblyDebuggerModel.h | 6 +- mix/CodeEditorExtensionManager.cpp | 4 +- mix/CodeModel.cpp | 12 +- mix/CodeModel.h | 22 ++-- mix/ConstantCompilationControl.cpp | 11 ++ mix/ConstantCompilationControl.h | 1 + mix/MixApplication.cpp | 2 + mix/qml/StateList.qml | 13 ++- mix/qml/main.qml | 7 +- 12 files changed, 179 insertions(+), 131 deletions(-) diff --git a/mix/AssemblyDebuggerControl.cpp b/mix/AssemblyDebuggerControl.cpp index 528d965c3..22e772409 100644 --- a/mix/AssemblyDebuggerControl.cpp +++ b/mix/AssemblyDebuggerControl.cpp @@ -22,6 +22,8 @@ #include #include #include +#include +#include #include #include #include @@ -55,7 +57,8 @@ QString toQString(dev::u256 _value) return QString::fromStdString(s.str()); } -AssemblyDebuggerControl::AssemblyDebuggerControl(AppContext* _context): Extension(_context, ExtensionDisplayBehavior::ModalDialog) +AssemblyDebuggerControl::AssemblyDebuggerControl(AppContext* _context): + Extension(_context, ExtensionDisplayBehavior::ModalDialog), m_running(false) { qRegisterMetaType("QVariableDefinition*"); qRegisterMetaType("QVariableDefinitionList*"); @@ -63,14 +66,11 @@ AssemblyDebuggerControl::AssemblyDebuggerControl(AppContext* _context): Extensio qRegisterMetaType>("QList"); qRegisterMetaType("QVariableDeclaration*"); qRegisterMetaType("AssemblyDebuggerData"); - qRegisterMetaType("DebuggingStatusResult"); - connect(this, SIGNAL(dataAvailable(bool, DebuggingStatusResult, QList, QList, AssemblyDebuggerData)), - this, SLOT(updateGUI(bool, DebuggingStatusResult, QList, QList, AssemblyDebuggerData)), Qt::QueuedConnection); + connect(this, &AssemblyDebuggerControl::dataAvailable, this, &AssemblyDebuggerControl::showDebugger, Qt::QueuedConnection); + m_modelDebugger = std::unique_ptr(new AssemblyDebuggerModel); _context->appEngine()->rootContext()->setContextProperty("debugModel", this); - - m_modelDebugger = std::unique_ptr(new AssemblyDebuggerModel); } QString AssemblyDebuggerControl::contentUrl() const @@ -80,7 +80,7 @@ QString AssemblyDebuggerControl::contentUrl() const QString AssemblyDebuggerControl::title() const { - return QApplication::tr("debugger"); + return QApplication::tr("Debugger"); } void AssemblyDebuggerControl::start() const @@ -89,7 +89,7 @@ void AssemblyDebuggerControl::start() const void AssemblyDebuggerControl::debugDeployment() { - deployContract(); + executeSequence(std::vector(), 0); } void AssemblyDebuggerControl::debugState(QVariantMap _state) @@ -97,8 +97,7 @@ void AssemblyDebuggerControl::debugState(QVariantMap _state) u256 balance = fromQString(_state.value("balance").toString()); QVariantList transactions = _state.value("transactions").toList(); - resetState(); - deployContract(); + std::vector transactionSequence; for (auto const& t : transactions) { @@ -114,93 +113,106 @@ void AssemblyDebuggerControl::debugState(QVariantMap _state) for (auto p = params.cbegin(); p != params.cend(); ++p) transactionSettings.parameterValues.insert(std::make_pair(p.key(), fromQString(p.value().toString()))); - runTransaction(transactionSettings); + transactionSequence.push_back(transactionSettings); } + executeSequence(transactionSequence, balance); } -void AssemblyDebuggerControl::resetState() -{ - m_modelDebugger->resetState(); - m_ctx->displayMessageDialog(QApplication::tr("State status"), QApplication::tr("State reseted ... need to redeploy contract")); -} - -void AssemblyDebuggerControl::callContract(TransactionSettings _tr, dev::Address _contract) +void AssemblyDebuggerControl::executeSequence(std::vector const& _sequence, u256 _balance) { + if (m_running) + throw (std::logic_error("debugging already running")); auto compilerRes = m_ctx->codeModel()->code(); - if (!compilerRes->successfull()) - m_ctx->displayMessageDialog("debugger","compilation failed"); - else + std::shared_ptr contractDef = compilerRes->sharedContract(); + m_running = true; + + emit runStarted(); + emit stateChanged(); + + //run sequence + QtConcurrent::run([=]() { - ContractCallDataEncoder c; - QContractDefinition const* contractDef = compilerRes->contract(); - QFunctionDefinition* f = nullptr; - for (int k = 0; k < contractDef->functionsList().size(); k++) + try { - if (contractDef->functionsList().at(k)->name() == _tr.functionId) + bytes contractCode = compilerRes->bytes(); + std::vector transactonData; + QFunctionDefinition* f; + ContractCallDataEncoder c; + //encode data for all transactions + for (auto const& t : _sequence) { - f = contractDef->functionsList().at(k); - break; + f = nullptr; + for (int k = 0; k < contractDef->functionsList().size(); k++) + { + if (contractDef->functionsList().at(k)->name() == t.functionId) + { + f = contractDef->functionsList().at(k); + break; + } + } + if (!f) + throw std::runtime_error("function " + t.functionId.toStdString() + " not found"); + + c.encode(f->index()); + for (int k = 0; k < f->parametersList().size(); k++) + { + QVariableDeclaration* var = (QVariableDeclaration*)f->parametersList().at(k); + u256 value = 0; + auto v = t.parameterValues.find(var->name()); + if (v != t.parameterValues.cend()) + value = v->second; + c.encode(var, value); + } + transactonData.emplace_back(c.encodedData()); } - } - if (!f) - m_ctx->displayMessageDialog(QApplication::tr("debugger"), QApplication::tr("function not found. Please redeploy this contract.")); - else - { - c.encode(f->index()); - for (int k = 0; k < f->parametersList().size(); k++) + + //run contract creation first + m_modelDebugger->resetState(_balance); + DebuggingContent debuggingContent = m_modelDebugger->deployContract(contractCode); + Address address = debuggingContent.contractAddress; + for (unsigned i = 0; i < _sequence.size(); ++i) + debuggingContent = m_modelDebugger->callContract(address, transactonData.at(i), _sequence.at(i)); + + if (f) + debuggingContent.returnParameters = c.decode(f->returnParameters(), debuggingContent.returnValue); + + //we need to wrap states in a QObject before sending to QML. + QList wStates; + for(int i = 0; i < debuggingContent.machineStates.size(); i++) { - QVariableDeclaration* var = (QVariableDeclaration*)f->parametersList().at(k); - c.encode(var, _tr.parameterValues[var->name()]); + QPointer s(new DebuggingStateWrapper(debuggingContent.executionCode, debuggingContent.executionData.toBytes())); + s->setState(debuggingContent.machineStates.at(i)); + wStates.append(s); } - DebuggingContent debuggingContent = m_modelDebugger->callContract(_contract, c.encodedData(), _tr); - debuggingContent.returnParameters = c.decode(f->returnParameters(), debuggingContent.returnValue); - finalizeExecution(debuggingContent); + //collect states for last transaction + AssemblyDebuggerData code = DebuggingStateWrapper::getHumanReadableCode(debuggingContent.executionCode); + emit dataAvailable(debuggingContent.returnParameters, wStates, code); + emit runComplete(); + } + catch(boost::exception const& e) + { + emit runFailed(QString::fromStdString(boost::current_exception_diagnostic_information())); } - } -} - -void AssemblyDebuggerControl::deployContract() -{ - auto compilerRes = m_ctx->codeModel()->code(); - if (!compilerRes->successfull()) - emit dataAvailable(false, DebuggingStatusResult::Compilationfailed); - else - { - m_previousDebugResult = m_modelDebugger->deployContract(compilerRes->bytes()); - finalizeExecution(m_previousDebugResult); - } -} -void AssemblyDebuggerControl::finalizeExecution(DebuggingContent _debuggingContent) -{ - //we need to wrap states in a QObject before sending to QML. - QList wStates; - for(int i = 0; i < _debuggingContent.machineStates.size(); i++) - { - QPointer s(new DebuggingStateWrapper(_debuggingContent.executionCode, _debuggingContent.executionData.toBytes())); - s->setState(_debuggingContent.machineStates.at(i)); - wStates.append(s); - } - AssemblyDebuggerData code = DebuggingStateWrapper::getHumanReadableCode(_debuggingContent.executionCode); - emit dataAvailable(true, DebuggingStatusResult::Ok, _debuggingContent.returnParameters, wStates, code); + catch(std::exception const& e) + { + emit runFailed(e.what()); + } + m_running = false; + emit stateChanged(); + }); } -void AssemblyDebuggerControl::updateGUI(bool _success, DebuggingStatusResult const& _reason, QList const& _returnParam, QList const& _wStates, AssemblyDebuggerData const& _code) +void AssemblyDebuggerControl::showDebugger(QList const& _returnParam, QList const& _wStates, AssemblyDebuggerData const& _code) { - Q_UNUSED(_reason); - if (_success) - { - m_appEngine->rootContext()->setContextProperty("debugStates", QVariant::fromValue(_wStates)); - m_appEngine->rootContext()->setContextProperty("humanReadableExecutionCode", QVariant::fromValue(std::get<0>(_code))); - m_appEngine->rootContext()->setContextProperty("bytesCodeMapping", QVariant::fromValue(std::get<1>(_code))); - m_appEngine->rootContext()->setContextProperty("contractCallReturnParameters", QVariant::fromValue(new QVariableDefinitionList(_returnParam))); - this->addContentOn(this); - } - else - m_ctx->displayMessageDialog(QApplication::tr("debugger"), QApplication::tr("compilation failed")); + m_appEngine->rootContext()->setContextProperty("debugStates", QVariant::fromValue(_wStates)); + m_appEngine->rootContext()->setContextProperty("humanReadableExecutionCode", QVariant::fromValue(std::get<0>(_code))); + m_appEngine->rootContext()->setContextProperty("bytesCodeMapping", QVariant::fromValue(std::get<1>(_code))); + m_appEngine->rootContext()->setContextProperty("contractCallReturnParameters", QVariant::fromValue(new QVariableDefinitionList(_returnParam))); + this->addContentOn(this); } -void AssemblyDebuggerControl::runTransaction(TransactionSettings const& _tr) +void AssemblyDebuggerControl::showDebugError(QString const& _error) { - callContract(_tr, m_previousDebugResult.contractAddress); + m_ctx->displayMessageDialog(QApplication::tr("Debugger"), _error); } diff --git a/mix/AssemblyDebuggerControl.h b/mix/AssemblyDebuggerControl.h index aaab913af..f56e85b3f 100644 --- a/mix/AssemblyDebuggerControl.h +++ b/mix/AssemblyDebuggerControl.h @@ -28,14 +28,8 @@ #include "AssemblyDebuggerModel.h" using AssemblyDebuggerData = std::tuple, dev::mix::QQMLMap*>; -enum DebuggingStatusResult -{ - Ok, - Compilationfailed -}; Q_DECLARE_METATYPE(AssemblyDebuggerData) -Q_DECLARE_METATYPE(DebuggingStatusResult) Q_DECLARE_METATYPE(dev::mix::DebuggingContent) class AppContext; @@ -59,26 +53,35 @@ public: QString title() const override; QString contentUrl() const override; + Q_PROPERTY(bool running MEMBER m_running NOTIFY stateChanged) + private: - void deployContract(); - void callContract(TransactionSettings _tr, Address _contract); - void finalizeExecution(DebuggingContent _content); + void executeSequence(std::vector const& _sequence, u256 _balance); std::unique_ptr m_modelDebugger; - DebuggingContent m_previousDebugResult; //TODO: to be replaced in a more consistent struct. Used for now to keep the contract address in case of future transaction call. + bool m_running; public slots: + /// Run the contract constructor and show debugger window. void debugDeployment(); + /// Setup state, run transaction sequence, show debugger for the last transaction + /// @param _state JS object with state configuration void debugState(QVariantMap _state); - void resetState(); + +private slots: /// Update UI with machine states result. Display a modal dialog. - void updateGUI(bool _success, DebuggingStatusResult const& _reason, QList const& _returnParams = QList(), QList const& _wStates = QList(), AssemblyDebuggerData const& _code = AssemblyDebuggerData()); - /// Run the given transaction. - void runTransaction(TransactionSettings const& _tr); + void showDebugger(QList const& _returnParams = QList(), QList const& _wStates = QList(), AssemblyDebuggerData const& _code = AssemblyDebuggerData()); + void showDebugError(QString const& _error); + signals: + void runStarted(); + void runComplete(); + void runFailed(QString const& _message); + void stateChanged(); + /// Emited when machine states are available. - void dataAvailable(bool _success, DebuggingStatusResult const& _reason, QList const& _returnParams = QList(), QList const& _wStates = QList(), AssemblyDebuggerData const& _code = AssemblyDebuggerData()); + void dataAvailable(QList const& _returnParams = QList(), QList const& _wStates = QList(), AssemblyDebuggerData const& _code = AssemblyDebuggerData()); }; } diff --git a/mix/AssemblyDebuggerModel.cpp b/mix/AssemblyDebuggerModel.cpp index 44789e8f9..8618b457f 100644 --- a/mix/AssemblyDebuggerModel.cpp +++ b/mix/AssemblyDebuggerModel.cpp @@ -41,20 +41,17 @@ namespace mix { AssemblyDebuggerModel::AssemblyDebuggerModel(): - m_userAccount(KeyPair::create()), - m_baseState(Address(), m_overlayDB, BaseState::Empty) + m_userAccount(KeyPair::create()) { - m_baseState.addBalance(m_userAccount.address(), 10000000 * ether); - m_executiveState = m_baseState; - m_currentExecution = std::unique_ptr(new Executive(m_executiveState, 0)); + resetState(10000000 * ether); } DebuggingContent AssemblyDebuggerModel::executeTransaction(bytesConstRef const& _rawTransaction) { QList machineStates; // Reset the state back to our clean premine. - m_currentExecution = std::unique_ptr(new Executive(m_executiveState, 0)); - m_currentExecution->setup(_rawTransaction); + eth::Executive execution(m_executiveState, 0); + execution.setup(_rawTransaction); std::vector levels; bytes code; bytesConstRef data; @@ -80,12 +77,12 @@ DebuggingContent AssemblyDebuggerModel::executeTransaction(bytesConstRef const& vm.stack(), vm.memory(), gasCost, ext.state().storage(ext.myAddress), levels})); }; - m_currentExecution->go(onOp); - m_currentExecution->finalize(onOp); + execution.go(onOp); + execution.finalize(onOp); m_executiveState.completeMine(); DebuggingContent d; - d.returnValue = m_currentExecution->out().toVector(); + d.returnValue = execution.out().toVector(); d.machineStates = machineStates; d.executionCode = code; d.executionData = data; @@ -99,7 +96,7 @@ DebuggingContent AssemblyDebuggerModel::deployContract(bytes const& _code) u256 gasPrice = 10000000000000; u256 gas = 1000000; u256 amount = 100; - Transaction _tr(amount, gasPrice, min(gas, m_baseState.gasLimitRemaining()), _code, m_executiveState.transactionsFrom(dev::toAddress(m_userAccount.secret())), m_userAccount.secret()); + Transaction _tr(amount, gasPrice, min(gas, m_executiveState.gasLimitRemaining()), _code, m_executiveState.transactionsFrom(dev::toAddress(m_userAccount.secret())), m_userAccount.secret()); bytes b = _tr.rlp(); dev::bytesConstRef bytesRef = &b; DebuggingContent d = executeTransaction(bytesRef); @@ -110,7 +107,7 @@ DebuggingContent AssemblyDebuggerModel::deployContract(bytes const& _code) DebuggingContent AssemblyDebuggerModel::callContract(Address const& _contract, bytes const& _data, TransactionSettings const& _tr) { - Transaction tr = Transaction(_tr.value, _tr.gasPrice, min(_tr.gas, m_baseState.gasLimitRemaining()), _contract, _data, m_executiveState.transactionsFrom(dev::toAddress(m_userAccount.secret())), m_userAccount.secret()); + Transaction tr = Transaction(_tr.value, _tr.gasPrice, min(_tr.gas, m_executiveState.gasLimitRemaining()), _contract, _data, m_executiveState.transactionsFrom(dev::toAddress(m_userAccount.secret())), m_userAccount.secret()); bytes b = tr.rlp(); dev::bytesConstRef bytesRef = &b; DebuggingContent d = executeTransaction(bytesRef); @@ -118,10 +115,10 @@ DebuggingContent AssemblyDebuggerModel::callContract(Address const& _contract, b return d; } -void AssemblyDebuggerModel::resetState() +void AssemblyDebuggerModel::resetState(u256 _balance) { - // Reset the state back to our clean premine. - m_executiveState = m_baseState; + m_executiveState = eth::State(Address(), m_overlayDB, BaseState::Empty); + m_executiveState.addBalance(m_userAccount.address(), _balance); } } diff --git a/mix/AssemblyDebuggerModel.h b/mix/AssemblyDebuggerModel.h index 833c6fa6e..db4b87f8f 100644 --- a/mix/AssemblyDebuggerModel.h +++ b/mix/AssemblyDebuggerModel.h @@ -66,15 +66,13 @@ public: DebuggingContent callContract(Address const& _contract, bytes const& _data, TransactionSettings const& _tr); /// Deploy the contract described by _code. DebuggingContent deployContract(bytes const& _code); - /// Reset state to the base state. - void resetState(); + /// Reset state to the empty state with given balance. + void resetState(u256 _balance); private: KeyPair m_userAccount; OverlayDB m_overlayDB; - eth::State m_baseState; eth::State m_executiveState; - std::unique_ptr m_currentExecution; DebuggingContent executeTransaction(dev::bytesConstRef const& _rawTransaction); }; diff --git a/mix/CodeEditorExtensionManager.cpp b/mix/CodeEditorExtensionManager.cpp index d2282655e..df43cac48 100644 --- a/mix/CodeEditorExtensionManager.cpp +++ b/mix/CodeEditorExtensionManager.cpp @@ -64,11 +64,13 @@ void CodeEditorExtensionManager::loadEditor(QQuickItem* _editor) void CodeEditorExtensionManager::initExtensions() { - initExtension(std::make_shared(m_appContext)); + std::shared_ptr output = std::make_shared(m_appContext); std::shared_ptr debug = std::make_shared(m_appContext); std::shared_ptr stateList = std::make_shared(m_appContext); QObject::connect(m_doc, &QTextDocument::contentsChanged, [=]() { m_appContext->codeModel()->registerCodeChange(m_doc->toPlainText()); }); + QObject::connect(debug.get(), &AssemblyDebuggerControl::runFailed, output.get(), &ConstantCompilationControl::displayError); + initExtension(output); initExtension(debug); initExtension(stateList); } diff --git a/mix/CodeModel.cpp b/mix/CodeModel.cpp index bafc42faa..b907c2e64 100644 --- a/mix/CodeModel.cpp +++ b/mix/CodeModel.cpp @@ -63,7 +63,7 @@ CompilationResult::CompilationResult(CompilationResult const& _prev, QString con {} CodeModel::CodeModel(QObject* _parent) : QObject(_parent), - m_result(new CompilationResult(nullptr)), m_backgroundWorker(this), m_backgroundJobId(0) + m_compiling(false), m_result(new CompilationResult(nullptr)), m_backgroundWorker(this), m_backgroundJobId(0) { m_backgroundWorker.moveToThread(&m_backgroundThread); connect(this, &CodeModel::scheduleCompilationJob, &m_backgroundWorker, &BackgroundWorker::queueCodeChange, Qt::QueuedConnection); @@ -94,10 +94,11 @@ void CodeModel::registerCodeChange(const QString &_code) { // launch the background thread m_backgroundJobId++; + m_compiling = true; + emit stateChanged(); emit scheduleCompilationJob(m_backgroundJobId, _code); } - void CodeModel::runCompilationJob(int _jobId, QString const& _code) { if (_jobId != m_backgroundJobId) @@ -124,11 +125,18 @@ void CodeModel::runCompilationJob(int _jobId, QString const& _code) void CodeModel::onCompilationComplete(CompilationResult*_newResult) { + m_compiling = false; m_result.reset(_newResult); emit compilationComplete(); + emit stateChanged(); if (m_result->successfull()) emit codeChanged(); } +bool CodeModel::hasContract() const +{ + return m_result->contract()->functionsList().size() > 0; +} + } } diff --git a/mix/CodeModel.h b/mix/CodeModel.h index c33110226..091c41843 100644 --- a/mix/CodeModel.h +++ b/mix/CodeModel.h @@ -69,8 +69,10 @@ public: /// Failed compilation result constructor CompilationResult(CompilationResult const& _prev, QString const& _compilerMessage, QObject* parent); - /// @returns contract definition + /// @returns contract definition for QML property QContractDefinition* contract() { return m_contract.get(); } + /// @returns contract definition + std::shared_ptr sharedContract() { return m_contract; } /// Indicates if the compilation was successfull bool successfull() const { return m_successfull; } @@ -96,12 +98,6 @@ private: /// Background code compiler class CodeModel : public QObject { - enum Status - { - Idle, ///< No compiation in progress - Compiling, ///< Compilation currently in progress - }; - Q_OBJECT public: @@ -114,10 +110,17 @@ public: CompilationResult const* code() const { return m_result.get(); } Q_PROPERTY(CompilationResult* code READ code NOTIFY codeChanged) + Q_PROPERTY(bool compiling READ isCompiling NOTIFY stateChanged) + Q_PROPERTY(bool hasContract READ hasContract NOTIFY codeChanged) + + /// @returns compilation status + bool isCompiling() const { return m_compiling; } + /// @returns true if contract has at least one function + bool hasContract() const; signals: - /// Emited on compilation status change - void statusChanged(Status _from, Status _to); + /// Emited on compilation state change + void stateChanged(); /// Emitted on compilation complete void compilationComplete(); /// Internal signal used to transfer compilation job to background thread @@ -138,6 +141,7 @@ private: void runCompilationJob(int _jobId, QString const& _content); void stop(); + bool m_compiling; std::unique_ptr m_result; QThread m_backgroundThread; BackgroundWorker m_backgroundWorker; diff --git a/mix/ConstantCompilationControl.cpp b/mix/ConstantCompilationControl.cpp index 6fc684860..e2d69bf62 100644 --- a/mix/ConstantCompilationControl.cpp +++ b/mix/ConstantCompilationControl.cpp @@ -37,6 +37,7 @@ using namespace dev::mix; ConstantCompilationControl::ConstantCompilationControl(AppContext* _context): Extension(_context, ExtensionDisplayBehavior::Tab) { connect(_context->codeModel(), &CodeModel::compilationComplete, this, &ConstantCompilationControl::update); + connect(_context->codeModel(), &CodeModel::compilationComplete, this, &ConstantCompilationControl::update); } QString ConstantCompilationControl::contentUrl() const @@ -80,3 +81,13 @@ void ConstantCompilationControl::resetOutPut() status->setProperty("text", ""); content->setProperty("text", ""); } + + +void ConstantCompilationControl::displayError(QString const& _error) +{ + QObject* status = m_view->findChild("status", Qt::FindChildrenRecursively); + QObject* content = m_view->findChild("content", Qt::FindChildrenRecursively); + status->setProperty("text", "failure"); + status->setProperty("color", "red"); + content->setProperty("text", _error); +} diff --git a/mix/ConstantCompilationControl.h b/mix/ConstantCompilationControl.h index fa056424e..227ad6080 100644 --- a/mix/ConstantCompilationControl.h +++ b/mix/ConstantCompilationControl.h @@ -45,6 +45,7 @@ private: public slots: void update(); + void displayError(QString const& _error); }; } diff --git a/mix/MixApplication.cpp b/mix/MixApplication.cpp index c2e856d8e..5cf71aa7d 100644 --- a/mix/MixApplication.cpp +++ b/mix/MixApplication.cpp @@ -25,6 +25,8 @@ #include "MixApplication.h" #include "AppContext.h" +#include + using namespace dev::mix; MixApplication::MixApplication(int _argc, char* _argv[]): diff --git a/mix/qml/StateList.qml b/mix/qml/StateList.qml index f22df3d39..152a35671 100644 --- a/mix/qml/StateList.qml +++ b/mix/qml/StateList.qml @@ -35,8 +35,7 @@ Rectangle { Button { anchors.bottom: parent.bottom - text: qsTr("Add") - onClicked: stateListModel.addState(); + action: addStateAction } StateDialog { @@ -61,7 +60,7 @@ Rectangle { function addState() { var item = { title: "", - balance: "1000000000000", + balance: "100000000000000000000000000", transactions: [] }; stateDialog.open(stateListModel.count, item); @@ -121,5 +120,13 @@ Rectangle { } } } + + Action { + id: addStateAction + text: "&Add State" + shortcut: "Ctrl+N" + enabled: codeModel.hasContract && !debugModel.running; + onTriggered: stateListModel.addState(); + } } diff --git a/mix/qml/main.qml b/mix/qml/main.qml index e44144f61..bba7c9088 100644 --- a/mix/qml/main.qml +++ b/mix/qml/main.qml @@ -1,6 +1,6 @@ import QtQuick 2.2 -import QtQuick.Controls 1.1 -import QtQuick.Controls.Styles 1.1 +import QtQuick.Controls 1.2 +import QtQuick.Controls.Styles 1.2 import QtQuick.Dialogs 1.1 import QtQuick.Layouts 1.1 import QtQuick.Window 2.1 @@ -51,6 +51,7 @@ ApplicationWindow { id: debugRunAction text: "&Run" shortcut: "F5" + enabled: codeModel.hasContract && !debugModel.running; onTriggered: debugModel.debugDeployment(); } @@ -60,4 +61,6 @@ ApplicationWindow { shortcut: "F6" onTriggered: debugModel.resetState(); } + + } From cc75d1bb5c8e95a715b72290bab2dee3b76c0b4e Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 27 Dec 2014 18:09:01 +0000 Subject: [PATCH 040/111] Receipts debugging. --- eth/main.cpp | 12 ++++++++++++ libethereum/Client.cpp | 8 +++++--- libethereum/Client.h | 2 +- libethereum/State.cpp | 30 ++++++++++++++---------------- libethereum/TransactionReceipt.cpp | 16 ++++++++++++++++ libethereum/TransactionReceipt.h | 3 +++ 6 files changed, 51 insertions(+), 20 deletions(-) diff --git a/eth/main.cpp b/eth/main.cpp index 1d139faa7..d55766cfd 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -89,6 +89,7 @@ void interactiveHelp() << " importConfig Import the config (.RLP) from the path provided." < Dumps a contract to /.evm." << endl << " dumptrace Dumps a transaction trace" << endl << "to . should be one of pretty, standard, standard+." << endl + << " dumpreceipt Dumps a transation receipt." << endl << " exit Exits the application." << endl; } @@ -606,6 +607,17 @@ int main(int argc, char** argv) else cwarn << "Require parameters: contract ENDOWMENT GASPRICE GAS CODEHEX"; } + else if (c && cmd == "dumpreceipt") + { + unsigned block; + unsigned index; + iss >> block >> index; + dev::eth::TransactionReceipt r = c->blockChain().receipts(c->blockChain().numberHash(block)).receipts[index]; + auto rb = r.rlp(); + cout << "RLP: " << RLP(rb) << endl; + cout << "Hex: " << toHex(rb) << endl; + cout << r << endl; + } else if (c && cmd == "dumptrace") { unsigned block; diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index edad31c6d..d8967c084 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -365,9 +365,11 @@ bytes Client::call(Address _dest, bytes const& _data, u256 _gas, u256 _value, u2 temp = m_postMine; } Executive e(temp, LastHashes(), 0); - e.call(_dest, _dest, Address(), _value, _gasPrice, &_data, _gas, Address()); - e.go(); - return e.out().toBytes(); + if (!e.call(_dest, _dest, Address(), _value, _gasPrice, &_data, _gas, Address())) + { + e.go(); + return e.out().toBytes(); + } } catch (...) { diff --git a/libethereum/Client.h b/libethereum/Client.h index 06c504355..bf6d902b7 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -125,7 +125,7 @@ template bytes abiIn(byte _id, T const& ... _t) } template struct ABIDeserialiser {}; -template struct ABIDeserialiser> { static FixedHash deserialise(bytesConstRef& io_t) { FixedHash ret(io_t.cropped(0, N).toBytes()); io_t = io_t.cropped(N); return ret; } }; +template struct ABIDeserialiser> { static FixedHash deserialise(bytesConstRef& io_t) { FixedHash ret; io_t.cropped(0, N).copyTo(ret.ref()); return ret; } }; template <> struct ABIDeserialiser { static u256 deserialise(bytesConstRef& io_t) { u256 ret = fromBigEndian(io_t.cropped(0, 32)); io_t = io_t.cropped(32); return ret; } }; template <> struct ABIDeserialiser { static u256 deserialise(bytesConstRef& io_t) { u160 ret = fromBigEndian(io_t.cropped(0, 20)); io_t = io_t.cropped(20); return ret; } }; template <> struct ABIDeserialiser { static string32 deserialise(bytesConstRef& io_t) { string32 ret; io_t.cropped(0, 32).copyTo(vector_ref(ret.data(), 32)); io_t = io_t.cropped(32); return ret; } }; diff --git a/libethereum/State.cpp b/libethereum/State.cpp index ecdf2dab3..ec9e2d31f 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -508,26 +508,11 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, bool _checkNonce) k << i; transactionsTrie.insert(&k.out(), tr.data()); - -// cnote << m_state.root() << m_state; -// cnote << *this; execute(lh, tr.data()); RLPStream receiptrlp; m_receipts.back().streamRLP(receiptrlp); receiptsTrie.insert(&k.out(), &receiptrlp.out()); -/* - if (tr[1].toHash() != m_state.root()) - { - // Invalid state root - cnote << m_state.root() << "\n" << m_state; - cnote << *this; - cnote << "INVALID: " << tr[1].toHash(); - BOOST_THROW_EXCEPTION(InvalidTransactionStateRoot()); - } - if (tr[2].toInt() != gasUsed()) - BOOST_THROW_EXCEPTION(InvalidTransactionGasUsed()); -*/ ++i; } @@ -539,7 +524,20 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, bool _checkNonce) if (receiptsTrie.root() != m_currentBlock.receiptsRoot) { - cwarn << "Bad receipts state root!"; + cwarn << "Bad receipts state root."; + cwarn << "Block:" << toHex(_block); + cwarn << "Block RLP:" << RLP(_block); + cwarn << "Want: " << receiptsTrie.root() << ", got: " << m_currentBlock.receiptsRoot; + for (unsigned j = 0; j < i; ++j) + { + RLPStream k; + k << j; + auto b = asBytes(receiptsTrie.at(&k.out())); + cwarn << j << ": "; + cwarn << "RLP: " << RLP(b); + cwarn << "Hex: " << toHex(b); + cwarn << TransactionReceipt(&b); + } BOOST_THROW_EXCEPTION(InvalidReceiptsStateRoot()); } diff --git a/libethereum/TransactionReceipt.cpp b/libethereum/TransactionReceipt.cpp index 0fb104490..868b00558 100644 --- a/libethereum/TransactionReceipt.cpp +++ b/libethereum/TransactionReceipt.cpp @@ -49,3 +49,19 @@ void TransactionReceipt::streamRLP(RLPStream& _s) const for (LogEntry const& l: m_log) l.streamRLP(_s); } + +std::ostream& dev::operator<<(std::ostream& _out, TransactionReceipt const& _r) +{ + _out << "Root: " << _r.stateRoot() << std::endl; + _out << "Gas used: " << _r.gasUsed() << std::endl; + _out << "Logs: " << _r.log().size() << " entries:" << std::endl; + for (LogEntry const& i: _r.log()) + { + _out << "Address " << i.address << ". Topics:" << std::endl; + for (auto const& j: i.topics) + _out << " " << j << std::endl; + _out << " Data: " << toHex(i.data) << std::endl; + } + _out << "Bloom: " << _r.bloom() << std::endl; + return _out; +} diff --git a/libethereum/TransactionReceipt.h b/libethereum/TransactionReceipt.h index 23995c75a..ebf591995 100644 --- a/libethereum/TransactionReceipt.h +++ b/libethereum/TransactionReceipt.h @@ -58,4 +58,7 @@ private: using TransactionReceipts = std::vector; } + +std::ostream& operator<<(std::ostream& _out, eth::TransactionReceipt const& _r); + } From 5b9b7543fad226a56aa9885cd2cef788bece7dfb Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 27 Dec 2014 20:27:25 +0000 Subject: [PATCH 041/111] Fix for copyTo bug. --- libdevcore/vector_ref.h | 3 ++- libethereum/Client.h | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/libdevcore/vector_ref.h b/libdevcore/vector_ref.h index 714c53b8c..2771c739a 100644 --- a/libdevcore/vector_ref.h +++ b/libdevcore/vector_ref.h @@ -40,7 +40,8 @@ public: vector_ref<_T> cropped(size_t _begin, size_t _count = ~size_t(0)) const { if (m_data && _begin + std::max(size_t(0), _count) <= m_count) return vector_ref<_T>(m_data + _begin, _count == ~size_t(0) ? m_count - _begin : _count); else return vector_ref<_T>(); } void retarget(_T const* _d, size_t _s) { m_data = _d; m_count = _s; } void retarget(std::vector<_T> const& _t) { m_data = _t.data(); m_count = _t.size(); } - void copyTo(vector_ref::type> _t) const { memcpy(_t.data(), m_data, std::min(_t.size(), m_count) * sizeof(_T)); memset(_t.data() + m_count, 0, std::max(_t.size(), m_count) - m_count); } + void copyTo(vector_ref::type> _t) const { memcpy(_t.data(), m_data, std::min(_t.size(), m_count) * sizeof(_T)); } + void populate(vector_ref::type> _t) const { copyTo(_t); memset(_t.data() + m_count, 0, std::max(_t.size(), m_count) - m_count); } _T* begin() { return m_data; } _T* end() { return m_data + m_count; } diff --git a/libethereum/Client.h b/libethereum/Client.h index bf6d902b7..6a3d7ec22 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -125,10 +125,10 @@ template bytes abiIn(byte _id, T const& ... _t) } template struct ABIDeserialiser {}; -template struct ABIDeserialiser> { static FixedHash deserialise(bytesConstRef& io_t) { FixedHash ret; io_t.cropped(0, N).copyTo(ret.ref()); return ret; } }; +template struct ABIDeserialiser> { static FixedHash deserialise(bytesConstRef& io_t) { FixedHash ret; io_t.cropped(0, N).populate(ret.ref()); return ret; } }; template <> struct ABIDeserialiser { static u256 deserialise(bytesConstRef& io_t) { u256 ret = fromBigEndian(io_t.cropped(0, 32)); io_t = io_t.cropped(32); return ret; } }; template <> struct ABIDeserialiser { static u256 deserialise(bytesConstRef& io_t) { u160 ret = fromBigEndian(io_t.cropped(0, 20)); io_t = io_t.cropped(20); return ret; } }; -template <> struct ABIDeserialiser { static string32 deserialise(bytesConstRef& io_t) { string32 ret; io_t.cropped(0, 32).copyTo(vector_ref(ret.data(), 32)); io_t = io_t.cropped(32); return ret; } }; +template <> struct ABIDeserialiser { static string32 deserialise(bytesConstRef& io_t) { string32 ret; io_t.cropped(0, 32).populate(vector_ref(ret.data(), 32)); io_t = io_t.cropped(32); return ret; } }; template T abiOut(bytes const& _data) { From a6cd367483c7cac867949a6ba518949a98eacf44 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 27 Dec 2014 21:09:24 +0000 Subject: [PATCH 042/111] Fix for overuse of stack. --- libethereum/State.cpp | 3 ++- libevm/ExtVMFace.h | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/libethereum/State.cpp b/libethereum/State.cpp index ec9e2d31f..a351b3da5 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -996,11 +996,12 @@ bool State::isTrieGood(bool _enforceRefs, bool _requireNoLeftOvers) const LastHashes State::getLastHashes(BlockChain const& _bc) const { LastHashes ret; + ret.resize(256); if (c_protocolVersion > 49) { unsigned n = (unsigned)m_previousBlock.number; for (unsigned i = 0; i < 256; ++i) - ret[i] = _bc.numberHash(n - i); + ret[i] = _bc.numberHash(std::max(n, i) - i); } return ret; } diff --git a/libevm/ExtVMFace.h b/libevm/ExtVMFace.h index 2c5e9400c..a4ec80ed8 100644 --- a/libevm/ExtVMFace.h +++ b/libevm/ExtVMFace.h @@ -93,7 +93,7 @@ struct SubState class ExtVMFace; class VM; -using LastHashes = std::array; +using LastHashes = std::vector; using OnOpFunc = std::function; From 92f43a7a35dc637f996a5750b3720a6def318503 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 27 Dec 2014 21:40:58 +0000 Subject: [PATCH 043/111] Fix allowed uncles. --- libethereum/State.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libethereum/State.cpp b/libethereum/State.cpp index a351b3da5..dfd65c713 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -564,7 +564,7 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, bool _checkNonce) BOOST_THROW_EXCEPTION(DuplicateUncleNonce()); BlockInfo uncleParent(_bc.block(uncle.parentHash)); - if ((bigint)uncleParent.number < (bigint)m_currentBlock.number - 6) + if ((bigint)uncleParent.number < (bigint)m_currentBlock.number - 7) BOOST_THROW_EXCEPTION(UncleTooOld()); uncle.verifyParent(uncleParent); From a54e2cee9af9753a8c8a5d54496e1e68266d1c0b Mon Sep 17 00:00:00 2001 From: subtly Date: Sun, 28 Dec 2014 13:10:59 +0100 Subject: [PATCH 044/111] code review updates --- libp2p/NodeTable.cpp | 23 ++++++++++++----------- libp2p/NodeTable.h | 10 +++++----- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/libp2p/NodeTable.cpp b/libp2p/NodeTable.cpp index 4cae6af0b..b586f377a 100644 --- a/libp2p/NodeTable.cpp +++ b/libp2p/NodeTable.cpp @@ -90,10 +90,11 @@ void NodeTable::doFindNode(Address _node, unsigned _round, std::shared_ptr>()); auto nearest = findNearest(_node); @@ -110,7 +111,7 @@ void NodeTable::doFindNode(Address _node, unsigned _round, std::shared_ptr> NodeTable::findNearest(Addres { // send s_alpha FindNode packets to nodes we know, closest to target static unsigned lastBin = s_bins - 1; - unsigned head = dist(m_node.id, _target); + unsigned head = hammingDist(m_node.id, _target); unsigned tail = head == 0 ? lastBin : (head - 1) % s_bins; std::map>> found; @@ -149,7 +150,7 @@ std::vector> NodeTable::findNearest(Addres if (auto p = n.lock()) { if (count < s_bucketSize) - found[dist(_target, p->id)].push_back(p); + found[hammingDist(_target, p->id)].push_back(p); else break; } @@ -159,7 +160,7 @@ std::vector> NodeTable::findNearest(Addres if (auto p = n.lock()) { if (count < s_bucketSize) - found[dist(_target, p->id)].push_back(p); + found[hammingDist(_target, p->id)].push_back(p); else break; } @@ -176,7 +177,7 @@ std::vector> NodeTable::findNearest(Addres if (auto p = n.lock()) { if (count < s_bucketSize) - found[dist(_target, p->id)].push_back(p); + found[hammingDist(_target, p->id)].push_back(p); else break; } @@ -190,7 +191,7 @@ std::vector> NodeTable::findNearest(Addres if (auto p = n.lock()) { if (count < s_bucketSize) - found[dist(_target, p->id)].push_back(p); + found[hammingDist(_target, p->id)].push_back(p); else break; } @@ -309,8 +310,8 @@ NodeTable::NodeBucket& NodeTable::bucket(NodeEntry const* _n) void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytesConstRef _packet) { - // h256 + Signature + RLP - if (_packet.size() < 100) + // h256 + Signature + RLP (smallest possible packet is empty neighbors packet which is 3 bytes) + if (_packet.size() < h256::size + Signature::size + 3) { clog(NodeTableMessageSummary) << "Invalid Message size from " << _from.address().to_string() << ":" << _from.port(); return; @@ -392,7 +393,7 @@ void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytes } catch (...) { - // likely culprit is invalid rlp encoding + clog(NodeTableWarn) << "Exception processing message from " << _from.address().to_string() << ":" << _from.port(); } } diff --git a/libp2p/NodeTable.h b/libp2p/NodeTable.h index 8457555d3..132a0f979 100644 --- a/libp2p/NodeTable.h +++ b/libp2p/NodeTable.h @@ -95,8 +95,8 @@ class NodeTable: UDPSocketEvents, public std::enable_shared_from_this */ struct NodeEntry: public Node { - NodeEntry(Node _src, Address _id, Public _pubk, NodeDefaultEndpoint _gw): Node(_id, _pubk, _gw), distance(dist(_src.id,_id)) {} - NodeEntry(Node _src, Address _id, Public _pubk, bi::udp::endpoint _udp): Node(_id, _pubk, NodeDefaultEndpoint(_udp)), distance(dist(_src.id,_id)) {} + NodeEntry(Node _src, Address _id, Public _pubk, NodeDefaultEndpoint _gw): Node(_id, _pubk, _gw), distance(hammingDist(_src.id,_id)) {} + NodeEntry(Node _src, Address _id, Public _pubk, bi::udp::endpoint _udp): Node(_id, _pubk, NodeDefaultEndpoint(_udp)), distance(hammingDist(_src.id,_id)) {} const unsigned distance; ///< Node's distance from _src (see constructor). }; @@ -130,7 +130,7 @@ public: std::chrono::milliseconds const c_reqTimeout = std::chrono::milliseconds(300); ///< How long to wait for requests (evict, find iterations). std::chrono::seconds const c_bucketRefresh = std::chrono::seconds(3600); ///< Refresh interval prevents bucket from becoming stale. [Kademlia] - static unsigned dist(Address const& _a, Address const& _b) { u160 d = _a ^ _b; unsigned ret; for (ret = 0; d >>= 1; ++ret) {}; return ret; } + static unsigned hammingDist(Address const& _a, Address const& _b) { u160 d = _a ^ _b; unsigned ret; for (ret = 0; d >>= 1; ++ret) {}; return ret; } void join(); @@ -142,7 +142,7 @@ public: protected: - /// Repeatedly sends s_alpha concurrent requests to nodes nearest to target, for nodes nearest to target, up to . + /// Repeatedly sends s_alpha concurrent requests to nodes nearest to target, for nodes nearest to target, up to s_maxSteps rounds. void doFindNode(Address _node, unsigned _round = 0, std::shared_ptr>> _tried = std::shared_ptr>>()); /// Returns nodes nearest to target. @@ -179,7 +179,7 @@ private: #else protected: #endif - /// Sends s_alpha concurrent FindNeighbor requests to nodes closest to target until + /// Sends FindNeighbor packet. See doFindNode. void requestNeighbors(NodeEntry const& _node, Address _target) const; Node m_node; ///< This node. From f37ff5ff4fc111851bb2f7d73a212f577f592644 Mon Sep 17 00:00:00 2001 From: Christian Date: Sun, 28 Dec 2014 13:35:58 +0100 Subject: [PATCH 045/111] Clarified binary operator checking for integer types. --- libsolidity/Types.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index 664b56ff6..c87ce2e60 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -201,17 +201,17 @@ TypePointer IntegerType::binaryOperatorResultImpl(Token::Value _operator, TypePo if (!commonType) return TypePointer(); + // All integer types can be compared + if (Token::isCompareOp(_operator)) + return commonType; + + // Nothing else can be done with addresses, but hashes can receive bit operators if (commonType->isAddress()) - { - if (!Token::isCompareOp(_operator)) - return TypePointer(); - } - else if (commonType->isHash()) - { - if (!(Token::isCompareOp(_operator) || Token::isBitOp(_operator))) - return TypePointer(); - } - return commonType; + return TypePointer(); + else if (commonType->isHash() && !Token::isBitOp(_operator)) + return TypePointer(); + else + return commonType; } const MemberList IntegerType::AddressMemberList = From c9982a4cb61c5fe98525400308c9f137bc272534 Mon Sep 17 00:00:00 2001 From: subtly Date: Sun, 28 Dec 2014 14:24:21 +0100 Subject: [PATCH 046/111] manually populate nodes for test rather than leveraging ping --- test/net.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/test/net.cpp b/test/net.cpp index d9b5d1579..8a2e2af78 100644 --- a/test/net.cpp +++ b/test/net.cpp @@ -111,6 +111,8 @@ struct TestNodeTableHost: public TestHost void pingAll() { for (auto& t: nodeTables) t->pingTestNodes(testNodes); } + void populateAll(size_t _count = 0) { for (auto& t: nodeTables) t->populateTestNodes(testNodes, _count); } + void populate(size_t _count = 0) { nodeTable->populateTestNodes(testNodes, _count); } KeyPair m_alias; @@ -171,22 +173,21 @@ BOOST_AUTO_TEST_CASE(test_findnode_neighbors) BOOST_AUTO_TEST_CASE(kademlia) { - TestNodeTableHost node(12); + // Not yet a 'real' test. + TestNodeTableHost node(8); node.start(); node.nodeTable->join(); // ideally, joining with empty node table logs warning we can check for node.setup(); node.populate(); clog << "NodeTable:\n" << *node.nodeTable.get() << endl; - node.pingAll(); - this_thread::sleep_for(chrono::milliseconds(1000)); + node.populateAll(); clog << "NodeTable:\n" << *node.nodeTable.get() << endl; node.nodeTable->reset(); clog << "NodeTable:\n" << *node.nodeTable.get() << endl; - node.populate(2); - this_thread::sleep_for(chrono::milliseconds(500)); + node.populate(1); clog << "NodeTable:\n" << *node.nodeTable.get() << endl; node.nodeTable->join(); From 4bea66340304eeedb733c90917b2e937e03d2daa Mon Sep 17 00:00:00 2001 From: winsvega Date: Sun, 28 Dec 2014 16:48:27 +0300 Subject: [PATCH 047/111] Transaction Tests --- test/stTransactionTestFiller.json | 137 +++++++++++++++++++++++++++++- 1 file changed, 136 insertions(+), 1 deletion(-) diff --git a/test/stTransactionTestFiller.json b/test/stTransactionTestFiller.json index 260e7953f..09c323cf5 100644 --- a/test/stTransactionTestFiller.json +++ b/test/stTransactionTestFiller.json @@ -187,5 +187,140 @@ "to" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b", "value" : "502" } - } + }, + + "ContractStoreClearsSuccess" : { + "env" : { + "currentCoinbase" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "currentDifficulty" : "45678256", + "currentGasLimit" : "10000", + "currentNumber" : "0", + "currentTimestamp" : 1, + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "pre" : + { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "7000", + "code" : "", + "nonce" : "0", + "storage" : { + } + }, + + "d2571607e241ecf590ed94b12d87c94babe36db6" : { + "balance" : "0", + "code" : "{(SSTORE 0 0)(SSTORE 1 0)(SSTORE 2 0)(SSTORE 3 0)(SSTORE 4 0)(SSTORE 5 0)(SSTORE 6 0)(SSTORE 7 0)(SSTORE 8 0)(SSTORE 9 0)}", + "nonce" : "0", + "storage" : { + "0x" : "0x0c", + "0x01" : "0x0c", + "0x02" : "0x0c", + "0x03" : "0x0c", + "0x04" : "0x0c", + "0x05" : "0x0c", + "0x06" : "0x0c", + "0x07" : "0x0c", + "0x08" : "0x0c", + "0x09" : "0x0c" + } + } + + }, + "transaction" : + { + "data" : "", + "gasLimit" : "600", + "gasPrice" : "1", + "nonce" : "", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "d2571607e241ecf590ed94b12d87c94babe36db6", + "value" : "10" + } + }, + + "ContractStoreClearsOOG" : { + "env" : { + "currentCoinbase" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "currentDifficulty" : "45678256", + "currentGasLimit" : "10000", + "currentNumber" : "0", + "currentTimestamp" : 1, + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "pre" : + { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "7000", + "code" : "", + "nonce" : "0", + "storage" : { + } + }, + + "d2571607e241ecf590ed94b12d87c94babe36db6" : { + "balance" : "0", + "code" : "{(SSTORE 0 0)(SSTORE 1 0)(SSTORE 2 0)(SSTORE 3 0)(SSTORE 4 0)(SSTORE 5 0)(SSTORE 6 0)(SSTORE 7 0)(SSTORE 8 0)(SSTORE 9 12)}", + "nonce" : "0", + "storage" : { + "0x" : "0x0c", + "0x01" : "0x0c", + "0x02" : "0x0c", + "0x03" : "0x0c", + "0x04" : "0x0c", + "0x05" : "0x0c", + "0x06" : "0x0c", + "0x07" : "0x0c", + "0x08" : "0x0c", + "0x09" : "0x0c" + } + } + + }, + "transaction" : + { + "data" : "", + "gasLimit" : "600", + "gasPrice" : "1", + "nonce" : "", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "d2571607e241ecf590ed94b12d87c94babe36db6", + "value" : "10" + } + }, + + "TransactionTooManyRlpElements" : { + "env" : { + "currentCoinbase" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "currentDifficulty" : "45678256", + "currentGasLimit" : "10000", + "currentNumber" : "0", + "currentTimestamp" : 1, + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "pre" : + { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "100000", + "code" : "", + "nonce" : "0", + "storage" : { + } + } + }, + "transaction" : + { + "data" : "", + "gasLimit" : "600", + "gasLimit" : "1600", + "gasPrice" : "1", + "gasPrice" : "12", + "nonce" : "", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d9", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "d2571607e241ecf590ed94b12d87c94babe36db6", + "value" : "10" + } + }, + } From 70b4389b096730b63901d33ced7e91f6077197f8 Mon Sep 17 00:00:00 2001 From: subtly Date: Sun, 28 Dec 2014 18:35:08 +0100 Subject: [PATCH 048/111] distance isn't hamming --- libp2p/NodeTable.cpp | 10 +++++----- libp2p/NodeTable.h | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/libp2p/NodeTable.cpp b/libp2p/NodeTable.cpp index b586f377a..7a98950ea 100644 --- a/libp2p/NodeTable.cpp +++ b/libp2p/NodeTable.cpp @@ -135,7 +135,7 @@ std::vector> NodeTable::findNearest(Addres { // send s_alpha FindNode packets to nodes we know, closest to target static unsigned lastBin = s_bins - 1; - unsigned head = hammingDist(m_node.id, _target); + unsigned head = dist(m_node.id, _target); unsigned tail = head == 0 ? lastBin : (head - 1) % s_bins; std::map>> found; @@ -150,7 +150,7 @@ std::vector> NodeTable::findNearest(Addres if (auto p = n.lock()) { if (count < s_bucketSize) - found[hammingDist(_target, p->id)].push_back(p); + found[dist(_target, p->id)].push_back(p); else break; } @@ -160,7 +160,7 @@ std::vector> NodeTable::findNearest(Addres if (auto p = n.lock()) { if (count < s_bucketSize) - found[hammingDist(_target, p->id)].push_back(p); + found[dist(_target, p->id)].push_back(p); else break; } @@ -177,7 +177,7 @@ std::vector> NodeTable::findNearest(Addres if (auto p = n.lock()) { if (count < s_bucketSize) - found[hammingDist(_target, p->id)].push_back(p); + found[dist(_target, p->id)].push_back(p); else break; } @@ -191,7 +191,7 @@ std::vector> NodeTable::findNearest(Addres if (auto p = n.lock()) { if (count < s_bucketSize) - found[hammingDist(_target, p->id)].push_back(p); + found[dist(_target, p->id)].push_back(p); else break; } diff --git a/libp2p/NodeTable.h b/libp2p/NodeTable.h index 132a0f979..314775955 100644 --- a/libp2p/NodeTable.h +++ b/libp2p/NodeTable.h @@ -95,8 +95,8 @@ class NodeTable: UDPSocketEvents, public std::enable_shared_from_this */ struct NodeEntry: public Node { - NodeEntry(Node _src, Address _id, Public _pubk, NodeDefaultEndpoint _gw): Node(_id, _pubk, _gw), distance(hammingDist(_src.id,_id)) {} - NodeEntry(Node _src, Address _id, Public _pubk, bi::udp::endpoint _udp): Node(_id, _pubk, NodeDefaultEndpoint(_udp)), distance(hammingDist(_src.id,_id)) {} + NodeEntry(Node _src, Address _id, Public _pubk, NodeDefaultEndpoint _gw): Node(_id, _pubk, _gw), distance(dist(_src.id,_id)) {} + NodeEntry(Node _src, Address _id, Public _pubk, bi::udp::endpoint _udp): Node(_id, _pubk, NodeDefaultEndpoint(_udp)), distance(dist(_src.id,_id)) {} const unsigned distance; ///< Node's distance from _src (see constructor). }; @@ -130,7 +130,7 @@ public: std::chrono::milliseconds const c_reqTimeout = std::chrono::milliseconds(300); ///< How long to wait for requests (evict, find iterations). std::chrono::seconds const c_bucketRefresh = std::chrono::seconds(3600); ///< Refresh interval prevents bucket from becoming stale. [Kademlia] - static unsigned hammingDist(Address const& _a, Address const& _b) { u160 d = _a ^ _b; unsigned ret; for (ret = 0; d >>= 1; ++ret) {}; return ret; } + static unsigned dist(Address const& _a, Address const& _b) { u160 d = _a ^ _b; unsigned ret; for (ret = 0; d >>= 1; ++ret) {}; return ret; } void join(); From 33c04f975d65ae306e21830e67d8763986e65bb6 Mon Sep 17 00:00:00 2001 From: wanderer Date: Mon, 29 Dec 2014 10:02:06 -0500 Subject: [PATCH 049/111] added balance tests --- test/stSystemOperationsTestFiller.json | 102 +++++++++++++++++++++++++ 1 file changed, 102 insertions(+) diff --git a/test/stSystemOperationsTestFiller.json b/test/stSystemOperationsTestFiller.json index 9fc8db773..34ab5078a 100644 --- a/test/stSystemOperationsTestFiller.json +++ b/test/stSystemOperationsTestFiller.json @@ -1410,5 +1410,107 @@ "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", "data" : "" } + }, + + "callValue": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[0]] (CALLVALUE) }", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "10000000", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "currentAccountBalance": { + "env": { + "previousHash": "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber": "0", + "currentGasLimit": "10000000", + "currentDifficulty": "256", + "currentTimestamp": 1, + "currentCoinbase": "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre": { + "095e7baea6a6c7c4c2dfeb977efac326af552d87": { + "balance": "1000000000000000000", + "nonce": 0, + "code": "{ [[0]] (balance (address)) }", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b": { + "balance": "1000000000000000000", + "nonce": 0, + "code": "", + "storage": {} + } + }, + "transaction": { + "nonce": "0", + "gasPrice": "1", + "gasLimit": "10000000", + "to": "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value": "100000", + "secretKey": "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data": "" + } + }, + + "callerAccountBalance": { + "env": { + "previousHash": "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber": "0", + "currentGasLimit": "10000000", + "currentDifficulty": "256", + "currentTimestamp": 1, + "currentCoinbase": "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre": { + "095e7baea6a6c7c4c2dfeb977efac326af552d87": { + "balance": "1000000000000000000", + "nonce": 0, + "code": "{ [[0]] (balance (caller)) }", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b": { + "balance": "1000000000000000000", + "nonce": 0, + "code": "", + "storage": {} + } + }, + "transaction": { + "nonce": "0", + "gasPrice": "1", + "gasLimit": "10000000", + "to": "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value": "100000", + "secretKey": "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data": "" } + } } From 1dcc22c9230781a97e80782fe851c25fbb305901 Mon Sep 17 00:00:00 2001 From: "U-SVZ13\\Arkady" Date: Mon, 29 Dec 2014 20:35:51 +0100 Subject: [PATCH 050/111] another attempt to fix msvc build --- mix/AppContext.cpp | 2 ++ mix/AppContext.h | 13 ++++++++++--- mix/AssemblyDebuggerControl.cpp | 4 ---- mix/AssemblyDebuggerControl.h | 4 ---- mix/AssemblyDebuggerModel.cpp | 4 ---- mix/AssemblyDebuggerModel.h | 4 ---- mix/QContractDefinition.cpp | 1 + mix/TransactionListView.h | 1 - 8 files changed, 13 insertions(+), 20 deletions(-) diff --git a/mix/AppContext.cpp b/mix/AppContext.cpp index 47040df30..6c48e9be1 100644 --- a/mix/AppContext.cpp +++ b/mix/AppContext.cpp @@ -26,7 +26,9 @@ #include #include #include +#include #include +#include #include "KeyEventManager.h" #include "AppContext.h" using namespace dev; diff --git a/mix/AppContext.h b/mix/AppContext.h index 5fde565e1..67861ad04 100644 --- a/mix/AppContext.h +++ b/mix/AppContext.h @@ -27,11 +27,19 @@ #pragma once +#include #include -#include -#include #include "KeyEventManager.h" +namespace dev +{ + class WebThreeDirect; + namespace solidity + { + class CompilerStack; + } +} + namespace dev { namespace mix @@ -46,7 +54,6 @@ class AppContext: public QObject public: AppContext(QQmlApplicationEngine* _engine); - ~AppContext() {} /// Get the current QQmlApplicationEngine instance. static AppContext* getInstance() { return Instance; } /// Renew QQMLApplicationEngine with a new instance. diff --git a/mix/AssemblyDebuggerControl.cpp b/mix/AssemblyDebuggerControl.cpp index fa76c8f5f..a3270fed7 100644 --- a/mix/AssemblyDebuggerControl.cpp +++ b/mix/AssemblyDebuggerControl.cpp @@ -17,10 +17,6 @@ * display opcode debugging. */ -//These 2 includes should be at the top to avoid conflicts with macros defined in windows.h -//@todo fix this is solidity headers -#include -#include #include #include #include diff --git a/mix/AssemblyDebuggerControl.h b/mix/AssemblyDebuggerControl.h index 0103af3b1..702839250 100644 --- a/mix/AssemblyDebuggerControl.h +++ b/mix/AssemblyDebuggerControl.h @@ -19,10 +19,6 @@ #pragma once -//These 2 includes should be at the top to avoid conflicts with macros defined in windows.h -//@todo fix this is solidity headers -#include -#include #include #include #include "Extension.h" diff --git a/mix/AssemblyDebuggerModel.cpp b/mix/AssemblyDebuggerModel.cpp index 21fa10873..1f260311a 100644 --- a/mix/AssemblyDebuggerModel.cpp +++ b/mix/AssemblyDebuggerModel.cpp @@ -17,10 +17,6 @@ * used as a model to debug contract assembly code. */ -//These 2 includes should be at the top to avoid conflicts with macros defined in windows.h -//@todo fix this is solidity headers -#include -#include #include #include #include diff --git a/mix/AssemblyDebuggerModel.h b/mix/AssemblyDebuggerModel.h index 9dbb58d78..1b1254464 100644 --- a/mix/AssemblyDebuggerModel.h +++ b/mix/AssemblyDebuggerModel.h @@ -19,10 +19,6 @@ #pragma once -//These 2 includes should be at the top to avoid conflicts with macros defined in windows.h -//@todo fix this is solidity headers -#include -#include #include #include #include diff --git a/mix/QContractDefinition.cpp b/mix/QContractDefinition.cpp index 6d98f67cb..55454f123 100644 --- a/mix/QContractDefinition.cpp +++ b/mix/QContractDefinition.cpp @@ -20,6 +20,7 @@ */ #include +#include #include #include #include diff --git a/mix/TransactionListView.h b/mix/TransactionListView.h index be1aef905..2ec775261 100644 --- a/mix/TransactionListView.h +++ b/mix/TransactionListView.h @@ -20,7 +20,6 @@ #pragma once #include -#include "TransactionListView.h" #include "Extension.h" namespace dev From 32ed9cbb466303b57c37408436cd595746b66f7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 31 Dec 2014 17:01:55 +0100 Subject: [PATCH 051/111] Update evmjit submodule: much better in memory caching --- evmjit | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/evmjit b/evmjit index 69930b9bc..3df5a125f 160000 --- a/evmjit +++ b/evmjit @@ -1 +1 @@ -Subproject commit 69930b9bcd27bb46d24890889bc1a4bdb2742271 +Subproject commit 3df5a125fa0baa579528abce80402118cad803fd From ceee87a1b74b85a0fd82bb60460d3ee3a9be8824 Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Thu, 1 Jan 2015 17:33:28 +0100 Subject: [PATCH 052/111] clean up --- test/trie.cpp.orig | 374 --------------------------------------------- 1 file changed, 374 deletions(-) delete mode 100644 test/trie.cpp.orig diff --git a/test/trie.cpp.orig b/test/trie.cpp.orig deleted file mode 100644 index 7a9461ce2..000000000 --- a/test/trie.cpp.orig +++ /dev/null @@ -1,374 +0,0 @@ -/* - This file is part of cpp-ethereum. - - cpp-ethereum is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - cpp-ethereum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with cpp-ethereum. If not, see . -*/ -/** @file trie.cpp - * @author Gav Wood - * @date 2014 - * Trie test functions. - */ - -#include -#include -#include "JsonSpiritHeaders.h" -#include -#include -#include "TrieHash.h" -#include "MemTrie.h" -#include -#include "TestHelper.h" - -using namespace std; -using namespace dev; - -namespace js = json_spirit; - -namespace dev -{ -namespace test -{ - -static unsigned fac(unsigned _i) -{ - return _i > 2 ? _i * fac(_i - 1) : _i; -} - -} -} - -BOOST_AUTO_TEST_SUITE(TrieTests) - -BOOST_AUTO_TEST_CASE(trie_tests) -{ - string testPath = test::getTestPath(); - - - testPath += "/TrieTests"; - - cnote << "Testing Trie..."; - js::mValue v; - string s = asString(contents(testPath + "/trieanyorder.json")); - BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of 'trieanyorder.json' is empty. Have you cloned the 'tests' repo branch develop?"); - js::read_string(s, v); - for (auto& i: v.get_obj()) - { - cnote << i.first; - js::mObject& o = i.second.get_obj(); - vector> ss; - for (auto& i: o["in"].get_array()) - { - vector values; - for (auto& s: i.get_array()) - values.push_back(s.get_str()); - - assert(values.size() == 2); - ss.push_back(make_pair(values[0], values[1])); - if (!ss.back().first.find("0x")) - ss.back().first = asString(fromHex(ss.back().first.substr(2))); - if (!ss.back().second.find("0x")) - ss.back().second = asString(fromHex(ss.back().second.substr(2))); - } - for (unsigned j = 0; j < min(1000u, dev::test::fac((unsigned)ss.size())); ++j) - { - MemoryDB m; - GenericTrieDB t(&m); - t.init(); - BOOST_REQUIRE(t.check(true)); - for (auto const& k: ss) - { - t.insert(k.first, k.second); - BOOST_REQUIRE(t.check(true)); - } - BOOST_REQUIRE(!o["root"].is_null()); - BOOST_CHECK_EQUAL(o["root"].get_str(), "0x" + toHex(t.root().asArray())); -<<<<<<< HEAD - if (o["root"].get_str() != "0x" + toHex(t.root().asArray())) - break; -======= ->>>>>>> upstream/develop - } - } -} - -inline h256 stringMapHash256(StringMap const& _s) -{ - return hash256(_s); -} - -BOOST_AUTO_TEST_CASE(moreTrieTests) -{ - cnote << "Testing Trie more..."; -#if 0 - // More tests... - { - MemoryDB m; - GenericTrieDB t(&m); - t.init(); // initialise as empty tree. - cout << t; - cout << m; - cout << t.root() << endl; - cout << hash256(StringMap()) << endl; - - t.insert(string("tesz"), string("test")); - cout << t; - cout << m; - cout << t.root() << endl; - cout << stringMapHash256({{"test", "test"}}) << endl; - - t.insert(string("tesa"), string("testy")); - cout << t; - cout << m; - cout << t.root() << endl; - cout << stringMapHash256({{"test", "test"}, {"te", "testy"}}) << endl; - cout << t.at(string("test")) << endl; - cout << t.at(string("te")) << endl; - cout << t.at(string("t")) << endl; - - t.remove(string("te")); - cout << m; - cout << t.root() << endl; - cout << stringMapHash256({{"test", "test"}}) << endl; - - t.remove(string("test")); - cout << m; - cout << t.root() << endl; - cout << hash256(StringMap()) << endl; - } - { - MemoryDB m; - GenericTrieDB t(&m); - t.init(); // initialise as empty tree. - t.insert(string("a"), string("A")); - t.insert(string("b"), string("B")); - cout << t; - cout << m; - cout << t.root() << endl; - cout << stringMapHash256({{"b", "B"}, {"a", "A"}}) << endl; - cout << RLP(rlp256({{"b", "B"}, {"a", "A"}})) << endl; - } - { - MemTrie t; - t.insert("dog", "puppy"); - cout << hex << t.hash256() << endl; - cout << RLP(t.rlp()) << endl; - } - { - MemTrie t; - t.insert("bed", "d"); - t.insert("be", "e"); - cout << hex << t.hash256() << endl; - cout << RLP(t.rlp()) << endl; - } - { - cout << hex << stringMapHash256({{"dog", "puppy"}, {"doe", "reindeer"}}) << endl; - MemTrie t; - t.insert("dog", "puppy"); - t.insert("doe", "reindeer"); - cout << hex << t.hash256() << endl; - cout << RLP(t.rlp()) << endl; - cout << toHex(t.rlp()) << endl; - } -#endif - { - MemoryDB m; - GenericTrieDB d(&m); - d.init(); // initialise as empty tree. - MemTrie t; - StringMap s; - - auto add = [&](char const* a, char const* b) - { - d.insert(string(a), string(b)); - t.insert(a, b); - s[a] = b; - - /*cout << endl << "-------------------------------" << endl; - cout << a << " -> " << b << endl; - cout << d; - cout << m; - cout << d.root() << endl; - cout << hash256(s) << endl;*/ - - BOOST_REQUIRE(d.check(true)); - BOOST_REQUIRE_EQUAL(t.hash256(), hash256(s)); - BOOST_REQUIRE_EQUAL(d.root(), hash256(s)); - for (auto const& i: s) - { - (void)i; - BOOST_REQUIRE_EQUAL(t.at(i.first), i.second); - BOOST_REQUIRE_EQUAL(d.at(i.first), i.second); - } - }; - - auto remove = [&](char const* a) - { - s.erase(a); - t.remove(a); - d.remove(string(a)); - - /*cout << endl << "-------------------------------" << endl; - cout << "X " << a << endl; - cout << d; - cout << m; - cout << d.root() << endl; - cout << hash256(s) << endl;*/ - - BOOST_REQUIRE(d.check(true)); - BOOST_REQUIRE(t.at(a).empty()); - BOOST_REQUIRE(d.at(string(a)).empty()); - BOOST_REQUIRE_EQUAL(t.hash256(), hash256(s)); - BOOST_REQUIRE_EQUAL(d.root(), hash256(s)); - for (auto const& i: s) - { - (void)i; - BOOST_REQUIRE_EQUAL(t.at(i.first), i.second); - BOOST_REQUIRE_EQUAL(d.at(i.first), i.second); - } - }; - - add("dogglesworth", "cat"); - add("doe", "reindeer"); - remove("dogglesworth"); - add("horse", "stallion"); - add("do", "verb"); - add("doge", "coin"); - remove("horse"); - remove("do"); - remove("doge"); - remove("doe"); - } -} - -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..."; - { - MemoryDB m; - MemoryDB dm; - EnforceRefs e(dm, true); - GenericTrieDB d(&dm); - d.init(); // initialise as empty tree. - MemTrie t; - BOOST_REQUIRE(d.check(true)); - 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; - t.insert(k, v); - d.insert(k, v); - BOOST_REQUIRE_EQUAL(hash256(m), t.hash256()); - BOOST_REQUIRE_EQUAL(hash256(m), d.root()); - BOOST_REQUIRE(d.check(true)); - } - while (!m.empty()) - { - auto k = m.begin()->first; - auto v = m.begin()->second; - d.remove(k); - t.remove(k); - m.erase(k); - if (!d.check(true)) - { - // cwarn << m; - for (auto i: d) - cwarn << i.first.toString() << i.second.toString(); - - MemoryDB dm2; - EnforceRefs e2(dm2, true); - GenericTrieDB d2(&dm2); - d2.init(); // initialise as empty tree. - for (auto i: d) - d2.insert(i.first, i.second); - - cwarn << "Good:" << d2.root(); -// for (auto i: dm2.get()) -// cwarn << i.first.abridged() << ": " << RLP(i.second); - d2.debugStructure(cerr); - cwarn << "Broken:" << d.root(); // Leaves an extension -> extension (3c1... -> 742...) -// for (auto i: dm.get()) -// cwarn << i.first.abridged() << ": " << RLP(i.second); - d.debugStructure(cerr); - - d2.insert(k, v); - cwarn << "Pres:" << d2.root(); -// for (auto i: dm2.get()) -// cwarn << i.first.abridged() << ": " << RLP(i.second); - d2.debugStructure(cerr); - g_logVerbosity = 99; - d2.remove(k); - g_logVerbosity = 4; - - cwarn << "Good?" << d2.root(); - } - BOOST_REQUIRE(d.check(true)); - BOOST_REQUIRE_EQUAL(hash256(m), t.hash256()); - BOOST_REQUIRE_EQUAL(hash256(m), d.root()); - } - } - } -} - -BOOST_AUTO_TEST_SUITE_END() - - From 7c642dbe24366cefb64c8a242bbc4d8e07cce31c Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Thu, 1 Jan 2015 21:36:02 +0100 Subject: [PATCH 053/111] add trie_tests_ordered --- test/trie.cpp | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/test/trie.cpp b/test/trie.cpp index 2141d5de9..59192f470 100644 --- a/test/trie.cpp +++ b/test/trie.cpp @@ -103,16 +103,31 @@ BOOST_AUTO_TEST_CASE(trie_tests_ordered) string s = asString(contents(testPath + "/trietest.json")); BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of 'trietest.json' is empty. Have you cloned the 'tests' repo branch develop?"); js::read_string(s, v); + for (auto& i: v.get_obj()) { cnote << i.first; js::mObject& o = i.second.get_obj(); vector> ss; + vector keysToBeDeleted; for (auto& i: o["in"].get_array()) { vector values; for (auto& s: i.get_array()) - values.push_back(s.get_str()); + { + if (s.type() == json_spirit::str_type) + values.push_back(s.get_str()); + else if (s.type() == json_spirit::null_type) + { + // mark entry for deletion + values.push_back(""); + if (!values[0].find("0x")) + values[0] = asString(fromHex(values[0].substr(2))); + keysToBeDeleted.push_back(values[0]); + } + else + cwarn << "Bad type (expected string): " << s.type(); + } assert(values.size() == 2); ss.push_back(make_pair(values[0], values[1])); @@ -128,9 +143,13 @@ BOOST_AUTO_TEST_CASE(trie_tests_ordered) BOOST_REQUIRE(t.check(true)); for (auto const& k: ss) { - t.insert(k.first, k.second); + if (find(keysToBeDeleted.begin(), keysToBeDeleted.end(), k.first) != keysToBeDeleted.end() && k.second.empty()) + t.remove(k.first); + else + t.insert(k.first, k.second); BOOST_REQUIRE(t.check(true)); } + BOOST_REQUIRE(!o["root"].is_null()); BOOST_CHECK_EQUAL(o["root"].get_str(), "0x" + toHex(t.root().asArray())); } From 0ee53a19357021cfbc76438a9fb1be0521ae0174 Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Thu, 1 Jan 2015 21:45:00 +0100 Subject: [PATCH 054/111] use boost_fail instead of warning --- test/trie.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/trie.cpp b/test/trie.cpp index 59192f470..39a3a59a5 100644 --- a/test/trie.cpp +++ b/test/trie.cpp @@ -126,10 +126,10 @@ BOOST_AUTO_TEST_CASE(trie_tests_ordered) keysToBeDeleted.push_back(values[0]); } else - cwarn << "Bad type (expected string): " << s.type(); + BOOST_FAIL("Bad type (expected string)"); } - assert(values.size() == 2); + BOOST_REQUIRE(values.size() == 2); ss.push_back(make_pair(values[0], values[1])); if (!ss.back().first.find("0x")) ss.back().first = asString(fromHex(ss.back().first.substr(2))); From 789abca7add480f696157afddd2f9e7390e58845 Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Fri, 2 Jan 2015 14:11:07 +0100 Subject: [PATCH 055/111] undo origin address change (in test) --- test/vmArithmeticTestFiller.json | 292 +++++++++++++++---------------- 1 file changed, 146 insertions(+), 146 deletions(-) diff --git a/test/vmArithmeticTestFiller.json b/test/vmArithmeticTestFiller.json index b93694575..90d714095 100644 --- a/test/vmArithmeticTestFiller.json +++ b/test/vmArithmeticTestFiller.json @@ -18,8 +18,8 @@ }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", "value" : "1000000000000000000", "data" : "", "gasPrice" : "100000000000000", @@ -46,8 +46,8 @@ }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", "value" : "1000000000000000000", "data" : "", "gasPrice" : "100000000000000", @@ -74,8 +74,8 @@ }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", "value" : "1000000000000000000", "data" : "", "gasPrice" : "100000000000000", @@ -102,8 +102,8 @@ }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", "value" : "1000000000000000000", "data" : "", "gasPrice" : "100000000000000", @@ -130,8 +130,8 @@ }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", "value" : "1000000000000000000", "data" : "", "gasPrice" : "100000000000000", @@ -158,8 +158,8 @@ }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", "value" : "1000000000000000000", "data" : "", "gasPrice" : "100000000000000", @@ -187,8 +187,8 @@ }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", "value" : "1000000000000000000", "data" : "", "gasPrice" : "100000000000000", @@ -216,8 +216,8 @@ }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", "value" : "1000000000000000000", "data" : "", "gasPrice" : "100000000000000", @@ -244,8 +244,8 @@ }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", "value" : "1000000000000000000", "data" : "", "gasPrice" : "100000000000000", @@ -272,8 +272,8 @@ }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", "value" : "1000000000000000000", "data" : "", "gasPrice" : "100000000000000", @@ -300,8 +300,8 @@ }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", "value" : "1000000000000000000", "data" : "", "gasPrice" : "100000000000000", @@ -328,8 +328,8 @@ }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", "value" : "1000000000000000000", "data" : "", "gasPrice" : "100000000000000", @@ -356,8 +356,8 @@ }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", "value" : "1000000000000000000", "data" : "", "gasPrice" : "100000000000000", @@ -385,8 +385,8 @@ }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", "value" : "1000000000000000000", "data" : "", "gasPrice" : "100000000000000", @@ -413,8 +413,8 @@ }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", "value" : "1000000000000000000", "data" : "", "gasPrice" : "100000000000000", @@ -441,8 +441,8 @@ }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", "value" : "1000000000000000000", "data" : "", "gasPrice" : "100000000000000", @@ -469,8 +469,8 @@ }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", "value" : "1000000000000000000", "data" : "", "gasPrice" : "100000000000000", @@ -497,8 +497,8 @@ }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", "value" : "1000000000000000000", "data" : "", "gasPrice" : "100000000000000", @@ -525,8 +525,8 @@ }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", "value" : "1000000000000000000", "data" : "", "gasPrice" : "100000000000000", @@ -553,8 +553,8 @@ }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", "value" : "1000000000000000000", "data" : "", "gasPrice" : "100000000000000", @@ -581,8 +581,8 @@ }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", "value" : "1000000000000000000", "data" : "", "gasPrice" : "100000000000000", @@ -609,8 +609,8 @@ }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", "value" : "1000000000000000000", "data" : "", "gasPrice" : "100000000000000", @@ -637,8 +637,8 @@ }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", "value" : "1000000000000000000", "data" : "", "gasPrice" : "100000000000000", @@ -665,8 +665,8 @@ }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", "value" : "1000000000000000000", "data" : "", "gasPrice" : "100000000000000", @@ -693,8 +693,8 @@ }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", "value" : "1000000000000000000", "data" : "", "gasPrice" : "100000000000000", @@ -721,8 +721,8 @@ }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", "value" : "1000000000000000000", "data" : "", "gasPrice" : "100000000000000", @@ -749,8 +749,8 @@ }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", "value" : "1000000000000000000", "data" : "", "gasPrice" : "100000000000000", @@ -777,8 +777,8 @@ }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", "value" : "1000000000000000000", "data" : "", "gasPrice" : "100000000000000", @@ -805,8 +805,8 @@ }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", "value" : "1000000000000000000", "data" : "", "gasPrice" : "100000000000000", @@ -833,8 +833,8 @@ }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", "value" : "1000000000000000000", "data" : "", "gasPrice" : "100000000000000", @@ -861,8 +861,8 @@ }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", "value" : "1000000000000000000", "data" : "", "gasPrice" : "100000000000000", @@ -889,8 +889,8 @@ }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", "value" : "1000000000000000000", "data" : "", "gasPrice" : "100000000000000", @@ -917,8 +917,8 @@ }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", "value" : "1000000000000000000", "data" : "", "gasPrice" : "100000000000000", @@ -945,8 +945,8 @@ }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", "value" : "1000000000000000000", "data" : "", "gasPrice" : "100000000000000", @@ -973,8 +973,8 @@ }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", "value" : "1000000000000000000", "data" : "", "gasPrice" : "100000000000000", @@ -1001,8 +1001,8 @@ }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", "value" : "1000000000000000000", "data" : "", "gasPrice" : "100000000000000", @@ -1029,8 +1029,8 @@ }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", "value" : "1000000000000000000", "data" : "", "gasPrice" : "100000000000000", @@ -1057,8 +1057,8 @@ }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", "value" : "1000000000000000000", "data" : "", "gasPrice" : "100000000000000", @@ -1085,8 +1085,8 @@ }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", "value" : "1000000000000000000", "data" : "", "gasPrice" : "100000000000000", @@ -1113,8 +1113,8 @@ }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", "value" : "1000000000000000000", "data" : "", "gasPrice" : "100000000000000", @@ -1141,8 +1141,8 @@ }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", "value" : "1000000000000000000", "data" : "", "gasPrice" : "100000000000000", @@ -1169,8 +1169,8 @@ }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", "value" : "1000000000000000000", "data" : "", "gasPrice" : "100000000000000", @@ -1197,8 +1197,8 @@ }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", "value" : "1000000000000000000", "data" : "", "gasPrice" : "100000000000000", @@ -1225,8 +1225,8 @@ }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", "value" : "1000000000000000000", "data" : "", "gasPrice" : "100000000000000", @@ -1253,8 +1253,8 @@ }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", "value" : "1000000000000000000", "data" : "", "gasPrice" : "100000000000000", @@ -1281,8 +1281,8 @@ }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", "value" : "1000000000000000000", "data" : "", "gasPrice" : "100000000000000", @@ -1310,8 +1310,8 @@ }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", "value" : "1000000000000000000", "data" : "", "gasPrice" : "100000000000000", @@ -1338,8 +1338,8 @@ }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", "value" : "1000000000000000000", "data" : "", "gasPrice" : "100000000000000", @@ -1366,8 +1366,8 @@ }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", "value" : "1000000000000000000", "data" : "", "gasPrice" : "100000000000000", @@ -1394,8 +1394,8 @@ }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", "value" : "1000000000000000000", "data" : "", "gasPrice" : "100000000000000", @@ -1422,8 +1422,8 @@ }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", "value" : "1000000000000000000", "data" : "", "gasPrice" : "100000000000000", @@ -1450,8 +1450,8 @@ }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", "value" : "1000000000000000000", "data" : "", "gasPrice" : "100000000000000", @@ -1478,8 +1478,8 @@ }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", "value" : "1000000000000000000", "data" : "", "gasPrice" : "100000000000000", @@ -1507,8 +1507,8 @@ }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", "value" : "1000000000000000000", "data" : "", "gasPrice" : "100000000000000", @@ -1535,8 +1535,8 @@ }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", "value" : "1000000000000000000", "data" : "", "gasPrice" : "100000000000000", @@ -1563,8 +1563,8 @@ }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", "value" : "1000000000000000000", "data" : "", "gasPrice" : "100000000000000", @@ -1591,8 +1591,8 @@ }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", "value" : "1000000000000000000", "data" : "", "gasPrice" : "100000000000000", @@ -1619,8 +1619,8 @@ }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", "value" : "1000000000000000000", "data" : "", "gasPrice" : "100000000000000", @@ -1647,8 +1647,8 @@ }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", "value" : "1000000000000000000", "data" : "", "gasPrice" : "100000000000000", @@ -1675,8 +1675,8 @@ }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", "value" : "1000000000000000000", "data" : "", "gasPrice" : "100000000000000", @@ -1703,8 +1703,8 @@ }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", "value" : "1000000000000000000", "data" : "", "gasPrice" : "100000000000000", @@ -1731,8 +1731,8 @@ }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", "value" : "1000000000000000000", "data" : "", "gasPrice" : "100000000000000", @@ -1759,8 +1759,8 @@ }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", "value" : "1000000000000000000", "data" : "", "gasPrice" : "100000000000000", @@ -1787,8 +1787,8 @@ }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", "value" : "1000000000000000000", "data" : "", "gasPrice" : "100000000000000", @@ -1815,8 +1815,8 @@ }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", "value" : "1000000000000000000", "data" : "", "gasPrice" : "100000000000000", @@ -1843,8 +1843,8 @@ }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", "value" : "1000000000000000000", "data" : "", "gasPrice" : "100000000000000", @@ -1871,8 +1871,8 @@ }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", "value" : "1000000000000000000", "data" : "", "gasPrice" : "100000000000000", @@ -1899,8 +1899,8 @@ }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", "value" : "1000000000000000000", "data" : "", "gasPrice" : "100000000000000", @@ -1927,8 +1927,8 @@ }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", "value" : "1000000000000000000", "data" : "", "gasPrice" : "100000000000000", @@ -1955,8 +1955,8 @@ }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", "value" : "1000000000000000000", "data" : "", "gasPrice" : "100000000000000", @@ -1983,8 +1983,8 @@ }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", "value" : "1000000000000000000", "data" : "", "gasPrice" : "100000000000000", @@ -2011,8 +2011,8 @@ }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", "value" : "1000000000000000000", "data" : "", "gasPrice" : "100000000000000", @@ -2039,8 +2039,8 @@ }, "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", "value" : "1000000000000000000", "data" : "", "gasPrice" : "100000000000000", From d1fc5354589d4ef612be2477b9fd42aae47e1ef5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 2 Jan 2015 14:35:53 +0100 Subject: [PATCH 056/111] Memleak fix: free genesis block at the end of program --- libethereum/BlockChain.cpp | 2 +- libethereum/BlockChain.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 6ed0a2ca6..b1938d54d 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -71,7 +71,7 @@ std::map const& dev::eth::genesisState() return s_ret; } -BlockInfo* BlockChain::s_genesis = nullptr; +std::unique_ptr BlockChain::s_genesis; boost::shared_mutex BlockChain::x_genesis; ldb::Slice dev::eth::toSlice(h256 _h, unsigned _sub) diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index d03818bd3..4e5d66c9a 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -132,7 +132,7 @@ public: h256Set allUnclesFrom(h256 _parent) const; /// @returns the genesis block header. - static BlockInfo const& genesis() { UpgradableGuard l(x_genesis); if (!s_genesis) { auto gb = createGenesisBlock(); UpgradeGuard ul(l); (s_genesis = new BlockInfo)->populate(&gb); } return *s_genesis; } + static BlockInfo const& genesis() { UpgradableGuard l(x_genesis); if (!s_genesis) { auto gb = createGenesisBlock(); UpgradeGuard ul(l); s_genesis.reset(new BlockInfo); s_genesis->populate(&gb); } return *s_genesis; } /// @returns the genesis block as its RLP-encoded byte array. /// @note This is slow as it's constructed anew each call. Consider genesis() instead. @@ -211,7 +211,7 @@ private: /// Static genesis info and its lock. static boost::shared_mutex x_genesis; - static BlockInfo* s_genesis; + static std::unique_ptr s_genesis; }; std::ostream& operator<<(std::ostream& _out, BlockChain const& _bc); From 25a744c13d26f44f57a6346fc8e2b0a298fc876b Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 2 Jan 2015 15:10:53 +0000 Subject: [PATCH 057/111] JUMPDESTs must be explicit. --- libevm/VM.h | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/libevm/VM.h b/libevm/VM.h index 64353e2db..47efbfcba 100644 --- a/libevm/VM.h +++ b/libevm/VM.h @@ -83,29 +83,9 @@ inline bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _st auto memNeed = [](dev::u256 _offset, dev::u256 _size) { return _size ? (bigint)_offset + _size : (bigint)0; }; if (m_jumpDests.empty()) - { - std::set implicit; for (unsigned i = 0; i < _ext.code.size(); ++i) if (_ext.code[i] == (byte)Instruction::JUMPDEST) m_jumpDests.insert(i); - else if (_ext.code[i] >= (byte)Instruction::PUSH1 && _ext.code[i] <= (byte)Instruction::PUSH32) - { - int in = _ext.code[i] - (unsigned)Instruction::PUSH1 + 1; - u256 p = 0; - for (i++; in--; i++) - p = (p << 8) | _ext.getCode(i); - if ((_ext.getCode(i) == (byte)Instruction::JUMP || _ext.getCode(i) == (byte)Instruction::JUMPI) && !(_ext.getCode(p) == (byte)Instruction::JUMP || _ext.getCode(p) == (byte)Instruction::JUMPI)) - if (p >= _ext.code.size()) - m_jumpDests.insert(p); - else - implicit.insert(p); - else {} - i--; - } - for (unsigned i = 0; i < _ext.code.size(); i += instructionInfo((Instruction)_ext.getCode(i)).additional + 1) - if (implicit.count(i)) - m_jumpDests.insert(i); - } u256 nextPC = m_curPC + 1; auto osteps = _steps; From de66950b52396e89bf1400dac2b043e56b5a2910 Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Fri, 2 Jan 2015 16:57:39 +0100 Subject: [PATCH 058/111] retuning gas prices of recursive bombs to test limits --- test/stSystemOperationsTestFiller.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/stSystemOperationsTestFiller.json b/test/stSystemOperationsTestFiller.json index 34ab5078a..b79066368 100644 --- a/test/stSystemOperationsTestFiller.json +++ b/test/stSystemOperationsTestFiller.json @@ -740,7 +740,7 @@ "transaction" : { "nonce" : "0", "gasPrice" : "1", - "gasLimit" : "365223", + "gasLimit" : "365243", "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", "value" : "100000", "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", @@ -774,7 +774,7 @@ "transaction" : { "nonce" : "0", "gasPrice" : "1", - "gasLimit" : "365224", + "gasLimit" : "365244", "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", "value" : "100000", "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", From 32fe54b49f1d50e7b3332c6a38473e39d8e72a36 Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Fri, 2 Jan 2015 16:58:14 +0100 Subject: [PATCH 059/111] added complete exp tests --- test/vmArithmeticTestFiller.json | 2100 ++++++++++++++++++++++++++++++ 1 file changed, 2100 insertions(+) diff --git a/test/vmArithmeticTestFiller.json b/test/vmArithmeticTestFiller.json index 90d714095..fb1fb8ddd 100644 --- a/test/vmArithmeticTestFiller.json +++ b/test/vmArithmeticTestFiller.json @@ -1712,6 +1712,2106 @@ } }, + "expPowerOf2_2": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EXP 2 2) [[ 1 ]] (EXP 2 1) [[ 2 ]] (EXP 2 3) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "expPowerOf2_4": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EXP 2 4) [[ 1 ]] (EXP 2 3) [[ 2 ]] (EXP 2 5) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "expPowerOf2_8": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EXP 2 8) [[ 1 ]] (EXP 2 7) [[ 2 ]] (EXP 2 9) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "expPowerOf2_16": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EXP 2 16) [[ 1 ]] (EXP 2 15) [[ 2 ]] (EXP 2 17) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "expPowerOf2_32": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EXP 2 32) [[ 1 ]] (EXP 2 31) [[ 2 ]] (EXP 2 33) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "expPowerOf2_64": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EXP 2 64) [[ 1 ]] (EXP 2 63) [[ 2 ]] (EXP 2 65) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "expPowerOf2_128": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EXP 2 128) [[ 1 ]] (EXP 2 127) [[ 2 ]] (EXP 2 129) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "expPowerOf2_256": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EXP 2 256) [[ 1 ]] (EXP 2 255) [[ 2 ]] (EXP 2 257) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "expPowerOf256_1": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EXP 256 1) [[ 1 ]] (EXP 255 1) [[ 2 ]] (EXP 257 1) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "expPowerOf256_2": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EXP 256 2) [[ 1 ]] (EXP 255 2) [[ 2 ]] (EXP 257 2) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "expPowerOf256_3": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EXP 256 3) [[ 1 ]] (EXP 255 3) [[ 2 ]] (EXP 257 3) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "expPowerOf256_4": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EXP 256 4) [[ 1 ]] (EXP 255 4) [[ 2 ]] (EXP 257 4) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "expPowerOf256_5": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EXP 256 5) [[ 1 ]] (EXP 255 5) [[ 2 ]] (EXP 257 5) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "expPowerOf256_6": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EXP 256 6) [[ 1 ]] (EXP 255 6) [[ 2 ]] (EXP 257 6) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "expPowerOf256_7": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EXP 256 7) [[ 1 ]] (EXP 255 7) [[ 2 ]] (EXP 257 7) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "expPowerOf256_8": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EXP 256 8) [[ 1 ]] (EXP 255 8) [[ 2 ]] (EXP 257 8) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "expPowerOf256_9": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EXP 256 9) [[ 1 ]] (EXP 255 9) [[ 2 ]] (EXP 257 9) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "expPowerOf256_10": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EXP 256 10) [[ 1 ]] (EXP 255 10) [[ 2 ]] (EXP 257 10) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "expPowerOf256_11": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EXP 256 11) [[ 1 ]] (EXP 255 11) [[ 2 ]] (EXP 257 11) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "expPowerOf256_12": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EXP 256 12) [[ 1 ]] (EXP 255 12) [[ 2 ]] (EXP 257 12) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "expPowerOf256_13": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EXP 256 13) [[ 1 ]] (EXP 255 13) [[ 2 ]] (EXP 257 13) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "expPowerOf256_14": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EXP 256 14) [[ 1 ]] (EXP 255 14) [[ 2 ]] (EXP 257 14) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "expPowerOf256_15": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EXP 256 15) [[ 1 ]] (EXP 255 15) [[ 2 ]] (EXP 257 15) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "expPowerOf256_16": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EXP 256 16) [[ 1 ]] (EXP 255 16) [[ 2 ]] (EXP 257 16) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "expPowerOf256_17": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EXP 256 17) [[ 1 ]] (EXP 255 17) [[ 2 ]] (EXP 257 17) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "expPowerOf256_18": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EXP 256 18) [[ 1 ]] (EXP 255 18) [[ 2 ]] (EXP 257 18) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "expPowerOf256_19": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EXP 256 19) [[ 1 ]] (EXP 255 19) [[ 2 ]] (EXP 257 19) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "expPowerOf256_20": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EXP 256 20) [[ 1 ]] (EXP 255 20) [[ 2 ]] (EXP 257 20) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "expPowerOf256_21": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EXP 256 21) [[ 1 ]] (EXP 255 21) [[ 2 ]] (EXP 257 21) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "expPowerOf256_22": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EXP 256 22) [[ 1 ]] (EXP 255 22) [[ 2 ]] (EXP 257 22) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "expPowerOf256_23": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EXP 256 23) [[ 1 ]] (EXP 255 23) [[ 2 ]] (EXP 257 23) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "expPowerOf256_24": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EXP 256 24) [[ 1 ]] (EXP 255 24) [[ 2 ]] (EXP 257 24) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "expPowerOf256_25": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EXP 256 25) [[ 1 ]] (EXP 255 25) [[ 2 ]] (EXP 257 25) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "expPowerOf256_26": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EXP 256 26) [[ 1 ]] (EXP 255 26) [[ 2 ]] (EXP 257 26) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "expPowerOf256_27": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EXP 256 27) [[ 1 ]] (EXP 255 27) [[ 2 ]] (EXP 257 27) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "expPowerOf256_28": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EXP 256 28) [[ 1 ]] (EXP 255 28) [[ 2 ]] (EXP 257 28) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "expPowerOf256_29": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EXP 256 29) [[ 1 ]] (EXP 255 29) [[ 2 ]] (EXP 257 29) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "expPowerOf256_30": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EXP 256 30) [[ 1 ]] (EXP 255 30) [[ 2 ]] (EXP 257 30) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "expPowerOf256_31": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EXP 256 31) [[ 1 ]] (EXP 255 31) [[ 2 ]] (EXP 257 31) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "expPowerOf256_32": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EXP 256 32) [[ 1 ]] (EXP 255 32) [[ 2 ]] (EXP 257 32) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "expPowerOf256_33": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EXP 256 33) [[ 1 ]] (EXP 255 33) [[ 2 ]] (EXP 257 33) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "expPowerOf256Of256_0": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EXP 256 (EXP 256 0)) [[ 1 ]] (EXP 256 (EXP 255 0)) [[ 2 ]] (EXP 256 (EXP 257 0)) [[ 3 ]] (EXP 255 (EXP 256 0)) [[ 4 ]] (EXP 255 (EXP 255 0)) [[ 5 ]] (EXP 255 (EXP 257 0)) [[ 6 ]] (EXP 257 (EXP 256 0)) [[ 7 ]] (EXP 257 (EXP 255 0)) [[ 8 ]] (EXP 257 (EXP 257 0)) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "expPowerOf256Of256_1": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EXP 256 (EXP 256 1)) [[ 1 ]] (EXP 256 (EXP 255 1)) [[ 2 ]] (EXP 256 (EXP 257 1)) [[ 3 ]] (EXP 255 (EXP 256 1)) [[ 4 ]] (EXP 255 (EXP 255 1)) [[ 5 ]] (EXP 255 (EXP 257 1)) [[ 6 ]] (EXP 257 (EXP 256 1)) [[ 7 ]] (EXP 257 (EXP 255 1)) [[ 8 ]] (EXP 257 (EXP 257 1)) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "expPowerOf256Of256_2": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EXP 256 (EXP 256 2)) [[ 1 ]] (EXP 256 (EXP 255 2)) [[ 2 ]] (EXP 256 (EXP 257 2)) [[ 3 ]] (EXP 255 (EXP 256 2)) [[ 4 ]] (EXP 255 (EXP 255 2)) [[ 5 ]] (EXP 255 (EXP 257 2)) [[ 6 ]] (EXP 257 (EXP 256 2)) [[ 7 ]] (EXP 257 (EXP 255 2)) [[ 8 ]] (EXP 257 (EXP 257 2)) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "expPowerOf256Of256_3": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EXP 256 (EXP 256 3)) [[ 1 ]] (EXP 256 (EXP 255 3)) [[ 2 ]] (EXP 256 (EXP 257 3)) [[ 3 ]] (EXP 255 (EXP 256 3)) [[ 4 ]] (EXP 255 (EXP 255 3)) [[ 5 ]] (EXP 255 (EXP 257 3)) [[ 6 ]] (EXP 257 (EXP 256 3)) [[ 7 ]] (EXP 257 (EXP 255 3)) [[ 8 ]] (EXP 257 (EXP 257 3)) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "expPowerOf256Of256_4": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EXP 256 (EXP 256 4)) [[ 1 ]] (EXP 256 (EXP 255 4)) [[ 2 ]] (EXP 256 (EXP 257 4)) [[ 3 ]] (EXP 255 (EXP 256 4)) [[ 4 ]] (EXP 255 (EXP 255 4)) [[ 5 ]] (EXP 255 (EXP 257 4)) [[ 6 ]] (EXP 257 (EXP 256 4)) [[ 7 ]] (EXP 257 (EXP 255 4)) [[ 8 ]] (EXP 257 (EXP 257 4)) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "expPowerOf256Of256_5": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EXP 256 (EXP 256 5)) [[ 1 ]] (EXP 256 (EXP 255 5)) [[ 2 ]] (EXP 256 (EXP 257 5)) [[ 3 ]] (EXP 255 (EXP 256 5)) [[ 4 ]] (EXP 255 (EXP 255 5)) [[ 5 ]] (EXP 255 (EXP 257 5)) [[ 6 ]] (EXP 257 (EXP 256 5)) [[ 7 ]] (EXP 257 (EXP 255 5)) [[ 8 ]] (EXP 257 (EXP 257 5)) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "expPowerOf256Of256_6": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EXP 256 (EXP 256 6)) [[ 1 ]] (EXP 256 (EXP 255 6)) [[ 2 ]] (EXP 256 (EXP 257 6)) [[ 3 ]] (EXP 255 (EXP 256 6)) [[ 4 ]] (EXP 255 (EXP 255 6)) [[ 5 ]] (EXP 255 (EXP 257 6)) [[ 6 ]] (EXP 257 (EXP 256 6)) [[ 7 ]] (EXP 257 (EXP 255 6)) [[ 8 ]] (EXP 257 (EXP 257 6)) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "expPowerOf256Of256_7": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EXP 256 (EXP 256 7)) [[ 1 ]] (EXP 256 (EXP 255 7)) [[ 2 ]] (EXP 256 (EXP 257 7)) [[ 3 ]] (EXP 255 (EXP 256 7)) [[ 4 ]] (EXP 255 (EXP 255 7)) [[ 5 ]] (EXP 255 (EXP 257 7)) [[ 6 ]] (EXP 257 (EXP 256 7)) [[ 7 ]] (EXP 257 (EXP 255 7)) [[ 8 ]] (EXP 257 (EXP 257 7)) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "expPowerOf256Of256_8": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EXP 256 (EXP 256 8)) [[ 1 ]] (EXP 256 (EXP 255 8)) [[ 2 ]] (EXP 256 (EXP 257 8)) [[ 3 ]] (EXP 255 (EXP 256 8)) [[ 4 ]] (EXP 255 (EXP 255 8)) [[ 5 ]] (EXP 255 (EXP 257 8)) [[ 6 ]] (EXP 257 (EXP 256 8)) [[ 7 ]] (EXP 257 (EXP 255 8)) [[ 8 ]] (EXP 257 (EXP 257 8)) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "expPowerOf256Of256_9": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EXP 256 (EXP 256 9)) [[ 1 ]] (EXP 256 (EXP 255 9)) [[ 2 ]] (EXP 256 (EXP 257 9)) [[ 3 ]] (EXP 255 (EXP 256 9)) [[ 4 ]] (EXP 255 (EXP 255 9)) [[ 5 ]] (EXP 255 (EXP 257 9)) [[ 6 ]] (EXP 257 (EXP 256 9)) [[ 7 ]] (EXP 257 (EXP 255 9)) [[ 8 ]] (EXP 257 (EXP 257 9)) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "expPowerOf256Of256_10": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EXP 256 (EXP 256 10)) [[ 1 ]] (EXP 256 (EXP 255 10)) [[ 2 ]] (EXP 256 (EXP 257 10)) [[ 3 ]] (EXP 255 (EXP 256 10)) [[ 4 ]] (EXP 255 (EXP 255 10)) [[ 5 ]] (EXP 255 (EXP 257 10)) [[ 6 ]] (EXP 257 (EXP 256 10)) [[ 7 ]] (EXP 257 (EXP 255 10)) [[ 8 ]] (EXP 257 (EXP 257 10)) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "expPowerOf256Of256_11": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EXP 256 (EXP 256 11)) [[ 1 ]] (EXP 256 (EXP 255 11)) [[ 2 ]] (EXP 256 (EXP 257 11)) [[ 3 ]] (EXP 255 (EXP 256 11)) [[ 4 ]] (EXP 255 (EXP 255 11)) [[ 5 ]] (EXP 255 (EXP 257 11)) [[ 6 ]] (EXP 257 (EXP 256 11)) [[ 7 ]] (EXP 257 (EXP 255 11)) [[ 8 ]] (EXP 257 (EXP 257 11)) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "expPowerOf256Of256_12": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EXP 256 (EXP 256 12)) [[ 1 ]] (EXP 256 (EXP 255 12)) [[ 2 ]] (EXP 256 (EXP 257 12)) [[ 3 ]] (EXP 255 (EXP 256 12)) [[ 4 ]] (EXP 255 (EXP 255 12)) [[ 5 ]] (EXP 255 (EXP 257 12)) [[ 6 ]] (EXP 257 (EXP 256 12)) [[ 7 ]] (EXP 257 (EXP 255 12)) [[ 8 ]] (EXP 257 (EXP 257 12)) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "expPowerOf256Of256_13": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EXP 256 (EXP 256 13)) [[ 1 ]] (EXP 256 (EXP 255 13)) [[ 2 ]] (EXP 256 (EXP 257 13)) [[ 3 ]] (EXP 255 (EXP 256 13)) [[ 4 ]] (EXP 255 (EXP 255 13)) [[ 5 ]] (EXP 255 (EXP 257 13)) [[ 6 ]] (EXP 257 (EXP 256 13)) [[ 7 ]] (EXP 257 (EXP 255 13)) [[ 8 ]] (EXP 257 (EXP 257 13)) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "expPowerOf256Of256_14": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EXP 256 (EXP 256 14)) [[ 1 ]] (EXP 256 (EXP 255 14)) [[ 2 ]] (EXP 256 (EXP 257 14)) [[ 3 ]] (EXP 255 (EXP 256 14)) [[ 4 ]] (EXP 255 (EXP 255 14)) [[ 5 ]] (EXP 255 (EXP 257 14)) [[ 6 ]] (EXP 257 (EXP 256 14)) [[ 7 ]] (EXP 257 (EXP 255 14)) [[ 8 ]] (EXP 257 (EXP 257 14)) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "expPowerOf256Of256_15": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EXP 256 (EXP 256 15)) [[ 1 ]] (EXP 256 (EXP 255 15)) [[ 2 ]] (EXP 256 (EXP 257 15)) [[ 3 ]] (EXP 255 (EXP 256 15)) [[ 4 ]] (EXP 255 (EXP 255 15)) [[ 5 ]] (EXP 255 (EXP 257 15)) [[ 6 ]] (EXP 257 (EXP 256 15)) [[ 7 ]] (EXP 257 (EXP 255 15)) [[ 8 ]] (EXP 257 (EXP 257 15)) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "expPowerOf256Of256_16": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EXP 256 (EXP 256 16)) [[ 1 ]] (EXP 256 (EXP 255 16)) [[ 2 ]] (EXP 256 (EXP 257 16)) [[ 3 ]] (EXP 255 (EXP 256 16)) [[ 4 ]] (EXP 255 (EXP 255 16)) [[ 5 ]] (EXP 255 (EXP 257 16)) [[ 6 ]] (EXP 257 (EXP 256 16)) [[ 7 ]] (EXP 257 (EXP 255 16)) [[ 8 ]] (EXP 257 (EXP 257 16)) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "expPowerOf256Of256_17": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EXP 256 (EXP 256 17)) [[ 1 ]] (EXP 256 (EXP 255 17)) [[ 2 ]] (EXP 256 (EXP 257 17)) [[ 3 ]] (EXP 255 (EXP 256 17)) [[ 4 ]] (EXP 255 (EXP 255 17)) [[ 5 ]] (EXP 255 (EXP 257 17)) [[ 6 ]] (EXP 257 (EXP 256 17)) [[ 7 ]] (EXP 257 (EXP 255 17)) [[ 8 ]] (EXP 257 (EXP 257 17)) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "expPowerOf256Of256_18": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EXP 256 (EXP 256 18)) [[ 1 ]] (EXP 256 (EXP 255 18)) [[ 2 ]] (EXP 256 (EXP 257 18)) [[ 3 ]] (EXP 255 (EXP 256 18)) [[ 4 ]] (EXP 255 (EXP 255 18)) [[ 5 ]] (EXP 255 (EXP 257 18)) [[ 6 ]] (EXP 257 (EXP 256 18)) [[ 7 ]] (EXP 257 (EXP 255 18)) [[ 8 ]] (EXP 257 (EXP 257 18)) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "expPowerOf256Of256_19": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EXP 256 (EXP 256 19)) [[ 1 ]] (EXP 256 (EXP 255 19)) [[ 2 ]] (EXP 256 (EXP 257 19)) [[ 3 ]] (EXP 255 (EXP 256 19)) [[ 4 ]] (EXP 255 (EXP 255 19)) [[ 5 ]] (EXP 255 (EXP 257 19)) [[ 6 ]] (EXP 257 (EXP 256 19)) [[ 7 ]] (EXP 257 (EXP 255 19)) [[ 8 ]] (EXP 257 (EXP 257 19)) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "expPowerOf256Of256_20": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EXP 256 (EXP 256 20)) [[ 1 ]] (EXP 256 (EXP 255 20)) [[ 2 ]] (EXP 256 (EXP 257 20)) [[ 3 ]] (EXP 255 (EXP 256 20)) [[ 4 ]] (EXP 255 (EXP 255 20)) [[ 5 ]] (EXP 255 (EXP 257 20)) [[ 6 ]] (EXP 257 (EXP 256 20)) [[ 7 ]] (EXP 257 (EXP 255 20)) [[ 8 ]] (EXP 257 (EXP 257 20)) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "expPowerOf256Of256_21": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EXP 256 (EXP 256 21)) [[ 1 ]] (EXP 256 (EXP 255 21)) [[ 2 ]] (EXP 256 (EXP 257 21)) [[ 3 ]] (EXP 255 (EXP 256 21)) [[ 4 ]] (EXP 255 (EXP 255 21)) [[ 5 ]] (EXP 255 (EXP 257 21)) [[ 6 ]] (EXP 257 (EXP 256 21)) [[ 7 ]] (EXP 257 (EXP 255 21)) [[ 8 ]] (EXP 257 (EXP 257 21)) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "expPowerOf256Of256_22": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EXP 256 (EXP 256 22)) [[ 1 ]] (EXP 256 (EXP 255 22)) [[ 2 ]] (EXP 256 (EXP 257 22)) [[ 3 ]] (EXP 255 (EXP 256 22)) [[ 4 ]] (EXP 255 (EXP 255 22)) [[ 5 ]] (EXP 255 (EXP 257 22)) [[ 6 ]] (EXP 257 (EXP 256 22)) [[ 7 ]] (EXP 257 (EXP 255 22)) [[ 8 ]] (EXP 257 (EXP 257 22)) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "expPowerOf256Of256_23": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EXP 256 (EXP 256 23)) [[ 1 ]] (EXP 256 (EXP 255 23)) [[ 2 ]] (EXP 256 (EXP 257 23)) [[ 3 ]] (EXP 255 (EXP 256 23)) [[ 4 ]] (EXP 255 (EXP 255 23)) [[ 5 ]] (EXP 255 (EXP 257 23)) [[ 6 ]] (EXP 257 (EXP 256 23)) [[ 7 ]] (EXP 257 (EXP 255 23)) [[ 8 ]] (EXP 257 (EXP 257 23)) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "expPowerOf256Of256_24": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EXP 256 (EXP 256 24)) [[ 1 ]] (EXP 256 (EXP 255 24)) [[ 2 ]] (EXP 256 (EXP 257 24)) [[ 3 ]] (EXP 255 (EXP 256 24)) [[ 4 ]] (EXP 255 (EXP 255 24)) [[ 5 ]] (EXP 255 (EXP 257 24)) [[ 6 ]] (EXP 257 (EXP 256 24)) [[ 7 ]] (EXP 257 (EXP 255 24)) [[ 8 ]] (EXP 257 (EXP 257 24)) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "expPowerOf256Of256_25": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EXP 256 (EXP 256 25)) [[ 1 ]] (EXP 256 (EXP 255 25)) [[ 2 ]] (EXP 256 (EXP 257 25)) [[ 3 ]] (EXP 255 (EXP 256 25)) [[ 4 ]] (EXP 255 (EXP 255 25)) [[ 5 ]] (EXP 255 (EXP 257 25)) [[ 6 ]] (EXP 257 (EXP 256 25)) [[ 7 ]] (EXP 257 (EXP 255 25)) [[ 8 ]] (EXP 257 (EXP 257 25)) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "expPowerOf256Of256_26": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EXP 256 (EXP 256 26)) [[ 1 ]] (EXP 256 (EXP 255 26)) [[ 2 ]] (EXP 256 (EXP 257 26)) [[ 3 ]] (EXP 255 (EXP 256 26)) [[ 4 ]] (EXP 255 (EXP 255 26)) [[ 5 ]] (EXP 255 (EXP 257 26)) [[ 6 ]] (EXP 257 (EXP 256 26)) [[ 7 ]] (EXP 257 (EXP 255 26)) [[ 8 ]] (EXP 257 (EXP 257 26)) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "expPowerOf256Of256_27": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EXP 256 (EXP 256 27)) [[ 1 ]] (EXP 256 (EXP 255 27)) [[ 2 ]] (EXP 256 (EXP 257 27)) [[ 3 ]] (EXP 255 (EXP 256 27)) [[ 4 ]] (EXP 255 (EXP 255 27)) [[ 5 ]] (EXP 255 (EXP 257 27)) [[ 6 ]] (EXP 257 (EXP 256 27)) [[ 7 ]] (EXP 257 (EXP 255 27)) [[ 8 ]] (EXP 257 (EXP 257 27)) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "expPowerOf256Of256_28": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EXP 256 (EXP 256 28)) [[ 1 ]] (EXP 256 (EXP 255 28)) [[ 2 ]] (EXP 256 (EXP 257 28)) [[ 3 ]] (EXP 255 (EXP 256 28)) [[ 4 ]] (EXP 255 (EXP 255 28)) [[ 5 ]] (EXP 255 (EXP 257 28)) [[ 6 ]] (EXP 257 (EXP 256 28)) [[ 7 ]] (EXP 257 (EXP 255 28)) [[ 8 ]] (EXP 257 (EXP 257 28)) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "expPowerOf256Of256_29": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EXP 256 (EXP 256 29)) [[ 1 ]] (EXP 256 (EXP 255 29)) [[ 2 ]] (EXP 256 (EXP 257 29)) [[ 3 ]] (EXP 255 (EXP 256 29)) [[ 4 ]] (EXP 255 (EXP 255 29)) [[ 5 ]] (EXP 255 (EXP 257 29)) [[ 6 ]] (EXP 257 (EXP 256 29)) [[ 7 ]] (EXP 257 (EXP 255 29)) [[ 8 ]] (EXP 257 (EXP 257 29)) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "expPowerOf256Of256_30": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EXP 256 (EXP 256 30)) [[ 1 ]] (EXP 256 (EXP 255 30)) [[ 2 ]] (EXP 256 (EXP 257 30)) [[ 3 ]] (EXP 255 (EXP 256 30)) [[ 4 ]] (EXP 255 (EXP 255 30)) [[ 5 ]] (EXP 255 (EXP 257 30)) [[ 6 ]] (EXP 257 (EXP 256 30)) [[ 7 ]] (EXP 257 (EXP 255 30)) [[ 8 ]] (EXP 257 (EXP 257 30)) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "expPowerOf256Of256_31": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EXP 256 (EXP 256 31)) [[ 1 ]] (EXP 256 (EXP 255 31)) [[ 2 ]] (EXP 256 (EXP 257 31)) [[ 3 ]] (EXP 255 (EXP 256 31)) [[ 4 ]] (EXP 255 (EXP 255 31)) [[ 5 ]] (EXP 255 (EXP 257 31)) [[ 6 ]] (EXP 257 (EXP 256 31)) [[ 7 ]] (EXP 257 (EXP 255 31)) [[ 8 ]] (EXP 257 (EXP 257 31)) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "expPowerOf256Of256_32": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EXP 256 (EXP 256 32)) [[ 1 ]] (EXP 256 (EXP 255 32)) [[ 2 ]] (EXP 256 (EXP 257 32)) [[ 3 ]] (EXP 255 (EXP 256 32)) [[ 4 ]] (EXP 255 (EXP 255 32)) [[ 5 ]] (EXP 255 (EXP 257 32)) [[ 6 ]] (EXP 257 (EXP 256 32)) [[ 7 ]] (EXP 257 (EXP 255 32)) [[ 8 ]] (EXP 257 (EXP 257 32)) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "expPowerOf256Of256_33": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EXP 256 (EXP 256 33)) [[ 1 ]] (EXP 256 (EXP 255 33)) [[ 2 ]] (EXP 256 (EXP 257 33)) [[ 3 ]] (EXP 255 (EXP 256 33)) [[ 4 ]] (EXP 255 (EXP 255 33)) [[ 5 ]] (EXP 255 (EXP 257 33)) [[ 6 ]] (EXP 257 (EXP 256 33)) [[ 7 ]] (EXP 257 (EXP 255 33)) [[ 8 ]] (EXP 257 (EXP 257 33)) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f2947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + "signextend_bitIsSet": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", From e70bf144c6f88e3dfbe48d7b506cd150b2ab175c Mon Sep 17 00:00:00 2001 From: arkpar Date: Fri, 2 Jan 2015 18:11:50 +0100 Subject: [PATCH 060/111] basic syntax highlighting --- mix/CodeEditorExtensionManager.cpp | 15 +++- mix/CodeEditorExtensionManager.h | 4 + mix/CodeHighlighter.cpp | 139 +++++++++++++++++++++++++++++ mix/CodeHighlighter.h | 94 +++++++++++++++++++ mix/CodeModel.cpp | 66 ++++++++++---- mix/CodeModel.h | 24 +++-- mix/qml/MainContent.qml | 6 +- 7 files changed, 318 insertions(+), 30 deletions(-) create mode 100644 mix/CodeHighlighter.cpp create mode 100644 mix/CodeHighlighter.h diff --git a/mix/CodeEditorExtensionManager.cpp b/mix/CodeEditorExtensionManager.cpp index df43cac48..79bbe9a9e 100644 --- a/mix/CodeEditorExtensionManager.cpp +++ b/mix/CodeEditorExtensionManager.cpp @@ -25,13 +25,13 @@ #include #include #include -#include #include "ConstantCompilationControl.h" #include "AssemblyDebuggerControl.h" #include "StateListView.h" #include "AppContext.h" #include "MixApplication.h" #include "CodeModel.h" +#include "CodeHighlighter.h" #include "CodeEditorExtensionManager.h" using namespace dev::mix; @@ -67,8 +67,9 @@ void CodeEditorExtensionManager::initExtensions() std::shared_ptr output = std::make_shared(m_appContext); std::shared_ptr debug = std::make_shared(m_appContext); std::shared_ptr stateList = std::make_shared(m_appContext); - QObject::connect(m_doc, &QTextDocument::contentsChanged, [=]() { m_appContext->codeModel()->registerCodeChange(m_doc->toPlainText()); }); + QObject::connect(m_doc, &QTextDocument::contentsChange, this, &CodeEditorExtensionManager::onCodeChange); QObject::connect(debug.get(), &AssemblyDebuggerControl::runFailed, output.get(), &ConstantCompilationControl::displayError); + QObject::connect(m_appContext->codeModel(), &CodeModel::compilationComplete, this, &CodeEditorExtensionManager::applyCodeHighlight); initExtension(output); initExtension(debug); @@ -111,6 +112,16 @@ void CodeEditorExtensionManager::setEditor(QQuickItem* _editor) } } +void CodeEditorExtensionManager::onCodeChange() +{ + m_appContext->codeModel()->registerCodeChange(m_doc->toPlainText()); +} + +void CodeEditorExtensionManager::applyCodeHighlight() +{ + m_appContext->codeModel()->updateFormatting(m_doc); +} + void CodeEditorExtensionManager::setRightTabView(QQuickItem* _tabView) { m_rightTabView = _tabView; diff --git a/mix/CodeEditorExtensionManager.h b/mix/CodeEditorExtensionManager.h index 22ba1acef..46ee6569f 100644 --- a/mix/CodeEditorExtensionManager.h +++ b/mix/CodeEditorExtensionManager.h @@ -61,6 +61,10 @@ public: /// Set current right tab view. void setRightTabView(QQuickItem*); +private slots: + void onCodeChange(); + void applyCodeHighlight(); + private: QQuickItem* m_editor; QVector> m_features; diff --git a/mix/CodeHighlighter.cpp b/mix/CodeHighlighter.cpp new file mode 100644 index 000000000..f246e9b7b --- /dev/null +++ b/mix/CodeHighlighter.cpp @@ -0,0 +1,139 @@ +/* + 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 CodeHighlighter.cpp + * @author Arkadiy Paronyan arkadiy@ethdev.com + * @date 2015 + * Ethereum IDE client. + */ + +#include +#include +#include +#include +#include +#include "CodeHighlighter.h" +#include "libsolidity/ASTVisitor.h" +#include "libsolidity/AST.h" +#include "libsolidity/Scanner.h" + +namespace dev +{ +namespace mix +{ + +CodeHighlighterSettings::CodeHighlighterSettings() +{ + bg = QColor(0x00, 0x2b, 0x36); + fg = QColor (0xee, 0xe8, 0xd5); + formats[Keyword].setForeground(QColor(0x93, 0xa1, 0xa1)); + //formats[Type].setForeground(Qt::darkCyan); + formats[Comment].setForeground(QColor(0x85, 0x99, 0x00)); + formats[StringLiteral].setForeground(QColor(0xdc, 0x32, 0x2f)); + formats[NumLiteral].setForeground(fg); + formats[Import].setForeground(QColor(0x6c, 0x71, 0xc4)); +} + +namespace +{ + using namespace dev::solidity; + class HighlightVisitor : public solidity::ASTConstVisitor + { + public: + HighlightVisitor(CodeHighlighter::Formats* _formats) { m_formats = _formats; } + private: + CodeHighlighter::Formats* m_formats; + + virtual bool visit(ImportDirective const& _node) + { + m_formats->push_back(CodeHighlighter::FormatRange(CodeHighlighterSettings::Import, _node.getLocation())); + return true; + } + }; +} + + +CodeHighlighter::FormatRange::FormatRange(CodeHighlighterSettings::Token _t, solidity::Location const& _location): + token(_t), start(_location.start), length(_location.end - _location.start) +{} + +void CodeHighlighter::processSource(solidity::Scanner* _scanner) +{ + solidity::Token::Value token = _scanner->getCurrentToken(); + while (token != Token::EOS) + { + if ((token >= Token::BREAK && token < Token::TYPES_END) || + token == Token::IN || token == Token::DELETE || token == Token::NULL_LITERAL || token == Token::TRUE_LITERAL || token == Token::FALSE_LITERAL) + m_formats.push_back(FormatRange(CodeHighlighterSettings::Keyword, _scanner->getCurrentLocation())); + else if (token == Token::STRING_LITERAL) + m_formats.push_back(FormatRange(CodeHighlighterSettings::StringLiteral, _scanner->getCurrentLocation())); + else if (token == Token::COMMENT_LITERAL) + m_formats.push_back(FormatRange(CodeHighlighterSettings::Comment, _scanner->getCurrentLocation())); + else if (token == Token::NUMBER) + m_formats.push_back(FormatRange(CodeHighlighterSettings::NumLiteral, _scanner->getCurrentLocation())); + + token = _scanner->next(); + } + std::sort(m_formats.begin(), m_formats.end()); +} + +void CodeHighlighter::processAST(solidity::ASTNode const& _ast) +{ + HighlightVisitor visitor(&m_formats); + _ast.accept(visitor); + + std::sort(m_formats.begin(), m_formats.end()); +} + +void CodeHighlighter::updateFormatting(QTextDocument* _document, CodeHighlighterSettings const& _settings) +{ + QTextBlock block = _document->firstBlock(); + QList ranges; + + Formats::const_iterator format = m_formats.begin(); + while (true) + { + while ((format == m_formats.end() || (block.position() + block.length() <= format->start)) && block.isValid()) + { + auto layout = block.layout(); + layout->clearAdditionalFormats(); + layout->setAdditionalFormats(ranges); + _document->markContentsDirty(block.position(), block.length()); + block = block.next(); + ranges.clear(); + } + if (!block.isValid()) + break; + + int intersectionStart = std::max(format->start, block.position()); + int intersectionLength = std::min(format->start + format->length, block.position() + block.length()) - intersectionStart; + if (intersectionLength > 0) + { + QTextLayout::FormatRange range; + range.format = _settings.formats[format->token]; + range.start = format->start - block.position(); + range.length = format->length; + ranges.append(range); + } + ++format; + } +} + + + + +} +} diff --git a/mix/CodeHighlighter.h b/mix/CodeHighlighter.h new file mode 100644 index 000000000..baf39bc66 --- /dev/null +++ b/mix/CodeHighlighter.h @@ -0,0 +1,94 @@ +/* + 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 CodeHighlighter.h + * @author Arkadiy Paronyan arkadiy@ethdev.com + * @date 2015 + * Ethereum IDE client. + */ + +#pragma once + +#include +#include +#include + +class QTextDocument; + +namespace dev +{ + +namespace solidity +{ + class ASTNode; + class Scanner; + struct Location; +} + +namespace mix +{ + +class CodeHighlighterSettings +{ +public: + enum Token + { + Import, + Keyword, + Comment, + StringLiteral, + NumLiteral, + Size, //this must be kept last + }; + + CodeHighlighterSettings(); + ///Format for each token + QTextCharFormat formats[Size]; + ///Background color + QColor bg; + ///Foreground color + QColor fg; +}; + + +class CodeHighlighter +{ +public: + struct FormatRange + { + FormatRange(CodeHighlighterSettings::Token _t, int _start, int _length): token(_t), start(_start), length(_length) {} + FormatRange(CodeHighlighterSettings::Token _t, solidity::Location const& _location); + bool operator<(FormatRange const& _other) { return start < _other.start || (start == _other.start && length < _other.length); } + + CodeHighlighterSettings::Token token; + int start; + int length; + }; + typedef std::vector Formats; // Sorted by start position + +public: + /// Collect highligting information + void processSource(solidity::Scanner* _scanner); + void processAST(solidity::ASTNode const& _ast); + void updateFormatting(QTextDocument* _document, CodeHighlighterSettings const& _settings); + +private: + Formats m_formats; +}; + +} + +} diff --git a/mix/CodeModel.cpp b/mix/CodeModel.cpp index b907c2e64..60c961045 100644 --- a/mix/CodeModel.cpp +++ b/mix/CodeModel.cpp @@ -24,12 +24,14 @@ #include #include #include +#include #include #include #include #include "QContractDefinition.h" #include "QFunctionDefinition.h" #include "QVariableDeclaration.h" +#include "CodeHighlighter.h" #include "CodeModel.h" namespace dev @@ -42,28 +44,36 @@ void BackgroundWorker::queueCodeChange(int _jobId, QString const& _content) m_model->runCompilationJob(_jobId, _content); } -CompilationResult::CompilationResult(QObject *_parent): - QObject(_parent), m_successfull(false), - m_contract(new QContractDefinition()) +CompilationResult::CompilationResult(): + QObject(nullptr), m_successfull(false), + m_contract(new QContractDefinition()), + m_codeHighlighter(new CodeHighlighter()) {} -CompilationResult::CompilationResult(const solidity::CompilerStack& _compiler, QObject *_parent): - QObject(_parent), m_successfull(true), - m_contract(new QContractDefinition(&_compiler.getContractDefinition(std::string()))), - m_bytes(_compiler.getBytecode()), - m_assemblyCode(QString::fromStdString((dev::eth::disassemble(m_bytes)))) -{} +CompilationResult::CompilationResult(const solidity::CompilerStack& _compiler): + QObject(nullptr), m_successfull(true) +{ + if (!_compiler.getContractNames().empty()) + { + m_contract.reset(new QContractDefinition(&_compiler.getContractDefinition(std::string()))); + m_bytes = _compiler.getBytecode(); + m_assemblyCode = QString::fromStdString(dev::eth::disassemble(m_bytes)); + } + else + m_contract.reset(new QContractDefinition()); +} -CompilationResult::CompilationResult(CompilationResult const& _prev, QString const& _compilerMessage, QObject* _parent): - QObject(_parent), m_successfull(false), +CompilationResult::CompilationResult(CompilationResult const& _prev, QString const& _compilerMessage): + QObject(nullptr), m_successfull(false), m_contract(_prev.m_contract), m_compilerMessage(_compilerMessage), m_bytes(_prev.m_bytes), - m_assemblyCode(_prev.m_assemblyCode) + m_assemblyCode(_prev.m_assemblyCode), + m_codeHighlighter(_prev.m_codeHighlighter) {} CodeModel::CodeModel(QObject* _parent) : QObject(_parent), - m_compiling(false), m_result(new CompilationResult(nullptr)), m_backgroundWorker(this), m_backgroundJobId(0) + m_compiling(false), m_result(new CompilationResult()), m_codeHighlighterSettings(new CodeHighlighterSettings()), m_backgroundWorker(this), m_backgroundJobId(0) { m_backgroundWorker.moveToThread(&m_backgroundThread); connect(this, &CodeModel::scheduleCompilationJob, &m_backgroundWorker, &BackgroundWorker::queueCodeChange, Qt::QueuedConnection); @@ -105,22 +115,35 @@ void CodeModel::runCompilationJob(int _jobId, QString const& _code) return; //obsolete job solidity::CompilerStack cs; + std::unique_ptr result; + + std::string source = _code.toStdString(); + // run syntax highlighting first + // @todo combine this with compilation step + auto codeHighlighter = std::make_shared(); + solidity::CharStream stream(source); + solidity::Scanner scanner(stream); + codeHighlighter->processSource(&scanner); + + // run compilation try { - cs.setSource(_code.toStdString()); + cs.setSource(source); cs.compile(false); - std::unique_ptr result(new CompilationResult(cs, nullptr)); + codeHighlighter->processAST(cs.getAST()); + result.reset(new CompilationResult(cs)); qDebug() << QString(QApplication::tr("compilation succeeded")); - emit compilationCompleteInternal(result.release()); } catch (dev::Exception const& _exception) { std::ostringstream error; solidity::SourceReferenceFormatter::printExceptionInformation(error, _exception, "Error", cs); - std::unique_ptr result(new CompilationResult(*m_result, QString::fromStdString(error.str()), nullptr)); - qDebug() << QString(QApplication::tr("compilation failed") + " " + m_result->compilerMessage()); - emit compilationCompleteInternal(result.release()); + result.reset(new CompilationResult(*m_result, QString::fromStdString(error.str()))); + qDebug() << QString(QApplication::tr("compilation failed:") + " " + m_result->compilerMessage()); } + result->m_codeHighlighter = codeHighlighter; + + emit compilationCompleteInternal(result.release()); } void CodeModel::onCompilationComplete(CompilationResult*_newResult) @@ -138,5 +161,10 @@ bool CodeModel::hasContract() const return m_result->contract()->functionsList().size() > 0; } +void CodeModel::updateFormatting(QTextDocument* _document) +{ + m_result->codeHighlighter()->updateFormatting(_document, *m_codeHighlighterSettings); +} + } } diff --git a/mix/CodeModel.h b/mix/CodeModel.h index 091c41843..d148cad87 100644 --- a/mix/CodeModel.h +++ b/mix/CodeModel.h @@ -23,10 +23,13 @@ #pragma once #include +#include #include #include #include +class QTextDocument; + namespace dev { @@ -39,6 +42,8 @@ namespace mix { class CodeModel; +class CodeHighlighter; +class CodeHighlighterSettings; class QContractDefinition; //utility class to perform tasks in background thread @@ -63,28 +68,26 @@ class CompilationResult : public QObject public: /// Empty compilation result constructor - CompilationResult(QObject* parent); + CompilationResult(); /// Successfull compilation result constructor - CompilationResult(solidity::CompilerStack const& _compiler, QObject* parent); + CompilationResult(solidity::CompilerStack const& _compiler); /// Failed compilation result constructor - CompilationResult(CompilationResult const& _prev, QString const& _compilerMessage, QObject* parent); + CompilationResult(CompilationResult const& _prev, QString const& _compilerMessage); /// @returns contract definition for QML property QContractDefinition* contract() { return m_contract.get(); } /// @returns contract definition std::shared_ptr sharedContract() { return m_contract; } - /// Indicates if the compilation was successfull bool successfull() const { return m_successfull; } - /// @returns compiler error message in case of unsuccessfull compilation QString compilerMessage() const { return m_compilerMessage; } - /// @returns contract bytecode dev::bytes const& bytes() const { return m_bytes; } - /// @returns contract bytecode in human-readable form QString assemblyCode() const { return m_assemblyCode; } + /// Get code highlighter + std::shared_ptr codeHighlighter() { return m_codeHighlighter; } private: bool m_successfull; @@ -92,7 +95,9 @@ private: QString m_compilerMessage; ///< @todo: use some structure here dev::bytes m_bytes; QString m_assemblyCode; + std::shared_ptr m_codeHighlighter; ///@todo syntax highlighting, etc + friend class CodeModel; }; /// Background code compiler @@ -117,6 +122,8 @@ public: bool isCompiling() const { return m_compiling; } /// @returns true if contract has at least one function bool hasContract() const; + /// Apply text document formatting. @todo Move this to editor module + void updateFormatting(QTextDocument* _document); signals: /// Emited on compilation state change @@ -141,8 +148,9 @@ private: void runCompilationJob(int _jobId, QString const& _content); void stop(); - bool m_compiling; + std::atomic m_compiling; std::unique_ptr m_result; + std::unique_ptr m_codeHighlighterSettings; QThread m_backgroundThread; BackgroundWorker m_backgroundWorker; int m_backgroundJobId = 0; //protects from starting obsolete compilation job diff --git a/mix/qml/MainContent.qml b/mix/qml/MainContent.qml index 794e5746d..0b3303aa8 100644 --- a/mix/qml/MainContent.qml +++ b/mix/qml/MainContent.qml @@ -30,7 +30,11 @@ Rectangle { width: parent.width height: parent.height * 0.7 TextArea { - id: codeEditor + id: codeEditor + textColor: "#EEE8D5" + style: TextAreaStyle { + backgroundColor: "#002B36" + } height: parent.height font.family: "Monospace" font.pointSize: 12 From fcbd25a8be6e88e642da4550569bd06dbcbd25bc Mon Sep 17 00:00:00 2001 From: arkpar Date: Sat, 3 Jan 2015 14:59:36 +0100 Subject: [PATCH 061/111] comment highlighting --- mix/CodeEditorExtensionManager.cpp | 1 + mix/CodeHighlighter.cpp | 48 +++++++++++++++++++++++++----- mix/CodeHighlighter.h | 6 ++-- mix/CodeModel.cpp | 14 +++++---- mix/CodeModel.h | 1 + mix/qml/MainContent.qml | 10 +++---- 6 files changed, 60 insertions(+), 20 deletions(-) diff --git a/mix/CodeEditorExtensionManager.cpp b/mix/CodeEditorExtensionManager.cpp index 79bbe9a9e..48c928a1f 100644 --- a/mix/CodeEditorExtensionManager.cpp +++ b/mix/CodeEditorExtensionManager.cpp @@ -114,6 +114,7 @@ void CodeEditorExtensionManager::setEditor(QQuickItem* _editor) void CodeEditorExtensionManager::onCodeChange() { + m_appContext->codeModel()->updateFormatting(m_doc); //update old formatting m_appContext->codeModel()->registerCodeChange(m_doc->toPlainText()); } diff --git a/mix/CodeHighlighter.cpp b/mix/CodeHighlighter.cpp index f246e9b7b..6476b0995 100644 --- a/mix/CodeHighlighter.cpp +++ b/mix/CodeHighlighter.cpp @@ -70,22 +70,25 @@ CodeHighlighter::FormatRange::FormatRange(CodeHighlighterSettings::Token _t, sol token(_t), start(_location.start), length(_location.end - _location.start) {} -void CodeHighlighter::processSource(solidity::Scanner* _scanner) +void CodeHighlighter::processSource(std::string const& _source) { - solidity::Token::Value token = _scanner->getCurrentToken(); + processComments(_source); + solidity::CharStream stream(_source); + solidity::Scanner scanner(stream); + solidity::Token::Value token = scanner.getCurrentToken(); while (token != Token::EOS) { if ((token >= Token::BREAK && token < Token::TYPES_END) || token == Token::IN || token == Token::DELETE || token == Token::NULL_LITERAL || token == Token::TRUE_LITERAL || token == Token::FALSE_LITERAL) - m_formats.push_back(FormatRange(CodeHighlighterSettings::Keyword, _scanner->getCurrentLocation())); + m_formats.push_back(FormatRange(CodeHighlighterSettings::Keyword, scanner.getCurrentLocation())); else if (token == Token::STRING_LITERAL) - m_formats.push_back(FormatRange(CodeHighlighterSettings::StringLiteral, _scanner->getCurrentLocation())); + m_formats.push_back(FormatRange(CodeHighlighterSettings::StringLiteral, scanner.getCurrentLocation())); else if (token == Token::COMMENT_LITERAL) - m_formats.push_back(FormatRange(CodeHighlighterSettings::Comment, _scanner->getCurrentLocation())); + m_formats.push_back(FormatRange(CodeHighlighterSettings::Comment, scanner.getCurrentLocation())); else if (token == Token::NUMBER) - m_formats.push_back(FormatRange(CodeHighlighterSettings::NumLiteral, _scanner->getCurrentLocation())); + m_formats.push_back(FormatRange(CodeHighlighterSettings::NumLiteral, scanner.getCurrentLocation())); - token = _scanner->next(); + token = scanner.next(); } std::sort(m_formats.begin(), m_formats.end()); } @@ -98,6 +101,37 @@ void CodeHighlighter::processAST(solidity::ASTNode const& _ast) std::sort(m_formats.begin(), m_formats.end()); } + +void CodeHighlighter::processComments(std::string const& _source) +{ + unsigned i = 0; + unsigned size = _source.size(); + if (size == 0) + return; + while (i < size - 1) + { + if (_source[i] == '/' && _source[i + 1] == '/') + { + //add single line comment + int start = i; + i += 2; + while (_source[i] != '\n' && i < size) + ++i; + m_formats.push_back(FormatRange(CodeHighlighterSettings::Comment, start, i - start)); + } + else if (_source[i] == '/' && _source[i + 1] == '*') + { + //add multiline comment + int start = i; + i += 2; + while ((_source[i] != '/' || _source[i - 1] != '*') && i < size) + ++i; + m_formats.push_back(FormatRange(CodeHighlighterSettings::Comment, start, i - start + 1)); + } + ++i; + } +} + void CodeHighlighter::updateFormatting(QTextDocument* _document, CodeHighlighterSettings const& _settings) { QTextBlock block = _document->firstBlock(); diff --git a/mix/CodeHighlighter.h b/mix/CodeHighlighter.h index baf39bc66..8cc8b69e9 100644 --- a/mix/CodeHighlighter.h +++ b/mix/CodeHighlighter.h @@ -34,7 +34,6 @@ namespace dev namespace solidity { class ASTNode; - class Scanner; struct Location; } @@ -81,10 +80,13 @@ public: public: /// Collect highligting information - void processSource(solidity::Scanner* _scanner); + void processSource(std::string const& _source); void processAST(solidity::ASTNode const& _ast); void updateFormatting(QTextDocument* _document, CodeHighlighterSettings const& _settings); +private: + void processComments(std::string const& _source); + private: Formats m_formats; }; diff --git a/mix/CodeModel.cpp b/mix/CodeModel.cpp index 60c961045..deb58416c 100644 --- a/mix/CodeModel.cpp +++ b/mix/CodeModel.cpp @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include @@ -47,7 +46,8 @@ void BackgroundWorker::queueCodeChange(int _jobId, QString const& _content) CompilationResult::CompilationResult(): QObject(nullptr), m_successfull(false), m_contract(new QContractDefinition()), - m_codeHighlighter(new CodeHighlighter()) + m_codeHighlighter(new CodeHighlighter()), + m_codeHash(qHash(QString())) {} CompilationResult::CompilationResult(const solidity::CompilerStack& _compiler): @@ -103,6 +103,9 @@ void CodeModel::stop() void CodeModel::registerCodeChange(const QString &_code) { // launch the background thread + uint hash = qHash(_code); + if (m_result->m_codeHash == hash) + return; m_backgroundJobId++; m_compiling = true; emit stateChanged(); @@ -121,9 +124,7 @@ void CodeModel::runCompilationJob(int _jobId, QString const& _code) // run syntax highlighting first // @todo combine this with compilation step auto codeHighlighter = std::make_shared(); - solidity::CharStream stream(source); - solidity::Scanner scanner(stream); - codeHighlighter->processSource(&scanner); + codeHighlighter->processSource(source); // run compilation try @@ -139,9 +140,10 @@ void CodeModel::runCompilationJob(int _jobId, QString const& _code) std::ostringstream error; solidity::SourceReferenceFormatter::printExceptionInformation(error, _exception, "Error", cs); result.reset(new CompilationResult(*m_result, QString::fromStdString(error.str()))); - qDebug() << QString(QApplication::tr("compilation failed:") + " " + m_result->compilerMessage()); + qDebug() << QString(QApplication::tr("compilation failed:") + " " + result->compilerMessage()); } result->m_codeHighlighter = codeHighlighter; + result->m_codeHash = qHash(_code); emit compilationCompleteInternal(result.release()); } diff --git a/mix/CodeModel.h b/mix/CodeModel.h index d148cad87..da093183d 100644 --- a/mix/CodeModel.h +++ b/mix/CodeModel.h @@ -98,6 +98,7 @@ private: std::shared_ptr m_codeHighlighter; ///@todo syntax highlighting, etc friend class CodeModel; + uint m_codeHash; }; /// Background code compiler diff --git a/mix/qml/MainContent.qml b/mix/qml/MainContent.qml index 0b3303aa8..99953344f 100644 --- a/mix/qml/MainContent.qml +++ b/mix/qml/MainContent.qml @@ -42,11 +42,11 @@ Rectangle { anchors.centerIn: parent tabChangesFocus: false Keys.onPressed: { - if (event.key === Qt.Key_Tab) { - codeEditor.insert(codeEditor.cursorPosition, "\t"); - event.accepted = true; - } - } + if (event.key === Qt.Key_Tab) { + codeEditor.insert(codeEditor.cursorPosition, "\t"); + event.accepted = true; + } + } } } Rectangle { From 1cddea44b5323376da2c49ce73597215a900cbff Mon Sep 17 00:00:00 2001 From: arkpar Date: Sat, 3 Jan 2015 18:18:22 +0100 Subject: [PATCH 062/111] line number indicator --- mix/qml/MainContent.qml | 73 +++++++++++++++++++++++++++++++---------- 1 file changed, 56 insertions(+), 17 deletions(-) diff --git a/mix/qml/MainContent.qml b/mix/qml/MainContent.qml index 99953344f..7f9a27d58 100644 --- a/mix/qml/MainContent.qml +++ b/mix/qml/MainContent.qml @@ -29,25 +29,64 @@ Rectangle { id: contentView width: parent.width height: parent.height * 0.7 - TextArea { - id: codeEditor - textColor: "#EEE8D5" - style: TextAreaStyle { - backgroundColor: "#002B36" - } - height: parent.height - font.family: "Monospace" - font.pointSize: 12 - width: parent.width - anchors.centerIn: parent - tabChangesFocus: false - Keys.onPressed: { - if (event.key === Qt.Key_Tab) { - codeEditor.insert(codeEditor.cursorPosition, "\t"); - event.accepted = true; + + Item { + anchors.fill: parent + Rectangle { + id: lineColumn + property int rowHeight: codeEditor.font.pixelSize + 3 + color: "#202020" + width: 50 + height: parent.height + Column { + y: -codeEditor.flickableItem.contentY + 4 + width: parent.width + Repeater { + model: Math.max(codeEditor.lineCount + 2, (lineColumn.height/lineColumn.rowHeight)) + delegate: Text { + id: text + color: codeEditor.textColor + font: codeEditor.font + width: lineColumn.width - 4 + horizontalAlignment: Text.AlignRight + verticalAlignment: Text.AlignVCenter + height: lineColumn.rowHeight + renderType: Text.NativeRendering + text: index + 1 + } + } + } + } + + TextArea { + id: codeEditor + textColor: "#EEE8D5" + style: TextAreaStyle { + backgroundColor: "#002B36" + } + + anchors.left: lineColumn.right + anchors.right: parent.right + anchors.top: parent.top + anchors.bottom: parent.bottom + wrapMode: TextEdit.NoWrap + frameVisible: false + + height: parent.height + font.family: "Monospace" + font.pointSize: 12 + width: parent.width + //anchors.centerIn: parent + tabChangesFocus: false + Keys.onPressed: { + if (event.key === Qt.Key_Tab) { + codeEditor.insert(codeEditor.cursorPosition, "\t"); + event.accepted = true; + } } } - } + } + } Rectangle { anchors.bottom: parent.bottom From 8d129924e38da38f1c30e2f0fe0d159b80b0fe89 Mon Sep 17 00:00:00 2001 From: arkpar Date: Sun, 4 Jan 2015 16:08:51 +0100 Subject: [PATCH 063/111] error highlighting --- mix/CodeHighlighter.cpp | 9 ++++++++- mix/CodeHighlighter.h | 6 +++++- mix/CodeModel.cpp | 1 + 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/mix/CodeHighlighter.cpp b/mix/CodeHighlighter.cpp index 6476b0995..5f6cf7489 100644 --- a/mix/CodeHighlighter.cpp +++ b/mix/CodeHighlighter.cpp @@ -29,6 +29,7 @@ #include "libsolidity/ASTVisitor.h" #include "libsolidity/AST.h" #include "libsolidity/Scanner.h" +#include "libsolidity/Exceptions.h" namespace dev { @@ -40,11 +41,12 @@ CodeHighlighterSettings::CodeHighlighterSettings() bg = QColor(0x00, 0x2b, 0x36); fg = QColor (0xee, 0xe8, 0xd5); formats[Keyword].setForeground(QColor(0x93, 0xa1, 0xa1)); - //formats[Type].setForeground(Qt::darkCyan); formats[Comment].setForeground(QColor(0x85, 0x99, 0x00)); formats[StringLiteral].setForeground(QColor(0xdc, 0x32, 0x2f)); formats[NumLiteral].setForeground(fg); formats[Import].setForeground(QColor(0x6c, 0x71, 0xc4)); + formats[CompilationError].setUnderlineColor(Qt::red); + formats[CompilationError].setUnderlineStyle(QTextCharFormat::SingleUnderline); } namespace @@ -101,6 +103,11 @@ void CodeHighlighter::processAST(solidity::ASTNode const& _ast) std::sort(m_formats.begin(), m_formats.end()); } +void CodeHighlighter::processError(dev::Exception const& _exception) +{ + Location const* location = boost::get_error_info(_exception); + m_formats.push_back(FormatRange(CodeHighlighterSettings::CompilationError, *location)); +} void CodeHighlighter::processComments(std::string const& _source) { diff --git a/mix/CodeHighlighter.h b/mix/CodeHighlighter.h index 8cc8b69e9..d0c92f3fc 100644 --- a/mix/CodeHighlighter.h +++ b/mix/CodeHighlighter.h @@ -31,6 +31,8 @@ class QTextDocument; namespace dev { +struct Exception; + namespace solidity { class ASTNode; @@ -50,6 +52,7 @@ public: Comment, StringLiteral, NumLiteral, + CompilationError, Size, //this must be kept last }; @@ -70,7 +73,7 @@ public: { FormatRange(CodeHighlighterSettings::Token _t, int _start, int _length): token(_t), start(_start), length(_length) {} FormatRange(CodeHighlighterSettings::Token _t, solidity::Location const& _location); - bool operator<(FormatRange const& _other) { return start < _other.start || (start == _other.start && length < _other.length); } + bool operator<(FormatRange const& _other) const { return start < _other.start || (start == _other.start && length < _other.length); } CodeHighlighterSettings::Token token; int start; @@ -82,6 +85,7 @@ public: /// Collect highligting information void processSource(std::string const& _source); void processAST(solidity::ASTNode const& _ast); + void processError(dev::Exception const& _exception); void updateFormatting(QTextDocument* _document, CodeHighlighterSettings const& _settings); private: diff --git a/mix/CodeModel.cpp b/mix/CodeModel.cpp index deb58416c..0c94173e9 100644 --- a/mix/CodeModel.cpp +++ b/mix/CodeModel.cpp @@ -140,6 +140,7 @@ void CodeModel::runCompilationJob(int _jobId, QString const& _code) std::ostringstream error; solidity::SourceReferenceFormatter::printExceptionInformation(error, _exception, "Error", cs); result.reset(new CompilationResult(*m_result, QString::fromStdString(error.str()))); + codeHighlighter->processError(_exception); qDebug() << QString(QApplication::tr("compilation failed:") + " " + result->compilerMessage()); } result->m_codeHighlighter = codeHighlighter; From 44f80248ad5d65358963b0c5fc2975e0f6e986c5 Mon Sep 17 00:00:00 2001 From: subtly Date: Sun, 4 Jan 2015 21:01:56 +0100 Subject: [PATCH 064/111] coding standards, h512 node id, mute warnings for clang builds. attempt inherited constructor fix for windows. --- libdevcore/Common.h | 6 ++++ libp2p/NodeTable.cpp | 34 ++++++++++++----------- libp2p/NodeTable.h | 65 +++++++++++++++++++------------------------- libp2p/UDP.cpp | 2 +- libp2p/UDP.h | 6 ++-- test/boostTest.cpp | 4 +++ test/net.cpp | 6 ++++ 7 files changed, 65 insertions(+), 58 deletions(-) diff --git a/libdevcore/Common.h b/libdevcore/Common.h index 198119f24..aa9a5ae03 100644 --- a/libdevcore/Common.h +++ b/libdevcore/Common.h @@ -36,7 +36,12 @@ #include #include #include +#pragma warning(push) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" #include +#pragma warning(pop) +#pragma GCC diagnostic pop #include "vector_ref.h" #include "debugbreak.h" @@ -64,6 +69,7 @@ using u256 = boost::multiprecision::number>; using u160 = boost::multiprecision::number>; using s160 = boost::multiprecision::number>; +using u512 = boost::multiprecision::number>; using u256s = std::vector; using u160s = std::vector; using u256Set = std::set; diff --git a/libp2p/NodeTable.cpp b/libp2p/NodeTable.cpp index 7a98950ea..20f9f5fdf 100644 --- a/libp2p/NodeTable.cpp +++ b/libp2p/NodeTable.cpp @@ -25,7 +25,7 @@ using namespace dev; using namespace dev::p2p; NodeTable::NodeTable(ba::io_service& _io, KeyPair _alias, uint16_t _listenPort): - m_node(Node(_alias.address(), _alias.pub(), bi::udp::endpoint())), + m_node(Node(_alias.pub(), bi::udp::endpoint())), m_secret(_alias.sec()), m_socket(new NodeSocket(_io, *this, _listenPort)), m_socketPtr(m_socket.get()), @@ -34,7 +34,11 @@ NodeTable::NodeTable(ba::io_service& _io, KeyPair _alias, uint16_t _listenPort): m_evictionCheckTimer(m_io) { for (unsigned i = 0; i < s_bins; i++) - m_state[i].distance = i, m_state[i].modified = chrono::steady_clock::now() - chrono::seconds(1); + { + m_state[i].distance = i; + m_state[i].modified = chrono::steady_clock::now() - chrono::seconds(1); + } + m_socketPtr->connect(); doRefreshBuckets(boost::system::error_code()); } @@ -51,9 +55,9 @@ void NodeTable::join() doFindNode(m_node.id); } -std::list
NodeTable::nodes() const +std::list NodeTable::nodes() const { - std::list
nodes; + std::list nodes; Guard l(x_nodes); for (auto& i: m_nodes) nodes.push_back(i.second->id); @@ -70,20 +74,20 @@ list NodeTable::state() const return move(ret); } -NodeTable::NodeEntry NodeTable::operator[](Address _id) +NodeTable::NodeEntry NodeTable::operator[](NodeId _id) { Guard l(x_nodes); return *m_nodes[_id]; } -void NodeTable::requestNeighbors(NodeEntry const& _node, Address _target) const +void NodeTable::requestNeighbors(NodeEntry const& _node, NodeId _target) const { FindNode p(_node.endpoint.udp, _target); p.sign(m_secret); m_socketPtr->send(p); } -void NodeTable::doFindNode(Address _node, unsigned _round, std::shared_ptr>> _tried) +void NodeTable::doFindNode(NodeId _node, unsigned _round, std::shared_ptr>> _tried) { if (!m_socketPtr->isOpen() || _round == s_maxSteps) return; @@ -131,7 +135,7 @@ void NodeTable::doFindNode(Address _node, unsigned _round, std::shared_ptr> NodeTable::findNearest(Address _target) +std::vector> NodeTable::findNearest(NodeId _target) { // send s_alpha FindNode packets to nodes we know, closest to target static unsigned lastBin = s_bins - 1; @@ -234,26 +238,24 @@ void NodeTable::evict(std::shared_ptr _leastSeen, std::shared_ptr node; { Guard l(x_nodes); - auto n = m_nodes.find(id); + auto n = m_nodes.find(_pubk); if (n == m_nodes.end()) { - node.reset(new NodeEntry(m_node, id, _pubk, _endpoint)); - m_nodes[id] = node; -// clog(NodeTableMessageSummary) << "Adding node to cache: " << id; + node.reset(new NodeEntry(m_node, _pubk, _endpoint)); + m_nodes[_pubk] = node; +// clog(NodeTableMessageSummary) << "Adding node to cache: " << _pubk; } else { node = n->second; -// clog(NodeTableMessageSummary) << "Found node in cache: " << id; +// clog(NodeTableMessageSummary) << "Found node in cache: " << _pubk; } } diff --git a/libp2p/NodeTable.h b/libp2p/NodeTable.h index 314775955..5466a3ae3 100644 --- a/libp2p/NodeTable.h +++ b/libp2p/NodeTable.h @@ -50,6 +50,7 @@ namespace p2p * @todo expiration and sha3(id) 'to' for messages which are replies (prevents replay) * @todo std::shared_ptr m_cachedPingPacket; * @todo std::shared_ptr m_cachedFindSelfPacket; + * @todo store root node in table? * * [Networking] * @todo TCP endpoints @@ -68,7 +69,7 @@ class NodeTable: UDPSocketEvents, public std::enable_shared_from_this friend struct Neighbors; using NodeSocket = UDPSocket; using TimePoint = std::chrono::steady_clock::time_point; - using EvictionTimeout = std::pair,Address>; + using EvictionTimeout = std::pair,NodeId>; ///< First NodeId may be evicted and replaced with second NodeId. struct NodeDefaultEndpoint { @@ -78,14 +79,13 @@ class NodeTable: UDPSocketEvents, public std::enable_shared_from_this struct Node { - Node(Address _id, Public _pubk, NodeDefaultEndpoint _udp): id(_id), pubk(_pubk), endpoint(_udp) {} - Node(Address _id, Public _pubk, bi::udp::endpoint _udp): Node(_id, _pubk, NodeDefaultEndpoint(_udp)) {} + Node(Public _pubk, NodeDefaultEndpoint _udp): id(_pubk), endpoint(_udp) {} + Node(Public _pubk, bi::udp::endpoint _udp): Node(_pubk, NodeDefaultEndpoint(_udp)) {} - virtual Address const& address() const { return id; } - virtual Public const& publicKey() const { return pubk; } + virtual NodeId const& address() const { return id; } + virtual Public const& publicKey() const { return id; } - Address id; - Public pubk; + NodeId id; NodeDefaultEndpoint endpoint; }; @@ -95,8 +95,8 @@ class NodeTable: UDPSocketEvents, public std::enable_shared_from_this */ struct NodeEntry: public Node { - NodeEntry(Node _src, Address _id, Public _pubk, NodeDefaultEndpoint _gw): Node(_id, _pubk, _gw), distance(dist(_src.id,_id)) {} - NodeEntry(Node _src, Address _id, Public _pubk, bi::udp::endpoint _udp): Node(_id, _pubk, NodeDefaultEndpoint(_udp)), distance(dist(_src.id,_id)) {} + NodeEntry(Node _src, Public _pubk, NodeDefaultEndpoint _gw): Node(_pubk, _gw), distance(dist(_src.id,_pubk)) {} + NodeEntry(Node _src, Public _pubk, bi::udp::endpoint _udp): Node(_pubk, NodeDefaultEndpoint(_udp)), distance(dist(_src.id,_pubk)) {} const unsigned distance; ///< Node's distance from _src (see constructor). }; @@ -114,7 +114,7 @@ public: /// Constants for Kademlia, mostly derived from address space. - static unsigned const s_addressByteSize = sizeof(Node::id); ///< Size of address type in bytes. + static unsigned const s_addressByteSize = sizeof(NodeId); ///< Size of address type in bytes. static unsigned const s_bits = 8 * s_addressByteSize; ///< Denoted by n in [Kademlia]. static unsigned const s_bins = s_bits - 1; ///< Size of m_state (excludes root, which is us). static unsigned const s_maxSteps = boost::static_log2::value; ///< Max iterations of discovery. (doFindNode) @@ -130,23 +130,23 @@ public: std::chrono::milliseconds const c_reqTimeout = std::chrono::milliseconds(300); ///< How long to wait for requests (evict, find iterations). std::chrono::seconds const c_bucketRefresh = std::chrono::seconds(3600); ///< Refresh interval prevents bucket from becoming stale. [Kademlia] - static unsigned dist(Address const& _a, Address const& _b) { u160 d = _a ^ _b; unsigned ret; for (ret = 0; d >>= 1; ++ret) {}; return ret; } + static unsigned dist(NodeId const& _a, NodeId const& _b) { u512 d = _a ^ _b; unsigned ret; for (ret = 0; d >>= 1; ++ret) {}; return ret; } void join(); - NodeEntry root() const { return NodeEntry(m_node, m_node.address(), m_node.publicKey(), m_node.endpoint.udp); } - std::list
nodes() const; + NodeEntry root() const { return NodeEntry(m_node, m_node.publicKey(), m_node.endpoint.udp); } + std::list nodes() const; std::list state() const; - NodeEntry operator[](Address _id); + NodeEntry operator[](NodeId _id); protected: /// Repeatedly sends s_alpha concurrent requests to nodes nearest to target, for nodes nearest to target, up to s_maxSteps rounds. - void doFindNode(Address _node, unsigned _round = 0, std::shared_ptr>> _tried = std::shared_ptr>>()); + void doFindNode(NodeId _node, unsigned _round = 0, std::shared_ptr>> _tried = std::shared_ptr>>()); /// Returns nodes nearest to target. - std::vector> findNearest(Address _target); + std::vector> findNearest(NodeId _target); void ping(bi::udp::endpoint _to) const; @@ -180,13 +180,13 @@ private: protected: #endif /// Sends FindNeighbor packet. See doFindNode. - void requestNeighbors(NodeEntry const& _node, Address _target) const; + void requestNeighbors(NodeEntry const& _node, NodeId _target) const; Node m_node; ///< This node. Secret m_secret; ///< This nodes secret key. mutable Mutex x_nodes; ///< Mutable for thread-safe copy in nodes() const. - std::map> m_nodes; ///< Address -> Node table (most common lookup path) + std::map> m_nodes; ///< NodeId -> Node table (most common lookup path) mutable Mutex x_state; std::array m_state; ///< State table of binned nodes. @@ -233,9 +233,9 @@ inline std::ostream& operator<<(std::ostream& _out, NodeTable const& _nodeTable) */ struct PingNode: RLPXDatagram { - using RLPXDatagram::RLPXDatagram; - PingNode(bi::udp::endpoint _ep, std::string _src, uint16_t _srcPort, std::chrono::seconds _expiration = std::chrono::seconds(60)): RLPXDatagram(_ep), ipAddress(_src), port(_srcPort), expiration(futureFromEpoch(_expiration)) {} - + PingNode(bi::udp::endpoint _ep): RLPXDatagram(_ep) {} + PingNode(bi::udp::endpoint _ep, std::string _src, uint16_t _srcPort, std::chrono::seconds _expiration = std::chrono::seconds(60)): RLPXDatagram(_ep), ipAddress(_src), port(_srcPort), expiration(futureFromEpoch(_expiration)) {} + std::string ipAddress; unsigned port; unsigned expiration; @@ -257,7 +257,7 @@ struct PingNode: RLPXDatagram */ struct Pong: RLPXDatagram { - using RLPXDatagram::RLPXDatagram; + Pong(bi::udp::endpoint _ep): RLPXDatagram(_ep) {} h256 replyTo; // hash of rlp of PingNode unsigned expiration; @@ -275,20 +275,20 @@ struct Pong: RLPXDatagram * Minimum Encoded Size: 21 bytes * Maximum Encoded Size: 30 bytes * - * target: Address of node. The responding node will send back nodes closest to the target. + * target: NodeId of node. The responding node will send back nodes closest to the target. * expiration: Triggers regeneration of packet. May also provide control over synchronization. * */ struct FindNode: RLPXDatagram { using RLPXDatagram::RLPXDatagram; - FindNode(bi::udp::endpoint _ep, Address _target, std::chrono::seconds _expiration = std::chrono::seconds(30)): RLPXDatagram(_ep), target(_target), expiration(futureFromEpoch(_expiration)) {} + FindNode(bi::udp::endpoint _ep, NodeId _target, std::chrono::seconds _expiration = std::chrono::seconds(30)): RLPXDatagram(_ep), target(_target), expiration(futureFromEpoch(_expiration)) {} - h160 target; + h512 target; unsigned expiration; - + void streamRLP(RLPStream& _s) const { _s.appendList(2); _s << target << expiration; } - void interpretRLP(bytesConstRef _bytes) { RLP r(_bytes); target = r[0].toHash(); expiration = r[1].toInt(); } + void interpretRLP(bytesConstRef _bytes) { RLP r(_bytes); target = r[0].toHash(); expiration = r[1].toInt(); } }; /** @@ -317,7 +317,7 @@ struct Neighbors: RLPXDatagram }; using RLPXDatagram::RLPXDatagram; - Neighbors(bi::udp::endpoint _to, std::vector> const& _nearest, unsigned _offset = 0, unsigned _limit = 0): RLPXDatagram(_to) + Neighbors(bi::udp::endpoint _to, std::vector> const& _nearest, unsigned _offset = 0, unsigned _limit = 0): RLPXDatagram(_to) { auto limit = _limit ? std::min(_nearest.size(), (size_t)(_offset + _limit)) : _nearest.size(); for (auto i = _offset; i < limit; i++) @@ -328,15 +328,6 @@ struct Neighbors: RLPXDatagram node.node = _nearest[i]->publicKey(); nodes.push_back(node); } - -// for (auto& n: _nearest) -// { -// Node node; -// node.ipAddress = n->endpoint.udp.address().to_string(); // 16 -// node.port = n->endpoint.udp.port(); // 3 -// node.node = n->publicKey();// 67 -// nodes.push_back(node); -// } } std::list nodes; diff --git a/libp2p/UDP.cpp b/libp2p/UDP.cpp index 8b60196e9..b1f87e409 100644 --- a/libp2p/UDP.cpp +++ b/libp2p/UDP.cpp @@ -37,7 +37,7 @@ h256 RLPXDatagramFace::sign(Secret const& _k) bytesConstRef packetHash(&data[0], h256::size); bytesConstRef signedPayload(&data[h256::size], Signature::size + rlp.size()); bytesConstRef payloadSig(&data[h256::size], Signature::size); - bytesConstRef payload(&data[h256::size+Signature::size], rlp.size()); + bytesConstRef payload(&data[h256::size + Signature::size], rlp.size()); sig.ref().copyTo(payloadSig); rlp.copyTo(payload); diff --git a/libp2p/UDP.h b/libp2p/UDP.h index cc8e58b9f..ac4afb0b1 100644 --- a/libp2p/UDP.h +++ b/libp2p/UDP.h @@ -60,10 +60,8 @@ protected: * @todo compact templates * @todo make data private/functional (see UDPDatagram) */ -//template struct RLPXDatagramFace: public UDPDatagram { -// static T fromBytesConstRef(bi::udp::endpoint const& _ep, bytesConstRef _bytes) { T t(_ep); t.interpretRLP(_bytes); return std::move(t); } static uint64_t futureFromEpoch(std::chrono::milliseconds _ms) { return std::chrono::duration_cast((std::chrono::system_clock::now() + _ms).time_since_epoch()).count(); } static uint64_t futureFromEpoch(std::chrono::seconds _sec) { return std::chrono::duration_cast((std::chrono::system_clock::now() + _sec).time_since_epoch()).count(); } static Public authenticate(bytesConstRef _sig, bytesConstRef _rlp); @@ -74,12 +72,12 @@ struct RLPXDatagramFace: public UDPDatagram virtual void streamRLP(RLPStream&) const =0; virtual void interpretRLP(bytesConstRef _bytes) =0; }; - + template struct RLPXDatagram: public RLPXDatagramFace { - static T fromBytesConstRef(bi::udp::endpoint const& _ep, bytesConstRef _bytes) { T t(_ep); t.interpretRLP(_bytes); return std::move(t); } using RLPXDatagramFace::RLPXDatagramFace; + static T fromBytesConstRef(bi::udp::endpoint const& _ep, bytesConstRef _bytes) { T t(_ep); t.interpretRLP(_bytes); return std::move(t); } }; /** diff --git a/test/boostTest.cpp b/test/boostTest.cpp index 7d89f853c..cef3cc0a7 100644 --- a/test/boostTest.cpp +++ b/test/boostTest.cpp @@ -21,4 +21,8 @@ */ #define BOOST_TEST_MODULE EthereumTests +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" #include +#pragma warning(pop) +#pragma GCC diagnostic pop diff --git a/test/net.cpp b/test/net.cpp index 8a2e2af78..0a008d6eb 100644 --- a/test/net.cpp +++ b/test/net.cpp @@ -171,6 +171,12 @@ BOOST_AUTO_TEST_CASE(test_findnode_neighbors) // into the same list of nearest nodes. } +BOOST_AUTO_TEST_CASE(test_windows_template) +{ + bi::udp::endpoint ep; + PingNode p(ep); +} + BOOST_AUTO_TEST_CASE(kademlia) { // Not yet a 'real' test. From 818d2daacfca8538b0e86d48c34e0be094a34122 Mon Sep 17 00:00:00 2001 From: yann300 Date: Mon, 5 Jan 2015 11:25:13 +0100 Subject: [PATCH 065/111] fix compilation --- mix/AppContext.h | 2 ++ mix/AssemblyDebuggerModel.cpp | 2 +- mix/Extension.cpp | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/mix/AppContext.h b/mix/AppContext.h index 67861ad04..4419633ed 100644 --- a/mix/AppContext.h +++ b/mix/AppContext.h @@ -29,6 +29,8 @@ #include #include +#include +#include #include "KeyEventManager.h" namespace dev diff --git a/mix/AssemblyDebuggerModel.cpp b/mix/AssemblyDebuggerModel.cpp index 07c4a5968..354d0bd1e 100644 --- a/mix/AssemblyDebuggerModel.cpp +++ b/mix/AssemblyDebuggerModel.cpp @@ -45,7 +45,7 @@ AssemblyDebuggerModel::AssemblyDebuggerModel(): DebuggingContent AssemblyDebuggerModel::executeTransaction(bytesConstRef const& _rawTransaction) { QList machineStates; - m_currentExecution.reset(new Executive(m_executiveState, 0)); + m_currentExecution.reset(new Executive(m_executiveState, LastHashes(), 0)); m_currentExecution->setup(_rawTransaction); std::vector levels; bytes code; diff --git a/mix/Extension.cpp b/mix/Extension.cpp index c6a41995a..53d3f491f 100644 --- a/mix/Extension.cpp +++ b/mix/Extension.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include "Extension.h" #include "AppContext.h" using namespace dev; From 1626213af0aa35eba1f32d8350f09e1609045a26 Mon Sep 17 00:00:00 2001 From: arkpar Date: Mon, 5 Jan 2015 12:06:15 +0100 Subject: [PATCH 066/111] coding standards --- mix/AssemblyDebuggerControl.h | 10 ++++++++-- mix/CodeHighlighter.cpp | 28 +++++++++------------------- mix/CodeHighlighter.h | 17 +++++++++++++---- mix/CodeModel.cpp | 16 +++++----------- mix/CodeModel.h | 4 ++-- mix/StateListView.cpp | 1 + 6 files changed, 38 insertions(+), 38 deletions(-) diff --git a/mix/AssemblyDebuggerControl.h b/mix/AssemblyDebuggerControl.h index 4341b46e0..b4dff38f5 100644 --- a/mix/AssemblyDebuggerControl.h +++ b/mix/AssemblyDebuggerControl.h @@ -19,6 +19,7 @@ #pragma once +#include #include #include "Extension.h" #include "AssemblyDebuggerModel.h" @@ -55,7 +56,7 @@ private: void executeSequence(std::vector const& _sequence, u256 _balance); std::unique_ptr m_modelDebugger; - bool m_running; + std::atomic m_running; public slots: /// Run the contract constructor and show debugger window. @@ -67,13 +68,18 @@ public slots: private slots: /// Update UI with machine states result. Display a modal dialog. void showDebugger(QList const& _returnParams = QList(), QList const& _wStates = QList(), AssemblyDebuggerData const& _code = AssemblyDebuggerData()); + /// Update UI with transaction run error. void showDebugError(QString const& _error); - signals: + /// Transaction execution started void runStarted(); + /// Transaction execution completed successfully void runComplete(); + /// Transaction execution completed with error + /// @param _message Error message void runFailed(QString const& _message); + /// Execution state changed void stateChanged(); /// Emited when machine states are available. diff --git a/mix/CodeHighlighter.cpp b/mix/CodeHighlighter.cpp index 5f6cf7489..7cc07c9a5 100644 --- a/mix/CodeHighlighter.cpp +++ b/mix/CodeHighlighter.cpp @@ -25,25 +25,22 @@ #include #include #include +#include +#include +#include +#include #include "CodeHighlighter.h" -#include "libsolidity/ASTVisitor.h" -#include "libsolidity/AST.h" -#include "libsolidity/Scanner.h" -#include "libsolidity/Exceptions.h" -namespace dev -{ -namespace mix -{ +using namespace dev::mix; CodeHighlighterSettings::CodeHighlighterSettings() { - bg = QColor(0x00, 0x2b, 0x36); - fg = QColor (0xee, 0xe8, 0xd5); + backgroundColor = QColor(0x00, 0x2b, 0x36); + foregroundColor = QColor (0xee, 0xe8, 0xd5); formats[Keyword].setForeground(QColor(0x93, 0xa1, 0xa1)); formats[Comment].setForeground(QColor(0x85, 0x99, 0x00)); formats[StringLiteral].setForeground(QColor(0xdc, 0x32, 0x2f)); - formats[NumLiteral].setForeground(fg); + formats[NumLiteral].setForeground(foregroundColor); formats[Import].setForeground(QColor(0x6c, 0x71, 0xc4)); formats[CompilationError].setUnderlineColor(Qt::red); formats[CompilationError].setUnderlineStyle(QTextCharFormat::SingleUnderline); @@ -52,7 +49,7 @@ CodeHighlighterSettings::CodeHighlighterSettings() namespace { using namespace dev::solidity; - class HighlightVisitor : public solidity::ASTConstVisitor + class HighlightVisitor : public ASTConstVisitor { public: HighlightVisitor(CodeHighlighter::Formats* _formats) { m_formats = _formats; } @@ -67,7 +64,6 @@ namespace }; } - CodeHighlighter::FormatRange::FormatRange(CodeHighlighterSettings::Token _t, solidity::Location const& _location): token(_t), start(_location.start), length(_location.end - _location.start) {} @@ -172,9 +168,3 @@ void CodeHighlighter::updateFormatting(QTextDocument* _document, CodeHighlighter ++format; } } - - - - -} -} diff --git a/mix/CodeHighlighter.h b/mix/CodeHighlighter.h index d0c92f3fc..5083e6c82 100644 --- a/mix/CodeHighlighter.h +++ b/mix/CodeHighlighter.h @@ -42,6 +42,7 @@ namespace solidity namespace mix { +/// Code highligting settings class CodeHighlighterSettings { public: @@ -60,15 +61,16 @@ public: ///Format for each token QTextCharFormat formats[Size]; ///Background color - QColor bg; + QColor backgroundColor; ///Foreground color - QColor fg; + QColor foregroundColor; }; - +/// Code highlighting engine class class CodeHighlighter { public: + /// Formatting range struct FormatRange { FormatRange(CodeHighlighterSettings::Token _t, int _start, int _length): token(_t), start(_start), length(_length) {} @@ -82,13 +84,20 @@ public: typedef std::vector Formats; // Sorted by start position public: - /// Collect highligting information + /// Collect highligting information by lexing the source void processSource(std::string const& _source); + /// Collect additional highligting information from AST void processAST(solidity::ASTNode const& _ast); + /// Collect highlighting information from compilation exception void processError(dev::Exception const& _exception); + + /// Apply formatting for a text document + /// @todo Remove this once editor is reworked void updateFormatting(QTextDocument* _document, CodeHighlighterSettings const& _settings); private: + /// Collect highligting information by paring for comments + /// @todo Support this in solidity? void processComments(std::string const& _source); private: diff --git a/mix/CodeModel.cpp b/mix/CodeModel.cpp index 0c94173e9..8d2c24725 100644 --- a/mix/CodeModel.cpp +++ b/mix/CodeModel.cpp @@ -33,10 +33,7 @@ #include "CodeHighlighter.h" #include "CodeModel.h" -namespace dev -{ -namespace mix -{ +using namespace dev::mix; void BackgroundWorker::queueCodeChange(int _jobId, QString const& _content) { @@ -45,13 +42,13 @@ void BackgroundWorker::queueCodeChange(int _jobId, QString const& _content) CompilationResult::CompilationResult(): QObject(nullptr), m_successfull(false), + m_codeHash(qHash(QString())), m_contract(new QContractDefinition()), - m_codeHighlighter(new CodeHighlighter()), - m_codeHash(qHash(QString())) + m_codeHighlighter(new CodeHighlighter()) {} CompilationResult::CompilationResult(const solidity::CompilerStack& _compiler): - QObject(nullptr), m_successfull(true) + QObject(nullptr), m_successfull(true), m_codeHash(qHash(QString())) { if (!_compiler.getContractNames().empty()) { @@ -64,7 +61,7 @@ CompilationResult::CompilationResult(const solidity::CompilerStack& _compiler): } CompilationResult::CompilationResult(CompilationResult const& _prev, QString const& _compilerMessage): - QObject(nullptr), m_successfull(false), + QObject(nullptr), m_successfull(false), m_codeHash(qHash(QString())), m_contract(_prev.m_contract), m_compilerMessage(_compilerMessage), m_bytes(_prev.m_bytes), @@ -168,6 +165,3 @@ void CodeModel::updateFormatting(QTextDocument* _document) { m_result->codeHighlighter()->updateFormatting(_document, *m_codeHighlighterSettings); } - -} -} diff --git a/mix/CodeModel.h b/mix/CodeModel.h index da093183d..69c840aa5 100644 --- a/mix/CodeModel.h +++ b/mix/CodeModel.h @@ -91,14 +91,14 @@ public: private: bool m_successfull; + uint m_codeHash; std::shared_ptr m_contract; QString m_compilerMessage; ///< @todo: use some structure here dev::bytes m_bytes; QString m_assemblyCode; std::shared_ptr m_codeHighlighter; - ///@todo syntax highlighting, etc + friend class CodeModel; - uint m_codeHash; }; /// Background code compiler diff --git a/mix/StateListView.cpp b/mix/StateListView.cpp index 62df6530a..fef9ab8e9 100644 --- a/mix/StateListView.cpp +++ b/mix/StateListView.cpp @@ -26,6 +26,7 @@ #include #include #include "StateListView.h" + using namespace dev::mix; StateListView::StateListView(AppContext* _context): Extension(_context, ExtensionDisplayBehavior::RightTab) From 37b05992d106c712c4289b90e746f3fee40f2d6c Mon Sep 17 00:00:00 2001 From: arkpar Date: Mon, 5 Jan 2015 12:28:22 +0100 Subject: [PATCH 067/111] style --- mix/StateListView.cpp | 2 +- mix/StateListView.h | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/mix/StateListView.cpp b/mix/StateListView.cpp index fef9ab8e9..79364fdfb 100644 --- a/mix/StateListView.cpp +++ b/mix/StateListView.cpp @@ -40,7 +40,7 @@ QString StateListView::contentUrl() const QString StateListView::title() const { - return QApplication::tr("State"); + return QApplication::tr("States"); } void StateListView::start() const diff --git a/mix/StateListView.h b/mix/StateListView.h index 12b5bac6a..18d1ae879 100644 --- a/mix/StateListView.h +++ b/mix/StateListView.h @@ -28,8 +28,7 @@ namespace dev namespace mix { -/// Transactions list control -/// @todo This should be moved into state as a sequence +/// State list control class StateListView: public Extension { Q_OBJECT From 9dd9b025d1cd86be8dfb085fc9b59ae13b246f41 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 5 Jan 2015 11:35:56 +0000 Subject: [PATCH 068/111] BLOCKHASH --- libethcore/CommonEth.cpp | 2 +- libevm/VM.h | 12 ++++-------- libevmcore/Instruction.cpp | 4 ++-- libevmcore/Instruction.h | 2 +- libserpent/opcodes.cpp | 2 +- libsolidity/ExpressionCompiler.cpp | 6 +++--- 6 files changed, 12 insertions(+), 16 deletions(-) diff --git a/libethcore/CommonEth.cpp b/libethcore/CommonEth.cpp index 9801bc89f..c70bc353b 100644 --- a/libethcore/CommonEth.cpp +++ b/libethcore/CommonEth.cpp @@ -32,7 +32,7 @@ namespace dev namespace eth { -const unsigned c_protocolVersion = 49; +const unsigned c_protocolVersion = 51; const unsigned c_databaseVersion = 5; static const vector> g_units = diff --git a/libevm/VM.h b/libevm/VM.h index 47efbfcba..6cdb53400 100644 --- a/libevm/VM.h +++ b/libevm/VM.h @@ -219,9 +219,8 @@ inline bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _st break; } - case Instruction::PREVHASH: - if (c_protocolVersion > 49) - require(1); + case Instruction::BLOCKHASH: + require(1); break; case Instruction::PC: @@ -563,11 +562,8 @@ inline bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _st case Instruction::GASPRICE: m_stack.push_back(_ext.gasPrice); break; - case Instruction::PREVHASH: - if (c_protocolVersion > 49) - m_stack.back() = (u256)_ext.prevhash(m_stack.back()); - else - m_stack.push_back(_ext.previousBlock.hash); + case Instruction::BLOCKHASH: + m_stack.back() = (u256)_ext.prevhash(m_stack.back()); break; case Instruction::COINBASE: m_stack.push_back((u160)_ext.currentBlock.coinbaseAddress); diff --git a/libevmcore/Instruction.cpp b/libevmcore/Instruction.cpp index b4a4d9f3b..bba3d7745 100644 --- a/libevmcore/Instruction.cpp +++ b/libevmcore/Instruction.cpp @@ -67,7 +67,7 @@ const std::map dev::eth::c_instructions = { "GASPRICE", Instruction::GASPRICE }, { "EXTCODESIZE", Instruction::EXTCODESIZE }, { "EXTCODECOPY", Instruction::EXTCODECOPY }, - { "PREVHASH", Instruction::PREVHASH }, + { "BLOCKHASH", Instruction::BLOCKHASH }, { "COINBASE", Instruction::COINBASE }, { "TIMESTAMP", Instruction::TIMESTAMP }, { "NUMBER", Instruction::NUMBER }, @@ -200,7 +200,7 @@ static const std::map c_instructionInfo = { Instruction::GASPRICE, { "GASPRICE", 0, 0, 1, false } }, { Instruction::EXTCODESIZE, { "EXTCODESIZE", 0, 1, 1, false } }, { Instruction::EXTCODECOPY, { "EXTCODECOPY", 0, 4, 0, true } }, - { Instruction::PREVHASH, { "PREVHASH", 0, 0, 1, false } }, + { Instruction::BLOCKHASH, { "BLOCKHASH", 0, 1, 1, false } }, { Instruction::COINBASE, { "COINBASE", 0, 0, 1, false } }, { Instruction::TIMESTAMP, { "TIMESTAMP", 0, 0, 1, false } }, { Instruction::NUMBER, { "NUMBER", 0, 0, 1, false } }, diff --git a/libevmcore/Instruction.h b/libevmcore/Instruction.h index 555dbf0ea..a28e8f8da 100644 --- a/libevmcore/Instruction.h +++ b/libevmcore/Instruction.h @@ -73,7 +73,7 @@ enum class Instruction: uint8_t EXTCODESIZE, ///< get external code size (from another contract) EXTCODECOPY, ///< copy external code (from another contract) - PREVHASH = 0x40, ///< get hash of most recent complete block + BLOCKHASH = 0x40, ///< get hash of most recent complete block COINBASE, ///< get the block's coinbase address TIMESTAMP, ///< get the block's timestamp NUMBER, ///< get the block's number diff --git a/libserpent/opcodes.cpp b/libserpent/opcodes.cpp index b24144e46..2fc7d7530 100644 --- a/libserpent/opcodes.cpp +++ b/libserpent/opcodes.cpp @@ -44,7 +44,7 @@ Mapping mapping[] = { Mapping("GASPRICE", 0x3a, 0, 1), Mapping("EXTCODESIZE", 0x3b, 1, 1), Mapping("EXTCODECOPY", 0x3c, 4, 0), - Mapping("PREVHASH", 0x40, 0, 1), + Mapping("BLOCKHASH", 0x40, 1, 1), Mapping("COINBASE", 0x41, 0, 1), Mapping("TIMESTAMP", 0x42, 0, 1), Mapping("NUMBER", 0x43, 0, 1), diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index cf641935a..6bf14f559 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -344,9 +344,9 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess) m_context << eth::Instruction::COINBASE; else if (member == "timestamp") m_context << eth::Instruction::TIMESTAMP; - else if (member == "prevhash") - m_context << eth::Instruction::PREVHASH; - else if (member == "difficulty") +/* else if (member == "blockhash") + m_context << eth::Instruction::BLOCKHASH; +*/ else if (member == "difficulty") m_context << eth::Instruction::DIFFICULTY; else if (member == "number") m_context << eth::Instruction::NUMBER; From 969ea19a44ff258b54c082d7920ffb8c8886d4a6 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 5 Jan 2015 15:24:09 +0100 Subject: [PATCH 069/111] Potential mac fix(?) --- libethereum/TransactionReceipt.cpp | 2 +- libethereum/TransactionReceipt.h | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/libethereum/TransactionReceipt.cpp b/libethereum/TransactionReceipt.cpp index 868b00558..eba991839 100644 --- a/libethereum/TransactionReceipt.cpp +++ b/libethereum/TransactionReceipt.cpp @@ -50,7 +50,7 @@ void TransactionReceipt::streamRLP(RLPStream& _s) const l.streamRLP(_s); } -std::ostream& dev::operator<<(std::ostream& _out, TransactionReceipt const& _r) +std::ostream& dev::eth::operator<<(std::ostream& _out, TransactionReceipt const& _r) { _out << "Root: " << _r.stateRoot() << std::endl; _out << "Gas used: " << _r.gasUsed() << std::endl; diff --git a/libethereum/TransactionReceipt.h b/libethereum/TransactionReceipt.h index ebf591995..1e0663054 100644 --- a/libethereum/TransactionReceipt.h +++ b/libethereum/TransactionReceipt.h @@ -57,8 +57,7 @@ private: using TransactionReceipts = std::vector; -} - std::ostream& operator<<(std::ostream& _out, eth::TransactionReceipt const& _r); } +} From d34f28dd3c748c7c558c1127d77643ac96ba4d34 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 5 Jan 2015 15:33:05 +0100 Subject: [PATCH 070/111] Mac warning fix. --- libsolidity/SourceReferenceFormatter.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsolidity/SourceReferenceFormatter.h b/libsolidity/SourceReferenceFormatter.h index 8e3f126f0..98f1c745d 100644 --- a/libsolidity/SourceReferenceFormatter.h +++ b/libsolidity/SourceReferenceFormatter.h @@ -28,7 +28,7 @@ namespace dev { -class Exception; // forward +struct Exception; // forward namespace solidity { From 1f0a22c48fc9d072ca71bae7d750f2669dd479ea Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 5 Jan 2015 16:07:43 +0100 Subject: [PATCH 071/111] Fourth precompiled contract: identity function. --- libethereum/Precompiled.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/libethereum/Precompiled.cpp b/libethereum/Precompiled.cpp index 1861385da..732782d3f 100644 --- a/libethereum/Precompiled.cpp +++ b/libethereum/Precompiled.cpp @@ -75,11 +75,17 @@ static bytes ripemd160Code(bytesConstRef _in) return ret; } +static bytes identityCode(bytesConstRef _in) +{ + return _in.toBytes(); +} + static const std::map c_precompiled = { { 1, { [](bytesConstRef) -> bigint { return (bigint)500; }, ecrecoverCode }}, { 2, { [](bytesConstRef i) -> bigint { return (bigint)50 + (i.size() + 31) / 32 * 50; }, sha256Code }}, - { 3, { [](bytesConstRef i) -> bigint { return (bigint)50 + (i.size() + 31) / 32 * 50; }, ripemd160Code }} + { 3, { [](bytesConstRef i) -> bigint { return (bigint)50 + (i.size() + 31) / 32 * 50; }, ripemd160Code }}, + { 4, { [](bytesConstRef i) -> bigint { return (bigint)1 + (i.size() + 31) / 32 * 1; }, identityCode }} }; std::map const& dev::eth::precompiled() From eddc0e7d13e8f2f689b560cbcaa73ea95dc2c3cb Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 5 Jan 2015 16:25:32 +0100 Subject: [PATCH 072/111] (Possibly) fixed #660 --- libethcore/Exceptions.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/libethcore/Exceptions.cpp b/libethcore/Exceptions.cpp index c6f35763e..b0aff4551 100644 --- a/libethcore/Exceptions.cpp +++ b/libethcore/Exceptions.cpp @@ -20,13 +20,22 @@ */ #include "Exceptions.h" +#include #include using namespace std; using namespace dev; using namespace dev::eth; -#define ETH_RETURN_STRING(S) static string s_what; s_what = S; return s_what.c_str(); +#if ALL_COMPILERS_ARE_CPP11_COMPLIANT +#define ETH_RETURN_STRING(S) thread_local static string s_what; s_what = S; return s_what.c_str(); +#else +#define ETH_RETURN_STRING(S) \ + static boost::thread_specific_ptr s_what; \ + if (!s_what.get()) \ + s_what.reset(new string); \ + *s_what = S; return s_what->c_str(); +#endif const char* InvalidBlockFormat::what() const noexcept { ETH_RETURN_STRING("Invalid block format: Bad field " + toString(m_f) + " (" + toHex(m_d) + ")"); } const char* UncleInChain::what() const noexcept { ETH_RETURN_STRING("Uncle in block already mentioned: Uncles " + toString(m_uncles) + " (" + m_block.abridged() + ")"); } From 631bd9ab38f9fc232f851fcb82121e258d729d11 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Mon, 5 Jan 2015 16:37:43 +0100 Subject: [PATCH 073/111] Fix for sol scanner where empty multiline comment became Natspec comment --- libsolidity/Scanner.cpp | 23 ++++++++++++++++------- libsolidity/Scanner.h | 1 + test/SolidityScanner.cpp | 7 +++++++ 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/libsolidity/Scanner.cpp b/libsolidity/Scanner.cpp index f22e69bc8..1f700d8b1 100644 --- a/libsolidity/Scanner.cpp +++ b/libsolidity/Scanner.cpp @@ -285,8 +285,6 @@ Token::Value Scanner::scanMultiLineDocComment() bool endFound = false; bool charsAdded = false; - advance(); //consume the last '*' at /** - skipWhitespaceExceptLF(); while (!isSourcePastEndOfInput()) { //handle newlines in multline comments @@ -354,11 +352,22 @@ Token::Value Scanner::scanSlash() return Token::WHITESPACE; else if (m_char == '*') { - Token::Value comment; - m_nextSkippedComment.location.start = firstSlashPosition; - comment = scanMultiLineDocComment(); - m_nextSkippedComment.location.end = getSourcePos(); - m_nextSkippedComment.token = comment; + advance(); //consume the last '*' at /** + skipWhitespaceExceptLF(); + + // special case of a closed normal multiline comment + if (!m_source.isPastEndOfInput() && m_source.get(0) == '/') + { + advance(); //skip the closing slash + } + else // we actually have a multiline documentation comment + { + Token::Value comment; + m_nextSkippedComment.location.start = firstSlashPosition; + comment = scanMultiLineDocComment(); + m_nextSkippedComment.location.end = getSourcePos(); + m_nextSkippedComment.token = comment; + } return Token::WHITESPACE; } else diff --git a/libsolidity/Scanner.h b/libsolidity/Scanner.h index 5b90a94eb..d93b79df0 100644 --- a/libsolidity/Scanner.h +++ b/libsolidity/Scanner.h @@ -119,6 +119,7 @@ public: { return m_currentToken.token; } + Location getCurrentLocation() const { return m_currentToken.location; } std::string const& getCurrentLiteral() const { return m_currentToken.literal; } ///@} diff --git a/test/SolidityScanner.cpp b/test/SolidityScanner.cpp index 355ea9e22..b7942d293 100644 --- a/test/SolidityScanner.cpp +++ b/test/SolidityScanner.cpp @@ -227,6 +227,13 @@ BOOST_AUTO_TEST_CASE(documentation_comment_before_eos) BOOST_CHECK_EQUAL(scanner.getCurrentCommentLiteral(), ""); } +BOOST_AUTO_TEST_CASE(empty_multiline_comment) +{ + Scanner scanner(CharStream("/**/")); + BOOST_CHECK_EQUAL(scanner.getCurrentToken(), Token::EOS); + BOOST_CHECK_EQUAL(scanner.getCurrentCommentLiteral(), ""); +} + BOOST_AUTO_TEST_CASE(empty_multiline_documentation_comment_before_eos) { Scanner scanner(CharStream("/***/")); From bec29881b07b673c33b4e0d26eabee6b62ae6ef8 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Mon, 5 Jan 2015 16:40:57 +0100 Subject: [PATCH 074/111] use of client() without if --- libweb3jsonrpc/WebThreeStubServer.cpp | 53 ++++----------------------- 1 file changed, 7 insertions(+), 46 deletions(-) diff --git a/libweb3jsonrpc/WebThreeStubServer.cpp b/libweb3jsonrpc/WebThreeStubServer.cpp index d88aa0a5f..e441ce6f3 100644 --- a/libweb3jsonrpc/WebThreeStubServer.cpp +++ b/libweb3jsonrpc/WebThreeStubServer.cpp @@ -272,15 +272,11 @@ std::string WebThreeStubServer::eth_balanceAt(string const& _address) Json::Value WebThreeStubServer::eth_blockByHash(std::string const& _hash) { - if (!client()) - return ""; return toJson(client()->blockInfo(jsToFixed<32>(_hash))); } Json::Value WebThreeStubServer::eth_blockByNumber(int const& _number) { - if (!client()) - return ""; return toJson(client()->blockInfo(client()->hashFromNumber(_number))); } @@ -332,8 +328,6 @@ static TransactionSkeleton toTransaction(Json::Value const& _json) std::string WebThreeStubServer::eth_call(Json::Value const& _json) { std::string ret; - if (!client()) - return ret; TransactionSkeleton t = toTransaction(_json); if (!t.from && m_accounts.size()) { @@ -355,31 +349,29 @@ std::string WebThreeStubServer::eth_call(Json::Value const& _json) bool WebThreeStubServer::eth_changed(int const& _id) { - if (!client()) - return false; return client()->checkWatch(_id); } std::string WebThreeStubServer::eth_codeAt(string const& _address) { int block = 0; - return client() ? jsFromBinary(client()->codeAt(jsToAddress(_address), block)) : ""; + return jsFromBinary(client()->codeAt(jsToAddress(_address), block)); } std::string WebThreeStubServer::eth_coinbase() { - return client() ? toJS(client()->address()) : ""; + return toJS(client()->address()); } double WebThreeStubServer::eth_countAt(string const& _address) { int block = 0; - return client() ? (double)(uint64_t)client()->countAt(jsToAddress(_address), block) : 0; + return (double)(uint64_t)client()->countAt(jsToAddress(_address), block); } int WebThreeStubServer::eth_defaultBlock() { - return client() ? client()->getDefault() : 0; + return client()->getDefault(); } std::string WebThreeStubServer::eth_gasPrice() @@ -397,15 +389,11 @@ std::string WebThreeStubServer::db_get(std::string const& _name, std::string con Json::Value WebThreeStubServer::eth_filterLogs(int const& _id) { - if (!client()) - return Json::Value(Json::arrayValue); return toJson(client()->logs(_id)); } Json::Value WebThreeStubServer::eth_logs(Json::Value const& _json) { - if (!client()) - return Json::Value(Json::arrayValue); return toJson(client()->logs(toLogFilter(_json))); } @@ -429,15 +417,12 @@ bool WebThreeStubServer::eth_listening() bool WebThreeStubServer::eth_mining() { - return client() ? client()->isMining() : false; + return client()->isMining(); } int WebThreeStubServer::eth_newFilter(Json::Value const& _json) { unsigned ret = -1; - if (!client()) - return ret; -// ret = client()->installWatch(toMessageFilter(_json)); ret = client()->installWatch(toLogFilter(_json)); return ret; } @@ -445,8 +430,6 @@ int WebThreeStubServer::eth_newFilter(Json::Value const& _json) int WebThreeStubServer::eth_newFilterString(std::string const& _filter) { unsigned ret = -1; - if (!client()) - return ret; if (_filter.compare("chain") == 0) ret = client()->installWatch(dev::eth::ChainChangedFilter); else if (_filter.compare("pending") == 0) @@ -528,7 +511,7 @@ std::string WebThreeStubServer::eth_solidity(std::string const& _code) int WebThreeStubServer::eth_number() { - return client() ? client()->number() + 1 : 0; + return client()->number() + 1; } int WebThreeStubServer::eth_peerCount() @@ -538,7 +521,6 @@ int WebThreeStubServer::eth_peerCount() bool WebThreeStubServer::shh_post(Json::Value const& _json) { -// cnote << this << m_ids; shh::Message m = toMessage(_json); Secret from; @@ -571,16 +553,12 @@ bool WebThreeStubServer::db_putString(std::string const& _name, std::string cons bool WebThreeStubServer::eth_setCoinbase(std::string const& _address) { - if (!client()) - return false; client()->setAddress(jsToAddress(_address)); return true; } bool WebThreeStubServer::eth_setDefaultBlock(int const& _block) { - if (!client()) - return false; client()->setDefault(_block); return true; } @@ -596,9 +574,6 @@ bool WebThreeStubServer::eth_setListening(bool const& _listening) bool WebThreeStubServer::eth_setMining(bool const& _mining) { - if (!client()) - return false; - if (_mining) client()->startMining(); else @@ -647,21 +622,17 @@ bool WebThreeStubServer::shh_uninstallFilter(int const& _id) std::string WebThreeStubServer::eth_stateAt(string const& _address, string const& _storage) { int block = 0; - return client() ? toJS(client()->stateAt(jsToAddress(_address), jsToU256(_storage), block)) : ""; + return toJS(client()->stateAt(jsToAddress(_address), jsToU256(_storage), block)); } Json::Value WebThreeStubServer::eth_storageAt(string const& _address) { - if (!client()) - return Json::Value(Json::objectValue); return toJson(client()->storageAt(jsToAddress(_address))); } std::string WebThreeStubServer::eth_transact(Json::Value const& _json) { std::string ret; - if (!client()) - return ret; TransactionSkeleton t = toTransaction(_json); if (!t.from && m_accounts.size()) { @@ -689,36 +660,26 @@ std::string WebThreeStubServer::eth_transact(Json::Value const& _json) Json::Value WebThreeStubServer::eth_transactionByHash(std::string const& _hash, int const& _i) { - if (!client()) - return ""; return toJson(client()->transaction(jsToFixed<32>(_hash), _i)); } Json::Value WebThreeStubServer::eth_transactionByNumber(int const& _number, int const& _i) { - if (!client()) - return ""; return toJson(client()->transaction(client()->hashFromNumber(_number), _i)); } Json::Value WebThreeStubServer::eth_uncleByHash(std::string const& _hash, int const& _i) { - if (!client()) - return ""; return toJson(client()->uncle(jsToFixed<32>(_hash), _i)); } Json::Value WebThreeStubServer::eth_uncleByNumber(int const& _number, int const& _i) { - if (!client()) - return ""; return toJson(client()->uncle(client()->hashFromNumber(_number), _i)); } bool WebThreeStubServer::eth_uninstallFilter(int const& _id) { - if (!client()) - return false; client()->uninstallWatch(_id); return true; } From 5e306b3a67b6336de38e1bc6b17ad10b30e8dbf6 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 5 Jan 2015 16:42:51 +0100 Subject: [PATCH 075/111] Latest YP changes (call depth limited in a less harsh manner). --- libevm/VM.h | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/libevm/VM.h b/libevm/VM.h index 6cdb53400..eab248b44 100644 --- a/libevm/VM.h +++ b/libevm/VM.h @@ -196,8 +196,6 @@ inline bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _st require(7); runGas = (bigint)c_callGas + m_stack[m_stack.size() - 1]; newTempSize = std::max(memNeed(m_stack[m_stack.size() - 6], m_stack[m_stack.size() - 7]), memNeed(m_stack[m_stack.size() - 4], m_stack[m_stack.size() - 5])); - if (_ext.depth == 1024) - BOOST_THROW_EXCEPTION(OutOfGas()); break; case Instruction::CREATE: @@ -207,8 +205,6 @@ inline bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _st u256 inSize = m_stack[m_stack.size() - 3]; newTempSize = (bigint)inOff + inSize; runGas = c_createGas; - if (_ext.depth == 1024) - BOOST_THROW_EXCEPTION(OutOfGas()); break; } case Instruction::EXP: @@ -780,7 +776,7 @@ inline bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _st unsigned initSize = (unsigned)m_stack.back(); m_stack.pop_back(); - if (_ext.balance(_ext.myAddress) >= endowment) + if (_ext.balance(_ext.myAddress) >= endowment && _ext.depth < 1024) { _ext.subBalance(endowment); m_stack.push_back((u160)_ext.create(endowment, m_gas, bytesConstRef(m_temp.data() + initOff, initSize), _onOp)); @@ -808,7 +804,7 @@ inline bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _st unsigned outSize = (unsigned)m_stack.back(); m_stack.pop_back(); - if (_ext.balance(_ext.myAddress) >= value) + if (_ext.balance(_ext.myAddress) >= value && _ext.depth < 1024) { _ext.subBalance(value); m_stack.push_back(_ext.call(inst == Instruction::CALL ? receiveAddress : _ext.myAddress, value, bytesConstRef(m_temp.data() + inOff, inSize), gas, bytesRef(m_temp.data() + outOff, outSize), _onOp, {}, receiveAddress)); From 58eb79733200ee12a73f799aab1056f00d8082ff Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Mon, 5 Jan 2015 16:46:44 +0100 Subject: [PATCH 076/111] applying changes from #715 --- libweb3jsonrpc/WebThreeStubServer.cpp | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/libweb3jsonrpc/WebThreeStubServer.cpp b/libweb3jsonrpc/WebThreeStubServer.cpp index e441ce6f3..6cba16f84 100644 --- a/libweb3jsonrpc/WebThreeStubServer.cpp +++ b/libweb3jsonrpc/WebThreeStubServer.cpp @@ -266,8 +266,7 @@ std::string WebThreeStubServer::shh_addToGroup(std::string const& _group, std::s std::string WebThreeStubServer::eth_balanceAt(string const& _address) { - int block = 0; - return toJS(client()->balanceAt(jsToAddress(_address), block)); + return toJS(client()->balanceAt(jsToAddress(_address), client()->getDefault())); } Json::Value WebThreeStubServer::eth_blockByHash(std::string const& _hash) @@ -354,8 +353,7 @@ bool WebThreeStubServer::eth_changed(int const& _id) std::string WebThreeStubServer::eth_codeAt(string const& _address) { - int block = 0; - return jsFromBinary(client()->codeAt(jsToAddress(_address), block)); + return jsFromBinary(client()->codeAt(jsToAddress(_address), client()->getDefault())); } std::string WebThreeStubServer::eth_coinbase() @@ -365,8 +363,7 @@ std::string WebThreeStubServer::eth_coinbase() double WebThreeStubServer::eth_countAt(string const& _address) { - int block = 0; - return (double)(uint64_t)client()->countAt(jsToAddress(_address), block); + return (double)(uint64_t)client()->countAt(jsToAddress(_address), client()->getDefault()); } int WebThreeStubServer::eth_defaultBlock() @@ -621,8 +618,7 @@ bool WebThreeStubServer::shh_uninstallFilter(int const& _id) std::string WebThreeStubServer::eth_stateAt(string const& _address, string const& _storage) { - int block = 0; - return toJS(client()->stateAt(jsToAddress(_address), jsToU256(_storage), block)); + return toJS(client()->stateAt(jsToAddress(_address), jsToU256(_storage), client()->getDefault())); } Json::Value WebThreeStubServer::eth_storageAt(string const& _address) From 6d098faab069b11db3427900c2476f3e0335e4f6 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Mon, 5 Jan 2015 16:55:17 +0100 Subject: [PATCH 077/111] style: curlies --- libsolidity/Scanner.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/libsolidity/Scanner.cpp b/libsolidity/Scanner.cpp index 1f700d8b1..6433b5262 100644 --- a/libsolidity/Scanner.cpp +++ b/libsolidity/Scanner.cpp @@ -357,9 +357,7 @@ Token::Value Scanner::scanSlash() // special case of a closed normal multiline comment if (!m_source.isPastEndOfInput() && m_source.get(0) == '/') - { advance(); //skip the closing slash - } else // we actually have a multiline documentation comment { Token::Value comment; From 4ba309d9ac4ac98e075a7dfc9a2609f5278cab4a Mon Sep 17 00:00:00 2001 From: subtly Date: Mon, 5 Jan 2015 17:43:06 +0100 Subject: [PATCH 078/111] code review fixes. remove std::, fix improper naming of class members, camelCase ivars for readability. --- libp2p/Host.cpp | 18 +++++++++--------- libp2p/NodeTable.cpp | 38 +++++++++++++++++++------------------- libp2p/UDP.h | 28 ++++++++++++++-------------- 3 files changed, 42 insertions(+), 42 deletions(-) diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index 4a99ac90f..d1c3cd19b 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -272,15 +272,15 @@ void Host::determinePublic(string const& _publicAddress, bool _upnp) // if user supplied address is a public address then we use it // if user supplied address is private, and localnetworking is enabled, we use it - bi::address reqpublicaddr(bi::address(_publicAddress.empty() ? bi::address() : bi::address::from_string(_publicAddress))); - bi::tcp::endpoint reqpublic(reqpublicaddr, m_listenPort); - bool isprivate = isPrivateAddress(reqpublicaddr); - bool ispublic = !isprivate && !isLocalHostAddress(reqpublicaddr); - if (!reqpublicaddr.is_unspecified() && (ispublic || (isprivate && m_netPrefs.localNetworking))) + bi::address reqPublicAddr(bi::address(_publicAddress.empty() ? bi::address() : bi::address::from_string(_publicAddress))); + bi::tcp::endpoint reqPublic(reqPublicAddr, m_listenPort); + bool isprivate = isPrivateAddress(reqPublicAddr); + bool ispublic = !isprivate && !isLocalHostAddress(reqPublicAddr); + if (!reqPublicAddr.is_unspecified() && (ispublic || (isprivate && m_netPrefs.localNetworking))) { - if (!m_peerAddresses.count(reqpublicaddr)) - m_peerAddresses.insert(reqpublicaddr); - m_tcpPublic = reqpublic; + if (!m_peerAddresses.count(reqPublicAddr)) + m_peerAddresses.insert(reqPublicAddr); + m_tcpPublic = reqPublic; return; } @@ -307,7 +307,7 @@ void Host::determinePublic(string const& _publicAddress, bool _upnp) } // or if no address provided, use private ipv4 address if local networking is enabled - if (reqpublicaddr.is_unspecified()) + if (reqPublicAddr.is_unspecified()) if (m_netPrefs.localNetworking) for (auto addr: m_peerAddresses) if (addr.is_v4() && isPrivateAddress(addr)) diff --git a/libp2p/NodeTable.cpp b/libp2p/NodeTable.cpp index 20f9f5fdf..bcaea2555 100644 --- a/libp2p/NodeTable.cpp +++ b/libp2p/NodeTable.cpp @@ -55,13 +55,13 @@ void NodeTable::join() doFindNode(m_node.id); } -std::list NodeTable::nodes() const +list NodeTable::nodes() const { - std::list nodes; + list nodes; Guard l(x_nodes); for (auto& i: m_nodes) nodes.push_back(i.second->id); - return std::move(nodes); + return move(nodes); } list NodeTable::state() const @@ -87,7 +87,7 @@ void NodeTable::requestNeighbors(NodeEntry const& _node, NodeId _target) const m_socketPtr->send(p); } -void NodeTable::doFindNode(NodeId _node, unsigned _round, std::shared_ptr>> _tried) +void NodeTable::doFindNode(NodeId _node, unsigned _round, shared_ptr>> _tried) { if (!m_socketPtr->isOpen() || _round == s_maxSteps) return; @@ -99,10 +99,10 @@ void NodeTable::doFindNode(NodeId _node, unsigned _round, std::shared_ptr>()); + _tried.reset(new set>()); auto nearest = findNearest(_node); - std::list> tried; + list> tried; for (unsigned i = 0; i < nearest.size() && tried.size() < s_alpha; i++) if (!_tried->count(nearest[i])) { @@ -135,14 +135,14 @@ void NodeTable::doFindNode(NodeId _node, unsigned _round, std::shared_ptr> NodeTable::findNearest(NodeId _target) +vector> NodeTable::findNearest(NodeId _target) { // send s_alpha FindNode packets to nodes we know, closest to target static unsigned lastBin = s_bins - 1; unsigned head = dist(m_node.id, _target); unsigned tail = head == 0 ? lastBin : (head - 1) % s_bins; - std::map>> found; + map>> found; unsigned count = 0; // if d is 0, then we roll look forward, if last, we reverse, else, spread from d @@ -202,11 +202,11 @@ std::vector> NodeTable::findNearest(NodeId tail--; } - std::vector> ret; + vector> ret; for (auto& nodes: found) for (auto n: nodes.second) ret.push_back(n); - return std::move(ret); + return move(ret); } void NodeTable::ping(bi::udp::endpoint _to) const @@ -222,7 +222,7 @@ void NodeTable::ping(NodeEntry* _n) const ping(_n->endpoint.udp); } -void NodeTable::evict(std::shared_ptr _leastSeen, std::shared_ptr _new) +void NodeTable::evict(shared_ptr _leastSeen, shared_ptr _new) { if (!m_socketPtr->isOpen()) return; @@ -242,7 +242,7 @@ void NodeTable::noteNode(Public const& _pubk, bi::udp::endpoint const& _endpoint if (_pubk == m_node.address()) return; - std::shared_ptr node; + shared_ptr node; { Guard l(x_nodes); auto n = m_nodes.find(_pubk); @@ -264,13 +264,13 @@ void NodeTable::noteNode(Public const& _pubk, bi::udp::endpoint const& _endpoint noteNode(node); } -void NodeTable::noteNode(std::shared_ptr _n) +void NodeTable::noteNode(shared_ptr _n) { - std::shared_ptr contested; + shared_ptr contested; { NodeBucket& s = bucket(_n.get()); Guard l(x_state); - s.nodes.remove_if([&_n](std::weak_ptr n) + s.nodes.remove_if([&_n](weak_ptr n) { if (n.lock() == _n) return true; @@ -294,12 +294,12 @@ void NodeTable::noteNode(std::shared_ptr _n) evict(contested, _n); } -void NodeTable::dropNode(std::shared_ptr _n) +void NodeTable::dropNode(shared_ptr _n) { NodeBucket &s = bucket(_n.get()); { Guard l(x_state); - s.nodes.remove_if([&_n](std::weak_ptr n) { return n.lock() == _n; }); + s.nodes.remove_if([&_n](weak_ptr n) { return n.lock() == _n; }); } Guard l(x_nodes); m_nodes.erase(_n->id); @@ -365,7 +365,7 @@ void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytes // clog(NodeTableMessageSummary) << "Received FindNode from " << _from.address().to_string() << ":" << _from.port(); FindNode in = FindNode::fromBytesConstRef(_from, rlpBytes); - std::vector> nearest = findNearest(in.target); + vector> nearest = findNearest(in.target); static unsigned const nlimit = (m_socketPtr->maxDatagramSize - 11) / 86; for (unsigned offset = 0; offset < nearest.size(); offset += nlimit) { @@ -412,7 +412,7 @@ void NodeTable::doCheckEvictions(boost::system::error_code const& _ec) return; bool evictionsRemain = false; - std::list> drop; + list> drop; { Guard le(x_evictions); Guard ln(x_nodes); diff --git a/libp2p/UDP.h b/libp2p/UDP.h index ac4afb0b1..0c878a3de 100644 --- a/libp2p/UDP.h +++ b/libp2p/UDP.h @@ -142,13 +142,13 @@ protected: bi::udp::endpoint m_endpoint; ///< Endpoint which we listen to. Mutex x_sendQ; - std::deque sendQ; ///< Queue for egress data. - std::array recvData; ///< Buffer for ingress data. - bi::udp::endpoint recvEndpoint; ///< Endpoint data was received from. + std::deque m_sendQ; ///< Queue for egress data. + std::array m_recvData; ///< Buffer for ingress data. + bi::udp::endpoint m_recvEndpoint; ///< Endpoint data was received from. bi::udp::socket m_socket; ///< Boost asio udp socket. Mutex x_socketError; ///< Mutex for error which can be set from host or IO thread. - boost::system::error_code socketError; ///< Set when shut down due to error. + boost::system::error_code m_socketError; ///< Set when shut down due to error. }; template @@ -163,7 +163,7 @@ void UDPSocket::connect() // clear write queue so reconnect doesn't send stale messages Guard l(x_sendQ); - sendQ.clear(); + m_sendQ.clear(); m_closed = false; doRead(); @@ -176,8 +176,8 @@ bool UDPSocket::send(UDPDatagram const& _datagram) return false; Guard l(x_sendQ); - sendQ.push_back(_datagram); - if (sendQ.size() == 1) + m_sendQ.push_back(_datagram); + if (m_sendQ.size() == 1) doWrite(); return true; @@ -190,13 +190,13 @@ void UDPSocket::doRead() return; auto self(UDPSocket::shared_from_this()); - m_socket.async_receive_from(boost::asio::buffer(recvData), recvEndpoint, [this, self](boost::system::error_code _ec, size_t _len) + m_socket.async_receive_from(boost::asio::buffer(m_recvData), m_recvEndpoint, [this, self](boost::system::error_code _ec, size_t _len) { if (_ec) return disconnectWithError(_ec); assert(_len); - m_host.onReceived(this, recvEndpoint, bytesConstRef(recvData.data(), _len)); + m_host.onReceived(this, m_recvEndpoint, bytesConstRef(m_recvData.data(), _len)); doRead(); }); } @@ -207,7 +207,7 @@ void UDPSocket::doWrite() if (m_closed) return; - const UDPDatagram& datagram = sendQ[0]; + const UDPDatagram& datagram = m_sendQ[0]; auto self(UDPSocket::shared_from_this()); m_socket.async_send_to(boost::asio::buffer(datagram.data), datagram.endpoint(), [this, self](boost::system::error_code _ec, std::size_t) { @@ -216,8 +216,8 @@ void UDPSocket::doWrite() else { Guard l(x_sendQ); - sendQ.pop_front(); - if (sendQ.empty()) + m_sendQ.pop_front(); + if (m_sendQ.empty()) return; } doWrite(); @@ -235,9 +235,9 @@ void UDPSocket::disconnectWithError(boost::system::erro { // disconnect-operation following prior non-zero errors are ignored Guard l(x_socketError); - if (socketError != boost::system::error_code()) + if (m_socketError != boost::system::error_code()) return; - socketError = _ec; + m_socketError = _ec; } // TODO: (if non-zero error) schedule high-priority writes From e9f4a7a43927dc3adc88307293ee31da8f6d69d3 Mon Sep 17 00:00:00 2001 From: subtly Date: Mon, 5 Jan 2015 22:01:23 +0100 Subject: [PATCH 079/111] code review --- libp2p/NodeTable.cpp | 13 +++++++------ libp2p/NodeTable.h | 26 ++++++++++---------------- libp2p/UDP.h | 11 +++++------ test/net.cpp | 12 ++++++------ 4 files changed, 28 insertions(+), 34 deletions(-) diff --git a/libp2p/NodeTable.cpp b/libp2p/NodeTable.cpp index bcaea2555..f6ab0f949 100644 --- a/libp2p/NodeTable.cpp +++ b/libp2p/NodeTable.cpp @@ -80,7 +80,7 @@ NodeTable::NodeEntry NodeTable::operator[](NodeId _id) return *m_nodes[_id]; } -void NodeTable::requestNeighbors(NodeEntry const& _node, NodeId _target) const +void NodeTable::requestNeighbours(NodeEntry const& _node, NodeId _target) const { FindNode p(_node.endpoint.udp, _target); p.sign(m_secret); @@ -312,7 +312,7 @@ NodeTable::NodeBucket& NodeTable::bucket(NodeEntry const* _n) void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytesConstRef _packet) { - // h256 + Signature + RLP (smallest possible packet is empty neighbors packet which is 3 bytes) + // h256 + Signature + RLP (smallest possible packet is empty neighbours packet which is 3 bytes) if (_packet.size() < h256::size + Signature::size + 3) { clog(NodeTableMessageSummary) << "Invalid Message size from " << _from.address().to_string() << ":" << _from.port(); @@ -341,7 +341,8 @@ void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytes noteNode(nodeid, _from); try { - switch (itemCount) { + switch (itemCount) + { case 1: { // clog(NodeTableMessageSummary) << "Received Pong from " << _from.address().to_string() << ":" << _from.port(); @@ -355,8 +356,8 @@ void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytes case 2: if (rlp[0].isList()) { - Neighbors in = Neighbors::fromBytesConstRef(_from, rlpBytes); -// clog(NodeTableMessageSummary) << "Received " << in.nodes.size() << " Neighbors from " << _from.address().to_string() << ":" << _from.port(); + Neighbours in = Neighbours::fromBytesConstRef(_from, rlpBytes); +// clog(NodeTableMessageSummary) << "Received " << in.nodes.size() << " Neighbours from " << _from.address().to_string() << ":" << _from.port(); for (auto n: in.nodes) noteNode(n.node, bi::udp::endpoint(bi::address::from_string(n.ipAddress), n.port)); } @@ -369,7 +370,7 @@ void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytes static unsigned const nlimit = (m_socketPtr->maxDatagramSize - 11) / 86; for (unsigned offset = 0; offset < nearest.size(); offset += nlimit) { - Neighbors out(_from, nearest, offset, nlimit); + Neighbours out(_from, nearest, offset, nlimit); out.sign(m_secret); m_socketPtr->send(out); } diff --git a/libp2p/NodeTable.h b/libp2p/NodeTable.h index 5466a3ae3..8f15cb958 100644 --- a/libp2p/NodeTable.h +++ b/libp2p/NodeTable.h @@ -49,7 +49,7 @@ namespace p2p * @todo Pong to include ip:port where ping was received * @todo expiration and sha3(id) 'to' for messages which are replies (prevents replay) * @todo std::shared_ptr m_cachedPingPacket; - * @todo std::shared_ptr m_cachedFindSelfPacket; + * @todo std::shared_ptr m_cachedFindSelfPacket; * @todo store root node in table? * * [Networking] @@ -66,7 +66,7 @@ namespace p2p */ class NodeTable: UDPSocketEvents, public std::enable_shared_from_this { - friend struct Neighbors; + friend struct Neighbours; using NodeSocket = UDPSocket; using TimePoint = std::chrono::steady_clock::time_point; using EvictionTimeout = std::pair,NodeId>; ///< First NodeId may be evicted and replaced with second NodeId. @@ -180,7 +180,7 @@ private: protected: #endif /// Sends FindNeighbor packet. See doFindNode. - void requestNeighbors(NodeEntry const& _node, NodeId _target) const; + void requestNeighbours(NodeEntry const& _node, NodeId _target) const; Node m_node; ///< This node. Secret m_secret; ///< This nodes secret key. @@ -269,7 +269,7 @@ struct Pong: RLPXDatagram /** * FindNode Packet: Request k-nodes, closest to the target. * FindNode is cached and regenerated after expiration - t, where t is timeout. - * FindNode implicitly results in finding neighbors of a given node. + * FindNode implicitly results in finding neighbours of a given node. * * RLP Encoded Items: 2 * Minimum Encoded Size: 21 bytes @@ -299,7 +299,7 @@ struct FindNode: RLPXDatagram * * @todo nonce: Should be replaced with expiration. */ -struct Neighbors: RLPXDatagram +struct Neighbours: RLPXDatagram { struct Node { @@ -308,16 +308,12 @@ struct Neighbors: RLPXDatagram std::string ipAddress; unsigned port; NodeId node; - void streamRLP(RLPStream& _s) const { - _s.appendList(3); _s << ipAddress << port << node; - } - void interpretRLP(RLP const& _r) { - ipAddress = _r[0].toString(); port = _r[1].toInt(); node = h512(_r[2].toBytes()); - } + void streamRLP(RLPStream& _s) const { _s.appendList(3); _s << ipAddress << port << node; } + void interpretRLP(RLP const& _r) { ipAddress = _r[0].toString(); port = _r[1].toInt(); node = h512(_r[2].toBytes()); } }; - using RLPXDatagram::RLPXDatagram; - Neighbors(bi::udp::endpoint _to, std::vector> const& _nearest, unsigned _offset = 0, unsigned _limit = 0): RLPXDatagram(_to) + using RLPXDatagram::RLPXDatagram; + Neighbours(bi::udp::endpoint _to, std::vector> const& _nearest, unsigned _offset = 0, unsigned _limit = 0): RLPXDatagram(_to) { auto limit = _limit ? std::min(_nearest.size(), (size_t)(_offset + _limit)) : _nearest.size(); for (auto i = _offset; i < limit; i++) @@ -334,9 +330,7 @@ struct Neighbors: RLPXDatagram unsigned expiration = 1; void streamRLP(RLPStream& _s) const { _s.appendList(2); _s.appendList(nodes.size()); for (auto& n: nodes) n.streamRLP(_s); _s << expiration; } - void interpretRLP(bytesConstRef _bytes) { - RLP r(_bytes); for (auto n: r[0]) nodes.push_back(Node(n)); expiration = r[1].toInt(); - } + void interpretRLP(bytesConstRef _bytes) { RLP r(_bytes); for (auto n: r[0]) nodes.push_back(Node(n)); expiration = r[1].toInt(); } }; struct NodeTableWarn: public LogChannel { static const char* name() { return "!P!"; } static const int verbosity = 0; }; diff --git a/libp2p/UDP.h b/libp2p/UDP.h index 0c878a3de..96e7fd99e 100644 --- a/libp2p/UDP.h +++ b/libp2p/UDP.h @@ -128,7 +128,6 @@ public: void disconnect() { disconnectWithError(boost::asio::error::connection_reset); } protected: - void doRead(); void doWrite(); @@ -152,7 +151,7 @@ protected: }; template -void UDPSocket::connect() +void UDPSocket::connect() { bool expect = false; if (!m_started.compare_exchange_strong(expect, true)) @@ -170,7 +169,7 @@ void UDPSocket::connect() } template -bool UDPSocket::send(UDPDatagram const& _datagram) +bool UDPSocket::send(UDPDatagram const& _datagram) { if (m_closed) return false; @@ -184,7 +183,7 @@ bool UDPSocket::send(UDPDatagram const& _datagram) } template -void UDPSocket::doRead() +void UDPSocket::doRead() { if (m_closed) return; @@ -202,7 +201,7 @@ void UDPSocket::doRead() } template -void UDPSocket::doWrite() +void UDPSocket::doWrite() { if (m_closed) return; @@ -225,7 +224,7 @@ void UDPSocket::doWrite() } template -void UDPSocket::disconnectWithError(boost::system::error_code _ec) +void UDPSocket::disconnectWithError(boost::system::error_code _ec) { // If !started and already stopped, shutdown has already occured. (EOF or Operation canceled) if (!m_started && m_closed && !m_socket.is_open() /* todo: veirfy this logic*/) diff --git a/test/net.cpp b/test/net.cpp index 0a008d6eb..6952c282a 100644 --- a/test/net.cpp +++ b/test/net.cpp @@ -134,16 +134,16 @@ public: bool success = false; }; -BOOST_AUTO_TEST_CASE(test_neighbors_packet) +BOOST_AUTO_TEST_CASE(test_neighbours_packet) { KeyPair k = KeyPair::create(); std::vector> testNodes(TestNodeTable::createTestNodes(16)); bi::udp::endpoint to(boost::asio::ip::address::from_string("127.0.0.1"), 30000); - Neighbors out(to); + Neighbours out(to); for (auto n: testNodes) { - Neighbors::Node node; + Neighbours::Node node; node.ipAddress = boost::asio::ip::address::from_string("127.0.0.1").to_string(); node.port = n.second; node.node = n.first.pub(); @@ -153,7 +153,7 @@ BOOST_AUTO_TEST_CASE(test_neighbors_packet) bytesConstRef packet(out.data.data(), out.data.size()); bytesConstRef rlpBytes(packet.cropped(97, packet.size() - 97)); - Neighbors in = Neighbors::fromBytesConstRef(to, rlpBytes); + Neighbours in = Neighbours::fromBytesConstRef(to, rlpBytes); int count = 0; for (auto n: in.nodes) { @@ -164,10 +164,10 @@ BOOST_AUTO_TEST_CASE(test_neighbors_packet) } } -BOOST_AUTO_TEST_CASE(test_findnode_neighbors) +BOOST_AUTO_TEST_CASE(test_findnode_neighbours) { // Executing findNode should result in a list which is serialized - // into Neighbors packet. Neighbors packet should then be deserialized + // into Neighbours packet. Neighbours packet should then be deserialized // into the same list of nearest nodes. } From 525ac762dd7128de7d2aec6560af495d8f3eb709 Mon Sep 17 00:00:00 2001 From: arkpar Date: Mon, 5 Jan 2015 22:25:41 +0100 Subject: [PATCH 080/111] fixed code style --- mix/AppContext.cpp | 4 ++-- mix/AppContext.h | 2 +- mix/AssemblyDebuggerControl.cpp | 18 +++++++++--------- mix/CodeHighlighter.cpp | 4 ++-- mix/CodeModel.cpp | 22 ++++++++++++++++------ mix/CodeModel.h | 10 +++++----- mix/MixApplication.h | 3 ++- mix/main.cpp | 2 +- 8 files changed, 38 insertions(+), 27 deletions(-) diff --git a/mix/AppContext.cpp b/mix/AppContext.cpp index 8eae2b230..ff2d10d01 100644 --- a/mix/AppContext.cpp +++ b/mix/AppContext.cpp @@ -60,7 +60,7 @@ void AppContext::loadProject() if (!path.isEmpty()) { QFile file(path); - if(file.open(QIODevice::ReadOnly | QIODevice::Text)) + if (file.open(QIODevice::ReadOnly | QIODevice::Text)) { QTextStream stream(&file); QString json = stream.readAll(); @@ -95,7 +95,7 @@ void AppContext::saveProject(QString const& _json) { dirPath.mkpath(dirPath.path()); QFile file(path); - if(file.open(QIODevice::WriteOnly | QIODevice::Text)) + if (file.open(QIODevice::WriteOnly | QIODevice::Text)) { QTextStream stream(&file); stream << _json; diff --git a/mix/AppContext.h b/mix/AppContext.h index a7fa8a017..7435c7777 100644 --- a/mix/AppContext.h +++ b/mix/AppContext.h @@ -51,7 +51,7 @@ class CodeModel; * @brief Provides access to application scope variable. */ -class AppContext : public QObject +class AppContext: public QObject { Q_OBJECT diff --git a/mix/AssemblyDebuggerControl.cpp b/mix/AssemblyDebuggerControl.cpp index c230d9b6f..136353dc6 100644 --- a/mix/AssemblyDebuggerControl.cpp +++ b/mix/AssemblyDebuggerControl.cpp @@ -92,7 +92,7 @@ void AssemblyDebuggerControl::debugState(QVariantMap _state) std::vector transactionSequence; - for (auto const& t : transactions) + for (auto const& t: transactions) { QVariantMap transaction = t.toMap(); @@ -132,14 +132,14 @@ void AssemblyDebuggerControl::executeSequence(std::vector c QFunctionDefinition* f; ContractCallDataEncoder c; //encode data for all transactions - for (auto const& t : _sequence) + for (auto const& t: _sequence) { f = nullptr; - for (int k = 0; k < contractDef->functionsList().size(); k++) + for (int tf = 0; tf < contractDef->functionsList().size(); tf++) { - if (contractDef->functionsList().at(k)->name() == t.functionId) + if (contractDef->functionsList().at(tf)->name() == t.functionId) { - f = contractDef->functionsList().at(k); + f = contractDef->functionsList().at(tf); break; } } @@ -147,9 +147,9 @@ void AssemblyDebuggerControl::executeSequence(std::vector c throw std::runtime_error("function " + t.functionId.toStdString() + " not found"); c.encode(f->index()); - for (int k = 0; k < f->parametersList().size(); k++) + for (int p = 0; p < f->parametersList().size(); p++) { - QVariableDeclaration* var = (QVariableDeclaration*)f->parametersList().at(k); + QVariableDeclaration* var = (QVariableDeclaration*)f->parametersList().at(p); u256 value = 0; auto v = t.parameterValues.find(var->name()); if (v != t.parameterValues.cend()) @@ -171,7 +171,7 @@ void AssemblyDebuggerControl::executeSequence(std::vector c //we need to wrap states in a QObject before sending to QML. QList wStates; - for(int i = 0; i < debuggingContent.machineStates.size(); i++) + for (int i = 0; i < debuggingContent.machineStates.size(); i++) { QPointer s(new DebuggingStateWrapper(debuggingContent.executionCode, debuggingContent.executionData.toBytes())); s->setState(debuggingContent.machineStates.at(i)); @@ -182,7 +182,7 @@ void AssemblyDebuggerControl::executeSequence(std::vector c emit dataAvailable(debuggingContent.returnParameters, wStates, code); emit runComplete(); } - catch(boost::exception const& e) + catch(boost::exception const&) { emit runFailed(QString::fromStdString(boost::current_exception_diagnostic_information())); } diff --git a/mix/CodeHighlighter.cpp b/mix/CodeHighlighter.cpp index 7cc07c9a5..5c126d8e2 100644 --- a/mix/CodeHighlighter.cpp +++ b/mix/CodeHighlighter.cpp @@ -36,7 +36,7 @@ using namespace dev::mix; CodeHighlighterSettings::CodeHighlighterSettings() { backgroundColor = QColor(0x00, 0x2b, 0x36); - foregroundColor = QColor (0xee, 0xe8, 0xd5); + foregroundColor = QColor(0xee, 0xe8, 0xd5); formats[Keyword].setForeground(QColor(0x93, 0xa1, 0xa1)); formats[Comment].setForeground(QColor(0x85, 0x99, 0x00)); formats[StringLiteral].setForeground(QColor(0xdc, 0x32, 0x2f)); @@ -49,7 +49,7 @@ CodeHighlighterSettings::CodeHighlighterSettings() namespace { using namespace dev::solidity; - class HighlightVisitor : public ASTConstVisitor + class HighlightVisitor: public ASTConstVisitor { public: HighlightVisitor(CodeHighlighter::Formats* _formats) { m_formats = _formats; } diff --git a/mix/CodeModel.cpp b/mix/CodeModel.cpp index 8d2c24725..7d8b0442a 100644 --- a/mix/CodeModel.cpp +++ b/mix/CodeModel.cpp @@ -41,14 +41,17 @@ void BackgroundWorker::queueCodeChange(int _jobId, QString const& _content) } CompilationResult::CompilationResult(): - QObject(nullptr), m_successfull(false), + QObject(nullptr), + m_successful(false), m_codeHash(qHash(QString())), m_contract(new QContractDefinition()), m_codeHighlighter(new CodeHighlighter()) {} CompilationResult::CompilationResult(const solidity::CompilerStack& _compiler): - QObject(nullptr), m_successfull(true), m_codeHash(qHash(QString())) + QObject(nullptr), + m_successful(true), + m_codeHash(qHash(QString())) { if (!_compiler.getContractNames().empty()) { @@ -61,7 +64,9 @@ CompilationResult::CompilationResult(const solidity::CompilerStack& _compiler): } CompilationResult::CompilationResult(CompilationResult const& _prev, QString const& _compilerMessage): - QObject(nullptr), m_successfull(false), m_codeHash(qHash(QString())), + QObject(nullptr), + m_successful(false), + m_codeHash(qHash(QString())), m_contract(_prev.m_contract), m_compilerMessage(_compilerMessage), m_bytes(_prev.m_bytes), @@ -69,8 +74,13 @@ CompilationResult::CompilationResult(CompilationResult const& _prev, QString con m_codeHighlighter(_prev.m_codeHighlighter) {} -CodeModel::CodeModel(QObject* _parent) : QObject(_parent), - m_compiling(false), m_result(new CompilationResult()), m_codeHighlighterSettings(new CodeHighlighterSettings()), m_backgroundWorker(this), m_backgroundJobId(0) +CodeModel::CodeModel(QObject* _parent): + QObject(_parent), + m_compiling(false), + m_result(new CompilationResult()), + m_codeHighlighterSettings(new CodeHighlighterSettings()), + m_backgroundWorker(this), + m_backgroundJobId(0) { m_backgroundWorker.moveToThread(&m_backgroundThread); connect(this, &CodeModel::scheduleCompilationJob, &m_backgroundWorker, &BackgroundWorker::queueCodeChange, Qt::QueuedConnection); @@ -97,7 +107,7 @@ void CodeModel::stop() m_backgroundThread.wait(); } -void CodeModel::registerCodeChange(const QString &_code) +void CodeModel::registerCodeChange(QString const& _code) { // launch the background thread uint hash = qHash(_code); diff --git a/mix/CodeModel.h b/mix/CodeModel.h index 69c840aa5..c66703b22 100644 --- a/mix/CodeModel.h +++ b/mix/CodeModel.h @@ -61,7 +61,7 @@ private: }; ///Compilation result model. Contains all the compiled contract data required by UI -class CompilationResult : public QObject +class CompilationResult: public QObject { Q_OBJECT Q_PROPERTY(QContractDefinition* contract READ contract) @@ -79,7 +79,7 @@ public: /// @returns contract definition std::shared_ptr sharedContract() { return m_contract; } /// Indicates if the compilation was successfull - bool successfull() const { return m_successfull; } + bool successfull() const { return m_successful; } /// @returns compiler error message in case of unsuccessfull compilation QString compilerMessage() const { return m_compilerMessage; } /// @returns contract bytecode @@ -90,7 +90,7 @@ public: std::shared_ptr codeHighlighter() { return m_codeHighlighter; } private: - bool m_successfull; + bool m_successful; uint m_codeHash; std::shared_ptr m_contract; QString m_compilerMessage; ///< @todo: use some structure here @@ -102,7 +102,7 @@ private: }; /// Background code compiler -class CodeModel : public QObject +class CodeModel: public QObject { Q_OBJECT @@ -139,7 +139,7 @@ signals: void compilationCompleteInternal(CompilationResult* _newResult); private slots: - void onCompilationComplete(CompilationResult*_newResult); + void onCompilationComplete(CompilationResult* _newResult); public slots: /// Update code model on source code change diff --git a/mix/MixApplication.h b/mix/MixApplication.h index e1cb1e5cf..86c1126fc 100644 --- a/mix/MixApplication.h +++ b/mix/MixApplication.h @@ -43,7 +43,8 @@ public: MixApplication(int _argc, char* _argv[]); virtual ~MixApplication(); AppContext* context() { return m_appContext.get(); } - QQmlApplicationEngine* engine( ) { return m_engine.get(); } + QQmlApplicationEngine* engine() { return m_engine.get(); } + private: std::unique_ptr m_engine; std::unique_ptr m_appContext; diff --git a/mix/main.cpp b/mix/main.cpp index e10903c80..90099555f 100644 --- a/mix/main.cpp +++ b/mix/main.cpp @@ -23,7 +23,7 @@ #include "MixApplication.h" using namespace dev::mix; -int main(int _argc, char *_argv[]) +int main(int _argc, char* _argv[]) { MixApplication app(_argc, _argv); return app.exec(); From 3d449785ded5c2c50d5678a189ab8fa88ed05c0e Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Tue, 6 Jan 2015 11:30:52 +0100 Subject: [PATCH 081/111] Blockhash correction and some tests --- libevm/ExtVMFace.h | 2 +- libevm/VM.h | 2 +- test/vmBlockInfoTestFiller.json | 90 +++++++++++++++++++++++++++++++-- 3 files changed, 89 insertions(+), 5 deletions(-) diff --git a/libevm/ExtVMFace.h b/libevm/ExtVMFace.h index a4ec80ed8..bf1b180e9 100644 --- a/libevm/ExtVMFace.h +++ b/libevm/ExtVMFace.h @@ -148,7 +148,7 @@ public: virtual void revert() {} /// Hash of a block if within the last 256 blocks, or h256() otherwise. - h256 prevhash(u256 _number) { return _number < currentBlock.number && _number > (std::max(257, currentBlock.number) - 257) ? lastHashes[(unsigned)(currentBlock.number - 1 - _number)] : h256(); } // TODO: CHECK!!! + h256 blockhash(u256 _number) { return _number < currentBlock.number && _number >= (std::max(256, currentBlock.number) - 256) ? lastHashes[(unsigned)(currentBlock.number - 1 - _number)] : h256(); } // TODO: CHECK!!! /// Get the code at the given location in code ROM. byte getCode(u256 _n) const { return _n < code.size() ? code[(size_t)_n] : 0; } diff --git a/libevm/VM.h b/libevm/VM.h index eab248b44..cc9556c26 100644 --- a/libevm/VM.h +++ b/libevm/VM.h @@ -559,7 +559,7 @@ inline bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _st m_stack.push_back(_ext.gasPrice); break; case Instruction::BLOCKHASH: - m_stack.back() = (u256)_ext.prevhash(m_stack.back()); + m_stack.back() = (u256)_ext.blockhash(m_stack.back()); break; case Instruction::COINBASE: m_stack.push_back((u160)_ext.currentBlock.coinbaseAddress); diff --git a/test/vmBlockInfoTestFiller.json b/test/vmBlockInfoTestFiller.json index 1ebedc12b..15c270173 100644 --- a/test/vmBlockInfoTestFiller.json +++ b/test/vmBlockInfoTestFiller.json @@ -1,8 +1,92 @@ { - "prevhash": { + "blockhashNotExistingBlock": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", - "currentNumber" : "0", + "currentNumber" : "1", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (BLOCKHASH 2) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "blockhashMyBlock": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "1", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (BLOCKHASH 1) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "blockhash258Block": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "258", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (BLOCKHASH 1) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "blockhash257Block": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "257", "currentGasLimit" : "1000000", "currentDifficulty" : "256", "currentTimestamp" : 1, @@ -12,7 +96,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "{ [[ 0 ]] (PREVHASH) }", + "code" : "{ [[ 0 ]] (BLOCKHASH 0) }", "storage": {} } }, From 00416dd1180b9516ae72a53a6475d6b56a1056b5 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Tue, 6 Jan 2015 13:48:23 +0100 Subject: [PATCH 082/111] removed evmjit submodule --- evmjit | 1 - 1 file changed, 1 deletion(-) delete mode 160000 evmjit diff --git a/evmjit b/evmjit deleted file mode 160000 index 3df5a125f..000000000 --- a/evmjit +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 3df5a125fa0baa579528abce80402118cad803fd From 49653da6078481d542ff6899080c818d844c68bb Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Tue, 6 Jan 2015 13:53:09 +0100 Subject: [PATCH 083/111] Squashed 'evmjit/' content from commit 334deeb git-subtree-dir: evmjit git-subtree-split: 334deeb4c6ca93a26f58979b609f6386042128ff --- .gitignore | 28 ++++++++++++++++++++++++++++ LICENSE | 22 ++++++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..b8bd0267b --- /dev/null +++ b/.gitignore @@ -0,0 +1,28 @@ +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..d7e0e57ac --- /dev/null +++ b/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2014 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + From 29c9178ff40adc093ef84f81fe3d995144f87627 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Tue, 6 Jan 2015 13:59:00 +0100 Subject: [PATCH 084/111] Squashed 'evmjit/' changes from 334deeb..533531b 533531b Create helper/external functions on demand (env_balance for now) e12fa12 Suicide rework ae6e709 Disalbe bswap constant folding ec30ce4 Object cache 5be8c59 Byte swap for constants 3df5a12 Do not compile LLVM module if machine code available in memory 2b31cba Memory manager cleanup 6a22491 Clean up ExecutionEngine 28a0623 Clean up ExecutionEngine de02425 Clean up ExecutionEngine ece7fe7 Clean up ExecutionEngine fe90c6f Clean up ExecutionEngine 9d9e73a Using one ExecutionEngine to cache compiled contracts 713b33e Remove global private memory pointers f8ffdfa Remove global privite pointers to runtime instance and runtime data 6643af5 Use code hash as main function name e3245e1 Remove addtional cost param from commitCostBlock(). Count additional cost manually. [#81461534] 90cb4a7 More aggresive gas counting optimization: do not commit cost before LOG. [#81461534] 5d5259e Do not auto-commit cost block c5de54d More aggresive gas counting optimization: do not commit cost before SSTORE. c5ebca6 More aggresive gas counting optimization: do not commit cost before memory access. 69930b9 Use sub "no-wrap" 6acbfe0 Remove unused function eaed9c3 Read push data using llvm::APInt 30f0a7a Type usage and other cleanups 4254b3f Fix memory copy [Delivers #84703344] 43e08ea Handle create/call depth limit in CREATE instruction 20190b1 Add -D__STDC_CONSTANT_MACROS -D__STDC_LIMIT_MACROS needed by LLVM (reverted from commit 66d5a2b5cdf1361dcf0205b191dd12be090ed224) 75fa672 Fix compilation with LLVM pre-3.5 (Ubuntu 14.04) (reverted from commit 6094aa30add22d56bee145bbb4a7d440c08db5c8) 6094aa3 Fix compilation with LLVM pre-3.5 (Ubuntu 14.04) 66d5a2b Add -D__STDC_CONSTANT_MACROS -D__STDC_LIMIT_MACROS needed by LLVM 1b49024 Workaround for Ubuntu broken LLVM package (llvm-3.5-dev does not have correct cmake files) ed63ced Disable rtti for Cache as LLVM has not rtti 232f9fe Refactor cmake files 8287c60 Own cached objects 6543cc4 Execution Engine cleanups (reverted from commit bd85efa299e661228a1ac6283b5fad14e09f88d9) 98b265b Merge commit '2332595c9c0d315dc9ecde22d236ae477b931863' into develop 2b83b75 Object cache wit memory leaks de22a0a Execution Engine cleanups 2332595 Change the name of a module to some hash (for caching) bd85efa Execution Engine cleanups b37ce8e Gas counting for CREATE instruction 0a64245 Fix checking memory requirements with size 0 a492760 Using llvm::ExecutionEngine::getFunctionAddress() instead of getPointerToFunction(). Cleanups. dd63bb3 Remove TODO comment 8f3edbc Disable cache. It's broken. 49bd78b SHA3 gas cost updated 76d30b8 Count additional gas cost for memory copies. Some GasMeter improvments. 077cf7b Count additional cost for EXP exponent c2699b3 Comment about MCJIT and caching pointers to entry functions 91cd37e Remove logs 47d92e9 Remove dummy int argument in entry function 2e1c90f Change the way entry function is called. 4a9d08d Change the way entry function is called. 70279f8 Changes in setjmps dbf8174 Update usage of ExtVMFace dc4bc0e Jit can handle call stack up to 1024 45fb3f5 Move some data from stack to JitVM object to save stack space. 6e318f8 Check current call depth 70348d9 Fix cache key and do not compile to LLVM module when it is not needed da02a18 Cache key is contract code. Does not work 7c9cf6e Trying to cache compiled contracts with pointer to code as a key (it's not a good idea) 2a7111c ExecBundle - all information needed to execute a JIT-compiled contracts b3a1734 Disable JIT logs b1b94de Opcodes update c9f5694 CMakeLists.txt cleanup (in progress) 63d6997 added missing b07f25d Detect endianness without boost help b176574 Remove usage of boost::lexical_cast 5f4c1c7 Fix evmcc compilation - provide fake runtime data e3ccc03 Fix MSVC warning 9452da9 Merge remote-tracking branch 'origin/develop' into develop 2fd2446 Simplify ExecutionEngine interface. It is possible to pass raw code instead of LLVM module. 46d1926 fixed gcc warnings (missing field initializers, unused functions) bd40486 Moving ext_calldataload helper function to evmjit library (does not depend on Env) 2b9b530 Cleanups c6fcdbc Arith performace tests adb5a68 A bit of work in evmcc. Not ready yet. b987258 A TODO comment 5362d50 SDIV & SMOD fixed 58d2bfb External code access in Env reimplemented 4366542 LOGs reimplemented 63719d2 env_call updated 69dae9a env_create updated 6f84f3d Rename sload, sstore & sha3 Env functions 408fda8 Old code removed 116ce60 Remove Env* param from env_sha3 function (not needed) 4fc4e76 Change the way memory is passed to sha3 Env function cc6bb83 Simplify JIT logs 259d1d2 Old files removed ddfe85b Update VM gas counter after execution 2b4430e Change Env functions first argument type to opaque Env* 969f1b5 The way runtime data is passed to jit'ed contract changed b8e0ad1 Fix exporting Env callback symbols 7db676c Client side Env updated a0d0f85 JIT VM updated 3298e10 Remove mock declaration 49b82cd Move EXP implementation from Ext to Arith256 8672c4b Updating Ext interface bb6e603 Updating ExecutionEngine interface 0509b3b Changing Runtime interface aa77158 Separate runtime classes 68648a2 Separating EVM JIT from CPP client (WIP) 99c7113 CMake scripts 5f61bdc Starting cmake scripts dc82664 C Interface draft 1 94e41d8 correct calculation of LOG cost fdd5275 fixed bug in implementation of LOG 30eea6e Merge branch 'develop-evmcc' of https://github.com/imapp-pl/ethereum into develop-evmcc f72cced resolved circular dependency between libevm and libevmjit c2c96e6 Merge remote-tracking branch 'origin/develop-evmcc' into develop-evmcc bf6a4d4 output gas updated in vmPerformanceTest.json d77ee40 EVM code updated in vmPerformanceTests 3517bfc fixed libevmjit dependencies in cmake files f7d6554 Move mock of ExtVMFace to evmcc tool 89e6d2f made _ext a mandatory arg of Runtime::run() aa7fc79 libevmface -> libevmcore: updated cmake files 320bdf5 Merge branch 'develop-evmcc' of https://github.com/imapp-pl/ethereum into develop-evmcc 86334f5 Handle bytecode as bytes 2bd4d6c Update Instruction.h location c907c71 codegen for LOG instructions [Delivers #81700490] cdcbb6b removed references to Memory::dump() 47e654c Merge branch 'develop' into develop-evmcc 7305fb3 fixed bug in llvm ir computing required memory size 4b4265c Merge branch 'develop-evmcc' of github.com:imapp-pl/ethereum into develop-evmcc ae9f57f (1) Handling evmcc options with boost::program_options. (2) Writing out .ll and .bc files cb87052 unused var removed 9a0f9d3 1) JUMP/I semantics updated. 2) Members of BasicBlock::LocalStack pulled out to BasicBlock c91c5df Rename BNOT -> NOT, NOT -> ISZERO 29432be Merge branch 'develop-evmcc' of https://github.com/imapp-pl/ethereum into develop-evmcc ee0e2d3 added struct for compiler options 172fc1c Merge branch 'develop-evmcc' of https://github.com/imapp-pl/ethereum into develop-evmcc 8f7b5d6 removed *.orig file 6f99869 code cleanup and coding-standardization 3fc508f Merge branch 'develop-evmcc' of https://github.com/imapp-pl/ethereum into develop-evmcc a44a7ab Use llvm.longjmp intrinsic for longjmp [Delivers #81792986] b6b4f5f Merge branch 'develop-evmcc' of github.com:imapp-pl/ethereum into develop-evmcc 8ee32d9 Coding style: use "o_" prefix for output function arguments 40561b1 code cleanup & coding-standardization aaaf543 Rename Type::i256 -> Type::Word b5abb70 Use common builder in GasMeter and Memory 33cc50d Empty lines removal 72398d2 Handle unsigned integer overflow in Memory::require() [Delivers #81773288] 350b004 Change Constant::get to support negative values 272c568 Remove Memory::require(size) interface [#81773288] 273b0f6 Deprecate Memory::require(size) function. Risk of unsigned integer overflow. 439561a Use readPushData() in basic block analysis bfb9660 Use readPushData() in instruction compilation 1008c70 Create dedicated function for pushdata reading 4ff7ba0 Fix u256 to APInt conversion 65af01c removed accidentally added *.orig file d32daf6 New performance tests [Delivers #81578852] 895d0aa Merge branch 'develop-evmcc' of github.com:imapp-pl/ethereum into develop-evmcc 7760b31 Cleaning up warnings and build dependencies [#81588646] 2d6aa46 CMakeLists updated, should now build without LLVM when EVMJIT is not enabled [#81588646] 43093d6 Fix MSIZE and memory resize step [Delivers #81777708] 85f67a5 Improve PUSH compilation 2bbbf6c Merge branch 'develop-evmcc' of https://github.com/imapp-pl/ethereum into develop-evmcc 3725432 Fix case where JUMPI is the last instruction 2524c72 Codegen for SIGNEXTEND [Delivers #81700414] 007641a SIGEXTEND: first try [#81700414] d778640 Fix BNOT instruction [Delivers #81700198] dd75da2 BNOT instruction [Delivers #81700198] e4a77c1 Increase refund counter if deleting a storage item [Delivers #81575908] 22e4d16 Remove old code af0530b Got rid of some gcc warnings c6cf723 Fix u256 to APInt conversion e6b4761 Allow creating LLVM constants directly from u256 33f1253 Update gas counting for SSTORE, no refunding yet [#81575908] e24c9c2 Improve Compiler code formatting f06445f Improve VM code formatting c03d36a Improve Ext code formatting bc1ef19 Improve GasMeter code formatting 3212b2b Improve ExecutionEngine code formatting de67937 Improve BasicBlock code formatting 64513d5 Improve Memory code formatting 3ee33cc Improve code formatting 1e8a091 Improve Arith256 code formatting 211d3c0 Change #include setjmp fa6d4c6 Improve Stack code formatting 7e3a9f4 Remove done FIXME tasks ce889fc Merge branch 'develop-evmcc' of github.com:imapp-pl/ethereum into develop-evmcc 4c9fed9 turned on stack optimization by default in jit compiler 664de37 json test file for performance testing 89d4a1c Merge branch 'develop-evmcc' of https://github.com/imapp-pl/ethereum into develop-evmcc 887bac9 Use clog for JIT logs 6e8d1ce added inlcude of setjmp.h required for jmp_buf type ac478d2 added dependency on libethereum to evmcc a3871e5 Merge branch 'develop-evmcc' of github.com:imapp-pl/ethereum into develop-evmcc cecf567 MULMOD/ADDMOD implemented in separate functions [FIXES #80566276] 65eaa13 Remove global Runtime pointer 25ccd49 Changed semantics of JUMPDEST so that *the next* instruction is a jump destination 6bf994d 1. Indenting spaces converted to tabs 2. Options changed: -G --> -g 4684c6f Using call helper 2493ef5 Call helper 6da6f3d Handle bad instructions (BadInstruction exception) [#81563132] ac38bf9 Add raiseException helper to RuntimeManager [#81563132] 31c9dd3 Ignore opOp callback silently 5a923d6 Ignore opOp callback silently c7ba567 Merge branch 'develop' into develop-evmcc 0da6823 Fix EXTCODECOPY 0eb8311 Restore correct memory access in Ext functions 05bbe53 Merge branch 'develop-evmcc' of https://github.com/imapp-pl/ethereum into develop-evmcc d5ddbfa Added missing changes [#79450108] 6a16efa Get Runtime pointer from main function argument if available e273299 Change some runtime names fd7b6da Move return data reference to Runtime [#81470252] 6d428d8 Fix ReturnData::Index::_size 64e3748 Move jmpbuf to Runtime [#81470252] 68ca696 256-bit arithmetic implemented via calls to boost::multiprecision library. [#79450108] 4bcd092 Merge branch 'develop-evmcc' of github.com:imapp-pl/ethereum into develop-evmcc a90ebe6 Print compilation/execution times 734dd31 Using RuntimeData pointer in ext functions [#81470252] a076ced Old bswap intrinsic removed 3cba473 Moving CODE data from Ext to Runtime [#81470252] 83b24b6 Moving CALLDATA data from Ext to Runtime [#81470252] 916f5ab Group instructions that access runtime data [#81470252] 088a4ef Moving the rest word-size data from Ext to Runtime [#81470252] bfe1216 Moving ORIGIN, CALLER & CALLVALUE data from Ext to Runtime [#81470252] 5c1e344 Add name to data indices [#81470252] 399cf28 Moving ADDRESS data from Ext to Runtime [#81470252] 2b898fc Introducing RuntimeHelper - a compiler helper that depends on runtime data [#81470252] 9ca2663 Use Type::RuntimePtr instead of RuntimeData::getType->getPointerTo() 3670e32 Access stack structure through runtime structure [#81470252] 693c4b3 Add Type::RuntimePtr predefined LLVM type c388a81 Access memory structure through runtime structure [#81470252] b579c70 Place current gas counter value in RuntimeData 097b7ae Merge branch 'develop-evmcc' of https://github.com/imapp-pl/ethereum into develop-evmcc 8da55ff Export runtime data to global variable in main function a60843e Merge branch 'develop-evmcc' of github.com:imapp-pl/ethereum into develop-evmcc 547ca38 Propagation of values between basic blocks' local stacks [#80895676] 6c2a120 Introducing RuntimeData struct - a data that will be provided to running program 6580a9b Visual Studio build fix 0dae894 new test cases d281396 Refactored local stack [#81180320] d41828f added option to set initial gas fc7a46b Change the way VMs are created (mostly for tracking where are created) dcb739e Better assert condition 16de530 Try not to use JIT in any interactive mode 48108f5 Implement VMFace with jit::VM 701d99e Fixed the order in which phi nodes are created (was incorrect) [#80895676] aaf0f7d Merge branch 'develop-evmcc' of github.com:imapp-pl/ethereum into develop-evmcc 044e838 Fixed bug in phi node rewriting [#80895676] 170ca15 Null gas in case of out-of-gas exception [Delivers #81118624] 54c636a Merge branch 'develop-evmcc' of https://github.com/imapp-pl/ethereum into develop-evmcc f28f8cc Add support for Big Endian architectures [Delivers #79877740] 0757523 Use Endianness in Ext [#79877740] 920ea2e Comment: storage uses native endianness [#79877740] 05741c2 Handle endianness for CALLDATALOAD correctly [#79877740] 5a8ba36 added assert in linkBasicBlocks() 8909c15 Merge branch 'develop-evmcc' of github.com:imapp-pl/ethereum into develop-evmcc 080cf20 Handling pop() from the empty EVM stack. [#80895676] 49b0769 Merge branch 'develop-evmcc' of https://github.com/imapp-pl/ethereum into develop-evmcc d95083a Remove unreachable basic blocks before "linking" a6ce4ba Merge branch 'develop-evmcc' of https://github.com/imapp-pl/ethereum into develop-evmcc 1cf3549 minor changes in the compiler driver a4416e5 Remove unreachable basic blocks before "linking" c4eb835 added missing CMakeLists.txt 937fbaa Merge branch 'develop-evmcc' of github.com:imapp-pl/ethereum into develop-evmcc 0a9e0f5 Propagation of values between basic blocks (and the stack): initial implementation (probably buggy, but simple cases work). [#80895676] 8ba533f Merge branch 'develop' into develop-evmcc c7eac0d Fix SHA3 instruction :) 5db2038 Handle endianness of MSTORE & MLOAD [#79877740] 51fc9ad Fix compiling empty bytecode c97ca24 Throw exception if EVM program is not jitable instead of terminating to make tests going 150162e Merge branch 'develop-evmcc' of https://github.com/imapp-pl/ethereum into develop-evmcc f83e23a Another round of fixing ExtVM interface 54e0824 Updated cmake files after moving the jit compiler to a lib. 58c5a4f Merge branch 'develop-evmcc' of github.com:imapp-pl/ethereum into develop-evmcc 607458b BYTE reimplementation afe0254 Endianness handler b13f1ac Check if pushed item is a word b01a75a Merge branch 'develop-evmcc' of github.com:imapp-pl/ethereum into develop-evmcc 52ba848 Add support for direct jump outside the code - terminates with STOP 6c3af96 Limit debug output de8deab Fix for invalid jump table basic block 0febd6a Do not try to add additional cost (call instruction) to cost-block f31f3bc Using gas provided by test engine and fix for creating fake ExtVMFace. dfac5a0 Using ExtVM provided by test engine f0928f5 Tests moved to test/ folder dd6fbda Fix not allocated arg8 for CALL 15714ce Fix GasMeter not nulling cost call 0f4c8eb VM execution wrapper with similar interface as libevm/VM 9105fb1 Merge branch 'develop' into develop-evmcc 7df24fa Move JIT compiler project to library 34afb85 Merge branch 'develop-evmcc' of github.com:imapp-pl/ethereum into develop-evmcc f062fd0 Dumping CFG to .dot: showing indirect jumps with dashed lines dcafa47 Merge branch 'develop-evmcc' of https://github.com/imapp-pl/ethereum into develop-evmcc 72a6fe4 InsertPointGuard definition moved to CompilerHelper.h 8eea475 Get IR module from IR builder on demand f233122 Added dumping of CFG to a .dot file [Delivers #80816506] c83739e Get IR module from IR builder 5e13d59 Introducing CompilerHelper - a base class for... compiler helper classes like Memory, GasMeter, etc. bb51b34 Cleanup block terminator generation 1463897 Basic block compilation in separated function e094ba9 Placing IRBuilder in Compiler class (for future refactoring) 5586ff5 Some changes about final/stop block 07f6bbf Removing unnecessary `dev` name prefixes 11bf67b Eliminating some `using namespace` a2da7c9 Change namespace from `evmcc` to `dev::eth::jit` f1ea6c9 Macros grouping PUSH, DUP and SWAP switch cases a36a432 Merge branch 'develop-evmcc' of https://github.com/imapp-pl/ethereum into develop-evmcc 67ee0b6 Unused rt_exit() function removed ec2013d Working longjmp solution 00a872e * codegen for CODECALL * fixes for EXTCODECOPY 59a392c Merge branch 'develop-evmcc' of github.com:imapp-pl/ethereum into develop-evmcc 564a593 Codegen for EXTCODESIZE & EXTCODECOPY [Delivers #80644732] 9007b74 Merge branch 'develop-evmcc' of https://github.com/imapp-pl/ethereum into develop-evmcc 7fcf24d Trying to implement "exceptions" with longjmp (does not work on Windows 64bit at least) 727691f Merge branch 'develop-evmcc' of github.com:imapp-pl/ethereum into develop-evmcc e22238f Merge branch 'develop-evmcc' of github.com:imapp-pl/ethereum into develop-evmcc c57de78 Use longjmp to return OutOfGas code from main function (WIP) dbb3e81 Try to throw an OutOfGas exception when out of gas. The exception cannot be handled. 04d6ffb Some LLVM function attribute fun e11a9bb Change a bit the implementation of GAS instruction (fix) 00e5afc Change a bit the implementation of GAS instruction 0d679f0 Count gas cost for SSTORE instruction df93292 Codegen for CODECOPY. [Delivers #80644732] 1c70f3d Prealloc memory and count gas for CALL instruction d56f60f Merge branch 'develop-evmcc' of https://github.com/imapp-pl/ethereum into develop-evmcc 7d67476 Prealloc memory and count gas for SHA3 and CREATE instructions 42b14ae Fixes in CALLDATACOPY [Delivers #80644732] 9d9e160 InsertPointGuard helper class for IRBuilder 7203120 Merge branch 'develop-evmcc' of github.com:imapp-pl/ethereum into develop-evmcc 0d97405 Initial implementation for CALLDATACOPY [Delivers #80644732] 82cba7a Use mem.require in mload, mstore & mstore8 0931289 Convenient Memory::require() overload ab556c6 Private mem.require function that preallocates memory and counts gas fee 01ca987 Give back an amount of gas not used by CALL instructions fb87a0b Count gas for CALL instructions 07131e4 Merge branch 'develop-evmcc' of github.com:imapp-pl/ethereum into develop-evmcc 475b85d Fixes in inline asm in some jump tests. 7494fdb Use Constant::get() interface to create LLVM constants f95999c Allocate memory and count gas for RETURN instruction 7a89751 Change the way compiled program returns 8fb6de0 Define constants and return codes 6caff31 Implemented ADDMOD, MULMOD and GAS [Delivers #80566276] 9b3c446 Codegen for GAS 3a25969 Report error if static-analysed stack is too small 0c259cd Merge branch 'develop-evmcc' of github.com:imapp-pl/ethereum into develop-evmcc a2a496e test cases for JUMPS/phi nodes 6131cca Merge branch 'develop-evmcc' of https://github.com/imapp-pl/ethereum into develop-evmcc 8a52283 Do not check gas cost of value 0 efe23ad Do not commit gas costs on JUMPDEST instruction 7c78ecb Merge branch 'develop-evmcc' of github.com:imapp-pl/ethereum into develop-evmcc 293f0de Merge branch 'develop-evmcc' of https://github.com/imapp-pl/ethereum into develop-evmcc 9bdfd59 Change basic block linking order to get better results (still not perfect) 56a17a0 test cases for JUMP e4cf741 Merge branch 'develop-evmcc' of github.com:imapp-pl/ethereum into develop-evmcc 6e2bcef Implemented indirect JUMPI and fixes for JUMPs to invalid PCs 2c3d0cc test cases for JUMP(I) d5f7de4 Always commit cost blocks 39ba3ae Use external counter for gas (external linkage global variable) 4eb65a8 Fix block cost counting (counter not reset) 5470faf Count gas for additional memory d6e6a5f MSIZE test 0128f09 Wrong resize condition fixed 4f87144 mload function added as implementation of MLOAD 5f1ea8f store8 function added as implementation of MSTORE8 f5a0975 Use mem.store as implementation of MSTORE f825a60 Generate mem.store function and dependencies (currently unused) 7a7d4e3 Fix for finding jumpTableBlock d6915b4 Renames & comments ad43b92 Merge branch 'develop-evmcc' of github.com:imapp-pl/ethereum into develop-evmcc fd7069e Indirect jump: jump table generated in separate bblock. 09a5899 Fix stack swap or dup not generating PHI nodes 973e0a2 Merge branch 'develop-evmcc' of https://github.com/imapp-pl/ethereum into develop-evmcc 52d1ceb test cases for jumps 5dd3037 Merge branch 'develop-evmcc' of https://github.com/imapp-pl/ethereum into develop-evmcc cfb226b Group gas counting into block of instructions called cost-block. dab29a9 Merge branch 'develop-evmcc' of github.com:imapp-pl/ethereum into develop-evmcc 6778940 test cases for JUMP 2b36803 Implementing JUMP/JUMPDEST (work in progress) e42217d Disable gas checking for now (does not work and makes IR code hard to read) 04cf0cf Generate gas checking function 97644d6 Cleanup LLVM types usage b7f31af Cleanup LLVM types usage 28d6dd7 Decrement global gas value by instruction step cost d3f59f6 Introducing GasMeter 7f88487 EXP instruction. dafa5bc Make the Stack an integral part of BasicBlock 58c5950 JUMP test in assembly bb19540 Cleanup Compiler b273b86 Provide end instruction to basic block 16ea3bf Improve basic blocks linking implementation 7a3f3f9 Remove external stack 1cbb9d5 Stack cleanups a338b88 Cleanups: move basic block linking to separated function 577438e Correct the order of basic blocks e52d421 Link basic blocks with phi functions 0961908 Introducing BasicBlock class. cc51bfd Pop entry state of basic block from external stack, push exit state to external stack. 33e36ce Basic stack implementation for basic block. Values on stack are not preserved between basic blocks (jumps) 3cba3a2 SHA3 instruction f230c82 SUICIDE instruction 3f57858 CALL instruction. Still needs gas counting and callback support. 3942b2e CREATE instruction. Still needs some work with ExtVM interface. a1a195b Merge branch 'develop-evmcc' of github.com:imapp-pl/ethereum into develop-evmcc f075b7b - fixes for RETURN and STOP - codegen for SLT, SGT, EQ and NEG b519b73 Stack functions simplified 7bee86a Runtime class that inits and keeps stack, memory and ExtVM interface 320add0 BYTE instruction implementation (with bug on BYTE 0) 710b734 TODO: implement BYTE 48897f4 Bitwise operators: AND, OR, XOR c002d9b PC instructions 20cd698 Merge branch 'develop-evmcc' of https://github.com/imapp-pl/ethereum into develop-evmcc 09a9f10 Block Information instructions: PREVHASH, COINBASE, TIMESTAMP, NUMBER, DIFFICULTY, GASLIMIT 9289508 Merge branch 'develop-evmcc' of github.com:imapp-pl/ethereum into develop-evmcc 48d4294 - implemented LT, GT - new tests for jumps and comparisons 954300f Merge branch 'develop-evmcc' of https://github.com/imapp-pl/ethereum into develop-evmcc fbe97fd BALANCE 8b625fa fixed implementation of NOT fa76d7a fixes for JUMP/JUMPI (generating final basic block) implementation of NOT ad2c4c4 fixed implementation of JUMPI (cond casted to bool) 1d17da1 Added Module* constructor argument to Memory and Ext. b730bdc Merge branch 'develop-evmcc' of github.com:imapp-pl/ethereum into develop-evmcc 0b8ba6d initial implementation of JUMP/JUMPI (untested) edf192b Print returned memory to standard output d073af7 Merge branch 'develop-evmcc' of https://github.com/imapp-pl/ethereum into develop-evmcc 748ee0f Implementing RETURN and STOP instructions eea755c fixed bug in memory handling e1abb20 Merge branch 'develop-evmcc' of github.com:imapp-pl/ethereum into develop-evmcc 00f9939 Implemented MLOAD, MSTORE, MSTORE8 and MSIZE b9cda13 Push call data on stack - CALLDATALOAD fcde2f3 Accessing Ext static data: CALLER, ORIGIN, CALLVALUE, CALLDATASIZE, GASPRICE ac795c4 Send Ext static data to running contract. ADDRESS instruction 9ba6a7c Improve stack binary interface 8cd4326 Set/get values in Ext store - SSTORE & SLOAD 0013656 added ethcore to libs required by evmcc 15b9452 Merge branch 'develop-evmcc' of git@github.com:imapp-pl/ethereum.git into develop-evmcc 68f15f9 initial implementation of memory f3a347b Starting ExtVM binary interface 78b188c Fix stack set/get bad function signature 58e03d5 Basic arithmetic, limited precision for MUL, DIV and MOD. e53c0a4 SWAP* instructions 3e01d18 POP and DUP* instructions 4266ce5 PUSH instruction implementation d8430db Output compilation (option -c) result to standard output by default e8ff67c Stack interface and implementation bbc3aa4 evmcc's CMakeLists updated: * added std=c++14 for gcc (required for std::make_unique) * added required llvm libnames dfa141a Staring with Stack helper f124be6 Implementation of ExecutionEngine with LLVM MCJIT e33fdea Remove public LLVM dependency in Compiler 507ba06 ExecutionEngine stub and -i program option for interpreting EVM Code f5eda1f Moving Compiler to separated files REVERT: 334deeb Initial commit git-subtree-dir: evmjit git-subtree-split: 533531bd07cb2d95f3fa017231484e91196d87a6 --- .gitignore | 28 - CMakeLists.txt | 27 + LICENSE | 22 - evmcc/CMakeLists.txt | 18 + evmcc/evmcc.cpp | 211 ++++ evmcc/test/arith/addmod.evm | 1 + evmcc/test/arith/addmod.lll | 12 + evmcc/test/arith/arith1.evm | 1 + evmcc/test/arith/arith1.lll | 37 + evmcc/test/arith/arith_bnot.evm | 1 + evmcc/test/arith/arith_bnot.lll | 14 + evmcc/test/arith/div.evm | 1 + evmcc/test/arith/div.lll | 10 + evmcc/test/arith/fib1.evm | 1 + evmcc/test/arith/fib1.lll | 57 ++ evmcc/test/arith/mul.evm | 1 + evmcc/test/arith/mul.lll | 13 + evmcc/test/arith/mulmod.evm | 1 + evmcc/test/arith/mulmod.lll | 12 + evmcc/test/except/badinst1.evm | 1 + evmcc/test/ext/calldatacopy1.evm | 1 + evmcc/test/ext/calldatacopy1.lll | 13 + evmcc/test/ext/calldatacopy2.evm | 1 + evmcc/test/ext/calldatacopy2.lll | 13 + evmcc/test/ext/codecopy1.evm | 1 + evmcc/test/ext/codecopy1.lll | 13 + evmcc/test/ext/codecopy2.evm | 1 + evmcc/test/ext/codecopy2.lll | 13 + evmcc/test/ext/codecopy3.evm | 1 + evmcc/test/ext/codecopy3.lll | 13 + evmcc/test/ext/ext_test.evm | 1 + evmcc/test/ext/ext_test.lll | 55 + evmcc/test/ext/extcodecopy1.evm | 1 + evmcc/test/ext/extcodecopy1.lll | 11 + evmcc/test/ext/store_delete.evm | 1 + evmcc/test/ext/store_delete.lll | 9 + evmcc/test/ext/store_test.evm | 1 + evmcc/test/ext/store_test.lll | 14 + evmcc/test/jump/ackermann.ethel | 7 + evmcc/test/jump/ackermann.evm | 1 + evmcc/test/jump/badindirect1.evm | 1 + evmcc/test/jump/badindirect1.lll | 9 + evmcc/test/jump/badindirect2.evm | 1 + evmcc/test/jump/badindirect2.lll | 12 + evmcc/test/jump/badjump1.evm | 1 + evmcc/test/jump/badjump1.lll | 6 + evmcc/test/jump/badjump2.evm | 1 + evmcc/test/jump/badjump2.lll | 9 + evmcc/test/jump/call1.ethel | 5 + evmcc/test/jump/call1.evm | 1 + evmcc/test/jump/call2.ethel | 5 + evmcc/test/jump/call2.evm | 1 + evmcc/test/jump/fac.ethel | 5 + evmcc/test/jump/fac.evm | 1 + evmcc/test/jump/fac_tail.ethel | 5 + evmcc/test/jump/fac_tail.evm | 1 + evmcc/test/jump/fib1.ethel | 6 + evmcc/test/jump/fib1.evm | 1 + evmcc/test/jump/for1.evm | 1 + evmcc/test/jump/for1.lll | 3 + evmcc/test/jump/for2.evm | 1 + evmcc/test/jump/for2.lll | 3 + evmcc/test/jump/if1.ethel | 1 + evmcc/test/jump/if1.evm | 1 + evmcc/test/jump/if2.ethel | 1 + evmcc/test/jump/if2.evm | 1 + evmcc/test/jump/indirect1.evm | 1 + evmcc/test/jump/indirect1.lll | 13 + evmcc/test/jump/indirect2.evm | 1 + evmcc/test/jump/indirect2.lll | 19 + evmcc/test/jump/indirect3.evm | 1 + evmcc/test/jump/indirect3.lll | 14 + evmcc/test/jump/indirect4.evm | 1 + evmcc/test/jump/indirect4.lll | 15 + evmcc/test/jump/jump1.evm | 1 + evmcc/test/jump/jump1.lll | 11 + evmcc/test/jump/jump2.evm | 1 + evmcc/test/jump/jump2.lll | 10 + evmcc/test/jump/jump3.evm | 1 + evmcc/test/jump/jump3.lll | 10 + evmcc/test/jump/jump4.evm | 1 + evmcc/test/jump/jump4.lll | 17 + evmcc/test/jump/jump5.evm | 1 + evmcc/test/jump/jump5.lll | 16 + evmcc/test/jump/jump6.evm | 1 + evmcc/test/jump/jump6.lll | 32 + evmcc/test/jump/jumpi_at_the_end.evm | 1 + evmcc/test/jump/jumpi_at_the_end.lll | 1 + evmcc/test/jump/loop1.evm | 1 + evmcc/test/jump/loop1.lll | 27 + evmcc/test/jump/loop2.evm | 1 + evmcc/test/jump/loop2.lll | 28 + evmcc/test/jump/rec1.ethel | 4 + evmcc/test/jump/rec1.evm | 1 + evmcc/test/jump/when1.asm | 10 + evmcc/test/jump/when1.evm | 1 + evmcc/test/jump/when1.lll | 2 + evmcc/test/kv.evm | 1 + evmcc/test/kv.lll | 10 + evmcc/test/mem/byte.evm | 1 + evmcc/test/mem/byte.lll | 105 ++ evmcc/test/mem/mem2.evm | 1 + evmcc/test/mem/mem2.lll | 15 + evmcc/test/mem/memtest1.evm | 1 + evmcc/test/mem/memtest1.lll | 18 + evmcc/test/mem/mstore1.evm | 1 + evmcc/test/mem/mstore1.lll | 6 + evmcc/test/ret/return1.evm | 1 + evmcc/test/ret/return1.lll | 6 + evmcc/test/ret/return2.evm | 1 + evmcc/test/ret/return2.lll | 6 + evmcc/test/ret/return_test.evm | 1 + evmcc/test/ret/return_test.lll | 15 + evmcc/test/stack/oos.evm | 1 + evmcc/test/stack/oos.lll | 11 + evmcc/test/stack/push_test.evm | 1 + evmcc/test/stack/push_test.lll | 35 + evmcc/test/stack/stack_test.evm | 1 + evmcc/test/stack/stack_test.lll | 8 + evmcc/test/stack/stackjump.evm | 1 + evmcc/test/stack/stackjump.lll | 3 + evmcc/test/stack/swap.evm | 1 + evmcc/test/stack/swap.lll | 31 + evmcc/test/stack/swapswap.evm | 1 + evmcc/test/stack/swapswap.lll | 32 + evmcc/test/stack/test.evm | 1 + .../test/vmtests/vmArithPerformanceTest.json | 260 +++++ evmcc/test/vmtests/vmPerformanceTest.json | 214 ++++ evmcc/test/vmtests/vm_jump.json | 41 + libevmjit-cpp/CMakeLists.txt | 16 + libevmjit-cpp/Env.cpp | 125 +++ libevmjit-cpp/JitVM.cpp | 69 ++ libevmjit-cpp/JitVM.h | 28 + libevmjit/Arith256.cpp | 194 ++++ libevmjit/Arith256.h | 49 + libevmjit/BasicBlock.cpp | 380 +++++++ libevmjit/BasicBlock.h | 117 +++ libevmjit/CMakeLists.txt | 24 + libevmjit/Cache.cpp | 60 ++ libevmjit/Cache.h | 41 + libevmjit/Common.h | 49 + libevmjit/Compiler.cpp | 949 ++++++++++++++++++ libevmjit/Compiler.h | 91 ++ libevmjit/CompilerHelper.cpp | 46 + libevmjit/CompilerHelper.h | 83 ++ libevmjit/Endianness.cpp | 38 + libevmjit/Endianness.h | 24 + libevmjit/ExecutionEngine.cpp | 127 +++ libevmjit/ExecutionEngine.h | 26 + libevmjit/Ext.cpp | 178 ++++ libevmjit/Ext.h | 69 ++ libevmjit/GasMeter.cpp | 222 ++++ libevmjit/GasMeter.h | 64 ++ libevmjit/Instruction.h | 235 +++++ libevmjit/Memory.cpp | 237 +++++ libevmjit/Memory.h | 46 + libevmjit/Runtime.cpp | 52 + libevmjit/Runtime.h | 62 ++ libevmjit/RuntimeData.h | 52 + libevmjit/RuntimeManager.cpp | 199 ++++ libevmjit/RuntimeManager.h | 51 + libevmjit/Stack.cpp | 133 +++ libevmjit/Stack.h | 43 + libevmjit/Type.cpp | 67 ++ libevmjit/Type.h | 54 + libevmjit/Utils.cpp | 66 ++ libevmjit/Utils.h | 24 + libevmjit/interface.c | 30 + 168 files changed, 6168 insertions(+), 50 deletions(-) delete mode 100644 .gitignore create mode 100644 CMakeLists.txt delete mode 100644 LICENSE create mode 100644 evmcc/CMakeLists.txt create mode 100644 evmcc/evmcc.cpp create mode 100644 evmcc/test/arith/addmod.evm create mode 100644 evmcc/test/arith/addmod.lll create mode 100644 evmcc/test/arith/arith1.evm create mode 100644 evmcc/test/arith/arith1.lll create mode 100644 evmcc/test/arith/arith_bnot.evm create mode 100644 evmcc/test/arith/arith_bnot.lll create mode 100644 evmcc/test/arith/div.evm create mode 100644 evmcc/test/arith/div.lll create mode 100644 evmcc/test/arith/fib1.evm create mode 100644 evmcc/test/arith/fib1.lll create mode 100644 evmcc/test/arith/mul.evm create mode 100644 evmcc/test/arith/mul.lll create mode 100644 evmcc/test/arith/mulmod.evm create mode 100644 evmcc/test/arith/mulmod.lll create mode 100644 evmcc/test/except/badinst1.evm create mode 100644 evmcc/test/ext/calldatacopy1.evm create mode 100644 evmcc/test/ext/calldatacopy1.lll create mode 100644 evmcc/test/ext/calldatacopy2.evm create mode 100644 evmcc/test/ext/calldatacopy2.lll create mode 100644 evmcc/test/ext/codecopy1.evm create mode 100644 evmcc/test/ext/codecopy1.lll create mode 100644 evmcc/test/ext/codecopy2.evm create mode 100644 evmcc/test/ext/codecopy2.lll create mode 100644 evmcc/test/ext/codecopy3.evm create mode 100644 evmcc/test/ext/codecopy3.lll create mode 100644 evmcc/test/ext/ext_test.evm create mode 100644 evmcc/test/ext/ext_test.lll create mode 100644 evmcc/test/ext/extcodecopy1.evm create mode 100644 evmcc/test/ext/extcodecopy1.lll create mode 100644 evmcc/test/ext/store_delete.evm create mode 100644 evmcc/test/ext/store_delete.lll create mode 100644 evmcc/test/ext/store_test.evm create mode 100644 evmcc/test/ext/store_test.lll create mode 100644 evmcc/test/jump/ackermann.ethel create mode 100644 evmcc/test/jump/ackermann.evm create mode 100644 evmcc/test/jump/badindirect1.evm create mode 100644 evmcc/test/jump/badindirect1.lll create mode 100644 evmcc/test/jump/badindirect2.evm create mode 100644 evmcc/test/jump/badindirect2.lll create mode 100644 evmcc/test/jump/badjump1.evm create mode 100644 evmcc/test/jump/badjump1.lll create mode 100644 evmcc/test/jump/badjump2.evm create mode 100644 evmcc/test/jump/badjump2.lll create mode 100644 evmcc/test/jump/call1.ethel create mode 100644 evmcc/test/jump/call1.evm create mode 100644 evmcc/test/jump/call2.ethel create mode 100644 evmcc/test/jump/call2.evm create mode 100644 evmcc/test/jump/fac.ethel create mode 100644 evmcc/test/jump/fac.evm create mode 100644 evmcc/test/jump/fac_tail.ethel create mode 100644 evmcc/test/jump/fac_tail.evm create mode 100644 evmcc/test/jump/fib1.ethel create mode 100644 evmcc/test/jump/fib1.evm create mode 100644 evmcc/test/jump/for1.evm create mode 100644 evmcc/test/jump/for1.lll create mode 100644 evmcc/test/jump/for2.evm create mode 100644 evmcc/test/jump/for2.lll create mode 100644 evmcc/test/jump/if1.ethel create mode 100644 evmcc/test/jump/if1.evm create mode 100644 evmcc/test/jump/if2.ethel create mode 100644 evmcc/test/jump/if2.evm create mode 100644 evmcc/test/jump/indirect1.evm create mode 100644 evmcc/test/jump/indirect1.lll create mode 100644 evmcc/test/jump/indirect2.evm create mode 100644 evmcc/test/jump/indirect2.lll create mode 100644 evmcc/test/jump/indirect3.evm create mode 100644 evmcc/test/jump/indirect3.lll create mode 100644 evmcc/test/jump/indirect4.evm create mode 100644 evmcc/test/jump/indirect4.lll create mode 100644 evmcc/test/jump/jump1.evm create mode 100644 evmcc/test/jump/jump1.lll create mode 100644 evmcc/test/jump/jump2.evm create mode 100644 evmcc/test/jump/jump2.lll create mode 100644 evmcc/test/jump/jump3.evm create mode 100644 evmcc/test/jump/jump3.lll create mode 100644 evmcc/test/jump/jump4.evm create mode 100644 evmcc/test/jump/jump4.lll create mode 100644 evmcc/test/jump/jump5.evm create mode 100644 evmcc/test/jump/jump5.lll create mode 100644 evmcc/test/jump/jump6.evm create mode 100644 evmcc/test/jump/jump6.lll create mode 100644 evmcc/test/jump/jumpi_at_the_end.evm create mode 100644 evmcc/test/jump/jumpi_at_the_end.lll create mode 100644 evmcc/test/jump/loop1.evm create mode 100644 evmcc/test/jump/loop1.lll create mode 100644 evmcc/test/jump/loop2.evm create mode 100644 evmcc/test/jump/loop2.lll create mode 100644 evmcc/test/jump/rec1.ethel create mode 100644 evmcc/test/jump/rec1.evm create mode 100644 evmcc/test/jump/when1.asm create mode 100644 evmcc/test/jump/when1.evm create mode 100644 evmcc/test/jump/when1.lll create mode 100644 evmcc/test/kv.evm create mode 100644 evmcc/test/kv.lll create mode 100644 evmcc/test/mem/byte.evm create mode 100644 evmcc/test/mem/byte.lll create mode 100644 evmcc/test/mem/mem2.evm create mode 100644 evmcc/test/mem/mem2.lll create mode 100644 evmcc/test/mem/memtest1.evm create mode 100644 evmcc/test/mem/memtest1.lll create mode 100644 evmcc/test/mem/mstore1.evm create mode 100644 evmcc/test/mem/mstore1.lll create mode 100644 evmcc/test/ret/return1.evm create mode 100644 evmcc/test/ret/return1.lll create mode 100644 evmcc/test/ret/return2.evm create mode 100644 evmcc/test/ret/return2.lll create mode 100644 evmcc/test/ret/return_test.evm create mode 100644 evmcc/test/ret/return_test.lll create mode 100644 evmcc/test/stack/oos.evm create mode 100644 evmcc/test/stack/oos.lll create mode 100644 evmcc/test/stack/push_test.evm create mode 100644 evmcc/test/stack/push_test.lll create mode 100644 evmcc/test/stack/stack_test.evm create mode 100644 evmcc/test/stack/stack_test.lll create mode 100644 evmcc/test/stack/stackjump.evm create mode 100644 evmcc/test/stack/stackjump.lll create mode 100644 evmcc/test/stack/swap.evm create mode 100644 evmcc/test/stack/swap.lll create mode 100644 evmcc/test/stack/swapswap.evm create mode 100644 evmcc/test/stack/swapswap.lll create mode 100644 evmcc/test/stack/test.evm create mode 100644 evmcc/test/vmtests/vmArithPerformanceTest.json create mode 100644 evmcc/test/vmtests/vmPerformanceTest.json create mode 100644 evmcc/test/vmtests/vm_jump.json create mode 100644 libevmjit-cpp/CMakeLists.txt create mode 100644 libevmjit-cpp/Env.cpp create mode 100644 libevmjit-cpp/JitVM.cpp create mode 100644 libevmjit-cpp/JitVM.h create mode 100644 libevmjit/Arith256.cpp create mode 100644 libevmjit/Arith256.h create mode 100644 libevmjit/BasicBlock.cpp create mode 100644 libevmjit/BasicBlock.h create mode 100644 libevmjit/CMakeLists.txt create mode 100644 libevmjit/Cache.cpp create mode 100644 libevmjit/Cache.h create mode 100644 libevmjit/Common.h create mode 100644 libevmjit/Compiler.cpp create mode 100644 libevmjit/Compiler.h create mode 100644 libevmjit/CompilerHelper.cpp create mode 100644 libevmjit/CompilerHelper.h create mode 100644 libevmjit/Endianness.cpp create mode 100644 libevmjit/Endianness.h create mode 100644 libevmjit/ExecutionEngine.cpp create mode 100644 libevmjit/ExecutionEngine.h create mode 100644 libevmjit/Ext.cpp create mode 100644 libevmjit/Ext.h create mode 100644 libevmjit/GasMeter.cpp create mode 100644 libevmjit/GasMeter.h create mode 100644 libevmjit/Instruction.h create mode 100644 libevmjit/Memory.cpp create mode 100644 libevmjit/Memory.h create mode 100644 libevmjit/Runtime.cpp create mode 100644 libevmjit/Runtime.h create mode 100644 libevmjit/RuntimeData.h create mode 100644 libevmjit/RuntimeManager.cpp create mode 100644 libevmjit/RuntimeManager.h create mode 100644 libevmjit/Stack.cpp create mode 100644 libevmjit/Stack.h create mode 100644 libevmjit/Type.cpp create mode 100644 libevmjit/Type.h create mode 100644 libevmjit/Utils.cpp create mode 100644 libevmjit/Utils.h create mode 100644 libevmjit/interface.c diff --git a/.gitignore b/.gitignore deleted file mode 100644 index b8bd0267b..000000000 --- a/.gitignore +++ /dev/null @@ -1,28 +0,0 @@ -# Compiled Object files -*.slo -*.lo -*.o -*.obj - -# Precompiled Headers -*.gch -*.pch - -# Compiled Dynamic libraries -*.so -*.dylib -*.dll - -# Fortran module files -*.mod - -# Compiled Static libraries -*.lai -*.la -*.a -*.lib - -# Executables -*.exe -*.out -*.app diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 000000000..26a8010d1 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,27 @@ +cmake_minimum_required(VERSION 2.8.12) + +project(evmjit) + +set_property(GLOBAL PROPERTY USE_FOLDERS ON) + +# LLVM +if(LLVM_DIR) # local LLVM build + find_package(LLVM REQUIRED CONFIG) + message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") + message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") + # TODO: bitwriter is needed only for evmcc + llvm_map_components_to_libnames(LLVM_LIBS core support mcjit x86asmparser x86codegen bitwriter) +else() + # Workaround for Ubuntu broken LLVM package + message(STATUS "Using llvm-3.5-dev package from Ubuntu. If does not work, build LLVM and set -DLLVM_DIR=llvm-build/share/llvm/cmake") + execute_process(COMMAND llvm-config-3.5 --includedir OUTPUT_VARIABLE LLVM_INCLUDE_DIRS) + message(STATUS "LLVM include dirs: ${LLVM_INCLUDE_DIRS}") + set(LLVM_LIBS "-lLLVMBitWriter -lLLVMX86CodeGen -lLLVMSelectionDAG -lLLVMAsmPrinter -lLLVMCodeGen -lLLVMScalarOpts -lLLVMInstCombine -lLLVMTransformUtils -lLLVMipa -lLLVMAnalysis -lLLVMX86AsmParser -lLLVMX86Desc -lLLVMX86Info -lLLVMX86AsmPrinter -lLLVMX86Utils -lLLVMMCJIT -lLLVMTarget -lLLVMRuntimeDyld -lLLVMObject -lLLVMMCParser -lLLVMBitReader -lLLVMExecutionEngine -lLLVMMC -lLLVMCore -lLLVMSupport -lz -lpthread -lffi -ltinfo -ldl -lm") +endif() + +# Boost +find_package(Boost REQUIRED) + +add_subdirectory(libevmjit) +add_subdirectory(libevmjit-cpp) +add_subdirectory(evmcc) \ No newline at end of file diff --git a/LICENSE b/LICENSE deleted file mode 100644 index d7e0e57ac..000000000 --- a/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2014 - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - diff --git a/evmcc/CMakeLists.txt b/evmcc/CMakeLists.txt new file mode 100644 index 000000000..4ffbf5fb5 --- /dev/null +++ b/evmcc/CMakeLists.txt @@ -0,0 +1,18 @@ +set(TARGET_NAME evmcc) + +set(SOURCES + evmcc.cpp +) +source_group("" FILES ${SOURCES}) + +add_executable(${TARGET_NAME} ${SOURCES}) +set_property(TARGET ${TARGET_NAME} PROPERTY FOLDER "tools") + +include_directories(../..) +include_directories(${LLVM_INCLUDE_DIRS}) +include_directories(${Boost_INCLUDE_DIRS}) + +target_link_libraries(${TARGET_NAME} ethereum) +target_link_libraries(${TARGET_NAME} ${Boost_PROGRAM_OPTIONS_LIBRARIES}) + +install(TARGETS ${TARGET_NAME} DESTINATION bin ) \ No newline at end of file diff --git a/evmcc/evmcc.cpp b/evmcc/evmcc.cpp new file mode 100644 index 000000000..3c43ab78b --- /dev/null +++ b/evmcc/evmcc.cpp @@ -0,0 +1,211 @@ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + + +void parseProgramOptions(int _argc, char** _argv, boost::program_options::variables_map& _varMap) +{ + namespace opt = boost::program_options; + + opt::options_description explicitOpts("Allowed options"); + explicitOpts.add_options() + ("help,h", "show usage information") + ("compile,c", "compile the code to LLVM IR") + ("interpret,i", "compile the code to LLVM IR and execute") + ("gas,g", opt::value(), "set initial gas for execution") + ("disassemble,d", "dissassemble the code") + ("dump-cfg", "dump control flow graph to graphviz file") + ("dont-optimize", "turn off optimizations") + ("optimize-stack", "optimize stack use between basic blocks (default: on)") + ("rewrite-switch", "rewrite LLVM switch to branches (default: on)") + ("output-ll", opt::value(), "dump generated LLVM IR to file") + ("output-bc", opt::value(), "dump generated LLVM bitcode to file") + ("show-logs", "output LOG statements to stderr") + ("verbose,V", "enable verbose output"); + + opt::options_description implicitOpts("Input files"); + implicitOpts.add_options() + ("input-file", opt::value(), "input file"); + + opt::options_description allOpts(""); + allOpts.add(explicitOpts).add(implicitOpts); + + opt::positional_options_description inputOpts; + inputOpts.add("input-file", 1); + + const char* errorMsg = nullptr; + try + { + auto parser = opt::command_line_parser(_argc, _argv).options(allOpts).positional(inputOpts); + opt::store(parser.run(), _varMap); + opt::notify(_varMap); + } + catch (boost::program_options::error& err) + { + errorMsg = err.what(); + } + + if (!errorMsg && _varMap.count("input-file") == 0) + errorMsg = "missing input file name"; + + if (_varMap.count("disassemble") == 0 + && _varMap.count("compile") == 0 + && _varMap.count("interpret") == 0) + { + errorMsg = "at least one of -c, -i, -d is required"; + } + + if (errorMsg || _varMap.count("help")) + { + if (errorMsg) + std::cerr << "Error: " << errorMsg << std::endl; + + std::cout << "Usage: " << _argv[0] << " input-file " << std::endl + << explicitOpts << std::endl; + std::exit(errorMsg ? 1 : 0); + } +} + +int main(int argc, char** argv) +{ + llvm::sys::PrintStackTraceOnErrorSignal(); + llvm::PrettyStackTraceProgram X(argc, argv); + + boost::program_options::variables_map options; + parseProgramOptions(argc, argv, options); + + auto inputFile = options["input-file"].as(); + std::ifstream ifs(inputFile); + if (!ifs.is_open()) + { + std::cerr << "cannot open input file " << inputFile << std::endl; + exit(1); + } + + std::string src((std::istreambuf_iterator(ifs)), + (std::istreambuf_iterator())); + + boost::algorithm::trim(src); + + using namespace dev; + + bytes bytecode = fromHex(src); + + if (options.count("disassemble")) + { + std::string assembly = eth::disassemble(bytecode); + std::cout << assembly << std::endl; + } + + if (options.count("compile") || options.count("interpret")) + { + size_t initialGas = 10000; + + if (options.count("gas")) + initialGas = options["gas"].as(); + + auto compilationStartTime = std::chrono::high_resolution_clock::now(); + + eth::jit::Compiler::Options compilerOptions; + compilerOptions.dumpCFG = options.count("dump-cfg") > 0; + bool optimize = options.count("dont-optimize") == 0; + compilerOptions.optimizeStack = optimize || options.count("optimize-stack") > 0; + compilerOptions.rewriteSwitchToBranches = optimize || options.count("rewrite-switch") > 0; + + auto compiler = eth::jit::Compiler(compilerOptions); + auto module = compiler.compile(bytecode, "main"); + + auto compilationEndTime = std::chrono::high_resolution_clock::now(); + + module->dump(); + + if (options.count("output-ll")) + { + auto outputFile = options["output-ll"].as(); + std::ofstream ofs(outputFile); + if (!ofs.is_open()) + { + std::cerr << "cannot open output file " << outputFile << std::endl; + exit(1); + } + llvm::raw_os_ostream ros(ofs); + module->print(ros, nullptr); + ofs.close(); + } + + if (options.count("output-bc")) + { + auto outputFile = options["output-bc"].as(); + std::ofstream ofs(outputFile); + if (!ofs.is_open()) + { + std::cerr << "cannot open output file " << outputFile << std::endl; + exit(1); + } + llvm::raw_os_ostream ros(ofs); + llvm::WriteBitcodeToFile(module.get(), ros); + ros.flush(); + ofs.close(); + } + + if (options.count("verbose")) + { + std::cerr << "*** Compilation time: " + << std::chrono::duration_cast(compilationEndTime - compilationStartTime).count() + << std::endl; + } + + if (options.count("interpret")) + { + using namespace eth::jit; + + ExecutionEngine engine; + eth::jit::u256 gas = initialGas; + + // Create random runtime data + RuntimeData data; + data.set(RuntimeData::Gas, gas); + data.set(RuntimeData::Address, (u160)Address(1122334455667788)); + data.set(RuntimeData::Caller, (u160)Address(0xfacefacefaceface)); + data.set(RuntimeData::Origin, (u160)Address(101010101010101010)); + data.set(RuntimeData::CallValue, 0xabcd); + data.set(RuntimeData::CallDataSize, 3); + data.set(RuntimeData::GasPrice, 1003); + data.set(RuntimeData::PrevHash, 1003); + data.set(RuntimeData::CoinBase, (u160)Address(101010101010101015)); + data.set(RuntimeData::TimeStamp, 1005); + data.set(RuntimeData::Number, 1006); + data.set(RuntimeData::Difficulty, 16); + data.set(RuntimeData::GasLimit, 1008); + data.set(RuntimeData::CodeSize, bytecode.size()); + data.callData = (uint8_t*)"abc"; + data.code = bytecode.data(); + + // BROKEN: env_* functions must be implemented & RuntimeData struct created + // TODO: Do not compile module again + auto result = engine.run(bytecode, &data, nullptr); + return static_cast(result); + } + } + + return 0; +} diff --git a/evmcc/test/arith/addmod.evm b/evmcc/test/arith/addmod.evm new file mode 100644 index 000000000..4ca71e065 --- /dev/null +++ b/evmcc/test/arith/addmod.evm @@ -0,0 +1 @@ +60646107b760271460005560006001f2 diff --git a/evmcc/test/arith/addmod.lll b/evmcc/test/arith/addmod.lll new file mode 100644 index 000000000..11a6b2cb9 --- /dev/null +++ b/evmcc/test/arith/addmod.lll @@ -0,0 +1,12 @@ +;; Should return (1975 + 39) `mod` 100 = 14 = 0x0e +(asm +100 +1975 +39 +ADDMOD +0 +MSTORE8 +0 +1 +RETURN +) \ No newline at end of file diff --git a/evmcc/test/arith/arith1.evm b/evmcc/test/arith/arith1.evm new file mode 100644 index 000000000..c7a029f52 --- /dev/null +++ b/evmcc/test/arith/arith1.evm @@ -0,0 +1 @@ +60016001900160070260050160029004600490066021900560150160030260059007600303600960110860005460086000f2 diff --git a/evmcc/test/arith/arith1.lll b/evmcc/test/arith/arith1.lll new file mode 100644 index 000000000..4757a7420 --- /dev/null +++ b/evmcc/test/arith/arith1.lll @@ -0,0 +1,37 @@ + +(asm +1 +1 +SWAP1 +ADD ;; 2 +7 +MUL ;; 14 +5 +ADD ;; 19 +2 +SWAP1 +DIV ;; 9 +4 +SWAP1 +MOD ;; 1 +33 +SWAP1 +SDIV;; 0 +21 +ADD ;; 21 +3 +MUL ;; 63 +5 +SWAP1 +SMOD;; 3 +3 +SUB ;; 0 +9 +17 +EXP ;; 17^9 +0 +MSTORE +8 +0 +RETURN +) \ No newline at end of file diff --git a/evmcc/test/arith/arith_bnot.evm b/evmcc/test/arith/arith_bnot.evm new file mode 100644 index 000000000..4cfaf8f55 --- /dev/null +++ b/evmcc/test/arith/arith_bnot.evm @@ -0,0 +1 @@ +6201e2406000546000530960005460206000f2 diff --git a/evmcc/test/arith/arith_bnot.lll b/evmcc/test/arith/arith_bnot.lll new file mode 100644 index 000000000..a83b05a9a --- /dev/null +++ b/evmcc/test/arith/arith_bnot.lll @@ -0,0 +1,14 @@ + +(asm +123456 +0 +MSTORE +0 +MLOAD +BNOT +0 +MSTORE +32 +0 +RETURN +) \ No newline at end of file diff --git a/evmcc/test/arith/div.evm b/evmcc/test/arith/div.evm new file mode 100644 index 000000000..b68d5d202 --- /dev/null +++ b/evmcc/test/arith/div.evm @@ -0,0 +1 @@ +60027ffedcba9876543210fedcba9876543210fedcba9876543210fedcba98765432100460005460206000f2 diff --git a/evmcc/test/arith/div.lll b/evmcc/test/arith/div.lll new file mode 100644 index 000000000..72c22bfdc --- /dev/null +++ b/evmcc/test/arith/div.lll @@ -0,0 +1,10 @@ +(asm +0x2 +0xfedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210 +DIV +0 +MSTORE +32 +0 +RETURN +) diff --git a/evmcc/test/arith/fib1.evm b/evmcc/test/arith/fib1.evm new file mode 100644 index 000000000..4c141314e --- /dev/null +++ b/evmcc/test/arith/fib1.evm @@ -0,0 +1 @@ +60016001818101818101818101818101818101818101818101818101818101818101818101818101818101818101818101818101818101 diff --git a/evmcc/test/arith/fib1.lll b/evmcc/test/arith/fib1.lll new file mode 100644 index 000000000..286bed275 --- /dev/null +++ b/evmcc/test/arith/fib1.lll @@ -0,0 +1,57 @@ +;; Fibbonacci unrolled + +(asm +1 +1 +DUP2 +DUP2 +ADD +DUP2 +DUP2 +ADD +DUP2 +DUP2 +ADD +DUP2 +DUP2 +ADD +DUP2 +DUP2 +ADD +DUP2 +DUP2 +ADD +DUP2 +DUP2 +ADD +DUP2 +DUP2 +ADD +DUP2 +DUP2 +ADD +DUP2 +DUP2 +ADD +DUP2 +DUP2 +ADD +DUP2 +DUP2 +ADD +DUP2 +DUP2 +ADD +DUP2 +DUP2 +ADD +DUP2 +DUP2 +ADD +DUP2 +DUP2 +ADD +DUP2 +DUP2 +ADD +) \ No newline at end of file diff --git a/evmcc/test/arith/mul.evm b/evmcc/test/arith/mul.evm new file mode 100644 index 000000000..7e8afd268 --- /dev/null +++ b/evmcc/test/arith/mul.evm @@ -0,0 +1 @@ +7001234567890abcdef0fedcba09876543217001234567890abcdef0fedcba09876543217001234567890abcdef0fedcba0987654321020260005460206000f2 diff --git a/evmcc/test/arith/mul.lll b/evmcc/test/arith/mul.lll new file mode 100644 index 000000000..b0fa343bb --- /dev/null +++ b/evmcc/test/arith/mul.lll @@ -0,0 +1,13 @@ +(asm +0x1234567890abcdef0fedcba0987654321 +0x1234567890abcdef0fedcba0987654321 +0x1234567890abcdef0fedcba0987654321 +MUL +MUL +0 +MSTORE +32 +0 +RETURN +;; 47d0817e4167b1eb4f9fc722b133ef9d7d9a6fb4c2c1c442d000107a5e419561 +) diff --git a/evmcc/test/arith/mulmod.evm b/evmcc/test/arith/mulmod.evm new file mode 100644 index 000000000..e34a06154 --- /dev/null +++ b/evmcc/test/arith/mulmod.evm @@ -0,0 +1 @@ +6064601b60251560005560006001f2 diff --git a/evmcc/test/arith/mulmod.lll b/evmcc/test/arith/mulmod.lll new file mode 100644 index 000000000..5e87f0843 --- /dev/null +++ b/evmcc/test/arith/mulmod.lll @@ -0,0 +1,12 @@ +;; Should return (27 * 37) `mod` 100 = 99 = 0x63 +(asm +100 +27 +37 +MULMOD +0 +MSTORE8 +0 +1 +RETURN +) \ No newline at end of file diff --git a/evmcc/test/except/badinst1.evm b/evmcc/test/except/badinst1.evm new file mode 100644 index 000000000..69aadac5e --- /dev/null +++ b/evmcc/test/except/badinst1.evm @@ -0,0 +1 @@ +4a diff --git a/evmcc/test/ext/calldatacopy1.evm b/evmcc/test/ext/calldatacopy1.evm new file mode 100644 index 000000000..f20019651 --- /dev/null +++ b/evmcc/test/ext/calldatacopy1.evm @@ -0,0 +1 @@ +60326000600a37600053600a6014f2 diff --git a/evmcc/test/ext/calldatacopy1.lll b/evmcc/test/ext/calldatacopy1.lll new file mode 100644 index 000000000..3d2ae0a78 --- /dev/null +++ b/evmcc/test/ext/calldatacopy1.lll @@ -0,0 +1,13 @@ +(asm +50 ;; byte count +0 ;; source index in calldata array +10 ;; dest index in memory +CALLDATACOPY + +0 +MLOAD ;; to dump memory + +10 +20 +RETURN +) \ No newline at end of file diff --git a/evmcc/test/ext/calldatacopy2.evm b/evmcc/test/ext/calldatacopy2.evm new file mode 100644 index 000000000..e8eea8da7 --- /dev/null +++ b/evmcc/test/ext/calldatacopy2.evm @@ -0,0 +1 @@ +606464e8d4a510006000376000536000600af2 diff --git a/evmcc/test/ext/calldatacopy2.lll b/evmcc/test/ext/calldatacopy2.lll new file mode 100644 index 000000000..6bbea48d8 --- /dev/null +++ b/evmcc/test/ext/calldatacopy2.lll @@ -0,0 +1,13 @@ +(asm +100 ;; byte count +1000000000000 ;; source index in calldata array +0 ;; dest index in memory +CALLDATACOPY + +0 +MLOAD ;; to dump memory + +0 +10 +RETURN +) \ No newline at end of file diff --git a/evmcc/test/ext/codecopy1.evm b/evmcc/test/ext/codecopy1.evm new file mode 100644 index 000000000..d286f9232 --- /dev/null +++ b/evmcc/test/ext/codecopy1.evm @@ -0,0 +1 @@ +60146000600a39600053600a6014f2 diff --git a/evmcc/test/ext/codecopy1.lll b/evmcc/test/ext/codecopy1.lll new file mode 100644 index 000000000..85a02b5d7 --- /dev/null +++ b/evmcc/test/ext/codecopy1.lll @@ -0,0 +1,13 @@ +(asm +20 ;; byte count +0 ;; source index in code array +10 ;; dest index in memory +CODECOPY + +0 +MLOAD ;; to dump memory + +10 +20 +RETURN +) \ No newline at end of file diff --git a/evmcc/test/ext/codecopy2.evm b/evmcc/test/ext/codecopy2.evm new file mode 100644 index 000000000..71cd92525 --- /dev/null +++ b/evmcc/test/ext/codecopy2.evm @@ -0,0 +1 @@ +606464e8d4a510006000396000536000600af2 diff --git a/evmcc/test/ext/codecopy2.lll b/evmcc/test/ext/codecopy2.lll new file mode 100644 index 000000000..dcbbcaa46 --- /dev/null +++ b/evmcc/test/ext/codecopy2.lll @@ -0,0 +1,13 @@ +(asm +100 ;; byte count +1000000000000 ;; source index in code array +0 ;; dest index in memory +CODECOPY + +0 +MLOAD ;; to dump memory + +0 +10 +RETURN +) \ No newline at end of file diff --git a/evmcc/test/ext/codecopy3.evm b/evmcc/test/ext/codecopy3.evm new file mode 100644 index 000000000..e4b6a9253 --- /dev/null +++ b/evmcc/test/ext/codecopy3.evm @@ -0,0 +1 @@ +3860006000396000536000600af2 diff --git a/evmcc/test/ext/codecopy3.lll b/evmcc/test/ext/codecopy3.lll new file mode 100644 index 000000000..80d9982c6 --- /dev/null +++ b/evmcc/test/ext/codecopy3.lll @@ -0,0 +1,13 @@ +(asm +CODESIZE ;; byte count +0 ;; source index in code array +0 ;; dest index in memory +CODECOPY + +0 +MLOAD ;; to dump memory + +0 +10 +RETURN +) \ No newline at end of file diff --git a/evmcc/test/ext/ext_test.evm b/evmcc/test/ext/ext_test.evm new file mode 100644 index 000000000..580bd9675 --- /dev/null +++ b/evmcc/test/ext/ext_test.evm @@ -0,0 +1 @@ +5a3031333234363a4041424344455a36600035602635601335387f1111222233334444555566667777888899990000aaaabbbbccccddddeeeeffff600054602060006000f06020600060206000600030610bb8f1600053611000545b60200260002030ff60016002f2 diff --git a/evmcc/test/ext/ext_test.lll b/evmcc/test/ext/ext_test.lll new file mode 100644 index 000000000..3287ae95f --- /dev/null +++ b/evmcc/test/ext/ext_test.lll @@ -0,0 +1,55 @@ + +(asm +PC +ADDRESS +BALANCE +CALLER +ORIGIN +CALLVALUE +CALLDATASIZE +GASPRICE +PREVHASH +COINBASE +TIMESTAMP +NUMBER +DIFFICULTY +GASLIMIT +PC +CALLDATASIZE +0 +CALLDATALOAD +38 +CALLDATALOAD +19 +CALLDATALOAD +CODESIZE +0x1111222233334444555566667777888899990000aaaabbbbccccddddeeeeffff +0 +MSTORE +32 +0 +0 +CREATE +32 +0 +32 +0 +0 +ADDRESS +3000 +CALL +0 +MLOAD +4096 +MSTORE +MSIZE +32 +MUL +0 +SHA3 +ADDRESS +SUICIDE +1 +2 +RETURN +) \ No newline at end of file diff --git a/evmcc/test/ext/extcodecopy1.evm b/evmcc/test/ext/extcodecopy1.evm new file mode 100644 index 000000000..6132b52d8 --- /dev/null +++ b/evmcc/test/ext/extcodecopy1.evm @@ -0,0 +1 @@ +60c86000600a303c60005360006020f2 diff --git a/evmcc/test/ext/extcodecopy1.lll b/evmcc/test/ext/extcodecopy1.lll new file mode 100644 index 000000000..c37054574 --- /dev/null +++ b/evmcc/test/ext/extcodecopy1.lll @@ -0,0 +1,11 @@ +(asm +200 ;; byte count +0 ;; source index in code array +10 ;; dest index in memory +ADDRESS +EXTCODECOPY + +0 MLOAD ;; to dump memory + +0 32 RETURN +) \ No newline at end of file diff --git a/evmcc/test/ext/store_delete.evm b/evmcc/test/ext/store_delete.evm new file mode 100644 index 000000000..d6acae03d --- /dev/null +++ b/evmcc/test/ext/store_delete.evm @@ -0,0 +1 @@ +6104d26063576000606357 diff --git a/evmcc/test/ext/store_delete.lll b/evmcc/test/ext/store_delete.lll new file mode 100644 index 000000000..3d8f0f23a --- /dev/null +++ b/evmcc/test/ext/store_delete.lll @@ -0,0 +1,9 @@ + +(asm +1234 +99 +SSTORE +0 +99 +SSTORE +) \ No newline at end of file diff --git a/evmcc/test/ext/store_test.evm b/evmcc/test/ext/store_test.evm new file mode 100644 index 000000000..54c9419b5 --- /dev/null +++ b/evmcc/test/ext/store_test.evm @@ -0,0 +1 @@ +607b607c60015760005760015660005603 diff --git a/evmcc/test/ext/store_test.lll b/evmcc/test/ext/store_test.lll new file mode 100644 index 000000000..c40471c40 --- /dev/null +++ b/evmcc/test/ext/store_test.lll @@ -0,0 +1,14 @@ + +(asm +123 +124 +1 +SSTORE +0 +SSTORE +1 +SLOAD +0 +SLOAD +SUB +) \ No newline at end of file diff --git a/evmcc/test/jump/ackermann.ethel b/evmcc/test/jump/ackermann.ethel new file mode 100644 index 000000000..971fd2b8d --- /dev/null +++ b/evmcc/test/jump/ackermann.ethel @@ -0,0 +1,7 @@ +let A m n = + if m == 0 then n+1 + else if n == 0 then A (m-1) 1 + else A (m-1) (A (m) (n-1)) + +return A 3 8 + diff --git a/evmcc/test/jump/ackermann.evm b/evmcc/test/jump/ackermann.evm new file mode 100644 index 000000000..964844045 --- /dev/null +++ b/evmcc/test/jump/ackermann.evm @@ -0,0 +1 @@ +6009600360086012585d60005460206000f26000820e6047596000810e603859603460018303603084600185036012585d6012585d60445860436001830360016012585d604b5860018101905090509058 \ No newline at end of file diff --git a/evmcc/test/jump/badindirect1.evm b/evmcc/test/jump/badindirect1.evm new file mode 100644 index 000000000..b2a8aad67 --- /dev/null +++ b/evmcc/test/jump/badindirect1.evm @@ -0,0 +1 @@ +601b602502585d diff --git a/evmcc/test/jump/badindirect1.lll b/evmcc/test/jump/badindirect1.lll new file mode 100644 index 000000000..d6291be68 --- /dev/null +++ b/evmcc/test/jump/badindirect1.lll @@ -0,0 +1,9 @@ +;; Indirect jump out of code + +(asm +27 +37 +MUL +JUMP +JUMPDEST +) \ No newline at end of file diff --git a/evmcc/test/jump/badindirect2.evm b/evmcc/test/jump/badindirect2.evm new file mode 100644 index 000000000..22217523d --- /dev/null +++ b/evmcc/test/jump/badindirect2.evm @@ -0,0 +1 @@ +60016003600302596000600058 diff --git a/evmcc/test/jump/badindirect2.lll b/evmcc/test/jump/badindirect2.lll new file mode 100644 index 000000000..53a6294f7 --- /dev/null +++ b/evmcc/test/jump/badindirect2.lll @@ -0,0 +1,12 @@ +;; Indirect jump into data + +(asm +1 ;; 0 +3 +3 +MUL ;; 6 +JUMPI ;; 7 +0 ;; 8 +0 +JUMP +) \ No newline at end of file diff --git a/evmcc/test/jump/badjump1.evm b/evmcc/test/jump/badjump1.evm new file mode 100644 index 000000000..5c11a8661 --- /dev/null +++ b/evmcc/test/jump/badjump1.evm @@ -0,0 +1 @@ +6103e758 diff --git a/evmcc/test/jump/badjump1.lll b/evmcc/test/jump/badjump1.lll new file mode 100644 index 000000000..1834a62ef --- /dev/null +++ b/evmcc/test/jump/badjump1.lll @@ -0,0 +1,6 @@ +;; Direct jump out of code. + +(asm +999 +JUMP +) \ No newline at end of file diff --git a/evmcc/test/jump/badjump2.evm b/evmcc/test/jump/badjump2.evm new file mode 100644 index 000000000..900a1c15a --- /dev/null +++ b/evmcc/test/jump/badjump2.evm @@ -0,0 +1 @@ +6004586000600058 diff --git a/evmcc/test/jump/badjump2.lll b/evmcc/test/jump/badjump2.lll new file mode 100644 index 000000000..ce61276d7 --- /dev/null +++ b/evmcc/test/jump/badjump2.lll @@ -0,0 +1,9 @@ +;; Direct jump into data + +(asm +4 ;; 0 0-3 +JUMP ;; 2 +0 ;; 3 3-4 +0 ;; 5 4-7 +JUMP ;; 6 +) \ No newline at end of file diff --git a/evmcc/test/jump/call1.ethel b/evmcc/test/jump/call1.ethel new file mode 100644 index 000000000..414ad0124 --- /dev/null +++ b/evmcc/test/jump/call1.ethel @@ -0,0 +1,5 @@ +let f n = n + 1 + +return f 2 + + diff --git a/evmcc/test/jump/call1.evm b/evmcc/test/jump/call1.evm new file mode 100644 index 000000000..252aaf778 --- /dev/null +++ b/evmcc/test/jump/call1.evm @@ -0,0 +1 @@ +600760026010585d60005460206000f28060010190509058 \ No newline at end of file diff --git a/evmcc/test/jump/call2.ethel b/evmcc/test/jump/call2.ethel new file mode 100644 index 000000000..bdeb9b734 --- /dev/null +++ b/evmcc/test/jump/call2.ethel @@ -0,0 +1,5 @@ +let f a b = a + b + +return f 2 3 + + diff --git a/evmcc/test/jump/call2.evm b/evmcc/test/jump/call2.evm new file mode 100644 index 000000000..6832e044d --- /dev/null +++ b/evmcc/test/jump/call2.evm @@ -0,0 +1 @@ +6009600260036012585d60005460206000f2818101905090509058 \ No newline at end of file diff --git a/evmcc/test/jump/fac.ethel b/evmcc/test/jump/fac.ethel new file mode 100644 index 000000000..8bfe94dd6 --- /dev/null +++ b/evmcc/test/jump/fac.ethel @@ -0,0 +1,5 @@ +let fac n = + if n == 0 then 1 + else n * fac (n-1) + +return fac 60 \ No newline at end of file diff --git a/evmcc/test/jump/fac.evm b/evmcc/test/jump/fac.evm new file mode 100644 index 000000000..04cd3e4f4 --- /dev/null +++ b/evmcc/test/jump/fac.evm @@ -0,0 +1 @@ +6007603c6010585d60005460206000f26000810e6026596020600182036010585d8102602858600190509058 \ No newline at end of file diff --git a/evmcc/test/jump/fac_tail.ethel b/evmcc/test/jump/fac_tail.ethel new file mode 100644 index 000000000..9ce5ecac7 --- /dev/null +++ b/evmcc/test/jump/fac_tail.ethel @@ -0,0 +1,5 @@ +let fac a n = + if n == 0 then a + else fac (a*n) (n-1) + +return fac 1 60 \ No newline at end of file diff --git a/evmcc/test/jump/fac_tail.evm b/evmcc/test/jump/fac_tail.evm new file mode 100644 index 000000000..8384d94e4 --- /dev/null +++ b/evmcc/test/jump/fac_tail.evm @@ -0,0 +1 @@ +60096001603c6012585d60005460206000f26000810e6029596025818302600183036012585d602a5881905090509058 \ No newline at end of file diff --git a/evmcc/test/jump/fib1.ethel b/evmcc/test/jump/fib1.ethel new file mode 100644 index 000000000..81b869f41 --- /dev/null +++ b/evmcc/test/jump/fib1.ethel @@ -0,0 +1,6 @@ +let fib n = + if n < 3 then 1 + else fib (n-1) + fib (n-2) + +return fib 10 + diff --git a/evmcc/test/jump/fib1.evm b/evmcc/test/jump/fib1.evm new file mode 100644 index 000000000..5042a192f --- /dev/null +++ b/evmcc/test/jump/fib1.evm @@ -0,0 +1 @@ +6007600a6010585d60005460206000f26003810a602f596020600282036010585d602a600183036010585d01603158600190509058 \ No newline at end of file diff --git a/evmcc/test/jump/for1.evm b/evmcc/test/jump/for1.evm new file mode 100644 index 000000000..f8e65cbf2 --- /dev/null +++ b/evmcc/test/jump/for1.evm @@ -0,0 +1 @@ +600a60805460006080530b0f60255960a0536080530160a054600160805303608054600558 diff --git a/evmcc/test/jump/for1.lll b/evmcc/test/jump/for1.lll new file mode 100644 index 000000000..419fc9b54 --- /dev/null +++ b/evmcc/test/jump/for1.lll @@ -0,0 +1,3 @@ +(for [i]:10 (> @i 0) [i](- @i 1) + [j](+ @i @j) +) diff --git a/evmcc/test/jump/for2.evm b/evmcc/test/jump/for2.evm new file mode 100644 index 000000000..628297778 --- /dev/null +++ b/evmcc/test/jump/for2.evm @@ -0,0 +1 @@ +6000608054600a6080530a0f60255960a0536080530160a054600160805301608054600558 diff --git a/evmcc/test/jump/for2.lll b/evmcc/test/jump/for2.lll new file mode 100644 index 000000000..de17d65ac --- /dev/null +++ b/evmcc/test/jump/for2.lll @@ -0,0 +1,3 @@ +(for [i]:0 (< @i 10) [i](+ @i 1) + [j](+ @i @j) +) diff --git a/evmcc/test/jump/if1.ethel b/evmcc/test/jump/if1.ethel new file mode 100644 index 000000000..85c3e126b --- /dev/null +++ b/evmcc/test/jump/if1.ethel @@ -0,0 +1 @@ +return if 0 then 1 else 2 \ No newline at end of file diff --git a/evmcc/test/jump/if1.evm b/evmcc/test/jump/if1.evm new file mode 100644 index 000000000..51fbe04bd --- /dev/null +++ b/evmcc/test/jump/if1.evm @@ -0,0 +1 @@ +60006300000010596002630000001258600160005460206000f2 \ No newline at end of file diff --git a/evmcc/test/jump/if2.ethel b/evmcc/test/jump/if2.ethel new file mode 100644 index 000000000..2a58d6365 --- /dev/null +++ b/evmcc/test/jump/if2.ethel @@ -0,0 +1 @@ +return if 1 then 1 else 2 \ No newline at end of file diff --git a/evmcc/test/jump/if2.evm b/evmcc/test/jump/if2.evm new file mode 100644 index 000000000..6d823b374 --- /dev/null +++ b/evmcc/test/jump/if2.evm @@ -0,0 +1 @@ +60016300000010596002630000001258600160005460206000f2 \ No newline at end of file diff --git a/evmcc/test/jump/indirect1.evm b/evmcc/test/jump/indirect1.evm new file mode 100644 index 000000000..ab6928304 --- /dev/null +++ b/evmcc/test/jump/indirect1.evm @@ -0,0 +1 @@ +600460030158005d6001600054 diff --git a/evmcc/test/jump/indirect1.lll b/evmcc/test/jump/indirect1.lll new file mode 100644 index 000000000..1ee7dc347 --- /dev/null +++ b/evmcc/test/jump/indirect1.lll @@ -0,0 +1,13 @@ +;; Indirect JUMP + +(asm +4 ;; 0 +3 ;; 2 +ADD ;; 4 +JUMP ;; 5 +STOP ;; 6 +JUMPDEST ;; 7 +1 +0 +MSTORE +) \ No newline at end of file diff --git a/evmcc/test/jump/indirect2.evm b/evmcc/test/jump/indirect2.evm new file mode 100644 index 000000000..e9697eaa1 --- /dev/null +++ b/evmcc/test/jump/indirect2.evm @@ -0,0 +1 @@ +600860060158005d6001600054005d600260005400 diff --git a/evmcc/test/jump/indirect2.lll b/evmcc/test/jump/indirect2.lll new file mode 100644 index 000000000..f2f068630 --- /dev/null +++ b/evmcc/test/jump/indirect2.lll @@ -0,0 +1,19 @@ +;; Indirect JUMP + +(asm +8 ;; 0 +6 ;; 2 +ADD ;; 4 +JUMP ;; 5 --> 14 +STOP ;; 6 +JUMPDEST ;; 7 +1 ;; 8 +0 ;; 10 +MSTORE ;; 12 +STOP ;; 13 +JUMPDEST ;; 14 +2 +0 +MSTORE +STOP +) \ No newline at end of file diff --git a/evmcc/test/jump/indirect3.evm b/evmcc/test/jump/indirect3.evm new file mode 100644 index 000000000..1fb0a356c --- /dev/null +++ b/evmcc/test/jump/indirect3.evm @@ -0,0 +1 @@ +6001600460050159005d6001600054 diff --git a/evmcc/test/jump/indirect3.lll b/evmcc/test/jump/indirect3.lll new file mode 100644 index 000000000..d6a679f9a --- /dev/null +++ b/evmcc/test/jump/indirect3.lll @@ -0,0 +1,14 @@ +;; Indirect JUMP + +(asm +1 ;; 0 +4 ;; 2 +5 ;; 4 +ADD ;; 6 +JUMPI ;; 7 +STOP ;; 8 +JUMPDEST ;; 9 +1 +0 +MSTORE +) \ No newline at end of file diff --git a/evmcc/test/jump/indirect4.evm b/evmcc/test/jump/indirect4.evm new file mode 100644 index 000000000..f0e31a8f4 --- /dev/null +++ b/evmcc/test/jump/indirect4.evm @@ -0,0 +1 @@ +60006007600501596001600054005d00 diff --git a/evmcc/test/jump/indirect4.lll b/evmcc/test/jump/indirect4.lll new file mode 100644 index 000000000..7fbe0b833 --- /dev/null +++ b/evmcc/test/jump/indirect4.lll @@ -0,0 +1,15 @@ +;; Indirect JUMP + +(asm +0 ;; 0 +7 ;; 2 +5 ;; 4 +ADD ;; 6 +JUMPI ;; 7 +1 ;; 8 +0 ;; 9 +MSTORE ;; 10 +STOP ;; 11 +JUMPDEST ;; 12 +STOP +) \ No newline at end of file diff --git a/evmcc/test/jump/jump1.evm b/evmcc/test/jump/jump1.evm new file mode 100644 index 000000000..0df9b4036 --- /dev/null +++ b/evmcc/test/jump/jump1.evm @@ -0,0 +1 @@ +600458006001600154 diff --git a/evmcc/test/jump/jump1.lll b/evmcc/test/jump/jump1.lll new file mode 100644 index 000000000..33119edb3 --- /dev/null +++ b/evmcc/test/jump/jump1.lll @@ -0,0 +1,11 @@ +;; Direct JUMP. +;; output: memory[1] == 1 + +(asm +4 ;; 0 +JUMP ;; 2 +STOP ;; 3 +1 ;; 4 +1 ;; 6 +MSTORE ;; 8 +) \ No newline at end of file diff --git a/evmcc/test/jump/jump2.evm b/evmcc/test/jump/jump2.evm new file mode 100644 index 000000000..35d75941d --- /dev/null +++ b/evmcc/test/jump/jump2.evm @@ -0,0 +1 @@ +6008586001600154 diff --git a/evmcc/test/jump/jump2.lll b/evmcc/test/jump/jump2.lll new file mode 100644 index 000000000..a70d50ecb --- /dev/null +++ b/evmcc/test/jump/jump2.lll @@ -0,0 +1,10 @@ +;; Direct JUMP to the end of code. +;; output: memory should have size 0. + +(asm +8 ;; 0 +JUMP ;; 2 +1 ;; 3 +1 ;; 5 +MSTORE ;; 7 +) \ No newline at end of file diff --git a/evmcc/test/jump/jump3.evm b/evmcc/test/jump/jump3.evm new file mode 100644 index 000000000..599d4a764 --- /dev/null +++ b/evmcc/test/jump/jump3.evm @@ -0,0 +1 @@ +602a586001600154 diff --git a/evmcc/test/jump/jump3.lll b/evmcc/test/jump/jump3.lll new file mode 100644 index 000000000..bc897e30c --- /dev/null +++ b/evmcc/test/jump/jump3.lll @@ -0,0 +1,10 @@ +;; Direct JUMP past the end of code. +;; output: memory should have size 0. + +(asm +42 +JUMP +1 +1 +MSTORE +) \ No newline at end of file diff --git a/evmcc/test/jump/jump4.evm b/evmcc/test/jump/jump4.evm new file mode 100644 index 000000000..41713f43e --- /dev/null +++ b/evmcc/test/jump/jump4.evm @@ -0,0 +1 @@ +600b6009580000600558005d6001600154 diff --git a/evmcc/test/jump/jump4.lll b/evmcc/test/jump/jump4.lll new file mode 100644 index 000000000..131baee2d --- /dev/null +++ b/evmcc/test/jump/jump4.lll @@ -0,0 +1,17 @@ +;; Direct JUMP. +;; output: memory[1] = 1 + +(asm +11 ;; 0 +9 ;; 2 +JUMP ;; 4 --> 9 +STOP ;; 5 +STOP ;; 6 +5 ;; 7 +JUMP ;; 9 --> 11 +STOP ;; 10 +JUMPDEST +1 ;; 11 +1 +MSTORE +) \ No newline at end of file diff --git a/evmcc/test/jump/jump5.evm b/evmcc/test/jump/jump5.evm new file mode 100644 index 000000000..c36d9615b --- /dev/null +++ b/evmcc/test/jump/jump5.evm @@ -0,0 +1 @@ +6005600e585d600160015400600f5800 diff --git a/evmcc/test/jump/jump5.lll b/evmcc/test/jump/jump5.lll new file mode 100644 index 000000000..d28b7d4ac --- /dev/null +++ b/evmcc/test/jump/jump5.lll @@ -0,0 +1,16 @@ +;; Direct JUMP. +;; output: memory[1] = 1 + +(asm +5 ;; 0 +14 ;; 2 +JUMP ;; 4 --> 14 +JUMPDEST ;; 5 +1 ;; 6 +1 ;; 8 +MSTORE ;; 10 +STOP ;; 11 +15 ;; 12 +JUMP ;; 14 --> 5 +STOP ;; 15 +) \ No newline at end of file diff --git a/evmcc/test/jump/jump6.evm b/evmcc/test/jump/jump6.evm new file mode 100644 index 000000000..029db7191 --- /dev/null +++ b/evmcc/test/jump/jump6.evm @@ -0,0 +1 @@ +600358600f600d58006014600758005d6001600154005d600260025400 diff --git a/evmcc/test/jump/jump6.lll b/evmcc/test/jump/jump6.lll new file mode 100644 index 000000000..1116aa663 --- /dev/null +++ b/evmcc/test/jump/jump6.lll @@ -0,0 +1,32 @@ +;; Direct JUMP. +;; output: memory[1] = 1 + +;; 0, 2 --> 3 .. 7 --> 13 -*-> 15 .. 19 + +(asm +3 ;; 0 +JUMP ;; 2 + +15 ;; 3 <- start +13 ;; 5 +JUMP ;; 7 <- b +STOP ;; 8 + +20 ;; 9 +7 ;; 11 + +JUMP ;; 13 <- a +STOP ;; 14 + +JUMPDEST ;; 15 <- c +1 ;; 16 +1 ;; 18 +MSTORE ;; 19 +STOP ;; 20 + +JUMPDEST ;; 21 <- d +2 ;; 22 +2 ;; 24 +MSTORE ;; 26 +STOP ;; 27 +) \ No newline at end of file diff --git a/evmcc/test/jump/jumpi_at_the_end.evm b/evmcc/test/jump/jumpi_at_the_end.evm new file mode 100644 index 000000000..2d7411761 --- /dev/null +++ b/evmcc/test/jump/jumpi_at_the_end.evm @@ -0,0 +1 @@ +600a6000545d6000536001900380600054600659 diff --git a/evmcc/test/jump/jumpi_at_the_end.lll b/evmcc/test/jump/jumpi_at_the_end.lll new file mode 100644 index 000000000..263ada6a7 --- /dev/null +++ b/evmcc/test/jump/jumpi_at_the_end.lll @@ -0,0 +1 @@ +(asm 10 0 MSTORE JUMPDEST 0 MLOAD 1 SWAP1 SUB DUP1 0 MSTORE 6 JUMPI) \ No newline at end of file diff --git a/evmcc/test/jump/loop1.evm b/evmcc/test/jump/loop1.evm new file mode 100644 index 000000000..7724d6308 --- /dev/null +++ b/evmcc/test/jump/loop1.evm @@ -0,0 +1 @@ +600a600181038060025960005460015460025400 diff --git a/evmcc/test/jump/loop1.lll b/evmcc/test/jump/loop1.lll new file mode 100644 index 000000000..0044ec1fb --- /dev/null +++ b/evmcc/test/jump/loop1.lll @@ -0,0 +1,27 @@ +;; Produces 1 2 3 4 5 6 7 8 9 10 on the stack and exits + +(asm +10 + +;; 2 +1 +DUP2 +SUB +DUP1 +2 +JUMPI + +;; stack = 1 2 3 4 5 6 7 8 9 10 +0 +MSTORE +1 +MSTORE +2 +MSTORE +;;3 +;;MSTORE + +STOP +) + + diff --git a/evmcc/test/jump/loop2.evm b/evmcc/test/jump/loop2.evm new file mode 100644 index 000000000..faffa4e5b --- /dev/null +++ b/evmcc/test/jump/loop2.evm @@ -0,0 +1 @@ +600a80600190038060025960005460015460025400 diff --git a/evmcc/test/jump/loop2.lll b/evmcc/test/jump/loop2.lll new file mode 100644 index 000000000..9996c52ba --- /dev/null +++ b/evmcc/test/jump/loop2.lll @@ -0,0 +1,28 @@ +;; Produces 1 2 3 4 5 6 7 8 9 10 on the stack and exits + +(asm +10 + +;; 2 +DUP1 +1 +SWAP1 +SUB +DUP1 +2 +JUMPI + +;; stack = 1 2 3 4 5 6 7 8 9 10 +0 +MSTORE +1 +MSTORE +2 +MSTORE +;;3 +;;MSTORE + +STOP +) + + diff --git a/evmcc/test/jump/rec1.ethel b/evmcc/test/jump/rec1.ethel new file mode 100644 index 000000000..f83c8e81e --- /dev/null +++ b/evmcc/test/jump/rec1.ethel @@ -0,0 +1,4 @@ +let f n = + if n == 0 then 2 else f (n-1) + +return f 10 diff --git a/evmcc/test/jump/rec1.evm b/evmcc/test/jump/rec1.evm new file mode 100644 index 000000000..2ae62aff6 --- /dev/null +++ b/evmcc/test/jump/rec1.evm @@ -0,0 +1 @@ +6007600a6010585d60005460206000f26000810e6024596020600182036010585d602658600290509058 \ No newline at end of file diff --git a/evmcc/test/jump/when1.asm b/evmcc/test/jump/when1.asm new file mode 100644 index 000000000..01d41c266 --- /dev/null +++ b/evmcc/test/jump/when1.asm @@ -0,0 +1,10 @@ +.code: + PUSH 1 + NOT + PUSH [tag0] + JUMPI + PUSH 13 + PUSH 128 + MSTORE +tag0: + diff --git a/evmcc/test/jump/when1.evm b/evmcc/test/jump/when1.evm new file mode 100644 index 000000000..303b02623 --- /dev/null +++ b/evmcc/test/jump/when1.evm @@ -0,0 +1 @@ +60010f600b59600d608054 diff --git a/evmcc/test/jump/when1.lll b/evmcc/test/jump/when1.lll new file mode 100644 index 000000000..990a6e64a --- /dev/null +++ b/evmcc/test/jump/when1.lll @@ -0,0 +1,2 @@ +(when (> 1 0) [i] 13) + \ No newline at end of file diff --git a/evmcc/test/kv.evm b/evmcc/test/kv.evm new file mode 100644 index 000000000..55141ea59 --- /dev/null +++ b/evmcc/test/kv.evm @@ -0,0 +1 @@ +33604557602a8060106000396000f200604556330e0f602a59366080530a0f602a59602060805301356080533557604060805301608054600958 diff --git a/evmcc/test/kv.lll b/evmcc/test/kv.lll new file mode 100644 index 000000000..c62d9fa70 --- /dev/null +++ b/evmcc/test/kv.lll @@ -0,0 +1,10 @@ +{ + [[69]] (caller) + (return 0 (lll + (when (= (caller) @@69) + (for {} (< @i (calldatasize)) [i](+ @i 64) + [[ (calldataload @i) ]] (calldataload (+ @i 32)) + ) + ) + 0)) +} diff --git a/evmcc/test/mem/byte.evm b/evmcc/test/mem/byte.evm new file mode 100644 index 000000000..ab63431ee --- /dev/null +++ b/evmcc/test/mem/byte.evm @@ -0,0 +1 @@ +7f112233445566778899001122334455667788990011223344556677889900aabb6000137f112233445566778899001122334455667788990011223344556677889900aabb6001137f112233445566778899001122334455667788990011223344556677889900aabb6002137f112233445566778899001122334455667788990011223344556677889900aabb6003137f112233445566778899001122334455667788990011223344556677889900aabb6004137f112233445566778899001122334455667788990011223344556677889900aabb6005137f112233445566778899001122334455667788990011223344556677889900aabb6006137f112233445566778899001122334455667788990011223344556677889900aabb6007137f112233445566778899001122334455667788990011223344556677889900aabb6008137f112233445566778899001122334455667788990011223344556677889900aabb6009137f112233445566778899001122334455667788990011223344556677889900aabb600a137f112233445566778899001122334455667788990011223344556677889900aabb600b137f112233445566778899001122334455667788990011223344556677889900aabb600c137f112233445566778899001122334455667788990011223344556677889900aabb600d137f112233445566778899001122334455667788990011223344556677889900aabb600e137f112233445566778899001122334455667788990011223344556677889900aabb600f137f112233445566778899001122334455667788990011223344556677889900aabb6010137f112233445566778899001122334455667788990011223344556677889900aabb6011137f112233445566778899001122334455667788990011223344556677889900aabb6012137f112233445566778899001122334455667788990011223344556677889900aabb6013137f112233445566778899001122334455667788990011223344556677889900aabb6014137f112233445566778899001122334455667788990011223344556677889900aabb6015137f112233445566778899001122334455667788990011223344556677889900aabb6016137f112233445566778899001122334455667788990011223344556677889900aabb6017137f112233445566778899001122334455667788990011223344556677889900aabb6018137f112233445566778899001122334455667788990011223344556677889900aabb6019137f112233445566778899001122334455667788990011223344556677889900aabb601a137f112233445566778899001122334455667788990011223344556677889900aabb601b137f112233445566778899001122334455667788990011223344556677889900aabb601c137f112233445566778899001122334455667788990011223344556677889900aabb601d137f112233445566778899001122334455667788990011223344556677889900aabb601e137f112233445566778899001122334455667788990011223344556677889900aabb601f137f112233445566778899001122334455667788990011223344556677889900aabb6020137f112233445566778899001122334455667788990011223344556677889900aabb6107de13 diff --git a/evmcc/test/mem/byte.lll b/evmcc/test/mem/byte.lll new file mode 100644 index 000000000..95b0f99dc --- /dev/null +++ b/evmcc/test/mem/byte.lll @@ -0,0 +1,105 @@ + +(asm +0x112233445566778899001122334455667788990011223344556677889900aabb +0 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +1 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +2 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +3 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +4 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +5 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +6 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +7 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +8 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +9 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +10 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +11 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +12 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +13 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +14 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +15 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +16 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +17 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +18 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +19 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +20 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +21 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +22 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +23 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +24 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +25 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +26 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +27 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +28 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +29 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +30 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +31 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +32 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +2014 +BYTE +) \ No newline at end of file diff --git a/evmcc/test/mem/mem2.evm b/evmcc/test/mem/mem2.evm new file mode 100644 index 000000000..49cc6e8b1 --- /dev/null +++ b/evmcc/test/mem/mem2.evm @@ -0,0 +1 @@ +6001610d805b01556504409585d6df620493e05462061a80535b01 diff --git a/evmcc/test/mem/mem2.lll b/evmcc/test/mem/mem2.lll new file mode 100644 index 000000000..5345ee47c --- /dev/null +++ b/evmcc/test/mem/mem2.lll @@ -0,0 +1,15 @@ + +(asm ;; [] +1 +3456 +MSIZE +ADD +MSTORE8 ;; [02] +4675432994527 +300000 +MSTORE +400000 +MLOAD +MSIZE +ADD +) \ No newline at end of file diff --git a/evmcc/test/mem/memtest1.evm b/evmcc/test/mem/memtest1.evm new file mode 100644 index 000000000..0506bf928 --- /dev/null +++ b/evmcc/test/mem/memtest1.evm @@ -0,0 +1 @@ +6002600055600360015560005360015301600254 diff --git a/evmcc/test/mem/memtest1.lll b/evmcc/test/mem/memtest1.lll new file mode 100644 index 000000000..4b4389ad8 --- /dev/null +++ b/evmcc/test/mem/memtest1.lll @@ -0,0 +1,18 @@ + +(asm ;; [] +2 +0 +MSTORE8 ;; [02] +3 +1 +MSTORE8 ;; [02 03] +0 +MLOAD ;; [2 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] +1 +MLOAD ;; [2 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + ;; 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] +ADD +2 +MSTORE ;; [2 3 5 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + ;; 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] +) \ No newline at end of file diff --git a/evmcc/test/mem/mstore1.evm b/evmcc/test/mem/mstore1.evm new file mode 100644 index 000000000..ba6141ab1 --- /dev/null +++ b/evmcc/test/mem/mstore1.evm @@ -0,0 +1 @@ +6001600054 diff --git a/evmcc/test/mem/mstore1.lll b/evmcc/test/mem/mstore1.lll new file mode 100644 index 000000000..2d2ca32b5 --- /dev/null +++ b/evmcc/test/mem/mstore1.lll @@ -0,0 +1,6 @@ + +(asm ;; [] +1 +0 +MSTORE ;; [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1] +) \ No newline at end of file diff --git a/evmcc/test/ret/return1.evm b/evmcc/test/ret/return1.evm new file mode 100644 index 000000000..8092cb007 --- /dev/null +++ b/evmcc/test/ret/return1.evm @@ -0,0 +1 @@ +600160805460006080530b601b59600160005460206000f2602a58602760005460206000f26002608054 diff --git a/evmcc/test/ret/return1.lll b/evmcc/test/ret/return1.lll new file mode 100644 index 000000000..159d15ca3 --- /dev/null +++ b/evmcc/test/ret/return1.lll @@ -0,0 +1,6 @@ +;; code should return 39 +;; i should remain 1 +{ + [i] 1 + ( if (> @i 0) { (return 39) [i] 2 } (return 1) ) +} \ No newline at end of file diff --git a/evmcc/test/ret/return2.evm b/evmcc/test/ret/return2.evm new file mode 100644 index 000000000..e29da7664 --- /dev/null +++ b/evmcc/test/ret/return2.evm @@ -0,0 +1 @@ +6001620f4240f2 diff --git a/evmcc/test/ret/return2.lll b/evmcc/test/ret/return2.lll new file mode 100644 index 000000000..f5ee68f6e --- /dev/null +++ b/evmcc/test/ret/return2.lll @@ -0,0 +1,6 @@ + +(asm +1 +1000000 +RETURN ;; return 1 byte from index 1M +) \ No newline at end of file diff --git a/evmcc/test/ret/return_test.evm b/evmcc/test/ret/return_test.evm new file mode 100644 index 000000000..977cf7c19 --- /dev/null +++ b/evmcc/test/ret/return_test.evm @@ -0,0 +1 @@ +60016064546002608454600360a45460606064f2 diff --git a/evmcc/test/ret/return_test.lll b/evmcc/test/ret/return_test.lll new file mode 100644 index 000000000..c87a2d812 --- /dev/null +++ b/evmcc/test/ret/return_test.lll @@ -0,0 +1,15 @@ + +(asm +1 +100 +MSTORE +2 +132 +MSTORE +3 +164 +MSTORE +96 +100 +RETURN +) \ No newline at end of file diff --git a/evmcc/test/stack/oos.evm b/evmcc/test/stack/oos.evm new file mode 100644 index 000000000..ea2f1c890 --- /dev/null +++ b/evmcc/test/stack/oos.evm @@ -0,0 +1 @@ +60018194505050509150 diff --git a/evmcc/test/stack/oos.lll b/evmcc/test/stack/oos.lll new file mode 100644 index 000000000..5394b06ba --- /dev/null +++ b/evmcc/test/stack/oos.lll @@ -0,0 +1,11 @@ +(asm ;; x . v y z +1 ;; 1 x . v y z +DUP2 ;; x 1 x . v y z +SWAP5 ;; y 1 x . v x z +POP ;; 1 x . v x z +POP ;; x . v x z +POP ;; . v x z +POP ;; v x z +SWAP2 ;; z x v +POP ;; x v +) diff --git a/evmcc/test/stack/push_test.evm b/evmcc/test/stack/push_test.evm new file mode 100644 index 000000000..d624cee1d --- /dev/null +++ b/evmcc/test/stack/push_test.evm @@ -0,0 +1 @@ +60656107d26204a0c763026921f4640bc5588eb165372d0f1dca6e661ba1d901961c71670c55f7bc23038e3868056bc75e2d630fffff69021e19e0c9bab24000016a085d1c6e8050f0ea1c71bd6b0688be36543f3c36e638e37a6c03d41f73d55d0d482ae55555376dc76810d0fe03c91964d31c71c6f46e615dd0360c07d931663b14e38e38b16f2da3f99955a3adcf27ebb1caaaaaaa6e7014ccba6a8bb1ed35bd86bf065c71c71c2b7109491c5d4781b79c9009de6bfb8e38e38de8720414a0f6fdec81304d4c563e740bffffffffa573118427b3b4a05bc8a8a4de8459868000000000017406eb15e7331e727940d4ac54b7cdca1c71c71c71bd750567a91c9fefc96ebaa626a22f98c5e638e38e38e37a76032abd16c5b68006e15d5aa307e383f4e55555555555377701a6427bdc4f0d58eab5f48a3ec67f64e21c71c71c71c6f478080dd0a0c9b9ff2c2a0c740b06853a0a980ee38e38e38e38b17903c679cb5e8f2f9cb3b5d6652b0e7334f746faaaaaaaaaaaaa6e7a01b873815917ebb2bf3b890a1af495d6235bae3c71c71c71c71c2b7b07ae4cca96e1a55dfa49c85ad3c3e60e426b92fb8e38e38e38e38de87c036018bf074e292bcc7d6c8bea0f9699443046178bffffffffffffffa57d0e7d34c64a9c85d4460dbbca87196b61618a4bd2168000000000000000017e05b901f48a5b994d6572502bc4ea43140486666416aa1c71c71c71c71c71bd7f047889870c178fc477414ea231d70467a388fffe31b4e638e38e38e38e38e37a diff --git a/evmcc/test/stack/push_test.lll b/evmcc/test/stack/push_test.lll new file mode 100644 index 000000000..832daaec1 --- /dev/null +++ b/evmcc/test/stack/push_test.lll @@ -0,0 +1,35 @@ + +(asm +101 ;; PUSH1 +2002 ;; PUSH2 +303303 ;; PUSH3 +40444404 ;; PUSH4 +50555555505 ;; PUSH5 +60666666666606 +7777777777777777 +888888888888888888 +99999999999999999999 +10000000000000000000001 +10111111111111111111111101 +2022222222222222222222222202 +303333333333333333333333333303 +4044444444444444444444444444444404 +505555555555555555555555555555555505 +60666666666666666666666666666666666606 +7077777777777777777777777777777777777707 +808888888888888888888888888888888888888808 +90999999999999999999999999999999999999999909 +100000000000000000000000000000000000000000000001 +10111111111111111111111111111111111111111111111101 +2022222222222222222222222222222222222222222222222202 +303333333333333333333333333333333333333333333333333303 +40444444444444444444444444444444444444444444444444444404 +50555555555555555555555555555555555555555555555555555555505 +6066666666666666666666666666666666666666666666666666666666606 +707777777777777777777777777777777777777777777777777777777777707 +808888888888888888888888888888888888888888888888888888888888888808 +90999999999999999999999999999999999999999999999999999999999999999909 +100000000000000000000000000000000000000000000000000000000000000000000001 +10111111111111111111111111111111111111111111111111111111111111111111111101 +2022222222222222222222222222222222222222222222222222222222222222222222222202 ;; PUSH32 +) \ No newline at end of file diff --git a/evmcc/test/stack/stack_test.evm b/evmcc/test/stack/stack_test.evm new file mode 100644 index 000000000..02417c967 --- /dev/null +++ b/evmcc/test/stack/stack_test.evm @@ -0,0 +1 @@ +65372d0f1dca6e661925338e3e5c2b808280848184505050505050506104576108ae81819290 diff --git a/evmcc/test/stack/stack_test.lll b/evmcc/test/stack/stack_test.lll new file mode 100644 index 000000000..fdf83594c --- /dev/null +++ b/evmcc/test/stack/stack_test.lll @@ -0,0 +1,8 @@ + +(asm +123 +SSTORE +SLOAD +123 +SUB +) \ No newline at end of file diff --git a/evmcc/test/stack/stackjump.evm b/evmcc/test/stack/stackjump.evm new file mode 100644 index 000000000..baddec42e --- /dev/null +++ b/evmcc/test/stack/stackjump.evm @@ -0,0 +1 @@ +600460066009601358600a036000545b6000f260005401600958 \ No newline at end of file diff --git a/evmcc/test/stack/stackjump.lll b/evmcc/test/stack/stackjump.lll new file mode 100644 index 000000000..f5da5e733 --- /dev/null +++ b/evmcc/test/stack/stackjump.lll @@ -0,0 +1,3 @@ +(asm +0x4 0x6 0x9 0x13 JUMP 0xa SUB 0x0 MSTORE MSIZE 0x0 RETURN 0x0 MSTORE ADD 0x9 JUMP +) diff --git a/evmcc/test/stack/swap.evm b/evmcc/test/stack/swap.evm new file mode 100644 index 000000000..d17f0ee09 --- /dev/null +++ b/evmcc/test/stack/swap.evm @@ -0,0 +1 @@ +600560026001600c59505000906001601559505000036000546001601ff2 diff --git a/evmcc/test/stack/swap.lll b/evmcc/test/stack/swap.lll new file mode 100644 index 000000000..90dee585d --- /dev/null +++ b/evmcc/test/stack/swap.lll @@ -0,0 +1,31 @@ +(asm +5 ;; 0 +2 ;; 2 +1 ;; 4 +12 ;; 6 +JUMPI ;; 8 + +POP ;; 9 +POP ;; 10 +STOP ;; 11 + +;; stack = 2,1 +SWAP1 ;; 12 +1 ;; 13 +21 ;; 15 +JUMPI ;; 17 + +POP ;; 18 +POP ;; 19 +STOP ;; 20 + +;; stack = 1,2 +SUB ;; 21 +0 +MSTORE +1 +31 +RETURN ;; returns 03 +) + + diff --git a/evmcc/test/stack/swapswap.evm b/evmcc/test/stack/swapswap.evm new file mode 100644 index 000000000..fb4f1bf75 --- /dev/null +++ b/evmcc/test/stack/swapswap.evm @@ -0,0 +1 @@ +600260056001600c5950500090906001601659505000036000546001601ff2 diff --git a/evmcc/test/stack/swapswap.lll b/evmcc/test/stack/swapswap.lll new file mode 100644 index 000000000..1fedf726e --- /dev/null +++ b/evmcc/test/stack/swapswap.lll @@ -0,0 +1,32 @@ +(asm +2 ;; 0 +5 ;; 2 +1 ;; 4 +12 ;; 6 +JUMPI ;; 8 + +POP ;; 9 +POP ;; 10 +STOP ;; 11 + +;; stack = 2,1 +SWAP1 ;; 12 +SWAP1 ;; 13 +1 ;; 14 +22 ;; 16 +JUMPI ;; 18 + +POP ;; 19 +POP ;; 20 +STOP ;; 21 + +;; stack = 2,1 +SUB ;; 22 +0 +MSTORE +1 +31 +RETURN ;; returns 03 +) + + diff --git a/evmcc/test/stack/test.evm b/evmcc/test/stack/test.evm new file mode 100644 index 000000000..ea2f1c890 --- /dev/null +++ b/evmcc/test/stack/test.evm @@ -0,0 +1 @@ +60018194505050509150 diff --git a/evmcc/test/vmtests/vmArithPerformanceTest.json b/evmcc/test/vmtests/vmArithPerformanceTest.json new file mode 100644 index 000000000..d9017517f --- /dev/null +++ b/evmcc/test/vmtests/vmArithPerformanceTest.json @@ -0,0 +1,260 @@ +{ + "arith-1" : { + "callcreates" : [ ], + "env" : { + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentDifficulty" : "256", + "currentGasLimit" : "10000000", + "currentNumber" : "0", + "currentTimestamp" : "1", + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "code" : "0x600a60005260005160105760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600556", + "data" : "0x", + "gas" : "1000000", + "gasPrice" : "100000000000000", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000" + }, + "gas" : "999538", + "out" : "0x0000000000000000000000000000000000000000000000000000001b9c636491", + "post" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x600a60005260005160105760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600556", + "nonce" : "0", + "storage" : { + } + } + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x600a60005260005160105760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600556", + "nonce" : "0", + "storage" : { } + } + } + } + + , + + "arith-2" : { + "callcreates" : [ ], + "env" : { + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentDifficulty" : "256", + "currentGasLimit" : "10000000", + "currentNumber" : "0", + "currentTimestamp" : "1", + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "code" : "0x606460005260005160105760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600556", + "data" : "0x", + "gas" : "1000000", + "gasPrice" : "100000000000000", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000" + }, + "gas" : "995488", + "out" : "0x0000000000000000000000000000000000000000000000000000001b9c636491", + "post" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x606460005260005160105760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600556", + "nonce" : "0", + "storage" : { + } + } + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x606460005260005160105760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600556", + "nonce" : "0", + "storage" : { } + } + } + } + + , + + "arith-3" : { + "callcreates" : [ ], + "env" : { + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentDifficulty" : "256", + "currentGasLimit" : "10000000", + "currentNumber" : "0", + "currentTimestamp" : "1", + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "code" : "0x6103e860005260005160115760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600656", + "data" : "0x", + "gas" : "1000000", + "gasPrice" : "100000000000000", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000" + }, + "gas" : "954988", + "out" : "0x0000000000000000000000000000000000000000000000000000001b9c636491", + "post" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x6103e860005260005160115760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600656", + "nonce" : "0", + "storage" : { + } + } + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x6103e860005260005160115760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600656", + "nonce" : "0", + "storage" : { } + } + } + } + + , + + "arith-4" : { + "callcreates" : [ ], + "env" : { + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentDifficulty" : "256", + "currentGasLimit" : "10000000", + "currentNumber" : "0", + "currentTimestamp" : "1", + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "code" : "0x61271060005260005160115760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600656", + "data" : "0x", + "gas" : "1000000", + "gasPrice" : "100000000000000", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000" + }, + "gas" : "549988", + "out" : "0x0000000000000000000000000000000000000000000000000000001b9c636491", + "post" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x61271060005260005160115760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600656", + "nonce" : "0", + "storage" : { + } + } + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x61271060005260005160115760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600656", + "nonce" : "0", + "storage" : { } + } + } + } + + + , + + + "arith-5" : { + "callcreates" : [ ], + "env" : { + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentDifficulty" : "256", + "currentGasLimit" : "10000000", + "currentNumber" : "0", + "currentTimestamp" : "1", + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "code" : "0x620186a060005260005160125760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600756", + "data" : "0x", + "gas" : "10000000", + "gasPrice" : "100000000000000", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000" + }, + "gas" : "5499988", + "out" : "0x0000000000000000000000000000000000000000000000000000001b9c636491", + "post" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x620186a060005260005160125760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600756", + "nonce" : "0", + "storage" : { + } + } + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x620186a060005260005160125760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600756", + "nonce" : "0", + "storage" : { } + } + } + } + +, + + "arith-6" : { + "callcreates" : [ ], + "env" : { + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentDifficulty" : "256", + "currentGasLimit" : "100000000", + "currentNumber" : "0", + "currentTimestamp" : "1", + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "code" : "0x620f424060005260005160125760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600756", + "data" : "0x", + "gas" : "100000000", + "gasPrice" : "100000000000000", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000" + }, + "gas" : "54999988", + "out" : "0x0000000000000000000000000000000000000000000000000000001b9c636491", + "post" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x620f424060005260005160125760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600756", + "nonce" : "0", + "storage" : { + } + } + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x620f424060005260005160125760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600756", + "nonce" : "0", + "storage" : { } + } + } + } + +} diff --git a/evmcc/test/vmtests/vmPerformanceTest.json b/evmcc/test/vmtests/vmPerformanceTest.json new file mode 100644 index 000000000..604e45993 --- /dev/null +++ b/evmcc/test/vmtests/vmPerformanceTest.json @@ -0,0 +1,214 @@ +{ + "mulmodloop" : { + "callcreates" : [ ], + "env" : { + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentDifficulty" : "256", + "currentGasLimit" : "10000000", + "currentNumber" : "0", + "currentTimestamp" : "1", + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "code" : "0x60015b68010000000000000000908060010109600356", + "data" : "0x", + "gas" : "10000000", + "gasPrice" : "100000000000000", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000" + }, + "gas" : "0", + "out" : "0x0", + "post" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x60015b68010000000000000000908060010109600356", + "nonce" : "0", + "storage" : { + } + } + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x60015b68010000000000000000908060010109600356", + "nonce" : "0", + "storage" : { } + } + } + }, + + + "for-1e06" : { + "callcreates" : [ ], + "env" : { + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentDifficulty" : "256", + "currentGasLimit" : "100000000", + "currentNumber" : "0", + "currentTimestamp" : "1", + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "code" : "0x620f42406080525b6000608051111560285760a0516080510160a0526001608051036080526007565b", + "data" : "0x", + "gas" : "30000000", + "gasPrice" : "100000000000000", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000" + }, + "gas" : "6999982", + "out" : "0x00", + "post" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x620f42406080525b6000608051111560285760a0516080510160a0526001608051036080526007565b", + "nonce" : "0", + "storage" : { + } + } + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x620f42406080525b6000608051111560285760a0516080510160a0526001608051036080526007565b", + "nonce" : "0", + "storage" : { } + } + } + }, + + "fib25" : { + "callcreates" : [ + ], + "env" : { + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentDifficulty" : "256", + "currentGasLimit" : "100000000", + "currentNumber" : "0", + "currentTimestamp" : "1", + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "code" : "0x6007601e6010565b60005260206000f25b600381106030576021600282036010565b602b600183036010565b016033565b60015b90509056", + "data" : "0x", + "gas" : "40000000", + "gasPrice" : "100000000000000", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000" + }, + "gas" : "5886377", + "out" : "0x00000000000000000000000000000000000000000000000000000000000cb228", + "post" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x6007601e6010565b60005260206000f25b600381106030576021600282036010565b602b600183036010565b016033565b60015b90509056", + "nonce" : "0", + "storage" : { + } + } + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x6007601e6010565b60005260206000f25b600381106030576021600282036010565b602b600183036010565b016033565b60015b90509056", + "nonce" : "0", + "storage" : { + } + } + } + }, + + "ackermann37" : { + "callcreates" : [ + ], + "env" : { + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentDifficulty" : "256", + "currentGasLimit" : "20000000", + "currentNumber" : "0", + "currentTimestamp" : "1", + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "code" : "0x6009600360076012565b60005260206000f25b60008214604a5760008114603957603560018303603184600185036012565b6012565b6046565b60456001830360016012565b5b604f565b600181015b905090509056", + "data" : "0x", + "gas" : "20000000", + "gasPrice" : "100000000000000", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000" + }, + "gas" : "913456", + "out" : "0x00000000000000000000000000000000000000000000000000000000000003fd", + "post" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x6009600360076012565b60005260206000f25b60008214604a5760008114603957603560018303603184600185036012565b6012565b6046565b60456001830360016012565b5b604f565b600181015b905090509056", + "nonce" : "0", + "storage" : { + } + } + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x6009600360076012565b60005260206000f25b60008214604a5760008114603957603560018303603184600185036012565b6012565b6046565b60456001830360016012565b5b604f565b600181015b905090509056", + "nonce" : "0", + "storage" : { + } + } + } + }, + + "jumptable100" : { + "callcreates" : [ + ], + "env" : { + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentDifficulty" : "256", + "currentGasLimit" : "10000000", + "currentNumber" : "0", + "currentTimestamp" : "1", + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "code" : "0x6103e85b60019003806000146104605761001a600160005256005b610025600260005256005b610030600360005256005b61003b600460005256005b610046600560005256005b610051600660005256005b61005c600760005256005b610067600860005256005b610072600960005256005b61007d600a60005256005b610088600b60005256005b610093600c60005256005b61009e600d60005256005b6100a9600e60005256005b6100b4600f60005256005b6100bf601060005256005b6100ca601160005256005b6100d5601260005256005b6100e0601360005256005b6100eb601460005256005b6100f6601560005256005b610101601660005256005b61010c601760005256005b610117601860005256005b610122601960005256005b61012d601a60005256005b610138601b60005256005b610143601c60005256005b61014e601d60005256005b610159601e60005256005b610164601f60005256005b61016f602060005256005b61017a602160005256005b610185602260005256005b610190602360005256005b61019b602460005256005b6101a6602560005256005b6101b1602660005256005b6101bc602760005256005b6101c7602860005256005b6101d2602960005256005b6101dd602a60005256005b6101e8602b60005256005b6101f3602c60005256005b6101fe602d60005256005b610209602e60005256005b610214602f60005256005b61021f603060005256005b61022a603160005256005b610235603260005256005b610240603360005256005b61024b603460005256005b610256603560005256005b610261603660005256005b61026c603760005256005b610277603860005256005b610282603960005256005b61028d603a60005256005b610298603b60005256005b6102a3603c60005256005b6102ae603d60005256005b6102b9603e60005256005b6102c4603f60005256005b6102cf604060005256005b6102da604160005256005b6102e5604260005256005b6102f0604360005256005b6102fb604460005256005b610306604560005256005b610311604660005256005b61031c604760005256005b610327604860005256005b610332604960005256005b61033d604a60005256005b610348604b60005256005b610353604c60005256005b61035e604d60005256005b610369604e60005256005b610374604f60005256005b61037f605060005256005b61038a605160005256005b610395605260005256005b6103a0605360005256005b6103ab605460005256005b6103b6605560005256005b6103c1605660005256005b6103cc605760005256005b6103d7605860005256005b6103e2605960005256005b6103ed605a60005256005b6103f8605b60005256005b610403605c60005256005b61040e605d60005256005b610419605e60005256005b610424605f60005256005b61042f606060005256005b61043a606160005256005b610445606260005256005b610450606360005256005b61045b606460005256005b610003565b60206000f2", + "data" : "0x", + "gas" : "1000000", + "gasPrice" : "100000000000000", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000" + }, + "gas" : "389596", + "out" : "0x0000000000000000000000000000000000000000000000000000000000000064", + "post" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x6103e85b60019003806000146104605761001a600160005256005b610025600260005256005b610030600360005256005b61003b600460005256005b610046600560005256005b610051600660005256005b61005c600760005256005b610067600860005256005b610072600960005256005b61007d600a60005256005b610088600b60005256005b610093600c60005256005b61009e600d60005256005b6100a9600e60005256005b6100b4600f60005256005b6100bf601060005256005b6100ca601160005256005b6100d5601260005256005b6100e0601360005256005b6100eb601460005256005b6100f6601560005256005b610101601660005256005b61010c601760005256005b610117601860005256005b610122601960005256005b61012d601a60005256005b610138601b60005256005b610143601c60005256005b61014e601d60005256005b610159601e60005256005b610164601f60005256005b61016f602060005256005b61017a602160005256005b610185602260005256005b610190602360005256005b61019b602460005256005b6101a6602560005256005b6101b1602660005256005b6101bc602760005256005b6101c7602860005256005b6101d2602960005256005b6101dd602a60005256005b6101e8602b60005256005b6101f3602c60005256005b6101fe602d60005256005b610209602e60005256005b610214602f60005256005b61021f603060005256005b61022a603160005256005b610235603260005256005b610240603360005256005b61024b603460005256005b610256603560005256005b610261603660005256005b61026c603760005256005b610277603860005256005b610282603960005256005b61028d603a60005256005b610298603b60005256005b6102a3603c60005256005b6102ae603d60005256005b6102b9603e60005256005b6102c4603f60005256005b6102cf604060005256005b6102da604160005256005b6102e5604260005256005b6102f0604360005256005b6102fb604460005256005b610306604560005256005b610311604660005256005b61031c604760005256005b610327604860005256005b610332604960005256005b61033d604a60005256005b610348604b60005256005b610353604c60005256005b61035e604d60005256005b610369604e60005256005b610374604f60005256005b61037f605060005256005b61038a605160005256005b610395605260005256005b6103a0605360005256005b6103ab605460005256005b6103b6605560005256005b6103c1605660005256005b6103cc605760005256005b6103d7605860005256005b6103e2605960005256005b6103ed605a60005256005b6103f8605b60005256005b610403605c60005256005b61040e605d60005256005b610419605e60005256005b610424605f60005256005b61042f606060005256005b61043a606160005256005b610445606260005256005b610450606360005256005b61045b606460005256005b610003565b60206000f2", + "nonce" : "0", + "storage" : { + } + } + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x6103e85b60019003806000146104605761001a600160005256005b610025600260005256005b610030600360005256005b61003b600460005256005b610046600560005256005b610051600660005256005b61005c600760005256005b610067600860005256005b610072600960005256005b61007d600a60005256005b610088600b60005256005b610093600c60005256005b61009e600d60005256005b6100a9600e60005256005b6100b4600f60005256005b6100bf601060005256005b6100ca601160005256005b6100d5601260005256005b6100e0601360005256005b6100eb601460005256005b6100f6601560005256005b610101601660005256005b61010c601760005256005b610117601860005256005b610122601960005256005b61012d601a60005256005b610138601b60005256005b610143601c60005256005b61014e601d60005256005b610159601e60005256005b610164601f60005256005b61016f602060005256005b61017a602160005256005b610185602260005256005b610190602360005256005b61019b602460005256005b6101a6602560005256005b6101b1602660005256005b6101bc602760005256005b6101c7602860005256005b6101d2602960005256005b6101dd602a60005256005b6101e8602b60005256005b6101f3602c60005256005b6101fe602d60005256005b610209602e60005256005b610214602f60005256005b61021f603060005256005b61022a603160005256005b610235603260005256005b610240603360005256005b61024b603460005256005b610256603560005256005b610261603660005256005b61026c603760005256005b610277603860005256005b610282603960005256005b61028d603a60005256005b610298603b60005256005b6102a3603c60005256005b6102ae603d60005256005b6102b9603e60005256005b6102c4603f60005256005b6102cf604060005256005b6102da604160005256005b6102e5604260005256005b6102f0604360005256005b6102fb604460005256005b610306604560005256005b610311604660005256005b61031c604760005256005b610327604860005256005b610332604960005256005b61033d604a60005256005b610348604b60005256005b610353604c60005256005b61035e604d60005256005b610369604e60005256005b610374604f60005256005b61037f605060005256005b61038a605160005256005b610395605260005256005b6103a0605360005256005b6103ab605460005256005b6103b6605560005256005b6103c1605660005256005b6103cc605760005256005b6103d7605860005256005b6103e2605960005256005b6103ed605a60005256005b6103f8605b60005256005b610403605c60005256005b61040e605d60005256005b610419605e60005256005b610424605f60005256005b61042f606060005256005b61043a606160005256005b610445606260005256005b610450606360005256005b61045b606460005256005b610003565b60206000f2", + "nonce" : "0", + "storage" : { + } + } + } + }, + +} diff --git a/evmcc/test/vmtests/vm_jump.json b/evmcc/test/vmtests/vm_jump.json new file mode 100644 index 000000000..6b63edeae --- /dev/null +++ b/evmcc/test/vmtests/vm_jump.json @@ -0,0 +1,41 @@ +{ + "jumpi_at_the_end" : { + "callcreates" : [ ], + "env" : { + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentDifficulty" : "256", + "currentGasLimit" : "10000000", + "currentNumber" : "0", + "currentTimestamp" : "1", + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "code" : "(asm 10 0 MSTORE JUMPDEST 0 MLOAD 1 SWAP1 SUB DUP1 0 MSTORE 6 JUMPI)", + "data" : "0x", + "gas" : "1000", + "gasPrice" : "100000000000000", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000" + }, + "gas" : "895", + "out" : "0x0", + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "(asm 10 0 MSTORE JUMPDEST 0 MLOAD 1 SWAP1 SUB DUP1 0 MSTORE 6 JUMPI)", + "nonce" : "0", + "storage" : {} + } + }, + "post" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "(asm 10 0 MSTORE JUMPDEST 0 MLOAD 1 SWAP1 SUB DUP1 0 MSTORE 6 JUMPI)", + "nonce" : "0", + "storage" : {} + } + } + } +} diff --git a/libevmjit-cpp/CMakeLists.txt b/libevmjit-cpp/CMakeLists.txt new file mode 100644 index 000000000..25be95177 --- /dev/null +++ b/libevmjit-cpp/CMakeLists.txt @@ -0,0 +1,16 @@ +set(TARGET_NAME evmjit-cpp) + +set(SOURCES + Env.cpp + JitVM.cpp JitVM.h +) +source_group("" FILES ${SOURCES}) + +add_library(${TARGET_NAME} ${SOURCES}) +set_property(TARGET ${TARGET_NAME} PROPERTY FOLDER "libs") + +include_directories(../..) +include_directories(${LLVM_INCLUDE_DIRS}) +include_directories(${Boost_INCLUDE_DIRS}) + +target_link_libraries(${TARGET_NAME} evmjit) diff --git a/libevmjit-cpp/Env.cpp b/libevmjit-cpp/Env.cpp new file mode 100644 index 000000000..1dcd38162 --- /dev/null +++ b/libevmjit-cpp/Env.cpp @@ -0,0 +1,125 @@ + +#include +#include +#include + +#include + +extern "C" +{ + #ifdef _MSC_VER + #define EXPORT __declspec(dllexport) + #else + #define EXPORT + #endif + + using namespace dev; + using namespace dev::eth; + using jit::i256; + using jit::eth2llvm; + + EXPORT void env_sload(ExtVMFace* _env, i256* _index, i256* o_value) + { + auto index = llvm2eth(*_index); + auto value = _env->store(index); // Interface uses native endianness + *o_value = eth2llvm(value); + } + + EXPORT void env_sstore(ExtVMFace* _env, i256* _index, i256* _value) + { + auto index = llvm2eth(*_index); + auto value = llvm2eth(*_value); + + if (value == 0 && _env->store(index) != 0) // If delete + _env->sub.refunds += c_sstoreRefundGas; // Increase refund counter + + _env->setStore(index, value); // Interface uses native endianness + } + + EXPORT void env_balance(ExtVMFace* _env, h256* _address, i256* o_value) + { + auto u = _env->balance(right160(*_address)); + *o_value = eth2llvm(u); + } + + EXPORT void env_create(ExtVMFace* _env, i256* io_gas, i256* _endowment, byte* _initBeg, uint64_t _initSize, h256* o_address) + { + if (_env->depth == 1024) + jit::terminate(jit::ReturnCode::OutOfGas); + + assert(_env->depth < 1024); + + auto endowment = llvm2eth(*_endowment); + + if (_env->balance(_env->myAddress) >= endowment) + { + _env->subBalance(endowment); + auto gas = llvm2eth(*io_gas); + OnOpFunc onOp {}; // TODO: Handle that thing + h256 address(_env->create(endowment, gas, {_initBeg, _initSize}, onOp), h256::AlignRight); + *io_gas = eth2llvm(gas); + *o_address = address; + } + else + *o_address = {}; + } + + EXPORT bool env_call(ExtVMFace* _env, i256* io_gas, h256* _receiveAddress, i256* _value, byte* _inBeg, uint64_t _inSize, byte* _outBeg, uint64_t _outSize, h256* _codeAddress) + { + if (_env->depth == 1024) + jit::terminate(jit::ReturnCode::OutOfGas); + + assert(_env->depth < 1024); + + auto value = llvm2eth(*_value); + if (_env->balance(_env->myAddress) >= value) + { + _env->subBalance(value); + auto receiveAddress = right160(*_receiveAddress); + auto inRef = bytesConstRef{_inBeg, _inSize}; + auto outRef = bytesConstRef{_outBeg, _outSize}; + OnOpFunc onOp {}; // TODO: Handle that thing + auto codeAddress = right160(*_codeAddress); + auto gas = llvm2eth(*io_gas); + auto ret = _env->call(receiveAddress, value, inRef, gas, outRef, onOp, {}, codeAddress); + *io_gas = eth2llvm(gas); + return ret; + } + + return false; + } + + EXPORT void env_sha3(byte* _begin, uint64_t _size, h256* o_hash) + { + auto hash = sha3({_begin, _size}); + *o_hash = hash; + } + + EXPORT byte const* env_getExtCode(ExtVMFace* _env, h256* _addr256, uint64_t* o_size) + { + auto addr = right160(*_addr256); + auto& code = _env->codeAt(addr); + *o_size = code.size(); + return code.data(); + } + + EXPORT void env_log(ExtVMFace* _env, byte* _beg, uint64_t _size, h256* _topic1, h256* _topic2, h256* _topic3, h256* _topic4) + { + dev::h256s topics; + + if (_topic1) + topics.push_back(*_topic1); + + if (_topic2) + topics.push_back(*_topic2); + + if (_topic3) + topics.push_back(*_topic3); + + if (_topic4) + topics.push_back(*_topic4); + + _env->log(std::move(topics), {_beg, _size}); + } +} + diff --git a/libevmjit-cpp/JitVM.cpp b/libevmjit-cpp/JitVM.cpp new file mode 100644 index 000000000..815aa6332 --- /dev/null +++ b/libevmjit-cpp/JitVM.cpp @@ -0,0 +1,69 @@ + +#include "JitVM.h" +#include +#include +#include + +namespace dev +{ +namespace eth +{ + +bytesConstRef JitVM::go(ExtVMFace& _ext, OnOpFunc const&, uint64_t) +{ + using namespace jit; + + m_data.set(RuntimeData::Gas, m_gas); + m_data.set(RuntimeData::Address, fromAddress(_ext.myAddress)); + m_data.set(RuntimeData::Caller, fromAddress(_ext.caller)); + m_data.set(RuntimeData::Origin, fromAddress(_ext.origin)); + m_data.set(RuntimeData::CallValue, _ext.value); + m_data.set(RuntimeData::CallDataSize, _ext.data.size()); + m_data.set(RuntimeData::GasPrice, _ext.gasPrice); + m_data.set(RuntimeData::PrevHash, _ext.previousBlock.hash); + m_data.set(RuntimeData::CoinBase, fromAddress(_ext.currentBlock.coinbaseAddress)); + m_data.set(RuntimeData::TimeStamp, _ext.currentBlock.timestamp); + m_data.set(RuntimeData::Number, _ext.currentBlock.number); + m_data.set(RuntimeData::Difficulty, _ext.currentBlock.difficulty); + m_data.set(RuntimeData::GasLimit, _ext.currentBlock.gasLimit); + m_data.set(RuntimeData::CodeSize, _ext.code.size()); + m_data.callData = _ext.data.data(); + m_data.code = _ext.code.data(); + + auto env = reinterpret_cast(&_ext); + auto exitCode = m_engine.run(_ext.code, &m_data, env); + switch (exitCode) + { + case ReturnCode::Suicide: + _ext.suicide(right160(m_data.get(RuntimeData::SuicideDestAddress))); + break; + + case ReturnCode::BadJumpDestination: + BOOST_THROW_EXCEPTION(BadJumpDestination()); + case ReturnCode::OutOfGas: + BOOST_THROW_EXCEPTION(OutOfGas()); + case ReturnCode::StackTooSmall: + BOOST_THROW_EXCEPTION(StackTooSmall()); + case ReturnCode::BadInstruction: + BOOST_THROW_EXCEPTION(BadInstruction()); + default: + break; + } + + m_gas = llvm2eth(m_data.elems[RuntimeData::Gas]); + return {m_engine.returnData.data(), m_engine.returnData.size()}; // TODO: This all bytesConstRef is problematic, review. +} + +} +} + +namespace +{ + // MSVS linker ignores export symbols in Env.cpp if nothing points at least one of them + extern "C" void env_sload(); + void linkerWorkaround() + { + env_sload(); + (void)&linkerWorkaround; // suppress unused function warning from GCC + } +} diff --git a/libevmjit-cpp/JitVM.h b/libevmjit-cpp/JitVM.h new file mode 100644 index 000000000..90855127e --- /dev/null +++ b/libevmjit-cpp/JitVM.h @@ -0,0 +1,28 @@ +#pragma once + +#include +#include + +namespace dev +{ +namespace eth +{ + +class JitVM: public VMFace +{ + virtual bytesConstRef go(ExtVMFace& _ext, OnOpFunc const& _onOp = {}, uint64_t _steps = (uint64_t)-1) override final; + + enum Kind: bool { Interpreter, JIT }; + static std::unique_ptr create(Kind, u256 _gas = 0); + +private: + friend class VMFactory; + explicit JitVM(u256 _gas = 0) : VMFace(_gas) {} + + jit::RuntimeData m_data; + jit::ExecutionEngine m_engine; +}; + + +} +} diff --git a/libevmjit/Arith256.cpp b/libevmjit/Arith256.cpp new file mode 100644 index 000000000..10d3e3449 --- /dev/null +++ b/libevmjit/Arith256.cpp @@ -0,0 +1,194 @@ +#include "Arith256.h" +#include "Runtime.h" +#include "Type.h" + +#include + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +Arith256::Arith256(llvm::IRBuilder<>& _builder) : + CompilerHelper(_builder) +{ + using namespace llvm; + + m_result = m_builder.CreateAlloca(Type::Word, nullptr, "arith.result"); + m_arg1 = m_builder.CreateAlloca(Type::Word, nullptr, "arith.arg1"); + m_arg2 = m_builder.CreateAlloca(Type::Word, nullptr, "arith.arg2"); + m_arg3 = m_builder.CreateAlloca(Type::Word, nullptr, "arith.arg3"); + + using Linkage = GlobalValue::LinkageTypes; + + llvm::Type* arg2Types[] = {Type::WordPtr, Type::WordPtr, Type::WordPtr}; + llvm::Type* arg3Types[] = {Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr}; + + m_mul = Function::Create(FunctionType::get(Type::Void, arg2Types, false), Linkage::ExternalLinkage, "arith_mul", getModule()); + m_div = Function::Create(FunctionType::get(Type::Void, arg2Types, false), Linkage::ExternalLinkage, "arith_div", getModule()); + m_mod = Function::Create(FunctionType::get(Type::Void, arg2Types, false), Linkage::ExternalLinkage, "arith_mod", getModule()); + m_sdiv = Function::Create(FunctionType::get(Type::Void, arg2Types, false), Linkage::ExternalLinkage, "arith_sdiv", getModule()); + m_smod = Function::Create(FunctionType::get(Type::Void, arg2Types, false), Linkage::ExternalLinkage, "arith_smod", getModule()); + m_exp = Function::Create(FunctionType::get(Type::Void, arg2Types, false), Linkage::ExternalLinkage, "arith_exp", getModule()); + m_addmod = Function::Create(FunctionType::get(Type::Void, arg3Types, false), Linkage::ExternalLinkage, "arith_addmod", getModule()); + m_mulmod = Function::Create(FunctionType::get(Type::Void, arg3Types, false), Linkage::ExternalLinkage, "arith_mulmod", getModule()); +} + +Arith256::~Arith256() +{} + +llvm::Value* Arith256::binaryOp(llvm::Function* _op, llvm::Value* _arg1, llvm::Value* _arg2) +{ + m_builder.CreateStore(_arg1, m_arg1); + m_builder.CreateStore(_arg2, m_arg2); + m_builder.CreateCall3(_op, m_arg1, m_arg2, m_result); + return m_builder.CreateLoad(m_result); +} + +llvm::Value* Arith256::ternaryOp(llvm::Function* _op, llvm::Value* _arg1, llvm::Value* _arg2, llvm::Value* _arg3) +{ + m_builder.CreateStore(_arg1, m_arg1); + m_builder.CreateStore(_arg2, m_arg2); + m_builder.CreateStore(_arg3, m_arg3); + m_builder.CreateCall4(_op, m_arg1, m_arg2, m_arg3, m_result); + return m_builder.CreateLoad(m_result); +} + +llvm::Value* Arith256::mul(llvm::Value* _arg1, llvm::Value* _arg2) +{ + return binaryOp(m_mul, _arg1, _arg2); +} + +llvm::Value* Arith256::div(llvm::Value* _arg1, llvm::Value* _arg2) +{ + return binaryOp(m_div, _arg1, _arg2); +} + +llvm::Value* Arith256::mod(llvm::Value* _arg1, llvm::Value* _arg2) +{ + return binaryOp(m_mod, _arg1, _arg2); +} + +llvm::Value* Arith256::sdiv(llvm::Value* _arg1, llvm::Value* _arg2) +{ + return binaryOp(m_sdiv, _arg1, _arg2); +} + +llvm::Value* Arith256::smod(llvm::Value* _arg1, llvm::Value* _arg2) +{ + return binaryOp(m_smod, _arg1, _arg2); +} + +llvm::Value* Arith256::exp(llvm::Value* _arg1, llvm::Value* _arg2) +{ + return binaryOp(m_exp, _arg1, _arg2); +} + +llvm::Value* Arith256::addmod(llvm::Value* _arg1, llvm::Value* _arg2, llvm::Value* _arg3) +{ + return ternaryOp(m_addmod, _arg1, _arg2, _arg3); +} + +llvm::Value* Arith256::mulmod(llvm::Value* _arg1, llvm::Value* _arg2, llvm::Value* _arg3) +{ + return ternaryOp(m_mulmod, _arg1, _arg2, _arg3); +} + +namespace +{ + using s256 = boost::multiprecision::int256_t; + + inline s256 u2s(u256 _u) + { + static const bigint c_end = (bigint)1 << 256; + static const u256 c_send = (u256)1 << 255; + if (_u < c_send) + return (s256)_u; + else + return (s256)-(c_end - _u); + } + + inline u256 s2u(s256 _u) + { + static const bigint c_end = (bigint)1 << 256; + if (_u >= 0) + return (u256)_u; + else + return (u256)(c_end + _u); + } +} + +} +} +} + + +extern "C" +{ + + using namespace dev::eth::jit; + + EXPORT void arith_mul(i256* _arg1, i256* _arg2, i256* o_result) + { + auto arg1 = llvm2eth(*_arg1); + auto arg2 = llvm2eth(*_arg2); + *o_result = eth2llvm(arg1 * arg2); + } + + EXPORT void arith_div(i256* _arg1, i256* _arg2, i256* o_result) + { + auto arg1 = llvm2eth(*_arg1); + auto arg2 = llvm2eth(*_arg2); + *o_result = eth2llvm(arg2 == 0 ? arg2 : arg1 / arg2); + } + + EXPORT void arith_mod(i256* _arg1, i256* _arg2, i256* o_result) + { + auto arg1 = llvm2eth(*_arg1); + auto arg2 = llvm2eth(*_arg2); + *o_result = eth2llvm(arg2 == 0 ? arg2 : arg1 % arg2); + } + + EXPORT void arith_sdiv(i256* _arg1, i256* _arg2, i256* o_result) + { + auto arg1 = llvm2eth(*_arg1); + auto arg2 = llvm2eth(*_arg2); + *o_result = eth2llvm(arg2 == 0 ? arg2 : s2u(u2s(arg1) / u2s(arg2))); + } + + EXPORT void arith_smod(i256* _arg1, i256* _arg2, i256* o_result) + { + auto arg1 = llvm2eth(*_arg1); + auto arg2 = llvm2eth(*_arg2); + *o_result = eth2llvm(arg2 == 0 ? arg2 : s2u(u2s(arg1) % u2s(arg2))); + } + + EXPORT void arith_exp(i256* _arg1, i256* _arg2, i256* o_result) + { + bigint left = llvm2eth(*_arg1); + bigint right = llvm2eth(*_arg2); + auto ret = static_cast(boost::multiprecision::powm(left, right, bigint(2) << 256)); + *o_result = eth2llvm(ret); + } + + EXPORT void arith_mulmod(i256* _arg1, i256* _arg2, i256* _arg3, i256* o_result) + { + auto arg1 = llvm2eth(*_arg1); + auto arg2 = llvm2eth(*_arg2); + auto arg3 = llvm2eth(*_arg3); + *o_result = eth2llvm(u256((bigint(arg1) * bigint(arg2)) % arg3)); + } + + EXPORT void arith_addmod(i256* _arg1, i256* _arg2, i256* _arg3, i256* o_result) + { + auto arg1 = llvm2eth(*_arg1); + auto arg2 = llvm2eth(*_arg2); + auto arg3 = llvm2eth(*_arg3); + *o_result = eth2llvm(u256((bigint(arg1) + bigint(arg2)) % arg3)); + } + +} + + diff --git a/libevmjit/Arith256.h b/libevmjit/Arith256.h new file mode 100644 index 000000000..57bc061de --- /dev/null +++ b/libevmjit/Arith256.h @@ -0,0 +1,49 @@ +#pragma once + +#include "CompilerHelper.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +class Arith256 : public CompilerHelper +{ +public: + Arith256(llvm::IRBuilder<>& _builder); + virtual ~Arith256(); + + llvm::Value* mul(llvm::Value* _arg1, llvm::Value* _arg2); + llvm::Value* div(llvm::Value* _arg1, llvm::Value* _arg2); + llvm::Value* mod(llvm::Value* _arg1, llvm::Value* _arg2); + llvm::Value* sdiv(llvm::Value* _arg1, llvm::Value* _arg2); + llvm::Value* smod(llvm::Value* _arg1, llvm::Value* _arg2); + llvm::Value* exp(llvm::Value* _arg1, llvm::Value* _arg2); + llvm::Value* mulmod(llvm::Value* _arg1, llvm::Value* _arg2, llvm::Value* _arg3); + llvm::Value* addmod(llvm::Value* _arg1, llvm::Value* _arg2, llvm::Value* _arg3); + +private: + llvm::Value* binaryOp(llvm::Function* _op, llvm::Value* _arg1, llvm::Value* _arg2); + llvm::Value* ternaryOp(llvm::Function* _op, llvm::Value* _arg1, llvm::Value* _arg2, llvm::Value* _arg3); + + llvm::Function* m_mul; + llvm::Function* m_div; + llvm::Function* m_mod; + llvm::Function* m_sdiv; + llvm::Function* m_smod; + llvm::Function* m_exp; + llvm::Function* m_mulmod; + llvm::Function* m_addmod; + + llvm::Value* m_arg1; + llvm::Value* m_arg2; + llvm::Value* m_arg3; + llvm::Value* m_result; +}; + + +} +} +} diff --git a/libevmjit/BasicBlock.cpp b/libevmjit/BasicBlock.cpp new file mode 100644 index 000000000..d233ea744 --- /dev/null +++ b/libevmjit/BasicBlock.cpp @@ -0,0 +1,380 @@ + +#include "BasicBlock.h" + +#include + +#include +#include +#include +#include +#include + +#include "Type.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +const char* BasicBlock::NamePrefix = "Instr."; + +BasicBlock::BasicBlock(ProgramCounter _beginInstIdx, ProgramCounter _endInstIdx, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder) : + m_beginInstIdx(_beginInstIdx), + m_endInstIdx(_endInstIdx), + m_llvmBB(llvm::BasicBlock::Create(_mainFunc->getContext(), {NamePrefix, std::to_string(_beginInstIdx)}, _mainFunc)), + m_stack(*this), + m_builder(_builder) +{} + +BasicBlock::BasicBlock(std::string _name, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder) : + m_beginInstIdx(0), + m_endInstIdx(0), + m_llvmBB(llvm::BasicBlock::Create(_mainFunc->getContext(), _name, _mainFunc)), + m_stack(*this), + m_builder(_builder) +{} + +BasicBlock::LocalStack::LocalStack(BasicBlock& _owner) : + m_bblock(_owner) +{} + +void BasicBlock::LocalStack::push(llvm::Value* _value) +{ + m_bblock.m_currentStack.push_back(_value); + m_bblock.m_tosOffset += 1; +} + +llvm::Value* BasicBlock::LocalStack::pop() +{ + auto result = get(0); + + if (m_bblock.m_currentStack.size() > 0) + m_bblock.m_currentStack.pop_back(); + + m_bblock.m_tosOffset -= 1; + return result; +} + +/** + * Pushes a copy of _index-th element (tos is 0-th elem). + */ +void BasicBlock::LocalStack::dup(size_t _index) +{ + auto val = get(_index); + push(val); +} + +/** + * Swaps tos with _index-th element (tos is 0-th elem). + * _index must be > 0. + */ +void BasicBlock::LocalStack::swap(size_t _index) +{ + assert(_index > 0); + auto val = get(_index); + auto tos = get(0); + set(_index, tos); + set(0, val); +} + +std::vector::iterator BasicBlock::LocalStack::getItemIterator(size_t _index) +{ + auto& currentStack = m_bblock.m_currentStack; + if (_index < currentStack.size()) + return currentStack.end() - _index - 1; + + // Need to map more elements from the EVM stack + auto nNewItems = 1 + _index - currentStack.size(); + currentStack.insert(currentStack.begin(), nNewItems, nullptr); + + return currentStack.end() - _index - 1; +} + +llvm::Value* BasicBlock::LocalStack::get(size_t _index) +{ + auto& initialStack = m_bblock.m_initialStack; + auto itemIter = getItemIterator(_index); + + if (*itemIter == nullptr) + { + // Need to fetch a new item from the EVM stack + assert(static_cast(_index) >= m_bblock.m_tosOffset); + size_t initialIdx = _index - m_bblock.m_tosOffset; + if (initialIdx >= initialStack.size()) + { + auto nNewItems = 1 + initialIdx - initialStack.size(); + initialStack.insert(initialStack.end(), nNewItems, nullptr); + } + + assert(initialStack[initialIdx] == nullptr); + // Create a dummy value. + std::string name = "get_" + std::to_string(_index); + initialStack[initialIdx] = m_bblock.m_builder.CreatePHI(Type::Word, 0, std::move(name)); + *itemIter = initialStack[initialIdx]; + } + + return *itemIter; +} + +void BasicBlock::LocalStack::set(size_t _index, llvm::Value* _word) +{ + auto itemIter = getItemIterator(_index); + *itemIter = _word; +} + + + + + +void BasicBlock::synchronizeLocalStack(Stack& _evmStack) +{ + auto blockTerminator = m_llvmBB->getTerminator(); + assert(blockTerminator != nullptr); + m_builder.SetInsertPoint(blockTerminator); + + auto currIter = m_currentStack.begin(); + auto endIter = m_currentStack.end(); + + // Update (emit set()) changed values + for (int idx = m_currentStack.size() - 1 - m_tosOffset; + currIter < endIter && idx >= 0; + ++currIter, --idx) + { + assert(static_cast(idx) < m_initialStack.size()); + if (*currIter != m_initialStack[idx]) // value needs update + _evmStack.set(static_cast(idx), *currIter); + } + + if (m_tosOffset < 0) + { + // Pop values + _evmStack.pop(static_cast(-m_tosOffset)); + } + + // Push new values + for (; currIter < endIter; ++currIter) + { + assert(*currIter != nullptr); + _evmStack.push(*currIter); + } + + // Emit get() for all (used) values from the initial stack + for (size_t idx = 0; idx < m_initialStack.size(); ++idx) + { + auto val = m_initialStack[idx]; + if (val == nullptr) + continue; + + assert(llvm::isa(val)); + llvm::PHINode* phi = llvm::cast(val); + if (! phi->use_empty()) + { + // Insert call to get() just before the PHI node and replace + // the uses of PHI with the uses of this new instruction. + m_builder.SetInsertPoint(phi); + auto newVal = _evmStack.get(idx); + phi->replaceAllUsesWith(newVal); + } + phi->eraseFromParent(); + } + + // Reset the stack + m_initialStack.erase(m_initialStack.begin(), m_initialStack.end()); + m_currentStack.erase(m_currentStack.begin(), m_currentStack.end()); + m_tosOffset = 0; +} + +void BasicBlock::linkLocalStacks(std::vector basicBlocks, llvm::IRBuilder<>& _builder) +{ + struct BBInfo + { + BasicBlock& bblock; + std::vector predecessors; + size_t inputItems; + size_t outputItems; + std::vector phisToRewrite; + + BBInfo(BasicBlock& _bblock) : + bblock(_bblock), + predecessors(), + inputItems(0), + outputItems(0) + { + auto& initialStack = bblock.m_initialStack; + for (auto it = initialStack.begin(); + it != initialStack.end() && *it != nullptr; + ++it, ++inputItems); + + //if (bblock.localStack().m_tosOffset > 0) + // outputItems = bblock.localStack().m_tosOffset; + auto& exitStack = bblock.m_currentStack; + for (auto it = exitStack.rbegin(); + it != exitStack.rend() && *it != nullptr; + ++it, ++outputItems); + } + }; + + std::map cfg; + + // Create nodes in cfg + for (auto bb : basicBlocks) + cfg.emplace(bb->llvm(), *bb); + + // Create edges in cfg: for each bb info fill the list + // of predecessor infos. + for (auto& pair : cfg) + { + auto bb = pair.first; + auto& info = pair.second; + + for (auto predIt = llvm::pred_begin(bb); predIt != llvm::pred_end(bb); ++predIt) + { + auto predInfoEntry = cfg.find(*predIt); + if (predInfoEntry != cfg.end()) + info.predecessors.push_back(&predInfoEntry->second); + } + } + + // Iteratively compute inputs and outputs of each block, until reaching fixpoint. + bool valuesChanged = true; + while (valuesChanged) + { + if (getenv("EVMCC_DEBUG_BLOCKS")) + { + for (auto& pair : cfg) + std::cerr << pair.second.bblock.llvm()->getName().str() + << ": in " << pair.second.inputItems + << ", out " << pair.second.outputItems + << "\n"; + } + + valuesChanged = false; + for (auto& pair : cfg) + { + auto& info = pair.second; + + if (info.predecessors.empty()) + info.inputItems = 0; // no consequences for other blocks, so leave valuesChanged false + + for (auto predInfo : info.predecessors) + { + if (predInfo->outputItems < info.inputItems) + { + info.inputItems = predInfo->outputItems; + valuesChanged = true; + } + else if (predInfo->outputItems > info.inputItems) + { + predInfo->outputItems = info.inputItems; + valuesChanged = true; + } + } + } + } + + // Propagate values between blocks. + for (auto& entry : cfg) + { + auto& info = entry.second; + auto& bblock = info.bblock; + + llvm::BasicBlock::iterator fstNonPhi(bblock.llvm()->getFirstNonPHI()); + auto phiIter = bblock.m_initialStack.begin(); + for (size_t index = 0; index < info.inputItems; ++index, ++phiIter) + { + assert(llvm::isa(*phiIter)); + auto phi = llvm::cast(*phiIter); + + for (auto predIt : info.predecessors) + { + auto& predExitStack = predIt->bblock.m_currentStack; + auto value = *(predExitStack.end() - 1 - index); + phi->addIncoming(value, predIt->bblock.llvm()); + } + + // Move phi to the front + if (llvm::BasicBlock::iterator(phi) != bblock.llvm()->begin()) + { + phi->removeFromParent(); + _builder.SetInsertPoint(bblock.llvm(), bblock.llvm()->begin()); + _builder.Insert(phi); + } + } + + // The items pulled directly from predecessors block must be removed + // from the list of items that has to be popped from the initial stack. + auto& initialStack = bblock.m_initialStack; + initialStack.erase(initialStack.begin(), initialStack.begin() + info.inputItems); + // Initial stack shrinks, so the size difference grows: + bblock.m_tosOffset += info.inputItems; + } + + // We must account for the items that were pushed directly to successor + // blocks and thus should not be on the list of items to be pushed onto + // to EVM stack + for (auto& entry : cfg) + { + auto& info = entry.second; + auto& bblock = info.bblock; + + auto& exitStack = bblock.m_currentStack; + exitStack.erase(exitStack.end() - info.outputItems, exitStack.end()); + bblock.m_tosOffset -= info.outputItems; + } +} + +void BasicBlock::dump() +{ + dump(std::cerr, false); +} + +void BasicBlock::dump(std::ostream& _out, bool _dotOutput) +{ + llvm::raw_os_ostream out(_out); + + out << (_dotOutput ? "" : "Initial stack:\n"); + for (auto val : m_initialStack) + { + if (val == nullptr) + out << " ?"; + else if (llvm::isa(val)) + out << *val; + else + out << " " << *val; + + out << (_dotOutput ? "\\l" : "\n"); + } + + out << (_dotOutput ? "| " : "Instructions:\n"); + for (auto ins = m_llvmBB->begin(); ins != m_llvmBB->end(); ++ins) + out << *ins << (_dotOutput ? "\\l" : "\n"); + + if (! _dotOutput) + out << "Current stack (offset = " << m_tosOffset << "):\n"; + else + out << "|"; + + for (auto val = m_currentStack.rbegin(); val != m_currentStack.rend(); ++val) + { + if (*val == nullptr) + out << " ?"; + else if (llvm::isa(*val)) + out << **val; + else + out << " " << **val; + out << (_dotOutput ? "\\l" : "\n"); + } + + if (! _dotOutput) + out << " ...\n----------------------------------------\n"; +} + + + + +} +} +} + diff --git a/libevmjit/BasicBlock.h b/libevmjit/BasicBlock.h new file mode 100644 index 000000000..f0643f342 --- /dev/null +++ b/libevmjit/BasicBlock.h @@ -0,0 +1,117 @@ +#pragma once + +#include + +#include + +#include "Stack.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +using ProgramCounter = uint64_t; // TODO: Rename + +class BasicBlock +{ +public: + class LocalStack + { + public: + /// Pushes value on stack + void push(llvm::Value* _value); + + /// Pops and returns top value + llvm::Value* pop(); + + /// Duplicates _index'th value on stack + void dup(size_t _index); + + /// Swaps _index'th value on stack with a value on stack top. + /// @param _index Index of value to be swaped. Must be > 0. + void swap(size_t _index); + + private: + LocalStack(BasicBlock& _owner); + LocalStack(LocalStack const&) = delete; + void operator=(LocalStack const&) = delete; + friend BasicBlock; + + /// Gets _index'th value from top (counting from 0) + llvm::Value* get(size_t _index); + + /// Sets _index'th value from top (counting from 0) + void set(size_t _index, llvm::Value* _value); + + std::vector::iterator getItemIterator(size_t _index); + + private: + BasicBlock& m_bblock; + }; + + /// Basic block name prefix. The rest is beging instruction index. + static const char* NamePrefix; + + explicit BasicBlock(ProgramCounter _beginInstIdx, ProgramCounter _endInstIdx, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder); + explicit BasicBlock(std::string _name, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder); + + BasicBlock(const BasicBlock&) = delete; + void operator=(const BasicBlock&) = delete; + + operator llvm::BasicBlock*() { return m_llvmBB; } + llvm::BasicBlock* llvm() { return m_llvmBB; } + + ProgramCounter begin() { return m_beginInstIdx; } + ProgramCounter end() { return m_endInstIdx; } + + LocalStack& localStack() { return m_stack; } + + /// Optimization: propagates values between local stacks in basic blocks + /// to avoid excessive pushing/popping on the EVM stack. + static void linkLocalStacks(std::vector _basicBlocks, llvm::IRBuilder<>& _builder); + + /// Synchronize current local stack with the EVM stack. + void synchronizeLocalStack(Stack& _evmStack); + + /// Prints local stack and block instructions to stderr. + /// Useful for calling in a debugger session. + void dump(); + void dump(std::ostream& os, bool _dotOutput = false); + +private: + ProgramCounter const m_beginInstIdx; + ProgramCounter const m_endInstIdx; + + llvm::BasicBlock* const m_llvmBB; + + /// Basic black state vector (stack) - current/end values and their positions on stack + /// @internal Must be AFTER m_llvmBB + LocalStack m_stack; + + llvm::IRBuilder<>& m_builder; + + /// This stack contains LLVM values that correspond to items found at + /// the EVM stack when the current basic block starts executing. + /// Location 0 corresponds to the top of the EVM stack, location 1 is + /// the item below the top and so on. The stack grows as the code + /// accesses more items on the EVM stack but once a value is put on + /// the stack, it will never be replaced. + std::vector m_initialStack = {}; + + /// This stack tracks the contents of the EVM stack as the basic block + /// executes. It may grow on both sides, as the code pushes items on + /// top of the stack or changes existing items. + std::vector m_currentStack = {}; + + /// How many items higher is the current stack than the initial one. + /// May be negative. + int m_tosOffset = 0; +}; + +} +} +} + diff --git a/libevmjit/CMakeLists.txt b/libevmjit/CMakeLists.txt new file mode 100644 index 000000000..7c35169a7 --- /dev/null +++ b/libevmjit/CMakeLists.txt @@ -0,0 +1,24 @@ +set(TARGET_NAME evmjit) + +file(GLOB SOURCES "*.cpp") +file(GLOB HEADERS "*.h") +source_group("" FILES ${HEADERS}) +source_group("" FILES ${SOURCES}) + +if (NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") + # Disable rtti for Cache as LLVM has no rtti + set_source_files_properties(Cache.cpp PROPERTIES COMPILE_FLAGS -fno-rtti) +endif () + +add_library(${TARGET_NAME} ${SOURCES} ${HEADERS}) +set_property(TARGET ${TARGET_NAME} PROPERTY FOLDER "libs") + +include_directories(${LLVM_INCLUDE_DIRS}) +include_directories(${Boost_INCLUDE_DIRS}) + +target_link_libraries(${TARGET_NAME} ${LLVM_LIBS}) + +#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti") + +#install( TARGETS ${EXECUTABLE} ARCHIVE DESTINATION lib LIBRARY DESTINATION lib ) +#install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} ) diff --git a/libevmjit/Cache.cpp b/libevmjit/Cache.cpp new file mode 100644 index 000000000..a887d91e9 --- /dev/null +++ b/libevmjit/Cache.cpp @@ -0,0 +1,60 @@ +#include "Cache.h" +#include +#include +#include +#include +#include +#include +#include + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +//#define LOG(...) std::cerr << "CACHE " +#define LOG(...) std::ostream(nullptr) + +ObjectCache* Cache::getObjectCache() +{ + static ObjectCache objectCache; + return &objectCache; +} + + +void ObjectCache::notifyObjectCompiled(llvm::Module const* _module, llvm::MemoryBuffer const* _object) +{ + auto&& id = _module->getModuleIdentifier(); + llvm::SmallString<256> cachePath; + llvm::sys::path::system_temp_directory(false, cachePath); + llvm::sys::path::append(cachePath, "evm_objs"); + + if (llvm::sys::fs::create_directory(cachePath.str())) + return; // TODO: Add log + + llvm::sys::path::append(cachePath, id); + + std::string error; + llvm::raw_fd_ostream cacheFile(cachePath.c_str(), error, llvm::sys::fs::F_None); + cacheFile << _object->getBuffer(); +} + +llvm::MemoryBuffer* ObjectCache::getObject(llvm::Module const* _module) +{ + auto&& id = _module->getModuleIdentifier(); + llvm::SmallString<256> cachePath; + llvm::sys::path::system_temp_directory(false, cachePath); + llvm::sys::path::append(cachePath, "evm_objs", id); + + if (auto r = llvm::MemoryBuffer::getFile(cachePath.str(), -1, false)) + return llvm::MemoryBuffer::getMemBufferCopy(r.get()->getBuffer()); + else if (r.getError() != std::make_error_code(std::errc::no_such_file_or_directory)) + std::cerr << r.getError().message(); // TODO: Add log + return nullptr; +} + +} +} +} diff --git a/libevmjit/Cache.h b/libevmjit/Cache.h new file mode 100644 index 000000000..80fe47ade --- /dev/null +++ b/libevmjit/Cache.h @@ -0,0 +1,41 @@ +#pragma once + +#include +#include +#include +#include + + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +class ObjectCache : public llvm::ObjectCache +{ +public: + /// notifyObjectCompiled - Provides a pointer to compiled code for Module M. + virtual void notifyObjectCompiled(llvm::Module const* _module, llvm::MemoryBuffer const* _object) final override; + + /// getObjectCopy - Returns a pointer to a newly allocated MemoryBuffer that + /// contains the object which corresponds with Module M, or 0 if an object is + /// not available. The caller owns both the MemoryBuffer returned by this + /// and the memory it references. + virtual llvm::MemoryBuffer* getObject(llvm::Module const* _module) final override; + +private: + std::unordered_map> m_map; +}; + + +class Cache +{ +public: + static ObjectCache* getObjectCache(); +}; + +} +} +} diff --git a/libevmjit/Common.h b/libevmjit/Common.h new file mode 100644 index 000000000..d98cc0acb --- /dev/null +++ b/libevmjit/Common.h @@ -0,0 +1,49 @@ +#pragma once + +#include +#include + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +using byte = uint8_t; +using bytes = std::vector; +using u256 = boost::multiprecision::uint256_t; +using bigint = boost::multiprecision::cpp_int; + +struct NoteChannel {}; // FIXME: Use some log library? + +enum class ReturnCode +{ + Stop = 0, + Return = 1, + Suicide = 2, + + BadJumpDestination = 101, + OutOfGas = 102, + StackTooSmall = 103, + BadInstruction = 104, + + LLVMConfigError = 201, + LLVMCompileError = 202, + LLVMLinkError = 203, +}; + +/// Representation of 256-bit value binary compatible with LLVM i256 +// TODO: Replace with h256 +struct i256 +{ + uint64_t a; + uint64_t b; + uint64_t c; + uint64_t d; +}; +static_assert(sizeof(i256) == 32, "Wrong i265 size"); + +} +} +} diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp new file mode 100644 index 000000000..48dc50d60 --- /dev/null +++ b/libevmjit/Compiler.cpp @@ -0,0 +1,949 @@ + +#include "Compiler.h" + +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include +#include + +#include "Instruction.h" +#include "Type.h" +#include "Memory.h" +#include "Stack.h" +#include "Ext.h" +#include "GasMeter.h" +#include "Utils.h" +#include "Endianness.h" +#include "Arith256.h" +#include "RuntimeManager.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +Compiler::Compiler(Options const& _options): + m_options(_options), + m_builder(llvm::getGlobalContext()) +{ + Type::init(m_builder.getContext()); +} + +void Compiler::createBasicBlocks(bytes const& _bytecode) +{ + std::set splitPoints; // Sorted collections of instruction indices where basic blocks start/end + + std::map directJumpTargets; + std::vector indirectJumpTargets; + boost::dynamic_bitset<> validJumpTargets(std::max(_bytecode.size(), size_t(1))); + + splitPoints.insert(0); // First basic block + validJumpTargets[0] = true; + + for (auto curr = _bytecode.begin(); curr != _bytecode.end(); ++curr) + { + ProgramCounter currentPC = curr - _bytecode.begin(); + validJumpTargets[currentPC] = true; + + auto inst = Instruction(*curr); + switch (inst) + { + + case Instruction::ANY_PUSH: + { + auto val = readPushData(curr, _bytecode.end()); + auto next = curr + 1; + if (next == _bytecode.end()) + break; + + auto nextInst = Instruction(*next); + if (nextInst == Instruction::JUMP || nextInst == Instruction::JUMPI) + { + // Create a block for the JUMP target. + ProgramCounter targetPC = val.ult(_bytecode.size()) ? val.getZExtValue() : _bytecode.size(); + splitPoints.insert(targetPC); + + ProgramCounter jumpPC = (next - _bytecode.begin()); + directJumpTargets[jumpPC] = targetPC; + } + break; + } + + case Instruction::JUMPDEST: + { + // A basic block starts here. + splitPoints.insert(currentPC); + indirectJumpTargets.push_back(currentPC); + break; + } + + case Instruction::JUMP: + case Instruction::JUMPI: + case Instruction::RETURN: + case Instruction::STOP: + case Instruction::SUICIDE: + { + // Create a basic block starting at the following instruction. + if (curr + 1 < _bytecode.end()) + splitPoints.insert(currentPC + 1); + break; + } + + default: + break; + } + } + + // Remove split points generated from jumps out of code or into data. + for (auto it = splitPoints.cbegin(); it != splitPoints.cend();) + { + if (*it > _bytecode.size() || !validJumpTargets[*it]) + it = splitPoints.erase(it); + else + ++it; + } + + for (auto it = splitPoints.cbegin(); it != splitPoints.cend();) + { + auto beginInstIdx = *it; + ++it; + auto endInstIdx = it != splitPoints.cend() ? *it : _bytecode.size(); + basicBlocks.emplace(std::piecewise_construct, std::forward_as_tuple(beginInstIdx), std::forward_as_tuple(beginInstIdx, endInstIdx, m_mainFunc, m_builder)); + } + + m_stopBB = llvm::BasicBlock::Create(m_mainFunc->getContext(), "Stop", m_mainFunc); + m_badJumpBlock = std::unique_ptr(new BasicBlock("BadJumpBlock", m_mainFunc, m_builder)); + m_jumpTableBlock = std::unique_ptr(new BasicBlock("JumpTableBlock", m_mainFunc, m_builder)); + + for (auto it = directJumpTargets.cbegin(); it != directJumpTargets.cend(); ++it) + { + if (it->second >= _bytecode.size()) + { + // Jumping out of code means STOP + m_directJumpTargets[it->first] = m_stopBB; + continue; + } + + auto blockIter = basicBlocks.find(it->second); + if (blockIter != basicBlocks.end()) + { + m_directJumpTargets[it->first] = blockIter->second.llvm(); + } + else + { + clog(JIT) << "Bad JUMP at PC " << it->first + << ": " << it->second << " is not a valid PC"; + m_directJumpTargets[it->first] = m_badJumpBlock->llvm(); + } + } + + for (auto it = indirectJumpTargets.cbegin(); it != indirectJumpTargets.cend(); ++it) + m_indirectJumpTargets.push_back(&basicBlocks.find(*it)->second); +} + +std::unique_ptr Compiler::compile(bytes const& _bytecode, std::string const& _id) +{ + auto compilationStartTime = std::chrono::high_resolution_clock::now(); + auto module = std::unique_ptr(new llvm::Module(_id, m_builder.getContext())); + + // Create main function + auto mainFuncType = llvm::FunctionType::get(Type::MainReturn, Type::RuntimePtr, false); + m_mainFunc = llvm::Function::Create(mainFuncType, llvm::Function::ExternalLinkage, _id, module.get()); + m_mainFunc->getArgumentList().front().setName("rt"); + + // Create the basic blocks. + auto entryBlock = llvm::BasicBlock::Create(m_builder.getContext(), "entry", m_mainFunc); + m_builder.SetInsertPoint(entryBlock); + + createBasicBlocks(_bytecode); + + // Init runtime structures. + RuntimeManager runtimeManager(m_builder); + GasMeter gasMeter(m_builder, runtimeManager); + Memory memory(runtimeManager, gasMeter); + Ext ext(runtimeManager, memory); + Stack stack(m_builder, runtimeManager); + Arith256 arith(m_builder); + + m_builder.CreateBr(basicBlocks.begin()->second); + + for (auto basicBlockPairIt = basicBlocks.begin(); basicBlockPairIt != basicBlocks.end(); ++basicBlockPairIt) + { + auto& basicBlock = basicBlockPairIt->second; + auto iterCopy = basicBlockPairIt; + ++iterCopy; + auto nextBasicBlock = (iterCopy != basicBlocks.end()) ? iterCopy->second.llvm() : nullptr; + compileBasicBlock(basicBlock, _bytecode, runtimeManager, arith, memory, ext, gasMeter, nextBasicBlock); + } + + // Code for special blocks: + // TODO: move to separate function. + m_builder.SetInsertPoint(m_stopBB); + m_builder.CreateRet(Constant::get(ReturnCode::Stop)); + + m_builder.SetInsertPoint(m_badJumpBlock->llvm()); + m_builder.CreateRet(Constant::get(ReturnCode::BadJumpDestination)); + + m_builder.SetInsertPoint(m_jumpTableBlock->llvm()); + if (m_indirectJumpTargets.size() > 0) + { + auto dest = m_jumpTableBlock->localStack().pop(); + auto switchInstr = m_builder.CreateSwitch(dest, m_badJumpBlock->llvm(), + m_indirectJumpTargets.size()); + for (auto it = m_indirectJumpTargets.cbegin(); it != m_indirectJumpTargets.cend(); ++it) + { + auto& bb = *it; + auto dest = Constant::get(bb->begin()); + switchInstr->addCase(dest, bb->llvm()); + } + } + else + m_builder.CreateBr(m_badJumpBlock->llvm()); + + removeDeadBlocks(); + + dumpCFGifRequired("blocks-init.dot"); + + if (m_options.optimizeStack) + { + std::vector blockList; + for (auto& entry : basicBlocks) + blockList.push_back(&entry.second); + + if (m_jumpTableBlock) + blockList.push_back(m_jumpTableBlock.get()); + + BasicBlock::linkLocalStacks(blockList, m_builder); + + dumpCFGifRequired("blocks-opt.dot"); + } + + for (auto& entry : basicBlocks) + entry.second.synchronizeLocalStack(stack); + if (m_jumpTableBlock) + m_jumpTableBlock->synchronizeLocalStack(stack); + + dumpCFGifRequired("blocks-sync.dot"); + + if (m_jumpTableBlock && m_options.rewriteSwitchToBranches) + { + llvm::FunctionPassManager fpManager(module.get()); + fpManager.add(llvm::createLowerSwitchPass()); + fpManager.doInitialization(); + fpManager.run(*m_mainFunc); + } + + auto compilationEndTime = std::chrono::high_resolution_clock::now(); + clog(JIT) << "JIT: " << std::chrono::duration_cast(compilationEndTime - compilationStartTime).count(); + return module; +} + + +void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode, RuntimeManager& _runtimeManager, + Arith256& _arith, Memory& _memory, Ext& _ext, GasMeter& _gasMeter, llvm::BasicBlock* _nextBasicBlock) +{ + if (!_nextBasicBlock) // this is the last block in the code + _nextBasicBlock = m_stopBB; + + m_builder.SetInsertPoint(_basicBlock.llvm()); + auto& stack = _basicBlock.localStack(); + + for (auto currentPC = _basicBlock.begin(); currentPC != _basicBlock.end(); ++currentPC) + { + auto inst = static_cast(_bytecode[currentPC]); + + _gasMeter.count(inst); + + switch (inst) + { + + case Instruction::ADD: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto result = m_builder.CreateAdd(lhs, rhs); + stack.push(result); + break; + } + + case Instruction::SUB: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto result = m_builder.CreateSub(lhs, rhs); + stack.push(result); + break; + } + + case Instruction::MUL: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res = _arith.mul(lhs, rhs); + stack.push(res); + break; + } + + case Instruction::DIV: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res = _arith.div(lhs, rhs); + stack.push(res); + break; + } + + case Instruction::SDIV: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res = _arith.sdiv(lhs, rhs); + stack.push(res); + break; + } + + case Instruction::MOD: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res = _arith.mod(lhs, rhs); + stack.push(res); + break; + } + + case Instruction::SMOD: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res = _arith.smod(lhs, rhs); + stack.push(res); + break; + } + + case Instruction::EXP: + { + auto base = stack.pop(); + auto exponent = stack.pop(); + _gasMeter.countExp(exponent); + auto ret = _arith.exp(base, exponent); + stack.push(ret); + break; + } + + case Instruction::NOT: + { + auto value = stack.pop(); + auto ret = m_builder.CreateXor(value, Constant::get(-1), "bnot"); + stack.push(ret); + break; + } + + case Instruction::LT: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res1 = m_builder.CreateICmpULT(lhs, rhs); + auto res256 = m_builder.CreateZExt(res1, Type::Word); + stack.push(res256); + break; + } + + case Instruction::GT: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res1 = m_builder.CreateICmpUGT(lhs, rhs); + auto res256 = m_builder.CreateZExt(res1, Type::Word); + stack.push(res256); + break; + } + + case Instruction::SLT: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res1 = m_builder.CreateICmpSLT(lhs, rhs); + auto res256 = m_builder.CreateZExt(res1, Type::Word); + stack.push(res256); + break; + } + + case Instruction::SGT: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res1 = m_builder.CreateICmpSGT(lhs, rhs); + auto res256 = m_builder.CreateZExt(res1, Type::Word); + stack.push(res256); + break; + } + + case Instruction::EQ: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res1 = m_builder.CreateICmpEQ(lhs, rhs); + auto res256 = m_builder.CreateZExt(res1, Type::Word); + stack.push(res256); + break; + } + + case Instruction::ISZERO: + { + auto top = stack.pop(); + auto iszero = m_builder.CreateICmpEQ(top, Constant::get(0), "iszero"); + auto result = m_builder.CreateZExt(iszero, Type::Word); + stack.push(result); + break; + } + + case Instruction::AND: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res = m_builder.CreateAnd(lhs, rhs); + stack.push(res); + break; + } + + case Instruction::OR: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res = m_builder.CreateOr(lhs, rhs); + stack.push(res); + break; + } + + case Instruction::XOR: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res = m_builder.CreateXor(lhs, rhs); + stack.push(res); + break; + } + + case Instruction::BYTE: + { + const auto byteNum = stack.pop(); + auto value = stack.pop(); + + value = Endianness::toBE(m_builder, value); + auto bytes = m_builder.CreateBitCast(value, llvm::VectorType::get(Type::Byte, 32), "bytes"); + auto byte = m_builder.CreateExtractElement(bytes, byteNum, "byte"); + value = m_builder.CreateZExt(byte, Type::Word); + + auto byteNumValid = m_builder.CreateICmpULT(byteNum, Constant::get(32)); + value = m_builder.CreateSelect(byteNumValid, value, Constant::get(0)); + stack.push(value); + break; + } + + case Instruction::ADDMOD: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto mod = stack.pop(); + auto res = _arith.addmod(lhs, rhs, mod); + stack.push(res); + break; + } + + case Instruction::MULMOD: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto mod = stack.pop(); + auto res = _arith.mulmod(lhs, rhs, mod); + stack.push(res); + break; + } + + case Instruction::SIGNEXTEND: + { + auto idx = stack.pop(); + auto word = stack.pop(); + + auto k32_ = m_builder.CreateTrunc(idx, m_builder.getIntNTy(5), "k_32"); + auto k32 = m_builder.CreateZExt(k32_, Type::Word); + auto k32x8 = m_builder.CreateMul(k32, Constant::get(8), "kx8"); + + // test for word >> (k * 8 + 7) + auto bitpos = m_builder.CreateAdd(k32x8, Constant::get(7), "bitpos"); + auto bitval = m_builder.CreateLShr(word, bitpos, "bitval"); + auto bittest = m_builder.CreateTrunc(bitval, Type::Bool, "bittest"); + + auto mask_ = m_builder.CreateShl(Constant::get(1), bitpos); + auto mask = m_builder.CreateSub(mask_, Constant::get(1), "mask"); + + auto negmask = m_builder.CreateXor(mask, llvm::ConstantInt::getAllOnesValue(Type::Word), "negmask"); + auto val1 = m_builder.CreateOr(word, negmask); + auto val0 = m_builder.CreateAnd(word, mask); + + auto kInRange = m_builder.CreateICmpULE(idx, llvm::ConstantInt::get(Type::Word, 30)); + auto result = m_builder.CreateSelect(kInRange, + m_builder.CreateSelect(bittest, val1, val0), + word); + stack.push(result); + break; + } + + case Instruction::SHA3: + { + auto inOff = stack.pop(); + auto inSize = stack.pop(); + _memory.require(inOff, inSize); + _gasMeter.countSha3Data(inSize); + auto hash = _ext.sha3(inOff, inSize); + stack.push(hash); + break; + } + + case Instruction::POP: + { + auto val = stack.pop(); + static_cast(val); + // Generate a dummy use of val to make sure that a get(0) will be emitted at this point, + // so that StackTooSmall will be thrown + // m_builder.CreateICmpEQ(val, val, "dummy"); + break; + } + + case Instruction::ANY_PUSH: + { + auto curr = _bytecode.begin() + currentPC; // TODO: replace currentPC with iterator + auto value = readPushData(curr, _bytecode.end()); + currentPC = curr - _bytecode.begin(); + + stack.push(Constant::get(value)); + break; + } + + case Instruction::ANY_DUP: + { + auto index = static_cast(inst) - static_cast(Instruction::DUP1); + stack.dup(index); + break; + } + + case Instruction::ANY_SWAP: + { + auto index = static_cast(inst) - static_cast(Instruction::SWAP1) + 1; + stack.swap(index); + break; + } + + case Instruction::MLOAD: + { + auto addr = stack.pop(); + auto word = _memory.loadWord(addr); + stack.push(word); + break; + } + + case Instruction::MSTORE: + { + auto addr = stack.pop(); + auto word = stack.pop(); + _memory.storeWord(addr, word); + break; + } + + case Instruction::MSTORE8: + { + auto addr = stack.pop(); + auto word = stack.pop(); + _memory.storeByte(addr, word); + break; + } + + case Instruction::MSIZE: + { + auto word = _memory.getSize(); + stack.push(word); + break; + } + + case Instruction::SLOAD: + { + auto index = stack.pop(); + auto value = _ext.sload(index); + stack.push(value); + break; + } + + case Instruction::SSTORE: + { + auto index = stack.pop(); + auto value = stack.pop(); + _gasMeter.countSStore(_ext, index, value); + _ext.sstore(index, value); + break; + } + + case Instruction::JUMP: + case Instruction::JUMPI: + { + // Generate direct jump iff: + // 1. this is not the first instruction in the block + // 2. m_directJumpTargets[currentPC] is defined (meaning that the previous instruction is a PUSH) + // Otherwise generate a indirect jump (a switch). + llvm::BasicBlock* targetBlock = nullptr; + if (currentPC != _basicBlock.begin()) + { + auto pairIter = m_directJumpTargets.find(currentPC); + if (pairIter != m_directJumpTargets.end()) + targetBlock = pairIter->second; + } + + if (inst == Instruction::JUMP) + { + if (targetBlock) + { + // The target address is computed at compile time, + // just pop it without looking... + stack.pop(); + m_builder.CreateBr(targetBlock); + } + else + m_builder.CreateBr(m_jumpTableBlock->llvm()); + } + else // JUMPI + { + stack.swap(1); + auto val = stack.pop(); + auto zero = Constant::get(0); + auto cond = m_builder.CreateICmpNE(val, zero, "nonzero"); + + if (targetBlock) + { + stack.pop(); + m_builder.CreateCondBr(cond, targetBlock, _nextBasicBlock); + } + else + m_builder.CreateCondBr(cond, m_jumpTableBlock->llvm(), _nextBasicBlock); + } + + break; + } + + case Instruction::JUMPDEST: + { + // Nothing to do + break; + } + + case Instruction::PC: + { + auto value = Constant::get(currentPC); + stack.push(value); + break; + } + + case Instruction::GAS: + { + _gasMeter.commitCostBlock(); + stack.push(_runtimeManager.getGas()); + break; + } + + case Instruction::ADDRESS: + case Instruction::CALLER: + case Instruction::ORIGIN: + case Instruction::CALLVALUE: + case Instruction::CALLDATASIZE: + case Instruction::CODESIZE: + case Instruction::GASPRICE: + case Instruction::PREVHASH: + case Instruction::COINBASE: + case Instruction::TIMESTAMP: + case Instruction::NUMBER: + case Instruction::DIFFICULTY: + case Instruction::GASLIMIT: + { + // Pushes an element of runtime data on stack + stack.push(_runtimeManager.get(inst)); + break; + } + + case Instruction::BALANCE: + { + auto address = stack.pop(); + auto value = _ext.balance(address); + stack.push(value); + break; + } + + case Instruction::EXTCODESIZE: + { + auto addr = stack.pop(); + auto codeRef = _ext.getExtCode(addr); + stack.push(codeRef.size); + break; + } + + case Instruction::CALLDATACOPY: + { + auto destMemIdx = stack.pop(); + auto srcIdx = stack.pop(); + auto reqBytes = stack.pop(); + + auto srcPtr = _runtimeManager.getCallData(); + auto srcSize = _runtimeManager.get(RuntimeData::CallDataSize); + + _memory.copyBytes(srcPtr, srcSize, srcIdx, destMemIdx, reqBytes); + break; + } + + case Instruction::CODECOPY: + { + auto destMemIdx = stack.pop(); + auto srcIdx = stack.pop(); + auto reqBytes = stack.pop(); + + auto srcPtr = _runtimeManager.getCode(); // TODO: Code & its size are constants, feature #80814234 + auto srcSize = _runtimeManager.get(RuntimeData::CodeSize); + + _memory.copyBytes(srcPtr, srcSize, srcIdx, destMemIdx, reqBytes); + break; + } + + case Instruction::EXTCODECOPY: + { + auto addr = stack.pop(); + auto destMemIdx = stack.pop(); + auto srcIdx = stack.pop(); + auto reqBytes = stack.pop(); + + auto codeRef = _ext.getExtCode(addr); + + _memory.copyBytes(codeRef.ptr, codeRef.size, srcIdx, destMemIdx, reqBytes); + break; + } + + case Instruction::CALLDATALOAD: + { + auto index = stack.pop(); + auto value = _ext.calldataload(index); + stack.push(value); + break; + } + + case Instruction::CREATE: + { + auto endowment = stack.pop(); + auto initOff = stack.pop(); + auto initSize = stack.pop(); + _memory.require(initOff, initSize); + + _gasMeter.commitCostBlock(); + + auto gas = _runtimeManager.getGas(); + auto address = _ext.create(gas, endowment, initOff, initSize); + _runtimeManager.setGas(gas); + stack.push(address); + break; + } + + case Instruction::CALL: + case Instruction::CALLCODE: + { + auto gas = stack.pop(); + auto codeAddress = stack.pop(); + auto value = stack.pop(); + auto inOff = stack.pop(); + auto inSize = stack.pop(); + auto outOff = stack.pop(); + auto outSize = stack.pop(); + + _gasMeter.commitCostBlock(); + + // Require memory for in and out buffers + _memory.require(outOff, outSize); // Out buffer first as we guess it will be after the in one + _memory.require(inOff, inSize); + + auto receiveAddress = codeAddress; + if (inst == Instruction::CALLCODE) + receiveAddress = _runtimeManager.get(RuntimeData::Address); + + _gasMeter.count(gas); + auto ret = _ext.call(gas, receiveAddress, value, inOff, inSize, outOff, outSize, codeAddress); + _gasMeter.giveBack(gas); + stack.push(ret); + break; + } + + case Instruction::RETURN: + { + auto index = stack.pop(); + auto size = stack.pop(); + + _memory.require(index, size); + _runtimeManager.registerReturnData(index, size); + + m_builder.CreateRet(Constant::get(ReturnCode::Return)); + break; + } + + case Instruction::SUICIDE: + { + _runtimeManager.registerSuicide(stack.pop()); + m_builder.CreateRet(Constant::get(ReturnCode::Suicide)); + break; + } + + + case Instruction::STOP: + { + m_builder.CreateRet(Constant::get(ReturnCode::Stop)); + break; + } + + case Instruction::LOG0: + case Instruction::LOG1: + case Instruction::LOG2: + case Instruction::LOG3: + case Instruction::LOG4: + { + auto beginIdx = stack.pop(); + auto numBytes = stack.pop(); + _memory.require(beginIdx, numBytes); + + // This will commit the current cost block + _gasMeter.countLogData(numBytes); + + std::array topics{{}}; + auto numTopics = static_cast(inst) - static_cast(Instruction::LOG0); + for (size_t i = 0; i < numTopics; ++i) + topics[i] = stack.pop(); + + _ext.log(beginIdx, numBytes, topics); + break; + } + + default: // Invalid instruction - runtime exception + { + _runtimeManager.raiseException(ReturnCode::BadInstruction); + } + + } + } + + _gasMeter.commitCostBlock(); + + // Block may have no terminator if the next instruction is a jump destination. + if (!_basicBlock.llvm()->getTerminator()) + m_builder.CreateBr(_nextBasicBlock); +} + + + +void Compiler::removeDeadBlocks() +{ + // Remove dead basic blocks + auto sthErased = false; + do + { + sthErased = false; + for (auto it = basicBlocks.begin(); it != basicBlocks.end();) + { + auto llvmBB = it->second.llvm(); + if (llvm::pred_begin(llvmBB) == llvm::pred_end(llvmBB)) + { + llvmBB->eraseFromParent(); + basicBlocks.erase(it++); + sthErased = true; + } + else + ++it; + } + } + while (sthErased); + + // Remove jump table block if no predecessors + if (llvm::pred_begin(m_jumpTableBlock->llvm()) == llvm::pred_end(m_jumpTableBlock->llvm())) + { + m_jumpTableBlock->llvm()->eraseFromParent(); + m_jumpTableBlock.reset(); + } +} + +void Compiler::dumpCFGifRequired(std::string const& _dotfilePath) +{ + if (! m_options.dumpCFG) + return; + + // TODO: handle i/o failures + std::ofstream ofs(_dotfilePath); + dumpCFGtoStream(ofs); + ofs.close(); +} + +void Compiler::dumpCFGtoStream(std::ostream& _out) +{ + _out << "digraph BB {\n" + << " node [shape=record, fontname=Courier, fontsize=10];\n" + << " entry [share=record, label=\"entry block\"];\n"; + + std::vector blocks; + for (auto& pair : basicBlocks) + blocks.push_back(&pair.second); + if (m_jumpTableBlock) + blocks.push_back(m_jumpTableBlock.get()); + if (m_badJumpBlock) + blocks.push_back(m_badJumpBlock.get()); + + // std::map phiNodesPerBlock; + + // Output nodes + for (auto bb : blocks) + { + std::string blockName = bb->llvm()->getName(); + + std::ostringstream oss; + bb->dump(oss, true); + + _out << " \"" << blockName << "\" [shape=record, label=\" { " << blockName << "|" << oss.str() << "} \"];\n"; + } + + // Output edges + for (auto bb : blocks) + { + std::string blockName = bb->llvm()->getName(); + + auto end = llvm::pred_end(bb->llvm()); + for (llvm::pred_iterator it = llvm::pred_begin(bb->llvm()); it != end; ++it) + { + _out << " \"" << (*it)->getName().str() << "\" -> \"" << blockName << "\" [" + << ((m_jumpTableBlock.get() && *it == m_jumpTableBlock.get()->llvm()) ? "style = dashed, " : "") + << "];\n"; + } + } + + _out << "}\n"; +} + +void Compiler::dump() +{ + for (auto& entry : basicBlocks) + entry.second.dump(); + if (m_jumpTableBlock != nullptr) + m_jumpTableBlock->dump(); +} + +} +} +} + diff --git a/libevmjit/Compiler.h b/libevmjit/Compiler.h new file mode 100644 index 000000000..8e3bf357c --- /dev/null +++ b/libevmjit/Compiler.h @@ -0,0 +1,91 @@ + +#pragma once + +#include + +#include "Common.h" +#include "BasicBlock.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +class Compiler +{ +public: + + struct Options + { + /// Optimize stack operations between basic blocks + bool optimizeStack; + + /// Rewrite switch instructions to sequences of branches + bool rewriteSwitchToBranches; + + /// Dump CFG as a .dot file for graphviz + bool dumpCFG; + + Options(): + optimizeStack(true), + rewriteSwitchToBranches(true), + dumpCFG(false) + {} + }; + + using ProgramCounter = uint64_t; + + Compiler(Options const& _options); + + std::unique_ptr compile(bytes const& _bytecode, std::string const& _id); + +private: + + void createBasicBlocks(bytes const& _bytecode); + + void compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode, class RuntimeManager& _runtimeManager, class Arith256& _arith, class Memory& _memory, class Ext& _ext, class GasMeter& _gasMeter, llvm::BasicBlock* _nextBasicBlock); + + void removeDeadBlocks(); + + /// Dumps basic block graph in graphviz format to a file, if option dumpCFG is enabled. + void dumpCFGifRequired(std::string const& _dotfilePath); + + /// Dumps basic block graph in graphviz format to a stream. + void dumpCFGtoStream(std::ostream& _out); + + /// Dumps all basic blocks to stderr. Useful in a debugging session. + void dump(); + + /// Compiler options + Options const& m_options; + + /// Helper class for generating IR + llvm::IRBuilder<> m_builder; + + /// Maps a program counter pc to a basic block that starts at pc (if any). + std::map basicBlocks = {}; + + /// Maps a pc at which there is a JUMP or JUMPI to the target block of the jump. + std::map m_directJumpTargets = {}; + + /// A list of possible blocks to which there may be indirect jumps. + std::vector m_indirectJumpTargets = {}; + + /// Stop basic block - terminates execution with STOP code (0) + llvm::BasicBlock* m_stopBB = nullptr; + + /// Block with a jump table. + std::unique_ptr m_jumpTableBlock = nullptr; + + /// Default destination for indirect jumps. + std::unique_ptr m_badJumpBlock = nullptr; + + /// Main program function + llvm::Function* m_mainFunc = nullptr; +}; + +} +} +} diff --git a/libevmjit/CompilerHelper.cpp b/libevmjit/CompilerHelper.cpp new file mode 100644 index 000000000..badf9d889 --- /dev/null +++ b/libevmjit/CompilerHelper.cpp @@ -0,0 +1,46 @@ + +#include "CompilerHelper.h" + +#include +#include + +#include "RuntimeManager.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +CompilerHelper::CompilerHelper(llvm::IRBuilder<>& _builder) : + m_builder(_builder) +{} + +llvm::Module* CompilerHelper::getModule() +{ + assert(m_builder.GetInsertBlock()); + assert(m_builder.GetInsertBlock()->getParent()); // BB must be in a function + return m_builder.GetInsertBlock()->getParent()->getParent(); +} + +llvm::Function* CompilerHelper::getMainFunction() +{ + // TODO: Rename or change semantics of getMainFunction() function + assert(m_builder.GetInsertBlock()); + auto mainFunc = m_builder.GetInsertBlock()->getParent(); + assert(mainFunc); + if (mainFunc == &mainFunc->getParent()->getFunctionList().front()) // Main function is the first one in module + return mainFunc; + return nullptr; +} + + +RuntimeHelper::RuntimeHelper(RuntimeManager& _runtimeManager): + CompilerHelper(_runtimeManager.getBuilder()), + m_runtimeManager(_runtimeManager) +{} + +} +} +} diff --git a/libevmjit/CompilerHelper.h b/libevmjit/CompilerHelper.h new file mode 100644 index 000000000..19315fe4a --- /dev/null +++ b/libevmjit/CompilerHelper.h @@ -0,0 +1,83 @@ + +#pragma once + +#include + + +namespace dev +{ +namespace eth +{ +namespace jit +{ +class RuntimeManager; + +/// Base class for compiler helpers like Memory, GasMeter, etc. +class CompilerHelper +{ +protected: + CompilerHelper(llvm::IRBuilder<>& _builder); + + CompilerHelper(const CompilerHelper&) = delete; + void operator=(CompilerHelper) = delete; + + /// Reference to the IR module being compiled + llvm::Module* getModule(); + + /// Reference to the main module function + llvm::Function* getMainFunction(); + + /// Reference to parent compiler IR builder + llvm::IRBuilder<>& m_builder; + llvm::IRBuilder<>& getBuilder() { return m_builder; } + + template + llvm::CallInst* createCall(llvm::Function* _func, _Args*... _args) + { + llvm::Value* args[] = {_args...}; + return getBuilder().CreateCall(_func, args); + } + + friend class RuntimeHelper; +}; + + +/// Compiler helper that depends on runtime data +class RuntimeHelper : public CompilerHelper +{ +protected: + RuntimeHelper(RuntimeManager& _runtimeManager); + + RuntimeManager& getRuntimeManager() { return m_runtimeManager; } + +private: + RuntimeManager& m_runtimeManager; +}; + + +/// Saves the insert point of the IR builder and restores it when destructed +struct InsertPointGuard +{ + InsertPointGuard(llvm::IRBuilder<>& _builder) : + m_builder(_builder), + m_insertBB(m_builder.GetInsertBlock()), + m_insertPt(m_builder.GetInsertPoint()) + {} + + InsertPointGuard(const InsertPointGuard&) = delete; + void operator=(InsertPointGuard) = delete; + + ~InsertPointGuard() + { + m_builder.SetInsertPoint(m_insertBB, m_insertPt); + } + +private: + llvm::IRBuilder<>& m_builder; + llvm::BasicBlock* m_insertBB; + llvm::BasicBlock::iterator m_insertPt; +}; + +} +} +} diff --git a/libevmjit/Endianness.cpp b/libevmjit/Endianness.cpp new file mode 100644 index 000000000..db7edfdc9 --- /dev/null +++ b/libevmjit/Endianness.cpp @@ -0,0 +1,38 @@ + +#include "Endianness.h" + +#include + +#include "Type.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +llvm::Value* Endianness::bswapIfLE(llvm::IRBuilder<>& _builder, llvm::Value* _word) +{ + union tester + { + unsigned int x; + unsigned char isLE; + }; + + if (tester{1}.isLE) + { + // FIXME: Disabled because of problems with BYTE + //if (auto constant = llvm::dyn_cast(_word)) + // return _builder.getInt(constant->getValue().byteSwap()); + + // OPT: Cache func declaration? + auto bswapFunc = llvm::Intrinsic::getDeclaration(_builder.GetInsertBlock()->getParent()->getParent(), llvm::Intrinsic::bswap, Type::Word); + return _builder.CreateCall(bswapFunc, _word); + } + return _word; +} + +} +} +} diff --git a/libevmjit/Endianness.h b/libevmjit/Endianness.h new file mode 100644 index 000000000..8a1f41085 --- /dev/null +++ b/libevmjit/Endianness.h @@ -0,0 +1,24 @@ + +#pragma once + +#include + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +struct Endianness +{ + static llvm::Value* toBE(llvm::IRBuilder<>& _builder, llvm::Value* _word) { return bswapIfLE(_builder, _word); } + static llvm::Value* toNative(llvm::IRBuilder<>& _builder, llvm::Value* _word) { return bswapIfLE(_builder, _word); } + +private: + static llvm::Value* bswapIfLE(llvm::IRBuilder<>& _builder, llvm::Value* _word); +}; + +} +} +} diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp new file mode 100644 index 000000000..862586575 --- /dev/null +++ b/libevmjit/ExecutionEngine.cpp @@ -0,0 +1,127 @@ +#include "ExecutionEngine.h" + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "Runtime.h" +#include "Compiler.h" +#include "Cache.h" + +extern "C" void env_sha3(dev::eth::jit::byte const* _begin, uint64_t _size, std::array* o_hash); + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +namespace +{ +typedef ReturnCode(*EntryFuncPtr)(Runtime*); + +ReturnCode runEntryFunc(EntryFuncPtr _mainFunc, Runtime* _runtime) +{ + // That function uses long jumps to handle "execeptions". + // Do not create any non-POD objects here + + ReturnCode returnCode{}; + auto sj = setjmp(_runtime->getJmpBuf()); + if (sj == 0) + returnCode = _mainFunc(_runtime); + else + returnCode = static_cast(sj); + + return returnCode; +} + +std::string codeHash(bytes const& _code) +{ + std::array binHash; + env_sha3(_code.data(), _code.size(), &binHash); + + std::ostringstream os; + for (auto i: binHash) + os << std::hex << std::setfill('0') << std::setw(2) << (int)(std::make_unsigned::type)i; + + return os.str(); +} + +} + +ReturnCode ExecutionEngine::run(bytes const& _code, RuntimeData* _data, Env* _env) +{ + static std::unique_ptr ee; // TODO: Use Managed Objects from LLVM? + + auto mainFuncName = codeHash(_code); + EntryFuncPtr entryFuncPtr{}; + Runtime runtime(_data, _env); // TODO: I don't know why but it must be created before getFunctionAddress() calls + + if (ee && (entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName))) + { + } + else + { + auto module = Compiler({}).compile(_code, mainFuncName); + //module->dump(); + if (!ee) + { + llvm::InitializeNativeTarget(); + llvm::InitializeNativeTargetAsmPrinter(); + + llvm::EngineBuilder builder(module.get()); + builder.setEngineKind(llvm::EngineKind::JIT); + builder.setUseMCJIT(true); + std::unique_ptr memoryManager(new llvm::SectionMemoryManager); + builder.setMCJITMemoryManager(memoryManager.get()); + builder.setOptLevel(llvm::CodeGenOpt::Default); + + auto triple = llvm::Triple(llvm::sys::getProcessTriple()); + if (triple.getOS() == llvm::Triple::OSType::Win32) + triple.setObjectFormat(llvm::Triple::ObjectFormatType::ELF); // MCJIT does not support COFF format + module->setTargetTriple(triple.str()); + + ee.reset(builder.create()); + if (!ee) + return ReturnCode::LLVMConfigError; + + module.release(); // Successfully created llvm::ExecutionEngine takes ownership of the module + memoryManager.release(); // and memory manager + + ee->setObjectCache(Cache::getObjectCache()); + entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName); + } + else + { + if (!entryFuncPtr) + { + ee->addModule(module.get()); + module.release(); + entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName); + } + } + } + assert(entryFuncPtr); + + auto executionStartTime = std::chrono::high_resolution_clock::now(); + + auto returnCode = runEntryFunc(entryFuncPtr, &runtime); + if (returnCode == ReturnCode::Return) + this->returnData = runtime.getReturnData(); + + auto executionEndTime = std::chrono::high_resolution_clock::now(); + clog(JIT) << " + " << std::chrono::duration_cast(executionEndTime - executionStartTime).count() << " ms\n"; + + return returnCode; +} + +} +} +} diff --git a/libevmjit/ExecutionEngine.h b/libevmjit/ExecutionEngine.h new file mode 100644 index 000000000..559701bba --- /dev/null +++ b/libevmjit/ExecutionEngine.h @@ -0,0 +1,26 @@ +#pragma once + +#include "RuntimeData.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +class ExecutionEngine +{ +public: + ExecutionEngine() = default; + ExecutionEngine(ExecutionEngine const&) = delete; + void operator=(ExecutionEngine) = delete; + + ReturnCode run(bytes const& _code, RuntimeData* _data, Env* _env); + + bytes returnData; +}; + +} +} +} diff --git a/libevmjit/Ext.cpp b/libevmjit/Ext.cpp new file mode 100644 index 000000000..38adffd3f --- /dev/null +++ b/libevmjit/Ext.cpp @@ -0,0 +1,178 @@ + +#include "Ext.h" + +#include +#include +#include + +//#include +//#include + +#include "RuntimeManager.h" +#include "Memory.h" +#include "Type.h" +#include "Endianness.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +Ext::Ext(RuntimeManager& _runtimeManager, Memory& _memoryMan): + RuntimeHelper(_runtimeManager), + m_memoryMan(_memoryMan) +{ + auto module = getModule(); + + m_args[0] = m_builder.CreateAlloca(Type::Word, nullptr, "ext.index"); + m_args[1] = m_builder.CreateAlloca(Type::Word, nullptr, "ext.value"); + m_arg2 = m_builder.CreateAlloca(Type::Word, nullptr, "ext.arg2"); + m_arg3 = m_builder.CreateAlloca(Type::Word, nullptr, "ext.arg3"); + m_arg4 = m_builder.CreateAlloca(Type::Word, nullptr, "ext.arg4"); + m_arg5 = m_builder.CreateAlloca(Type::Word, nullptr, "ext.arg5"); + m_arg6 = m_builder.CreateAlloca(Type::Word, nullptr, "ext.arg6"); + m_arg7 = m_builder.CreateAlloca(Type::Word, nullptr, "ext.arg7"); + m_arg8 = m_builder.CreateAlloca(Type::Word, nullptr, "ext.arg8"); + m_size = m_builder.CreateAlloca(Type::Size, nullptr, "env.size"); + + using Linkage = llvm::GlobalValue::LinkageTypes; + + llvm::Type* argsTypes[] = {Type::EnvPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr}; + + m_sload = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 3}, false), Linkage::ExternalLinkage, "env_sload", module); + m_sstore = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 3}, false), Linkage::ExternalLinkage, "env_sstore", module); + + llvm::Type* sha3ArgsTypes[] = {Type::BytePtr, Type::Size, Type::WordPtr}; + m_sha3 = llvm::Function::Create(llvm::FunctionType::get(Type::Void, sha3ArgsTypes, false), Linkage::ExternalLinkage, "env_sha3", module); + + llvm::Type* createArgsTypes[] = {Type::EnvPtr, Type::WordPtr, Type::WordPtr, Type::BytePtr, Type::Size, Type::WordPtr}; + m_create = llvm::Function::Create(llvm::FunctionType::get(Type::Void, createArgsTypes, false), Linkage::ExternalLinkage, "env_create", module); + + llvm::Type* callArgsTypes[] = {Type::EnvPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::BytePtr, Type::Size, Type::BytePtr, Type::Size, Type::WordPtr}; + m_call = llvm::Function::Create(llvm::FunctionType::get(Type::Bool, callArgsTypes, false), Linkage::ExternalLinkage, "env_call", module); + + llvm::Type* logArgsTypes[] = {Type::EnvPtr, Type::BytePtr, Type::Size, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr}; + m_log = llvm::Function::Create(llvm::FunctionType::get(Type::Void, logArgsTypes, false), Linkage::ExternalLinkage, "env_log", module); + + llvm::Type* getExtCodeArgsTypes[] = {Type::EnvPtr, Type::WordPtr, Type::Size->getPointerTo()}; + m_getExtCode = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, getExtCodeArgsTypes, false), Linkage::ExternalLinkage, "env_getExtCode", module); + + // Helper function, not client Env interface + llvm::Type* callDataLoadArgsTypes[] = {Type::RuntimeDataPtr, Type::WordPtr, Type::WordPtr}; + m_calldataload = llvm::Function::Create(llvm::FunctionType::get(Type::Void, callDataLoadArgsTypes, false), Linkage::ExternalLinkage, "ext_calldataload", module); +} + +llvm::Function* Ext::getBalanceFunc() +{ + if (!m_balance) + { + llvm::Type* argsTypes[] = {Type::EnvPtr, Type::WordPtr, Type::WordPtr}; + m_balance = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argsTypes, false), llvm::Function::ExternalLinkage, "env_balance", getModule()); + } + return m_balance; +} + +llvm::Value* Ext::sload(llvm::Value* _index) +{ + m_builder.CreateStore(_index, m_args[0]); + m_builder.CreateCall3(m_sload, getRuntimeManager().getEnvPtr(), m_args[0], m_args[1]); // Uses native endianness + return m_builder.CreateLoad(m_args[1]); +} + +void Ext::sstore(llvm::Value* _index, llvm::Value* _value) +{ + m_builder.CreateStore(_index, m_args[0]); + m_builder.CreateStore(_value, m_args[1]); + m_builder.CreateCall3(m_sstore, getRuntimeManager().getEnvPtr(), m_args[0], m_args[1]); // Uses native endianness +} + +llvm::Value* Ext::calldataload(llvm::Value* _index) +{ + m_builder.CreateStore(_index, m_args[0]); + createCall(m_calldataload, getRuntimeManager().getDataPtr(), m_args[0], m_args[1]); + auto ret = m_builder.CreateLoad(m_args[1]); + return Endianness::toNative(m_builder, ret); +} + +llvm::Value* Ext::balance(llvm::Value* _address) +{ + auto address = Endianness::toBE(m_builder, _address); + m_builder.CreateStore(address, m_args[0]); + createCall(getBalanceFunc(), getRuntimeManager().getEnvPtr(), m_args[0], m_args[1]); + return m_builder.CreateLoad(m_args[1]); +} + +llvm::Value* Ext::create(llvm::Value*& _gas, llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* _initSize) +{ + m_builder.CreateStore(_gas, m_args[0]); + m_builder.CreateStore(_endowment, m_arg2); + auto begin = m_memoryMan.getBytePtr(_initOff); + auto size = m_builder.CreateTrunc(_initSize, Type::Size, "size"); + createCall(m_create, getRuntimeManager().getEnvPtr(), m_args[0], m_arg2, begin, size, m_args[1]); + _gas = m_builder.CreateLoad(m_args[0]); // Return gas + llvm::Value* address = m_builder.CreateLoad(m_args[1]); + address = Endianness::toNative(m_builder, address); + return address; +} + +llvm::Value* Ext::call(llvm::Value*& _gas, llvm::Value* _receiveAddress, llvm::Value* _value, llvm::Value* _inOff, llvm::Value* _inSize, llvm::Value* _outOff, llvm::Value* _outSize, llvm::Value* _codeAddress) +{ + m_builder.CreateStore(_gas, m_args[0]); + auto receiveAddress = Endianness::toBE(m_builder, _receiveAddress); + m_builder.CreateStore(receiveAddress, m_arg2); + m_builder.CreateStore(_value, m_arg3); + auto inBeg = m_memoryMan.getBytePtr(_inOff); + auto inSize = m_builder.CreateTrunc(_inSize, Type::Size, "in.size"); + auto outBeg = m_memoryMan.getBytePtr(_outOff); + auto outSize = m_builder.CreateTrunc(_outSize, Type::Size, "out.size"); + auto codeAddress = Endianness::toBE(m_builder, _codeAddress); + m_builder.CreateStore(codeAddress, m_arg8); + auto ret = createCall(m_call, getRuntimeManager().getEnvPtr(), m_args[0], m_arg2, m_arg3, inBeg, inSize, outBeg, outSize, m_arg8); + _gas = m_builder.CreateLoad(m_args[0]); // Return gas + return m_builder.CreateZExt(ret, Type::Word, "ret"); +} + +llvm::Value* Ext::sha3(llvm::Value* _inOff, llvm::Value* _inSize) +{ + auto begin = m_memoryMan.getBytePtr(_inOff); + auto size = m_builder.CreateTrunc(_inSize, Type::Size, "size"); + createCall(m_sha3, begin, size, m_args[1]); + llvm::Value* hash = m_builder.CreateLoad(m_args[1]); + hash = Endianness::toNative(m_builder, hash); + return hash; +} + +MemoryRef Ext::getExtCode(llvm::Value* _addr) +{ + auto addr = Endianness::toBE(m_builder, _addr); + m_builder.CreateStore(addr, m_args[0]); + auto code = createCall(m_getExtCode, getRuntimeManager().getEnvPtr(), m_args[0], m_size); + auto codeSize = m_builder.CreateLoad(m_size); + auto codeSize256 = m_builder.CreateZExt(codeSize, Type::Word); + return {code, codeSize256}; +} + +void Ext::log(llvm::Value* _memIdx, llvm::Value* _numBytes, std::array const& _topics) +{ + auto begin = m_memoryMan.getBytePtr(_memIdx); + auto size = m_builder.CreateTrunc(_numBytes, Type::Size, "size"); + llvm::Value* args[] = {getRuntimeManager().getEnvPtr(), begin, size, m_arg2, m_arg3, m_arg4, m_arg5}; + + auto topicArgPtr = &args[3]; + for (auto&& topic : _topics) + { + if (topic) + m_builder.CreateStore(Endianness::toBE(m_builder, topic), *topicArgPtr); + else + *topicArgPtr = llvm::ConstantPointerNull::get(Type::WordPtr); + ++topicArgPtr; + } + + m_builder.CreateCall(m_log, args); +} + +} +} +} diff --git a/libevmjit/Ext.h b/libevmjit/Ext.h new file mode 100644 index 000000000..be71dc1ff --- /dev/null +++ b/libevmjit/Ext.h @@ -0,0 +1,69 @@ + +#pragma once + +#include +#include "CompilerHelper.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + class Memory; + +struct MemoryRef +{ + llvm::Value* ptr; + llvm::Value* size; +}; + +class Ext : public RuntimeHelper +{ +public: + Ext(RuntimeManager& _runtimeManager, Memory& _memoryMan); + + llvm::Value* sload(llvm::Value* _index); + void sstore(llvm::Value* _index, llvm::Value* _value); + + llvm::Value* balance(llvm::Value* _address); + llvm::Value* calldataload(llvm::Value* _index); + llvm::Value* create(llvm::Value*& _gas, llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* _initSize); + llvm::Value* call(llvm::Value*& _gas, llvm::Value* _receiveAddress, llvm::Value* _value, llvm::Value* _inOff, llvm::Value* _inSize, llvm::Value* _outOff, llvm::Value* _outSize, llvm::Value* _codeAddress); + + llvm::Value* sha3(llvm::Value* _inOff, llvm::Value* _inSize); + MemoryRef getExtCode(llvm::Value* _addr); + + void log(llvm::Value* _memIdx, llvm::Value* _numBytes, std::array const& _topics); + +private: + Memory& m_memoryMan; + + llvm::Value* m_args[2]; + llvm::Value* m_arg2; + llvm::Value* m_arg3; + llvm::Value* m_arg4; + llvm::Value* m_arg5; + llvm::Value* m_arg6; + llvm::Value* m_arg7; + llvm::Value* m_arg8; + llvm::Value* m_size; + llvm::Value* m_data = nullptr; + llvm::Function* m_sload; + llvm::Function* m_sstore; + llvm::Function* m_calldataload; + llvm::Function* m_balance = nullptr; + llvm::Function* m_create; + llvm::Function* m_call; + llvm::Function* m_sha3; + llvm::Function* m_getExtCode; + llvm::Function* m_log; + + llvm::Function* getBalanceFunc(); +}; + + +} +} +} + diff --git a/libevmjit/GasMeter.cpp b/libevmjit/GasMeter.cpp new file mode 100644 index 000000000..c31942a45 --- /dev/null +++ b/libevmjit/GasMeter.cpp @@ -0,0 +1,222 @@ + +#include "GasMeter.h" + +#include +#include +#include + +#include "Type.h" +#include "Ext.h" +#include "RuntimeManager.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +namespace // Helper functions +{ + +uint64_t const c_stepGas = 1; +uint64_t const c_balanceGas = 20; +uint64_t const c_sha3Gas = 10; +uint64_t const c_sha3WordGas = 10; +uint64_t const c_sloadGas = 20; +uint64_t const c_sstoreSetGas = 300; +uint64_t const c_sstoreResetGas = 100; +uint64_t const c_sstoreRefundGas = 100; +uint64_t const c_createGas = 100; +uint64_t const c_createDataGas = 5; +uint64_t const c_callGas = 20; +uint64_t const c_expGas = 1; +uint64_t const c_expByteGas = 1; +uint64_t const c_memoryGas = 1; +uint64_t const c_txDataZeroGas = 1; +uint64_t const c_txDataNonZeroGas = 5; +uint64_t const c_txGas = 500; +uint64_t const c_logGas = 32; +uint64_t const c_logDataGas = 1; +uint64_t const c_logTopicGas = 32; +uint64_t const c_copyGas = 1; + +uint64_t getStepCost(Instruction inst) // TODO: Add this function to FeeSructure (pull request submitted) +{ + switch (inst) + { + default: // Assumes instruction code is valid + return c_stepGas; + + case Instruction::STOP: + case Instruction::SUICIDE: + case Instruction::SSTORE: // Handle cost of SSTORE separately in GasMeter::countSStore() + return 0; + + case Instruction::EXP: return c_expGas; + + case Instruction::SLOAD: return c_sloadGas; + + case Instruction::SHA3: return c_sha3Gas; + + case Instruction::BALANCE: return c_balanceGas; + + case Instruction::CALL: + case Instruction::CALLCODE: return c_callGas; + + case Instruction::CREATE: return c_createGas; + + case Instruction::LOG0: + case Instruction::LOG1: + case Instruction::LOG2: + case Instruction::LOG3: + case Instruction::LOG4: + { + auto numTopics = static_cast(inst) - static_cast(Instruction::LOG0); + return c_logGas + numTopics * c_logTopicGas; + } + } +} + +} + +GasMeter::GasMeter(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager) : + CompilerHelper(_builder), + m_runtimeManager(_runtimeManager) +{ + auto module = getModule(); + + llvm::Type* gasCheckArgs[] = {Type::RuntimePtr, Type::Word}; + m_gasCheckFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Void, gasCheckArgs, false), llvm::Function::PrivateLinkage, "gas.check", module); + InsertPointGuard guard(m_builder); + + auto checkBB = llvm::BasicBlock::Create(_builder.getContext(), "Check", m_gasCheckFunc); + auto outOfGasBB = llvm::BasicBlock::Create(_builder.getContext(), "OutOfGas", m_gasCheckFunc); + auto updateBB = llvm::BasicBlock::Create(_builder.getContext(), "Update", m_gasCheckFunc); + + m_builder.SetInsertPoint(checkBB); + auto arg = m_gasCheckFunc->arg_begin(); + arg->setName("rt"); + ++arg; + arg->setName("cost"); + auto cost = arg; + auto gas = m_runtimeManager.getGas(); + auto isOutOfGas = m_builder.CreateICmpUGT(cost, gas, "isOutOfGas"); + m_builder.CreateCondBr(isOutOfGas, outOfGasBB, updateBB); + + m_builder.SetInsertPoint(outOfGasBB); + m_runtimeManager.raiseException(ReturnCode::OutOfGas); + m_builder.CreateUnreachable(); + + m_builder.SetInsertPoint(updateBB); + gas = m_builder.CreateSub(gas, cost); + m_runtimeManager.setGas(gas); + m_builder.CreateRetVoid(); +} + +void GasMeter::count(Instruction _inst) +{ + if (!m_checkCall) + { + // Create gas check call with mocked block cost at begining of current cost-block + m_checkCall = createCall(m_gasCheckFunc, m_runtimeManager.getRuntimePtr(), llvm::UndefValue::get(Type::Word)); + } + + m_blockCost += getStepCost(_inst); +} + +void GasMeter::count(llvm::Value* _cost) +{ + createCall(m_gasCheckFunc, m_runtimeManager.getRuntimePtr(), _cost); +} + +void GasMeter::countExp(llvm::Value* _exponent) +{ + // Additional cost is 1 per significant byte of exponent + // lz - leading zeros + // cost = ((256 - lz) + 7) / 8 + + // OPT: All calculations can be done on 32/64 bits + + auto ctlz = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::ctlz, Type::Word); + auto lz = m_builder.CreateCall2(ctlz, _exponent, m_builder.getInt1(false)); + auto sigBits = m_builder.CreateSub(Constant::get(256), lz); + auto sigBytes = m_builder.CreateUDiv(m_builder.CreateAdd(sigBits, Constant::get(7)), Constant::get(8)); + count(sigBytes); +} + +void GasMeter::countSStore(Ext& _ext, llvm::Value* _index, llvm::Value* _newValue) +{ + auto oldValue = _ext.sload(_index); + auto oldValueIsZero = m_builder.CreateICmpEQ(oldValue, Constant::get(0), "oldValueIsZero"); + auto newValueIsZero = m_builder.CreateICmpEQ(_newValue, Constant::get(0), "newValueIsZero"); + auto oldValueIsntZero = m_builder.CreateICmpNE(oldValue, Constant::get(0), "oldValueIsntZero"); + auto newValueIsntZero = m_builder.CreateICmpNE(_newValue, Constant::get(0), "newValueIsntZero"); + auto isInsert = m_builder.CreateAnd(oldValueIsZero, newValueIsntZero, "isInsert"); + auto isDelete = m_builder.CreateAnd(oldValueIsntZero, newValueIsZero, "isDelete"); + auto cost = m_builder.CreateSelect(isInsert, Constant::get(c_sstoreSetGas), Constant::get(c_sstoreResetGas), "cost"); + cost = m_builder.CreateSelect(isDelete, Constant::get(0), cost, "cost"); + count(cost); +} + +void GasMeter::countLogData(llvm::Value* _dataLength) +{ + assert(m_checkCall); + assert(m_blockCost > 0); // LOGn instruction is already counted + static_assert(c_logDataGas == 1, "Log data gas cost has changed. Update GasMeter."); + count(_dataLength); +} + +void GasMeter::countSha3Data(llvm::Value* _dataLength) +{ + assert(m_checkCall); + assert(m_blockCost > 0); // SHA3 instruction is already counted + + // TODO: This round ups to 32 happens in many places + // FIXME: Overflow possible but Memory::require() also called. Probably 64-bit arith can be used. + static_assert(c_sha3WordGas != 1, "SHA3 data cost has changed. Update GasMeter"); + auto words = m_builder.CreateUDiv(m_builder.CreateAdd(_dataLength, Constant::get(31)), Constant::get(32)); + auto cost = m_builder.CreateNUWMul(Constant::get(c_sha3WordGas), words); + count(cost); +} + +void GasMeter::giveBack(llvm::Value* _gas) +{ + m_runtimeManager.setGas(m_builder.CreateAdd(m_runtimeManager.getGas(), _gas)); +} + +void GasMeter::commitCostBlock() +{ + // If any uncommited block + if (m_checkCall) + { + if (m_blockCost == 0) // Do not check 0 + { + m_checkCall->eraseFromParent(); // Remove the gas check call + m_checkCall = nullptr; + return; + } + + m_checkCall->setArgOperand(1, Constant::get(m_blockCost)); // Update block cost in gas check call + m_checkCall = nullptr; // End cost-block + m_blockCost = 0; + } + assert(m_blockCost == 0); +} + +void GasMeter::countMemory(llvm::Value* _additionalMemoryInWords) +{ + static_assert(c_memoryGas == 1, "Memory gas cost has changed. Update GasMeter."); + count(_additionalMemoryInWords); +} + +void GasMeter::countCopy(llvm::Value* _copyWords) +{ + static_assert(c_copyGas == 1, "Copy gas cost has changed. Update GasMeter."); + count(_copyWords); +} + +} +} +} + diff --git a/libevmjit/GasMeter.h b/libevmjit/GasMeter.h new file mode 100644 index 000000000..56da6eb9f --- /dev/null +++ b/libevmjit/GasMeter.h @@ -0,0 +1,64 @@ + +#pragma once + +#include "CompilerHelper.h" +#include "Instruction.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ +class RuntimeManager; + +class GasMeter : public CompilerHelper // TODO: Use RuntimeHelper +{ +public: + GasMeter(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager); + + /// Count step cost of instruction + void count(Instruction _inst); + + /// Count additional cost + void count(llvm::Value* _cost); + + /// Calculate & count gas cost for SSTORE instruction + void countSStore(class Ext& _ext, llvm::Value* _index, llvm::Value* _newValue); + + /// Calculate & count additional gas cost for EXP instruction + void countExp(llvm::Value* _exponent); + + /// Count gas cost of LOG data + void countLogData(llvm::Value* _dataLength); + + /// Count gas cost of SHA3 data + void countSha3Data(llvm::Value* _dataLength); + + /// Finalize cost-block by checking gas needed for the block before the block + void commitCostBlock(); + + /// Give back an amount of gas not used by a call + void giveBack(llvm::Value* _gas); + + /// Generate code that checks the cost of additional memory used by program + void countMemory(llvm::Value* _additionalMemoryInWords); + + /// Count addional gas cost for memory copy + void countCopy(llvm::Value* _copyWords); + +private: + /// Cumulative gas cost of a block of instructions + /// @TODO Handle overflow + uint64_t m_blockCost = 0; + + llvm::CallInst* m_checkCall = nullptr; + llvm::Function* m_gasCheckFunc = nullptr; + + RuntimeManager& m_runtimeManager; +}; + +} +} +} + diff --git a/libevmjit/Instruction.h b/libevmjit/Instruction.h new file mode 100644 index 000000000..502c4b66e --- /dev/null +++ b/libevmjit/Instruction.h @@ -0,0 +1,235 @@ +#pragma once + +#include "Common.h" + +namespace llvm +{ + class APInt; +} + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +/// Virtual machine bytecode instruction. +enum class Instruction: uint8_t +{ + STOP = 0x00, ///< halts execution + ADD, ///< addition operation + MUL, ///< mulitplication operation + SUB, ///< subtraction operation + DIV, ///< integer division operation + SDIV, ///< signed integer division operation + MOD, ///< modulo remainder operation + SMOD, ///< signed modulo remainder operation + ADDMOD, ///< unsigned modular addition + MULMOD, ///< unsigned modular multiplication + EXP, ///< exponential operation + SIGNEXTEND, ///< extend length of signed integer + + LT = 0x10, ///< less-than comparision + GT, ///< greater-than comparision + SLT, ///< signed less-than comparision + SGT, ///< signed greater-than comparision + EQ, ///< equality comparision + ISZERO, ///< simple not operator + AND, ///< bitwise AND operation + OR, ///< bitwise OR operation + XOR, ///< bitwise XOR operation + NOT, ///< bitwise NOT opertation + BYTE, ///< retrieve single byte from word + + SHA3 = 0x20, ///< compute SHA3-256 hash + + ADDRESS = 0x30, ///< get address of currently executing account + BALANCE, ///< get balance of the given account + ORIGIN, ///< get execution origination address + CALLER, ///< get caller address + CALLVALUE, ///< get deposited value by the instruction/transaction responsible for this execution + CALLDATALOAD, ///< get input data of current environment + CALLDATASIZE, ///< get size of input data in current environment + CALLDATACOPY, ///< copy input data in current environment to memory + CODESIZE, ///< get size of code running in current environment + CODECOPY, ///< copy code running in current environment to memory + GASPRICE, ///< get price of gas in current environment + EXTCODESIZE, ///< get external code size (from another contract) + EXTCODECOPY, ///< copy external code (from another contract) + + PREVHASH = 0x40, ///< get hash of most recent complete block + COINBASE, ///< get the block's coinbase address + TIMESTAMP, ///< get the block's timestamp + NUMBER, ///< get the block's number + DIFFICULTY, ///< get the block's difficulty + GASLIMIT, ///< get the block's gas limit + + POP = 0x50, ///< remove item from stack + MLOAD, ///< load word from memory + MSTORE, ///< save word to memory + MSTORE8, ///< save byte to memory + SLOAD, ///< load word from storage + SSTORE, ///< save word to storage + JUMP, ///< alter the program counter + JUMPI, ///< conditionally alter the program counter + PC, ///< get the program counter + MSIZE, ///< get the size of active memory + GAS, ///< get the amount of available gas + JUMPDEST, ///< set a potential jump destination + + PUSH1 = 0x60, ///< place 1 byte item on stack + PUSH2, ///< place 2 byte item on stack + PUSH3, ///< place 3 byte item on stack + PUSH4, ///< place 4 byte item on stack + PUSH5, ///< place 5 byte item on stack + PUSH6, ///< place 6 byte item on stack + PUSH7, ///< place 7 byte item on stack + PUSH8, ///< place 8 byte item on stack + PUSH9, ///< place 9 byte item on stack + PUSH10, ///< place 10 byte item on stack + PUSH11, ///< place 11 byte item on stack + PUSH12, ///< place 12 byte item on stack + PUSH13, ///< place 13 byte item on stack + PUSH14, ///< place 14 byte item on stack + PUSH15, ///< place 15 byte item on stack + PUSH16, ///< place 16 byte item on stack + PUSH17, ///< place 17 byte item on stack + PUSH18, ///< place 18 byte item on stack + PUSH19, ///< place 19 byte item on stack + PUSH20, ///< place 20 byte item on stack + PUSH21, ///< place 21 byte item on stack + PUSH22, ///< place 22 byte item on stack + PUSH23, ///< place 23 byte item on stack + PUSH24, ///< place 24 byte item on stack + PUSH25, ///< place 25 byte item on stack + PUSH26, ///< place 26 byte item on stack + PUSH27, ///< place 27 byte item on stack + PUSH28, ///< place 28 byte item on stack + PUSH29, ///< place 29 byte item on stack + PUSH30, ///< place 30 byte item on stack + PUSH31, ///< place 31 byte item on stack + PUSH32, ///< place 32 byte item on stack + + DUP1 = 0x80, ///< copies the highest item in the stack to the top of the stack + DUP2, ///< copies the second highest item in the stack to the top of the stack + DUP3, ///< copies the third highest item in the stack to the top of the stack + DUP4, ///< copies the 4th highest item in the stack to the top of the stack + DUP5, ///< copies the 5th highest item in the stack to the top of the stack + DUP6, ///< copies the 6th highest item in the stack to the top of the stack + DUP7, ///< copies the 7th highest item in the stack to the top of the stack + DUP8, ///< copies the 8th highest item in the stack to the top of the stack + DUP9, ///< copies the 9th highest item in the stack to the top of the stack + DUP10, ///< copies the 10th highest item in the stack to the top of the stack + DUP11, ///< copies the 11th highest item in the stack to the top of the stack + DUP12, ///< copies the 12th highest item in the stack to the top of the stack + DUP13, ///< copies the 13th highest item in the stack to the top of the stack + DUP14, ///< copies the 14th highest item in the stack to the top of the stack + DUP15, ///< copies the 15th highest item in the stack to the top of the stack + DUP16, ///< copies the 16th highest item in the stack to the top of the stack + + SWAP1 = 0x90, ///< swaps the highest and second highest value on the stack + SWAP2, ///< swaps the highest and third highest value on the stack + SWAP3, ///< swaps the highest and 4th highest value on the stack + SWAP4, ///< swaps the highest and 5th highest value on the stack + SWAP5, ///< swaps the highest and 6th highest value on the stack + SWAP6, ///< swaps the highest and 7th highest value on the stack + SWAP7, ///< swaps the highest and 8th highest value on the stack + SWAP8, ///< swaps the highest and 9th highest value on the stack + SWAP9, ///< swaps the highest and 10th highest value on the stack + SWAP10, ///< swaps the highest and 11th highest value on the stack + SWAP11, ///< swaps the highest and 12th highest value on the stack + SWAP12, ///< swaps the highest and 13th highest value on the stack + SWAP13, ///< swaps the highest and 14th highest value on the stack + SWAP14, ///< swaps the highest and 15th highest value on the stack + SWAP15, ///< swaps the highest and 16th highest value on the stack + SWAP16, ///< swaps the highest and 17th highest value on the stack + + LOG0 = 0xa0, ///< Makes a log entry; no topics. + LOG1, ///< Makes a log entry; 1 topic. + LOG2, ///< Makes a log entry; 2 topics. + LOG3, ///< Makes a log entry; 3 topics. + LOG4, ///< Makes a log entry; 4 topics. + + CREATE = 0xf0, ///< create a new account with associated code + CALL, ///< message-call into an account + CALLCODE, ///< message-call with another account's code only + RETURN, ///< halt execution returning output data + SUICIDE = 0xff ///< halt execution and register account for later deletion +}; + +/// Reads PUSH data from pointed fragment of bytecode and constructs number out of it +/// Reading out of bytecode means reading 0 +/// @param _curr is updates and points the last real byte read +llvm::APInt readPushData(bytes::const_iterator& _curr, bytes::const_iterator _end); + +#define ANY_PUSH PUSH1: \ + case Instruction::PUSH2: \ + case Instruction::PUSH3: \ + case Instruction::PUSH4: \ + case Instruction::PUSH5: \ + case Instruction::PUSH6: \ + case Instruction::PUSH7: \ + case Instruction::PUSH8: \ + case Instruction::PUSH9: \ + case Instruction::PUSH10: \ + case Instruction::PUSH11: \ + case Instruction::PUSH12: \ + case Instruction::PUSH13: \ + case Instruction::PUSH14: \ + case Instruction::PUSH15: \ + case Instruction::PUSH16: \ + case Instruction::PUSH17: \ + case Instruction::PUSH18: \ + case Instruction::PUSH19: \ + case Instruction::PUSH20: \ + case Instruction::PUSH21: \ + case Instruction::PUSH22: \ + case Instruction::PUSH23: \ + case Instruction::PUSH24: \ + case Instruction::PUSH25: \ + case Instruction::PUSH26: \ + case Instruction::PUSH27: \ + case Instruction::PUSH28: \ + case Instruction::PUSH29: \ + case Instruction::PUSH30: \ + case Instruction::PUSH31: \ + case Instruction::PUSH32 + +#define ANY_DUP DUP1: \ + case Instruction::DUP2: \ + case Instruction::DUP3: \ + case Instruction::DUP4: \ + case Instruction::DUP5: \ + case Instruction::DUP6: \ + case Instruction::DUP7: \ + case Instruction::DUP8: \ + case Instruction::DUP9: \ + case Instruction::DUP10: \ + case Instruction::DUP11: \ + case Instruction::DUP12: \ + case Instruction::DUP13: \ + case Instruction::DUP14: \ + case Instruction::DUP15: \ + case Instruction::DUP16 + +#define ANY_SWAP SWAP1: \ + case Instruction::SWAP2: \ + case Instruction::SWAP3: \ + case Instruction::SWAP4: \ + case Instruction::SWAP5: \ + case Instruction::SWAP6: \ + case Instruction::SWAP7: \ + case Instruction::SWAP8: \ + case Instruction::SWAP9: \ + case Instruction::SWAP10: \ + case Instruction::SWAP11: \ + case Instruction::SWAP12: \ + case Instruction::SWAP13: \ + case Instruction::SWAP14: \ + case Instruction::SWAP15: \ + case Instruction::SWAP16 + +} +} +} diff --git a/libevmjit/Memory.cpp b/libevmjit/Memory.cpp new file mode 100644 index 000000000..c60a5e554 --- /dev/null +++ b/libevmjit/Memory.cpp @@ -0,0 +1,237 @@ +#include "Memory.h" + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "Type.h" +#include "Runtime.h" +#include "GasMeter.h" +#include "Endianness.h" +#include "RuntimeManager.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +Memory::Memory(RuntimeManager& _runtimeManager, GasMeter& _gasMeter): + RuntimeHelper(_runtimeManager), // TODO: RuntimeHelper not needed + m_gasMeter(_gasMeter) +{ + llvm::Type* resizeArgs[] = {Type::RuntimePtr, Type::WordPtr}; + m_resize = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, resizeArgs, false), llvm::Function::ExternalLinkage, "mem_resize", getModule()); + llvm::AttrBuilder attrBuilder; + attrBuilder.addAttribute(llvm::Attribute::NoAlias).addAttribute(llvm::Attribute::NoCapture).addAttribute(llvm::Attribute::NonNull).addAttribute(llvm::Attribute::ReadOnly); + m_resize->setAttributes(llvm::AttributeSet::get(m_resize->getContext(), 1, attrBuilder)); + + m_require = createRequireFunc(_gasMeter); + m_loadWord = createFunc(false, Type::Word, _gasMeter); + m_storeWord = createFunc(true, Type::Word, _gasMeter); + m_storeByte = createFunc(true, Type::Byte, _gasMeter); +} + +llvm::Function* Memory::createRequireFunc(GasMeter& _gasMeter) +{ + llvm::Type* argTypes[] = {Type::RuntimePtr, Type::Word, Type::Word}; + auto func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::PrivateLinkage, "mem.require", getModule()); + auto rt = func->arg_begin(); + rt->setName("rt"); + auto offset = rt->getNextNode(); + offset->setName("offset"); + auto size = offset->getNextNode(); + size->setName("size"); + + auto preBB = llvm::BasicBlock::Create(func->getContext(), "Pre", func); + auto checkBB = llvm::BasicBlock::Create(func->getContext(), "Check", func); + auto resizeBB = llvm::BasicBlock::Create(func->getContext(), "Resize", func); + auto returnBB = llvm::BasicBlock::Create(func->getContext(), "Return", func); + + InsertPointGuard guard(m_builder); // Restores insert point at function exit + + // BB "Pre": Ignore checks with size 0 + m_builder.SetInsertPoint(preBB); + auto sizeIsZero = m_builder.CreateICmpEQ(size, Constant::get(0)); + m_builder.CreateCondBr(sizeIsZero, returnBB, checkBB); + + // BB "Check" + m_builder.SetInsertPoint(checkBB); + auto uaddWO = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::uadd_with_overflow, Type::Word); + auto uaddRes = m_builder.CreateCall2(uaddWO, offset, size, "res"); + auto sizeRequired = m_builder.CreateExtractValue(uaddRes, 0, "sizeReq"); + auto overflow1 = m_builder.CreateExtractValue(uaddRes, 1, "overflow1"); + auto rtPtr = getRuntimeManager().getRuntimePtr(); + auto sizePtr = m_builder.CreateStructGEP(rtPtr, 4); + auto currSize = m_builder.CreateLoad(sizePtr, "currSize"); + auto tooSmall = m_builder.CreateICmpULE(currSize, sizeRequired, "tooSmall"); + auto resizeNeeded = m_builder.CreateOr(tooSmall, overflow1, "resizeNeeded"); + m_builder.CreateCondBr(resizeNeeded, resizeBB, returnBB); // OPT branch weights? + + // BB "Resize" + m_builder.SetInsertPoint(resizeBB); + // Check gas first + uaddRes = m_builder.CreateCall2(uaddWO, sizeRequired, Constant::get(31), "res"); + auto wordsRequired = m_builder.CreateExtractValue(uaddRes, 0); + auto overflow2 = m_builder.CreateExtractValue(uaddRes, 1, "overflow2"); + auto overflow = m_builder.CreateOr(overflow1, overflow2, "overflow"); + wordsRequired = m_builder.CreateSelect(overflow, Constant::get(-1), wordsRequired); + wordsRequired = m_builder.CreateUDiv(wordsRequired, Constant::get(32), "wordsReq"); + sizeRequired = m_builder.CreateMul(wordsRequired, Constant::get(32), "roundedSizeReq"); + auto words = m_builder.CreateUDiv(currSize, Constant::get(32), "words"); // size is always 32*k + auto newWords = m_builder.CreateSub(wordsRequired, words, "addtionalWords"); + _gasMeter.countMemory(newWords); + // Resize + m_builder.CreateStore(sizeRequired, sizePtr); + auto newData = m_builder.CreateCall2(m_resize, rt, sizePtr, "newData"); + auto dataPtr = m_builder.CreateStructGEP(rtPtr, 3); + m_builder.CreateStore(newData, dataPtr); + m_builder.CreateBr(returnBB); + + // BB "Return" + m_builder.SetInsertPoint(returnBB); + m_builder.CreateRetVoid(); + return func; +} + +llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType, GasMeter&) +{ + auto isWord = _valueType == Type::Word; + + llvm::Type* storeArgs[] = {Type::RuntimePtr, Type::Word, _valueType}; + llvm::Type* loadArgs[] = {Type::RuntimePtr, Type::Word}; + auto name = _isStore ? isWord ? "mstore" : "mstore8" : "mload"; + auto funcType = _isStore ? llvm::FunctionType::get(Type::Void, storeArgs, false) : llvm::FunctionType::get(Type::Word, loadArgs, false); + auto func = llvm::Function::Create(funcType, llvm::Function::PrivateLinkage, name, getModule()); + + InsertPointGuard guard(m_builder); // Restores insert point at function exit + + m_builder.SetInsertPoint(llvm::BasicBlock::Create(func->getContext(), {}, func)); + auto rt = func->arg_begin(); + rt->setName("rt"); + auto index = rt->getNextNode(); + index->setName("index"); + + auto valueSize = _valueType->getPrimitiveSizeInBits() / 8; + this->require(index, Constant::get(valueSize)); + auto ptr = getBytePtr(index); + if (isWord) + ptr = m_builder.CreateBitCast(ptr, Type::WordPtr, "wordPtr"); + if (_isStore) + { + llvm::Value* value = index->getNextNode(); + value->setName("value"); + if (isWord) + value = Endianness::toBE(m_builder, value); + m_builder.CreateStore(value, ptr); + m_builder.CreateRetVoid(); + } + else + { + llvm::Value* ret = m_builder.CreateLoad(ptr); + ret = Endianness::toNative(m_builder, ret); + m_builder.CreateRet(ret); + } + + return func; +} + + +llvm::Value* Memory::loadWord(llvm::Value* _addr) +{ + return createCall(m_loadWord, getRuntimeManager().getRuntimePtr(), _addr); +} + +void Memory::storeWord(llvm::Value* _addr, llvm::Value* _word) +{ + createCall(m_storeWord, getRuntimeManager().getRuntimePtr(), _addr, _word); +} + +void Memory::storeByte(llvm::Value* _addr, llvm::Value* _word) +{ + auto byte = m_builder.CreateTrunc(_word, Type::Byte, "byte"); + createCall(m_storeByte, getRuntimeManager().getRuntimePtr(), _addr, byte); +} + +llvm::Value* Memory::getData() +{ + auto rtPtr = getRuntimeManager().getRuntimePtr(); + auto dataPtr = m_builder.CreateStructGEP(rtPtr, 3); + return m_builder.CreateLoad(dataPtr, "data"); +} + +llvm::Value* Memory::getSize() +{ + auto rtPtr = getRuntimeManager().getRuntimePtr(); + auto sizePtr = m_builder.CreateStructGEP(rtPtr, 4); + return m_builder.CreateLoad(sizePtr, "size"); +} + +llvm::Value* Memory::getBytePtr(llvm::Value* _index) +{ + return m_builder.CreateGEP(getData(), _index, "ptr"); +} + +void Memory::require(llvm::Value* _offset, llvm::Value* _size) +{ + createCall(m_require, getRuntimeManager().getRuntimePtr(), _offset, _size); +} + +void Memory::copyBytes(llvm::Value* _srcPtr, llvm::Value* _srcSize, llvm::Value* _srcIdx, + llvm::Value* _destMemIdx, llvm::Value* _reqBytes) +{ + require(_destMemIdx, _reqBytes); + + // Additional copy cost + // TODO: This round ups to 32 happens in many places + auto copyWords = m_builder.CreateUDiv(m_builder.CreateAdd(_reqBytes, Constant::get(31)), Constant::get(32)); + m_gasMeter.countCopy(copyWords); + + // Algorithm: + // isOutsideData = idx256 >= size256 + // idx64 = trunc idx256 + // size64 = trunc size256 + // dataLeftSize = size64 - idx64 // safe if not isOutsideData + // reqBytes64 = trunc _reqBytes // require() handles large values + // bytesToCopy0 = select(reqBytes64 > dataLeftSize, dataSizeLeft, reqBytes64) // min + // bytesToCopy = select(isOutsideData, 0, bytesToCopy0) + + auto isOutsideData = m_builder.CreateICmpUGE(_srcIdx, _srcSize); + auto idx64 = m_builder.CreateTrunc(_srcIdx, Type::lowPrecision); + auto size64 = m_builder.CreateTrunc(_srcSize, Type::lowPrecision); + auto dataLeftSize = m_builder.CreateNUWSub(size64, idx64); + auto reqBytes64 = m_builder.CreateTrunc(_reqBytes, Type::lowPrecision); + auto outOfBound = m_builder.CreateICmpUGT(reqBytes64, dataLeftSize); + auto bytesToCopyInner = m_builder.CreateSelect(outOfBound, dataLeftSize, reqBytes64); + auto zero64 = llvm::ConstantInt::get(Type::lowPrecision, 0); // TODO: Cache common constants + auto bytesToCopy = m_builder.CreateSelect(isOutsideData, zero64, bytesToCopyInner); + + auto src = m_builder.CreateGEP(_srcPtr, idx64, "src"); + auto dst = m_builder.CreateGEP(getData(), _destMemIdx, "dst"); + m_builder.CreateMemCpy(dst, src, bytesToCopy, 0); +} + +} +} +} + + +extern "C" +{ + using namespace dev::eth::jit; + + EXPORT byte* mem_resize(Runtime* _rt, i256* _size) // TODO: Use uint64 as size OR use realloc in LLVM IR + { + auto size = _size->a; // Trunc to 64-bit + auto& memory = _rt->getMemory(); + memory.resize(size); + return memory.data(); + } +} diff --git a/libevmjit/Memory.h b/libevmjit/Memory.h new file mode 100644 index 000000000..ed9c51805 --- /dev/null +++ b/libevmjit/Memory.h @@ -0,0 +1,46 @@ +#pragma once + +#include "CompilerHelper.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ +class GasMeter; + +class Memory : public RuntimeHelper +{ +public: + Memory(RuntimeManager& _runtimeManager, GasMeter& _gasMeter); + + llvm::Value* loadWord(llvm::Value* _addr); + void storeWord(llvm::Value* _addr, llvm::Value* _word); + void storeByte(llvm::Value* _addr, llvm::Value* _byte); + llvm::Value* getData(); + llvm::Value* getSize(); + llvm::Value* getBytePtr(llvm::Value* _index); + void copyBytes(llvm::Value* _srcPtr, llvm::Value* _srcSize, llvm::Value* _srcIndex, + llvm::Value* _destMemIdx, llvm::Value* _byteCount); + + /// Requires the amount of memory to for data defined by offset and size. And counts gas fee for that memory. + void require(llvm::Value* _offset, llvm::Value* _size); + +private: + GasMeter& m_gasMeter; + + llvm::Function* createFunc(bool _isStore, llvm::Type* _type, GasMeter& _gasMeter); + llvm::Function* createRequireFunc(GasMeter& _gasMeter); + + llvm::Function* m_resize; + llvm::Function* m_require; + llvm::Function* m_loadWord; + llvm::Function* m_storeWord; + llvm::Function* m_storeByte; +}; + +} +} +} + diff --git a/libevmjit/Runtime.cpp b/libevmjit/Runtime.cpp new file mode 100644 index 000000000..27c81ea86 --- /dev/null +++ b/libevmjit/Runtime.cpp @@ -0,0 +1,52 @@ + +#include "Runtime.h" + +#include +#include +#include + +namespace dev +{ +namespace eth +{ +namespace jit +{ +namespace +{ + jmp_buf_ref g_currJmpBuf; +} + +jmp_buf_ref Runtime::getCurrJmpBuf() +{ + return g_currJmpBuf; +} + +Runtime::Runtime(RuntimeData* _data, Env* _env): + m_data(*_data), + m_env(*_env), + m_currJmpBuf(m_jmpBuf), + m_prevJmpBuf(g_currJmpBuf) +{ + g_currJmpBuf = m_jmpBuf; +} + +Runtime::~Runtime() +{ + g_currJmpBuf = m_prevJmpBuf; +} + +bytes Runtime::getReturnData() const // FIXME: Reconsider returning by copy +{ + // TODO: Handle large indexes + auto offset = static_cast(llvm2eth(m_data.elems[RuntimeData::ReturnDataOffset])); + auto size = static_cast(llvm2eth(m_data.elems[RuntimeData::ReturnDataSize])); + + assert(offset + size <= m_memory.size()); + // TODO: Handle invalid data access by returning empty ref + auto dataBeg = m_memory.begin() + offset; + return {dataBeg, dataBeg + size}; +} + +} +} +} diff --git a/libevmjit/Runtime.h b/libevmjit/Runtime.h new file mode 100644 index 000000000..e11dac319 --- /dev/null +++ b/libevmjit/Runtime.h @@ -0,0 +1,62 @@ + +#pragma once + +#include +#include + +#include "Instruction.h" +#include "CompilerHelper.h" +#include "Utils.h" +#include "Type.h" +#include "RuntimeData.h" + + +#ifdef _MSC_VER + #define EXPORT __declspec(dllexport) +#else + #define EXPORT +#endif + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +using StackImpl = std::vector; +using MemoryImpl = bytes; +using jmp_buf_ref = decltype(&std::jmp_buf{}[0]); + +class Runtime +{ +public: + Runtime(RuntimeData* _data, Env* _env); + ~Runtime(); + + Runtime(const Runtime&) = delete; + void operator=(const Runtime&) = delete; + + StackImpl& getStack() { return m_stack; } + MemoryImpl& getMemory() { return m_memory; } + Env* getEnvPtr() { return &m_env; } + + bytes getReturnData() const; + jmp_buf_ref getJmpBuf() { return m_jmpBuf; } + static jmp_buf_ref getCurrJmpBuf(); + +private: + RuntimeData& m_data; ///< Pointer to data. Expected by compiled contract. + Env& m_env; ///< Pointer to environment proxy. Expected by compiled contract. + jmp_buf_ref m_currJmpBuf; ///< Pointer to jump buffer. Expected by compiled contract. + byte* m_memoryData = nullptr; + i256 m_memorySize = {}; + jmp_buf_ref m_prevJmpBuf; + std::jmp_buf m_jmpBuf; + StackImpl m_stack; + MemoryImpl m_memory; +}; + +} +} +} diff --git a/libevmjit/RuntimeData.h b/libevmjit/RuntimeData.h new file mode 100644 index 000000000..89987bdeb --- /dev/null +++ b/libevmjit/RuntimeData.h @@ -0,0 +1,52 @@ +#pragma once + +#include "Utils.h" + + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +struct RuntimeData +{ + enum Index + { + Gas, + Address, + Caller, + Origin, + CallValue, + CallDataSize, + GasPrice, + PrevHash, + CoinBase, + TimeStamp, + Number, + Difficulty, + GasLimit, + CodeSize, + + _size, + + ReturnDataOffset = CallValue, // Reuse 2 fields for return data reference + ReturnDataSize = CallDataSize, + SuicideDestAddress = Address, ///< Suicide balance destination address + }; + + i256 elems[_size] = {}; + byte const* callData = nullptr; + byte const* code = nullptr; + + void set(Index _index, u256 _value) { elems[_index] = eth2llvm(_value); } + u256 get(Index _index) { return llvm2eth(elems[_index]); } +}; + +/// VM Environment (ExtVM) opaque type +struct Env; + +} +} +} diff --git a/libevmjit/RuntimeManager.cpp b/libevmjit/RuntimeManager.cpp new file mode 100644 index 000000000..14280f80f --- /dev/null +++ b/libevmjit/RuntimeManager.cpp @@ -0,0 +1,199 @@ + +#include "RuntimeManager.h" + +#include +#include +#include + +#include "RuntimeData.h" +#include "Instruction.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +llvm::StructType* RuntimeManager::getRuntimeDataType() +{ + static llvm::StructType* type = nullptr; + if (!type) + { + llvm::Type* elems[] = + { + llvm::ArrayType::get(Type::Word, RuntimeData::_size), // i256[] + Type::BytePtr, // callData + Type::BytePtr // code + }; + type = llvm::StructType::create(elems, "RuntimeData"); + } + return type; +} + +llvm::StructType* RuntimeManager::getRuntimeType() +{ + static llvm::StructType* type = nullptr; + if (!type) + { + llvm::Type* elems[] = + { + Type::RuntimeDataPtr, // data + Type::EnvPtr, // Env* + Type::BytePtr, // jmpbuf + Type::BytePtr, // memory data + Type::Word, // memory size + }; + type = llvm::StructType::create(elems, "Runtime"); + } + return type; +} + +namespace +{ +llvm::Twine getName(RuntimeData::Index _index) +{ + switch (_index) + { + default: return "data"; + case RuntimeData::Gas: return "gas"; + case RuntimeData::Address: return "address"; + case RuntimeData::Caller: return "caller"; + case RuntimeData::Origin: return "origin"; + case RuntimeData::CallValue: return "callvalue"; + case RuntimeData::CallDataSize: return "calldatasize"; + case RuntimeData::GasPrice: return "gasprice"; + case RuntimeData::PrevHash: return "prevhash"; + case RuntimeData::CoinBase: return "coinbase"; + case RuntimeData::TimeStamp: return "timestamp"; + case RuntimeData::Number: return "number"; + case RuntimeData::Difficulty: return "difficulty"; + case RuntimeData::GasLimit: return "gaslimit"; + case RuntimeData::CodeSize: return "codesize"; + } +} +} + +RuntimeManager::RuntimeManager(llvm::IRBuilder<>& _builder): CompilerHelper(_builder) +{ + m_longjmp = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::longjmp); + + // Unpack data + auto rtPtr = getRuntimePtr(); + m_dataPtr = m_builder.CreateLoad(m_builder.CreateStructGEP(rtPtr, 0), "data"); + assert(m_dataPtr->getType() == Type::RuntimeDataPtr); + m_envPtr = m_builder.CreateLoad(m_builder.CreateStructGEP(rtPtr, 1), "env"); + assert(m_envPtr->getType() == Type::EnvPtr); +} + +llvm::Value* RuntimeManager::getRuntimePtr() +{ + // Expect first argument of a function to be a pointer to Runtime + auto func = m_builder.GetInsertBlock()->getParent(); + auto rtPtr = &func->getArgumentList().front(); + assert(rtPtr->getType() == Type::RuntimePtr); + return rtPtr; +} + +llvm::Value* RuntimeManager::getDataPtr() +{ + if (getMainFunction()) + return m_dataPtr; + + auto rtPtr = getRuntimePtr(); + return m_builder.CreateLoad(m_builder.CreateStructGEP(rtPtr, 0), "data"); +} + +llvm::Value* RuntimeManager::getEnvPtr() +{ + assert(getMainFunction()); // Available only in main function + return m_envPtr; +} + +llvm::Value* RuntimeManager::getPtr(RuntimeData::Index _index) +{ + llvm::Value* idxList[] = {m_builder.getInt32(0), m_builder.getInt32(0), m_builder.getInt32(_index)}; + return m_builder.CreateInBoundsGEP(getDataPtr(), idxList, getName(_index) + "Ptr"); +} + +llvm::Value* RuntimeManager::get(RuntimeData::Index _index) +{ + return m_builder.CreateLoad(getPtr(_index), getName(_index)); +} + +void RuntimeManager::set(RuntimeData::Index _index, llvm::Value* _value) +{ + m_builder.CreateStore(_value, getPtr(_index)); +} + +void RuntimeManager::registerReturnData(llvm::Value* _offset, llvm::Value* _size) +{ + set(RuntimeData::ReturnDataOffset, _offset); + set(RuntimeData::ReturnDataSize, _size); +} + +void RuntimeManager::registerSuicide(llvm::Value* _balanceAddress) +{ + set(RuntimeData::SuicideDestAddress, _balanceAddress); +} + +void RuntimeManager::raiseException(ReturnCode _returnCode) +{ + m_builder.CreateCall2(m_longjmp, getJmpBuf(), Constant::get(_returnCode)); +} + +llvm::Value* RuntimeManager::get(Instruction _inst) +{ + switch (_inst) + { + default: assert(false); return nullptr; + case Instruction::GAS: return get(RuntimeData::Gas); + case Instruction::ADDRESS: return get(RuntimeData::Address); + case Instruction::CALLER: return get(RuntimeData::Caller); + case Instruction::ORIGIN: return get(RuntimeData::Origin); + case Instruction::CALLVALUE: return get(RuntimeData::CallValue); + case Instruction::CALLDATASIZE: return get(RuntimeData::CallDataSize); + case Instruction::GASPRICE: return get(RuntimeData::GasPrice); + case Instruction::PREVHASH: return get(RuntimeData::PrevHash); + case Instruction::COINBASE: return get(RuntimeData::CoinBase); + case Instruction::TIMESTAMP: return get(RuntimeData::TimeStamp); + case Instruction::NUMBER: return get(RuntimeData::Number); + case Instruction::DIFFICULTY: return get(RuntimeData::Difficulty); + case Instruction::GASLIMIT: return get(RuntimeData::GasLimit); + case Instruction::CODESIZE: return get(RuntimeData::CodeSize); + } +} + +llvm::Value* RuntimeManager::getCallData() +{ + auto ptr = getBuilder().CreateStructGEP(getDataPtr(), 1, "calldataPtr"); + return getBuilder().CreateLoad(ptr, "calldata"); +} + +llvm::Value* RuntimeManager::getCode() +{ + auto ptr = getBuilder().CreateStructGEP(getDataPtr(), 2, "codePtr"); + return getBuilder().CreateLoad(ptr, "code"); +} + +llvm::Value* RuntimeManager::getJmpBuf() +{ + auto ptr = getBuilder().CreateStructGEP(getRuntimePtr(), 2, "jmpbufPtr"); + return getBuilder().CreateLoad(ptr, "jmpbuf"); +} + +llvm::Value* RuntimeManager::getGas() +{ + return get(RuntimeData::Gas); +} + +void RuntimeManager::setGas(llvm::Value* _gas) +{ + llvm::Value* idxList[] = {m_builder.getInt32(0), m_builder.getInt32(0), m_builder.getInt32(RuntimeData::Gas)}; + auto ptr = m_builder.CreateInBoundsGEP(getDataPtr(), idxList, "gasPtr"); + m_builder.CreateStore(_gas, ptr); +} + +} +} +} diff --git a/libevmjit/RuntimeManager.h b/libevmjit/RuntimeManager.h new file mode 100644 index 000000000..ce60424ac --- /dev/null +++ b/libevmjit/RuntimeManager.h @@ -0,0 +1,51 @@ +#pragma once + +#include "CompilerHelper.h" +#include "Type.h" +#include "RuntimeData.h" +#include "Instruction.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +class RuntimeManager: public CompilerHelper +{ +public: + RuntimeManager(llvm::IRBuilder<>& _builder); + + llvm::Value* getRuntimePtr(); + llvm::Value* getDataPtr(); + llvm::Value* getEnvPtr(); // TODO: Can we make it const? + + llvm::Value* get(RuntimeData::Index _index); + llvm::Value* get(Instruction _inst); + llvm::Value* getGas(); // TODO: Remove + llvm::Value* getCallData(); + llvm::Value* getCode(); + void setGas(llvm::Value* _gas); + + void registerReturnData(llvm::Value* _index, llvm::Value* _size); + void registerSuicide(llvm::Value* _balanceAddress); + + void raiseException(ReturnCode _returnCode); + + static llvm::StructType* getRuntimeType(); + static llvm::StructType* getRuntimeDataType(); + +private: + llvm::Value* getPtr(RuntimeData::Index _index); + void set(RuntimeData::Index _index, llvm::Value* _value); + llvm::Value* getJmpBuf(); + + llvm::Function* m_longjmp = nullptr; + llvm::Value* m_dataPtr = nullptr; + llvm::Value* m_envPtr = nullptr; +}; + +} +} +} diff --git a/libevmjit/Stack.cpp b/libevmjit/Stack.cpp new file mode 100644 index 000000000..52782999a --- /dev/null +++ b/libevmjit/Stack.cpp @@ -0,0 +1,133 @@ +#include "Stack.h" +#include "RuntimeManager.h" +#include "Runtime.h" +#include "Type.h" + +#include +#include + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +Stack::Stack(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager): + CompilerHelper(_builder), + m_runtimeManager(_runtimeManager) +{ + m_arg = m_builder.CreateAlloca(Type::Word, nullptr, "stack.arg"); + + using namespace llvm; + using Linkage = GlobalValue::LinkageTypes; + + auto module = getModule(); + + llvm::Type* pushArgTypes[] = {Type::RuntimePtr, Type::WordPtr}; + m_push = Function::Create(FunctionType::get(Type::Void, pushArgTypes, false), Linkage::ExternalLinkage, "stack_push", module); + + llvm::Type* popArgTypes[] = {Type::RuntimePtr, Type::Size}; + m_pop = Function::Create(FunctionType::get(Type::Void, popArgTypes, false), Linkage::ExternalLinkage, "stack_pop", module); + + llvm::Type* getSetArgTypes[] = {Type::RuntimePtr, Type::Size, Type::WordPtr}; + m_get = Function::Create(FunctionType::get(Type::Void, getSetArgTypes, false), Linkage::ExternalLinkage, "stack_get", module); + m_set = Function::Create(FunctionType::get(Type::Void, getSetArgTypes, false), Linkage::ExternalLinkage, "stack_set", module); +} + +llvm::Value* Stack::get(size_t _index) +{ + m_builder.CreateCall3(m_get, m_runtimeManager.getRuntimePtr(), llvm::ConstantInt::get(Type::Size, _index, false), m_arg); + return m_builder.CreateLoad(m_arg); +} + +void Stack::set(size_t _index, llvm::Value* _value) +{ + m_builder.CreateStore(_value, m_arg); + m_builder.CreateCall3(m_set, m_runtimeManager.getRuntimePtr(), llvm::ConstantInt::get(Type::Size, _index, false), m_arg); +} + +void Stack::pop(size_t _count) +{ + m_builder.CreateCall2(m_pop, m_runtimeManager.getRuntimePtr(), llvm::ConstantInt::get(Type::Size, _count, false)); +} + +void Stack::push(llvm::Value* _value) +{ + m_builder.CreateStore(_value, m_arg); + m_builder.CreateCall2(m_push, m_runtimeManager.getRuntimePtr(), m_arg); +} + + +size_t Stack::maxStackSize = 0; + +} +} +} + +extern "C" +{ + using namespace dev::eth::jit; + + EXPORT void stack_pop(Runtime* _rt, uint64_t _count) + { + auto& stack = _rt->getStack(); + if (stack.size() < _count) + longjmp(_rt->getJmpBuf(), static_cast(ReturnCode::StackTooSmall)); + + stack.erase(stack.end() - _count, stack.end()); + } + + EXPORT void stack_push(Runtime* _rt, i256 const* _word) + { + auto& stack = _rt->getStack(); + stack.push_back(*_word); + + if (stack.size() > Stack::maxStackSize) + Stack::maxStackSize = stack.size(); + } + + EXPORT void stack_get(Runtime* _rt, uint64_t _index, i256* o_ret) + { + auto& stack = _rt->getStack(); + // TODO: encode _index and stack size in the return code + if (stack.size() <= _index) + longjmp(_rt->getJmpBuf(), static_cast(ReturnCode::StackTooSmall)); + + *o_ret = *(stack.rbegin() + _index); + } + + EXPORT void stack_set(Runtime* _rt, uint64_t _index, i256 const* _word) + { + auto& stack = _rt->getStack(); + // TODO: encode _index and stack size in the return code + if (stack.size() <= _index) + longjmp(_rt->getJmpBuf(), static_cast(ReturnCode::StackTooSmall)); + + *(stack.rbegin() + _index) = *_word; + } + + EXPORT void ext_calldataload(RuntimeData* _rtData, i256* _index, byte* o_value) + { + // It asumes all indexes are less than 2^64 + + auto index = _index->a; + if (_index->b || _index->c || _index->d) // if bigger that 2^64 + index = std::numeric_limits::max(); // set max to fill with 0 leter + + auto data = _rtData->callData; + auto size = _rtData->elems[RuntimeData::CallDataSize].a; + for (auto i = 0; i < 32; ++i) + { + if (index < size) + { + o_value[i] = data[index]; + ++index; // increment only if in range + } + else + o_value[i] = 0; + } + } + +} // extern "C" + diff --git a/libevmjit/Stack.h b/libevmjit/Stack.h new file mode 100644 index 000000000..3e8881e4f --- /dev/null +++ b/libevmjit/Stack.h @@ -0,0 +1,43 @@ +#pragma once + +#include "CompilerHelper.h" + +#include + +namespace dev +{ +namespace eth +{ +namespace jit +{ +class RuntimeManager; + +class Stack : public CompilerHelper +{ +public: + Stack(llvm::IRBuilder<>& builder, RuntimeManager& runtimeManager); + + llvm::Value* get(size_t _index); + void set(size_t _index, llvm::Value* _value); + void pop(size_t _count); + void push(llvm::Value* _value); + + static size_t maxStackSize; + +private: + RuntimeManager& m_runtimeManager; + + llvm::Function* m_push; + llvm::Function* m_pop; + llvm::Function* m_get; + llvm::Function* m_set; + + llvm::Value* m_arg; +}; + + +} +} +} + + diff --git a/libevmjit/Type.cpp b/libevmjit/Type.cpp new file mode 100644 index 000000000..22ccea12e --- /dev/null +++ b/libevmjit/Type.cpp @@ -0,0 +1,67 @@ + +#include "Type.h" + +#include + +#include "RuntimeManager.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +llvm::IntegerType* Type::Word; +llvm::PointerType* Type::WordPtr; +llvm::IntegerType* Type::lowPrecision; +llvm::IntegerType* Type::Bool; +llvm::IntegerType* Type::Size; +llvm::IntegerType* Type::Byte; +llvm::PointerType* Type::BytePtr; +llvm::Type* Type::Void; +llvm::IntegerType* Type::MainReturn; +llvm::PointerType* Type::EnvPtr; +llvm::PointerType* Type::RuntimeDataPtr; +llvm::PointerType* Type::RuntimePtr; + +void Type::init(llvm::LLVMContext& _context) +{ + if (!Word) // Do init only once + { + Word = llvm::Type::getIntNTy(_context, 256); + WordPtr = Word->getPointerTo(); + lowPrecision = llvm::Type::getInt64Ty(_context); + // TODO: Size should be architecture-dependent + Bool = llvm::Type::getInt1Ty(_context); + Size = llvm::Type::getInt64Ty(_context); + Byte = llvm::Type::getInt8Ty(_context); + BytePtr = Byte->getPointerTo(); + Void = llvm::Type::getVoidTy(_context); + MainReturn = llvm::Type::getInt32Ty(_context); + + EnvPtr = llvm::StructType::create(_context, "Env")->getPointerTo(); + RuntimeDataPtr = RuntimeManager::getRuntimeDataType()->getPointerTo(); + RuntimePtr = RuntimeManager::getRuntimeType()->getPointerTo(); + } +} + +llvm::ConstantInt* Constant::get(int64_t _n) +{ + return llvm::ConstantInt::getSigned(Type::Word, _n); +} + +llvm::ConstantInt* Constant::get(llvm::APInt const& _n) +{ + return llvm::ConstantInt::get(Type::Word->getContext(), _n); +} + +llvm::ConstantInt* Constant::get(ReturnCode _returnCode) +{ + return llvm::ConstantInt::get(Type::MainReturn, static_cast(_returnCode)); +} + +} +} +} + diff --git a/libevmjit/Type.h b/libevmjit/Type.h new file mode 100644 index 000000000..d4804ee59 --- /dev/null +++ b/libevmjit/Type.h @@ -0,0 +1,54 @@ + +#pragma once + +#include +#include +#include "Common.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +struct Type +{ + static llvm::IntegerType* Word; + static llvm::PointerType* WordPtr; + + /// Type for doing low precision arithmetics where 256-bit precision is not supported by native target + /// @TODO: Use 64-bit for now. In 128-bit compiler-rt library functions are required + static llvm::IntegerType* lowPrecision; + + static llvm::IntegerType* Bool; + static llvm::IntegerType* Size; + + static llvm::IntegerType* Byte; + static llvm::PointerType* BytePtr; + + static llvm::Type* Void; + + /// Main function return type + static llvm::IntegerType* MainReturn; + + static llvm::PointerType* EnvPtr; + static llvm::PointerType* RuntimeDataPtr; + static llvm::PointerType* RuntimePtr; + + static void init(llvm::LLVMContext& _context); +}; + +struct Constant +{ + /// Returns word-size constant + static llvm::ConstantInt* get(int64_t _n); + static llvm::ConstantInt* get(llvm::APInt const& _n); + + static llvm::ConstantInt* get(ReturnCode _returnCode); +}; + +} +} +} + diff --git a/libevmjit/Utils.cpp b/libevmjit/Utils.cpp new file mode 100644 index 000000000..f1ffbf67f --- /dev/null +++ b/libevmjit/Utils.cpp @@ -0,0 +1,66 @@ + +#include +#include "Utils.h" +#include "Instruction.h" +#include "Runtime.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +u256 llvm2eth(i256 _i) +{ + u256 u = 0; + u |= _i.d; + u <<= 64; + u |= _i.c; + u <<= 64; + u |= _i.b; + u <<= 64; + u |= _i.a; + return u; +} + +i256 eth2llvm(u256 _u) +{ + i256 i; + u256 mask = 0xFFFFFFFFFFFFFFFF; + i.a = static_cast(_u & mask); + _u >>= 64; + i.b = static_cast(_u & mask); + _u >>= 64; + i.c = static_cast(_u & mask); + _u >>= 64; + i.d = static_cast(_u & mask); + return i; +} + +llvm::APInt readPushData(bytes::const_iterator& _curr, bytes::const_iterator _end) +{ + auto pushInst = *_curr; + assert(Instruction(pushInst) >= Instruction::PUSH1 && Instruction(pushInst) <= Instruction::PUSH32); + auto numBytes = pushInst - static_cast(Instruction::PUSH1) + 1; + llvm::APInt value(256, 0); + ++_curr; // Point the data + for (decltype(numBytes) i = 0; i < numBytes; ++i) + { + byte b = (_curr != _end) ? *_curr++ : 0; + value <<= 8; + value |= b; + } + --_curr; // Point the last real byte read + return value; +} + +void terminate(ReturnCode _returnCode) +{ + auto jmpBuf = Runtime::getCurrJmpBuf(); + std::longjmp(jmpBuf, static_cast(_returnCode)); +} + +} +} +} diff --git a/libevmjit/Utils.h b/libevmjit/Utils.h new file mode 100644 index 000000000..db0647fdf --- /dev/null +++ b/libevmjit/Utils.h @@ -0,0 +1,24 @@ +#pragma once + +#include "Common.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +struct JIT: public NoteChannel { static const char* name() { return "JIT"; } }; + +//#define clog(CHANNEL) std::cerr +#define clog(CHANNEL) std::ostream(nullptr) + +u256 llvm2eth(i256); +i256 eth2llvm(u256); + +void terminate(ReturnCode _returnCode); + +} +} +} diff --git a/libevmjit/interface.c b/libevmjit/interface.c new file mode 100644 index 000000000..47589578b --- /dev/null +++ b/libevmjit/interface.c @@ -0,0 +1,30 @@ +#include + +// JIT object opaque type +typedef struct evm_jit evm_jit; + +// Contract execution return code +typedef int evm_jit_return_code; + +// Host-endian 256-bit integer type +typedef struct i256 i256; + +// Big-endian right aligned 256-bit hash +typedef struct h256 h256; + +// Runtime data struct - must be provided by external language (Go, C++, Python) +typedef struct evm_jit_rt evm_jit_rt; + +// Runtime callback functions - implementations must be provided by external language (Go, C++, Python) +void evm_jit_rt_sload(evm_jit_rt* _rt, i256* _index, i256* _ret); +void evm_jit_rt_sstore(evm_jit_rt* _rt, i256* _index, i256* _value); +void evm_jit_rt_balance(evm_jit_rt* _rt, h256* _address, i256* _ret); +// And so on... + +evm_jit* evm_jit_create(evm_jit_rt* _runtime_data); + +evm_jit_return_code evm_jit_execute(evm_jit* _jit); + +void evm_jit_get_return_data(evm_jit* _jit, char* _return_data_offset, size_t* _return_data_size); + +void evm_jit_destroy(evm_jit* _jit); From 8badd50826c56ab0730c153b8773551206e12e3c Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Tue, 6 Jan 2015 14:42:37 +0100 Subject: [PATCH 085/111] added more jumpdest tests --- test/vmIOandFlowOperationsTestFiller.json | 709 +++++++++++++++++++++- 1 file changed, 704 insertions(+), 5 deletions(-) diff --git a/test/vmIOandFlowOperationsTestFiller.json b/test/vmIOandFlowOperationsTestFiller.json index dce594e1e..073c8ac80 100644 --- a/test/vmIOandFlowOperationsTestFiller.json +++ b/test/vmIOandFlowOperationsTestFiller.json @@ -475,6 +475,174 @@ } }, + "jumpAfterStop": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "0x6006560060015b6002600355", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "jumpiAfterStop": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "0x60016008570060015b6002600355", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "jumpInsidePushWithoutJumpDest": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "0x60055661eeff", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "jumpInsidePushWithJumpDest": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "0x600456655b6001600155", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "jumpifInsidePushWithoutJumpDest": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "0x600160075761eeff", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "jumpifInsidePushWithJumpDest": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "0x6001600657655b6001600155", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + "jump0_foreverOutOfGas": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", @@ -488,7 +656,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x600056", + "code" : "0x5b600056", "storage": {} } }, @@ -503,7 +671,7 @@ } }, - "jump0": { + "jump0_outOfBoundary": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -558,7 +726,35 @@ } }, - "jump0_jumpdest1": { + "jump0_withoutJumpdest": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "0x60236007566001600255", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "jump0_AfterJumpdest": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -614,7 +810,7 @@ } }, - "jump0_jumpdest3": { + "jump0_AfterJumpdest3": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -754,7 +950,7 @@ } }, - "jumpi2": { + "jumpiOutsideBoundary": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -782,6 +978,509 @@ } }, + "DynamicJumpAfterStop": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "0x6008600101560060015b6002600355", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "DynamicJumpiAfterStop": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "0x60016008600301570060015b6002600355", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "DynamicJumpInsidePushWithoutJumpDest": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "0x60056003015661eeff", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "DynamicJumpInsidePushWithJumpDest": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "0x600460030156655b6001600155", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "DynamicJumpifInsidePushWithoutJumpDest": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "0x600160076003015761eeff", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "DynamicJumpifInsidePushWithJumpDest": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "0x6001600660030157655b6001600155", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "DynamicJump0_foreverOutOfGas": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "0x5b600060000156", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "DyanmicJump0_outOfBoundary": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "0x60236007600301566001600255", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + "DynamicJump0_jumpdest0": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "0x602360076003015660015b600255", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "DynamicJump0_withoutJumpdest": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "0x60236007600301566001600255", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "DynamicJump0_AfterJumpdest": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "0x602360086003015660015b600255", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "DynamicJump0_jumpdest2": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "0x6023600a6008506003015660015b600255", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "DynamicJump0_AfterJumpdest3": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "0x6023600b6008506003015660015b600255", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "DynamicJump1": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "0x620fffff620fffff0160030156", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "DynamicJumpi0": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "0x602360016009600301576001600255", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "DynamicJumpi1_jumpdest": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "0x60236001600a6003015760015b600255", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "DynamicJumpi1": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "0x602360006009600301576001600255", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "DynamicJumpiOutsideBoundary": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "0x60017ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0600301576002600355", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + "pc0": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", From 418357cfbd1dfffde12c74444484c350ec256a1f Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Tue, 6 Jan 2015 15:05:13 +0100 Subject: [PATCH 086/111] eth --version display protocol version --- eth/main.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/eth/main.cpp b/eth/main.cpp index d55766cfd..ffd8481ea 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -145,6 +145,8 @@ string credits(bool _interactive = false) void version() { cout << "eth version " << dev::Version << endl; + cout << "Network protocol version: " << dev::eth::c_protocolVersion << endl; + cout << "Client database version: " << dev::eth::c_databaseVersion << endl; cout << "Build: " << DEV_QUOTED(ETH_BUILD_PLATFORM) << "/" << DEV_QUOTED(ETH_BUILD_TYPE) << endl; exit(0); } From 13a836987d41fb3fc039dc44e6cf7fd4cbf9bd24 Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Tue, 6 Jan 2015 16:25:21 +0100 Subject: [PATCH 087/111] add zero memory expansion tests --- test/stSystemOperationsTestFiller.json | 117 +++++++++++++++++++++++++ 1 file changed, 117 insertions(+) diff --git a/test/stSystemOperationsTestFiller.json b/test/stSystemOperationsTestFiller.json index b79066368..47d18b7b1 100644 --- a/test/stSystemOperationsTestFiller.json +++ b/test/stSystemOperationsTestFiller.json @@ -33,6 +33,40 @@ } }, + "createNameRegistratorZeroMemExpansion": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (MSTORE 0 0x601080600c6000396000f30060003554156009570060203560003555) [[ 0 ]] (CREATE 23 0 0) }", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "10000", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + "createNameRegistratorValueTooHigh": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", @@ -177,6 +211,48 @@ } }, + "CallToNameRegistratorZeorSizeMemExpansion": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (MSTORE 32 0xaaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffaa ) [[ 0 ]] (CALL 1000 0x945304eb96065b2a98b57a48a06ae28d285a71b5 23 0 0 0 0) }", + "storage": {} + }, + "945304eb96065b2a98b57a48a06ae28d285a71b5" : { + "balance" : "23", + "code" : "0x60003554156009570060203560003555", + "nonce" : "0", + "storage" : { + } + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "", + "storage": {} + } + + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "10000", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + "CallToReturn1": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", @@ -1132,6 +1208,47 @@ } }, + "callcodeToNameRegistratorZeroMemExpanion": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (MSTORE 32 0xaaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffaa ) [[ 0 ]] (CALLCODE 1000 0x945304eb96065b2a98b57a48a06ae28d285a71b5 23 0 0 0 0) }", + "storage": {} + }, + "945304eb96065b2a98b57a48a06ae28d285a71b5" : { + "balance" : "23", + "code" : "0x60003554156009570060203560003555", + "nonce" : "0", + "storage" : { + } + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "1000000", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + "TestNameRegistrator": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", From 3cf6da492bbfc5f527895fb9563915dbd9854bdf Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Tue, 6 Jan 2015 16:32:01 +0100 Subject: [PATCH 088/111] add zero memory expansion tests for vm --- test/vmEnvironmentalInfoTestFiller.json | 94 ++++++++++++++++++++++++- 1 file changed, 92 insertions(+), 2 deletions(-) diff --git a/test/vmEnvironmentalInfoTestFiller.json b/test/vmEnvironmentalInfoTestFiller.json index abeed9945..91b09cd33 100644 --- a/test/vmEnvironmentalInfoTestFiller.json +++ b/test/vmEnvironmentalInfoTestFiller.json @@ -478,6 +478,34 @@ } }, + "calldatacopyZeroMemExpansion": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (CALLDATACOPY 0 0 0 ) [[ 0 ]] @0}", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "0x1234567890abcdef01234567890abcdef", + "gasPrice" : "1000000000", + "gas" : "100000000000" + } + }, + "calldatacopy_DataIndexTooHigh": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", @@ -674,7 +702,35 @@ } }, - "codecopy1": { + "codecopy0": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (CODECOPY 0 0 5 ) [[ 0 ]] @0 }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "0x1234567890abcdef01234567890abcdef", + "gasPrice" : "1000000000", + "gas" : "100000000000" + } + }, + + "codecopyZeroMemExpansion": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -687,7 +743,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "{ (CODECOPY 0 0 (CODESIZE) ) [[ 0 ]] @0 }", + "code" : "{ (CODECOPY 0 0 0 ) [[ 0 ]] @0 }", "storage": {} } }, @@ -825,6 +881,40 @@ } }, + "extcodecopyZeroMemExpansion": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (EXTCODECOPY (CALLER) 0 0 0 ) ) [[ 0 ]] @0 }", + "storage": {} + }, + "cd1722f3947def4cf144679da39c4c32bdc35681" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] 5 }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "0x1234567890abcdef01234567890abcdef", + "gasPrice" : "123456789", + "gas" : "100000000000" + } + }, + "extcodecopy0": { "env" : { From 8491e5f2f797fdbb82e68acc1a7208b5a0f754c7 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 6 Jan 2015 16:42:58 +0100 Subject: [PATCH 089/111] Various fixes. Initial portion of NatSpec integration. --- alethzero/MainWin.cpp | 2 +- alethzero/MainWin.h | 2 ++ alethzero/OurWebThreeStubServer.cpp | 40 ++++++++++++++++++++++++++- alethzero/OurWebThreeStubServer.h | 4 +++ eth/main.cpp | 2 +- libdevcrypto/CryptoPP.cpp | 4 +-- libethereum/EthereumPeer.cpp | 8 ------ libethereum/Executive.cpp | 2 +- libethereum/Executive.h | 2 +- libethereum/State.cpp | 7 +++++ libethereum/State.h | 4 +++ libweb3jsonrpc/WebThreeStubServer.cpp | 22 ++++++++++----- libweb3jsonrpc/WebThreeStubServer.h | 6 +++- mix/AssemblyDebuggerModel.cpp | 2 +- 14 files changed, 83 insertions(+), 24 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index dbcd0f493..b73a2cd0d 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -1475,7 +1475,7 @@ void Main::populateDebugger(dev::bytesConstRef _r) m_history.append(WorldState({steps, ext.myAddress, vm.curPC(), inst, newMemSize, vm.gas(), lastHash, lastDataHash, vm.stack(), vm.memory(), gasCost, ext.state().storage(ext.myAddress), levels})); }; m_currentExecution->go(onOp); - m_currentExecution->finalize(onOp); + m_currentExecution->finalize(); initDebugger(); updateDebugger(); } diff --git a/alethzero/MainWin.h b/alethzero/MainWin.h index 5c196792d..ed5d275eb 100644 --- a/alethzero/MainWin.h +++ b/alethzero/MainWin.h @@ -78,6 +78,8 @@ public: dev::eth::Client* ethereum() const { return m_webThree->ethereum(); } std::shared_ptr whisper() const { return m_webThree->whisper(); } + std::string lookupNatSpec(dev::h256 const& _contractCode) const { (void)_contractCode; return ""; } // TODO: actually implement with leveldb & a UI. + QList owned() const { return m_myIdentities + m_myKeys; } public slots: diff --git a/alethzero/OurWebThreeStubServer.cpp b/alethzero/OurWebThreeStubServer.cpp index 0c6f42b5a..0d840e8d4 100644 --- a/alethzero/OurWebThreeStubServer.cpp +++ b/alethzero/OurWebThreeStubServer.cpp @@ -20,12 +20,16 @@ */ #include "OurWebThreeStubServer.h" + +#include +#include +#include "MainWin.h" using namespace std; using namespace dev; using namespace dev::eth; OurWebThreeStubServer::OurWebThreeStubServer(jsonrpc::AbstractServerConnector& _conn, dev::WebThreeDirect& _web3, std::vector const& _accounts): - WebThreeStubServer(_conn, _web3, _accounts) + WebThreeStubServer(_conn, _web3, _accounts), m_web3(&_web3) {} std::string OurWebThreeStubServer::shh_newIdentity() @@ -34,3 +38,37 @@ std::string OurWebThreeStubServer::shh_newIdentity() emit onNewId(QString::fromStdString(toJS(kp.sec()))); return toJS(kp.pub()); } + +bool OurWebThreeStubServer::authenticate(dev::TransactionSkeleton const& _t) const +{ + return true; + + // To get the balance of the sender + cnote << "Sender has ETH: " << m_web3->ethereum()->postState().balance(_t.from); + + Main* main; // don't know this yet, should be a member and set at construction time by Main, who will construct us. + + h256 contractCodeHash = m_web3->ethereum()->postState().codeHash(_t.to); + + if (contractCodeHash == EmptySHA3) + { + // recipient has no code - nothing special about this transaction. + // TODO: show basic message for value transfer. + return true; // or whatever. + } + + std::string natspecJson = main->lookupNatSpec(contractCodeHash); + + if (natspecJson.empty()) + { + // TODO: HUGE warning - we don't know what this will do! + return false; // or whatever. + } + + // otherwise it's a transaction to contract for which we have the natspec: + // determine the actual message (embellish with real data) and ask user. + +// QMessageBox::question(); + + return true; +} diff --git a/alethzero/OurWebThreeStubServer.h b/alethzero/OurWebThreeStubServer.h index fb026d07e..9ff973371 100644 --- a/alethzero/OurWebThreeStubServer.h +++ b/alethzero/OurWebThreeStubServer.h @@ -32,7 +32,11 @@ public: OurWebThreeStubServer(jsonrpc::AbstractServerConnector& _conn, dev::WebThreeDirect& _web3, std::vector const& _accounts); virtual std::string shh_newIdentity() override; + virtual bool authenticate(dev::TransactionSkeleton const& _t) const; signals: void onNewId(QString _s); + +private: + dev::WebThreeDirect* m_web3; }; diff --git a/eth/main.cpp b/eth/main.cpp index d55766cfd..c6435235e 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -672,7 +672,7 @@ int main(int argc, char** argv) f << ext->myAddress << " " << hex << toHex(dev::toCompactBigEndian(vm->curPC(), 1)) << " " << hex << toHex(dev::toCompactBigEndian((int)(byte)instr, 1)) << " " << hex << toHex(dev::toCompactBigEndian((uint64_t)vm->gas(), 1)) << endl; }; e.go(oof); - e.finalize(oof); + e.finalize(); } catch(Exception const& _e) { diff --git a/libdevcrypto/CryptoPP.cpp b/libdevcrypto/CryptoPP.cpp index 766ca485d..d73e3fa43 100644 --- a/libdevcrypto/CryptoPP.cpp +++ b/libdevcrypto/CryptoPP.cpp @@ -108,7 +108,7 @@ Signature Secp256k1::sign(Secret const& _key, h256 const& _hash) Integer kInv = k.InverseMod(m_q); Integer z(_hash.asBytes().data(), 32); - Integer s = (kInv * (Integer(_key.asBytes().data(), 32)*r + z)) % m_q; + Integer s = (kInv * (Integer(_key.asBytes().data(), 32) * r + z)) % m_q; if (r == 0 || s == 0) BOOST_THROW_EXCEPTION(InvalidState()); @@ -144,7 +144,7 @@ Public Secp256k1::recover(Signature _signature, bytesConstRef _message) Integer s(_signature.data()+32, 32); // cryptopp encodes sign of y as 0x02/0x03 instead of 0/1 or 27/28 byte encodedpoint[33]; - encodedpoint[0] = _signature[64]|2; + encodedpoint[0] = _signature[64] | 2; memcpy(&encodedpoint[1], _signature.data(), 32); ECP::Element x; diff --git a/libethereum/EthereumPeer.cpp b/libethereum/EthereumPeer.cpp index b204546d4..0901766bf 100644 --- a/libethereum/EthereumPeer.cpp +++ b/libethereum/EthereumPeer.cpp @@ -317,14 +317,6 @@ bool EthereumPeer::interpret(unsigned _id, RLP const& _r) disable("Blacklisted client version."); else if (host()->isBanned(session()->id())) disable("Peer banned for previous bad behaviour."); - else - { - // Grab transactions off them. - RLPStream s; - prep(s, GetTransactionsPacket); - sealAndSend(s); - transition(Asking::Nothing); - } break; } case GetTransactionsPacket: break; // DEPRECATED. diff --git a/libethereum/Executive.cpp b/libethereum/Executive.cpp index 965d6f0af..f79bb4a3b 100644 --- a/libethereum/Executive.cpp +++ b/libethereum/Executive.cpp @@ -220,7 +220,7 @@ bool Executive::go(OnOpFunc const& _onOp) return true; } -void Executive::finalize(OnOpFunc const&) +void Executive::finalize() { // SSTORE refunds... // must be done before the miner gets the fees. diff --git a/libethereum/Executive.h b/libethereum/Executive.h index 5a97e5f87..d743e3746 100644 --- a/libethereum/Executive.h +++ b/libethereum/Executive.h @@ -64,7 +64,7 @@ public: bool setup(bytesConstRef _transaction); /// Finalise a transaction previously set up with setup(). /// @warning Only valid after setup(), and possibly go(). - void finalize(OnOpFunc const& _onOp = OnOpFunc()); + void finalize(); /// @returns the transaction from setup(). /// @warning Only valid after setup(). Transaction const& t() const { return m_t; } diff --git a/libethereum/State.cpp b/libethereum/State.cpp index dfd65c713..c6a6ce125 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -958,6 +958,13 @@ bytes const& State::code(Address _contract) const return m_cache[_contract].code(); } +h256 State::codeHash(Address _contract) const +{ + if (!addressHasCode(_contract)) + return EmptySHA3; + return m_cache[_contract].codeHash(); +} + bool State::isTrieGood(bool _enforceRefs, bool _requireNoLeftOvers) const { for (int e = 0; e < (_enforceRefs ? 2 : 1); ++e) diff --git a/libethereum/State.h b/libethereum/State.h index 0473893c4..921c82bb9 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -201,6 +201,10 @@ public: /// @returns bytes() if no account exists at that address. bytes const& code(Address _contract) const; + /// Get the code hash of an account. + /// @returns EmptySHA3 if no account exists at that address or if there is no code associated with the address. + h256 codeHash(Address _contract) const; + /// Note that the given address is sending a transaction and thus increment the associated ticker. void noteSending(Address _id); diff --git a/libweb3jsonrpc/WebThreeStubServer.cpp b/libweb3jsonrpc/WebThreeStubServer.cpp index d88aa0a5f..8dc95b8c2 100644 --- a/libweb3jsonrpc/WebThreeStubServer.cpp +++ b/libweb3jsonrpc/WebThreeStubServer.cpp @@ -677,16 +677,24 @@ std::string WebThreeStubServer::eth_transact(Json::Value const& _json) t.gasPrice = 10 * dev::eth::szabo; if (!t.gas) 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) - // TODO: from qethereum, insert validification hook here. - client()->transact(m_accounts[t.from].secret(), t.value, t.to, t.data, t.gas, t.gasPrice); - else - ret = toJS(client()->transact(m_accounts[t.from].secret(), t.value, t.data, t.gas, t.gasPrice)); - client()->flushTransactions(); + if (authenticate(t)) + { + if (t.to) + // TODO: from qethereum, insert validification hook here. + client()->transact(m_accounts[t.from].secret(), t.value, t.to, t.data, t.gas, t.gasPrice); + else + ret = toJS(client()->transact(m_accounts[t.from].secret(), t.value, t.data, t.gas, t.gasPrice)); + client()->flushTransactions(); + } return ret; } +bool WebThreeStubServer::authenticate(TransactionSkeleton const& _t) const +{ + cwarn << "Silently signing transaction from address" << _t.from.abridged() << ": User validation hook goes here."; + return true; +} + Json::Value WebThreeStubServer::eth_transactionByHash(std::string const& _hash, int const& _i) { if (!client()) diff --git a/libweb3jsonrpc/WebThreeStubServer.h b/libweb3jsonrpc/WebThreeStubServer.h index 6d54c59ef..0f81fce9d 100644 --- a/libweb3jsonrpc/WebThreeStubServer.h +++ b/libweb3jsonrpc/WebThreeStubServer.h @@ -42,6 +42,7 @@ namespace dev { class WebThreeDirect; class KeyPair; +class TransactionSkeleton; namespace eth { class Interface; @@ -119,12 +120,15 @@ public: void setIdentities(std::vector const& _ids); std::map const& ids() const { return m_ids; } +protected: + virtual bool authenticate(dev::TransactionSkeleton const& _t) const; + private: dev::eth::Interface* client() const; std::shared_ptr face() const; dev::WebThreeDirect& m_web3; std::map m_accounts; - + ldb::ReadOptions m_readOptions; ldb::WriteOptions m_writeOptions; ldb::DB* m_db; diff --git a/mix/AssemblyDebuggerModel.cpp b/mix/AssemblyDebuggerModel.cpp index 354d0bd1e..3967b09af 100644 --- a/mix/AssemblyDebuggerModel.cpp +++ b/mix/AssemblyDebuggerModel.cpp @@ -73,7 +73,7 @@ DebuggingContent AssemblyDebuggerModel::executeTransaction(bytesConstRef const& }; m_currentExecution->go(onOp); - m_currentExecution->finalize(onOp); + m_currentExecution->finalize(); m_executiveState.completeMine(); DebuggingContent d; From 506fe0f6e88f268192403dc39ab8bb72c0367a98 Mon Sep 17 00:00:00 2001 From: subtly Date: Tue, 6 Jan 2015 16:51:10 +0100 Subject: [PATCH 090/111] define constructors for windows --- libp2p/NodeTable.h | 5 +++-- libp2p/UDP.h | 2 +- test/net.cpp | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/libp2p/NodeTable.h b/libp2p/NodeTable.h index 8f15cb958..e8385998e 100644 --- a/libp2p/NodeTable.h +++ b/libp2p/NodeTable.h @@ -46,6 +46,7 @@ namespace p2p * @todo makeRequired: exclude bucket from refresh if we have node as peer. * * [Optimization] + * @todo encapsulate doFindNode into NetworkAlgorithm (task) * @todo Pong to include ip:port where ping was received * @todo expiration and sha3(id) 'to' for messages which are replies (prevents replay) * @todo std::shared_ptr m_cachedPingPacket; @@ -281,7 +282,7 @@ struct Pong: RLPXDatagram */ struct FindNode: RLPXDatagram { - using RLPXDatagram::RLPXDatagram; + FindNode(bi::udp::endpoint _ep): RLPXDatagram(_ep) {} FindNode(bi::udp::endpoint _ep, NodeId _target, std::chrono::seconds _expiration = std::chrono::seconds(30)): RLPXDatagram(_ep), target(_target), expiration(futureFromEpoch(_expiration)) {} h512 target; @@ -312,7 +313,7 @@ struct Neighbours: RLPXDatagram void interpretRLP(RLP const& _r) { ipAddress = _r[0].toString(); port = _r[1].toInt(); node = h512(_r[2].toBytes()); } }; - using RLPXDatagram::RLPXDatagram; + Neighbours(bi::udp::endpoint _ep): RLPXDatagram(_ep) {} Neighbours(bi::udp::endpoint _to, std::vector> const& _nearest, unsigned _offset = 0, unsigned _limit = 0): RLPXDatagram(_to) { auto limit = _limit ? std::min(_nearest.size(), (size_t)(_offset + _limit)) : _nearest.size(); diff --git a/libp2p/UDP.h b/libp2p/UDP.h index 96e7fd99e..6de783509 100644 --- a/libp2p/UDP.h +++ b/libp2p/UDP.h @@ -76,7 +76,7 @@ struct RLPXDatagramFace: public UDPDatagram template struct RLPXDatagram: public RLPXDatagramFace { - using RLPXDatagramFace::RLPXDatagramFace; + RLPXDatagram(bi::udp::endpoint const& _ep): RLPXDatagramFace(_ep) {} static T fromBytesConstRef(bi::udp::endpoint const& _ep, bytesConstRef _bytes) { T t(_ep); t.interpretRLP(_bytes); return std::move(t); } }; diff --git a/test/net.cpp b/test/net.cpp index 6952c282a..946995130 100644 --- a/test/net.cpp +++ b/test/net.cpp @@ -51,7 +51,7 @@ protected: struct TestNodeTable: public NodeTable { /// Constructor - using NodeTable::NodeTable; + TestNodeTable(ba::io_service& _io, KeyPair _alias, uint16_t _port = 30300): NodeTable(_io, _alias, _port) {} static std::vector> createTestNodes(unsigned _count) { From 2c168ffa142831aa537ad8669495ddfb1acaa562 Mon Sep 17 00:00:00 2001 From: subtly Date: Tue, 6 Jan 2015 17:01:17 +0100 Subject: [PATCH 091/111] stl sleep_for, for windows --- test/net.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/net.cpp b/test/net.cpp index 946995130..67c50dae8 100644 --- a/test/net.cpp +++ b/test/net.cpp @@ -206,7 +206,7 @@ BOOST_AUTO_TEST_CASE(test_udp_once) UDPDatagram d(bi::udp::endpoint(boost::asio::ip::address::from_string("127.0.0.1"), 30300), bytes({65,65,65,65})); TestUDPSocket a; a.m_socket->connect(); a.start(); a.m_socket->send(d); - sleep(1); + this_thread::sleep_for(chrono::seconds(1)); BOOST_REQUIRE_EQUAL(true, a.success); } From c2b194d4c35bdbb2e8b2cda948af1556ed969bdc Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Tue, 6 Jan 2015 17:42:38 +0100 Subject: [PATCH 092/111] Creating the canonical signature of a function, for later use in the ABI --- libsolidity/AST.cpp | 17 +++++++++++++++++ libsolidity/AST.h | 6 ++++++ 2 files changed, 23 insertions(+) diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index 1fa6d8f6f..629525210 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -110,6 +110,23 @@ void FunctionDefinition::checkTypeRequirements() m_body->checkTypeRequirements(); } +std::string FunctionDefinition::getCanonicalSignature() +{ + auto parameters = getParameters(); + std::string ret = getName() + "("; + unsigned int i = 1; + + for (ASTPointer const& member: parameters) + { + ret += member->getType()->toString(); + if (i != parameters.size()) { + ret += ","; + } + } + ret += ")"; + return ret; +} + void Block::checkTypeRequirements() { for (shared_ptr const& statement: m_statements) diff --git a/libsolidity/AST.h b/libsolidity/AST.h index b7c3dc6c0..32cc23a5b 100644 --- a/libsolidity/AST.h +++ b/libsolidity/AST.h @@ -277,6 +277,12 @@ public: /// Checks that all parameters have allowed types and calls checkTypeRequirements on the body. void checkTypeRequirements(); + /// Returns the canonical signature of the function + /// That consists of the name of the function followed by the + /// types of the arguments separated by commas all enclosed in parentheses + /// without any spaces + std::string getCanonicalSignature(); + private: bool m_isPublic; ASTPointer m_parameters; From 3387d82a9c1b438dd298a3048c722d4d1b9fc29b Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 6 Jan 2015 20:12:54 +0100 Subject: [PATCH 093/111] More efficient getLastHashes. --- libethereum/State.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libethereum/State.cpp b/libethereum/State.cpp index c6a6ce125..e0705859f 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -1006,9 +1006,9 @@ LastHashes State::getLastHashes(BlockChain const& _bc) const ret.resize(256); if (c_protocolVersion > 49) { - unsigned n = (unsigned)m_previousBlock.number; - for (unsigned i = 0; i < 256; ++i) - ret[i] = _bc.numberHash(std::max(n, i) - i); + ret[0] = _bc.currentHash(); + for (unsigned i = 1; i < 256; ++i) + ret[i] = ret[i - 1] ? _bc.details(ret[i - 1]).parent : h256(); } return ret; } From 42fbfb818241f4db9193c84c69b1057f81b6300d Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Tue, 6 Jan 2015 20:57:33 +0100 Subject: [PATCH 094/111] Blockhash tests --- test/stBlockHashTestFiller.json | 103 ++++++++++++++++++++++++++++++++ test/state.cpp | 15 ++++- 2 files changed, 117 insertions(+), 1 deletion(-) create mode 100644 test/stBlockHashTestFiller.json diff --git a/test/stBlockHashTestFiller.json b/test/stBlockHashTestFiller.json new file mode 100644 index 000000000..ccbff5d21 --- /dev/null +++ b/test/stBlockHashTestFiller.json @@ -0,0 +1,103 @@ +{ + "blockhash0" : { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "5", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (BLOCKHASH 0) [[ 1 ]] (BLOCKHASH 5) [[ 2 ]] (BLOCKHASH 4) }", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "100000", + "nonce" : 0, + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "8500", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "10", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "blockhashOutOfRange" : { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "257", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (BLOCKHASH 0) [[ 1 ]] (BLOCKHASH 257) [[ 2 ]] (BLOCKHASH 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) }", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "100000", + "nonce" : 0, + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "8500", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "10", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "blockhashInRange" : { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "257", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (BLOCKHASH 1) [[ 1 ]] (BLOCKHASH 2) [[ 2 ]] (BLOCKHASH 256) }", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "100000", + "nonce" : 0, + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "8500", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "10", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + } +} diff --git a/test/state.cpp b/test/state.cpp index 133468226..db8350e42 100644 --- a/test/state.cpp +++ b/test/state.cpp @@ -39,6 +39,14 @@ using namespace dev::eth; namespace dev { namespace test { +LastHashes lastHashes(u256 _currentBlockNumber) +{ + LastHashes ret; + for (u256 i = 1; i <= 256 && i <= _currentBlockNumber; ++i) + ret.push_back(sha3(toString(_currentBlockNumber - i))); + return ret; +} + void doStateTests(json_spirit::mValue& v, bool _fillin) @@ -62,7 +70,7 @@ void doStateTests(json_spirit::mValue& v, bool _fillin) try { - theState.execute(LastHashes(), tx, &output); + theState.execute(lastHashes(importer.m_environment.currentBlock.number), tx, &output); } catch (Exception const& _e) { @@ -157,6 +165,11 @@ BOOST_AUTO_TEST_CASE(stRefundTest) dev::test::executeTests("stRefundTest", "/StateTests", dev::test::doStateTests); } +BOOST_AUTO_TEST_CASE(stBlockHashTest) +{ + dev::test::executeTests("stBlockHashTest", "/StateTests", dev::test::doStateTests); +} + BOOST_AUTO_TEST_CASE(stCreateTest) { for (int i = 1; i < boost::unit_test::framework::master_test_suite().argc; ++i) From 0c83932d911eccc61383990f0e1da1e5ecad5531 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Wed, 7 Jan 2015 02:07:34 +0100 Subject: [PATCH 095/111] Test for the Canonical Signature of a function --- libsolidity/AST.cpp | 1 + test/SolidityNameAndTypeResolution.cpp | 21 ++++++++++++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index 629525210..fd8f45a73 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -122,6 +122,7 @@ std::string FunctionDefinition::getCanonicalSignature() if (i != parameters.size()) { ret += ","; } + i++; } ret += ")"; return ret; diff --git a/test/SolidityNameAndTypeResolution.cpp b/test/SolidityNameAndTypeResolution.cpp index 25bff71f7..e44c9fa29 100644 --- a/test/SolidityNameAndTypeResolution.cpp +++ b/test/SolidityNameAndTypeResolution.cpp @@ -38,7 +38,7 @@ namespace test namespace { -void parseTextAndResolveNames(std::string const& _source) +ASTPointer parseTextAndResolveNames(std::string const& _source) { Parser parser; ASTPointer sourceUnit = parser.parse(std::make_shared(CharStream(_source))); @@ -50,6 +50,8 @@ void parseTextAndResolveNames(std::string const& _source) for (ASTPointer const& node: sourceUnit->getNodes()) if (ContractDefinition* contract = dynamic_cast(node.get())) resolver.checkTypeRequirements(*contract); + + return sourceUnit; } } @@ -321,6 +323,23 @@ BOOST_AUTO_TEST_CASE(comparison_bitop_precedence) BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text)); } +BOOST_AUTO_TEST_CASE(function_canonical_signature) +{ + ASTPointer sourceUnit; + char const* text = "contract Test {\n" + " function foo(uint256 arg1, uint64 arg2, bool arg3) returns (uint256 ret) {\n" + " ret = arg1 + arg2;\n" + " }\n" + "}\n"; + BOOST_CHECK_NO_THROW(sourceUnit = parseTextAndResolveNames(text)); + for (ASTPointer const& node: sourceUnit->getNodes()) + if (ContractDefinition* contract = dynamic_cast(node.get())) + { + auto functions = contract->getDefinedFunctions(); + BOOST_ASSERT("foo(uint256,uint64,bool)" == functions[0]->getCanonicalSignature()); + } +} + BOOST_AUTO_TEST_SUITE_END() } From 0c003958b942e3cfbd0023b61939c0b0fde5e5bd Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Wed, 7 Jan 2015 02:27:05 +0100 Subject: [PATCH 096/111] FunctionType also gets CanonicalSignature - also using iterators in the signature creation function --- libsolidity/AST.cpp | 14 +++----------- libsolidity/Types.cpp | 11 +++++++++++ libsolidity/Types.h | 1 + 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index fd8f45a73..cdbfb4e9a 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -114,18 +114,10 @@ std::string FunctionDefinition::getCanonicalSignature() { auto parameters = getParameters(); std::string ret = getName() + "("; - unsigned int i = 1; - for (ASTPointer const& member: parameters) - { - ret += member->getType()->toString(); - if (i != parameters.size()) { - ret += ","; - } - i++; - } - ret += ")"; - return ret; + for (auto it = parameters.cbegin(); it != parameters.cend(); ++it) + ret += (*it)->getType()->toString() + (it + 1 == parameters.end() ? "" : ","); + return ret + ")"; } void Block::checkTypeRequirements() diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index 71319c3ac..640a34ca8 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -452,6 +452,17 @@ unsigned FunctionType::getSizeOnStack() const } } +std::string FunctionType::getCanonicalSignature() const +{ + auto parameters = getParameterTypes(); + std::string ret = "NAME("; //TODO: how to get function name from FunctionType + + for (auto it = parameters.cbegin(); it != parameters.cend(); ++it) + ret += (*it)->toString() + (it + 1 == m_parameterTypes.end() ? "" : ","); + + return ret + ")"; +} + bool MappingType::operator==(Type const& _other) const { if (_other.getCategory() != getCategory()) diff --git a/libsolidity/Types.h b/libsolidity/Types.h index 48539a1d7..0fe685b87 100644 --- a/libsolidity/Types.h +++ b/libsolidity/Types.h @@ -325,6 +325,7 @@ public: virtual unsigned getSizeOnStack() const override; Location const& getLocation() const { return m_location; } + std::string getCanonicalSignature() const; private: TypePointers m_parameterTypes; From 48080e041500135cf0379724f769a04e881d2dce Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Wed, 7 Jan 2015 10:45:59 +0100 Subject: [PATCH 097/111] Small issues with Canonical Function Signature - Also added an extra test --- libsolidity/AST.cpp | 9 ++------- libsolidity/AST.h | 9 ++++----- libsolidity/Types.cpp | 9 ++++----- test/SolidityNameAndTypeResolution.cpp | 19 ++++++++++++++++++- 4 files changed, 28 insertions(+), 18 deletions(-) diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index cdbfb4e9a..0c56cb7a7 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -110,14 +110,9 @@ void FunctionDefinition::checkTypeRequirements() m_body->checkTypeRequirements(); } -std::string FunctionDefinition::getCanonicalSignature() +string FunctionDefinition::getCanonicalSignature() const { - auto parameters = getParameters(); - std::string ret = getName() + "("; - - for (auto it = parameters.cbegin(); it != parameters.cend(); ++it) - ret += (*it)->getType()->toString() + (it + 1 == parameters.end() ? "" : ","); - return ret + ")"; + return getName() + FunctionType(*this).getCanonicalSignature(); } void Block::checkTypeRequirements() diff --git a/libsolidity/AST.h b/libsolidity/AST.h index 32cc23a5b..8493d4323 100644 --- a/libsolidity/AST.h +++ b/libsolidity/AST.h @@ -277,11 +277,10 @@ public: /// Checks that all parameters have allowed types and calls checkTypeRequirements on the body. void checkTypeRequirements(); - /// Returns the canonical signature of the function - /// That consists of the name of the function followed by the - /// types of the arguments separated by commas all enclosed in parentheses - /// without any spaces - std::string getCanonicalSignature(); + /// @returns the canonical signature of the function + /// That consists of the name of the function followed by the types of the + /// arguments separated by commas all enclosed in parentheses without any spaces. + std::string getCanonicalSignature() const; private: bool m_isPublic; diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index 640a34ca8..7a4c45c6f 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -452,13 +452,12 @@ unsigned FunctionType::getSizeOnStack() const } } -std::string FunctionType::getCanonicalSignature() const +string FunctionType::getCanonicalSignature() const { - auto parameters = getParameterTypes(); - std::string ret = "NAME("; //TODO: how to get function name from FunctionType + string ret = "("; - for (auto it = parameters.cbegin(); it != parameters.cend(); ++it) - ret += (*it)->toString() + (it + 1 == m_parameterTypes.end() ? "" : ","); + for (auto it = m_parameterTypes.cbegin(); it != m_parameterTypes.cend(); ++it) + ret += (*it)->toString() + (it + 1 == m_parameterTypes.cend() ? "" : ","); return ret + ")"; } diff --git a/test/SolidityNameAndTypeResolution.cpp b/test/SolidityNameAndTypeResolution.cpp index e44c9fa29..94271b1f7 100644 --- a/test/SolidityNameAndTypeResolution.cpp +++ b/test/SolidityNameAndTypeResolution.cpp @@ -336,7 +336,24 @@ BOOST_AUTO_TEST_CASE(function_canonical_signature) if (ContractDefinition* contract = dynamic_cast(node.get())) { auto functions = contract->getDefinedFunctions(); - BOOST_ASSERT("foo(uint256,uint64,bool)" == functions[0]->getCanonicalSignature()); + BOOST_CHECK_EQUAL("foo(uint256,uint64,bool)", functions[0]->getCanonicalSignature()); + } +} + +BOOST_AUTO_TEST_CASE(function_canonical_signature_type_aliases) +{ + ASTPointer sourceUnit; + char const* text = "contract Test {\n" + " function boo(uint arg1, hash arg2, address arg3) returns (uint ret) {\n" + " ret = 5;\n" + " }\n" + "}\n"; + BOOST_CHECK_NO_THROW(sourceUnit = parseTextAndResolveNames(text)); + for (ASTPointer const& node: sourceUnit->getNodes()) + if (ContractDefinition* contract = dynamic_cast(node.get())) + { + auto functions = contract->getDefinedFunctions(); + BOOST_CHECK_EQUAL("boo(uint256,hash256,address)", functions[0]->getCanonicalSignature()); } } From 132a3e7dd487bc1419bd12979665d058a5e1e5c7 Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Wed, 7 Jan 2015 11:14:45 +0100 Subject: [PATCH 098/111] check address input greater then 2**160 --- test/stSystemOperationsTestFiller.json | 300 ++++++++++++++++++++++-- test/vmEnvironmentalInfoTestFiller.json | 210 +++++++++++++++++ 2 files changed, 494 insertions(+), 16 deletions(-) diff --git a/test/stSystemOperationsTestFiller.json b/test/stSystemOperationsTestFiller.json index 47d18b7b1..70ce448fc 100644 --- a/test/stSystemOperationsTestFiller.json +++ b/test/stSystemOperationsTestFiller.json @@ -12,7 +12,7 @@ "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "{ (MSTORE 0 0x601080600c6000396000f30060003554156009570060203560003555) [[ 0 ]] (CREATE 23 4 28) }", + "code" : "{ (MSTORE 0 0x601080600c6000396000f3006000355415600957005b60203560003555) [[ 0 ]] (CREATE 23 3 29) }", "storage": {} }, "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { @@ -46,7 +46,7 @@ "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "{ (MSTORE 0 0x601080600c6000396000f30060003554156009570060203560003555) [[ 0 ]] (CREATE 23 0 0) }", + "code" : "{ (MSTORE 0 0x601080600c6000396000f3006000355415600957005b60203560003555) [[ 0 ]] (CREATE 23 0 0) }", "storage": {} }, "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { @@ -80,7 +80,7 @@ "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "{ (MSTORE 0 0x601080600c6000396000f30060003554156009570060203560003555) [[ 0 ]] (CREATE 1000 4 28) }", + "code" : "{ (MSTORE 0 0x601080600c6000396000f3006000355415600957005b60203560003555) [[ 0 ]] (CREATE 1000 3 29) }", "storage": {} }, "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { @@ -114,7 +114,7 @@ "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "{ (MSTORE 0 0x601080600c6000396000f30060003554156009570060203560003555) [[ 0 ]] (CREATE 23 0xfffffffffff 28) }", + "code" : "{ (MSTORE 0 0x601080600c6000396000f3006000355415600957005b60203560003555) [[ 0 ]] (CREATE 23 0xfffffffffff 29) }", "storage": {} }, "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { @@ -148,7 +148,41 @@ "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "{ (MSTORE 0 0x601080600c6000396000f30060003554156009570060203560003555) [[ 0 ]] (CREATE 23 4 0xfffffffffff) }", + "code" : "{ (MSTORE 0 0x601080600c6000396000f3006000355415600957005b60203560003555) [[ 0 ]] (CREATE 23 3 0xfffffffffff) }", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "10000", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "balanceInputAddressTooBig": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (BALANCE 0xa94f5374fce5edbc8e2a8697c15331677e6ebf0baa ) }", "storage": {} }, "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { @@ -187,7 +221,91 @@ }, "945304eb96065b2a98b57a48a06ae28d285a71b5" : { "balance" : "23", - "code" : "0x60003554156009570060203560003555", + "code" : "0x6000355415600957005b60203560003555", + "nonce" : "0", + "storage" : { + } + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "", + "storage": {} + } + + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "10000", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CallToNameRegistratorAddressTooBigLeft": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (MSTORE 32 0xaaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffaa ) [[ 0 ]] (CALL 1000 0xaa945304eb96065b2a98b57a48a06ae28d285a71b5 23 0 64 64 0) }", + "storage": {} + }, + "945304eb96065b2a98b57a48a06ae28d285a71b5" : { + "balance" : "23", + "code" : "0x6000355415600957005b60203560003555", + "nonce" : "0", + "storage" : { + } + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "", + "storage": {} + } + + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "10000", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CallToNameRegistratorAddressTooBigRight": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (MSTORE 32 0xaaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffaa ) [[ 0 ]] (CALL 1000 0x945304eb96065b2a98b57a48a06ae28d285a71b5aa 23 0 64 64 0) }", + "storage": {} + }, + "945304eb96065b2a98b57a48a06ae28d285a71b5" : { + "balance" : "23", + "code" : "0x6000355415600957005b60203560003555", "nonce" : "0", "storage" : { } @@ -229,7 +347,7 @@ }, "945304eb96065b2a98b57a48a06ae28d285a71b5" : { "balance" : "23", - "code" : "0x60003554156009570060203560003555", + "code" : "0x6000355415600957005b60203560003555", "nonce" : "0", "storage" : { } @@ -440,7 +558,7 @@ }, "945304eb96065b2a98b57a48a06ae28d285a71b5" : { "balance" : "23", - "code" : "0x60003554156009570060203560003555", + "code" : "0x6000355415600957005b60203560003555", "nonce" : "0", "storage" : { } @@ -482,7 +600,7 @@ }, "945304eb96065b2a98b57a48a06ae28d285a71b5" : { "balance" : "23", - "code" : "0x60003554156009570060203560003555", + "code" : "0x6000355415600957005b60203560003555", "nonce" : "0", "storage" : { } @@ -523,7 +641,7 @@ }, "945304eb96065b2a98b57a48a06ae28d285a71b5" : { "balance" : "23", - "code" : "0x60003554156009570060203560003555", + "code" : "0x6000355415600957005b60203560003555", "nonce" : "0", "storage" : { } @@ -564,7 +682,7 @@ }, "945304eb96065b2a98b57a48a06ae28d285a71b5" : { "balance" : "23", - "code" : "0x60003554156009570060203560003555", + "code" : "0x6000355415600957005b60203560003555", "nonce" : "0", "storage" : { } @@ -606,7 +724,7 @@ }, "945304eb96065b2a98b57a48a06ae28d285a71b5" : { "balance" : "23", - "code" : "0x60003554156009570060203560003555", + "code" : "0x6000355415600957005b60203560003555", "nonce" : "0", "storage" : { } @@ -647,7 +765,7 @@ }, "945304eb96065b2a98b57a48a06ae28d285a71b5" : { "balance" : "23", - "code" : "0x60003554156009570060203560003555", + "code" : "0x6000355415600957005b60203560003555", "nonce" : "0", "storage" : { } @@ -926,6 +1044,74 @@ } }, + "suicideCallerAddresTooBigLeft": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[0]] (CALLER) (SUICIDE 0xaaa94f5374fce5edbc8e2a8697c15331677e6ebf0b)}", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "1000000", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "suicideCallerAddresTooBigRight": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[0]] (CALLER) (SUICIDE 0xa94f5374fce5edbc8e2a8697c15331677e6ebf0baa)}", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "1000000", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + "suicideOrigin": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", @@ -1185,7 +1371,7 @@ }, "945304eb96065b2a98b57a48a06ae28d285a71b5" : { "balance" : "23", - "code" : "0x60003554156009570060203560003555", + "code" : "0x6000355415600957005b60203560003555", "nonce" : "0", "storage" : { } @@ -1208,6 +1394,88 @@ } }, + "callcodeToNameRegistratorAddresTooBigLeft": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (MSTORE 32 0xaaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffaa ) [[ 0 ]] (CALLCODE 1000 0xaa945304eb96065b2a98b57a48a06ae28d285a71b5 23 0 64 64 0) }", + "storage": {} + }, + "945304eb96065b2a98b57a48a06ae28d285a71b5" : { + "balance" : "23", + "code" : "0x6000355415600957005b60203560003555", + "nonce" : "0", + "storage" : { + } + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "1000000", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "callcodeToNameRegistratorAddresTooBigRight": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (MSTORE 32 0xaaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffaa ) [[ 0 ]] (CALLCODE 1000 0x945304eb96065b2a98b57a48a06ae28d285a71b5aa 23 0 64 64 0) }", + "storage": {} + }, + "945304eb96065b2a98b57a48a06ae28d285a71b5" : { + "balance" : "23", + "code" : "0x6000355415600957005b60203560003555", + "nonce" : "0", + "storage" : { + } + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "1000000", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + "callcodeToNameRegistratorZeroMemExpanion": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", @@ -1226,7 +1494,7 @@ }, "945304eb96065b2a98b57a48a06ae28d285a71b5" : { "balance" : "23", - "code" : "0x60003554156009570060203560003555", + "code" : "0x6000355415600957005b60203560003555", "nonce" : "0", "storage" : { } @@ -1262,7 +1530,7 @@ "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "0x60003554156009570060203560003555", + "code" : "0x6000355415600957005b60203560003555", "storage": {} }, "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { diff --git a/test/vmEnvironmentalInfoTestFiller.json b/test/vmEnvironmentalInfoTestFiller.json index 91b09cd33..43f4706cb 100644 --- a/test/vmEnvironmentalInfoTestFiller.json +++ b/test/vmEnvironmentalInfoTestFiller.json @@ -83,6 +83,91 @@ } }, + "balanceAddressInputTooBig": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (BALANCE 0xcd1722f3947def4cf144679da39c4c32bdc35681aa )}", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "1000000000", + "gas" : "100000000000" + } + }, + + "balanceAddressInputTooBigRightMyAddress": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (BALANCE 0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6aa )}", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "1000000000", + "gas" : "100000000000" + } + }, + + "balanceAddressInputTooBigLeftMyAddress": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (BALANCE 0xaa0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6 )}", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "1000000000", + "gas" : "100000000000" + } + }, + + "balance1": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", @@ -786,6 +871,63 @@ } }, + "ExtCodeSizeAddressInputTooBigRightMyAddress": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EXTCODESIZE 0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6aa )}", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "1000000000", + "gas" : "100000000000" + } + }, + + "ExtCodeSizeAddressInputTooBigLeftMyAddress": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (EXTCODESIZE 0xaa0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6 )}", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "1000000000", + "gas" : "100000000000" + } + }, + + "extcodesize0": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", @@ -948,6 +1090,74 @@ "gasPrice" : "123456789", "gas" : "100000000000" } + }, + + "extcodecopy0AddressTooBigLeft": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (EXTCODECOPY 0xaacd1722f3947def4cf144679da39c4c32bdc35681 0 0 (EXTCODESIZE (CALLER) ) ) [[ 0 ]] @0 }", + "storage": {} + }, + "cd1722f3947def4cf144679da39c4c32bdc35681" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] 5 }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "0x1234567890abcdef01234567890abcdef", + "gasPrice" : "123456789", + "gas" : "100000000000" + } + }, + + "extcodecopy0AddressTooBigRight": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (EXTCODECOPY 0xcd1722f3947def4cf144679da39c4c32bdc35681aa 0 0 (EXTCODESIZE (CALLER) ) ) [[ 0 ]] @0 }", + "storage": {} + }, + "cd1722f3947def4cf144679da39c4c32bdc35681" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] 5 }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "0x1234567890abcdef01234567890abcdef", + "gasPrice" : "123456789", + "gas" : "100000000000" + } } } From 3871bac1d0ac3b0e7f8490fba646f159fa65d8b5 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Wed, 7 Jan 2015 11:26:23 +0100 Subject: [PATCH 099/111] Squashed 'libjsqrc/ethereumjs/' content from commit df4d784 git-subtree-dir: libjsqrc/ethereumjs git-subtree-split: df4d7846e58f98191b9811413a7be02f48a78aa3 --- .bowerrc | 5 + .editorconfig | 12 + .gitignore | 18 ++ .jshintrc | 50 +++++ .npmignore | 9 + .travis.yml | 11 + LICENSE | 14 ++ README.md | 79 +++++++ bower.json | 51 +++++ dist/ethereum.js | 20 ++ dist/ethereum.js.map | 29 +++ dist/ethereum.min.js | 1 + example/balance.html | 41 ++++ example/contract.html | 75 +++++++ example/node-app.js | 16 ++ gulpfile.js | 123 ++++++++++ index.js | 8 + index_qt.js | 5 + lib/abi.js | 265 ++++++++++++++++++++++ lib/autoprovider.js | 102 +++++++++ lib/contract.js | 65 ++++++ lib/httprpc.js | 94 ++++++++ lib/main.js | 508 ++++++++++++++++++++++++++++++++++++++++++ lib/qt.js | 45 ++++ lib/websocket.js | 77 +++++++ package.json | 67 ++++++ 26 files changed, 1790 insertions(+) create mode 100644 .bowerrc create mode 100644 .editorconfig create mode 100644 .gitignore create mode 100644 .jshintrc create mode 100644 .npmignore create mode 100644 .travis.yml create mode 100644 LICENSE create mode 100644 README.md create mode 100644 bower.json create mode 100644 dist/ethereum.js create mode 100644 dist/ethereum.js.map create mode 100644 dist/ethereum.min.js create mode 100644 example/balance.html create mode 100644 example/contract.html create mode 100644 example/node-app.js create mode 100644 gulpfile.js create mode 100644 index.js create mode 100644 index_qt.js create mode 100644 lib/abi.js create mode 100644 lib/autoprovider.js create mode 100644 lib/contract.js create mode 100644 lib/httprpc.js create mode 100644 lib/main.js create mode 100644 lib/qt.js create mode 100644 lib/websocket.js create mode 100644 package.json diff --git a/.bowerrc b/.bowerrc new file mode 100644 index 000000000..c3a8813e8 --- /dev/null +++ b/.bowerrc @@ -0,0 +1,5 @@ +{ + "directory": "example/js/", + "cwd": "./", + "analytics": false +} \ No newline at end of file diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000..60a2751d3 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,12 @@ +root = true + +[*] +indent_style = space +indent_size = 4 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.md] +trim_trailing_whitespace = false \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..399b6dc88 --- /dev/null +++ b/.gitignore @@ -0,0 +1,18 @@ +# See http://help.github.com/ignore-files/ for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile ~/.gitignore_global + +*.swp +/tmp +*/**/*un~ +*un~ +.DS_Store +*/**/.DS_Store +ethereum/ethereum +ethereal/ethereal +example/js +node_modules +bower_components +npm-debug.log diff --git a/.jshintrc b/.jshintrc new file mode 100644 index 000000000..c0ec5f89d --- /dev/null +++ b/.jshintrc @@ -0,0 +1,50 @@ +{ + "predef": [ + "console", + "require", + "equal", + "test", + "testBoth", + "testWithDefault", + "raises", + "deepEqual", + "start", + "stop", + "ok", + "strictEqual", + "module", + "expect", + "reject", + "impl" + ], + + "esnext": true, + "proto": true, + "node" : true, + "browser" : true, + "browserify" : true, + + "boss" : true, + "curly": false, + "debug": true, + "devel": true, + "eqeqeq": true, + "evil": true, + "forin": false, + "immed": false, + "laxbreak": false, + "newcap": true, + "noarg": true, + "noempty": false, + "nonew": false, + "nomen": false, + "onevar": false, + "plusplus": false, + "regexp": false, + "undef": true, + "sub": true, + "strict": false, + "white": false, + "shadow": true, + "eqnull": true +} \ No newline at end of file diff --git a/.npmignore b/.npmignore new file mode 100644 index 000000000..5bbffe4fd --- /dev/null +++ b/.npmignore @@ -0,0 +1,9 @@ +example/js +node_modules +test +.gitignore +.editorconfig +.travis.yml +.npmignore +component.json +testling.html \ No newline at end of file diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 000000000..fafacbd5a --- /dev/null +++ b/.travis.yml @@ -0,0 +1,11 @@ +language: node_js +node_js: + - "0.11" + - "0.10" +before_script: + - npm install + - npm install jshint +script: + - "jshint *.js lib" +after_script: + - npm run-script gulp diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..0f187b873 --- /dev/null +++ b/LICENSE @@ -0,0 +1,14 @@ +This file is part of ethereum.js. + +ethereum.js is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +ethereum.js is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with ethereum.js. If not, see . \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 000000000..865b62c6b --- /dev/null +++ b/README.md @@ -0,0 +1,79 @@ +# Ethereum JavaScript API + +This is the Ethereum compatible JavaScript API using `Promise`s +which implements the [Generic JSON RPC](https://github.com/ethereum/wiki/wiki/Generic-JSON-RPC) spec. It's available on npm as a node module and also for bower and component as an embeddable js + +[![NPM version][npm-image]][npm-url] [![Build Status][travis-image]][travis-url] [![dependency status][dep-image]][dep-url] [![dev dependency status][dep-dev-image]][dep-dev-url] + + + +## Installation + +### Node.js + + npm install ethereum.js + +### For browser +Bower + + bower install ethereum.js + +Component + + component install ethereum/ethereum.js + +* Include `ethereum.min.js` in your html file. +* Include [es6-promise](https://github.com/jakearchibald/es6-promise) or another ES6-Shim if your browser doesn't support ECMAScript 6. + +## Usage +Require the library: + + var web3 = require('web3'); + +Set a provider (QtProvider, WebSocketProvider, HttpRpcProvider) + + var web3.setProvider(new web3.providers.WebSocketProvider('ws://localhost:40404/eth')); + +There you go, now you can use it: + +``` +web3.eth.coinbase.then(function(result){ + console.log(result); + return web3.eth.balanceAt(result); +}).then(function(balance){ + console.log(web3.toDecimal(balance)); +}).catch(function(err){ + console.log(err); +}); +``` + + +For another example see `example/index.html`. + +## Building + +* `gulp build` + + +### Testing + +**Please note this repo is in it's early stage.** + +If you'd like to run a WebSocket ethereum node check out +[go-ethereum](https://github.com/ethereum/go-ethereum). + +To install ethereum and spawn a node: + +``` +go get github.com/ethereum/go-ethereum/ethereum +ethereum -ws -loglevel=4 +``` + +[npm-image]: https://badge.fury.io/js/ethereum.js.png +[npm-url]: https://npmjs.org/package/ethereum.js +[travis-image]: https://travis-ci.org/ethereum/ethereum.js.svg +[travis-url]: https://travis-ci.org/ethereum/ethereum.js +[dep-image]: https://david-dm.org/ethereum/ethereum.js.svg +[dep-url]: https://david-dm.org/ethereum/ethereum.js +[dep-dev-image]: https://david-dm.org/ethereum/ethereum.js/dev-status.svg +[dep-dev-url]: https://david-dm.org/ethereum/ethereum.js#info=devDependencies \ No newline at end of file diff --git a/bower.json b/bower.json new file mode 100644 index 000000000..cedae9023 --- /dev/null +++ b/bower.json @@ -0,0 +1,51 @@ +{ + "name": "ethereum.js", + "namespace": "ethereum", + "version": "0.0.3", + "description": "Ethereum Compatible JavaScript API", + "main": ["./dist/ethereum.js", "./dist/ethereum.min.js"], + "dependencies": { + "es6-promise": "#master" + }, + "repository": { + "type": "git", + "url": "https://github.com/ethereum/ethereum.js.git" + }, + "homepage": "https://github.com/ethereum/ethereum.js", + "bugs": { + "url": "https://github.com/ethereum/ethereum.js/issues" + }, + "keywords": [ + "ethereum", + "javascript", + "API" + ], + "authors": [ + { + "name": "Marek Kotewicz", + "email": "marek@ethdev.com", + "homepage": "https://github.com/debris" + }, + { + "name": "Marian Oancea", + "email": "marian@ethdev.com", + "homepage": "https://github.com/cubedro" + } + ], + "license": "LGPL-3.0", + "ignore": [ + "example", + "lib", + "node_modules", + "package.json", + ".bowerrc", + ".editorconfig", + ".gitignore", + ".jshintrc", + ".npmignore", + ".travis.yml", + "gulpfile.js", + "index.js", + "**/*.txt" + ] +} \ No newline at end of file diff --git a/dist/ethereum.js b/dist/ethereum.js new file mode 100644 index 000000000..8abe6ad53 --- /dev/null +++ b/dist/ethereum.js @@ -0,0 +1,20 @@ +require=(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;oi;i++)padding+=sizes[i]/8;return padding},setupInputTypes=function(){var prefixedType=function(prefix,calcPadding){return function(type,value){var padding,expected=prefix;return 0!==type.indexOf(expected)?!1:(padding=calcPadding(type,expected),value="number"==typeof value?value.toString(16):"string"==typeof value?web3.toHex(value):0===value.indexOf("0x")?value.substr(2):(+value).toString(16),padLeft(value,2*padding))}},namedType=function(name,padding,formatter){return function(type,value){return type!==name?!1:padLeft(formatter?formatter(value):value,2*padding)}},formatBool=function(value){return value?"0x1":"0x0"};return[prefixedType("uint",calcBitPadding),prefixedType("int",calcBitPadding),prefixedType("hash",calcBitPadding),prefixedType("string",calcBytePadding),prefixedType("real",calcRealPadding),prefixedType("ureal",calcRealPadding),namedType("address",20),namedType("bool",1,formatBool)]},inputTypes=setupInputTypes(),toAbiInput=function(json,methodName,params){var method,i,found,j,bytes="",index=findMethodIndex(json,methodName);if(-1!==index){for(bytes="0x"+padLeft(index.toString(16),2),method=json[index],i=0;ii&&(code=hex.charCodeAt(i),0!==code);i+=2)str+=String.fromCharCode(parseInt(hex.substr(i,2),16));return str},fromAscii:function(str,pad){pad=void 0===pad?32:pad;for(var hex=this.toHex(str);hex.length<2*pad;)hex+="00";return"0x"+hex},toDecimal:function(val){return hexToDec(val.substring(2))},fromDecimal:function(val){return"0x"+decToHex(val)},toEth:function(str){for(var s,replaceFunction,o,val="string"==typeof str?0===str.indexOf("0x")?parseInt(str.substr(2),16):parseInt(str):str,unit=0,units=["wei","Kwei","Mwei","Gwei","szabo","finney","ether","grand","Mether","Gether","Tether","Pether","Eether","Zether","Yether","Nether","Dether","Vether","Uether"];val>3e3&&uniti;i++)padding+=sizes[i]/8;return padding},setupInputTypes=function(){var prefixedType=function(prefix,calcPadding){return function(type,value){var padding,expected=prefix;return 0!==type.indexOf(expected)?!1:(padding=calcPadding(type,expected),value=\"number\"==typeof value?value.toString(16):\"string\"==typeof value?web3.toHex(value):0===value.indexOf(\"0x\")?value.substr(2):(+value).toString(16),padLeft(value,2*padding))}},namedType=function(name,padding,formatter){return function(type,value){return type!==name?!1:padLeft(formatter?formatter(value):value,2*padding)}},formatBool=function(value){return value?\"0x1\":\"0x0\"};return[prefixedType(\"uint\",calcBitPadding),prefixedType(\"int\",calcBitPadding),prefixedType(\"hash\",calcBitPadding),prefixedType(\"string\",calcBytePadding),prefixedType(\"real\",calcRealPadding),prefixedType(\"ureal\",calcRealPadding),namedType(\"address\",20),namedType(\"bool\",1,formatBool)]},inputTypes=setupInputTypes(),toAbiInput=function(json,methodName,params){var method,i,found,j,bytes=\"\",index=findMethodIndex(json,methodName);if(-1!==index){for(bytes=\"0x\"+padLeft(index.toString(16),2),method=json[index],i=0;ii&&(code=hex.charCodeAt(i),0!==code);i+=2)str+=String.fromCharCode(parseInt(hex.substr(i,2),16));return str},fromAscii:function(str,pad){pad=void 0===pad?32:pad;for(var hex=this.toHex(str);hex.length<2*pad;)hex+=\"00\";return\"0x\"+hex},toDecimal:function(val){return hexToDec(val.substring(2))},fromDecimal:function(val){return\"0x\"+decToHex(val)},toEth:function(str){for(var s,replaceFunction,o,val=\"string\"==typeof str?0===str.indexOf(\"0x\")?parseInt(str.substr(2),16):parseInt(str):str,unit=0,units=[\"wei\",\"Kwei\",\"Mwei\",\"Gwei\",\"szabo\",\"finney\",\"ether\",\"grand\",\"Mether\",\"Gether\",\"Tether\",\"Pether\",\"Eether\",\"Zether\",\"Yether\",\"Nether\",\"Dether\",\"Vether\",\"Uether\"];val>3e3&&unito;o++)r+=n[o]/8;return r},l=function(){var t=function(t,e){return function(n,r){var o,i=t;return 0!==n.indexOf(i)?!1:(o=e(n,i),r="number"==typeof r?r.toString(16):"string"==typeof r?web3.toHex(r):0===r.indexOf("0x")?r.substr(2):(+r).toString(16),s(r,2*o))}},e=function(t,e,n){return function(r,o){return r!==t?!1:s(n?n(o):o,2*e)}},n=function(t){return t?"0x1":"0x0"};return[t("uint",a),t("int",a),t("hash",a),t("string",u),t("real",c),t("ureal",c),e("address",20),e("bool",1,n)]},h=l(),p=function(t,e,n){var r,o,a,u,c="",l=i(t,e);if(-1!==l){for(c="0x"+s(l.toString(16),2),r=t[l],o=0;or&&(e=t.charCodeAt(r),0!==e);r+=2)n+=String.fromCharCode(parseInt(t.substr(r,2),16));return n},fromAscii:function(t,e){e=void 0===e?32:e;for(var n=this.toHex(t);n.length<2*e;)n+="00";return"0x"+n},toDecimal:function(t){return m(t.substring(2))},fromDecimal:function(t){return"0x"+b(t)},toEth:function(t){for(var e,n,r,o="string"==typeof t?0===t.indexOf("0x")?parseInt(t.substr(2),16):parseInt(t):t,i=0,s=["wei","Kwei","Mwei","Gwei","szabo","finney","ether","grand","Mether","Gether","Tether","Pether","Eether","Zether","Yether","Nether","Dether","Vether","Uether"];o>3e3&&i + + + + + + + + +

coinbase balance

+ +
+
+
+
+ + + diff --git a/example/contract.html b/example/contract.html new file mode 100644 index 000000000..44f0b03a1 --- /dev/null +++ b/example/contract.html @@ -0,0 +1,75 @@ + + + + + + + + + +

contract

+
+
+ +
+ +
+ + + diff --git a/example/node-app.js b/example/node-app.js new file mode 100644 index 000000000..f63fa9115 --- /dev/null +++ b/example/node-app.js @@ -0,0 +1,16 @@ +#!/usr/bin/env node + +require('es6-promise').polyfill(); + +var web3 = require("../index.js"); + +web3.setProvider(new web3.providers.HttpRpcProvider('http://localhost:8080')); + +web3.eth.coinbase.then(function(result){ + console.log(result); + return web3.eth.balanceAt(result); +}).then(function(balance){ + console.log(web3.toDecimal(balance)); +}).catch(function(err){ + console.log(err); +}); \ No newline at end of file diff --git a/gulpfile.js b/gulpfile.js new file mode 100644 index 000000000..9e0717d8b --- /dev/null +++ b/gulpfile.js @@ -0,0 +1,123 @@ +#!/usr/bin/env node + +'use strict'; + +var path = require('path'); + +var del = require('del'); +var gulp = require('gulp'); +var browserify = require('browserify'); +var jshint = require('gulp-jshint'); +var uglify = require('gulp-uglify'); +var rename = require('gulp-rename'); +var envify = require('envify/custom'); +var unreach = require('unreachable-branch-transform'); +var source = require('vinyl-source-stream'); +var exorcist = require('exorcist'); +var bower = require('bower'); + +var DEST = './dist/'; + +var build = function(src, dst) { + return browserify({ + debug: true, + insert_global_vars: false, + detectGlobals: false, + bundleExternal: false + }) + .require('./' + src + '.js', {expose: 'web3'}) + .add('./' + src + '.js') + .transform('envify', { + NODE_ENV: 'build' + }) + .transform('unreachable-branch-transform') + .transform('uglifyify', { + mangle: false, + compress: { + dead_code: false, + conditionals: true, + unused: false, + hoist_funs: true, + hoist_vars: true, + negate_iife: false + }, + beautify: true, + warnings: true + }) + .bundle() + .pipe(exorcist(path.join( DEST, dst + '.js.map'))) + .pipe(source(dst + '.js')) + .pipe(gulp.dest( DEST )); +}; + +var buildDev = function(src, dst) { + return browserify({ + debug: true, + insert_global_vars: false, + detectGlobals: false, + bundleExternal: false + }) + .require('./' + src + '.js', {expose: 'web3'}) + .add('./' + src + '.js') + .transform('envify', { + NODE_ENV: 'build' + }) + .transform('unreachable-branch-transform') + .bundle() + .pipe(exorcist(path.join( DEST, dst + '.js.map'))) + .pipe(source(dst + '.js')) + .pipe(gulp.dest( DEST )); +}; + +var uglifyFile = function(file) { + return gulp.src( DEST + file + '.js') + .pipe(uglify()) + .pipe(rename(file + '.min.js')) + .pipe(gulp.dest( DEST )); +}; + +gulp.task('bower', function(cb){ + bower.commands.install().on('end', function (installed){ + console.log(installed); + cb(); + }); +}); + +gulp.task('lint', function(){ + return gulp.src(['./*.js', './lib/*.js']) + .pipe(jshint()) + .pipe(jshint.reporter('default')); +}); + +gulp.task('clean', ['lint'], function(cb) { + del([ DEST ], cb); +}); + +gulp.task('build', ['clean'], function () { + return build('index', 'ethereum'); +}); + +gulp.task('buildQt', ['clean'], function () { + return build('index_qt', 'ethereum'); +}); + +gulp.task('buildDev', ['clean'], function () { + return buildDev('index', 'ethereum'); +}); + +gulp.task('uglify', ['build'], function(){ + return uglifyFile('ethereum'); +}); + +gulp.task('uglifyQt', ['buildQt'], function () { + return uglifyFile('ethereum'); +}); + +gulp.task('watch', function() { + gulp.watch(['./lib/*.js'], ['lint', 'prepare', 'build']); +}); + +gulp.task('default', ['bower', 'lint', 'build', 'uglify']); +gulp.task('qt', ['bower', 'lint', 'buildQt', 'uglifyQt']); +gulp.task('dev', ['bower', 'lint', 'buildDev']); + diff --git a/index.js b/index.js new file mode 100644 index 000000000..c2de7e735 --- /dev/null +++ b/index.js @@ -0,0 +1,8 @@ +var web3 = require('./lib/main'); +web3.providers.WebSocketProvider = require('./lib/websocket'); +web3.providers.HttpRpcProvider = require('./lib/httprpc'); +web3.providers.QtProvider = require('./lib/qt'); +web3.providers.AutoProvider = require('./lib/autoprovider'); +web3.contract = require('./lib/contract'); + +module.exports = web3; diff --git a/index_qt.js b/index_qt.js new file mode 100644 index 000000000..d5e47597e --- /dev/null +++ b/index_qt.js @@ -0,0 +1,5 @@ +var web3 = require('./lib/main'); +web3.providers.QtProvider = require('./lib/qt'); +web3.contract = require('./lib/contract'); + +module.exports = web3; diff --git a/lib/abi.js b/lib/abi.js new file mode 100644 index 000000000..5a4d64515 --- /dev/null +++ b/lib/abi.js @@ -0,0 +1,265 @@ +/* + This file is part of ethereum.js. + + ethereum.js is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ethereum.js is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with ethereum.js. If not, see . +*/ +/** @file abi.js + * @authors: + * Marek Kotewicz + * Gav Wood + * @date 2014 + */ + +// TODO: is these line is supposed to be here? +if (process.env.NODE_ENV !== 'build') { + var web3 = require('./web3'); // jshint ignore:line +} + +// TODO: make these be actually accurate instead of falling back onto JS's doubles. +var hexToDec = function (hex) { + return parseInt(hex, 16).toString(); +}; + +var decToHex = function (dec) { + return parseInt(dec).toString(16); +}; + +var findIndex = function (array, callback) { + var end = false; + var i = 0; + for (; i < array.length && !end; i++) { + end = callback(array[i]); + } + return end ? i - 1 : -1; +}; + +var findMethodIndex = function (json, methodName) { + return findIndex(json, function (method) { + return method.name === methodName; + }); +}; + +var padLeft = function (string, chars) { + return new Array(chars - string.length + 1).join("0") + string; +}; + +var calcBitPadding = function (type, expected) { + var value = type.slice(expected.length); + if (value === "") { + return 32; + } + return parseInt(value) / 8; +}; + +var calcBytePadding = function (type, expected) { + var value = type.slice(expected.length); + if (value === "") { + return 32; + } + return parseInt(value); +}; + +var calcRealPadding = function (type, expected) { + var value = type.slice(expected.length); + if (value === "") { + return 32; + } + var sizes = value.split('x'); + for (var padding = 0, i = 0; i < sizes; i++) { + padding += (sizes[i] / 8); + } + return padding; +}; + +var setupInputTypes = function () { + + var prefixedType = function (prefix, calcPadding) { + return function (type, value) { + var expected = prefix; + if (type.indexOf(expected) !== 0) { + return false; + } + + var padding = calcPadding(type, expected); + if (typeof value === "number") + value = value.toString(16); + else if (typeof value === "string") + value = web3.toHex(value); + else if (value.indexOf('0x') === 0) + value = value.substr(2); + else + value = (+value).toString(16); + return padLeft(value, padding * 2); + }; + }; + + var namedType = function (name, padding, formatter) { + return function (type, value) { + if (type !== name) { + return false; + } + + return padLeft(formatter ? formatter(value) : value, padding * 2); + }; + }; + + var formatBool = function (value) { + return value ? '0x1' : '0x0'; + }; + + return [ + prefixedType('uint', calcBitPadding), + prefixedType('int', calcBitPadding), + prefixedType('hash', calcBitPadding), + prefixedType('string', calcBytePadding), + prefixedType('real', calcRealPadding), + prefixedType('ureal', calcRealPadding), + namedType('address', 20), + namedType('bool', 1, formatBool), + ]; +}; + +var inputTypes = setupInputTypes(); + +var toAbiInput = function (json, methodName, params) { + var bytes = ""; + var index = findMethodIndex(json, methodName); + + if (index === -1) { + return; + } + + bytes = "0x" + padLeft(index.toString(16), 2); + var method = json[index]; + + for (var i = 0; i < method.inputs.length; i++) { + var found = false; + for (var j = 0; j < inputTypes.length && !found; j++) { + found = inputTypes[j](method.inputs[i].type, params[i]); + } + if (!found) { + console.error('unsupported json type: ' + method.inputs[i].type); + } + bytes += found; + } + return bytes; +}; + +var setupOutputTypes = function () { + + var prefixedType = function (prefix, calcPadding) { + return function (type) { + var expected = prefix; + if (type.indexOf(expected) !== 0) { + return -1; + } + + var padding = calcPadding(type, expected); + return padding * 2; + }; + }; + + var namedType = function (name, padding) { + return function (type) { + return name === type ? padding * 2 : -1; + }; + }; + + var formatInt = function (value) { + return value.length <= 8 ? +parseInt(value, 16) : hexToDec(value); + }; + + var formatHash = function (value) { + return "0x" + value; + }; + + var formatBool = function (value) { + return value === '1' ? true : false; + }; + + var formatString = function (value) { + return web3.toAscii(value); + }; + + return [ + { padding: prefixedType('uint', calcBitPadding), format: formatInt }, + { padding: prefixedType('int', calcBitPadding), format: formatInt }, + { padding: prefixedType('hash', calcBitPadding), format: formatHash }, + { padding: prefixedType('string', calcBytePadding), format: formatString }, + { padding: prefixedType('real', calcRealPadding), format: formatInt }, + { padding: prefixedType('ureal', calcRealPadding), format: formatInt }, + { padding: namedType('address', 20) }, + { padding: namedType('bool', 1), format: formatBool } + ]; +}; + +var outputTypes = setupOutputTypes(); + +var fromAbiOutput = function (json, methodName, output) { + var index = findMethodIndex(json, methodName); + + if (index === -1) { + return; + } + + output = output.slice(2); + + var result = []; + var method = json[index]; + for (var i = 0; i < method.outputs.length; i++) { + var padding = -1; + for (var j = 0; j < outputTypes.length && padding === -1; j++) { + padding = outputTypes[j].padding(method.outputs[i].type); + } + + if (padding === -1) { + // not found output parsing + continue; + } + var res = output.slice(0, padding); + var formatter = outputTypes[j - 1].format; + result.push(formatter ? formatter(res) : ("0x" + res)); + output = output.slice(padding); + } + + return result; +}; + +var inputParser = function (json) { + var parser = {}; + json.forEach(function (method) { + parser[method.name] = function () { + var params = Array.prototype.slice.call(arguments); + return toAbiInput(json, method.name, params); + }; + }); + + return parser; +}; + +var outputParser = function (json) { + var parser = {}; + json.forEach(function (method) { + parser[method.name] = function (output) { + return fromAbiOutput(json, method.name, output); + }; + }); + + return parser; +}; + +module.exports = { + inputParser: inputParser, + outputParser: outputParser +}; diff --git a/lib/autoprovider.js b/lib/autoprovider.js new file mode 100644 index 000000000..2f0a3e627 --- /dev/null +++ b/lib/autoprovider.js @@ -0,0 +1,102 @@ +/* + This file is part of ethereum.js. + + ethereum.js is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ethereum.js is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with ethereum.js. If not, see . +*/ +/** @file autoprovider.js + * @authors: + * Marek Kotewicz + * Marian Oancea + * @date 2014 + */ + +/* + * @brief if qt object is available, uses QtProvider, + * if not tries to connect over websockets + * if it fails, it uses HttpRpcProvider + */ + +// TODO: is these line is supposed to be here? +if (process.env.NODE_ENV !== 'build') { + var WebSocket = require('ws'); // jshint ignore:line + var web3 = require('./main.js'); // jshint ignore:line +} + +var AutoProvider = function (userOptions) { + if (web3.haveProvider()) { + return; + } + + // before we determine what provider we are, we have to cache request + this.sendQueue = []; + this.onmessageQueue = []; + + if (navigator.qt) { + this.provider = new web3.providers.QtProvider(); + return; + } + + userOptions = userOptions || {}; + var options = { + httprpc: userOptions.httprpc || 'http://localhost:8080', + websockets: userOptions.websockets || 'ws://localhost:40404/eth' + }; + + var self = this; + var closeWithSuccess = function (success) { + ws.close(); + if (success) { + self.provider = new web3.providers.WebSocketProvider(options.websockets); + } else { + self.provider = new web3.providers.HttpRpcProvider(options.httprpc); + self.poll = self.provider.poll.bind(self.provider); + } + self.sendQueue.forEach(function (payload) { + self.provider(payload); + }); + self.onmessageQueue.forEach(function (handler) { + self.provider.onmessage = handler; + }); + }; + + var ws = new WebSocket(options.websockets); + + ws.onopen = function() { + closeWithSuccess(true); + }; + + ws.onerror = function() { + closeWithSuccess(false); + }; +}; + +AutoProvider.prototype.send = function (payload) { + if (this.provider) { + this.provider.send(payload); + return; + } + this.sendQueue.push(payload); +}; + +Object.defineProperty(AutoProvider.prototype, 'onmessage', { + set: function (handler) { + if (this.provider) { + this.provider.onmessage = handler; + return; + } + this.onmessageQueue.push(handler); + } +}); + +module.exports = AutoProvider; diff --git a/lib/contract.js b/lib/contract.js new file mode 100644 index 000000000..b10339003 --- /dev/null +++ b/lib/contract.js @@ -0,0 +1,65 @@ +/* + This file is part of ethereum.js. + + ethereum.js is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ethereum.js is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with ethereum.js. If not, see . +*/ +/** @file contract.js + * @authors: + * Marek Kotewicz + * @date 2014 + */ + +// TODO: is these line is supposed to be here? +if (process.env.NODE_ENV !== 'build') { + var web3 = require('./web3'); // jshint ignore:line +} + +var abi = require('./abi'); + +var contract = function (address, desc) { + var inputParser = abi.inputParser(desc); + var outputParser = abi.outputParser(desc); + + var contract = {}; + + desc.forEach(function (method) { + contract[method.name] = function () { + var params = Array.prototype.slice.call(arguments); + var parsed = inputParser[method.name].apply(null, params); + + var onSuccess = function (result) { + return outputParser[method.name](result); + }; + + return { + call: function (extra) { + extra = extra || {}; + extra.to = address; + extra.data = parsed; + return web3.eth.call(extra).then(onSuccess); + }, + transact: function (extra) { + extra = extra || {}; + extra.to = address; + extra.data = parsed; + return web3.eth.transact(extra).then(onSuccess); + } + }; + }; + }); + + return contract; +}; + +module.exports = contract; diff --git a/lib/httprpc.js b/lib/httprpc.js new file mode 100644 index 000000000..d315201f1 --- /dev/null +++ b/lib/httprpc.js @@ -0,0 +1,94 @@ +/* + This file is part of ethereum.js. + + ethereum.js is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ethereum.js is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with ethereum.js. If not, see . +*/ +/** @file httprpc.js + * @authors: + * Marek Kotewicz + * Marian Oancea + * @date 2014 + */ + +// TODO: is these line is supposed to be here? +if (process.env.NODE_ENV !== 'build') { + var XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest; // jshint ignore:line +} + +var HttpRpcProvider = function (host) { + this.handlers = []; + this.host = host; +}; + +function formatJsonRpcObject(object) { + return { + jsonrpc: '2.0', + method: object.call, + params: object.args, + id: object._id + }; +} + +function formatJsonRpcMessage(message) { + var object = JSON.parse(message); + + return { + _id: object.id, + data: object.result, + error: object.error + }; +} + +HttpRpcProvider.prototype.sendRequest = function (payload, cb) { + var data = formatJsonRpcObject(payload); + + var request = new XMLHttpRequest(); + request.open("POST", this.host, true); + request.send(JSON.stringify(data)); + request.onreadystatechange = function () { + if (request.readyState === 4 && cb) { + cb(request); + } + }; +}; + +HttpRpcProvider.prototype.send = function (payload) { + var self = this; + this.sendRequest(payload, function (request) { + self.handlers.forEach(function (handler) { + handler.call(self, formatJsonRpcMessage(request.responseText)); + }); + }); +}; + +HttpRpcProvider.prototype.poll = function (payload, id) { + var self = this; + this.sendRequest(payload, function (request) { + var parsed = JSON.parse(request.responseText); + if (parsed.error || (parsed.result instanceof Array ? parsed.result.length === 0 : !parsed.result)) { + return; + } + self.handlers.forEach(function (handler) { + handler.call(self, {_event: payload.call, _id: id, data: parsed.result}); + }); + }); +}; + +Object.defineProperty(HttpRpcProvider.prototype, "onmessage", { + set: function (handler) { + this.handlers.push(handler); + } +}); + +module.exports = HttpRpcProvider; diff --git a/lib/main.js b/lib/main.js new file mode 100644 index 000000000..b240bdae2 --- /dev/null +++ b/lib/main.js @@ -0,0 +1,508 @@ +/* + This file is part of ethereum.js. + + ethereum.js is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ethereum.js is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with ethereum.js. If not, see . +*/ +/** @file main.js + * @authors: + * Jeffrey Wilcke + * Marek Kotewicz + * Marian Oancea + * Gav Wood + * @date 2014 + */ + +function flattenPromise (obj) { + if (obj instanceof Promise) { + return Promise.resolve(obj); + } + + if (obj instanceof Array) { + return new Promise(function (resolve) { + var promises = obj.map(function (o) { + return flattenPromise(o); + }); + + return Promise.all(promises).then(function (res) { + for (var i = 0; i < obj.length; i++) { + obj[i] = res[i]; + } + resolve(obj); + }); + }); + } + + if (obj instanceof Object) { + return new Promise(function (resolve) { + var keys = Object.keys(obj); + var promises = keys.map(function (key) { + return flattenPromise(obj[key]); + }); + + return Promise.all(promises).then(function (res) { + for (var i = 0; i < keys.length; i++) { + obj[keys[i]] = res[i]; + } + resolve(obj); + }); + }); + } + + return Promise.resolve(obj); +} + +var web3Methods = function () { + return [ + { name: 'sha3', call: 'web3_sha3' } + ]; +}; + +var ethMethods = function () { + var blockCall = function (args) { + return typeof args[0] === "string" ? "eth_blockByHash" : "eth_blockByNumber"; + }; + + var transactionCall = function (args) { + return typeof args[0] === "string" ? 'eth_transactionByHash' : 'eth_transactionByNumber'; + }; + + var uncleCall = function (args) { + return typeof args[0] === "string" ? 'eth_uncleByHash' : 'eth_uncleByNumber'; + }; + + var methods = [ + { name: 'balanceAt', call: 'eth_balanceAt' }, + { name: 'stateAt', call: 'eth_stateAt' }, + { name: 'storageAt', call: 'eth_storageAt' }, + { name: 'countAt', call: 'eth_countAt'}, + { name: 'codeAt', call: 'eth_codeAt' }, + { name: 'transact', call: 'eth_transact' }, + { name: 'call', call: 'eth_call' }, + { name: 'block', call: blockCall }, + { name: 'transaction', call: transactionCall }, + { name: 'uncle', call: uncleCall }, + { name: 'compilers', call: 'eth_compilers' }, + { name: 'lll', call: 'eth_lll' }, + { name: 'solidity', call: 'eth_solidity' }, + { name: 'serpent', call: 'eth_serpent' }, + { name: 'logs', call: 'eth_logs' } + ]; + return methods; +}; + +var ethProperties = function () { + return [ + { name: 'coinbase', getter: 'eth_coinbase', setter: 'eth_setCoinbase' }, + { name: 'listening', getter: 'eth_listening', setter: 'eth_setListening' }, + { name: 'mining', getter: 'eth_mining', setter: 'eth_setMining' }, + { name: 'gasPrice', getter: 'eth_gasPrice' }, + { name: 'account', getter: 'eth_account' }, + { name: 'accounts', getter: 'eth_accounts' }, + { name: 'peerCount', getter: 'eth_peerCount' }, + { name: 'defaultBlock', getter: 'eth_defaultBlock', setter: 'eth_setDefaultBlock' }, + { name: 'number', getter: 'eth_number'} + ]; +}; + +var dbMethods = function () { + return [ + { name: 'put', call: 'db_put' }, + { name: 'get', call: 'db_get' }, + { name: 'putString', call: 'db_putString' }, + { name: 'getString', call: 'db_getString' } + ]; +}; + +var shhMethods = function () { + return [ + { name: 'post', call: 'shh_post' }, + { name: 'newIdentity', call: 'shh_newIdentity' }, + { name: 'haveIdentity', call: 'shh_haveIdentity' }, + { name: 'newGroup', call: 'shh_newGroup' }, + { name: 'addToGroup', call: 'shh_addToGroup' } + ]; +}; + +var ethWatchMethods = function () { + var newFilter = function (args) { + return typeof args[0] === 'string' ? 'eth_newFilterString' : 'eth_newFilter'; + }; + + return [ + { name: 'newFilter', call: newFilter }, + { name: 'uninstallFilter', call: 'eth_uninstallFilter' }, + { name: 'getMessages', call: 'eth_filterLogs' } + ]; +}; + +var shhWatchMethods = function () { + return [ + { name: 'newFilter', call: 'shh_newFilter' }, + { name: 'uninstallFilter', call: 'shh_uninstallFilter' }, + { name: 'getMessage', call: 'shh_getMessages' } + ]; +}; + +var setupMethods = function (obj, methods) { + methods.forEach(function (method) { + obj[method.name] = function () { + return flattenPromise(Array.prototype.slice.call(arguments)).then(function (args) { + var call = typeof method.call === "function" ? method.call(args) : method.call; + return {call: call, args: args}; + }).then(function (request) { + return new Promise(function (resolve, reject) { + web3.provider.send(request, function (err, result) { + if (!err) { + resolve(result); + return; + } + reject(err); + }); + }); + }).catch(function(err) { + console.error(err); + }); + }; + }); +}; + +var setupProperties = function (obj, properties) { + properties.forEach(function (property) { + var proto = {}; + proto.get = function () { + return new Promise(function(resolve, reject) { + web3.provider.send({call: property.getter}, function(err, result) { + if (!err) { + resolve(result); + return; + } + reject(err); + }); + }); + }; + if (property.setter) { + proto.set = function (val) { + return flattenPromise([val]).then(function (args) { + return new Promise(function (resolve) { + web3.provider.send({call: property.setter, args: args}, function (err, result) { + if (!err) { + resolve(result); + return; + } + reject(err); + }); + }); + }).catch(function (err) { + console.error(err); + }); + }; + } + Object.defineProperty(obj, property.name, proto); + }); +}; + +// TODO: import from a dependency, don't duplicate. +var hexToDec = function (hex) { + return parseInt(hex, 16).toString(); +}; + +var decToHex = function (dec) { + return parseInt(dec).toString(16); +}; + + +var web3 = { + _callbacks: {}, + _events: {}, + providers: {}, + + toHex: function(str) { + var hex = ""; + for(var i = 0; i < str.length; i++) { + var n = str.charCodeAt(i).toString(16); + hex += n.length < 2 ? '0' + n : n; + } + + return hex; + }, + + toAscii: function(hex) { + // Find termination + var str = ""; + var i = 0, l = hex.length; + if (hex.substring(0, 2) === '0x') + i = 2; + for(; i < l; i+=2) { + var code = hex.charCodeAt(i); + if(code === 0) { + break; + } + + str += String.fromCharCode(parseInt(hex.substr(i, 2), 16)); + } + + return str; + }, + + fromAscii: function(str, pad) { + pad = pad === undefined ? 32 : pad; + var hex = this.toHex(str); + while(hex.length < pad*2) + hex += "00"; + return "0x" + hex; + }, + + toDecimal: function (val) { + return hexToDec(val.substring(2)); + }, + + fromDecimal: function (val) { + return "0x" + decToHex(val); + }, + + toEth: function(str) { + var val = typeof str === "string" ? str.indexOf('0x') === 0 ? parseInt(str.substr(2), 16) : parseInt(str) : str; + var unit = 0; + var units = [ 'wei', 'Kwei', 'Mwei', 'Gwei', 'szabo', 'finney', 'ether', 'grand', 'Mether', 'Gether', 'Tether', 'Pether', 'Eether', 'Zether', 'Yether', 'Nether', 'Dether', 'Vether', 'Uether' ]; + while (val > 3000 && unit < units.length - 1) + { + val /= 1000; + unit++; + } + var s = val.toString().length < val.toFixed(2).length ? val.toString() : val.toFixed(2); + var replaceFunction = function($0, $1, $2) { + return $1 + ',' + $2; + }; + + while (true) { + var o = s; + s = s.replace(/(\d)(\d\d\d[\.\,])/, replaceFunction); + if (o === s) + break; + } + return s + ' ' + units[unit]; + }, + + eth: { + prototype: Object(), // jshint ignore:line + watch: function (params) { + return new Filter(params, ethWatch); + } + }, + + db: { + prototype: Object() // jshint ignore:line + }, + + shh: { + prototype: Object(), // jshint ignore:line + watch: function (params) { + return new Filter(params, shhWatch); + } + }, + + on: function(event, id, cb) { + if(web3._events[event] === undefined) { + web3._events[event] = {}; + } + + web3._events[event][id] = cb; + return this; + }, + + off: function(event, id) { + if(web3._events[event] !== undefined) { + delete web3._events[event][id]; + } + + return this; + }, + + trigger: function(event, id, data) { + var callbacks = web3._events[event]; + if (!callbacks || !callbacks[id]) { + return; + } + var cb = callbacks[id]; + cb(data); + } +}; + +setupMethods(web3, web3Methods()); +setupMethods(web3.eth, ethMethods()); +setupProperties(web3.eth, ethProperties()); +setupMethods(web3.db, dbMethods()); +setupMethods(web3.shh, shhMethods()); + +var ethWatch = { + changed: 'eth_changed' +}; +setupMethods(ethWatch, ethWatchMethods()); +var shhWatch = { + changed: 'shh_changed' +}; +setupMethods(shhWatch, shhWatchMethods()); + +var ProviderManager = function() { + this.queued = []; + this.polls = []; + this.ready = false; + this.provider = undefined; + this.id = 1; + + var self = this; + var poll = function () { + if (self.provider && self.provider.poll) { + self.polls.forEach(function (data) { + data.data._id = self.id; + self.id++; + self.provider.poll(data.data, data.id); + }); + } + setTimeout(poll, 12000); + }; + poll(); +}; + +ProviderManager.prototype.send = function(data, cb) { + data._id = this.id; + if (cb) { + web3._callbacks[data._id] = cb; + } + + data.args = data.args || []; + this.id++; + + if(this.provider !== undefined) { + this.provider.send(data); + } else { + console.warn("provider is not set"); + this.queued.push(data); + } +}; + +ProviderManager.prototype.set = function(provider) { + if(this.provider !== undefined && this.provider.unload !== undefined) { + this.provider.unload(); + } + + this.provider = provider; + this.ready = true; +}; + +ProviderManager.prototype.sendQueued = function() { + for(var i = 0; this.queued.length; i++) { + // Resend + this.send(this.queued[i]); + } +}; + +ProviderManager.prototype.installed = function() { + return this.provider !== undefined; +}; + +ProviderManager.prototype.startPolling = function (data, pollId) { + if (!this.provider || !this.provider.poll) { + return; + } + this.polls.push({data: data, id: pollId}); +}; + +ProviderManager.prototype.stopPolling = function (pollId) { + for (var i = this.polls.length; i--;) { + var poll = this.polls[i]; + if (poll.id === pollId) { + this.polls.splice(i, 1); + } + } +}; + +web3.provider = new ProviderManager(); + +web3.setProvider = function(provider) { + provider.onmessage = messageHandler; + web3.provider.set(provider); + web3.provider.sendQueued(); +}; + +web3.haveProvider = function() { + return !!web3.provider.provider; +}; + +var Filter = function(options, impl) { + this.impl = impl; + this.callbacks = []; + + var self = this; + this.promise = impl.newFilter(options); + this.promise.then(function (id) { + self.id = id; + web3.on(impl.changed, id, self.trigger.bind(self)); + web3.provider.startPolling({call: impl.changed, args: [id]}, id); + }); +}; + +Filter.prototype.arrived = function(callback) { + this.changed(callback); +}; + +Filter.prototype.changed = function(callback) { + var self = this; + this.promise.then(function(id) { + self.callbacks.push(callback); + }); +}; + +Filter.prototype.trigger = function(messages) { + for(var i = 0; i < this.callbacks.length; i++) { + this.callbacks[i].call(this, messages); + } +}; + +Filter.prototype.uninstall = function() { + var self = this; + this.promise.then(function (id) { + self.impl.uninstallFilter(id); + web3.provider.stopPolling(id); + web3.off(impl.changed, id); + }); +}; + +Filter.prototype.messages = function() { + var self = this; + return this.promise.then(function (id) { + return self.impl.getMessages(id); + }); +}; + +Filter.prototype.logs = function () { + return this.messages(); +}; + +function messageHandler(data) { + if(data._event !== undefined) { + web3.trigger(data._event, data._id, data.data); + return; + } + + if(data._id) { + var cb = web3._callbacks[data._id]; + if (cb) { + cb.call(this, data.error, data.data); + delete web3._callbacks[data._id]; + } + } +} + +module.exports = web3; diff --git a/lib/qt.js b/lib/qt.js new file mode 100644 index 000000000..f02239547 --- /dev/null +++ b/lib/qt.js @@ -0,0 +1,45 @@ +/* + This file is part of ethereum.js. + + ethereum.js is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ethereum.js is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with ethereum.js. If not, see . +*/ +/** @file qt.js + * @authors: + * Jeffrey Wilcke + * Marek Kotewicz + * @date 2014 + */ + +var QtProvider = function() { + this.handlers = []; + + var self = this; + navigator.qt.onmessage = function (message) { + self.handlers.forEach(function (handler) { + handler.call(self, JSON.parse(message.data)); + }); + }; +}; + +QtProvider.prototype.send = function(payload) { + navigator.qt.postMessage(JSON.stringify(payload)); +}; + +Object.defineProperty(QtProvider.prototype, "onmessage", { + set: function(handler) { + this.handlers.push(handler); + } +}); + +module.exports = QtProvider; diff --git a/lib/websocket.js b/lib/websocket.js new file mode 100644 index 000000000..ddb44aed5 --- /dev/null +++ b/lib/websocket.js @@ -0,0 +1,77 @@ +/* + This file is part of ethereum.js. + + ethereum.js is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ethereum.js is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with ethereum.js. If not, see . +*/ +/** @file websocket.js + * @authors: + * Jeffrey Wilcke + * Marek Kotewicz + * Marian Oancea + * @date 2014 + */ + +// TODO: is these line is supposed to be here? +if (process.env.NODE_ENV !== 'build') { + var WebSocket = require('ws'); // jshint ignore:line +} + +var WebSocketProvider = function(host) { + // onmessage handlers + this.handlers = []; + // queue will be filled with messages if send is invoked before the ws is ready + this.queued = []; + this.ready = false; + + this.ws = new WebSocket(host); + + var self = this; + this.ws.onmessage = function(event) { + for(var i = 0; i < self.handlers.length; i++) { + self.handlers[i].call(self, JSON.parse(event.data), event); + } + }; + + this.ws.onopen = function() { + self.ready = true; + + for(var i = 0; i < self.queued.length; i++) { + // Resend + self.send(self.queued[i]); + } + }; +}; + +WebSocketProvider.prototype.send = function(payload) { + if(this.ready) { + var data = JSON.stringify(payload); + + this.ws.send(data); + } else { + this.queued.push(payload); + } +}; + +WebSocketProvider.prototype.onMessage = function(handler) { + this.handlers.push(handler); +}; + +WebSocketProvider.prototype.unload = function() { + this.ws.close(); +}; +Object.defineProperty(WebSocketProvider.prototype, "onmessage", { + set: function(provider) { this.onMessage(provider); } +}); + +module.exports = WebSocketProvider; diff --git a/package.json b/package.json new file mode 100644 index 000000000..24141ea2e --- /dev/null +++ b/package.json @@ -0,0 +1,67 @@ +{ + "name": "ethereum.js", + "namespace": "ethereum", + "version": "0.0.5", + "description": "Ethereum Compatible JavaScript API", + "main": "./index.js", + "directories": { + "lib": "./lib" + }, + "dependencies": { + "es6-promise": "*", + "ws": "*", + "xmlhttprequest": "*" + }, + "devDependencies": { + "bower": ">=1.3.0", + "browserify": ">=6.0", + "del": ">=0.1.1", + "envify": "^3.0.0", + "exorcist": "^0.1.6", + "gulp": ">=3.4.0", + "gulp-jshint": ">=1.5.0", + "gulp-rename": ">=1.2.0", + "gulp-uglify": ">=1.0.0", + "jshint": ">=2.5.0", + "uglifyify": "^2.6.0", + "unreachable-branch-transform": "^0.1.0", + "vinyl-source-stream": "^1.0.0" + }, + "scripts": { + "build": "gulp", + "watch": "gulp watch", + "lint": "gulp lint" + }, + "repository": { + "type": "git", + "url": "https://github.com/ethereum/ethereum.js.git" + }, + "homepage": "https://github.com/ethereum/ethereum.js", + "bugs": { + "url": "https://github.com/ethereum/ethereum.js/issues" + }, + "keywords": [ + "ethereum", + "javascript", + "API" + ], + "author": "ethdev.com", + "authors": [ + { + "name": "Jeffery Wilcke", + "email": "jeff@ethdev.com", + "url": "https://github.com/obscuren" + }, + { + "name": "Marek Kotewicz", + "email": "marek@ethdev.com", + "url": "https://github.com/debris" + }, + { + "name": "Marian Oancea", + "email": "marian@ethdev.com", + "url": "https://github.com/cubedro" + } + ], + "license": "LGPL-3.0" +} From f95a8be58b62cea0ba2997737d90b32a5eeabe40 Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Wed, 7 Jan 2015 11:29:44 +0100 Subject: [PATCH 100/111] checked --- libevm/ExtVMFace.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libevm/ExtVMFace.h b/libevm/ExtVMFace.h index bf1b180e9..84cfe0a94 100644 --- a/libevm/ExtVMFace.h +++ b/libevm/ExtVMFace.h @@ -148,7 +148,7 @@ public: virtual void revert() {} /// Hash of a block if within the last 256 blocks, or h256() otherwise. - h256 blockhash(u256 _number) { return _number < currentBlock.number && _number >= (std::max(256, currentBlock.number) - 256) ? lastHashes[(unsigned)(currentBlock.number - 1 - _number)] : h256(); } // TODO: CHECK!!! + h256 blockhash(u256 _number) { return _number < currentBlock.number && _number >= (std::max(256, currentBlock.number) - 256) ? lastHashes[(unsigned)(currentBlock.number - 1 - _number)] : h256(); } /// Get the code at the given location in code ROM. byte getCode(u256 _n) const { return _n < code.size() ? code[(size_t)_n] : 0; } From fb2419d4bee639cbca102050d27885498cd50fe7 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Wed, 7 Jan 2015 11:43:51 +0100 Subject: [PATCH 101/111] removed ethereum.js --- libjsqrc/ethereum.js | 1119 ------------------------------------------ libjsqrc/js.qrc | 2 +- 2 files changed, 1 insertion(+), 1120 deletions(-) delete mode 100644 libjsqrc/ethereum.js diff --git a/libjsqrc/ethereum.js b/libjsqrc/ethereum.js deleted file mode 100644 index 08bb5014c..000000000 --- a/libjsqrc/ethereum.js +++ /dev/null @@ -1,1119 +0,0 @@ -require=(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o. -*/ -/** @file abi.js - * @authors: - * Marek Kotewicz - * Gav Wood - * @date 2014 - */ - -// TODO: make these be actually accurate instead of falling back onto JS's doubles. -var hexToDec = function (hex) { - return parseInt(hex, 16).toString(); -}; - -var decToHex = function (dec) { - return parseInt(dec).toString(16); -}; - -var findIndex = function (array, callback) { - var end = false; - var i = 0; - for (; i < array.length && !end; i++) { - end = callback(array[i]); - } - return end ? i - 1 : -1; -}; - -var findMethodIndex = function (json, methodName) { - return findIndex(json, function (method) { - return method.name === methodName; - }); -}; - -var padLeft = function (string, chars) { - return Array(chars - string.length + 1).join("0") + string; -}; - -var setupInputTypes = function () { - var prefixedType = function (prefix) { - return function (type, value) { - var expected = prefix; - if (type.indexOf(expected) !== 0) { - return false; - } - - var padding = parseInt(type.slice(expected.length)) / 8; - if (typeof value === "number") - value = value.toString(16); - else if (value.indexOf('0x') === 0) - value = value.substr(2); - else - value = (+value).toString(16); - return padLeft(value, padding * 2); - }; - }; - - var namedType = function (name, padding, formatter) { - return function (type, value) { - if (type !== name) { - return false; - } - - return padLeft(formatter ? formatter(value) : value, padding * 2); - }; - }; - - var formatBool = function (value) { - return value ? '0x1' : '0x0'; - }; - - return [ - prefixedType('uint'), - prefixedType('int'), - prefixedType('hash'), - namedType('address', 20), - namedType('bool', 1, formatBool), - ]; -}; - -var inputTypes = setupInputTypes(); - -var toAbiInput = function (json, methodName, params) { - var bytes = ""; - var index = findMethodIndex(json, methodName); - - if (index === -1) { - return; - } - - bytes = "0x" + padLeft(index.toString(16), 2); - var method = json[index]; - - for (var i = 0; i < method.inputs.length; i++) { - var found = false; - for (var j = 0; j < inputTypes.length && !found; j++) { - found = inputTypes[j](method.inputs[i].type, params[i]); - } - if (!found) { - console.error('unsupported json type: ' + method.inputs[i].type); - } - bytes += found; - } - return bytes; -}; - -var setupOutputTypes = function () { - var prefixedType = function (prefix) { - return function (type) { - var expected = prefix; - if (type.indexOf(expected) !== 0) { - return -1; - } - - var padding = parseInt(type.slice(expected.length)) / 8; - return padding * 2; - }; - }; - - var namedType = function (name, padding) { - return function (type) { - return name === type ? padding * 2 : -1; - }; - }; - - var formatInt = function (value) { - return value.length <= 8 ? +parseInt(value, 16) : hexToDec(value); - }; - - var formatHash = function (value) { - return "0x" + value; - }; - - var formatBool = function (value) { - return value === '1' ? true : false; - }; - - return [ - { padding: prefixedType('uint'), format: formatInt }, - { padding: prefixedType('int'), format: formatInt }, - { padding: prefixedType('hash'), format: formatHash }, - { padding: namedType('address', 20) }, - { padding: namedType('bool', 1), format: formatBool } - ]; -}; - -var outputTypes = setupOutputTypes(); - -var fromAbiOutput = function (json, methodName, output) { - var index = findMethodIndex(json, methodName); - - if (index === -1) { - return; - } - - output = output.slice(2); - - var result = []; - var method = json[index]; - for (var i = 0; i < method.outputs.length; i++) { - var padding = -1; - for (var j = 0; j < outputTypes.length && padding === -1; j++) { - padding = outputTypes[j].padding(method.outputs[i].type); - } - - if (padding === -1) { - // not found output parsing - continue; - } - var res = output.slice(0, padding); - var formatter = outputTypes[j - 1].format; - result.push(formatter ? formatter(res) : ("0x" + res)); - output = output.slice(padding); - } - - return result; -}; - -var inputParser = function (json) { - var parser = {}; - json.forEach(function (method) { - parser[method.name] = function () { - var params = Array.prototype.slice.call(arguments); - return toAbiInput(json, method.name, params); - }; - }); - - return parser; -}; - -var outputParser = function (json) { - var parser = {}; - json.forEach(function (method) { - parser[method.name] = function (output) { - return fromAbiOutput(json, method.name, output); - }; - }); - - return parser; -}; - -module.exports = { - inputParser: inputParser, - outputParser: outputParser -}; - - -},{}],2:[function(require,module,exports){ -/* - This file is part of ethereum.js. - - ethereum.js is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - ethereum.js is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with ethereum.js. If not, see . -*/ -/** @file autoprovider.js - * @authors: - * Marek Kotewicz - * Marian Oancea - * @date 2014 - */ - -/* - * @brief if qt object is available, uses QtProvider, - * if not tries to connect over websockets - * if it fails, it uses HttpRpcProvider - */ -if ("build" !== 'build') {/* - var WebSocket = require('ws'); // jshint ignore:line - var web3 = require('./main.js'); // jshint ignore:line -*/} - -var AutoProvider = function (userOptions) { - if (web3.haveProvider()) { - return; - } - - // before we determine what provider we are, we have to cache request - this.sendQueue = []; - this.onmessageQueue = []; - - if (navigator.qt) { - this.provider = new web3.providers.QtProvider(); - return; - } - - userOptions = userOptions || {}; - var options = { - httprpc: userOptions.httprpc || 'http://localhost:8080', - websockets: userOptions.websockets || 'ws://localhost:40404/eth' - }; - - var self = this; - var closeWithSuccess = function (success) { - ws.close(); - if (success) { - self.provider = new web3.providers.WebSocketProvider(options.websockets); - } else { - self.provider = new web3.providers.HttpRpcProvider(options.httprpc); - self.poll = self.provider.poll.bind(self.provider); - } - self.sendQueue.forEach(function (payload) { - self.provider(payload); - }); - self.onmessageQueue.forEach(function (handler) { - self.provider.onmessage = handler; - }); - }; - - var ws = new WebSocket(options.websockets); - - ws.onopen = function() { - closeWithSuccess(true); - }; - - ws.onerror = function() { - closeWithSuccess(false); - }; -}; - -AutoProvider.prototype.send = function (payload) { - if (this.provider) { - this.provider.send(payload); - return; - } - this.sendQueue.push(payload); -}; - -Object.defineProperty(AutoProvider.prototype, 'onmessage', { - set: function (handler) { - if (this.provider) { - this.provider.onmessage = handler; - return; - } - this.onmessageQueue.push(handler); - } -}); - -module.exports = AutoProvider; - -},{}],3:[function(require,module,exports){ -/* - This file is part of ethereum.js. - - ethereum.js is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - ethereum.js is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with ethereum.js. If not, see . -*/ -/** @file contract.js - * @authors: - * Marek Kotewicz - * @date 2014 - */ - -if ("build" !== 'build') {/* - var web3 = require('./web3'); // jshint ignore:line -*/} -var abi = require('./abi'); - -var contract = function (address, desc) { - var inputParser = abi.inputParser(desc); - var outputParser = abi.outputParser(desc); - - var contract = {}; - - desc.forEach(function (method) { - contract[method.name] = function () { - var params = Array.prototype.slice.call(arguments); - var parsed = inputParser[method.name].apply(null, params); - - var onSuccess = function (result) { - return outputParser[method.name](result); - }; - - return { - call: function (extra) { - extra = extra || {}; - extra.to = address; - extra.data = parsed; - return web3.eth.call(extra).then(onSuccess); - }, - transact: function (extra) { - extra = extra || {}; - extra.to = address; - extra.data = parsed; - return web3.eth.transact(extra).then(onSuccess); - } - }; - }; - }); - - return contract; -}; - -module.exports = contract; - -},{"./abi":1}],4:[function(require,module,exports){ -/* - This file is part of ethereum.js. - - ethereum.js is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - ethereum.js is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with ethereum.js. If not, see . -*/ -/** @file httprpc.js - * @authors: - * Marek Kotewicz - * Marian Oancea - * @date 2014 - */ - -if ("build" !== "build") {/* - var XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest; // jshint ignore:line -*/} - -var HttpRpcProvider = function (host) { - this.handlers = []; - this.host = host; -}; - -function formatJsonRpcObject(object) { - return { - jsonrpc: '2.0', - method: object.call, - params: object.args, - id: object._id - }; -} - -function formatJsonRpcMessage(message) { - var object = JSON.parse(message); - - return { - _id: object.id, - data: object.result, - error: object.error - }; -} - -HttpRpcProvider.prototype.sendRequest = function (payload, cb) { - var data = formatJsonRpcObject(payload); - - var request = new XMLHttpRequest(); - request.open("POST", this.host, true); - request.send(JSON.stringify(data)); - request.onreadystatechange = function () { - if (request.readyState === 4 && cb) { - cb(request); - } - }; -}; - -HttpRpcProvider.prototype.send = function (payload) { - var self = this; - this.sendRequest(payload, function (request) { - self.handlers.forEach(function (handler) { - handler.call(self, formatJsonRpcMessage(request.responseText)); - }); - }); -}; - -HttpRpcProvider.prototype.poll = function (payload, id) { - var self = this; - this.sendRequest(payload, function (request) { - var parsed = JSON.parse(request.responseText); - if (parsed.error || (parsed.result instanceof Array ? parsed.result.length === 0 : !parsed.result)) { - return; - } - self.handlers.forEach(function (handler) { - handler.call(self, {_event: payload.call, _id: id, data: parsed.result}); - }); - }); -}; - -Object.defineProperty(HttpRpcProvider.prototype, "onmessage", { - set: function (handler) { - this.handlers.push(handler); - } -}); - -module.exports = HttpRpcProvider; - -},{}],5:[function(require,module,exports){ -/* - This file is part of ethereum.js. - - ethereum.js is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - ethereum.js is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with ethereum.js. If not, see . -*/ -/** @file main.js - * @authors: - * Jeffrey Wilcke - * Marek Kotewicz - * Marian Oancea - * Gav Wood - * @date 2014 - */ - -function flattenPromise (obj) { - if (obj instanceof Promise) { - return Promise.resolve(obj); - } - - if (obj instanceof Array) { - return new Promise(function (resolve) { - var promises = obj.map(function (o) { - return flattenPromise(o); - }); - - return Promise.all(promises).then(function (res) { - for (var i = 0; i < obj.length; i++) { - obj[i] = res[i]; - } - resolve(obj); - }); - }); - } - - if (obj instanceof Object) { - return new Promise(function (resolve) { - var keys = Object.keys(obj); - var promises = keys.map(function (key) { - return flattenPromise(obj[key]); - }); - - return Promise.all(promises).then(function (res) { - for (var i = 0; i < keys.length; i++) { - obj[keys[i]] = res[i]; - } - resolve(obj); - }); - }); - } - - return Promise.resolve(obj); -} - -var web3Methods = function () { - return [ - { name: 'sha3', call: 'web3_sha3' } - ]; -}; - -var ethMethods = function () { - var blockCall = function (args) { - return typeof args[0] === "string" ? "eth_blockByHash" : "eth_blockByNumber"; - }; - - var transactionCall = function (args) { - return typeof args[0] === "string" ? 'eth_transactionByHash' : 'eth_transactionByNumber'; - }; - - var uncleCall = function (args) { - return typeof args[0] === "string" ? 'eth_uncleByHash' : 'eth_uncleByNumber'; - }; - - var methods = [ - { name: 'balanceAt', call: 'eth_balanceAt' }, - { name: 'stateAt', call: 'eth_stateAt' }, - { name: 'storageAt', call: 'eth_storageAt' }, - { name: 'countAt', call: 'eth_countAt'}, - { name: 'codeAt', call: 'eth_codeAt' }, - { name: 'transact', call: 'eth_transact' }, - { name: 'call', call: 'eth_call' }, - { name: 'block', call: blockCall }, - { name: 'transaction', call: transactionCall }, - { name: 'uncle', call: uncleCall }, - { name: 'compilers', call: 'eth_compilers' }, - { name: 'lll', call: 'eth_lll' }, - { name: 'solidity', call: 'eth_solidity' }, - { name: 'serpent', call: 'eth_serpent' }, - { name: 'logs', call: 'eth_logs' } - ]; - return methods; -}; - -var ethProperties = function () { - return [ - { name: 'coinbase', getter: 'eth_coinbase', setter: 'eth_setCoinbase' }, - { name: 'listening', getter: 'eth_listening', setter: 'eth_setListening' }, - { name: 'mining', getter: 'eth_mining', setter: 'eth_setMining' }, - { name: 'gasPrice', getter: 'eth_gasPrice' }, - { name: 'account', getter: 'eth_account' }, - { name: 'accounts', getter: 'eth_accounts' }, - { name: 'peerCount', getter: 'eth_peerCount' }, - { name: 'defaultBlock', getter: 'eth_defaultBlock', setter: 'eth_setDefaultBlock' }, - { name: 'number', getter: 'eth_number'} - ]; -}; - -var dbMethods = function () { - return [ - { name: 'put', call: 'db_put' }, - { name: 'get', call: 'db_get' }, - { name: 'putString', call: 'db_putString' }, - { name: 'getString', call: 'db_getString' } - ]; -}; - -var shhMethods = function () { - return [ - { name: 'post', call: 'shh_post' }, - { name: 'newIdentity', call: 'shh_newIdentity' }, - { name: 'haveIdentity', call: 'shh_haveIdentity' }, - { name: 'newGroup', call: 'shh_newGroup' }, - { name: 'addToGroup', call: 'shh_addToGroup' } - ]; -}; - -var ethWatchMethods = function () { - var newFilter = function (args) { - return typeof args[0] === 'string' ? 'eth_newFilterString' : 'eth_newFilter'; - }; - - return [ - { name: 'newFilter', call: newFilter }, - { name: 'uninstallFilter', call: 'eth_uninstallFilter' }, - { name: 'getMessages', call: 'eth_filterLogs' } - ]; -}; - -var shhWatchMethods = function () { - return [ - { name: 'newFilter', call: 'shh_newFilter' }, - { name: 'uninstallFilter', call: 'shh_uninstallFilter' }, - { name: 'getMessage', call: 'shh_getMessages' } - ]; -}; - -var setupMethods = function (obj, methods) { - methods.forEach(function (method) { - obj[method.name] = function () { - return flattenPromise(Array.prototype.slice.call(arguments)).then(function (args) { - var call = typeof method.call === "function" ? method.call(args) : method.call; - return {call: call, args: args}; - }).then(function (request) { - return new Promise(function (resolve, reject) { - web3.provider.send(request, function (err, result) { - if (!err) { - resolve(result); - return; - } - reject(err); - }); - }); - }).catch(function(err) { - console.error(err); - }); - }; - }); -}; - -var setupProperties = function (obj, properties) { - properties.forEach(function (property) { - var proto = {}; - proto.get = function () { - return new Promise(function(resolve, reject) { - web3.provider.send({call: property.getter}, function(err, result) { - if (!err) { - resolve(result); - return; - } - reject(err); - }); - }); - }; - if (property.setter) { - proto.set = function (val) { - return flattenPromise([val]).then(function (args) { - return new Promise(function (resolve) { - web3.provider.send({call: property.setter, args: args}, function (err, result) { - if (!err) { - resolve(result); - return; - } - reject(err); - }); - }); - }).catch(function (err) { - console.error(err); - }); - }; - } - Object.defineProperty(obj, property.name, proto); - }); -}; - -// TODO: import from a dependency, don't duplicate. -var hexToDec = function (hex) { - return parseInt(hex, 16).toString(); -}; - -var decToHex = function (dec) { - return parseInt(dec).toString(16); -}; - - -var web3 = { - _callbacks: {}, - _events: {}, - providers: {}, - - toAscii: function(hex) { - // Find termination - var str = ""; - var i = 0, l = hex.length; - if (hex.substring(0, 2) === '0x') - i = 2; - for(; i < l; i+=2) { - var code = hex.charCodeAt(i); - if(code === 0) { - break; - } - - str += String.fromCharCode(parseInt(hex.substr(i, 2), 16)); - } - - return str; - }, - - fromAscii: function(str, pad) { - pad = pad === undefined ? 32 : pad; - var hex = this.toHex(str); - while(hex.length < pad*2) - hex += "00"; - return "0x" + hex; - }, - - toDecimal: function (val) { - return hexToDec(val.substring(2)); - }, - - fromDecimal: function (val) { - return "0x" + decToHex(val); - }, - - toEth: function(str) { - var val = typeof str === "string" ? str.indexOf('0x') == 0 ? parseInt(str.substr(2), 16) : parseInt(str) : str; - var unit = 0; - var units = [ 'wei', 'Kwei', 'Mwei', 'Gwei', 'szabo', 'finney', 'ether', 'grand', 'Mether', 'Gether', 'Tether', 'Pether', 'Eether', 'Zether', 'Yether', 'Nether', 'Dether', 'Vether', 'Uether' ]; - while (val > 3000 && unit < units.length - 1) - { - val /= 1000; - unit++; - } - var s = val.toString().length < val.toFixed(2).length ? val.toString() : val.toFixed(2); - while (true) { - var o = s; - s = s.replace(/(\d)(\d\d\d[\.\,])/, function($0, $1, $2) { return $1 + ',' + $2; }); - if (o == s) - break; - } - return s + ' ' + units[unit]; - }, - - eth: { - prototype: Object(), // jshint ignore:line - watch: function (params) { - return new Filter(params, ethWatch); - } - }, - - db: { - prototype: Object() // jshint ignore:line - }, - - shh: { - prototype: Object(), // jshint ignore:line - watch: function (params) { - return new Filter(params, shhWatch); - } - }, - - on: function(event, id, cb) { - if(web3._events[event] === undefined) { - web3._events[event] = {}; - } - - web3._events[event][id] = cb; - return this; - }, - - off: function(event, id) { - if(web3._events[event] !== undefined) { - delete web3._events[event][id]; - } - - return this; - }, - - trigger: function(event, id, data) { - var callbacks = web3._events[event]; - if (!callbacks || !callbacks[id]) { - return; - } - var cb = callbacks[id]; - cb(data); - } -}; - -setupMethods(web3, web3Methods()); -setupMethods(web3.eth, ethMethods()); -setupProperties(web3.eth, ethProperties()); -setupMethods(web3.db, dbMethods()); -setupMethods(web3.shh, shhMethods()); - -var ethWatch = { - changed: 'eth_changed' -}; -setupMethods(ethWatch, ethWatchMethods()); -var shhWatch = { - changed: 'shh_changed' -}; -setupMethods(shhWatch, shhWatchMethods()); - -var ProviderManager = function() { - this.queued = []; - this.polls = []; - this.ready = false; - this.provider = undefined; - this.id = 1; - - var self = this; - var poll = function () { - if (self.provider && self.provider.poll) { - self.polls.forEach(function (data) { - data.data._id = self.id; - self.id++; - self.provider.poll(data.data, data.id); - }); - } - setTimeout(poll, 12000); - }; - poll(); -}; - -ProviderManager.prototype.send = function(data, cb) { - data._id = this.id; - if (cb) { - web3._callbacks[data._id] = cb; - } - - data.args = data.args || []; - this.id++; - - if(this.provider !== undefined) { - this.provider.send(data); - } else { - console.warn("provider is not set"); - this.queued.push(data); - } -}; - -ProviderManager.prototype.set = function(provider) { - if(this.provider !== undefined && this.provider.unload !== undefined) { - this.provider.unload(); - } - - this.provider = provider; - this.ready = true; -}; - -ProviderManager.prototype.sendQueued = function() { - for(var i = 0; this.queued.length; i++) { - // Resend - this.send(this.queued[i]); - } -}; - -ProviderManager.prototype.installed = function() { - return this.provider !== undefined; -}; - -ProviderManager.prototype.startPolling = function (data, pollId) { - if (!this.provider || !this.provider.poll) { - return; - } - this.polls.push({data: data, id: pollId}); -}; - -ProviderManager.prototype.stopPolling = function (pollId) { - for (var i = this.polls.length; i--;) { - var poll = this.polls[i]; - if (poll.id === pollId) { - this.polls.splice(i, 1); - } - } -}; - -web3.provider = new ProviderManager(); - -web3.setProvider = function(provider) { - provider.onmessage = messageHandler; - web3.provider.set(provider); - web3.provider.sendQueued(); -}; - -web3.haveProvider = function() { - return !!web3.provider.provider; -}; - -var Filter = function(options, impl) { - this.impl = impl; - this.callbacks = []; - - var self = this; - this.promise = impl.newFilter(options); - this.promise.then(function (id) { - self.id = id; - web3.on(impl.changed, id, self.trigger.bind(self)); - web3.provider.startPolling({call: impl.changed, args: [id]}, id); - }); -}; - -Filter.prototype.arrived = function(callback) { - this.changed(callback); -}; - -Filter.prototype.changed = function(callback) { - var self = this; - this.promise.then(function(id) { - self.callbacks.push(callback); - }); -}; - -Filter.prototype.trigger = function(messages) { - for(var i = 0; i < this.callbacks.length; i++) { - this.callbacks[i].call(this, messages); - } -}; - -Filter.prototype.uninstall = function() { - var self = this; - this.promise.then(function (id) { - self.impl.uninstallFilter(id); - web3.provider.stopPolling(id); - web3.off(impl.changed, id); - }); -}; - -Filter.prototype.messages = function() { - var self = this; - return this.promise.then(function (id) { - return self.impl.getMessages(id); - }); -}; - -Filter.prototype.logs = function () { - return this.messages(); -}; - -function messageHandler(data) { - if(data._event !== undefined) { - web3.trigger(data._event, data._id, data.data); - return; - } - - if(data._id) { - var cb = web3._callbacks[data._id]; - if (cb) { - cb.call(this, data.error, data.data); - delete web3._callbacks[data._id]; - } - } -} - -module.exports = web3; - - -},{}],6:[function(require,module,exports){ -/* - This file is part of ethereum.js. - - ethereum.js is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - ethereum.js is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with ethereum.js. If not, see . -*/ -/** @file qt.js - * @authors: - * Jeffrey Wilcke - * Marek Kotewicz - * @date 2014 - */ - -var QtProvider = function() { - this.handlers = []; - - var self = this; - navigator.qt.onmessage = function (message) { - self.handlers.forEach(function (handler) { - handler.call(self, JSON.parse(message.data)); - }); - }; -}; - -QtProvider.prototype.send = function(payload) { - navigator.qt.postMessage(JSON.stringify(payload)); -}; - -Object.defineProperty(QtProvider.prototype, "onmessage", { - set: function(handler) { - this.handlers.push(handler); - } -}); - -module.exports = QtProvider; - -},{}],7:[function(require,module,exports){ -/* - This file is part of ethereum.js. - - ethereum.js is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - ethereum.js is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with ethereum.js. If not, see . -*/ -/** @file websocket.js - * @authors: - * Jeffrey Wilcke - * Marek Kotewicz - * Marian Oancea - * @date 2014 - */ - -if ("build" !== "build") {/* - var WebSocket = require('ws'); // jshint ignore:line -*/} - -var WebSocketProvider = function(host) { - // onmessage handlers - this.handlers = []; - // queue will be filled with messages if send is invoked before the ws is ready - this.queued = []; - this.ready = false; - - this.ws = new WebSocket(host); - - var self = this; - this.ws.onmessage = function(event) { - for(var i = 0; i < self.handlers.length; i++) { - self.handlers[i].call(self, JSON.parse(event.data), event); - } - }; - - this.ws.onopen = function() { - self.ready = true; - - for(var i = 0; i < self.queued.length; i++) { - // Resend - self.send(self.queued[i]); - } - }; -}; - -WebSocketProvider.prototype.send = function(payload) { - if(this.ready) { - var data = JSON.stringify(payload); - - this.ws.send(data); - } else { - this.queued.push(payload); - } -}; - -WebSocketProvider.prototype.onMessage = function(handler) { - this.handlers.push(handler); -}; - -WebSocketProvider.prototype.unload = function() { - this.ws.close(); -}; -Object.defineProperty(WebSocketProvider.prototype, "onmessage", { - set: function(provider) { this.onMessage(provider); } -}); - -module.exports = WebSocketProvider; - -},{}],"web3":[function(require,module,exports){ -var web3 = require('./lib/main'); -web3.providers.WebSocketProvider = require('./lib/websocket'); -web3.providers.HttpRpcProvider = require('./lib/httprpc'); -web3.providers.QtProvider = require('./lib/qt'); -web3.providers.AutoProvider = require('./lib/autoprovider'); -web3.contract = require('./lib/contract'); - -module.exports = web3; - -},{"./lib/autoprovider":2,"./lib/contract":3,"./lib/httprpc":4,"./lib/main":5,"./lib/qt":6,"./lib/websocket":7}]},{},[]) - - -//# sourceMappingURL=ethereum.js.map diff --git a/libjsqrc/js.qrc b/libjsqrc/js.qrc index 56cab75f1..eee8f6652 100644 --- a/libjsqrc/js.qrc +++ b/libjsqrc/js.qrc @@ -2,6 +2,6 @@ es6-promise-2.0.0.js setup.js - ethereum.js + ethereumjs/dist/ethereum.js From e855cf9426ddacf95b078098d438a78f98997bde Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Wed, 7 Jan 2015 12:14:33 +0100 Subject: [PATCH 102/111] memory test: high offset, zero size -> zero gas cost --- test/stSystemOperationsTestFiller.json | 69 ++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/test/stSystemOperationsTestFiller.json b/test/stSystemOperationsTestFiller.json index 70ce448fc..757c8a235 100644 --- a/test/stSystemOperationsTestFiller.json +++ b/test/stSystemOperationsTestFiller.json @@ -33,6 +33,75 @@ } }, + "createNameRegistratorZeroMem": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (MSTORE 0 0x601080600c6000396000f3006000355415600957005b60203560003555) [[ 0 ]] (CREATE 23 3 0) }", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "10000", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "createNameRegistratorZeroMem2": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (MSTORE 0 0x601080600c6000396000f3006000355415600957005b60203560003555) [[ 0 ]] (CREATE 23 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 0) }", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "10000", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "createNameRegistratorZeroMemExpansion": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", From 67debe5ea5df33baa53793f536fcbfd522559b1e Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Wed, 7 Jan 2015 12:36:15 +0100 Subject: [PATCH 103/111] jump onto jump, dynamic and static jump with same destination --- test/vmIOandFlowOperationsTestFiller.json | 56 +++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/test/vmIOandFlowOperationsTestFiller.json b/test/vmIOandFlowOperationsTestFiller.json index 073c8ac80..efbd0d683 100644 --- a/test/vmIOandFlowOperationsTestFiller.json +++ b/test/vmIOandFlowOperationsTestFiller.json @@ -671,6 +671,62 @@ } }, + "jumpOntoJump": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "0x565b600056", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "jumpDynamicJumpSameDest": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "0x6002600401565b600360005260206000f3600656", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + "jump0_outOfBoundary": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", From 7963e26aeb39d4ecb24edf1b206b2ef0757a0c70 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Wed, 7 Jan 2015 14:15:51 +0100 Subject: [PATCH 104/111] Squashed 'libjsqrc/ethereumjs/' changes from df4d784..5208bb3 5208bb3 gulpfile modifications, default build set to dev git-subtree-dir: libjsqrc/ethereumjs git-subtree-split: 5208bb32f147bd00ba36ca684faba31c0cc7fc9a --- dist/ethereum.js | 1180 +++++++++++++++++++++++++++++++++++++++++- dist/ethereum.js.map | 18 +- dist/ethereum.min.js | 2 +- gulpfile.js | 81 ++- 4 files changed, 1213 insertions(+), 68 deletions(-) diff --git a/dist/ethereum.js b/dist/ethereum.js index 8abe6ad53..e496c30f4 100644 --- a/dist/ethereum.js +++ b/dist/ethereum.js @@ -1,19 +1,1183 @@ require=(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;oi;i++)padding+=sizes[i]/8;return padding},setupInputTypes=function(){var prefixedType=function(prefix,calcPadding){return function(type,value){var padding,expected=prefix;return 0!==type.indexOf(expected)?!1:(padding=calcPadding(type,expected),value="number"==typeof value?value.toString(16):"string"==typeof value?web3.toHex(value):0===value.indexOf("0x")?value.substr(2):(+value).toString(16),padLeft(value,2*padding))}},namedType=function(name,padding,formatter){return function(type,value){return type!==name?!1:padLeft(formatter?formatter(value):value,2*padding)}},formatBool=function(value){return value?"0x1":"0x0"};return[prefixedType("uint",calcBitPadding),prefixedType("int",calcBitPadding),prefixedType("hash",calcBitPadding),prefixedType("string",calcBytePadding),prefixedType("real",calcRealPadding),prefixedType("ureal",calcRealPadding),namedType("address",20),namedType("bool",1,formatBool)]},inputTypes=setupInputTypes(),toAbiInput=function(json,methodName,params){var method,i,found,j,bytes="",index=findMethodIndex(json,methodName);if(-1!==index){for(bytes="0x"+padLeft(index.toString(16),2),method=json[index],i=0;i. +*/ +/** @file abi.js + * @authors: + * Marek Kotewicz + * Gav Wood + * @date 2014 + */ + +// TODO: is these line is supposed to be here? +if ("build" !== 'build') {/* + var web3 = require('./web3'); // jshint ignore:line +*/} + +// TODO: make these be actually accurate instead of falling back onto JS's doubles. +var hexToDec = function (hex) { + return parseInt(hex, 16).toString(); +}; + +var decToHex = function (dec) { + return parseInt(dec).toString(16); +}; + +var findIndex = function (array, callback) { + var end = false; + var i = 0; + for (; i < array.length && !end; i++) { + end = callback(array[i]); + } + return end ? i - 1 : -1; +}; + +var findMethodIndex = function (json, methodName) { + return findIndex(json, function (method) { + return method.name === methodName; + }); +}; + +var padLeft = function (string, chars) { + return new Array(chars - string.length + 1).join("0") + string; +}; + +var calcBitPadding = function (type, expected) { + var value = type.slice(expected.length); + if (value === "") { + return 32; + } + return parseInt(value) / 8; +}; + +var calcBytePadding = function (type, expected) { + var value = type.slice(expected.length); + if (value === "") { + return 32; + } + return parseInt(value); +}; + +var calcRealPadding = function (type, expected) { + var value = type.slice(expected.length); + if (value === "") { + return 32; + } + var sizes = value.split('x'); + for (var padding = 0, i = 0; i < sizes; i++) { + padding += (sizes[i] / 8); + } + return padding; +}; + +var setupInputTypes = function () { + + var prefixedType = function (prefix, calcPadding) { + return function (type, value) { + var expected = prefix; + if (type.indexOf(expected) !== 0) { + return false; + } + + var padding = calcPadding(type, expected); + if (typeof value === "number") + value = value.toString(16); + else if (typeof value === "string") + value = web3.toHex(value); + else if (value.indexOf('0x') === 0) + value = value.substr(2); + else + value = (+value).toString(16); + return padLeft(value, padding * 2); + }; + }; + + var namedType = function (name, padding, formatter) { + return function (type, value) { + if (type !== name) { + return false; + } + + return padLeft(formatter ? formatter(value) : value, padding * 2); + }; + }; + + var formatBool = function (value) { + return value ? '0x1' : '0x0'; + }; + + return [ + prefixedType('uint', calcBitPadding), + prefixedType('int', calcBitPadding), + prefixedType('hash', calcBitPadding), + prefixedType('string', calcBytePadding), + prefixedType('real', calcRealPadding), + prefixedType('ureal', calcRealPadding), + namedType('address', 20), + namedType('bool', 1, formatBool), + ]; +}; + +var inputTypes = setupInputTypes(); + +var toAbiInput = function (json, methodName, params) { + var bytes = ""; + var index = findMethodIndex(json, methodName); + + if (index === -1) { + return; + } + + bytes = "0x" + padLeft(index.toString(16), 2); + var method = json[index]; + + for (var i = 0; i < method.inputs.length; i++) { + var found = false; + for (var j = 0; j < inputTypes.length && !found; j++) { + found = inputTypes[j](method.inputs[i].type, params[i]); + } + if (!found) { + console.error('unsupported json type: ' + method.inputs[i].type); + } + bytes += found; + } + return bytes; +}; + +var setupOutputTypes = function () { + + var prefixedType = function (prefix, calcPadding) { + return function (type) { + var expected = prefix; + if (type.indexOf(expected) !== 0) { + return -1; + } + + var padding = calcPadding(type, expected); + return padding * 2; + }; + }; + + var namedType = function (name, padding) { + return function (type) { + return name === type ? padding * 2 : -1; + }; + }; + + var formatInt = function (value) { + return value.length <= 8 ? +parseInt(value, 16) : hexToDec(value); + }; + + var formatHash = function (value) { + return "0x" + value; + }; + + var formatBool = function (value) { + return value === '1' ? true : false; + }; + + var formatString = function (value) { + return web3.toAscii(value); + }; + + return [ + { padding: prefixedType('uint', calcBitPadding), format: formatInt }, + { padding: prefixedType('int', calcBitPadding), format: formatInt }, + { padding: prefixedType('hash', calcBitPadding), format: formatHash }, + { padding: prefixedType('string', calcBytePadding), format: formatString }, + { padding: prefixedType('real', calcRealPadding), format: formatInt }, + { padding: prefixedType('ureal', calcRealPadding), format: formatInt }, + { padding: namedType('address', 20) }, + { padding: namedType('bool', 1), format: formatBool } + ]; +}; + +var outputTypes = setupOutputTypes(); + +var fromAbiOutput = function (json, methodName, output) { + var index = findMethodIndex(json, methodName); + + if (index === -1) { + return; + } + + output = output.slice(2); + + var result = []; + var method = json[index]; + for (var i = 0; i < method.outputs.length; i++) { + var padding = -1; + for (var j = 0; j < outputTypes.length && padding === -1; j++) { + padding = outputTypes[j].padding(method.outputs[i].type); + } + + if (padding === -1) { + // not found output parsing + continue; + } + var res = output.slice(0, padding); + var formatter = outputTypes[j - 1].format; + result.push(formatter ? formatter(res) : ("0x" + res)); + output = output.slice(padding); + } + + return result; +}; + +var inputParser = function (json) { + var parser = {}; + json.forEach(function (method) { + parser[method.name] = function () { + var params = Array.prototype.slice.call(arguments); + return toAbiInput(json, method.name, params); + }; + }); + + return parser; +}; + +var outputParser = function (json) { + var parser = {}; + json.forEach(function (method) { + parser[method.name] = function (output) { + return fromAbiOutput(json, method.name, output); + }; + }); + + return parser; +}; + +module.exports = { + inputParser: inputParser, + outputParser: outputParser +}; + },{}],2:[function(require,module,exports){ -var AutoProvider=function(userOptions){var options,self,closeWithSuccess,ws;if(!web3.haveProvider()){if(this.sendQueue=[],this.onmessageQueue=[],navigator.qt)return void(this.provider=new web3.providers.QtProvider);userOptions=userOptions||{},options={httprpc:userOptions.httprpc||"http://localhost:8080",websockets:userOptions.websockets||"ws://localhost:40404/eth"},self=this,closeWithSuccess=function(success){ws.close(),success?self.provider=new web3.providers.WebSocketProvider(options.websockets):(self.provider=new web3.providers.HttpRpcProvider(options.httprpc),self.poll=self.provider.poll.bind(self.provider)),self.sendQueue.forEach(function(payload){self.provider(payload)}),self.onmessageQueue.forEach(function(handler){self.provider.onmessage=handler})},ws=new WebSocket(options.websockets),ws.onopen=function(){closeWithSuccess(!0)},ws.onerror=function(){closeWithSuccess(!1)}}};AutoProvider.prototype.send=function(payload){return this.provider?void this.provider.send(payload):void this.sendQueue.push(payload)},Object.defineProperty(AutoProvider.prototype,"onmessage",{set:function(handler){return this.provider?void(this.provider.onmessage=handler):void this.onmessageQueue.push(handler)}}),module.exports=AutoProvider; +/* + This file is part of ethereum.js. + + ethereum.js is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ethereum.js is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with ethereum.js. If not, see . +*/ +/** @file autoprovider.js + * @authors: + * Marek Kotewicz + * Marian Oancea + * @date 2014 + */ + +/* + * @brief if qt object is available, uses QtProvider, + * if not tries to connect over websockets + * if it fails, it uses HttpRpcProvider + */ + +// TODO: is these line is supposed to be here? +if ("build" !== 'build') {/* + var WebSocket = require('ws'); // jshint ignore:line + var web3 = require('./main.js'); // jshint ignore:line +*/} + +var AutoProvider = function (userOptions) { + if (web3.haveProvider()) { + return; + } + + // before we determine what provider we are, we have to cache request + this.sendQueue = []; + this.onmessageQueue = []; + + if (navigator.qt) { + this.provider = new web3.providers.QtProvider(); + return; + } + + userOptions = userOptions || {}; + var options = { + httprpc: userOptions.httprpc || 'http://localhost:8080', + websockets: userOptions.websockets || 'ws://localhost:40404/eth' + }; + + var self = this; + var closeWithSuccess = function (success) { + ws.close(); + if (success) { + self.provider = new web3.providers.WebSocketProvider(options.websockets); + } else { + self.provider = new web3.providers.HttpRpcProvider(options.httprpc); + self.poll = self.provider.poll.bind(self.provider); + } + self.sendQueue.forEach(function (payload) { + self.provider(payload); + }); + self.onmessageQueue.forEach(function (handler) { + self.provider.onmessage = handler; + }); + }; + + var ws = new WebSocket(options.websockets); + + ws.onopen = function() { + closeWithSuccess(true); + }; + + ws.onerror = function() { + closeWithSuccess(false); + }; +}; + +AutoProvider.prototype.send = function (payload) { + if (this.provider) { + this.provider.send(payload); + return; + } + this.sendQueue.push(payload); +}; + +Object.defineProperty(AutoProvider.prototype, 'onmessage', { + set: function (handler) { + if (this.provider) { + this.provider.onmessage = handler; + return; + } + this.onmessageQueue.push(handler); + } +}); + +module.exports = AutoProvider; + },{}],3:[function(require,module,exports){ -var abi,contract;abi=require("./abi"),contract=function(address,desc){var inputParser=abi.inputParser(desc),outputParser=abi.outputParser(desc),contract={};return desc.forEach(function(method){contract[method.name]=function(){var params=Array.prototype.slice.call(arguments),parsed=inputParser[method.name].apply(null,params),onSuccess=function(result){return outputParser[method.name](result)};return{call:function(extra){return extra=extra||{},extra.to=address,extra.data=parsed,web3.eth.call(extra).then(onSuccess)},transact:function(extra){return extra=extra||{},extra.to=address,extra.data=parsed,web3.eth.transact(extra).then(onSuccess)}}}}),contract},module.exports=contract; +/* + This file is part of ethereum.js. + + ethereum.js is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ethereum.js is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with ethereum.js. If not, see . +*/ +/** @file contract.js + * @authors: + * Marek Kotewicz + * @date 2014 + */ + +// TODO: is these line is supposed to be here? +if ("build" !== 'build') {/* + var web3 = require('./web3'); // jshint ignore:line +*/} + +var abi = require('./abi'); + +var contract = function (address, desc) { + var inputParser = abi.inputParser(desc); + var outputParser = abi.outputParser(desc); + + var contract = {}; + + desc.forEach(function (method) { + contract[method.name] = function () { + var params = Array.prototype.slice.call(arguments); + var parsed = inputParser[method.name].apply(null, params); + + var onSuccess = function (result) { + return outputParser[method.name](result); + }; + + return { + call: function (extra) { + extra = extra || {}; + extra.to = address; + extra.data = parsed; + return web3.eth.call(extra).then(onSuccess); + }, + transact: function (extra) { + extra = extra || {}; + extra.to = address; + extra.data = parsed; + return web3.eth.transact(extra).then(onSuccess); + } + }; + }; + }); + + return contract; +}; + +module.exports = contract; + },{"./abi":1}],4:[function(require,module,exports){ -function formatJsonRpcObject(object){return{jsonrpc:"2.0",method:object.call,params:object.args,id:object._id}}function formatJsonRpcMessage(message){var object=JSON.parse(message);return{_id:object.id,data:object.result,error:object.error}}var HttpRpcProvider=function(host){this.handlers=[],this.host=host};HttpRpcProvider.prototype.sendRequest=function(payload,cb){var data=formatJsonRpcObject(payload),request=new XMLHttpRequest;request.open("POST",this.host,!0),request.send(JSON.stringify(data)),request.onreadystatechange=function(){4===request.readyState&&cb&&cb(request)}},HttpRpcProvider.prototype.send=function(payload){var self=this;this.sendRequest(payload,function(request){self.handlers.forEach(function(handler){handler.call(self,formatJsonRpcMessage(request.responseText))})})},HttpRpcProvider.prototype.poll=function(payload,id){var self=this;this.sendRequest(payload,function(request){var parsed=JSON.parse(request.responseText);!parsed.error&&(parsed.result instanceof Array?0!==parsed.result.length:parsed.result)&&self.handlers.forEach(function(handler){handler.call(self,{_event:payload.call,_id:id,data:parsed.result})})})},Object.defineProperty(HttpRpcProvider.prototype,"onmessage",{set:function(handler){this.handlers.push(handler)}}),module.exports=HttpRpcProvider; +/* + This file is part of ethereum.js. + + ethereum.js is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ethereum.js is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with ethereum.js. If not, see . +*/ +/** @file httprpc.js + * @authors: + * Marek Kotewicz + * Marian Oancea + * @date 2014 + */ + +// TODO: is these line is supposed to be here? +if ("build" !== 'build') {/* + var XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest; // jshint ignore:line +*/} + +var HttpRpcProvider = function (host) { + this.handlers = []; + this.host = host; +}; + +function formatJsonRpcObject(object) { + return { + jsonrpc: '2.0', + method: object.call, + params: object.args, + id: object._id + }; +} + +function formatJsonRpcMessage(message) { + var object = JSON.parse(message); + + return { + _id: object.id, + data: object.result, + error: object.error + }; +} + +HttpRpcProvider.prototype.sendRequest = function (payload, cb) { + var data = formatJsonRpcObject(payload); + + var request = new XMLHttpRequest(); + request.open("POST", this.host, true); + request.send(JSON.stringify(data)); + request.onreadystatechange = function () { + if (request.readyState === 4 && cb) { + cb(request); + } + }; +}; + +HttpRpcProvider.prototype.send = function (payload) { + var self = this; + this.sendRequest(payload, function (request) { + self.handlers.forEach(function (handler) { + handler.call(self, formatJsonRpcMessage(request.responseText)); + }); + }); +}; + +HttpRpcProvider.prototype.poll = function (payload, id) { + var self = this; + this.sendRequest(payload, function (request) { + var parsed = JSON.parse(request.responseText); + if (parsed.error || (parsed.result instanceof Array ? parsed.result.length === 0 : !parsed.result)) { + return; + } + self.handlers.forEach(function (handler) { + handler.call(self, {_event: payload.call, _id: id, data: parsed.result}); + }); + }); +}; + +Object.defineProperty(HttpRpcProvider.prototype, "onmessage", { + set: function (handler) { + this.handlers.push(handler); + } +}); + +module.exports = HttpRpcProvider; + },{}],5:[function(require,module,exports){ -function flattenPromise(obj){return obj instanceof Promise?Promise.resolve(obj):obj instanceof Array?new Promise(function(resolve){var promises=obj.map(function(o){return flattenPromise(o)});return Promise.all(promises).then(function(res){for(var i=0;ii&&(code=hex.charCodeAt(i),0!==code);i+=2)str+=String.fromCharCode(parseInt(hex.substr(i,2),16));return str},fromAscii:function(str,pad){pad=void 0===pad?32:pad;for(var hex=this.toHex(str);hex.length<2*pad;)hex+="00";return"0x"+hex},toDecimal:function(val){return hexToDec(val.substring(2))},fromDecimal:function(val){return"0x"+decToHex(val)},toEth:function(str){for(var s,replaceFunction,o,val="string"==typeof str?0===str.indexOf("0x")?parseInt(str.substr(2),16):parseInt(str):str,unit=0,units=["wei","Kwei","Mwei","Gwei","szabo","finney","ether","grand","Mether","Gether","Tether","Pether","Eether","Zether","Yether","Nether","Dether","Vether","Uether"];val>3e3&&unit. +*/ +/** @file main.js + * @authors: + * Jeffrey Wilcke + * Marek Kotewicz + * Marian Oancea + * Gav Wood + * @date 2014 + */ + +function flattenPromise (obj) { + if (obj instanceof Promise) { + return Promise.resolve(obj); + } + + if (obj instanceof Array) { + return new Promise(function (resolve) { + var promises = obj.map(function (o) { + return flattenPromise(o); + }); + + return Promise.all(promises).then(function (res) { + for (var i = 0; i < obj.length; i++) { + obj[i] = res[i]; + } + resolve(obj); + }); + }); + } + + if (obj instanceof Object) { + return new Promise(function (resolve) { + var keys = Object.keys(obj); + var promises = keys.map(function (key) { + return flattenPromise(obj[key]); + }); + + return Promise.all(promises).then(function (res) { + for (var i = 0; i < keys.length; i++) { + obj[keys[i]] = res[i]; + } + resolve(obj); + }); + }); + } + + return Promise.resolve(obj); +} + +var web3Methods = function () { + return [ + { name: 'sha3', call: 'web3_sha3' } + ]; +}; + +var ethMethods = function () { + var blockCall = function (args) { + return typeof args[0] === "string" ? "eth_blockByHash" : "eth_blockByNumber"; + }; + + var transactionCall = function (args) { + return typeof args[0] === "string" ? 'eth_transactionByHash' : 'eth_transactionByNumber'; + }; + + var uncleCall = function (args) { + return typeof args[0] === "string" ? 'eth_uncleByHash' : 'eth_uncleByNumber'; + }; + + var methods = [ + { name: 'balanceAt', call: 'eth_balanceAt' }, + { name: 'stateAt', call: 'eth_stateAt' }, + { name: 'storageAt', call: 'eth_storageAt' }, + { name: 'countAt', call: 'eth_countAt'}, + { name: 'codeAt', call: 'eth_codeAt' }, + { name: 'transact', call: 'eth_transact' }, + { name: 'call', call: 'eth_call' }, + { name: 'block', call: blockCall }, + { name: 'transaction', call: transactionCall }, + { name: 'uncle', call: uncleCall }, + { name: 'compilers', call: 'eth_compilers' }, + { name: 'lll', call: 'eth_lll' }, + { name: 'solidity', call: 'eth_solidity' }, + { name: 'serpent', call: 'eth_serpent' }, + { name: 'logs', call: 'eth_logs' } + ]; + return methods; +}; + +var ethProperties = function () { + return [ + { name: 'coinbase', getter: 'eth_coinbase', setter: 'eth_setCoinbase' }, + { name: 'listening', getter: 'eth_listening', setter: 'eth_setListening' }, + { name: 'mining', getter: 'eth_mining', setter: 'eth_setMining' }, + { name: 'gasPrice', getter: 'eth_gasPrice' }, + { name: 'account', getter: 'eth_account' }, + { name: 'accounts', getter: 'eth_accounts' }, + { name: 'peerCount', getter: 'eth_peerCount' }, + { name: 'defaultBlock', getter: 'eth_defaultBlock', setter: 'eth_setDefaultBlock' }, + { name: 'number', getter: 'eth_number'} + ]; +}; + +var dbMethods = function () { + return [ + { name: 'put', call: 'db_put' }, + { name: 'get', call: 'db_get' }, + { name: 'putString', call: 'db_putString' }, + { name: 'getString', call: 'db_getString' } + ]; +}; + +var shhMethods = function () { + return [ + { name: 'post', call: 'shh_post' }, + { name: 'newIdentity', call: 'shh_newIdentity' }, + { name: 'haveIdentity', call: 'shh_haveIdentity' }, + { name: 'newGroup', call: 'shh_newGroup' }, + { name: 'addToGroup', call: 'shh_addToGroup' } + ]; +}; + +var ethWatchMethods = function () { + var newFilter = function (args) { + return typeof args[0] === 'string' ? 'eth_newFilterString' : 'eth_newFilter'; + }; + + return [ + { name: 'newFilter', call: newFilter }, + { name: 'uninstallFilter', call: 'eth_uninstallFilter' }, + { name: 'getMessages', call: 'eth_filterLogs' } + ]; +}; + +var shhWatchMethods = function () { + return [ + { name: 'newFilter', call: 'shh_newFilter' }, + { name: 'uninstallFilter', call: 'shh_uninstallFilter' }, + { name: 'getMessage', call: 'shh_getMessages' } + ]; +}; + +var setupMethods = function (obj, methods) { + methods.forEach(function (method) { + obj[method.name] = function () { + return flattenPromise(Array.prototype.slice.call(arguments)).then(function (args) { + var call = typeof method.call === "function" ? method.call(args) : method.call; + return {call: call, args: args}; + }).then(function (request) { + return new Promise(function (resolve, reject) { + web3.provider.send(request, function (err, result) { + if (!err) { + resolve(result); + return; + } + reject(err); + }); + }); + }).catch(function(err) { + console.error(err); + }); + }; + }); +}; + +var setupProperties = function (obj, properties) { + properties.forEach(function (property) { + var proto = {}; + proto.get = function () { + return new Promise(function(resolve, reject) { + web3.provider.send({call: property.getter}, function(err, result) { + if (!err) { + resolve(result); + return; + } + reject(err); + }); + }); + }; + if (property.setter) { + proto.set = function (val) { + return flattenPromise([val]).then(function (args) { + return new Promise(function (resolve) { + web3.provider.send({call: property.setter, args: args}, function (err, result) { + if (!err) { + resolve(result); + return; + } + reject(err); + }); + }); + }).catch(function (err) { + console.error(err); + }); + }; + } + Object.defineProperty(obj, property.name, proto); + }); +}; + +// TODO: import from a dependency, don't duplicate. +var hexToDec = function (hex) { + return parseInt(hex, 16).toString(); +}; + +var decToHex = function (dec) { + return parseInt(dec).toString(16); +}; + + +var web3 = { + _callbacks: {}, + _events: {}, + providers: {}, + + toHex: function(str) { + var hex = ""; + for(var i = 0; i < str.length; i++) { + var n = str.charCodeAt(i).toString(16); + hex += n.length < 2 ? '0' + n : n; + } + + return hex; + }, + + toAscii: function(hex) { + // Find termination + var str = ""; + var i = 0, l = hex.length; + if (hex.substring(0, 2) === '0x') + i = 2; + for(; i < l; i+=2) { + var code = hex.charCodeAt(i); + if(code === 0) { + break; + } + + str += String.fromCharCode(parseInt(hex.substr(i, 2), 16)); + } + + return str; + }, + + fromAscii: function(str, pad) { + pad = pad === undefined ? 32 : pad; + var hex = this.toHex(str); + while(hex.length < pad*2) + hex += "00"; + return "0x" + hex; + }, + + toDecimal: function (val) { + return hexToDec(val.substring(2)); + }, + + fromDecimal: function (val) { + return "0x" + decToHex(val); + }, + + toEth: function(str) { + var val = typeof str === "string" ? str.indexOf('0x') === 0 ? parseInt(str.substr(2), 16) : parseInt(str) : str; + var unit = 0; + var units = [ 'wei', 'Kwei', 'Mwei', 'Gwei', 'szabo', 'finney', 'ether', 'grand', 'Mether', 'Gether', 'Tether', 'Pether', 'Eether', 'Zether', 'Yether', 'Nether', 'Dether', 'Vether', 'Uether' ]; + while (val > 3000 && unit < units.length - 1) + { + val /= 1000; + unit++; + } + var s = val.toString().length < val.toFixed(2).length ? val.toString() : val.toFixed(2); + var replaceFunction = function($0, $1, $2) { + return $1 + ',' + $2; + }; + + while (true) { + var o = s; + s = s.replace(/(\d)(\d\d\d[\.\,])/, replaceFunction); + if (o === s) + break; + } + return s + ' ' + units[unit]; + }, + + eth: { + prototype: Object(), // jshint ignore:line + watch: function (params) { + return new Filter(params, ethWatch); + } + }, + + db: { + prototype: Object() // jshint ignore:line + }, + + shh: { + prototype: Object(), // jshint ignore:line + watch: function (params) { + return new Filter(params, shhWatch); + } + }, + + on: function(event, id, cb) { + if(web3._events[event] === undefined) { + web3._events[event] = {}; + } + + web3._events[event][id] = cb; + return this; + }, + + off: function(event, id) { + if(web3._events[event] !== undefined) { + delete web3._events[event][id]; + } + + return this; + }, + + trigger: function(event, id, data) { + var callbacks = web3._events[event]; + if (!callbacks || !callbacks[id]) { + return; + } + var cb = callbacks[id]; + cb(data); + } +}; + +setupMethods(web3, web3Methods()); +setupMethods(web3.eth, ethMethods()); +setupProperties(web3.eth, ethProperties()); +setupMethods(web3.db, dbMethods()); +setupMethods(web3.shh, shhMethods()); + +var ethWatch = { + changed: 'eth_changed' +}; +setupMethods(ethWatch, ethWatchMethods()); +var shhWatch = { + changed: 'shh_changed' +}; +setupMethods(shhWatch, shhWatchMethods()); + +var ProviderManager = function() { + this.queued = []; + this.polls = []; + this.ready = false; + this.provider = undefined; + this.id = 1; + + var self = this; + var poll = function () { + if (self.provider && self.provider.poll) { + self.polls.forEach(function (data) { + data.data._id = self.id; + self.id++; + self.provider.poll(data.data, data.id); + }); + } + setTimeout(poll, 12000); + }; + poll(); +}; + +ProviderManager.prototype.send = function(data, cb) { + data._id = this.id; + if (cb) { + web3._callbacks[data._id] = cb; + } + + data.args = data.args || []; + this.id++; + + if(this.provider !== undefined) { + this.provider.send(data); + } else { + console.warn("provider is not set"); + this.queued.push(data); + } +}; + +ProviderManager.prototype.set = function(provider) { + if(this.provider !== undefined && this.provider.unload !== undefined) { + this.provider.unload(); + } + + this.provider = provider; + this.ready = true; +}; + +ProviderManager.prototype.sendQueued = function() { + for(var i = 0; this.queued.length; i++) { + // Resend + this.send(this.queued[i]); + } +}; + +ProviderManager.prototype.installed = function() { + return this.provider !== undefined; +}; + +ProviderManager.prototype.startPolling = function (data, pollId) { + if (!this.provider || !this.provider.poll) { + return; + } + this.polls.push({data: data, id: pollId}); +}; + +ProviderManager.prototype.stopPolling = function (pollId) { + for (var i = this.polls.length; i--;) { + var poll = this.polls[i]; + if (poll.id === pollId) { + this.polls.splice(i, 1); + } + } +}; + +web3.provider = new ProviderManager(); + +web3.setProvider = function(provider) { + provider.onmessage = messageHandler; + web3.provider.set(provider); + web3.provider.sendQueued(); +}; + +web3.haveProvider = function() { + return !!web3.provider.provider; +}; + +var Filter = function(options, impl) { + this.impl = impl; + this.callbacks = []; + + var self = this; + this.promise = impl.newFilter(options); + this.promise.then(function (id) { + self.id = id; + web3.on(impl.changed, id, self.trigger.bind(self)); + web3.provider.startPolling({call: impl.changed, args: [id]}, id); + }); +}; + +Filter.prototype.arrived = function(callback) { + this.changed(callback); +}; + +Filter.prototype.changed = function(callback) { + var self = this; + this.promise.then(function(id) { + self.callbacks.push(callback); + }); +}; + +Filter.prototype.trigger = function(messages) { + for(var i = 0; i < this.callbacks.length; i++) { + this.callbacks[i].call(this, messages); + } +}; + +Filter.prototype.uninstall = function() { + var self = this; + this.promise.then(function (id) { + self.impl.uninstallFilter(id); + web3.provider.stopPolling(id); + web3.off(impl.changed, id); + }); +}; + +Filter.prototype.messages = function() { + var self = this; + return this.promise.then(function (id) { + return self.impl.getMessages(id); + }); +}; + +Filter.prototype.logs = function () { + return this.messages(); +}; + +function messageHandler(data) { + if(data._event !== undefined) { + web3.trigger(data._event, data._id, data.data); + return; + } + + if(data._id) { + var cb = web3._callbacks[data._id]; + if (cb) { + cb.call(this, data.error, data.data); + delete web3._callbacks[data._id]; + } + } +} + +module.exports = web3; + },{}],6:[function(require,module,exports){ -var QtProvider=function(){this.handlers=[];var self=this;navigator.qt.onmessage=function(message){self.handlers.forEach(function(handler){handler.call(self,JSON.parse(message.data))})}};QtProvider.prototype.send=function(payload){navigator.qt.postMessage(JSON.stringify(payload))},Object.defineProperty(QtProvider.prototype,"onmessage",{set:function(handler){this.handlers.push(handler)}}),module.exports=QtProvider; +/* + This file is part of ethereum.js. + + ethereum.js is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ethereum.js is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with ethereum.js. If not, see . +*/ +/** @file qt.js + * @authors: + * Jeffrey Wilcke + * Marek Kotewicz + * @date 2014 + */ + +var QtProvider = function() { + this.handlers = []; + + var self = this; + navigator.qt.onmessage = function (message) { + self.handlers.forEach(function (handler) { + handler.call(self, JSON.parse(message.data)); + }); + }; +}; + +QtProvider.prototype.send = function(payload) { + navigator.qt.postMessage(JSON.stringify(payload)); +}; + +Object.defineProperty(QtProvider.prototype, "onmessage", { + set: function(handler) { + this.handlers.push(handler); + } +}); + +module.exports = QtProvider; + },{}],7:[function(require,module,exports){ -var WebSocketProvider=function(host){this.handlers=[],this.queued=[],this.ready=!1,this.ws=new WebSocket(host);var self=this;this.ws.onmessage=function(event){for(var i=0;i. +*/ +/** @file websocket.js + * @authors: + * Jeffrey Wilcke + * Marek Kotewicz + * Marian Oancea + * @date 2014 + */ + +// TODO: is these line is supposed to be here? +if ("build" !== 'build') {/* + var WebSocket = require('ws'); // jshint ignore:line +*/} + +var WebSocketProvider = function(host) { + // onmessage handlers + this.handlers = []; + // queue will be filled with messages if send is invoked before the ws is ready + this.queued = []; + this.ready = false; + + this.ws = new WebSocket(host); + + var self = this; + this.ws.onmessage = function(event) { + for(var i = 0; i < self.handlers.length; i++) { + self.handlers[i].call(self, JSON.parse(event.data), event); + } + }; + + this.ws.onopen = function() { + self.ready = true; + + for(var i = 0; i < self.queued.length; i++) { + // Resend + self.send(self.queued[i]); + } + }; +}; + +WebSocketProvider.prototype.send = function(payload) { + if(this.ready) { + var data = JSON.stringify(payload); + + this.ws.send(data); + } else { + this.queued.push(payload); + } +}; + +WebSocketProvider.prototype.onMessage = function(handler) { + this.handlers.push(handler); +}; + +WebSocketProvider.prototype.unload = function() { + this.ws.close(); +}; +Object.defineProperty(WebSocketProvider.prototype, "onmessage", { + set: function(provider) { this.onMessage(provider); } +}); + +module.exports = WebSocketProvider; + },{}],"web3":[function(require,module,exports){ -var web3=require("./lib/main");web3.providers.WebSocketProvider=require("./lib/websocket"),web3.providers.HttpRpcProvider=require("./lib/httprpc"),web3.providers.QtProvider=require("./lib/qt"),web3.providers.AutoProvider=require("./lib/autoprovider"),web3.contract=require("./lib/contract"),module.exports=web3; +var web3 = require('./lib/main'); +web3.providers.WebSocketProvider = require('./lib/websocket'); +web3.providers.HttpRpcProvider = require('./lib/httprpc'); +web3.providers.QtProvider = require('./lib/qt'); +web3.providers.AutoProvider = require('./lib/autoprovider'); +web3.contract = require('./lib/contract'); + +module.exports = web3; + },{"./lib/autoprovider":2,"./lib/contract":3,"./lib/httprpc":4,"./lib/main":5,"./lib/qt":6,"./lib/websocket":7}]},{},["web3"]) diff --git a/dist/ethereum.js.map b/dist/ethereum.js.map index f15143fac..b54a294d7 100644 --- a/dist/ethereum.js.map +++ b/dist/ethereum.js.map @@ -12,18 +12,18 @@ "index.js" ], "names": [], - "mappings": "AAAA;ACAA;;ACAA;;ACAA;;ACAA;;ACAA;;ACAA;;ACAA;;ACAA", + "mappings": "AAAA;ACAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACzQA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACtGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACjEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC9FA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC5fA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC7CA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC7EA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA", "file": "generated.js", "sourceRoot": "", "sourcesContent": [ "(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require==\"function\"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error(\"Cannot find module '\"+o+\"'\");throw f.code=\"MODULE_NOT_FOUND\",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require==\"function\"&&require;for(var o=0;oi;i++)padding+=sizes[i]/8;return padding},setupInputTypes=function(){var prefixedType=function(prefix,calcPadding){return function(type,value){var padding,expected=prefix;return 0!==type.indexOf(expected)?!1:(padding=calcPadding(type,expected),value=\"number\"==typeof value?value.toString(16):\"string\"==typeof value?web3.toHex(value):0===value.indexOf(\"0x\")?value.substr(2):(+value).toString(16),padLeft(value,2*padding))}},namedType=function(name,padding,formatter){return function(type,value){return type!==name?!1:padLeft(formatter?formatter(value):value,2*padding)}},formatBool=function(value){return value?\"0x1\":\"0x0\"};return[prefixedType(\"uint\",calcBitPadding),prefixedType(\"int\",calcBitPadding),prefixedType(\"hash\",calcBitPadding),prefixedType(\"string\",calcBytePadding),prefixedType(\"real\",calcRealPadding),prefixedType(\"ureal\",calcRealPadding),namedType(\"address\",20),namedType(\"bool\",1,formatBool)]},inputTypes=setupInputTypes(),toAbiInput=function(json,methodName,params){var method,i,found,j,bytes=\"\",index=findMethodIndex(json,methodName);if(-1!==index){for(bytes=\"0x\"+padLeft(index.toString(16),2),method=json[index],i=0;ii&&(code=hex.charCodeAt(i),0!==code);i+=2)str+=String.fromCharCode(parseInt(hex.substr(i,2),16));return str},fromAscii:function(str,pad){pad=void 0===pad?32:pad;for(var hex=this.toHex(str);hex.length<2*pad;)hex+=\"00\";return\"0x\"+hex},toDecimal:function(val){return hexToDec(val.substring(2))},fromDecimal:function(val){return\"0x\"+decToHex(val)},toEth:function(str){for(var s,replaceFunction,o,val=\"string\"==typeof str?0===str.indexOf(\"0x\")?parseInt(str.substr(2),16):parseInt(str):str,unit=0,units=[\"wei\",\"Kwei\",\"Mwei\",\"Gwei\",\"szabo\",\"finney\",\"ether\",\"grand\",\"Mether\",\"Gether\",\"Tether\",\"Pether\",\"Eether\",\"Zether\",\"Yether\",\"Nether\",\"Dether\",\"Vether\",\"Uether\"];val>3e3&&unit.\n*/\n/** @file abi.js\n * @authors:\n * Marek Kotewicz \n * Gav Wood \n * @date 2014\n */\n\n// TODO: is these line is supposed to be here? \nif (\"build\" !== 'build') {/*\n var web3 = require('./web3'); // jshint ignore:line\n*/}\n\n// TODO: make these be actually accurate instead of falling back onto JS's doubles.\nvar hexToDec = function (hex) {\n return parseInt(hex, 16).toString();\n};\n\nvar decToHex = function (dec) {\n return parseInt(dec).toString(16);\n};\n\nvar findIndex = function (array, callback) {\n var end = false;\n var i = 0;\n for (; i < array.length && !end; i++) {\n end = callback(array[i]);\n }\n return end ? i - 1 : -1;\n};\n\nvar findMethodIndex = function (json, methodName) {\n return findIndex(json, function (method) {\n return method.name === methodName;\n });\n};\n\nvar padLeft = function (string, chars) {\n return new Array(chars - string.length + 1).join(\"0\") + string;\n};\n\nvar calcBitPadding = function (type, expected) {\n var value = type.slice(expected.length);\n if (value === \"\") {\n return 32;\n }\n return parseInt(value) / 8;\n};\n\nvar calcBytePadding = function (type, expected) {\n var value = type.slice(expected.length);\n if (value === \"\") {\n return 32;\n }\n return parseInt(value);\n};\n\nvar calcRealPadding = function (type, expected) {\n var value = type.slice(expected.length);\n if (value === \"\") {\n return 32;\n }\n var sizes = value.split('x');\n for (var padding = 0, i = 0; i < sizes; i++) {\n padding += (sizes[i] / 8);\n }\n return padding;\n};\n\nvar setupInputTypes = function () {\n \n var prefixedType = function (prefix, calcPadding) {\n return function (type, value) {\n var expected = prefix;\n if (type.indexOf(expected) !== 0) {\n return false;\n }\n\n var padding = calcPadding(type, expected);\n if (typeof value === \"number\")\n value = value.toString(16);\n else if (typeof value === \"string\")\n value = web3.toHex(value); \n else if (value.indexOf('0x') === 0)\n value = value.substr(2);\n else\n value = (+value).toString(16);\n return padLeft(value, padding * 2);\n };\n };\n\n var namedType = function (name, padding, formatter) {\n return function (type, value) {\n if (type !== name) {\n return false;\n }\n\n return padLeft(formatter ? formatter(value) : value, padding * 2);\n };\n };\n\n var formatBool = function (value) {\n return value ? '0x1' : '0x0';\n };\n\n return [\n prefixedType('uint', calcBitPadding),\n prefixedType('int', calcBitPadding),\n prefixedType('hash', calcBitPadding),\n prefixedType('string', calcBytePadding),\n prefixedType('real', calcRealPadding),\n prefixedType('ureal', calcRealPadding),\n namedType('address', 20),\n namedType('bool', 1, formatBool),\n ];\n};\n\nvar inputTypes = setupInputTypes();\n\nvar toAbiInput = function (json, methodName, params) {\n var bytes = \"\";\n var index = findMethodIndex(json, methodName);\n\n if (index === -1) {\n return;\n }\n\n bytes = \"0x\" + padLeft(index.toString(16), 2);\n var method = json[index];\n\n for (var i = 0; i < method.inputs.length; i++) {\n var found = false;\n for (var j = 0; j < inputTypes.length && !found; j++) {\n found = inputTypes[j](method.inputs[i].type, params[i]);\n }\n if (!found) {\n console.error('unsupported json type: ' + method.inputs[i].type);\n }\n bytes += found;\n }\n return bytes;\n};\n\nvar setupOutputTypes = function () {\n\n var prefixedType = function (prefix, calcPadding) {\n return function (type) {\n var expected = prefix;\n if (type.indexOf(expected) !== 0) {\n return -1;\n }\n\n var padding = calcPadding(type, expected);\n return padding * 2;\n };\n };\n\n var namedType = function (name, padding) {\n return function (type) {\n return name === type ? padding * 2 : -1;\n };\n };\n\n var formatInt = function (value) {\n return value.length <= 8 ? +parseInt(value, 16) : hexToDec(value);\n };\n\n var formatHash = function (value) {\n return \"0x\" + value;\n };\n\n var formatBool = function (value) {\n return value === '1' ? true : false;\n };\n\n var formatString = function (value) {\n return web3.toAscii(value);\n };\n\n return [\n { padding: prefixedType('uint', calcBitPadding), format: formatInt },\n { padding: prefixedType('int', calcBitPadding), format: formatInt },\n { padding: prefixedType('hash', calcBitPadding), format: formatHash },\n { padding: prefixedType('string', calcBytePadding), format: formatString },\n { padding: prefixedType('real', calcRealPadding), format: formatInt },\n { padding: prefixedType('ureal', calcRealPadding), format: formatInt },\n { padding: namedType('address', 20) },\n { padding: namedType('bool', 1), format: formatBool }\n ];\n};\n\nvar outputTypes = setupOutputTypes();\n\nvar fromAbiOutput = function (json, methodName, output) {\n var index = findMethodIndex(json, methodName);\n\n if (index === -1) {\n return;\n }\n\n output = output.slice(2);\n\n var result = [];\n var method = json[index];\n for (var i = 0; i < method.outputs.length; i++) {\n var padding = -1;\n for (var j = 0; j < outputTypes.length && padding === -1; j++) {\n padding = outputTypes[j].padding(method.outputs[i].type);\n }\n\n if (padding === -1) {\n // not found output parsing\n continue;\n }\n var res = output.slice(0, padding);\n var formatter = outputTypes[j - 1].format;\n result.push(formatter ? formatter(res) : (\"0x\" + res));\n output = output.slice(padding);\n }\n\n return result;\n};\n\nvar inputParser = function (json) {\n var parser = {};\n json.forEach(function (method) {\n parser[method.name] = function () {\n var params = Array.prototype.slice.call(arguments);\n return toAbiInput(json, method.name, params);\n };\n });\n\n return parser;\n};\n\nvar outputParser = function (json) {\n var parser = {};\n json.forEach(function (method) {\n parser[method.name] = function (output) {\n return fromAbiOutput(json, method.name, output);\n };\n });\n\n return parser;\n};\n\nmodule.exports = {\n inputParser: inputParser,\n outputParser: outputParser\n};\n", + "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file autoprovider.js\n * @authors:\n * Marek Kotewicz \n * Marian Oancea \n * @date 2014\n */\n\n/*\n * @brief if qt object is available, uses QtProvider,\n * if not tries to connect over websockets\n * if it fails, it uses HttpRpcProvider\n */\n\n// TODO: is these line is supposed to be here? \nif (\"build\" !== 'build') {/*\n var WebSocket = require('ws'); // jshint ignore:line\n var web3 = require('./main.js'); // jshint ignore:line\n*/}\n\nvar AutoProvider = function (userOptions) {\n if (web3.haveProvider()) {\n return;\n }\n\n // before we determine what provider we are, we have to cache request\n this.sendQueue = [];\n this.onmessageQueue = [];\n\n if (navigator.qt) {\n this.provider = new web3.providers.QtProvider();\n return;\n }\n\n userOptions = userOptions || {};\n var options = {\n httprpc: userOptions.httprpc || 'http://localhost:8080',\n websockets: userOptions.websockets || 'ws://localhost:40404/eth'\n };\n\n var self = this;\n var closeWithSuccess = function (success) {\n ws.close();\n if (success) {\n self.provider = new web3.providers.WebSocketProvider(options.websockets);\n } else {\n self.provider = new web3.providers.HttpRpcProvider(options.httprpc);\n self.poll = self.provider.poll.bind(self.provider);\n }\n self.sendQueue.forEach(function (payload) {\n self.provider(payload);\n });\n self.onmessageQueue.forEach(function (handler) {\n self.provider.onmessage = handler;\n });\n };\n\n var ws = new WebSocket(options.websockets);\n\n ws.onopen = function() {\n closeWithSuccess(true);\n };\n\n ws.onerror = function() {\n closeWithSuccess(false);\n };\n};\n\nAutoProvider.prototype.send = function (payload) {\n if (this.provider) {\n this.provider.send(payload);\n return;\n }\n this.sendQueue.push(payload);\n};\n\nObject.defineProperty(AutoProvider.prototype, 'onmessage', {\n set: function (handler) {\n if (this.provider) {\n this.provider.onmessage = handler;\n return;\n }\n this.onmessageQueue.push(handler);\n }\n});\n\nmodule.exports = AutoProvider;\n", + "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file contract.js\n * @authors:\n * Marek Kotewicz \n * @date 2014\n */\n\n// TODO: is these line is supposed to be here? \nif (\"build\" !== 'build') {/*\n var web3 = require('./web3'); // jshint ignore:line\n*/}\n\nvar abi = require('./abi');\n\nvar contract = function (address, desc) {\n var inputParser = abi.inputParser(desc);\n var outputParser = abi.outputParser(desc);\n\n var contract = {};\n\n desc.forEach(function (method) {\n contract[method.name] = function () {\n var params = Array.prototype.slice.call(arguments);\n var parsed = inputParser[method.name].apply(null, params);\n\n var onSuccess = function (result) {\n return outputParser[method.name](result);\n };\n\n return {\n call: function (extra) {\n extra = extra || {};\n extra.to = address;\n extra.data = parsed;\n return web3.eth.call(extra).then(onSuccess);\n },\n transact: function (extra) {\n extra = extra || {};\n extra.to = address;\n extra.data = parsed;\n return web3.eth.transact(extra).then(onSuccess);\n }\n };\n };\n });\n\n return contract;\n};\n\nmodule.exports = contract;\n", + "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file httprpc.js\n * @authors:\n * Marek Kotewicz \n * Marian Oancea \n * @date 2014\n */\n\n// TODO: is these line is supposed to be here? \nif (\"build\" !== 'build') {/*\n var XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest; // jshint ignore:line\n*/}\n\nvar HttpRpcProvider = function (host) {\n this.handlers = [];\n this.host = host;\n};\n\nfunction formatJsonRpcObject(object) {\n return {\n jsonrpc: '2.0',\n method: object.call,\n params: object.args,\n id: object._id\n };\n}\n\nfunction formatJsonRpcMessage(message) {\n var object = JSON.parse(message);\n\n return {\n _id: object.id,\n data: object.result,\n error: object.error\n };\n}\n\nHttpRpcProvider.prototype.sendRequest = function (payload, cb) {\n var data = formatJsonRpcObject(payload);\n\n var request = new XMLHttpRequest();\n request.open(\"POST\", this.host, true);\n request.send(JSON.stringify(data));\n request.onreadystatechange = function () {\n if (request.readyState === 4 && cb) {\n cb(request);\n }\n };\n};\n\nHttpRpcProvider.prototype.send = function (payload) {\n var self = this;\n this.sendRequest(payload, function (request) {\n self.handlers.forEach(function (handler) {\n handler.call(self, formatJsonRpcMessage(request.responseText));\n });\n });\n};\n\nHttpRpcProvider.prototype.poll = function (payload, id) {\n var self = this;\n this.sendRequest(payload, function (request) {\n var parsed = JSON.parse(request.responseText);\n if (parsed.error || (parsed.result instanceof Array ? parsed.result.length === 0 : !parsed.result)) {\n return;\n }\n self.handlers.forEach(function (handler) {\n handler.call(self, {_event: payload.call, _id: id, data: parsed.result});\n });\n });\n};\n\nObject.defineProperty(HttpRpcProvider.prototype, \"onmessage\", {\n set: function (handler) {\n this.handlers.push(handler);\n }\n});\n\nmodule.exports = HttpRpcProvider;\n", + "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file main.js\n * @authors:\n * Jeffrey Wilcke \n * Marek Kotewicz \n * Marian Oancea \n * Gav Wood \n * @date 2014\n */\n\nfunction flattenPromise (obj) {\n if (obj instanceof Promise) {\n return Promise.resolve(obj);\n }\n\n if (obj instanceof Array) {\n return new Promise(function (resolve) {\n var promises = obj.map(function (o) {\n return flattenPromise(o);\n });\n\n return Promise.all(promises).then(function (res) {\n for (var i = 0; i < obj.length; i++) {\n obj[i] = res[i];\n }\n resolve(obj);\n });\n });\n }\n\n if (obj instanceof Object) {\n return new Promise(function (resolve) {\n var keys = Object.keys(obj);\n var promises = keys.map(function (key) {\n return flattenPromise(obj[key]);\n });\n\n return Promise.all(promises).then(function (res) {\n for (var i = 0; i < keys.length; i++) {\n obj[keys[i]] = res[i];\n }\n resolve(obj);\n });\n });\n }\n\n return Promise.resolve(obj);\n}\n\nvar web3Methods = function () {\n return [\n { name: 'sha3', call: 'web3_sha3' }\n ];\n};\n\nvar ethMethods = function () {\n var blockCall = function (args) {\n return typeof args[0] === \"string\" ? \"eth_blockByHash\" : \"eth_blockByNumber\";\n };\n\n var transactionCall = function (args) {\n return typeof args[0] === \"string\" ? 'eth_transactionByHash' : 'eth_transactionByNumber';\n };\n\n var uncleCall = function (args) {\n return typeof args[0] === \"string\" ? 'eth_uncleByHash' : 'eth_uncleByNumber';\n };\n\n var methods = [\n { name: 'balanceAt', call: 'eth_balanceAt' },\n { name: 'stateAt', call: 'eth_stateAt' },\n { name: 'storageAt', call: 'eth_storageAt' },\n { name: 'countAt', call: 'eth_countAt'},\n { name: 'codeAt', call: 'eth_codeAt' },\n { name: 'transact', call: 'eth_transact' },\n { name: 'call', call: 'eth_call' },\n { name: 'block', call: blockCall },\n { name: 'transaction', call: transactionCall },\n { name: 'uncle', call: uncleCall },\n { name: 'compilers', call: 'eth_compilers' },\n { name: 'lll', call: 'eth_lll' },\n { name: 'solidity', call: 'eth_solidity' },\n { name: 'serpent', call: 'eth_serpent' },\n { name: 'logs', call: 'eth_logs' }\n ];\n return methods;\n};\n\nvar ethProperties = function () {\n return [\n { name: 'coinbase', getter: 'eth_coinbase', setter: 'eth_setCoinbase' },\n { name: 'listening', getter: 'eth_listening', setter: 'eth_setListening' },\n { name: 'mining', getter: 'eth_mining', setter: 'eth_setMining' },\n { name: 'gasPrice', getter: 'eth_gasPrice' },\n { name: 'account', getter: 'eth_account' },\n { name: 'accounts', getter: 'eth_accounts' },\n { name: 'peerCount', getter: 'eth_peerCount' },\n { name: 'defaultBlock', getter: 'eth_defaultBlock', setter: 'eth_setDefaultBlock' },\n { name: 'number', getter: 'eth_number'}\n ];\n};\n\nvar dbMethods = function () {\n return [\n { name: 'put', call: 'db_put' },\n { name: 'get', call: 'db_get' },\n { name: 'putString', call: 'db_putString' },\n { name: 'getString', call: 'db_getString' }\n ];\n};\n\nvar shhMethods = function () {\n return [\n { name: 'post', call: 'shh_post' },\n { name: 'newIdentity', call: 'shh_newIdentity' },\n { name: 'haveIdentity', call: 'shh_haveIdentity' },\n { name: 'newGroup', call: 'shh_newGroup' },\n { name: 'addToGroup', call: 'shh_addToGroup' }\n ];\n};\n\nvar ethWatchMethods = function () {\n var newFilter = function (args) {\n return typeof args[0] === 'string' ? 'eth_newFilterString' : 'eth_newFilter';\n };\n\n return [\n { name: 'newFilter', call: newFilter },\n { name: 'uninstallFilter', call: 'eth_uninstallFilter' },\n { name: 'getMessages', call: 'eth_filterLogs' }\n ];\n};\n\nvar shhWatchMethods = function () {\n return [\n { name: 'newFilter', call: 'shh_newFilter' },\n { name: 'uninstallFilter', call: 'shh_uninstallFilter' },\n { name: 'getMessage', call: 'shh_getMessages' }\n ];\n};\n\nvar setupMethods = function (obj, methods) {\n methods.forEach(function (method) {\n obj[method.name] = function () {\n return flattenPromise(Array.prototype.slice.call(arguments)).then(function (args) {\n var call = typeof method.call === \"function\" ? method.call(args) : method.call;\n return {call: call, args: args};\n }).then(function (request) {\n return new Promise(function (resolve, reject) {\n web3.provider.send(request, function (err, result) {\n if (!err) {\n resolve(result);\n return;\n }\n reject(err);\n });\n });\n }).catch(function(err) {\n console.error(err);\n });\n };\n });\n};\n\nvar setupProperties = function (obj, properties) {\n properties.forEach(function (property) {\n var proto = {};\n proto.get = function () {\n return new Promise(function(resolve, reject) {\n web3.provider.send({call: property.getter}, function(err, result) {\n if (!err) {\n resolve(result);\n return;\n }\n reject(err);\n });\n });\n };\n if (property.setter) {\n proto.set = function (val) {\n return flattenPromise([val]).then(function (args) {\n return new Promise(function (resolve) {\n web3.provider.send({call: property.setter, args: args}, function (err, result) {\n if (!err) {\n resolve(result);\n return;\n }\n reject(err);\n });\n });\n }).catch(function (err) {\n console.error(err);\n });\n };\n }\n Object.defineProperty(obj, property.name, proto);\n });\n};\n\n// TODO: import from a dependency, don't duplicate.\nvar hexToDec = function (hex) {\n return parseInt(hex, 16).toString();\n};\n\nvar decToHex = function (dec) {\n return parseInt(dec).toString(16);\n};\n\n\nvar web3 = {\n _callbacks: {},\n _events: {},\n providers: {},\n\n toHex: function(str) {\n var hex = \"\";\n for(var i = 0; i < str.length; i++) {\n var n = str.charCodeAt(i).toString(16);\n hex += n.length < 2 ? '0' + n : n;\n }\n\n return hex;\n },\n\n toAscii: function(hex) {\n // Find termination\n var str = \"\";\n var i = 0, l = hex.length;\n if (hex.substring(0, 2) === '0x')\n i = 2;\n for(; i < l; i+=2) {\n var code = hex.charCodeAt(i);\n if(code === 0) {\n break;\n }\n\n str += String.fromCharCode(parseInt(hex.substr(i, 2), 16));\n }\n\n return str;\n },\n\n fromAscii: function(str, pad) {\n pad = pad === undefined ? 32 : pad;\n var hex = this.toHex(str);\n while(hex.length < pad*2)\n hex += \"00\";\n return \"0x\" + hex;\n },\n\n toDecimal: function (val) {\n return hexToDec(val.substring(2));\n },\n\n fromDecimal: function (val) {\n return \"0x\" + decToHex(val);\n },\n\n toEth: function(str) {\n var val = typeof str === \"string\" ? str.indexOf('0x') === 0 ? parseInt(str.substr(2), 16) : parseInt(str) : str;\n var unit = 0;\n var units = [ 'wei', 'Kwei', 'Mwei', 'Gwei', 'szabo', 'finney', 'ether', 'grand', 'Mether', 'Gether', 'Tether', 'Pether', 'Eether', 'Zether', 'Yether', 'Nether', 'Dether', 'Vether', 'Uether' ];\n while (val > 3000 && unit < units.length - 1)\n {\n val /= 1000;\n unit++;\n }\n var s = val.toString().length < val.toFixed(2).length ? val.toString() : val.toFixed(2);\n var replaceFunction = function($0, $1, $2) {\n return $1 + ',' + $2;\n };\n\n while (true) {\n var o = s;\n s = s.replace(/(\\d)(\\d\\d\\d[\\.\\,])/, replaceFunction);\n if (o === s)\n break;\n }\n return s + ' ' + units[unit];\n },\n\n eth: {\n prototype: Object(), // jshint ignore:line\n watch: function (params) {\n return new Filter(params, ethWatch);\n }\n },\n\n db: {\n prototype: Object() // jshint ignore:line\n },\n\n shh: {\n prototype: Object(), // jshint ignore:line\n watch: function (params) {\n return new Filter(params, shhWatch);\n }\n },\n\n on: function(event, id, cb) {\n if(web3._events[event] === undefined) {\n web3._events[event] = {};\n }\n\n web3._events[event][id] = cb;\n return this;\n },\n\n off: function(event, id) {\n if(web3._events[event] !== undefined) {\n delete web3._events[event][id];\n }\n\n return this;\n },\n\n trigger: function(event, id, data) {\n var callbacks = web3._events[event];\n if (!callbacks || !callbacks[id]) {\n return;\n }\n var cb = callbacks[id];\n cb(data);\n }\n};\n\nsetupMethods(web3, web3Methods());\nsetupMethods(web3.eth, ethMethods());\nsetupProperties(web3.eth, ethProperties());\nsetupMethods(web3.db, dbMethods());\nsetupMethods(web3.shh, shhMethods());\n\nvar ethWatch = {\n changed: 'eth_changed'\n};\nsetupMethods(ethWatch, ethWatchMethods());\nvar shhWatch = {\n changed: 'shh_changed'\n};\nsetupMethods(shhWatch, shhWatchMethods());\n\nvar ProviderManager = function() {\n this.queued = [];\n this.polls = [];\n this.ready = false;\n this.provider = undefined;\n this.id = 1;\n\n var self = this;\n var poll = function () {\n if (self.provider && self.provider.poll) {\n self.polls.forEach(function (data) {\n data.data._id = self.id;\n self.id++;\n self.provider.poll(data.data, data.id);\n });\n }\n setTimeout(poll, 12000);\n };\n poll();\n};\n\nProviderManager.prototype.send = function(data, cb) {\n data._id = this.id;\n if (cb) {\n web3._callbacks[data._id] = cb;\n }\n\n data.args = data.args || [];\n this.id++;\n\n if(this.provider !== undefined) {\n this.provider.send(data);\n } else {\n console.warn(\"provider is not set\");\n this.queued.push(data);\n }\n};\n\nProviderManager.prototype.set = function(provider) {\n if(this.provider !== undefined && this.provider.unload !== undefined) {\n this.provider.unload();\n }\n\n this.provider = provider;\n this.ready = true;\n};\n\nProviderManager.prototype.sendQueued = function() {\n for(var i = 0; this.queued.length; i++) {\n // Resend\n this.send(this.queued[i]);\n }\n};\n\nProviderManager.prototype.installed = function() {\n return this.provider !== undefined;\n};\n\nProviderManager.prototype.startPolling = function (data, pollId) {\n if (!this.provider || !this.provider.poll) {\n return;\n }\n this.polls.push({data: data, id: pollId});\n};\n\nProviderManager.prototype.stopPolling = function (pollId) {\n for (var i = this.polls.length; i--;) {\n var poll = this.polls[i];\n if (poll.id === pollId) {\n this.polls.splice(i, 1);\n }\n }\n};\n\nweb3.provider = new ProviderManager();\n\nweb3.setProvider = function(provider) {\n provider.onmessage = messageHandler;\n web3.provider.set(provider);\n web3.provider.sendQueued();\n};\n\nweb3.haveProvider = function() {\n return !!web3.provider.provider;\n};\n\nvar Filter = function(options, impl) {\n this.impl = impl;\n this.callbacks = [];\n\n var self = this;\n this.promise = impl.newFilter(options);\n this.promise.then(function (id) {\n self.id = id;\n web3.on(impl.changed, id, self.trigger.bind(self));\n web3.provider.startPolling({call: impl.changed, args: [id]}, id);\n });\n};\n\nFilter.prototype.arrived = function(callback) {\n this.changed(callback);\n};\n\nFilter.prototype.changed = function(callback) {\n var self = this;\n this.promise.then(function(id) {\n self.callbacks.push(callback);\n });\n};\n\nFilter.prototype.trigger = function(messages) {\n for(var i = 0; i < this.callbacks.length; i++) {\n this.callbacks[i].call(this, messages);\n }\n};\n\nFilter.prototype.uninstall = function() {\n var self = this;\n this.promise.then(function (id) {\n self.impl.uninstallFilter(id);\n web3.provider.stopPolling(id);\n web3.off(impl.changed, id);\n });\n};\n\nFilter.prototype.messages = function() {\n var self = this;\n return this.promise.then(function (id) {\n return self.impl.getMessages(id);\n });\n};\n\nFilter.prototype.logs = function () {\n return this.messages();\n};\n\nfunction messageHandler(data) {\n if(data._event !== undefined) {\n web3.trigger(data._event, data._id, data.data);\n return;\n }\n\n if(data._id) {\n var cb = web3._callbacks[data._id];\n if (cb) {\n cb.call(this, data.error, data.data);\n delete web3._callbacks[data._id];\n }\n }\n}\n\nmodule.exports = web3;\n", + "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file qt.js\n * @authors:\n * Jeffrey Wilcke \n * Marek Kotewicz \n * @date 2014\n */\n\nvar QtProvider = function() {\n this.handlers = [];\n\n var self = this;\n navigator.qt.onmessage = function (message) {\n self.handlers.forEach(function (handler) {\n handler.call(self, JSON.parse(message.data));\n });\n };\n};\n\nQtProvider.prototype.send = function(payload) {\n navigator.qt.postMessage(JSON.stringify(payload));\n};\n\nObject.defineProperty(QtProvider.prototype, \"onmessage\", {\n set: function(handler) {\n this.handlers.push(handler);\n }\n});\n\nmodule.exports = QtProvider;\n", + "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file websocket.js\n * @authors:\n * Jeffrey Wilcke \n * Marek Kotewicz \n * Marian Oancea \n * @date 2014\n */\n\n// TODO: is these line is supposed to be here? \nif (\"build\" !== 'build') {/*\n var WebSocket = require('ws'); // jshint ignore:line\n*/}\n\nvar WebSocketProvider = function(host) {\n // onmessage handlers\n this.handlers = [];\n // queue will be filled with messages if send is invoked before the ws is ready\n this.queued = [];\n this.ready = false;\n\n this.ws = new WebSocket(host);\n\n var self = this;\n this.ws.onmessage = function(event) {\n for(var i = 0; i < self.handlers.length; i++) {\n self.handlers[i].call(self, JSON.parse(event.data), event);\n }\n };\n\n this.ws.onopen = function() {\n self.ready = true;\n\n for(var i = 0; i < self.queued.length; i++) {\n // Resend\n self.send(self.queued[i]);\n }\n };\n};\n\nWebSocketProvider.prototype.send = function(payload) {\n if(this.ready) {\n var data = JSON.stringify(payload);\n\n this.ws.send(data);\n } else {\n this.queued.push(payload);\n }\n};\n\nWebSocketProvider.prototype.onMessage = function(handler) {\n this.handlers.push(handler);\n};\n\nWebSocketProvider.prototype.unload = function() {\n this.ws.close();\n};\nObject.defineProperty(WebSocketProvider.prototype, \"onmessage\", {\n set: function(provider) { this.onMessage(provider); }\n});\n\nmodule.exports = WebSocketProvider;\n", + "var web3 = require('./lib/main');\nweb3.providers.WebSocketProvider = require('./lib/websocket');\nweb3.providers.HttpRpcProvider = require('./lib/httprpc');\nweb3.providers.QtProvider = require('./lib/qt');\nweb3.providers.AutoProvider = require('./lib/autoprovider');\nweb3.contract = require('./lib/contract');\n\nmodule.exports = web3;\n" ] } \ No newline at end of file diff --git a/dist/ethereum.min.js b/dist/ethereum.min.js index b1ecdfb83..f9eac6a9d 100644 --- a/dist/ethereum.min.js +++ b/dist/ethereum.min.js @@ -1 +1 @@ -require=function t(e,n,r){function o(s,a){if(!n[s]){if(!e[s]){var u="function"==typeof require&&require;if(!a&&u)return u(s,!0);if(i)return i(s,!0);var c=new Error("Cannot find module '"+s+"'");throw c.code="MODULE_NOT_FOUND",c}var l=n[s]={exports:{}};e[s][0].call(l.exports,function(t){var n=e[s][1][t];return o(n?n:t)},l,l.exports,t,e,n,r)}return n[s].exports}for(var i="function"==typeof require&&require,s=0;so;o++)r+=n[o]/8;return r},l=function(){var t=function(t,e){return function(n,r){var o,i=t;return 0!==n.indexOf(i)?!1:(o=e(n,i),r="number"==typeof r?r.toString(16):"string"==typeof r?web3.toHex(r):0===r.indexOf("0x")?r.substr(2):(+r).toString(16),s(r,2*o))}},e=function(t,e,n){return function(r,o){return r!==t?!1:s(n?n(o):o,2*e)}},n=function(t){return t?"0x1":"0x0"};return[t("uint",a),t("int",a),t("hash",a),t("string",u),t("real",c),t("ureal",c),e("address",20),e("bool",1,n)]},h=l(),p=function(t,e,n){var r,o,a,u,c="",l=i(t,e);if(-1!==l){for(c="0x"+s(l.toString(16),2),r=t[l],o=0;or&&(e=t.charCodeAt(r),0!==e);r+=2)n+=String.fromCharCode(parseInt(t.substr(r,2),16));return n},fromAscii:function(t,e){e=void 0===e?32:e;for(var n=this.toHex(t);n.length<2*e;)n+="00";return"0x"+n},toDecimal:function(t){return m(t.substring(2))},fromDecimal:function(t){return"0x"+b(t)},toEth:function(t){for(var e,n,r,o="string"==typeof t?0===t.indexOf("0x")?parseInt(t.substr(2),16):parseInt(t):t,i=0,s=["wei","Kwei","Mwei","Gwei","szabo","finney","ether","grand","Mether","Gether","Tether","Pether","Eether","Zether","Yether","Nether","Dether","Vether","Uether"];o>3e3&&ii;i++)o+=r[i]/8;return o},c=function(){var t=function(t,e){return function(n,r){var o=t;if(0!==n.indexOf(o))return!1;var a=e(n,o);return r="number"==typeof r?r.toString(16):"string"==typeof r?web3.toHex(r):0===r.indexOf("0x")?r.substr(2):(+r).toString(16),i(r,2*a)}},e=function(t,e,n){return function(r,o){return r!==t?!1:i(n?n(o):o,2*e)}},n=function(t){return t?"0x1":"0x0"};return[t("uint",a),t("int",a),t("hash",a),t("string",s),t("real",u),t("ureal",u),e("address",20),e("bool",1,n)]},l=c(),h=function(t,e,n){var r="",a=o(t,e);if(-1!==a){r="0x"+i(a.toString(16),2);for(var s=t[a],u=0;un;n+=2){var o=t.charCodeAt(n);if(0===o)break;e+=String.fromCharCode(parseInt(t.substr(n,2),16))}return e},fromAscii:function(t,e){e=void 0===e?32:e;for(var n=this.toHex(t);n.length<2*e;)n+="00";return"0x"+n},toDecimal:function(t){return p(t.substring(2))},fromDecimal:function(t){return"0x"+d(t)},toEth:function(t){for(var e="string"==typeof t?0===t.indexOf("0x")?parseInt(t.substr(2),16):parseInt(t):t,n=0,r=["wei","Kwei","Mwei","Gwei","szabo","finney","ether","grand","Mether","Gether","Tether","Pether","Eether","Zether","Yether","Nether","Dether","Vether","Uether"];e>3e3&&n Date: Wed, 7 Jan 2015 15:37:00 +0100 Subject: [PATCH 105/111] add tests for OOG at max call depth --- test/stSystemOperationsTestFiller.json | 110 +++++++++++++++++++++++++ 1 file changed, 110 insertions(+) diff --git a/test/stSystemOperationsTestFiller.json b/test/stSystemOperationsTestFiller.json index 757c8a235..12f10fde5 100644 --- a/test/stSystemOperationsTestFiller.json +++ b/test/stSystemOperationsTestFiller.json @@ -33,6 +33,40 @@ } }, + "createNameRegistratorOOG_MemExpansionInsufficientBalance": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "10000", + "nonce" : 0, + "code" : "{ (MSTORE 0 0x601080600c6000396000f3006000355415600957005b60203560003555) [[ 0 ]] (CREATE 11000 3 0xffffffffffffffffffffff) }", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "10000", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + "createNameRegistratorZeroMem": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", @@ -314,6 +348,48 @@ } }, + "CallToNameRegistratorMemOOGAndInsufficientBalance": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (MSTORE 32 0xaaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffaa ) [[ 0 ]] (CALL 0xffffffffff 0x945304eb96065b2a98b57a48a06ae28d285a71b5 23 0 0xffffffffffff 64 0) }", + "storage": {} + }, + "945304eb96065b2a98b57a48a06ae28d285a71b5" : { + "balance" : "23", + "code" : "0x6000355415600957005b60203560003555", + "nonce" : "0", + "storage" : { + } + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "", + "storage": {} + } + + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "10000", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + "CallToNameRegistratorAddressTooBigLeft": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", @@ -977,6 +1053,40 @@ } }, + "CallRecursiveBomb0_OOG_atMaxCallDepth": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (+ (SLOAD 0) 1) [[ 2 ]] (MUL (DIV @@0 0x0402) 0xfffffffffffffffffff) [[ 1 ]] (CALL (- (GAS) 1024) (ADDRESS) 0 0 (MUL (DIV @@0 0x0402) 0xfffffffffffffffffff) 0 0) } ", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "1000000000", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + "CallRecursiveBomb1": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", From 0de9e2aebd43a9fe9e4fdac68d1915dcff7f0607 Mon Sep 17 00:00:00 2001 From: Christian Date: Wed, 7 Jan 2015 12:50:23 +0100 Subject: [PATCH 106/111] Bugfix: Use parameter (not argument) type size on stack for function calls. --- libsolidity/ExpressionCompiler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index 6bf14f559..aa7406132 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -217,7 +217,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) unsigned returnParametersSize = CompilerUtils::getSizeOnStack(function.getReturnParameterTypes()); // callee adds return parameters, but removes arguments and return label - m_context.adjustStackOffset(returnParametersSize - CompilerUtils::getSizeOnStack(arguments) - 1); + m_context.adjustStackOffset(returnParametersSize - CompilerUtils::getSizeOnStack(function.getParameterTypes()) - 1); // @todo for now, the return value of a function is its first return value, so remove // all others From c6ae1754b955d50e893bb4f2e453ffd5c6c930e2 Mon Sep 17 00:00:00 2001 From: Christian Date: Wed, 7 Jan 2015 15:41:11 +0100 Subject: [PATCH 107/111] Some changes to the optimizer. --- libevmcore/Assembly.cpp | 9 +++------ test/SolidityOptimizer.cpp | 14 +++++++------- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/libevmcore/Assembly.cpp b/libevmcore/Assembly.cpp index 5efbb9487..fd256d688 100644 --- a/libevmcore/Assembly.cpp +++ b/libevmcore/Assembly.cpp @@ -393,7 +393,6 @@ Assembly& Assembly::optimise(bool _enable) auto rw = r.second(vr); unsigned const vrSize = bytesRequiredBySlice(vr.begin(), vr.end()); unsigned const rwSize = bytesRequiredBySlice(rw.begin(), rw.end()); - //@todo check the actual size (including constant sizes) if (rwSize < vrSize || (rwSize == vrSize && popCountIncreased(vr, rw))) { copt << vr << "matches" << AssemblyItemsConstRef(&r.first) << "becomes..."; @@ -405,12 +404,10 @@ Assembly& Assembly::optimise(bool _enable) m_items.resize(m_items.size() + sizeIncrease, AssemblyItem(UndefinedItem)); move_backward(m_items.begin() + i, m_items.end() - sizeIncrease, m_items.end()); } + else + m_items.erase(m_items.begin() + i + rw.size(), m_items.begin() + i + vr.size()); - for (unsigned j = 0; j < max(rw.size(), vr.size()); ++j) - if (j < rw.size()) - m_items[i + j] = rw[j]; - else - m_items.erase(m_items.begin() + i + rw.size()); + copy(rw.begin(), rw.end(), m_items.begin() + i); count++; copt << "Now:\n" << m_items; diff --git a/test/SolidityOptimizer.cpp b/test/SolidityOptimizer.cpp index ef5c6f9b5..7e06c2e30 100644 --- a/test/SolidityOptimizer.cpp +++ b/test/SolidityOptimizer.cpp @@ -48,7 +48,7 @@ public: m_optimize = true; bytes optimizedBytecode = compileAndRun(_sourceCode, _value, _contractName); int sizeDiff = nonOptimizedBytecode.size() - optimizedBytecode.size(); - BOOST_CHECK_MESSAGE(sizeDiff == int(_expectedSizeDecrease), "Bytecode did only shrink by " + BOOST_CHECK_MESSAGE(sizeDiff == int(_expectedSizeDecrease), "Bytecode shrank by " + boost::lexical_cast(sizeDiff) + " bytes, expected: " + boost::lexical_cast(_expectedSizeDecrease)); m_optimizedContract = m_contractAddress; @@ -91,10 +91,10 @@ BOOST_AUTO_TEST_CASE(large_integers) contract test { function f() returns (uint a, uint b) { a = 0x234234872642837426347000000; - b = 0x110000000000000000000000002; + b = 0x10000000000000000000000002; } })"; - compileBothVersions(28, sourceCode); + compileBothVersions(33, sourceCode); compareVersions(0); } @@ -102,8 +102,8 @@ BOOST_AUTO_TEST_CASE(invariants) { char const* sourceCode = R"( contract test { - function f(uint a) returns (uint b) { - return (((a + (1 - 1)) ^ 0) | 0) & (uint(0) - 1); + function f(int a) returns (int b) { + return int(0) | (int(1) * (int(0) ^ (0 + a))); } })"; compileBothVersions(28, sourceCode); @@ -127,8 +127,8 @@ BOOST_AUTO_TEST_CASE(unused_expressions) BOOST_AUTO_TEST_CASE(constant_folding_both_sides) { // if constants involving the same associative and commutative operator are applied from both - // sides, the operator should be applied only once, because the expression compiler - // (even in non-optimized mode) pushes literals as late as possible + // sides, the operator should be applied only once, because the expression compiler pushes + // literals as late as possible char const* sourceCode = R"( contract test { function f(uint x) returns (uint y) { From 460571bd7732d6829327c51c18c82cd705931345 Mon Sep 17 00:00:00 2001 From: Christian Date: Wed, 7 Jan 2015 16:46:15 +0100 Subject: [PATCH 108/111] Fix some warnings about uninitialized members. --- libsolidity/Compiler.h | 2 +- libsolidity/CompilerStack.h | 2 +- libsolidity/ExpressionCompiler.h | 6 +++--- libsolidity/GlobalContext.h | 2 +- libsolidity/NameAndTypeResolver.h | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/libsolidity/Compiler.h b/libsolidity/Compiler.h index 8471fae2a..e83d1ed3a 100644 --- a/libsolidity/Compiler.h +++ b/libsolidity/Compiler.h @@ -30,7 +30,7 @@ namespace solidity { class Compiler: private ASTConstVisitor { public: - explicit Compiler(bool _optimize = false): m_optimize(_optimize), m_returnTag(m_context.newTag()) {} + explicit Compiler(bool _optimize = false): m_optimize(_optimize), m_context(), m_returnTag(m_context.newTag()) {} void compileContract(ContractDefinition const& _contract, std::vector const& _magicGlobals, std::map const& _contracts); diff --git a/libsolidity/CompilerStack.h b/libsolidity/CompilerStack.h index 358c8fb77..e7143b7bb 100644 --- a/libsolidity/CompilerStack.h +++ b/libsolidity/CompilerStack.h @@ -113,7 +113,7 @@ private: struct Contract { - ContractDefinition const* contract; + ContractDefinition const* contract = nullptr; std::shared_ptr compiler; bytes bytecode; std::shared_ptr interfaceHandler; diff --git a/libsolidity/ExpressionCompiler.h b/libsolidity/ExpressionCompiler.h index 67b16aac0..c0ee4ab48 100644 --- a/libsolidity/ExpressionCompiler.h +++ b/libsolidity/ExpressionCompiler.h @@ -146,12 +146,12 @@ private: private: CompilerContext* m_context; - LValueType m_type; + LValueType m_type = NONE; /// If m_type is STACK, this is base stack offset (@see /// CompilerContext::getBaseStackOffsetOfVariable) of a local variable. - unsigned m_baseStackOffset; + unsigned m_baseStackOffset = 0; /// Size of the value of this lvalue on the stack. - unsigned m_stackSize; + unsigned m_stackSize = 0; }; bool m_optimize; diff --git a/libsolidity/GlobalContext.h b/libsolidity/GlobalContext.h index 50a21f702..c6e35f504 100644 --- a/libsolidity/GlobalContext.h +++ b/libsolidity/GlobalContext.h @@ -56,7 +56,7 @@ public: private: std::vector> m_magicVariables; - ContractDefinition const* m_currentContract; + ContractDefinition const* m_currentContract = nullptr; std::map> mutable m_thisPointer; }; diff --git a/libsolidity/NameAndTypeResolver.h b/libsolidity/NameAndTypeResolver.h index 23ac5fe77..1032a87cf 100644 --- a/libsolidity/NameAndTypeResolver.h +++ b/libsolidity/NameAndTypeResolver.h @@ -69,7 +69,7 @@ private: /// not contain code. std::map m_scopes; - DeclarationContainer* m_currentScope; + DeclarationContainer* m_currentScope = nullptr; }; /** From bf8174ecee66f024bf46ef249dd70967aaeee9d9 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 7 Jan 2015 16:58:09 +0100 Subject: [PATCH 109/111] Warnings fixes. Make Mix work with Qt 5.2 Minor other alterations. --- libevmcore/Assembly.cpp | 6 +++--- libsolidity/Types.h | 3 +++ mix/AssemblyDebuggerModel.cpp | 1 - mix/qml/StateDialog.qml | 2 +- mix/qml/StateList.qml | 6 +++--- mix/qml/TransactionDialog.qml | 2 +- mix/qml/main.qml | 4 ++-- 7 files changed, 13 insertions(+), 11 deletions(-) diff --git a/libevmcore/Assembly.cpp b/libevmcore/Assembly.cpp index fd256d688..f7a71102f 100644 --- a/libevmcore/Assembly.cpp +++ b/libevmcore/Assembly.cpp @@ -391,9 +391,9 @@ Assembly& Assembly::optimise(bool _enable) if (matches(vr, &r.first)) { auto rw = r.second(vr); - unsigned const vrSize = bytesRequiredBySlice(vr.begin(), vr.end()); - unsigned const rwSize = bytesRequiredBySlice(rw.begin(), rw.end()); - if (rwSize < vrSize || (rwSize == vrSize && popCountIncreased(vr, rw))) + unsigned const vrSizeInBytes = bytesRequiredBySlice(vr.begin(), vr.end()); + unsigned const rwSizeInBytes = bytesRequiredBySlice(rw.begin(), rw.end()); + if (rwSizeInBytes < vrSizeInBytes || (rwSizeInBytes == vrSizeInBytes && popCountIncreased(vr, rw))) { copt << vr << "matches" << AssemblyItemsConstRef(&r.first) << "becomes..."; copt << AssemblyItemsConstRef(&rw); diff --git a/libsolidity/Types.h b/libsolidity/Types.h index ff8a48877..6f3ca6abf 100644 --- a/libsolidity/Types.h +++ b/libsolidity/Types.h @@ -387,6 +387,9 @@ public: protected: virtual TypePointer binaryOperatorResultImpl(Token::Value _operator, TypePointer const& _this, TypePointer const& _other) const override { + (void)_operator; + (void)_this; + (void)_other; return TypePointer(); } }; diff --git a/mix/AssemblyDebuggerModel.cpp b/mix/AssemblyDebuggerModel.cpp index d09c2cd18..e822d0a3f 100644 --- a/mix/AssemblyDebuggerModel.cpp +++ b/mix/AssemblyDebuggerModel.cpp @@ -74,7 +74,6 @@ DebuggingContent AssemblyDebuggerModel::executeTransaction(bytesConstRef const& execution.go(onOp); execution.finalize(); - m_executiveState.completeMine(); DebuggingContent d; d.returnValue = execution.out().toVector(); diff --git a/mix/qml/StateDialog.qml b/mix/qml/StateDialog.qml index eb0b68ac8..862e6f854 100644 --- a/mix/qml/StateDialog.qml +++ b/mix/qml/StateDialog.qml @@ -1,5 +1,5 @@ import QtQuick 2.2 -import QtQuick.Controls 1.2 +import QtQuick.Controls 1.1 import QtQuick.Layouts 1.1 import QtQuick.Window 2.0 diff --git a/mix/qml/StateList.qml b/mix/qml/StateList.qml index 152a35671..0d4b6e5c6 100644 --- a/mix/qml/StateList.qml +++ b/mix/qml/StateList.qml @@ -1,7 +1,7 @@ import QtQuick 2.2 -import QtQuick.Controls.Styles 1.2 -import QtQuick.Controls 1.2 -import QtQuick.Dialogs 1.2 +import QtQuick.Controls.Styles 1.1 +import QtQuick.Controls 1.1 +import QtQuick.Dialogs 1.1 import QtQuick.Layouts 1.1 Rectangle { diff --git a/mix/qml/TransactionDialog.qml b/mix/qml/TransactionDialog.qml index b7c556272..54528f97f 100644 --- a/mix/qml/TransactionDialog.qml +++ b/mix/qml/TransactionDialog.qml @@ -1,5 +1,5 @@ import QtQuick 2.2 -import QtQuick.Controls 1.2 +import QtQuick.Controls 1.1 import QtQuick.Layouts 1.1 import QtQuick.Window 2.0 diff --git a/mix/qml/main.qml b/mix/qml/main.qml index bba7c9088..6e946cdfd 100644 --- a/mix/qml/main.qml +++ b/mix/qml/main.qml @@ -1,6 +1,6 @@ import QtQuick 2.2 -import QtQuick.Controls 1.2 -import QtQuick.Controls.Styles 1.2 +import QtQuick.Controls 1.1 +import QtQuick.Controls.Styles 1.1 import QtQuick.Dialogs 1.1 import QtQuick.Layouts 1.1 import QtQuick.Window 2.1 From e9913a3d10136ce46090bdd94b0d0a4c870f69d8 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Tue, 6 Jan 2015 19:17:05 +0100 Subject: [PATCH 110/111] new vps for windows build --- extdep/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extdep/CMakeLists.txt b/extdep/CMakeLists.txt index 19cd00f7b..fdee34602 100644 --- a/extdep/CMakeLists.txt +++ b/extdep/CMakeLists.txt @@ -7,7 +7,7 @@ include(eth_download.cmake) # all dependencies will be installed into this directory, separated by platform string(TOLOWER ${CMAKE_SYSTEM_NAME} _system_name) set(ETH_DEPENDENCY_INSTALL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/install/${_system_name}") -set(ETH_DEPENDENCY_SERVER "http://poc-7.ethdev.com/precompiled/${_system_name}") +set(ETH_DEPENDENCY_SERVER "http://build.ethdev.com/builds/${_system_name}-precompiled") file(MAKE_DIRECTORY ${ETH_DEPENDENCY_INSTALL_DIR}/lib) file(MAKE_DIRECTORY ${ETH_DEPENDENCY_INSTALL_DIR}/include) file(MAKE_DIRECTORY ${ETH_DEPENDENCY_INSTALL_DIR}/bin) From 6cc8c9de6953db631f67888f5a5c0abdee307975 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 7 Jan 2015 20:23:33 +0100 Subject: [PATCH 111/111] VM skips push data when looking for JUMPDEST. Warnings fixes. --- libevm/VM.h | 3 ++- libsolidity/Types.h | 6 ++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/libevm/VM.h b/libevm/VM.h index cc9556c26..b8a33909c 100644 --- a/libevm/VM.h +++ b/libevm/VM.h @@ -86,7 +86,8 @@ inline bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _st for (unsigned i = 0; i < _ext.code.size(); ++i) if (_ext.code[i] == (byte)Instruction::JUMPDEST) m_jumpDests.insert(i); - + else if (_ext.code[i] >= (byte)Instruction::PUSH1 && _ext.code[i] <= (byte)Instruction::PUSH32) + i += _ext.code[i] - (unsigned)Instruction::PUSH1 + 1; u256 nextPC = m_curPC + 1; auto osteps = _steps; for (bool stopped = false; !stopped && _steps--; m_curPC = nextPC, nextPC = m_curPC + 1) diff --git a/libsolidity/Types.h b/libsolidity/Types.h index 6f3ca6abf..a91a6c24e 100644 --- a/libsolidity/Types.h +++ b/libsolidity/Types.h @@ -415,6 +415,9 @@ public: protected: virtual TypePointer binaryOperatorResultImpl(Token::Value _operator, TypePointer const& _this, TypePointer const& _other) const override { + (void)_operator; + (void)_this; + (void)_other; return TypePointer(); } @@ -445,6 +448,9 @@ public: protected: virtual TypePointer binaryOperatorResultImpl(Token::Value _operator, TypePointer const& _this, TypePointer const& _other) const override { + (void)_operator; + (void)_this; + (void)_other; return TypePointer(); }