From eda9393fd09e7e79b20aa37e805261d2b6f0cf54 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 23 Oct 2014 22:06:57 +0200 Subject: [PATCH 01/41] Watch API. --- libethereum/Client.h | 2 +- libp2p/Host.cpp | 3 +++ libwhisper/Interface.h | 25 +++++++++++++++---------- 3 files changed, 19 insertions(+), 11 deletions(-) diff --git a/libethereum/Client.h b/libethereum/Client.h index cabc9ac23..8ec65c199 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -285,7 +285,7 @@ private: State m_preMine; ///< The present state of the client. State m_postMine; ///< The state of the client which we're mining (i.e. it'll have all the rewards added). - std::weak_ptr m_host; ///< Our Ethereum Host. Don't do anything if we can't lock. + std::weak_ptr m_host; ///< Our Ethereum Host. Don't do anything if we can't lock. std::vector m_miners; mutable boost::shared_mutex x_miners; diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index ff6bdf996..fafb7d48a 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -143,6 +143,9 @@ void Host::stop() 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(); m_ioService.reset(); // m_acceptor & m_socket are DANGEROUS now. diff --git a/libwhisper/Interface.h b/libwhisper/Interface.h index e131a3ada..63cc44a9b 100644 --- a/libwhisper/Interface.h +++ b/libwhisper/Interface.h @@ -43,6 +43,8 @@ namespace shh Topic mask; };*/ +class Watch; + struct InstalledFilter { InstalledFilter(TopicFilter const& _f): filter(_f) {} @@ -87,9 +89,11 @@ struct WatshhChannel: public dev::LogChannel { static const char* name() { retur } } -/* -namespace std { void swap(shh::Watch& _a, shh::Watch& _b); } +namespace std { void swap(dev::shh::Watch& _a, dev::shh::Watch& _b); } + +namespace dev +{ namespace shh { @@ -99,28 +103,29 @@ class Watch: public boost::noncopyable public: Watch() {} - Watch(Whisper& _c, h256 _f): m_c(&_c), m_id(_c.installWatch(_f)) {} - Watch(Whisper& _c, TopicFilter const& _tf): m_c(&_c), m_id(_c.installWatch(_tf)) {} + Watch(Interface& _c, TopicMask const& _f): m_c(&_c), m_id(_c.installWatch(_f)) {} + Watch(Interface& _c, TopicFilter const& _tf): m_c(&_c), m_id(_c.installWatch(_tf)) {} ~Watch() { if (m_c) m_c->uninstallWatch(m_id); } - bool check() { return m_c ? m_c->checkWatch(m_id) : false; } - bool peek() { return m_c ? m_c->peekWatch(m_id) : false; } + h256s check() { return m_c ? m_c->checkWatch(m_id) : h256s(); } + h256s peek() { return m_c ? m_c->peekWatch(m_id) : h256s(); } private: - Whisper* m_c; + Interface* m_c; unsigned m_id; }; +} } -namespace shh +namespace std { -inline void swap(shh::Watch& _a, shh::Watch& _b) +inline void swap(dev::shh::Watch& _a, dev::shh::Watch& _b) { swap(_a.m_c, _b.m_c); swap(_a.m_id, _b.m_id); } } -*/ + From 6181b6d2c7a2d9a43a8fba35c8d24f54952f20bb Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 24 Oct 2014 21:28:55 +0200 Subject: [PATCH 02/41] Whisper is functional from the JS API. --- alethzero/MainWin.cpp | 3 + libqethereum/QEthereum.cpp | 139 +++++++++++++++++++++++++++++++++---- libqethereum/QEthereum.h | 22 +++--- libwhisper/Common.cpp | 16 +++-- libwhisper/Common.h | 6 +- libwhisper/Interface.h | 4 +- libwhisper/Message.cpp | 7 +- libwhisper/Message.h | 14 ++-- libwhisper/WhisperHost.cpp | 2 +- third/MainWin.cpp | 3 + 10 files changed, 172 insertions(+), 44 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 68fe0a0f1..9a98f54ee 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -151,6 +151,7 @@ Main::Main(QWidget *parent) : connect(ui->webView, &QWebView::loadFinished, [=]() { m_ethereum->poll(); + m_whisper->poll(); }); connect(ui->webView, &QWebView::titleChanged, [=]() @@ -1001,6 +1002,8 @@ void Main::timerEvent(QTimerEvent*) if (m_ethereum) m_ethereum->poll(); + if (m_whisper) + m_whisper->poll(); for (auto const& i: m_handlers) if (ethereum()->checkWatch(i.first)) diff --git a/libqethereum/QEthereum.cpp b/libqethereum/QEthereum.cpp index 267fed35e..d87f4ecb3 100644 --- a/libqethereum/QEthereum.cpp +++ b/libqethereum/QEthereum.cpp @@ -5,6 +5,8 @@ #include #include #include +#include +#include #include "QEthereum.h" using namespace std; using namespace dev; @@ -21,7 +23,7 @@ dev::bytes toBytes(QString const& _s) else { // Binary - cwarn << "THIS FUNCTIONALITY IS DEPRECATED. DO NOT ASSUME ASCII/BINARY-STRINGS WILL BE ACCEPTED. USE eth.fromAscii()."; + cwarn << "'" << _s.toStdString() << "': Unrecognised format for number/hash. USE eth.fromAscii() if you mean to convert from ASCII."; return asBytes(_s); } } @@ -558,37 +560,148 @@ void QWhisper::faceDieing() } -void QWhisper::send(QString /*dev::Address*/ _dest, QString /*ev::KeyPair*/ _from, QString /*dev::h256 const&*/ _topic, QString /*dev::bytes const&*/ _payload) +static shh::Message toMessage(QString _json) { - (void)_dest; - (void)_from; - (void)_topic; - (void)_payload; + shh::Message ret; + + QJsonObject f = QJsonDocument::fromJson(_json.toUtf8()).object(); + if (f.contains("from")) + ret.setFrom(toPublic(f["from"].toString())); + if (f.contains("to")) + ret.setTo(toPublic(f["to"].toString())); + if (f.contains("payload")) + ret.setPayload(toBytes(f["payload"].toString())); + + return ret; } -unsigned QWhisper::newWatch(QString _json) +static shh::Envelope toSealed(QString _json, shh::Message const& _m, Secret _from) { - (void)_json; - return 0; + unsigned ttl = 50; + unsigned workToProve = 50; + + shh::BuildTopic bt; + + QJsonObject f = QJsonDocument::fromJson(_json.toUtf8()).object(); + if (f.contains("ttl")) + ttl = f["ttl"].toInt(); + if (f.contains("workToProve")) + workToProve = f["workToProve"].toInt(); + if (f.contains("topic")) + { + if (f["topic"].isString()) + bt.shift(asBytes(padded(f["topic"].toString(), 32))); + else if (f["topic"].isArray()) + for (auto i: f["topic"].toArray()) + bt.shift(asBytes(padded(i.toString(), 32))); + } + return _m.seal(_from, bt, workToProve, ttl); } -QString QWhisper::watchMessages(unsigned _w) +void QWhisper::doPost(QString _json) { - (void)_w; - return ""; + shh::Message m = toMessage(_json); + Secret from; + + if (m.from() && m_ids.count(m.from())) + { + cwarn << "Silently signing message from identity" << m.from().abridged() << ": User validation hook goes here."; + // TODO: insert validification hook here. + from = m_ids[m.from()]; + } + + face()->inject(toSealed(_json, m, from)); +} + +static pair toWatch(QString _json) +{ + shh::BuildTopicMask bt(shh::BuildTopicMask::Empty); + Public to; + + QJsonObject f = QJsonDocument::fromJson(_json.toUtf8()).object(); + if (f.contains("to")) + to = toPublic(f["to"].toString()); + + if (f.contains("topic")) + { + if (f["topic"].isString()) + bt.shift(asBytes(padded(f["topic"].toString(), 32))); + else if (f["topic"].isArray()) + for (auto i: f["topic"].toArray()) + if (i.isString()) + bt.shift(asBytes(padded(i.toString(), 32))); + else + bt.shift(); + } + return make_pair(bt.toTopicMask(), to); +} + +// _json contains +// topic: the topic as an array of components, some may be null. +// to: specifies the id to which the message is encrypted. null if broadcast. +unsigned QWhisper::newWatch(QString _json) +{ + auto w = toWatch(_json); + auto ret = face()->installWatch(w.first); + m_watches.insert(make_pair(ret, w.second)); + return ret; } void QWhisper::killWatch(unsigned _w) { - (void)_w; + face()->uninstallWatch(_w); + m_watches.erase(_w); } void QWhisper::clearWatches() { + for (auto i: m_watches) + face()->uninstallWatch(i.first); + m_watches.clear(); +} + +QString QWhisper::newIdentity() +{ + KeyPair kp = KeyPair::create(); + m_ids[kp.pub()] = kp.sec(); + return toQJS(kp.pub()); +} + +static QString toJson(h256 const& _h, shh::Envelope const& _e, shh::Message const& _m) +{ + QJsonObject v; + v["hash"] = toQJS(_h); + + v["expiry"] = (int)_e.expiry(); + v["sent"] = (int)_e.sent(); + v["ttl"] = (int)_e.ttl(); + v["workProved"] = (int)_e.workProved(); + v["topic"] = toQJS(_e.topic()); + + v["payload"] = toQJS(_m.payload()); + v["from"] = toQJS(_m.from()); + v["to"] = toQJS(_m.to()); + + return QString::fromUtf8(QJsonDocument(v).toJson()); } void QWhisper::poll() { + for (auto const& w: m_watches) + if (!w.second || m_ids.count(w.second)) + for (h256 const& h: face()->checkWatch(w.first)) + { + auto e = face()->envelope(h); + shh::Message m; + if (w.second) + { + cwarn << "Silently decrypting message from identity" << w.second.abridged() << ": User validation hook goes here."; + m = e.open(m_ids[w.second]); + } + else + m = e.open(); + emit watchChanged(w.first, toJson(h, e, m)); + } } // extra bits needed to link on VS diff --git a/libqethereum/QEthereum.h b/libqethereum/QEthereum.h index 2d6ea8b4c..42696d40c 100644 --- a/libqethereum/QEthereum.h +++ b/libqethereum/QEthereum.h @@ -59,8 +59,9 @@ template dev::FixedHash toFixed(QString const& _s) template inline boost::multiprecision::number> toInt(QString const& _s); -inline dev::Address toAddress(QString const& _s) { return toFixed<20>(_s); } -inline dev::Secret toSecret(QString const& _s) { return toFixed<32>(_s); } +inline dev::Address toAddress(QString const& _s) { return toFixed(_s); } +inline dev::Public toPublic(QString const& _s) { return toFixed(_s); } +inline dev::Secret toSecret(QString const& _s) { return toFixed(_s); } inline dev::u256 toU256(QString const& _s) { return toInt<32>(_s); } template QString toQJS(dev::FixedHash const& _h) { return QString::fromStdString("0x" + toHex(_h.ref())); } @@ -225,12 +226,12 @@ public: Q_INVOKABLE QWhisper* self() { return this; } /// Basic message send. - Q_INVOKABLE void send(QString /*dev::Address*/ _dest, QString /*ev::KeyPair*/ _from, QString /*dev::h256 const&*/ _topic, QString /*dev::bytes const&*/ _payload); + Q_INVOKABLE void doPost(QString _json); - // Watches interface + Q_INVOKABLE QString newIdentity(); + // Watches interface Q_INVOKABLE unsigned newWatch(QString _json); - Q_INVOKABLE QString watchMessages(unsigned _w); Q_INVOKABLE void killWatch(unsigned _w); void clearWatches(); @@ -240,11 +241,13 @@ public slots: void poll(); signals: - void watchChanged(unsigned _w); + void watchChanged(unsigned _w, QString _envelopeJson); private: std::weak_ptr m_face; - std::vector m_watches; + std::map m_watches; + + std::map m_ids; }; // TODO: add p2p object @@ -269,8 +272,9 @@ private: if (_shh) \ { \ _frame->addToJavaScriptWindowObject("_web3_dot_shh", _shh, QWebFrame::ScriptOwnership); \ - _frame->evaluateJavaScript("_web3_dot_shh.makeWatch = function(a) { var ww = _web3_dot_shh.newWatch(a); var ret = { w: ww }; ret.uninstall = function() { _web3_dot_shh.killWatch(w); }; ret.changed = function(f) { _web3_dot_shh.watchChanged.connect(function(nw) { if (nw == ww) f() }); }; ret.messages = function() { return JSON.parse(_web3_dot_shh.watchMessages(this.w)) }; return ret; }"); \ - _frame->evaluateJavaScript("_web3_dot_shh.watch = function(a) { return _web3_dot_shh.makeWatch(JSON.stringify(a)) }"); \ + _frame->evaluateJavaScript("_web3_dot_shh.makeWatch = function(json) { var ww = _web3_dot_shh.newWatch(json); var ret = { w: ww }; ret.uninstall = function() { _web3_dot_shh.killWatch(w); }; ret.arrived = function(f) { _web3_dot_shh.watchChanged.connect(function(nw, envelope) { if (nw == ww) f(JSON.parse(envelope)) }); }; return ret; }"); \ + _frame->evaluateJavaScript("_web3_dot_shh.watch = function(filter) { return _web3_dot_shh.makeWatch(JSON.stringify(filter)) }"); \ + _frame->evaluateJavaScript("_web3_dot_shh.post = function(message) { return _web3_dot_shh.doPost(JSON.stringify(message)) }"); \ _frame->evaluateJavaScript("web3.shh = _web3_dot_shh"); \ } \ } diff --git a/libwhisper/Common.cpp b/libwhisper/Common.cpp index e4903821c..c4c103de3 100644 --- a/libwhisper/Common.cpp +++ b/libwhisper/Common.cpp @@ -43,10 +43,16 @@ h256 TopicFilter::sha3() const TopicMask BuildTopicMask::toTopicMask() const { TopicMask ret; - for (auto i = 0; i < 32; ++i) - { - ret.first[i] = m_parts[i * m_parts.size() / 32][i]; - ret.second[i] = m_parts[i * m_parts.size() / 32] ? 255 : 0; - } + if (m_parts.size()) + for (auto i = 0; i < 32; ++i) + { + ret.first[i] = m_parts[i * m_parts.size() / 32][i]; + ret.second[i] = m_parts[i * m_parts.size() / 32] ? 255 : 0; + } return ret; } +/* +web3.shh.watch({}, function(m) { env.note("New message:\n"+JSON.stringify(m)); }) +k = web3.shh.newIdentity() +web3.shh.post({from: k, topic: web3.fromAscii("test"), payload: web3.fromAscii("Hello world!")}) +*/ diff --git a/libwhisper/Common.h b/libwhisper/Common.h index 1f4c4a17f..a85caafe1 100644 --- a/libwhisper/Common.h +++ b/libwhisper/Common.h @@ -64,6 +64,7 @@ using Topic = h256; class BuildTopic { public: + BuildTopic() {} template BuildTopic(T const& _t) { shift(_t); } template BuildTopic& shift(T const& _r) { return shiftBytes(RLPStream().append(_r).out()); } @@ -75,8 +76,6 @@ public: Topic toTopic() const { Topic ret; for (auto i = 0; i < 32; ++i) ret[i] = m_parts[i * m_parts.size() / 32][i]; return ret; } protected: - BuildTopic() {} - BuildTopic& shiftBytes(bytes const& _b); h256s m_parts; @@ -105,7 +104,10 @@ private: class BuildTopicMask: BuildTopic { public: + enum EmptyType { Empty }; + BuildTopicMask() { shift(); } + BuildTopicMask(EmptyType) {} template BuildTopicMask(T const& _t) { shift(_t); } template BuildTopicMask& shift(T const& _r) { BuildTopic::shift(_r); return *this; } diff --git a/libwhisper/Interface.h b/libwhisper/Interface.h index 63cc44a9b..8bc37ff5e 100644 --- a/libwhisper/Interface.h +++ b/libwhisper/Interface.h @@ -79,9 +79,9 @@ public: virtual Envelope envelope(h256 _m) const = 0; void post(bytes const& _payload, Topic _topic, unsigned _ttl = 50, unsigned _workToProve = 50) { inject(Message(_payload).seal(_topic, _ttl, _workToProve)); } - void post(Public _to, bytes const& _payload, Topic _topic, unsigned _ttl = 50, unsigned _workToProve = 50) { inject(Message(_payload).seal(_to, _topic, _ttl, _workToProve)); } + void post(Public _to, bytes const& _payload, Topic _topic, unsigned _ttl = 50, unsigned _workToProve = 50) { inject(Message(_payload).sealTo(_to, _topic, _ttl, _workToProve)); } void post(Secret _from, bytes const& _payload, Topic _topic, unsigned _ttl = 50, unsigned _workToProve = 50) { inject(Message(_payload).seal(_from, _topic, _ttl, _workToProve)); } - void post(Secret _from, Public _to, bytes const& _payload, Topic _topic, unsigned _ttl = 50, unsigned _workToProve = 50) { inject(Message(_payload).seal(_from, _to, _topic, _ttl, _workToProve)); } + void post(Secret _from, Public _to, bytes const& _payload, Topic _topic, unsigned _ttl = 50, unsigned _workToProve = 50) { inject(Message(_payload).sealTo(_from, _to, _topic, _ttl, _workToProve)); } }; struct WatshhChannel: public dev::LogChannel { static const char* name() { return "shh"; } static const int verbosity = 1; }; diff --git a/libwhisper/Message.cpp b/libwhisper/Message.cpp index 80b493076..52caf2f90 100644 --- a/libwhisper/Message.cpp +++ b/libwhisper/Message.cpp @@ -60,7 +60,7 @@ void Message::populate(bytes const& _data) m_payload = bytesConstRef(&_data).cropped(1).toBytes(); } -Envelope Message::seal(Secret _from, Topic const& _topic, unsigned _ttl, unsigned _workToProve) +Envelope Message::seal(Secret _from, Topic const& _topic, unsigned _ttl, unsigned _workToProve) const { Envelope ret(time(0) + _ttl, _ttl, _topic); @@ -91,11 +91,6 @@ Message Envelope::open(Secret const& _s) const return Message(*this, _s); } -Message Envelope::open() const -{ - return Message(*this); -} - unsigned Envelope::workProved() const { h256 d[2]; diff --git a/libwhisper/Message.h b/libwhisper/Message.h index fa5cc3662..67b34e321 100644 --- a/libwhisper/Message.h +++ b/libwhisper/Message.h @@ -65,8 +65,7 @@ public: Topic const& topic() const { return m_topic; } bytes const& data() const { return m_data; } - Message open(Secret const& _s) const; - Message open() const; + Message open(Secret const& _s = Secret()) const; unsigned workProved() const; void proveWork(unsigned _ms); @@ -102,16 +101,19 @@ public: Public to() const { return m_to; } bytes const& payload() const { return m_payload; } + void setFrom(Public _from) { m_from = _from; } void setTo(Public _to) { m_to = _to; } + void setPayload(bytes const& _payload) { m_payload = _payload; } + void setPayload(bytes&& _payload) { swap(m_payload, _payload); } operator bool() const { return !!m_payload.size() || m_from || m_to; } /// Turn this message into a ditributable Envelope. - Envelope seal(Secret _from, Topic const& _topic, unsigned _workToProve = 50, unsigned _ttl = 50); + Envelope seal(Secret _from, Topic const& _topic, unsigned _workToProve = 50, unsigned _ttl = 50) const; // Overloads for skipping _from or specifying _to. - Envelope seal(Topic const& _topic, unsigned _ttl = 50, unsigned _workToProve = 50) { return seal(Secret(), _topic, _workToProve, _ttl); } - Envelope seal(Public _to, Topic const& _topic, unsigned _workToProve = 50, unsigned _ttl = 50) { m_to = _to; return seal(Secret(), _topic, _workToProve, _ttl); } - Envelope seal(Secret _from, Public _to, Topic const& _topic, unsigned _workToProve = 50, unsigned _ttl = 50) { m_to = _to; return seal(_from, _topic, _workToProve, _ttl); } + Envelope seal(Topic const& _topic, unsigned _ttl = 50, unsigned _workToProve = 50) const { return seal(Secret(), _topic, _workToProve, _ttl); } + Envelope sealTo(Public _to, Topic const& _topic, unsigned _workToProve = 50, unsigned _ttl = 50) { m_to = _to; return seal(Secret(), _topic, _workToProve, _ttl); } + Envelope sealTo(Secret _from, Public _to, Topic const& _topic, unsigned _workToProve = 50, unsigned _ttl = 50) { m_to = _to; return seal(_from, _topic, _workToProve, _ttl); } private: void populate(bytes const& _data); diff --git a/libwhisper/WhisperHost.cpp b/libwhisper/WhisperHost.cpp index 2d9a5e6b6..b11b4af3a 100644 --- a/libwhisper/WhisperHost.cpp +++ b/libwhisper/WhisperHost.cpp @@ -62,7 +62,7 @@ void WhisperHost::inject(Envelope const& _m, WhisperPeer* _p) m_messages[h] = _m; } - if (_p) +// if (_p) { Guard l(m_filterLock); for (auto const& f: m_filters) diff --git a/third/MainWin.cpp b/third/MainWin.cpp index d1f5938aa..dd5b01733 100644 --- a/third/MainWin.cpp +++ b/third/MainWin.cpp @@ -120,6 +120,7 @@ Main::Main(QWidget *parent) : connect(ui->webView, &QWebView::loadFinished, [=]() { m_ethereum->poll(); + m_whisper->poll(); }); connect(ui->webView, &QWebView::titleChanged, [=]() @@ -522,6 +523,8 @@ void Main::timerEvent(QTimerEvent*) if (m_ethereum) m_ethereum->poll(); + if (m_whisper) + m_whisper->poll(); for (auto const& i: m_handlers) if (ethereum()->checkWatch(i.first)) From e1d42ee25042e2415dd014946713aa8f7bb727cc Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 25 Oct 2014 13:15:15 +0200 Subject: [PATCH 03/41] Update serpent. Disable wallet import for now. --- alethzero/Main.ui | 3 + libdevcrypto/CryptoPP.h | 6 +- libpyserpent/pyserpent.cpp | 12 +++ libserpent/compiler.cpp | 6 +- libserpent/funcs.cpp | 12 +++ libserpent/funcs.h | 6 ++ libserpent/parser.cpp | 22 ++-- libserpent/rewriter.cpp | 16 ++- libserpent/rewriter.h | 3 + libserpent/util.cpp | 6 +- libwhisper/Common.cpp | 2 +- sc/cmdline.cpp | 205 ++++++++++++++++++++----------------- 12 files changed, 184 insertions(+), 115 deletions(-) diff --git a/alethzero/Main.ui b/alethzero/Main.ui index 5a6eb6f32..16dcd8a4c 100644 --- a/alethzero/Main.ui +++ b/alethzero/Main.ui @@ -1789,6 +1789,9 @@ font-size: 14pt + + false + Claim Ether Presale &Wallet... diff --git a/libdevcrypto/CryptoPP.h b/libdevcrypto/CryptoPP.h index d7e4181ee..6070b651b 100644 --- a/libdevcrypto/CryptoPP.h +++ b/libdevcrypto/CryptoPP.h @@ -23,12 +23,11 @@ #pragma once -// need to leave this one disabled -//#pragma GCC diagnostic ignored "-Wunused-function" +// need to leave this one disabled for link-time. blame cryptopp. +#pragma GCC diagnostic ignored "-Wunused-function" #pragma warning(push) #pragma warning(disable:4100 4244) #pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunused-function" #pragma GCC diagnostic ignored "-Wconversion" #pragma GCC diagnostic ignored "-Wunused-parameter" #pragma GCC diagnostic ignored "-Wunused-variable" @@ -58,6 +57,7 @@ namespace crypto namespace pp { + /// RNG used by CryptoPP inline CryptoPP::AutoSeededRandomPool& PRNG() { static CryptoPP::AutoSeededRandomPool prng; return prng; } diff --git a/libpyserpent/pyserpent.cpp b/libpyserpent/pyserpent.cpp index d97fd8fed..ff8813fcf 100644 --- a/libpyserpent/pyserpent.cpp +++ b/libpyserpent/pyserpent.cpp @@ -120,11 +120,15 @@ std::vector cppifyNodeList(PyObject* o) { } PYMETHOD(ps_compile, FROMSTR, compile, pyifyString) +PYMETHOD(ps_compile_chunk, FROMSTR, compileChunk, pyifyString) PYMETHOD(ps_compile_to_lll, FROMSTR, compileToLLL, pyifyNode) +PYMETHOD(ps_compile_chunk_to_lll, FROMSTR, compileChunkToLLL, pyifyNode) PYMETHOD(ps_compile_lll, FROMNODE, compileLLL, pyifyString) PYMETHOD(ps_parse, FROMSTR, parseSerpent, pyifyNode) PYMETHOD(ps_rewrite, FROMNODE, rewrite, pyifyNode) +PYMETHOD(ps_rewrite_chunk, FROMNODE, rewriteChunk, pyifyNode) PYMETHOD(ps_pretty_compile, FROMSTR, prettyCompile, pyifyNodeList) +PYMETHOD(ps_pretty_compile_chunk, FROMSTR, prettyCompileChunk, pyifyNodeList) PYMETHOD(ps_pretty_compile_lll, FROMNODE, prettyCompileLLL, pyifyNodeList) PYMETHOD(ps_serialize, FROMLIST, serialize, pyifyString) PYMETHOD(ps_deserialize, FROMSTR, deserialize, pyifyNodeList) @@ -134,16 +138,24 @@ PYMETHOD(ps_parse_lll, FROMSTR, parseLLL, pyifyNode) static PyMethodDef PyextMethods[] = { {"compile", ps_compile, METH_VARARGS, "Compile code."}, + {"compile_chunk", ps_compile_chunk, METH_VARARGS, + "Compile code chunk (no wrappers)."}, {"compile_to_lll", ps_compile_to_lll, METH_VARARGS, "Compile code to LLL."}, + {"compile_chunk_to_lll", ps_compile_chunk_to_lll, METH_VARARGS, + "Compile code chunk to LLL (no wrappers)."}, {"compile_lll", ps_compile_lll, METH_VARARGS, "Compile LLL to EVM."}, {"parse", ps_parse, METH_VARARGS, "Parse serpent"}, {"rewrite", ps_rewrite, METH_VARARGS, "Rewrite parsed serpent to LLL"}, + {"rewrite_chunk", ps_rewrite_chunk, METH_VARARGS, + "Rewrite parsed serpent to LLL (no wrappers)"}, {"pretty_compile", ps_pretty_compile, METH_VARARGS, "Compile to EVM opcodes"}, + {"pretty_compile_chunk", ps_pretty_compile_chunk, METH_VARARGS, + "Compile chunk to EVM opcodes (no wrappers)"}, {"pretty_compile_lll", ps_pretty_compile_lll, METH_VARARGS, "Compile LLL to EVM opcodes"}, {"serialize", ps_serialize, METH_VARARGS, diff --git a/libserpent/compiler.cpp b/libserpent/compiler.cpp index 4360bfba6..61b70de05 100644 --- a/libserpent/compiler.cpp +++ b/libserpent/compiler.cpp @@ -298,7 +298,7 @@ Node finalize(programData c) { Metadata m = c.code.metadata; // If we are using both alloc and variables, we need to pre-zfill // some memory - if (c.aux.allocUsed && c.aux.vars.size() > 0) { + if ((c.aux.allocUsed || c.aux.calldataUsed) && c.aux.vars.size() > 0) { Node nodelist[] = { token("0", m), token(unsignedToDecimal(c.aux.vars.size() * 32 - 1)), @@ -309,8 +309,8 @@ Node finalize(programData c) { // If msg.data is being used as an array, then we need to copy it if (c.aux.calldataUsed) { Node nodelist[] = { - token("MSIZE", m), token("CALLDATASIZE", m), token("MSIZE", m), - token("0", m), token("CALLDATACOPY", m), + token("MSIZE", m), token("CALLDATASIZE", m), token("0", m), + token("MSIZE", m), token("CALLDATACOPY", m), token(c.aux.vars["'msg.data"], m), token("MSTORE", m) }; bottom.push_back(multiToken(nodelist, 7, m)); diff --git a/libserpent/funcs.cpp b/libserpent/funcs.cpp index e80fcff06..ea9be14a6 100644 --- a/libserpent/funcs.cpp +++ b/libserpent/funcs.cpp @@ -14,6 +14,10 @@ Node compileToLLL(std::string input) { return rewrite(parseSerpent(input)); } +Node compileChunkToLLL(std::string input) { + return rewriteChunk(parseSerpent(input)); +} + std::string compile(std::string input) { return compileLLL(compileToLLL(input)); } @@ -21,3 +25,11 @@ std::string compile(std::string input) { std::vector prettyCompile(std::string input) { return prettyCompileLLL(compileToLLL(input)); } + +std::string compileChunk(std::string input) { + return compileLLL(compileChunkToLLL(input)); +} + +std::vector prettyCompileChunk(std::string input) { + return prettyCompileLLL(compileChunkToLLL(input)); +} diff --git a/libserpent/funcs.h b/libserpent/funcs.h index 0f3355ec8..d9bf44549 100644 --- a/libserpent/funcs.h +++ b/libserpent/funcs.h @@ -24,6 +24,12 @@ Node compileToLLL(std::string input); +Node compileChunkToLLL(std::string input); + std::string compile(std::string input); std::vector prettyCompile(std::string input); + +std::string compileChunk(std::string input); + +std::vector prettyCompileChunk(std::string input); diff --git a/libserpent/parser.cpp b/libserpent/parser.cpp index 5adf1672d..09fcdfc47 100644 --- a/libserpent/parser.cpp +++ b/libserpent/parser.cpp @@ -32,7 +32,7 @@ int toktype(Node tok) { if (v == "(" || v == "[" || v == "{") return LPAREN; else if (v == ")" || v == "]" || v == "}") return RPAREN; else if (v == ",") return COMMA; - else if (v == "!" || v == "not") return UNARY_OP; + else if (v == "!" || v == "not" || v == "neg") return UNARY_OP; else if (precedence(tok) >= 0) return BINARY_OP; if (tok.val[0] != '"' && tok.val[0] != '\'') { for (unsigned i = 0; i < tok.val.length(); i++) { @@ -91,17 +91,19 @@ std::vector shuntingYard(std::vector tokens) { // If binary op, keep popping from stack while higher bedmas precedence else if (toktyp == BINARY_OP) { if (tok.val == "-" && prevtyp != ALPHANUM && prevtyp != RPAREN) { - oq.push_back(token("0", tok.metadata)); + stack.push_back(token("neg", tok.metadata)); } - int prec = precedence(tok); - while (stack.size() - && (toktype(stack.back()) == BINARY_OP - || toktype(stack.back()) == UNARY_OP) - && precedence(stack.back()) <= prec) { - oq.push_back(stack.back()); - stack.pop_back(); + else { + int prec = precedence(tok); + while (stack.size() + && (toktype(stack.back()) == BINARY_OP + || toktype(stack.back()) == UNARY_OP) + && precedence(stack.back()) <= prec) { + oq.push_back(stack.back()); + stack.pop_back(); + } + stack.push_back(tok); } - stack.push_back(tok); } // Comma means finish evaluating the argument else if (toktyp == COMMA) { diff --git a/libserpent/rewriter.cpp b/libserpent/rewriter.cpp index 72feb1277..eeefd2d09 100644 --- a/libserpent/rewriter.cpp +++ b/libserpent/rewriter.cpp @@ -28,6 +28,8 @@ std::string valid[][3] = { { "sha3", "1", "2" }, { "return", "1", "2" }, { "inset", "1", "1" }, + { "min", "2", "2" }, + { "max", "2", "2" }, { "array_lit", "0", tt256 }, { "seq", "0", tt256 }, { "---END---", "", "" } //Keep this line at the end of the list @@ -70,6 +72,14 @@ std::string macros[][2] = { "(!= $a $b)", "(not (eq $a $b))" }, + { + "(min a b)", + "(with $1 a (with $2 b (if (lt $1 $2) $1 $2)))" + }, + { + "(max a b)", + "(with $1 a (with $2 b (if (lt $1 $2) $2 $1)))" + }, { "(if $cond $do (else $else))", "(if $cond $do $else)" @@ -229,7 +239,7 @@ std::string macros[][2] = { }, { "(msg $gas $to $val $inp $inpsz $outsz)", - "(with $1 (mul 32 $outsz) (with $2 (alloc (get $1)) (call $gas $to $val $inp (mul 32 $inpsz) (get $2) (get $1)) (get $2)))" + "(with $1 (mul 32 $outsz) (with $2 (alloc (get $1)) (seq (call $gas $to $val $inp (mul 32 $inpsz) (get $2) (get $1)) (get $2))))" }, // Call stateless and msg stateless { @@ -561,4 +571,8 @@ Node rewrite(Node inp) { return optimize(apply_rules(validate(preprocess(inp)))); } +Node rewriteChunk(Node inp) { + return optimize(apply_rules(validate(inp))); +} + using namespace std; diff --git a/libserpent/rewriter.h b/libserpent/rewriter.h index b2e8f00dd..716815cee 100644 --- a/libserpent/rewriter.h +++ b/libserpent/rewriter.h @@ -10,4 +10,7 @@ // Applies rewrite rules Node rewrite(Node inp); +// Applies rewrite rules adding without wrapper +Node rewriteChunk(Node inp); + #endif diff --git a/libserpent/util.cpp b/libserpent/util.cpp index 693427c3f..cc1394a21 100644 --- a/libserpent/util.cpp +++ b/libserpent/util.cpp @@ -137,7 +137,7 @@ std::string strToNumeric(std::string inp) { } else if (inp.substr(0,2) == "0x") { for (unsigned i = 2; i < inp.length(); i++) { - int dig = std::string("0123456789abcdef").find(inp[i]); + int dig = std::string("0123456789abcdef0123456789ABCDEF").find(inp[i]) % 16; if (dig < 0) return ""; o = decimalAdd(decimalMul(o,"16"), unsignedToDecimal(dig)); } @@ -219,8 +219,8 @@ void err(std::string errtext, Metadata met) { std::string err = "Error (file \"" + met.file + "\", line " + unsignedToDecimal(met.ln + 1) + ", char " + unsignedToDecimal(met.ch) + "): " + errtext; - std::cerr << err << "\n"; - throw(err); + std::cerr << err << "\n"; + throw(err); } //Bin to hex diff --git a/libwhisper/Common.cpp b/libwhisper/Common.cpp index c4c103de3..11908d181 100644 --- a/libwhisper/Common.cpp +++ b/libwhisper/Common.cpp @@ -52,7 +52,7 @@ TopicMask BuildTopicMask::toTopicMask() const return ret; } /* -web3.shh.watch({}, function(m) { env.note("New message:\n"+JSON.stringify(m)); }) +web3.shh.watch({}).arrived(function(m) { env.note("New message:\n"+JSON.stringify(m)); }) k = web3.shh.newIdentity() web3.shh.post({from: k, topic: web3.fromAscii("test"), payload: web3.fromAscii("Hello world!")}) */ diff --git a/sc/cmdline.cpp b/sc/cmdline.cpp index d6602c56d..b44d2538c 100644 --- a/sc/cmdline.cpp +++ b/sc/cmdline.cpp @@ -3,100 +3,117 @@ #include #include #include -#include #include -#include -int main(int argv, char** argc) -{ - if (argv == 1) - { - std::cerr << "Must provide a command and arguments! Try parse, rewrite, compile, assemble\n"; - return 0; - } - std::string flag = ""; - std::string command = argc[1]; - std::string input; - std::string secondInput; - if (std::string(argc[1]) == "-s") - { - flag = command.substr(1); - command = argc[2]; - input = ""; - std::string line; - while (std::getline(std::cin, line)) - { - input += line + "\n"; - } - secondInput = argv == 3 ? "" : argc[3]; - } - else - { - if (argv == 2) - { - std::cerr << "Not enough arguments for serpent cmdline\n"; - BOOST_THROW_EXCEPTION(dev::Exception() << dev::errinfo_comment("Not enough arguments for serpent cmdline")); - } - input = argc[2]; - secondInput = argv == 3 ? "" : argc[3]; - } - bool haveSec = secondInput.length() > 0; - if (command == "parse" || command == "parse_serpent") - std::cout << printAST(parseSerpent(input), haveSec) << "\n"; - else if (command == "rewrite") - std::cout << printAST(rewrite(parseLLL(input, true)), haveSec) << "\n"; - else if (command == "compile_to_lll") - std::cout << printAST(compileToLLL(input), haveSec) << "\n"; - else if (command == "build_fragtree") - std::cout << printAST(buildFragmentTree(parseLLL(input, true))) << "\n"; - else if (command == "compile_lll") - std::cout << binToHex(compileLLL(parseLLL(input, true))) << "\n"; - else if (command == "dereference") - std::cout << printAST(dereference(parseLLL(input, true)), haveSec) <<"\n"; - else if (command == "pretty_assemble") - std::cout << printTokens(prettyAssemble(parseLLL(input, true))) <<"\n"; - else if (command == "pretty_compile_lll") - std::cout << printTokens(prettyCompileLLL(parseLLL(input, true))) << "\n"; - else if (command == "pretty_compile") - std::cout << printTokens(prettyCompile(input)) << "\n"; - else if (command == "assemble") - std::cout << assemble(parseLLL(input, true)) << "\n"; - else if (command == "serialize") - std::cout << binToHex(serialize(tokenize(input, Metadata(), false))) << "\n"; - else if (command == "flatten") - std::cout << printTokens(flatten(parseLLL(input, true))) << "\n"; - else if (command == "deserialize") - std::cout << printTokens(deserialize(hexToBin(input))) << "\n"; - else if (command == "compile") - std::cout << binToHex(compile(input)) << "\n"; - else if (command == "encode_datalist") - { - std::vector tokens = tokenize(input); - std::vector o; - for (int i = 0; i < (int)tokens.size(); i++) - o.push_back(tokens[i].val); - std::cout << binToHex(encodeDatalist(o)) << "\n"; - } - else if (command == "decode_datalist") - { - std::vector o = decodeDatalist(hexToBin(input)); - std::vector tokens; - for (int i = 0; i < (int)o.size(); i++) - tokens.push_back(token(o[i])); - std::cout << printTokens(tokens) << "\n"; - } - else if (command == "tokenize") - std::cout << printTokens(tokenize(input)); - else if (command == "biject") - { - if (argv == 3) - std::cerr << "Not enough arguments for biject\n"; - int pos = decimalToUnsigned(secondInput); - std::vector n = prettyCompile(input); - if (pos >= (int)n.size()) - std::cerr << "Code position too high\n"; - Metadata m = n[pos].metadata; - std::cout << "Opcode: " << n[pos].val << ", file: " << m.file << - ", line: " << m.ln << ", char: " << m.ch << "\n"; - } +int main(int argv, char** argc) { + if (argv == 1) { + std::cerr << "Must provide a command and arguments! Try parse, rewrite, compile, assemble\n"; + return 0; + } + std::string flag = ""; + std::string command = argc[1]; + std::string input; + std::string secondInput; + if (std::string(argc[1]) == "-s") { + flag = command.substr(1); + command = argc[2]; + input = ""; + std::string line; + while (std::getline(std::cin, line)) { + input += line + "\n"; + } + secondInput = argv == 3 ? "" : argc[3]; + } + else { + if (argv == 2) { + std::cerr << "Not enough arguments for serpent cmdline\n"; + throw(0); + } + input = argc[2]; + secondInput = argv == 3 ? "" : argc[3]; + } + bool haveSec = secondInput.length() > 0; + if (command == "parse" || command == "parse_serpent") { + std::cout << printAST(parseSerpent(input), haveSec) << "\n"; + } + else if (command == "rewrite") { + std::cout << printAST(rewrite(parseLLL(input, true)), haveSec) << "\n"; + } + else if (command == "compile_to_lll") { + std::cout << printAST(compileToLLL(input), haveSec) << "\n"; + } + else if (command == "rewrite_chunk") { + std::cout << printAST(rewriteChunk(parseLLL(input, true)), haveSec) << "\n"; + } + else if (command == "compile_chunk_to_lll") { + std::cout << printAST(compileChunkToLLL(input), haveSec) << "\n"; + } + else if (command == "build_fragtree") { + std::cout << printAST(buildFragmentTree(parseLLL(input, true))) << "\n"; + } + else if (command == "compile_lll") { + std::cout << binToHex(compileLLL(parseLLL(input, true))) << "\n"; + } + else if (command == "dereference") { + std::cout << printAST(dereference(parseLLL(input, true)), haveSec) <<"\n"; + } + else if (command == "pretty_assemble") { + std::cout << printTokens(prettyAssemble(parseLLL(input, true))) <<"\n"; + } + else if (command == "pretty_compile_lll") { + std::cout << printTokens(prettyCompileLLL(parseLLL(input, true))) << "\n"; + } + else if (command == "pretty_compile") { + std::cout << printTokens(prettyCompile(input)) << "\n"; + } + else if (command == "pretty_compile_chunk") { + std::cout << printTokens(prettyCompileChunk(input)) << "\n"; + } + else if (command == "assemble") { + std::cout << assemble(parseLLL(input, true)) << "\n"; + } + else if (command == "serialize") { + std::cout << binToHex(serialize(tokenize(input, Metadata(), false))) << "\n"; + } + else if (command == "flatten") { + std::cout << printTokens(flatten(parseLLL(input, true))) << "\n"; + } + else if (command == "deserialize") { + std::cout << printTokens(deserialize(hexToBin(input))) << "\n"; + } + else if (command == "compile") { + std::cout << binToHex(compile(input)) << "\n"; + } + else if (command == "compile_chunk") { + std::cout << binToHex(compileChunk(input)) << "\n"; + } + else if (command == "encode_datalist") { + std::vector tokens = tokenize(input); + std::vector o; + for (int i = 0; i < (int)tokens.size(); i++) { + o.push_back(tokens[i].val); + } + std::cout << binToHex(encodeDatalist(o)) << "\n"; + } + else if (command == "decode_datalist") { + std::vector o = decodeDatalist(hexToBin(input)); + std::vector tokens; + for (int i = 0; i < (int)o.size(); i++) + tokens.push_back(token(o[i])); + std::cout << printTokens(tokens) << "\n"; + } + else if (command == "tokenize") { + std::cout << printTokens(tokenize(input)); + } + else if (command == "biject") { + if (argv == 3) + std::cerr << "Not enough arguments for biject\n"; + int pos = decimalToUnsigned(secondInput); + std::vector n = prettyCompile(input); + if (pos >= (int)n.size()) + std::cerr << "Code position too high\n"; + Metadata m = n[pos].metadata; + std::cout << "Opcode: " << n[pos].val << ", file: " << m.file << + ", line: " << m.ln << ", char: " << m.ch << "\n"; + } } From b9ba1943c442a1e61e0395affe4be82ee0ea5f74 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 25 Oct 2014 15:12:35 +0200 Subject: [PATCH 04/41] Latest PoC-7 serpent. --- libserpent/compiler.cpp | 26 ++++++++++++---------- libserpent/opcodes.h | 4 ++-- libserpent/parser.cpp | 2 +- libserpent/rewriter.cpp | 44 +++++++++++--------------------------- libwhisper/Interface.h | 1 + libwhisper/WhisperHost.cpp | 21 ++++++++++++++++++ libwhisper/WhisperHost.h | 17 ++++++++------- 7 files changed, 62 insertions(+), 53 deletions(-) diff --git a/libserpent/compiler.cpp b/libserpent/compiler.cpp index 61b70de05..251c7d9da 100644 --- a/libserpent/compiler.cpp +++ b/libserpent/compiler.cpp @@ -123,9 +123,10 @@ programData opcodeify(Node node, token("$begincode"+symb+".endcode"+symb, m), token("DUP1", m), token("$begincode"+symb, m), sub.code, token("CODECOPY", m), token("$endcode"+symb, m), token("JUMP", m), - token("~begincode"+symb, m), code, token("~endcode"+symb, m) + token("~begincode"+symb, m), code, token("~endcode"+symb, m), + token("JUMPDEST", m) }; - return pd(sub.aux, multiToken(nodelist, 10, m), 1); + return pd(sub.aux, multiToken(nodelist, 11, m), 1); } // Stack variables if (node.val == "with") { @@ -171,9 +172,9 @@ programData opcodeify(Node node, cond.code, token("$endif"+symb, m), token("JUMPI", m), action.code, - token("~endif"+symb, m) + token("~endif"+symb, m), token("JUMPDEST", m) }; - return pd(aux, multiToken(nodelist, 5, m), 0); + return pd(aux, multiToken(nodelist, 6, m), 0); } // 3-part conditional else if (node.val == "if" && node.args.size() == 3) { @@ -190,13 +191,15 @@ programData opcodeify(Node node, if (elsed.outs > outs) elsed.code = popwrap(elsed.code); Node nodelist[] = { ifd.code, - token("NOT", m), token("$else"+symb, m), token("JUMPI", m), + token("NOT", m), + token("$else"+symb, m), token("JUMPI", m), thend.code, - token("$endif"+symb, m), token("JUMP", m), token("~else"+symb, m), + token("$endif"+symb, m), token("JUMP", m), + token("~else"+symb, m), token("JUMPDEST", m), elsed.code, - token("~endif"+symb, m) + token("~endif"+symb, m), token("JUMPDEST", m) }; - return pd(aux, multiToken(nodelist, 10, m), outs); + return pd(aux, multiToken(nodelist, 12, m), outs); } // While (rewritten to this in rewrites) else if (node.val == "until") { @@ -207,13 +210,14 @@ programData opcodeify(Node node, err("Condition of while/until loop has arity 0", m); if (action.outs) action.code = popwrap(action.code); Node nodelist[] = { - token("~beg"+symb, m), + token("~beg"+symb, m), token("JUMPDEST", m), cond.code, token("$end"+symb, m), token("JUMPI", m), action.code, - token("$beg"+symb, m), token("JUMP", m), token("~end"+symb, m) + token("$beg"+symb, m), token("JUMP", m), + token("~end"+symb, m), token("JUMPDEST", m) }; - return pd(aux, multiToken(nodelist, 8, m)); + return pd(aux, multiToken(nodelist, 10, m)); } // Memory allocations else if (node.val == "alloc") { diff --git a/libserpent/opcodes.h b/libserpent/opcodes.h index f55834efa..552364731 100644 --- a/libserpent/opcodes.h +++ b/libserpent/opcodes.h @@ -72,11 +72,11 @@ Mapping mapping[] = { Mapping("PC", 0x5a, 0, 1), Mapping("MSIZE", 0x5b, 0, 1), Mapping("GAS", 0x5c, 0, 1), + Mapping("JUMPDEST", 0x5d, 0, 0), Mapping("CREATE", 0xf0, 3, 1), Mapping("CALL", 0xf1, 7, 1), Mapping("RETURN", 0xf2, 2, 0), - Mapping("POST", 0xf3, 5, 0), - Mapping("CALL_STATELESS", 0xf4, 7, 1), + Mapping("CALL_CODE", 0xf3, 7, 1), Mapping("SUICIDE", 0xff, 1, 0), Mapping("---END---", 0x00, 0, 0), }; diff --git a/libserpent/parser.cpp b/libserpent/parser.cpp index 09fcdfc47..0460c974c 100644 --- a/libserpent/parser.cpp +++ b/libserpent/parser.cpp @@ -155,10 +155,10 @@ Node treefy(std::vector stream) { else if (typ == RPAREN) { std::vector args; while (1) { - if (!oq.size()) err("Bracket without matching", tok.metadata); if (toktype(oq.back()) == LPAREN) break; args.push_back(oq.back()); oq.pop_back(); + if (!oq.size()) err("Bracket without matching", tok.metadata); } oq.pop_back(); args.push_back(oq.back()); diff --git a/libserpent/rewriter.cpp b/libserpent/rewriter.cpp index eeefd2d09..bf6a73828 100644 --- a/libserpent/rewriter.cpp +++ b/libserpent/rewriter.cpp @@ -17,9 +17,7 @@ std::string valid[][3] = { { "alloc", "1", "1" }, { "array", "1", "1" }, { "call", "2", "4" }, - { "call_stateless", "2", "4" }, - { "post", "4", "5" }, - { "postcall", "3", "4" }, + { "call_code", "2", "4" }, { "create", "1", "4" }, { "msg", "4", "6" }, { "msg_stateless", "4", "6" }, @@ -144,22 +142,6 @@ std::string macros[][2] = { "(send $to $value)", "(call (sub (gas) 25) $to $value 0 0 0 0)" }, - { - "(post $gas $to $value $datain $datainsz)", - "(~post $gas $to $value $datain (mul $datainsz 32))" - }, - { - "(post $gas $to $value $datain)", - "(seq (set $1 $datain) (~post $gas $to $value (ref $1) 32))" - }, - { - "(postcall $gas $to $datain)", - "(post $gas $to 0 $datain)", - }, - { - "(postcall $gas $to $datain $datainsz)", - "(post $gas $to 0 $datain $datainsz)", - }, { "(send $gas $to $value)", "(call $gas $to $value 0 0 0 0)" @@ -243,28 +225,28 @@ std::string macros[][2] = { }, // Call stateless and msg stateless { - "(call_stateless $f $dataval)", - "(msg_stateless (sub (gas) 45) $f 0 $dataval)" + "(call_code $f $dataval)", + "(msg_code (sub (gas) 45) $f 0 $dataval)" }, { - "(call_stateless $f $inp $inpsz)", - "(msg_stateless (sub (gas) 25) $f 0 $inp $inpsz)" + "(call_code $f $inp $inpsz)", + "(msg_code (sub (gas) 25) $f 0 $inp $inpsz)" }, { - "(call_stateless $f $inp $inpsz $outsz)", - "(with $1 $outsz (with $2 (alloc (mul 32 (get $1))) (seq (call_stateless (sub (gas) (add 25 (get $1))) $f 0 $inp (mul 32 $inpsz) (get $2) (mul 32 (get $1))) (get $2))))" + "(call_code $f $inp $inpsz $outsz)", + "(with $1 $outsz (with $2 (alloc (mul 32 (get $1))) (seq (call_code (sub (gas) (add 25 (get $1))) $f 0 $inp (mul 32 $inpsz) (get $2) (mul 32 (get $1))) (get $2))))" }, { - "(msg_stateless $gas $to $val $inp $inpsz)", - "(seq (call_stateless $gas $to $val $inp (mul 32 $inpsz) (ref $1) 32) (get $1))" + "(msg_code $gas $to $val $inp $inpsz)", + "(seq (call_code $gas $to $val $inp (mul 32 $inpsz) (ref $1) 32) (get $1))" }, { - "(msg_stateless $gas $to $val $dataval)", - "(seq (set $1 $dataval) (call_stateless $gas $to $val (ref $1) 32 (ref $2) 32) (get $2))" + "(msg_code $gas $to $val $dataval)", + "(seq (set $1 $dataval) (call_code $gas $to $val (ref $1) 32 (ref $2) 32) (get $2))" }, { - "(msg_stateless $gas $to $val $inp $inpsz $outsz)", - "(with $1 (mul 32 $outsz) (with $2 (alloc (get $1)) (call_stateless $gas $to $val $inp (mul 32 $inpsz) (get $2) (get $1)) (get $2)))" + "(msg_code $gas $to $val $inp $inpsz $outsz)", + "(with $1 (mul 32 $outsz) (with $2 (alloc (get $1)) (call_code $gas $to $val $inp (mul 32 $inpsz) (get $2) (get $1)) (get $2)))" }, // Wrappers { diff --git a/libwhisper/Interface.h b/libwhisper/Interface.h index 8bc37ff5e..56b3be599 100644 --- a/libwhisper/Interface.h +++ b/libwhisper/Interface.h @@ -75,6 +75,7 @@ public: virtual void uninstallWatch(unsigned _watchId) = 0; virtual h256s peekWatch(unsigned _watchId) const = 0; virtual h256s checkWatch(unsigned _watchId) = 0; + virtual h256s watchMessages(unsigned _watchId) = 0; virtual Envelope envelope(h256 _m) const = 0; diff --git a/libwhisper/WhisperHost.cpp b/libwhisper/WhisperHost.cpp index b11b4af3a..25c1a06bf 100644 --- a/libwhisper/WhisperHost.cpp +++ b/libwhisper/WhisperHost.cpp @@ -107,6 +107,27 @@ unsigned WhisperHost::installWatch(shh::TopicFilter const& _f) return installWatchOnId(h); } +h256s WhisperHost::watchMessages(unsigned _watchId) +{ + h256s ret; + auto wit = m_watches.find(_watchId); + if (wit == m_watches.end()) + return ret; + TopicFilter f; + { + Guard l(m_filterLock); + auto fit = m_filters.find(wit->second.id); + if (fit == m_filters.end()) + return ret; + f = fit->second.filter; + } + ReadGuard l(x_messages); + for (auto const& m: m_messages) + if (f.matches(m.second)) + ret.push_back(m.first); + return ret; +} + void WhisperHost::uninstallWatch(unsigned _i) { cwatshh << "XXX" << _i; diff --git a/libwhisper/WhisperHost.h b/libwhisper/WhisperHost.h index 2a8789956..9ad859967 100644 --- a/libwhisper/WhisperHost.h +++ b/libwhisper/WhisperHost.h @@ -48,16 +48,17 @@ public: unsigned protocolVersion() const { return 0; } - virtual void inject(Envelope const& _e, WhisperPeer* _from = nullptr); + virtual void inject(Envelope const& _e, WhisperPeer* _from = nullptr) override; using Interface::installWatch; - virtual unsigned installWatch(TopicFilter const& _filter); - virtual unsigned installWatchOnId(h256 _filterId); - virtual void uninstallWatch(unsigned _watchId); - virtual h256s peekWatch(unsigned _watchId) const { dev::Guard l(m_filterLock); try { return m_watches.at(_watchId).changes; } catch (...) { return h256s(); } } - virtual h256s checkWatch(unsigned _watchId) { dev::Guard l(m_filterLock); h256s ret; try { ret = m_watches.at(_watchId).changes; m_watches.at(_watchId).changes.clear(); } catch (...) {} return ret; } - - virtual Envelope envelope(h256 _m) const { try { dev::ReadGuard l(x_messages); return m_messages.at(_m); } catch (...) { return Envelope(); } } + virtual unsigned installWatch(TopicFilter const& _filter) override; + virtual unsigned installWatchOnId(h256 _filterId) override; + virtual void uninstallWatch(unsigned _watchId) override; + virtual h256s peekWatch(unsigned _watchId) const override { dev::Guard l(m_filterLock); try { return m_watches.at(_watchId).changes; } catch (...) { return h256s(); } } + virtual h256s checkWatch(unsigned _watchId) override { dev::Guard l(m_filterLock); h256s ret; try { ret = m_watches.at(_watchId).changes; m_watches.at(_watchId).changes.clear(); } catch (...) {} return ret; } + virtual h256s watchMessages(unsigned _watchId) override; + + virtual Envelope envelope(h256 _m) const override { try { dev::ReadGuard l(x_messages); return m_messages.at(_m); } catch (...) { return Envelope(); } } private: void streamMessage(h256 _m, RLPStream& _s) const; From 91d6506e94d4b9de490ee802ee4897575b393dfb Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 25 Oct 2014 15:12:56 +0200 Subject: [PATCH 05/41] Whisper calls back for pre-existing messages. --- libqethereum/QEthereum.cpp | 42 +++++++++++++++++++++++++++++++------- libqethereum/QEthereum.h | 3 ++- 2 files changed, 37 insertions(+), 8 deletions(-) diff --git a/libqethereum/QEthereum.cpp b/libqethereum/QEthereum.cpp index d87f4ecb3..a71aca2b4 100644 --- a/libqethereum/QEthereum.cpp +++ b/libqethereum/QEthereum.cpp @@ -660,13 +660,6 @@ void QWhisper::clearWatches() m_watches.clear(); } -QString QWhisper::newIdentity() -{ - KeyPair kp = KeyPair::create(); - m_ids[kp.pub()] = kp.sec(); - return toQJS(kp.pub()); -} - static QString toJson(h256 const& _h, shh::Envelope const& _e, shh::Message const& _m) { QJsonObject v; @@ -685,6 +678,41 @@ static QString toJson(h256 const& _h, shh::Envelope const& _e, shh::Message cons return QString::fromUtf8(QJsonDocument(v).toJson()); } +QString QWhisper::watchMessages(unsigned _w) +{ + QString ret = "["; + auto wit = m_watches.find(_w); + if (wit == m_watches.end()) + { + cwarn << "watchMessages called with invalid watch id" << _w; + return ""; + } + Public p = wit->second; + if (!p || m_ids.count(p)) + for (h256 const& h: face()->watchMessages(_w)) + { + auto e = face()->envelope(h); + shh::Message m; + if (p) + { + cwarn << "Silently decrypting message from identity" << p.abridged() << ": User validation hook goes here."; + m = e.open(m_ids[p]); + } + else + m = e.open(); + ret.append((ret == "[" ? "" : ",") + toJson(h, e, m)); + } + + return ret + "]"; +} + +QString QWhisper::newIdentity() +{ + KeyPair kp = KeyPair::create(); + m_ids[kp.pub()] = kp.sec(); + return toQJS(kp.pub()); +} + void QWhisper::poll() { for (auto const& w: m_watches) diff --git a/libqethereum/QEthereum.h b/libqethereum/QEthereum.h index 42696d40c..f17b967a4 100644 --- a/libqethereum/QEthereum.h +++ b/libqethereum/QEthereum.h @@ -234,6 +234,7 @@ public: Q_INVOKABLE unsigned newWatch(QString _json); Q_INVOKABLE void killWatch(unsigned _w); void clearWatches(); + Q_INVOKABLE QString watchMessages(unsigned _w); public slots: /// Check to see if anything has changed, fire off signals if so. @@ -272,7 +273,7 @@ private: if (_shh) \ { \ _frame->addToJavaScriptWindowObject("_web3_dot_shh", _shh, QWebFrame::ScriptOwnership); \ - _frame->evaluateJavaScript("_web3_dot_shh.makeWatch = function(json) { var ww = _web3_dot_shh.newWatch(json); var ret = { w: ww }; ret.uninstall = function() { _web3_dot_shh.killWatch(w); }; ret.arrived = function(f) { _web3_dot_shh.watchChanged.connect(function(nw, envelope) { if (nw == ww) f(JSON.parse(envelope)) }); }; return ret; }"); \ + _frame->evaluateJavaScript("_web3_dot_shh.makeWatch = function(json) { var ww = _web3_dot_shh.newWatch(json); var ret = { w: ww }; ret.uninstall = function() { _web3_dot_shh.killWatch(w); }; ret.arrived = function(f) { _web3_dot_shh.watchChanged.connect(function(nw, envelope) { if (nw == ww) f(JSON.parse(envelope)) }); var existing = JSON.parse(_web3_dot_shh.watchMessages(ww)); for (var e in existing) f(existing[e]) }; return ret; }"); \ _frame->evaluateJavaScript("_web3_dot_shh.watch = function(filter) { return _web3_dot_shh.makeWatch(JSON.stringify(filter)) }"); \ _frame->evaluateJavaScript("_web3_dot_shh.post = function(message) { return _web3_dot_shh.doPost(JSON.stringify(message)) }"); \ _frame->evaluateJavaScript("web3.shh = _web3_dot_shh"); \ From 11015aba10c9a29efbd622448e596651196a23e8 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 25 Oct 2014 15:32:29 +0200 Subject: [PATCH 06/41] TTL works. --- libqethereum/QEthereum.cpp | 2 +- libwhisper/WhisperHost.cpp | 15 +++++++++++++++ libwhisper/WhisperHost.h | 5 ++++- 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/libqethereum/QEthereum.cpp b/libqethereum/QEthereum.cpp index a71aca2b4..e77c9d632 100644 --- a/libqethereum/QEthereum.cpp +++ b/libqethereum/QEthereum.cpp @@ -595,7 +595,7 @@ static shh::Envelope toSealed(QString _json, shh::Message const& _m, Secret _fro for (auto i: f["topic"].toArray()) bt.shift(asBytes(padded(i.toString(), 32))); } - return _m.seal(_from, bt, workToProve, ttl); + return _m.seal(_from, bt, ttl, workToProve); } void QWhisper::doPost(QString _json) diff --git a/libwhisper/WhisperHost.cpp b/libwhisper/WhisperHost.cpp index 25c1a06bf..26ca3d93b 100644 --- a/libwhisper/WhisperHost.cpp +++ b/libwhisper/WhisperHost.cpp @@ -53,6 +53,9 @@ void WhisperHost::streamMessage(h256 _m, RLPStream& _s) const void WhisperHost::inject(Envelope const& _m, WhisperPeer* _p) { + if (_m.expiry() <= time(0)) + return; + auto h = _m.sha3(); { UpgradableGuard l(x_messages); @@ -60,6 +63,7 @@ void WhisperHost::inject(Envelope const& _m, WhisperPeer* _p) return; UpgradeGuard ll(l); m_messages[h] = _m; + m_expiryQueue[_m.expiry()] = h; } // if (_p) @@ -109,6 +113,7 @@ unsigned WhisperHost::installWatch(shh::TopicFilter const& _f) h256s WhisperHost::watchMessages(unsigned _watchId) { + cleanup(); h256s ret; auto wit = m_watches.find(_watchId); if (wit == m_watches.end()) @@ -145,3 +150,13 @@ void WhisperHost::uninstallWatch(unsigned _i) if (!--fit->second.refCount) m_filters.erase(fit); } + +void WhisperHost::cleanup() +{ + // remove old messages. + // should be called every now and again. + auto now = time(0); + WriteGuard l(x_messages); + for (auto it = m_expiryQueue.begin(); it != m_expiryQueue.end() && it->first <= now; it = m_expiryQueue.erase(it)) + m_messages.erase(it->second); +} diff --git a/libwhisper/WhisperHost.h b/libwhisper/WhisperHost.h index 9ad859967..2eb4856ee 100644 --- a/libwhisper/WhisperHost.h +++ b/libwhisper/WhisperHost.h @@ -55,11 +55,13 @@ public: virtual unsigned installWatchOnId(h256 _filterId) override; virtual void uninstallWatch(unsigned _watchId) override; virtual h256s peekWatch(unsigned _watchId) const override { dev::Guard l(m_filterLock); try { return m_watches.at(_watchId).changes; } catch (...) { return h256s(); } } - virtual h256s checkWatch(unsigned _watchId) override { dev::Guard l(m_filterLock); h256s ret; try { ret = m_watches.at(_watchId).changes; m_watches.at(_watchId).changes.clear(); } catch (...) {} return ret; } + virtual h256s checkWatch(unsigned _watchId) override { cleanup(); dev::Guard l(m_filterLock); h256s ret; try { ret = m_watches.at(_watchId).changes; m_watches.at(_watchId).changes.clear(); } catch (...) {} return ret; } virtual h256s watchMessages(unsigned _watchId) override; virtual Envelope envelope(h256 _m) const override { try { dev::ReadGuard l(x_messages); return m_messages.at(_m); } catch (...) { return Envelope(); } } + void cleanup(); + private: void streamMessage(h256 _m, RLPStream& _s) const; @@ -67,6 +69,7 @@ private: mutable dev::SharedMutex x_messages; std::map m_messages; + std::map m_expiryQueue; mutable dev::Mutex m_filterLock; std::map m_filters; From 91e38ec706d0baf3641efd9007f8a66d29bea58f Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 25 Oct 2014 17:13:40 +0200 Subject: [PATCH 07/41] Remove stupid assertion. Add licence header to solc. --- libdevcrypto/EC.cpp | 2 +- libqethereum/QEthereum.cpp | 2 ++ libqethereum/QEthereum.h | 2 +- solc/main.cpp | 21 +++++++++++++++++++++ 4 files changed, 25 insertions(+), 2 deletions(-) diff --git a/libdevcrypto/EC.cpp b/libdevcrypto/EC.cpp index b38703ac3..75c2fcc3d 100644 --- a/libdevcrypto/EC.cpp +++ b/libdevcrypto/EC.cpp @@ -66,7 +66,7 @@ void dev::crypto::decrypt(Secret const& _k, bytes& io_text) p.resize(d.MaxPlaintextLength(io_text.size())); // todo: use StringSource with _c as input and output. DecodingResult r = d.Decrypt(pp::PRNG(), io_text.data(), clen, p.data()); - assert(r.messageLength); +// assert(r.messageLength); io_text.resize(r.messageLength); io_text = std::move(p); } diff --git a/libqethereum/QEthereum.cpp b/libqethereum/QEthereum.cpp index e77c9d632..92180817b 100644 --- a/libqethereum/QEthereum.cpp +++ b/libqethereum/QEthereum.cpp @@ -725,6 +725,8 @@ void QWhisper::poll() { cwarn << "Silently decrypting message from identity" << w.second.abridged() << ": User validation hook goes here."; m = e.open(m_ids[w.second]); + if (!m) + continue; } else m = e.open(); diff --git a/libqethereum/QEthereum.h b/libqethereum/QEthereum.h index f17b967a4..37f0800cc 100644 --- a/libqethereum/QEthereum.h +++ b/libqethereum/QEthereum.h @@ -233,7 +233,7 @@ public: // Watches interface Q_INVOKABLE unsigned newWatch(QString _json); Q_INVOKABLE void killWatch(unsigned _w); - void clearWatches(); + Q_INVOKABLE void clearWatches(); Q_INVOKABLE QString watchMessages(unsigned _w); public slots: diff --git a/solc/main.cpp b/solc/main.cpp index ba0b6ccf7..1acdefd8c 100644 --- a/solc/main.cpp +++ b/solc/main.cpp @@ -1,3 +1,24 @@ +/* + 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 + * Solidity abstract syntax tree. + */ #include #include From c379bea27bec20f7c46306da73c08dd1a6a88c86 Mon Sep 17 00:00:00 2001 From: Christian Date: Sat, 25 Oct 2014 17:56:44 +0200 Subject: [PATCH 08/41] CMakeLists library dependency cleanup for libdevcore, libevmface, libsolidity and solc. Fixes #417. --- libdevcore/CMakeLists.txt | 6 +++--- libevmface/CMakeLists.txt | 19 ------------------- libsolidity/CMakeLists.txt | 27 +-------------------------- solc/CMakeLists.txt | 17 ----------------- 4 files changed, 4 insertions(+), 65 deletions(-) diff --git a/libdevcore/CMakeLists.txt b/libdevcore/CMakeLists.txt index 81e210cad..7c54301c9 100644 --- a/libdevcore/CMakeLists.txt +++ b/libdevcore/CMakeLists.txt @@ -19,8 +19,6 @@ endif() include_directories(..) -target_link_libraries(${EXECUTABLE} devcore) - if("${TARGET_PLATFORM}" STREQUAL "w64") include_directories(/usr/x86_64-w64-mingw32/include/cryptopp) target_link_libraries(${EXECUTABLE} boost_system-mt-s) @@ -37,7 +35,9 @@ elseif (APPLE) find_package(Threads REQUIRED) target_link_libraries(${EXECUTABLE} ${CMAKE_THREAD_LIBS_INIT}) elseif (UNIX) - target_link_libraries(${EXECUTABLE} ${Boost_THREAD_LIBRARY}) + find_package(Boost 1.53 REQUIRED COMPONENTS thread system) + target_link_libraries(${EXECUTABLE} ${Boost_THREAD_LIBRARY} ${Boost_SYSTEM_LIBRARY}) + find_package(Threads REQUIRED) target_link_libraries(${EXECUTABLE} ${CMAKE_THREAD_LIBS_INIT}) else () target_link_libraries(${EXECUTABLE} boost_thread) diff --git a/libevmface/CMakeLists.txt b/libevmface/CMakeLists.txt index 874b9e397..f82d2b96b 100644 --- a/libevmface/CMakeLists.txt +++ b/libevmface/CMakeLists.txt @@ -17,25 +17,6 @@ include_directories(..) target_link_libraries(${EXECUTABLE} devcore) -if("${TARGET_PLATFORM}" STREQUAL "w64") - target_link_libraries(${EXECUTABLE} boost_thread_win32-mt-s) - target_link_libraries(${EXECUTABLE} iphlpapi) - target_link_libraries(${EXECUTABLE} ws2_32) - target_link_libraries(${EXECUTABLE} mswsock) - target_link_libraries(${EXECUTABLE} shlwapi) -elseif (APPLE) - # Latest mavericks boost libraries only come with -mt - find_package(Threads REQUIRED) - target_link_libraries(${EXECUTABLE} ${CMAKE_THREAD_LIBS_INIT}) -elseif (UNIX) - target_link_libraries(${EXECUTABLE} ${Boost_THREAD_LIBRARY}) - target_link_libraries(${EXECUTABLE} ${CMAKE_THREAD_LIBS_INIT}) -else () - target_link_libraries(${EXECUTABLE} boost_thread) - find_package(Threads REQUIRED) - target_link_libraries(${EXECUTABLE} ${CMAKE_THREAD_LIBS_INIT}) -endif () - install( TARGETS ${EXECUTABLE} ARCHIVE DESTINATION lib LIBRARY DESTINATION lib ) install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} ) diff --git a/libsolidity/CMakeLists.txt b/libsolidity/CMakeLists.txt index 59aa78364..757d0cc06 100644 --- a/libsolidity/CMakeLists.txt +++ b/libsolidity/CMakeLists.txt @@ -16,33 +16,8 @@ file(GLOB HEADERS "*.h") include_directories(..) -target_link_libraries(${EXECUTABLE} evmface) target_link_libraries(${EXECUTABLE} devcore) - - -if("${TARGET_PLATFORM}" STREQUAL "w64") - target_link_libraries(${EXECUTABLE} boost_system-mt-s) - target_link_libraries(${EXECUTABLE} boost_thread_win32-mt-s) - target_link_libraries(${EXECUTABLE} iphlpapi) - target_link_libraries(${EXECUTABLE} ws2_32) - target_link_libraries(${EXECUTABLE} mswsock) - target_link_libraries(${EXECUTABLE} shlwapi) -elseif (APPLE) - # Latest mavericks boost libraries only come with -mt - target_link_libraries(${EXECUTABLE} boost_system-mt) - target_link_libraries(${EXECUTABLE} boost_thread-mt) - find_package(Threads REQUIRED) - target_link_libraries(${EXECUTABLE} ${CMAKE_THREAD_LIBS_INIT}) -elseif (UNIX) - target_link_libraries(${EXECUTABLE} ${Boost_SYSTEM_LIBRARY}) - target_link_libraries(${EXECUTABLE} ${Boost_THREAD_LIBRARY}) - target_link_libraries(${EXECUTABLE} ${CMAKE_THREAD_LIBS_INIT}) -else () - target_link_libraries(${EXECUTABLE} boost_system) - target_link_libraries(${EXECUTABLE} boost_thread) - find_package(Threads REQUIRED) - target_link_libraries(${EXECUTABLE} ${CMAKE_THREAD_LIBS_INIT}) -endif () +target_link_libraries(${EXECUTABLE} evmface) install( TARGETS ${EXECUTABLE} ARCHIVE DESTINATION lib LIBRARY DESTINATION lib ) install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} ) diff --git a/solc/CMakeLists.txt b/solc/CMakeLists.txt index 9224c109d..386d4a1a8 100644 --- a/solc/CMakeLists.txt +++ b/solc/CMakeLists.txt @@ -9,23 +9,6 @@ set(EXECUTABLE solc) add_executable(${EXECUTABLE} ${SRC_LIST}) target_link_libraries(${EXECUTABLE} solidity) -target_link_libraries(${EXECUTABLE} devcore) - -if ("${TARGET_PLATFORM}" STREQUAL "w64") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-libgcc -static-libstdc++") - target_link_libraries(${EXECUTABLE} gcc) - target_link_libraries(${EXECUTABLE} gdi32) - target_link_libraries(${EXECUTABLE} ws2_32) - target_link_libraries(${EXECUTABLE} mswsock) - target_link_libraries(${EXECUTABLE} shlwapi) - target_link_libraries(${EXECUTABLE} iphlpapi) - target_link_libraries(${EXECUTABLE} boost_thread_win32-mt-s) - set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS) -elseif (UNIX) -else () - find_package(Threads REQUIRED) - target_link_libraries(${EXECUTABLE} ${CMAKE_THREAD_LIBS_INIT}) -endif () install( TARGETS ${EXECUTABLE} DESTINATION bin ) From b866e7f723ce430664e07715a768549b5742b7f2 Mon Sep 17 00:00:00 2001 From: Christian Date: Sat, 25 Oct 2014 18:30:43 +0200 Subject: [PATCH 09/41] Corrected file description. --- solc/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/solc/main.cpp b/solc/main.cpp index 1acdefd8c..0843cfa02 100644 --- a/solc/main.cpp +++ b/solc/main.cpp @@ -17,7 +17,7 @@ /** * @author Christian * @date 2014 - * Solidity abstract syntax tree. + * Solidity commandline compiler. */ #include From bfd797c3a17782898be4b8d7f24cbb140ea67f46 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 25 Oct 2014 22:10:53 +0200 Subject: [PATCH 10/41] Whisperer in AZ. More Whisper fixups. --- alethzero/Main.ui | 217 ++++++++++++++++++++++++++++++++++++- alethzero/MainWin.cpp | 193 ++++++++++++++++++++++++--------- alethzero/MainWin.h | 4 + libdevcore/Common.cpp | 2 +- libdevcore/FixedHash.h | 2 +- libdevcrypto/EC.cpp | 6 +- libp2p/Host.h | 2 +- libqethereum/QEthereum.cpp | 8 +- libqethereum/QEthereum.h | 4 + libwhisper/WhisperHost.cpp | 6 +- 10 files changed, 385 insertions(+), 59 deletions(-) diff --git a/alethzero/Main.ui b/alethzero/Main.ui index 16dcd8a4c..db246107d 100644 --- a/alethzero/Main.ui +++ b/alethzero/Main.ui @@ -6,8 +6,8 @@ 0 0 - 1711 - 1138 + 1617 + 1371 @@ -116,7 +116,7 @@ 0 0 - 1711 + 1617 25 @@ -204,11 +204,18 @@ + + + &Whisper + + + + @@ -1514,6 +1521,205 @@ font-size: 14pt + + + QDockWidget::DockWidgetFeatureMask + + + Whisper + + + 1 + + + + + + + ms + + + 1 + + + 1000 + + + 50 + + + + + + + + 0 + 0 + + + + Topic + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + data + + + + + + + + 0 + 0 + + + + QFrame::NoFrame + + + 0 + + + + + + + + 0 + 0 + + + + QFrame::NoFrame + + + 0 + + + + + + + Post + + + + + + + + 0 + 0 + + + + TTL + + + destination + + + + + + + + 0 + 0 + + + + From + + + destination + + + + + + + + 0 + 0 + + + + To + + + destination + + + + + + + false + + + + + + + true + + + + + + + + 0 + 0 + + + + Data + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + data + + + + + + + seconds + + + 5 + + + 259200 + + + + + + + + 0 + 0 + + + + Work to Prove + + + destination + + + + + + &Quit @@ -1801,6 +2007,11 @@ font-size: 14pt Go! + + + New Identity + + diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 9a98f54ee..d4d0b6050 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -146,6 +146,7 @@ Main::Main(QWidget *parent) : auto qeth = m_ethereum; auto qshh = m_whisper; connect(f, &QWebFrame::javaScriptWindowObjectCleared, QETH_INSTALL_JS_NAMESPACE(f, this, qdev, qeth, qshh)); + connect(m_whisper, SIGNAL(idsChanged()), this, SLOT(refreshWhisper())); }); connect(ui->webView, &QWebView::loadFinished, [=]() @@ -332,8 +333,6 @@ void Main::load(QString _s) } } -// env.load("/home/gav/eth/init.eth") - void Main::on_loadJS_triggered() { QString f = QFileDialog::getOpenFileName(this, "Load Javascript", QString(), "Javascript (*.js);;All files (*)"); @@ -388,6 +387,17 @@ void Main::eval(QString const& _js) ui->jsConsole->setHtml(s); } +static Public stringToPublic(QString const& _a) +{ + string sn = _a.toStdString(); + if (_a.size() == sizeof(Public) * 2) + return Public(fromHex(_a.toStdString())); + else if (_a.size() == sizeof(Public) * 2 + 2 && _a.startsWith("0x")) + return Public(fromHex(_a.mid(2).toStdString())); + else + return Public(); +} + QString Main::pretty(dev::Address _a) const { h256 n; @@ -1385,6 +1395,112 @@ void Main::on_destination_currentTextChanged() // updateFee(); } +static bytes dataFromText(QString _s) +{ + bytes ret; + while (_s.size()) + { + QRegExp r("(@|\\$)?\"([^\"]*)\"(\\s.*)?"); + QRegExp d("(@|\\$)?([0-9]+)(\\s*(ether)|(finney)|(szabo))?(\\s.*)?"); + QRegExp h("(@|\\$)?(0x)?(([a-fA-F0-9])+)(\\s.*)?"); + if (r.exactMatch(_s)) + { + for (auto i: r.cap(2)) + ret.push_back((byte)i.toLatin1()); + if (r.cap(1) != "$") + for (int i = r.cap(2).size(); i < 32; ++i) + ret.push_back(0); + else + ret.push_back(0); + _s = r.cap(3); + } + else if (d.exactMatch(_s)) + { + u256 v(d.cap(2).toStdString()); + if (d.cap(6) == "szabo") + v *= dev::eth::szabo; + else if (d.cap(5) == "finney") + v *= dev::eth::finney; + else if (d.cap(4) == "ether") + v *= dev::eth::ether; + bytes bs = dev::toCompactBigEndian(v); + if (d.cap(1) != "$") + for (auto i = bs.size(); i < 32; ++i) + ret.push_back(0); + for (auto b: bs) + ret.push_back(b); + _s = d.cap(7); + } + else if (h.exactMatch(_s)) + { + bytes bs = fromHex((((h.cap(3).size() & 1) ? "0" : "") + h.cap(3)).toStdString()); + if (h.cap(1) != "$") + for (auto i = bs.size(); i < 32; ++i) + ret.push_back(0); + for (auto b: bs) + ret.push_back(b); + _s = h.cap(5); + } + else + _s = _s.mid(1); + } + return ret; +} + +static shh::Topic topicFromText(QString _s) +{ + shh::BuildTopic ret; + while (_s.size()) + { + QRegExp r("(@|\\$)?\"([^\"]*)\"(\\s.*)?"); + QRegExp d("(@|\\$)?([0-9]+)(\\s*(ether)|(finney)|(szabo))?(\\s.*)?"); + QRegExp h("(@|\\$)?(0x)?(([a-fA-F0-9])+)(\\s.*)?"); + bytes part; + if (r.exactMatch(_s)) + { + for (auto i: r.cap(2)) + part.push_back((byte)i.toLatin1()); + if (r.cap(1) != "$") + for (int i = r.cap(2).size(); i < 32; ++i) + part.push_back(0); + else + part.push_back(0); + _s = r.cap(3); + } + else if (d.exactMatch(_s)) + { + u256 v(d.cap(2).toStdString()); + if (d.cap(6) == "szabo") + v *= dev::eth::szabo; + else if (d.cap(5) == "finney") + v *= dev::eth::finney; + else if (d.cap(4) == "ether") + v *= dev::eth::ether; + bytes bs = dev::toCompactBigEndian(v); + if (d.cap(1) != "$") + for (auto i = bs.size(); i < 32; ++i) + part.push_back(0); + for (auto b: bs) + part.push_back(b); + _s = d.cap(7); + } + else if (h.exactMatch(_s)) + { + bytes bs = fromHex((((h.cap(3).size() & 1) ? "0" : "") + h.cap(3)).toStdString()); + if (h.cap(1) != "$") + for (auto i = bs.size(); i < 32; ++i) + part.push_back(0); + for (auto b: bs) + part.push_back(b); + _s = h.cap(5); + } + else + _s = _s.mid(1); + ret.shift(part); + } + return ret; +} + void Main::on_data_textChanged() { m_pcWarp.clear(); @@ -1439,54 +1555,7 @@ void Main::on_data_textChanged() } else { - m_data.clear(); - QString s = ui->data->toPlainText(); - while (s.size()) - { - QRegExp r("(@|\\$)?\"([^\"]*)\"(\\s.*)?"); - QRegExp d("(@|\\$)?([0-9]+)(\\s*(ether)|(finney)|(szabo))?(\\s.*)?"); - QRegExp h("(@|\\$)?(0x)?(([a-fA-F0-9])+)(\\s.*)?"); - if (r.exactMatch(s)) - { - for (auto i: r.cap(2)) - m_data.push_back((byte)i.toLatin1()); - if (r.cap(1) != "$") - for (int i = r.cap(2).size(); i < 32; ++i) - m_data.push_back(0); - else - m_data.push_back(0); - s = r.cap(3); - } - else if (d.exactMatch(s)) - { - u256 v(d.cap(2).toStdString()); - if (d.cap(6) == "szabo") - v *= dev::eth::szabo; - else if (d.cap(5) == "finney") - v *= dev::eth::finney; - else if (d.cap(4) == "ether") - v *= dev::eth::ether; - bytes bs = dev::toCompactBigEndian(v); - if (d.cap(1) != "$") - for (auto i = bs.size(); i < 32; ++i) - m_data.push_back(0); - for (auto b: bs) - m_data.push_back(b); - s = d.cap(7); - } - else if (h.exactMatch(s)) - { - bytes bs = fromHex((((h.cap(3).size() & 1) ? "0" : "") + h.cap(3)).toStdString()); - if (h.cap(1) != "$") - for (auto i = bs.size(); i < 32; ++i) - m_data.push_back(0); - for (auto b: bs) - m_data.push_back(b); - s = h.cap(5); - } - else - s = s.mid(1); - } + m_data = dataFromText(ui->data->toPlainText()); ui->code->setHtml(QString::fromStdString(dev::memDump(m_data, 8, true))); if (ethereum()->codeAt(fromString(ui->destination->currentText()), 0).size()) { @@ -2015,6 +2084,30 @@ void Main::updateDebugger() } } +void Main::on_post_clicked() +{ + shh::Message m; + m.setTo(stringToPublic(ui->shhTo->currentText())); + m.setPayload(dataFromText(ui->shhData->toPlainText())); + Public f = stringToPublic(ui->shhFrom->currentText()); + Secret from; + if (m_whisper->ids().count(f)) + from = m_whisper->ids().at(f); + whisper()->inject(m.seal(from, topicFromText(ui->shhTopic->toPlainText()), ui->shhWork->value(), ui->shhTtl->value())); +} + +void Main::on_newIdentity_triggered() +{ + m_whisper->makeIdentity(); +} + +void Main::refreshWhisper() +{ + ui->shhFrom->clear(); + for (auto i: m_whisper->ids()) + ui->shhFrom->addItem(QString::fromStdString(toHex(i.first.ref()))); +} + // extra bits needed to link on VS #ifdef _MSC_VER diff --git a/alethzero/MainWin.h b/alethzero/MainWin.h index aa5fcf572..b8231ddf7 100644 --- a/alethzero/MainWin.h +++ b/alethzero/MainWin.h @@ -149,6 +149,10 @@ private slots: void on_turboMining_triggered(); void on_go_triggered(); void on_importKeyFile_triggered(); + void on_post_clicked(); + void on_newIdentity_triggered(); + + void refreshWhisper(); signals: void poll(); diff --git a/libdevcore/Common.cpp b/libdevcore/Common.cpp index d9192c79f..97c1d32c7 100644 --- a/libdevcore/Common.cpp +++ b/libdevcore/Common.cpp @@ -27,7 +27,7 @@ using namespace dev; namespace dev { -char const* Version = "0.7.5"; +char const* Version = "0.7.6"; } diff --git a/libdevcore/FixedHash.h b/libdevcore/FixedHash.h index c8d250b35..0032a1314 100644 --- a/libdevcore/FixedHash.h +++ b/libdevcore/FixedHash.h @@ -59,7 +59,7 @@ public: FixedHash() { m_data.fill(0); } /// Construct from another hash, filling with zeroes or cropping as necessary. - template FixedHash(FixedHash const& _h, ConstructFromHashType _t = AlignLeft) { m_data.fill(0); unsigned c = std::min(M, N); for (unsigned i = 0; i < c; ++i) m_data[_t == AlignRight ? N - 1 - i : i] = _h[_t == AlignRight ? M - 1 - i : i]; } + template explicit FixedHash(FixedHash const& _h, ConstructFromHashType _t = AlignLeft) { m_data.fill(0); unsigned c = std::min(M, N); for (unsigned i = 0; i < c; ++i) m_data[_t == AlignRight ? N - 1 - i : i] = _h[_t == AlignRight ? M - 1 - i : i]; } /// Convert from the corresponding arithmetic type. FixedHash(Arith const& _arith) { toBigEndian(_arith, m_data); } diff --git a/libdevcrypto/EC.cpp b/libdevcrypto/EC.cpp index 75c2fcc3d..7072753b1 100644 --- a/libdevcrypto/EC.cpp +++ b/libdevcrypto/EC.cpp @@ -66,7 +66,11 @@ void dev::crypto::decrypt(Secret const& _k, bytes& io_text) p.resize(d.MaxPlaintextLength(io_text.size())); // todo: use StringSource with _c as input and output. DecodingResult r = d.Decrypt(pp::PRNG(), io_text.data(), clen, p.data()); -// assert(r.messageLength); + if (!r.isValidCoding) + { + io_text.clear(); + return; + } io_text.resize(r.messageLength); io_text = std::move(p); } diff --git a/libp2p/Host.h b/libp2p/Host.h index 34179a3b4..6e60b915e 100644 --- a/libp2p/Host.h +++ b/libp2p/Host.h @@ -203,7 +203,7 @@ private: /// This won't touch alter the blockchain. virtual void doWork(); - std::shared_ptr noteNode(NodeId _id, bi::tcp::endpoint _a, Origin _o, bool _ready, NodeId _oldId = h256()); + std::shared_ptr noteNode(NodeId _id, bi::tcp::endpoint _a, Origin _o, bool _ready, NodeId _oldId = NodeId()); Nodes potentialPeers(RangeMask const& _known); std::string m_clientVersion; ///< Our version string. diff --git a/libqethereum/QEthereum.cpp b/libqethereum/QEthereum.cpp index 92180817b..535c43325 100644 --- a/libqethereum/QEthereum.cpp +++ b/libqethereum/QEthereum.cpp @@ -707,10 +707,16 @@ QString QWhisper::watchMessages(unsigned _w) } QString QWhisper::newIdentity() +{ + return toQJS(makeIdentity()); +} + +Public QWhisper::makeIdentity() { KeyPair kp = KeyPair::create(); m_ids[kp.pub()] = kp.sec(); - return toQJS(kp.pub()); + emit idsChanged(); + return kp.pub(); } void QWhisper::poll() diff --git a/libqethereum/QEthereum.h b/libqethereum/QEthereum.h index 37f0800cc..9866a4e7a 100644 --- a/libqethereum/QEthereum.h +++ b/libqethereum/QEthereum.h @@ -236,6 +236,9 @@ public: Q_INVOKABLE void clearWatches(); Q_INVOKABLE QString watchMessages(unsigned _w); + dev::Public makeIdentity(); + std::map const& ids() const { return m_ids; } + public slots: /// Check to see if anything has changed, fire off signals if so. /// @note Must be called in the QObject's thread. @@ -243,6 +246,7 @@ public slots: signals: void watchChanged(unsigned _w, QString _envelopeJson); + void idsChanged(); private: std::weak_ptr m_face; diff --git a/libwhisper/WhisperHost.cpp b/libwhisper/WhisperHost.cpp index 26ca3d93b..591574bf0 100644 --- a/libwhisper/WhisperHost.cpp +++ b/libwhisper/WhisperHost.cpp @@ -47,12 +47,16 @@ void WhisperHost::streamMessage(h256 _m, RLPStream& _s) const if (m_messages.count(_m)) { UpgradeGuard ll(l); - m_messages.at(_m).streamOut(_s, true); + auto const& m = m_messages.at(_m); + cnote << "streamOut: " << m.expiry() << m.ttl() << m.topic() << toHex(m.data()); + m.streamOut(_s, true); } } void WhisperHost::inject(Envelope const& _m, WhisperPeer* _p) { + cnote << "inject: " << _m.expiry() << _m.ttl() << _m.topic() << toHex(_m.data()); + if (_m.expiry() <= time(0)) return; From 42cb5ae9f0ef82d9a8e2a0671b5fa7549446b9db Mon Sep 17 00:00:00 2001 From: nicksavers Date: Sat, 25 Oct 2014 22:33:41 +0200 Subject: [PATCH 11/41] Add files fix VS2013 --- libdevcrypto/All.h | 3 +++ windows/LibEthereum.vcxproj | 6 ++++++ windows/LibEthereum.vcxproj.filters | 18 ++++++++++++++++++ 3 files changed, 27 insertions(+) diff --git a/libdevcrypto/All.h b/libdevcrypto/All.h index 6d1844857..db6d7c615 100644 --- a/libdevcrypto/All.h +++ b/libdevcrypto/All.h @@ -1,9 +1,12 @@ #pragma once #include "Common.h" +#include "CryptoPP.h" +#include "EC.h" #include "FileSystem.h" #include "MemoryDB.h" #include "OverlayDB.h" #include "SHA3.h" +#include "SHA3MAC.h" #include "TrieCommon.h" #include "TrieDB.h" diff --git a/windows/LibEthereum.vcxproj b/windows/LibEthereum.vcxproj index 8c08091ec..2ece3cd28 100644 --- a/windows/LibEthereum.vcxproj +++ b/windows/LibEthereum.vcxproj @@ -69,10 +69,13 @@ + + + @@ -270,10 +273,13 @@ + + + diff --git a/windows/LibEthereum.vcxproj.filters b/windows/LibEthereum.vcxproj.filters index 7d743d82d..b4d898890 100644 --- a/windows/LibEthereum.vcxproj.filters +++ b/windows/LibEthereum.vcxproj.filters @@ -193,6 +193,15 @@ libethcore + + libdevcrypto + + + libdevcrypto + + + libdevcrypto + @@ -417,6 +426,15 @@ libwebthree + + libdevcrypto + + + libdevcrypto + + + libdevcrypto + From 2df5cc9fda7f07567f635ac2146937dea491f666 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 25 Oct 2014 23:23:51 +0200 Subject: [PATCH 12/41] Whispers pane. --- alethzero/Main.ui | 37 +++++++++++++++++++++++++++++++++++++ alethzero/MainWin.cpp | 29 ++++++++++++++++++++++++++++- alethzero/MainWin.h | 1 + libdevcrypto/EC.cpp | 2 +- libwhisper/Message.cpp | 11 +++++++---- libwhisper/Message.h | 2 +- libwhisper/WhisperHost.h | 2 ++ 7 files changed, 77 insertions(+), 7 deletions(-) diff --git a/alethzero/Main.ui b/alethzero/Main.ui index db246107d..1fdf7de19 100644 --- a/alethzero/Main.ui +++ b/alethzero/Main.ui @@ -1720,6 +1720,43 @@ font-size: 14pt + + + QDockWidget::DockWidgetFeatureMask + + + Active Whispers + + + 2 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::NoFrame + + + + + + &Quit diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index d4d0b6050..b196c1dcc 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -763,7 +763,6 @@ void Main::refreshNetwork() { auto ps = web3()->peers(); - ui->peerCount->setText(QString::fromStdString(toString(ps.size())) + " peer(s)"); ui->peers->clear(); ui->nodes->clear(); @@ -1006,6 +1005,7 @@ void Main::timerEvent(QTimerEvent*) { interval = 0; refreshNetwork(); + refreshWhispers(); } else interval += 100; @@ -2108,6 +2108,33 @@ void Main::refreshWhisper() ui->shhFrom->addItem(QString::fromStdString(toHex(i.first.ref()))); } +void Main::refreshWhispers() +{ + ui->whispers->clear(); + for (auto const& w: whisper()->all()) + { + shh::Envelope const& e = w.second; + shh::Message m; + for (pair const& i: m_whisper->ids()) + if (!!(m = e.open(i.second))) + break; + if (!m) + m = e.open(); + + QString msg; + if (m.from()) + // Good message. + msg = QString("%1->%2: %3").arg(m.from() ? m.from().abridged().c_str() : "?").arg(m.to() ? m.to().abridged().c_str() : "?").arg(toHex(m.payload()).c_str()); + else if (m) + // Maybe message. + msg = QString("%1->%2: %3 (?)").arg(m.from() ? m.from().abridged().c_str() : "?").arg(m.to() ? m.to().abridged().c_str() : "?").arg(toHex(m.payload()).c_str()); + + time_t ex = e.expiry(); + QString item = QString("[%1 - %2s] *%3 %5 %4").arg(asctime(localtime(&ex))).arg(e.ttl()).arg(e.workProved()).arg(toString(e.topic()).c_str()).arg(msg); + ui->whispers->addItem(item); + } +} + // extra bits needed to link on VS #ifdef _MSC_VER diff --git a/alethzero/MainWin.h b/alethzero/MainWin.h index b8231ddf7..b6c4c85e1 100644 --- a/alethzero/MainWin.h +++ b/alethzero/MainWin.h @@ -206,6 +206,7 @@ private: void refreshNetwork(); void refreshMining(); + void refreshWhispers(); void refreshAll(); void refreshPending(); diff --git a/libdevcrypto/EC.cpp b/libdevcrypto/EC.cpp index 7072753b1..5086e3203 100644 --- a/libdevcrypto/EC.cpp +++ b/libdevcrypto/EC.cpp @@ -52,7 +52,7 @@ void dev::crypto::encrypt(Public const& _key, bytes& io_cipher) c.resize(e.CiphertextLength(plen)); // todo: use StringSource with _plain as input and output. e.Encrypt(pp::PRNG(), io_cipher.data(), plen, c.data()); - bzero(io_cipher.data(), io_cipher.size()); + memset(io_cipher.data(), 0, io_cipher.size()); io_cipher = std::move(c); } diff --git a/libwhisper/Message.cpp b/libwhisper/Message.cpp index 52caf2f90..cdfc050d8 100644 --- a/libwhisper/Message.cpp +++ b/libwhisper/Message.cpp @@ -34,18 +34,18 @@ Message::Message(Envelope const& _e, Secret const& _s) if (_s) if (!decrypt(_s, &(_e.data()), b)) return; - populate(_s ? b : _e.data()); - m_to = KeyPair(_s).pub(); + if (populate(_s ? b : _e.data())) + m_to = KeyPair(_s).pub(); } catch (...) // Invalid secret? TODO: replace ... with InvalidSecret { } } -void Message::populate(bytes const& _data) +bool Message::populate(bytes const& _data) { if (!_data.size()) - return; + return false; byte flags = _data[0]; if (!!(flags & ContainsSignature) && _data.size() > sizeof(Signature) + 1) // has a signature @@ -54,10 +54,13 @@ void Message::populate(bytes const& _data) h256 h = sha3(payload); Signature const& sig = *(Signature const*)&(_data[1 + payload.size()]); m_from = recover(sig, h); + if (!m_from) + return false; m_payload = payload.toBytes(); } else m_payload = bytesConstRef(&_data).cropped(1).toBytes(); + return true; } Envelope Message::seal(Secret _from, Topic const& _topic, unsigned _ttl, unsigned _workToProve) const diff --git a/libwhisper/Message.h b/libwhisper/Message.h index 67b34e321..84214fd18 100644 --- a/libwhisper/Message.h +++ b/libwhisper/Message.h @@ -116,7 +116,7 @@ public: Envelope sealTo(Secret _from, Public _to, Topic const& _topic, unsigned _workToProve = 50, unsigned _ttl = 50) { m_to = _to; return seal(_from, _topic, _workToProve, _ttl); } private: - void populate(bytes const& _data); + bool populate(bytes const& _data); Public m_from; Public m_to; diff --git a/libwhisper/WhisperHost.h b/libwhisper/WhisperHost.h index 2eb4856ee..4d761919c 100644 --- a/libwhisper/WhisperHost.h +++ b/libwhisper/WhisperHost.h @@ -60,6 +60,8 @@ public: virtual Envelope envelope(h256 _m) const override { try { dev::ReadGuard l(x_messages); return m_messages.at(_m); } catch (...) { return Envelope(); } } + std::map all() const { ReadGuard l(x_messages); return m_messages; } + void cleanup(); private: From 55ee4abe195242fca7a544b0ed2afda4857c5849 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 25 Oct 2014 23:37:30 +0200 Subject: [PATCH 13/41] Nicer whispers. --- alethzero/MainWin.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index b196c1dcc..982103e4c 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -2124,13 +2124,13 @@ void Main::refreshWhispers() QString msg; if (m.from()) // Good message. - msg = QString("%1->%2: %3").arg(m.from() ? m.from().abridged().c_str() : "?").arg(m.to() ? m.to().abridged().c_str() : "?").arg(toHex(m.payload()).c_str()); + msg = QString("%1->%2: %3").arg(m.from() ? m.from().abridged().c_str() : "?").arg(m.to() ? m.to().abridged().c_str() : "*").arg(toHex(m.payload()).c_str()); else if (m) // Maybe message. - msg = QString("%1->%2: %3 (?)").arg(m.from() ? m.from().abridged().c_str() : "?").arg(m.to() ? m.to().abridged().c_str() : "?").arg(toHex(m.payload()).c_str()); + msg = QString("%1->%2: %3 (?)").arg(m.from() ? m.from().abridged().c_str() : "?").arg(m.to() ? m.to().abridged().c_str() : "*").arg(toHex(m.payload()).c_str()); time_t ex = e.expiry(); - QString item = QString("[%1 - %2s] *%3 %5 %4").arg(asctime(localtime(&ex))).arg(e.ttl()).arg(e.workProved()).arg(toString(e.topic()).c_str()).arg(msg); + QString item = QString("[%1 - %2s] *%3 %5 %4").arg(ctime(&ex)).arg(e.ttl()).arg(e.workProved()).arg(toString(e.topic()).c_str()).arg(msg); ui->whispers->addItem(item); } } From 41ce2597081042c41ae84c6deaacffdfdfbbefb7 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 25 Oct 2014 23:42:34 +0200 Subject: [PATCH 14/41] Fix. --- alethzero/MainWin.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 982103e4c..e57397f04 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -2093,7 +2093,7 @@ void Main::on_post_clicked() Secret from; if (m_whisper->ids().count(f)) from = m_whisper->ids().at(f); - whisper()->inject(m.seal(from, topicFromText(ui->shhTopic->toPlainText()), ui->shhWork->value(), ui->shhTtl->value())); + whisper()->inject(m.seal(from, topicFromText(ui->shhTopic->toPlainText()), ui->shhTtl->value(), ui->shhWork->value())); } void Main::on_newIdentity_triggered() @@ -2130,7 +2130,9 @@ void Main::refreshWhispers() msg = QString("%1->%2: %3 (?)").arg(m.from() ? m.from().abridged().c_str() : "?").arg(m.to() ? m.to().abridged().c_str() : "*").arg(toHex(m.payload()).c_str()); time_t ex = e.expiry(); - QString item = QString("[%1 - %2s] *%3 %5 %4").arg(ctime(&ex)).arg(e.ttl()).arg(e.workProved()).arg(toString(e.topic()).c_str()).arg(msg); + QString t(ctime(&ex)); + t.chop(1); + QString item = QString("[%1 - %2s] *%3 %5 %4").arg(t).arg(e.ttl()).arg(e.workProved()).arg(toString(e.topic()).c_str()).arg(msg); ui->whispers->addItem(item); } } From 9a16d80df794b253575872ae9253e4bafc61d054 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 25 Oct 2014 23:56:16 +0200 Subject: [PATCH 15/41] Warnings fixes. --- libdevcrypto/Common.cpp | 4 +++- libsolidity/Types.cpp | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/libdevcrypto/Common.cpp b/libdevcrypto/Common.cpp index 6d57bf2b2..b4623ba24 100644 --- a/libdevcrypto/Common.cpp +++ b/libdevcrypto/Common.cpp @@ -144,7 +144,9 @@ Public dev::recover(Signature _sig, h256 _message) cout << "PUB: " << toHex(bytesConstRef(&(pubkey[1]), 64)) << endl; #endif - return *(Public const*)&(pubkey[1]); + Public ret; + memcpy(&ret, &(pubkey[1]), sizeof(Public)); + return ret; } inline h256 kFromMessage(h256 _msg, h256 _priv) diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index 62324f8c2..301e95778 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -51,6 +51,7 @@ std::shared_ptr Type::fromElementaryTypeName(Token::Value _typeToken) return std::make_shared(); else BOOST_ASSERT(false); // @todo add other tyes + return std::shared_ptr(); } std::shared_ptr Type::fromUserDefinedTypeName(UserDefinedTypeName const& _typeName) From 844a50d2bb26487f8958d90f66c1db041c7b4750 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 26 Oct 2014 00:48:19 +0200 Subject: [PATCH 16/41] Fix for moving to super-low number of ideal peers. --- alethzero/MainWin.cpp | 4 ++-- libp2p/Host.cpp | 21 ++++++++++++--------- libp2p/Session.cpp | 1 - 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index e57397f04..870442a36 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -2124,10 +2124,10 @@ void Main::refreshWhispers() QString msg; if (m.from()) // Good message. - msg = QString("%1->%2: %3").arg(m.from() ? m.from().abridged().c_str() : "?").arg(m.to() ? m.to().abridged().c_str() : "*").arg(toHex(m.payload()).c_str()); + msg = QString("{%1 -> %2} %3").arg(m.from() ? m.from().abridged().c_str() : "???").arg(m.to() ? m.to().abridged().c_str() : "*").arg(toHex(m.payload()).c_str()); else if (m) // Maybe message. - msg = QString("%1->%2: %3 (?)").arg(m.from() ? m.from().abridged().c_str() : "?").arg(m.to() ? m.to().abridged().c_str() : "*").arg(toHex(m.payload()).c_str()); + msg = QString("{%1 -> %2} %3 (?)").arg(m.from() ? m.from().abridged().c_str() : "???").arg(m.to() ? m.to().abridged().c_str() : "*").arg(toHex(m.payload()).c_str()); time_t ex = e.expiry(); QString t(ctime(&ex)); diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index fafb7d48a..b2d56c7d1 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -651,23 +651,26 @@ void Host::prunePeers() { RecursiveGuard l(x_peers); // We'll keep at most twice as many as is ideal, halfing what counts as "too young to kill" until we get there. - for (unsigned old = 15000; m_peers.size() > m_idealPeerCount * 2 && old > 100; old /= 2) - while (m_peers.size() > m_idealPeerCount) + set dc; + for (unsigned old = 15000; m_peers.size() - dc.size() > m_idealPeerCount * 2 && old > 100; old /= 2) + if (m_peers.size() - dc.size() > m_idealPeerCount) { // look for worst peer to kick off // first work out how many are old enough to kick off. shared_ptr worst; unsigned agedPeers = 0; for (auto i: m_peers) - if (auto p = i.second.lock()) - if (/*(m_mode != NodeMode::Host || p->m_caps != 0x01) &&*/ chrono::steady_clock::now() > p->m_connect + chrono::milliseconds(old)) // don't throw off new peers; peer-servers should never kick off other peer-servers. - { - ++agedPeers; - if ((!worst || p->rating() < worst->rating() || (p->rating() == worst->rating() && p->m_connect > worst->m_connect))) // kill older ones - worst = p; - } + if (!dc.count(i.first)) + if (auto p = i.second.lock()) + if (/*(m_mode != NodeMode::Host || p->m_caps != 0x01) &&*/ chrono::steady_clock::now() > p->m_connect + chrono::milliseconds(old)) // don't throw off new peers; peer-servers should never kick off other peer-servers. + { + ++agedPeers; + if ((!worst || p->rating() < worst->rating() || (p->rating() == worst->rating() && p->m_connect > worst->m_connect))) // kill older ones + worst = p; + } if (!worst || agedPeers <= m_idealPeerCount) break; + dc.insert(worst->id()); worst->disconnect(TooManyPeers); } diff --git a/libp2p/Session.cpp b/libp2p/Session.cpp index beb6f161d..c4385df5f 100644 --- a/libp2p/Session.cpp +++ b/libp2p/Session.cpp @@ -475,7 +475,6 @@ void Session::drop(DisconnectReason _reason) { if (m_dropped) return; - cerr << (void*)this << " dropped" << endl; if (m_socket.is_open()) try { From 82100d1cc75df72aef3455ac5db3018838204599 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 26 Oct 2014 18:39:34 +0100 Subject: [PATCH 17/41] Force name entry. --- alethzero/MainWin.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 870442a36..3ba203244 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -564,6 +564,8 @@ void Main::readSettings(bool _skipGeometry) m_enableOptimizer = s.value("enableOptimizer", true).toBool(); ui->enableOptimizer->setChecked(m_enableOptimizer); ui->clientName->setText(s.value("clientName", "").toString()); + if (ui->clientName->text().isEmpty()) + ui->clientName->setText(QInputDialog::getText(this, "Enter identity", "Enter a string that will identify you on the peer network")); ui->idealPeers->setValue(s.value("idealPeers", ui->idealPeers->value()).toInt()); ui->port->setValue(s.value("port", ui->port->value()).toInt()); ui->nameReg->setText(s.value("nameReg", "").toString()); From 2c29f1bc3ae841b5063909fd43cc4fe884ada3bc Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 26 Oct 2014 20:47:26 +0100 Subject: [PATCH 18/41] Minor reload issue eased. --- alethzero/MainWin.cpp | 4 +++- libwhisper/Message.cpp | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 3ba203244..c42cddc4f 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -134,6 +134,8 @@ Main::Main(QWidget *parent) : connect(ui->webView, &QWebView::loadStarted, [this]() { + m_ethereum = nullptr; + m_whisper = nullptr; // NOTE: no need to delete as QETH_INSTALL_JS_NAMESPACE adopts it. m_dev = new QDev(this); m_ethereum = new QEthereum(this, ethereum(), owned()); @@ -565,7 +567,7 @@ void Main::readSettings(bool _skipGeometry) ui->enableOptimizer->setChecked(m_enableOptimizer); ui->clientName->setText(s.value("clientName", "").toString()); if (ui->clientName->text().isEmpty()) - ui->clientName->setText(QInputDialog::getText(this, "Enter identity", "Enter a string that will identify you on the peer network")); + ui->clientName->setText(QInputDialog::getText(this, "Enter identity", "Enter a name that will identify you on the peer network")); ui->idealPeers->setValue(s.value("idealPeers", ui->idealPeers->value()).toInt()); ui->port->setValue(s.value("port", ui->port->value()).toInt()); ui->nameReg->setText(s.value("nameReg", "").toString()); diff --git a/libwhisper/Message.cpp b/libwhisper/Message.cpp index cdfc050d8..93dcaa033 100644 --- a/libwhisper/Message.cpp +++ b/libwhisper/Message.cpp @@ -48,7 +48,7 @@ bool Message::populate(bytes const& _data) return false; byte flags = _data[0]; - if (!!(flags & ContainsSignature) && _data.size() > sizeof(Signature) + 1) // has a signature + if (!!(flags & ContainsSignature) && _data.size() >= sizeof(Signature) + 1) // has a signature { bytesConstRef payload = bytesConstRef(&_data).cropped(1, _data.size() - sizeof(Signature) - 1); h256 h = sha3(payload); From dfea821aaf4de7e0487468cacc0d611d7c0c14ef Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 27 Oct 2014 12:02:01 +0100 Subject: [PATCH 19/41] DB prototyped. --- alethzero/MainWin.cpp | 86 ++++++++++++++++++++++++++---------- alethzero/MainWin.h | 10 +++-- libp2p/Host.cpp | 2 +- libqethereum/QEthereum.cpp | 89 ++++++++++++++++++++++++++++++++++++-- libqethereum/QEthereum.h | 67 ++++++++++++++++++++++++++-- third/MainWin.cpp | 9 ++-- third/MainWin.h | 6 ++- 7 files changed, 231 insertions(+), 38 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index c42cddc4f..674509b53 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -131,6 +131,7 @@ Main::Main(QWidget *parent) : connect(ui->ourAccounts->model(), SIGNAL(rowsMoved(const QModelIndex &, int, int, const QModelIndex &, int)), SLOT(ourAccountsRowsMoved())); m_webThree.reset(new WebThreeDirect(string("AlethZero/v") + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM), getDataDir() + "/AlethZero", false, {"eth", "shh"})); + m_ldb = new QLDB(this); connect(ui->webView, &QWebView::loadStarted, [this]() { @@ -138,8 +139,8 @@ Main::Main(QWidget *parent) : m_whisper = nullptr; // NOTE: no need to delete as QETH_INSTALL_JS_NAMESPACE adopts it. m_dev = new QDev(this); - m_ethereum = new QEthereum(this, ethereum(), owned()); - m_whisper = new QWhisper(this, whisper()); + m_ethereum = new QEthereum(this, ethereum(), m_myKeys); + m_whisper = new QWhisper(this, whisper(), owned()); QWebSettings::globalSettings()->setAttribute(QWebSettings::DeveloperExtrasEnabled, true); QWebFrame* f = ui->webView->page()->mainFrame(); @@ -147,8 +148,9 @@ Main::Main(QWidget *parent) : auto qdev = m_dev; auto qeth = m_ethereum; auto qshh = m_whisper; - connect(f, &QWebFrame::javaScriptWindowObjectCleared, QETH_INSTALL_JS_NAMESPACE(f, this, qdev, qeth, qshh)); - connect(m_whisper, SIGNAL(idsChanged()), this, SLOT(refreshWhisper())); + auto qldb = m_ldb; + connect(f, &QWebFrame::javaScriptWindowObjectCleared, QETH_INSTALL_JS_NAMESPACE(f, this, qdev, qeth, qshh, qldb)); + connect(m_whisper, SIGNAL(newIdToAdd(QString)), this, SLOT(addNewId(QString))); }); connect(ui->webView, &QWebView::loadFinished, [=]() @@ -183,11 +185,20 @@ Main::~Main() // Must do this here since otherwise m_ethereum'll be deleted (and therefore clearWatches() called by the destructor) // *after* the client is dead. m_ethereum->clientDieing(); + m_whisper->faceDieing(); g_logPost = simpleDebugOut; writeSettings(); } +void Main::addNewId(QString _ids) +{ + Secret _id = toSecret(_ids); + KeyPair kp(_id); + m_myIdentities.push_back(kp); + m_whisper->setIdentities(owned()); +} + dev::p2p::NetworkPreferences Main::netPrefs() const { return NetworkPreferences(ui->port->value(), ui->forceAddress->text().toStdString(), ui->upnp->isChecked(), ui->localNetworking->isChecked()); @@ -494,15 +505,28 @@ void Main::on_paranoia_triggered() void Main::writeSettings() { QSettings s("ethereum", "alethzero"); - QByteArray b; - b.resize(sizeof(Secret) * m_myKeys.size()); - auto p = b.data(); - for (auto i: m_myKeys) { - memcpy(p, &(i.secret()), sizeof(Secret)); - p += sizeof(Secret); + QByteArray b; + b.resize(sizeof(Secret) * m_myKeys.size()); + auto p = b.data(); + for (auto i: m_myKeys) + { + memcpy(p, &(i.secret()), sizeof(Secret)); + p += sizeof(Secret); + } + s.setValue("address", b); + } + { + QByteArray b; + b.resize(sizeof(Secret) * m_myIdentities.size()); + auto p = b.data(); + for (auto i: m_myIdentities) + { + memcpy(p, &(i.secret()), sizeof(Secret)); + p += sizeof(Secret); + } + s.setValue("identities", b); } - s.setValue("address", b); s.setValue("upnp", ui->upnp->isChecked()); s.setValue("forceAddress", ui->forceAddress->text()); @@ -538,21 +562,39 @@ void Main::readSettings(bool _skipGeometry) restoreGeometry(s.value("geometry").toByteArray()); restoreState(s.value("windowState").toByteArray()); - m_myKeys.clear(); - QByteArray b = s.value("address").toByteArray(); - if (b.isEmpty()) - m_myKeys.append(KeyPair::create()); - else { - h256 k; - for (unsigned i = 0; i < b.size() / sizeof(Secret); ++i) + m_myKeys.clear(); + QByteArray b = s.value("address").toByteArray(); + if (b.isEmpty()) + m_myKeys.append(KeyPair::create()); + else { - memcpy(&k, b.data() + i * sizeof(Secret), sizeof(Secret)); - if (!count(m_myKeys.begin(), m_myKeys.end(), KeyPair(k))) - m_myKeys.append(KeyPair(k)); + h256 k; + for (unsigned i = 0; i < b.size() / sizeof(Secret); ++i) + { + memcpy(&k, b.data() + i * sizeof(Secret), sizeof(Secret)); + if (!count(m_myKeys.begin(), m_myKeys.end(), KeyPair(k))) + m_myKeys.append(KeyPair(k)); + } } + ethereum()->setAddress(m_myKeys.back().address()); } - ethereum()->setAddress(m_myKeys.back().address()); + + { + m_myIdentities.clear(); + QByteArray b = s.value("identities").toByteArray(); + if (!b.isEmpty()) + { + h256 k; + for (unsigned i = 0; i < b.size() / sizeof(Secret); ++i) + { + memcpy(&k, b.data() + i * sizeof(Secret), sizeof(Secret)); + if (!count(m_myIdentities.begin(), m_myIdentities.end(), KeyPair(k))) + m_myIdentities.append(KeyPair(k)); + } + } + } + m_peers = s.value("peers").toByteArray(); ui->upnp->setChecked(s.value("upnp", true).toBool()); ui->forceAddress->setText(s.value("forceAddress", "").toString()); diff --git a/alethzero/MainWin.h b/alethzero/MainWin.h index b6c4c85e1..8905e53dc 100644 --- a/alethzero/MainWin.h +++ b/alethzero/MainWin.h @@ -77,7 +77,7 @@ public: dev::eth::Client* ethereum() const { return m_webThree->ethereum(); } std::shared_ptr whisper() const { return m_webThree->whisper(); } - QList const& owned() const { return m_myKeys; } + QList owned() const { return m_myIdentities + m_myKeys; } public slots: void load(QString _file); @@ -153,9 +153,11 @@ private slots: void on_newIdentity_triggered(); void refreshWhisper(); + void addNewId(QString); signals: void poll(); + void idsChanged(); private: dev::p2p::NetworkPreferences netPrefs() const; @@ -179,6 +181,8 @@ private: void readSettings(bool _skipGeometry = false); void writeSettings(); + void keysChanged(); + bool isCreation() const; dev::u256 fee() const; dev::u256 total() const; @@ -189,8 +193,6 @@ private: unsigned installWatch(dev::h256 _tf, std::function const& _f); void uninstallWatch(unsigned _w); - void keysChanged(); - void onNewPending(); void onNewBlock(); void onNameRegChange(); @@ -228,6 +230,7 @@ private: QByteArray m_peers; QStringList m_servers; QList m_myKeys; + QList m_myIdentities; QString m_privateChain; dev::bytes m_data; dev::Address m_nameReg; @@ -255,4 +258,5 @@ private: QDev* m_dev = nullptr; QEthereum* m_ethereum = nullptr; QWhisper* m_whisper = nullptr; + QLDB* m_ldb = nullptr; }; diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index b2d56c7d1..2af4d2808 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -369,7 +369,7 @@ void Host::populateAddresses() shared_ptr Host::noteNode(NodeId _id, bi::tcp::endpoint _a, Origin _o, bool _ready, NodeId _oldId) { RecursiveGuard l(x_peers); - if (_a.port() < 30300 && _a.port() > 30303) + if (_a.port() < 30300 || _a.port() > 30303) cwarn << "Wierd port being recorded!"; if (_a.port() >= /*49152*/32768) diff --git a/libqethereum/QEthereum.cpp b/libqethereum/QEthereum.cpp index 535c43325..a13559ec5 100644 --- a/libqethereum/QEthereum.cpp +++ b/libqethereum/QEthereum.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 QEthereum.cpp + * @author Gav Wood + * @date 2014 + */ + +#include #include #include #include @@ -536,8 +558,9 @@ void QEthereum::poll() // TODO: repot and hook all these up. -QWhisper::QWhisper(QObject* _p, std::shared_ptr const& _c): QObject(_p), m_face(_c) +QWhisper::QWhisper(QObject* _p, std::shared_ptr const& _c, QList _ids): QObject(_p), m_face(_c) { + setIdentities(_ids); } QWhisper::~QWhisper() @@ -613,6 +636,14 @@ void QWhisper::doPost(QString _json) face()->inject(toSealed(_json, m, from)); } +void QWhisper::setIdentities(QList const& _l) +{ + m_ids.clear(); + for (auto i: _l) + m_ids[i.pub()] = i.secret(); + emit idsChanged(); +} + static pair toWatch(QString _json) { shh::BuildTopicMask bt(shh::BuildTopicMask::Empty); @@ -714,11 +745,18 @@ QString QWhisper::newIdentity() Public QWhisper::makeIdentity() { KeyPair kp = KeyPair::create(); - m_ids[kp.pub()] = kp.sec(); - emit idsChanged(); + emit newIdToAdd(toQJS(kp.sec())); return kp.pub(); } +QString QWhisper::createGroup(QString _json) +{ +} + +QString QWhisper::addToGroup(QString _group, QString _who) +{ +} + void QWhisper::poll() { for (auto const& w: m_watches) @@ -740,6 +778,51 @@ void QWhisper::poll() } } +#include + +QLDB::QLDB(QObject* _p): QObject(_p) +{ + auto path = getDataDir() + "/.web3"; + boost::filesystem::create_directories(path); + ldb::Options o; + o.create_if_missing = true; + ldb::DB::Open(o, path, &m_db); +} + +QLDB::~QLDB() +{ +} + +void QLDB::put(QString _p, QString _k, QString _v) +{ + bytes k = sha3(_p.toStdString()).asBytes() + sha3(_k.toStdString()).asBytes(); + bytes v = toBytes(_v); + m_db->Put(m_writeOptions, ldb::Slice((char const*)k.data(), k.size()), ldb::Slice((char const*)v.data(), v.size())); +} + +QString QLDB::get(QString _p, QString _k) +{ + bytes k = sha3(_p.toStdString()).asBytes() + sha3(_k.toStdString()).asBytes(); + string ret; + m_db->Get(m_readOptions, ldb::Slice((char const*)k.data(), k.size()), &ret); + return toQJS(dev::asBytes(ret)); +} + +void QLDB::putString(QString _p, QString _k, QString _v) +{ + bytes k = sha3(_p.toStdString()).asBytes() + sha3(_k.toStdString()).asBytes(); + string v = _v.toStdString(); + m_db->Put(m_writeOptions, ldb::Slice((char const*)k.data(), k.size()), ldb::Slice((char const*)v.data(), v.size())); +} + +QString QLDB::getString(QString _p, QString _k) +{ + bytes k = sha3(_p.toStdString()).asBytes() + sha3(_k.toStdString()).asBytes(); + string ret; + m_db->Get(m_readOptions, ldb::Slice((char const*)k.data(), k.size()), &ret); + return QString::fromStdString(ret); +} + // extra bits needed to link on VS #ifdef _MSC_VER diff --git a/libqethereum/QEthereum.h b/libqethereum/QEthereum.h index 9866a4e7a..042b3c081 100644 --- a/libqethereum/QEthereum.h +++ b/libqethereum/QEthereum.h @@ -1,11 +1,39 @@ +/* + 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 QEthereum.h + * @author Gav Wood + * @date 2014 + */ + #pragma once +#pragma warning(push) +#pragma warning(disable: 4100 4267) +#include +#pragma warning(pop) + #include #include #include #include #include +namespace ldb = leveldb; + namespace dev { namespace eth { class Interface; @@ -214,12 +242,14 @@ class QWhisper: public QObject Q_OBJECT public: - QWhisper(QObject* _p, std::shared_ptr const& _c); + QWhisper(QObject* _p, std::shared_ptr const& _c, QList _ids); virtual ~QWhisper(); std::shared_ptr face() const; void setFace(std::shared_ptr const& _c) { m_face = _c; } + void setIdentities(QList const& _l); + /// Call when the face() is going to be deleted to make this object useless but safe. void faceDieing(); @@ -230,6 +260,9 @@ public: Q_INVOKABLE QString newIdentity(); + Q_INVOKABLE QString newGroup(QString _id, QString _who); + Q_INVOKABLE QString addToGroup(QString _group, QString _who); + // Watches interface Q_INVOKABLE unsigned newWatch(QString _json); Q_INVOKABLE void killWatch(unsigned _w); @@ -247,6 +280,7 @@ public slots: signals: void watchChanged(unsigned _w, QString _envelopeJson); void idsChanged(); + void newIdToAdd(QString _id); private: std::weak_ptr m_face; @@ -255,16 +289,41 @@ private: std::map m_ids; }; +class QLDB: public QObject +{ + Q_OBJECT + +public: + QLDB(QObject* _p); + ~QLDB(); + + Q_INVOKABLE void put(QString _name, QString _key, QString _value); + Q_INVOKABLE QString get(QString _name, QString _key); + Q_INVOKABLE void putString(QString _name, QString _key, QString _value); + Q_INVOKABLE QString getString(QString _name, QString _key); + +private: + ldb::ReadOptions m_readOptions; + ldb::WriteOptions m_writeOptions; + + ldb::DB* m_db; +}; + // TODO: add p2p object -#define QETH_INSTALL_JS_NAMESPACE(_frame, _env, _web3, _eth, _shh) [_frame, _env, _web3, _eth, _shh]() \ +#define QETH_INSTALL_JS_NAMESPACE(_frame, _env, _web3, _eth, _shh, _ldb) [_frame, _env, _web3, _eth, _shh, _ldb]() \ { \ _frame->disconnect(); \ _frame->addToJavaScriptWindowObject("env", _env, QWebFrame::QtOwnership); \ _frame->addToJavaScriptWindowObject("web3", _web3, QWebFrame::ScriptOwnership); \ + if (_ldb) \ + { \ + _frame->addToJavaScriptWindowObject("_web3_dot_db", _ldb, QWebFrame::QtOwnership); \ + _frame->evaluateJavaScript("web3.db = _web3_dot_db"); \ + } \ if (_eth) \ { \ _frame->addToJavaScriptWindowObject("_web3_dot_eth", _eth, QWebFrame::ScriptOwnership); \ - _frame->evaluateJavaScript("_web3_dot_eth.makeWatch = function(a) { var ww = _web3_dot_eth.newWatch(a); var ret = { w: ww }; ret.uninstall = function() { _web3_dot_eth.killWatch(w); }; ret.changed = function(f) { _web3_dot_eth.watchChanged.connect(function(nw) { if (nw == ww) f() }); }; ret.messages = function() { return JSON.parse(_web3_dot_eth.watchMessages(this.w)) }; return ret; }"); \ + _frame->evaluateJavaScript("_web3_dot_eth.makeWatch = function(a) { var ww = _web3_dot_eth.newWatch(a); var ret = { w: ww }; ret.uninstall = function() { _web3_dot_eth.killWatch(this.w); }; ret.changed = function(f) { _web3_dot_eth.watchChanged.connect(function(nw) { if (nw == ww) f() }); }; ret.messages = function() { return JSON.parse(_web3_dot_eth.watchMessages(this.w)) }; return ret; }"); \ _frame->evaluateJavaScript("_web3_dot_eth.watch = function(a) { return _web3_dot_eth.makeWatch(JSON.stringify(a)) }"); \ _frame->evaluateJavaScript("_web3_dot_eth.transact = function(a, f) { var r = _web3_dot_eth.doTransact(JSON.stringify(a)); if (f) f(r); }"); \ _frame->evaluateJavaScript("_web3_dot_eth.call = function(a, f) { var ret = _web3_dot_eth.doCallJson(JSON.stringify(a)); if (f) f(ret); return ret; }"); \ @@ -277,7 +336,7 @@ private: if (_shh) \ { \ _frame->addToJavaScriptWindowObject("_web3_dot_shh", _shh, QWebFrame::ScriptOwnership); \ - _frame->evaluateJavaScript("_web3_dot_shh.makeWatch = function(json) { var ww = _web3_dot_shh.newWatch(json); var ret = { w: ww }; ret.uninstall = function() { _web3_dot_shh.killWatch(w); }; ret.arrived = function(f) { _web3_dot_shh.watchChanged.connect(function(nw, envelope) { if (nw == ww) f(JSON.parse(envelope)) }); var existing = JSON.parse(_web3_dot_shh.watchMessages(ww)); for (var e in existing) f(existing[e]) }; return ret; }"); \ + _frame->evaluateJavaScript("_web3_dot_shh.makeWatch = function(json) { var ww = _web3_dot_shh.newWatch(json); var ret = { w: ww }; ret.uninstall = function() { _web3_dot_shh.killWatch(this.w); }; ret.arrived = function(f) { _web3_dot_shh.watchChanged.connect(function(nw, envelope) { if (nw == ww) f(JSON.parse(envelope)) }); var existing = JSON.parse(_web3_dot_shh.watchMessages(this.w)); for (var e in existing) f(existing[e]) }; return ret; }"); \ _frame->evaluateJavaScript("_web3_dot_shh.watch = function(filter) { return _web3_dot_shh.makeWatch(JSON.stringify(filter)) }"); \ _frame->evaluateJavaScript("_web3_dot_shh.post = function(message) { return _web3_dot_shh.doPost(JSON.stringify(message)) }"); \ _frame->evaluateJavaScript("web3.shh = _web3_dot_shh"); \ diff --git a/third/MainWin.cpp b/third/MainWin.cpp index dd5b01733..1af1de7fc 100644 --- a/third/MainWin.cpp +++ b/third/MainWin.cpp @@ -102,19 +102,22 @@ Main::Main(QWidget *parent) : m_web3.reset(new WebThreeDirect("Third", getDataDir() + "/Third", false, {"eth", "shh"})); m_web3->connect(Host::pocHost()); + m_ldb = new QLDB(this); + connect(ui->webView, &QWebView::loadStarted, [this]() { // NOTE: no need to delete as QETH_INSTALL_JS_NAMESPACE adopts it. m_dev = new QDev(this); - m_ethereum = new QEthereum(this, ethereum(), owned()); - m_whisper = new QWhisper(this, whisper()); + m_ethereum = new QEthereum(this, ethereum(), m_myKeys); + m_whisper = new QWhisper(this, whisper(), owned()); QWebFrame* f = ui->webView->page()->mainFrame(); f->disconnect(SIGNAL(javaScriptWindowObjectCleared())); auto qdev = m_dev; auto qeth = m_ethereum; auto qshh = m_whisper; - connect(f, &QWebFrame::javaScriptWindowObjectCleared, QETH_INSTALL_JS_NAMESPACE(f, this, qdev, qeth, qshh)); + auto qldb = m_ldb; + connect(f, &QWebFrame::javaScriptWindowObjectCleared, QETH_INSTALL_JS_NAMESPACE(f, this, qdev, qeth, qshh, qldb)); }); connect(ui->webView, &QWebView::loadFinished, [=]() diff --git a/third/MainWin.h b/third/MainWin.h index 0122cc257..3fa848439 100644 --- a/third/MainWin.h +++ b/third/MainWin.h @@ -61,8 +61,8 @@ public: dev::eth::Client* ethereum() const; std::shared_ptr whisper() const; - QList const& owned() const { return m_myKeys; } - + QList owned() const { return m_myKeys + m_myIdentities; } + public slots: void note(QString _entry); void debug(QString _entry); @@ -121,6 +121,7 @@ private: std::unique_ptr m_web3; QList m_myKeys; + QList m_myIdentities; std::map> m_handlers; unsigned m_nameRegFilter = (unsigned)-1; @@ -135,4 +136,5 @@ private: QDev* m_dev = nullptr; QEthereum* m_ethereum = nullptr; QWhisper* m_whisper = nullptr; + QLDB* m_ldb = nullptr; }; From 721abb8f0fe23de40493f19b99e2224560661f02 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 27 Oct 2014 12:13:14 +0100 Subject: [PATCH 20/41] PoC-7 Exception severity uniform. --- libethereum/Executive.cpp | 7 +++++-- libethereum/State.cpp | 20 ++++++++++++++------ libevm/VM.h | 2 +- 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/libethereum/Executive.cpp b/libethereum/Executive.cpp index 193010cfa..d1ed3da11 100644 --- a/libethereum/Executive.cpp +++ b/libethereum/Executive.cpp @@ -187,14 +187,17 @@ bool Executive::go(OnOpFunc const& _onOp) { clog(StateChat) << "VM Exception: " << diagnostic_information(_e); m_endGas = m_vm->gas(); + revert = true; } catch (Exception const& _e) { - clog(StateChat) << "Exception in VM: " << diagnostic_information(_e); + // TODO: AUDIT: check that this can never reasonably happen. Consider what to do if it does. + cwarn << "Unexpected exception in VM. There may be a bug in this implementation. " << diagnostic_information(_e); } catch (std::exception const& _e) { - clog(StateChat) << "std::exception in VM: " << _e.what(); + // TODO: AUDIT: check that this can never reasonably happen. Consider what to do if it does. + cwarn << "Unexpected std::exception in VM. This is probably unrecoverable. " << _e.what(); } cnote << "VM took:" << t.elapsed() << "; gas used: " << (sgas - m_endGas); diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 931ee2cf6..0f0d5dc90 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -1168,6 +1168,7 @@ bool State::call(Address _receiveAddress, Address _codeAddress, Address _senderA catch (VMException const& _e) { clog(StateChat) << "VM Exception: " << diagnostic_information(_e); + revert = true; } catch (Exception const& _e) { @@ -1230,25 +1231,32 @@ h160 State::create(Address _sender, u256 _endowment, u256 _gasPrice, u256* _gas, catch (VMException const& _e) { clog(StateChat) << "VM Exception: " << diagnostic_information(_e); + revert = true; } catch (Exception const& _e) { - clog(StateChat) << "Exception in VM: " << diagnostic_information(_e); + // TODO: AUDIT: check that this can never reasonably happen. Consider what to do if it does. + cwarn << "Unexpected exception in VM. There may be a bug in this implementation. " << diagnostic_information(_e); } catch (std::exception const& _e) { - clog(StateChat) << "std::exception in VM: " << _e.what(); + // TODO: AUDIT: check that this can never reasonably happen. Consider what to do if it does. + cwarn << "Unexpected std::exception in VM. This is probably unrecoverable. " << _e.what(); } // TODO: CHECK: IS THIS CORRECT?! (esp. given account created prior to revertion init.) // Write state out only in the case of a non-out-of-gas transaction. if (revert) + { evm.revert(); - - // Set code. - if (addressInUse(newAddress)) - m_cache[newAddress].setCode(out); + m_cache.erase(newAddress); + newAddress = Address(); + } + else + // Set code. + if (addressInUse(newAddress)) + m_cache[newAddress].setCode(out); *_gas = vm.gas(); diff --git a/libevm/VM.h b/libevm/VM.h index ce8001bbf..3ea9d1b87 100644 --- a/libevm/VM.h +++ b/libevm/VM.h @@ -41,7 +41,7 @@ struct BreakPointHit: virtual VMException {}; struct BadInstruction: virtual VMException {}; struct BadJumpDestination: virtual VMException {}; struct OutOfGas: virtual VMException {}; -class StackTooSmall: virtual public VMException { public: StackTooSmall(u256 _req, u256 _got): req(_req), got(_got) {} u256 req; u256 got; }; +struct StackTooSmall: virtual public VMException { StackTooSmall(u256 _req, u256 _got): req(_req), got(_got) {} u256 req; u256 got; }; // Convert from a 256-bit integer stack/memory entry into a 160-bit Address hash. // Currently we just pull out the right (low-order in BE) 160-bits. From d0072072526f8fc908cf388aaa8db51451b81eb4 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 27 Oct 2014 12:15:07 +0100 Subject: [PATCH 21/41] Fix QEthereum. --- libqethereum/QEthereum.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/libqethereum/QEthereum.cpp b/libqethereum/QEthereum.cpp index a13559ec5..89d5f1ea5 100644 --- a/libqethereum/QEthereum.cpp +++ b/libqethereum/QEthereum.cpp @@ -749,12 +749,18 @@ Public QWhisper::makeIdentity() return kp.pub(); } -QString QWhisper::createGroup(QString _json) +QString QWhisper::newGroup(QString _me, QString _others) { + (void)_me; + (void)_others; + return ""; } QString QWhisper::addToGroup(QString _group, QString _who) { + (void)_group; + (void)_who; + return ""; } void QWhisper::poll() From eb73eb2974e88ecadbe4da7b382f3648b5c980e5 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 27 Oct 2014 12:17:06 +0100 Subject: [PATCH 22/41] Build fix. --- libqethereum/QEthereum.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/libqethereum/QEthereum.cpp b/libqethereum/QEthereum.cpp index a13559ec5..89d5f1ea5 100644 --- a/libqethereum/QEthereum.cpp +++ b/libqethereum/QEthereum.cpp @@ -749,12 +749,18 @@ Public QWhisper::makeIdentity() return kp.pub(); } -QString QWhisper::createGroup(QString _json) +QString QWhisper::newGroup(QString _me, QString _others) { + (void)_me; + (void)_others; + return ""; } QString QWhisper::addToGroup(QString _group, QString _who) { + (void)_group; + (void)_who; + return ""; } void QWhisper::poll() From 15013a3e8866052206a394fd04e396e757761a69 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 27 Oct 2014 14:13:16 +0100 Subject: [PATCH 23/41] PoC-7: Reversion of 0-hashes, empty-list hashes and sha3('') -> '' --- alethzero/MainWin.cpp | 1 + libdevcrypto/SHA3.cpp | 4 +++- libdevcrypto/SHA3.h | 1 + libdevcrypto/TrieDB.h | 6 +++--- libethcore/BlockInfo.cpp | 10 +++------- libethcore/CommonEth.cpp | 2 +- libethereum/BlockChain.cpp | 4 ++-- libethereum/Client.cpp | 3 +++ libethereum/State.cpp | 4 ++-- libethereum/State.h | 10 ++-------- libethereum/Transaction.cpp | 3 ++- libethereum/Transaction.h | 9 ++++++++- libevm/VM.h | 23 ++++++++++++++++++++--- libevmface/Instruction.cpp | 6 ++++-- libevmface/Instruction.h | 3 ++- test/MemTrie.cpp | 4 ++-- test/TrieHash.cpp | 6 +++--- test/crypto.cpp | 3 +++ test/state.cpp | 1 + test/vm.cpp | 7 ++++--- 20 files changed, 70 insertions(+), 40 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 674509b53..227f739ce 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -1784,6 +1784,7 @@ void Main::on_debug_clicked() t.gasPrice = gasPrice(); t.gas = ui->gas->value(); t.data = m_data; + t.type = isCreation() ? Transaction::ContractCreation : Transaction::MessageCall; t.receiveAddress = isCreation() ? Address() : fromString(ui->destination->currentText()); t.sign(s); auto r = t.rlp(); diff --git a/libdevcrypto/SHA3.cpp b/libdevcrypto/SHA3.cpp index b3a6e5955..eaabae0ff 100644 --- a/libdevcrypto/SHA3.cpp +++ b/libdevcrypto/SHA3.cpp @@ -20,8 +20,9 @@ */ #include "SHA3.h" -#include "CryptoPP.h" +#include +#include "CryptoPP.h" using namespace std; using namespace dev; @@ -29,6 +30,7 @@ namespace dev { h256 EmptySHA3 = sha3(bytesConstRef()); +h256 ZeroRLPSHA3 = sha3(rlp(bytesConstRef())); std::string sha3(std::string const& _input, bool _hex) { diff --git a/libdevcrypto/SHA3.h b/libdevcrypto/SHA3.h index fc2cfcfc3..5948cb3bd 100644 --- a/libdevcrypto/SHA3.h +++ b/libdevcrypto/SHA3.h @@ -57,6 +57,7 @@ inline h256 sha3(bytes const& _input) { return sha3(bytesConstRef((bytes*)&_inpu inline h256 sha3(std::string const& _input) { return sha3(bytesConstRef(_input)); } extern h256 EmptySHA3; +extern h256 ZeroRLPSHA3; // Other crypto convenience routines diff --git a/libdevcrypto/TrieDB.h b/libdevcrypto/TrieDB.h index 1fca92294..0ca0b9d98 100644 --- a/libdevcrypto/TrieDB.h +++ b/libdevcrypto/TrieDB.h @@ -74,7 +74,7 @@ public: void init(); void setRoot(h256 _root) { - m_root = _root == h256() ? c_shaNull : _root; + m_root = _root; if (m_root == c_shaNull && !m_db->exists(m_root)) init(); @@ -82,14 +82,14 @@ public: if (!node(m_root).size()) BOOST_THROW_EXCEPTION(RootNotFound()); } - bool haveRoot(h256 _root, bool _enforceRefs = true) { return _root == h256() ? true : m_db->lookup(_root, _enforceRefs).size(); } + bool haveRoot(h256 _root, bool _enforceRefs = true) { return _root == c_shaNull ? true : m_db->lookup(_root, _enforceRefs).size(); } /// True if the trie is uninitialised (i.e. that the DB doesn't contain the root node). bool isNull() const { return !node(m_root).size(); } /// True if the trie is initialised but empty (i.e. that the DB contains the root node which is empty). bool isEmpty() const { return m_root == c_shaNull && node(m_root).size(); } - h256 root() const { assert(node(m_root).size()); h256 ret = (m_root == c_shaNull ? h256() : m_root); /*std::cout << "Returning root as " << ret << " (really " << m_root << ")" << std::endl;*/ return ret; } // patch the root in the case of the empty trie. TODO: handle this properly. + h256 root() const { assert(node(m_root).size()); /*std::cout << "Returning root as " << ret << " (really " << m_root << ")" << std::endl;*/ return m_root; } // patch the root in the case of the empty trie. TODO: handle this properly. void debugPrint() {} diff --git a/libethcore/BlockInfo.cpp b/libethcore/BlockInfo.cpp index 4c9e2bef7..6e4af247f 100644 --- a/libethcore/BlockInfo.cpp +++ b/libethcore/BlockInfo.cpp @@ -60,11 +60,9 @@ auto static const c_sha3EmptyList = sha3(RLPEmptyList); void BlockInfo::fillStream(RLPStream& _s, bool _nonce) const { - _s.appendList(_nonce ? 13 : 12) << parentHash; - _s.append(sha3Uncles == c_sha3EmptyList ? h256() : sha3Uncles, false, true); - _s << coinbaseAddress; - _s.append(stateRoot, false, true).append(transactionsRoot, false, true); - _s << difficulty << number << minGasPrice << gasLimit << gasUsed << timestamp << extraData; + _s.appendList(_nonce ? 13 : 12) + << parentHash << sha3Uncles << coinbaseAddress << stateRoot << transactionsRoot + << difficulty << number << minGasPrice << gasLimit << gasUsed << timestamp << extraData; if (_nonce) _s << nonce; } @@ -83,8 +81,6 @@ void BlockInfo::populateFromHeader(RLP const& _header, bool _checkNonce) { parentHash = _header[field = 0].toHash(); sha3Uncles = _header[field = 1].toHash(); - if (sha3Uncles == h256()) - sha3Uncles = c_sha3EmptyList; coinbaseAddress = _header[field = 2].toHash
(); stateRoot = _header[field = 3].toHash(); transactionsRoot = _header[field = 4].toHash(); diff --git a/libethcore/CommonEth.cpp b/libethcore/CommonEth.cpp index 5f989689c..44ebe19c5 100644 --- a/libethcore/CommonEth.cpp +++ b/libethcore/CommonEth.cpp @@ -34,7 +34,7 @@ namespace dev namespace eth { -const unsigned c_protocolVersion = 36; +const unsigned c_protocolVersion = 37; const unsigned c_databaseVersion = 3; static const vector> g_units = diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 7b7b8a9e5..b08179f9e 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -101,8 +101,8 @@ bytes BlockChain::createGenesisBlock() stateRoot = state.root(); } - block.appendList(13) << h256() << bytes() << h160(); - block.append(stateRoot, false, true) << bytes() << c_genesisDifficulty << 0 << 0 << 1000000 << 0 << (unsigned)0 << string() << sha3(bytes(1, 42)); + block.appendList(13) + << h256() << c_shaNull << h160() << stateRoot << c_shaNull << c_genesisDifficulty << 0 << 0 << 1000000 << 0 << (unsigned)0 << string() << sha3(bytes(1, 42)); block.appendRaw(RLPEmptyList); block.appendRaw(RLPEmptyList); return block.out(); diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index ecce7406d..dc36957ee 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -325,6 +325,7 @@ void Client::transact(Secret _secret, u256 _value, Address _dest, bytes const& _ t.value = _value; t.gasPrice = _gasPrice; t.gas = _gas; + t.type = Transaction::MessageCall; t.receiveAddress = _dest; t.data = _data; t.sign(_secret); @@ -348,6 +349,7 @@ bytes Client::call(Secret _secret, u256 _value, Address _dest, bytes const& _dat t.value = _value; t.gasPrice = _gasPrice; t.gas = _gas; + t.type = Transaction::ContractCreation; t.receiveAddress = _dest; t.data = _data; t.sign(_secret); @@ -373,6 +375,7 @@ Address Client::transact(Secret _secret, u256 _endowment, bytes const& _init, u2 t.value = _endowment; t.gasPrice = _gasPrice; t.gas = _gas; + t.type = Transaction::ContractCreation; t.receiveAddress = Address(); t.data = _init; t.sign(_secret); diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 931ee2cf6..9ec835833 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -353,9 +353,9 @@ void State::ensureCached(std::map& _cache, Address _a, bo RLP state(stateBack); AddressState s; if (state.isNull()) - s = AddressState(0, 0, h256(), EmptySHA3); + s = AddressState(0, 0, ZeroRLPSHA3, EmptySHA3); else - s = AddressState(state[0].toInt(), state[1].toInt(), state[2].toHash(), state[3].isEmpty() ? EmptySHA3 : state[3].toHash()); + s = AddressState(state[0].toInt(), state[1].toInt(), state[2].toHash(), state[3].toHash()); bool ok; tie(it, ok) = _cache.insert(make_pair(_a, s)); } diff --git a/libethereum/State.h b/libethereum/State.h index dd6043c73..6e65bfd53 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -367,16 +367,10 @@ void commit(std::map const& _cache, DB& _db, TrieDB(); gasPrice = rlp[field = 1].toInt(); gas = rlp[field = 2].toInt(); + type = rlp[field = 3].isEmpty() ? ContractCreation : MessageCall; receiveAddress = rlp[field = 3].toHash
(); value = rlp[field = 4].toInt(); data = rlp[field = 5].toBytes(); @@ -88,7 +89,7 @@ void Transaction::fillStream(RLPStream& _s, bool _sig) const { _s.appendList((_sig ? 3 : 0) + 6); _s << nonce << gasPrice << gas; - if (receiveAddress) + if (type == MessageCall) _s << receiveAddress; else _s << ""; diff --git a/libethereum/Transaction.h b/libethereum/Transaction.h index eb40c5fcb..ca73ba06a 100644 --- a/libethereum/Transaction.h +++ b/libethereum/Transaction.h @@ -32,13 +32,20 @@ namespace eth struct Transaction { + enum Type + { + ContractCreation, + MessageCall + }; + Transaction() {} Transaction(bytesConstRef _rlp, bool _checkSender = false); Transaction(bytes const& _rlp, bool _checkSender = false): Transaction(&_rlp, _checkSender) {} - bool operator==(Transaction const& _c) const { return receiveAddress == _c.receiveAddress && value == _c.value && data == _c.data; } + bool operator==(Transaction const& _c) const { return type == _c.type && (type == ContractCreation || receiveAddress == _c.receiveAddress) && value == _c.value && data == _c.data; } bool operator!=(Transaction const& _c) const { return !operator==(_c); } + Type type; ///< True if this is a contract-creation transaction. F u256 nonce; ///< The transaction-count of the sender. u256 value; ///< The amount of ETH to be transferred by this transaction. Called 'endowment' for contract-creation transactions. Address receiveAddress; ///< The receiving address of the transaction. diff --git a/libevm/VM.h b/libevm/VM.h index ce8001bbf..226b1d6cf 100644 --- a/libevm/VM.h +++ b/libevm/VM.h @@ -236,7 +236,7 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con case Instruction::PUSH31: case Instruction::PUSH32: break; - case Instruction::NEG: + case Instruction::BNOT: case Instruction::NOT: case Instruction::CALLDATALOAD: case Instruction::EXTCODESIZE: @@ -262,6 +262,7 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con case Instruction::XOR: case Instruction::BYTE: case Instruction::JUMPI: + case Instruction::SIGNEXTEND: require(2); break; case Instruction::ADDMOD: @@ -368,8 +369,8 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con m_stack.back() = (u256)boost::multiprecision::powm((bigint)base, (bigint)expon, bigint(2) << 256); break; } - case Instruction::NEG: - m_stack.back() = ~(m_stack.back() - 1); + case Instruction::BNOT: + m_stack.back() = ~m_stack.back(); break; case Instruction::LT: m_stack[m_stack.size() - 2] = m_stack.back() < m_stack[m_stack.size() - 2] ? 1 : 0; @@ -420,6 +421,22 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con m_stack.pop_back(); m_stack.pop_back(); break; + case Instruction::SIGNEXTEND: + { + unsigned k = m_stack[m_stack.size() - 2]; + if (k > 31) + m_stack[m_stack.size() - 2] = m_stack.back(); + else + { + u256 b = m_stack.back(); + if ((b >> (k * 8)) & 0x80) + for (int i = 31; i > k; --i) + b |= (u256(0xff) << i); + m_stack[m_stack.size() - 2] = b; + } + m_stack.pop_back(); + break; + } case Instruction::SHA3: { unsigned inOff = (unsigned)m_stack.back(); diff --git a/libevmface/Instruction.cpp b/libevmface/Instruction.cpp index 7b253f388..c9b6ea2ce 100644 --- a/libevmface/Instruction.cpp +++ b/libevmface/Instruction.cpp @@ -39,7 +39,7 @@ const std::map dev::eth::c_instructions = { "MOD", Instruction::MOD }, { "SMOD", Instruction::SMOD }, { "EXP", Instruction::EXP }, - { "NEG", Instruction::NEG }, + { "BNOT", Instruction::BNOT }, { "LT", Instruction::LT }, { "GT", Instruction::GT }, { "SLT", Instruction::SLT }, @@ -52,6 +52,7 @@ const std::map dev::eth::c_instructions = { "BYTE", Instruction::BYTE }, { "ADDMOD", Instruction::ADDMOD }, { "MULMOD", Instruction::MULMOD }, + { "SIGNEXTEND", Instruction::SIGNEXTEND }, { "SHA3", Instruction::SHA3 }, { "ADDRESS", Instruction::ADDRESS }, { "BALANCE", Instruction::BALANCE }, @@ -166,7 +167,7 @@ static const std::map c_instructionInfo = { Instruction::MOD, { "MOD", 0, 2, 1 } }, { Instruction::SMOD, { "SMOD", 0, 2, 1 } }, { Instruction::EXP, { "EXP", 0, 2, 1 } }, - { Instruction::NEG, { "NEG", 0, 1, 1 } }, + { Instruction::BNOT, { "BNOT", 0, 1, 1 } }, { Instruction::LT, { "LT", 0, 2, 1 } }, { Instruction::GT, { "GT", 0, 2, 1 } }, { Instruction::SLT, { "SLT", 0, 2, 1 } }, @@ -179,6 +180,7 @@ static const std::map c_instructionInfo = { Instruction::BYTE, { "BYTE", 0, 2, 1 } }, { Instruction::ADDMOD, { "ADDMOD", 0, 3, 1 } }, { Instruction::MULMOD, { "MULMOD", 0, 3, 1 } }, + { Instruction::SIGNEXTEND, { "SIGNEXTEND", 0, 2, 1 } }, { Instruction::SHA3, { "SHA3", 0, 2, 1 } }, { Instruction::ADDRESS, { "ADDRESS", 0, 0, 1 } }, { Instruction::BALANCE, { "BALANCE", 0, 1, 1 } }, diff --git a/libevmface/Instruction.h b/libevmface/Instruction.h index b6aa477b1..faad50fb2 100644 --- a/libevmface/Instruction.h +++ b/libevmface/Instruction.h @@ -44,7 +44,7 @@ enum class Instruction: uint8_t MOD, ///< modulo remainder operation SMOD, ///< signed modulo remainder operation EXP, ///< exponential operation - NEG, ///< negation operation + BNOT, ///< bitwise not LT, ///< less-than comparision GT, ///< greater-than comparision SLT, ///< signed less-than comparision @@ -58,6 +58,7 @@ enum class Instruction: uint8_t BYTE, ///< retrieve single byte from word ADDMOD, ///< unsigned modular addition MULMOD, ///< unsigned modular multiplication + SIGNEXTEND, ///< extend length of signed integer SHA3 = 0x20, ///< compute SHA3-256 hash ADDRESS = 0x30, ///< get address of currently executing account diff --git a/test/MemTrie.cpp b/test/MemTrie.cpp index 4879f2674..c3a44e1e5 100644 --- a/test/MemTrie.cpp +++ b/test/MemTrie.cpp @@ -437,12 +437,12 @@ MemTrie::~MemTrie() h256 MemTrie::hash256() const { - return m_root ? m_root->hash256() : h256(); + return m_root ? m_root->hash256() : sha3(dev::rlp(bytesConstRef())); } bytes MemTrie::rlp() const { - return m_root ? m_root->rlp() : bytes(); + return m_root ? m_root->rlp() : dev::rlp(bytesConstRef()); } void MemTrie::debugPrint() diff --git a/test/TrieHash.cpp b/test/TrieHash.cpp index af32e870d..ee4f2e87d 100644 --- a/test/TrieHash.cpp +++ b/test/TrieHash.cpp @@ -162,7 +162,7 @@ h256 hash256(StringMap const& _s) { // build patricia tree. if (_s.empty()) - return h256(); + return sha3(rlp("")); HexMap hexMap; for (auto i = _s.rbegin(); i != _s.rend(); ++i) hexMap[asNibbles(i->first)] = i->second; @@ -175,7 +175,7 @@ bytes rlp256(StringMap const& _s) { // build patricia tree. if (_s.empty()) - return bytes(); + return rlp(""); HexMap hexMap; for (auto i = _s.rbegin(); i != _s.rend(); ++i) hexMap[asNibbles(i->first)] = i->second; @@ -188,7 +188,7 @@ h256 hash256(u256Map const& _s) { // build patricia tree. if (_s.empty()) - return h256(); + return sha3(rlp("")); HexMap hexMap; for (auto i = _s.rbegin(); i != _s.rend(); ++i) hexMap[asNibbles(toBigEndianString(i->first))] = asString(rlp(i->second)); diff --git a/test/crypto.cpp b/test/crypto.cpp index 0d3b6202f..67286bfca 100644 --- a/test/crypto.cpp +++ b/test/crypto.cpp @@ -341,6 +341,7 @@ BOOST_AUTO_TEST_CASE(eth_keypairs) { eth::Transaction t; t.nonce = 0; + t.type = eth::Transaction::MessageCall; t.receiveAddress = h160(fromHex("944400f4b88ac9589a0f17ed4671da26bddb668b")); t.value = 1000; auto rlp = t.rlp(false); @@ -369,6 +370,7 @@ int cryptoTest() { eth::Transaction t; t.nonce = 0; + t.type = eth::Transaction::MessageCall; t.receiveAddress = h160(fromHex("944400f4b88ac9589a0f17ed4671da26bddb668b")); t.value = 1000; auto rlp = t.rlp(false); @@ -397,6 +399,7 @@ int cryptoTest() Transaction t; t.nonce = 0; t.value = 1; // 1 wei. + t.type = eth::Transaction::MessageCall; t.receiveAddress = toAddress(sha3("123")); bytes sig64 = toBigEndian(t.vrs.r) + toBigEndian(t.vrs.s); diff --git a/test/state.cpp b/test/state.cpp index 99ce30957..b0f279bac 100644 --- a/test/state.cpp +++ b/test/state.cpp @@ -68,6 +68,7 @@ int stateTest() Transaction t; t.nonce = s.transactionsFrom(myMiner.address()); t.value = 1000; // 1e3 wei. + t.type = eth::Transaction::MessageCall; t.receiveAddress = me.address(); t.sign(myMiner.secret()); assert(t.sender() == myMiner.address()); diff --git a/test/vm.cpp b/test/vm.cpp index 2e4571be5..b49c5cd27 100644 --- a/test/vm.cpp +++ b/test/vm.cpp @@ -56,14 +56,13 @@ h160 FakeExtVM::create(u256 _endowment, u256* _gas, bytesConstRef _init, OnOpFun get<3>(addresses[ret]) = m_s.code(ret); } - t.receiveAddress = ret; + t.type = eth::Transaction::ContractCreation; callcreates.push_back(t); return ret; } bool FakeExtVM::call(Address _receiveAddress, u256 _value, bytesConstRef _data, u256* _gas, bytesRef _out, OnOpFunc const&, Address _myAddressOverride, Address _codeAddressOverride) { - u256 contractgas = 0xffff; Transaction t; @@ -71,6 +70,7 @@ bool FakeExtVM::call(Address _receiveAddress, u256 _value, bytesConstRef _data, t.gasPrice = gasPrice; t.gas = *_gas; t.data = _data.toVector(); + t.type = eth::Transaction::MessageCall; t.receiveAddress = _receiveAddress; callcreates.push_back(t); @@ -384,7 +384,7 @@ mArray FakeExtVM::exportCallCreates() for (Transaction const& tx: callcreates) { mObject o; - o["destination"] = toString(tx.receiveAddress); + o["destination"] = tx.type == Transaction::ContractCreation ? "" : toString(tx.receiveAddress); push(o, "gasLimit", tx.gas); push(o, "value", tx.value); o["data"] = "0x" + toHex(tx.data); @@ -403,6 +403,7 @@ void FakeExtVM::importCallCreates(mArray& _callcreates) BOOST_REQUIRE(tx.count("destination") > 0); BOOST_REQUIRE(tx.count("gasLimit") > 0); Transaction t; + t.type = tx["destination"].get_str().empty() ? Transaction::ContractCreation : Transaction::MessageCall; t.receiveAddress = Address(tx["destination"].get_str()); t.value = toInt(tx["value"]); t.gas = toInt(tx["gasLimit"]); From 52e385905e2a1730296b7b75c178e0a63d0da5cc Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 27 Oct 2014 16:32:53 +0100 Subject: [PATCH 24/41] Move suicides into SubState and include logs and refunds. Refund gas from zero-resetting SSTOREs. --- libdevcore/CommonData.h | 30 +++++++++++++++++++----------- libethereum/Executive.cpp | 4 +++- libethereum/Executive.h | 3 +++ libethereum/ExtVM.h | 4 ++-- libethereum/State.cpp | 16 +++++++--------- libethereum/State.h | 4 ++-- libevm/ExtVMFace.h | 28 ++++++++++++++++++++++------ libevm/FeeStructure.cpp | 4 +++- libevm/FeeStructure.h | 4 +++- libevm/VM.h | 7 +++++-- test/vm.cpp | 24 ++++++++++++++---------- test/vm.h | 2 +- 12 files changed, 84 insertions(+), 46 deletions(-) diff --git a/libdevcore/CommonData.h b/libdevcore/CommonData.h index 11850fa69..5f14f38f8 100644 --- a/libdevcore/CommonData.h +++ b/libdevcore/CommonData.h @@ -190,7 +190,7 @@ void pushFront(_T& _t, _U _e) _t[0] = _e; } -/// Concatenate two vectors of elements. _T must be POD. +/// Concatenate two vectors of elements of POD types. template inline std::vector<_T>& operator+=(std::vector::value, _T>::type>& _a, std::vector<_T> const& _b) { @@ -201,30 +201,38 @@ inline std::vector<_T>& operator+=(std::vector -inline std::vector<_T> operator+(std::vector::value, _T>::type> const& _a, std::vector<_T> const& _b) +inline std::vector<_T>& operator+=(std::vector::value, _T>::type>& _a, std::vector<_T> const& _b) +{ + _a.reserve(_a.size() + _b.size()); + for (auto& i: _b) + _a.push_back(i); + return _a; +} + +/// Concatenate two vectors of elements. +template +inline std::vector<_T> operator+(std::vector<_T> const& _a, std::vector<_T> const& _b) { std::vector<_T> ret(_a); return ret += _b; } -/// Concatenate two vectors of elements. _T must be POD. +/// Merge two sets of elements. template -inline std::vector<_T>& operator+=(std::vector::value, _T>::type>& _a, std::vector<_T> const& _b) +inline std::set<_T>& operator+=(std::set<_T>& _a, std::set<_T> const& _b) { - _a.reserve(_a.size() + _b.size()); for (auto& i: _b) - _a.push_back(i); + _a.insert(i); return _a; - } -/// Concatenate two vectors of elements. _T must be POD. +/// Merge two sets of elements. template -inline std::vector<_T> operator+(std::vector::value, _T>::type> const& _a, std::vector<_T> const& _b) +inline std::set<_T> operator+(std::set<_T> const& _a, std::set<_T> const& _b) { - std::vector<_T> ret(_a); + std::set<_T> ret(_a); return ret += _b; } diff --git a/libethereum/Executive.cpp b/libethereum/Executive.cpp index 193010cfa..840287ca9 100644 --- a/libethereum/Executive.cpp +++ b/libethereum/Executive.cpp @@ -172,6 +172,8 @@ bool Executive::go(OnOpFunc const& _onOp) try { m_out = m_vm->go(*m_ext, _onOp); + if (m_ext) + m_endGas += min((m_t.gas - m_endGas) / 2, m_ext->sub.refunds); m_endGas = m_vm->gas(); } catch (StepsDone const&) @@ -236,6 +238,6 @@ void Executive::finalize(OnOpFunc const&) // Suicides... if (m_ext) - for (auto a: m_ext->suicides) + for (auto a: m_ext->sub.suicides) m_s.m_cache[a].kill(); } diff --git a/libethereum/Executive.h b/libethereum/Executive.h index 82b7df7e9..cdfe23966 100644 --- a/libethereum/Executive.h +++ b/libethereum/Executive.h @@ -61,6 +61,7 @@ public: bytesConstRef out() const { return m_out; } h160 newAddress() const { return m_newAddress; } + LogEntries const& logs() const { return m_logs; } VM const& vm() const { return *m_vm; } State const& state() const { return m_s; } @@ -77,6 +78,8 @@ private: Transaction m_t; Address m_sender; u256 m_endGas; + + LogEntries m_logs; }; } diff --git a/libethereum/ExtVM.h b/libethereum/ExtVM.h index fc76d56b0..59b6eb2ab 100644 --- a/libethereum/ExtVM.h +++ b/libethereum/ExtVM.h @@ -61,7 +61,7 @@ public: m_s.noteSending(myAddress); if (m_ms) m_ms->internal.resize(m_ms->internal.size() + 1); - auto ret = m_s.create(myAddress, _endowment, gasPrice, _gas, _code, origin, &suicides, m_ms ? &(m_ms->internal.back()) : nullptr, _onOp, depth + 1); + auto ret = m_s.create(myAddress, _endowment, gasPrice, _gas, _code, origin, &sub, m_ms ? &(m_ms->internal.back()) : nullptr, _onOp, depth + 1); if (m_ms && !m_ms->internal.back().from) m_ms->internal.pop_back(); return ret; @@ -72,7 +72,7 @@ public: { if (m_ms) m_ms->internal.resize(m_ms->internal.size() + 1); - auto ret = m_s.call(_receiveAddress, _codeAddressOverride ? _codeAddressOverride : _receiveAddress, _myAddressOverride ? _myAddressOverride : myAddress, _txValue, gasPrice, _txData, _gas, _out, origin, &suicides, m_ms ? &(m_ms->internal.back()) : nullptr, _onOp, depth + 1); + auto ret = m_s.call(_receiveAddress, _codeAddressOverride ? _codeAddressOverride : _receiveAddress, _myAddressOverride ? _myAddressOverride : myAddress, _txValue, gasPrice, _txData, _gas, _out, origin, &sub, m_ms ? &(m_ms->internal.back()) : nullptr, _onOp, depth + 1); if (m_ms && !m_ms->internal.back().from) m_ms->internal.pop_back(); return ret; diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 9ec835833..40fac4883 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -1119,7 +1119,7 @@ u256 State::execute(bytesConstRef _rlp, bytes* o_output, bool _commit) return e.gasUsed(); } -bool State::call(Address _receiveAddress, Address _codeAddress, Address _senderAddress, u256 _value, u256 _gasPrice, bytesConstRef _data, u256* _gas, bytesRef _out, Address _originAddress, std::set
* o_suicides, Manifest* o_ms, OnOpFunc const& _onOp, unsigned _level) +bool State::call(Address _receiveAddress, Address _codeAddress, Address _senderAddress, u256 _value, u256 _gasPrice, bytesConstRef _data, u256* _gas, bytesRef _out, Address _originAddress, SubState* o_sub, Manifest* o_ms, OnOpFunc const& _onOp, unsigned _level) { if (!_originAddress) _originAddress = _senderAddress; @@ -1154,9 +1154,8 @@ bool State::call(Address _receiveAddress, Address _codeAddress, Address _senderA { auto out = vm.go(evm, _onOp); memcpy(_out.data(), out.data(), std::min(out.size(), _out.size())); - if (o_suicides) - for (auto i: evm.suicides) - o_suicides->insert(i); + if (o_sub) + *o_sub += evm.sub; if (o_ms) o_ms->output = out.toBytes(); } @@ -1189,7 +1188,7 @@ bool State::call(Address _receiveAddress, Address _codeAddress, Address _senderA return true; } -h160 State::create(Address _sender, u256 _endowment, u256 _gasPrice, u256* _gas, bytesConstRef _code, Address _origin, std::set
* o_suicides, Manifest* o_ms, OnOpFunc const& _onOp, unsigned _level) +h160 State::create(Address _sender, u256 _endowment, u256 _gasPrice, u256* _gas, bytesConstRef _code, Address _origin, SubState* o_sub, Manifest* o_ms, OnOpFunc const& _onOp, unsigned _level) { if (!_origin) _origin = _sender; @@ -1218,9 +1217,8 @@ h160 State::create(Address _sender, u256 _endowment, u256 _gasPrice, u256* _gas, out = vm.go(evm, _onOp); if (o_ms) o_ms->output = out.toBytes(); - if (o_suicides) - for (auto i: evm.suicides) - o_suicides->insert(i); + if (o_sub) + *o_sub += evm.sub; } catch (OutOfGas const& /*_e*/) { @@ -1240,7 +1238,7 @@ h160 State::create(Address _sender, u256 _endowment, u256 _gasPrice, u256* _gas, clog(StateChat) << "std::exception in VM: " << _e.what(); } - // TODO: CHECK: IS THIS CORRECT?! (esp. given account created prior to revertion init.) + // TODO: CHECK: AUDIT: IS THIS CORRECT?! (esp. given account created prior to revertion init.) // Write state out only in the case of a non-out-of-gas transaction. if (revert) diff --git a/libethereum/State.h b/libethereum/State.h index 6e65bfd53..776fb80e7 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -288,12 +288,12 @@ private: // We assume all instrinsic fees are paid up before this point. /// Execute a contract-creation transaction. - h160 create(Address _txSender, u256 _endowment, u256 _gasPrice, u256* _gas, bytesConstRef _code, Address _originAddress = Address(), std::set
* o_suicides = nullptr, Manifest* o_ms = nullptr, OnOpFunc const& _onOp = OnOpFunc(), unsigned _level = 0); + h160 create(Address _txSender, u256 _endowment, u256 _gasPrice, u256* _gas, bytesConstRef _code, Address _originAddress = Address(), SubState* o_sub = nullptr, Manifest* o_ms = nullptr, OnOpFunc const& _onOp = OnOpFunc(), unsigned _level = 0); /// Execute a call. /// @a _gas points to the amount of gas to use for the call, and will lower it accordingly. /// @returns false if the call ran out of gas before completion. true otherwise. - bool call(Address _myAddress, Address _codeAddress, Address _txSender, u256 _txValue, u256 _gasPrice, bytesConstRef _txData, u256* _gas, bytesRef _out, Address _originAddress = Address(), std::set
* o_suicides = nullptr, Manifest* o_ms = nullptr, OnOpFunc const& _onOp = OnOpFunc(), unsigned _level = 0); + bool call(Address _myAddress, Address _codeAddress, Address _txSender, u256 _txValue, u256 _gasPrice, bytesConstRef _txData, u256* _gas, bytesRef _out, Address _originAddress = Address(), SubState* o_sub = nullptr, Manifest* o_ms = nullptr, OnOpFunc const& _onOp = OnOpFunc(), unsigned _level = 0); /// Sets m_currentBlock to a clean state, (i.e. no change from m_previousBlock). void resetCurrent(); diff --git a/libevm/ExtVMFace.h b/libevm/ExtVMFace.h index 67fec9321..b57818907 100644 --- a/libevm/ExtVMFace.h +++ b/libevm/ExtVMFace.h @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -33,13 +34,28 @@ namespace dev namespace eth { -struct Post +struct LogEntry { Address from; - Address to; - u256 value; + h256 topics; bytes data; - u256 gas; +}; + +using LogEntries = std::vector; + +struct SubState +{ + std::set
suicides; ///< Any accounts that have suicided. + LogEntries logs; ///< Any logs. + u256 refunds; ///< Refund counter of SSTORE nonzero->zero. + + SubState& operator+=(SubState const& _s) + { + suicides += _s.suicides; + refunds += _s.refunds; + suicides += _s.suicides; + return *this; + } }; using OnOpFunc = std::function; @@ -80,7 +96,7 @@ public: virtual u256 txCount(Address) { return 0; } /// Suicide the associated contract and give proceeds to the given address. - virtual void suicide(Address) { suicides.insert(myAddress); } + virtual void suicide(Address) { sub.suicides.insert(myAddress); } /// Create a new (contract) account. virtual h160 create(u256, u256*, bytesConstRef, OnOpFunc const&) { return h160(); } @@ -103,7 +119,7 @@ public: bytesConstRef code; ///< Current code that is executing. BlockInfo previousBlock; ///< The previous block's information. BlockInfo currentBlock; ///< The current block's information. - std::set
suicides; ///< Any accounts that have suicided. + SubState sub; ///< Sub-band VM state (suicides, refund counter, logs). unsigned depth; ///< Depth of the present call. }; diff --git a/libevm/FeeStructure.cpp b/libevm/FeeStructure.cpp index d29b9fef9..47236b506 100644 --- a/libevm/FeeStructure.cpp +++ b/libevm/FeeStructure.cpp @@ -29,7 +29,9 @@ u256 const dev::eth::c_stepGas = 1; u256 const dev::eth::c_balanceGas = 20; u256 const dev::eth::c_sha3Gas = 20; u256 const dev::eth::c_sloadGas = 20; -u256 const dev::eth::c_sstoreGas = 100; +u256 const dev::eth::c_sstoreSetGas = 300; +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_memoryGas = 1; diff --git a/libevm/FeeStructure.h b/libevm/FeeStructure.h index 76be9a398..84a2551d9 100644 --- a/libevm/FeeStructure.h +++ b/libevm/FeeStructure.h @@ -32,7 +32,9 @@ extern u256 const c_stepGas; ///< Once per operation, except for SSTORE, SLOAD extern u256 const c_balanceGas; ///< Once per BALANCE operation. extern u256 const c_sha3Gas; ///< Once per SHA3 operation. extern u256 const c_sloadGas; ///< Once per SLOAD operation. -extern u256 const c_sstoreGas; ///< Once per non-zero storage element in a CREATE call/transaction. Also, once/twice per SSTORE operation depending on whether the zeroness changes (twice iff it changes from zero; nothing at all if to zero) or doesn't (once). +extern u256 const c_sstoreSetGas; ///< Once per SSTORE operation if the zeroness changes from zero. +extern u256 const c_sstoreResetGas; ///< Once per SSTORE operation if the zeroness doesn't change. +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_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. diff --git a/libevm/VM.h b/libevm/VM.h index 226b1d6cf..f3c82c714 100644 --- a/libevm/VM.h +++ b/libevm/VM.h @@ -117,11 +117,14 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con case Instruction::SSTORE: require(2); if (!_ext.store(m_stack.back()) && m_stack[m_stack.size() - 2]) - runGas = c_sstoreGas * 2; + runGas = c_sstoreSetGas; else if (_ext.store(m_stack.back()) && !m_stack[m_stack.size() - 2]) + { runGas = 0; + _ext.sub.refunds += c_sstoreRefundGas; + } else - runGas = c_sstoreGas; + runGas = c_sstoreResetGas; break; case Instruction::SLOAD: diff --git a/test/vm.cpp b/test/vm.cpp index b49c5cd27..fe4863041 100644 --- a/test/vm.cpp +++ b/test/vm.cpp @@ -45,7 +45,7 @@ h160 FakeExtVM::create(u256 _endowment, u256* _gas, bytesConstRef _init, OnOpFun m_s.noteSending(myAddress); m_ms.internal.resize(m_ms.internal.size() + 1); - auto ret = m_s.create(myAddress, _endowment, gasPrice, _gas, _init, origin, &suicides, &m_ms ? &(m_ms.internal.back()) : nullptr, {}, 1); + auto ret = m_s.create(myAddress, _endowment, gasPrice, _gas, _init, origin, &sub, &m_ms ? &(m_ms.internal.back()) : nullptr, {}, 1); if (!m_ms.internal.back().from) m_ms.internal.pop_back(); @@ -91,7 +91,7 @@ bool FakeExtVM::call(Address _receiveAddress, u256 _value, bytesConstRef _data, if (!m_s.addresses().count(myAddress)) { m_ms.internal.resize(m_ms.internal.size() + 1); - auto na = m_s.createNewAddress(myAddress, myAddress, balance(myAddress), gasPrice, &contractgas, init, origin, &suicides, &m_ms ? &(m_ms.internal.back()) : nullptr, {}, 1); + auto na = m_s.createNewAddress(myAddress, myAddress, balance(myAddress), gasPrice, &contractgas, init, origin, &sub, &m_ms ? &(m_ms.internal.back()) : nullptr, {}, 1); if (!m_ms.internal.back().from) m_ms.internal.pop_back(); if (na != myAddress) @@ -116,7 +116,7 @@ bool FakeExtVM::call(Address _receiveAddress, u256 _value, bytesConstRef _data, { m_s.noteSending(myAddress); m_ms.internal.resize(m_ms.internal.size() + 1); - auto na = m_s.createNewAddress(_codeAddressOverride ? _codeAddressOverride : _receiveAddress, myAddress, balance(_codeAddressOverride ? _codeAddressOverride : _receiveAddress), gasPrice, &contractgas, init, origin, &suicides, &m_ms ? &(m_ms.internal.back()) : nullptr, OnOpFunc(), 1); + auto na = m_s.createNewAddress(_codeAddressOverride ? _codeAddressOverride : _receiveAddress, myAddress, balance(_codeAddressOverride ? _codeAddressOverride : _receiveAddress), gasPrice, &contractgas, init, origin, &sub, &m_ms ? &(m_ms.internal.back()) : nullptr, OnOpFunc(), 1); if (!m_ms.internal.back().from) m_ms.internal.pop_back(); @@ -131,7 +131,7 @@ bool FakeExtVM::call(Address _receiveAddress, u256 _value, bytesConstRef _data, m_ms.internal.resize(m_ms.internal.size() + 1); - auto ret = m_s.call(_receiveAddress,_codeAddressOverride ? _codeAddressOverride : _receiveAddress, _myAddressOverride ? _myAddressOverride : myAddress, _value, gasPrice, _data, _gas, _out, origin, &suicides, &(m_ms.internal.back()), OnOpFunc(), 1); + auto ret = m_s.call(_receiveAddress,_codeAddressOverride ? _codeAddressOverride : _receiveAddress, _myAddressOverride ? _myAddressOverride : myAddress, _value, gasPrice, _data, _gas, _out, origin, &sub, &(m_ms.internal.back()), OnOpFunc(), 1); if (!m_ms.internal.back().from) m_ms.internal.pop_back(); @@ -146,12 +146,15 @@ bool FakeExtVM::call(Address _receiveAddress, u256 _value, bytesConstRef _data, if (!ret) return false; + // TODO: @CJentzsch refund SSTORE stuff. + // TODO: @CJentzsch test logs. + // do suicides - for (auto const& f: suicides) + for (auto const& f: sub.suicides) addresses.erase(f); // get storage - if ((get<0>(addresses[myAddress]) >= _value) && (suicides.find(_receiveAddress) == suicides.end())) + if ((get<0>(addresses[myAddress]) >= _value) && (sub.suicides.find(_receiveAddress) == sub.suicides.end())) { for (auto const& j: m_s.storage(_receiveAddress)) { @@ -419,8 +422,11 @@ void FakeExtVM::importCallCreates(mArray& _callcreates) } } -h160 FakeState::createNewAddress(Address _newAddress, Address _sender, u256 _endowment, u256 _gasPrice, u256* _gas, bytesConstRef _code, Address _origin, std::set
* o_suicides, Manifest* o_ms, OnOpFunc const& _onOp, unsigned _level) +// THIS IS BROKEN AND NEEDS TO BE REMOVED. +h160 FakeState::createNewAddress(Address _newAddress, Address _sender, u256 _endowment, u256 _gasPrice, u256* _gas, bytesConstRef _code, Address _origin, SubState* o_sub, Manifest* o_ms, OnOpFunc const& _onOp, unsigned _level) { + (void)o_sub; + if (!_origin) _origin = _sender; @@ -446,9 +452,7 @@ h160 FakeState::createNewAddress(Address _newAddress, Address _sender, u256 _end out = vm.go(evm, _onOp); if (o_ms) o_ms->output = out.toBytes(); - if (o_suicides) - for (auto i: evm.suicides) - o_suicides->insert(i); + // TODO: deal with evm.sub } catch (OutOfGas const& /*_e*/) { diff --git a/test/vm.h b/test/vm.h index d9dca1d7a..58ff58cd9 100644 --- a/test/vm.h +++ b/test/vm.h @@ -44,7 +44,7 @@ class FakeState: public eth::State { public: /// Execute a contract-creation transaction. - h160 createNewAddress(Address _newAddress, Address _txSender, u256 _endowment, u256 _gasPrice, u256* _gas, bytesConstRef _code, Address _originAddress = {}, std::set
* o_suicides = nullptr, eth::Manifest* o_ms = nullptr, eth::OnOpFunc const& _onOp = {}, unsigned _level = 0); + h160 createNewAddress(Address _newAddress, Address _txSender, u256 _endowment, u256 _gasPrice, u256* _gas, bytesConstRef _code, Address _originAddress = {}, eth::SubState* o_suicides = nullptr, eth::Manifest* o_ms = nullptr, eth::OnOpFunc const& _onOp = {}, unsigned _level = 0); }; class FakeExtVM: public eth::ExtVMFace From 6bace568d01c90b8d2ee7d43eed840c10955a2c4 Mon Sep 17 00:00:00 2001 From: Christoph Jentzsch Date: Mon, 27 Oct 2014 17:04:18 +0100 Subject: [PATCH 25/41] use ETHEREUM_TEST_PATH in all tests --- test/genesis.cpp | 13 ++++++++++++- test/hexPrefix.cpp | 13 ++++++++++++- test/rlp.cpp | 13 ++++++++++++- test/trie.cpp | 13 ++++++++++++- 4 files changed, 48 insertions(+), 4 deletions(-) diff --git a/test/genesis.cpp b/test/genesis.cpp index 5f17d2762..16ffb1859 100644 --- a/test/genesis.cpp +++ b/test/genesis.cpp @@ -35,9 +35,20 @@ namespace js = json_spirit; BOOST_AUTO_TEST_CASE(genesis_tests) { + const char* ptestPath = getenv("ETHEREUM_TEST_PATH"); + string testPath; + + if (ptestPath == NULL) + { + cnote << " could not find environment variable ETHEREUM_TEST_PATH \n"; + testPath = "../../../tests"; + } + else + testPath = ptestPath; + cnote << "Testing Genesis block..."; js::mValue v; - string s = asString(contents("../../../tests/genesishashestest.json")); + string s = asString(contents(testPath + "/genesishashestest.json")); BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of 'genesishashestest.json' is empty. Have you cloned the 'tests' repo branch develop?"); js::read_string(s, v); diff --git a/test/hexPrefix.cpp b/test/hexPrefix.cpp index fb2fbc826..99207ab97 100644 --- a/test/hexPrefix.cpp +++ b/test/hexPrefix.cpp @@ -33,9 +33,20 @@ namespace js = json_spirit; BOOST_AUTO_TEST_CASE(hexPrefix_test) { + const char* ptestPath = getenv("ETHEREUM_TEST_PATH"); + string testPath; + + if (ptestPath == NULL) + { + cnote << " could not find environment variable ETHEREUM_TEST_PATH \n"; + testPath = "../../../tests"; + } + else + testPath = ptestPath; + cnote << "Testing Hex-Prefix-Encode..."; js::mValue v; - string s = asString(contents("../../../tests/hexencodetest.json")); + string s = asString(contents(testPath + "/hexencodetest.json")); BOOST_REQUIRE_MESSAGE(s.length() > 0, "Content from 'hexencodetest.json' is empty. Have you cloned the 'tests' repo branch develop?"); js::read_string(s, v); for (auto& i: v.get_obj()) diff --git a/test/rlp.cpp b/test/rlp.cpp index 69360ad66..608a8499e 100644 --- a/test/rlp.cpp +++ b/test/rlp.cpp @@ -61,7 +61,18 @@ namespace dev static void getRLPTestCases(js::mValue& v) { - string s = asString(contents("../../../tests/rlptest.json")); + const char* ptestPath = getenv("ETHEREUM_TEST_PATH"); + string testPath; + + if (ptestPath == NULL) + { + cnote << " could not find environment variable ETHEREUM_TEST_PATH \n"; + testPath = "../../../tests"; + } + else + testPath = ptestPath; + + string s = asString(contents(testPath + "/rlptest.json")); BOOST_REQUIRE_MESSAGE( s.length() > 0, "Contents of 'rlptest.json' is empty. Have you cloned the 'tests' repo branch develop?"); js::read_string(s, v); diff --git a/test/trie.cpp b/test/trie.cpp index 899eb1f60..f8ebd10c8 100644 --- a/test/trie.cpp +++ b/test/trie.cpp @@ -49,9 +49,20 @@ static unsigned fac(unsigned _i) BOOST_AUTO_TEST_CASE(trie_tests) { + const char* ptestPath = getenv("ETHEREUM_TEST_PATH"); + string testPath; + + if (ptestPath == NULL) + { + cnote << " could not find environment variable ETHEREUM_TEST_PATH \n"; + testPath = "../../../tests"; + } + else + testPath = ptestPath; + cnote << "Testing Trie..."; js::mValue v; - string s = asString(contents("../../../tests/trietest.json")); + string s = asString(contents(testPath + "/trietest.json")); BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of 'trietest.json' is empty. Have you cloned the 'tests' repo branch develop?"); js::read_string(s, v); for (auto& i: v.get_obj()) From 7b1afe3b10fa574ebc4afa46922a5f428b7a2388 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 27 Oct 2014 18:17:01 +0100 Subject: [PATCH 26/41] LOG instructions. --- libethereum/State.cpp | 2 +- libethereum/State.h | 3 ++- libevm/ExtVMFace.h | 7 ++++++- libevm/VM.h | 27 +++++++++++++++++++++++++++ libevmface/Instruction.cpp | 10 ++++++++++ libevmface/Instruction.h | 6 ++++++ 6 files changed, 52 insertions(+), 3 deletions(-) diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 40fac4883..7e2489f4d 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -1114,7 +1114,7 @@ u256 State::execute(bytesConstRef _rlp, bytes* o_output, bool _commit) // TODO: CHECK TRIE after level DB flush to make sure exactly the same. // Add to the user-originated transactions that we've executed. - m_transactions.push_back(TransactionReceipt(e.t(), rootHash(), startGasUsed + e.gasUsed(), ms)); + m_transactions.push_back(TransactionReceipt(e.t(), rootHash(), startGasUsed + e.gasUsed(), ms, e.logs())); m_transactionSet.insert(e.t().sha3()); return e.gasUsed(); } diff --git a/libethereum/State.h b/libethereum/State.h index 776fb80e7..d6087fc01 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -54,7 +54,7 @@ struct StateDetail: public LogChannel { static const char* name() { return "/S/" struct TransactionReceipt { - TransactionReceipt(Transaction const& _t, h256 _root, u256 _gasUsed, Manifest const& _ms): transaction(_t), stateRoot(_root), gasUsed(_gasUsed), changes(_ms) {} + TransactionReceipt(Transaction const& _t, h256 _root, u256 _gasUsed, Manifest const& _ms, LogEntries const& _logs): transaction(_t), stateRoot(_root), gasUsed(_gasUsed), changes(_ms), logs(_logs) {} // Manifest const& changes() const { return changes; } @@ -69,6 +69,7 @@ struct TransactionReceipt h256 stateRoot; u256 gasUsed; Manifest changes; + LogEntries logs; }; struct PrecompiledAddress diff --git a/libevm/ExtVMFace.h b/libevm/ExtVMFace.h index b57818907..4aa3ee122 100644 --- a/libevm/ExtVMFace.h +++ b/libevm/ExtVMFace.h @@ -36,8 +36,10 @@ namespace eth struct LogEntry { + LogEntry() {} + LogEntry(Address const& _f, h256s&& _ts, bytes&& _d): from(_f), topics(std::move(_ts)), data(std::move(_d)) {} Address from; - h256 topics; + h256s topics; bytes data; }; @@ -104,6 +106,9 @@ public: /// Make a new message call. virtual bool call(Address, u256, bytesConstRef, u256*, bytesRef, OnOpFunc const&, Address, Address) { return false; } + /// Revert any changes made (by any of the other calls). + virtual void log(h256s&& _topics, bytesConstRef _data) { sub.logs.push_back(LogEntry(myAddress, std::move(_topics), _data.toBytes())); } + /// Revert any changes made (by any of the other calls). virtual void revert() {} diff --git a/libevm/VM.h b/libevm/VM.h index f3c82c714..7e39623e1 100644 --- a/libevm/VM.h +++ b/libevm/VM.h @@ -172,6 +172,18 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con runGas = c_balanceGas; break; + case Instruction::LOG0: + case Instruction::LOG1: + case Instruction::LOG2: + case Instruction::LOG3: + case Instruction::LOG4: + { + unsigned n = (unsigned)inst - (unsigned)Instruction::LOG0; + require(n + 2); + newTempSize = memNeed(m_stack[m_stack.size() - 1 - n], m_stack[m_stack.size() - 2 - n]); + break; + } + case Instruction::CALL: case Instruction::CALLCODE: require(7); @@ -691,6 +703,21 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con break; case Instruction::JUMPDEST: break; + case Instruction::LOG0: + _ext.log({}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 1], (unsigned)m_stack[m_stack.size() - 2])); + break; + case Instruction::LOG1: + _ext.log({m_stack[m_stack.size() - 1]}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 2], (unsigned)m_stack[m_stack.size() - 3])); + break; + case Instruction::LOG2: + _ext.log({m_stack[m_stack.size() - 1], m_stack[m_stack.size() - 2]}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 3], (unsigned)m_stack[m_stack.size() - 4])); + break; + case Instruction::LOG3: + _ext.log({m_stack[m_stack.size() - 1], m_stack[m_stack.size() - 2], m_stack[m_stack.size() - 3]}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 4], (unsigned)m_stack[m_stack.size() - 5])); + break; + case Instruction::LOG4: + _ext.log({m_stack[m_stack.size() - 1], m_stack[m_stack.size() - 2], m_stack[m_stack.size() - 3], m_stack[m_stack.size() - 4]}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 5], (unsigned)m_stack[m_stack.size() - 6])); + break; case Instruction::CREATE: { u256 endowment = m_stack.back(); diff --git a/libevmface/Instruction.cpp b/libevmface/Instruction.cpp index c9b6ea2ce..2c2af8eb0 100644 --- a/libevmface/Instruction.cpp +++ b/libevmface/Instruction.cpp @@ -149,6 +149,11 @@ const std::map dev::eth::c_instructions = { "SWAP14", Instruction::SWAP14 }, { "SWAP15", Instruction::SWAP15 }, { "SWAP16", Instruction::SWAP16 }, + { "LOG0", Instruction::LOG0 }, + { "LOG1", Instruction::LOG1 }, + { "LOG2", Instruction::LOG2 }, + { "LOG3", Instruction::LOG3 }, + { "LOG4", Instruction::LOG4 }, { "CREATE", Instruction::CREATE }, { "CALL", Instruction::CALL }, { "CALLCODE", Instruction::CALLCODE }, @@ -277,6 +282,11 @@ static const std::map c_instructionInfo = { Instruction::SWAP14, { "SWAP14", 0, 15, 15 } }, { Instruction::SWAP15, { "SWAP15", 0, 16, 16 } }, { Instruction::SWAP16, { "SWAP16", 0, 17, 17 } }, + { Instruction::LOG0, { "LOG0", 0, 1, 0 } }, + { Instruction::LOG1, { "LOG1", 0, 2, 0 } }, + { Instruction::LOG2, { "LOG2", 0, 3, 0 } }, + { Instruction::LOG3, { "LOG3", 0, 4, 0 } }, + { Instruction::LOG4, { "LOG4", 0, 5, 0 } }, { Instruction::CREATE, { "CREATE", 0, 3, 1 } }, { Instruction::CALL, { "CALL", 0, 7, 1 } }, { Instruction::CALLCODE, { "CALLCODE", 0, 7, 1 } }, diff --git a/libevmface/Instruction.h b/libevmface/Instruction.h index faad50fb2..ea355fab1 100644 --- a/libevmface/Instruction.h +++ b/libevmface/Instruction.h @@ -162,6 +162,12 @@ enum class Instruction: uint8_t SWAP15, ///< swaps the highest and 16th highest value on the stack SWAP16, ///< swaps the highest and 17th highest value on the stack + LOG0 = 0xa0, ///< Makes a log entry; no topics. + LOG1, ///< Makes a log entry; 1 topic. + LOG2, ///< Makes a log entry; 2 topics. + LOG3, ///< Makes a log entry; 3 topics. + LOG4, ///< Makes a log entry; 4 topics. + CREATE = 0xf0, ///< create a new account with associated code CALL, ///< message-call into an account RETURN, ///< halt execution returning output data From bc1e4ceee23b924bc89c385aae136eb97a52d749 Mon Sep 17 00:00:00 2001 From: Christoph Jentzsch Date: Mon, 27 Oct 2014 18:59:42 +0100 Subject: [PATCH 27/41] Add VMTRACE to user defined vm test Conflicts: test/vm.cpp --- test/vm.cpp | 57 ++++++++++++++++++++++++++++++++++++++++++++++++----- test/vm.h | 3 +++ 2 files changed, 55 insertions(+), 5 deletions(-) diff --git a/test/vm.cpp b/test/vm.cpp index fe4863041..c0452ef78 100644 --- a/test/vm.cpp +++ b/test/vm.cpp @@ -20,9 +20,9 @@ * vm test functions. */ -#include "vm.h" -#include #include +#include +#include "vm.h" //#define FILL_TESTS @@ -63,6 +63,7 @@ h160 FakeExtVM::create(u256 _endowment, u256* _gas, bytesConstRef _init, OnOpFun bool FakeExtVM::call(Address _receiveAddress, u256 _value, bytesConstRef _data, u256* _gas, bytesRef _out, OnOpFunc const&, Address _myAddressOverride, Address _codeAddressOverride) { + u256 contractgas = 0xffff; Transaction t; @@ -422,8 +423,27 @@ void FakeExtVM::importCallCreates(mArray& _callcreates) } } -// THIS IS BROKEN AND NEEDS TO BE REMOVED. -h160 FakeState::createNewAddress(Address _newAddress, Address _sender, u256 _endowment, u256 _gasPrice, u256* _gas, bytesConstRef _code, Address _origin, SubState* o_sub, Manifest* o_ms, OnOpFunc const& _onOp, unsigned _level) +OnOpFunc FakeExtVM::simpleTrace() +{ + return [](uint64_t steps, Instruction inst, bigint newMemSize, bigint gasCost, void* voidVM, void const* voidExt) + { + FakeExtVM const& ext = *(FakeExtVM const*)voidExt; + VM& vm = *(VM*)voidVM; + + ostringstream o; + o << endl << " STACK" << endl; + for (auto i: vm.stack()) + o << (h256)i << endl; + o << " MEMORY" << endl << memDump(vm.memory()); + o << " STORAGE" << endl; + for (auto const& i: ext.state().storage(ext.myAddress)) + o << showbase << hex << i.first << ": " << i.second << endl; + dev::LogOutputStream(true) << o.str(); + dev::LogOutputStream(false) << " | " << dec << ext.depth << " | " << ext.myAddress << " | #" << steps << " | " << hex << setw(4) << setfill('0') << vm.curPC() << " : " << instructionInfo(inst).name << " | " << dec << vm.gas() << " | -" << dec << gasCost << " | " << newMemSize << "x32" << " ]"; + }; +} + +h160 FakeState::createNewAddress(Address _newAddress, Address _sender, u256 _endowment, u256 _gasPrice, u256* _gas, bytesConstRef _code, Address _origin, std::set
* o_suicides, Manifest* o_ms, OnOpFunc const& _onOp, unsigned _level) { (void)o_sub; @@ -520,7 +540,7 @@ void doTests(json_spirit::mValue& v, bool _fillin) VM vm(fev.gas); try { - output = vm.go(fev).toVector(); + output = vm.go(fev, fev.simpleTrace()).toVector(); } catch (Exception const& _e) { @@ -756,3 +776,30 @@ BOOST_AUTO_TEST_CASE(vmSystemOperationsTest) { dev::test::executeTests("vmSystemOperationsTest"); } + +BOOST_AUTO_TEST_CASE(userDefinedFile) +{ + + if (boost::unit_test::framework::master_test_suite().argc == 2) + { + string filename = boost::unit_test::framework::master_test_suite().argv[1]; + g_logVerbosity = 12; + try + { + cnote << "Testing VM..." << "user defined test"; + json_spirit::mValue v; + string s = asString(contents(filename)); + BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of " + filename + " is empty. "); + json_spirit::read_string(s, v); + dev::test::doTests(v, false); + } + catch (Exception const& _e) + { + BOOST_ERROR("Failed VM Test with Exception: " << diagnostic_information(_e)); + } + catch (std::exception const& _e) + { + BOOST_ERROR("Failed VM Test with Exception: " << _e.what()); + } + } +} diff --git a/test/vm.h b/test/vm.h index 58ff58cd9..bf44c4b42 100644 --- a/test/vm.h +++ b/test/vm.h @@ -80,6 +80,9 @@ public: json_spirit::mArray exportCallCreates(); void importCallCreates(json_spirit::mArray& _callcreates); + static eth::OnOpFunc simpleTrace(); + FakeState state() const { return m_s; } + std::map, bytes>> addresses; eth::Transactions callcreates; bytes thisTxData; From 8cf0e2bd9ceb55b6170e32a19403fc9fcacf800e Mon Sep 17 00:00:00 2001 From: Christoph Jentzsch Date: Mon, 27 Oct 2014 19:01:10 +0100 Subject: [PATCH 28/41] VMTRACE for internal calls Conflicts: test/vm.cpp --- test/vm.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/test/vm.cpp b/test/vm.cpp index c0452ef78..fe2aff8cd 100644 --- a/test/vm.cpp +++ b/test/vm.cpp @@ -509,6 +509,7 @@ h160 FakeState::createNewAddress(Address _newAddress, Address _sender, u256 _end + namespace dev { namespace test { void doTests(json_spirit::mValue& v, bool _fillin) From 2c193627eda6c3b245c8a21c7255c41eab294399 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 27 Oct 2014 20:26:34 +0100 Subject: [PATCH 29/41] Draft of new LOG/bloom/headers/block format. --- libdevcore/FixedHash.h | 19 +++++++++++ libdevcrypto/SHA3.cpp | 1 - libdevcrypto/SHA3.h | 1 - libdevcrypto/TrieDB.cpp | 3 +- libdevcrypto/TrieDB.h | 1 + libethcore/BlockInfo.cpp | 26 ++++++++------- libethcore/BlockInfo.h | 11 +++++-- libethereum/BlockChain.cpp | 5 +-- libethereum/BlockDetails.h | 2 +- libethereum/Client.cpp | 2 +- libethereum/Executive.cpp | 4 +++ libethereum/Manifest.cpp | 4 +-- libethereum/Manifest.h | 2 +- libethereum/MessageFilter.cpp | 4 +-- libethereum/MessageFilter.h | 2 +- libethereum/State.cpp | 61 ++++++++++++++++++++++++----------- libethereum/State.h | 59 ++++++++++++++++++++++----------- libethereum/Transaction.cpp | 2 +- libethereum/Transaction.h | 8 ++--- libevm/ExtVMFace.h | 25 ++++++++++++++ libevm/VM.h | 17 +++++++++- liblll/Assembly.cpp | 4 +-- liblll/Assembly.h | 6 ++-- libwhisper/Common.cpp | 2 +- libwhisper/Common.h | 2 +- libwhisper/Message.h | 6 ++-- libwhisper/WhisperHost.cpp | 4 +-- test/main.cpp | 2 +- 28 files changed, 201 insertions(+), 84 deletions(-) diff --git a/libdevcore/FixedHash.h b/libdevcore/FixedHash.h index 0032a1314..284745c64 100644 --- a/libdevcore/FixedHash.h +++ b/libdevcore/FixedHash.h @@ -158,6 +158,25 @@ public: return ret; } + template inline FixedHash& shiftBloom(FixedHash const& _h) { return (*this |= _h.nbloom()); } + + template inline FixedHash nbloom() const + { + static const unsigned c_bloomBytes = (M + 7) / 8; + unsigned mask = (1 << c_bloomBytes) - 1; + FixedHash ret; + byte const* p = data(); + for (unsigned i = 0; i < P; ++i) + { + unsigned index = 0; + for (unsigned j = 0; j < c_bloomBytes; ++j, ++p) + index = (index << 8) | *p; + index &= mask; + ret[N - 1 - index / 8] |= (1 << (index % 8)); + } + return ret; + } + /// Returns the index of the first bit set to one, or size() * 8 if no bits are set. inline unsigned firstBitSet() const { diff --git a/libdevcrypto/SHA3.cpp b/libdevcrypto/SHA3.cpp index eaabae0ff..7c2cc01a3 100644 --- a/libdevcrypto/SHA3.cpp +++ b/libdevcrypto/SHA3.cpp @@ -30,7 +30,6 @@ namespace dev { h256 EmptySHA3 = sha3(bytesConstRef()); -h256 ZeroRLPSHA3 = sha3(rlp(bytesConstRef())); std::string sha3(std::string const& _input, bool _hex) { diff --git a/libdevcrypto/SHA3.h b/libdevcrypto/SHA3.h index 5948cb3bd..fc2cfcfc3 100644 --- a/libdevcrypto/SHA3.h +++ b/libdevcrypto/SHA3.h @@ -57,7 +57,6 @@ inline h256 sha3(bytes const& _input) { return sha3(bytesConstRef((bytes*)&_inpu inline h256 sha3(std::string const& _input) { return sha3(bytesConstRef(_input)); } extern h256 EmptySHA3; -extern h256 ZeroRLPSHA3; // Other crypto convenience routines diff --git a/libdevcrypto/TrieDB.cpp b/libdevcrypto/TrieDB.cpp index 168b2fdf7..674f21aa4 100644 --- a/libdevcrypto/TrieDB.cpp +++ b/libdevcrypto/TrieDB.cpp @@ -26,6 +26,7 @@ using namespace dev; #if !ETH_LANGUAGES -const h256 dev::c_shaNull = sha3(rlp("")); +h256 const dev::c_shaNull = sha3(rlp("")); +h256 const dev::EmptyTrie = c_shaNull; #endif diff --git a/libdevcrypto/TrieDB.h b/libdevcrypto/TrieDB.h index 0ca0b9d98..b42d67aea 100644 --- a/libdevcrypto/TrieDB.h +++ b/libdevcrypto/TrieDB.h @@ -45,6 +45,7 @@ struct TrieDBChannel: public LogChannel { static const char* name() { return "- struct InvalidTrie: virtual dev::Exception {}; extern const h256 c_shaNull; +extern const h256 EmptyTrie; /** * @brief Merkle Patricia Tree "Trie": a modifed base-16 Radix tree. diff --git a/libethcore/BlockInfo.cpp b/libethcore/BlockInfo.cpp index 6e4af247f..da609d5b4 100644 --- a/libethcore/BlockInfo.cpp +++ b/libethcore/BlockInfo.cpp @@ -52,16 +52,16 @@ BlockInfo BlockInfo::fromHeader(bytesConstRef _block) h256 BlockInfo::headerHashWithoutNonce() const { RLPStream s; - fillStream(s, false); + streamRLP(s, false); return sha3(s.out()); } auto static const c_sha3EmptyList = sha3(RLPEmptyList); -void BlockInfo::fillStream(RLPStream& _s, bool _nonce) const +void BlockInfo::streamRLP(RLPStream& _s, bool _nonce) const { - _s.appendList(_nonce ? 13 : 12) - << parentHash << sha3Uncles << coinbaseAddress << stateRoot << transactionsRoot + _s.appendList(_nonce ? 15 : 14) + << parentHash << sha3Uncles << coinbaseAddress << stateRoot << transactionsRoot << receiptsRoot << logBloom << difficulty << number << minGasPrice << gasLimit << gasUsed << timestamp << extraData; if (_nonce) _s << nonce; @@ -84,14 +84,16 @@ void BlockInfo::populateFromHeader(RLP const& _header, bool _checkNonce) coinbaseAddress = _header[field = 2].toHash
(); stateRoot = _header[field = 3].toHash(); transactionsRoot = _header[field = 4].toHash(); - difficulty = _header[field = 5].toInt(); - number = _header[field = 6].toInt(); - minGasPrice = _header[field = 7].toInt(); - gasLimit = _header[field = 8].toInt(); - gasUsed = _header[field = 9].toInt(); - timestamp = _header[field = 10].toInt(); - extraData = _header[field = 11].toBytes(); - nonce = _header[field = 12].toHash(); + receiptsRoot = _header[field = 5].toHash(); + 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(); } catch (Exception & _e) diff --git a/libethcore/BlockInfo.h b/libethcore/BlockInfo.h index 283f11b88..18628e2ec 100644 --- a/libethcore/BlockInfo.h +++ b/libethcore/BlockInfo.h @@ -47,7 +47,7 @@ extern u256 c_genesisDifficulty; * corresponding RLP block created with createGenesisBlock(). * * The difficulty and gas-limit derivations may be calculated with the calculateDifficulty() - * and calculateGasLimit() and the object serialised to RLP with fillStream. To determine the + * and calculateGasLimit() and the object serialised to RLP with streamRLP. To determine the * header hash without the nonce (for mining), the method headerHashWithoutNonce() is provided. * * The default constructor creates an empty object, which can be tested against with the boolean @@ -62,6 +62,8 @@ public: Address coinbaseAddress; h256 stateRoot; h256 transactionsRoot; + h256 receiptsRoot; + h512 logBloom; // TODO LogBloom - get include u256 difficulty; u256 number; u256 minGasPrice; @@ -89,6 +91,8 @@ public: coinbaseAddress == _cmp.coinbaseAddress && stateRoot == _cmp.stateRoot && transactionsRoot == _cmp.transactionsRoot && + receiptsRoot == _cmp.receiptsRoot && + logBloom == _cmp.logBloom && difficulty == _cmp.difficulty && number == _cmp.number && minGasPrice == _cmp.minGasPrice && @@ -112,13 +116,14 @@ public: /// No-nonce sha3 of the header only. h256 headerHashWithoutNonce() const; - void fillStream(RLPStream& _s, bool _nonce) const; + void streamRLP(RLPStream& _s, bool _nonce) const; }; inline std::ostream& operator<<(std::ostream& _out, BlockInfo const& _bi) { _out << _bi.hash << " " << _bi.parentHash << " " << _bi.sha3Uncles << " " << _bi.coinbaseAddress << " " << _bi.stateRoot << " " << _bi.transactionsRoot << " " << - _bi.difficulty << " " << _bi.number << " " << _bi.minGasPrice << " " << _bi.gasLimit << " " << _bi.gasUsed << " " << _bi.timestamp << " " << _bi.nonce; + _bi.receiptsRoot << " " << _bi.logBloom << " " << _bi.difficulty << " " << _bi.number << " " << _bi.minGasPrice << " " << _bi.gasLimit << " " << + _bi.gasUsed << " " << _bi.timestamp << " " << _bi.nonce; return _out; } diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index b08179f9e..f63eb64cd 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -102,7 +102,8 @@ bytes BlockChain::createGenesisBlock() } block.appendList(13) - << h256() << c_shaNull << h160() << stateRoot << c_shaNull << c_genesisDifficulty << 0 << 0 << 1000000 << 0 << (unsigned)0 << string() << sha3(bytes(1, 42)); + // TODO: maybe make logbloom correct? + << h256() << EmptySHA3 << h160() << stateRoot << EmptyTrie << EmptyTrie << LogBloom() << c_genesisDifficulty << 0 << 0 << 1000000 << 0 << (unsigned)0 << string() << sha3(bytes(1, 42)); block.appendRaw(RLPEmptyList); block.appendRaw(RLPEmptyList); return block.out(); @@ -305,7 +306,7 @@ h256s BlockChain::import(bytes const& _block, OverlayDB const& _db) // Get total difficulty increase and update state, checking it. State s(bi.coinbaseAddress, _db); auto tdIncrease = s.enactOn(&_block, bi, *this); - auto b = s.bloom(); + auto b = s.oldBloom(); BlockBlooms bb; BlockTraces bt; for (unsigned i = 0; i < s.pending().size(); ++i) diff --git a/libethereum/BlockDetails.h b/libethereum/BlockDetails.h index 9cb49a21c..90bf65bdd 100644 --- a/libethereum/BlockDetails.h +++ b/libethereum/BlockDetails.h @@ -66,7 +66,7 @@ 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.streamOut(s); return s.out(); } + bytes rlp() const { RLPStream s(traces.size()); for (auto const& i: traces) i.streamRLP(s); return s.out(); } Manifests traces; }; diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index dc36957ee..63e093b17 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -159,7 +159,7 @@ void Client::clearPending() if (!m_postMine.pending().size()) return; for (unsigned i = 0; i < m_postMine.pending().size(); ++i) - appendFromNewPending(m_postMine.bloom(i), changeds); + appendFromNewPending(m_postMine.oldBloom(i), changeds); changeds.insert(PendingChangedFilter); m_postMine = m_preMine; } diff --git a/libethereum/Executive.cpp b/libethereum/Executive.cpp index 840287ca9..22d538231 100644 --- a/libethereum/Executive.cpp +++ b/libethereum/Executive.cpp @@ -123,7 +123,11 @@ bool Executive::call(Address _receiveAddress, Address _senderAddress, u256 _valu m_ext = new ExtVM(m_s, _receiveAddress, _senderAddress, _originAddress, _value, _gasPrice, _data, &c, m_ms); } else + { m_endGas = _gas; + if (m_ext) + m_ext->sub.logs.push_back(LogEntry(_receiveAddress, {u256((u160)_senderAddress) + 1}, bytes())); + } return !m_ext; } diff --git a/libethereum/Manifest.cpp b/libethereum/Manifest.cpp index 2d1e4aa6e..9e6d2f651 100644 --- a/libethereum/Manifest.cpp +++ b/libethereum/Manifest.cpp @@ -37,10 +37,10 @@ Manifest::Manifest(bytesConstRef _r) internal.emplace_back(i.data()); } -void Manifest::streamOut(RLPStream& _s) const +void Manifest::streamRLP(RLPStream& _s) const { _s.appendList(7) << from << to << value << altered << input << output; _s.appendList(internal.size()); for (auto const& i: internal) - i.streamOut(_s); + i.streamRLP(_s); } diff --git a/libethereum/Manifest.h b/libethereum/Manifest.h index 12c40b3a9..e0e512c92 100644 --- a/libethereum/Manifest.h +++ b/libethereum/Manifest.h @@ -41,7 +41,7 @@ struct Manifest { Manifest() {} Manifest(bytesConstRef _r); - void streamOut(RLPStream& _s) const; + void streamRLP(RLPStream& _s) const; h256 bloom() const { h256 ret = from.bloom() | to.bloom(); for (auto const& i: internal) ret |= i.bloom(); for (auto const& i: altered) ret |= h256(i).bloom(); return ret; } diff --git a/libethereum/MessageFilter.cpp b/libethereum/MessageFilter.cpp index 951bfec98..fc6af1308 100644 --- a/libethereum/MessageFilter.cpp +++ b/libethereum/MessageFilter.cpp @@ -27,7 +27,7 @@ using namespace std; using namespace dev; using namespace dev::eth; -void MessageFilter::fillStream(RLPStream& _s) const +void MessageFilter::streamRLP(RLPStream& _s) const { _s.appendList(8) << m_from << m_to << m_stateAltered << m_altered << m_earliest << m_latest << m_max << m_skip; } @@ -35,7 +35,7 @@ void MessageFilter::fillStream(RLPStream& _s) const h256 MessageFilter::sha3() const { RLPStream s; - fillStream(s); + streamRLP(s); return dev::sha3(s.out()); } diff --git a/libethereum/MessageFilter.h b/libethereum/MessageFilter.h index c9fb4e51c..83cbb7237 100644 --- a/libethereum/MessageFilter.h +++ b/libethereum/MessageFilter.h @@ -39,7 +39,7 @@ class MessageFilter public: MessageFilter(int _earliest = 0, int _latest = -1, unsigned _max = 10, unsigned _skip = 0): m_earliest(_earliest), m_latest(_latest), m_max(_max), m_skip(_skip) {} - void fillStream(RLPStream& _s) const; + void streamRLP(RLPStream& _s) const; h256 sha3() const; int earliest() const { return m_earliest; } diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 7e2489f4d..5571a02e0 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -161,6 +161,7 @@ State::State(State const& _s): m_db(_s.m_db), m_state(&m_db, _s.m_state.root()), m_transactions(_s.m_transactions), + m_receipts(_s.m_receipts), m_transactionSet(_s.m_transactionSet), m_cache(_s.m_cache), m_previousBlock(_s.m_previousBlock), @@ -192,6 +193,7 @@ State& State::operator=(State const& _s) m_db = _s.m_db; m_state.open(&m_db, _s.m_state.root()); m_transactions = _s.m_transactions; + m_receipts = _s.m_receipts; m_transactionSet = _s.m_transactionSet; m_cache = _s.m_cache; m_previousBlock = _s.m_previousBlock; @@ -353,7 +355,7 @@ void State::ensureCached(std::map& _cache, Address _a, bo RLP state(stateBack); AddressState s; if (state.isNull()) - s = AddressState(0, 0, ZeroRLPSHA3, EmptySHA3); + s = AddressState(0, 0, EmptyTrie, EmptySHA3); else s = AddressState(state[0].toInt(), state[1].toInt(), state[2].toHash(), state[3].toHash()); bool ok; @@ -484,6 +486,7 @@ map State::addresses() const void State::resetCurrent() { m_transactions.clear(); + m_receipts.clear(); m_transactionSet.clear(); m_cache.clear(); m_currentBlock = BlockInfo(); @@ -547,7 +550,7 @@ h256s State::sync(TransactionQueue& _tq, bool* o_transactionQueueChanged) { uncommitToMine(); execute(i.second); - ret.push_back(m_transactions.back().changes.bloom()); + ret.push_back(m_receipts.back().changes().bloom()); _tq.noteGood(i); ++goodTxs; } @@ -713,7 +716,7 @@ void State::uncommitToMine() if (!m_transactions.size()) m_state.setRoot(m_previousBlock.stateRoot); else - m_state.setRoot(m_transactions[m_transactions.size() - 1].stateRoot); + m_state.setRoot(m_receipts[m_receipts.size() - 1].stateRoot()); m_db = m_lastTx; paranoia("Uncommited to mine", true); m_currentBlock.sha3Uncles = h256(); @@ -730,7 +733,7 @@ bool State::amIJustParanoid(BlockChain const& _bc) // Compile block: RLPStream block; block.appendList(3); - m_currentBlock.fillStream(block, true); + m_currentBlock.streamRLP(block, true); block.appendRaw(m_currentTxs); block.appendRaw(m_currentUncles); @@ -757,11 +760,20 @@ bool State::amIJustParanoid(BlockChain const& _bc) return false; } -h256 State::bloom() const +h256 State::oldBloom() const { h256 ret = m_currentBlock.coinbaseAddress.bloom(); - for (auto const& i: m_transactions) - ret |= i.changes.bloom(); + for (auto const& i: m_receipts) + ret |= i.changes().bloom(); + return ret; +} + +LogBloom State::logBloom() const +{ + LogBloom ret; + ret.shiftBloom<3>(sha3(m_currentBlock.coinbaseAddress.ref())); + for (TransactionReceipt const& i: m_receipts) + ret |= i.bloom(); return ret; } @@ -797,7 +809,7 @@ void State::commitToMine(BlockChain const& _bc) if (!knownUncles.count(u)) // ignore any uncles/mainline blocks that we know about. { BlockInfo ubi(_bc.block(u)); - ubi.fillStream(unclesData, true); + ubi.streamRLP(unclesData, true); ++unclesCount; uncleAddresses.push_back(ubi.coinbaseAddress); } @@ -805,8 +817,8 @@ void State::commitToMine(BlockChain const& _bc) } MemoryDB tm; - GenericTrieDB transactionReceipts(&tm); - transactionReceipts.init(); + GenericTrieDB receipts(&tm); + receipts.init(); RLPStream txs; txs.appendList(m_transactions.size()); @@ -816,16 +828,20 @@ void State::commitToMine(BlockChain const& _bc) RLPStream k; k << i; RLPStream v; - m_transactions[i].fillStream(v); - transactionReceipts.insert(&k.out(), &v.out()); - txs.appendRaw(v.out()); + m_receipts[i].streamRLP(v); + receipts.insert(&k.out(), &v.out()); + + RLPStream txrlp; + m_transactions[i].streamRLP(txrlp); + txs.appendRaw(txrlp.out()); } txs.swapOut(m_currentTxs); RLPStream(unclesCount).appendRaw(unclesData.out(), unclesCount).swapOut(m_currentUncles); - m_currentBlock.transactionsRoot = transactionReceipts.root(); + m_currentBlock.receiptsRoot = receipts.root(); + m_currentBlock.logBloom = logBloom(); m_currentBlock.sha3Uncles = sha3(m_currentUncles); // Apply rewards last of all. @@ -865,7 +881,7 @@ void State::completeMine() // Compile block: RLPStream ret; ret.appendList(3); - m_currentBlock.fillStream(ret, true); + m_currentBlock.streamRLP(ret, true); ret.appendRaw(m_currentTxs); ret.appendRaw(m_currentUncles); ret.swapOut(m_currentBytes); @@ -875,6 +891,7 @@ void State::completeMine() // Quickly reset the transactions. // TODO: Leave this in a better state than this limbo, or at least record that it's in limbo. m_transactions.clear(); + m_receipts.clear(); m_transactionSet.clear(); m_lastTx = m_db; } @@ -1114,7 +1131,8 @@ u256 State::execute(bytesConstRef _rlp, bytes* o_output, bool _commit) // TODO: CHECK TRIE after level DB flush to make sure exactly the same. // Add to the user-originated transactions that we've executed. - m_transactions.push_back(TransactionReceipt(e.t(), rootHash(), startGasUsed + e.gasUsed(), ms, e.logs())); + m_transactions.push_back(e.t()); + m_receipts.push_back(TransactionReceipt(rootHash(), startGasUsed + e.gasUsed(), e.logs(), ms)); m_transactionSet.insert(e.t().sha3()); return e.gasUsed(); } @@ -1185,6 +1203,12 @@ bool State::call(Address _receiveAddress, Address _codeAddress, Address _senderA return !revert; } + else + { + // non-contract call + if (o_sub) + o_sub->logs.push_back(LogEntry(_receiveAddress, {u256((u160)_senderAddress) + 1}, bytes())); + } return true; } @@ -1261,11 +1285,12 @@ State State::fromPending(unsigned _i) const if (!_i) ret.m_state.setRoot(m_previousBlock.stateRoot); else - ret.m_state.setRoot(m_transactions[_i - 1].stateRoot); + ret.m_state.setRoot(m_receipts[_i - 1].stateRoot()); while (ret.m_transactions.size() > _i) { - ret.m_transactionSet.erase(ret.m_transactions.back().transaction.sha3()); + ret.m_transactionSet.erase(ret.m_transactions.back().sha3()); ret.m_transactions.pop_back(); + ret.m_receipts.pop_back(); } return ret; } diff --git a/libethereum/State.h b/libethereum/State.h index d6087fc01..aa241fbef 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -52,26 +52,37 @@ struct StateChat: public LogChannel { static const char* name() { return "-S-"; struct StateTrace: public LogChannel { static const char* name() { return "=S="; } static const int verbosity = 7; }; struct StateDetail: public LogChannel { static const char* name() { return "/S/"; } static const int verbosity = 14; }; -struct TransactionReceipt +class TransactionReceipt { - TransactionReceipt(Transaction const& _t, h256 _root, u256 _gasUsed, Manifest const& _ms, LogEntries const& _logs): transaction(_t), stateRoot(_root), gasUsed(_gasUsed), changes(_ms), logs(_logs) {} +public: + TransactionReceipt(h256 _root, u256 _gasUsed, LogEntries const& _log, Manifest const& _ms): m_stateRoot(_root), m_gasUsed(_gasUsed), m_bloom(eth::bloom(_log)), m_log(_log), m_changes(_ms) {} + + Manifest const& changes() const { return m_changes; } -// Manifest const& changes() const { return changes; } + h256 const& stateRoot() const { return m_stateRoot; } + u256 const& gasUsed() const { return m_gasUsed; } + LogBloom const& bloom() const { return m_bloom; } + LogEntries const& log() const { return m_log; } - void fillStream(RLPStream& _s) const + void streamRLP(RLPStream& _s) const { - _s.appendList(3); - transaction.fillStream(_s); - _s.append(stateRoot, false, true) << gasUsed; + _s.appendList(4) << m_stateRoot << m_gasUsed << m_bloom; + _s.appendList(m_log.size()); + for (LogEntry const& l: m_log) + l.streamRLP(_s); } - Transaction transaction; - h256 stateRoot; - u256 gasUsed; - Manifest changes; - LogEntries logs; +private: + h256 m_stateRoot; + u256 m_gasUsed; + LogBloom m_bloom; + LogEntries m_log; + + Manifest m_changes; ///< TODO: PoC-7: KILL }; +using TransactionReceipts = std::vector; + struct PrecompiledAddress { unsigned gas; @@ -227,16 +238,25 @@ public: h256 rootHash() const { return m_state.root(); } /// Get the list of pending transactions. - Transactions pending() const { Transactions ret; for (auto const& t: m_transactions) ret.push_back(t.transaction); return ret; } + Transactions const& pending() const { return m_transactions; } + + /// Get the list of pending transactions. TODO: PoC-7: KILL + Manifest changesFromPending(unsigned _i) const { return m_receipts[_i].changes(); } + + /// Get the bloom filter of all changes happened in the block. TODO: PoC-7: KILL + h256 oldBloom() const; + + /// Get the bloom filter of a particular transaction that happened in the block. TODO: PoC-7: KILL + h256 oldBloom(unsigned _i) const { return m_receipts[_i].changes().bloom(); } /// Get the list of pending transactions. - Manifest changesFromPending(unsigned _i) const { return m_transactions[_i].changes; } + LogEntries const& log(unsigned _i) const { return m_receipts[_i].log(); } - /// Get the bloom filter of all changes happened in the block. - h256 bloom() const; + /// Get the bloom filter of all logs that happened in the block. + LogBloom logBloom() const; /// Get the bloom filter of a particular transaction that happened in the block. - h256 bloom(unsigned _i) const { return m_transactions[_i].changes.bloom(); } + LogBloom const& logBloom(unsigned _i) const { return m_receipts[_i].bloom(); } /// Get the State immediately after the given number of pending transactions have been applied. /// If (_i == 0) returns the initial state of the block. @@ -305,14 +325,15 @@ private: void refreshManifest(RLPStream* _txs = nullptr); /// @returns gas used by transactions thus far executed. - u256 gasUsed() const { return m_transactions.size() ? m_transactions.back().gasUsed : 0; } + u256 gasUsed() const { return m_receipts.size() ? m_receipts.back().gasUsed() : 0; } bool isTrieGood(bool _enforceRefs, bool _requireNoLeftOvers) const; void paranoia(std::string const& _when, bool _enforceRefs = false) const; OverlayDB m_db; ///< Our overlay for the state tree. TrieDB m_state; ///< Our state tree, as an OverlayDB DB. - std::vector m_transactions; ///< The current list of transactions that we've included in the state. + Transactions m_transactions; ///< The current list of transactions that we've included in the state. + TransactionReceipts m_receipts; ///< The corresponding list of transaction receipts. std::set m_transactionSet; ///< The set of transaction hashes that we've included in the state. OverlayDB m_lastTx; diff --git a/libethereum/Transaction.cpp b/libethereum/Transaction.cpp index b707efde3..bdc8bf34d 100644 --- a/libethereum/Transaction.cpp +++ b/libethereum/Transaction.cpp @@ -85,7 +85,7 @@ void Transaction::sign(Secret _priv) vrs = *(SignatureStruct const*)&sig; } -void Transaction::fillStream(RLPStream& _s, bool _sig) const +void Transaction::streamRLP(RLPStream& _s, bool _sig) const { _s.appendList((_sig ? 3 : 0) + 6); _s << nonce << gasPrice << gas; diff --git a/libethereum/Transaction.h b/libethereum/Transaction.h index ca73ba06a..2492e32bc 100644 --- a/libethereum/Transaction.h +++ b/libethereum/Transaction.h @@ -64,11 +64,11 @@ struct Transaction static h256 kFromMessage(h256 _msg, h256 _priv); - void fillStream(RLPStream& _s, bool _sig = true) const; - bytes rlp(bool _sig = true) const { RLPStream s; fillStream(s, _sig); return s.out(); } + void streamRLP(RLPStream& _s, bool _sig = true) const; + bytes rlp(bool _sig = true) const { RLPStream s; streamRLP(s, _sig); return s.out(); } std::string rlpString(bool _sig = true) const { return asString(rlp(_sig)); } - h256 sha3(bool _sig = true) const { RLPStream s; fillStream(s, _sig); return dev::sha3(s.out()); } - bytes sha3Bytes(bool _sig = true) const { RLPStream s; fillStream(s, _sig); return dev::sha3Bytes(s.out()); } + h256 sha3(bool _sig = true) const { RLPStream s; streamRLP(s, _sig); return dev::sha3(s.out()); } + bytes sha3Bytes(bool _sig = true) const { RLPStream s; streamRLP(s, _sig); return dev::sha3Bytes(s.out()); } private: mutable Address m_sender; diff --git a/libevm/ExtVMFace.h b/libevm/ExtVMFace.h index 4aa3ee122..1b1ae7455 100644 --- a/libevm/ExtVMFace.h +++ b/libevm/ExtVMFace.h @@ -25,6 +25,8 @@ #include #include #include +#include +#include #include #include #include @@ -34,10 +36,25 @@ namespace dev namespace eth { +using LogBloom = h512; + struct LogEntry { LogEntry() {} + LogEntry(RLP const& _r) { from = (Address)_r[0]; topics = (h256s)_r[1]; data = (bytes)_r[2]; } LogEntry(Address const& _f, h256s&& _ts, bytes&& _d): from(_f), topics(std::move(_ts)), data(std::move(_d)) {} + + void streamRLP(RLPStream& _s) const { _s.appendList(3) << from << topics << data; } + + LogBloom bloom() const + { + LogBloom ret; + ret.shiftBloom<3, 32>(sha3(from.ref())); + for (auto t: topics) + ret.shiftBloom<3, 32>(sha3(t.ref())); + return ret; + } + Address from; h256s topics; bytes data; @@ -45,6 +62,14 @@ struct LogEntry using LogEntries = std::vector; +inline LogBloom bloom(LogEntries const& _logs) +{ + LogBloom ret; + for (auto const& l: _logs) + ret |= l.bloom(); + return ret; +} + struct SubState { std::set
suicides; ///< Any accounts that have suicided. diff --git a/libevm/VM.h b/libevm/VM.h index 7e39623e1..4b17d9e73 100644 --- a/libevm/VM.h +++ b/libevm/VM.h @@ -703,7 +703,7 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con break; case Instruction::JUMPDEST: break; - case Instruction::LOG0: +/* case Instruction::LOG0: _ext.log({}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 1], (unsigned)m_stack[m_stack.size() - 2])); break; case Instruction::LOG1: @@ -717,6 +717,21 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con break; case Instruction::LOG4: _ext.log({m_stack[m_stack.size() - 1], m_stack[m_stack.size() - 2], m_stack[m_stack.size() - 3], m_stack[m_stack.size() - 4]}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 5], (unsigned)m_stack[m_stack.size() - 6])); + break;*/ + case Instruction::LOG0: + _ext.log({}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 1], (unsigned)m_stack[m_stack.size() - 2])); + break; + case Instruction::LOG1: + _ext.log({m_stack[m_stack.size() - 3]}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 1], (unsigned)m_stack[m_stack.size() - 2])); + break; + case Instruction::LOG2: + _ext.log({m_stack[m_stack.size() - 3], m_stack[m_stack.size() - 4]}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 1], (unsigned)m_stack[m_stack.size() - 2])); + break; + case Instruction::LOG3: + _ext.log({m_stack[m_stack.size() - 3], m_stack[m_stack.size() - 4], m_stack[m_stack.size() - 5]}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 1], (unsigned)m_stack[m_stack.size() - 2])); + break; + case Instruction::LOG4: + _ext.log({m_stack[m_stack.size() - 3], m_stack[m_stack.size() - 4], m_stack[m_stack.size() - 5], m_stack[m_stack.size() - 6]}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 1], (unsigned)m_stack[m_stack.size() - 2])); break; case Instruction::CREATE: { diff --git a/liblll/Assembly.cpp b/liblll/Assembly.cpp index c26a9a98e..5b10138d1 100644 --- a/liblll/Assembly.cpp +++ b/liblll/Assembly.cpp @@ -147,7 +147,7 @@ ostream& dev::eth::operator<<(ostream& _out, AssemblyItemsConstRef _i) return _out; } -ostream& Assembly::streamOut(ostream& _out, string const& _prefix) const +ostream& Assembly::streamRLP(ostream& _out, string const& _prefix) const { _out << _prefix << ".code:" << endl; for (AssemblyItem const& i: m_items) @@ -189,7 +189,7 @@ ostream& Assembly::streamOut(ostream& _out, string const& _prefix) const for (auto const& i: m_subs) { _out << _prefix << " " << hex << (unsigned)(u256)i.first << ": " << endl; - i.second.streamOut(_out, _prefix + " "); + i.second.streamRLP(_out, _prefix + " "); } } return _out; diff --git a/liblll/Assembly.h b/liblll/Assembly.h index b7feaf4f4..8ab3062dc 100644 --- a/liblll/Assembly.h +++ b/liblll/Assembly.h @@ -104,11 +104,11 @@ public: void injectStart(AssemblyItem const& _i); - std::string out() const { std::stringstream ret; streamOut(ret); return ret.str(); } + std::string out() const { std::stringstream ret; streamRLP(ret); return ret.str(); } int deposit() const { return m_deposit; } bytes assemble() const; Assembly& optimise(bool _enable); - std::ostream& streamOut(std::ostream& _out, std::string const& _prefix = "") const; + std::ostream& streamRLP(std::ostream& _out, std::string const& _prefix = "") const; private: void donePath() { if (m_totalDeposit != INT_MAX && m_totalDeposit != m_deposit) BOOST_THROW_EXCEPTION(InvalidDeposit()); } @@ -127,7 +127,7 @@ private: inline std::ostream& operator<<(std::ostream& _out, Assembly const& _a) { - _a.streamOut(_out); + _a.streamRLP(_out); return _out; } diff --git a/libwhisper/Common.cpp b/libwhisper/Common.cpp index 11908d181..15b07e433 100644 --- a/libwhisper/Common.cpp +++ b/libwhisper/Common.cpp @@ -36,7 +36,7 @@ BuildTopic& BuildTopic::shiftBytes(bytes const& _b) h256 TopicFilter::sha3() const { RLPStream s; - fillStream(s); + streamRLP(s); return dev::sha3(s.out()); } diff --git a/libwhisper/Common.h b/libwhisper/Common.h index a85caafe1..21296e193 100644 --- a/libwhisper/Common.h +++ b/libwhisper/Common.h @@ -92,7 +92,7 @@ public: TopicFilter(TopicMasks const& _m): m_topicMasks(_m) {} TopicFilter(RLP const& _r): m_topicMasks((TopicMasks)_r) {} - void fillStream(RLPStream& _s) const { _s << m_topicMasks; } + void streamRLP(RLPStream& _s) const { _s << m_topicMasks; } h256 sha3() const; bool matches(Envelope const& _m) const; diff --git a/libwhisper/Message.h b/libwhisper/Message.h index 84214fd18..6b28073b7 100644 --- a/libwhisper/Message.h +++ b/libwhisper/Message.h @@ -55,9 +55,9 @@ public: operator bool() const { return !!m_expiry; } - void streamOut(RLPStream& _s, bool _withNonce) const { _s.appendList(_withNonce ? 5 : 4) << m_expiry << m_ttl << m_topic << m_data; if (_withNonce) _s << m_nonce; } - h256 sha3() const { RLPStream s; streamOut(s, true); return dev::sha3(s.out()); } - h256 sha3NoNonce() const { RLPStream s; streamOut(s, false); return dev::sha3(s.out()); } + void streamRLP(RLPStream& _s, bool _withNonce) const { _s.appendList(_withNonce ? 5 : 4) << m_expiry << m_ttl << m_topic << m_data; if (_withNonce) _s << m_nonce; } + h256 sha3() const { RLPStream s; streamRLP(s, true); return dev::sha3(s.out()); } + h256 sha3NoNonce() const { RLPStream s; streamRLP(s, false); return dev::sha3(s.out()); } unsigned sent() const { return m_expiry - m_ttl; } unsigned expiry() const { return m_expiry; } diff --git a/libwhisper/WhisperHost.cpp b/libwhisper/WhisperHost.cpp index 591574bf0..71030aae2 100644 --- a/libwhisper/WhisperHost.cpp +++ b/libwhisper/WhisperHost.cpp @@ -48,8 +48,8 @@ void WhisperHost::streamMessage(h256 _m, RLPStream& _s) const { UpgradeGuard ll(l); auto const& m = m_messages.at(_m); - cnote << "streamOut: " << m.expiry() << m.ttl() << m.topic() << toHex(m.data()); - m.streamOut(_s, true); + cnote << "streamRLP: " << m.expiry() << m.ttl() << m.topic() << toHex(m.data()); + m.streamRLP(_s, true); } } diff --git a/test/main.cpp b/test/main.cpp index ef009e299..3f8860d7a 100644 --- a/test/main.cpp +++ b/test/main.cpp @@ -44,7 +44,7 @@ using namespace dev::eth; BOOST_AUTO_TEST_CASE(basic_tests) { /* RLPStream s; - BlockInfo::genesis().fillStream(s, false); + BlockInfo::genesis().streamRLP(s, false); std::cout << RLP(s.out()) << std::endl; std::cout << toHex(s.out()) << std::endl; std::cout << sha3(s.out()) << std::endl;*/ From 744470b731e1940e701c8ad6960cfa9d01e91d36 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 27 Oct 2014 21:22:21 +0100 Subject: [PATCH 30/41] Fixes for the latest LOG stuff. --- alethzero/MainWin.cpp | 1 + libethcore/BlockInfo.cpp | 2 +- libethereum/BlockChain.cpp | 2 +- libethereum/State.cpp | 20 ++++++++++++++------ 4 files changed, 17 insertions(+), 8 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 227f739ce..4da7026fe 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -1227,6 +1227,7 @@ void Main::on_blocks_currentItemChanged() s << "
Nonce: " << info.nonce << ""; s << "
Parent: " << info.parentHash << ""; s << "
Bloom: " << details.bloom << ""; + s << "
Log Bloom: " << info.logBloom << ""; s << "
Transactions: " << block[1].itemCount() << " @" << info.transactionsRoot << ""; s << "
Uncles: " << block[2].itemCount() << " @" << info.sha3Uncles << ""; if (info.parentHash) diff --git a/libethcore/BlockInfo.cpp b/libethcore/BlockInfo.cpp index da609d5b4..ea9cc3055 100644 --- a/libethcore/BlockInfo.cpp +++ b/libethcore/BlockInfo.cpp @@ -96,7 +96,7 @@ void BlockInfo::populateFromHeader(RLP const& _header, bool _checkNonce) nonce = _header[field = 14].toHash(); } - catch (Exception & _e) + catch (Exception const& _e) { _e << errinfo_name("invalid block header format") << BadFieldError(field, toHex(_header[field].data().toBytes())); throw; diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index f63eb64cd..a9bdbf247 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -101,7 +101,7 @@ bytes BlockChain::createGenesisBlock() stateRoot = state.root(); } - block.appendList(13) + block.appendList(15) // TODO: maybe make logbloom correct? << h256() << EmptySHA3 << h160() << stateRoot << EmptyTrie << EmptyTrie << LogBloom() << c_genesisDifficulty << 0 << 0 << 1000000 << 0 << (unsigned)0 << string() << sha3(bytes(1, 42)); block.appendRaw(RLPEmptyList); diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 5571a02e0..e49fa8082 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -817,8 +817,12 @@ void State::commitToMine(BlockChain const& _bc) } MemoryDB tm; - GenericTrieDB receipts(&tm); - receipts.init(); + GenericTrieDB transactionsTrie(&tm); + transactionsTrie.init(); + + MemoryDB rm; + GenericTrieDB receiptsTrie(&rm); + receiptsTrie.init(); RLPStream txs; txs.appendList(m_transactions.size()); @@ -827,12 +831,15 @@ void State::commitToMine(BlockChain const& _bc) { RLPStream k; k << i; - RLPStream v; - m_receipts[i].streamRLP(v); - receipts.insert(&k.out(), &v.out()); + + RLPStream receiptrlp; + m_receipts[i].streamRLP(receiptrlp); + receiptsTrie.insert(&k.out(), &receiptrlp.out()); RLPStream txrlp; m_transactions[i].streamRLP(txrlp); + transactionsTrie.insert(&k.out(), &txrlp.out()); + txs.appendRaw(txrlp.out()); } @@ -840,7 +847,8 @@ void State::commitToMine(BlockChain const& _bc) RLPStream(unclesCount).appendRaw(unclesData.out(), unclesCount).swapOut(m_currentUncles); - m_currentBlock.receiptsRoot = receipts.root(); + m_currentBlock.transactionsRoot = transactionsTrie.root(); + m_currentBlock.receiptsRoot = receiptsTrie.root(); m_currentBlock.logBloom = logBloom(); m_currentBlock.sha3Uncles = sha3(m_currentUncles); From 875d526590ee8e4ff0645125559fb453cc1a6418 Mon Sep 17 00:00:00 2001 From: Christoph Jentzsch Date: Mon, 27 Oct 2014 22:21:30 +0100 Subject: [PATCH 31/41] log VMTRACE in file for user defined test --- test/vm.cpp | 31 ++++++------------------------- test/vm.h | 36 ++++++++++++++++++++++++++++++++++-- 2 files changed, 40 insertions(+), 27 deletions(-) diff --git a/test/vm.cpp b/test/vm.cpp index fe2aff8cd..feb2bbaaa 100644 --- a/test/vm.cpp +++ b/test/vm.cpp @@ -21,7 +21,6 @@ */ #include -#include #include "vm.h" //#define FILL_TESTS @@ -63,7 +62,6 @@ h160 FakeExtVM::create(u256 _endowment, u256* _gas, bytesConstRef _init, OnOpFun bool FakeExtVM::call(Address _receiveAddress, u256 _value, bytesConstRef _data, u256* _gas, bytesRef _out, OnOpFunc const&, Address _myAddressOverride, Address _codeAddressOverride) { - u256 contractgas = 0xffff; Transaction t; @@ -132,7 +130,7 @@ bool FakeExtVM::call(Address _receiveAddress, u256 _value, bytesConstRef _data, m_ms.internal.resize(m_ms.internal.size() + 1); - auto ret = m_s.call(_receiveAddress,_codeAddressOverride ? _codeAddressOverride : _receiveAddress, _myAddressOverride ? _myAddressOverride : myAddress, _value, gasPrice, _data, _gas, _out, origin, &sub, &(m_ms.internal.back()), OnOpFunc(), 1); + auto ret = m_s.call(_receiveAddress,_codeAddressOverride ? _codeAddressOverride : _receiveAddress, _myAddressOverride ? _myAddressOverride : myAddress, _value, gasPrice, _data, _gas, _out, origin, &sub, &(m_ms.internal.back()), simpleTrace(), 1); if (!m_ms.internal.back().from) m_ms.internal.pop_back(); @@ -423,27 +421,8 @@ void FakeExtVM::importCallCreates(mArray& _callcreates) } } -OnOpFunc FakeExtVM::simpleTrace() -{ - return [](uint64_t steps, Instruction inst, bigint newMemSize, bigint gasCost, void* voidVM, void const* voidExt) - { - FakeExtVM const& ext = *(FakeExtVM const*)voidExt; - VM& vm = *(VM*)voidVM; - - ostringstream o; - o << endl << " STACK" << endl; - for (auto i: vm.stack()) - o << (h256)i << endl; - o << " MEMORY" << endl << memDump(vm.memory()); - o << " STORAGE" << endl; - for (auto const& i: ext.state().storage(ext.myAddress)) - o << showbase << hex << i.first << ": " << i.second << endl; - dev::LogOutputStream(true) << o.str(); - dev::LogOutputStream(false) << " | " << dec << ext.depth << " | " << ext.myAddress << " | #" << steps << " | " << hex << setw(4) << setfill('0') << vm.curPC() << " : " << instructionInfo(inst).name << " | " << dec << vm.gas() << " | -" << dec << gasCost << " | " << newMemSize << "x32" << " ]"; - }; -} - -h160 FakeState::createNewAddress(Address _newAddress, Address _sender, u256 _endowment, u256 _gasPrice, u256* _gas, bytesConstRef _code, Address _origin, std::set
* o_suicides, Manifest* o_ms, OnOpFunc const& _onOp, unsigned _level) +// THIS IS BROKEN AND NEEDS TO BE REMOVED. +h160 FakeState::createNewAddress(Address _newAddress, Address _sender, u256 _endowment, u256 _gasPrice, u256* _gas, bytesConstRef _code, Address _origin, SubState* o_sub, Manifest* o_ms, OnOpFunc const& _onOp, unsigned _level) { (void)o_sub; @@ -541,7 +520,7 @@ void doTests(json_spirit::mValue& v, bool _fillin) VM vm(fev.gas); try { - output = vm.go(fev, fev.simpleTrace()).toVector(); + output = vm.go(fev, fev.simpleTrace()).toVector(); } catch (Exception const& _e) { @@ -784,6 +763,7 @@ BOOST_AUTO_TEST_CASE(userDefinedFile) if (boost::unit_test::framework::master_test_suite().argc == 2) { string filename = boost::unit_test::framework::master_test_suite().argv[1]; + int currentVerbosity = g_logVerbosity; g_logVerbosity = 12; try { @@ -802,5 +782,6 @@ BOOST_AUTO_TEST_CASE(userDefinedFile) { BOOST_ERROR("Failed VM Test with Exception: " << _e.what()); } + g_logVerbosity = currentVerbosity; } } diff --git a/test/vm.h b/test/vm.h index bf44c4b42..1718cd6f0 100644 --- a/test/vm.h +++ b/test/vm.h @@ -28,6 +28,7 @@ along with cpp-ethereum. If not, see . #include #include "JsonSpiritHeaders.h" #include +#include #include #include #include @@ -36,6 +37,7 @@ along with cpp-ethereum. If not, see . #include #include + namespace dev { namespace test { struct FakeExtVMFailure : virtual Exception {}; @@ -44,7 +46,7 @@ class FakeState: public eth::State { public: /// Execute a contract-creation transaction. - h160 createNewAddress(Address _newAddress, Address _txSender, u256 _endowment, u256 _gasPrice, u256* _gas, bytesConstRef _code, Address _originAddress = {}, eth::SubState* o_suicides = nullptr, eth::Manifest* o_ms = nullptr, eth::OnOpFunc const& _onOp = {}, unsigned _level = 0); + h160 createNewAddress(Address _newAddress, Address _txSender, u256 _endowment, u256 _gasPrice, u256* _gas, bytesConstRef _code, Address _originAddress = {}, eth::SubState* o_sub = nullptr, eth::Manifest* o_ms = nullptr, eth::OnOpFunc const& _onOp = {}, unsigned _level = 0); }; class FakeExtVM: public eth::ExtVMFace @@ -80,7 +82,9 @@ public: json_spirit::mArray exportCallCreates(); void importCallCreates(json_spirit::mArray& _callcreates); - static eth::OnOpFunc simpleTrace(); + template + eth::OnOpFunc simpleTrace(); + FakeState state() const { return m_s; } std::map, bytes>> addresses; @@ -94,4 +98,32 @@ private: eth::Manifest m_ms; }; +template +eth::OnOpFunc FakeExtVM::simpleTrace() +{ + return [](uint64_t steps, eth::Instruction inst, bigint newMemSize, bigint gasCost, void* voidVM, void const* voidExt) + { + ExtVMType const& ext = *(ExtVMType const*)voidExt; + eth::VM& vm = *(eth::VM*)voidVM; + + std::ostringstream o; + o << std::endl << " STACK" << std::endl; + for (auto i: vm.stack()) + o << (h256)i << std::endl; + o << " MEMORY" << std::endl << memDump(vm.memory()); + o << " STORAGE" << std::endl; + for (auto const& i: ext.state().storage(ext.myAddress)) + o << std::showbase << std::hex << i.first << ": " << i.second << std::endl; + dev::LogOutputStream(true) << o.str(); + dev::LogOutputStream(false) << " | " << std::dec << ext.depth << " | " << ext.myAddress << " | #" << steps << " | " << std::hex << std::setw(4) << std::setfill('0') << vm.curPC() << " : " << instructionInfo(inst).name << " | " << std::dec << vm.gas() << " | -" << std::dec << gasCost << " | " << newMemSize << "x32" << " ]"; + + if (eth::VMTraceChannel::verbosity <= g_logVerbosity) + { + std::ofstream f; + f.open("./vmtrace.log", std::ofstream::app); + f << o.str(); + f << " | " << std::dec << ext.depth << " | " << ext.myAddress << " | #" << steps << " | " << std::hex << std::setw(4) << std::setfill('0') << vm.curPC() << " : " << instructionInfo(inst).name << " | " << std::dec << vm.gas() << " | -" << std::dec << gasCost << " | " << newMemSize << "x32"; + } + }; +} } } // Namespace Close From 3332043ec2159493c6650dbe455b3705d4219b60 Mon Sep 17 00:00:00 2001 From: Christoph Jentzsch Date: Mon, 27 Oct 2014 22:33:23 +0100 Subject: [PATCH 32/41] Update vm.cpp --- test/vm.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/test/vm.cpp b/test/vm.cpp index feb2bbaaa..40a0a862b 100644 --- a/test/vm.cpp +++ b/test/vm.cpp @@ -486,9 +486,6 @@ h160 FakeState::createNewAddress(Address _newAddress, Address _sender, u256 _end return _newAddress; } - - - namespace dev { namespace test { void doTests(json_spirit::mValue& v, bool _fillin) From 314b070d364e7d6783241e8b7e1b318df5528544 Mon Sep 17 00:00:00 2001 From: Christoph Jentzsch Date: Mon, 27 Oct 2014 22:33:50 +0100 Subject: [PATCH 33/41] Update vm.h --- test/vm.h | 1 - 1 file changed, 1 deletion(-) diff --git a/test/vm.h b/test/vm.h index 1718cd6f0..f3aae694a 100644 --- a/test/vm.h +++ b/test/vm.h @@ -37,7 +37,6 @@ along with cpp-ethereum. If not, see . #include #include - namespace dev { namespace test { struct FakeExtVMFailure : virtual Exception {}; From 480ca5d1e7e96d25364314c54968e282a06c9ee7 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 28 Oct 2014 01:31:25 +0100 Subject: [PATCH 34/41] Paranoia mining fix. --- libethcore/BlockInfo.cpp | 7 ++++--- libethcore/BlockInfo.h | 2 +- libethcore/Exceptions.h | 3 ++- libethereum/State.cpp | 41 ++++++++++++++++++++++++++++++++-------- libethereum/State.h | 3 +++ 5 files changed, 43 insertions(+), 13 deletions(-) diff --git a/libethcore/BlockInfo.cpp b/libethcore/BlockInfo.cpp index ea9cc3055..60c190470 100644 --- a/libethcore/BlockInfo.cpp +++ b/libethcore/BlockInfo.cpp @@ -37,9 +37,9 @@ BlockInfo::BlockInfo(): timestamp(Invalid256) { } -BlockInfo::BlockInfo(bytesConstRef _block) +BlockInfo::BlockInfo(bytesConstRef _block, bool _checkNonce) { - populate(_block); + populate(_block, _checkNonce); } BlockInfo BlockInfo::fromHeader(bytesConstRef _block) @@ -103,6 +103,7 @@ void BlockInfo::populateFromHeader(RLP const& _header, bool _checkNonce) } // check it hashes according to proof of work or that it's the genesis block. + cnote << "Verifying" << headerHashWithoutNonce().abridged() << nonce.abridged() << difficulty; if (_checkNonce && parentHash && !ProofOfWork::verify(headerHashWithoutNonce(), nonce, difficulty)) BOOST_THROW_EXCEPTION(InvalidBlockNonce(headerHashWithoutNonce(), nonce, difficulty)); @@ -142,7 +143,7 @@ void BlockInfo::verifyInternals(bytesConstRef _block) const { bytes k = rlp(i); t.insert(&k, tr.data()); - u256 gp = tr[0][1].toInt(); + u256 gp = tr[1].toInt(); mgp = min(mgp, gp); ++i; } diff --git a/libethcore/BlockInfo.h b/libethcore/BlockInfo.h index 18628e2ec..d91ff244d 100644 --- a/libethcore/BlockInfo.h +++ b/libethcore/BlockInfo.h @@ -75,7 +75,7 @@ public: BlockInfo(); explicit BlockInfo(bytes const& _block): BlockInfo(&_block) {} - explicit BlockInfo(bytesConstRef _block); + explicit BlockInfo(bytesConstRef _block, bool _checkNonce = true); static h256 headerHash(bytes const& _block) { return headerHash(&_block); } static h256 headerHash(bytesConstRef _block); diff --git a/libethcore/Exceptions.h b/libethcore/Exceptions.h index 8e4fcb2d2..5a07407d2 100644 --- a/libethcore/Exceptions.h +++ b/libethcore/Exceptions.h @@ -57,7 +57,8 @@ struct InvalidDifficulty: virtual dev::Exception {}; class InvalidGasLimit: virtual public dev::Exception { public: InvalidGasLimit(u256 _provided = 0, u256 _valid = 0): provided(_provided), valid(_valid) {} u256 provided; u256 valid; virtual const char* what() const noexcept; }; class InvalidMinGasPrice: virtual public dev::Exception { public: InvalidMinGasPrice(u256 _provided = 0, u256 _limit = 0): provided(_provided), limit(_limit) {} u256 provided; u256 limit; virtual const char* what() const noexcept; }; struct InvalidTransactionGasUsed: virtual dev::Exception {}; -struct InvalidTransactionStateRoot: virtual dev::Exception {}; +struct InvalidTransactionsStateRoot: virtual dev::Exception {}; +struct InvalidReceiptsStateRoot: virtual dev::Exception {}; struct InvalidTimestamp: virtual dev::Exception {}; class InvalidNonce: virtual public dev::Exception { public: InvalidNonce(u256 _required = 0, u256 _candidate = 0): required(_required), candidate(_candidate) {} u256 required; u256 candidate; virtual const char* what() const noexcept; }; class InvalidBlockNonce: virtual public dev::Exception { public: InvalidBlockNonce(h256 _h = h256(), h256 _n = h256(), u256 _d = 0): h(_h), n(_n), d(_d) {} h256 h; h256 n; u256 d; virtual const char* what() const noexcept; }; diff --git a/libethereum/State.cpp b/libethereum/State.cpp index e49fa8082..d6bdc74d1 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -591,7 +591,7 @@ u256 State::enact(bytesConstRef _block, BlockChain const* _bc, bool _checkNonce) // m_currentBlock is assumed to be prepopulated and reset. #if !ETH_RELEASE - BlockInfo bi(_block); + BlockInfo bi(_block, _checkNonce); assert(m_previousBlock.hash == bi.parentHash); assert(m_currentBlock.parentHash == bi.parentHash); assert(rootHash() == m_previousBlock.stateRoot); @@ -608,16 +608,32 @@ u256 State::enact(bytesConstRef _block, BlockChain const* _bc, bool _checkNonce) // cnote << m_state; MemoryDB tm; - GenericTrieDB transactionManifest(&tm); - transactionManifest.init(); + GenericTrieDB transactionsTrie(&tm); + transactionsTrie.init(); + + MemoryDB rm; + GenericTrieDB receiptsTrie(&rm); + receiptsTrie.init(); // All ok with the block generally. Play back the transactions now... unsigned i = 0; for (auto const& tr: RLP(_block)[1]) { + RLPStream k; + k << i; + + RLPStream txrlp; + m_transactions[i].streamRLP(txrlp); + transactionsTrie.insert(&k.out(), tr.data()); + // cnote << m_state.root() << m_state; // cnote << *this; - execute(tr[0].data()); + execute(tr.data()); + + RLPStream receiptrlp; + m_receipts.back().streamRLP(receiptrlp); + receiptsTrie.insert(&k.out(), &receiptrlp.out()); +/* if (tr[1].toHash() != m_state.root()) { // Invalid state root @@ -628,15 +644,20 @@ u256 State::enact(bytesConstRef _block, BlockChain const* _bc, bool _checkNonce) } if (tr[2].toInt() != gasUsed()) BOOST_THROW_EXCEPTION(InvalidTransactionGasUsed()); - bytes k = rlp(i); - transactionManifest.insert(&k, tr.data()); +*/ ++i; } - if (m_currentBlock.transactionsRoot && transactionManifest.root() != m_currentBlock.transactionsRoot) + if (transactionsTrie.root() != m_currentBlock.transactionsRoot) { cwarn << "Bad transactions state root!"; - BOOST_THROW_EXCEPTION(InvalidTransactionStateRoot()); + BOOST_THROW_EXCEPTION(InvalidTransactionsStateRoot()); + } + + if (receiptsTrie.root() != m_currentBlock.receiptsRoot) + { + cwarn << "Bad receipts state root!"; + BOOST_THROW_EXCEPTION(InvalidReceiptsStateRoot()); } // Initialise total difficulty calculation. @@ -877,6 +898,10 @@ MineInfo State::mine(unsigned _msTimeout, bool _turbo) if (!ret.completed) m_currentBytes.clear(); + else + { + cnote << "Completed" << m_currentBlock.headerHashWithoutNonce().abridged() << m_currentBlock.nonce.abridged() << m_currentBlock.difficulty << ProofOfWork::verify(m_currentBlock.headerHashWithoutNonce(), m_currentBlock.nonce, m_currentBlock.difficulty); + } return ret; } diff --git a/libethereum/State.h b/libethereum/State.h index aa241fbef..b32bb6c7c 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -249,6 +249,9 @@ public: /// Get the bloom filter of a particular transaction that happened in the block. TODO: PoC-7: KILL h256 oldBloom(unsigned _i) const { return m_receipts[_i].changes().bloom(); } + /// Get the transaction receipt for the transaction of the given index. + TransactionReceipt const& receipt(unsigned _i) const { return m_receipts[_i]; } + /// Get the list of pending transactions. LogEntries const& log(unsigned _i) const { return m_receipts[_i].log(); } From 5a949f0b016a6e9091beccdd3894e581aeb9523b Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 28 Oct 2014 01:47:38 +0100 Subject: [PATCH 35/41] Facility to check for ids. Less tracing. --- libethcore/BlockInfo.cpp | 1 - libqethereum/QEthereum.h | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/libethcore/BlockInfo.cpp b/libethcore/BlockInfo.cpp index 60c190470..d87e6f5df 100644 --- a/libethcore/BlockInfo.cpp +++ b/libethcore/BlockInfo.cpp @@ -103,7 +103,6 @@ void BlockInfo::populateFromHeader(RLP const& _header, bool _checkNonce) } // check it hashes according to proof of work or that it's the genesis block. - cnote << "Verifying" << headerHashWithoutNonce().abridged() << nonce.abridged() << difficulty; if (_checkNonce && parentHash && !ProofOfWork::verify(headerHashWithoutNonce(), nonce, difficulty)) BOOST_THROW_EXCEPTION(InvalidBlockNonce(headerHashWithoutNonce(), nonce, difficulty)); diff --git a/libqethereum/QEthereum.h b/libqethereum/QEthereum.h index 042b3c081..b27ca84ca 100644 --- a/libqethereum/QEthereum.h +++ b/libqethereum/QEthereum.h @@ -259,6 +259,7 @@ public: Q_INVOKABLE void doPost(QString _json); Q_INVOKABLE QString newIdentity(); + Q_INVOKABLE bool haveIdentity(QString _id) { return m_ids.count(toPublic(_id)); } Q_INVOKABLE QString newGroup(QString _id, QString _who); Q_INVOKABLE QString addToGroup(QString _group, QString _who); From 482e7b639d3a9b89a2de41f2b1a19d7a9e7b2560 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 28 Oct 2014 02:35:46 +0100 Subject: [PATCH 36/41] Version bump, minor fix for badly formatted manual hosts. --- libdevcore/Common.cpp | 2 +- libp2p/Host.cpp | 20 +++++++++++++++----- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/libdevcore/Common.cpp b/libdevcore/Common.cpp index 97c1d32c7..a32125354 100644 --- a/libdevcore/Common.cpp +++ b/libdevcore/Common.cpp @@ -27,7 +27,7 @@ using namespace dev; namespace dev { -char const* Version = "0.7.6"; +char const* Version = "0.7.7"; } diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index 2af4d2808..020c7e420 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -252,17 +252,27 @@ void Host::determinePublic(string const& _publicAddress, bool _upnp) m_public = bi::tcp::endpoint(bi::address(), (unsigned short)p); else { - m_public = bi::tcp::endpoint(bi::address::from_string(_publicAddress.empty() ? eip : _publicAddress), (unsigned short)p); + bi::address adr = 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. - m_public = bi::tcp::endpoint(_publicAddress.size() ? bi::address::from_string(_publicAddress) - : m_peerAddresses.size() ? m_peerAddresses[0] - : bi::address(), m_listenPort); - m_addresses.push_back(m_public.address()); + bi::address adr = m_peerAddresses.size() ? m_peerAddresses[0] : bi::address(); + try + { + adr = bi::address::from_string(_publicAddress); + } + catch (...) {} + m_public = bi::tcp::endpoint(adr, m_listenPort); + m_addresses.push_back(adr); } } From bf493a91993630bac952fe28ffddeb9ab8085785 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 28 Oct 2014 02:51:39 +0100 Subject: [PATCH 37/41] PoC-7: 6. Illegal to jump into pushdata. --- libevm/VM.cpp | 1 + libevm/VM.h | 15 +++++++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/libevm/VM.cpp b/libevm/VM.cpp index e47237d5a..c9bf81c15 100644 --- a/libevm/VM.cpp +++ b/libevm/VM.cpp @@ -29,4 +29,5 @@ void VM::reset(u256 _gas) { m_gas = _gas; m_curPC = 0; + m_jumpDests.reset(); } diff --git a/libevm/VM.h b/libevm/VM.h index e5502b484..e81ddb475 100644 --- a/libevm/VM.h +++ b/libevm/VM.h @@ -84,6 +84,7 @@ private: u256 m_curPC = 0; bytes m_temp; u256s m_stack; + std::set m_jumpDests; }; } @@ -93,6 +94,16 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con { auto memNeed = [](dev::u256 _offset, dev::u256 _size) { return _size ? _offset + _size : 0; }; + if (m_jumpDests.empty()) + { + m_jumpDests.insert(0); + for (unsigned i = 1; i < _ext.code.size(); ++i) + if (_ext.code[i] == (byte)Instruction::JUMPDEST) + m_jumpDests.insert(i + 1); + else if (_ext.code[i] >= (byte)Instruction::PUSH1 && _ext.code[i] <= (byte)Instruction::PUSH32) + i += _ext.code[i] - (int)Instruction::PUSH1 + 1; + } + u256 nextPC = m_curPC + 1; auto osteps = _steps; for (bool stopped = false; !stopped && _steps--; m_curPC = nextPC, nextPC = m_curPC + 1) @@ -678,7 +689,7 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con break; case Instruction::JUMP: nextPC = m_stack.back(); - if (nextPC && (Instruction)_ext.getCode(nextPC - 1) != Instruction::JUMPDEST) + if (!m_jumpDests.count((unsigned)nextPC)) BOOST_THROW_EXCEPTION(BadJumpDestination()); m_stack.pop_back(); break; @@ -686,7 +697,7 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con if (m_stack[m_stack.size() - 2]) { nextPC = m_stack.back(); - if (nextPC && (Instruction)_ext.getCode(nextPC - 1) != Instruction::JUMPDEST) + if (!m_jumpDests.count((unsigned)nextPC)) BOOST_THROW_EXCEPTION(BadJumpDestination()); } m_stack.pop_back(); From 0053ae05204ea97764c6795f643256d5958cddb7 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 28 Oct 2014 02:51:56 +0100 Subject: [PATCH 38/41] Build fix. --- libevm/VM.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libevm/VM.cpp b/libevm/VM.cpp index c9bf81c15..bded9a10d 100644 --- a/libevm/VM.cpp +++ b/libevm/VM.cpp @@ -29,5 +29,5 @@ void VM::reset(u256 _gas) { m_gas = _gas; m_curPC = 0; - m_jumpDests.reset(); + m_jumpDests.clear(); } From 67ed69d59b9e7f49f528975e035a7f2a6d9d9185 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 28 Oct 2014 13:43:33 +0100 Subject: [PATCH 39/41] PoC-7: Latest SIGNEXTEND. --- libevm/VM.h | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/libevm/VM.h b/libevm/VM.h index e81ddb475..774667902 100644 --- a/libevm/VM.h +++ b/libevm/VM.h @@ -449,18 +449,13 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con break; case Instruction::SIGNEXTEND: { - unsigned k = m_stack[m_stack.size() - 2]; - if (k > 31) - m_stack[m_stack.size() - 2] = m_stack.back(); - else - { - u256 b = m_stack.back(); + unsigned k = m_stack.back(); + m_stack.pop_back(); + auto& b = m_stack.back(); + if (k <= 31) if ((b >> (k * 8)) & 0x80) for (int i = 31; i > k; --i) b |= (u256(0xff) << i); - m_stack[m_stack.size() - 2] = b; - } - m_stack.pop_back(); break; } case Instruction::SHA3: From 7b681b091365b138a4a9665dd4dc28c6c34ee56f Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Tue, 28 Oct 2014 15:05:38 +0100 Subject: [PATCH 40/41] fix for compiling under llvm --- libdevcore/FixedHash.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libdevcore/FixedHash.h b/libdevcore/FixedHash.h index 284745c64..41d140cad 100644 --- a/libdevcore/FixedHash.h +++ b/libdevcore/FixedHash.h @@ -158,7 +158,7 @@ public: return ret; } - template inline FixedHash& shiftBloom(FixedHash const& _h) { return (*this |= _h.nbloom()); } + template inline FixedHash& shiftBloom(FixedHash const& _h) { return (*this |= _h.template nbloom()); } template inline FixedHash nbloom() const { From e17e240b5dfc033e14c8e91122ef5522c293e28c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 28 Oct 2014 16:26:33 +0100 Subject: [PATCH 41/41] Fix VM test code loading conditions --- test/vm.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/vm.cpp b/test/vm.cpp index 40a0a862b..d69f03fda 100644 --- a/test/vm.cpp +++ b/test/vm.cpp @@ -359,9 +359,9 @@ void FakeExtVM::importExec(mObject& _o) code = &thisTxCode; if (_o["code"].type() == str_type) if (_o["code"].get_str().find_first_of("0x") == 0) - thisTxCode = compileLLL(_o["code"].get_str()); - else thisTxCode = fromHex(_o["code"].get_str().substr(2)); + else + thisTxCode = compileLLL(_o["code"].get_str()); else if (_o["code"].type() == array_type) for (auto const& j: _o["code"].get_array()) thisTxCode.push_back(toByte(j));