From d865b2b56d107229ea4477667a425fb16da6b0f2 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 25 Jan 2014 01:36:34 -0500 Subject: [PATCH 01/86] Documentation. --- libethereum/Utility.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/libethereum/Utility.h b/libethereum/Utility.h index 93c3d54c8..893604139 100644 --- a/libethereum/Utility.h +++ b/libethereum/Utility.h @@ -29,6 +29,17 @@ namespace dev namespace eth { +/** + * Takes a user-authorable string with several whitespace delimited arguments and builds a byte array + * from it. Arguments can be hex data/numerals, decimal numbers or ASCII strings. Literals are padded + * to 32 bytes if prefixed by a '@' (or not prefixed at all), and tightly packed if prefixed by a '$'. + * Currency multipliers can be provided. + * + * Example: + * @code + * parseData("$42 0x42 $\"Hello\""); // == bytes(1, 0x2a) + bytes(31, 0) + bytes(1, 0x42) + asBytes("Hello"); + * @endcode + */ bytes parseData(std::string const& _args); } From de099b2d8b6c59ad297ffa372ca684ca77a5adec Mon Sep 17 00:00:00 2001 From: subtly Date: Wed, 19 Nov 2014 06:14:56 +0100 Subject: [PATCH 02/86] remove network pause. fix client repeat-disconnect loop. removed resolver from getifaddr dance (not reqd) and updated getifaddr code (needs windowz/linux testing). don't accept new connections if listenport bind fails (possible due to OS firewall settings). only use upnp w/ipv4 addresses. re: disconnect loop. Looks like ethhost session isn't deallocating once stopped. Thinking UI might have shared_ptr. For now, letting dealloc/quit continue as long as isOpen returns false -- maybe okay since network will be halted. Also, it maybe possible the issue is due to network thread not running after disconnect so packets aren't tx/rx to kill peer -- either way, it's possible remote end doesn't ack disconnect and timeout/force-close-dealloc is required, so will need more attention later. --- libdevcore/Worker.cpp | 3 +- libdevcore/Worker.h | 18 +- libethereum/EthereumHost.h | 1 + libp2p/Host.cpp | 376 +++++++++++++++++++++---------------- libp2p/Host.h | 42 +++-- 5 files changed, 256 insertions(+), 184 deletions(-) diff --git a/libdevcore/Worker.cpp b/libdevcore/Worker.cpp index b2660305a..d9246f9fd 100644 --- a/libdevcore/Worker.cpp +++ b/libdevcore/Worker.cpp @@ -41,7 +41,8 @@ void Worker::startWorking() startedWorking(); while (!m_stop) { - this_thread::sleep_for(chrono::milliseconds(30)); + if (m_idlewaitms) + this_thread::sleep_for(chrono::milliseconds(m_idlewaitms)); doWork(); } cdebug << "Finishing up worker thread"; diff --git a/libdevcore/Worker.h b/libdevcore/Worker.h index a4a998dd7..f8d694681 100644 --- a/libdevcore/Worker.h +++ b/libdevcore/Worker.h @@ -31,7 +31,7 @@ namespace dev class Worker { protected: - Worker(std::string const& _name = "anon"): m_name(_name) {} + Worker(std::string const& _name = "anon", unsigned _idlewaitms = 30): m_name(_name), m_idlewaitms(_idlewaitms) {} /// Move-constructor. Worker(Worker&& _m) { std::swap(m_name, _m.m_name); } @@ -41,20 +41,34 @@ protected: virtual ~Worker() { stopWorking(); } + /// Allows changing worker name if work is stopped. void setName(std::string _n) { if (!isWorking()) m_name = _n; } + /// Starts worker thread; causes startedWorking() to be called. void startWorking(); + + /// Stop worker thread; causes call to stopWorking(). void stopWorking(); + + /// Returns if worker thread is present. bool isWorking() const { Guard l(x_work); return !!m_work; } + + /// Called after thread is started from startWorking(). virtual void startedWorking() {} + + /// Called continuously following sleep for m_idlewaitms. virtual void doWork() = 0; + + /// Called when is to be stopped, just prior to thread being joined. virtual void doneWorking() {} private: + std::string m_name; + unsigned m_idlewaitms; + mutable Mutex x_work; ///< Lock for the network existance. std::unique_ptr m_work; ///< The network thread. bool m_stop = false; - std::string m_name; }; } diff --git a/libethereum/EthereumHost.h b/libethereum/EthereumHost.h index 18ba765aa..c732f2dc1 100644 --- a/libethereum/EthereumHost.h +++ b/libethereum/EthereumHost.h @@ -51,6 +51,7 @@ class BlockQueue; /** * @brief The EthereumHost class * @warning None of this is thread-safe. You have been warned. + * @doWork Syncs to peers and sends new blocks and transactions. */ class EthereumHost: public p2p::HostCapability, Worker { diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index 996e219db..4c6973ae3 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -46,19 +46,17 @@ using namespace std; using namespace dev; using namespace dev::p2p; -// Addresses we will skip during network interface discovery -// Use a vector as the list is small -// Why this and not names? -// Under MacOSX loopback (127.0.0.1) can be named lo0 and br0 are bridges (0.0.0.0) +// Addresses skipped during network interface discovery +// @todo: filter out ivp6 link-local network mess on macos, ex: fe80::1%lo0 static const set c_rejectAddresses = { {bi::address_v4::from_string("127.0.0.1")}, - {bi::address_v6::from_string("::1")}, {bi::address_v4::from_string("0.0.0.0")}, + {bi::address_v6::from_string("::1")}, {bi::address_v6::from_string("::")} }; Host::Host(std::string const& _clientVersion, NetworkPreferences const& _n, bool _start): - Worker("p2p"), + Worker("p2p", 0), m_clientVersion(_clientVersion), m_netPrefs(_n), m_ioService(new ba::io_service), @@ -79,70 +77,17 @@ Host::~Host() void Host::start() { - // if there's no ioService, it means we've had quit() called - bomb out - we're not allowed in here. - if (!m_ioService) - return; - - if (isWorking()) - stop(); - - for (unsigned i = 0; i < 2; ++i) - { - bi::tcp::endpoint endpoint(bi::tcp::v4(), i ? 0 : m_netPrefs.listenPort); - try - { - m_acceptor->open(endpoint.protocol()); - m_acceptor->set_option(ba::socket_base::reuse_address(true)); - m_acceptor->bind(endpoint); - m_acceptor->listen(); - m_listenPort = i ? m_acceptor->local_endpoint().port() : m_netPrefs.listenPort; - break; - } - catch (...) - { - if (i) - { - cwarn << "Couldn't start accepting connections on host. Something very wrong with network?\n" << boost::current_exception_diagnostic_information(); - return; - } - m_acceptor->close(); - continue; - } - } - - for (auto const& h: m_capabilities) - h.second->onStarting(); - startWorking(); } void Host::stop() { - // if there's no ioService, it means we've had quit() called - bomb out - we're not allowed in here. - if (!m_ioService) - return; - - for (auto const& h: m_capabilities) - h.second->onStopping(); - + // flag transition to shutdown network + // once m_run is false the scheduler will shutdown network and stopWorking() + m_run = false; + while (m_timer) + this_thread::sleep_for(chrono::milliseconds(100)); stopWorking(); - - if (m_acceptor->is_open()) - { - if (m_accepting) - m_acceptor->cancel(); - m_acceptor->close(); - m_accepting = false; - } - if (m_socket->is_open()) - m_socket->close(); - disconnectPeers(); - - if (!!m_ioService) - { - m_ioService->stop(); - m_ioService->reset(); - } } void Host::quit() @@ -150,7 +95,8 @@ void Host::quit() // called to force io_service to kill any remaining tasks it might have - // such tasks may involve socket reads from Capabilities that maintain references // to resources we're about to free. - stop(); + if (isWorking()) + stop(); m_acceptor.reset(); m_socket.reset(); m_ioService.reset(); @@ -183,33 +129,6 @@ void Host::registerPeer(std::shared_ptr _s, CapDescs const& _caps) } } -void Host::disconnectPeers() -{ - // if there's no ioService, it means we've had quit() called - bomb out - we're not allowed in here. - if (!m_ioService) - return; - - for (unsigned n = 0;; n = 0) - { - { - RecursiveGuard l(x_peers); - for (auto i: m_peers) - if (auto p = i.second.lock()) - { - p->disconnect(ClientQuit); - n++; - } - } - if (!n) - break; - m_ioService->poll(); - this_thread::sleep_for(chrono::milliseconds(100)); - } - - delete m_upnp; - m_upnp = nullptr; -} - void Host::seal(bytes& _b) { _b[0] = 0x22; @@ -225,10 +144,6 @@ void Host::seal(bytes& _b) void Host::determinePublic(string const& _publicAddress, bool _upnp) { - // if there's no ioService, it means we've had quit() called - bomb out - we're not allowed in here. - if (!m_ioService) - return; - if (_upnp) try { @@ -236,11 +151,12 @@ void Host::determinePublic(string const& _publicAddress, bool _upnp) } catch (NoUPnPDevice) {} // let m_upnp continue as null - we handle it properly. - bi::tcp::resolver r(*m_ioService); if (m_upnp && m_upnp->isValid() && m_peerAddresses.size()) { clog(NetNote) << "External addr:" << m_upnp->externalIP(); int p; + + // iterate m_peerAddresses (populated by populateAddresses()) for (auto const& addr : m_peerAddresses) if ((p = m_upnp->addRedirect(addr.to_string().c_str(), m_listenPort))) break; @@ -258,7 +174,7 @@ void Host::determinePublic(string const& _publicAddress, bool _upnp) m_public = bi::tcp::endpoint(bi::address(), (unsigned short)p); else { - bi::address adr = adr = bi::address::from_string(eip); + bi::address adr = bi::address::from_string(eip); try { adr = bi::address::from_string(_publicAddress); @@ -271,7 +187,21 @@ void Host::determinePublic(string const& _publicAddress, bool _upnp) else { // No UPnP - fallback on given public address or, if empty, the assumed peer address. - bi::address adr = m_peerAddresses.size() ? m_peerAddresses[0] : bi::address(); + bi::address adr; // = m_peerAddresses.size() ? m_peerAddresses[0] : bi::address(); + if (m_peerAddresses.size()) + { + // prefer local ipv4 over local ipv6 + for (auto const& ip: m_peerAddresses) + if (ip.is_v4()) + { + adr = ip; + break; + } + + if (adr.is_unspecified()) + adr = m_peerAddresses[0]; + } + try { adr = bi::address::from_string(_publicAddress); @@ -328,57 +258,43 @@ void Host::populateAddresses() if (getifaddrs(&ifaddr) == -1) BOOST_THROW_EXCEPTION(NoNetworking()); - bi::tcp::resolver r(*m_ioService); - - for (ifaddrs* ifa = ifaddr; ifa; ifa = ifa->ifa_next) - { - if (!ifa->ifa_addr) + for (auto ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { + if (!ifa->ifa_addr || (strlen(ifa->ifa_name) > 2 && !strncmp(ifa->ifa_name, "lo0", 3))) { continue; + } + if (ifa->ifa_addr->sa_family == AF_INET) { - char host[NI_MAXHOST]; - if (getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in), host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST)) - continue; - try - { - auto it = r.resolve({host, "30303"}); - bi::tcp::endpoint ep = it->endpoint(); - bi::address ad = ep.address(); - m_addresses.push_back(ad.to_v4()); - bool isLocal = std::find(c_rejectAddresses.begin(), c_rejectAddresses.end(), ad) != c_rejectAddresses.end(); - if (!isLocal) - m_peerAddresses.push_back(ad.to_v4()); - clog(NetNote) << "Address: " << host << " = " << m_addresses.back() << (isLocal ? " [LOCAL]" : " [PEER]"); - } - catch (...) - { - clog(NetNote) << "Couldn't resolve: " << host; - } + in_addr addr = ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr; + boost::asio::ip::address_v4 address(boost::asio::detail::socket_ops::network_to_host_long(addr.s_addr)); + if (std::find(c_rejectAddresses.begin(), c_rejectAddresses.end(), address) == c_rejectAddresses.end()) + m_peerAddresses.push_back(address); + + // Log IPv4 Address: + auto addr4 = &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr; + char addressBuffer[INET_ADDRSTRLEN]; + inet_ntop(AF_INET, addr4, addressBuffer, INET_ADDRSTRLEN); + printf("%s IP Address %s\n", ifa->ifa_name, addressBuffer); } else if (ifa->ifa_addr->sa_family == AF_INET6) { - char host[NI_MAXHOST]; - if (getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in6), host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST)) - continue; - try - { - auto it = r.resolve({host, "30303"}); - bi::tcp::endpoint ep = it->endpoint(); - bi::address ad = ep.address(); - m_addresses.push_back(ad.to_v6()); - bool isLocal = std::find(c_rejectAddresses.begin(), c_rejectAddresses.end(), ad) != c_rejectAddresses.end(); - if (!isLocal) - m_peerAddresses.push_back(ad); - clog(NetNote) << "Address: " << host << " = " << m_addresses.back() << (isLocal ? " [LOCAL]" : " [PEER]"); - } - catch (...) - { - clog(NetNote) << "Couldn't resolve: " << host; - } + sockaddr_in6* sockaddr = ((struct sockaddr_in6 *)ifa->ifa_addr); + in6_addr addr = sockaddr->sin6_addr; + boost::asio::ip::address_v6::bytes_type bytes; + memcpy(&bytes[0], addr.s6_addr, 16); + boost::asio::ip::address_v6 address(bytes, sockaddr->sin6_scope_id); + if (std::find(c_rejectAddresses.begin(), c_rejectAddresses.end(), address) == c_rejectAddresses.end()) + m_peerAddresses.push_back(address); + + // Log IPv6 Address: + auto addr6 = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr; + char addressBuffer[INET6_ADDRSTRLEN]; + inet_ntop(AF_INET6, addr6, addressBuffer, INET6_ADDRSTRLEN); + printf("%s IP Address %s\n", ifa->ifa_name, addressBuffer); } } + if (ifaddr!=NULL) freeifaddrs(ifaddr); - freeifaddrs(ifaddr); #endif } @@ -461,8 +377,8 @@ Nodes Host::potentialPeers(RangeMask const& _known) void Host::ensureAccepting() { - // if there's no ioService, it means we've had quit() called - bomb out - we're not allowed in here. - if (!m_ioService) + // return if there's no io-server (quit called) or we're not listening + if (!m_ioService || m_listenPort < 1) return; if (!m_accepting) @@ -654,12 +570,9 @@ void Host::growPeers() return; } else - { - ensureAccepting(); for (auto const& i: m_peers) if (auto p = i.second.lock()) p->ensureNodesRequested(); - } } } @@ -717,36 +630,150 @@ PeerInfos Host::peers(bool _updatePing) const ret.push_back(j->m_info); return ret; } - -void Host::startedWorking() -{ - determinePublic(m_netPrefs.publicIP, m_netPrefs.upnp); - ensureAccepting(); - - if (!m_public.address().is_unspecified() && (m_nodes.empty() || m_nodes[m_nodesList[0]]->id != id())) - noteNode(id(), m_public, Origin::Perfect, false); - - clog(NetNote) << "Id:" << id().abridged(); -} - -void Host::doWork() + +void Host::run(boost::system::error_code const& error) { - // if there's no ioService, it means we've had quit() called - bomb out - we're not allowed in here. - if (asserts(!!m_ioService)) + static unsigned s_lasttick = 0; + s_lasttick += c_timerInterval; + + if (error) + // tood: error handling. + { + m_timer.reset(); return; + } + + // no timer means this is first run and network must be started + if (!m_timer) + // run once when host worker thread calls startedWorking() + { + // reset io service and create deadline timer + m_ioService->reset(); + m_timer.reset(new boost::asio::deadline_timer(*m_ioService)); + m_run = true; + + // try to open acceptor (ipv4; todo: update for ipv6) + for (unsigned i = 0; i < 2; ++i) + { + // try to connect w/listenPort, else attempt net-allocated port + bi::tcp::endpoint endpoint(bi::tcp::v4(), i ? 0 : m_netPrefs.listenPort); + try + { + m_acceptor->open(endpoint.protocol()); + m_acceptor->set_option(ba::socket_base::reuse_address(true)); + m_acceptor->bind(endpoint); + m_acceptor->listen(); + m_listenPort = i ? m_acceptor->local_endpoint().port() : m_netPrefs.listenPort; + break; + } + catch (...) + { + if (i) + { + // both attempts failed + cwarn << "Couldn't start accepting connections on host. Something very wrong with network?\n" << boost::current_exception_diagnostic_information(); + m_listenPort = -1; + } + + // first attempt failed + m_acceptor->close(); + continue; + } + } + + // start capability threads + for (auto const& h: m_capabilities) + h.second->onStarting(); + + // determine public IP, but only if we're able to listen for connections + // todo: visualize when listen is unavailable in UI + // tood: only punch hole for ipv4 + if (m_listenPort) + { + determinePublic(m_netPrefs.publicIP, m_netPrefs.upnp); + ensureAccepting(); + } + + // 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); + + clog(NetNote) << "Id:" << id().abridged(); + } + + // io service went away, so stop here + if (!m_ioService) + { + m_timer.reset(); + return; + } - growPeers(); - prunePeers(); - + // network stopped; disconnect peers + if (!m_run) + { + // close acceptor + if (m_acceptor->is_open()) + { + if (m_accepting) + m_acceptor->cancel(); + m_acceptor->close(); + m_accepting = false; + } + + // stop capabilities (eth: stops syncing or block/tx broadcast) + for (auto const& h: m_capabilities) + h.second->onStopping(); + + // disconnect peers + for (unsigned n = 0;; n = 0) + { + { + RecursiveGuard l(x_peers); + for (auto i: m_peers) + if (auto p = i.second.lock()) + if (p->isOpen()) + { + p->disconnect(ClientQuit); + n++; + } + } + if (!n) + break; + this_thread::sleep_for(chrono::milliseconds(100)); + } + + if (m_socket->is_open()) + m_socket->close(); + + if (m_upnp != nullptr) + delete m_upnp; + + // m_run is false, so we're stopping; kill timer + s_lasttick = 0; + m_timer.reset(); + if (!!m_ioService) + m_ioService->stop(); + return; + } + + + if (s_lasttick == c_timerInterval * 100) + { + growPeers(); + prunePeers(); + s_lasttick = 0; + } + if (m_hadNewNodes) { for (auto p: m_peers) if (auto pp = p.second.lock()) pp->serviceNodesRequest(); - + m_hadNewNodes = false; } - + if (chrono::steady_clock::now() - m_lastPing > chrono::seconds(30)) // ping every 30s. { for (auto p: m_peers) @@ -756,7 +783,22 @@ void Host::doWork() pingAll(); } - m_ioService->poll(); + auto runcb = [this](boost::system::error_code const& error)->void{ run(error); }; + m_timer->expires_from_now(boost::posix_time::milliseconds(c_timerInterval)); + m_timer->async_wait(runcb); +} + +void Host::startedWorking() +{ + run(boost::system::error_code()); +} + +void Host::doWork() +{ + // no ioService means we've had quit() called - bomb out - we're not allowed in here. + if (asserts(!!m_ioService)) + return; + m_ioService->run(); } void Host::pingAll() diff --git a/libp2p/Host.h b/libp2p/Host.h index 7722905ab..7c4fbe1ce 100644 --- a/libp2p/Host.h +++ b/libp2p/Host.h @@ -110,7 +110,7 @@ struct NetworkPreferences bool upnp = true; bool localNetworking = false; }; - + /** * @brief The Host class * Capabilities should be registered prior to startNetwork, since m_capabilities is not thread-safe. @@ -147,7 +147,7 @@ public: void connect(bi::tcp::endpoint const& _ep); void connect(std::shared_ptr const& _n); - /// @returns true iff we have the a peer of the given id. + /// @returns true if we have the a peer of the given id. bool havePeer(NodeId _id) const; /// Set ideal number of peers. @@ -175,10 +175,16 @@ public: void setNetworkPreferences(NetworkPreferences const& _p) { auto had = isStarted(); if (had) stop(); m_netPrefs = _p; if (had) start(); } + /// Start network. void start(); + + /// Stop network. void stop(); + + /// @returns if network is running bool isStarted() const { return isWorking(); } + /// Reset acceptor, socket, and IO service. Called by deallocator. Maybe called by implementation when ordered deallocation is required. void quit(); NodeId id() const { return m_key.pub(); } @@ -190,17 +196,23 @@ public: private: void seal(bytes& _b); void populateAddresses(); + + /// Try UPNP or listen to assumed address. Requires valid m_listenPort. void determinePublic(std::string const& _publicAddress, bool _upnp); + + void ensureAccepting(); void growPeers(); void prunePeers(); + /// Called by Worker. Not thread-safe; to be called only by worker. virtual void startedWorking(); + /// Called by startedWorking. Not thread-safe; to be called only be worker callback. + void run(boost::system::error_code const& error); ///< Run network. Called serially via ASIO deadline timer. Manages connection state transitions. + bool m_run = false; - /// Conduct I/O, polling, syncing, whatever. - /// Ideally all time-consuming I/O is done in a background thread or otherwise asynchronously, but you get this call every 100ms or so anyway. - /// This won't touch alter the blockchain. + /// Run network virtual void doWork(); std::shared_ptr noteNode(NodeId _id, bi::tcp::endpoint _a, Origin _o, bool _ready, NodeId _oldId = NodeId()); @@ -208,18 +220,20 @@ private: std::string m_clientVersion; ///< Our version string. - NetworkPreferences m_netPrefs; ///< Network settings. + NetworkPreferences m_netPrefs; ///< Network settings. - static const int NetworkStopped = -1; ///< The value meaning we're not actually listening. - int m_listenPort = NetworkStopped; ///< What port are we listening on? + int m_listenPort = -1; ///< What port are we listening on. -1 means binding failed or acceptor hasn't been initialized. std::unique_ptr m_ioService; ///< IOService for network stuff. - std::unique_ptr m_acceptor; ///< Listening acceptor. - std::unique_ptr m_socket; ///< Listening socket. - - UPnP* m_upnp = nullptr; ///< UPnP helper. - bi::tcp::endpoint m_public; ///< Our public listening endpoint. - KeyPair m_key; ///< Our unique ID. + std::unique_ptr m_acceptor; ///< 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. + static const unsigned c_timerInterval = 100; ///< Interval which m_timer is run when network is connected. + + UPnP* m_upnp = nullptr; ///< UPnP helper. + bi::tcp::endpoint m_public; ///< Our public listening endpoint. + KeyPair m_key; ///< Our unique ID. bool m_hadNewNodes = false; From c479f23561d8b987e710cfcd09b6d3e1eb9f5a24 Mon Sep 17 00:00:00 2001 From: subtly Date: Wed, 19 Nov 2014 06:18:11 +0100 Subject: [PATCH 03/86] remove unused method. skip upnp for ipv6. --- libp2p/Host.cpp | 5 ++--- libp2p/Host.h | 4 ---- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index 4c6973ae3..e7c476441 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -158,7 +158,7 @@ void Host::determinePublic(string const& _publicAddress, bool _upnp) // iterate m_peerAddresses (populated by populateAddresses()) for (auto const& addr : m_peerAddresses) - if ((p = m_upnp->addRedirect(addr.to_string().c_str(), m_listenPort))) + if (addr.is_v4() && (p = m_upnp->addRedirect(addr.to_string().c_str(), m_listenPort))) break; if (p) clog(NetNote) << "Punched through NAT and mapped local port" << m_listenPort << "onto external port" << p << "."; @@ -187,7 +187,7 @@ void Host::determinePublic(string const& _publicAddress, bool _upnp) else { // No UPnP - fallback on given public address or, if empty, the assumed peer address. - bi::address adr; // = m_peerAddresses.size() ? m_peerAddresses[0] : bi::address(); + bi::address adr; if (m_peerAddresses.size()) { // prefer local ipv4 over local ipv6 @@ -687,7 +687,6 @@ void Host::run(boost::system::error_code const& error) // determine public IP, but only if we're able to listen for connections // todo: visualize when listen is unavailable in UI - // tood: only punch hole for ipv4 if (m_listenPort) { determinePublic(m_netPrefs.publicIP, m_netPrefs.upnp); diff --git a/libp2p/Host.h b/libp2p/Host.h index 7c4fbe1ce..b60949278 100644 --- a/libp2p/Host.h +++ b/libp2p/Host.h @@ -128,9 +128,6 @@ public: /// Will block on network process events. virtual ~Host(); - /// Closes all peers. - void disconnectPeers(); - /// Basic peer network protocol version. unsigned protocolVersion() const; @@ -200,7 +197,6 @@ private: /// Try UPNP or listen to assumed address. Requires valid m_listenPort. void determinePublic(std::string const& _publicAddress, bool _upnp); - void ensureAccepting(); void growPeers(); From 056e201e8e1beebfd494ea45a9b35cf65f08ed80 Mon Sep 17 00:00:00 2001 From: Christoph Jentzsch Date: Wed, 19 Nov 2014 10:55:28 +0100 Subject: [PATCH 04/86] more precompiled contract tests Conflicts: libevm/VM.h --- libevm/VM.h | 2 +- test/stPreCompiledContractsFiller.json | 68 ++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 1 deletion(-) diff --git a/libevm/VM.h b/libevm/VM.h index 487c8cd1a..52149a9a1 100644 --- a/libevm/VM.h +++ b/libevm/VM.h @@ -71,7 +71,7 @@ public: template bytesConstRef go(Ext& _ext, OnOpFunc const& _onOp = OnOpFunc(), uint64_t _steps = (uint64_t)-1); - void require(u256 _n) { if (m_stack.size() < _n) BOOST_THROW_EXCEPTION(StackTooSmall() << RequirementError((bigint)_n, (bigint)m_stack.size())); } + void require(u256 _n) { if (m_stack.size() < _n) BOOST_THROW_EXCEPTION(StackTooSmall() << RequirementError(int(_n), m_stack.size())); } void requireMem(unsigned _n) { if (m_temp.size() < _n) { m_temp.resize(_n); } } u256 gas() const { return m_gas; } u256 curPC() const { return m_curPC; } diff --git a/test/stPreCompiledContractsFiller.json b/test/stPreCompiledContractsFiller.json index bb2b35756..9c65ad37b 100644 --- a/test/stPreCompiledContractsFiller.json +++ b/test/stPreCompiledContractsFiller.json @@ -33,6 +33,40 @@ } }, + "CallEcrecover0_completeReturnValue": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20000000", + "nonce" : 0, + "code": "{ (MSTORE 0 0x18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c) (MSTORE 32 28) (MSTORE 64 0x73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f) (MSTORE 96 0xeeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549) [[ 2 ]] (CALL 1000 1 0 0 128 128 32) [[ 0 ]] (MLOAD 128) }", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "365224", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + "CallEcrecover0_gas500": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", @@ -305,6 +339,40 @@ } }, + "CallSha256_1_nonzeroValue": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20000000", + "nonce" : 0, + "code" : "{ [[ 2 ]] (CALL 500 2 0x13 0 0 0 32) [[ 0 ]] (MLOAD 0)}", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "365224", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + "CallSha256_2": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", From 7e8b65b6070acd8eab4453b907de7d8a4878b238 Mon Sep 17 00:00:00 2001 From: Christoph Jentzsch Date: Mon, 17 Nov 2014 22:51:08 +0100 Subject: [PATCH 05/86] Changed name of some tests --- test/vmIOandFlowOperationsTestFiller.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/vmIOandFlowOperationsTestFiller.json b/test/vmIOandFlowOperationsTestFiller.json index e2ec1def1..dce594e1e 100644 --- a/test/vmIOandFlowOperationsTestFiller.json +++ b/test/vmIOandFlowOperationsTestFiller.json @@ -55,7 +55,7 @@ } }, - "dupAt51doesNotExistAnymore": { + "dupAt51becameMload": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -83,7 +83,7 @@ } }, - "swapAt52doesNotExistAnymore": { + "swapAt52becameMstore": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", From c7032ff55cc64239bf73356f97c27c11fbfcef00 Mon Sep 17 00:00:00 2001 From: Christoph Jentzsch Date: Wed, 19 Nov 2014 10:03:26 +0100 Subject: [PATCH 06/86] new push32 test and renaming --- test/vmPushDupSwapTestFiller.json | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/test/vmPushDupSwapTestFiller.json b/test/vmPushDupSwapTestFiller.json index 3fc7e4a79..69d0254b7 100644 --- a/test/vmPushDupSwapTestFiller.json +++ b/test/vmPushDupSwapTestFiller.json @@ -924,7 +924,7 @@ } }, - "push32error": { + "push32AndSuicide": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -952,6 +952,35 @@ } }, + + "push32FillUpInputWithZerosAtTheEnd": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "0x7fff10112233445566778899aabbccddeeff00112233445566778899aabbccdd", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + "dup1": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", From ff408ef6017783c9eddfe7d8b7609c8799511855 Mon Sep 17 00:00:00 2001 From: Christoph Jentzsch Date: Wed, 19 Nov 2014 10:58:21 +0100 Subject: [PATCH 07/86] merge --- libevm/VM.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libevm/VM.h b/libevm/VM.h index 52149a9a1..487c8cd1a 100644 --- a/libevm/VM.h +++ b/libevm/VM.h @@ -71,7 +71,7 @@ public: template bytesConstRef go(Ext& _ext, OnOpFunc const& _onOp = OnOpFunc(), uint64_t _steps = (uint64_t)-1); - void require(u256 _n) { if (m_stack.size() < _n) BOOST_THROW_EXCEPTION(StackTooSmall() << RequirementError(int(_n), m_stack.size())); } + void require(u256 _n) { if (m_stack.size() < _n) BOOST_THROW_EXCEPTION(StackTooSmall() << RequirementError((bigint)_n, (bigint)m_stack.size())); } void requireMem(unsigned _n) { if (m_temp.size() < _n) { m_temp.resize(_n); } } u256 gas() const { return m_gas; } u256 curPC() const { return m_curPC; } From 946f7d3d85d0bfda2d76d444452ce6eb429181f6 Mon Sep 17 00:00:00 2001 From: Christoph Jentzsch Date: Wed, 19 Nov 2014 14:30:42 +0100 Subject: [PATCH 08/86] Add Log tests --- test/TestHelper.cpp | 12 ++++ test/TestHelper.h | 2 + test/vm.cpp | 49 ++++++++++++++++- test/vm.h | 2 + test/vmLogTestFiller.json | 113 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 177 insertions(+), 1 deletion(-) create mode 100644 test/vmLogTestFiller.json diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp index 1b13f9e82..a0e2d5723 100644 --- a/test/TestHelper.cpp +++ b/test/TestHelper.cpp @@ -287,6 +287,18 @@ void checkStorage(map _expectedStore, map _resultStore, } } +void checkLog(LogEntries _resultLogs, LogEntries _expectedLogs) +{ + BOOST_REQUIRE_EQUAL(_resultLogs.size(), _expectedLogs.size()); + + for (size_t i = 0; i < _resultLogs.size(); ++i) + { + BOOST_CHECK(_resultLogs[i].address == _expectedLogs[i].address); + BOOST_CHECK(_resultLogs[i].topics == _expectedLogs[i].topics); + BOOST_CHECK(_resultLogs[i].data == _expectedLogs[i].data); + } +} + std::string getTestPath() { string testPath; diff --git a/test/TestHelper.h b/test/TestHelper.h index ef67d52fb..7a2b8da51 100644 --- a/test/TestHelper.h +++ b/test/TestHelper.h @@ -25,6 +25,7 @@ #include #include "JsonSpiritHeaders.h" #include +#include namespace dev { @@ -69,6 +70,7 @@ bytes importCode(json_spirit::mObject& _o); bytes importData(json_spirit::mObject& _o); void checkOutput(bytes const& _output, json_spirit::mObject& _o); void checkStorage(std::map _expectedStore, std::map _resultStore, Address _expectedAddr); +void checkLog(eth::LogEntries _resultLogs, eth::LogEntries _expectedLogs); void executeTests(const std::string& _name, const std::string& _testPathAppendix, std::function doTests); std::string getTestPath(); void userDefinedTest(std::string testTypeFlag, std::function doTests); diff --git a/test/vm.cpp b/test/vm.cpp index cacbf94cc..2503f89d1 100644 --- a/test/vm.cpp +++ b/test/vm.cpp @@ -120,6 +120,43 @@ void FakeExtVM::importEnv(mObject& _o) currentBlock.coinbaseAddress = Address(_o["currentCoinbase"].get_str()); } +mObject FakeExtVM::exportLog() +{ + mObject ret; + for (LogEntry const& l: sub.logs) + { + mObject o; + o["address"] = toString(l.address); + mArray topics; + for (auto const& t: l.topics) + topics.push_back(toString(t)); + o["topics"] = topics; + o["data"] = "0x" + toHex(l.data); + ret[toString(l.bloom())] = o; + } + return ret; +} + +void FakeExtVM::importLog(mObject& _o) +{ + for (auto const& l: _o) + { + mObject o = l.second.get_obj(); + // cant use BOOST_REQUIRE, because this function is used outside boost test (createRandomTest) + assert(o.count("address") > 0); + assert(o.count("topics") > 0); + assert(o.count("data") > 0); + LogEntry log; + log.address = Address(o["address"].get_str()); + for (auto const& t: o["topics"].get_array()) + { + log.topics.insert(h256(t.get_str())); + } + log.data = importData(o); + sub.logs.push_back(log); + } +} + mObject FakeExtVM::exportState() { mObject ret; @@ -302,7 +339,7 @@ void doVMTests(json_spirit::mValue& v, bool _fillin) u256 gas; try { - output = vm.go(fev, fev.simpleTrace()).toVector(); + output = vm.go(fev, fev.simpleTrace()).toBytes(); gas = vm.gas(); } catch (VMException const& _e) @@ -346,6 +383,7 @@ void doVMTests(json_spirit::mValue& v, bool _fillin) o["callcreates"] = fev.exportCallCreates(); o["out"] = "0x" + toHex(output); fev.push(o, "gas", gas); + o["logs"] = mValue(fev.exportLog()); } else { @@ -353,10 +391,12 @@ void doVMTests(json_spirit::mValue& v, bool _fillin) BOOST_REQUIRE(o.count("callcreates") > 0); BOOST_REQUIRE(o.count("out") > 0); BOOST_REQUIRE(o.count("gas") > 0); + BOOST_REQUIRE(o.count("logs") > 0); dev::test::FakeExtVM test; test.importState(o["post"].get_obj()); test.importCallCreates(o["callcreates"].get_array()); + test.importLog(o["logs"].get_obj()); checkOutput(output, o); @@ -384,6 +424,8 @@ void doVMTests(json_spirit::mValue& v, bool _fillin) checkAddresses, bytes> > >(test.addresses, fev.addresses); BOOST_CHECK(test.callcreates == fev.callcreates); + + checkLog(fev.sub.logs, test.sub.logs); } } } @@ -432,6 +474,11 @@ BOOST_AUTO_TEST_CASE(vmPushDupSwapTest) dev::test::executeTests("vmPushDupSwapTest", "/VMTests", dev::test::doVMTests); } +BOOST_AUTO_TEST_CASE(vmLogTest) +{ + dev::test::executeTests("vmLogTest", "/VMTests", dev::test::doVMTests); +} + BOOST_AUTO_TEST_CASE(vmRandom) { string testPath = getTestPath(); diff --git a/test/vm.h b/test/vm.h index a52a02e31..eb98aa0ab 100644 --- a/test/vm.h +++ b/test/vm.h @@ -66,6 +66,8 @@ public: u256 doPosts(); json_spirit::mObject exportEnv(); void importEnv(json_spirit::mObject& _o); + json_spirit::mObject exportLog(); + void importLog(json_spirit::mObject& _o); json_spirit::mObject exportState(); void importState(json_spirit::mObject& _object); json_spirit::mObject exportExec(); diff --git a/test/vmLogTestFiller.json b/test/vmLogTestFiller.json new file mode 100644 index 000000000..fbf206283 --- /dev/null +++ b/test/vmLogTestFiller.json @@ -0,0 +1,113 @@ +{ + "log0": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (LOG0 0 0) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "log1": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (LOG1 0 0 (CALLER)) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "log2": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (LOG2 0 0 (CALLER) (ADDRESS)) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "log2_1": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (LOG2 0 0 (CALLER) 23) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + } +} From 1dff07b1b468a59bb95bf9d60102bd6681cf95a1 Mon Sep 17 00:00:00 2001 From: Christoph Jentzsch Date: Wed, 19 Nov 2014 15:17:03 +0100 Subject: [PATCH 09/86] more log tests --- test/vmLogTestFiller.json | 1167 ++++++++++++++++++++++++++++++++++++- 1 file changed, 1160 insertions(+), 7 deletions(-) diff --git a/test/vmLogTestFiller.json b/test/vmLogTestFiller.json index fbf206283..f4fb48b52 100644 --- a/test/vmLogTestFiller.json +++ b/test/vmLogTestFiller.json @@ -1,5 +1,5 @@ { - "log0": { + "log0_emptyMem": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -27,7 +27,7 @@ } }, - "log1": { + "log0_nonEmptyMem": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -40,7 +40,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "{ (LOG1 0 0 (CALLER)) }", + "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (LOG0 0 32) }", "storage": {} } }, @@ -55,7 +55,7 @@ } }, - "log2": { + "log0_nonEmptyMem_logMemSize1": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -68,7 +68,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "{ (LOG2 0 0 (CALLER) (ADDRESS)) }", + "code" : "{ (MSTORE 0 0xaabbffffffffffffffffffffffffffffffffffffffffffffffffffffffffccdd) (LOG0 0 1) }", "storage": {} } }, @@ -83,7 +83,1160 @@ } }, - "log2_1": { + + "log0_nonEmptyMem_logMemSize1_logMemStart31": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (MSTORE 0 0xaabbffffffffffffffffffffffffffffffffffffffffffffffffffffffffccdd) (LOG0 31 1) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "log0_logMemStartTooHigh": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (MSTORE 0 0xaabbffffffffffffffffffffffffffffffffffffffffffffffffffffffffccdd) (LOG0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 1) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "log0_logMemsizeTooHigh": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (MSTORE 0 0xaabbffffffffffffffffffffffffffffffffffffffffffffffffffffffffccdd) (LOG0 1 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "log0_logMemsizeZero": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (MSTORE 0 0xaabbffffffffffffffffffffffffffffffffffffffffffffffffffffffffccdd) (LOG0 1 0) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "log1_emptyMem": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (LOG1 0 0 0) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "log1_nonEmptyMem": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (LOG1 0 32 0) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "log1_nonEmptyMem_logMemSize1": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (MSTORE 0 0xaabbffffffffffffffffffffffffffffffffffffffffffffffffffffffffccdd) (LOG1 0 1 0) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + + "log1_nonEmptyMem_logMemSize1_logMemStart31": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (MSTORE 0 0xaabbffffffffffffffffffffffffffffffffffffffffffffffffffffffffccdd) (LOG1 31 1 0) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "log1_logMemStartTooHigh": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (MSTORE 0 0xaabbffffffffffffffffffffffffffffffffffffffffffffffffffffffffccdd) (LOG1 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 1 0) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "log1_logMemsizeTooHigh": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (MSTORE 0 0xaabbffffffffffffffffffffffffffffffffffffffffffffffffffffffffccdd) (LOG1 1 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 0) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "log1_logMemsizeZero": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (MSTORE 0 0xaabbffffffffffffffffffffffffffffffffffffffffffffffffffffffffccdd) (LOG1 1 0 0) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "log1_MaxTopic": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (MSTORE 0 0xaabbffffffffffffffffffffffffffffffffffffffffffffffffffffffffccdd) (LOG1 0 32 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "log1_Caller": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (MSTORE8 0 0xff) (LOG1 0 32 (CALLER)) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "log2_emptyMem": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (LOG2 0 0 0 0) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "log2_nonEmptyMem": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (LOG2 0 32 0 0) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "log2_nonEmptyMem_logMemSize1": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (MSTORE 0 0xaabbffffffffffffffffffffffffffffffffffffffffffffffffffffffffccdd) (LOG2 0 1 0 0) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + + "log2_nonEmptyMem_logMemSize1_logMemStart31": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (MSTORE 0 0xaabbffffffffffffffffffffffffffffffffffffffffffffffffffffffffccdd) (LOG2 31 1 0 0) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "log2_logMemStartTooHigh": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (MSTORE 0 0xaabbffffffffffffffffffffffffffffffffffffffffffffffffffffffffccdd) (LOG2 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 1 0 0) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "log2_logMemsizeTooHigh": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (MSTORE 0 0xaabbffffffffffffffffffffffffffffffffffffffffffffffffffffffffccdd) (LOG2 1 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 0 0) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "log2_logMemsizeZero": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (MSTORE 0 0xaabbffffffffffffffffffffffffffffffffffffffffffffffffffffffffccdd) (LOG2 1 0 0 0) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "log2_MaxTopic": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (MSTORE 0 0xaabbffffffffffffffffffffffffffffffffffffffffffffffffffffffffccdd) (LOG2 0 32 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "log2_Caller": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (MSTORE8 0 0xff) (LOG2 0 32 0 (CALLER) ) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "log3_emptyMem": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (LOG3 0 0 0 0 0) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "log3_nonEmptyMem": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (LOG3 0 32 0 0 0) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "log3_nonEmptyMem_logMemSize1": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (MSTORE 0 0xaabbffffffffffffffffffffffffffffffffffffffffffffffffffffffffccdd) (LOG3 0 1 0 0 0) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + + "log3_nonEmptyMem_logMemSize1_logMemStart31": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (MSTORE 0 0xaabbffffffffffffffffffffffffffffffffffffffffffffffffffffffffccdd) (LOG3 31 1 0 0 0) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "log3_logMemStartTooHigh": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (MSTORE 0 0xaabbffffffffffffffffffffffffffffffffffffffffffffffffffffffffccdd) (LOG3 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 1 0 0 0) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "log3_logMemsizeTooHigh": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (MSTORE 0 0xaabbffffffffffffffffffffffffffffffffffffffffffffffffffffffffccdd) (LOG3 1 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 0 0 0) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "log3_logMemsizeZero": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (MSTORE 0 0xaabbffffffffffffffffffffffffffffffffffffffffffffffffffffffffccdd) (LOG3 1 0 0 0 0) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "log3_MaxTopic": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (MSTORE 0 0xaabbffffffffffffffffffffffffffffffffffffffffffffffffffffffffccdd) (LOG3 0 32 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "log3_Caller": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (MSTORE8 0 0xff) (LOG3 0 32 0 0 (CALLER) ) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "log3_PC": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (MSTORE8 0 0xff) (LOG3 0 32 (PC) (PC) (PC) ) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "log4_emptyMem": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (LOG4 0 0 0 0 0 0) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "log4_nonEmptyMem": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (LOG4 0 32 0 0 0 0) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "log4_nonEmptyMem_logMemSize1": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (MSTORE 0 0xaabbffffffffffffffffffffffffffffffffffffffffffffffffffffffffccdd) (LOG4 0 1 0 0 0 0) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + + "log4_nonEmptyMem_logMemSize1_logMemStart31": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (MSTORE 0 0xaabbffffffffffffffffffffffffffffffffffffffffffffffffffffffffccdd) (LOG4 31 1 0 0 0 0) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "log4_logMemStartTooHigh": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (MSTORE 0 0xaabbffffffffffffffffffffffffffffffffffffffffffffffffffffffffccdd) (LOG4 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 1 0 0 0 0) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "log4_logMemsizeTooHigh": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (MSTORE 0 0xaabbffffffffffffffffffffffffffffffffffffffffffffffffffffffffccdd) (LOG4 1 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 0 0 0 0) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "log4_logMemsizeZero": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (MSTORE 0 0xaabbffffffffffffffffffffffffffffffffffffffffffffffffffffffffccdd) (LOG4 1 0 0 0 0 0) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "log4_MaxTopic": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (MSTORE 0 0xaabbffffffffffffffffffffffffffffffffffffffffffffffffffffffffccdd) (LOG4 0 32 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "log4_Caller": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (MSTORE8 0 0xff) (LOG3 0 32 0 0 0 (CALLER) ) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + + "log4_PC": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -96,7 +1249,7 @@ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "{ (LOG2 0 0 (CALLER) 23) }", + "code" : "{ (MSTORE8 0 0xff) (LOG3 0 32 (PC) (PC) (PC) (PC) ) }", "storage": {} } }, From b5210dd1c8d1c3229f5e28655f2ffec3306f2d16 Mon Sep 17 00:00:00 2001 From: Christoph Jentzsch Date: Wed, 19 Nov 2014 18:39:53 +0100 Subject: [PATCH 10/86] add make money test --- test/stSpecialTestFiller.json | 41 +++++++++++++++++++++++++++++++++++ test/state.cpp | 5 +++++ 2 files changed, 46 insertions(+) create mode 100644 test/stSpecialTestFiller.json diff --git a/test/stSpecialTestFiller.json b/test/stSpecialTestFiller.json new file mode 100644 index 000000000..fcb1d74a6 --- /dev/null +++ b/test/stSpecialTestFiller.json @@ -0,0 +1,41 @@ +{ + "makeMoney" : { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ (MSTORE 0 0x601080600c6000396000f20060003554156009570060203560003555) (CALL 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec 0xaaaaaaaaace5edbc8e2a8697c15331677e6ebf0b 23 0 0 0 0) }", + "storage": {} + }, + "aaaaaaaaace5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "0x600160015532600255", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000", + "nonce" : 0, + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "850", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "10", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + } +} diff --git a/test/state.cpp b/test/state.cpp index b5b238299..8ee7b2e96 100644 --- a/test/state.cpp +++ b/test/state.cpp @@ -122,6 +122,11 @@ BOOST_AUTO_TEST_CASE(stPreCompiledContracts) dev::test::executeTests("stPreCompiledContracts", "/StateTests", dev::test::doStateTests); } +BOOST_AUTO_TEST_CASE(stSpecialTest) +{ + dev::test::executeTests("stSpecialTest", "/StateTests", dev::test::doStateTests); +} + BOOST_AUTO_TEST_CASE(stCreateTest) { for (int i = 1; i < boost::unit_test::framework::master_test_suite().argc; ++i) From d84ec425e790b0a1265484ffed5869b3b8356b26 Mon Sep 17 00:00:00 2001 From: yann300 Date: Wed, 19 Nov 2014 20:25:37 +0100 Subject: [PATCH 11/86] m1 --- mix/ApplicationContext.cpp | 33 ++++++++++++ mix/ApplicationContext.h | 23 +++++++++ mix/BasicContent.qml | 36 +++++++++++++ mix/CMakeLists.txt | 94 ++++++++++++++++++++++++++++++++++ mix/CodeEditorExtensionMan.cpp | 60 ++++++++++++++++++++++ mix/CodeEditorExtensionMan.h | 28 ++++++++++ mix/ConstantCompilation.cpp | 88 +++++++++++++++++++++++++++++++ mix/ConstantCompilation.h | 26 ++++++++++ mix/ContextualTabs.qml | 5 ++ mix/Feature.cpp | 33 ++++++++++++ mix/Feature.h | 21 ++++++++ mix/MainContent.qml | 47 +++++++++++++++++ mix/Qt47supp.txt | 29 +++++++++++ mix/TabStyle.qml | 24 +++++++++ mix/main.cpp | 19 +++++++ mix/main.qml | 27 ++++++++++ mix/mix.pro | 19 +++++++ mix/qml.qrc | 8 +++ 18 files changed, 620 insertions(+) create mode 100644 mix/ApplicationContext.cpp create mode 100644 mix/ApplicationContext.h create mode 100644 mix/BasicContent.qml create mode 100644 mix/CMakeLists.txt create mode 100644 mix/CodeEditorExtensionMan.cpp create mode 100644 mix/CodeEditorExtensionMan.h create mode 100644 mix/ConstantCompilation.cpp create mode 100644 mix/ConstantCompilation.h create mode 100644 mix/ContextualTabs.qml create mode 100644 mix/Feature.cpp create mode 100644 mix/Feature.h create mode 100644 mix/MainContent.qml create mode 100644 mix/Qt47supp.txt create mode 100644 mix/TabStyle.qml create mode 100644 mix/main.cpp create mode 100644 mix/main.qml create mode 100644 mix/mix.pro create mode 100644 mix/qml.qrc diff --git a/mix/ApplicationContext.cpp b/mix/ApplicationContext.cpp new file mode 100644 index 000000000..dcbb6d958 --- /dev/null +++ b/mix/ApplicationContext.cpp @@ -0,0 +1,33 @@ +#include "ApplicationContext.h" +#include + +ApplicationContext* ApplicationContext::m_instance = nullptr; + +ApplicationContext::ApplicationContext(QQmlApplicationEngine* _engine) +{ + m_applicationEngine = _engine; +} + +ApplicationContext::~ApplicationContext() +{ + delete m_applicationEngine; +} + +ApplicationContext* ApplicationContext::GetInstance() +{ + return m_instance; +} + +void ApplicationContext::SetApplicationContext(QQmlApplicationEngine* engine) +{ + m_instance = new ApplicationContext(engine); +} + +QQmlApplicationEngine* ApplicationContext::appEngine(){ + return m_applicationEngine; +} + +void ApplicationContext::QuitApplication() +{ + delete m_instance; +} diff --git a/mix/ApplicationContext.h b/mix/ApplicationContext.h new file mode 100644 index 000000000..154a4120e --- /dev/null +++ b/mix/ApplicationContext.h @@ -0,0 +1,23 @@ +#ifndef APPLICATIONCONTEXT_H +#define APPLICATIONCONTEXT_H + +#include + +class ApplicationContext : public QObject +{ + Q_OBJECT + +public: + ApplicationContext(QQmlApplicationEngine*); + ~ApplicationContext(); + QQmlApplicationEngine* appEngine(); + static ApplicationContext* GetInstance(); + static void SetApplicationContext(QQmlApplicationEngine*); +private: + static ApplicationContext* m_instance; + QQmlApplicationEngine* m_applicationEngine; +public slots: + void QuitApplication(); +}; + +#endif // APPLICATIONCONTEXT_H diff --git a/mix/BasicContent.qml b/mix/BasicContent.qml new file mode 100644 index 000000000..a61ee8b8f --- /dev/null +++ b/mix/BasicContent.qml @@ -0,0 +1,36 @@ +import QtQuick 2.3 +import QtQuick.Controls 1.2 + +Rectangle { + anchors.fill: parent + width: parent.width + height: parent.height + color: "lightgray" + Text { + font.pointSize: 7 + anchors.left: parent.left + anchors.top: parent.top + anchors.topMargin: 3 + anchors.leftMargin: 3 + height: 9 + font.family: "Sego UI light" + objectName: "status" + id: status + } + + TextArea{ + readOnly: true + anchors.left: parent.left + anchors.leftMargin: 10 + anchors.top: status.bottom + anchors.topMargin: 3 + font.pointSize: 7 + font.family: "Sego UI light" + height: parent.height * 0.8 + width: parent.width - 20 + wrapMode: Text.Wrap + backgroundVisible: false + objectName: "content" + id: content + } +} diff --git a/mix/CMakeLists.txt b/mix/CMakeLists.txt new file mode 100644 index 000000000..7272c4d99 --- /dev/null +++ b/mix/CMakeLists.txt @@ -0,0 +1,94 @@ +set(CMAKE_INCLUDE_CURRENT_DIR ON) +aux_source_directory(. SRC_LIST) +include_directories(..) + +if (APPLE) + # Add homebrew path for qt5 + set(CMAKE_PREFIX_PATH /usr/local/opt/qt5) + include_directories(/usr/local/opt/qt5/include /usr/local/include) +elseif ("${TARGET_PLATFORM}" STREQUAL "w64") + set(SRC_LIST ${SRC_LIST} ../windows/qt_plugin_import.cpp) + include_directories(/usr/x86_64-w64-mingw32/include /usr/x86_64-w64-mingw32/include/QtCore /usr/x86_64-w64-mingw32/include/QtGui /usr/x86_64-w64-mingw32/include/QtQuick /usr/x86_64-w64-mingw32/include/QtQml /usr/x86_64-w64-mingw32/include/QtNetwork /usr/x86_64-w64-mingw32/include/QtWidgets /usr/x86_64-w64-mingw32/include/QtWebKit /usr/x86_64-w64-mingw32/include/QtWebKitWidgets) +elseif (UNIX) + set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} ";$ENV{QTDIR}/lib/cmake" /opt/Qt5.3.2/5.3/gcc_64/lib/cmake/Qt5Declarative) +endif () + +find_package(Qt5Core REQUIRED) +find_package(Qt5Gui REQUIRED) +find_package(Qt5Quick REQUIRED) +find_package(Qt5Qml REQUIRED) +find_package(Qt5Network REQUIRED) +find_package(Qt5Widgets REQUIRED) +find_package(Qt5WebKit REQUIRED) +find_package(Qt5WebKitWidgets REQUIRED) +find_package(Qt5Declarative REQUIRED) + +#qt5_wrap_ui(ui_Main.h Main.ui) + +qt5_add_resources(UI_RESOURCES qml.qrc) + +# Set name of binary and add_executable() +file(GLOB HEADERS "*.h") +if (APPLE) + set(EXECUTEABLE mix) + set(BIN_INSTALL_DIR ".") + set(DOC_INSTALL_DIR ".") + + set(PROJECT_VERSION "${ETH_VERSION}") + set(MACOSX_BUNDLE_INFO_STRING "${PROJECT_NAME} ${PROJECT_VERSION}") + set(MACOSX_BUNDLE_BUNDLE_VERSION "${PROJECT_NAME} ${PROJECT_VERSION}") + set(MACOSX_BUNDLE_LONG_VERSION_STRING "${PROJECT_NAME} ${PROJECT_VERSION}") + set(MACOSX_BUNDLE_SHORT_VERSION_STRING "${PROJECT_VERSION}") + set(MACOSX_BUNDLE_COPYRIGHT "${PROJECT_COPYRIGHT_YEAR} ${PROJECT_VENDOR}") + set(MACOSX_BUNDLE_GUI_IDENTIFIER "${PROJECT_DOMAIN_SECOND}.${PROJECT_DOMAIN_FIRST}") + set(MACOSX_BUNDLE_BUNDLE_NAME ${EXECUTEABLE}) + set(MACOSX_BUNDLE_ICON_FILE mix) + include(BundleUtilities) + + add_executable(${EXECUTEABLE} MACOSX_BUNDLE ${SRC_LIST} ${HEADERS} ${UI_RESOURCES}) + set_target_properties(${EXECUTEABLE} PROPERTIES MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/EthereumMacOSXBundleInfo.plist.in") + SET_SOURCE_FILES_PROPERTIES(${EXECUTEABLE} PROPERTIES MACOSX_PACKAGE_LOCATION MacOS) + SET_SOURCE_FILES_PROPERTIES(${MACOSX_BUNDLE_ICON_FILE}.icns PROPERTIES MACOSX_PACKAGE_LOCATION "Resources") + +else () + set(EXECUTEABLE mix) + add_executable(${EXECUTEABLE} ${SRC_LIST} ${HEADERS} ${UI_RESOURCES}) +endif () + +qt5_use_modules(${EXECUTEABLE} Core)# Gui Widgets Network WebKit WebKitWidgets) +target_link_libraries(${EXECUTEABLE} webthree qethereum ethereum evm ethcore devcrypto secp256k1 gmp ${CRYPTOPP_LS} serpent lll solidity evmcore devcore web3jsonrpc jsqrc) + +if (APPLE) + # First have qt5 install plugins and frameworks + add_custom_command(TARGET ${EXECUTEABLE} POST_BUILD + COMMAND /usr/local/opt/qt5/bin/macdeployqt ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${EXECUTEABLE}.app + WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) + + # This tool and next will inspect linked libraries in order to determine which dependencies are required + if (${CMAKE_CFG_INTDIR} STREQUAL ".") + set(APP_BUNDLE_PATH "${CMAKE_CURRENT_BINARY_DIR}/${EXECUTEABLE}.app") + else () + set(APP_BUNDLE_PATH "${CMAKE_CURRENT_BINARY_DIR}/\$ENV{CONFIGURATION}/${EXECUTEABLE}.app") + endif () + install(CODE " + include(BundleUtilities) + set(BU_CHMOD_BUNDLE_ITEMS 1) + fixup_bundle(\"${APP_BUNDLE_PATH}\" \"${BUNDLELIBS}\" \"../libqethereum ../libethereum ../secp256k1\") + " COMPONENT RUNTIME ) + # Cleanup duplicate libs from macdeployqt + install(CODE " + file(GLOB LINGER_RM \"${APP_BUNDLE_PATH}/Contents/Frameworks/*.dylib\") + if (LINGER_RM) + file(REMOVE \${LINGER_RM}) + endif () + ") +elseif (UNIX) +else () + target_link_libraries(${EXECUTEABLE} boost_system) + target_link_libraries(${EXECUTEABLE} boost_filesystem) + find_package(Threads REQUIRED) + target_link_libraries(${EXECUTEABLE} ${CMAKE_THREAD_LIBS_INIT}) + install( TARGETS ${EXECUTEABLE} RUNTIME DESTINATION bin ) +endif () + +qt5_use_modules(${EXECUTEABLE} Core Gui Declarative) diff --git a/mix/CodeEditorExtensionMan.cpp b/mix/CodeEditorExtensionMan.cpp new file mode 100644 index 000000000..1c845dbbf --- /dev/null +++ b/mix/CodeEditorExtensionMan.cpp @@ -0,0 +1,60 @@ +#include +#include +#include +#include +#include +#include +#include +#include "CodeEditorExtensionMan.h" +#include "ConstantCompilation.h" +#include "features.h" +#include "ApplicationContext.h" +#include +using namespace dev; + +CodeEditorExtensionManager::CodeEditorExtensionManager() +{ +} + +void CodeEditorExtensionManager::loadEditor(QQuickItem* _editor) +{ + if (!_editor) + return; + try{ + QVariant doc = _editor->property("textDocument"); + if (doc.canConvert()) { + QQuickTextDocument* qqdoc = doc.value(); + if (qqdoc) { + m_doc = qqdoc->textDocument(); + } + } + } + catch (dev::Exception const& exception){ + qDebug() << "unable to load editor: "; + qDebug() << exception.what(); + } +} + +void CodeEditorExtensionManager::initExtensions() +{ + try{ + //only one for now + ConstantCompilation* compil = new ConstantCompilation(m_doc); + if (compil->tabUrl() != "") + compil->addContentOn(m_tabView); + compil->start(); + } + catch (dev::Exception const& exception){ + qDebug() << "unable to load extensions: "; + qDebug() << exception.what(); + } +} + +void CodeEditorExtensionManager::setEditor(QQuickItem* _editor){ + this->loadEditor(_editor); + this->initExtensions(); +} + +void CodeEditorExtensionManager::setTabView(QQuickItem* _tabView){ + m_tabView = _tabView; +} diff --git a/mix/CodeEditorExtensionMan.h b/mix/CodeEditorExtensionMan.h new file mode 100644 index 000000000..cfe505c09 --- /dev/null +++ b/mix/CodeEditorExtensionMan.h @@ -0,0 +1,28 @@ +#ifndef CODEEDITOREXTENSIONMANAGER_H +#define CODEEDITOREXTENSIONMANAGER_H + +#include +#include +#include "Feature.h" + +class CodeEditorExtensionManager : public QObject +{ + Q_OBJECT + + Q_PROPERTY(QQuickItem* editor MEMBER m_editor WRITE setEditor) + Q_PROPERTY(QQuickItem* tabView MEMBER m_tabView WRITE setTabView) + +public: + CodeEditorExtensionManager(); + void initExtensions(); + void setEditor(QQuickItem*); + void setTabView(QQuickItem*); + +private: + QQuickItem* m_editor; + QQuickItem* m_tabView; + QTextDocument* m_doc; + void loadEditor(QQuickItem*); +}; + +#endif // CODEEDITOREXTENSIONMANAGER_H diff --git a/mix/ConstantCompilation.cpp b/mix/ConstantCompilation.cpp new file mode 100644 index 000000000..76fbd1546 --- /dev/null +++ b/mix/ConstantCompilation.cpp @@ -0,0 +1,88 @@ +#include "ConstantCompilation.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +using namespace std; +using namespace dev; +using namespace dev::eth; + +ConstantCompilation::ConstantCompilation(QTextDocument* _doc) +{ + m_editor = _doc; +} + +QString ConstantCompilation::tabUrl(){ + return QStringLiteral("qrc:/BasicContent.qml"); +} + +void ConstantCompilation::start() +{ + connect(m_editor, SIGNAL(contentsChange(int,int,int)), this, SLOT(compile())); +} + +QString ConstantCompilation::title() +{ + return "compilation"; +} + +void ConstantCompilation::compile() +{ + QString codeContent = m_editor->toPlainText(); + if (codeContent == ""){ + this->writeOutPut(true, codeContent); + return; + } + dev::solidity::CompilerStack compiler; + dev::bytes m_data; + QString content; + try + { + m_data = compiler.compile(codeContent.toStdString(), true); + content = QString::fromStdString(dev::eth::disassemble(m_data)); + this->writeOutPut(true, content); + } + catch (dev::Exception const& exception) + { + ostringstream error; + solidity::SourceReferenceFormatter::printExceptionInformation(error, exception, "Error", compiler.getScanner()); + content = QString::fromStdString(error.str()).toHtmlEscaped(); + this->writeOutPut(false, content); + } + catch (...) + { + content = "Uncaught exception."; + this->writeOutPut(false, content); + } + +} +void ConstantCompilation::writeOutPut(bool _success, QString _content){ + QObject* status = m_view->findChild("status", Qt::FindChildrenRecursively); + QObject* content = m_view->findChild("content", Qt::FindChildrenRecursively); + if (_content == ""){ + status->setProperty("text", ""); + content->setProperty("text", ""); + } + else if (_success){ + status->setProperty("text", "compile successfull"); + status->setProperty("color", "green"); + content->setProperty("text", _content); + qDebug() << QString("compile suceeded " + _content); + } + else { + status->setProperty("text", "compile failed"); + status->setProperty("color", "red"); + content->setProperty("text", _content); + qDebug() << QString("compile failed " + _content); + } +} + + + + diff --git a/mix/ConstantCompilation.h b/mix/ConstantCompilation.h new file mode 100644 index 000000000..c3c93b8aa --- /dev/null +++ b/mix/ConstantCompilation.h @@ -0,0 +1,26 @@ +#ifndef CONSTANTCOMPILATION_H +#define CONSTANTCOMPILATION_H + +#include +#include "Feature.h" + +class ConstantCompilation : public Feature +{ + Q_OBJECT + +public: + ConstantCompilation(QTextDocument* doc); + void start(); + QString title(); + QString tabUrl(); + +private: + QTextDocument* m_editor; + void writeOutPut(bool success, QString content); + +public Q_SLOTS: + void compile(); + +}; + +#endif // CONSTANTCOMPILATION_H diff --git a/mix/ContextualTabs.qml b/mix/ContextualTabs.qml new file mode 100644 index 000000000..d32e6c3af --- /dev/null +++ b/mix/ContextualTabs.qml @@ -0,0 +1,5 @@ +import QtQuick 2.3 +import QtQuick.Controls 1.2 + + + diff --git a/mix/Feature.cpp b/mix/Feature.cpp new file mode 100644 index 000000000..028dca8bd --- /dev/null +++ b/mix/Feature.cpp @@ -0,0 +1,33 @@ +#include "Feature.h" +#include "ApplicationContext.h" +#include +#include +#include +using namespace dev; + +Feature::Feature() +{ +} + +void Feature::addContentOn(QObject* tabView) { + try{ + if (tabUrl() == "") + return; + + QVariant returnValue; + QQmlComponent* component = new QQmlComponent( + ApplicationContext::GetInstance()->appEngine(), + QUrl(this->tabUrl())); + + QMetaObject::invokeMethod(tabView, "addTab", + Q_RETURN_ARG(QVariant, returnValue), + Q_ARG(QVariant, this->title()), + Q_ARG(QVariant, QVariant::fromValue(component))); + + m_view = qvariant_cast(returnValue); + } + catch (dev::Exception const& exception){ + qDebug() << exception.what(); + } +} + diff --git a/mix/Feature.h b/mix/Feature.h new file mode 100644 index 000000000..5a51f928d --- /dev/null +++ b/mix/Feature.h @@ -0,0 +1,21 @@ +#ifndef FEATURE_H +#define FEATURE_H + +#include +#include + +class Feature : public QObject +{ + Q_OBJECT + +public: + Feature(); + virtual QString tabUrl() { return ""; } + virtual QString title() { return ""; } + void addContentOn(QObject* tabView); + +protected: + QObject* m_view; +}; + +#endif // FEATURE_H diff --git a/mix/MainContent.qml b/mix/MainContent.qml new file mode 100644 index 000000000..d1170b185 --- /dev/null +++ b/mix/MainContent.qml @@ -0,0 +1,47 @@ +import QtQuick 2.3 +import QtQuick.Controls 1.2 +import QtQuick.Layouts 1.0 +import QtQuick.Controls.Styles 1.2 +import CodeEditorExtensionManager 1.0 + +Rectangle { + anchors.fill: parent + height: parent.height + width: parent.width; + id:root + SplitView { + anchors.fill: parent + orientation: Qt.Vertical + Rectangle { + anchors.top : parent.top + id: contentView + width: parent.width + height: parent.height * 0.7 + TextArea { + id: codeEditor + height: parent.height + font.family: "Verdana" + font.pointSize: 9 + width: parent.width + anchors.centerIn: parent + } + } + Rectangle { + anchors.bottom: parent.bottom + id: contextualView + width: parent.width + Layout.minimumHeight: 20 + height: parent.height * 0.3 + TabView { + id: contextualTabs + antialiasing: true + anchors.fill: parent + style: TabStyle{} + } + } + CodeEditorExtensionManager{ + tabView: contextualTabs + editor: codeEditor + } + } +} diff --git a/mix/Qt47supp.txt b/mix/Qt47supp.txt new file mode 100644 index 000000000..1da4f51bf --- /dev/null +++ b/mix/Qt47supp.txt @@ -0,0 +1,29 @@ +{ + + Memcheck:Cond + fun:_ZN20QSharedMemoryPrivate6detachEv + fun:_ZN13QSharedMemory6detachEv + fun:_ZN13QSharedMemory6setKeyERK7QString + fun:_ZN13QSharedMemoryD1Ev + fun:_ZN20QRasterWindowSurface5flushEP7QWidgetRK7QRegionRK6QPoint + fun:_Z8qt_flushP7QWidgetRK7QRegionP14QWindowSurfaceS0_RK6QPoint + fun:_ZN19QWidgetBackingStore5flushEP7QWidgetP14QWindowSurface + fun:_ZN19QWidgetBackingStore8endPaintERK7QRegionP14QWindowSurfaceP14BeginPaintInfo + fun:_ZN19QWidgetBackingStore4syncEv + fun:_ZN14QWidgetPrivate16syncBackingStoreEv + fun:_ZN7QWidget5eventEP6QEvent + fun:_ZN11QMainWindow5eventEP6QEvent +} +{ + + Memcheck:Leak + fun:_Znwm + fun:_ZN18QtSimulatorPrivate15connectToServerEv + fun:_ZN18QtSimulatorPrivate19SimulatorConnection18connectToSimulatorEv + fun:_ZN18QtSimulatorPrivate19SimulatorConnection8instanceEv + fun:_ZN9QColormap10initializeEv + fun:_Z7qt_initP19QApplicationPrivatei + fun:_ZN19QApplicationPrivate9constructEv + fun:_ZN12QApplicationC1ERiPPci + fun:main +} diff --git a/mix/TabStyle.qml b/mix/TabStyle.qml new file mode 100644 index 000000000..df31f9910 --- /dev/null +++ b/mix/TabStyle.qml @@ -0,0 +1,24 @@ +import QtQuick 2.3 +import QtQuick.Controls 1.2 +import QtQuick.Controls.Styles 1.2 + +TabViewStyle { + frameOverlap: 1 + tabBar: Rectangle { + color: "lightgray" + } + tab: Rectangle { + + color: "lightsteelblue" + implicitWidth: Math.max(text.width + 4, 80) + implicitHeight: 20 + radius: 2 + Text { + id: text + anchors.centerIn: parent + text: styleData.title + color: styleData.selected ? "white" : "black" + } + } + frame: Rectangle { color: "steelblue" } +} diff --git a/mix/main.cpp b/mix/main.cpp new file mode 100644 index 000000000..3aa0cb85a --- /dev/null +++ b/mix/main.cpp @@ -0,0 +1,19 @@ +#include +#include +#include +#include "CodeEditorExtensionMan.h" +#include "ApplicationContext.h" + +int main(int argc, char *argv[]) +{ + QApplication app(argc, argv); + QQmlApplicationEngine* engine = new QQmlApplicationEngine(); + qmlRegisterType("CodeEditorExtensionManager", 1, 0, "CodeEditorExtensionManager"); + + ApplicationContext::SetApplicationContext(engine); + QObject::connect(&app, SIGNAL(lastWindowClosed()), ApplicationContext::GetInstance(), SLOT(QuitApplication())); //use to kill ApplicationContext and other stuff + + engine->load(QUrl(QStringLiteral("qrc:/main.qml"))); + return app.exec(); +} + diff --git a/mix/main.qml b/mix/main.qml new file mode 100644 index 000000000..6486c1dfd --- /dev/null +++ b/mix/main.qml @@ -0,0 +1,27 @@ +import QtQuick 2.3 +import QtQuick.Controls 1.2 +import QtQuick.Controls.Styles 1.2 +import CodeEditorExtensionManager 1.0 + +ApplicationWindow { + + visible: true + width: 1000 + height: 480 + minimumWidth: 400 + minimumHeight: 300 + title: qsTr("mix") + + menuBar: MenuBar { + Menu { + title: qsTr("File") + MenuItem { + text: qsTr("Exit") + onTriggered: Qt.quit(); + } + } + } + + MainContent{ + } +} diff --git a/mix/mix.pro b/mix/mix.pro new file mode 100644 index 000000000..6595db37f --- /dev/null +++ b/mix/mix.pro @@ -0,0 +1,19 @@ +TEMPLATE = app + +QT += qml quick widgets + +SOURCES += main.cpp \ + CodeEditorExtensionManager.cpp \ + ConstantCompilation.cpp + +RESOURCES += qml.qrc + +# Additional import path used to resolve QML modules in Qt Creator's code model +QML_IMPORT_PATH = + +# Default rules for deployment. +include(deployment.pri) + +HEADERS += \ + CodeEditorExtensionManager.h \ + ConstantCompilation.h diff --git a/mix/qml.qrc b/mix/qml.qrc new file mode 100644 index 000000000..65dc7f826 --- /dev/null +++ b/mix/qml.qrc @@ -0,0 +1,8 @@ + + + main.qml + BasicContent.qml + TabStyle.qml + MainContent.qml + + From 4a870cda7b511cd4489532c01e5ec8fe37e5e00e Mon Sep 17 00:00:00 2001 From: yann300 Date: Thu, 20 Nov 2014 10:04:02 +0100 Subject: [PATCH 12/86] small changes --- CMakeLists.txt | 2 + mix/ApplicationContext.cpp | 33 ----------- mix/ApplicationCtx.cpp | 55 +++++++++++++++++++ ...{ApplicationContext.h => ApplicationCtx.h} | 12 ++-- mix/CodeEditorExtensionMan.cpp | 2 +- mix/ConstantCompilation.cpp | 10 ++-- mix/ConstantCompilation.h | 22 ++++++++ mix/Feature.cpp | 7 ++- mix/Feature.h | 22 ++++++++ mix/MainContent.qml | 7 +++ mix/main.cpp | 28 +++++++++- 11 files changed, 149 insertions(+), 51 deletions(-) delete mode 100644 mix/ApplicationContext.cpp create mode 100644 mix/ApplicationCtx.cpp rename mix/{ApplicationContext.h => ApplicationCtx.h} (57%) diff --git a/CMakeLists.txt b/CMakeLists.txt index d8c517fef..e3a7d9b83 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -158,6 +158,7 @@ if (NOT LANGUAGES) add_subdirectory(libqethereum) add_subdirectory(alethzero) add_subdirectory(third) + add_subdirectory(mix) if(QTQML) #add_subdirectory(iethxi) #add_subdirectory(walleth) // resurect once we want to submit ourselves to QML. @@ -171,3 +172,4 @@ add_test(NAME alltests WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/test COMMAND testet #unset(TARGET_PLATFORM CACHE) + diff --git a/mix/ApplicationContext.cpp b/mix/ApplicationContext.cpp deleted file mode 100644 index dcbb6d958..000000000 --- a/mix/ApplicationContext.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include "ApplicationContext.h" -#include - -ApplicationContext* ApplicationContext::m_instance = nullptr; - -ApplicationContext::ApplicationContext(QQmlApplicationEngine* _engine) -{ - m_applicationEngine = _engine; -} - -ApplicationContext::~ApplicationContext() -{ - delete m_applicationEngine; -} - -ApplicationContext* ApplicationContext::GetInstance() -{ - return m_instance; -} - -void ApplicationContext::SetApplicationContext(QQmlApplicationEngine* engine) -{ - m_instance = new ApplicationContext(engine); -} - -QQmlApplicationEngine* ApplicationContext::appEngine(){ - return m_applicationEngine; -} - -void ApplicationContext::QuitApplication() -{ - delete m_instance; -} diff --git a/mix/ApplicationCtx.cpp b/mix/ApplicationCtx.cpp new file mode 100644 index 000000000..1c8ed9820 --- /dev/null +++ b/mix/ApplicationCtx.cpp @@ -0,0 +1,55 @@ +/* + 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 main.cpp + * @author Gav Wood + * @date 2014 + * Ethereum client. + */ + +#include "ApplicationCtx.h" +#include + +ApplicationCtx* ApplicationCtx::m_instance = nullptr; + +ApplicationCtx::ApplicationCtx(QQmlApplicationEngine* _engine) +{ + m_applicationEngine = _engine; +} + +ApplicationCtx::~ApplicationCtx() +{ + delete m_applicationEngine; +} + +ApplicationCtx* ApplicationCtx::GetInstance() +{ + return m_instance; +} + +void ApplicationCtx::SetApplicationContext(QQmlApplicationEngine* engine) +{ + m_instance = new ApplicationCtx(engine); +} + +QQmlApplicationEngine* ApplicationCtx::appEngine(){ + return m_applicationEngine; +} + +void ApplicationCtx::QuitApplication() +{ + delete m_instance; +} diff --git a/mix/ApplicationContext.h b/mix/ApplicationCtx.h similarity index 57% rename from mix/ApplicationContext.h rename to mix/ApplicationCtx.h index 154a4120e..f54eb7f09 100644 --- a/mix/ApplicationContext.h +++ b/mix/ApplicationCtx.h @@ -3,21 +3,21 @@ #include -class ApplicationContext : public QObject +class ApplicationCtx : public QObject { Q_OBJECT public: - ApplicationContext(QQmlApplicationEngine*); - ~ApplicationContext(); + ApplicationCtx(QQmlApplicationEngine*); + ~ApplicationCtx(); QQmlApplicationEngine* appEngine(); - static ApplicationContext* GetInstance(); + static ApplicationCtx* GetInstance(); static void SetApplicationContext(QQmlApplicationEngine*); private: - static ApplicationContext* m_instance; + static ApplicationCtx* m_instance; QQmlApplicationEngine* m_applicationEngine; public slots: void QuitApplication(); }; -#endif // APPLICATIONCONTEXT_H +#endif // APPLICATIONCTX_H diff --git a/mix/CodeEditorExtensionMan.cpp b/mix/CodeEditorExtensionMan.cpp index 1c845dbbf..d9691fb42 100644 --- a/mix/CodeEditorExtensionMan.cpp +++ b/mix/CodeEditorExtensionMan.cpp @@ -8,7 +8,7 @@ #include "CodeEditorExtensionMan.h" #include "ConstantCompilation.h" #include "features.h" -#include "ApplicationContext.h" +#include "ApplicationCtx.h" #include using namespace dev; diff --git a/mix/ConstantCompilation.cpp b/mix/ConstantCompilation.cpp index 76fbd1546..8a2d14af9 100644 --- a/mix/ConstantCompilation.cpp +++ b/mix/ConstantCompilation.cpp @@ -29,7 +29,7 @@ void ConstantCompilation::start() QString ConstantCompilation::title() { - return "compilation"; + return "compiler"; } void ConstantCompilation::compile() @@ -60,8 +60,8 @@ void ConstantCompilation::compile() content = "Uncaught exception."; this->writeOutPut(false, content); } - } + void ConstantCompilation::writeOutPut(bool _success, QString _content){ QObject* status = m_view->findChild("status", Qt::FindChildrenRecursively); QObject* content = m_view->findChild("content", Qt::FindChildrenRecursively); @@ -70,13 +70,13 @@ void ConstantCompilation::writeOutPut(bool _success, QString _content){ content->setProperty("text", ""); } else if (_success){ - status->setProperty("text", "compile successfull"); + status->setProperty("text", "succeeded"); status->setProperty("color", "green"); content->setProperty("text", _content); - qDebug() << QString("compile suceeded " + _content); + qDebug() << QString("compile succeeded " + _content); } else { - status->setProperty("text", "compile failed"); + status->setProperty("text", "failure"); status->setProperty("color", "red"); content->setProperty("text", _content); qDebug() << QString("compile failed " + _content); diff --git a/mix/ConstantCompilation.h b/mix/ConstantCompilation.h index c3c93b8aa..ed99c6a5f 100644 --- a/mix/ConstantCompilation.h +++ b/mix/ConstantCompilation.h @@ -1,3 +1,25 @@ +/* + 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 ConstantCompilation.h + * @author Yann yann@ethdev.com + * @date 2014 + * Ethereum IDE client. + */ + #ifndef CONSTANTCOMPILATION_H #define CONSTANTCOMPILATION_H diff --git a/mix/Feature.cpp b/mix/Feature.cpp index 028dca8bd..f3239252f 100644 --- a/mix/Feature.cpp +++ b/mix/Feature.cpp @@ -1,5 +1,5 @@ #include "Feature.h" -#include "ApplicationContext.h" +#include "ApplicationCtx.h" #include #include #include @@ -16,8 +16,8 @@ void Feature::addContentOn(QObject* tabView) { QVariant returnValue; QQmlComponent* component = new QQmlComponent( - ApplicationContext::GetInstance()->appEngine(), - QUrl(this->tabUrl())); + ApplicationCtx::GetInstance()->appEngine(), + QUrl(this->tabUrl()), tabView); QMetaObject::invokeMethod(tabView, "addTab", Q_RETURN_ARG(QVariant, returnValue), @@ -25,6 +25,7 @@ void Feature::addContentOn(QObject* tabView) { Q_ARG(QVariant, QVariant::fromValue(component))); m_view = qvariant_cast(returnValue); + } catch (dev::Exception const& exception){ qDebug() << exception.what(); diff --git a/mix/Feature.h b/mix/Feature.h index 5a51f928d..7a53f3a44 100644 --- a/mix/Feature.h +++ b/mix/Feature.h @@ -1,3 +1,25 @@ +/* + 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 Feature.h + * @author Yann yann@ethdev.com + * @date 2014 + * Ethereum IDE client. + */ + #ifndef FEATURE_H #define FEATURE_H diff --git a/mix/MainContent.qml b/mix/MainContent.qml index d1170b185..abae4a37f 100644 --- a/mix/MainContent.qml +++ b/mix/MainContent.qml @@ -24,6 +24,13 @@ Rectangle { font.pointSize: 9 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 { diff --git a/mix/main.cpp b/mix/main.cpp index 3aa0cb85a..088830c3c 100644 --- a/mix/main.cpp +++ b/mix/main.cpp @@ -1,8 +1,30 @@ +/* + 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 main.cpp + * @author Yann yann@ethdev.com + * @date 2014 + * Ethereum IDE client. + */ + #include #include #include #include "CodeEditorExtensionMan.h" -#include "ApplicationContext.h" +#include "ApplicationCtx.h" int main(int argc, char *argv[]) { @@ -10,8 +32,8 @@ int main(int argc, char *argv[]) QQmlApplicationEngine* engine = new QQmlApplicationEngine(); qmlRegisterType("CodeEditorExtensionManager", 1, 0, "CodeEditorExtensionManager"); - ApplicationContext::SetApplicationContext(engine); - QObject::connect(&app, SIGNAL(lastWindowClosed()), ApplicationContext::GetInstance(), SLOT(QuitApplication())); //use to kill ApplicationContext and other stuff + ApplicationCtx::SetApplicationContext(engine); + QObject::connect(&app, SIGNAL(lastWindowClosed()), ApplicationCtx::GetInstance(), SLOT(QuitApplication())); //use to kill ApplicationContext and other stuff engine->load(QUrl(QStringLiteral("qrc:/main.qml"))); return app.exec(); From 860259c2a58e43ee96dfdc8a7ba9e08700166e1a Mon Sep 17 00:00:00 2001 From: yann300 Date: Thu, 20 Nov 2014 10:05:46 +0100 Subject: [PATCH 13/86] delete unused file --- mix/Qt47supp.txt | 29 ----------------------------- 1 file changed, 29 deletions(-) delete mode 100644 mix/Qt47supp.txt diff --git a/mix/Qt47supp.txt b/mix/Qt47supp.txt deleted file mode 100644 index 1da4f51bf..000000000 --- a/mix/Qt47supp.txt +++ /dev/null @@ -1,29 +0,0 @@ -{ - - Memcheck:Cond - fun:_ZN20QSharedMemoryPrivate6detachEv - fun:_ZN13QSharedMemory6detachEv - fun:_ZN13QSharedMemory6setKeyERK7QString - fun:_ZN13QSharedMemoryD1Ev - fun:_ZN20QRasterWindowSurface5flushEP7QWidgetRK7QRegionRK6QPoint - fun:_Z8qt_flushP7QWidgetRK7QRegionP14QWindowSurfaceS0_RK6QPoint - fun:_ZN19QWidgetBackingStore5flushEP7QWidgetP14QWindowSurface - fun:_ZN19QWidgetBackingStore8endPaintERK7QRegionP14QWindowSurfaceP14BeginPaintInfo - fun:_ZN19QWidgetBackingStore4syncEv - fun:_ZN14QWidgetPrivate16syncBackingStoreEv - fun:_ZN7QWidget5eventEP6QEvent - fun:_ZN11QMainWindow5eventEP6QEvent -} -{ - - Memcheck:Leak - fun:_Znwm - fun:_ZN18QtSimulatorPrivate15connectToServerEv - fun:_ZN18QtSimulatorPrivate19SimulatorConnection18connectToSimulatorEv - fun:_ZN18QtSimulatorPrivate19SimulatorConnection8instanceEv - fun:_ZN9QColormap10initializeEv - fun:_Z7qt_initP19QApplicationPrivatei - fun:_ZN19QApplicationPrivate9constructEv - fun:_ZN12QApplicationC1ERiPPci - fun:main -} From 2b2b1f1701e99b333f551df22200f2fa1811b809 Mon Sep 17 00:00:00 2001 From: yann300 Date: Thu, 20 Nov 2014 10:10:05 +0100 Subject: [PATCH 14/86] misc --- mix/ApplicationCtx.cpp | 6 +++--- mix/ApplicationCtx.h | 22 ++++++++++++++++++++++ mix/CodeEditorExtensionMan.cpp | 22 ++++++++++++++++++++++ mix/CodeEditorExtensionMan.h | 22 ++++++++++++++++++++++ mix/ConstantCompilation.cpp | 22 ++++++++++++++++++++++ mix/Feature.cpp | 22 ++++++++++++++++++++++ 6 files changed, 113 insertions(+), 3 deletions(-) diff --git a/mix/ApplicationCtx.cpp b/mix/ApplicationCtx.cpp index 1c8ed9820..7475c1b57 100644 --- a/mix/ApplicationCtx.cpp +++ b/mix/ApplicationCtx.cpp @@ -14,10 +14,10 @@ You should have received a copy of the GNU General Public License along with cpp-ethereum. If not, see . */ -/** @file main.cpp - * @author Gav Wood +/** @file ApplicationCtx.cpp + * @author Yann yann@ethdev.com * @date 2014 - * Ethereum client. + * Ethereum IDE client. */ #include "ApplicationCtx.h" diff --git a/mix/ApplicationCtx.h b/mix/ApplicationCtx.h index f54eb7f09..68806cc33 100644 --- a/mix/ApplicationCtx.h +++ b/mix/ApplicationCtx.h @@ -1,3 +1,25 @@ +/* + 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 ApplicationCtx.h + * @author Yann yann@ethdev.com + * @date 2014 + * Ethereum IDE client. + */ + #ifndef APPLICATIONCONTEXT_H #define APPLICATIONCONTEXT_H diff --git a/mix/CodeEditorExtensionMan.cpp b/mix/CodeEditorExtensionMan.cpp index d9691fb42..d1ad6c075 100644 --- a/mix/CodeEditorExtensionMan.cpp +++ b/mix/CodeEditorExtensionMan.cpp @@ -1,3 +1,25 @@ +/* + 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 CodeEditorExtensionMan.cpp + * @author Yann yann@ethdev.com + * @date 2014 + * Ethereum IDE client. + */ + #include #include #include diff --git a/mix/CodeEditorExtensionMan.h b/mix/CodeEditorExtensionMan.h index cfe505c09..32f435338 100644 --- a/mix/CodeEditorExtensionMan.h +++ b/mix/CodeEditorExtensionMan.h @@ -1,3 +1,25 @@ +/* + 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 CodeEditorExtensionMan.h + * @author Yann yann@ethdev.com + * @date 2014 + * Ethereum IDE client. + */ + #ifndef CODEEDITOREXTENSIONMANAGER_H #define CODEEDITOREXTENSIONMANAGER_H diff --git a/mix/ConstantCompilation.cpp b/mix/ConstantCompilation.cpp index 8a2d14af9..34f5b3967 100644 --- a/mix/ConstantCompilation.cpp +++ b/mix/ConstantCompilation.cpp @@ -1,3 +1,25 @@ +/* + 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 ConstantCompilation.cpp + * @author Yann yann@ethdev.com + * @date 2014 + * Ethereum IDE client. + */ + #include "ConstantCompilation.h" #include #include diff --git a/mix/Feature.cpp b/mix/Feature.cpp index f3239252f..309cf7eff 100644 --- a/mix/Feature.cpp +++ b/mix/Feature.cpp @@ -1,3 +1,25 @@ +/* + 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 Feature.cpp + * @author Yann yann@ethdev.com + * @date 2014 + * Ethereum IDE client. + */ + #include "Feature.h" #include "ApplicationCtx.h" #include From 37b9f56d305f867ccc3bc5d460b451be67022430 Mon Sep 17 00:00:00 2001 From: yann300 Date: Thu, 20 Nov 2014 10:12:11 +0100 Subject: [PATCH 15/86] gitignore --- mix/.gitignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 mix/.gitignore diff --git a/mix/.gitignore b/mix/.gitignore new file mode 100644 index 000000000..f96209dc3 --- /dev/null +++ b/mix/.gitignore @@ -0,0 +1 @@ +*.pro From c97e7199a7d133fb7b31b9e148a813881548e0f7 Mon Sep 17 00:00:00 2001 From: yann300 Date: Thu, 20 Nov 2014 10:18:48 +0100 Subject: [PATCH 16/86] delete pro file --- mix/mix.pro | 19 ------------------- 1 file changed, 19 deletions(-) delete mode 100644 mix/mix.pro diff --git a/mix/mix.pro b/mix/mix.pro deleted file mode 100644 index 6595db37f..000000000 --- a/mix/mix.pro +++ /dev/null @@ -1,19 +0,0 @@ -TEMPLATE = app - -QT += qml quick widgets - -SOURCES += main.cpp \ - CodeEditorExtensionManager.cpp \ - ConstantCompilation.cpp - -RESOURCES += qml.qrc - -# Additional import path used to resolve QML modules in Qt Creator's code model -QML_IMPORT_PATH = - -# Default rules for deployment. -include(deployment.pri) - -HEADERS += \ - CodeEditorExtensionManager.h \ - ConstantCompilation.h From e79d5709d0fae8011349b927fbf22d4ffdcec44c Mon Sep 17 00:00:00 2001 From: yann300 Date: Thu, 20 Nov 2014 10:25:25 +0100 Subject: [PATCH 17/86] put qml file in folder --- mix/ConstantCompilation.cpp | 2 +- mix/ContextualTabs.qml | 5 ----- mix/main.cpp | 2 +- mix/qml.qrc | 8 ++++---- mix/{ => qml}/BasicContent.qml | 0 mix/{ => qml}/MainContent.qml | 0 mix/{ => qml}/TabStyle.qml | 0 mix/{ => qml}/main.qml | 0 8 files changed, 6 insertions(+), 11 deletions(-) delete mode 100644 mix/ContextualTabs.qml rename mix/{ => qml}/BasicContent.qml (100%) rename mix/{ => qml}/MainContent.qml (100%) rename mix/{ => qml}/TabStyle.qml (100%) rename mix/{ => qml}/main.qml (100%) diff --git a/mix/ConstantCompilation.cpp b/mix/ConstantCompilation.cpp index 34f5b3967..72e7b2bfe 100644 --- a/mix/ConstantCompilation.cpp +++ b/mix/ConstantCompilation.cpp @@ -41,7 +41,7 @@ ConstantCompilation::ConstantCompilation(QTextDocument* _doc) } QString ConstantCompilation::tabUrl(){ - return QStringLiteral("qrc:/BasicContent.qml"); + return QStringLiteral("qrc:/qml/BasicContent.qml"); } void ConstantCompilation::start() diff --git a/mix/ContextualTabs.qml b/mix/ContextualTabs.qml deleted file mode 100644 index d32e6c3af..000000000 --- a/mix/ContextualTabs.qml +++ /dev/null @@ -1,5 +0,0 @@ -import QtQuick 2.3 -import QtQuick.Controls 1.2 - - - diff --git a/mix/main.cpp b/mix/main.cpp index 088830c3c..49b6e5195 100644 --- a/mix/main.cpp +++ b/mix/main.cpp @@ -35,7 +35,7 @@ int main(int argc, char *argv[]) ApplicationCtx::SetApplicationContext(engine); QObject::connect(&app, SIGNAL(lastWindowClosed()), ApplicationCtx::GetInstance(), SLOT(QuitApplication())); //use to kill ApplicationContext and other stuff - engine->load(QUrl(QStringLiteral("qrc:/main.qml"))); + engine->load(QUrl(QStringLiteral("qrc:/qml/main.qml"))); return app.exec(); } diff --git a/mix/qml.qrc b/mix/qml.qrc index 65dc7f826..267427ce5 100644 --- a/mix/qml.qrc +++ b/mix/qml.qrc @@ -1,8 +1,8 @@ - main.qml - BasicContent.qml - TabStyle.qml - MainContent.qml + qml/BasicContent.qml + qml/main.qml + qml/MainContent.qml + qml/TabStyle.qml diff --git a/mix/BasicContent.qml b/mix/qml/BasicContent.qml similarity index 100% rename from mix/BasicContent.qml rename to mix/qml/BasicContent.qml diff --git a/mix/MainContent.qml b/mix/qml/MainContent.qml similarity index 100% rename from mix/MainContent.qml rename to mix/qml/MainContent.qml diff --git a/mix/TabStyle.qml b/mix/qml/TabStyle.qml similarity index 100% rename from mix/TabStyle.qml rename to mix/qml/TabStyle.qml diff --git a/mix/main.qml b/mix/qml/main.qml similarity index 100% rename from mix/main.qml rename to mix/qml/main.qml From d97c0b51413ae2dd4e0cc528835d45d7fdb4c4a6 Mon Sep 17 00:00:00 2001 From: yann300 Date: Thu, 20 Nov 2014 11:04:44 +0100 Subject: [PATCH 18/86] misc --- mix/CMakeLists.txt | 2 +- mix/CodeEditorExtensionMan.cpp | 16 ++++++++++++---- mix/CodeEditorExtensionMan.h | 9 ++++++--- mix/ConstantCompilation.cpp | 11 ++++++----- mix/ConstantCompilation.h | 6 +++--- mix/Feature.cpp | 1 - mix/Feature.h | 1 + 7 files changed, 29 insertions(+), 17 deletions(-) diff --git a/mix/CMakeLists.txt b/mix/CMakeLists.txt index 7272c4d99..6bcb76704 100644 --- a/mix/CMakeLists.txt +++ b/mix/CMakeLists.txt @@ -10,7 +10,7 @@ elseif ("${TARGET_PLATFORM}" STREQUAL "w64") set(SRC_LIST ${SRC_LIST} ../windows/qt_plugin_import.cpp) include_directories(/usr/x86_64-w64-mingw32/include /usr/x86_64-w64-mingw32/include/QtCore /usr/x86_64-w64-mingw32/include/QtGui /usr/x86_64-w64-mingw32/include/QtQuick /usr/x86_64-w64-mingw32/include/QtQml /usr/x86_64-w64-mingw32/include/QtNetwork /usr/x86_64-w64-mingw32/include/QtWidgets /usr/x86_64-w64-mingw32/include/QtWebKit /usr/x86_64-w64-mingw32/include/QtWebKitWidgets) elseif (UNIX) - set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} ";$ENV{QTDIR}/lib/cmake" /opt/Qt5.3.2/5.3/gcc_64/lib/cmake/Qt5Declarative) + set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} ";$ENV{QTDIR}/lib/cmake") endif () find_package(Qt5Core REQUIRED) diff --git a/mix/CodeEditorExtensionMan.cpp b/mix/CodeEditorExtensionMan.cpp index d1ad6c075..6e2c72c7f 100644 --- a/mix/CodeEditorExtensionMan.cpp +++ b/mix/CodeEditorExtensionMan.cpp @@ -38,6 +38,13 @@ CodeEditorExtensionManager::CodeEditorExtensionManager() { } +CodeEditorExtensionManager::~CodeEditorExtensionManager() +{ + for (int k = 0; k < m_features.length(); k++){ + delete m_features.at(k); + } +} + void CodeEditorExtensionManager::loadEditor(QQuickItem* _editor) { if (!_editor) @@ -61,10 +68,11 @@ void CodeEditorExtensionManager::initExtensions() { try{ //only one for now - ConstantCompilation* compil = new ConstantCompilation(m_doc); - if (compil->tabUrl() != "") - compil->addContentOn(m_tabView); - compil->start(); + ConstantCompilation* m_constantCompilation = new ConstantCompilation(m_doc); + if (m_constantCompilation->tabUrl() != "") + m_constantCompilation->addContentOn(m_tabView); + m_constantCompilation->start(); + m_features.append(m_constantCompilation); } catch (dev::Exception const& exception){ qDebug() << "unable to load extensions: "; diff --git a/mix/CodeEditorExtensionMan.h b/mix/CodeEditorExtensionMan.h index 32f435338..306392254 100644 --- a/mix/CodeEditorExtensionMan.h +++ b/mix/CodeEditorExtensionMan.h @@ -20,11 +20,12 @@ * Ethereum IDE client. */ -#ifndef CODEEDITOREXTENSIONMANAGER_H -#define CODEEDITOREXTENSIONMANAGER_H +#ifndef CODEEDITOREXTENSIONMAN_H +#define CODEEDITOREXTENSIONMAN_H #include #include +#include #include "Feature.h" class CodeEditorExtensionManager : public QObject @@ -36,15 +37,17 @@ class CodeEditorExtensionManager : public QObject public: CodeEditorExtensionManager(); + ~CodeEditorExtensionManager(); void initExtensions(); void setEditor(QQuickItem*); void setTabView(QQuickItem*); private: QQuickItem* m_editor; + QVector m_features; QQuickItem* m_tabView; QTextDocument* m_doc; void loadEditor(QQuickItem*); }; -#endif // CODEEDITOREXTENSIONMANAGER_H +#endif // CODEEDITOREXTENSIONMAN_H diff --git a/mix/ConstantCompilation.cpp b/mix/ConstantCompilation.cpp index 72e7b2bfe..3ed687177 100644 --- a/mix/ConstantCompilation.cpp +++ b/mix/ConstantCompilation.cpp @@ -40,18 +40,19 @@ ConstantCompilation::ConstantCompilation(QTextDocument* _doc) m_editor = _doc; } -QString ConstantCompilation::tabUrl(){ +QString ConstantCompilation::tabUrl() +{ return QStringLiteral("qrc:/qml/BasicContent.qml"); } -void ConstantCompilation::start() +QString ConstantCompilation::title() { - connect(m_editor, SIGNAL(contentsChange(int,int,int)), this, SLOT(compile())); + return "compiler"; } -QString ConstantCompilation::title() +void ConstantCompilation::start() { - return "compiler"; + connect(m_editor, SIGNAL(contentsChange(int,int,int)), this, SLOT(compile())); } void ConstantCompilation::compile() diff --git a/mix/ConstantCompilation.h b/mix/ConstantCompilation.h index ed99c6a5f..974277d2a 100644 --- a/mix/ConstantCompilation.h +++ b/mix/ConstantCompilation.h @@ -32,9 +32,9 @@ class ConstantCompilation : public Feature public: ConstantCompilation(QTextDocument* doc); - void start(); - QString title(); - QString tabUrl(); + void start() override; + QString title() override; + QString tabUrl() override; private: QTextDocument* m_editor; diff --git a/mix/Feature.cpp b/mix/Feature.cpp index 309cf7eff..747b538d8 100644 --- a/mix/Feature.cpp +++ b/mix/Feature.cpp @@ -47,7 +47,6 @@ void Feature::addContentOn(QObject* tabView) { Q_ARG(QVariant, QVariant::fromValue(component))); m_view = qvariant_cast(returnValue); - } catch (dev::Exception const& exception){ qDebug() << exception.what(); diff --git a/mix/Feature.h b/mix/Feature.h index 7a53f3a44..d5cee7e74 100644 --- a/mix/Feature.h +++ b/mix/Feature.h @@ -34,6 +34,7 @@ public: Feature(); virtual QString tabUrl() { return ""; } virtual QString title() { return ""; } + virtual void start() {} void addContentOn(QObject* tabView); protected: From f6dfd4ac963687c1297355518f3d18a6f5607e89 Mon Sep 17 00:00:00 2001 From: yann300 Date: Thu, 20 Nov 2014 12:16:45 +0100 Subject: [PATCH 19/86] add ConstantCompilationModel --- mix/CMakeLists.txt | 1 + mix/CodeEditorExtensionMan.cpp | 14 ++-- mix/CodeEditorExtensionMan.h | 6 +- ...lation.cpp => ConstantCompilationCtrl.cpp} | 68 ++++++++----------- ...ompilation.h => ConstantCompilationCtrl.h} | 6 +- mix/ConstantCompilationModel.cpp | 44 ++++++++++++ mix/ConstantCompilationModel.h | 19 ++++++ mix/main.cpp | 2 +- 8 files changed, 107 insertions(+), 53 deletions(-) rename mix/{ConstantCompilation.cpp => ConstantCompilationCtrl.cpp} (55%) rename mix/{ConstantCompilation.h => ConstantCompilationCtrl.h} (87%) create mode 100644 mix/ConstantCompilationModel.cpp create mode 100644 mix/ConstantCompilationModel.h diff --git a/mix/CMakeLists.txt b/mix/CMakeLists.txt index 6bcb76704..28fbc7342 100644 --- a/mix/CMakeLists.txt +++ b/mix/CMakeLists.txt @@ -2,6 +2,7 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON) aux_source_directory(. SRC_LIST) include_directories(..) + if (APPLE) # Add homebrew path for qt5 set(CMAKE_PREFIX_PATH /usr/local/opt/qt5) diff --git a/mix/CodeEditorExtensionMan.cpp b/mix/CodeEditorExtensionMan.cpp index 6e2c72c7f..39473af84 100644 --- a/mix/CodeEditorExtensionMan.cpp +++ b/mix/CodeEditorExtensionMan.cpp @@ -28,24 +28,24 @@ #include #include #include "CodeEditorExtensionMan.h" -#include "ConstantCompilation.h" +#include "ConstantCompilationCtrl.h" #include "features.h" #include "ApplicationCtx.h" #include using namespace dev; -CodeEditorExtensionManager::CodeEditorExtensionManager() +CodeEditorExtensionMan::CodeEditorExtensionMan() { } -CodeEditorExtensionManager::~CodeEditorExtensionManager() +CodeEditorExtensionMan::~CodeEditorExtensionMan() { for (int k = 0; k < m_features.length(); k++){ delete m_features.at(k); } } -void CodeEditorExtensionManager::loadEditor(QQuickItem* _editor) +void CodeEditorExtensionMan::loadEditor(QQuickItem* _editor) { if (!_editor) return; @@ -64,7 +64,7 @@ void CodeEditorExtensionManager::loadEditor(QQuickItem* _editor) } } -void CodeEditorExtensionManager::initExtensions() +void CodeEditorExtensionMan::initExtensions() { try{ //only one for now @@ -80,11 +80,11 @@ void CodeEditorExtensionManager::initExtensions() } } -void CodeEditorExtensionManager::setEditor(QQuickItem* _editor){ +void CodeEditorExtensionMan::setEditor(QQuickItem* _editor){ this->loadEditor(_editor); this->initExtensions(); } -void CodeEditorExtensionManager::setTabView(QQuickItem* _tabView){ +void CodeEditorExtensionMan::setTabView(QQuickItem* _tabView){ m_tabView = _tabView; } diff --git a/mix/CodeEditorExtensionMan.h b/mix/CodeEditorExtensionMan.h index 306392254..b3c99c3df 100644 --- a/mix/CodeEditorExtensionMan.h +++ b/mix/CodeEditorExtensionMan.h @@ -28,7 +28,7 @@ #include #include "Feature.h" -class CodeEditorExtensionManager : public QObject +class CodeEditorExtensionMan : public QObject { Q_OBJECT @@ -36,8 +36,8 @@ class CodeEditorExtensionManager : public QObject Q_PROPERTY(QQuickItem* tabView MEMBER m_tabView WRITE setTabView) public: - CodeEditorExtensionManager(); - ~CodeEditorExtensionManager(); + CodeEditorExtensionMan(); + ~CodeEditorExtensionMan(); void initExtensions(); void setEditor(QQuickItem*); void setTabView(QQuickItem*); diff --git a/mix/ConstantCompilation.cpp b/mix/ConstantCompilationCtrl.cpp similarity index 55% rename from mix/ConstantCompilation.cpp rename to mix/ConstantCompilationCtrl.cpp index 3ed687177..69f493a98 100644 --- a/mix/ConstantCompilation.cpp +++ b/mix/ConstantCompilationCtrl.cpp @@ -20,24 +20,24 @@ * Ethereum IDE client. */ -#include "ConstantCompilation.h" +#include "ConstantCompilationCtrl.h" +#include "ConstantCompilationModel.h" #include #include #include #include #include #include -#include -#include -#include -#include -using namespace std; -using namespace dev; -using namespace dev::eth; ConstantCompilation::ConstantCompilation(QTextDocument* _doc) { m_editor = _doc; + compilationModel = new ConstantCompilationModel(); +} + +ConstantCompilation::~ConstantCompilation() +{ + delete compilationModel; } QString ConstantCompilation::tabUrl() @@ -57,52 +57,38 @@ void ConstantCompilation::start() void ConstantCompilation::compile() { - QString codeContent = m_editor->toPlainText(); + QString codeContent = m_editor->toPlainText().replace("\n", ""); if (codeContent == ""){ - this->writeOutPut(true, codeContent); + resetOutPut(); return; } - dev::solidity::CompilerStack compiler; - dev::bytes m_data; - QString content; - try - { - m_data = compiler.compile(codeContent.toStdString(), true); - content = QString::fromStdString(dev::eth::disassemble(m_data)); - this->writeOutPut(true, content); - } - catch (dev::Exception const& exception) - { - ostringstream error; - solidity::SourceReferenceFormatter::printExceptionInformation(error, exception, "Error", compiler.getScanner()); - content = QString::fromStdString(error.str()).toHtmlEscaped(); - this->writeOutPut(false, content); - } - catch (...) - { - content = "Uncaught exception."; - this->writeOutPut(false, content); - } + compilerResult res = compilationModel->compile(m_editor->toPlainText()); + writeOutPut(res); } -void ConstantCompilation::writeOutPut(bool _success, QString _content){ +void ConstantCompilation::resetOutPut() +{ QObject* status = m_view->findChild("status", Qt::FindChildrenRecursively); QObject* content = m_view->findChild("content", Qt::FindChildrenRecursively); - if (_content == ""){ - status->setProperty("text", ""); - content->setProperty("text", ""); - } - else if (_success){ + status->setProperty("text", ""); + content->setProperty("text", ""); +} + +void ConstantCompilation::writeOutPut(compilerResult res) +{ + QObject* status = m_view->findChild("status", Qt::FindChildrenRecursively); + QObject* content = m_view->findChild("content", Qt::FindChildrenRecursively); + if (res.success){ status->setProperty("text", "succeeded"); status->setProperty("color", "green"); - content->setProperty("text", _content); - qDebug() << QString("compile succeeded " + _content); + content->setProperty("text", res.hexCode); + qDebug() << QString("compile succeeded " + res.hexCode); } else { status->setProperty("text", "failure"); status->setProperty("color", "red"); - content->setProperty("text", _content); - qDebug() << QString("compile failed " + _content); + content->setProperty("text", res.comment); + qDebug() << QString("compile failed " + res.comment); } } diff --git a/mix/ConstantCompilation.h b/mix/ConstantCompilationCtrl.h similarity index 87% rename from mix/ConstantCompilation.h rename to mix/ConstantCompilationCtrl.h index 974277d2a..193c8db77 100644 --- a/mix/ConstantCompilation.h +++ b/mix/ConstantCompilationCtrl.h @@ -24,6 +24,7 @@ #define CONSTANTCOMPILATION_H #include +#include "ConstantCompilationModel.h" #include "Feature.h" class ConstantCompilation : public Feature @@ -32,13 +33,16 @@ class ConstantCompilation : public Feature public: ConstantCompilation(QTextDocument* doc); + ~ConstantCompilation(); void start() override; QString title() override; QString tabUrl() override; private: QTextDocument* m_editor; - void writeOutPut(bool success, QString content); + ConstantCompilationModel* compilationModel; + void writeOutPut(compilerResult); + void resetOutPut(); public Q_SLOTS: void compile(); diff --git a/mix/ConstantCompilationModel.cpp b/mix/ConstantCompilationModel.cpp new file mode 100644 index 000000000..1801bc854 --- /dev/null +++ b/mix/ConstantCompilationModel.cpp @@ -0,0 +1,44 @@ +#include "ConstantCompilationModel.h" +#include +#include +#include +#include +#include +using namespace std; +using namespace dev; +using namespace dev::eth; + +ConstantCompilationModel::ConstantCompilationModel() +{ +} + +compilerResult ConstantCompilationModel::compile(QString code) +{ + dev::solidity::CompilerStack compiler; + dev::bytes m_data; + compilerResult res; + try + { + m_data = compiler.compile(code.toStdString(), true); + res.success = true; + res.comment = "ok"; + res.hexCode = QString::fromStdString(dev::eth::disassemble(m_data)); + + } + catch (dev::Exception const& exception) + { + ostringstream error; + solidity::SourceReferenceFormatter::printExceptionInformation(error, exception, "Error", compiler.getScanner()); + res.success = false; + res.comment = QString::fromStdString(error.str()).toHtmlEscaped(); + res.hexCode = ""; + } + catch (...) + { + res.success = false; + res.comment = "Uncaught exception."; + res.hexCode = ""; + } + return res; +} + diff --git a/mix/ConstantCompilationModel.h b/mix/ConstantCompilationModel.h new file mode 100644 index 000000000..fb1f18e1c --- /dev/null +++ b/mix/ConstantCompilationModel.h @@ -0,0 +1,19 @@ +#ifndef CONSTANTCOMPILATIONMODEL_H +#define CONSTANTCOMPILATIONMODEL_H +#include + +struct compilerResult{ + QString hexCode; + QString comment; + bool success; +}; + +class ConstantCompilationModel +{ + +public: + ConstantCompilationModel(); + compilerResult compile(QString code); +}; + +#endif // CONSTANTCOMPILATIONMODEL_H diff --git a/mix/main.cpp b/mix/main.cpp index 49b6e5195..e1aa5d9a5 100644 --- a/mix/main.cpp +++ b/mix/main.cpp @@ -30,7 +30,7 @@ int main(int argc, char *argv[]) { QApplication app(argc, argv); QQmlApplicationEngine* engine = new QQmlApplicationEngine(); - qmlRegisterType("CodeEditorExtensionManager", 1, 0, "CodeEditorExtensionManager"); + qmlRegisterType("CodeEditorExtensionManager", 1, 0, "CodeEditorExtensionManager"); ApplicationCtx::SetApplicationContext(engine); QObject::connect(&app, SIGNAL(lastWindowClosed()), ApplicationCtx::GetInstance(), SLOT(QuitApplication())); //use to kill ApplicationContext and other stuff From 1da0ca9aa6715dc6b3897978c619f06da7cddb2b Mon Sep 17 00:00:00 2001 From: Christoph Jentzsch Date: Thu, 20 Nov 2014 20:41:35 +0100 Subject: [PATCH 20/86] Specify user defined test --- test/TestHelper.cpp | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp index 114399a49..4ce175892 100644 --- a/test/TestHelper.cpp +++ b/test/TestHelper.cpp @@ -310,12 +310,13 @@ void userDefinedTest(string testTypeFlag, std::function= boost::unit_test::framework::master_test_suite().argc) + if (i + 2 >= boost::unit_test::framework::master_test_suite().argc) { - cnote << "Missing filename\nUsage: testeth " << testTypeFlag << " \n"; + cnote << "Missing filename\nUsage: testeth " << testTypeFlag << " \n"; return; } string filename = boost::unit_test::framework::master_test_suite().argv[i + 1]; + string testname = boost::unit_test::framework::master_test_suite().argv[i + 2]; int currentVerbosity = g_logVerbosity; g_logVerbosity = 12; try @@ -325,7 +326,19 @@ void userDefinedTest(string testTypeFlag, std::function 0, "Contents of " + filename + " is empty. "); json_spirit::read_string(s, v); - doTests(v, false); + json_spirit::mObject oSingleTest; + + json_spirit::mObject::const_iterator pos = v.get_obj().find(testname); + if (pos == v.get_obj().end()) + { + cnote << "Could not find test: " << testname << " in " << filename << "\n"; + return; + } + else + oSingleTest[pos->first] = pos->second; + + json_spirit::mValue v_singleTest(oSingleTest); + doTests(v_singleTest, false); } catch (Exception const& _e) { From 648da92534e7983dbe0077b0fffe72e41f707245 Mon Sep 17 00:00:00 2001 From: Christoph Jentzsch Date: Thu, 20 Nov 2014 22:21:08 +0100 Subject: [PATCH 21/86] style --- test/TestHelper.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp index 4ce175892..d724eb395 100644 --- a/test/TestHelper.cpp +++ b/test/TestHelper.cpp @@ -310,7 +310,7 @@ void userDefinedTest(string testTypeFlag, std::function= boost::unit_test::framework::master_test_suite().argc) + if (boost::unit_test::framework::master_test_suite().argc <= i + 2) { cnote << "Missing filename\nUsage: testeth " << testTypeFlag << " \n"; return; From c74f5ae0e5c1e3d61bf8f44666e023f6eb47345a Mon Sep 17 00:00:00 2001 From: Christoph Jentzsch Date: Fri, 21 Nov 2014 07:42:41 +0100 Subject: [PATCH 22/86] style --- test/TestHelper.cpp | 4 ++-- test/vm.cpp | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp index 66370ca3c..c41289329 100644 --- a/test/TestHelper.cpp +++ b/test/TestHelper.cpp @@ -293,8 +293,8 @@ void checkLog(LogEntries _resultLogs, LogEntries _expectedLogs) for (size_t i = 0; i < _resultLogs.size(); ++i) { - BOOST_CHECK(_resultLogs[i].address == _expectedLogs[i].address); - BOOST_CHECK(_resultLogs[i].topics == _expectedLogs[i].topics); + BOOST_CHECK_EQUAL(_resultLogs[i].address, _expectedLogs[i].address); + BOOST_CHECK_EQUAL(_resultLogs[i].topics, _expectedLogs[i].topics); BOOST_CHECK(_resultLogs[i].data == _expectedLogs[i].data); } } diff --git a/test/vm.cpp b/test/vm.cpp index 5b3c010f5..edb983714 100644 --- a/test/vm.cpp +++ b/test/vm.cpp @@ -149,9 +149,7 @@ void FakeExtVM::importLog(mObject& _o) LogEntry log; log.address = Address(o["address"].get_str()); for (auto const& t: o["topics"].get_array()) - { log.topics.insert(h256(t.get_str())); - } log.data = importData(o); sub.logs.push_back(log); } From 0a496d772546bc46d8ad24a51cc11a1079ea55ae Mon Sep 17 00:00:00 2001 From: yann300 Date: Fri, 21 Nov 2014 16:18:09 +0100 Subject: [PATCH 23/86] - ApplicationCtx.h: refactor of singleton (put inline code in *.h). - Coding standards (#pragma once, ...). - CodeEditorExtensionManager.cpp: replace normal pointer by shared_ptr. - Add namespace dev::mix. - MixApplication: will be used to catch exception (not used now). --- mix/ApplicationCtx.cpp | 37 ++--------- mix/ApplicationCtx.h | 30 ++++++--- ...Man.cpp => CodeEditorExtensionManager.cpp} | 66 ++++++++++--------- ...sionMan.h => CodeEditorExtensionManager.h} | 24 ++++--- mix/ConstantCompilationCtrl.cpp | 48 +++++++------- mix/ConstantCompilationCtrl.h | 35 +++++----- mix/ConstantCompilationModel.cpp | 41 ++++++++---- mix/ConstantCompilationModel.h | 44 +++++++++++-- mix/{Feature.cpp => Extension.cpp} | 43 +++++------- mix/{Feature.h => Extension.h} | 26 ++++---- mix/MixApplication.cpp | 42 ++++++++++++ mix/MixApplication.h | 46 +++++++++++++ mix/main.cpp | 17 +++-- mix/qml/BasicContent.qml | 1 + mix/qml/MainContent.qml | 2 +- mix/qml/TabStyle.qml | 1 - mix/qml/main.qml | 1 - 17 files changed, 315 insertions(+), 189 deletions(-) rename mix/{CodeEditorExtensionMan.cpp => CodeEditorExtensionManager.cpp} (57%) rename mix/{CodeEditorExtensionMan.h => CodeEditorExtensionManager.h} (81%) rename mix/{Feature.cpp => Extension.cpp} (54%) rename mix/{Feature.h => Extension.h} (79%) create mode 100644 mix/MixApplication.cpp create mode 100644 mix/MixApplication.h diff --git a/mix/ApplicationCtx.cpp b/mix/ApplicationCtx.cpp index 7475c1b57..8ea8bd8d8 100644 --- a/mix/ApplicationCtx.cpp +++ b/mix/ApplicationCtx.cpp @@ -1,55 +1,30 @@ /* 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 ApplicationCtx.cpp * @author Yann yann@ethdev.com * @date 2014 - * Ethereum IDE client. + * Provide an access to the current QQmlApplicationEngine which is used to add QML file on the fly. + * In the future this class can be extended to add more variable related to the context of the application. */ -#include "ApplicationCtx.h" #include +#include "ApplicationCtx.h" +using namespace dev::mix; -ApplicationCtx* ApplicationCtx::m_instance = nullptr; - -ApplicationCtx::ApplicationCtx(QQmlApplicationEngine* _engine) -{ - m_applicationEngine = _engine; -} - -ApplicationCtx::~ApplicationCtx() -{ - delete m_applicationEngine; -} - -ApplicationCtx* ApplicationCtx::GetInstance() -{ - return m_instance; -} +ApplicationCtx* ApplicationCtx::Instance = nullptr; -void ApplicationCtx::SetApplicationContext(QQmlApplicationEngine* engine) +QQmlApplicationEngine* ApplicationCtx::appEngine() { - m_instance = new ApplicationCtx(engine); -} - -QQmlApplicationEngine* ApplicationCtx::appEngine(){ return m_applicationEngine; } - -void ApplicationCtx::QuitApplication() -{ - delete m_instance; -} diff --git a/mix/ApplicationCtx.h b/mix/ApplicationCtx.h index 68806cc33..32e2bd3f1 100644 --- a/mix/ApplicationCtx.h +++ b/mix/ApplicationCtx.h @@ -17,29 +17,39 @@ /** @file ApplicationCtx.h * @author Yann yann@ethdev.com * @date 2014 - * Ethereum IDE client. + * Provide an access to the current QQmlApplicationEngine which is used to add QML file on the fly. + * In the future this class can be extended to add more variable related to the context of the application. */ -#ifndef APPLICATIONCONTEXT_H -#define APPLICATIONCONTEXT_H +#pragma once #include +namespace dev +{ + +namespace mix +{ + class ApplicationCtx : public QObject { Q_OBJECT public: - ApplicationCtx(QQmlApplicationEngine*); - ~ApplicationCtx(); + ApplicationCtx(QQmlApplicationEngine* _engine) { m_applicationEngine = _engine; } + ~ApplicationCtx() { delete m_applicationEngine; } + static ApplicationCtx* getInstance() { return Instance; } + static void setApplicationContext(QQmlApplicationEngine* _engine) { Instance = new ApplicationCtx(_engine); } QQmlApplicationEngine* appEngine(); - static ApplicationCtx* GetInstance(); - static void SetApplicationContext(QQmlApplicationEngine*); + private: - static ApplicationCtx* m_instance; + static ApplicationCtx* Instance; QQmlApplicationEngine* m_applicationEngine; + public slots: - void QuitApplication(); + void quitApplication() { delete Instance; } }; -#endif // APPLICATIONCTX_H +} + +} diff --git a/mix/CodeEditorExtensionMan.cpp b/mix/CodeEditorExtensionManager.cpp similarity index 57% rename from mix/CodeEditorExtensionMan.cpp rename to mix/CodeEditorExtensionManager.cpp index 39473af84..316c37ee0 100644 --- a/mix/CodeEditorExtensionMan.cpp +++ b/mix/CodeEditorExtensionManager.cpp @@ -27,64 +27,66 @@ #include #include #include -#include "CodeEditorExtensionMan.h" +#include #include "ConstantCompilationCtrl.h" #include "features.h" #include "ApplicationCtx.h" -#include -using namespace dev; +#include "CodeEditorExtensionManager.h" +using namespace dev::mix; -CodeEditorExtensionMan::CodeEditorExtensionMan() -{ -} - -CodeEditorExtensionMan::~CodeEditorExtensionMan() +CodeEditorExtensionManager::~CodeEditorExtensionManager() { - for (int k = 0; k < m_features.length(); k++){ - delete m_features.at(k); - } + m_features.clear(); } -void CodeEditorExtensionMan::loadEditor(QQuickItem* _editor) +void CodeEditorExtensionManager::loadEditor(QQuickItem* _editor) { if (!_editor) return; - try{ + try + { QVariant doc = _editor->property("textDocument"); - if (doc.canConvert()) { + if (doc.canConvert()) + { QQuickTextDocument* qqdoc = doc.value(); - if (qqdoc) { + if (qqdoc) m_doc = qqdoc->textDocument(); - } } } - catch (dev::Exception const& exception){ + catch (...) + { qDebug() << "unable to load editor: "; - qDebug() << exception.what(); } } -void CodeEditorExtensionMan::initExtensions() +void CodeEditorExtensionManager::initExtensions() { - try{ - //only one for now - ConstantCompilation* m_constantCompilation = new ConstantCompilation(m_doc); - if (m_constantCompilation->tabUrl() != "") - m_constantCompilation->addContentOn(m_tabView); - m_constantCompilation->start(); - m_features.append(m_constantCompilation); - } - catch (dev::Exception const& exception){ - qDebug() << "unable to load extensions: "; - qDebug() << exception.what(); + //only one for now + std::shared_ptr m_constantCompilation(new ConstantCompilationCtrl(m_doc)); + ConstantCompilationCtrl* ext = m_constantCompilation.get(); + if (ext->contentUrl() != "") + { + try + { + ext->addContentOn(m_tabView); + } + catch (...) + { + qDebug() << "Exception when adding content into view."; + return; + } } + ext->start(); + m_features.append(m_constantCompilation); } -void CodeEditorExtensionMan::setEditor(QQuickItem* _editor){ +void CodeEditorExtensionManager::setEditor(QQuickItem* _editor) +{ this->loadEditor(_editor); this->initExtensions(); } -void CodeEditorExtensionMan::setTabView(QQuickItem* _tabView){ +void CodeEditorExtensionManager::setTabView(QQuickItem* _tabView) +{ m_tabView = _tabView; } diff --git a/mix/CodeEditorExtensionMan.h b/mix/CodeEditorExtensionManager.h similarity index 81% rename from mix/CodeEditorExtensionMan.h rename to mix/CodeEditorExtensionManager.h index b3c99c3df..c368a9714 100644 --- a/mix/CodeEditorExtensionMan.h +++ b/mix/CodeEditorExtensionManager.h @@ -20,15 +20,21 @@ * Ethereum IDE client. */ -#ifndef CODEEDITOREXTENSIONMAN_H -#define CODEEDITOREXTENSIONMAN_H +#pragma once +#include "memory" #include #include #include -#include "Feature.h" +#include "ConstantCompilationCtrl.h" -class CodeEditorExtensionMan : public QObject +namespace dev +{ + +namespace mix +{ + +class CodeEditorExtensionManager : public QObject { Q_OBJECT @@ -36,18 +42,20 @@ class CodeEditorExtensionMan : public QObject Q_PROPERTY(QQuickItem* tabView MEMBER m_tabView WRITE setTabView) public: - CodeEditorExtensionMan(); - ~CodeEditorExtensionMan(); + CodeEditorExtensionManager() {} + ~CodeEditorExtensionManager(); void initExtensions(); void setEditor(QQuickItem*); void setTabView(QQuickItem*); private: QQuickItem* m_editor; - QVector m_features; + QVector> m_features; QQuickItem* m_tabView; QTextDocument* m_doc; void loadEditor(QQuickItem*); }; -#endif // CODEEDITOREXTENSIONMAN_H +} + +} diff --git a/mix/ConstantCompilationCtrl.cpp b/mix/ConstantCompilationCtrl.cpp index 69f493a98..0f73da781 100644 --- a/mix/ConstantCompilationCtrl.cpp +++ b/mix/ConstantCompilationCtrl.cpp @@ -20,53 +20,55 @@ * Ethereum IDE client. */ -#include "ConstantCompilationCtrl.h" -#include "ConstantCompilationModel.h" #include #include #include #include #include #include +#include "ConstantCompilationCtrl.h" +#include "ConstantCompilationModel.h" +using namespace dev::mix; -ConstantCompilation::ConstantCompilation(QTextDocument* _doc) +ConstantCompilationCtrl::ConstantCompilationCtrl(QTextDocument* _doc) { m_editor = _doc; - compilationModel = new ConstantCompilationModel(); + m_compilationModel = new ConstantCompilationModel(); } -ConstantCompilation::~ConstantCompilation() +ConstantCompilationCtrl::~ConstantCompilationCtrl() { - delete compilationModel; + delete m_compilationModel; } -QString ConstantCompilation::tabUrl() +QString ConstantCompilationCtrl::contentUrl() const { return QStringLiteral("qrc:/qml/BasicContent.qml"); } -QString ConstantCompilation::title() +QString ConstantCompilationCtrl::title() const { return "compiler"; } -void ConstantCompilation::start() +void ConstantCompilationCtrl::start() const { connect(m_editor, SIGNAL(contentsChange(int,int,int)), this, SLOT(compile())); } -void ConstantCompilation::compile() +void ConstantCompilationCtrl::compile() { QString codeContent = m_editor->toPlainText().replace("\n", ""); - if (codeContent == ""){ + if (codeContent == "") + { resetOutPut(); return; } - compilerResult res = compilationModel->compile(m_editor->toPlainText()); + CompilerResult res = m_compilationModel->compile(m_editor->toPlainText()); writeOutPut(res); } -void ConstantCompilation::resetOutPut() +void ConstantCompilationCtrl::resetOutPut() { QObject* status = m_view->findChild("status", Qt::FindChildrenRecursively); QObject* content = m_view->findChild("content", Qt::FindChildrenRecursively); @@ -74,24 +76,22 @@ void ConstantCompilation::resetOutPut() content->setProperty("text", ""); } -void ConstantCompilation::writeOutPut(compilerResult res) +void ConstantCompilationCtrl::writeOutPut(CompilerResult _res) { QObject* status = m_view->findChild("status", Qt::FindChildrenRecursively); QObject* content = m_view->findChild("content", Qt::FindChildrenRecursively); - if (res.success){ + if (_res.success) + { status->setProperty("text", "succeeded"); status->setProperty("color", "green"); - content->setProperty("text", res.hexCode); - qDebug() << QString("compile succeeded " + res.hexCode); + content->setProperty("text", _res.hexCode); + qDebug() << QString("compile succeeded " + _res.hexCode); } - else { + else + { status->setProperty("text", "failure"); status->setProperty("color", "red"); - content->setProperty("text", res.comment); - qDebug() << QString("compile failed " + res.comment); + content->setProperty("text", _res.comment); + qDebug() << QString("compile failed " + _res.comment); } } - - - - diff --git a/mix/ConstantCompilationCtrl.h b/mix/ConstantCompilationCtrl.h index 193c8db77..3bb221b3d 100644 --- a/mix/ConstantCompilationCtrl.h +++ b/mix/ConstantCompilationCtrl.h @@ -1,16 +1,13 @@ /* 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 . */ @@ -20,33 +17,39 @@ * Ethereum IDE client. */ -#ifndef CONSTANTCOMPILATION_H -#define CONSTANTCOMPILATION_H +#pragma once #include #include "ConstantCompilationModel.h" -#include "Feature.h" +#include "Extension.h" + +namespace dev +{ -class ConstantCompilation : public Feature +namespace mix +{ + +class ConstantCompilationCtrl : public Extension { Q_OBJECT public: - ConstantCompilation(QTextDocument* doc); - ~ConstantCompilation(); - void start() override; - QString title() override; - QString tabUrl() override; + ConstantCompilationCtrl(QTextDocument*); + ~ConstantCompilationCtrl(); + void start() const override; + QString title() const override; + QString contentUrl() const override; private: QTextDocument* m_editor; - ConstantCompilationModel* compilationModel; - void writeOutPut(compilerResult); + ConstantCompilationModel* m_compilationModel; + void writeOutPut(CompilerResult); void resetOutPut(); public Q_SLOTS: void compile(); - }; -#endif // CONSTANTCOMPILATION_H +} + +} diff --git a/mix/ConstantCompilationModel.cpp b/mix/ConstantCompilationModel.cpp index 1801bc854..533523a4e 100644 --- a/mix/ConstantCompilationModel.cpp +++ b/mix/ConstantCompilationModel.cpp @@ -1,34 +1,52 @@ -#include "ConstantCompilationModel.h" +/* + 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 ApplicationCtx.h + * @author Yann yann@ethdev.com + * @date 2014 + * Ethereum IDE client. + */ + #include #include #include #include #include +#include "ConstantCompilationModel.h" using namespace std; using namespace dev; using namespace dev::eth; +using namespace dev::mix; -ConstantCompilationModel::ConstantCompilationModel() -{ -} - -compilerResult ConstantCompilationModel::compile(QString code) +CompilerResult ConstantCompilationModel::compile(QString _code) { dev::solidity::CompilerStack compiler; dev::bytes m_data; - compilerResult res; + CompilerResult res; try { - m_data = compiler.compile(code.toStdString(), true); + m_data = compiler.compile(_code.toStdString(), true); res.success = true; res.comment = "ok"; res.hexCode = QString::fromStdString(dev::eth::disassemble(m_data)); - } - catch (dev::Exception const& exception) + catch (dev::Exception const& _exception) { ostringstream error; - solidity::SourceReferenceFormatter::printExceptionInformation(error, exception, "Error", compiler.getScanner()); + solidity::SourceReferenceFormatter::printExceptionInformation(error, _exception, "Error", compiler.getScanner()); res.success = false; res.comment = QString::fromStdString(error.str()).toHtmlEscaped(); res.hexCode = ""; @@ -41,4 +59,3 @@ compilerResult ConstantCompilationModel::compile(QString code) } return res; } - diff --git a/mix/ConstantCompilationModel.h b/mix/ConstantCompilationModel.h index fb1f18e1c..4c84bc0eb 100644 --- a/mix/ConstantCompilationModel.h +++ b/mix/ConstantCompilationModel.h @@ -1,8 +1,37 @@ -#ifndef CONSTANTCOMPILATIONMODEL_H -#define CONSTANTCOMPILATIONMODEL_H +/* + 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 ApplicationCtx.h + * @author Yann yann@ethdev.com + * @date 2014 + * Ethereum IDE client. + */ + +#pragma once + #include -struct compilerResult{ +namespace dev +{ + +namespace mix +{ + +struct CompilerResult +{ QString hexCode; QString comment; bool success; @@ -12,8 +41,11 @@ class ConstantCompilationModel { public: - ConstantCompilationModel(); - compilerResult compile(QString code); + ConstantCompilationModel() { } + ~ConstantCompilationModel() { } + CompilerResult compile(QString code); }; -#endif // CONSTANTCOMPILATIONMODEL_H +} + +} diff --git a/mix/Feature.cpp b/mix/Extension.cpp similarity index 54% rename from mix/Feature.cpp rename to mix/Extension.cpp index 747b538d8..b1ae31ecc 100644 --- a/mix/Feature.cpp +++ b/mix/Extension.cpp @@ -1,16 +1,13 @@ /* 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 . */ @@ -20,36 +17,28 @@ * Ethereum IDE client. */ -#include "Feature.h" -#include "ApplicationCtx.h" -#include #include #include +#include +#include "Extension.h" +#include "ApplicationCtx.h" using namespace dev; +using namespace dev::mix; -Feature::Feature() +void Extension::addContentOn(QObject* _tabView) { -} + if (contentUrl() == "") + return; -void Feature::addContentOn(QObject* tabView) { - try{ - if (tabUrl() == "") - return; + QVariant returnValue; + QQmlComponent* component = new QQmlComponent( + ApplicationCtx::getInstance()->appEngine(), + QUrl(this->contentUrl()), _tabView); - QVariant returnValue; - QQmlComponent* component = new QQmlComponent( - ApplicationCtx::GetInstance()->appEngine(), - QUrl(this->tabUrl()), tabView); + QMetaObject::invokeMethod(_tabView, "addTab", + Q_RETURN_ARG(QVariant, returnValue), + Q_ARG(QVariant, this->title()), + Q_ARG(QVariant, QVariant::fromValue(component))); - QMetaObject::invokeMethod(tabView, "addTab", - Q_RETURN_ARG(QVariant, returnValue), - Q_ARG(QVariant, this->title()), - Q_ARG(QVariant, QVariant::fromValue(component))); - - m_view = qvariant_cast(returnValue); - } - catch (dev::Exception const& exception){ - qDebug() << exception.what(); - } + m_view = qvariant_cast(returnValue); } - diff --git a/mix/Feature.h b/mix/Extension.h similarity index 79% rename from mix/Feature.h rename to mix/Extension.h index d5cee7e74..3a401eeeb 100644 --- a/mix/Feature.h +++ b/mix/Extension.h @@ -1,16 +1,13 @@ /* 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 . */ @@ -20,25 +17,32 @@ * Ethereum IDE client. */ -#ifndef FEATURE_H -#define FEATURE_H +#pragma once #include #include -class Feature : public QObject +namespace dev +{ + +namespace mix +{ + +class Extension : public QObject { Q_OBJECT public: - Feature(); - virtual QString tabUrl() { return ""; } - virtual QString title() { return ""; } - virtual void start() {} + Extension() {} + virtual QString contentUrl() const { return ""; } + virtual QString title() const { return ""; } + virtual void start() const {} void addContentOn(QObject* tabView); protected: QObject* m_view; }; -#endif // FEATURE_H +} + +} diff --git a/mix/MixApplication.cpp b/mix/MixApplication.cpp new file mode 100644 index 000000000..fa9feadb5 --- /dev/null +++ b/mix/MixApplication.cpp @@ -0,0 +1,42 @@ +/* + 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 main.cpp + * @author Yann yann@ethdev.com + * @date 2014 + */ + +#include +#include "MixApplication.h" +using namespace dev::mix; + +MixApplication::MixApplication(int _argc, char *_argv[]) + : QApplication(_argc, _argv) +{ +} + +bool MixApplication::notify(QObject* _receiver, QEvent* _event) +{ + try + { + return MixApplication::notify(_receiver, _event); + } + catch (std::exception& _ex) + { + qDebug() << "std::exception was caught " << _ex.what(); + } + return false; +} diff --git a/mix/MixApplication.h b/mix/MixApplication.h new file mode 100644 index 000000000..3f4ace5a6 --- /dev/null +++ b/mix/MixApplication.h @@ -0,0 +1,46 @@ +/* + 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 main.cpp + * @author Yann yann@ethdev.com + * @date 2014 + * This class will be use instead of QApplication to launch the application. the method 'notify' allows to catch all exceptions. + * Not use for now: TODO. + */ + +#pragma once + +#include + +namespace dev +{ + +namespace mix +{ + +class MixApplication : public QApplication +{ + Q_OBJECT + +public: + MixApplication(int _argc, char* _argv[]); + virtual ~MixApplication() { } + virtual bool notify(QObject* _receiver, QEvent* _event); +}; + +} + +} diff --git a/mix/main.cpp b/mix/main.cpp index e1aa5d9a5..c0fc76bdd 100644 --- a/mix/main.cpp +++ b/mix/main.cpp @@ -23,19 +23,18 @@ #include #include #include -#include "CodeEditorExtensionMan.h" +#include "CodeEditorExtensionManager.h" #include "ApplicationCtx.h" +#include "MixApplication.h" +using namespace dev::mix; -int main(int argc, char *argv[]) +int main(int _argc, char *_argv[]) { - QApplication app(argc, argv); + QApplication app(_argc, _argv); + qmlRegisterType("CodeEditorExtensionManager", 1, 0, "CodeEditorExtensionManager"); QQmlApplicationEngine* engine = new QQmlApplicationEngine(); - qmlRegisterType("CodeEditorExtensionManager", 1, 0, "CodeEditorExtensionManager"); - - ApplicationCtx::SetApplicationContext(engine); - QObject::connect(&app, SIGNAL(lastWindowClosed()), ApplicationCtx::GetInstance(), SLOT(QuitApplication())); //use to kill ApplicationContext and other stuff - + ApplicationCtx::setApplicationContext(engine); + QObject::connect(&app, SIGNAL(lastWindowClosed()), ApplicationCtx::getInstance(), SLOT(quitApplication())); //use to kill ApplicationContext and other stuff engine->load(QUrl(QStringLiteral("qrc:/qml/main.qml"))); return app.exec(); } - diff --git a/mix/qml/BasicContent.qml b/mix/qml/BasicContent.qml index a61ee8b8f..8e450dabf 100644 --- a/mix/qml/BasicContent.qml +++ b/mix/qml/BasicContent.qml @@ -6,6 +6,7 @@ Rectangle { width: parent.width height: parent.height color: "lightgray" + Text { font.pointSize: 7 anchors.left: parent.left diff --git a/mix/qml/MainContent.qml b/mix/qml/MainContent.qml index abae4a37f..80bbec3aa 100644 --- a/mix/qml/MainContent.qml +++ b/mix/qml/MainContent.qml @@ -13,7 +13,7 @@ Rectangle { anchors.fill: parent orientation: Qt.Vertical Rectangle { - anchors.top : parent.top + anchors.top: parent.top id: contentView width: parent.width height: parent.height * 0.7 diff --git a/mix/qml/TabStyle.qml b/mix/qml/TabStyle.qml index df31f9910..8f72fa12c 100644 --- a/mix/qml/TabStyle.qml +++ b/mix/qml/TabStyle.qml @@ -8,7 +8,6 @@ TabViewStyle { color: "lightgray" } tab: Rectangle { - color: "lightsteelblue" implicitWidth: Math.max(text.width + 4, 80) implicitHeight: 20 diff --git a/mix/qml/main.qml b/mix/qml/main.qml index 6486c1dfd..331720f41 100644 --- a/mix/qml/main.qml +++ b/mix/qml/main.qml @@ -4,7 +4,6 @@ import QtQuick.Controls.Styles 1.2 import CodeEditorExtensionManager 1.0 ApplicationWindow { - visible: true width: 1000 height: 480 From 381f2dfe64cadf954929073de0777dd16b248632 Mon Sep 17 00:00:00 2001 From: subtly Date: Sat, 22 Nov 2014 02:25:35 +0100 Subject: [PATCH 24/86] reduce timeout, coding standards --- libp2p/Host.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index e7c476441..41ac2e856 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -757,7 +757,7 @@ void Host::run(boost::system::error_code const& error) } - if (s_lasttick == c_timerInterval * 100) + if (s_lasttick == c_timerInterval * 10) { growPeers(); prunePeers(); @@ -782,7 +782,7 @@ void Host::run(boost::system::error_code const& error) pingAll(); } - auto runcb = [this](boost::system::error_code const& error)->void{ run(error); }; + auto runcb = [this](boost::system::error_code const& error) -> void{ run(error); }; m_timer->expires_from_now(boost::posix_time::milliseconds(c_timerInterval)); m_timer->async_wait(runcb); } From 24bbbefd5dee9c4d02093466ae6590053a4e8f94 Mon Sep 17 00:00:00 2001 From: subtly Date: Sat, 22 Nov 2014 08:48:02 +0100 Subject: [PATCH 25/86] pr fixes. refactor of network code. moved network-start methods into static methods, as they can only be called during certain stages or do not need Host class. Mutex start/stop. Added m_ifAddresses and removed m_addresses. Rewrite determinePublic. IP address preference is now: user-supplied public > user-supplied private (if localnetwork enabled) > first public4 interface > upnp4 > first private4 interface (if localnetwork enabled) > unspecified. IPv6 addresses are currently ignored (unless manually entered by user) until link-local addresses can be properly detected. --- libp2p/Host.cpp | 547 ++++++++++++++++++++++++--------------------- libp2p/Host.h | 48 ++-- libp2p/Session.cpp | 2 +- 3 files changed, 326 insertions(+), 271 deletions(-) diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index 41ac2e856..b51443e63 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -55,16 +55,167 @@ static const set c_rejectAddresses = { {bi::address_v6::from_string("::")} }; +std::vector Host::getInterfaceAddresses() +{ + std::vector addresses; + +#ifdef _WIN32 + WSAData wsaData; + if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0) + BOOST_THROW_EXCEPTION(NoNetworking()); + + char ac[80]; + if (gethostname(ac, sizeof(ac)) == SOCKET_ERROR) + { + clog(NetWarn) << "Error " << WSAGetLastError() << " when getting local host name."; + WSACleanup(); + BOOST_THROW_EXCEPTION(NoNetworking()); + } + + struct hostent* phe = gethostbyname(ac); + if (phe == 0) + { + clog(NetWarn) << "Bad host lookup."; + WSACleanup(); + BOOST_THROW_EXCEPTION(NoNetworking()); + } + + for (int i = 0; phe->h_addr_list[i] != 0; ++i) + { + struct in_addr addr; + memcpy(&addr, phe->h_addr_list[i], sizeof(struct in_addr)); + char *addrStr = inet_ntoa(addr); + bi::address address(bi::address::from_string(addrStr)); + if (std::find(c_rejectAddresses.begin(), c_rejectAddresses.end(), address) == c_rejectAddresses.end()) + addresses.push_back(ad.to_v4()); + } + + WSACleanup(); +#else + ifaddrs* ifaddr; + if (getifaddrs(&ifaddr) == -1) + BOOST_THROW_EXCEPTION(NoNetworking()); + + for (auto ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) + { + if (!ifa->ifa_addr || string(ifa->ifa_name) == "lo0") + continue; + + if (ifa->ifa_addr->sa_family == AF_INET) + { + in_addr addr = ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr; + boost::asio::ip::address_v4 address(boost::asio::detail::socket_ops::network_to_host_long(addr.s_addr)); + if (std::find(c_rejectAddresses.begin(), c_rejectAddresses.end(), address) == c_rejectAddresses.end()) + addresses.push_back(address); + } + else if (ifa->ifa_addr->sa_family == AF_INET6) + { + sockaddr_in6* sockaddr = ((struct sockaddr_in6 *)ifa->ifa_addr); + in6_addr addr = sockaddr->sin6_addr; + boost::asio::ip::address_v6::bytes_type bytes; + memcpy(&bytes[0], addr.s6_addr, 16); + boost::asio::ip::address_v6 address(bytes, sockaddr->sin6_scope_id); + if (std::find(c_rejectAddresses.begin(), c_rejectAddresses.end(), address) == c_rejectAddresses.end()) + addresses.push_back(address); + } + } + if (ifaddr!=NULL) freeifaddrs(ifaddr); + +#endif + + return std::move(addresses); +} + +int Host::listen4(bi::tcp::acceptor* _acceptor, unsigned short _listenPort) +{ + int retport = -1; + for (unsigned i = 0; i < 2; ++i) + { + // try to connect w/listenPort, else attempt net-allocated port + bi::tcp::endpoint endpoint(bi::tcp::v4(), i ? 0 : _listenPort); + try + { + _acceptor->open(endpoint.protocol()); + _acceptor->set_option(ba::socket_base::reuse_address(true)); + _acceptor->bind(endpoint); + _acceptor->listen(); + retport = _acceptor->local_endpoint().port(); + break; + } + catch (...) + { + if (i) + { + // both attempts failed + cwarn << "Couldn't start accepting connections on host. Something very wrong with network?\n" << boost::current_exception_diagnostic_information(); + _acceptor->close(); + } + + // first attempt failed + _acceptor->close(); + continue; + } + } + return retport; +} + +bi::tcp::endpoint Host::traverseNAT(std::vector const& _ifAddresses, unsigned short _listenPort, bi::address& o_upnpifaddr) +{ + asserts(_listenPort); + + UPnP* upnp; + try + { + upnp = new UPnP; + } + // let m_upnp continue as null - we handle it properly. + catch (NoUPnPDevice) {} + + bi::tcp::endpoint upnpep; + if (upnp && upnp->isValid()) + { + bi::address paddr; + int p; + for (auto const& addr : _ifAddresses) + if (addr.is_v4() && isPrivateAddress(addr) && (p = upnp->addRedirect(addr.to_string().c_str(), _listenPort))) + { + paddr = addr; + break; + } + + auto eip = upnp->externalIP(); + bi::address eipaddr(bi::address::from_string(eip)); + if (p && eip != string("0.0.0.0") && !isPrivateAddress(eipaddr)) + { + clog(NetNote) << "Punched through NAT and mapped local port" << _listenPort << "onto external port" << p << "."; + clog(NetNote) << "External addr:" << eip; + o_upnpifaddr = paddr; + upnpep = bi::tcp::endpoint(eipaddr, (unsigned short)p); + } + else + clog(NetWarn) << "Couldn't punch through NAT (or no NAT in place)."; + + if(upnp) + delete upnp; + } + + return upnpep; +} + Host::Host(std::string const& _clientVersion, NetworkPreferences const& _n, bool _start): Worker("p2p", 0), m_clientVersion(_clientVersion), m_netPrefs(_n), + m_ifAddresses(getInterfaceAddresses()), m_ioService(new ba::io_service), m_acceptor(new bi::tcp::acceptor(*m_ioService)), m_socket(new bi::tcp::socket(*m_ioService)), m_key(KeyPair::create()) { - populateAddresses(); + for (auto address: m_ifAddresses) + if (address.is_v4()) + clog(NetNote) << "IP Address: " << address << " = " << (isPrivateAddress(address) ? "[LOCAL]" : "[PEER]"); + clog(NetNote) << "Id:" << id().abridged(); if (_start) start(); @@ -82,11 +233,16 @@ void Host::start() void Host::stop() { - // flag transition to shutdown network - // once m_run is false the scheduler will shutdown network and stopWorking() - m_run = false; + { + // prevent m_run from being set to false at same time as set to true by start() + lock_guard l(x_runtimer); + // once m_run is false the scheduler will shutdown network and stopWorking() + m_run = false; + } + + // we know shutdown is complete when m_timer is reset while (m_timer) - this_thread::sleep_for(chrono::milliseconds(100)); + this_thread::sleep_for(chrono::milliseconds(50)); stopWorking(); } @@ -142,162 +298,6 @@ void Host::seal(bytes& _b) _b[7] = len & 0xff; } -void Host::determinePublic(string const& _publicAddress, bool _upnp) -{ - if (_upnp) - try - { - m_upnp = new UPnP; - } - catch (NoUPnPDevice) {} // let m_upnp continue as null - we handle it properly. - - if (m_upnp && m_upnp->isValid() && m_peerAddresses.size()) - { - clog(NetNote) << "External addr:" << m_upnp->externalIP(); - int p; - - // iterate m_peerAddresses (populated by populateAddresses()) - for (auto const& addr : m_peerAddresses) - if (addr.is_v4() && (p = m_upnp->addRedirect(addr.to_string().c_str(), m_listenPort))) - break; - if (p) - clog(NetNote) << "Punched through NAT and mapped local port" << m_listenPort << "onto external port" << p << "."; - else - { - // couldn't map - clog(NetWarn) << "Couldn't punch through NAT (or no NAT in place). Assuming" << m_listenPort << "is local & external port."; - p = m_listenPort; - } - - auto eip = m_upnp->externalIP(); - if (eip == string("0.0.0.0") && _publicAddress.empty()) - m_public = bi::tcp::endpoint(bi::address(), (unsigned short)p); - else - { - bi::address adr = bi::address::from_string(eip); - try - { - adr = bi::address::from_string(_publicAddress); - } - catch (...) {} - m_public = bi::tcp::endpoint(adr, (unsigned short)p); - m_addresses.push_back(m_public.address()); - } - } - else - { - // No UPnP - fallback on given public address or, if empty, the assumed peer address. - bi::address adr; - if (m_peerAddresses.size()) - { - // prefer local ipv4 over local ipv6 - for (auto const& ip: m_peerAddresses) - if (ip.is_v4()) - { - adr = ip; - break; - } - - if (adr.is_unspecified()) - adr = m_peerAddresses[0]; - } - - try - { - adr = bi::address::from_string(_publicAddress); - } - catch (...) {} - m_public = bi::tcp::endpoint(adr, m_listenPort); - m_addresses.push_back(adr); - } -} - -void Host::populateAddresses() -{ - // if there's no ioService, it means we've had quit() called - bomb out - we're not allowed in here. - if (!m_ioService) - return; - -#ifdef _WIN32 - WSAData wsaData; - if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0) - BOOST_THROW_EXCEPTION(NoNetworking()); - - char ac[80]; - if (gethostname(ac, sizeof(ac)) == SOCKET_ERROR) - { - clog(NetWarn) << "Error " << WSAGetLastError() << " when getting local host name."; - WSACleanup(); - BOOST_THROW_EXCEPTION(NoNetworking()); - } - - struct hostent* phe = gethostbyname(ac); - if (phe == 0) - { - clog(NetWarn) << "Bad host lookup."; - WSACleanup(); - BOOST_THROW_EXCEPTION(NoNetworking()); - } - - for (int i = 0; phe->h_addr_list[i] != 0; ++i) - { - struct in_addr addr; - memcpy(&addr, phe->h_addr_list[i], sizeof(struct in_addr)); - char *addrStr = inet_ntoa(addr); - bi::address ad(bi::address::from_string(addrStr)); - m_addresses.push_back(ad.to_v4()); - bool isLocal = std::find(c_rejectAddresses.begin(), c_rejectAddresses.end(), ad) != c_rejectAddresses.end(); - if (!isLocal) - m_peerAddresses.push_back(ad.to_v4()); - clog(NetNote) << "Address: " << ac << " = " << m_addresses.back() << (isLocal ? " [LOCAL]" : " [PEER]"); - } - - WSACleanup(); -#else - ifaddrs* ifaddr; - if (getifaddrs(&ifaddr) == -1) - BOOST_THROW_EXCEPTION(NoNetworking()); - - for (auto ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { - if (!ifa->ifa_addr || (strlen(ifa->ifa_name) > 2 && !strncmp(ifa->ifa_name, "lo0", 3))) { - continue; - } - - if (ifa->ifa_addr->sa_family == AF_INET) - { - in_addr addr = ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr; - boost::asio::ip::address_v4 address(boost::asio::detail::socket_ops::network_to_host_long(addr.s_addr)); - if (std::find(c_rejectAddresses.begin(), c_rejectAddresses.end(), address) == c_rejectAddresses.end()) - m_peerAddresses.push_back(address); - - // Log IPv4 Address: - auto addr4 = &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr; - char addressBuffer[INET_ADDRSTRLEN]; - inet_ntop(AF_INET, addr4, addressBuffer, INET_ADDRSTRLEN); - printf("%s IP Address %s\n", ifa->ifa_name, addressBuffer); - } - else if (ifa->ifa_addr->sa_family == AF_INET6) - { - sockaddr_in6* sockaddr = ((struct sockaddr_in6 *)ifa->ifa_addr); - in6_addr addr = sockaddr->sin6_addr; - boost::asio::ip::address_v6::bytes_type bytes; - memcpy(&bytes[0], addr.s6_addr, 16); - boost::asio::ip::address_v6 address(bytes, sockaddr->sin6_scope_id); - if (std::find(c_rejectAddresses.begin(), c_rejectAddresses.end(), address) == c_rejectAddresses.end()) - m_peerAddresses.push_back(address); - - // Log IPv6 Address: - auto addr6 = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr; - char addressBuffer[INET6_ADDRSTRLEN]; - inet_ntop(AF_INET6, addr6, addressBuffer, INET6_ADDRSTRLEN); - printf("%s IP Address %s\n", ifa->ifa_name, addressBuffer); - } - } - if (ifaddr!=NULL) freeifaddrs(ifaddr); - -#endif -} - shared_ptr Host::noteNode(NodeId _id, bi::tcp::endpoint _a, Origin _o, bool _ready, NodeId _oldId) { RecursiveGuard l(x_peers); @@ -375,6 +375,69 @@ Nodes Host::potentialPeers(RangeMask const& _known) return ret; } +void Host::determinePublic(string const& _publicAddress, bool _upnp) +{ + m_peerAddresses.clear(); + + // no point continuing if there are no interface addresses or valid listen port + if (!m_ifAddresses.size() || m_listenPort < 1) + return; + + // populate interfaces we'll listen on (eth listens on all interfaces); ignores local + for (auto addr: m_ifAddresses) + if ((m_netPrefs.localNetworking || !isPrivateAddress(addr)) && find(c_rejectAddresses.begin(), c_rejectAddresses.end(), addr) == c_rejectAddresses.end()) + m_peerAddresses.insert(addr); + + // 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 ? false : find(c_rejectAddresses.begin(), c_rejectAddresses.end(), reqpublicaddr) == c_rejectAddresses.end(); + if (!reqpublicaddr.is_unspecified() && (ispublic || (isprivate && m_netPrefs.localNetworking))) + { + if (!m_peerAddresses.count(reqpublicaddr)) + m_peerAddresses.insert(reqpublicaddr); + m_public = reqpublic; + return; + } + + // if address wasn't provided, then use first public ipv4 address found + for (auto addr: m_peerAddresses) + if (addr.is_v4() && !isPrivateAddress(addr)) + { + m_public = bi::tcp::endpoint(*m_peerAddresses.begin(), m_listenPort); + return; + } + + // or find address via upnp + if (_upnp) + { + bi::address upnpifaddr; + bi::tcp::endpoint upnpep = traverseNAT(m_ifAddresses, m_listenPort, upnpifaddr); + if (!upnpep.address().is_unspecified() && !upnpifaddr.is_unspecified()) + { + if (!m_peerAddresses.count(upnpep.address())) + m_peerAddresses.insert(upnpep.address()); + m_public = upnpep; + return; + } + } + + // or if no address provided, use private ipv4 address if local networking is enabled + if (reqpublicaddr.is_unspecified()) + if (m_netPrefs.localNetworking) + for (auto addr: m_peerAddresses) + if (addr.is_v4() && isPrivateAddress(addr)) + { + m_public = bi::tcp::endpoint(addr, m_listenPort); + return; + } + + // otherwise address is unspecified + m_public = bi::tcp::endpoint(bi::address(), m_listenPort); +} + void Host::ensureAccepting() { // return if there's no io-server (quit called) or we're not listening @@ -636,79 +699,49 @@ void Host::run(boost::system::error_code const& error) static unsigned s_lasttick = 0; s_lasttick += c_timerInterval; - if (error) - // tood: error handling. + if (error || !m_ioService) { + // timer died or io service went away, so stop here m_timer.reset(); return; } - - // no timer means this is first run and network must be started - if (!m_timer) - // run once when host worker thread calls startedWorking() + + // network running + if (m_run) { - // reset io service and create deadline timer - m_ioService->reset(); - m_timer.reset(new boost::asio::deadline_timer(*m_ioService)); - m_run = true; - - // try to open acceptor (ipv4; todo: update for ipv6) - for (unsigned i = 0; i < 2; ++i) + if (s_lasttick == c_timerInterval * 50) { - // try to connect w/listenPort, else attempt net-allocated port - bi::tcp::endpoint endpoint(bi::tcp::v4(), i ? 0 : m_netPrefs.listenPort); - try - { - m_acceptor->open(endpoint.protocol()); - m_acceptor->set_option(ba::socket_base::reuse_address(true)); - m_acceptor->bind(endpoint); - m_acceptor->listen(); - m_listenPort = i ? m_acceptor->local_endpoint().port() : m_netPrefs.listenPort; - break; - } - catch (...) - { - if (i) - { - // both attempts failed - cwarn << "Couldn't start accepting connections on host. Something very wrong with network?\n" << boost::current_exception_diagnostic_information(); - m_listenPort = -1; - } - - // first attempt failed - m_acceptor->close(); - continue; - } + growPeers(); + prunePeers(); + s_lasttick = 0; } - // start capability threads - for (auto const& h: m_capabilities) - h.second->onStarting(); + if (m_hadNewNodes) + { + for (auto p: m_peers) + if (auto pp = p.second.lock()) + pp->serviceNodesRequest(); + + m_hadNewNodes = false; + } - // determine public IP, but only if we're able to listen for connections - // todo: visualize when listen is unavailable in UI - if (m_listenPort) + if (chrono::steady_clock::now() - m_lastPing > chrono::seconds(30)) // ping every 30s. { - determinePublic(m_netPrefs.publicIP, m_netPrefs.upnp); - ensureAccepting(); + for (auto p: m_peers) + if (auto pp = p.second.lock()) + if (chrono::steady_clock::now() - pp->m_lastReceived > chrono::seconds(60)) + pp->disconnect(PingTimeout); + pingAll(); } - // 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); + auto runcb = [this](boost::system::error_code const& error) -> void{ run(error); }; + m_timer->expires_from_now(boost::posix_time::milliseconds(c_timerInterval)); + m_timer->async_wait(runcb); - clog(NetNote) << "Id:" << id().abridged(); - } - - // io service went away, so stop here - if (!m_ioService) - { - m_timer.reset(); return; } - - // network stopped; disconnect peers + + // network stopping if (!m_run) { // close acceptor @@ -745,50 +778,60 @@ void Host::run(boost::system::error_code const& error) if (m_socket->is_open()) m_socket->close(); - if (m_upnp != nullptr) - delete m_upnp; - // m_run is false, so we're stopping; kill timer s_lasttick = 0; + + // causes parent thread's stop() to continue which calls stopWorking() m_timer.reset(); + + // stop ioservice (stops blocking worker thread, allowing thread to join) if (!!m_ioService) m_ioService->stop(); return; } - - - if (s_lasttick == c_timerInterval * 10) - { - growPeers(); - prunePeers(); - s_lasttick = 0; - } - - if (m_hadNewNodes) - { - for (auto p: m_peers) - if (auto pp = p.second.lock()) - pp->serviceNodesRequest(); - - m_hadNewNodes = false; - } - - if (chrono::steady_clock::now() - m_lastPing > chrono::seconds(30)) // ping every 30s. - { - for (auto p: m_peers) - if (auto pp = p.second.lock()) - if (chrono::steady_clock::now() - pp->m_lastReceived > chrono::seconds(60)) - pp->disconnect(PingTimeout); - pingAll(); - } - - auto runcb = [this](boost::system::error_code const& error) -> void{ run(error); }; - m_timer->expires_from_now(boost::posix_time::milliseconds(c_timerInterval)); - m_timer->async_wait(runcb); } void Host::startedWorking() { + if (asserts(!m_timer)) + { + // no timer means this is first run and network must be started + // (run once when host worker thread calls startedWorking()) + + { + // prevent m_run from being set to true at same time as set to false by stop() + // don't release mutex until m_timer is set so in case stop() is called at same + // time, stop will wait on m_timer and graceful network shutdown. + lock_guard l(x_runtimer); + // reset io service and create deadline timer + m_timer.reset(new boost::asio::deadline_timer(*m_ioService)); + m_run = true; + } + m_ioService->reset(); + + // try to open acceptor (todo: ipv6) + m_listenPort = listen4(m_acceptor.get(), m_netPrefs.listenPort); + + // start capability threads + for (auto const& h: m_capabilities) + h.second->onStarting(); + + // determine public IP, but only if we're able to listen for connections + // todo: GUI when listen is unavailable in UI + if (m_listenPort) + { + determinePublic(m_netPrefs.publicIP, m_netPrefs.upnp); + ensureAccepting(); + } + + // 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); + + clog(NetNote) << "Id:" << id().abridged(); + } + run(boost::system::error_code()); } diff --git a/libp2p/Host.h b/libp2p/Host.h index b60949278..c619b6867 100644 --- a/libp2p/Host.h +++ b/libp2p/Host.h @@ -121,13 +121,24 @@ class Host: public Worker friend class HostCapabilityFace; friend struct Node; + /// Static network interface methods +public: + /// @returns public and private interface addresses + 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); + + /// 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); + public: /// Start server, listening for connections on the given port. Host(std::string const& _clientVersion, NetworkPreferences const& _n = NetworkPreferences(), bool _start = false); /// Will block on network process events. virtual ~Host(); - + /// Basic peer network protocol version. unsigned protocolVersion() const; @@ -144,7 +155,7 @@ public: void connect(bi::tcp::endpoint const& _ep); void connect(std::shared_ptr const& _n); - /// @returns true if we have the a peer of the given id. + /// @returns true iff we have a peer of the given id. bool havePeer(NodeId _id) const; /// Set ideal number of peers. @@ -172,14 +183,14 @@ public: void setNetworkPreferences(NetworkPreferences const& _p) { auto had = isStarted(); if (had) stop(); m_netPrefs = _p; if (had) start(); } - /// Start network. + /// Start network. @threadsafe void start(); - /// Stop network. + /// Stop network. @threadsafe void stop(); - /// @returns if network is running - bool isStarted() const { return isWorking(); } + /// @returns if network is running. + bool isStarted() const { return m_run; } /// Reset acceptor, socket, and IO service. Called by deallocator. Maybe called by implementation when ordered deallocation is required. void quit(); @@ -191,13 +202,12 @@ public: std::shared_ptr node(NodeId _id) const { if (m_nodes.count(_id)) return m_nodes.at(_id); return std::shared_ptr(); } private: - void seal(bytes& _b); - void populateAddresses(); - - /// Try UPNP or listen to assumed address. Requires valid m_listenPort. + /// Populate m_peerAddresses with available public addresses. void determinePublic(std::string const& _publicAddress, bool _upnp); void ensureAccepting(); + + void seal(bytes& _b); void growPeers(); void prunePeers(); @@ -206,7 +216,6 @@ private: virtual void startedWorking(); /// Called by startedWorking. Not thread-safe; to be called only be worker callback. void run(boost::system::error_code const& error); ///< Run network. Called serially via ASIO deadline timer. Manages connection state transitions. - bool m_run = false; /// Run network virtual void doWork(); @@ -214,9 +223,15 @@ private: std::shared_ptr noteNode(NodeId _id, bi::tcp::endpoint _a, Origin _o, bool _ready, NodeId _oldId = NodeId()); Nodes potentialPeers(RangeMask const& _known); + bool m_run = false; ///< Whether network is running. + std::mutex x_runtimer; ///< Start/stop mutex. + std::string m_clientVersion; ///< Our version string. NetworkPreferences m_netPrefs; ///< Network settings. + + /// Interface addresses (private, public) + std::vector m_ifAddresses; ///< Interface addresses. int m_listenPort = -1; ///< What port are we listening on. -1 means binding failed or acceptor hasn't been initialized. @@ -227,7 +242,6 @@ private: std::unique_ptr m_timer; ///< Timer which, when network is running, calls scheduler() every c_timerInterval ms. static const unsigned c_timerInterval = 100; ///< Interval which m_timer is run when network is connected. - UPnP* m_upnp = nullptr; ///< UPnP helper. bi::tcp::endpoint m_public; ///< Our public listening endpoint. KeyPair m_key; ///< Our unique ID. @@ -247,13 +261,11 @@ private: std::vector m_nodesList; RangeMask m_ready; ///< Indices into m_nodesList over to which nodes we are not currently connected, connecting or otherwise ignoring. - RangeMask m_private; ///< Indices into m_nodesList over to which nodes are private. - - unsigned m_idealPeerCount = 5; ///< Ideal number of peers to be connected to. + RangeMask m_private; ///< Indices into m_nodesList over to which nodes are private. - // Our addresses. - std::vector m_addresses; ///< Addresses for us. - std::vector m_peerAddresses; ///< Addresses that peers (can) know us by. + unsigned m_idealPeerCount = 5; ///< Ideal number of peers to be connected to. + + std::set m_peerAddresses; ///< Public addresses that peers (can) know us by. // Our capabilities. std::map> m_capabilities; ///< Each of the capabilities we support. diff --git a/libp2p/Session.cpp b/libp2p/Session.cpp index c4385df5f..958473870 100644 --- a/libp2p/Session.cpp +++ b/libp2p/Session.cpp @@ -344,7 +344,7 @@ bool Session::interpret(RLP const& _r) // goto CONTINUE; // Wierd port. // Avoid our random other addresses that they might end up giving us. - for (auto i: m_server->m_addresses) + for (auto i: m_server->m_peerAddresses) if (ep.address() == i && ep.port() == m_server->listenPort()) goto CONTINUE; From fb7f8e782ea61781cf64e5595b6b79c6babebf59 Mon Sep 17 00:00:00 2001 From: subtly Date: Sat, 22 Nov 2014 08:56:16 +0100 Subject: [PATCH 26/86] fix --- libp2p/Host.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index b51443e63..471d1dc56 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -793,7 +793,7 @@ void Host::run(boost::system::error_code const& error) void Host::startedWorking() { - if (asserts(!m_timer)) + if (!m_timer) { // no timer means this is first run and network must be started // (run once when host worker thread calls startedWorking()) From 1bdf76922eb9a484d2bc695811de6025cca63bef Mon Sep 17 00:00:00 2001 From: subtly Date: Sun, 23 Nov 2014 06:51:18 +0100 Subject: [PATCH 27/86] remove spontaneous whitespace --- libp2p/Host.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libp2p/Host.h b/libp2p/Host.h index c619b6867..c82ecf84c 100644 --- a/libp2p/Host.h +++ b/libp2p/Host.h @@ -110,7 +110,7 @@ struct NetworkPreferences bool upnp = true; bool localNetworking = false; }; - + /** * @brief The Host class * Capabilities should be registered prior to startNetwork, since m_capabilities is not thread-safe. From ad1a1f3ee2cb2aad3f1d594dce999ccdd7006aff Mon Sep 17 00:00:00 2001 From: Christian Date: Wed, 19 Nov 2014 18:56:10 +0100 Subject: [PATCH 28/86] We only care about member types. --- libsolidity/AST.cpp | 2 +- libsolidity/Types.cpp | 8 ++++---- libsolidity/Types.h | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index e8bdecf31..2972cb5c2 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -469,7 +469,7 @@ void MemberAccess::checkTypeRequirements() unsigned memberIndex = type.memberNameToIndex(*m_memberName); if (memberIndex >= type.getMemberCount()) BOOST_THROW_EXCEPTION(createTypeError("Member \"" + *m_memberName + "\" not found in " + type.toString())); - m_type = type.getMemberByIndex(memberIndex).getType(); + m_type = type.getMemberByIndex(memberIndex); m_isLvalue = true; } diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index e24435976..79d4a1c17 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -234,7 +234,7 @@ u256 StructType::getStorageSize() const bool StructType::canLiveOutsideStorage() const { for (unsigned i = 0; i < getMemberCount(); ++i) - if (!getMemberByIndex(i).getType()->canLiveOutsideStorage()) + if (!getMemberByIndex(i)->canLiveOutsideStorage()) return false; return true; } @@ -258,9 +258,9 @@ unsigned StructType::memberNameToIndex(string const& _name) const return unsigned(-1); } -VariableDeclaration const& StructType::getMemberByIndex(unsigned _index) const +shared_ptr const& StructType::getMemberByIndex(unsigned _index) const { - return *m_struct.getMembers()[_index]; + return m_struct.getMembers()[_index].getType(); } u256 StructType::getStorageOffsetOfMember(unsigned _index) const @@ -269,7 +269,7 @@ u256 StructType::getStorageOffsetOfMember(unsigned _index) const u256 offset; // vector> const& members = m_struct.getMembers(); for (unsigned index = 0; index < _index; ++index) - offset += getMemberByIndex(index).getType()->getStorageSize(); + offset += getMemberByIndex(index)->getStorageSize(); return offset; } diff --git a/libsolidity/Types.h b/libsolidity/Types.h index 726470172..b0d95d291 100644 --- a/libsolidity/Types.h +++ b/libsolidity/Types.h @@ -190,7 +190,7 @@ public: unsigned getMemberCount() const; /// Returns the index of the member with name @a _name or unsigned(-1) if it does not exist. unsigned memberNameToIndex(std::string const& _name) const; - VariableDeclaration const& getMemberByIndex(unsigned _index) const; + std::shared_ptr const& getMemberByIndex(unsigned _index) const; u256 getStorageOffsetOfMember(unsigned _index) const; private: From 6ee07c2cb8cff638cf80fad2974e97c0f7d8ddb0 Mon Sep 17 00:00:00 2001 From: Christian Date: Thu, 20 Nov 2014 10:19:43 +0100 Subject: [PATCH 29/86] Convenience class for type members. --- libsolidity/AST.cpp | 10 ++---- libsolidity/ExpressionCompiler.cpp | 5 +-- libsolidity/Types.cpp | 49 +++++++++++++++--------------- libsolidity/Types.h | 47 +++++++++++++++++++++++++--- 4 files changed, 70 insertions(+), 41 deletions(-) diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index 2972cb5c2..9aecbdedf 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -462,14 +462,10 @@ void MemberAccess::checkTypeRequirements() { m_expression->checkTypeRequirements(); m_expression->requireLValue(); - if (m_expression->getType()->getCategory() != Type::Category::STRUCT) - BOOST_THROW_EXCEPTION(createTypeError("Member access to a non-struct (is " + - m_expression->getType()->toString() + ")")); - StructType const& type = dynamic_cast(*m_expression->getType()); - unsigned memberIndex = type.memberNameToIndex(*m_memberName); - if (memberIndex >= type.getMemberCount()) + Type const& type = *m_expression->getType(); + m_type = type.getMemberType(*m_memberName); + if (!m_type) BOOST_THROW_EXCEPTION(createTypeError("Member \"" + *m_memberName + "\" not found in " + type.toString())); - m_type = type.getMemberByIndex(memberIndex); m_isLvalue = true; } diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index f37ce39ce..89eeb31f2 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -208,10 +208,7 @@ void ExpressionCompiler::endVisit(MemberAccess& _memberAccess) if (asserts(m_currentLValue.isInStorage())) BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Member access to a non-storage value.")); StructType const& type = dynamic_cast(*_memberAccess.getExpression().getType()); - unsigned memberIndex = type.memberNameToIndex(_memberAccess.getMemberName()); - if (asserts(memberIndex <= type.getMemberCount())) - BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Member not found in struct during compilation.")); - m_context << type.getStorageOffsetOfMember(memberIndex) << eth::Instruction::ADD; + m_context << type.getStorageOffsetOfMember(_memberAccess.getMemberName()) << eth::Instruction::ADD; m_currentLValue.retrieveValueIfLValueNotRequested(_memberAccess); } diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index 79d4a1c17..897ca221c 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -86,6 +86,8 @@ shared_ptr Type::forLiteral(Literal const& _literal) } } +const MemberList Type::EmptyMemberList = MemberList(); + shared_ptr IntegerType::smallestTypeForLiteral(string const& _literal) { bigint value(_literal); @@ -226,15 +228,15 @@ bool StructType::operator==(Type const& _other) const u256 StructType::getStorageSize() const { u256 size = 0; - for (ASTPointer const& variable: m_struct.getMembers()) - size += variable->getType()->getStorageSize(); + for (pair> const& member: getMembers()) + size += member.second->getStorageSize(); return max(1, size); } bool StructType::canLiveOutsideStorage() const { - for (unsigned i = 0; i < getMemberCount(); ++i) - if (!getMemberByIndex(i)->canLiveOutsideStorage()) + for (pair> const& member: getMembers()) + if (!member.second->canLiveOutsideStorage()) return false; return true; } @@ -244,33 +246,30 @@ string StructType::toString() const return string("struct ") + m_struct.getName(); } -unsigned StructType::getMemberCount() const -{ - return m_struct.getMembers().size(); -} - -unsigned StructType::memberNameToIndex(string const& _name) const -{ - vector> const& members = m_struct.getMembers(); - for (unsigned index = 0; index < members.size(); ++index) - if (members[index]->getName() == _name) - return index; - return unsigned(-1); -} - -shared_ptr const& StructType::getMemberByIndex(unsigned _index) const +MemberList const& StructType::getMembers() const { - return m_struct.getMembers()[_index].getType(); + // We need to lazy-initialize it because of recursive references. + if (!m_members) + { + map> members; + for (ASTPointer const& variable: m_struct.getMembers()) + members[variable->getName()] = variable->getType(); + m_members.reset(new MemberList(members)); + } + return *m_members; } -u256 StructType::getStorageOffsetOfMember(unsigned _index) const +u256 StructType::getStorageOffsetOfMember(string const& _name) const { //@todo cache member offset? u256 offset; -// vector> const& members = m_struct.getMembers(); - for (unsigned index = 0; index < _index; ++index) - offset += getMemberByIndex(index)->getStorageSize(); - return offset; + for (ASTPointer variable: m_struct.getMembers()) + { + offset += variable->getType()->getStorageSize(); + if (variable->getName() == _name) + return offset; + } + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Storage offset of non-existing member requested.")); } bool FunctionType::operator==(Type const& _other) const diff --git a/libsolidity/Types.h b/libsolidity/Types.h index b0d95d291..2208a880e 100644 --- a/libsolidity/Types.h +++ b/libsolidity/Types.h @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -37,6 +38,33 @@ namespace solidity // @todo realMxN, string +class Type; // forward + +/** + * List of members of a type. + */ +class MemberList +{ +public: + using TypePointer = std::shared_ptr; + using MemberMap = std::map; + + MemberList() {} + explicit MemberList(MemberMap const& _members): m_memberTypes(_members) {} + TypePointer getMemberType(std::string const& _name) const + { + auto it = m_memberTypes.find(_name); + return it != m_memberTypes.end() ? it->second : std::shared_ptr(); + } + + MemberMap::const_iterator begin() const { return m_memberTypes.begin(); } + MemberMap::const_iterator end() const { return m_memberTypes.end(); } + +private: + MemberMap m_memberTypes; +}; + + /** * Abstract base class that forms the root of the type hierarchy. */ @@ -81,12 +109,21 @@ public: /// Returns false if the type cannot live outside the storage, i.e. if it includes some mapping. virtual bool canLiveOutsideStorage() const { return true; } + /// Returns the list of all members of this type. Default implementation: no members. + virtual MemberList const& getMembers() const { return EmptyMemberList; } + /// Convenience method, returns the type of the given named member or an empty pointer if no such member exists. + std::shared_ptr getMemberType(std::string const& _name) const { return getMembers().getMemberType(_name); } + virtual std::string toString() const = 0; virtual u256 literalValue(Literal const&) const { BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Literal value requested " "for type without literals.")); } + +protected: + /// Convenience object used when returning an empty member list. + static const MemberList EmptyMemberList; }; /** @@ -187,14 +224,14 @@ public: virtual bool canLiveOutsideStorage() const; virtual std::string toString() const override; - unsigned getMemberCount() const; - /// Returns the index of the member with name @a _name or unsigned(-1) if it does not exist. - unsigned memberNameToIndex(std::string const& _name) const; - std::shared_ptr const& getMemberByIndex(unsigned _index) const; - u256 getStorageOffsetOfMember(unsigned _index) const; + virtual MemberList const& getMembers() const override; + + u256 getStorageOffsetOfMember(std::string const& _name) const; private: StructDefinition const& m_struct; + /// List of member types, will be lazy-initialized because of recursive references. + mutable std::unique_ptr m_members; }; /** From 638960f22f5c5d394dce0bb8223b860e4869b8c7 Mon Sep 17 00:00:00 2001 From: Christian Date: Thu, 20 Nov 2014 18:33:23 +0100 Subject: [PATCH 30/86] Contracts as types and framework for special global variables. --- libsolidity/AST.cpp | 36 ++++++++++++- libsolidity/AST.h | 20 +++++--- libsolidity/CompilerStack.cpp | 5 +- libsolidity/CompilerStack.h | 9 ++-- libsolidity/ExpressionCompiler.cpp | 14 ++++-- libsolidity/GlobalContext.cpp | 70 ++++++++++++++++++++++++++ libsolidity/GlobalContext.h | 61 ++++++++++++++++++++++ libsolidity/NameAndTypeResolver.cpp | 43 +++++----------- libsolidity/NameAndTypeResolver.h | 3 +- libsolidity/Scanner.cpp | 1 - libsolidity/Token.h | 1 - libsolidity/Types.cpp | 30 +++++++++-- libsolidity/Types.h | 32 +++++++----- test/solidityCompiler.cpp | 2 +- test/solidityEndToEndTest.cpp | 29 +++++++---- test/solidityExpressionCompiler.cpp | 2 +- test/solidityNameAndTypeResolution.cpp | 2 +- test/solidityParser.cpp | 20 ++++++++ 18 files changed, 302 insertions(+), 78 deletions(-) create mode 100644 libsolidity/GlobalContext.cpp create mode 100644 libsolidity/GlobalContext.h diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index 9aecbdedf..22a658d40 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -51,6 +51,40 @@ void StructDefinition::accept(ASTVisitor& _visitor) _visitor.endVisit(*this); } +void StructDefinition::checkValidityOfMembers() +{ + checkMemberTypes(); + checkRecursion(); +} + +void StructDefinition::checkMemberTypes() +{ + for (ASTPointer const& member: getMembers()) + if (!member->getType()->canBeStored()) + BOOST_THROW_EXCEPTION(member->createTypeError("Type cannot be used in struct.")); +} + +void StructDefinition::checkRecursion() +{ + set definitionsSeen; + vector queue = {this}; + while (!queue.empty()) + { + StructDefinition const* def = queue.back(); + queue.pop_back(); + if (definitionsSeen.count(def)) + BOOST_THROW_EXCEPTION(ParserError() << errinfo_sourceLocation(def->getLocation()) + << errinfo_comment("Recursive struct definition.")); + definitionsSeen.insert(def); + for (ASTPointer const& member: def->getMembers()) + if (member->getType()->getCategory() == Type::Category::STRUCT) + { + UserDefinedTypeName const& typeName = dynamic_cast(*member->getTypeName()); + queue.push_back(&dynamic_cast(*typeName.getReferencedDeclaration())); + } + } +} + void ParameterList::accept(ASTVisitor& _visitor) { if (_visitor.visit(*this)) @@ -258,7 +292,7 @@ void Literal::accept(ASTVisitor& _visitor) _visitor.endVisit(*this); } -TypeError ASTNode::createTypeError(string const& _description) +TypeError ASTNode::createTypeError(string const& _description) const { return TypeError() << errinfo_sourceLocation(getLocation()) << errinfo_comment(_description); } diff --git a/libsolidity/AST.h b/libsolidity/AST.h index 80c7dd198..01e1b54f0 100644 --- a/libsolidity/AST.h +++ b/libsolidity/AST.h @@ -66,7 +66,7 @@ public: /// Creates a @ref TypeError exception and decorates it with the location of the node and /// the given description - TypeError createTypeError(std::string const& _description); + TypeError createTypeError(std::string const& _description) const; ///@{ ///@name equality operators @@ -139,7 +139,14 @@ public: std::vector> const& getMembers() const { return m_members; } + /// Checks that the members do not include any recursive structs and have valid types + /// (e.g. no functions). + void checkValidityOfMembers(); + private: + void checkMemberTypes(); + void checkRecursion(); + std::vector> m_members; }; @@ -210,7 +217,6 @@ public: Declaration(_location, _name), m_typeName(_type) {} virtual void accept(ASTVisitor& _visitor) override; - bool isTypeGivenExplicitly() const { return bool(m_typeName); } TypeName* getTypeName() const { return m_typeName.get(); } /// Returns the declared or inferred type. Can be an empty pointer if no type was explicitly @@ -238,6 +244,7 @@ public: /// Retrieve the element of the type hierarchy this node refers to. Can return an empty shared /// pointer until the types have been resolved using the @ref NameAndTypeResolver. + /// If it returns an empty shared pointer after that, this indicates that the type was not found. virtual std::shared_ptr toType() const = 0; }; @@ -263,8 +270,7 @@ private: }; /** - * Name referring to a user-defined type (i.e. a struct). - * @todo some changes are necessary if this is also used to refer to contract types later + * Name referring to a user-defined type (i.e. a struct, contract, etc.). */ class UserDefinedTypeName: public TypeName { @@ -275,13 +281,13 @@ public: virtual std::shared_ptr toType() const override { return Type::fromUserDefinedTypeName(*this); } ASTString const& getName() const { return *m_name; } - void setReferencedStruct(StructDefinition& _referencedStruct) { m_referencedStruct = &_referencedStruct; } - StructDefinition const* getReferencedStruct() const { return m_referencedStruct; } + void setReferencedDeclaration(Declaration& _referencedDeclaration) { m_referencedDeclaration = &_referencedDeclaration; } + Declaration const* getReferencedDeclaration() const { return m_referencedDeclaration; } private: ASTPointer m_name; - StructDefinition* m_referencedStruct; + Declaration* m_referencedDeclaration; }; /** diff --git a/libsolidity/CompilerStack.cpp b/libsolidity/CompilerStack.cpp index d87c27916..f051d58fd 100644 --- a/libsolidity/CompilerStack.cpp +++ b/libsolidity/CompilerStack.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -45,7 +46,9 @@ void CompilerStack::parse() if (!m_scanner) BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Source not available.")); m_contractASTNode = Parser().parse(m_scanner); - NameAndTypeResolver().resolveNamesAndTypes(*m_contractASTNode); + m_globalContext = make_shared(); + m_globalContext->setCurrentContract(*m_contractASTNode); + NameAndTypeResolver(m_globalContext->getDeclarations()).resolveNamesAndTypes(*m_contractASTNode); m_parseSuccessful = true; } diff --git a/libsolidity/CompilerStack.h b/libsolidity/CompilerStack.h index 2fb505897..6cae8660f 100644 --- a/libsolidity/CompilerStack.h +++ b/libsolidity/CompilerStack.h @@ -30,9 +30,11 @@ namespace dev { namespace solidity { -class Scanner; // forward -class ContractDefinition; // forward -class Compiler; // forward +// forward declarations +class Scanner; +class ContractDefinition; +class Compiler; +class GlobalContext; /** * Easy to use and self-contained Solidity compiler with as few header dependencies as possible. @@ -71,6 +73,7 @@ public: private: std::shared_ptr m_scanner; + std::shared_ptr m_globalContext; std::shared_ptr m_contractASTNode; bool m_parseSuccessful; std::string m_interface; diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index 89eeb31f2..4d175527a 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -167,7 +167,15 @@ bool ExpressionCompiler::visit(FunctionCall& _functionCall) BOOST_THROW_EXCEPTION(InternalCompilerError()); Expression& firstArgument = *_functionCall.getArguments().front(); firstArgument.accept(*this); - appendTypeConversion(*firstArgument.getType(), *_functionCall.getType()); + if (firstArgument.getType()->getCategory() == Type::Category::CONTRACT && + _functionCall.getType()->getCategory() == Type::Category::INTEGER) + { + // explicit type conversion contract -> address, nothing to do. + } + else + { + appendTypeConversion(*firstArgument.getType(), *_functionCall.getType()); + } } else { @@ -466,7 +474,7 @@ void ExpressionCompiler::LValue::storeValue(Expression const& _expression, bool } } -void ExpressionCompiler::LValue::retrieveValueIfLValueNotRequested(const Expression& _expression) +void ExpressionCompiler::LValue::retrieveValueIfLValueNotRequested(Expression const& _expression) { if (!_expression.lvalueRequested()) { @@ -475,7 +483,7 @@ void ExpressionCompiler::LValue::retrieveValueIfLValueNotRequested(const Express } } -void ExpressionCompiler::LValue::fromDeclaration( Expression const& _expression, Declaration const& _declaration) +void ExpressionCompiler::LValue::fromDeclaration(Expression const& _expression, Declaration const& _declaration) { if (m_context->isLocalVariable(&_declaration)) { diff --git a/libsolidity/GlobalContext.cpp b/libsolidity/GlobalContext.cpp new file mode 100644 index 000000000..6179722b2 --- /dev/null +++ b/libsolidity/GlobalContext.cpp @@ -0,0 +1,70 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** + * @author Christian + * @date 2014 + * Container of the (implicit and explicit) global objects. + */ + +#include +#include +#include +#include + +using namespace std; + +namespace dev +{ +namespace solidity +{ + +GlobalContext::GlobalContext() +{ + // CurrentContract this; // @todo type depends on context -> switch prior to entering contract + // Message msg; + // Transaction tx; + // Block block; + + //@todo type will be a custom complex type, maybe the same type class for msg tx and block. + //addVariable("msg", ); +} + +void GlobalContext::setCurrentContract(ContractDefinition const& _contract) +{ + m_this = createVariable("this", make_shared(_contract)); +} + +vector GlobalContext::getDeclarations() const +{ + vector declarations; + declarations.reserve(m_objects.size() + 1); + for (ASTPointer const& declaration: m_objects) + declarations.push_back(declaration.get()); + declarations.push_back(m_this.get()); + return declarations; +} + +ASTPointer GlobalContext::createVariable(const string& _name, shared_ptr const& _type) +{ + ASTPointer variable = make_shared(Location(), ASTPointer(), + make_shared(_name)); + variable->setType(_type); + return variable; +} + +} +} diff --git a/libsolidity/GlobalContext.h b/libsolidity/GlobalContext.h new file mode 100644 index 000000000..b6dea7d56 --- /dev/null +++ b/libsolidity/GlobalContext.h @@ -0,0 +1,61 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** + * @author Christian + * @date 2014 + * Container of the (implicit and explicit) global objects. + */ + +#pragma once + +#include +#include +#include +#include +#include + +namespace dev +{ +namespace solidity +{ + +class Type; // forward + +/** + * Container for all global objects which look like AST nodes, but are not part of the AST + * that is currently being compiled. + * @note must not be destroyed or moved during compilation as its objects can be referenced from + * other objects. + */ +class GlobalContext: private boost::noncopyable +{ +public: + GlobalContext(); + void setCurrentContract(ContractDefinition const& _contract); + + std::vector getDeclarations() const; + +private: + /// Creates a virtual variable declaration with the given name and type. + static ASTPointer createVariable(std::string const& _name, std::shared_ptr const& _type); + + std::vector> m_objects; + ASTPointer m_this; +}; + +} +} diff --git a/libsolidity/NameAndTypeResolver.cpp b/libsolidity/NameAndTypeResolver.cpp index aa7726582..225f2a78a 100644 --- a/libsolidity/NameAndTypeResolver.cpp +++ b/libsolidity/NameAndTypeResolver.cpp @@ -32,15 +32,20 @@ namespace solidity { +NameAndTypeResolver::NameAndTypeResolver(std::vector const& _globals) +{ + for (Declaration* declaration: _globals) + m_scopes[nullptr].registerDeclaration(*declaration); +} + void NameAndTypeResolver::resolveNamesAndTypes(ContractDefinition& _contract) { - reset(); DeclarationRegistrationHelper registrar(m_scopes, _contract); m_currentScope = &m_scopes[&_contract]; for (ASTPointer const& structDef: _contract.getDefinedStructs()) ReferencesResolver resolver(*structDef, *this, nullptr); for (ASTPointer const& structDef: _contract.getDefinedStructs()) - checkForRecursion(*structDef); + structDef->checkValidityOfMembers(); for (ASTPointer const& variable: _contract.getStateVariables()) ReferencesResolver resolver(*variable, *this, nullptr); for (ASTPointer const& function: _contract.getDefinedFunctions()) @@ -73,30 +78,6 @@ Declaration* NameAndTypeResolver::getNameFromCurrentScope(ASTString const& _name return m_currentScope->resolveName(_name, _recursive); } -void NameAndTypeResolver::checkForRecursion(StructDefinition const& _struct) -{ - set definitionsSeen; - vector queue = {&_struct}; - while (!queue.empty()) - { - StructDefinition const* def = queue.back(); - queue.pop_back(); - if (definitionsSeen.count(def)) - BOOST_THROW_EXCEPTION(ParserError() << errinfo_sourceLocation(def->getLocation()) - << errinfo_comment("Recursive struct definition.")); - definitionsSeen.insert(def); - for (ASTPointer const& member: def->getMembers()) - if (member->getType()->getCategory() == Type::Category::STRUCT) - queue.push_back(dynamic_cast(*member->getTypeName()).getReferencedStruct()); - } -} - -void NameAndTypeResolver::reset() -{ - m_scopes.clear(); - m_currentScope = nullptr; -} - DeclarationRegistrationHelper::DeclarationRegistrationHelper(map& _scopes, ASTNode& _astRoot): m_scopes(_scopes), m_currentScope(&m_scopes[nullptr]) @@ -195,7 +176,11 @@ void ReferencesResolver::endVisit(VariableDeclaration& _variable) // endVisit because the internal type needs resolving if it is a user defined type // or mapping if (_variable.getTypeName()) + { _variable.setType(_variable.getTypeName()->toType()); + if (!_variable.getType()) + BOOST_THROW_EXCEPTION(_variable.getTypeName()->createTypeError("Invalid type name")); + } else if (!m_allowLazyTypes) BOOST_THROW_EXCEPTION(_variable.createTypeError("Explicit type needed.")); // otherwise we have a "var"-declaration whose type is resolved by the first assignment @@ -221,11 +206,7 @@ bool ReferencesResolver::visit(UserDefinedTypeName& _typeName) if (!declaration) BOOST_THROW_EXCEPTION(DeclarationError() << errinfo_sourceLocation(_typeName.getLocation()) << errinfo_comment("Undeclared identifier.")); - StructDefinition* referencedStruct = dynamic_cast(declaration); - //@todo later, contracts are also valid types - if (!referencedStruct) - BOOST_THROW_EXCEPTION(_typeName.createTypeError("Identifier does not name a type name.")); - _typeName.setReferencedStruct(*referencedStruct); + _typeName.setReferencedDeclaration(*declaration); return false; } diff --git a/libsolidity/NameAndTypeResolver.h b/libsolidity/NameAndTypeResolver.h index d335807e5..64f3c89db 100644 --- a/libsolidity/NameAndTypeResolver.h +++ b/libsolidity/NameAndTypeResolver.h @@ -41,8 +41,7 @@ namespace solidity class NameAndTypeResolver: private boost::noncopyable { public: - NameAndTypeResolver() {} - + explicit NameAndTypeResolver(std::vector const& _globals); void resolveNamesAndTypes(ContractDefinition& _contract); /// Resolves the given @a _name inside the scope @a _scope. If @a _scope is omitted, diff --git a/libsolidity/Scanner.cpp b/libsolidity/Scanner.cpp index 895b8ae7a..dd18a320f 100644 --- a/libsolidity/Scanner.cpp +++ b/libsolidity/Scanner.cpp @@ -683,7 +683,6 @@ Token::Value Scanner::scanNumber(char _charSeen) KEYWORD("switch", Token::SWITCH) \ KEYWORD_GROUP('t') \ KEYWORD("text", Token::TEXT) \ - KEYWORD("this", Token::THIS) \ KEYWORD("true", Token::TRUE_LITERAL) \ KEYWORD_GROUP('u') \ KEYWORD("uint", Token::UINT) \ diff --git a/libsolidity/Token.h b/libsolidity/Token.h index 524487521..8974ca1ad 100644 --- a/libsolidity/Token.h +++ b/libsolidity/Token.h @@ -160,7 +160,6 @@ namespace solidity K(RETURNS, "returns", 0) \ K(STRUCT, "struct", 0) \ K(SWITCH, "switch", 0) \ - K(THIS, "this", 0) \ K(VAR, "var", 0) \ K(WHILE, "while", 0) \ \ diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index 897ca221c..f9d3d90fa 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -60,13 +60,24 @@ shared_ptr Type::fromElementaryTypeName(Token::Value _typeToken) shared_ptr Type::fromUserDefinedTypeName(UserDefinedTypeName const& _typeName) { - return make_shared(*_typeName.getReferencedStruct()); + Declaration const* declaration = _typeName.getReferencedDeclaration(); + if (StructDefinition const* structDef = dynamic_cast(declaration)) + return make_shared(*structDef); + else if (FunctionDefinition const* function = dynamic_cast(declaration)) + return make_shared(*function); + else if (ContractDefinition const* contract = dynamic_cast(declaration)) + return make_shared(*contract); + return shared_ptr(); } shared_ptr Type::fromMapping(Mapping const& _typeName) { shared_ptr keyType = _typeName.getKeyType().toType(); + if (!keyType) + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Error resolving type name.")); shared_ptr valueType = _typeName.getValueType().toType(); + if (!valueType) + BOOST_THROW_EXCEPTION(_typeName.getValueType().createTypeError("Invalid type name")); return make_shared(keyType, valueType); } @@ -201,6 +212,15 @@ u256 BoolType::literalValue(Literal const& _literal) const BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Bool type constructed from non-boolean literal.")); } +bool ContractType::isExplicitlyConvertibleTo(Type const& _convertTo) const +{ + if (isImplicitlyConvertibleTo(_convertTo)) + return true; + if (_convertTo.getCategory() == Category::INTEGER) + return dynamic_cast(_convertTo).isAddress(); + return false; +} + bool ContractType::operator==(Type const& _other) const { if (_other.getCategory() != getCategory()) @@ -217,6 +237,11 @@ u256 ContractType::getStorageSize() const return max(1, size); } +string ContractType::toString() const +{ + return "contract " + m_contract.getName(); +} + bool StructType::operator==(Type const& _other) const { if (_other.getCategory() != getCategory()) @@ -282,8 +307,7 @@ bool FunctionType::operator==(Type const& _other) const string FunctionType::toString() const { - //@todo nice string for function types - return "function(...)returns(...)"; + return "function " + m_function.getName(); } bool MappingType::operator==(Type const& _other) const diff --git a/libsolidity/Types.h b/libsolidity/Types.h index 2208a880e..297284ba0 100644 --- a/libsolidity/Types.h +++ b/libsolidity/Types.h @@ -106,6 +106,8 @@ public: /// @returns number of bytes required to hold this value in storage. /// For dynamically "allocated" types, it returns the size of the statically allocated head, virtual u256 getStorageSize() const { return 1; } + /// Returns true if the type can be stored in storage. + virtual bool canBeStored() const { return true; } /// Returns false if the type cannot live outside the storage, i.e. if it includes some mapping. virtual bool canLiveOutsideStorage() const { return true; } @@ -151,7 +153,7 @@ public: virtual bool operator==(Type const& _other) const override; - virtual unsigned getCalldataEncodedSize() const { return m_bits / 8; } + virtual unsigned getCalldataEncodedSize() const override { return m_bits / 8; } virtual std::string toString() const override; virtual u256 literalValue(Literal const& _literal) const override; @@ -197,10 +199,11 @@ class ContractType: public Type public: virtual Category getCategory() const override { return Category::CONTRACT; } ContractType(ContractDefinition const& _contract): m_contract(_contract) {} - + /// Contracts can be converted to themselves and to addresses. + virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const override; virtual bool operator==(Type const& _other) const override; - virtual u256 getStorageSize() const; - virtual std::string toString() const override { return "contract{...}"; } + virtual u256 getStorageSize() const override; + virtual std::string toString() const override; private: ContractDefinition const& m_contract; @@ -220,8 +223,8 @@ public: } virtual bool operator==(Type const& _other) const override; - virtual u256 getStorageSize() const; - virtual bool canLiveOutsideStorage() const; + virtual u256 getStorageSize() const override; + virtual bool canLiveOutsideStorage() const override; virtual std::string toString() const override; virtual MemberList const& getMembers() const override; @@ -247,8 +250,9 @@ public: virtual bool operator==(Type const& _other) const override; virtual std::string toString() const override; - virtual u256 getStorageSize() const { BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Storage size of non-storable function type requested.")); } - virtual bool canLiveOutsideStorage() const { return false; } + virtual bool canBeStored() const override { return false; } + virtual u256 getStorageSize() const override { BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Storage size of non-storable function type requested.")); } + virtual bool canLiveOutsideStorage() const override { return false; } private: FunctionDefinition const& m_function; @@ -266,7 +270,7 @@ public: virtual bool operator==(Type const& _other) const override; virtual std::string toString() const override; - virtual bool canLiveOutsideStorage() const { return false; } + virtual bool canLiveOutsideStorage() const override { return false; } std::shared_ptr getKeyType() const { return m_keyType; } std::shared_ptr getValueType() const { return m_valueType; } @@ -287,8 +291,9 @@ public: VoidType() {} virtual std::string toString() const override { return "void"; } - virtual u256 getStorageSize() const { BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Storage size of non-storable void type requested.")); } - virtual bool canLiveOutsideStorage() const { return false; } + virtual bool canBeStored() const override { return false; } + 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; } }; /** @@ -304,8 +309,9 @@ public: std::shared_ptr const& getActualType() const { return m_actualType; } virtual bool operator==(Type const& _other) const override; - virtual u256 getStorageSize() const { BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Storage size of non-storable type type requested.")); } - virtual bool canLiveOutsideStorage() const { return false; } + virtual bool canBeStored() const override { return false; } + virtual u256 getStorageSize() const override { BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Storage size of non-storable type type requested.")); } + virtual bool canLiveOutsideStorage() const override { return false; } virtual std::string toString() const override { return "type(" + m_actualType->toString() + ")"; } private: diff --git a/test/solidityCompiler.cpp b/test/solidityCompiler.cpp index e0635b6ae..1767a0f36 100644 --- a/test/solidityCompiler.cpp +++ b/test/solidityCompiler.cpp @@ -48,7 +48,7 @@ bytes compileContract(const string& _sourceCode) Parser parser; ASTPointer contract; BOOST_REQUIRE_NO_THROW(contract = parser.parse(make_shared(CharStream(_sourceCode)))); - NameAndTypeResolver resolver; + NameAndTypeResolver resolver({}); BOOST_REQUIRE_NO_THROW(resolver.resolveNamesAndTypes(*contract)); Compiler compiler; diff --git a/test/solidityEndToEndTest.cpp b/test/solidityEndToEndTest.cpp index 4e68103ac..a7c6357bf 100644 --- a/test/solidityEndToEndTest.cpp +++ b/test/solidityEndToEndTest.cpp @@ -45,17 +45,17 @@ class ExecutionFramework public: ExecutionFramework() { g_logVerbosity = 0; } - bytes const& compileAndRun(string const& _sourceCode) + bytes const& compileAndRun(string const& _sourceCode, u256 const& _value = 0) { bytes code = dev::solidity::CompilerStack::staticCompile(_sourceCode); - sendMessage(code, true); + sendMessage(code, true, _value); BOOST_REQUIRE(!m_output.empty()); return m_output; } - bytes const& callContractFunction(byte _index, bytes const& _data = bytes()) + bytes const& callContractFunction(byte _index, bytes const& _data = bytes(), u256 const& _value = 0) { - sendMessage(bytes(1, _index) + _data, false); + sendMessage(bytes(1, _index) + _data, false, _value); return m_output; } @@ -111,11 +111,11 @@ private: return toBigEndian(_cppFunction(_arguments...)); } - void sendMessage(bytes const& _data, bool _isCreation) + void sendMessage(bytes const& _data, bool _isCreation, u256 const& _value = 0) { eth::Executive executive(m_state); - eth::Transaction t = _isCreation ? eth::Transaction(0, m_gasPrice, m_gas, _data, 0, KeyPair::create().sec()) - : eth::Transaction(0, m_gasPrice, m_gas, m_contractAddress, _data, 0, KeyPair::create().sec()); + 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(); try { @@ -125,7 +125,7 @@ private: catch (...) {} if (_isCreation) { - BOOST_REQUIRE(!executive.create(Address(), 0, m_gasPrice, m_gas, &_data, Address())); + BOOST_REQUIRE(!executive.create(Address(), _value, m_gasPrice, m_gas, &_data, Address())); m_contractAddress = executive.newAddress(); BOOST_REQUIRE(m_contractAddress); BOOST_REQUIRE(m_state.addressHasCode(m_contractAddress)); @@ -133,7 +133,7 @@ private: else { BOOST_REQUIRE(m_state.addressHasCode(m_contractAddress)); - BOOST_REQUIRE(!executive.call(m_contractAddress, Address(), 0, m_gasPrice, &_data, m_gas, Address())); + BOOST_REQUIRE(!executive.call(m_contractAddress, Address(), _value, m_gasPrice, &_data, m_gas, Address())); } BOOST_REQUIRE(executive.go()); executive.finalize(); @@ -722,6 +722,17 @@ BOOST_AUTO_TEST_CASE(constructor) testSolidityAgainstCpp(0, get, u256(7)); } +BOOST_AUTO_TEST_CASE(balance) +{ + char const* sourceCode = "contract test {\n" + " function getBalance() returns (u256 balance) {\n" + " return address(this).balance;\n" + " }\n" + "}\n"; + compileAndRun(sourceCode, 23); + BOOST_CHECK(callContractFunction(0) == toBigEndian(u256(23))); +} + BOOST_AUTO_TEST_SUITE_END() } diff --git a/test/solidityExpressionCompiler.cpp b/test/solidityExpressionCompiler.cpp index 59a9e9336..6ea66badb 100644 --- a/test/solidityExpressionCompiler.cpp +++ b/test/solidityExpressionCompiler.cpp @@ -88,7 +88,7 @@ bytes compileFirstExpression(const string& _sourceCode, vector> _ Parser parser; ASTPointer contract; BOOST_REQUIRE_NO_THROW(contract = parser.parse(make_shared(CharStream(_sourceCode)))); - NameAndTypeResolver resolver; + NameAndTypeResolver resolver({}); BOOST_REQUIRE_NO_THROW(resolver.resolveNamesAndTypes(*contract)); FirstExpressionExtractor extractor(*contract); BOOST_REQUIRE(extractor.getExpression() != nullptr); diff --git a/test/solidityNameAndTypeResolution.cpp b/test/solidityNameAndTypeResolution.cpp index 930bba0e3..61aabb346 100644 --- a/test/solidityNameAndTypeResolution.cpp +++ b/test/solidityNameAndTypeResolution.cpp @@ -43,7 +43,7 @@ void parseTextAndResolveNames(std::string const& _source) Parser parser; ASTPointer contract = parser.parse( std::make_shared(CharStream(_source))); - NameAndTypeResolver resolver; + NameAndTypeResolver resolver({}); resolver.resolveNamesAndTypes(*contract); } } diff --git a/test/solidityParser.cpp b/test/solidityParser.cpp index 9319a02c5..0ee88b261 100644 --- a/test/solidityParser.cpp +++ b/test/solidityParser.cpp @@ -221,6 +221,26 @@ BOOST_AUTO_TEST_CASE(statement_starting_with_type_conversion) BOOST_CHECK_NO_THROW(parseText(text)); } +BOOST_AUTO_TEST_CASE(blockchain_access) +{ + char const* text = "contract test {\n" + " function fun() {\n" + " u256 x = address(0).balance;\n" + " }\n" + "}\n"; + BOOST_CHECK_NO_THROW(parseText(text)); +} + +BOOST_AUTO_TEST_CASE(blockchain_access_invalid) +{ + char const* text = "contract test {\n" + " function fun() {\n" + " address(0).balance = 7;\n" + " }\n" + "}\n"; + BOOST_CHECK_THROW(parseText(text), TypeError); +} + BOOST_AUTO_TEST_SUITE_END() } From 27d20cd849d7404e69ee92588b35120265214eb6 Mon Sep 17 00:00:00 2001 From: Christian Date: Fri, 21 Nov 2014 19:14:56 +0100 Subject: [PATCH 31/86] Magic variables. --- libsolidity/AST.cpp | 17 +++--- libsolidity/AST.h | 22 +++++++ libsolidity/ASTForward.h | 1 + libsolidity/Compiler.cpp | 15 ++--- libsolidity/Compiler.h | 5 +- libsolidity/CompilerContext.cpp | 5 ++ libsolidity/CompilerContext.h | 4 ++ libsolidity/CompilerStack.cpp | 2 +- libsolidity/ExpressionCompiler.cpp | 85 +++++++++++++++++--------- libsolidity/ExpressionCompiler.h | 13 ++-- libsolidity/GlobalContext.cpp | 32 +++++++--- libsolidity/GlobalContext.h | 11 ++-- libsolidity/Types.cpp | 2 + libsolidity/Types.h | 10 ++- test/solidityCompiler.cpp | 2 +- test/solidityEndToEndTest.cpp | 2 +- test/solidityNameAndTypeResolution.cpp | 20 ++++++ test/solidityParser.cpp | 20 ------ 18 files changed, 172 insertions(+), 96 deletions(-) diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index 22a658d40..168a095c8 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -372,8 +372,6 @@ void VariableDefinition::checkTypeRequirements() m_variable->setType(m_value->getType()); } } - if (m_variable->getType() && !m_variable->getType()->canLiveOutsideStorage()) - BOOST_THROW_EXCEPTION(m_variable->createTypeError("Type is required to live outside storage.")); } void Assignment::checkTypeRequirements() @@ -466,8 +464,6 @@ void FunctionCall::checkTypeRequirements() } else { - m_expression->requireLValue(); - //@todo would be nice to create a struct type from the arguments // and then ask if that is implicitly convertible to the struct represented by the // function parameters @@ -495,25 +491,23 @@ bool FunctionCall::isTypeConversion() const void MemberAccess::checkTypeRequirements() { m_expression->checkTypeRequirements(); - m_expression->requireLValue(); Type const& type = *m_expression->getType(); m_type = type.getMemberType(*m_memberName); if (!m_type) BOOST_THROW_EXCEPTION(createTypeError("Member \"" + *m_memberName + "\" not found in " + type.toString())); - m_isLvalue = true; + m_isLvalue = (type.getCategory() == Type::Category::STRUCT && m_type->getCategory() != Type::Category::MAPPING); } void IndexAccess::checkTypeRequirements() { m_base->checkTypeRequirements(); - m_base->requireLValue(); if (m_base->getType()->getCategory() != Type::Category::MAPPING) BOOST_THROW_EXCEPTION(m_base->createTypeError("Indexed expression has to be a mapping (is " + m_base->getType()->toString() + ")")); MappingType const& type = dynamic_cast(*m_base->getType()); m_index->expectType(*type.getKeyType()); m_type = type.getValueType(); - m_isLvalue = true; + m_isLvalue = m_type->getCategory() != Type::Category::MAPPING; } void Identifier::checkTypeRequirements() @@ -545,7 +539,6 @@ void Identifier::checkTypeRequirements() // Calling a function (e.g. function(12), otherContract.function(34)) does not do a type // conversion. m_type = make_shared(*functionDef); - m_isLvalue = true; return; } ContractDefinition* contractDef = dynamic_cast(m_referencedDeclaration); @@ -554,6 +547,12 @@ void Identifier::checkTypeRequirements() m_type = make_shared(make_shared(*contractDef)); return; } + MagicVariableDeclaration* magicVariable = dynamic_cast(m_referencedDeclaration); + if (magicVariable) + { + m_type = magicVariable->getType(); + return; + } BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Declaration reference of unknown/forbidden type.")); } diff --git a/libsolidity/AST.h b/libsolidity/AST.h index 01e1b54f0..f8ff52749 100644 --- a/libsolidity/AST.h +++ b/libsolidity/AST.h @@ -230,6 +230,28 @@ private: std::shared_ptr m_type; ///< derived type, initially empty }; +/** + * Pseudo AST node that is used as declaration for "this", "msg", "tx" and "block" when the + * identifier is encountered. Will never have a valid location in the source code. + */ +class MagicVariableDeclaration: public Declaration +{ +public: + enum class VariableKind { THIS, MSG, TX, BLOCK }; + MagicVariableDeclaration(VariableKind _kind, ASTString const& _name, + std::shared_ptr const& _type): + Declaration(Location(), std::make_shared(_name)), m_kind(_kind), m_type(_type) {} + virtual void accept(ASTVisitor&) override { BOOST_THROW_EXCEPTION(InternalCompilerError() + << errinfo_comment("MagicVariableDeclaration used inside real AST.")); } + + std::shared_ptr const& getType() const { return m_type; } + VariableKind getKind() const { return m_kind; } + +private: + VariableKind m_kind; + std::shared_ptr m_type; +}; + /// Types /// @{ diff --git a/libsolidity/ASTForward.h b/libsolidity/ASTForward.h index 2b0bd8869..a369c8a79 100644 --- a/libsolidity/ASTForward.h +++ b/libsolidity/ASTForward.h @@ -40,6 +40,7 @@ class StructDefinition; class ParameterList; class FunctionDefinition; class VariableDeclaration; +class MagicVariableDeclaration; class TypeName; class ElementaryTypeName; class UserDefinedTypeName; diff --git a/libsolidity/Compiler.cpp b/libsolidity/Compiler.cpp index a3865bc30..a82ecd95a 100644 --- a/libsolidity/Compiler.cpp +++ b/libsolidity/Compiler.cpp @@ -32,17 +32,13 @@ using namespace std; namespace dev { namespace solidity { -bytes Compiler::compile(ContractDefinition& _contract, bool _optimize) -{ - Compiler compiler; - compiler.compileContract(_contract); - return compiler.m_context.getAssembledBytecode(_optimize); -} - -void Compiler::compileContract(ContractDefinition& _contract) +void Compiler::compileContract(ContractDefinition& _contract, vector const& _magicGlobals) { m_context = CompilerContext(); // clear it just in case + for (MagicVariableDeclaration const* variable: _magicGlobals) + m_context.addMagicGlobal(*variable); + for (ASTPointer const& function: _contract.getDefinedFunctions()) if (function->getName() != _contract.getName()) // don't add the constructor here m_context.addFunction(*function); @@ -328,7 +324,8 @@ bool Compiler::visit(ExpressionStatement& _expressionStatement) { Expression& expression = _expressionStatement.getExpression(); ExpressionCompiler::compileExpression(m_context, expression); - if (expression.getType()->getCategory() != Type::Category::VOID) + Type::Category category = expression.getType()->getCategory(); + if (category != Type::Category::VOID && category != Type::Category::MAGIC) m_context << eth::Instruction::POP; return false; } diff --git a/libsolidity/Compiler.h b/libsolidity/Compiler.h index 3887d3b5b..70e6c44f2 100644 --- a/libsolidity/Compiler.h +++ b/libsolidity/Compiler.h @@ -32,13 +32,10 @@ class Compiler: private ASTVisitor public: Compiler(): m_returnTag(m_context.newTag()) {} - void compileContract(ContractDefinition& _contract); + void compileContract(ContractDefinition& _contract, std::vector const& _magicGlobals); bytes getAssembledBytecode(bool _optimize = false) { return m_context.getAssembledBytecode(_optimize); } void streamAssembly(std::ostream& _stream) const { m_context.streamAssembly(_stream); } - /// Compile the given contract and return the EVM bytecode. - static bytes compile(ContractDefinition& _contract, bool _optimize); - private: /// Creates a new compiler context / assembly, packs the current code into the data part and /// adds the constructor code. diff --git a/libsolidity/CompilerContext.cpp b/libsolidity/CompilerContext.cpp index 3c1acdfa7..b89a8e5b5 100644 --- a/libsolidity/CompilerContext.cpp +++ b/libsolidity/CompilerContext.cpp @@ -30,6 +30,11 @@ using namespace std; namespace dev { namespace solidity { +void CompilerContext::addMagicGlobal(MagicVariableDeclaration const& _declaration) +{ + m_magicGlobals.insert(&_declaration); +} + void CompilerContext::addStateVariable(VariableDeclaration const& _declaration) { m_stateVariables[&_declaration] = m_stateVariablesSize; diff --git a/libsolidity/CompilerContext.h b/libsolidity/CompilerContext.h index e624222dd..6a48e1485 100644 --- a/libsolidity/CompilerContext.h +++ b/libsolidity/CompilerContext.h @@ -40,6 +40,7 @@ class CompilerContext public: CompilerContext(): m_stateVariablesSize(0) {} + void addMagicGlobal(MagicVariableDeclaration const& _declaration); void addStateVariable(VariableDeclaration const& _declaration); void startNewFunction() { m_localVariables.clear(); m_asm.setDeposit(0); } void initializeLocalVariables(unsigned _numVariables); @@ -48,6 +49,7 @@ public: void adjustStackOffset(int _adjustment) { m_asm.adjustDeposit(_adjustment); } + bool isMagicGlobal(Declaration const* _declaration) const { return m_magicGlobals.count(_declaration); } bool isFunctionDefinition(Declaration const* _declaration) const { return m_functionEntryLabels.count(_declaration); } bool isLocalVariable(Declaration const* _declaration) const; bool isStateVariable(Declaration const* _declaration) const { return m_stateVariables.count(_declaration); } @@ -90,6 +92,8 @@ public: private: eth::Assembly m_asm; + /// Magic global variables like msg, tx or this, distinguished by type. + std::set m_magicGlobals; /// Size of the state variables, offset of next variable to be added. u256 m_stateVariablesSize; /// Storage offsets of state variables diff --git a/libsolidity/CompilerStack.cpp b/libsolidity/CompilerStack.cpp index f051d58fd..6535e00d4 100644 --- a/libsolidity/CompilerStack.cpp +++ b/libsolidity/CompilerStack.cpp @@ -64,7 +64,7 @@ bytes const& CompilerStack::compile(bool _optimize) BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful.")); m_bytecode.clear(); m_compiler = make_shared(); - m_compiler->compileContract(*m_contractASTNode); + m_compiler->compileContract(*m_contractASTNode, m_globalContext->getMagicVariables()); return m_bytecode = m_compiler->getAssembledBytecode(_optimize); } diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index 4d175527a..b1a49457c 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -162,7 +162,7 @@ bool ExpressionCompiler::visit(FunctionCall& _functionCall) { if (_functionCall.isTypeConversion()) { - //@todo we only have integers and bools for now which cannot be explicitly converted + //@todo struct construction if (asserts(_functionCall.getArguments().size() == 1)) BOOST_THROW_EXCEPTION(InternalCompilerError()); Expression& firstArgument = *_functionCall.getArguments().front(); @@ -179,6 +179,8 @@ bool ExpressionCompiler::visit(FunctionCall& _functionCall) } else { + //@todo: check for "external call" (to be stored in type) + // Calling convention: Caller pushes return address and arguments // Callee removes them and pushes return values FunctionDefinition const& function = dynamic_cast(*_functionCall.getExpression().getType()).getFunction(); @@ -193,9 +195,6 @@ bool ExpressionCompiler::visit(FunctionCall& _functionCall) appendTypeConversion(*arguments[i]->getType(), *function.getParameters()[i]->getType()); } _functionCall.getExpression().accept(*this); - if (asserts(m_currentLValue.isInCode())) - BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Code reference expected.")); - m_currentLValue.reset(); m_context.appendJump(); m_context << returnLabel; @@ -213,19 +212,36 @@ bool ExpressionCompiler::visit(FunctionCall& _functionCall) void ExpressionCompiler::endVisit(MemberAccess& _memberAccess) { - if (asserts(m_currentLValue.isInStorage())) - BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Member access to a non-storage value.")); - StructType const& type = dynamic_cast(*_memberAccess.getExpression().getType()); - m_context << type.getStorageOffsetOfMember(_memberAccess.getMemberName()) << eth::Instruction::ADD; - m_currentLValue.retrieveValueIfLValueNotRequested(_memberAccess); + switch (_memberAccess.getExpression().getType()->getCategory()) + { + case Type::Category::INTEGER: + if (asserts(_memberAccess.getMemberName() == "balance")) + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Invalid member access to integer.")); + m_context << eth::Instruction::BALANCE; + break; + case Type::Category::CONTRACT: + // call function + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Contract variables not yet implemented.")); + break; + case Type::Category::MAGIC: + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Magic variables not yet implemented.")); + break; + case Type::Category::STRUCT: + { + StructType const& type = dynamic_cast(*_memberAccess.getExpression().getType()); + m_context << type.getStorageOffsetOfMember(_memberAccess.getMemberName()) << eth::Instruction::ADD; + m_currentLValue = LValue(m_context, LValue::STORAGE); + m_currentLValue.retrieveValueIfLValueNotRequested(_memberAccess); + break; + } + default: + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Member access to unknown type.")); + } } bool ExpressionCompiler::visit(IndexAccess& _indexAccess) { - m_currentLValue.reset(); _indexAccess.getBaseExpression().accept(*this); - if (asserts(m_currentLValue.isInStorage())) - BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Index access to a non-storage value.")); _indexAccess.getIndexExpression().accept(*this); appendTypeConversion(*_indexAccess.getIndexExpression().getType(), *dynamic_cast(*_indexAccess.getBaseExpression().getType()).getKeyType(), @@ -242,8 +258,25 @@ bool ExpressionCompiler::visit(IndexAccess& _indexAccess) void ExpressionCompiler::endVisit(Identifier& _identifier) { - m_currentLValue.fromDeclaration(_identifier, *_identifier.getReferencedDeclaration()); - m_currentLValue.retrieveValueIfLValueNotRequested(_identifier); + Declaration* declaration = _identifier.getReferencedDeclaration(); + if (MagicVariableDeclaration* magicVar = dynamic_cast(declaration)) + { + if (magicVar->getKind() == MagicVariableDeclaration::VariableKind::THIS) + m_context << eth::Instruction::ADDRESS; + return; + } + if (FunctionDefinition* functionDef = dynamic_cast(declaration)) + { + m_context << m_context.getFunctionEntryLabel(*functionDef).pushTag(); + return; + } + if (VariableDeclaration* varDef = dynamic_cast(declaration)) + { + m_currentLValue.fromIdentifier(_identifier, *_identifier.getReferencedDeclaration()); + m_currentLValue.retrieveValueIfLValueNotRequested(_identifier); + return; + } + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Identifier type not expected in expression context.")); } void ExpressionCompiler::endVisit(Literal& _literal) @@ -410,9 +443,6 @@ void ExpressionCompiler::LValue::retrieveValue(Expression const& _expression, bo { switch (m_type) { - case CODE: - BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Tried to retrieve value of a function.")); - break; case STACK: { unsigned stackPos = m_context->baseToCurrentStackOffset(unsigned(m_baseStackOffset)); @@ -423,11 +453,15 @@ void ExpressionCompiler::LValue::retrieveValue(Expression const& _expression, bo break; } case STORAGE: + if (!_expression.getType()->isValueType()) + break; // no distinction between value and reference for non-value types if (!_remove) *m_context << eth::Instruction::DUP1; *m_context << eth::Instruction::SLOAD; break; case MEMORY: + if (!_expression.getType()->isValueType()) + break; // no distinction between value and reference for non-value types BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_sourceLocation(_expression.getLocation()) << errinfo_comment("Location type not yet implemented.")); break; @@ -455,15 +489,15 @@ void ExpressionCompiler::LValue::storeValue(Expression const& _expression, bool break; } case LValue::STORAGE: + if (!_expression.getType()->isValueType()) + break; // no distinction between value and reference for non-value types if (!_move) *m_context << eth::Instruction::DUP2 << eth::Instruction::SWAP1; *m_context << eth::Instruction::SSTORE; break; - case LValue::CODE: - BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_sourceLocation(_expression.getLocation()) - << errinfo_comment("Location type does not support assignment.")); - break; case LValue::MEMORY: + if (!_expression.getType()->isValueType()) + break; // no distinction between value and reference for non-value types BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_sourceLocation(_expression.getLocation()) << errinfo_comment("Location type not yet implemented.")); break; @@ -483,7 +517,7 @@ void ExpressionCompiler::LValue::retrieveValueIfLValueNotRequested(Expression co } } -void ExpressionCompiler::LValue::fromDeclaration(Expression const& _expression, Declaration const& _declaration) +void ExpressionCompiler::LValue::fromIdentifier(Identifier const& _identifier, Declaration const& _declaration) { if (m_context->isLocalVariable(&_declaration)) { @@ -495,13 +529,8 @@ void ExpressionCompiler::LValue::fromDeclaration(Expression const& _expression, m_type = STORAGE; *m_context << m_context->getStorageLocationOfVariable(_declaration); } - else if (m_context->isFunctionDefinition(&_declaration)) - { - m_type = CODE; - *m_context << m_context->getFunctionEntryLabel(dynamic_cast(_declaration)).pushTag(); - } else - BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_sourceLocation(_expression.getLocation()) + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_sourceLocation(_identifier.getLocation()) << errinfo_comment("Identifier type not supported or identifier not found.")); } diff --git a/libsolidity/ExpressionCompiler.h b/libsolidity/ExpressionCompiler.h index f52da29ec..3ed7848b5 100644 --- a/libsolidity/ExpressionCompiler.h +++ b/libsolidity/ExpressionCompiler.h @@ -83,31 +83,30 @@ private: /** * Helper class to store and retrieve lvalues to and from various locations. - * All types except STACK store a reference in a slot on the stack, STACK just stores the - * base stack offset of the variable in @a m_baseStackOffset. + * All types except STACK store a reference in a slot on the stack, STACK just + * stores the base stack offset of the variable in @a m_baseStackOffset. */ class LValue { public: - enum LValueType { NONE, CODE, STACK, MEMORY, STORAGE }; + enum LValueType { NONE, STACK, MEMORY, STORAGE }; explicit LValue(CompilerContext& _compilerContext): m_context(&_compilerContext) { reset(); } LValue(CompilerContext& _compilerContext, LValueType _type, unsigned _baseStackOffset = 0): m_context(&_compilerContext), m_type(_type), m_baseStackOffset(_baseStackOffset) {} /// Set type according to the declaration and retrieve the reference. - /// @a _expression is the current expression, used for error reporting. - void fromDeclaration(Expression const& _expression, Declaration const& _declaration); + /// @a _expression is the current expression + void fromIdentifier(Identifier const& _identifier, Declaration const& _declaration); void reset() { m_type = NONE; m_baseStackOffset = 0; } bool isValid() const { return m_type != NONE; } - bool isInCode() const { return m_type == CODE; } bool isInOnStack() const { return m_type == STACK; } bool isInMemory() const { return m_type == MEMORY; } bool isInStorage() const { return m_type == STORAGE; } /// @returns true if this lvalue reference type occupies a slot on the stack. - bool storesReferenceOnStack() const { return m_type == STORAGE || m_type == MEMORY || m_type == CODE; } + bool storesReferenceOnStack() const { return m_type == STORAGE || m_type == MEMORY; } /// Copies the value of the current lvalue to the top of the stack and, if @a _remove is true, /// also removes the reference from the stack (note that is does not reset the type to @a NONE). diff --git a/libsolidity/GlobalContext.cpp b/libsolidity/GlobalContext.cpp index 6179722b2..f2e6d9ce9 100644 --- a/libsolidity/GlobalContext.cpp +++ b/libsolidity/GlobalContext.cpp @@ -45,25 +45,37 @@ GlobalContext::GlobalContext() void GlobalContext::setCurrentContract(ContractDefinition const& _contract) { - m_this = createVariable("this", make_shared(_contract)); + m_currentContract = &_contract; } vector GlobalContext::getDeclarations() const { vector declarations; - declarations.reserve(m_objects.size() + 1); - for (ASTPointer const& declaration: m_objects) - declarations.push_back(declaration.get()); - declarations.push_back(m_this.get()); + declarations.reserve(m_magicVariables.size() + 1); + for (ASTPointer const& variable: m_magicVariables) + declarations.push_back(variable.get()); + declarations.push_back(getCurrentThis()); return declarations; } -ASTPointer GlobalContext::createVariable(const string& _name, shared_ptr const& _type) +MagicVariableDeclaration*GlobalContext::getCurrentThis() const { - ASTPointer variable = make_shared(Location(), ASTPointer(), - make_shared(_name)); - variable->setType(_type); - return variable; + if (!m_thisPointer[m_currentContract]) + m_thisPointer[m_currentContract] = make_shared( + MagicVariableDeclaration::VariableKind::THIS, + "this", make_shared(*m_currentContract)); + return m_thisPointer[m_currentContract].get(); + +} + +vector GlobalContext::getMagicVariables() const +{ + vector declarations; + declarations.reserve(m_magicVariables.size() + 1); + for (ASTPointer const& variable: m_magicVariables) + declarations.push_back(variable.get()); + declarations.push_back(getCurrentThis()); + return declarations; } } diff --git a/libsolidity/GlobalContext.h b/libsolidity/GlobalContext.h index b6dea7d56..0166734ca 100644 --- a/libsolidity/GlobalContext.h +++ b/libsolidity/GlobalContext.h @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -47,14 +48,14 @@ public: GlobalContext(); void setCurrentContract(ContractDefinition const& _contract); + std::vector getMagicVariables() const; std::vector getDeclarations() const; private: - /// Creates a virtual variable declaration with the given name and type. - static ASTPointer createVariable(std::string const& _name, std::shared_ptr const& _type); - - std::vector> m_objects; - ASTPointer m_this; + MagicVariableDeclaration* getCurrentThis() const; + std::vector> m_magicVariables; + ContractDefinition const* m_currentContract; + std::map> mutable m_thisPointer; }; } diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index f9d3d90fa..8ded428f8 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -189,6 +189,8 @@ u256 IntegerType::literalValue(Literal const& _literal) const return u256(value); } +const MemberList IntegerType::AddressMemberList = MemberList({{"balance", std::make_shared(256)}}); + bool BoolType::isExplicitlyConvertibleTo(Type const& _convertTo) const { // conversion to integer is fine, but not to address diff --git a/libsolidity/Types.h b/libsolidity/Types.h index 297284ba0..a8caf7154 100644 --- a/libsolidity/Types.h +++ b/libsolidity/Types.h @@ -73,7 +73,7 @@ class Type: private boost::noncopyable public: enum class Category { - INTEGER, BOOL, REAL, STRING, CONTRACT, STRUCT, FUNCTION, MAPPING, VOID, TYPE + INTEGER, BOOL, REAL, STRING, CONTRACT, STRUCT, FUNCTION, MAPPING, VOID, TYPE, MAGIC }; ///@{ @@ -110,6 +110,9 @@ public: virtual bool canBeStored() const { return true; } /// Returns false if the type cannot live outside the storage, i.e. if it includes some mapping. virtual bool canLiveOutsideStorage() const { return true; } + /// Returns true if the type can be stored as a value (as opposed to a reference) on the stack, + /// i.e. it behaves differently in lvalue context and in value context. + virtual bool isValueType() const { return false; } /// Returns the list of all members of this type. Default implementation: no members. virtual MemberList const& getMembers() const { return EmptyMemberList; } @@ -154,6 +157,9 @@ public: virtual bool operator==(Type const& _other) const override; virtual unsigned getCalldataEncodedSize() const override { return m_bits / 8; } + virtual bool isValueType() const override { return true; } + + virtual MemberList const& getMembers() const { return isAddress() ? AddressMemberList : EmptyMemberList; } virtual std::string toString() const override; virtual u256 literalValue(Literal const& _literal) const override; @@ -166,6 +172,7 @@ public: private: int m_bits; Modifier m_modifier; + static const MemberList AddressMemberList; }; /** @@ -186,6 +193,7 @@ public: } virtual unsigned getCalldataEncodedSize() const { return 1; } + virtual bool isValueType() const override { return true; } virtual std::string toString() const override { return "bool"; } virtual u256 literalValue(Literal const& _literal) const override; diff --git a/test/solidityCompiler.cpp b/test/solidityCompiler.cpp index 1767a0f36..3e86919a6 100644 --- a/test/solidityCompiler.cpp +++ b/test/solidityCompiler.cpp @@ -52,7 +52,7 @@ bytes compileContract(const string& _sourceCode) BOOST_REQUIRE_NO_THROW(resolver.resolveNamesAndTypes(*contract)); Compiler compiler; - compiler.compileContract(*contract); + compiler.compileContract(*contract, {}); // debug //compiler.streamAssembly(cout); return compiler.getAssembledBytecode(); diff --git a/test/solidityEndToEndTest.cpp b/test/solidityEndToEndTest.cpp index a7c6357bf..46081a63c 100644 --- a/test/solidityEndToEndTest.cpp +++ b/test/solidityEndToEndTest.cpp @@ -725,7 +725,7 @@ BOOST_AUTO_TEST_CASE(constructor) BOOST_AUTO_TEST_CASE(balance) { char const* sourceCode = "contract test {\n" - " function getBalance() returns (u256 balance) {\n" + " function getBalance() returns (uint256 balance) {\n" " return address(this).balance;\n" " }\n" "}\n"; diff --git a/test/solidityNameAndTypeResolution.cpp b/test/solidityNameAndTypeResolution.cpp index 61aabb346..a19e7450c 100644 --- a/test/solidityNameAndTypeResolution.cpp +++ b/test/solidityNameAndTypeResolution.cpp @@ -224,6 +224,26 @@ BOOST_AUTO_TEST_CASE(type_inference_explicit_conversion) BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text)); } +BOOST_AUTO_TEST_CASE(balance) +{ + char const* text = "contract test {\n" + " function fun() {\n" + " uint256 x = address(0).balance;\n" + " }\n" + "}\n"; + BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text)); +} + +BOOST_AUTO_TEST_CASE(balance_invalid) +{ + char const* text = "contract test {\n" + " function fun() {\n" + " address(0).balance = 7;\n" + " }\n" + "}\n"; + BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError); +} + BOOST_AUTO_TEST_SUITE_END() } diff --git a/test/solidityParser.cpp b/test/solidityParser.cpp index 0ee88b261..9319a02c5 100644 --- a/test/solidityParser.cpp +++ b/test/solidityParser.cpp @@ -221,26 +221,6 @@ BOOST_AUTO_TEST_CASE(statement_starting_with_type_conversion) BOOST_CHECK_NO_THROW(parseText(text)); } -BOOST_AUTO_TEST_CASE(blockchain_access) -{ - char const* text = "contract test {\n" - " function fun() {\n" - " u256 x = address(0).balance;\n" - " }\n" - "}\n"; - BOOST_CHECK_NO_THROW(parseText(text)); -} - -BOOST_AUTO_TEST_CASE(blockchain_access_invalid) -{ - char const* text = "contract test {\n" - " function fun() {\n" - " address(0).balance = 7;\n" - " }\n" - "}\n"; - BOOST_CHECK_THROW(parseText(text), TypeError); -} - BOOST_AUTO_TEST_SUITE_END() } From 60a62708c4df4d79ed47c9510a7c40fc643b181a Mon Sep 17 00:00:00 2001 From: Christian Date: Sun, 23 Nov 2014 21:17:51 +0100 Subject: [PATCH 32/86] Another test for struct references. --- test/solidityEndToEndTest.cpp | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/test/solidityEndToEndTest.cpp b/test/solidityEndToEndTest.cpp index 46081a63c..11535d4f6 100644 --- a/test/solidityEndToEndTest.cpp +++ b/test/solidityEndToEndTest.cpp @@ -700,6 +700,34 @@ BOOST_AUTO_TEST_CASE(structs) BOOST_CHECK(callContractFunction(0) == bytes({0x01})); } +BOOST_AUTO_TEST_CASE(struct_reference) +{ + char const* sourceCode = "contract test {\n" + " struct s2 {\n" + " uint32 z;\n" + " mapping(uint8 => s2) recursive;\n" + " }\n" + " s2 data;\n" + " function check() returns (bool ok) {\n" + " return data.z == 2 && \n" + " data.recursive[0].z == 3 && \n" + " data.recursive[0].recursive[1].z == 0 && \n" + " data.recursive[0].recursive[0].z == 1;\n" + " }\n" + " function set() {\n" + " data.z = 2;\n" + " var map = data.recursive;\n" + " s2 inner = map[0];\n" + " inner.z = 3;\n" + " inner.recursive[0].z = inner.recursive[1].z + 1;\n" + " }\n" + "}\n"; + compileAndRun(sourceCode); + BOOST_CHECK(callContractFunction(0) == bytes({0x00})); + BOOST_CHECK(callContractFunction(1) == bytes()); + BOOST_CHECK(callContractFunction(0) == bytes({0x01})); +} + BOOST_AUTO_TEST_CASE(constructor) { char const* sourceCode = "contract test {\n" From c1ae9fc1262ef18541c2af74c3195c4f89de206b Mon Sep 17 00:00:00 2001 From: subtly Date: Sun, 23 Nov 2014 22:57:47 +0100 Subject: [PATCH 33/86] pr fixes --- libp2p/Common.cpp | 14 ++++++++++++++ libp2p/Common.h | 1 + libp2p/Host.cpp | 42 +++++++++++++++++------------------------- 3 files changed, 32 insertions(+), 25 deletions(-) diff --git a/libp2p/Common.cpp b/libp2p/Common.cpp index 8a3b27ef0..e0f3b5629 100644 --- a/libp2p/Common.cpp +++ b/libp2p/Common.cpp @@ -53,6 +53,20 @@ bool p2p::isPrivateAddress(bi::address const& _addressToCheck) return false; } +// Helper function to determine if an address is localhost +bool p2p::isLocalHostAddress(bi::address const& _addressToCheck) +{ + // @todo: ivp6 link-local adresses (macos), ex: fe80::1%lo0 + static const set c_rejectAddresses = { + {bi::address_v4::from_string("127.0.0.1")}, + {bi::address_v4::from_string("0.0.0.0")}, + {bi::address_v6::from_string("::1")}, + {bi::address_v6::from_string("::")} + }; + + return find(c_rejectAddresses.begin(), c_rejectAddresses.end(), _addressToCheck) != c_rejectAddresses.end(); +} + std::string p2p::reasonOf(DisconnectReason _r) { switch (_r) diff --git a/libp2p/Common.h b/libp2p/Common.h index 0df7f14fe..34f47b236 100644 --- a/libp2p/Common.h +++ b/libp2p/Common.h @@ -47,6 +47,7 @@ namespace p2p using NodeId = h512; bool isPrivateAddress(bi::address const& _addressToCheck); +bool isLocalHostAddress(bi::address const& _addressToCheck); class UPnP; class Capability; diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index 471d1dc56..6e151d34d 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -46,15 +46,6 @@ using namespace std; using namespace dev; using namespace dev::p2p; -// Addresses skipped during network interface discovery -// @todo: filter out ivp6 link-local network mess on macos, ex: fe80::1%lo0 -static const set c_rejectAddresses = { - {bi::address_v4::from_string("127.0.0.1")}, - {bi::address_v4::from_string("0.0.0.0")}, - {bi::address_v6::from_string("::1")}, - {bi::address_v6::from_string("::")} -}; - std::vector Host::getInterfaceAddresses() { std::vector addresses; @@ -86,7 +77,7 @@ std::vector Host::getInterfaceAddresses() memcpy(&addr, phe->h_addr_list[i], sizeof(struct in_addr)); char *addrStr = inet_ntoa(addr); bi::address address(bi::address::from_string(addrStr)); - if (std::find(c_rejectAddresses.begin(), c_rejectAddresses.end(), address) == c_rejectAddresses.end()) + if (!isLocalHostAddress(address)) addresses.push_back(ad.to_v4()); } @@ -105,7 +96,7 @@ std::vector Host::getInterfaceAddresses() { in_addr addr = ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr; boost::asio::ip::address_v4 address(boost::asio::detail::socket_ops::network_to_host_long(addr.s_addr)); - if (std::find(c_rejectAddresses.begin(), c_rejectAddresses.end(), address) == c_rejectAddresses.end()) + if (!isLocalHostAddress(address)) addresses.push_back(address); } else if (ifa->ifa_addr->sa_family == AF_INET6) @@ -115,11 +106,13 @@ std::vector Host::getInterfaceAddresses() boost::asio::ip::address_v6::bytes_type bytes; memcpy(&bytes[0], addr.s6_addr, 16); boost::asio::ip::address_v6 address(bytes, sockaddr->sin6_scope_id); - if (std::find(c_rejectAddresses.begin(), c_rejectAddresses.end(), address) == c_rejectAddresses.end()) + if (!isLocalHostAddress(address)) addresses.push_back(address); } } - if (ifaddr!=NULL) freeifaddrs(ifaddr); + + if (ifaddr!=NULL) + freeifaddrs(ifaddr); #endif @@ -148,7 +141,6 @@ int Host::listen4(bi::tcp::acceptor* _acceptor, unsigned short _listenPort) { // both attempts failed cwarn << "Couldn't start accepting connections on host. Something very wrong with network?\n" << boost::current_exception_diagnostic_information(); - _acceptor->close(); } // first attempt failed @@ -175,9 +167,9 @@ bi::tcp::endpoint Host::traverseNAT(std::vector const& _ifAddresses if (upnp && upnp->isValid()) { bi::address paddr; - int p; - for (auto const& addr : _ifAddresses) - if (addr.is_v4() && isPrivateAddress(addr) && (p = upnp->addRedirect(addr.to_string().c_str(), _listenPort))) + int extPort = 0; + for (auto const& addr: _ifAddresses) + if (addr.is_v4() && isPrivateAddress(addr) && (extPort = upnp->addRedirect(addr.to_string().c_str(), _listenPort))) { paddr = addr; break; @@ -185,17 +177,17 @@ bi::tcp::endpoint Host::traverseNAT(std::vector const& _ifAddresses auto eip = upnp->externalIP(); bi::address eipaddr(bi::address::from_string(eip)); - if (p && eip != string("0.0.0.0") && !isPrivateAddress(eipaddr)) + if (extPort && eip != string("0.0.0.0") && !isPrivateAddress(eipaddr)) { - clog(NetNote) << "Punched through NAT and mapped local port" << _listenPort << "onto external port" << p << "."; + clog(NetNote) << "Punched through NAT and mapped local port" << _listenPort << "onto external port" << extPort << "."; clog(NetNote) << "External addr:" << eip; o_upnpifaddr = paddr; - upnpep = bi::tcp::endpoint(eipaddr, (unsigned short)p); + upnpep = bi::tcp::endpoint(eipaddr, (unsigned short)extPort); } else clog(NetWarn) << "Couldn't punch through NAT (or no NAT in place)."; - if(upnp) + if (upnp) delete upnp; } @@ -385,7 +377,7 @@ void Host::determinePublic(string const& _publicAddress, bool _upnp) // populate interfaces we'll listen on (eth listens on all interfaces); ignores local for (auto addr: m_ifAddresses) - if ((m_netPrefs.localNetworking || !isPrivateAddress(addr)) && find(c_rejectAddresses.begin(), c_rejectAddresses.end(), addr) == c_rejectAddresses.end()) + if ((m_netPrefs.localNetworking || !isPrivateAddress(addr)) && !isLocalHostAddress(addr)) m_peerAddresses.insert(addr); // if user supplied address is a public address then we use it @@ -393,7 +385,7 @@ void Host::determinePublic(string const& _publicAddress, bool _upnp) 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 ? false : find(c_rejectAddresses.begin(), c_rejectAddresses.end(), reqpublicaddr) == c_rejectAddresses.end(); + bool ispublic = !isprivate && !isLocalHostAddress(reqpublicaddr); if (!reqpublicaddr.is_unspecified() && (ispublic || (isprivate && m_netPrefs.localNetworking))) { if (!m_peerAddresses.count(reqpublicaddr)) @@ -709,7 +701,7 @@ void Host::run(boost::system::error_code const& error) // network running if (m_run) { - if (s_lasttick == c_timerInterval * 50) + if (s_lasttick >= c_timerInterval * 50) { growPeers(); prunePeers(); @@ -734,7 +726,7 @@ void Host::run(boost::system::error_code const& error) pingAll(); } - auto runcb = [this](boost::system::error_code const& error) -> void{ run(error); }; + auto runcb = [this](boost::system::error_code const& error) -> void { run(error); }; m_timer->expires_from_now(boost::posix_time::milliseconds(c_timerInterval)); m_timer->async_wait(runcb); From 0669eb8d4ca663cfe5415f186fd82cefaa09b877 Mon Sep 17 00:00:00 2001 From: chriseth Date: Mon, 24 Nov 2014 00:00:46 +0100 Subject: [PATCH 34/86] Whitespace change. --- libsolidity/AST.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libsolidity/AST.h b/libsolidity/AST.h index f8ff52749..89f268b33 100644 --- a/libsolidity/AST.h +++ b/libsolidity/AST.h @@ -122,6 +122,7 @@ public: /// Returns the functions that make up the calling interface in the intended order. std::vector getInterfaceFunctions() const; + private: std::vector> m_definedStructs; std::vector> m_stateVariables; @@ -195,6 +196,7 @@ public: /// Checks that all parameters have allowed types and calls checkTypeRequirements on the body. void checkTypeRequirements(); + private: bool m_isPublic; ASTPointer m_parameters; @@ -238,8 +240,7 @@ class MagicVariableDeclaration: public Declaration { public: enum class VariableKind { THIS, MSG, TX, BLOCK }; - MagicVariableDeclaration(VariableKind _kind, ASTString const& _name, - std::shared_ptr const& _type): + MagicVariableDeclaration(VariableKind _kind, ASTString const& _name, std::shared_ptr const& _type): Declaration(Location(), std::make_shared(_name)), m_kind(_kind), m_type(_type) {} virtual void accept(ASTVisitor&) override { BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("MagicVariableDeclaration used inside real AST.")); } From b185a748a5fefa9d1d6485df116a13773b18de18 Mon Sep 17 00:00:00 2001 From: Christian Date: Mon, 24 Nov 2014 13:23:58 +0100 Subject: [PATCH 35/86] Access to blockchain data. --- libsolidity/ExpressionCompiler.cpp | 31 ++++++++++++++++-- libsolidity/GlobalContext.cpp | 18 ++++++----- libsolidity/Types.cpp | 50 ++++++++++++++++++++++++++++++ libsolidity/Types.h | 24 ++++++++++++++ test/solidityEndToEndTest.cpp | 13 ++++++++ 5 files changed, 125 insertions(+), 11 deletions(-) diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index b1a49457c..de8bc1d28 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -212,10 +212,11 @@ bool ExpressionCompiler::visit(FunctionCall& _functionCall) void ExpressionCompiler::endVisit(MemberAccess& _memberAccess) { + ASTString const& member = _memberAccess.getMemberName(); switch (_memberAccess.getExpression().getType()->getCategory()) { case Type::Category::INTEGER: - if (asserts(_memberAccess.getMemberName() == "balance")) + if (asserts(member == "balance")) BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Invalid member access to integer.")); m_context << eth::Instruction::BALANCE; break; @@ -224,12 +225,36 @@ void ExpressionCompiler::endVisit(MemberAccess& _memberAccess) BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Contract variables not yet implemented.")); break; case Type::Category::MAGIC: - BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Magic variables not yet implemented.")); + // we can ignore the kind of magic and only look at the name of the member + if (member == "coinbase") + 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") + m_context << eth::Instruction::DIFFICULTY; + else if (member == "number") + m_context << eth::Instruction::NUMBER; + else if (member == "gaslimit") + m_context << eth::Instruction::GASLIMIT; + else if (member == "sender") + m_context << eth::Instruction::CALLER; + else if (member == "value") + m_context << eth::Instruction::CALLVALUE; + else if (member == "origin") + m_context << eth::Instruction::ORIGIN; + else if (member == "gas") + m_context << eth::Instruction::GAS; + else if (member == "gasprice") + m_context << eth::Instruction::GASPRICE; + else + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown magic member.")); break; case Type::Category::STRUCT: { StructType const& type = dynamic_cast(*_memberAccess.getExpression().getType()); - m_context << type.getStorageOffsetOfMember(_memberAccess.getMemberName()) << eth::Instruction::ADD; + m_context << type.getStorageOffsetOfMember(member) << eth::Instruction::ADD; m_currentLValue = LValue(m_context, LValue::STORAGE); m_currentLValue.retrieveValueIfLValueNotRequested(_memberAccess); break; diff --git a/libsolidity/GlobalContext.cpp b/libsolidity/GlobalContext.cpp index f2e6d9ce9..4120dae5e 100644 --- a/libsolidity/GlobalContext.cpp +++ b/libsolidity/GlobalContext.cpp @@ -32,15 +32,17 @@ namespace dev namespace solidity { -GlobalContext::GlobalContext() +GlobalContext::GlobalContext(): + m_magicVariables{make_shared(MagicVariableDeclaration::VariableKind::BLOCK, + "block", + make_shared(MagicType::Kind::BLOCK)), + make_shared(MagicVariableDeclaration::VariableKind::MSG, + "msg", + make_shared(MagicType::Kind::MSG)), + make_shared(MagicVariableDeclaration::VariableKind::TX, + "tx", + make_shared(MagicType::Kind::TX))} { - // CurrentContract this; // @todo type depends on context -> switch prior to entering contract - // Message msg; - // Transaction tx; - // Block block; - - //@todo type will be a custom complex type, maybe the same type class for msg tx and block. - //addVariable("msg", ); } void GlobalContext::setCurrentContract(ContractDefinition const& _contract) diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index 8ded428f8..616c91831 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -333,5 +333,55 @@ bool TypeType::operator==(Type const& _other) const return *getActualType() == *other.getActualType(); } +MagicType::MagicType(MagicType::Kind _kind): + m_kind(_kind) +{ + switch (m_kind) + { + case Kind::BLOCK: + m_members = MemberList({{"coinbase", make_shared(0, IntegerType::Modifier::ADDRESS)}, + {"timestamp", make_shared(256)}, + {"prevhash", make_shared(256, IntegerType::Modifier::HASH)}, + {"difficulty", make_shared(256)}, + {"number", make_shared(256)}, + {"gaslimit", make_shared(256)}}); + break; + case Kind::MSG: + m_members = MemberList({{"sender", make_shared(0, IntegerType::Modifier::ADDRESS)}, + {"value", make_shared(256)}}); + break; + case Kind::TX: + m_members = MemberList({{"origin", make_shared(0, IntegerType::Modifier::ADDRESS)}, + {"gas", make_shared(256)}, + {"gasprice", make_shared(256)}}); + break; + default: + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown kind of magic.")); + } +} + +bool MagicType::operator==(Type const& _other) const +{ + if (_other.getCategory() != getCategory()) + return false; + MagicType const& other = dynamic_cast(_other); + return other.m_kind == m_kind; +} + +string MagicType::toString() const +{ + switch (m_kind) + { + case Kind::BLOCK: + return "block"; + case Kind::MSG: + return "msg"; + case Kind::TX: + return "tx"; + default: + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown kind of magic.")); + } +} + } } diff --git a/libsolidity/Types.h b/libsolidity/Types.h index a8caf7154..2dd4af64f 100644 --- a/libsolidity/Types.h +++ b/libsolidity/Types.h @@ -327,5 +327,29 @@ private: }; +/** + * Special type for magic variables (block, msg, tx), similar to a struct but without any reference + * (it always references a global singleton by name). + */ +class MagicType: public Type +{ +public: + enum class Kind { BLOCK, MSG, TX }; //@todo should be unified with MagicVariableDeclaration::VariableKind; + virtual Category getCategory() const override { return Category::MAGIC; } + + MagicType(Kind _kind); + virtual bool operator==(Type const& _other) const; + virtual bool canBeStored() const override { return false; } + virtual bool canLiveOutsideStorage() const override { return true; } + virtual MemberList const& getMembers() const override { return m_members; } + + virtual std::string toString() const override; + +private: + Kind m_kind; + + MemberList m_members; +}; + } } diff --git a/test/solidityEndToEndTest.cpp b/test/solidityEndToEndTest.cpp index 11535d4f6..fc542f141 100644 --- a/test/solidityEndToEndTest.cpp +++ b/test/solidityEndToEndTest.cpp @@ -761,6 +761,19 @@ BOOST_AUTO_TEST_CASE(balance) BOOST_CHECK(callContractFunction(0) == toBigEndian(u256(23))); } +BOOST_AUTO_TEST_CASE(blockchain) +{ + char const* sourceCode = "contract test {\n" + " function someInfo() returns (uint256 value, address coinbase, uint256 blockNumber) {\n" + " value = msg.value;\n" + " coinbase = block.coinbase;\n" + " blockNumber = block.number;\n" + " }\n" + "}\n"; + compileAndRun(sourceCode, 27); + BOOST_CHECK(callContractFunction(0, bytes{0}, u256(28)) == toBigEndian(u256(28)) + bytes(20, 0) + toBigEndian(u256(1))); +} + BOOST_AUTO_TEST_SUITE_END() } From 965e5bd58cac4414305a815701d42ac4ed07e8fc Mon Sep 17 00:00:00 2001 From: subtly Date: Mon, 24 Nov 2014 17:24:42 +0100 Subject: [PATCH 36/86] coding standards --- libdevcore/Worker.cpp | 4 ++-- libdevcore/Worker.h | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/libdevcore/Worker.cpp b/libdevcore/Worker.cpp index d9246f9fd..014780a66 100644 --- a/libdevcore/Worker.cpp +++ b/libdevcore/Worker.cpp @@ -41,8 +41,8 @@ void Worker::startWorking() startedWorking(); while (!m_stop) { - if (m_idlewaitms) - this_thread::sleep_for(chrono::milliseconds(m_idlewaitms)); + if (m_idleWaitMs) + this_thread::sleep_for(chrono::milliseconds(m_idleWaitMs)); doWork(); } cdebug << "Finishing up worker thread"; diff --git a/libdevcore/Worker.h b/libdevcore/Worker.h index f8d694681..f73a0f4aa 100644 --- a/libdevcore/Worker.h +++ b/libdevcore/Worker.h @@ -31,7 +31,7 @@ namespace dev class Worker { protected: - Worker(std::string const& _name = "anon", unsigned _idlewaitms = 30): m_name(_name), m_idlewaitms(_idlewaitms) {} + Worker(std::string const& _name = "anon", unsigned _idleWaitMs = 30): m_name(_name), m_idleWaitMs(_idleWaitMs) {} /// Move-constructor. Worker(Worker&& _m) { std::swap(m_name, _m.m_name); } @@ -56,7 +56,7 @@ protected: /// Called after thread is started from startWorking(). virtual void startedWorking() {} - /// Called continuously following sleep for m_idlewaitms. + /// Called continuously following sleep for m_idleWaitMs. virtual void doWork() = 0; /// Called when is to be stopped, just prior to thread being joined. @@ -64,7 +64,7 @@ protected: private: std::string m_name; - unsigned m_idlewaitms; + unsigned m_idleWaitMs; mutable Mutex x_work; ///< Lock for the network existance. std::unique_ptr m_work; ///< The network thread. From 66ca33d2fab96d9addf653debe5461006f2ae561 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 25 Nov 2014 11:33:19 +0100 Subject: [PATCH 37/86] Protocol bump. --- libethcore/CommonEth.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libethcore/CommonEth.cpp b/libethcore/CommonEth.cpp index 19522d5de..c12c71774 100644 --- a/libethcore/CommonEth.cpp +++ b/libethcore/CommonEth.cpp @@ -33,7 +33,7 @@ namespace dev namespace eth { -const unsigned c_protocolVersion = 43; +const unsigned c_protocolVersion = 44; const unsigned c_databaseVersion = 4; static const vector> g_units = From d759075528805a8b470dce2c8a3b9caeade62050 Mon Sep 17 00:00:00 2001 From: Christian Date: Tue, 25 Nov 2014 14:43:23 +0100 Subject: [PATCH 38/86] More general function types and references. --- libsolidity/AST.cpp | 12 ++++----- libsolidity/ExpressionCompiler.cpp | 10 ++++---- libsolidity/Types.cpp | 41 +++++++++++++++++++++++++++--- libsolidity/Types.h | 38 ++++++++++++++++----------- test/solidityEndToEndTest.cpp | 20 +++++++++++++++ 5 files changed, 92 insertions(+), 29 deletions(-) diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index 168a095c8..5c07ec80e 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -467,19 +467,19 @@ void FunctionCall::checkTypeRequirements() //@todo would be nice to create a struct type from the arguments // and then ask if that is implicitly convertible to the struct represented by the // function parameters - FunctionDefinition const& fun = dynamic_cast(*expressionType).getFunction(); - vector> const& parameters = fun.getParameters(); - if (parameters.size() != m_arguments.size()) + FunctionType const& functionType = dynamic_cast(*expressionType); + TypePointers const& parameterTypes = functionType.getParameterTypes(); + if (parameterTypes.size() != m_arguments.size()) BOOST_THROW_EXCEPTION(createTypeError("Wrong argument count for function call.")); for (size_t i = 0; i < m_arguments.size(); ++i) - if (!m_arguments[i]->getType()->isImplicitlyConvertibleTo(*parameters[i]->getType())) + if (!m_arguments[i]->getType()->isImplicitlyConvertibleTo(*parameterTypes[i])) BOOST_THROW_EXCEPTION(createTypeError("Invalid type for argument in function call.")); // @todo actually the return type should be an anonymous struct, // but we change it to the type of the first return value until we have structs - if (fun.getReturnParameters().empty()) + if (functionType.getReturnParameterTypes().empty()) m_type = make_shared(); else - m_type = fun.getReturnParameters().front()->getType(); + m_type = functionType.getReturnParameterTypes().front(); } } diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index de8bc1d28..9e396874c 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -183,16 +183,16 @@ bool ExpressionCompiler::visit(FunctionCall& _functionCall) // Calling convention: Caller pushes return address and arguments // Callee removes them and pushes return values - FunctionDefinition const& function = dynamic_cast(*_functionCall.getExpression().getType()).getFunction(); + FunctionType const& function = dynamic_cast(*_functionCall.getExpression().getType()); eth::AssemblyItem returnLabel = m_context.pushNewTag(); std::vector> const& arguments = _functionCall.getArguments(); - if (asserts(arguments.size() == function.getParameters().size())) + if (asserts(arguments.size() == function.getParameterTypes().size())) BOOST_THROW_EXCEPTION(InternalCompilerError()); for (unsigned i = 0; i < arguments.size(); ++i) { arguments[i]->accept(*this); - appendTypeConversion(*arguments[i]->getType(), *function.getParameters()[i]->getType()); + appendTypeConversion(*arguments[i]->getType(), *function.getParameterTypes()[i]); } _functionCall.getExpression().accept(*this); @@ -200,11 +200,11 @@ bool ExpressionCompiler::visit(FunctionCall& _functionCall) m_context << returnLabel; // callee adds return parameters, but removes arguments and return label - m_context.adjustStackOffset(function.getReturnParameters().size() - arguments.size() - 1); + m_context.adjustStackOffset(function.getReturnParameterTypes().size() - arguments.size() - 1); // @todo for now, the return value of a function is its first return value, so remove // all others - for (unsigned i = 1; i < function.getReturnParameters().size(); ++i) + for (unsigned i = 1; i < function.getReturnParameterTypes().size(); ++i) m_context << eth::Instruction::POP; } return false; diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index 616c91831..a6b18b10e 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -189,7 +189,10 @@ u256 IntegerType::literalValue(Literal const& _literal) const return u256(value); } -const MemberList IntegerType::AddressMemberList = MemberList({{"balance", std::make_shared(256)}}); +const MemberList IntegerType::AddressMemberList = + MemberList({{"balance", make_shared(256)}, + {"send", make_shared(TypePointers({make_shared(256)}), + TypePointers())}}); bool BoolType::isExplicitlyConvertibleTo(Type const& _convertTo) const { @@ -299,17 +302,49 @@ u256 StructType::getStorageOffsetOfMember(string const& _name) const BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Storage offset of non-existing member requested.")); } +FunctionType::FunctionType(FunctionDefinition const& _function) +{ + TypePointers params; + TypePointers retParams; + params.reserve(_function.getParameters().size()); + for (ASTPointer const& var: _function.getParameters()) + params.push_back(var->getType()); + retParams.reserve(_function.getReturnParameters().size()); + for (ASTPointer const& var: _function.getReturnParameters()) + retParams.push_back(var->getType()); + swap(params, m_parameterTypes); + swap(retParams, m_returnParameterTypes); +} + bool FunctionType::operator==(Type const& _other) const { if (_other.getCategory() != getCategory()) return false; FunctionType const& other = dynamic_cast(_other); - return other.m_function == m_function; + + if (m_parameterTypes.size() != other.m_parameterTypes.size() || + m_returnParameterTypes.size() != other.m_returnParameterTypes.size()) + return false; + auto typeCompare = [](TypePointer const& _a, TypePointer const& _b) -> bool { return *_a == *_b; }; + + if (!equal(m_parameterTypes.cbegin(), m_parameterTypes.cend(), + other.m_parameterTypes.cbegin(), typeCompare)) + return false; + if (!equal(m_returnParameterTypes.cbegin(), m_returnParameterTypes.cend(), + other.m_returnParameterTypes.cbegin(), typeCompare)) + return false; + return true; } string FunctionType::toString() const { - return "function " + m_function.getName(); + string name = "function ("; + for (auto it = m_parameterTypes.begin(); it != m_parameterTypes.end(); ++it) + name += (*it)->toString() + (it + 1 == m_parameterTypes.end() ? "" : ","); + name += ") returns ("; + for (auto it = m_returnParameterTypes.begin(); it != m_returnParameterTypes.end(); ++it) + name += (*it)->toString() + (it + 1 == m_returnParameterTypes.end() ? "" : ","); + return name + ")"; } bool MappingType::operator==(Type const& _other) const diff --git a/libsolidity/Types.h b/libsolidity/Types.h index 2dd4af64f..17d9053b4 100644 --- a/libsolidity/Types.h +++ b/libsolidity/Types.h @@ -39,6 +39,8 @@ namespace solidity // @todo realMxN, string class Type; // forward +using TypePointer = std::shared_ptr; +using TypePointers = std::vector; /** * List of members of a type. @@ -46,7 +48,6 @@ class Type; // forward class MemberList { public: - using TypePointer = std::shared_ptr; using MemberMap = std::map; MemberList() {} @@ -54,7 +55,7 @@ public: TypePointer getMemberType(std::string const& _name) const { auto it = m_memberTypes.find(_name); - return it != m_memberTypes.end() ? it->second : std::shared_ptr(); + return it != m_memberTypes.end() ? it->second : TypePointer(); } MemberMap::const_iterator begin() const { return m_memberTypes.begin(); } @@ -82,6 +83,7 @@ public: 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); /// @} /// Auto-detect the proper type for a literal. @returns an empty pointer if the literal does @@ -117,7 +119,7 @@ public: /// Returns the list of all members of this type. Default implementation: no members. virtual MemberList const& getMembers() const { return EmptyMemberList; } /// Convenience method, returns the type of the given named member or an empty pointer if no such member exists. - std::shared_ptr getMemberType(std::string const& _name) const { return getMembers().getMemberType(_name); } + TypePointer getMemberType(std::string const& _name) const { return getMembers().getMemberType(_name); } virtual std::string toString() const = 0; virtual u256 literalValue(Literal const&) const @@ -246,15 +248,20 @@ private: }; /** - * The type of a function, there is one distinct type per function definition. + * The type of a function, identified by its (return) parameter types. + * @todo the return parameters should also have names, i.e. return parameters should be a struct + * type. */ class FunctionType: public Type { public: virtual Category getCategory() const override { return Category::FUNCTION; } - FunctionType(FunctionDefinition const& _function): m_function(_function) {} + explicit FunctionType(FunctionDefinition const& _function); + FunctionType(TypePointers const& _parameterTypes, TypePointers const& _returnParameterTypes): + m_parameterTypes(_parameterTypes), m_returnParameterTypes(_returnParameterTypes) {} - FunctionDefinition const& getFunction() const { return m_function; } + TypePointers const& getParameterTypes() const { return m_parameterTypes; } + TypePointers const& getReturnParameterTypes() const { return m_returnParameterTypes; } virtual bool operator==(Type const& _other) const override; virtual std::string toString() const override; @@ -263,7 +270,8 @@ public: virtual bool canLiveOutsideStorage() const override { return false; } private: - FunctionDefinition const& m_function; + TypePointers m_parameterTypes; + TypePointers m_returnParameterTypes; }; /** @@ -273,19 +281,19 @@ class MappingType: public Type { public: virtual Category getCategory() const override { return Category::MAPPING; } - MappingType(std::shared_ptr _keyType, std::shared_ptr _valueType): + MappingType(TypePointer const& _keyType, TypePointer const& _valueType): m_keyType(_keyType), m_valueType(_valueType) {} virtual bool operator==(Type const& _other) const override; virtual std::string toString() const override; virtual bool canLiveOutsideStorage() const override { return false; } - std::shared_ptr getKeyType() const { return m_keyType; } - std::shared_ptr getValueType() const { return m_valueType; } + TypePointer getKeyType() const { return m_keyType; } + TypePointer getValueType() const { return m_valueType; } private: - std::shared_ptr m_keyType; - std::shared_ptr m_valueType; + TypePointer m_keyType; + TypePointer m_valueType; }; /** @@ -312,9 +320,9 @@ class TypeType: public Type { public: virtual Category getCategory() const override { return Category::TYPE; } - TypeType(std::shared_ptr const& _actualType): m_actualType(_actualType) {} + TypeType(TypePointer const& _actualType): m_actualType(_actualType) {} - std::shared_ptr const& getActualType() const { return m_actualType; } + TypePointer const& getActualType() const { return m_actualType; } virtual bool operator==(Type const& _other) const override; virtual bool canBeStored() const override { return false; } @@ -323,7 +331,7 @@ public: virtual std::string toString() const override { return "type(" + m_actualType->toString() + ")"; } private: - std::shared_ptr m_actualType; + TypePointer m_actualType; }; diff --git a/test/solidityEndToEndTest.cpp b/test/solidityEndToEndTest.cpp index fc542f141..66bb0bd7f 100644 --- a/test/solidityEndToEndTest.cpp +++ b/test/solidityEndToEndTest.cpp @@ -774,6 +774,26 @@ BOOST_AUTO_TEST_CASE(blockchain) BOOST_CHECK(callContractFunction(0, bytes{0}, u256(28)) == toBigEndian(u256(28)) + bytes(20, 0) + toBigEndian(u256(1))); } +BOOST_AUTO_TEST_CASE(function_types) +{ + char const* sourceCode = "contract test {\n" + " function a(bool selector) returns (uint b) {\n" + " var f = fun1;\n" + " if (selector) f = fun2;\n" + " return f(9);\n" + " }\n" + " function fun1(uint x) returns (uint b) {\n" + " return 11;\n" + " }\n" + " function fun2(uint x) returns (uint b) {\n" + " return 12;\n" + " }\n" + "}\n"; + compileAndRun(sourceCode); + BOOST_CHECK(callContractFunction(0, bytes{0}) == toBigEndian(u256(11))); + BOOST_CHECK(callContractFunction(0, bytes{1}) == toBigEndian(u256(12))); +} + BOOST_AUTO_TEST_SUITE_END() } From 898f989aa19416cba74c6e07db05588e0c02d976 Mon Sep 17 00:00:00 2001 From: Christian Date: Tue, 25 Nov 2014 18:23:39 +0100 Subject: [PATCH 39/86] Sending ether. --- libsolidity/Compiler.cpp | 2 +- libsolidity/ExpressionCompiler.cpp | 79 +++++++++++++++++++++--------- libsolidity/ExpressionCompiler.h | 4 ++ libsolidity/Types.cpp | 16 +++++- libsolidity/Types.h | 19 ++++++- test/solidityEndToEndTest.cpp | 15 ++++++ 6 files changed, 108 insertions(+), 27 deletions(-) diff --git a/libsolidity/Compiler.cpp b/libsolidity/Compiler.cpp index a82ecd95a..988390d0b 100644 --- a/libsolidity/Compiler.cpp +++ b/libsolidity/Compiler.cpp @@ -325,7 +325,7 @@ bool Compiler::visit(ExpressionStatement& _expressionStatement) Expression& expression = _expressionStatement.getExpression(); ExpressionCompiler::compileExpression(m_context, expression); Type::Category category = expression.getType()->getCategory(); - if (category != Type::Category::VOID && category != Type::Category::MAGIC) + for (unsigned i = 0; i < expression.getType()->getSizeOnStack(); ++i) m_context << eth::Instruction::POP; return false; } diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index 9e396874c..f5ab829c3 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -179,33 +179,62 @@ bool ExpressionCompiler::visit(FunctionCall& _functionCall) } else { - //@todo: check for "external call" (to be stored in type) - - // Calling convention: Caller pushes return address and arguments - // Callee removes them and pushes return values FunctionType const& function = dynamic_cast(*_functionCall.getExpression().getType()); - - eth::AssemblyItem returnLabel = m_context.pushNewTag(); std::vector> const& arguments = _functionCall.getArguments(); if (asserts(arguments.size() == function.getParameterTypes().size())) BOOST_THROW_EXCEPTION(InternalCompilerError()); - for (unsigned i = 0; i < arguments.size(); ++i) + + if (function.getLocation() == FunctionType::Location::INTERNAL) { - arguments[i]->accept(*this); - appendTypeConversion(*arguments[i]->getType(), *function.getParameterTypes()[i]); + // Calling convention: Caller pushes return address and arguments + // Callee removes them and pushes return values + + eth::AssemblyItem returnLabel = m_context.pushNewTag(); + for (unsigned i = 0; i < arguments.size(); ++i) + { + arguments[i]->accept(*this); + appendTypeConversion(*arguments[i]->getType(), *function.getParameterTypes()[i]); + } + _functionCall.getExpression().accept(*this); + + m_context.appendJump(); + m_context << returnLabel; + + // callee adds return parameters, but removes arguments and return label + m_context.adjustStackOffset(function.getReturnParameterTypes().size() - arguments.size() - 1); + + // @todo for now, the return value of a function is its first return value, so remove + // all others + for (unsigned i = 1; i < function.getReturnParameterTypes().size(); ++i) + m_context << eth::Instruction::POP; + } + else if (function.getLocation() == FunctionType::Location::EXTERNAL) + { + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("External function calls not implemented yet.")); + } + else + { + switch (function.getLocation()) + { + case FunctionType::Location::SEND: + m_context << u256(0) << u256(0) << u256(0) << u256(0); + arguments.front()->accept(*this); + //@todo might not be necessary + appendTypeConversion(*arguments.front()->getType(), *function.getParameterTypes().front()); + _functionCall.getExpression().accept(*this); + m_context << u256(25) << eth::Instruction::GAS << eth::Instruction::SUB + << eth::Instruction::CALL + << eth::Instruction::POP; + break; + case FunctionType::Location::SUICIDE: + arguments.front()->accept(*this); + //@todo might not be necessary + appendTypeConversion(*arguments.front()->getType(), *function.getParameterTypes().front()); + m_context << eth::Instruction::SUICIDE; + default: + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Function not yet implemented.")); + } } - _functionCall.getExpression().accept(*this); - - m_context.appendJump(); - m_context << returnLabel; - - // callee adds return parameters, but removes arguments and return label - m_context.adjustStackOffset(function.getReturnParameterTypes().size() - arguments.size() - 1); - - // @todo for now, the return value of a function is its first return value, so remove - // all others - for (unsigned i = 1; i < function.getReturnParameterTypes().size(); ++i) - m_context << eth::Instruction::POP; } return false; } @@ -216,9 +245,13 @@ void ExpressionCompiler::endVisit(MemberAccess& _memberAccess) switch (_memberAccess.getExpression().getType()->getCategory()) { case Type::Category::INTEGER: - if (asserts(member == "balance")) + if (member == "balance") + m_context << eth::Instruction::BALANCE; + else if (member == "send") + { // no modification + } + else BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Invalid member access to integer.")); - m_context << eth::Instruction::BALANCE; break; case Type::Category::CONTRACT: // call function diff --git a/libsolidity/ExpressionCompiler.h b/libsolidity/ExpressionCompiler.h index 3ed7848b5..83d7cdc6c 100644 --- a/libsolidity/ExpressionCompiler.h +++ b/libsolidity/ExpressionCompiler.h @@ -132,6 +132,10 @@ private: CompilerContext& m_context; LValue m_currentLValue; + /// If a "virtual" function (i.e. a bulit-in function without jump tag) is encountered, the + /// actual function is stored here. @todo prevent assignment or store it with assignment + enum class SpecialFunction { NONE, SEND, SHA3, SUICIDE, ECRECOVER, SHA256, RIPEMD160 }; + SpecialFunction m_currentSpecialFunction; }; diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index a6b18b10e..4ab53bf86 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -192,7 +192,7 @@ u256 IntegerType::literalValue(Literal const& _literal) const const MemberList IntegerType::AddressMemberList = MemberList({{"balance", make_shared(256)}, {"send", make_shared(TypePointers({make_shared(256)}), - TypePointers())}}); + TypePointers(), FunctionType::Location::SEND)}}); bool BoolType::isExplicitlyConvertibleTo(Type const& _convertTo) const { @@ -314,6 +314,7 @@ FunctionType::FunctionType(FunctionDefinition const& _function) retParams.push_back(var->getType()); swap(params, m_parameterTypes); swap(retParams, m_returnParameterTypes); + m_location = Location::INTERNAL; } bool FunctionType::operator==(Type const& _other) const @@ -347,6 +348,19 @@ string FunctionType::toString() const return name + ")"; } +unsigned FunctionType::getSizeOnStack() const +{ + switch (m_location) + { + case Location::INTERNAL: + return 1; + case Location::EXTERNAL: + return 2; + default: + return 0; + } +} + bool MappingType::operator==(Type const& _other) const { if (_other.getCategory() != getCategory()) diff --git a/libsolidity/Types.h b/libsolidity/Types.h index 17d9053b4..630c9c213 100644 --- a/libsolidity/Types.h +++ b/libsolidity/Types.h @@ -115,6 +115,7 @@ public: /// Returns true if the type can be stored as a value (as opposed to a reference) on the stack, /// i.e. it behaves differently in lvalue context and in value context. virtual bool isValueType() const { return false; } + virtual unsigned getSizeOnStack() const { return 1; } /// Returns the list of all members of this type. Default implementation: no members. virtual MemberList const& getMembers() const { return EmptyMemberList; } @@ -235,6 +236,7 @@ public: virtual bool operator==(Type const& _other) const override; virtual u256 getStorageSize() const override; virtual bool canLiveOutsideStorage() const override; + virtual unsigned getSizeOnStack() const override { return 1; /*@todo*/ } virtual std::string toString() const override; virtual MemberList const& getMembers() const override; @@ -255,10 +257,17 @@ private: class FunctionType: public Type { public: + /// The meaning of the value(s) on the stack referencing the function: + /// INTERNAL: jump tag, EXTERNAL: contract address + function index, + /// OTHERS: special virtual function, nothing on the stack + enum class Location { INTERNAL, EXTERNAL, SEND, SHA3, SUICIDE, ECRECOVER, SHA256, RIPEMD160 }; + virtual Category getCategory() const override { return Category::FUNCTION; } explicit FunctionType(FunctionDefinition const& _function); - FunctionType(TypePointers const& _parameterTypes, TypePointers const& _returnParameterTypes): - m_parameterTypes(_parameterTypes), m_returnParameterTypes(_returnParameterTypes) {} + FunctionType(TypePointers const& _parameterTypes, TypePointers const& _returnParameterTypes, + Location _location = Location::INTERNAL): + m_parameterTypes(_parameterTypes), m_returnParameterTypes(_returnParameterTypes), + m_location(_location) {} TypePointers const& getParameterTypes() const { return m_parameterTypes; } TypePointers const& getReturnParameterTypes() const { return m_returnParameterTypes; } @@ -268,10 +277,14 @@ public: virtual bool canBeStored() const override { return false; } virtual u256 getStorageSize() const override { BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Storage size of non-storable function type requested.")); } virtual bool canLiveOutsideStorage() const override { return false; } + virtual unsigned getSizeOnStack() const override; + + Location getLocation() const { return m_location; } private: TypePointers m_parameterTypes; TypePointers m_returnParameterTypes; + Location m_location; }; /** @@ -310,6 +323,7 @@ public: virtual bool canBeStored() const override { return false; } 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; } }; /** @@ -349,6 +363,7 @@ public: virtual bool operator==(Type const& _other) const; virtual bool canBeStored() const override { return false; } virtual bool canLiveOutsideStorage() const override { return true; } + virtual unsigned getSizeOnStack() const override { return 0; } virtual MemberList const& getMembers() const override { return m_members; } virtual std::string toString() const override; diff --git a/test/solidityEndToEndTest.cpp b/test/solidityEndToEndTest.cpp index 66bb0bd7f..80a435d1e 100644 --- a/test/solidityEndToEndTest.cpp +++ b/test/solidityEndToEndTest.cpp @@ -794,6 +794,21 @@ BOOST_AUTO_TEST_CASE(function_types) BOOST_CHECK(callContractFunction(0, bytes{1}) == toBigEndian(u256(12))); } +BOOST_AUTO_TEST_CASE(send_ether) +{ + char const* sourceCode = "contract test {\n" + " function a(address addr, uint amount) returns (uint ret) {\n" + " addr.send(amount);\n" + " return address(this).balance;\n" + " }\n" + "}\n"; + u256 amount(130); + compileAndRun(sourceCode, amount + 1); + u160 address(23); + BOOST_CHECK(callContractFunction(0, address, amount) == toBigEndian(u256(1))); + BOOST_CHECK_EQUAL(m_state.balance(address), amount); +} + BOOST_AUTO_TEST_SUITE_END() } From 68acfc0544c7121fa1d25d2421122b97a1e67684 Mon Sep 17 00:00:00 2001 From: Christian Date: Wed, 26 Nov 2014 13:19:17 +0100 Subject: [PATCH 40/86] Global functions. --- libsolidity/AST.h | 11 ++-- libsolidity/ExpressionCompiler.cpp | 55 ++++++++++++++---- libsolidity/GlobalContext.cpp | 37 ++++++++---- libsolidity/Types.h | 2 +- test/solidityEndToEndTest.cpp | 91 +++++++++++++++++++++++++++++- 5 files changed, 167 insertions(+), 29 deletions(-) diff --git a/libsolidity/AST.h b/libsolidity/AST.h index 89f268b33..3fb251d95 100644 --- a/libsolidity/AST.h +++ b/libsolidity/AST.h @@ -233,23 +233,20 @@ private: }; /** - * Pseudo AST node that is used as declaration for "this", "msg", "tx" and "block" when the - * identifier is encountered. Will never have a valid location in the source code. + * Pseudo AST node that is used as declaration for "this", "msg", "tx", "block" and the global + * functions when such an identifier is encountered. Will never have a valid location in the source code. */ class MagicVariableDeclaration: public Declaration { public: - enum class VariableKind { THIS, MSG, TX, BLOCK }; - MagicVariableDeclaration(VariableKind _kind, ASTString const& _name, std::shared_ptr const& _type): - Declaration(Location(), std::make_shared(_name)), m_kind(_kind), m_type(_type) {} + MagicVariableDeclaration(ASTString const& _name, std::shared_ptr const& _type): + Declaration(Location(), std::make_shared(_name)), m_type(_type) {} virtual void accept(ASTVisitor&) override { BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("MagicVariableDeclaration used inside real AST.")); } std::shared_ptr const& getType() const { return m_type; } - VariableKind getKind() const { return m_kind; } private: - VariableKind m_kind; std::shared_ptr m_type; }; diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index f5ab829c3..4dc377791 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -160,6 +160,7 @@ bool ExpressionCompiler::visit(BinaryOperation& _binaryOperation) bool ExpressionCompiler::visit(FunctionCall& _functionCall) { + using Location = FunctionType::Location; if (_functionCall.isTypeConversion()) { //@todo struct construction @@ -184,7 +185,7 @@ bool ExpressionCompiler::visit(FunctionCall& _functionCall) if (asserts(arguments.size() == function.getParameterTypes().size())) BOOST_THROW_EXCEPTION(InternalCompilerError()); - if (function.getLocation() == FunctionType::Location::INTERNAL) + if (function.getLocation() == Location::INTERNAL) { // Calling convention: Caller pushes return address and arguments // Callee removes them and pushes return values @@ -208,29 +209,57 @@ bool ExpressionCompiler::visit(FunctionCall& _functionCall) for (unsigned i = 1; i < function.getReturnParameterTypes().size(); ++i) m_context << eth::Instruction::POP; } - else if (function.getLocation() == FunctionType::Location::EXTERNAL) - { + else if (function.getLocation() == Location::EXTERNAL) BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("External function calls not implemented yet.")); - } else { switch (function.getLocation()) { - case FunctionType::Location::SEND: + case Location::SEND: m_context << u256(0) << u256(0) << u256(0) << u256(0); arguments.front()->accept(*this); //@todo might not be necessary - appendTypeConversion(*arguments.front()->getType(), *function.getParameterTypes().front()); + appendTypeConversion(*arguments.front()->getType(), *function.getParameterTypes().front(), true); _functionCall.getExpression().accept(*this); m_context << u256(25) << eth::Instruction::GAS << eth::Instruction::SUB << eth::Instruction::CALL << eth::Instruction::POP; break; - case FunctionType::Location::SUICIDE: + case Location::SUICIDE: arguments.front()->accept(*this); //@todo might not be necessary - appendTypeConversion(*arguments.front()->getType(), *function.getParameterTypes().front()); + appendTypeConversion(*arguments.front()->getType(), *function.getParameterTypes().front(), true); m_context << eth::Instruction::SUICIDE; + break; + case Location::SHA3: + arguments.front()->accept(*this); + appendTypeConversion(*arguments.front()->getType(), *function.getParameterTypes().front(), true); + // @todo move this once we actually use memory + m_context << u256(0) << eth::Instruction::MSTORE << u256(32) << u256(0) << eth::Instruction::SHA3; + break; + case Location::ECRECOVER: + case Location::SHA256: + case Location::RIPEMD160: + { + static const map contractAddresses{{Location::ECRECOVER, 1}, + {Location::SHA256, 2}, + {Location::RIPEMD160, 3}}; + u256 contractAddress = contractAddresses.find(function.getLocation())->second; + // @todo later, combine this code with external function call + for (unsigned i = 0; i < arguments.size(); ++i) + { + arguments[i]->accept(*this); + appendTypeConversion(*arguments[i]->getType(), *function.getParameterTypes()[i], true); + // @todo move this once we actually use memory + m_context << u256(i * 32) << eth::Instruction::MSTORE; + } + m_context << u256(32) << u256(0) << u256(arguments.size() * 32) << u256(0) << u256(0) + << contractAddress << u256(500) //@todo determine actual gas requirement + << eth::Instruction::CALL + << eth::Instruction::POP + << u256(0) << eth::Instruction::MLOAD; + break; + } default: BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Function not yet implemented.")); } @@ -246,9 +275,15 @@ void ExpressionCompiler::endVisit(MemberAccess& _memberAccess) { case Type::Category::INTEGER: if (member == "balance") + { + appendTypeConversion(*_memberAccess.getExpression().getType(), + IntegerType(0, IntegerType::Modifier::ADDRESS), true); m_context << eth::Instruction::BALANCE; + } else if (member == "send") - { // no modification + { + appendTypeConversion(*_memberAccess.getExpression().getType(), + IntegerType(0, IntegerType::Modifier::ADDRESS), true); } else BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Invalid member access to integer.")); @@ -319,7 +354,7 @@ void ExpressionCompiler::endVisit(Identifier& _identifier) Declaration* declaration = _identifier.getReferencedDeclaration(); if (MagicVariableDeclaration* magicVar = dynamic_cast(declaration)) { - if (magicVar->getKind() == MagicVariableDeclaration::VariableKind::THIS) + if (magicVar->getType()->getCategory() == Type::Category::CONTRACT) // must be "this" m_context << eth::Instruction::ADDRESS; return; } diff --git a/libsolidity/GlobalContext.cpp b/libsolidity/GlobalContext.cpp index 4120dae5e..e958352fd 100644 --- a/libsolidity/GlobalContext.cpp +++ b/libsolidity/GlobalContext.cpp @@ -33,15 +33,33 @@ namespace solidity { GlobalContext::GlobalContext(): - m_magicVariables{make_shared(MagicVariableDeclaration::VariableKind::BLOCK, - "block", - make_shared(MagicType::Kind::BLOCK)), - make_shared(MagicVariableDeclaration::VariableKind::MSG, - "msg", - make_shared(MagicType::Kind::MSG)), - make_shared(MagicVariableDeclaration::VariableKind::TX, - "tx", - make_shared(MagicType::Kind::TX))} + m_magicVariables{make_shared("block", make_shared(MagicType::Kind::BLOCK)), + make_shared("msg", make_shared(MagicType::Kind::MSG)), + make_shared("tx", make_shared(MagicType::Kind::TX)), + make_shared("suicide", + make_shared(TypePointers({std::make_shared(0, + IntegerType::Modifier::ADDRESS)}), + TypePointers(), + FunctionType::Location::SUICIDE)), + make_shared("sha3", + make_shared(TypePointers({std::make_shared(256, IntegerType::Modifier::HASH)}), + TypePointers({std::make_shared(256, IntegerType::Modifier::HASH)}), + FunctionType::Location::SHA3)), + make_shared("sha256", + make_shared(TypePointers({std::make_shared(256, IntegerType::Modifier::HASH)}), + TypePointers({std::make_shared(256, IntegerType::Modifier::HASH)}), + FunctionType::Location::SHA256)), + make_shared("ecrecover", + make_shared(TypePointers({std::make_shared(256, IntegerType::Modifier::HASH), + std::make_shared(8, IntegerType::Modifier::HASH), + std::make_shared(256, IntegerType::Modifier::HASH), + std::make_shared(256, IntegerType::Modifier::HASH)}), + TypePointers({std::make_shared(0, IntegerType::Modifier::ADDRESS)}), + FunctionType::Location::ECRECOVER)), + make_shared("ripemd160", + make_shared(TypePointers({std::make_shared(256, IntegerType::Modifier::HASH)}), + TypePointers({std::make_shared(256, IntegerType::Modifier::HASH)}), + FunctionType::Location::RIPEMD160))} { } @@ -64,7 +82,6 @@ MagicVariableDeclaration*GlobalContext::getCurrentThis() const { if (!m_thisPointer[m_currentContract]) m_thisPointer[m_currentContract] = make_shared( - MagicVariableDeclaration::VariableKind::THIS, "this", make_shared(*m_currentContract)); return m_thisPointer[m_currentContract].get(); diff --git a/libsolidity/Types.h b/libsolidity/Types.h index 630c9c213..b655f9e0d 100644 --- a/libsolidity/Types.h +++ b/libsolidity/Types.h @@ -356,7 +356,7 @@ private: class MagicType: public Type { public: - enum class Kind { BLOCK, MSG, TX }; //@todo should be unified with MagicVariableDeclaration::VariableKind; + enum class Kind { BLOCK, MSG, TX }; virtual Category getCategory() const override { return Category::MAGIC; } MagicType(Kind _kind); diff --git a/test/solidityEndToEndTest.cpp b/test/solidityEndToEndTest.cpp index 80a435d1e..8b25d4031 100644 --- a/test/solidityEndToEndTest.cpp +++ b/test/solidityEndToEndTest.cpp @@ -27,12 +27,14 @@ #include #include #include +#include using namespace std; namespace dev { -/// Provider another overload for toBigEndian to encode arguments and return values. +/// Provides additional overloads for toBigEndian to encode arguments and return values. +inline bytes toBigEndian(byte _value) { return bytes({_value}); } inline bytes toBigEndian(bool _value) { return bytes({byte(_value)}); } namespace solidity @@ -809,6 +811,93 @@ BOOST_AUTO_TEST_CASE(send_ether) BOOST_CHECK_EQUAL(m_state.balance(address), amount); } +BOOST_AUTO_TEST_CASE(suicide) +{ + char const* sourceCode = "contract test {\n" + " function a(address receiver) returns (uint ret) {\n" + " suicide(receiver);\n" + " return 10;\n" + " }\n" + "}\n"; + u256 amount(130); + compileAndRun(sourceCode, amount); + u160 address(23); + BOOST_CHECK(callContractFunction(0, address) == bytes()); + BOOST_CHECK(!m_state.addressHasCode(m_contractAddress)); + BOOST_CHECK_EQUAL(m_state.balance(address), amount); +} + +BOOST_AUTO_TEST_CASE(sha3) +{ + char const* sourceCode = "contract test {\n" + " function a(hash input) returns (hash sha3hash) {\n" + " return sha3(input);\n" + " }\n" + "}\n"; + compileAndRun(sourceCode); + auto f = [&](u256 const& _x) -> u256 + { + return dev::sha3(toBigEndian(_x)); + }; + testSolidityAgainstCpp(0, f, u256(4)); + testSolidityAgainstCpp(0, f, u256(5)); + testSolidityAgainstCpp(0, f, u256(-1)); +} + +BOOST_AUTO_TEST_CASE(sha256) +{ + char const* sourceCode = "contract test {\n" + " function a(hash input) returns (hash sha256hash) {\n" + " return sha256(input);\n" + " }\n" + "}\n"; + compileAndRun(sourceCode); + auto f = [&](u256 const& _input) -> u256 + { + h256 ret; + dev::sha256(dev::ref(toBigEndian(_input)), bytesRef(&ret[0], 32)); + return ret; + }; + testSolidityAgainstCpp(0, f, u256(4)); + testSolidityAgainstCpp(0, f, u256(5)); + testSolidityAgainstCpp(0, f, u256(-1)); +} + +BOOST_AUTO_TEST_CASE(ripemd) +{ + char const* sourceCode = "contract test {\n" + " function a(hash input) returns (hash sha256hash) {\n" + " return ripemd160(input);\n" + " }\n" + "}\n"; + compileAndRun(sourceCode); + auto f = [&](u256 const& _input) -> u256 + { + h256 ret; + dev::ripemd160(dev::ref(toBigEndian(_input)), bytesRef(&ret[0], 32)); + return u256(ret) >> (256 - 160); + }; + testSolidityAgainstCpp(0, f, u256(4)); + testSolidityAgainstCpp(0, f, u256(5)); + testSolidityAgainstCpp(0, f, u256(-1)); +} + +BOOST_AUTO_TEST_CASE(ecrecover) +{ + char const* sourceCode = "contract test {\n" + " function a(hash h, uint8 v, hash r, hash s) returns (address addr) {\n" + " return ecrecover(h, v, r, s);\n" + " }\n" + "}\n"; + compileAndRun(sourceCode); + u256 h("0x18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c"); + byte v = 28; + u256 r("0x73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f"); + u256 s("0xeeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549"); + u160 addr("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b"); + BOOST_CHECK(callContractFunction(0, h, v, r, s) == toBigEndian(addr)); +} + BOOST_AUTO_TEST_SUITE_END() } From 2f45a8deb51d0c5fbabcf5845d261050b2ea897a Mon Sep 17 00:00:00 2001 From: Christian Date: Wed, 26 Nov 2014 19:41:28 +0100 Subject: [PATCH 41/86] Prevent uninitialized output memory in ecrecover. --- libethereum/State.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 1ac1507fe..40327b108 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -51,14 +51,16 @@ void ecrecoverCode(bytesConstRef _in, bytesRef _out) h256 s; } in; - h256 ret; - memcpy(&in, _in.data(), min(_in.size(), sizeof(in))); + memset(_out.data(), 0, _out.size()); + if (in.v > 28) + return; SignatureStruct sig{in.r, in.s, (byte)((int)(u256)in.v - 27)}; - if (!sig.isValid() || in.v > 28) + if (!sig.isValid()) return; + h256 ret; byte pubkey[65]; int pubkeylen = 65; secp256k1_start(); From 43f269ce9a9114496a7e9a57876aa8a976ff042c Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Thu, 27 Nov 2014 15:21:22 +0100 Subject: [PATCH 42/86] Solidity function AST nodes get documentation attribute --- libsolidity/AST.h | 20 +++++++++++++------- libsolidity/Parser.cpp | 5 +++-- test/solidityParser.cpp | 33 ++++++++++++++++++++++++++++++++- 3 files changed, 48 insertions(+), 10 deletions(-) diff --git a/libsolidity/AST.h b/libsolidity/AST.h index 3fb251d95..dc34e3695 100644 --- a/libsolidity/AST.h +++ b/libsolidity/AST.h @@ -174,13 +174,17 @@ class FunctionDefinition: public Declaration { public: FunctionDefinition(Location const& _location, ASTPointer const& _name, bool _isPublic, - ASTPointer const& _parameters, - bool _isDeclaredConst, - ASTPointer const& _returnParameters, - ASTPointer const& _body): - Declaration(_location, _name), m_isPublic(_isPublic), m_parameters(_parameters), - m_isDeclaredConst(_isDeclaredConst), m_returnParameters(_returnParameters), - m_body(_body) {} + std::string const& _documentation, + ASTPointer const& _parameters, + bool _isDeclaredConst, + ASTPointer const& _returnParameters, + ASTPointer const& _body): + Declaration(_location, _name), m_isPublic(_isPublic), + m_parameters(_parameters), + m_isDeclaredConst(_isDeclaredConst), + m_returnParameters(_returnParameters), + m_body(_body), + m_documentation(_documentation) {} virtual void accept(ASTVisitor& _visitor) override; bool isPublic() const { return m_isPublic; } @@ -190,6 +194,7 @@ public: std::vector> const& getReturnParameters() const { return m_returnParameters->getParameters(); } ASTPointer const& getReturnParameterList() const { return m_returnParameters; } Block& getBody() { return *m_body; } + std::string& getDocumentation() { return m_documentation; } void addLocalVariable(VariableDeclaration const& _localVariable) { m_localVariables.push_back(&_localVariable); } std::vector const& getLocalVariables() const { return m_localVariables; } @@ -203,6 +208,7 @@ private: bool m_isDeclaredConst; ASTPointer m_returnParameters; ASTPointer m_body; + std::string m_documentation; std::vector m_localVariables; }; diff --git a/libsolidity/Parser.cpp b/libsolidity/Parser.cpp index 276da0728..3cf44014f 100644 --- a/libsolidity/Parser.cpp +++ b/libsolidity/Parser.cpp @@ -142,8 +142,9 @@ ASTPointer Parser::parseFunctionDefinition(bool _isPublic) } ASTPointer block = parseBlock(); nodeFactory.setEndPositionFromNode(block); - return nodeFactory.createNode(name, _isPublic, parameters, - isDeclaredConst, returnParameters, block); + return nodeFactory.createNode(name, _isPublic, m_scanner->getCurrentCommentLiteral(), + parameters, + isDeclaredConst, returnParameters, block); } ASTPointer Parser::parseStructDefinition() diff --git a/test/solidityParser.cpp b/test/solidityParser.cpp index 9319a02c5..88a1fd5f0 100644 --- a/test/solidityParser.cpp +++ b/test/solidityParser.cpp @@ -37,13 +37,14 @@ namespace test namespace { -ASTPointer parseText(std::string const& _source) +ASTPointer parseText(std::string const& _source) { Parser parser; return parser.parse(std::make_shared(CharStream(_source))); } } + BOOST_AUTO_TEST_SUITE(SolidityParser) BOOST_AUTO_TEST_CASE(smoke_test) @@ -91,6 +92,36 @@ BOOST_AUTO_TEST_CASE(single_function_param) BOOST_CHECK_NO_THROW(parseText(text)); } +BOOST_AUTO_TEST_CASE(function_natspec_documentation) +{ + ASTPointer contract; + ASTPointer function; + char const* text = "contract test {\n" + " uint256 stateVar;\n" + " /// This is a test function\n" + " function functionName(hash hashin) returns (hash hashout) {}\n" + "}\n"; + BOOST_CHECK_NO_THROW(contract = parseText(text)); + auto functions = contract->getDefinedFunctions(); + BOOST_CHECK_NO_THROW(function = functions.at(0)); + BOOST_CHECK_EQUAL(function->getDocumentation(), " This is a test function"); +} + +BOOST_AUTO_TEST_CASE(function_normal_comments) +{ + ASTPointer contract; + ASTPointer function; + char const* text = "contract test {\n" + " uint256 stateVar;\n" + " // We won't see this comment\n" + " function functionName(hash hashin) returns (hash hashout) {}\n" + "}\n"; + BOOST_CHECK_NO_THROW(contract = parseText(text)); + auto functions = contract->getDefinedFunctions(); + BOOST_CHECK_NO_THROW(function = functions.at(0)); + BOOST_CHECK_EQUAL(function->getDocumentation(), ""); +} + BOOST_AUTO_TEST_CASE(struct_definition) { char const* text = "contract test {\n" From 390e2e8634f350b3515aeebb33116c0e4172332b Mon Sep 17 00:00:00 2001 From: Christian Date: Thu, 27 Nov 2014 18:24:59 +0100 Subject: [PATCH 43/86] Minor changes to magic variables. gas moves to "msg", ripemd160 returns hash160. --- libsolidity/GlobalContext.cpp | 2 +- libsolidity/Types.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libsolidity/GlobalContext.cpp b/libsolidity/GlobalContext.cpp index e958352fd..d8b637076 100644 --- a/libsolidity/GlobalContext.cpp +++ b/libsolidity/GlobalContext.cpp @@ -58,7 +58,7 @@ GlobalContext::GlobalContext(): FunctionType::Location::ECRECOVER)), make_shared("ripemd160", make_shared(TypePointers({std::make_shared(256, IntegerType::Modifier::HASH)}), - TypePointers({std::make_shared(256, IntegerType::Modifier::HASH)}), + TypePointers({std::make_shared(160, IntegerType::Modifier::HASH)}), FunctionType::Location::RIPEMD160))} { } diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index 4ab53bf86..b81fbbe31 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -397,11 +397,11 @@ MagicType::MagicType(MagicType::Kind _kind): break; case Kind::MSG: m_members = MemberList({{"sender", make_shared(0, IntegerType::Modifier::ADDRESS)}, + {"gas", make_shared(256)}, {"value", make_shared(256)}}); break; case Kind::TX: m_members = MemberList({{"origin", make_shared(0, IntegerType::Modifier::ADDRESS)}, - {"gas", make_shared(256)}, {"gasprice", make_shared(256)}}); break; default: From e5da1ba6c6e8eaa6eb46eb0507ff0b348b297128 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Thu, 27 Nov 2014 18:57:50 +0100 Subject: [PATCH 44/86] Solidity work for documentation strings - Still a work in progress - Parser now properly gets each function's doc comment - Small changes in the scanner - Multiline comments are considered --- libsolidity/Parser.cpp | 4 +++- libsolidity/Scanner.cpp | 34 +++++++++++++++++++++++---- libsolidity/Scanner.h | 41 ++++++++++++++++++++++++++++---- test/solidityParser.cpp | 52 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 121 insertions(+), 10 deletions(-) diff --git a/libsolidity/Parser.cpp b/libsolidity/Parser.cpp index 3cf44014f..17fd2d78c 100644 --- a/libsolidity/Parser.cpp +++ b/libsolidity/Parser.cpp @@ -118,6 +118,8 @@ ASTPointer Parser::parseFunctionDefinition(bool _isPublic) { ASTNodeFactory nodeFactory(*this); expectToken(Token::FUNCTION); + std::string docstring = m_scanner->getCurrentCommentLiteral(); + m_scanner->clearCurrentCommentLiteral(); ASTPointer name(expectIdentifierToken()); ASTPointer parameters(parseParameterList()); bool isDeclaredConst = false; @@ -142,7 +144,7 @@ ASTPointer Parser::parseFunctionDefinition(bool _isPublic) } ASTPointer block = parseBlock(); nodeFactory.setEndPositionFromNode(block); - return nodeFactory.createNode(name, _isPublic, m_scanner->getCurrentCommentLiteral(), + return nodeFactory.createNode(name, _isPublic, docstring, parameters, isDeclaredConst, returnParameters, block); } diff --git a/libsolidity/Scanner.cpp b/libsolidity/Scanner.cpp index dd18a320f..c40d98af5 100644 --- a/libsolidity/Scanner.cpp +++ b/libsolidity/Scanner.cpp @@ -180,10 +180,26 @@ Token::Value Scanner::skipSingleLineComment() /// For the moment this function simply consumes a single line triple slash doc comment Token::Value Scanner::scanDocumentationComment() { - LiteralScope literal(this); + LiteralScope literal(this, LITERAL_TYPE_COMMENT); advance(); //consume the last '/' - while (!isSourcePastEndOfInput() && !isLineTerminator(m_char)) + while (!isSourcePastEndOfInput()) { + if (isLineTerminator(m_char)) + { + // check if next line is also a documentation comment + skipWhitespace(); + if (m_source.get(0) == '/' && + m_source.get(1) == '/' && + m_source.get(2) == '/' && + !m_source.isPastEndOfInput(3)) + { + m_source.advanceBy(3); + addCommentLiteralChar('\n'); + } + else + break; // next line is not a documentation comment, we are done + + } addCommentLiteralChar(m_char); advance(); } @@ -474,7 +490,7 @@ Token::Value Scanner::scanString() { char const quote = m_char; advance(); // consume quote - LiteralScope literal(this); + LiteralScope literal(this, LITERAL_TYPE_STRING); while (m_char != quote && !isSourcePastEndOfInput() && !isLineTerminator(m_char)) { char c = m_char; @@ -505,7 +521,7 @@ void Scanner::scanDecimalDigits() Token::Value Scanner::scanNumber(char _charSeen) { enum { DECIMAL, HEX, BINARY } kind = DECIMAL; - LiteralScope literal(this); + LiteralScope literal(this, LITERAL_TYPE_NUMBER); if (_charSeen == '.') { // we have already seen a decimal point of the float @@ -758,7 +774,7 @@ Token::Value Scanner::scanIdentifierOrKeyword() { if (asserts(isIdentifierStart(m_char))) BOOST_THROW_EXCEPTION(InternalCompilerError()); - LiteralScope literal(this); + LiteralScope literal(this, LITERAL_TYPE_STRING); addLiteralCharAndAdvance(); // Scan the rest of the identifier characters. while (isIdentifierPart(m_char)) @@ -777,6 +793,14 @@ char CharStream::advanceAndGet() return get(); } +void CharStream::advanceBy(size_t _chars) +{ + if (asserts(!isPastEndOfInput(_chars))) + BOOST_THROW_EXCEPTION(InternalCompilerError()); + + m_pos += _chars; +} + char CharStream::rollback(size_t _amount) { if (asserts(m_pos >= _amount)) diff --git a/libsolidity/Scanner.h b/libsolidity/Scanner.h index 957f02b1f..5123ccccc 100644 --- a/libsolidity/Scanner.h +++ b/libsolidity/Scanner.h @@ -74,9 +74,10 @@ public: CharStream(): m_pos(0) {} explicit CharStream(std::string const& _source): m_source(_source), m_pos(0) {} int getPos() const { return m_pos; } - bool isPastEndOfInput() const { return m_pos >= m_source.size(); } - char get() const { return m_source[m_pos]; } + bool isPastEndOfInput(size_t _charsForward = 0) const { return (m_pos + _charsForward) >= m_source.size(); } + char get(size_t _charsForward = 0) const { return m_source[m_pos + _charsForward]; } char advanceAndGet(); + void advanceBy(size_t _chars); char rollback(size_t _amount); ///@{ @@ -93,19 +94,45 @@ private: }; + class Scanner { public: + + enum LiteralType { + LITERAL_TYPE_STRING, + LITERAL_TYPE_NUMBER, // not really different from string type in behaviour + LITERAL_TYPE_COMMENT + }; /// Scoped helper for literal recording. Automatically drops the literal /// if aborting the scanning before it's complete. class LiteralScope { public: - explicit LiteralScope(Scanner* self): m_scanner(self), m_complete(false) { m_scanner->startNewLiteral(); } - ~LiteralScope() { if (!m_complete) m_scanner->dropLiteral(); } + explicit LiteralScope(Scanner* _self, enum LiteralType _type) + : m_type(_type) + , m_scanner(_self) + , m_complete(false) + { + if (_type == LITERAL_TYPE_COMMENT) + m_scanner->startNewCommentLiteral(); + else + m_scanner->startNewLiteral(); + } + ~LiteralScope() + { + if (!m_complete) + { + if (m_type == LITERAL_TYPE_COMMENT) + m_scanner->dropCommentLiteral(); + else + m_scanner->dropLiteral(); + } + } void complete() { m_complete = true; } private: + enum LiteralType m_type; Scanner* m_scanner; bool m_complete; }; @@ -133,8 +160,12 @@ public: ///@{ ///@name Information about the current comment token + Location getCurrentCommentLocation() const { return m_skippedComment.location; } std::string const& getCurrentCommentLiteral() const { return m_skippedComment.literal; } + /// Called by the parser during FunctionDefinition parsing to clear the current comment + void clearCurrentCommentLiteral() { m_skippedComment.literal.clear(); } + ///@} ///@{ @@ -166,9 +197,11 @@ private: ///@{ ///@name Literal buffer support inline void startNewLiteral() { m_nextToken.literal.clear(); } + inline void startNewCommentLiteral() { m_nextSkippedComment.literal.clear(); } inline void addLiteralChar(char c) { m_nextToken.literal.push_back(c); } inline void addCommentLiteralChar(char c) { m_nextSkippedComment.literal.push_back(c); } inline void dropLiteral() { m_nextToken.literal.clear(); } + inline void dropCommentLiteral() { m_nextSkippedComment.literal.clear(); } inline void addLiteralCharAndAdvance() { addLiteralChar(m_char); advance(); } ///@} diff --git a/test/solidityParser.cpp b/test/solidityParser.cpp index 88a1fd5f0..bda820b98 100644 --- a/test/solidityParser.cpp +++ b/test/solidityParser.cpp @@ -122,6 +122,58 @@ BOOST_AUTO_TEST_CASE(function_normal_comments) BOOST_CHECK_EQUAL(function->getDocumentation(), ""); } +BOOST_AUTO_TEST_CASE(multiple_functions_natspec_documentation) +{ + ASTPointer contract; + ASTPointer function; + char const* text = "contract test {\n" + " uint256 stateVar;\n" + " /// This is test function 1\n" + " function functionName1(hash hashin) returns (hash hashout) {}\n" + " /// This is test function 2\n" + " function functionName2(hash hashin) returns (hash hashout) {}\n" + " // nothing to see here\n" + " function functionName3(hash hashin) returns (hash hashout) {}\n" + " /// This is test function 4\n" + " function functionName4(hash hashin) returns (hash hashout) {}\n" + "}\n"; + BOOST_CHECK_NO_THROW(contract = parseText(text)); + auto functions = contract->getDefinedFunctions(); + + BOOST_CHECK_NO_THROW(function = functions.at(0)); + BOOST_CHECK_EQUAL(function->getDocumentation(), " This is test function 1"); + + BOOST_CHECK_NO_THROW(function = functions.at(1)); + BOOST_CHECK_EQUAL(function->getDocumentation(), " This is test function 2"); + + BOOST_CHECK_NO_THROW(function = functions.at(2)); + BOOST_CHECK_EQUAL(function->getDocumentation(), ""); + + BOOST_CHECK_NO_THROW(function = functions.at(3)); + BOOST_CHECK_EQUAL(function->getDocumentation(), " This is test function 4"); +} + +#if 0 /* Work in progress - currently fails*/ +BOOST_AUTO_TEST_CASE(multiline_function_documentation) +{ + ASTPointer contract; + ASTPointer function; + char const* text = "contract test {\n" + " uint256 stateVar;\n" + " /// This is a test function\n" + " /// and it has 2 lines\n" + " function functionName1(hash hashin) returns (hash hashout) {}\n" + "}\n"; + BOOST_CHECK_NO_THROW(contract = parseText(text)); + auto functions = contract->getDefinedFunctions(); + + BOOST_CHECK_NO_THROW(function = functions.at(0)); + BOOST_CHECK_EQUAL(function->getDocumentation(), + " This is a test function\n" + " and it has 2 lines"); +} +#endif + BOOST_AUTO_TEST_CASE(struct_definition) { char const* text = "contract test {\n" From 170ff1a07f8f4926afc53ad862b5ba8e6ab356d4 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Fri, 28 Nov 2014 00:06:38 +0100 Subject: [PATCH 45/86] Fixing multiline comment parsing in solidity --- libsolidity/Scanner.cpp | 6 ++++-- libsolidity/Scanner.h | 2 +- test/solidityParser.cpp | 2 -- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/libsolidity/Scanner.cpp b/libsolidity/Scanner.cpp index c40d98af5..4da9874a2 100644 --- a/libsolidity/Scanner.cpp +++ b/libsolidity/Scanner.cpp @@ -193,8 +193,8 @@ Token::Value Scanner::scanDocumentationComment() m_source.get(2) == '/' && !m_source.isPastEndOfInput(3)) { - m_source.advanceBy(3); addCommentLiteralChar('\n'); + m_char = m_source.advanceBy(3); } else break; // next line is not a documentation comment, we are done @@ -793,12 +793,14 @@ char CharStream::advanceAndGet() return get(); } -void CharStream::advanceBy(size_t _chars) +char CharStream::advanceBy(size_t _chars) { if (asserts(!isPastEndOfInput(_chars))) BOOST_THROW_EXCEPTION(InternalCompilerError()); m_pos += _chars; + + return m_source[m_pos]; } char CharStream::rollback(size_t _amount) diff --git a/libsolidity/Scanner.h b/libsolidity/Scanner.h index 5123ccccc..edec344ac 100644 --- a/libsolidity/Scanner.h +++ b/libsolidity/Scanner.h @@ -77,7 +77,7 @@ public: bool isPastEndOfInput(size_t _charsForward = 0) const { return (m_pos + _charsForward) >= m_source.size(); } char get(size_t _charsForward = 0) const { return m_source[m_pos + _charsForward]; } char advanceAndGet(); - void advanceBy(size_t _chars); + char advanceBy(size_t _chars); char rollback(size_t _amount); ///@{ diff --git a/test/solidityParser.cpp b/test/solidityParser.cpp index bda820b98..e05b88580 100644 --- a/test/solidityParser.cpp +++ b/test/solidityParser.cpp @@ -153,7 +153,6 @@ BOOST_AUTO_TEST_CASE(multiple_functions_natspec_documentation) BOOST_CHECK_EQUAL(function->getDocumentation(), " This is test function 4"); } -#if 0 /* Work in progress - currently fails*/ BOOST_AUTO_TEST_CASE(multiline_function_documentation) { ASTPointer contract; @@ -172,7 +171,6 @@ BOOST_AUTO_TEST_CASE(multiline_function_documentation) " This is a test function\n" " and it has 2 lines"); } -#endif BOOST_AUTO_TEST_CASE(struct_definition) { From 3e42b5ff0d5d61348472f6fb076b6960d1c0ea83 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Fri, 28 Nov 2014 00:40:00 +0100 Subject: [PATCH 46/86] Adding solidity natspec comment inside function body --- test/solidityParser.cpp | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/test/solidityParser.cpp b/test/solidityParser.cpp index e05b88580..3a95ec065 100644 --- a/test/solidityParser.cpp +++ b/test/solidityParser.cpp @@ -172,6 +172,36 @@ BOOST_AUTO_TEST_CASE(multiline_function_documentation) " and it has 2 lines"); } +BOOST_AUTO_TEST_CASE(natspec_comment_in_function_body) +{ + ASTPointer contract; + ASTPointer function; + char const* text = "contract test {\n" + " /// fun1 description\n" + " function fun1(uint256 a) {\n" + " var b;\n" + " /// I should not interfere with actual natspec comments\n" + " uint256 c;\n" + " mapping(address=>hash) d;\n" + " string name = \"Solidity\";" + " }\n" + " uint256 stateVar;\n" + " /// This is a test function\n" + " /// and it has 2 lines\n" + " function fun(hash hashin) returns (hash hashout) {}\n" + "}\n"; + BOOST_CHECK_NO_THROW(contract = parseText(text)); + auto functions = contract->getDefinedFunctions(); + + BOOST_CHECK_NO_THROW(function = functions.at(0)); + BOOST_CHECK_EQUAL(function->getDocumentation(), " fun1 description"); + + BOOST_CHECK_NO_THROW(function = functions.at(1)); + BOOST_CHECK_EQUAL(function->getDocumentation(), + " This is a test function\n" + " and it has 2 lines"); +} + BOOST_AUTO_TEST_CASE(struct_definition) { char const* text = "contract test {\n" From 4bb7cc9f676fe3a3876c667630f27cd25a97362c Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Fri, 28 Nov 2014 01:26:37 +0100 Subject: [PATCH 47/86] Solidity FunctionDefinition used ASTString shared ptr for docstrings --- libsolidity/AST.h | 15 ++++++++++----- libsolidity/Parser.cpp | 8 ++++++-- test/solidityParser.cpp | 20 +++++++++++--------- 3 files changed, 27 insertions(+), 16 deletions(-) diff --git a/libsolidity/AST.h b/libsolidity/AST.h index dc34e3695..81a12ad1a 100644 --- a/libsolidity/AST.h +++ b/libsolidity/AST.h @@ -173,8 +173,9 @@ private: class FunctionDefinition: public Declaration { public: - FunctionDefinition(Location const& _location, ASTPointer const& _name, bool _isPublic, - std::string const& _documentation, + FunctionDefinition(Location const& _location, ASTPointer const& _name, + bool _isPublic, + ASTPointer const& _documentation, ASTPointer const& _parameters, bool _isDeclaredConst, ASTPointer const& _returnParameters, @@ -184,7 +185,9 @@ public: m_isDeclaredConst(_isDeclaredConst), m_returnParameters(_returnParameters), m_body(_body), - m_documentation(_documentation) {} + m_documentation(_documentation) + {} + virtual void accept(ASTVisitor& _visitor) override; bool isPublic() const { return m_isPublic; } @@ -194,7 +197,9 @@ public: std::vector> const& getReturnParameters() const { return m_returnParameters->getParameters(); } ASTPointer const& getReturnParameterList() const { return m_returnParameters; } Block& getBody() { return *m_body; } - std::string& getDocumentation() { return m_documentation; } + /// @return A shared pointer of an ASTString. + /// Can contain a nullptr in which case indicates absence of documentation + ASTPointer const& getDocumentation() { return m_documentation; } void addLocalVariable(VariableDeclaration const& _localVariable) { m_localVariables.push_back(&_localVariable); } std::vector const& getLocalVariables() const { return m_localVariables; } @@ -208,7 +213,7 @@ private: bool m_isDeclaredConst; ASTPointer m_returnParameters; ASTPointer m_body; - std::string m_documentation; + ASTPointer m_documentation; std::vector m_localVariables; }; diff --git a/libsolidity/Parser.cpp b/libsolidity/Parser.cpp index 17fd2d78c..72921623a 100644 --- a/libsolidity/Parser.cpp +++ b/libsolidity/Parser.cpp @@ -117,9 +117,13 @@ ASTPointer Parser::parseContractDefinition() ASTPointer Parser::parseFunctionDefinition(bool _isPublic) { ASTNodeFactory nodeFactory(*this); + ASTPointer docstring; expectToken(Token::FUNCTION); - std::string docstring = m_scanner->getCurrentCommentLiteral(); - m_scanner->clearCurrentCommentLiteral(); + if (m_scanner->getCurrentCommentLiteral() != "") + { + docstring = std::make_shared(m_scanner->getCurrentCommentLiteral()); + m_scanner->clearCurrentCommentLiteral(); + } ASTPointer name(expectIdentifierToken()); ASTPointer parameters(parseParameterList()); bool isDeclaredConst = false; diff --git a/test/solidityParser.cpp b/test/solidityParser.cpp index 3a95ec065..89ef0ac0f 100644 --- a/test/solidityParser.cpp +++ b/test/solidityParser.cpp @@ -104,7 +104,7 @@ BOOST_AUTO_TEST_CASE(function_natspec_documentation) BOOST_CHECK_NO_THROW(contract = parseText(text)); auto functions = contract->getDefinedFunctions(); BOOST_CHECK_NO_THROW(function = functions.at(0)); - BOOST_CHECK_EQUAL(function->getDocumentation(), " This is a test function"); + BOOST_CHECK_EQUAL(*function->getDocumentation().get(), " This is a test function"); } BOOST_AUTO_TEST_CASE(function_normal_comments) @@ -119,7 +119,8 @@ BOOST_AUTO_TEST_CASE(function_normal_comments) BOOST_CHECK_NO_THROW(contract = parseText(text)); auto functions = contract->getDefinedFunctions(); BOOST_CHECK_NO_THROW(function = functions.at(0)); - BOOST_CHECK_EQUAL(function->getDocumentation(), ""); + BOOST_CHECK_MESSAGE(function->getDocumentation().get() == nullptr, + "Should not have gotten a Natspect comment for this function"); } BOOST_AUTO_TEST_CASE(multiple_functions_natspec_documentation) @@ -141,16 +142,17 @@ BOOST_AUTO_TEST_CASE(multiple_functions_natspec_documentation) auto functions = contract->getDefinedFunctions(); BOOST_CHECK_NO_THROW(function = functions.at(0)); - BOOST_CHECK_EQUAL(function->getDocumentation(), " This is test function 1"); + BOOST_CHECK_EQUAL(*function->getDocumentation().get(), " This is test function 1"); BOOST_CHECK_NO_THROW(function = functions.at(1)); - BOOST_CHECK_EQUAL(function->getDocumentation(), " This is test function 2"); + BOOST_CHECK_EQUAL(*function->getDocumentation().get(), " This is test function 2"); BOOST_CHECK_NO_THROW(function = functions.at(2)); - BOOST_CHECK_EQUAL(function->getDocumentation(), ""); + BOOST_CHECK_MESSAGE(function->getDocumentation().get() == nullptr, + "Should not have gotten natspec comment for functionName3()"); BOOST_CHECK_NO_THROW(function = functions.at(3)); - BOOST_CHECK_EQUAL(function->getDocumentation(), " This is test function 4"); + BOOST_CHECK_EQUAL(*function->getDocumentation().get(), " This is test function 4"); } BOOST_AUTO_TEST_CASE(multiline_function_documentation) @@ -167,7 +169,7 @@ BOOST_AUTO_TEST_CASE(multiline_function_documentation) auto functions = contract->getDefinedFunctions(); BOOST_CHECK_NO_THROW(function = functions.at(0)); - BOOST_CHECK_EQUAL(function->getDocumentation(), + BOOST_CHECK_EQUAL(*function->getDocumentation().get(), " This is a test function\n" " and it has 2 lines"); } @@ -194,10 +196,10 @@ BOOST_AUTO_TEST_CASE(natspec_comment_in_function_body) auto functions = contract->getDefinedFunctions(); BOOST_CHECK_NO_THROW(function = functions.at(0)); - BOOST_CHECK_EQUAL(function->getDocumentation(), " fun1 description"); + BOOST_CHECK_EQUAL(*function->getDocumentation().get(), " fun1 description"); BOOST_CHECK_NO_THROW(function = functions.at(1)); - BOOST_CHECK_EQUAL(function->getDocumentation(), + BOOST_CHECK_EQUAL(*function->getDocumentation().get(), " This is a test function\n" " and it has 2 lines"); } From 7ac651726f41bef005f163d21a862474a6518ca5 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Fri, 28 Nov 2014 11:17:18 +0100 Subject: [PATCH 48/86] Solidity natspec docstring test improvements - Adding a test for docstring being between function signature and function body - Properly checking for exceptions in parsing - Small parser fix --- libsolidity/Parser.cpp | 2 +- libsolidity/Scanner.h | 3 +- test/solidityParser.cpp | 70 +++++++++++++++++++++++++++-------------- 3 files changed, 49 insertions(+), 26 deletions(-) diff --git a/libsolidity/Parser.cpp b/libsolidity/Parser.cpp index 72921623a..9ed081cce 100644 --- a/libsolidity/Parser.cpp +++ b/libsolidity/Parser.cpp @@ -118,12 +118,12 @@ ASTPointer Parser::parseFunctionDefinition(bool _isPublic) { ASTNodeFactory nodeFactory(*this); ASTPointer docstring; - expectToken(Token::FUNCTION); if (m_scanner->getCurrentCommentLiteral() != "") { docstring = std::make_shared(m_scanner->getCurrentCommentLiteral()); m_scanner->clearCurrentCommentLiteral(); } + expectToken(Token::FUNCTION); ASTPointer name(expectIdentifierToken()); ASTPointer parameters(parseParameterList()); bool isDeclaredConst = false; diff --git a/libsolidity/Scanner.h b/libsolidity/Scanner.h index edec344ac..702310102 100644 --- a/libsolidity/Scanner.h +++ b/libsolidity/Scanner.h @@ -109,8 +109,7 @@ public: class LiteralScope { public: - explicit LiteralScope(Scanner* _self, enum LiteralType _type) - : m_type(_type) + explicit LiteralScope(Scanner* _self, enum LiteralType _type): m_type(_type) , m_scanner(_self) , m_complete(false) { diff --git a/test/solidityParser.cpp b/test/solidityParser.cpp index 89ef0ac0f..e4db2ece7 100644 --- a/test/solidityParser.cpp +++ b/test/solidityParser.cpp @@ -101,10 +101,10 @@ BOOST_AUTO_TEST_CASE(function_natspec_documentation) " /// This is a test function\n" " function functionName(hash hashin) returns (hash hashout) {}\n" "}\n"; - BOOST_CHECK_NO_THROW(contract = parseText(text)); + BOOST_REQUIRE_NO_THROW(contract = parseText(text)); auto functions = contract->getDefinedFunctions(); - BOOST_CHECK_NO_THROW(function = functions.at(0)); - BOOST_CHECK_EQUAL(*function->getDocumentation().get(), " This is a test function"); + BOOST_REQUIRE_NO_THROW(function = functions.at(0)); + BOOST_CHECK_EQUAL(*function->getDocumentation(), " This is a test function"); } BOOST_AUTO_TEST_CASE(function_normal_comments) @@ -116,10 +116,10 @@ BOOST_AUTO_TEST_CASE(function_normal_comments) " // We won't see this comment\n" " function functionName(hash hashin) returns (hash hashout) {}\n" "}\n"; - BOOST_CHECK_NO_THROW(contract = parseText(text)); + BOOST_REQUIRE_NO_THROW(contract = parseText(text)); auto functions = contract->getDefinedFunctions(); - BOOST_CHECK_NO_THROW(function = functions.at(0)); - BOOST_CHECK_MESSAGE(function->getDocumentation().get() == nullptr, + BOOST_REQUIRE_NO_THROW(function = functions.at(0)); + BOOST_CHECK_MESSAGE(function->getDocumentation() == nullptr, "Should not have gotten a Natspect comment for this function"); } @@ -138,21 +138,21 @@ BOOST_AUTO_TEST_CASE(multiple_functions_natspec_documentation) " /// This is test function 4\n" " function functionName4(hash hashin) returns (hash hashout) {}\n" "}\n"; - BOOST_CHECK_NO_THROW(contract = parseText(text)); + BOOST_REQUIRE_NO_THROW(contract = parseText(text)); auto functions = contract->getDefinedFunctions(); - BOOST_CHECK_NO_THROW(function = functions.at(0)); - BOOST_CHECK_EQUAL(*function->getDocumentation().get(), " This is test function 1"); + BOOST_REQUIRE_NO_THROW(function = functions.at(0)); + BOOST_CHECK_EQUAL(*function->getDocumentation(), " This is test function 1"); - BOOST_CHECK_NO_THROW(function = functions.at(1)); - BOOST_CHECK_EQUAL(*function->getDocumentation().get(), " This is test function 2"); + BOOST_REQUIRE_NO_THROW(function = functions.at(1)); + BOOST_CHECK_EQUAL(*function->getDocumentation(), " This is test function 2"); - BOOST_CHECK_NO_THROW(function = functions.at(2)); - BOOST_CHECK_MESSAGE(function->getDocumentation().get() == nullptr, + BOOST_REQUIRE_NO_THROW(function = functions.at(2)); + BOOST_CHECK_MESSAGE(function->getDocumentation() == nullptr, "Should not have gotten natspec comment for functionName3()"); - BOOST_CHECK_NO_THROW(function = functions.at(3)); - BOOST_CHECK_EQUAL(*function->getDocumentation().get(), " This is test function 4"); + BOOST_REQUIRE_NO_THROW(function = functions.at(3)); + BOOST_CHECK_EQUAL(*function->getDocumentation(), " This is test function 4"); } BOOST_AUTO_TEST_CASE(multiline_function_documentation) @@ -165,11 +165,11 @@ BOOST_AUTO_TEST_CASE(multiline_function_documentation) " /// and it has 2 lines\n" " function functionName1(hash hashin) returns (hash hashout) {}\n" "}\n"; - BOOST_CHECK_NO_THROW(contract = parseText(text)); + BOOST_REQUIRE_NO_THROW(contract = parseText(text)); auto functions = contract->getDefinedFunctions(); - BOOST_CHECK_NO_THROW(function = functions.at(0)); - BOOST_CHECK_EQUAL(*function->getDocumentation().get(), + BOOST_REQUIRE_NO_THROW(function = functions.at(0)); + BOOST_CHECK_EQUAL(*function->getDocumentation(), " This is a test function\n" " and it has 2 lines"); } @@ -192,18 +192,42 @@ BOOST_AUTO_TEST_CASE(natspec_comment_in_function_body) " /// and it has 2 lines\n" " function fun(hash hashin) returns (hash hashout) {}\n" "}\n"; - BOOST_CHECK_NO_THROW(contract = parseText(text)); + BOOST_REQUIRE_NO_THROW(contract = parseText(text)); auto functions = contract->getDefinedFunctions(); - BOOST_CHECK_NO_THROW(function = functions.at(0)); - BOOST_CHECK_EQUAL(*function->getDocumentation().get(), " fun1 description"); + BOOST_REQUIRE_NO_THROW(function = functions.at(0)); + BOOST_CHECK_EQUAL(*function->getDocumentation(), " fun1 description"); - BOOST_CHECK_NO_THROW(function = functions.at(1)); - BOOST_CHECK_EQUAL(*function->getDocumentation().get(), + BOOST_REQUIRE_NO_THROW(function = functions.at(1)); + BOOST_CHECK_EQUAL(*function->getDocumentation(), " This is a test function\n" " and it has 2 lines"); } +BOOST_AUTO_TEST_CASE(natspec_docstring_after_signature) +{ + ASTPointer contract; + ASTPointer function; + char const* text = "contract test {\n" + " uint256 stateVar;\n" + " function fun1(uint256 a) {\n" + " /// I should have been above the function signature" + " {\n" + " var b;\n" + " /// I should not interfere with actual natspec comments\n" + " uint256 c;\n" + " mapping(address=>hash) d;\n" + " string name = \"Solidity\";" + " }\n" + "}\n"; + BOOST_REQUIRE_NO_THROW(contract = parseText(text)); + auto functions = contract->getDefinedFunctions(); + + BOOST_REQUIRE_NO_THROW(function = functions.at(0)); + BOOST_CHECK_MESSAGE(!function->getDocumentation(), + "Shouldn't get natspec docstring for this function"); +} + BOOST_AUTO_TEST_CASE(struct_definition) { char const* text = "contract test {\n" From 0238863bfcd13ad98caf87e9fd2aabcdcabeda9d Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 28 Nov 2014 12:44:57 +0100 Subject: [PATCH 49/86] Avoid 20ms sleep time in Whisper. --- libwhisper/WhisperHost.cpp | 6 ++++++ libwhisper/WhisperHost.h | 9 ++++++++- libwhisper/WhisperPeer.cpp | 14 +++++++++----- libwhisper/WhisperPeer.h | 2 ++ 4 files changed, 25 insertions(+), 6 deletions(-) diff --git a/libwhisper/WhisperHost.cpp b/libwhisper/WhisperHost.cpp index 0fb7a206c..9b26e3260 100644 --- a/libwhisper/WhisperHost.cpp +++ b/libwhisper/WhisperHost.cpp @@ -156,6 +156,12 @@ void WhisperHost::uninstallWatch(unsigned _i) m_filters.erase(fit); } +void WhisperHost::doWork() +{ + for (auto& i: peers()) + i->cap()->sendMessages(); +} + void WhisperHost::cleanup() { // remove old messages. diff --git a/libwhisper/WhisperHost.h b/libwhisper/WhisperHost.h index 91934dd98..b38964f8e 100644 --- a/libwhisper/WhisperHost.h +++ b/libwhisper/WhisperHost.h @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include "Common.h" @@ -38,7 +39,7 @@ namespace dev namespace shh { -class WhisperHost: public HostCapability, public Interface +class WhisperHost: public HostCapability, public Interface, public Worker { friend class WhisperPeer; @@ -64,7 +65,13 @@ public: void cleanup(); +protected: + void doWork(); + private: + virtual void onStarting() { startWorking(); } + virtual void onStopping() { stopWorking(); } + void streamMessage(h256 _m, RLPStream& _s) const; void noteChanged(h256 _messageHash, h256 _filter); diff --git a/libwhisper/WhisperPeer.cpp b/libwhisper/WhisperPeer.cpp index 56f4e456e..c3a28e3c3 100644 --- a/libwhisper/WhisperPeer.cpp +++ b/libwhisper/WhisperPeer.cpp @@ -72,7 +72,6 @@ bool WhisperPeer::interpret(unsigned _id, RLP const& _r) for (auto i: _r) if (n++) host()->inject(Envelope(i), this); - sendMessages(); break; } default: @@ -97,10 +96,15 @@ void WhisperPeer::sendMessages() } } - if (!n) - // pause for a bit if no messages to send - this is horrible and broken. - // the message subsystem should really just keep pumping out messages while m_unseen.size() and there's bandwidth for them. - this_thread::sleep_for(chrono::milliseconds(20)); + // the message subsystem should really just keep pumping out messages while m_unseen.size() and there's bandwidth for them. + auto diff = chrono::duration_cast(chrono::system_clock::now() - m_timer); + if (n || diff.count() > 0) + { + RLPStream s; + prep(s, MessagesPacket, n).appendRaw(amalg.out(), n); + sealAndSend(s); + m_timer = chrono::system_clock::now(); + } { RLPStream s; diff --git a/libwhisper/WhisperPeer.h b/libwhisper/WhisperPeer.h index f60de8f01..faac2d870 100644 --- a/libwhisper/WhisperPeer.h +++ b/libwhisper/WhisperPeer.h @@ -68,6 +68,8 @@ private: mutable dev::Mutex x_unseen; std::map m_unseen; ///< Rated according to what they want. + + std::chrono::system_clock::time_point m_timer = std::chrono::system_clock::now(); }; } From fa78d8bb9acba0f1fa0559a36191a0a80c0deb6b Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 28 Nov 2014 13:14:56 +0100 Subject: [PATCH 50/86] Remove minGasPrice --- alethzero/MainWin.cpp | 1 - eth/main.cpp | 6 +----- libethcore/BlockInfo.cpp | 18 +++++++----------- libethcore/BlockInfo.h | 4 +--- libethcore/CommonEth.cpp | 2 +- libethereum/BlockChain.cpp | 4 ++-- libethereum/Executive.cpp | 7 ------- libethereum/State.cpp | 1 - libweb3jsonrpc/WebThreeStubServer.cpp | 1 - neth/main.cpp | 12 ++++-------- 10 files changed, 16 insertions(+), 40 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index e5506a660..d4a122732 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -1259,7 +1259,6 @@ void Main::on_blocks_currentItemChanged() s << "
D/TD: 2^" << log2((double)info.difficulty) << "/2^" << log2((double)details.totalDifficulty) << ""; s << "   Children: " << details.children.size() << ""; s << "
Gas used/limit: " << info.gasUsed << "/" << info.gasLimit << ""; - s << "   Minimum gas price: " << formatBalance(info.minGasPrice) << ""; s << "
Coinbase: " << pretty(info.coinbaseAddress).toHtmlEscaped().toStdString() << " " << info.coinbaseAddress; s << "
Nonce: " << info.nonce << ""; s << "
Parent: " << info.parentHash << ""; diff --git a/eth/main.cpp b/eth/main.cpp index 408654018..be1a4ae65 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -498,8 +498,6 @@ int main(int argc, char** argv) if (size > 0) cwarn << "Invalid address length:" << size; } - else if (gasPrice < info.minGasPrice) - cwarn << "Minimum gas price is" << info.minGasPrice; else if (gas < minGas) cwarn << "Minimum gas amount is" << minGas; else if (ssize < 40) @@ -561,7 +559,7 @@ int main(int argc, char** argv) BlockInfo info(blockData); u256 minGas = (u256)Client::txGas(0, 0); Address dest = h160(fromHex(hexAddr)); - c->transact(us.secret(), amount, dest, bytes(), minGas, info.minGasPrice); + c->transact(us.secret(), amount, dest, bytes(), minGas); } } else @@ -601,8 +599,6 @@ int main(int argc, char** argv) u256 minGas = (u256)Client::txGas(init.size(), 0); if (endowment < 0) cwarn << "Invalid endowment"; - else if (gasPrice < info.minGasPrice) - cwarn << "Minimum gas price is" << info.minGasPrice; else if (gas < minGas) cwarn << "Minimum gas amount is" << minGas; else diff --git a/libethcore/BlockInfo.cpp b/libethcore/BlockInfo.cpp index 44da9603c..015f8dad6 100644 --- a/libethcore/BlockInfo.cpp +++ b/libethcore/BlockInfo.cpp @@ -58,9 +58,9 @@ h256 BlockInfo::headerHashWithoutNonce() const void BlockInfo::streamRLP(RLPStream& _s, bool _nonce) const { - _s.appendList(_nonce ? 15 : 14) + _s.appendList(_nonce ? 14 : 13) << parentHash << sha3Uncles << coinbaseAddress << stateRoot << transactionsRoot << receiptsRoot << logBloom - << difficulty << number << minGasPrice << gasLimit << gasUsed << timestamp << extraData; + << difficulty << number << gasLimit << gasUsed << timestamp << extraData; if (_nonce) _s << nonce; } @@ -86,12 +86,11 @@ void BlockInfo::populateFromHeader(RLP const& _header, bool _checkNonce) logBloom = _header[field = 6].toHash(); difficulty = _header[field = 7].toInt(); number = _header[field = 8].toInt(); - minGasPrice = _header[field = 9].toInt(); - gasLimit = _header[field = 10].toInt(); - gasUsed = _header[field = 11].toInt(); - timestamp = _header[field = 12].toInt(); - extraData = _header[field = 13].toBytes(); - nonce = _header[field = 14].toHash(); + gasLimit = _header[field = 9].toInt(); + gasUsed = _header[field = 10].toInt(); + timestamp = _header[field = 11].toInt(); + extraData = _header[field = 12].toBytes(); + nonce = _header[field = 13].toHash(); } catch (Exception const& _e) @@ -147,9 +146,6 @@ void BlockInfo::verifyInternals(bytesConstRef _block) const if (transactionsRoot != t.root()) BOOST_THROW_EXCEPTION(InvalidTransactionsHash(t.root(), transactionsRoot)); - if (minGasPrice > mgp) - BOOST_THROW_EXCEPTION(InvalidMinGasPrice(minGasPrice, mgp)); - if (sha3Uncles != sha3(root[2].data())) BOOST_THROW_EXCEPTION(InvalidUnclesHash()); } diff --git a/libethcore/BlockInfo.h b/libethcore/BlockInfo.h index d91ff244d..aa7456f72 100644 --- a/libethcore/BlockInfo.h +++ b/libethcore/BlockInfo.h @@ -66,7 +66,6 @@ public: h512 logBloom; // TODO LogBloom - get include u256 difficulty; u256 number; - u256 minGasPrice; u256 gasLimit; u256 gasUsed; u256 timestamp; @@ -95,7 +94,6 @@ public: logBloom == _cmp.logBloom && difficulty == _cmp.difficulty && number == _cmp.number && - minGasPrice == _cmp.minGasPrice && gasLimit == _cmp.gasLimit && gasUsed == _cmp.gasUsed && timestamp == _cmp.timestamp && @@ -122,7 +120,7 @@ public: inline std::ostream& operator<<(std::ostream& _out, BlockInfo const& _bi) { _out << _bi.hash << " " << _bi.parentHash << " " << _bi.sha3Uncles << " " << _bi.coinbaseAddress << " " << _bi.stateRoot << " " << _bi.transactionsRoot << " " << - _bi.receiptsRoot << " " << _bi.logBloom << " " << _bi.difficulty << " " << _bi.number << " " << _bi.minGasPrice << " " << _bi.gasLimit << " " << + _bi.receiptsRoot << " " << _bi.logBloom << " " << _bi.difficulty << " " << _bi.number << " " << _bi.gasLimit << " " << _bi.gasUsed << " " << _bi.timestamp << " " << _bi.nonce; return _out; } diff --git a/libethcore/CommonEth.cpp b/libethcore/CommonEth.cpp index c12c71774..610d141ed 100644 --- a/libethcore/CommonEth.cpp +++ b/libethcore/CommonEth.cpp @@ -33,7 +33,7 @@ namespace dev namespace eth { -const unsigned c_protocolVersion = 44; +const unsigned c_protocolVersion = 45; const unsigned c_databaseVersion = 4; static const vector> g_units = diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 765b54627..264cdbd57 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -101,9 +101,9 @@ bytes BlockChain::createGenesisBlock() stateRoot = state.root(); } - block.appendList(15) + block.appendList(14) // TODO: maybe make logbloom correct? - << h256() << EmptyListSHA3 << h160() << stateRoot << EmptyTrie << EmptyTrie << LogBloom() << c_genesisDifficulty << 0 << 0 << 1000000 << 0 << (unsigned)0 << string() << sha3(bytes(1, 42)); + << h256() << EmptyListSHA3 << h160() << stateRoot << EmptyTrie << EmptyTrie << LogBloom() << c_genesisDifficulty << 0 << 0 << 0 << (unsigned)0 << string() << sha3(bytes(1, 42)); block.appendRaw(RLPEmptyList); block.appendRaw(RLPEmptyList); return block.out(); diff --git a/libethereum/Executive.cpp b/libethereum/Executive.cpp index c3a8b2a80..ac557e198 100644 --- a/libethereum/Executive.cpp +++ b/libethereum/Executive.cpp @@ -58,13 +58,6 @@ bool Executive::setup(bytesConstRef _rlp) BOOST_THROW_EXCEPTION(InvalidNonce(nonceReq, m_t.nonce())); } - // Don't like transactions whose gas price is too low. NOTE: this won't stay here forever - it's just until we get a proper gas price discovery protocol going. - if (m_t.gasPrice() < m_s.m_currentBlock.minGasPrice) - { - clog(StateDetail) << "Offered gas-price is too low: Require >" << m_s.m_currentBlock.minGasPrice << " Got" << m_t.gasPrice(); - BOOST_THROW_EXCEPTION(GasPriceTooLow()); - } - // Check gas cost is enough. u256 gasCost = m_t.data().size() * c_txDataGas + c_txGas; diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 40327b108..8cd53e912 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -501,7 +501,6 @@ void State::resetCurrent() m_currentBlock.timestamp = time(0); m_currentBlock.transactionsRoot = h256(); m_currentBlock.sha3Uncles = h256(); - m_currentBlock.minGasPrice = 10 * szabo; m_currentBlock.populateFromParent(m_previousBlock); // Update timestamp according to clock. diff --git a/libweb3jsonrpc/WebThreeStubServer.cpp b/libweb3jsonrpc/WebThreeStubServer.cpp index 8ee9ee722..7607b7a95 100644 --- a/libweb3jsonrpc/WebThreeStubServer.cpp +++ b/libweb3jsonrpc/WebThreeStubServer.cpp @@ -51,7 +51,6 @@ static Json::Value toJson(dev::eth::BlockInfo const& _bi) res["transactionsRoot"] = toJS(_bi.transactionsRoot); res["difficulty"] = toJS(_bi.difficulty); res["number"] = (int)_bi.number; - res["minGasPrice"] = toJS(_bi.minGasPrice); res["gasLimit"] = (int)_bi.gasLimit; res["timestamp"] = (int)_bi.timestamp; res["extraData"] = jsFromBinary(_bi.extraData); diff --git a/neth/main.cpp b/neth/main.cpp index 6be555fbb..e3a27c1d8 100644 --- a/neth/main.cpp +++ b/neth/main.cpp @@ -603,7 +603,7 @@ int main(int argc, char** argv) vector l; l.push_back("Amount"); stringstream label; - label << "Gas price (" << info.minGasPrice << ")"; + label << "Gas price"; l.push_back(label.str()); l.push_back("Gas"); vector b; @@ -652,8 +652,6 @@ int main(int argc, char** argv) if (size > 0) cwarn << "Invalid address length:" << size; } - else if (gasPrice < info.minGasPrice) - cwarn << "Minimum gas price is" << info.minGasPrice; else if (gas < minGas) cwarn << "Minimum gas amount is" << minGas; else if (ssize < 40) @@ -704,7 +702,7 @@ int main(int argc, char** argv) BlockInfo info(blockData); u256 minGas = (u256)Client::txGas(0, 0); Address dest = h160(fromHex(fields[0])); - c.transact(us.secret(), amount, dest, bytes(), minGas, info.minGasPrice); + c.transact(us.secret(), amount, dest, bytes(), minGas, 10 * dev::eth::szabo); } } } @@ -718,7 +716,7 @@ int main(int argc, char** argv) vector l; l.push_back("Endowment"); stringstream label; - label << "Gas price (" << info.minGasPrice << ")"; + label << "Gas price"; l.push_back(label.str()); l.push_back("Gas"); vector b; @@ -766,13 +764,11 @@ int main(int argc, char** argv) u256 minGas = (u256)Client::txGas(init.size(), 0); if (endowment < 0) cwarn << "Invalid endowment"; - else if (gasPrice < info.minGasPrice) - cwarn << "Minimum gas price is" << info.minGasPrice; else if (gas < minGas) cwarn << "Minimum gas amount is" << minGas; else { - c.transact(us.secret(), endowment, init, gas, gasPrice); + c.transact(us.secret(), endowment, init, gas, 10 * dev::eth::szabo); } } } From d9bdfe5b4dd7a81d0a37c138cf80ae1b38f6a87e Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 28 Nov 2014 14:22:50 +0100 Subject: [PATCH 51/86] Latest PoC-7 changes. --- alethzero/MainWin.cpp | 6 +++--- eth/main.cpp | 6 +++--- libethereum/Executive.cpp | 7 ++++--- libethereum/Interface.h | 2 +- libevm/FeeStructure.cpp | 4 +++- libevm/FeeStructure.h | 4 +++- libevm/VM.h | 5 +++++ neth/main.cpp | 10 +++++----- 8 files changed, 27 insertions(+), 17 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index d4a122732..fc27d6e30 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -1664,7 +1664,7 @@ void Main::on_data_textChanged() errs.append("
" + QString::fromStdString(i).toHtmlEscaped() + "
"); } ui->code->setHtml(errs + lll + solidity + "

Code

" + QString::fromStdString(disassemble(m_data)).toHtmlEscaped()); - ui->gas->setMinimum((qint64)Client::txGas(m_data.size(), 0)); + ui->gas->setMinimum((qint64)Client::txGas(m_data, 0)); if (!ui->gas->isEnabled()) ui->gas->setValue(m_backupGas); ui->gas->setEnabled(true); @@ -1675,7 +1675,7 @@ void Main::on_data_textChanged() ui->code->setHtml(QString::fromStdString(dev::memDump(m_data, 8, true))); if (ethereum()->codeAt(fromString(ui->destination->currentText()), 0).size()) { - ui->gas->setMinimum((qint64)Client::txGas(m_data.size(), 1)); + ui->gas->setMinimum((qint64)Client::txGas(m_data, 1)); if (!ui->gas->isEnabled()) ui->gas->setValue(m_backupGas); ui->gas->setEnabled(true); @@ -1684,7 +1684,7 @@ void Main::on_data_textChanged() { if (ui->gas->isEnabled()) m_backupGas = ui->gas->value(); - ui->gas->setValue((qint64)Client::txGas(m_data.size())); + ui->gas->setValue((qint64)Client::txGas(m_data)); ui->gas->setEnabled(false); } } diff --git a/eth/main.cpp b/eth/main.cpp index be1a4ae65..9b63e0643 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -492,7 +492,7 @@ int main(int argc, char** argv) cnote << ssbd.str(); int ssize = sechex.length(); int size = hexAddr.length(); - u256 minGas = (u256)Client::txGas(data.size(), 0); + u256 minGas = (u256)Client::txGas(data, 0); if (size < 40) { if (size > 0) @@ -557,7 +557,7 @@ int main(int argc, char** argv) auto h = bc.currentHash(); auto blockData = bc.block(h); BlockInfo info(blockData); - u256 minGas = (u256)Client::txGas(0, 0); + u256 minGas = (u256)Client::txGas(bytes(), 0); Address dest = h160(fromHex(hexAddr)); c->transact(us.secret(), amount, dest, bytes(), minGas); } @@ -596,7 +596,7 @@ int main(int argc, char** argv) cnote << "Init:"; cnote << ssc.str(); } - u256 minGas = (u256)Client::txGas(init.size(), 0); + u256 minGas = (u256)Client::txGas(init, 0); if (endowment < 0) cwarn << "Invalid endowment"; else if (gas < minGas) diff --git a/libethereum/Executive.cpp b/libethereum/Executive.cpp index ac557e198..6a123875c 100644 --- a/libethereum/Executive.cpp +++ b/libethereum/Executive.cpp @@ -22,6 +22,7 @@ #include #include #include +#include "Interface.h" #include "Executive.h" #include "State.h" #include "ExtVM.h" @@ -59,7 +60,7 @@ bool Executive::setup(bytesConstRef _rlp) } // Check gas cost is enough. - u256 gasCost = m_t.data().size() * c_txDataGas + c_txGas; + auto gasCost = Interface::txGas(m_t.data()); if (m_t.gas() < gasCost) { @@ -99,9 +100,9 @@ bool Executive::setup(bytesConstRef _rlp) } if (m_t.isCreation()) - return create(m_sender, m_t.value(), m_t.gasPrice(), m_t.gas() - gasCost, &m_t.data(), m_sender); + return create(m_sender, m_t.value(), m_t.gasPrice(), m_t.gas() - (u256)gasCost, &m_t.data(), m_sender); else - return call(m_t.receiveAddress(), m_sender, m_t.value(), m_t.gasPrice(), bytesConstRef(&m_t.data()), m_t.gas() - gasCost, m_sender); + return call(m_t.receiveAddress(), m_sender, m_t.value(), m_t.gasPrice(), bytesConstRef(&m_t.data()), m_t.gas() - (u256)gasCost, m_sender); } bool Executive::call(Address _receiveAddress, Address _senderAddress, u256 _value, u256 _gasPrice, bytesConstRef _data, u256 _gas, Address _originAddress) diff --git a/libethereum/Interface.h b/libethereum/Interface.h index add9a1bda..d598e1f9b 100644 --- a/libethereum/Interface.h +++ b/libethereum/Interface.h @@ -128,7 +128,7 @@ public: virtual Addresses addresses(int _block) const = 0; /// Get the fee associated for a transaction with the given data. - static u256 txGas(unsigned _dataCount, u256 _gas = 0) { return c_txDataGas * _dataCount + c_txGas + _gas; } + template static bigint txGas(T const& _data, u256 _gas = 0) { bigint ret = c_txGas + _gas; for (auto i: _data) ret += i ? c_txDataNonZeroGas : c_txDataZeroGas; return ret; } /// Get the remaining gas limit in this block. virtual u256 gasLimitRemaining() const = 0; diff --git a/libevm/FeeStructure.cpp b/libevm/FeeStructure.cpp index 6d868cac5..59a5329bc 100644 --- a/libevm/FeeStructure.cpp +++ b/libevm/FeeStructure.cpp @@ -35,8 +35,10 @@ u256 const dev::eth::c_sstoreRefundGas = 100; u256 const dev::eth::c_createGas = 100; u256 const dev::eth::c_callGas = 20; u256 const dev::eth::c_memoryGas = 1; -u256 const dev::eth::c_txDataGas = 5; +u256 const dev::eth::c_txDataZeroGas = 1; +u256 const dev::eth::c_txDataNonZeroGas = 5; u256 const dev::eth::c_txGas = 500; u256 const dev::eth::c_logGas = 32; u256 const dev::eth::c_logDataGas = 1; u256 const dev::eth::c_logTopicGas = 32; +u256 const dev::eth::c_copyGas = 1; diff --git a/libevm/FeeStructure.h b/libevm/FeeStructure.h index e57f7ccf8..4f415da5d 100644 --- a/libevm/FeeStructure.h +++ b/libevm/FeeStructure.h @@ -38,11 +38,13 @@ extern u256 const c_sstoreRefundGas; ///< Refunded gas, once per SSTORE operatio extern u256 const c_createGas; ///< Once per CREATE operation & contract-creation transaction. extern u256 const c_callGas; ///< Once per CALL operation & message call transaction. extern u256 const c_memoryGas; ///< Times the address of the (highest referenced byte in memory + 1). NOTE: referencing happens on read, write and in instructions such as RETURN and CALL. -extern u256 const c_txDataGas; ///< Per byte of data attached to a transaction. NOTE: Not payable on data of calls between transactions. +extern u256 const c_txDataZeroGas; ///< Per byte of data attached to a transaction that equals zero. NOTE: Not payable on data of calls between transactions. +extern u256 const c_txDataNonZeroGas; ///< Per byte of data attached to a transaction that is not equal to zero. NOTE: Not payable on data of calls between transactions. extern u256 const c_txGas; ///< Per transaction. NOTE: Not payable on data of calls between transactions. extern u256 const c_logGas; ///< Per LOG* operation. extern u256 const c_logDataGas; ///< Per byte in a LOG* operation's data. extern u256 const c_logTopicGas; ///< Multiplied by the * of the LOG*, per LOG transaction. e.g. LOG0 incurs 0 * c_txLogTopicGas, LOG4 incurs 4 * c_txLogTopicGas. +extern u256 const c_copyGas; ///< Multiplied by the number of 32-byte words that are copied (round up) for any *COPY operation and added. } } diff --git a/libevm/VM.h b/libevm/VM.h index 425eab8c8..9d43d7177 100644 --- a/libevm/VM.h +++ b/libevm/VM.h @@ -131,6 +131,7 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con // FEES... bigint runGas = c_stepGas; bigint newTempSize = m_temp.size(); + bigint copySize = 0; auto onOperation = [&]() { @@ -193,14 +194,17 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con break; case Instruction::CALLDATACOPY: require(3); + copySize = m_stack[m_stack.size() - 3]; newTempSize = memNeed(m_stack.back(), m_stack[m_stack.size() - 3]); break; case Instruction::CODECOPY: require(3); + copySize = m_stack[m_stack.size() - 3]; newTempSize = memNeed(m_stack.back(), m_stack[m_stack.size() - 3]); break; case Instruction::EXTCODECOPY: require(4); + copySize = m_stack[m_stack.size() - 4]; newTempSize = memNeed(m_stack[m_stack.size() - 2], m_stack[m_stack.size() - 4]); break; @@ -365,6 +369,7 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con newTempSize = (newTempSize + 31) / 32 * 32; if (newTempSize > m_temp.size()) runGas += c_memoryGas * (newTempSize - m_temp.size()) / 32; + runGas += c_copyGas * (copySize + 31) / 32; onOperation(); // if (_onOp) diff --git a/neth/main.cpp b/neth/main.cpp index e3a27c1d8..cb6d35593 100644 --- a/neth/main.cpp +++ b/neth/main.cpp @@ -646,7 +646,7 @@ int main(int argc, char** argv) ssbd << bbd; cnote << ssbd.str(); int ssize = fields[4].length(); - u256 minGas = (u256)Client::txGas(data.size(), 0); + u256 minGas = (u256)Client::txGas(data, 0); if (size < 40) { if (size > 0) @@ -700,9 +700,9 @@ int main(int argc, char** argv) auto h = bc.currentHash(); auto blockData = bc.block(h); BlockInfo info(blockData); - u256 minGas = (u256)Client::txGas(0, 0); + u256 minGas = (u256)Client::txGas(bytes(), 0); Address dest = h160(fromHex(fields[0])); - c.transact(us.secret(), amount, dest, bytes(), minGas, 10 * dev::eth::szabo); + c.transact(us.secret(), amount, dest, bytes(), minGas); } } } @@ -761,14 +761,14 @@ int main(int argc, char** argv) cnote << "Init:"; cnote << ssc.str(); } - u256 minGas = (u256)Client::txGas(init.size(), 0); + u256 minGas = (u256)Client::txGas(init, 0); if (endowment < 0) cwarn << "Invalid endowment"; else if (gas < minGas) cwarn << "Minimum gas amount is" << minGas; else { - c.transact(us.secret(), endowment, init, gas, 10 * dev::eth::szabo); + c.transact(us.secret(), endowment, init, gas); } } } From 362e5d81450825b019e0f95c3a8f418f1545de5f Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 28 Nov 2014 14:28:02 +0100 Subject: [PATCH 52/86] Warning fix. ECDSA recover fix. --- libethereum/State.cpp | 2 +- libsolidity/ExpressionCompiler.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 8cd53e912..9a0426e18 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -54,7 +54,7 @@ void ecrecoverCode(bytesConstRef _in, bytesRef _out) memcpy(&in, _in.data(), min(_in.size(), sizeof(in))); memset(_out.data(), 0, _out.size()); - if (in.v > 28) + if ((u256)in.v > 28) return; SignatureStruct sig{in.r, in.s, (byte)((int)(u256)in.v - 27)}; if (!sig.isValid()) diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index 4dc377791..c3c7116e4 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -363,7 +363,7 @@ void ExpressionCompiler::endVisit(Identifier& _identifier) m_context << m_context.getFunctionEntryLabel(*functionDef).pushTag(); return; } - if (VariableDeclaration* varDef = dynamic_cast(declaration)) + if (/*VariableDeclaration* varDef = */dynamic_cast(declaration)) { m_currentLValue.fromIdentifier(_identifier, *_identifier.getReferencedDeclaration()); m_currentLValue.retrieveValueIfLValueNotRequested(_identifier); From 0e391e50a214537431deeab6dd21868ab8d641d6 Mon Sep 17 00:00:00 2001 From: yann300 Date: Fri, 28 Nov 2014 14:52:08 +0100 Subject: [PATCH 53/86] misc corrections --- mix/ApplicationCtx.cpp | 6 ++++++ mix/ApplicationCtx.h | 4 ++-- mix/CodeEditorExtensionManager.cpp | 11 +++++------ mix/CodeEditorExtensionManager.h | 2 +- mix/ConstantCompilationCtrl.cpp | 2 +- mix/ConstantCompilationCtrl.h | 4 ++-- mix/Extension.h | 2 +- mix/MixApplication.cpp | 4 ++++ mix/MixApplication.h | 2 +- 9 files changed, 23 insertions(+), 14 deletions(-) diff --git a/mix/ApplicationCtx.cpp b/mix/ApplicationCtx.cpp index 8ea8bd8d8..5b8c34aaf 100644 --- a/mix/ApplicationCtx.cpp +++ b/mix/ApplicationCtx.cpp @@ -28,3 +28,9 @@ QQmlApplicationEngine* ApplicationCtx::appEngine() { return m_applicationEngine; } + +void ApplicationCtx::setApplicationContext(QQmlApplicationEngine* _engine) +{ + if (Instance == nullptr) + Instance = new ApplicationCtx(_engine); +} diff --git a/mix/ApplicationCtx.h b/mix/ApplicationCtx.h index 32e2bd3f1..3938c7bf5 100644 --- a/mix/ApplicationCtx.h +++ b/mix/ApplicationCtx.h @@ -31,7 +31,7 @@ namespace dev namespace mix { -class ApplicationCtx : public QObject +class ApplicationCtx: public QObject { Q_OBJECT @@ -39,7 +39,7 @@ public: ApplicationCtx(QQmlApplicationEngine* _engine) { m_applicationEngine = _engine; } ~ApplicationCtx() { delete m_applicationEngine; } static ApplicationCtx* getInstance() { return Instance; } - static void setApplicationContext(QQmlApplicationEngine* _engine) { Instance = new ApplicationCtx(_engine); } + static void setApplicationContext(QQmlApplicationEngine* _engine); QQmlApplicationEngine* appEngine(); private: diff --git a/mix/CodeEditorExtensionManager.cpp b/mix/CodeEditorExtensionManager.cpp index 316c37ee0..92400cd63 100644 --- a/mix/CodeEditorExtensionManager.cpp +++ b/mix/CodeEditorExtensionManager.cpp @@ -62,13 +62,12 @@ void CodeEditorExtensionManager::loadEditor(QQuickItem* _editor) void CodeEditorExtensionManager::initExtensions() { //only one for now - std::shared_ptr m_constantCompilation(new ConstantCompilationCtrl(m_doc)); - ConstantCompilationCtrl* ext = m_constantCompilation.get(); - if (ext->contentUrl() != "") + std::shared_ptr constantCompilation = std::make_shared(m_doc); + if (constantCompilation.get()->contentUrl() != "") { try { - ext->addContentOn(m_tabView); + constantCompilation.get()->addContentOn(m_tabView); } catch (...) { @@ -76,8 +75,8 @@ void CodeEditorExtensionManager::initExtensions() return; } } - ext->start(); - m_features.append(m_constantCompilation); + constantCompilation.get()->start(); + m_features.append(constantCompilation); } void CodeEditorExtensionManager::setEditor(QQuickItem* _editor) diff --git a/mix/CodeEditorExtensionManager.h b/mix/CodeEditorExtensionManager.h index c368a9714..1d8fb1ec5 100644 --- a/mix/CodeEditorExtensionManager.h +++ b/mix/CodeEditorExtensionManager.h @@ -34,7 +34,7 @@ namespace dev namespace mix { -class CodeEditorExtensionManager : public QObject +class CodeEditorExtensionManager: public QObject { Q_OBJECT diff --git a/mix/ConstantCompilationCtrl.cpp b/mix/ConstantCompilationCtrl.cpp index 0f73da781..2c42a28dd 100644 --- a/mix/ConstantCompilationCtrl.cpp +++ b/mix/ConstantCompilationCtrl.cpp @@ -76,7 +76,7 @@ void ConstantCompilationCtrl::resetOutPut() content->setProperty("text", ""); } -void ConstantCompilationCtrl::writeOutPut(CompilerResult _res) +void ConstantCompilationCtrl::writeOutPut(const CompilerResult& _res) { QObject* status = m_view->findChild("status", Qt::FindChildrenRecursively); QObject* content = m_view->findChild("content", Qt::FindChildrenRecursively); diff --git a/mix/ConstantCompilationCtrl.h b/mix/ConstantCompilationCtrl.h index 3bb221b3d..af7c97951 100644 --- a/mix/ConstantCompilationCtrl.h +++ b/mix/ConstantCompilationCtrl.h @@ -29,7 +29,7 @@ namespace dev namespace mix { -class ConstantCompilationCtrl : public Extension +class ConstantCompilationCtrl: public Extension { Q_OBJECT @@ -43,7 +43,7 @@ public: private: QTextDocument* m_editor; ConstantCompilationModel* m_compilationModel; - void writeOutPut(CompilerResult); + void writeOutPut(const CompilerResult&); void resetOutPut(); public Q_SLOTS: diff --git a/mix/Extension.h b/mix/Extension.h index 3a401eeeb..0678fdd5b 100644 --- a/mix/Extension.h +++ b/mix/Extension.h @@ -28,7 +28,7 @@ namespace dev namespace mix { -class Extension : public QObject +class Extension: public QObject { Q_OBJECT diff --git a/mix/MixApplication.cpp b/mix/MixApplication.cpp index fa9feadb5..634b3142a 100644 --- a/mix/MixApplication.cpp +++ b/mix/MixApplication.cpp @@ -38,5 +38,9 @@ bool MixApplication::notify(QObject* _receiver, QEvent* _event) { qDebug() << "std::exception was caught " << _ex.what(); } + catch (...) + { + qDebug() << "uncaught exception "; + } return false; } diff --git a/mix/MixApplication.h b/mix/MixApplication.h index 3f4ace5a6..ba344fcdc 100644 --- a/mix/MixApplication.h +++ b/mix/MixApplication.h @@ -31,7 +31,7 @@ namespace dev namespace mix { -class MixApplication : public QApplication +class MixApplication: public QApplication { Q_OBJECT From 6ee69c2141ecdc513612e7194587fa684047f134 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 28 Nov 2014 15:40:01 +0100 Subject: [PATCH 54/86] Version bump. --- libdevcore/Common.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libdevcore/Common.cpp b/libdevcore/Common.cpp index ae073b9b1..280268d8b 100644 --- a/libdevcore/Common.cpp +++ b/libdevcore/Common.cpp @@ -27,7 +27,7 @@ using namespace dev; namespace dev { -char const* Version = "0.7.10"; +char const* Version = "0.7.11"; } From 369268c0cedf0e0e4a7dfb8175ed35cd2989b235 Mon Sep 17 00:00:00 2001 From: yann300 Date: Sat, 29 Nov 2014 01:02:12 +0100 Subject: [PATCH 55/86] tab indentation --- mix/ApplicationCtx.cpp | 28 ++++----- mix/ApplicationCtx.h | 40 ++++++------- mix/CodeEditorExtensionManager.cpp | 94 +++++++++++++++--------------- mix/CodeEditorExtensionManager.h | 48 +++++++-------- mix/ConstantCompilationCtrl.cpp | 92 ++++++++++++++--------------- mix/ConstantCompilationCtrl.h | 44 +++++++------- mix/ConstantCompilationModel.cpp | 72 +++++++++++------------ mix/ConstantCompilationModel.h | 34 +++++------ mix/Extension.cpp | 44 +++++++------- mix/Extension.h | 36 ++++++------ mix/MixApplication.cpp | 50 ++++++++-------- mix/MixApplication.h | 30 +++++----- mix/main.cpp | 36 ++++++------ mix/qml/BasicContent.qml | 3 +- 14 files changed, 326 insertions(+), 325 deletions(-) diff --git a/mix/ApplicationCtx.cpp b/mix/ApplicationCtx.cpp index 5b8c34aaf..f97478f3c 100644 --- a/mix/ApplicationCtx.cpp +++ b/mix/ApplicationCtx.cpp @@ -1,15 +1,15 @@ /* - 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 . + 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 ApplicationCtx.cpp * @author Yann yann@ethdev.com @@ -26,11 +26,11 @@ ApplicationCtx* ApplicationCtx::Instance = nullptr; QQmlApplicationEngine* ApplicationCtx::appEngine() { - return m_applicationEngine; + return m_applicationEngine; } void ApplicationCtx::setApplicationContext(QQmlApplicationEngine* _engine) { - if (Instance == nullptr) - Instance = new ApplicationCtx(_engine); + if (Instance == nullptr) + Instance = new ApplicationCtx(_engine); } diff --git a/mix/ApplicationCtx.h b/mix/ApplicationCtx.h index 3938c7bf5..37166ea05 100644 --- a/mix/ApplicationCtx.h +++ b/mix/ApplicationCtx.h @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + 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 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. + 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 . + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . */ /** @file ApplicationCtx.h * @author Yann yann@ethdev.com @@ -33,21 +33,21 @@ namespace mix class ApplicationCtx: public QObject { - Q_OBJECT + Q_OBJECT public: - ApplicationCtx(QQmlApplicationEngine* _engine) { m_applicationEngine = _engine; } - ~ApplicationCtx() { delete m_applicationEngine; } - static ApplicationCtx* getInstance() { return Instance; } - static void setApplicationContext(QQmlApplicationEngine* _engine); - QQmlApplicationEngine* appEngine(); + ApplicationCtx(QQmlApplicationEngine* _engine) { m_applicationEngine = _engine; } + ~ApplicationCtx() { delete m_applicationEngine; } + static ApplicationCtx* getInstance() { return Instance; } + static void setApplicationContext(QQmlApplicationEngine* _engine); + QQmlApplicationEngine* appEngine(); private: - static ApplicationCtx* Instance; - QQmlApplicationEngine* m_applicationEngine; + static ApplicationCtx* Instance; + QQmlApplicationEngine* m_applicationEngine; public slots: - void quitApplication() { delete Instance; } + void quitApplication() { delete Instance; } }; } diff --git a/mix/CodeEditorExtensionManager.cpp b/mix/CodeEditorExtensionManager.cpp index 92400cd63..4a46c60d4 100644 --- a/mix/CodeEditorExtensionManager.cpp +++ b/mix/CodeEditorExtensionManager.cpp @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + 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 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. + 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 . + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . */ /** @file CodeEditorExtensionMan.cpp * @author Yann yann@ethdev.com @@ -36,56 +36,56 @@ using namespace dev::mix; CodeEditorExtensionManager::~CodeEditorExtensionManager() { - m_features.clear(); + m_features.clear(); } void CodeEditorExtensionManager::loadEditor(QQuickItem* _editor) { - if (!_editor) - return; - try - { - QVariant doc = _editor->property("textDocument"); - if (doc.canConvert()) - { - QQuickTextDocument* qqdoc = doc.value(); - if (qqdoc) - m_doc = qqdoc->textDocument(); - } - } - catch (...) - { - qDebug() << "unable to load editor: "; - } + if (!_editor) + return; + try + { + QVariant doc = _editor->property("textDocument"); + if (doc.canConvert()) + { + QQuickTextDocument* qqdoc = doc.value(); + if (qqdoc) + m_doc = qqdoc->textDocument(); + } + } + catch (...) + { + qDebug() << "unable to load editor: "; + } } void CodeEditorExtensionManager::initExtensions() { - //only one for now - std::shared_ptr constantCompilation = std::make_shared(m_doc); - if (constantCompilation.get()->contentUrl() != "") - { - try - { - constantCompilation.get()->addContentOn(m_tabView); - } - catch (...) - { - qDebug() << "Exception when adding content into view."; - return; - } - } - constantCompilation.get()->start(); - m_features.append(constantCompilation); + //only one for now + std::shared_ptr constantCompilation = std::make_shared(m_doc); + if (constantCompilation.get()->contentUrl() != "") + { + try + { + constantCompilation.get()->addContentOn(m_tabView); + } + catch (...) + { + qDebug() << "Exception when adding content into view."; + return; + } + } + constantCompilation.get()->start(); + m_features.append(constantCompilation); } void CodeEditorExtensionManager::setEditor(QQuickItem* _editor) { - this->loadEditor(_editor); - this->initExtensions(); + this->loadEditor(_editor); + this->initExtensions(); } void CodeEditorExtensionManager::setTabView(QQuickItem* _tabView) { - m_tabView = _tabView; + m_tabView = _tabView; } diff --git a/mix/CodeEditorExtensionManager.h b/mix/CodeEditorExtensionManager.h index 1d8fb1ec5..2b8402bf2 100644 --- a/mix/CodeEditorExtensionManager.h +++ b/mix/CodeEditorExtensionManager.h @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + 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 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. + 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 . + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . */ /** @file CodeEditorExtensionMan.h * @author Yann yann@ethdev.com @@ -36,24 +36,24 @@ namespace mix class CodeEditorExtensionManager: public QObject { - Q_OBJECT + Q_OBJECT - Q_PROPERTY(QQuickItem* editor MEMBER m_editor WRITE setEditor) - Q_PROPERTY(QQuickItem* tabView MEMBER m_tabView WRITE setTabView) + Q_PROPERTY(QQuickItem* editor MEMBER m_editor WRITE setEditor) + Q_PROPERTY(QQuickItem* tabView MEMBER m_tabView WRITE setTabView) public: - CodeEditorExtensionManager() {} - ~CodeEditorExtensionManager(); - void initExtensions(); - void setEditor(QQuickItem*); - void setTabView(QQuickItem*); + CodeEditorExtensionManager() {} + ~CodeEditorExtensionManager(); + void initExtensions(); + void setEditor(QQuickItem*); + void setTabView(QQuickItem*); private: - QQuickItem* m_editor; - QVector> m_features; - QQuickItem* m_tabView; - QTextDocument* m_doc; - void loadEditor(QQuickItem*); + QQuickItem* m_editor; + QVector> m_features; + QQuickItem* m_tabView; + QTextDocument* m_doc; + void loadEditor(QQuickItem*); }; } diff --git a/mix/ConstantCompilationCtrl.cpp b/mix/ConstantCompilationCtrl.cpp index 2c42a28dd..06b9c0284 100644 --- a/mix/ConstantCompilationCtrl.cpp +++ b/mix/ConstantCompilationCtrl.cpp @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + 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 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. + 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 . + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . */ /** @file ConstantCompilation.cpp * @author Yann yann@ethdev.com @@ -32,66 +32,66 @@ using namespace dev::mix; ConstantCompilationCtrl::ConstantCompilationCtrl(QTextDocument* _doc) { - m_editor = _doc; - m_compilationModel = new ConstantCompilationModel(); + m_editor = _doc; + m_compilationModel = new ConstantCompilationModel(); } ConstantCompilationCtrl::~ConstantCompilationCtrl() { - delete m_compilationModel; + delete m_compilationModel; } QString ConstantCompilationCtrl::contentUrl() const { - return QStringLiteral("qrc:/qml/BasicContent.qml"); + return QStringLiteral("qrc:/qml/BasicContent.qml"); } QString ConstantCompilationCtrl::title() const { - return "compiler"; + return "compiler"; } void ConstantCompilationCtrl::start() const { - connect(m_editor, SIGNAL(contentsChange(int,int,int)), this, SLOT(compile())); + connect(m_editor, SIGNAL(contentsChange(int,int,int)), this, SLOT(compile())); } void ConstantCompilationCtrl::compile() { - QString codeContent = m_editor->toPlainText().replace("\n", ""); - if (codeContent == "") - { - resetOutPut(); - return; - } - CompilerResult res = m_compilationModel->compile(m_editor->toPlainText()); - writeOutPut(res); + QString codeContent = m_editor->toPlainText().replace("\n", ""); + if (codeContent.isEmpty()) + { + resetOutPut(); + return; + } + CompilerResult res = m_compilationModel->compile(m_editor->toPlainText()); + writeOutPut(res); } void ConstantCompilationCtrl::resetOutPut() { - QObject* status = m_view->findChild("status", Qt::FindChildrenRecursively); - QObject* content = m_view->findChild("content", Qt::FindChildrenRecursively); - status->setProperty("text", ""); - content->setProperty("text", ""); + QObject* status = m_view->findChild("status", Qt::FindChildrenRecursively); + QObject* content = m_view->findChild("content", Qt::FindChildrenRecursively); + status->setProperty("text", ""); + content->setProperty("text", ""); } -void ConstantCompilationCtrl::writeOutPut(const CompilerResult& _res) +void ConstantCompilationCtrl::writeOutPut(CompilerResult const& _res) { - QObject* status = m_view->findChild("status", Qt::FindChildrenRecursively); - QObject* content = m_view->findChild("content", Qt::FindChildrenRecursively); - if (_res.success) - { - status->setProperty("text", "succeeded"); - status->setProperty("color", "green"); - content->setProperty("text", _res.hexCode); - qDebug() << QString("compile succeeded " + _res.hexCode); - } - else - { - status->setProperty("text", "failure"); - status->setProperty("color", "red"); - content->setProperty("text", _res.comment); - qDebug() << QString("compile failed " + _res.comment); - } + QObject* status = m_view->findChild("status", Qt::FindChildrenRecursively); + QObject* content = m_view->findChild("content", Qt::FindChildrenRecursively); + if (_res.success) + { + status->setProperty("text", "succeeded"); + status->setProperty("color", "green"); + content->setProperty("text", _res.hexCode); + qDebug() << QString("compile succeeded " + _res.hexCode); + } + else + { + status->setProperty("text", "failure"); + status->setProperty("color", "red"); + content->setProperty("text", _res.comment); + qDebug() << QString("compile failed " + _res.comment); + } } diff --git a/mix/ConstantCompilationCtrl.h b/mix/ConstantCompilationCtrl.h index af7c97951..e4661c800 100644 --- a/mix/ConstantCompilationCtrl.h +++ b/mix/ConstantCompilationCtrl.h @@ -1,15 +1,15 @@ /* - 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 . + 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 ConstantCompilation.h * @author Yann yann@ethdev.com @@ -31,23 +31,23 @@ namespace mix class ConstantCompilationCtrl: public Extension { - Q_OBJECT + Q_OBJECT public: - ConstantCompilationCtrl(QTextDocument*); - ~ConstantCompilationCtrl(); - void start() const override; - QString title() const override; - QString contentUrl() const override; + ConstantCompilationCtrl(QTextDocument*); + ~ConstantCompilationCtrl(); + void start() const override; + QString title() const override; + QString contentUrl() const override; private: - QTextDocument* m_editor; - ConstantCompilationModel* m_compilationModel; - void writeOutPut(const CompilerResult&); - void resetOutPut(); + QTextDocument* m_editor; + ConstantCompilationModel* m_compilationModel; + void writeOutPut(CompilerResult const&); + void resetOutPut(); public Q_SLOTS: - void compile(); + void compile(); }; } diff --git a/mix/ConstantCompilationModel.cpp b/mix/ConstantCompilationModel.cpp index 533523a4e..e06734f59 100644 --- a/mix/ConstantCompilationModel.cpp +++ b/mix/ConstantCompilationModel.cpp @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + 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 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. + 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 . + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . */ /** @file ApplicationCtx.h * @author Yann yann@ethdev.com @@ -33,29 +33,29 @@ using namespace dev::mix; CompilerResult ConstantCompilationModel::compile(QString _code) { - dev::solidity::CompilerStack compiler; - dev::bytes m_data; - CompilerResult res; - try - { - m_data = compiler.compile(_code.toStdString(), true); - res.success = true; - res.comment = "ok"; - res.hexCode = QString::fromStdString(dev::eth::disassemble(m_data)); - } - catch (dev::Exception const& _exception) - { - ostringstream error; - solidity::SourceReferenceFormatter::printExceptionInformation(error, _exception, "Error", compiler.getScanner()); - res.success = false; - res.comment = QString::fromStdString(error.str()).toHtmlEscaped(); - res.hexCode = ""; - } - catch (...) - { - res.success = false; - res.comment = "Uncaught exception."; - res.hexCode = ""; - } - return res; + dev::solidity::CompilerStack compiler; + dev::bytes m_data; + CompilerResult res; + try + { + m_data = compiler.compile(_code.toStdString(), true); + res.success = true; + res.comment = "ok"; + res.hexCode = QString::fromStdString(dev::eth::disassemble(m_data)); + } + catch (dev::Exception const& _exception) + { + ostringstream error; + solidity::SourceReferenceFormatter::printExceptionInformation(error, _exception, "Error", compiler.getScanner()); + res.success = false; + res.comment = QString::fromStdString(error.str()).toHtmlEscaped(); + res.hexCode = ""; + } + catch (...) + { + res.success = false; + res.comment = "Uncaught exception."; + res.hexCode = ""; + } + return res; } diff --git a/mix/ConstantCompilationModel.h b/mix/ConstantCompilationModel.h index 4c84bc0eb..faeb853e0 100644 --- a/mix/ConstantCompilationModel.h +++ b/mix/ConstantCompilationModel.h @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + 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 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. + 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 . + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . */ /** @file ApplicationCtx.h * @author Yann yann@ethdev.com @@ -32,18 +32,18 @@ namespace mix struct CompilerResult { - QString hexCode; - QString comment; - bool success; + QString hexCode; + QString comment; + bool success; }; class ConstantCompilationModel { public: - ConstantCompilationModel() { } - ~ConstantCompilationModel() { } - CompilerResult compile(QString code); + ConstantCompilationModel() { } + ~ConstantCompilationModel() { } + CompilerResult compile(QString code); }; } diff --git a/mix/Extension.cpp b/mix/Extension.cpp index b1ae31ecc..5aeb0cc17 100644 --- a/mix/Extension.cpp +++ b/mix/Extension.cpp @@ -1,15 +1,15 @@ /* - 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 . + 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 Feature.cpp * @author Yann yann@ethdev.com @@ -27,18 +27,18 @@ using namespace dev::mix; void Extension::addContentOn(QObject* _tabView) { - if (contentUrl() == "") - return; + if (contentUrl() == "") + return; - QVariant returnValue; - QQmlComponent* component = new QQmlComponent( - ApplicationCtx::getInstance()->appEngine(), - QUrl(this->contentUrl()), _tabView); + QVariant returnValue; + QQmlComponent* component = new QQmlComponent( + ApplicationCtx::getInstance()->appEngine(), + QUrl(this->contentUrl()), _tabView); - QMetaObject::invokeMethod(_tabView, "addTab", - Q_RETURN_ARG(QVariant, returnValue), - Q_ARG(QVariant, this->title()), - Q_ARG(QVariant, QVariant::fromValue(component))); + QMetaObject::invokeMethod(_tabView, "addTab", + Q_RETURN_ARG(QVariant, returnValue), + Q_ARG(QVariant, this->title()), + Q_ARG(QVariant, QVariant::fromValue(component))); - m_view = qvariant_cast(returnValue); + m_view = qvariant_cast(returnValue); } diff --git a/mix/Extension.h b/mix/Extension.h index 0678fdd5b..f8fef0aa6 100644 --- a/mix/Extension.h +++ b/mix/Extension.h @@ -1,15 +1,15 @@ /* - 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 . + 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 Feature.h * @author Yann yann@ethdev.com @@ -30,17 +30,17 @@ namespace mix class Extension: public QObject { - Q_OBJECT + Q_OBJECT public: - Extension() {} - virtual QString contentUrl() const { return ""; } - virtual QString title() const { return ""; } - virtual void start() const {} - void addContentOn(QObject* tabView); + Extension() {} + virtual QString contentUrl() const { return ""; } + virtual QString title() const { return ""; } + virtual void start() const {} + void addContentOn(QObject* tabView); protected: - QObject* m_view; + QObject* m_view; }; } diff --git a/mix/MixApplication.cpp b/mix/MixApplication.cpp index 634b3142a..c63349409 100644 --- a/mix/MixApplication.cpp +++ b/mix/MixApplication.cpp @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + 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 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. + 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 . + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . */ /** @file main.cpp * @author Yann yann@ethdev.com @@ -24,23 +24,23 @@ using namespace dev::mix; MixApplication::MixApplication(int _argc, char *_argv[]) - : QApplication(_argc, _argv) + : QApplication(_argc, _argv) { } bool MixApplication::notify(QObject* _receiver, QEvent* _event) { - try - { - return MixApplication::notify(_receiver, _event); - } - catch (std::exception& _ex) - { - qDebug() << "std::exception was caught " << _ex.what(); - } - catch (...) - { - qDebug() << "uncaught exception "; - } - return false; + try + { + return MixApplication::notify(_receiver, _event); + } + catch (std::exception& _ex) + { + qDebug() << "std::exception was caught " << _ex.what(); + } + catch (...) + { + qDebug() << "uncaught exception "; + } + return false; } diff --git a/mix/MixApplication.h b/mix/MixApplication.h index ba344fcdc..fdc506268 100644 --- a/mix/MixApplication.h +++ b/mix/MixApplication.h @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + 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 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. + 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 . + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . */ /** @file main.cpp * @author Yann yann@ethdev.com @@ -33,12 +33,12 @@ namespace mix class MixApplication: public QApplication { - Q_OBJECT + Q_OBJECT public: - MixApplication(int _argc, char* _argv[]); - virtual ~MixApplication() { } - virtual bool notify(QObject* _receiver, QEvent* _event); + MixApplication(int _argc, char* _argv[]); + virtual ~MixApplication() {} + virtual bool notify(QObject* _receiver, QEvent* _event); }; } diff --git a/mix/main.cpp b/mix/main.cpp index c0fc76bdd..537941290 100644 --- a/mix/main.cpp +++ b/mix/main.cpp @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + 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 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. + 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 . + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . */ /** @file main.cpp * @author Yann yann@ethdev.com @@ -30,11 +30,11 @@ using namespace dev::mix; int main(int _argc, char *_argv[]) { - QApplication app(_argc, _argv); - qmlRegisterType("CodeEditorExtensionManager", 1, 0, "CodeEditorExtensionManager"); - QQmlApplicationEngine* engine = new QQmlApplicationEngine(); - ApplicationCtx::setApplicationContext(engine); - QObject::connect(&app, SIGNAL(lastWindowClosed()), ApplicationCtx::getInstance(), SLOT(quitApplication())); //use to kill ApplicationContext and other stuff - engine->load(QUrl(QStringLiteral("qrc:/qml/main.qml"))); - return app.exec(); + QApplication app(_argc, _argv); + qmlRegisterType("CodeEditorExtensionManager", 1, 0, "CodeEditorExtensionManager"); + QQmlApplicationEngine* engine = new QQmlApplicationEngine(); + ApplicationCtx::setApplicationContext(engine); + QObject::connect(&app, SIGNAL(lastWindowClosed()), ApplicationCtx::getInstance(), SLOT(quitApplication())); //use to kill ApplicationContext and other stuff + engine->load(QUrl(QStringLiteral("qrc:/qml/main.qml"))); + return app.exec(); } diff --git a/mix/qml/BasicContent.qml b/mix/qml/BasicContent.qml index 8e450dabf..6d5020d3d 100644 --- a/mix/qml/BasicContent.qml +++ b/mix/qml/BasicContent.qml @@ -2,6 +2,7 @@ import QtQuick 2.3 import QtQuick.Controls 1.2 Rectangle { + anchors.fill: parent width: parent.width height: parent.height @@ -19,7 +20,7 @@ Rectangle { id: status } - TextArea{ + TextArea { readOnly: true anchors.left: parent.left anchors.leftMargin: 10 From 252910d387ad72e28bc675cc661c3ffe39337b3c Mon Sep 17 00:00:00 2001 From: yann300 Date: Sat, 29 Nov 2014 01:11:07 +0100 Subject: [PATCH 56/86] tab indentation in QML --- mix/qml/BasicContent.qml | 63 +++++++++++++-------------- mix/qml/MainContent.qml | 92 ++++++++++++++++++++-------------------- mix/qml/TabStyle.qml | 34 +++++++-------- mix/qml/main.qml | 36 ++++++++-------- 4 files changed, 110 insertions(+), 115 deletions(-) diff --git a/mix/qml/BasicContent.qml b/mix/qml/BasicContent.qml index 6d5020d3d..0049e6127 100644 --- a/mix/qml/BasicContent.qml +++ b/mix/qml/BasicContent.qml @@ -2,37 +2,34 @@ import QtQuick 2.3 import QtQuick.Controls 1.2 Rectangle { - - anchors.fill: parent - width: parent.width - height: parent.height - color: "lightgray" - - Text { - font.pointSize: 7 - anchors.left: parent.left - anchors.top: parent.top - anchors.topMargin: 3 - anchors.leftMargin: 3 - height: 9 - font.family: "Sego UI light" - objectName: "status" - id: status - } - - TextArea { - readOnly: true - anchors.left: parent.left - anchors.leftMargin: 10 - anchors.top: status.bottom - anchors.topMargin: 3 - font.pointSize: 7 - font.family: "Sego UI light" - height: parent.height * 0.8 - width: parent.width - 20 - wrapMode: Text.Wrap - backgroundVisible: false - objectName: "content" - id: content - } + anchors.fill: parent + width: parent.width + height: parent.height + color: "lightgray" + Text { + font.pointSize: 7 + anchors.left: parent.left + anchors.top: parent.top + anchors.topMargin: 3 + anchors.leftMargin: 3 + height: 9 + font.family: "Sego UI light" + objectName: "status" + id: status + } + TextArea { + readOnly: true + anchors.left: parent.left + anchors.leftMargin: 10 + anchors.top: status.bottom + anchors.topMargin: 3 + font.pointSize: 7 + font.family: "Sego UI light" + height: parent.height * 0.8 + width: parent.width - 20 + wrapMode: Text.Wrap + backgroundVisible: false + objectName: "content" + id: content + } } diff --git a/mix/qml/MainContent.qml b/mix/qml/MainContent.qml index 80bbec3aa..f243b16ac 100644 --- a/mix/qml/MainContent.qml +++ b/mix/qml/MainContent.qml @@ -5,50 +5,50 @@ import QtQuick.Controls.Styles 1.2 import CodeEditorExtensionManager 1.0 Rectangle { - anchors.fill: parent - height: parent.height - width: parent.width; - id:root - SplitView { - anchors.fill: parent - orientation: Qt.Vertical - Rectangle { - anchors.top: parent.top - id: contentView - width: parent.width - height: parent.height * 0.7 - TextArea { - id: codeEditor - height: parent.height - font.family: "Verdana" - font.pointSize: 9 - 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 - id: contextualView - width: parent.width - Layout.minimumHeight: 20 - height: parent.height * 0.3 - TabView { - id: contextualTabs - antialiasing: true - anchors.fill: parent - style: TabStyle{} - } - } - CodeEditorExtensionManager{ - tabView: contextualTabs - editor: codeEditor - } - } + anchors.fill: parent + height: parent.height + width: parent.width; + id:root + SplitView { + anchors.fill: parent + orientation: Qt.Vertical + Rectangle { + anchors.top: parent.top + id: contentView + width: parent.width + height: parent.height * 0.7 + TextArea { + id: codeEditor + height: parent.height + font.family: "Verdana" + font.pointSize: 9 + 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 + id: contextualView + width: parent.width + Layout.minimumHeight: 20 + height: parent.height * 0.3 + TabView { + id: contextualTabs + antialiasing: true + anchors.fill: parent + style: TabStyle {} + } + } + CodeEditorExtensionManager{ + tabView: contextualTabs + editor: codeEditor + } + } } diff --git a/mix/qml/TabStyle.qml b/mix/qml/TabStyle.qml index 8f72fa12c..5f78f8947 100644 --- a/mix/qml/TabStyle.qml +++ b/mix/qml/TabStyle.qml @@ -3,21 +3,21 @@ import QtQuick.Controls 1.2 import QtQuick.Controls.Styles 1.2 TabViewStyle { - frameOverlap: 1 - tabBar: Rectangle { - color: "lightgray" - } - tab: Rectangle { - color: "lightsteelblue" - implicitWidth: Math.max(text.width + 4, 80) - implicitHeight: 20 - radius: 2 - Text { - id: text - anchors.centerIn: parent - text: styleData.title - color: styleData.selected ? "white" : "black" - } - } - frame: Rectangle { color: "steelblue" } + frameOverlap: 1 + tabBar: Rectangle { + color: "lightgray" + } + tab: Rectangle { + color: "lightsteelblue" + implicitWidth: Math.max(text.width + 4, 80) + implicitHeight: 20 + radius: 2 + Text { + id: text + anchors.centerIn: parent + text: styleData.title + color: styleData.selected ? "white" : "black" + } + } + frame: Rectangle { color: "steelblue" } } diff --git a/mix/qml/main.qml b/mix/qml/main.qml index 331720f41..8a1b86cee 100644 --- a/mix/qml/main.qml +++ b/mix/qml/main.qml @@ -4,23 +4,21 @@ import QtQuick.Controls.Styles 1.2 import CodeEditorExtensionManager 1.0 ApplicationWindow { - visible: true - width: 1000 - height: 480 - minimumWidth: 400 - minimumHeight: 300 - title: qsTr("mix") - - menuBar: MenuBar { - Menu { - title: qsTr("File") - MenuItem { - text: qsTr("Exit") - onTriggered: Qt.quit(); - } - } - } - - MainContent{ - } + visible: true + width: 1000 + height: 480 + minimumWidth: 400 + minimumHeight: 300 + title: qsTr("mix") + menuBar: MenuBar { + Menu { + title: qsTr("File") + MenuItem { + text: qsTr("Exit") + onTriggered: Qt.quit(); + } + } + } + MainContent{ + } } From c0896891748b4bdb21287947de5ed87d77d2bbf8 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 29 Nov 2014 18:31:02 +0100 Subject: [PATCH 57/86] Remove old bloom stuff. Fix genesis. --- libethcore/CommonEth.cpp | 2 +- libethereum/BlockChain.cpp | 19 +------------------ libethereum/BlockChain.h | 12 ------------ libethereum/BlockDetails.h | 22 ---------------------- 4 files changed, 2 insertions(+), 53 deletions(-) diff --git a/libethcore/CommonEth.cpp b/libethcore/CommonEth.cpp index 610d141ed..010b7e408 100644 --- a/libethcore/CommonEth.cpp +++ b/libethcore/CommonEth.cpp @@ -34,7 +34,7 @@ namespace eth { const unsigned c_protocolVersion = 45; -const unsigned c_databaseVersion = 4; +const unsigned c_databaseVersion = 5; static const vector> g_units = { diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 264cdbd57..531005fb2 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -102,8 +102,7 @@ bytes BlockChain::createGenesisBlock() } block.appendList(14) - // TODO: maybe make logbloom correct? - << h256() << EmptyListSHA3 << h160() << stateRoot << EmptyTrie << EmptyTrie << LogBloom() << c_genesisDifficulty << 0 << 0 << 0 << (unsigned)0 << string() << sha3(bytes(1, 42)); + << h256() << EmptyListSHA3 << h160() << stateRoot << EmptyTrie << EmptyTrie << LogBloom() << c_genesisDifficulty << 0 << 1000000 << 0 << (unsigned)0 << string() << sha3(bytes(1, 42)); block.appendRaw(RLPEmptyList); block.appendRaw(RLPEmptyList); return block.out(); @@ -169,8 +168,6 @@ void BlockChain::close() delete m_db; m_lastBlockHash = m_genesisHash; m_details.clear(); - m_blooms.clear(); - m_traces.clear(); m_cache.clear(); } @@ -307,14 +304,10 @@ h256s BlockChain::import(bytes const& _block, OverlayDB const& _db) State s(bi.coinbaseAddress, _db); auto tdIncrease = s.enactOn(&_block, bi, *this); auto b = s.oldBloom(); - BlockBlooms bb; - BlockTraces bt; BlockLogBlooms blb; BlockReceipts br; for (unsigned i = 0; i < s.pending().size(); ++i) { - bb.blooms.push_back(s.changesFromPending(i).bloom()); - bt.traces.push_back(s.changesFromPending(i)); blb.blooms.push_back(s.receipt(i).bloom()); br.receipts.push_back(s.receipt(i)); } @@ -330,14 +323,6 @@ h256s BlockChain::import(bytes const& _block, OverlayDB const& _db) m_details[newHash] = BlockDetails((unsigned)pd.number + 1, td, bi.parentHash, {}, b); m_details[bi.parentHash].children.push_back(newHash); } - { - WriteGuard l(x_blooms); - m_blooms[newHash] = bb; - } - { - WriteGuard l(x_traces); - m_traces[newHash] = bt; - } { WriteGuard l(x_logBlooms); m_logBlooms[newHash] = blb; @@ -349,8 +334,6 @@ h256s BlockChain::import(bytes const& _block, OverlayDB const& _db) m_extrasDB->Put(m_writeOptions, toSlice(newHash), (ldb::Slice)dev::ref(m_details[newHash].rlp())); m_extrasDB->Put(m_writeOptions, toSlice(bi.parentHash), (ldb::Slice)dev::ref(m_details[bi.parentHash].rlp())); - m_extrasDB->Put(m_writeOptions, toSlice(newHash, 1), (ldb::Slice)dev::ref(m_blooms[newHash].rlp())); - m_extrasDB->Put(m_writeOptions, toSlice(newHash, 2), (ldb::Slice)dev::ref(m_traces[newHash].rlp())); m_extrasDB->Put(m_writeOptions, toSlice(newHash, 3), (ldb::Slice)dev::ref(m_logBlooms[newHash].rlp())); m_extrasDB->Put(m_writeOptions, toSlice(newHash, 4), (ldb::Slice)dev::ref(m_receipts[newHash].rlp())); m_db->Put(m_writeOptions, toSlice(newHash), (ldb::Slice)ref(_block)); diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index 74d94e164..d03818bd3 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -101,14 +101,6 @@ public: BlockDetails details(h256 _hash) const { return queryExtras(_hash, m_details, x_details, NullBlockDetails); } BlockDetails details() const { return details(currentHash()); } - /// Get the transactions' bloom filters of a block (or the most recent mined if none given). Thread-safe. - BlockBlooms blooms(h256 _hash) const { return queryExtras(_hash, m_blooms, x_blooms, NullBlockBlooms); } - BlockBlooms blooms() const { return blooms(currentHash()); } - - /// Get the transactions' trace manifests of a block (or the most recent mined if none given). Thread-safe. - BlockTraces traces(h256 _hash) const { return queryExtras(_hash, m_traces, x_traces, NullBlockTraces); } - BlockTraces traces() const { return traces(currentHash()); } - /// Get the transactions' log blooms of a block (or the most recent mined if none given). Thread-safe. BlockLogBlooms logBlooms(h256 _hash) const { return queryExtras(_hash, m_logBlooms, x_logBlooms, NullBlockLogBlooms); } BlockLogBlooms logBlooms() const { return logBlooms(currentHash()); } @@ -193,10 +185,6 @@ private: /// The caches of the disk DB and their locks. mutable boost::shared_mutex x_details; mutable BlockDetailsHash m_details; - mutable boost::shared_mutex x_blooms; - mutable BlockBloomsHash m_blooms; - mutable boost::shared_mutex x_traces; - mutable BlockTracesHash m_traces; mutable boost::shared_mutex x_logBlooms; mutable BlockLogBloomsHash m_logBlooms; mutable boost::shared_mutex x_receipts; diff --git a/libethereum/BlockDetails.h b/libethereum/BlockDetails.h index 973e93070..0c3af5b33 100644 --- a/libethereum/BlockDetails.h +++ b/libethereum/BlockDetails.h @@ -54,24 +54,6 @@ struct BlockDetails h256 bloom; }; -struct BlockBlooms -{ - BlockBlooms() {} - BlockBlooms(RLP const& _r) { blooms = _r.toVector(); } - bytes rlp() const { RLPStream s; s << blooms; return s.out(); } - - h256s blooms; -}; - -struct BlockTraces -{ - BlockTraces() {} - BlockTraces(RLP const& _r) { for (auto const& i: _r) traces.emplace_back(i.data()); } - bytes rlp() const { RLPStream s(traces.size()); for (auto const& i: traces) i.streamRLP(s); return s.out(); } - - Manifests traces; -}; - struct BlockLogBlooms { BlockLogBlooms() {} @@ -91,14 +73,10 @@ struct BlockReceipts }; typedef std::map BlockDetailsHash; -typedef std::map BlockBloomsHash; -typedef std::map BlockTracesHash; typedef std::map BlockLogBloomsHash; typedef std::map BlockReceiptsHash; static const BlockDetails NullBlockDetails; -static const BlockBlooms NullBlockBlooms; -static const BlockTraces NullBlockTraces; static const BlockLogBlooms NullBlockLogBlooms; static const BlockReceipts NullBlockReceipts; From db1ba8b5b4c609cc0ddada528dccf2f5cdc62f6e Mon Sep 17 00:00:00 2001 From: yann300 Date: Sat, 29 Nov 2014 19:28:03 +0100 Subject: [PATCH 58/86] style correction. --- mix/ConstantCompilationModel.h | 4 ++-- mix/MixApplication.cpp | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/mix/ConstantCompilationModel.h b/mix/ConstantCompilationModel.h index faeb853e0..4a17853f6 100644 --- a/mix/ConstantCompilationModel.h +++ b/mix/ConstantCompilationModel.h @@ -41,8 +41,8 @@ class ConstantCompilationModel { public: - ConstantCompilationModel() { } - ~ConstantCompilationModel() { } + ConstantCompilationModel() {} + ~ConstantCompilationModel() {} CompilerResult compile(QString code); }; diff --git a/mix/MixApplication.cpp b/mix/MixApplication.cpp index c63349409..e67ca1b12 100644 --- a/mix/MixApplication.cpp +++ b/mix/MixApplication.cpp @@ -23,8 +23,7 @@ #include "MixApplication.h" using namespace dev::mix; -MixApplication::MixApplication(int _argc, char *_argv[]) - : QApplication(_argc, _argv) +MixApplication::MixApplication(int _argc, char *_argv[]): QApplication(_argc, _argv) { } From eccdf006ea8646986f982aec0e4ba658592726db Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 29 Nov 2014 20:31:44 +0100 Subject: [PATCH 59/86] Variable EXP gas cost. --- libevm/FeeStructure.cpp | 2 ++ libevm/FeeStructure.h | 2 ++ libevm/VM.h | 8 +++++++- 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/libevm/FeeStructure.cpp b/libevm/FeeStructure.cpp index 59a5329bc..3e957118e 100644 --- a/libevm/FeeStructure.cpp +++ b/libevm/FeeStructure.cpp @@ -34,6 +34,8 @@ u256 const dev::eth::c_sstoreResetGas = 100; u256 const dev::eth::c_sstoreRefundGas = 100; u256 const dev::eth::c_createGas = 100; u256 const dev::eth::c_callGas = 20; +u256 const dev::eth::c_expGas = 1; +u256 const dev::eth::c_expByteGas = 1; u256 const dev::eth::c_memoryGas = 1; u256 const dev::eth::c_txDataZeroGas = 1; u256 const dev::eth::c_txDataNonZeroGas = 5; diff --git a/libevm/FeeStructure.h b/libevm/FeeStructure.h index 4f415da5d..3fb8175e6 100644 --- a/libevm/FeeStructure.h +++ b/libevm/FeeStructure.h @@ -37,6 +37,8 @@ extern u256 const c_sstoreResetGas; ///< Once per SSTORE operation if the zeron extern u256 const c_sstoreRefundGas; ///< Refunded gas, once per SSTORE operation if the zeroness changes to zero. extern u256 const c_createGas; ///< Once per CREATE operation & contract-creation transaction. extern u256 const c_callGas; ///< Once per CALL operation & message call transaction. +extern u256 const c_expGas; ///< Once per EXP instuction. +extern u256 const c_expByteGas; ///< Times ceil(log256(exponent)) for the EXP instruction. extern u256 const c_memoryGas; ///< Times the address of the (highest referenced byte in memory + 1). NOTE: referencing happens on read, write and in instructions such as RETURN and CALL. extern u256 const c_txDataZeroGas; ///< Per byte of data attached to a transaction that equals zero. NOTE: Not payable on data of calls between transactions. extern u256 const c_txDataNonZeroGas; ///< Per byte of data attached to a transaction that is not equal to zero. NOTE: Not payable on data of calls between transactions. diff --git a/libevm/VM.h b/libevm/VM.h index 9d43d7177..b0267c051 100644 --- a/libevm/VM.h +++ b/libevm/VM.h @@ -242,6 +242,13 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con runGas = c_createGas; break; } + case Instruction::EXP: + { + require(2); + auto expon = m_stack[m_stack.size() - 2]; + runGas = c_expGas + c_extByteGas * (32 - (h256(expon).firstBitSet() / 8)); + break; + } case Instruction::PC: case Instruction::MSIZE: @@ -308,7 +315,6 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con case Instruction::SDIV: case Instruction::MOD: case Instruction::SMOD: - case Instruction::EXP: case Instruction::LT: case Instruction::GT: case Instruction::SLT: From 278dc7981b1a496a49bc4eef5c495da61149e441 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 29 Nov 2014 20:42:01 +0100 Subject: [PATCH 60/86] Compile fix. --- libevm/VM.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libevm/VM.h b/libevm/VM.h index b0267c051..8fdd3de92 100644 --- a/libevm/VM.h +++ b/libevm/VM.h @@ -246,7 +246,7 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con { require(2); auto expon = m_stack[m_stack.size() - 2]; - runGas = c_expGas + c_extByteGas * (32 - (h256(expon).firstBitSet() / 8)); + runGas = c_expGas + c_expByteGas * (32 - (h256(expon).firstBitSet() / 8)); break; } From eb5369d6f213fbedb3fae40c8668a30726b19645 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Sun, 30 Nov 2014 22:43:40 +0100 Subject: [PATCH 61/86] Simplifying scanning for natspec documentation - Scanner no longer remembers the last natspect comment until a new one is encountered. It remembers it only until the next scan() --- libsolidity/Parser.cpp | 4 +--- libsolidity/Scanner.cpp | 42 ++++++++++++++--------------------------- libsolidity/Scanner.h | 8 +++----- 3 files changed, 18 insertions(+), 36 deletions(-) diff --git a/libsolidity/Parser.cpp b/libsolidity/Parser.cpp index 9ed081cce..0506bc3e3 100644 --- a/libsolidity/Parser.cpp +++ b/libsolidity/Parser.cpp @@ -119,10 +119,8 @@ ASTPointer Parser::parseFunctionDefinition(bool _isPublic) ASTNodeFactory nodeFactory(*this); ASTPointer docstring; if (m_scanner->getCurrentCommentLiteral() != "") - { docstring = std::make_shared(m_scanner->getCurrentCommentLiteral()); - m_scanner->clearCurrentCommentLiteral(); - } + expectToken(Token::FUNCTION); ASTPointer name(expectIdentifierToken()); ASTPointer parameters(parseParameterList()); diff --git a/libsolidity/Scanner.cpp b/libsolidity/Scanner.cpp index 4da9874a2..3335e9df4 100644 --- a/libsolidity/Scanner.cpp +++ b/libsolidity/Scanner.cpp @@ -104,16 +104,14 @@ int hexValue(char c) void Scanner::reset(CharStream const& _source) { - bool foundDocComment; m_source = _source; m_char = m_source.get(); skipWhitespace(); - foundDocComment = scanToken(); + scanToken(); - // special version of Scanner:next() taking the previous scanToken() result into account m_currentToken = m_nextToken; - if (scanToken() || foundDocComment) - m_skippedComment = m_nextSkippedComment; + m_skippedComment = m_nextSkippedComment; + scanToken(); } @@ -142,8 +140,9 @@ BOOST_STATIC_ASSERT(Token::NUM_TOKENS <= 0x100); Token::Value Scanner::next() { m_currentToken = m_nextToken; - if (scanToken()) - m_skippedComment = m_nextSkippedComment; + m_skippedComment = m_nextSkippedComment; + scanToken(); + return m_currentToken.token; } @@ -188,13 +187,13 @@ Token::Value Scanner::scanDocumentationComment() { // check if next line is also a documentation comment skipWhitespace(); - if (m_source.get(0) == '/' && + if (!m_source.isPastEndOfInput(3) && + m_source.get(0) == '/' && m_source.get(1) == '/' && - m_source.get(2) == '/' && - !m_source.isPastEndOfInput(3)) + m_source.get(2) == '/') { addCommentLiteralChar('\n'); - m_char = m_source.advanceBy(3); + m_char = m_source.advanceAndGet(3); } else break; // next line is not a documentation comment, we are done @@ -230,10 +229,10 @@ Token::Value Scanner::skipMultiLineComment() return Token::ILLEGAL; } -bool Scanner::scanToken() +void Scanner::scanToken() { - bool foundDocComment = false; m_nextToken.literal.clear(); + m_nextSkippedComment.literal.clear(); Token::Value token; do { @@ -345,7 +344,6 @@ bool Scanner::scanToken() m_nextSkippedComment.location.end = getSourcePos(); m_nextSkippedComment.token = comment; token = Token::WHITESPACE; - foundDocComment = true; } else token = skipSingleLineComment(); @@ -441,8 +439,6 @@ bool Scanner::scanToken() while (token == Token::WHITESPACE); m_nextToken.location.end = getSourcePos(); m_nextToken.token = token; - - return foundDocComment; } bool Scanner::scanEscape() @@ -783,23 +779,13 @@ Token::Value Scanner::scanIdentifierOrKeyword() return KeywordOrIdentifierToken(m_nextToken.literal); } -char CharStream::advanceAndGet() +char CharStream::advanceAndGet(size_t _chars) { if (isPastEndOfInput()) return 0; - ++m_pos; + m_pos += _chars; if (isPastEndOfInput()) return 0; - return get(); -} - -char CharStream::advanceBy(size_t _chars) -{ - if (asserts(!isPastEndOfInput(_chars))) - BOOST_THROW_EXCEPTION(InternalCompilerError()); - - m_pos += _chars; - return m_source[m_pos]; } diff --git a/libsolidity/Scanner.h b/libsolidity/Scanner.h index 702310102..e9262ba39 100644 --- a/libsolidity/Scanner.h +++ b/libsolidity/Scanner.h @@ -76,8 +76,7 @@ public: int getPos() const { return m_pos; } bool isPastEndOfInput(size_t _charsForward = 0) const { return (m_pos + _charsForward) >= m_source.size(); } char get(size_t _charsForward = 0) const { return m_source[m_pos + _charsForward]; } - char advanceAndGet(); - char advanceBy(size_t _chars); + char advanceAndGet(size_t _chars=1); char rollback(size_t _amount); ///@{ @@ -213,9 +212,8 @@ private: bool scanHexByte(char& o_scannedByte); - /// Scans a single Solidity token. Returns true if the scanned token was - /// a skipped documentation comment. False in all other cases. - bool scanToken(); + /// Scans a single Solidity token. + void scanToken(); /// Skips all whitespace and @returns true if something was skipped. bool skipWhitespace(); From 87c58e48666c7b79ae58aa2fffeb6a9234711c33 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Sun, 30 Nov 2014 23:25:42 +0100 Subject: [PATCH 62/86] Moving LiteralScope to Scanner.cpp --- libsolidity/Scanner.cpp | 41 ++++++++++++++++++++++++++++++++++++++++ libsolidity/Scanner.h | 42 +---------------------------------------- 2 files changed, 42 insertions(+), 41 deletions(-) diff --git a/libsolidity/Scanner.cpp b/libsolidity/Scanner.cpp index 3335e9df4..6ef8a6c79 100644 --- a/libsolidity/Scanner.cpp +++ b/libsolidity/Scanner.cpp @@ -102,6 +102,47 @@ int hexValue(char c) } } // end anonymous namespace + + +/// Scoped helper for literal recording. Automatically drops the literal +/// if aborting the scanning before it's complete. +enum LiteralType { + LITERAL_TYPE_STRING, + LITERAL_TYPE_NUMBER, // not really different from string type in behaviour + LITERAL_TYPE_COMMENT +}; + +class LiteralScope +{ +public: + explicit LiteralScope(Scanner* _self, enum LiteralType _type): m_type(_type) + , m_scanner(_self) + , m_complete(false) + { + if (_type == LITERAL_TYPE_COMMENT) + m_scanner->m_nextSkippedComment.literal.clear(); + else + m_scanner->m_nextToken.literal.clear(); + } + ~LiteralScope() + { + if (!m_complete) + { + if (m_type == LITERAL_TYPE_COMMENT) + m_scanner->m_nextSkippedComment.literal.clear(); + else + m_scanner->m_nextToken.literal.clear(); + } + } + void complete() { m_complete = true; } + +private: + enum LiteralType m_type; + Scanner* m_scanner; + bool m_complete; +}; // end of LiteralScope class + + void Scanner::reset(CharStream const& _source) { m_source = _source; diff --git a/libsolidity/Scanner.h b/libsolidity/Scanner.h index e9262ba39..49ac3651c 100644 --- a/libsolidity/Scanner.h +++ b/libsolidity/Scanner.h @@ -96,45 +96,9 @@ private: class Scanner { + friend class LiteralScope; public: - enum LiteralType { - LITERAL_TYPE_STRING, - LITERAL_TYPE_NUMBER, // not really different from string type in behaviour - LITERAL_TYPE_COMMENT - }; - /// Scoped helper for literal recording. Automatically drops the literal - /// if aborting the scanning before it's complete. - class LiteralScope - { - public: - explicit LiteralScope(Scanner* _self, enum LiteralType _type): m_type(_type) - , m_scanner(_self) - , m_complete(false) - { - if (_type == LITERAL_TYPE_COMMENT) - m_scanner->startNewCommentLiteral(); - else - m_scanner->startNewLiteral(); - } - ~LiteralScope() - { - if (!m_complete) - { - if (m_type == LITERAL_TYPE_COMMENT) - m_scanner->dropCommentLiteral(); - else - m_scanner->dropLiteral(); - } - } - void complete() { m_complete = true; } - - private: - enum LiteralType m_type; - Scanner* m_scanner; - bool m_complete; - }; - Scanner() { reset(CharStream()); } explicit Scanner(CharStream const& _source) { reset(_source); } @@ -194,12 +158,8 @@ private: ///@{ ///@name Literal buffer support - inline void startNewLiteral() { m_nextToken.literal.clear(); } - inline void startNewCommentLiteral() { m_nextSkippedComment.literal.clear(); } inline void addLiteralChar(char c) { m_nextToken.literal.push_back(c); } inline void addCommentLiteralChar(char c) { m_nextSkippedComment.literal.push_back(c); } - inline void dropLiteral() { m_nextToken.literal.clear(); } - inline void dropCommentLiteral() { m_nextSkippedComment.literal.clear(); } inline void addLiteralCharAndAdvance() { addLiteralChar(m_char); advance(); } ///@} From 70dd83f88748c0737fac034f450432f67e81d3b0 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Sun, 30 Nov 2014 23:33:04 +0100 Subject: [PATCH 63/86] Adding natspec comment test being between keyword and signature --- test/solidityParser.cpp | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/test/solidityParser.cpp b/test/solidityParser.cpp index e4db2ece7..6a97a5d99 100644 --- a/test/solidityParser.cpp +++ b/test/solidityParser.cpp @@ -204,6 +204,29 @@ BOOST_AUTO_TEST_CASE(natspec_comment_in_function_body) " and it has 2 lines"); } +BOOST_AUTO_TEST_CASE(natspec_docstring_between_keyword_and_signature) +{ + ASTPointer contract; + ASTPointer function; + char const* text = "contract test {\n" + " uint256 stateVar;\n" + " function ///I am in the wrong place \n" + " fun1(uint256 a) {\n" + " var b;\n" + " /// I should not interfere with actual natspec comments\n" + " uint256 c;\n" + " mapping(address=>hash) d;\n" + " string name = \"Solidity\";" + " }\n" + "}\n"; + BOOST_REQUIRE_NO_THROW(contract = parseText(text)); + auto functions = contract->getDefinedFunctions(); + + BOOST_REQUIRE_NO_THROW(function = functions.at(0)); + BOOST_CHECK_MESSAGE(!function->getDocumentation(), + "Shouldn't get natspec docstring for this function"); +} + BOOST_AUTO_TEST_CASE(natspec_docstring_after_signature) { ASTPointer contract; @@ -211,8 +234,7 @@ BOOST_AUTO_TEST_CASE(natspec_docstring_after_signature) char const* text = "contract test {\n" " uint256 stateVar;\n" " function fun1(uint256 a) {\n" - " /// I should have been above the function signature" - " {\n" + " /// I should have been above the function signature\n" " var b;\n" " /// I should not interfere with actual natspec comments\n" " uint256 c;\n" From 6e0839efe38ef7573f220777f077c2ba782f8eae Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Mon, 1 Dec 2014 01:05:55 +0100 Subject: [PATCH 64/86] simplifying Scanner::reset() --- libsolidity/Scanner.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/libsolidity/Scanner.cpp b/libsolidity/Scanner.cpp index 6ef8a6c79..4ffc2223f 100644 --- a/libsolidity/Scanner.cpp +++ b/libsolidity/Scanner.cpp @@ -150,9 +150,7 @@ void Scanner::reset(CharStream const& _source) skipWhitespace(); scanToken(); - m_currentToken = m_nextToken; - m_skippedComment = m_nextSkippedComment; - scanToken(); + next(); } From 53608c9d776a3eb42455aafd9da99c8ee348b58a Mon Sep 17 00:00:00 2001 From: Christian Date: Mon, 1 Dec 2014 13:46:04 +0100 Subject: [PATCH 65/86] Cleanup of scanner. Removed redundancy of keyword definitions and removed some unused token predicates. --- libsolidity/Scanner.cpp | 197 +++------------------------------------- libsolidity/Token.h | 14 --- 2 files changed, 12 insertions(+), 199 deletions(-) diff --git a/libsolidity/Scanner.cpp b/libsolidity/Scanner.cpp index 4ffc2223f..487d5c205 100644 --- a/libsolidity/Scanner.cpp +++ b/libsolidity/Scanner.cpp @@ -194,7 +194,6 @@ Token::Value Scanner::selectToken(char _next, Token::Value _then, Token::Value _ return _else; } - bool Scanner::skipWhitespace() { int const startPosition = getSourcePos(); @@ -204,7 +203,6 @@ bool Scanner::skipWhitespace() return getSourcePos() != startPosition; } - Token::Value Scanner::skipSingleLineComment() { // The line terminator at the end of the line is not considered @@ -215,7 +213,6 @@ Token::Value Scanner::skipSingleLineComment() return Token::WHITESPACE; } -/// For the moment this function simply consumes a single line triple slash doc comment Token::Value Scanner::scanDocumentationComment() { LiteralScope literal(this, LITERAL_TYPE_COMMENT); @@ -545,14 +542,12 @@ Token::Value Scanner::scanString() return Token::STRING_LITERAL; } - void Scanner::scanDecimalDigits() { while (isDecimalDigit(m_char)) addLiteralCharAndAdvance(); } - Token::Value Scanner::scanNumber(char _charSeen) { enum { DECIMAL, HEX, BINARY } kind = DECIMAL; @@ -623,186 +618,18 @@ Token::Value Scanner::scanNumber(char _charSeen) // ---------------------------------------------------------------------------- // Keyword Matcher -#define KEYWORDS(KEYWORD_GROUP, KEYWORD) \ - KEYWORD_GROUP('a') \ - KEYWORD("address", Token::ADDRESS) \ - KEYWORD_GROUP('b') \ - KEYWORD("break", Token::BREAK) \ - KEYWORD("bool", Token::BOOL) \ - KEYWORD_GROUP('c') \ - KEYWORD("case", Token::CASE) \ - KEYWORD("const", Token::CONST) \ - KEYWORD("continue", Token::CONTINUE) \ - KEYWORD("contract", Token::CONTRACT) \ - KEYWORD_GROUP('d') \ - KEYWORD("default", Token::DEFAULT) \ - KEYWORD("delete", Token::DELETE) \ - KEYWORD("do", Token::DO) \ - KEYWORD_GROUP('e') \ - KEYWORD("else", Token::ELSE) \ - KEYWORD("extends", Token::EXTENDS) \ - KEYWORD_GROUP('f') \ - KEYWORD("false", Token::FALSE_LITERAL) \ - KEYWORD("for", Token::FOR) \ - KEYWORD("function", Token::FUNCTION) \ - KEYWORD_GROUP('h') \ - KEYWORD("hash", Token::HASH) \ - KEYWORD("hash8", Token::HASH8) \ - KEYWORD("hash16", Token::HASH16) \ - KEYWORD("hash24", Token::HASH24) \ - KEYWORD("hash32", Token::HASH32) \ - KEYWORD("hash40", Token::HASH40) \ - KEYWORD("hash48", Token::HASH48) \ - KEYWORD("hash56", Token::HASH56) \ - KEYWORD("hash64", Token::HASH64) \ - KEYWORD("hash72", Token::HASH72) \ - KEYWORD("hash80", Token::HASH80) \ - KEYWORD("hash88", Token::HASH88) \ - KEYWORD("hash96", Token::HASH96) \ - KEYWORD("hash104", Token::HASH104) \ - KEYWORD("hash112", Token::HASH112) \ - KEYWORD("hash120", Token::HASH120) \ - KEYWORD("hash128", Token::HASH128) \ - KEYWORD("hash136", Token::HASH136) \ - KEYWORD("hash144", Token::HASH144) \ - KEYWORD("hash152", Token::HASH152) \ - KEYWORD("hash160", Token::HASH160) \ - KEYWORD("hash168", Token::HASH168) \ - KEYWORD("hash178", Token::HASH176) \ - KEYWORD("hash184", Token::HASH184) \ - KEYWORD("hash192", Token::HASH192) \ - KEYWORD("hash200", Token::HASH200) \ - KEYWORD("hash208", Token::HASH208) \ - KEYWORD("hash216", Token::HASH216) \ - KEYWORD("hash224", Token::HASH224) \ - KEYWORD("hash232", Token::HASH232) \ - KEYWORD("hash240", Token::HASH240) \ - KEYWORD("hash248", Token::HASH248) \ - KEYWORD("hash256", Token::HASH256) \ - KEYWORD_GROUP('i') \ - KEYWORD("if", Token::IF) \ - KEYWORD("in", Token::IN) \ - KEYWORD("int", Token::INT) \ - KEYWORD("int8", Token::INT8) \ - KEYWORD("int16", Token::INT16) \ - KEYWORD("int24", Token::INT24) \ - KEYWORD("int32", Token::INT32) \ - KEYWORD("int40", Token::INT40) \ - KEYWORD("int48", Token::INT48) \ - KEYWORD("int56", Token::INT56) \ - KEYWORD("int64", Token::INT64) \ - KEYWORD("int72", Token::INT72) \ - KEYWORD("int80", Token::INT80) \ - KEYWORD("int88", Token::INT88) \ - KEYWORD("int96", Token::INT96) \ - KEYWORD("int104", Token::INT104) \ - KEYWORD("int112", Token::INT112) \ - KEYWORD("int120", Token::INT120) \ - KEYWORD("int128", Token::INT128) \ - KEYWORD("int136", Token::INT136) \ - KEYWORD("int144", Token::INT144) \ - KEYWORD("int152", Token::INT152) \ - KEYWORD("int160", Token::INT160) \ - KEYWORD("int168", Token::INT168) \ - KEYWORD("int178", Token::INT176) \ - KEYWORD("int184", Token::INT184) \ - KEYWORD("int192", Token::INT192) \ - KEYWORD("int200", Token::INT200) \ - KEYWORD("int208", Token::INT208) \ - KEYWORD("int216", Token::INT216) \ - KEYWORD("int224", Token::INT224) \ - KEYWORD("int232", Token::INT232) \ - KEYWORD("int240", Token::INT240) \ - KEYWORD("int248", Token::INT248) \ - KEYWORD("int256", Token::INT256) \ - KEYWORD_GROUP('l') \ - KEYWORD_GROUP('m') \ - KEYWORD("mapping", Token::MAPPING) \ - KEYWORD_GROUP('n') \ - KEYWORD("new", Token::NEW) \ - KEYWORD("null", Token::NULL_LITERAL) \ - KEYWORD_GROUP('p') \ - KEYWORD("private", Token::PRIVATE) \ - KEYWORD("public", Token::PUBLIC) \ - KEYWORD_GROUP('r') \ - KEYWORD("real", Token::REAL) \ - KEYWORD("return", Token::RETURN) \ - KEYWORD("returns", Token::RETURNS) \ - KEYWORD_GROUP('s') \ - KEYWORD("string", Token::STRING_TYPE) \ - KEYWORD("struct", Token::STRUCT) \ - KEYWORD("switch", Token::SWITCH) \ - KEYWORD_GROUP('t') \ - KEYWORD("text", Token::TEXT) \ - KEYWORD("true", Token::TRUE_LITERAL) \ - KEYWORD_GROUP('u') \ - KEYWORD("uint", Token::UINT) \ - KEYWORD("uint8", Token::UINT8) \ - KEYWORD("uint16", Token::UINT16) \ - KEYWORD("uint24", Token::UINT24) \ - KEYWORD("uint32", Token::UINT32) \ - KEYWORD("uint40", Token::UINT40) \ - KEYWORD("uint48", Token::UINT48) \ - KEYWORD("uint56", Token::UINT56) \ - KEYWORD("uint64", Token::UINT64) \ - KEYWORD("uint72", Token::UINT72) \ - KEYWORD("uint80", Token::UINT80) \ - KEYWORD("uint88", Token::UINT88) \ - KEYWORD("uint96", Token::UINT96) \ - KEYWORD("uint104", Token::UINT104) \ - KEYWORD("uint112", Token::UINT112) \ - KEYWORD("uint120", Token::UINT120) \ - KEYWORD("uint128", Token::UINT128) \ - KEYWORD("uint136", Token::UINT136) \ - KEYWORD("uint144", Token::UINT144) \ - KEYWORD("uint152", Token::UINT152) \ - KEYWORD("uint160", Token::UINT160) \ - KEYWORD("uint168", Token::UINT168) \ - KEYWORD("uint178", Token::UINT176) \ - KEYWORD("uint184", Token::UINT184) \ - KEYWORD("uint192", Token::UINT192) \ - KEYWORD("uint200", Token::UINT200) \ - KEYWORD("uint208", Token::UINT208) \ - KEYWORD("uint216", Token::UINT216) \ - KEYWORD("uint224", Token::UINT224) \ - KEYWORD("uint232", Token::UINT232) \ - KEYWORD("uint240", Token::UINT240) \ - KEYWORD("uint248", Token::UINT248) \ - KEYWORD("uint256", Token::UINT256) \ - KEYWORD("ureal", Token::UREAL) \ - KEYWORD_GROUP('v') \ - KEYWORD("var", Token::VAR) \ - KEYWORD_GROUP('w') \ - KEYWORD("while", Token::WHILE) \ - - -static Token::Value KeywordOrIdentifierToken(string const& _input) + +static Token::Value keywordOrIdentifierToken(string const& _input) { - if (asserts(!_input.empty())) - BOOST_THROW_EXCEPTION(InternalCompilerError()); - int const kMinLength = 2; - int const kMaxLength = 10; - if (_input.size() < kMinLength || _input.size() > kMaxLength) - return Token::IDENTIFIER; - switch (_input[0]) - { - default: -#define KEYWORD_GROUP_CASE(ch) \ - break; \ - case ch: -#define KEYWORD(keyword, token) \ - { \ - /* 'keyword' is a char array, so sizeof(keyword) is */ \ - /* strlen(keyword) plus 1 for the NUL char. */ \ - int const keywordLength = sizeof(keyword) - 1; \ - BOOST_STATIC_ASSERT(keywordLength >= kMinLength); \ - BOOST_STATIC_ASSERT(keywordLength <= kMaxLength); \ - if (_input == keyword) \ - return token; \ - } - KEYWORDS(KEYWORD_GROUP_CASE, KEYWORD) - } - return Token::IDENTIFIER; +#define KEYWORD(name, string, precedence) {string, Token::name}, +#define TOKEN(name, string, precedence) + static const map keywords{ + TOKEN_LIST(TOKEN, KEYWORD) + }; +#undef KEYWORD +#undef TOKEN + auto it = keywords.find(_input); + return it == keywords.end() ? Token::IDENTIFIER : it->second; } Token::Value Scanner::scanIdentifierOrKeyword() @@ -815,7 +642,7 @@ Token::Value Scanner::scanIdentifierOrKeyword() while (isIdentifierPart(m_char)) addLiteralCharAndAdvance(); literal.complete(); - return KeywordOrIdentifierToken(m_nextToken.literal); + return keywordOrIdentifierToken(m_nextToken.literal); } char CharStream::advanceAndGet(size_t _chars) diff --git a/libsolidity/Token.h b/libsolidity/Token.h index 8974ca1ad..f1a94af35 100644 --- a/libsolidity/Token.h +++ b/libsolidity/Token.h @@ -314,25 +314,11 @@ public: } // Predicates - static bool isKeyword(Value tok) { return m_tokenType[tok] == 'K'; } - static bool isIdentifier(Value tok) { return tok == IDENTIFIER; } static bool isElementaryTypeName(Value tok) { return INT <= tok && tok < TYPES_END; } static bool isAssignmentOp(Value tok) { return ASSIGN <= tok && tok <= ASSIGN_MOD; } static bool isBinaryOp(Value op) { return COMMA <= op && op <= MOD; } - static bool isTruncatingBinaryOp(Value op) { return BIT_OR <= op && op <= SHR; } static bool isArithmeticOp(Value op) { return ADD <= op && op <= MOD; } static bool isCompareOp(Value op) { return EQ <= op && op <= IN; } - static bool isOrderedRelationalCompareOp(Value op) - { - return op == LT || op == LTE || op == GT || op == GTE; - } - static bool isEqualityOp(Value op) { return op == EQ; } - static bool isInequalityOp(Value op) { return op == NE; } - static bool isArithmeticCompareOp(Value op) - { - return isOrderedRelationalCompareOp(op) || - isEqualityOp(op) || isInequalityOp(op); - } static Value AssignmentToBinaryOp(Value op) { From 9baae5fbf4d88ab4b27d5c6a726d08c29acdfa29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 1 Dec 2014 14:49:40 +0100 Subject: [PATCH 66/86] Windows fix --- libp2p/Host.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index 6e151d34d..b233fe552 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -78,7 +78,7 @@ std::vector Host::getInterfaceAddresses() char *addrStr = inet_ntoa(addr); bi::address address(bi::address::from_string(addrStr)); if (!isLocalHostAddress(address)) - addresses.push_back(ad.to_v4()); + addresses.push_back(address.to_v4()); } WSACleanup(); @@ -153,7 +153,7 @@ int Host::listen4(bi::tcp::acceptor* _acceptor, unsigned short _listenPort) bi::tcp::endpoint Host::traverseNAT(std::vector const& _ifAddresses, unsigned short _listenPort, bi::address& o_upnpifaddr) { - asserts(_listenPort); + asserts(_listenPort != 0); UPnP* upnp; try From 51f746f523c28becc25f9dcd82a3c886aacf5f1b Mon Sep 17 00:00:00 2001 From: yann300 Date: Mon, 1 Dec 2014 15:22:48 +0100 Subject: [PATCH 67/86] Add cmake file path (used to find QtDeclarativeConfig.cmake module) --- mix/CMakeLists.txt | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/mix/CMakeLists.txt b/mix/CMakeLists.txt index 28fbc7342..152485cec 100644 --- a/mix/CMakeLists.txt +++ b/mix/CMakeLists.txt @@ -11,7 +11,8 @@ elseif ("${TARGET_PLATFORM}" STREQUAL "w64") set(SRC_LIST ${SRC_LIST} ../windows/qt_plugin_import.cpp) include_directories(/usr/x86_64-w64-mingw32/include /usr/x86_64-w64-mingw32/include/QtCore /usr/x86_64-w64-mingw32/include/QtGui /usr/x86_64-w64-mingw32/include/QtQuick /usr/x86_64-w64-mingw32/include/QtQml /usr/x86_64-w64-mingw32/include/QtNetwork /usr/x86_64-w64-mingw32/include/QtWidgets /usr/x86_64-w64-mingw32/include/QtWebKit /usr/x86_64-w64-mingw32/include/QtWebKitWidgets) elseif (UNIX) - set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} ";$ENV{QTDIR}/lib/cmake") + set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} ";$ENV{QTDIR}/lib/cmake") + set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} ";/opt/Qt5.3.2/5.3/gcc_64/lib/cmake") endif () find_package(Qt5Core REQUIRED) @@ -46,14 +47,14 @@ if (APPLE) set(MACOSX_BUNDLE_ICON_FILE mix) include(BundleUtilities) - add_executable(${EXECUTEABLE} MACOSX_BUNDLE ${SRC_LIST} ${HEADERS} ${UI_RESOURCES}) + add_executable(${EXECUTEABLE} MACOSX_BUNDLE ${SRC_LIST} ${HEADERS} ${UI_RESOURCES}) set_target_properties(${EXECUTEABLE} PROPERTIES MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/EthereumMacOSXBundleInfo.plist.in") SET_SOURCE_FILES_PROPERTIES(${EXECUTEABLE} PROPERTIES MACOSX_PACKAGE_LOCATION MacOS) SET_SOURCE_FILES_PROPERTIES(${MACOSX_BUNDLE_ICON_FILE}.icns PROPERTIES MACOSX_PACKAGE_LOCATION "Resources") else () set(EXECUTEABLE mix) - add_executable(${EXECUTEABLE} ${SRC_LIST} ${HEADERS} ${UI_RESOURCES}) + add_executable(${EXECUTEABLE} ${SRC_LIST} ${HEADERS} ${UI_RESOURCES}) endif () qt5_use_modules(${EXECUTEABLE} Core)# Gui Widgets Network WebKit WebKitWidgets) @@ -64,7 +65,7 @@ if (APPLE) add_custom_command(TARGET ${EXECUTEABLE} POST_BUILD COMMAND /usr/local/opt/qt5/bin/macdeployqt ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${EXECUTEABLE}.app WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) - + # This tool and next will inspect linked libraries in order to determine which dependencies are required if (${CMAKE_CFG_INTDIR} STREQUAL ".") set(APP_BUNDLE_PATH "${CMAKE_CURRENT_BINARY_DIR}/${EXECUTEABLE}.app") From b51454692716f07e56f2f2a0f1ba5f4efe4bba8a Mon Sep 17 00:00:00 2001 From: Christian Date: Mon, 1 Dec 2014 15:22:45 +0100 Subject: [PATCH 68/86] Save the scope for every declaration. --- libsolidity/AST.h | 7 ++++++- .../{Scope.cpp => DeclarationContainer.cpp} | 10 +++++----- .../{Scope.h => DeclarationContainer.h} | 10 ++++++---- libsolidity/NameAndTypeResolver.cpp | 19 +++++++++---------- libsolidity/NameAndTypeResolver.h | 14 +++++++------- 5 files changed, 33 insertions(+), 27 deletions(-) rename libsolidity/{Scope.cpp => DeclarationContainer.cpp} (78%) rename libsolidity/{Scope.h => DeclarationContainer.h} (77%) diff --git a/libsolidity/AST.h b/libsolidity/AST.h index 81a12ad1a..68b5c8b80 100644 --- a/libsolidity/AST.h +++ b/libsolidity/AST.h @@ -88,11 +88,16 @@ public: Declaration(Location const& _location, ASTPointer const& _name): ASTNode(_location), m_name(_name) {} - /// Returns the declared name. + /// @returns the declared name. ASTString const& getName() const { return *m_name; } + /// @returns the scope this declaration resides in. Can be nullptr if it is the global scope. + /// Available only after name and type resolution step. + Declaration* getScope() const { return m_scope; } + void setScope(Declaration* const& _scope) { m_scope = _scope; } private: ASTPointer m_name; + Declaration* m_scope; }; /** diff --git a/libsolidity/Scope.cpp b/libsolidity/DeclarationContainer.cpp similarity index 78% rename from libsolidity/Scope.cpp rename to libsolidity/DeclarationContainer.cpp index 540c41204..6ea9c28c5 100644 --- a/libsolidity/Scope.cpp +++ b/libsolidity/DeclarationContainer.cpp @@ -20,7 +20,7 @@ * Scope - object that holds declaration of names. */ -#include +#include #include namespace dev @@ -28,7 +28,7 @@ namespace dev namespace solidity { -bool Scope::registerDeclaration(Declaration& _declaration) +bool DeclarationContainer::registerDeclaration(Declaration& _declaration) { if (m_declarations.find(_declaration.getName()) != m_declarations.end()) return false; @@ -36,13 +36,13 @@ bool Scope::registerDeclaration(Declaration& _declaration) return true; } -Declaration* Scope::resolveName(ASTString const& _name, bool _recursive) const +Declaration* DeclarationContainer::resolveName(ASTString const& _name, bool _recursive) const { auto result = m_declarations.find(_name); if (result != m_declarations.end()) return result->second; - if (_recursive && m_enclosingScope) - return m_enclosingScope->resolveName(_name, true); + if (_recursive && m_enclosingContainer) + return m_enclosingContainer->resolveName(_name, true); return nullptr; } diff --git a/libsolidity/Scope.h b/libsolidity/DeclarationContainer.h similarity index 77% rename from libsolidity/Scope.h rename to libsolidity/DeclarationContainer.h index 637c2d5ce..db6812890 100644 --- a/libsolidity/Scope.h +++ b/libsolidity/DeclarationContainer.h @@ -36,18 +36,20 @@ namespace solidity * Container that stores mappings betwee names and declarations. It also contains a link to the * enclosing scope. */ -class Scope +class DeclarationContainer { public: - explicit Scope(Scope* _enclosingScope = nullptr): m_enclosingScope(_enclosingScope) {} + explicit DeclarationContainer(Declaration* _enclosingDeclaration = nullptr, DeclarationContainer* _enclosingContainer = nullptr): + m_enclosingDeclaration(_enclosingDeclaration), m_enclosingContainer(_enclosingContainer) {} /// Registers the declaration in the scope unless its name is already declared. Returns true iff /// it was not yet declared. bool registerDeclaration(Declaration& _declaration); Declaration* resolveName(ASTString const& _name, bool _recursive = false) const; - Scope* getEnclosingScope() const { return m_enclosingScope; } + Declaration* getEnclosingDeclaration() const { return m_enclosingDeclaration; } private: - Scope* m_enclosingScope; + Declaration* m_enclosingDeclaration; + DeclarationContainer* m_enclosingContainer; std::map m_declarations; }; diff --git a/libsolidity/NameAndTypeResolver.cpp b/libsolidity/NameAndTypeResolver.cpp index 225f2a78a..d473348b8 100644 --- a/libsolidity/NameAndTypeResolver.cpp +++ b/libsolidity/NameAndTypeResolver.cpp @@ -78,9 +78,9 @@ Declaration* NameAndTypeResolver::getNameFromCurrentScope(ASTString const& _name return m_currentScope->resolveName(_name, _recursive); } -DeclarationRegistrationHelper::DeclarationRegistrationHelper(map& _scopes, +DeclarationRegistrationHelper::DeclarationRegistrationHelper(map& _scopes, ASTNode& _astRoot): - m_scopes(_scopes), m_currentScope(&m_scopes[nullptr]) + m_scopes(_scopes), m_currentScope(nullptr) { _astRoot.accept(*this); } @@ -135,31 +135,30 @@ bool DeclarationRegistrationHelper::visit(VariableDeclaration& _declaration) return true; } -void DeclarationRegistrationHelper::enterNewSubScope(ASTNode& _node) +void DeclarationRegistrationHelper::enterNewSubScope(Declaration& _declaration) { - map::iterator iter; + map::iterator iter; bool newlyAdded; - tie(iter, newlyAdded) = m_scopes.emplace(&_node, Scope(m_currentScope)); + tie(iter, newlyAdded) = m_scopes.emplace(&_declaration, DeclarationContainer(m_currentScope, &m_scopes[m_currentScope])); if (asserts(newlyAdded)) BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unable to add new scope.")); - m_currentScope = &iter->second; + m_currentScope = &_declaration; } void DeclarationRegistrationHelper::closeCurrentScope() { if (asserts(m_currentScope)) BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Closed non-existing scope.")); - m_currentScope = m_currentScope->getEnclosingScope(); + m_currentScope = m_scopes[m_currentScope].getEnclosingDeclaration(); } void DeclarationRegistrationHelper::registerDeclaration(Declaration& _declaration, bool _opensScope) { - if (asserts(m_currentScope)) - BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Declaration registered without scope.")); - if (!m_currentScope->registerDeclaration(_declaration)) + if (!m_scopes[m_currentScope].registerDeclaration(_declaration)) BOOST_THROW_EXCEPTION(DeclarationError() << errinfo_sourceLocation(_declaration.getLocation()) << errinfo_comment("Identifier already declared.")); //@todo the exception should also contain the location of the first declaration + _declaration.setScope(m_currentScope); if (_opensScope) enterNewSubScope(_declaration); } diff --git a/libsolidity/NameAndTypeResolver.h b/libsolidity/NameAndTypeResolver.h index 64f3c89db..797eca605 100644 --- a/libsolidity/NameAndTypeResolver.h +++ b/libsolidity/NameAndTypeResolver.h @@ -25,7 +25,7 @@ #include #include -#include +#include #include namespace dev @@ -61,9 +61,9 @@ private: /// Maps nodes declaring a scope to scopes, i.e. ContractDefinition and FunctionDeclaration, /// where nullptr denotes the global scope. Note that structs are not scope since they do /// not contain code. - std::map m_scopes; + std::map m_scopes; - Scope* m_currentScope; + DeclarationContainer* m_currentScope; }; /** @@ -73,7 +73,7 @@ private: class DeclarationRegistrationHelper: private ASTVisitor { public: - DeclarationRegistrationHelper(std::map& _scopes, ASTNode& _astRoot); + DeclarationRegistrationHelper(std::map& _scopes, ASTNode& _astRoot); private: bool visit(ContractDefinition& _contract); @@ -85,12 +85,12 @@ private: void endVisit(VariableDefinition& _variableDefinition); bool visit(VariableDeclaration& _declaration); - void enterNewSubScope(ASTNode& _node); + void enterNewSubScope(Declaration& _declaration); void closeCurrentScope(); void registerDeclaration(Declaration& _declaration, bool _opensScope); - std::map& m_scopes; - Scope* m_currentScope; + std::map& m_scopes; + Declaration* m_currentScope; FunctionDefinition* m_currentFunction; }; From a2aa117a6b2c07747d467ee73afb8776b2813ff3 Mon Sep 17 00:00:00 2001 From: Christian Date: Mon, 1 Dec 2014 17:32:10 +0100 Subject: [PATCH 69/86] Disallow assignments to structs and mappings. --- libsolidity/AST.cpp | 12 +++++++---- libsolidity/AST.h | 16 +++++++++----- test/solidityNameAndTypeResolution.cpp | 30 ++++++++++++++++++++++++++ 3 files changed, 49 insertions(+), 9 deletions(-) diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index 5c07ec80e..4bd0b2c0e 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -378,6 +378,9 @@ void Assignment::checkTypeRequirements() { m_leftHandSide->checkTypeRequirements(); m_leftHandSide->requireLValue(); + //@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) @@ -403,7 +406,7 @@ void Expression::expectType(Type const& _expectedType) void Expression::requireLValue() { - if (!isLvalue()) + if (!isLValue()) BOOST_THROW_EXCEPTION(createTypeError("Expression has to be an lvalue.")); m_lvalueRequested = true; } @@ -495,7 +498,8 @@ void MemberAccess::checkTypeRequirements() m_type = type.getMemberType(*m_memberName); if (!m_type) BOOST_THROW_EXCEPTION(createTypeError("Member \"" + *m_memberName + "\" not found in " + type.toString())); - m_isLvalue = (type.getCategory() == Type::Category::STRUCT && m_type->getCategory() != Type::Category::MAPPING); + //@todo later, this will not always be STORAGE + m_lvalue = type.getCategory() == Type::Category::STRUCT ? LValueType::STORAGE : LValueType::NONE; } void IndexAccess::checkTypeRequirements() @@ -507,7 +511,7 @@ void IndexAccess::checkTypeRequirements() MappingType const& type = dynamic_cast(*m_base->getType()); m_index->expectType(*type.getKeyType()); m_type = type.getValueType(); - m_isLvalue = m_type->getCategory() != Type::Category::MAPPING; + m_lvalue = LValueType::STORAGE; } void Identifier::checkTypeRequirements() @@ -521,7 +525,7 @@ void Identifier::checkTypeRequirements() if (!variable->getType()) BOOST_THROW_EXCEPTION(createTypeError("Variable referenced before type could be determined.")); m_type = variable->getType(); - m_isLvalue = true; + m_lvalue = variable->isLocalVariable() ? LValueType::LOCAL : LValueType::STORAGE; return; } //@todo can we unify these with TypeName::toType()? diff --git a/libsolidity/AST.h b/libsolidity/AST.h index 68b5c8b80..87bc3cd40 100644 --- a/libsolidity/AST.h +++ b/libsolidity/AST.h @@ -242,6 +242,8 @@ public: std::shared_ptr const& getType() const { return m_type; } void setType(std::shared_ptr const& _type) { m_type = _type; } + bool isLocalVariable() const { return !!dynamic_cast(getScope()); } + private: ASTPointer m_typeName; ///< can be empty ("var") @@ -526,12 +528,16 @@ private: */ class Expression: public ASTNode { +protected: + enum class LValueType { NONE, LOCAL, STORAGE }; + public: - Expression(Location const& _location): ASTNode(_location), m_isLvalue(false), m_lvalueRequested(false) {} + Expression(Location const& _location): ASTNode(_location), m_lvalue(LValueType::NONE), m_lvalueRequested(false) {} virtual void checkTypeRequirements() = 0; std::shared_ptr const& getType() const { return m_type; } - bool isLvalue() const { return m_isLvalue; } + bool isLValue() const { return m_lvalue != LValueType::NONE; } + bool isLocalLValue() const { return m_lvalue == LValueType::LOCAL; } /// Helper function, infer the type via @ref checkTypeRequirements and then check that it /// is implicitly convertible to @a _expectedType. If not, throw exception. @@ -546,9 +552,9 @@ public: protected: //! Inferred type of the expression, only filled after a call to checkTypeRequirements(). std::shared_ptr m_type; - //! Whether or not this expression is an lvalue, i.e. something that can be assigned to. - //! This is set during calls to @a checkTypeRequirements() - bool m_isLvalue; + //! If this expression is an lvalue (i.e. something that can be assigned to) and is stored + //! locally or in storage. This is set during calls to @a checkTypeRequirements() + LValueType m_lvalue; //! Whether the outer expression requested the address (true) or the value (false) of this expression. bool m_lvalueRequested; }; diff --git a/test/solidityNameAndTypeResolution.cpp b/test/solidityNameAndTypeResolution.cpp index a19e7450c..8804c519c 100644 --- a/test/solidityNameAndTypeResolution.cpp +++ b/test/solidityNameAndTypeResolution.cpp @@ -244,6 +244,36 @@ BOOST_AUTO_TEST_CASE(balance_invalid) BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError); } +BOOST_AUTO_TEST_CASE(assignment_to_mapping) +{ + char const* text = "contract test {\n" + " struct str {\n" + " mapping(uint=>uint) map;\n" + " }\n" + " str data;" + " function fun() {\n" + " var a = data.map;\n" + " data.map = a;\n" + " }\n" + "}\n"; + BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError); +} + +BOOST_AUTO_TEST_CASE(assignment_to_struct) +{ + char const* text = "contract test {\n" + " struct str {\n" + " mapping(uint=>uint) map;\n" + " }\n" + " str data;" + " function fun() {\n" + " var a = data;\n" + " data = a;\n" + " }\n" + "}\n"; + BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError); +} + BOOST_AUTO_TEST_SUITE_END() } From e6358fce31089c40f88fd5215d0fb734b118f741 Mon Sep 17 00:00:00 2001 From: Christoph Jentzsch Date: Sat, 29 Nov 2014 09:38:48 +0100 Subject: [PATCH 70/86] Avoid memneed overflow --- libevm/VM.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/libevm/VM.h b/libevm/VM.h index 8fdd3de92..2feb6c77e 100644 --- a/libevm/VM.h +++ b/libevm/VM.h @@ -173,15 +173,15 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con // These all operate on memory and therefore potentially expand it: case Instruction::MSTORE: require(2); - newTempSize = m_stack.back() + 32; + newTempSize = (bigint)m_stack.back() + 32; break; case Instruction::MSTORE8: require(2); - newTempSize = m_stack.back() + 1; + newTempSize = (bigint)m_stack.back() + 1; break; case Instruction::MLOAD: require(1); - newTempSize = m_stack.back() + 32; + newTempSize = (bigint)m_stack.back() + 32; break; case Instruction::RETURN: require(2); @@ -236,9 +236,9 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con case Instruction::CREATE: { require(3); - auto inOff = m_stack[m_stack.size() - 2]; - auto inSize = m_stack[m_stack.size() - 3]; - newTempSize = inOff + inSize; + u256 inOff = m_stack[m_stack.size() - 2]; + u256 inSize = m_stack[m_stack.size() - 3]; + newTempSize = (bigint)inOff + inSize; runGas = c_createGas; break; } From c4138a5ad4e9d91954f5a6fb480466f32f4317d5 Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Mon, 1 Dec 2014 22:04:09 +0100 Subject: [PATCH 71/86] added logs to state tests --- test/TestHelper.cpp | 43 +++++++++++++++++++++++++++++++++++++++ test/TestHelper.h | 2 ++ test/stExampleFiller.json | 37 +++++++++++++++++++++++++++++++++ test/state.cpp | 3 +++ test/vm.cpp | 39 ++--------------------------------- test/vm.h | 2 -- 6 files changed, 87 insertions(+), 39 deletions(-) create mode 100644 test/stExampleFiller.json diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp index b3d1bbe80..b9575ad2b 100644 --- a/test/TestHelper.cpp +++ b/test/TestHelper.cpp @@ -72,6 +72,7 @@ ImportTest::ImportTest(json_spirit::mObject& _o, bool isFiller): m_TestObject(_o if (!isFiller) { importState(_o["post"].get_obj(), m_statePost); + m_environment.sub.logs = importLog(_o["logs"].get_obj()); } } @@ -95,6 +96,7 @@ void ImportTest::importEnv(json_spirit::mObject& _o) m_statePre.m_currentBlock = m_environment.currentBlock; } + void ImportTest::importState(json_spirit::mObject& _o, State& _state) { for (auto& i: _o) @@ -148,6 +150,9 @@ void ImportTest::exportTest(bytes _output, State& _statePost) // export output m_TestObject["out"] = "0x" + toHex(_output); + // export logs + m_TestObject["logs"] = exportLog(_statePost.pending().size() ? _statePost.log(0) : LogEntries()); + // export post state json_spirit::mObject postState; @@ -255,6 +260,44 @@ bytes importCode(json_spirit::mObject& _o) return code; } +LogEntries importLog(json_spirit::mObject& _o) +{ + LogEntries logEntries; + for (auto const& l: _o) + { + json_spirit::mObject o = l.second.get_obj(); + // cant use BOOST_REQUIRE, because this function is used outside boost test (createRandomTest) + assert(o.count("address") > 0); + assert(o.count("topics") > 0); + assert(o.count("data") > 0); + LogEntry log; + log.address = Address(o["address"].get_str()); + for (auto const& t: o["topics"].get_array()) + log.topics.insert(h256(t.get_str())); + log.data = importData(o); + logEntries.push_back(log); + } + return logEntries; +} + +json_spirit::mObject exportLog(eth::LogEntries _logs) +{ + json_spirit::mObject ret; + if (_logs.size() == 0) return ret; + for (LogEntry const& l: _logs) + { + json_spirit::mObject o; + o["address"] = toString(l.address); + json_spirit::mArray topics; + for (auto const& t: l.topics) + topics.push_back(toString(t)); + o["topics"] = topics; + o["data"] = "0x" + toHex(l.data); + ret[toString(l.bloom())] = o; + } + return ret; +} + void checkOutput(bytes const& _output, json_spirit::mObject& _o) { int j = 0; diff --git a/test/TestHelper.h b/test/TestHelper.h index 7a2b8da51..c5c3a083d 100644 --- a/test/TestHelper.h +++ b/test/TestHelper.h @@ -68,6 +68,8 @@ u256 toInt(json_spirit::mValue const& _v); byte toByte(json_spirit::mValue const& _v); bytes importCode(json_spirit::mObject& _o); bytes importData(json_spirit::mObject& _o); +eth::LogEntries importLog(json_spirit::mObject& _o); +json_spirit::mObject exportLog(eth::LogEntries _logs); void checkOutput(bytes const& _output, json_spirit::mObject& _o); void checkStorage(std::map _expectedStore, std::map _resultStore, Address _expectedAddr); void checkLog(eth::LogEntries _resultLogs, eth::LogEntries _expectedLogs); diff --git a/test/stExampleFiller.json b/test/stExampleFiller.json new file mode 100644 index 000000000..7acf695ed --- /dev/null +++ b/test/stExampleFiller.json @@ -0,0 +1,37 @@ +{ + "add11" : { + "env" : { + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentDifficulty" : "256", + "currentGasLimit" : "1000000", + "currentNumber" : "0", + "currentTimestamp" : 1, + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "1000000000000000000", + "code" : "0x6001600101600055", + "nonce" : "0", + "storage" : { + } + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "code" : "0x", + "nonce" : "0", + "storage" : { + } + } + }, + "transaction" : { + "data" : "", + "gasLimit" : "10000", + "gasPrice" : "1", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000" + } + } +} diff --git a/test/state.cpp b/test/state.cpp index 8ee7b2e96..c2b41fca5 100644 --- a/test/state.cpp +++ b/test/state.cpp @@ -81,6 +81,9 @@ void doStateTests(json_spirit::mValue& v, bool _fillin) // check output checkOutput(output, o); + // check logs + checkLog(theState.pending().size() ? theState.log(0) : LogEntries(), importer.m_environment.sub.logs); + // check addresses auto expectedAddrs = importer.m_statePost.addresses(); auto resultAddrs = theState.addresses(); diff --git a/test/vm.cpp b/test/vm.cpp index edb983714..0d61bf6ba 100644 --- a/test/vm.cpp +++ b/test/vm.cpp @@ -120,41 +120,6 @@ void FakeExtVM::importEnv(mObject& _o) currentBlock.coinbaseAddress = Address(_o["currentCoinbase"].get_str()); } -mObject FakeExtVM::exportLog() -{ - mObject ret; - for (LogEntry const& l: sub.logs) - { - mObject o; - o["address"] = toString(l.address); - mArray topics; - for (auto const& t: l.topics) - topics.push_back(toString(t)); - o["topics"] = topics; - o["data"] = "0x" + toHex(l.data); - ret[toString(l.bloom())] = o; - } - return ret; -} - -void FakeExtVM::importLog(mObject& _o) -{ - for (auto const& l: _o) - { - mObject o = l.second.get_obj(); - // cant use BOOST_REQUIRE, because this function is used outside boost test (createRandomTest) - assert(o.count("address") > 0); - assert(o.count("topics") > 0); - assert(o.count("data") > 0); - LogEntry log; - log.address = Address(o["address"].get_str()); - for (auto const& t: o["topics"].get_array()) - log.topics.insert(h256(t.get_str())); - log.data = importData(o); - sub.logs.push_back(log); - } -} - mObject FakeExtVM::exportState() { mObject ret; @@ -384,7 +349,7 @@ void doVMTests(json_spirit::mValue& v, bool _fillin) o["callcreates"] = fev.exportCallCreates(); o["out"] = "0x" + toHex(output); fev.push(o, "gas", gas); - o["logs"] = mValue(fev.exportLog()); + o["logs"] = mValue(exportLog(fev.sub.logs)); } } else @@ -402,7 +367,7 @@ void doVMTests(json_spirit::mValue& v, bool _fillin) dev::test::FakeExtVM test; test.importState(o["post"].get_obj()); test.importCallCreates(o["callcreates"].get_array()); - test.importLog(o["logs"].get_obj()); + test.sub.logs = importLog(o["logs"].get_obj()); checkOutput(output, o); diff --git a/test/vm.h b/test/vm.h index eb98aa0ab..a52a02e31 100644 --- a/test/vm.h +++ b/test/vm.h @@ -66,8 +66,6 @@ public: u256 doPosts(); json_spirit::mObject exportEnv(); void importEnv(json_spirit::mObject& _o); - json_spirit::mObject exportLog(); - void importLog(json_spirit::mObject& _o); json_spirit::mObject exportState(); void importState(json_spirit::mObject& _object); json_spirit::mObject exportExec(); From 934d366cdbbeb5bc422cb0a68f4dc81303d6e61d Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Mon, 1 Dec 2014 22:26:13 +0100 Subject: [PATCH 72/86] updated createRandomTest to correct exception behavior --- test/createRandomTest.cpp | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/test/createRandomTest.cpp b/test/createRandomTest.cpp index 60a2039c8..1647ce810 100644 --- a/test/createRandomTest.cpp +++ b/test/createRandomTest.cpp @@ -121,14 +121,14 @@ void doMyTests(json_spirit::mValue& v) { for (auto& i: v.get_obj()) { + cnote << i.first; mObject& o = i.second.get_obj(); assert(o.count("env") > 0); assert(o.count("pre") > 0); assert(o.count("exec") > 0); - eth::VM vm; - test::FakeExtVM fev; + dev::test::FakeExtVM fev; fev.importEnv(o["env"].get_obj()); fev.importState(o["pre"].get_obj()); @@ -141,17 +141,20 @@ void doMyTests(json_spirit::mValue& v) fev.code = fev.thisTxCode; } - vm.reset(fev.gas); bytes output; + eth::VM vm(fev.gas); + u256 gas; + bool vmExceptionOccured = false; try { - output = vm.go(fev).toBytes(); + output = vm.go(fev, fev.simpleTrace()).toBytes(); + gas = vm.gas(); } catch (eth::VMException const& _e) { cnote << "VM did throw an exception: " << diagnostic_information(_e); - gas = 0; + vmExceptionOccured = true; } catch (Exception const& _e) { @@ -180,9 +183,13 @@ void doMyTests(json_spirit::mValue& v) o["env"] = mValue(fev.exportEnv()); o["exec"] = mValue(fev.exportExec()); - o["post"] = mValue(fev.exportState()); - o["callcreates"] = fev.exportCallCreates(); - o["out"] = "0x" + toHex(output); - fev.push(o, "gas", gas); + if (!vmExceptionOccured) + { + o["post"] = mValue(fev.exportState()); + o["callcreates"] = fev.exportCallCreates(); + o["out"] = "0x" + toHex(output); + fev.push(o, "gas", gas); + o["logs"] = mValue(test::exportLog(fev.sub.logs)); + } } } From 8245dd69789fe3ff0241af416841f923ce3001f4 Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Mon, 1 Dec 2014 22:44:31 +0100 Subject: [PATCH 73/86] style Conflicts: libevm/VM.h --- test/TestHelper.cpp | 67 ++++++++++++++++++++++----------------------- test/state.cpp | 4 +-- test/vm.cpp | 4 +-- 3 files changed, 37 insertions(+), 38 deletions(-) diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp index b9575ad2b..bfdd393d7 100644 --- a/test/TestHelper.cpp +++ b/test/TestHelper.cpp @@ -72,7 +72,7 @@ ImportTest::ImportTest(json_spirit::mObject& _o, bool isFiller): m_TestObject(_o if (!isFiller) { importState(_o["post"].get_obj(), m_statePost); - m_environment.sub.logs = importLog(_o["logs"].get_obj()); + m_environment.sub.logs = importLog(_o["logs"].get_obj()); } } @@ -96,7 +96,6 @@ void ImportTest::importEnv(json_spirit::mObject& _o) m_statePre.m_currentBlock = m_environment.currentBlock; } - void ImportTest::importState(json_spirit::mObject& _o, State& _state) { for (auto& i: _o) @@ -150,8 +149,8 @@ void ImportTest::exportTest(bytes _output, State& _statePost) // export output m_TestObject["out"] = "0x" + toHex(_output); - // export logs - m_TestObject["logs"] = exportLog(_statePost.pending().size() ? _statePost.log(0) : LogEntries()); + // export logs + m_TestObject["logs"] = exportLog(_statePost.pending().size() ? _statePost.log(0) : LogEntries()); // export post state json_spirit::mObject postState; @@ -262,40 +261,40 @@ bytes importCode(json_spirit::mObject& _o) LogEntries importLog(json_spirit::mObject& _o) { - LogEntries logEntries; - for (auto const& l: _o) - { - json_spirit::mObject o = l.second.get_obj(); - // cant use BOOST_REQUIRE, because this function is used outside boost test (createRandomTest) - assert(o.count("address") > 0); - assert(o.count("topics") > 0); - assert(o.count("data") > 0); - LogEntry log; - log.address = Address(o["address"].get_str()); - for (auto const& t: o["topics"].get_array()) - log.topics.insert(h256(t.get_str())); - log.data = importData(o); - logEntries.push_back(log); - } - return logEntries; + LogEntries logEntries; + for (auto const& l: _o) + { + json_spirit::mObject o = l.second.get_obj(); + // cant use BOOST_REQUIRE, because this function is used outside boost test (createRandomTest) + assert(o.count("address") > 0); + assert(o.count("topics") > 0); + assert(o.count("data") > 0); + LogEntry log; + log.address = Address(o["address"].get_str()); + for (auto const& t: o["topics"].get_array()) + log.topics.insert(h256(t.get_str())); + log.data = importData(o); + logEntries.push_back(log); + } + return logEntries; } json_spirit::mObject exportLog(eth::LogEntries _logs) { - json_spirit::mObject ret; - if (_logs.size() == 0) return ret; - for (LogEntry const& l: _logs) - { - json_spirit::mObject o; - o["address"] = toString(l.address); - json_spirit::mArray topics; - for (auto const& t: l.topics) - topics.push_back(toString(t)); - o["topics"] = topics; - o["data"] = "0x" + toHex(l.data); - ret[toString(l.bloom())] = o; - } - return ret; + json_spirit::mObject ret; + if (_logs.size() == 0) return ret; + for (LogEntry const& l: _logs) + { + json_spirit::mObject o; + o["address"] = toString(l.address); + json_spirit::mArray topics; + for (auto const& t: l.topics) + topics.push_back(toString(t)); + o["topics"] = topics; + o["data"] = "0x" + toHex(l.data); + ret[toString(l.bloom())] = o; + } + return ret; } void checkOutput(bytes const& _output, json_spirit::mObject& _o) diff --git a/test/state.cpp b/test/state.cpp index c2b41fca5..5fc23f149 100644 --- a/test/state.cpp +++ b/test/state.cpp @@ -81,8 +81,8 @@ void doStateTests(json_spirit::mValue& v, bool _fillin) // check output checkOutput(output, o); - // check logs - checkLog(theState.pending().size() ? theState.log(0) : LogEntries(), importer.m_environment.sub.logs); + // check logs + checkLog(theState.pending().size() ? theState.log(0) : LogEntries(), importer.m_environment.sub.logs); // check addresses auto expectedAddrs = importer.m_statePost.addresses(); diff --git a/test/vm.cpp b/test/vm.cpp index 0d61bf6ba..8c9810a2c 100644 --- a/test/vm.cpp +++ b/test/vm.cpp @@ -349,7 +349,7 @@ void doVMTests(json_spirit::mValue& v, bool _fillin) o["callcreates"] = fev.exportCallCreates(); o["out"] = "0x" + toHex(output); fev.push(o, "gas", gas); - o["logs"] = mValue(exportLog(fev.sub.logs)); + o["logs"] = mValue(exportLog(fev.sub.logs)); } } else @@ -367,7 +367,7 @@ void doVMTests(json_spirit::mValue& v, bool _fillin) dev::test::FakeExtVM test; test.importState(o["post"].get_obj()); test.importCallCreates(o["callcreates"].get_array()); - test.sub.logs = importLog(o["logs"].get_obj()); + test.sub.logs = importLog(o["logs"].get_obj()); checkOutput(output, o); From 34652f0284c15d76538c6eed7a034c20f0cc6b25 Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Mon, 1 Dec 2014 22:51:16 +0100 Subject: [PATCH 74/86] style --- libevm/VM.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/libevm/VM.h b/libevm/VM.h index 8fdd3de92..95af13e6f 100644 --- a/libevm/VM.h +++ b/libevm/VM.h @@ -53,9 +53,6 @@ inline Address asAddress(u256 _item) inline u256 fromAddress(Address _a) { return (u160)_a; -// h256 ret; -// memcpy(&ret, &_a, sizeof(_a)); -// return ret; } /** From 7269fe10651c34ad04e44263af8082b2d9db9fa3 Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Mon, 1 Dec 2014 22:56:18 +0100 Subject: [PATCH 75/86] style --- libevm/VM.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/libevm/VM.h b/libevm/VM.h index 2feb6c77e..be5147b16 100644 --- a/libevm/VM.h +++ b/libevm/VM.h @@ -173,15 +173,15 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con // These all operate on memory and therefore potentially expand it: case Instruction::MSTORE: require(2); - newTempSize = (bigint)m_stack.back() + 32; + newTempSize = (bigint)m_stack.back() + 32; break; case Instruction::MSTORE8: require(2); - newTempSize = (bigint)m_stack.back() + 1; + newTempSize = (bigint)m_stack.back() + 1; break; case Instruction::MLOAD: require(1); - newTempSize = (bigint)m_stack.back() + 32; + newTempSize = (bigint)m_stack.back() + 32; break; case Instruction::RETURN: require(2); @@ -236,10 +236,10 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con case Instruction::CREATE: { require(3); - u256 inOff = m_stack[m_stack.size() - 2]; - u256 inSize = m_stack[m_stack.size() - 3]; - newTempSize = (bigint)inOff + inSize; - runGas = c_createGas; + u256 inOff = m_stack[m_stack.size() - 2]; + u256 inSize = m_stack[m_stack.size() - 3]; + newTempSize = (bigint)inOff + inSize; + runGas = c_createGas; break; } case Instruction::EXP: From 1edbaae205354f4f1c08545d01e3d3359f07295f Mon Sep 17 00:00:00 2001 From: yann300 Date: Tue, 2 Dec 2014 11:54:33 +0100 Subject: [PATCH 76/86] delete reference to Qt5Declarative --- mix/CMakeLists.txt | 4 +--- mix/CodeEditorExtensionManager.cpp | 2 -- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/mix/CMakeLists.txt b/mix/CMakeLists.txt index 152485cec..14a33ab11 100644 --- a/mix/CMakeLists.txt +++ b/mix/CMakeLists.txt @@ -11,8 +11,7 @@ elseif ("${TARGET_PLATFORM}" STREQUAL "w64") set(SRC_LIST ${SRC_LIST} ../windows/qt_plugin_import.cpp) include_directories(/usr/x86_64-w64-mingw32/include /usr/x86_64-w64-mingw32/include/QtCore /usr/x86_64-w64-mingw32/include/QtGui /usr/x86_64-w64-mingw32/include/QtQuick /usr/x86_64-w64-mingw32/include/QtQml /usr/x86_64-w64-mingw32/include/QtNetwork /usr/x86_64-w64-mingw32/include/QtWidgets /usr/x86_64-w64-mingw32/include/QtWebKit /usr/x86_64-w64-mingw32/include/QtWebKitWidgets) elseif (UNIX) - set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} ";$ENV{QTDIR}/lib/cmake") - set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} ";/opt/Qt5.3.2/5.3/gcc_64/lib/cmake") + set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} ";$ENV{QTDIR}/lib/cmake;../cmake/") endif () find_package(Qt5Core REQUIRED) @@ -23,7 +22,6 @@ find_package(Qt5Network REQUIRED) find_package(Qt5Widgets REQUIRED) find_package(Qt5WebKit REQUIRED) find_package(Qt5WebKitWidgets REQUIRED) -find_package(Qt5Declarative REQUIRED) #qt5_wrap_ui(ui_Main.h Main.ui) diff --git a/mix/CodeEditorExtensionManager.cpp b/mix/CodeEditorExtensionManager.cpp index 4a46c60d4..596aea165 100644 --- a/mix/CodeEditorExtensionManager.cpp +++ b/mix/CodeEditorExtensionManager.cpp @@ -22,9 +22,7 @@ #include #include -#include #include -#include #include #include #include From 2f355039b609b50dc2099a50aa1c9abecbc584ce Mon Sep 17 00:00:00 2001 From: yann300 Date: Tue, 2 Dec 2014 12:13:28 +0100 Subject: [PATCH 77/86] delete qt5declarative from qt5_use_modules (cmake) --- mix/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mix/CMakeLists.txt b/mix/CMakeLists.txt index 14a33ab11..da214fd29 100644 --- a/mix/CMakeLists.txt +++ b/mix/CMakeLists.txt @@ -11,7 +11,7 @@ elseif ("${TARGET_PLATFORM}" STREQUAL "w64") set(SRC_LIST ${SRC_LIST} ../windows/qt_plugin_import.cpp) include_directories(/usr/x86_64-w64-mingw32/include /usr/x86_64-w64-mingw32/include/QtCore /usr/x86_64-w64-mingw32/include/QtGui /usr/x86_64-w64-mingw32/include/QtQuick /usr/x86_64-w64-mingw32/include/QtQml /usr/x86_64-w64-mingw32/include/QtNetwork /usr/x86_64-w64-mingw32/include/QtWidgets /usr/x86_64-w64-mingw32/include/QtWebKit /usr/x86_64-w64-mingw32/include/QtWebKitWidgets) elseif (UNIX) - set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} ";$ENV{QTDIR}/lib/cmake;../cmake/") + set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} ";$ENV{QTDIR}/lib/cmake") endif () find_package(Qt5Core REQUIRED) @@ -91,4 +91,4 @@ else () install( TARGETS ${EXECUTEABLE} RUNTIME DESTINATION bin ) endif () -qt5_use_modules(${EXECUTEABLE} Core Gui Declarative) +qt5_use_modules(${EXECUTEABLE} Core Gui) From 5cb03bf293c3a7764d2260899fc91c68f0fdcf75 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 2 Dec 2014 15:19:00 +0100 Subject: [PATCH 78/86] Debug outputs. --- alethzero/MainWin.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index fc27d6e30..4a32f66b2 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -1261,6 +1261,9 @@ void Main::on_blocks_currentItemChanged() s << "
Gas used/limit: " << info.gasUsed << "/" << info.gasLimit << ""; s << "
Coinbase: " << pretty(info.coinbaseAddress).toHtmlEscaped().toStdString() << " " << info.coinbaseAddress; s << "
Nonce: " << info.nonce << ""; + s << "
Hash w/o nonce: " << info.headerHashWithoutNonce() << ""; + s << "
Difficulty: " << info.difficulty << ""; + s << "
Proof-of-Work: " << ProofOfWork::eval(info.headerHashWithoutNonce(), info.nonce) << " <= " << (h256)u256((bigint(1) << 256) / info.difficulty) << ""; s << "
Parent: " << info.parentHash << ""; // s << "
Bloom: " << details.bloom << ""; s << "
Log Bloom: " << info.logBloom << ""; @@ -1281,6 +1284,7 @@ void Main::on_blocks_currentItemChanged() for (auto const& i: block[1]) s << "
" << sha3(i.data()).abridged();// << ": " << i[1].toHash() << " [" << i[2].toInt() << " used]"; s << "
Post: " << info.stateRoot << ""; + s << "
Dump: " << toHex(block[0].data()) << ""; } else { From 8cbea38df9a05f79f128ecfd67b5e3670b19c07a Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 2 Dec 2014 17:13:17 +0100 Subject: [PATCH 79/86] PV46. Minor protocol alterations. --- libdevcore/Common.cpp | 2 +- libethcore/CommonEth.cpp | 2 +- libethereum/MessageFilter.cpp | 2 +- libevm/ExtVMFace.h | 6 +++--- libevmcore/Instruction.h | 2 +- test/vm.cpp | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/libdevcore/Common.cpp b/libdevcore/Common.cpp index 280268d8b..55250b418 100644 --- a/libdevcore/Common.cpp +++ b/libdevcore/Common.cpp @@ -27,7 +27,7 @@ using namespace dev; namespace dev { -char const* Version = "0.7.11"; +char const* Version = "0.7.12"; } diff --git a/libethcore/CommonEth.cpp b/libethcore/CommonEth.cpp index 010b7e408..744e85a27 100644 --- a/libethcore/CommonEth.cpp +++ b/libethcore/CommonEth.cpp @@ -33,7 +33,7 @@ namespace dev namespace eth { -const unsigned c_protocolVersion = 45; +const unsigned c_protocolVersion = 46; const unsigned c_databaseVersion = 5; static const vector> g_units = diff --git a/libethereum/MessageFilter.cpp b/libethereum/MessageFilter.cpp index b04d213f9..0519fe28b 100644 --- a/libethereum/MessageFilter.cpp +++ b/libethereum/MessageFilter.cpp @@ -198,7 +198,7 @@ LogEntries LogFilter::matches(TransactionReceipt const& _m) const if (!m_addresses.empty() && !m_addresses.count(e.address)) continue; for (auto const& t: m_topics) - if (!e.topics.count(t)) + if (!std::count(e.topics.begin(), e.topics.end(), t)) continue; ret.push_back(e); } diff --git a/libevm/ExtVMFace.h b/libevm/ExtVMFace.h index 65761e410..9e6601d0a 100644 --- a/libevm/ExtVMFace.h +++ b/libevm/ExtVMFace.h @@ -49,8 +49,8 @@ using LogBloom = h512; struct LogEntry { LogEntry() {} - LogEntry(RLP const& _r) { address = (Address)_r[0]; topics = (h256Set)_r[1]; data = _r[2].toBytes(); } - LogEntry(Address const& _address, h256s const& _ts, bytes&& _d): address(_address), topics(toSet(_ts)), data(std::move(_d)) {} + LogEntry(RLP const& _r) { address = (Address)_r[0]; topics = (h256s)_r[1]; data = _r[2].toBytes(); } + LogEntry(Address const& _address, h256s const& _ts, bytes&& _d): address(_address), topics(_ts), data(std::move(_d)) {} void streamRLP(RLPStream& _s) const { _s.appendList(3) << address << topics << data; } @@ -64,7 +64,7 @@ struct LogEntry } Address address; - h256Set topics; + h256s topics; bytes data; }; diff --git a/libevmcore/Instruction.h b/libevmcore/Instruction.h index eb85c0610..f8a0478f1 100644 --- a/libevmcore/Instruction.h +++ b/libevmcore/Instruction.h @@ -168,8 +168,8 @@ enum class Instruction: uint8_t 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 - CALLCODE, SUICIDE = 0xff ///< halt execution and register account for later deletion }; diff --git a/test/vm.cpp b/test/vm.cpp index edb983714..1286df420 100644 --- a/test/vm.cpp +++ b/test/vm.cpp @@ -149,7 +149,7 @@ void FakeExtVM::importLog(mObject& _o) LogEntry log; log.address = Address(o["address"].get_str()); for (auto const& t: o["topics"].get_array()) - log.topics.insert(h256(t.get_str())); + log.topics.push_back(h256(t.get_str())); log.data = importData(o); sub.logs.push_back(log); } From 92b0ff7a10c6577509e07e66f755a585f36fce20 Mon Sep 17 00:00:00 2001 From: Christian Date: Tue, 2 Dec 2014 17:53:25 +0100 Subject: [PATCH 80/86] Fix: Storage offset of first struct member should be zero. --- libsolidity/Types.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index b81fbbe31..7e07b1162 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -295,9 +295,9 @@ u256 StructType::getStorageOffsetOfMember(string const& _name) const u256 offset; for (ASTPointer variable: m_struct.getMembers()) { - offset += variable->getType()->getStorageSize(); if (variable->getName() == _name) return offset; + offset += variable->getType()->getStorageSize(); } BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Storage offset of non-existing member requested.")); } From e9972a551c757663f2db5249c5ab0bb7b4083a75 Mon Sep 17 00:00:00 2001 From: Christian Date: Tue, 2 Dec 2014 17:51:52 +0100 Subject: [PATCH 81/86] Optimizer for literals and identity operations. --- libevmcore/Assembly.cpp | 117 +++++++++++++++++++++++++++++----------- libevmcore/Assembly.h | 3 ++ 2 files changed, 88 insertions(+), 32 deletions(-) diff --git a/libevmcore/Assembly.cpp b/libevmcore/Assembly.cpp index 4725c8c1a..059810af8 100644 --- a/libevmcore/Assembly.cpp +++ b/libevmcore/Assembly.cpp @@ -27,6 +27,32 @@ using namespace std; using namespace dev; using namespace dev::eth; +unsigned AssemblyItem::bytesRequired(unsigned _addressLength) const +{ + switch (m_type) + { + case Operation: + case Tag: // 1 byte for the JUMPDEST + return 1; + case PushString: + return 33; + case Push: + return 1 + max(1, dev::bytesRequired(m_data)); + case PushSubSize: + return 4; // worst case: a 16MB program + case PushTag: + case PushData: + case PushSub: + return 1 + _addressLength; + case NoOptimizeBegin: + case NoOptimizeEnd: + return 0; + default: + break; + } + BOOST_THROW_EXCEPTION(InvalidOpcode()); +} + int AssemblyItem::deposit() const { switch (m_type) @@ -51,32 +77,7 @@ unsigned Assembly::bytesRequired() const ret += i.second.size(); for (AssemblyItem const& i: m_items) - switch (i.m_type) - { - case Operation: - case Tag: // 1 byte for the JUMPDEST - ret++; - break; - case PushString: - ret += 33; - break; - case Push: - ret += 1 + max(1, dev::bytesRequired(i.m_data)); - break; - case PushSubSize: - ret += 4; // worst case: a 16MB program - break; - case PushTag: - case PushData: - case PushSub: - ret += 1 + br; - break; - case NoOptimizeBegin: - case NoOptimizeEnd: - break; - default: - BOOST_THROW_EXCEPTION(InvalidOpcode()); - } + ret += i.bytesRequired(br); if (dev::bytesRequired(ret) <= br) return ret; } @@ -243,6 +244,18 @@ inline bool popCountIncreased(AssemblyItemsConstRef _pre, AssemblyItems const& _ return count_if(begin(_post), end(_post), isPop) > count_if(begin(_pre), end(_pre), isPop); } +//@todo this has to move to a special optimizer class soon +template +unsigned bytesRequiredBySlice(Iterator _begin, Iterator _end) +{ + // this is only used in the optimizer, so we can provide a guess for the address length + unsigned addressLength = 4; + unsigned size = 0; + for (; _begin != _end; ++_begin) + size += _begin->bytesRequired(addressLength); + return size; +} + struct OptimiserChannel: public LogChannel { static const char* name() { return "OPT"; } static const int verbosity = 12; }; #define copt dev::LogOutputStream() @@ -258,7 +271,7 @@ Assembly& Assembly::optimise(bool _enable) u256 mask = (u256(1) << testBit) - 1; return boost::multiprecision::bit_test(b, testBit) ? b | ~mask : b & mask; }; - map> c_simple = + map> const c_simple = { { Instruction::SUB, [](u256 a, u256 b)->u256{return a - b;} }, { Instruction::DIV, [](u256 a, u256 b)->u256{return a / b;} }, @@ -273,7 +286,7 @@ Assembly& Assembly::optimise(bool _enable) { Instruction::SGT, [](u256 a, u256 b)->u256{return u2s(a) > u2s(b) ? 1 : 0;} }, { Instruction::EQ, [](u256 a, u256 b)->u256{return a == b ? 1 : 0;} }, }; - map> c_associative = + map> const c_associative = { { Instruction::ADD, [](u256 a, u256 b)->u256{return a + b;} }, { Instruction::MUL, [](u256 a, u256 b)->u256{return a * b;} }, @@ -281,6 +294,8 @@ Assembly& Assembly::optimise(bool _enable) { Instruction::OR, [](u256 a, u256 b)->u256{return a | b;} }, { Instruction::XOR, [](u256 a, u256 b)->u256{return a ^ b;} }, }; + std::vector> const c_identities = + { { Instruction::ADD, 0}, { Instruction::MUL, 1}, { Instruction::MOD, 0}, { Instruction::OR, 0}, { Instruction::XOR, 0} }; std::vector>> rules = { { { Push, Instruction::POP }, [](AssemblyItemsConstRef) -> AssemblyItems { return {}; } }, @@ -299,8 +314,11 @@ Assembly& Assembly::optimise(bool _enable) rules.push_back({ { Push, Push, i.first }, [&](AssemblyItemsConstRef m) -> AssemblyItems { return { i.second(m[1].data(), m[0].data()) }; } }); rules.push_back({ { Push, i.first, Push, i.first }, [&](AssemblyItemsConstRef m) -> AssemblyItems { return { i.second(m[2].data(), m[0].data()), i.first }; } }); } + for (auto const& i: c_identities) + rules.push_back({{Push, i.first}, [&](AssemblyItemsConstRef m) -> AssemblyItems + { return m[0].data() == i.second ? AssemblyItems() : m.toVector(); }}); // jump to next instruction - rules.push_back({ { PushTag, Instruction::JUMP, Tag }, [&](AssemblyItemsConstRef m) -> AssemblyItems { if (m[0].m_data == m[2].m_data) return {m[2]}; else return m.toVector(); }}); + rules.push_back({ { PushTag, Instruction::JUMP, Tag }, [](AssemblyItemsConstRef m) -> AssemblyItems { if (m[0].m_data == m[2].m_data) return {m[2]}; else return m.toVector(); }}); // pop optimization, do not compute values that are popped again anyway rules.push_back({ { AssemblyItem(UndefinedItem), Instruction::POP }, [](AssemblyItemsConstRef m) -> AssemblyItems @@ -315,6 +333,29 @@ Assembly& Assembly::optimise(bool _enable) return m.toVector(); return AssemblyItems(info.args, Instruction::POP); } }); + // compute constants close to powers of two by expressions + auto computeConstants = [](AssemblyItemsConstRef m) -> AssemblyItems + { + u256 const& c = m[0].data(); + unsigned const minBits = 4 * 8; + if (c < (bigint(1) << minBits)) + return m.toVector(); // we need at least "PUSH1 PUSH1 <2> EXP" + if (c == u256(-1)) + return {u256(0), Instruction::NOT}; + for (unsigned bits = minBits; bits < 256; ++bits) + { + bigint const diff = c - (bigint(1) << bits); + if (abs(diff) > 0xff) + continue; + AssemblyItems powerOfTwo{u256(bits), u256(2), Instruction::EXP}; + if (diff == 0) + return powerOfTwo; + return AssemblyItems{u256(abs(diff))} + powerOfTwo + + AssemblyItems{diff > 0 ? Instruction::ADD : Instruction::SUB}; + } + return m.toVector(); + }; + rules.push_back({{Push}, computeConstants}); copt << *this; @@ -336,15 +377,27 @@ Assembly& Assembly::optimise(bool _enable) if (matches(vr, &r.first)) { auto rw = r.second(vr); - if (rw.size() < vr.size() || (rw.size() == vr.size() && popCountIncreased(vr, rw))) + 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..."; - for (unsigned j = 0; j < vr.size(); ++j) + copt << AssemblyItemsConstRef(&rw); + if (rw.size() > vr.size()) + { + // create hole in the vector + unsigned sizeIncrease = rw.size() - vr.size(); + m_items.resize(m_items.size() + sizeIncrease, AssemblyItem(UndefinedItem)); + move_backward(m_items.begin() + i, m_items.end() - sizeIncrease, m_items.end()); + } + + 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()); - copt << AssemblyItemsConstRef(&rw); + count++; copt << "Now:\n" << m_items; } diff --git a/libevmcore/Assembly.h b/libevmcore/Assembly.h index b8e59a474..b144dd8d9 100644 --- a/libevmcore/Assembly.h +++ b/libevmcore/Assembly.h @@ -51,6 +51,9 @@ public: AssemblyItemType type() const { return m_type; } u256 data() const { return m_data; } + /// @returns an upper bound for the number of bytes required by this item, assuming that + /// the value of a jump tag takes @a _addressLength bytes. + unsigned bytesRequired(unsigned _addressLength) const; int deposit() const; bool match(AssemblyItem const& _i) const { return _i.m_type == UndefinedItem || (m_type == _i.m_type && (m_type != Operation || m_data == _i.m_data)); } From 240f6b0df7d03534b7ea9cf22e4113f8e1307ccb Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 2 Dec 2014 20:18:01 +0100 Subject: [PATCH 82/86] Warnings fixes (well.. the UPnP was actually a crash fix.) --- libp2p/Host.cpp | 2 +- libsolidity/Compiler.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index b233fe552..cad1b179c 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -155,7 +155,7 @@ bi::tcp::endpoint Host::traverseNAT(std::vector const& _ifAddresses { asserts(_listenPort != 0); - UPnP* upnp; + UPnP* upnp = nullptr; try { upnp = new UPnP; diff --git a/libsolidity/Compiler.cpp b/libsolidity/Compiler.cpp index 988390d0b..17ad4fd16 100644 --- a/libsolidity/Compiler.cpp +++ b/libsolidity/Compiler.cpp @@ -324,7 +324,7 @@ bool Compiler::visit(ExpressionStatement& _expressionStatement) { Expression& expression = _expressionStatement.getExpression(); ExpressionCompiler::compileExpression(m_context, expression); - Type::Category category = expression.getType()->getCategory(); +// Type::Category category = expression.getType()->getCategory(); for (unsigned i = 0; i < expression.getType()->getSizeOnStack(); ++i) m_context << eth::Instruction::POP; return false; From e7be7244960c4f2898b6ba5c32f8a0f36b4bcb21 Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Wed, 3 Dec 2014 08:36:52 +0100 Subject: [PATCH 83/86] test update due to CALLCODA <-> RETURN --- test/stSystemOperationsTestFiller.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/stSystemOperationsTestFiller.json b/test/stSystemOperationsTestFiller.json index e62753089..edd803641 100644 --- a/test/stSystemOperationsTestFiller.json +++ b/test/stSystemOperationsTestFiller.json @@ -12,7 +12,7 @@ "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "{ (MSTORE 0 0x601080600c6000396000f20060003554156009570060203560003555) [[ 0 ]] (CREATE 23 4 28) }", + "code" : "{ (MSTORE 0 0x601080600c6000396000f30060003554156009570060203560003555) [[ 0 ]] (CREATE 23 4 28) }", "storage": {} }, "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { @@ -46,7 +46,7 @@ "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "{ (MSTORE 0 0x601080600c6000396000f20060003554156009570060203560003555) [[ 0 ]] (CREATE 1000 4 28) }", + "code" : "{ (MSTORE 0 0x601080600c6000396000f30060003554156009570060203560003555) [[ 0 ]] (CREATE 1000 4 28) }", "storage": {} }, "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { @@ -80,7 +80,7 @@ "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "{ (MSTORE 0 0x601080600c6000396000f20060003554156009570060203560003555) [[ 0 ]] (CREATE 23 0xfffffffffff 28) }", + "code" : "{ (MSTORE 0 0x601080600c6000396000f30060003554156009570060203560003555) [[ 0 ]] (CREATE 23 0xfffffffffff 28) }", "storage": {} }, "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { @@ -114,7 +114,7 @@ "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "{ (MSTORE 0 0x601080600c6000396000f20060003554156009570060203560003555) [[ 0 ]] (CREATE 23 4 0xfffffffffff) }", + "code" : "{ (MSTORE 0 0x601080600c6000396000f30060003554156009570060203560003555) [[ 0 ]] (CREATE 23 4 0xfffffffffff) }", "storage": {} }, "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { @@ -195,7 +195,7 @@ }, "945304eb96065b2a98b57a48a06ae28d285a71b5" : { "balance" : "23", - "code" : "0x6001600155603760005360026000f2", + "code" : "0x6001600155603760005360026000f3", "nonce" : "0", "storage" : { } @@ -321,7 +321,7 @@ }, "945304eb96065b2a98b57a48a06ae28d285a71b5" : { "balance" : "23", - "code" : "0x6001600155603760005360026000f2", + "code" : "0x6001600155603760005360026000f3", "nonce" : "0", "storage" : { } From 3e53d0bdeea8f79b956f7b9ad57f009601a5f700 Mon Sep 17 00:00:00 2001 From: Christian Date: Wed, 3 Dec 2014 09:37:34 +0100 Subject: [PATCH 84/86] Replace auto_ptr by shared_ptr. --- eth/main.cpp | 6 +++--- neth/main.cpp | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eth/main.cpp b/eth/main.cpp index 9b63e0643..9485a11bf 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -337,10 +337,10 @@ int main(int argc, char** argv) web3.connect(remoteHost, remotePort); #if ETH_JSONRPC - auto_ptr jsonrpcServer; + shared_ptr jsonrpcServer; if (jsonrpc > -1) { - jsonrpcServer = auto_ptr(new WebThreeStubServer(new jsonrpc::CorsHttpServer(jsonrpc), web3, {us})); + jsonrpcServer = shared_ptr(new WebThreeStubServer(new jsonrpc::CorsHttpServer(jsonrpc), web3, {us})); jsonrpcServer->setIdentities({us}); jsonrpcServer->StartListening(); } @@ -428,7 +428,7 @@ int main(int argc, char** argv) { if (jsonrpc < 0) jsonrpc = 8080; - jsonrpcServer = auto_ptr(new WebThreeStubServer(new jsonrpc::CorsHttpServer(jsonrpc), web3, {us})); + jsonrpcServer = make_shared(new jsonrpc::CorsHttpServer(jsonrpc), web3, vector({us})); jsonrpcServer->setIdentities({us}); jsonrpcServer->StartListening(); } diff --git a/neth/main.cpp b/neth/main.cpp index cb6d35593..82968bf03 100644 --- a/neth/main.cpp +++ b/neth/main.cpp @@ -475,10 +475,10 @@ int main(int argc, char** argv) c.startMining(); #if ETH_JSONRPC - auto_ptr jsonrpcServer; + shared_ptr jsonrpcServer; if (jsonrpc > -1) { - jsonrpcServer = auto_ptr(new WebThreeStubServer(new jsonrpc::HttpServer(jsonrpc), web3, {us})); + jsonrpcServer = make_shared(new jsonrpc::HttpServer(jsonrpc), web3, vector({us})); jsonrpcServer->setIdentities({us}); jsonrpcServer->StartListening(); } @@ -552,7 +552,7 @@ int main(int argc, char** argv) { if (jsonrpc < 0) jsonrpc = 8080; - jsonrpcServer = auto_ptr(new WebThreeStubServer(new jsonrpc::HttpServer(jsonrpc), web3, {us})); + jsonrpcServer = make_shared(new jsonrpc::HttpServer(jsonrpc), web3, vector({us})); jsonrpcServer->setIdentities({us}); jsonrpcServer->StartListening(); } From 735fdf72a1f3e03f8c13e1719af6a17499433926 Mon Sep 17 00:00:00 2001 From: Christian Date: Wed, 3 Dec 2014 09:41:12 +0100 Subject: [PATCH 85/86] Comments for the TOKEN_LIST usage. --- libsolidity/Scanner.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libsolidity/Scanner.cpp b/libsolidity/Scanner.cpp index 487d5c205..2f5f8d37a 100644 --- a/libsolidity/Scanner.cpp +++ b/libsolidity/Scanner.cpp @@ -621,11 +621,11 @@ Token::Value Scanner::scanNumber(char _charSeen) static Token::Value keywordOrIdentifierToken(string const& _input) { + // The following macros are used inside TOKEN_LIST and cause non-keyword tokens to be ignored + // and keywords to be put inside the keywords variable. #define KEYWORD(name, string, precedence) {string, Token::name}, #define TOKEN(name, string, precedence) - static const map keywords{ - TOKEN_LIST(TOKEN, KEYWORD) - }; + static const map keywords({TOKEN_LIST(TOKEN, KEYWORD)}); #undef KEYWORD #undef TOKEN auto it = keywords.find(_input); From 9e5a49736cb212468023244d3ae6d5b9c44feb84 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 3 Dec 2014 17:00:52 +0100 Subject: [PATCH 86/86] Avoid need for Qt 5.3. --- mix/qml/BasicContent.qml | 4 ++-- mix/qml/MainContent.qml | 6 +++--- mix/qml/TabStyle.qml | 6 +++--- mix/qml/main.qml | 6 +++--- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/mix/qml/BasicContent.qml b/mix/qml/BasicContent.qml index 0049e6127..ea1017186 100644 --- a/mix/qml/BasicContent.qml +++ b/mix/qml/BasicContent.qml @@ -1,5 +1,5 @@ -import QtQuick 2.3 -import QtQuick.Controls 1.2 +import QtQuick 2.2 +import QtQuick.Controls 1.1 Rectangle { anchors.fill: parent diff --git a/mix/qml/MainContent.qml b/mix/qml/MainContent.qml index f243b16ac..bd4737c3b 100644 --- a/mix/qml/MainContent.qml +++ b/mix/qml/MainContent.qml @@ -1,7 +1,7 @@ -import QtQuick 2.3 -import QtQuick.Controls 1.2 +import QtQuick 2.2 +import QtQuick.Controls 1.1 import QtQuick.Layouts 1.0 -import QtQuick.Controls.Styles 1.2 +import QtQuick.Controls.Styles 1.1 import CodeEditorExtensionManager 1.0 Rectangle { diff --git a/mix/qml/TabStyle.qml b/mix/qml/TabStyle.qml index 5f78f8947..cbae6e25e 100644 --- a/mix/qml/TabStyle.qml +++ b/mix/qml/TabStyle.qml @@ -1,6 +1,6 @@ -import QtQuick 2.3 -import QtQuick.Controls 1.2 -import QtQuick.Controls.Styles 1.2 +import QtQuick 2.2 +import QtQuick.Controls 1.1 +import QtQuick.Controls.Styles 1.1 TabViewStyle { frameOverlap: 1 diff --git a/mix/qml/main.qml b/mix/qml/main.qml index 8a1b86cee..3553f7710 100644 --- a/mix/qml/main.qml +++ b/mix/qml/main.qml @@ -1,6 +1,6 @@ -import QtQuick 2.3 -import QtQuick.Controls 1.2 -import QtQuick.Controls.Styles 1.2 +import QtQuick 2.2 +import QtQuick.Controls 1.1 +import QtQuick.Controls.Styles 1.1 import CodeEditorExtensionManager 1.0 ApplicationWindow {