From e1e2fd79ad684e542aa5bd5e58567d3eda66d0f6 Mon Sep 17 00:00:00 2001 From: Christoph Jentzsch Date: Wed, 22 Oct 2014 22:13:08 +0200 Subject: [PATCH 1/4] bug fix --- test/vm.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/test/vm.cpp b/test/vm.cpp index f74076399..36837eea4 100644 --- a/test/vm.cpp +++ b/test/vm.cpp @@ -512,12 +512,10 @@ void doTests(json_spirit::mValue& v, bool _fillin) } bytes output; - u256 gas; + VM vm(fev.gas); try { - VM vm(fev.gas); output = vm.go(fev).toVector(); - gas = vm.gas(); // Get the remaining gas } catch (Exception const& _e) { @@ -554,7 +552,7 @@ void doTests(json_spirit::mValue& v, bool _fillin) o["post"] = mValue(fev.exportState()); o["callcreates"] = fev.exportCallCreates(); o["out"] = "0x" + toHex(output); - fev.push(o, "gas", gas); + fev.push(o, "gas", vm.gas()); } else { @@ -578,7 +576,7 @@ void doTests(json_spirit::mValue& v, bool _fillin) else BOOST_CHECK(output == fromHex(o["out"].get_str())); - BOOST_CHECK_EQUAL(test.toInt(o["gas"]), gas); + BOOST_CHECK_EQUAL(test.toInt(o["gas"]), vm.gas()); auto& expectedAddrs = test.addresses; auto& resultAddrs = fev.addresses; @@ -657,11 +655,13 @@ void executeTests(const string& _name) if (ptestPath == NULL) { cnote << " could not find environment variable ETHEREUM_TEST_PATH \n"; - testPath = "../../../tests/vmtests"; + testPath = "../../../tests"; } else testPath = ptestPath; + testPath += "/vmtests"; + #ifdef FILL_TESTS try { @@ -690,7 +690,7 @@ void executeTests(const string& _name) cnote << "Testing VM..." << _name; json_spirit::mValue v; string s = asString(contents(testPath + "/" + _name + ".json")); - BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of " + _name + ".json is empty. Have you cloned the 'tests' repo branch develop and set ETHEREUM_TEST_PATH to its path?"); + BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of " + testPath + "/" + _name + ".json is empty. Have you cloned the 'tests' repo branch develop and set ETHEREUM_TEST_PATH to its path?"); json_spirit::read_string(s, v); dev::test::doTests(v, false); } From e14416d96a59053e14c8292240deb0cda533286d Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 23 Oct 2014 01:59:31 +0200 Subject: [PATCH 2/4] web3, web3.eth, web3.shh for the JS API. Following up on Whisper for the dream C++ API. Crpyto stubs in ready for Alex. stdserv.js updated to latest. --- exp/main.cpp | 6 +-- libdevcore/FixedHash.h | 16 ++++++ libdevcrypto/Common.cpp | 61 +++++++++++++++++++++++ libdevcrypto/Common.h | 20 ++++++-- libethcore/All.h | 1 - libethereum/Transaction.cpp | 72 +++------------------------ libethereum/Transaction.h | 9 +--- libqethereum/QEthereum.cpp | 9 ++-- libqethereum/QEthereum.h | 30 ++++++------ libwhisper/Interface.cpp | 4 +- libwhisper/Interface.h | 27 ++++++----- libwhisper/Message.cpp | 97 +++++++++++++++++++++++++++++++++++++ libwhisper/Message.h | 91 ++++++++++++++++++++++++++++------ libwhisper/WhisperHost.cpp | 6 +-- libwhisper/WhisperHost.h | 10 ++-- libwhisper/WhisperPeer.cpp | 2 +- stdserv.js | 14 +++--- 17 files changed, 332 insertions(+), 143 deletions(-) diff --git a/exp/main.cpp b/exp/main.cpp index 9ee26644c..30ef36408 100644 --- a/exp/main.cpp +++ b/exp/main.cpp @@ -104,14 +104,14 @@ int main(int argc, char** argv) ph.connect(remoteHost, remotePort); /// Only interested in the packet if the lowest bit is 1 - auto w = wh->installWatch(MessageFilter(TopicMasks({{Topic("0000000000000000000000000000000000000000000000000000000000000001"), Topic("0000000000000000000000000000000000000000000000000000000000000001")}}))); + auto w = wh->installWatch(TopicFilter(TopicMasks({{Topic("0000000000000000000000000000000000000000000000000000000000000001"), Topic("0000000000000000000000000000000000000000000000000000000000000001")}}))); for (int i = 0; ; ++i) { - wh->sendRaw(RLPStream().append(i * i).out(), Topic(u256(i)), 1000); + wh->sendRaw(RLPStream().append(i * i).out(), Topic(u256(i))); for (auto i: wh->checkWatch(w)) { - auto p = wh->message(i).payload; + auto p = wh->envelope(i).open().payload(); cnote << "New message:" << RLP(p).toInt(); } } diff --git a/libdevcore/FixedHash.h b/libdevcore/FixedHash.h index 36b10d0bf..c8d250b35 100644 --- a/libdevcore/FixedHash.h +++ b/libdevcore/FixedHash.h @@ -158,6 +158,21 @@ public: return ret; } + /// Returns the index of the first bit set to one, or size() * 8 if no bits are set. + inline unsigned firstBitSet() const + { + unsigned ret = 0; + for (auto d: m_data) + if (d) + for (;; ++ret, d <<= 1) + if (d & 0x80) + return ret; + else {} + else + ret += 8; + return ret; + } + private: std::array m_data; ///< The binary data. }; @@ -193,6 +208,7 @@ inline std::ostream& operator<<(std::ostream& _out, FixedHash const& _h) } // Common types of FixedHash. +using h520 = FixedHash<65>; using h512 = FixedHash<64>; using h256 = FixedHash<32>; using h160 = FixedHash<20>; diff --git a/libdevcrypto/Common.cpp b/libdevcrypto/Common.cpp index a9fff83c4..482a63cfc 100644 --- a/libdevcrypto/Common.cpp +++ b/libdevcrypto/Common.cpp @@ -108,3 +108,64 @@ KeyPair KeyPair::fromEncryptedSeed(bytesConstRef _seed, std::string const& _pass return KeyPair(sha3(aesDecrypt(_seed, _password))); } +void dev::encrypt(Public _k, bytesConstRef _plain, bytes& _cipher) +{ + (void)_k; + _cipher = _plain.toBytes(); +} + +bool dev::decrypt(Secret _k, bytesConstRef _cipher, bytes& _plain) +{ + (void)_k; + _plain = _cipher.toBytes(); + return true; +} + +Public dev::recover(Signature _sig, h256 _message) +{ + secp256k1_start(); + + byte pubkey[65]; + int pubkeylen = 65; + if (!secp256k1_ecdsa_recover_compact(_message.data(), 32, _sig.data(), pubkey, &pubkeylen, 0, (int)_sig[64])) + return Public(); + + // right160(dev::sha3(bytesConstRef(&(pubkey[1]), 64))); +#if ETH_CRYPTO_TRACE + h256* sig = (h256 const*)_sig.data(); + cout << "---- RECOVER -------------------------------" << endl; + cout << "MSG: " << _message << endl; + cout << "R S V: " << sig[0] << " " << sig[1] << " " << (int)(_sig[64] - 27) << "+27" << endl; + cout << "PUB: " << toHex(bytesConstRef(&(pubkey[1]), 64)) << endl; +#endif + + return *(Public const*)&(pubkey[1]); +} + +inline h256 kFromMessage(h256 _msg, h256 _priv) +{ + return _msg ^ _priv; +} + +Signature dev::sign(Secret _k, h256 _message) +{ + int v = 0; + + secp256k1_start(); + + SignatureStruct ret; + h256 nonce = kFromMessage(_message, _k); + + if (!secp256k1_ecdsa_sign_compact(_message.data(), 32, ret.r.data(), _k.data(), nonce.data(), &v)) + return Signature(); +#if ETH_ADDRESS_DEBUG + cout << "---- SIGN -------------------------------" << endl; + cout << "MSG: " << _message << endl; + cout << "SEC: " << _k << endl; + cout << "NON: " << nonce << endl; + cout << "R S V: " << ret.r << " " << ret.s << " " << v << "+27" << endl; +#endif + + ret.v = v; + return *(Signature const*)&ret; +} diff --git a/libdevcrypto/Common.h b/libdevcrypto/Common.h index d55bab51d..9d642201a 100644 --- a/libdevcrypto/Common.h +++ b/libdevcrypto/Common.h @@ -37,6 +37,12 @@ using Secret = h256; /// @NOTE This is not endian-specific; it's just a bunch of bytes. using Public = h512; +/// A signature: 65 bytes: r: [0, 32), s: [32, 64), v: 64. +/// @NOTE This is not endian-specific; it's just a bunch of bytes. +using Signature = h520; + +struct SignatureStruct { h256 r; h256 s; byte v; }; + /// An Ethereum address: 20 bytes. /// @NOTE This is not endian-specific; it's just a bunch of bytes. using Address = h160; @@ -44,9 +50,17 @@ using Address = h160; /// A vector of Ethereum addresses. using Addresses = h160s; -/// Convert a private key into the public key equivalent. -/// @returns 0 if it's not a valid private key. -Address toAddress(h256 _private); +/// A vector of secrets. +using Secrets = h256s; + +/// Convert a secret key into the public key equivalent. +/// @returns 0 if it's not a valid secret key. +Address toAddress(Secret _secret); + +void encrypt(Public _k, bytesConstRef _plain, bytes& o_cipher); +bool decrypt(Secret _k, bytesConstRef _cipher, bytes& o_plain); +Public recover(Signature _sig, h256 _message); +Signature sign(Secret _k, h256 _message); /// Simple class that represents a "key pair". /// All of the data of the class can be regenerated from the secret key (m_secret) alone. diff --git a/libethcore/All.h b/libethcore/All.h index 7a1ca8f51..cb1d3f5a3 100644 --- a/libethcore/All.h +++ b/libethcore/All.h @@ -3,6 +3,5 @@ #include "BlockInfo.h" #include "CommonEth.h" #include "ProofOfWork.h" -#include "CryptoHeaders.h" #include "Exceptions.h" diff --git a/libethereum/Transaction.cpp b/libethereum/Transaction.cpp index bc8423bb1..16b0f9614 100644 --- a/libethereum/Transaction.cpp +++ b/libethereum/Transaction.cpp @@ -19,9 +19,9 @@ * @date 2014 */ -#include #include #include +#include #include #include "Transaction.h" using namespace std; @@ -42,7 +42,7 @@ Transaction::Transaction(bytesConstRef _rlpData, bool _checkSender) receiveAddress = rlp[field = 3].toHash
(); value = rlp[field = 4].toInt(); data = rlp[field = 5].toBytes(); - vrs = Signature{ rlp[field = 6].toInt(), rlp[field = 7].toInt(), rlp[field = 8].toInt() }; + vrs = SignatureStruct{ rlp[field = 7].toInt(), rlp[field = 8].toInt(), byte(rlp[field = 6].toInt() - 27) }; if (_checkSender) m_sender = sender(); } @@ -70,53 +70,18 @@ Address Transaction::sender() const { if (!m_sender) { - secp256k1_start(); - - h256 sig[2] = { vrs.r, vrs.s }; - h256 msg = sha3(false); - - byte pubkey[65]; - int pubkeylen = 65; - if (!secp256k1_ecdsa_recover_compact(msg.data(), 32, sig[0].data(), pubkey, &pubkeylen, 0, (int)vrs.v - 27)) + auto p = recover(*(Signature const*)&vrs, sha3(false)); + if (!p) BOOST_THROW_EXCEPTION(InvalidSignature()); - - // TODO: check right160 is correct and shouldn't be left160. - m_sender = right160(dev::sha3(bytesConstRef(&(pubkey[1]), 64))); - -#if ETH_ADDRESS_DEBUG - cout << "---- RECOVER -------------------------------" << endl; - cout << "MSG: " << msg << endl; - cout << "R S V: " << sig[0] << " " << sig[1] << " " << (int)(vrs.v - 27) << "+27" << endl; - cout << "PUB: " << toHex(bytesConstRef(&(pubkey[1]), 64)) << endl; - cout << "ADR: " << m_sender << endl; -#endif + m_sender = right160(dev::sha3(bytesConstRef(p.data(), sizeof(p)))); } return m_sender; } void Transaction::sign(Secret _priv) { - int v = 0; - - secp256k1_start(); - - h256 msg = sha3(false); - h256 sig[2]; - h256 nonce = kFromMessage(msg, _priv); - - if (!secp256k1_ecdsa_sign_compact(msg.data(), 32, sig[0].data(), _priv.data(), nonce.data(), &v)) - BOOST_THROW_EXCEPTION(InvalidSignature()); -#if ETH_ADDRESS_DEBUG - cout << "---- SIGN -------------------------------" << endl; - cout << "MSG: " << msg << endl; - cout << "SEC: " << _priv << endl; - cout << "NON: " << nonce << endl; - cout << "R S V: " << sig[0] << " " << sig[1] << " " << v << "+27" << endl; -#endif - - vrs.v = (byte)(v + 27); - vrs.r = (u256)sig[0]; - vrs.s = (u256)sig[1]; + auto sig = dev::sign(_priv, sha3(false)); + vrs = *(SignatureStruct const*)&sig; } void Transaction::fillStream(RLPStream& _s, bool _sig) const @@ -129,26 +94,5 @@ void Transaction::fillStream(RLPStream& _s, bool _sig) const _s << ""; _s << value << data; if (_sig) - _s << vrs.v << vrs.r << vrs.s; -} - -// If the h256 return is an integer, store it in bigendian (i.e. u256 ret; ... return (h256)ret; ) -h256 Transaction::kFromMessage(h256 _msg, h256 _priv) -{ - // TODO! -// bytes v(32, 1); -// bytes k(32, 0); - /* - v = '\x01' * 32 - k = '\x00' * 32 - priv = encode_privkey(priv,'bin') - msghash = encode(hash_to_int(msghash),256,32) - k = hmac.new(k, v+'\x00'+priv+msghash, hashlib.sha256).digest() - v = hmac.new(k, v, hashlib.sha256).digest() - k = hmac.new(k, v+'\x01'+priv+msghash, hashlib.sha256).digest() - v = hmac.new(k, v, hashlib.sha256).digest() - return decode(hmac.new(k, v, hashlib.sha256).digest(),256) - */ - return _msg ^ _priv; + _s << (vrs.v + 27) << (u256)vrs.r << (u256)vrs.s; } - diff --git a/libethereum/Transaction.h b/libethereum/Transaction.h index ecfbe24f0..eb40c5fcb 100644 --- a/libethereum/Transaction.h +++ b/libethereum/Transaction.h @@ -30,13 +30,6 @@ namespace dev namespace eth { -struct Signature -{ - byte v; - u256 r; - u256 s; -}; - struct Transaction { Transaction() {} @@ -54,7 +47,7 @@ struct Transaction bytes data; ///< The data associated with the transaction, or the initialiser if it's a creation transaction. - Signature vrs; ///< The signature of the transaction. Encodes the sender. + SignatureStruct vrs; ///< The signature of the transaction. Encodes the sender. Address safeSender() const noexcept; ///< Like sender() but will never throw. Address sender() const; ///< Determine the sender of the transaction from the signature (and hash). diff --git a/libqethereum/QEthereum.cpp b/libqethereum/QEthereum.cpp index 197b5052f..267fed35e 100644 --- a/libqethereum/QEthereum.cpp +++ b/libqethereum/QEthereum.cpp @@ -448,11 +448,10 @@ QString QEthereum::doTransact(QString _json) TransactionSkeleton t = toTransaction(_json); if (!t.from && m_accounts.size()) { - auto b = m_accounts.begin()->first; + u256 b = 0; for (auto a: m_accounts) - if (client()->balanceAt(a.first) > client()->balanceAt(b)) - b = a.first; - t.from = b; + if (client()->balanceAt(a.first) > b) + t.from = a.first, b = client()->balanceAt(a.first); } if (!m_accounts.count(t.from)) return QString(); @@ -466,7 +465,7 @@ QString QEthereum::doTransact(QString _json) // TODO: insert validification hook here. client()->transact(m_accounts[t.from].secret(), t.value, t.to, t.data, t.gas, t.gasPrice); else - ret = toQJS(client()->transact(t.from, t.value, t.data, t.gas, t.gasPrice)); + ret = toQJS(client()->transact(m_accounts[t.from].secret(), t.value, t.data, t.gas, t.gasPrice)); client()->flushTransactions(); return ret; } diff --git a/libqethereum/QEthereum.h b/libqethereum/QEthereum.h index f7b978e4b..2d6ea8b4c 100644 --- a/libqethereum/QEthereum.h +++ b/libqethereum/QEthereum.h @@ -248,28 +248,30 @@ private: }; // TODO: add p2p object -#define QETH_INSTALL_JS_NAMESPACE(_frame, _env, _dev, _eth, _shh) [_frame, _env, _dev, _eth, _shh]() \ +#define QETH_INSTALL_JS_NAMESPACE(_frame, _env, _web3, _eth, _shh) [_frame, _env, _web3, _eth, _shh]() \ { \ _frame->disconnect(); \ _frame->addToJavaScriptWindowObject("env", _env, QWebFrame::QtOwnership); \ - _frame->addToJavaScriptWindowObject("dev", _dev, QWebFrame::ScriptOwnership); \ + _frame->addToJavaScriptWindowObject("web3", _web3, QWebFrame::ScriptOwnership); \ if (_eth) \ { \ - _frame->addToJavaScriptWindowObject("eth", _eth, QWebFrame::ScriptOwnership); \ - _frame->evaluateJavaScript("eth.makeWatch = function(a) { var ww = eth.newWatch(a); var ret = { w: ww }; ret.uninstall = function() { eth.killWatch(w); }; ret.changed = function(f) { eth.watchChanged.connect(function(nw) { if (nw == ww) f() }); }; ret.messages = function() { return JSON.parse(eth.watchMessages(this.w)) }; return ret; }"); \ - _frame->evaluateJavaScript("eth.watch = function(a) { return eth.makeWatch(JSON.stringify(a)) }"); \ - _frame->evaluateJavaScript("eth.transact = function(a, f) { var r = eth.doTransact(JSON.stringify(a)); if (f) f(r); }"); \ - _frame->evaluateJavaScript("eth.call = function(a, f) { var ret = eth.doCallJson(JSON.stringify(a)); if (f) f(ret); return ret; }"); \ - _frame->evaluateJavaScript("eth.messages = function(a) { return JSON.parse(eth.getMessages(JSON.stringify(a))); }"); \ - _frame->evaluateJavaScript("eth.block = function(a) { return JSON.parse(eth.getBlock(a)); }"); \ - _frame->evaluateJavaScript("eth.transaction = function(a) { return JSON.parse(eth.getTransaction(a)); }"); \ - _frame->evaluateJavaScript("eth.uncle = function(a) { return JSON.parse(eth.getUncle(a)); }"); \ + _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.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; }"); \ + _frame->evaluateJavaScript("_web3_dot_eth.messages = function(a) { return JSON.parse(_web3_dot_eth.getMessages(JSON.stringify(a))); }"); \ + _frame->evaluateJavaScript("_web3_dot_eth.block = function(a) { return JSON.parse(_web3_dot_eth.getBlock(a)); }"); \ + _frame->evaluateJavaScript("_web3_dot_eth.transaction = function(a) { return JSON.parse(_web3_dot_eth.getTransaction(a)); }"); \ + _frame->evaluateJavaScript("_web3_dot_eth.uncle = function(a) { return JSON.parse(_web3_dot_eth.getUncle(a)); }"); \ + _frame->evaluateJavaScript("web3.eth = _web3_dot_eth"); \ } \ if (_shh) \ { \ - _frame->addToJavaScriptWindowObject("shh", _shh, QWebFrame::ScriptOwnership); \ - _frame->evaluateJavaScript("shh.makeWatch = function(a) { var ww = shh.newWatch(a); var ret = { w: ww }; ret.uninstall = function() { shh.killWatch(w); }; ret.changed = function(f) { shh.watchChanged.connect(function(nw) { if (nw == ww) f() }); }; ret.messages = function() { return JSON.parse(shh.watchMessages(this.w)) }; return ret; }"); \ - _frame->evaluateJavaScript("shh.watch = function(a) { return shh.makeWatch(JSON.stringify(a)) }"); \ + _frame->addToJavaScriptWindowObject("_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.shh = _web3_dot_shh"); \ } \ } diff --git a/libwhisper/Interface.cpp b/libwhisper/Interface.cpp index beab00f3c..9b6815f0d 100644 --- a/libwhisper/Interface.cpp +++ b/libwhisper/Interface.cpp @@ -34,10 +34,10 @@ using namespace dev::shh; #endif #define clogS(X) dev::LogOutputStream(false) << "| " << std::setw(2) << session()->socketId() << "] " -bool MessageFilter::matches(Message const& _m) const +bool TopicFilter::matches(Envelope const& _e) const { for (TopicMask const& t: m_topicMasks) - if (((t.first ^ _m.topic) & t.second) == 0) + if (((t.first ^ _e.topic()) & t.second) == 0) return true; return false; } diff --git a/libwhisper/Interface.h b/libwhisper/Interface.h index 6bed02977..fda070263 100644 --- a/libwhisper/Interface.h +++ b/libwhisper/Interface.h @@ -46,17 +46,17 @@ namespace shh using TopicMask = std::pair; using TopicMasks = std::vector; -class MessageFilter +class TopicFilter { public: - MessageFilter() {} - MessageFilter(TopicMasks const& _m): m_topicMasks(_m) {} - MessageFilter(RLP const& _r): m_topicMasks((TopicMasks)_r) {} + TopicFilter() {} + TopicFilter(TopicMasks const& _m): m_topicMasks(_m) {} + TopicFilter(RLP const& _r): m_topicMasks((TopicMasks)_r) {} void fillStream(RLPStream& _s) const { _s << m_topicMasks; } h256 sha3() const { RLPStream s; fillStream(s); return dev::sha3(s.out()); } - bool matches(Message const& _m) const; + bool matches(Envelope const& _m) const; private: TopicMasks m_topicMasks; @@ -64,9 +64,9 @@ private: struct InstalledFilter { - InstalledFilter(MessageFilter const& _f): filter(_f) {} + InstalledFilter(TopicFilter const& _f): filter(_f) {} - MessageFilter filter; + TopicFilter filter; unsigned refCount = 1; }; @@ -84,17 +84,20 @@ class Interface public: virtual ~Interface() {} - virtual void inject(Message const& _m, WhisperPeer* _from = nullptr) = 0; + virtual void inject(Envelope const& _m, WhisperPeer* _from = nullptr) = 0; - virtual unsigned installWatch(MessageFilter const& _filter) = 0; + virtual unsigned installWatch(TopicFilter const& _filter) = 0; virtual unsigned installWatch(h256 _filterId) = 0; virtual void uninstallWatch(unsigned _watchId) = 0; virtual h256s peekWatch(unsigned _watchId) const = 0; virtual h256s checkWatch(unsigned _watchId) = 0; - virtual Message message(h256 _m) const = 0; + virtual Envelope envelope(h256 _m) const = 0; - virtual void sendRaw(bytes const& _payload, h256 _topic, unsigned _ttl) = 0; + void sendRaw(bytes const& _payload, Topic _topic, unsigned _ttl = 50, unsigned _workToProve = 50) { inject(Message(_payload).seal(_topic, _ttl, _workToProve)); } + void sendRaw(Public _to, bytes const& _payload, Topic _topic, unsigned _ttl = 50, unsigned _workToProve = 50) { inject(Message(_payload).seal(_to, _topic, _ttl, _workToProve)); } + void sendRaw(Secret _from, bytes const& _payload, Topic _topic, unsigned _ttl = 50, unsigned _workToProve = 50) { inject(Message(_payload).seal(_from, _topic, _ttl, _workToProve)); } + void sendRaw(Secret _from, Public _to, bytes const& _payload, Topic _topic, unsigned _ttl = 50, unsigned _workToProve = 50) { inject(Message(_payload).seal(_from, _to, _topic, _ttl, _workToProve)); } }; struct WatshhChannel: public dev::LogChannel { static const char* name() { return "shh"; } static const int verbosity = 1; }; @@ -115,7 +118,7 @@ class Watch: public boost::noncopyable public: Watch() {} Watch(Whisper& _c, h256 _f): m_c(&_c), m_id(_c.installWatch(_f)) {} - Watch(Whisper& _c, MessageFilter const& _tf): m_c(&_c), m_id(_c.installWatch(_tf)) {} + Watch(Whisper& _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; } diff --git a/libwhisper/Message.cpp b/libwhisper/Message.cpp index 8a3b8f435..04f510917 100644 --- a/libwhisper/Message.cpp +++ b/libwhisper/Message.cpp @@ -25,3 +25,100 @@ using namespace std; using namespace dev; using namespace dev::p2p; using namespace dev::shh; + +Message::Message(Envelope const& _e, Secret const& _s) +{ + try + { + bytes b; + if (_s) + decrypt(_s, &(_e.data()), b); + populate(_s ? b : _e.data()); + m_to = KeyPair(_s).pub(); + } + catch (...) // Invalid secret? TODO: replace ... with InvalidSecret + { + } +} + +void Message::populate(bytes const& _data) +{ + if (!_data.size()) + return; + + byte flags = _data[0]; + if (!!(flags & ContainsSignature) && _data.size() > sizeof(Signature) + 1) // has a signature + { + bytesConstRef payload = bytesConstRef(&_data).cropped(sizeof(Signature) + 1); + h256 h = sha3(payload); + m_from = recover(*(Signature const*)&(_data[1]), h); + m_payload = payload.toBytes(); + } + else + m_payload = bytesConstRef(&_data).cropped(1).toBytes(); +} + +Envelope Message::seal(Secret _from, Topic const& _topic, unsigned _ttl, unsigned _workToProve) +{ + Envelope ret(time(0) + _ttl, _ttl, _topic); + + bytes input(1 + m_payload.size()); + input[0] = 0; + memcpy(input.data() + 1, m_payload.data(), m_payload.size()); + + if (_from) // needs a sig + { + input.resize(1 + m_payload.size() + sizeof(Signature)); + input[0] |= ContainsSignature; + *(Signature*)&(input[1 + m_payload.size()]) = sign(_from, sha3(m_payload)); + } + + if (m_to) + encrypt(m_to, &input, ret.m_data); + else + swap(ret.m_data, input); + + ret.proveWork(_workToProve); + return ret; +} + +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]; + d[0] = sha3NoNonce(); + d[1] = m_nonce; + return dev::sha3(bytesConstRef(d[0].data(), 64)).firstBitSet(); +} + +void Envelope::proveWork(unsigned _ms) +{ + // PoW + h256 d[2]; + d[0] = sha3NoNonce(); + uint32_t& n = *(uint32_t*)&(d[1][30]); + unsigned bestBitSet = 0; + bytesConstRef chuck(d[0].data(), 64); + + chrono::high_resolution_clock::time_point then = chrono::high_resolution_clock::now() + chrono::milliseconds(_ms); + for (n = 0; chrono::high_resolution_clock::now() < then; ) + // do it rounds of 1024 for efficiency + for (unsigned i = 0; i < 1024; ++i, ++n) + { + auto fbs = dev::sha3(chuck).firstBitSet(); + if (fbs > bestBitSet) + { + bestBitSet = fbs; + m_nonce = n; + } + } +} diff --git a/libwhisper/Message.h b/libwhisper/Message.h index 9bc36c6a2..cbe6355be 100644 --- a/libwhisper/Message.h +++ b/libwhisper/Message.h @@ -36,27 +36,88 @@ namespace dev namespace shh { -struct Message +class Message; + +class Envelope { - unsigned expiry = 0; - unsigned ttl = 0; - Topic topic; // TODO: change to h256 - bytes payload; + friend class Message; - Message() {} - Message(unsigned _exp, unsigned _ttl, Topic const& _topic, bytes const& _payload): expiry(_exp), ttl(_ttl), topic(_topic), payload(_payload) {} - Message(RLP const& _m) +public: + Envelope() {} + Envelope(RLP const& _m) { - expiry = _m[0].toInt(); - ttl = _m[1].toInt(); - topic = (Topic)_m[2]; - payload = _m[3].toBytes(); + m_expiry = _m[0].toInt(); + m_ttl = _m[1].toInt(); + m_topic = (Topic)_m[2]; + m_data = _m[3].toBytes(); } - operator bool () const { return !!expiry; } + 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()); } + + unsigned sent() const { return m_expiry - m_ttl; } + unsigned expiry() const { return m_expiry; } + unsigned ttl() const { return m_ttl; } + Topic const& topic() const { return m_topic; } + bytes const& data() const { return m_data; } + + Message open(Secret const& _s) const; + Message open() const; + + unsigned workProved() const; + void proveWork(unsigned _ms); + +private: + Envelope(unsigned _exp, unsigned _ttl, Topic const& _topic): m_expiry(_exp), m_ttl(_ttl), m_topic(_topic) {} + + unsigned m_expiry = 0; + unsigned m_ttl = 0; + u256 m_nonce; + + Topic m_topic; + bytes m_data; +}; + +enum /*Message Flags*/ +{ + ContainsSignature = 0 +}; + +/// An (unencrypted) message, constructed from the combination of an Envelope, and, potentially, +/// a Secret key to decrypt the Message. +class Message +{ +public: + Message() {} + Message(Envelope const& _e, Secret const& _s = Secret()); + Message(bytes const& _payload): m_payload(_payload) {} + Message(bytesConstRef _payload): m_payload(_payload.toBytes()) {} + Message(bytes&& _payload) { std::swap(_payload, m_payload); } + + Public from() const { return m_from; } + Public to() const { return m_to; } + bytes const& payload() const { return m_payload; } + + void setTo(Public _to) { m_to = _to; } + + 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); + // 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); } + +private: + void populate(bytes const& _data); - void streamOut(RLPStream& _s) const { _s.appendList(4) << expiry << ttl << topic << payload; } - h256 sha3() const { RLPStream s; streamOut(s); return dev::sha3(s.out()); } + Public m_from; + Public m_to; + bytes m_payload; }; } diff --git a/libwhisper/WhisperHost.cpp b/libwhisper/WhisperHost.cpp index 8ed88bca8..2f3a21d3e 100644 --- a/libwhisper/WhisperHost.cpp +++ b/libwhisper/WhisperHost.cpp @@ -47,11 +47,11 @@ void WhisperHost::streamMessage(h256 _m, RLPStream& _s) const if (m_messages.count(_m)) { UpgradeGuard ll(l); - m_messages.at(_m).streamOut(_s); + m_messages.at(_m).streamOut(_s, true); } } -void WhisperHost::inject(Message const& _m, WhisperPeer* _p) +void WhisperHost::inject(Envelope const& _m, WhisperPeer* _p) { auto h = _m.sha3(); { @@ -95,7 +95,7 @@ unsigned WhisperHost::installWatch(h256 _h) return ret; } -unsigned WhisperHost::installWatch(shh::MessageFilter const& _f) +unsigned WhisperHost::installWatch(shh::TopicFilter const& _f) { Guard l(m_filterLock); diff --git a/libwhisper/WhisperHost.h b/libwhisper/WhisperHost.h index 081be20a1..cd6746c24 100644 --- a/libwhisper/WhisperHost.h +++ b/libwhisper/WhisperHost.h @@ -48,17 +48,15 @@ public: unsigned protocolVersion() const { return 0; } - virtual void inject(Message const& _m, WhisperPeer* _from = nullptr); + virtual void inject(Envelope const& _e, WhisperPeer* _from = nullptr); - virtual unsigned installWatch(MessageFilter const& _filter); + virtual unsigned installWatch(TopicFilter const& _filter); virtual unsigned installWatch(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 Message message(h256 _m) const { try { dev::ReadGuard l(x_messages); return m_messages.at(_m); } catch (...) { return Message(); } } - - virtual void sendRaw(bytes const& _payload, Topic _topic, unsigned _ttl) { inject(Message(time(0) + _ttl, _ttl, _topic, _payload)); } + virtual Envelope envelope(h256 _m) const { try { dev::ReadGuard l(x_messages); return m_messages.at(_m); } catch (...) { return Envelope(); } } private: void streamMessage(h256 _m, RLPStream& _s) const; @@ -66,7 +64,7 @@ private: void noteChanged(h256 _messageHash, h256 _filter); mutable dev::SharedMutex x_messages; - std::map m_messages; + std::map m_messages; mutable dev::Mutex m_filterLock; std::map m_filters; diff --git a/libwhisper/WhisperPeer.cpp b/libwhisper/WhisperPeer.cpp index a8e72a40e..58f9a4cf4 100644 --- a/libwhisper/WhisperPeer.cpp +++ b/libwhisper/WhisperPeer.cpp @@ -71,7 +71,7 @@ bool WhisperPeer::interpret(unsigned _id, RLP const& _r) unsigned n = 0; for (auto i: _r) if (n++) - host()->inject(Message(i), this); + host()->inject(Envelope(i), this); sendMessages(); break; } diff --git a/stdserv.js b/stdserv.js index b6f6a2acd..68d33ddd9 100644 --- a/stdserv.js +++ b/stdserv.js @@ -1,3 +1,5 @@ +eth = web3.eth; + env.note('Creating Config...') var configCode = eth.lll(" { @@ -277,25 +279,25 @@ eth.transact({ 'to': config, 'data': ['3', exchange] }); env.note('Register my name...') -eth.transact({ 'to': nameReg, 'data': [ eth.fromAscii('register'), eth.fromAscii('Gav') ] }); +eth.transact({ 'to': nameReg, 'data': [ web3.fromAscii('register'), web3.fromAscii('Gav') ] }); env.note('Dole out ETH to other address...') eth.transact({ 'value': '100000000000000000000', 'to': eth.accounts[1] }); env.note('Register my other name...') -eth.transact({ 'from': eth.keys[1], 'to': nameReg, 'data': [ eth.fromAscii('register'), eth.fromAscii("Gav Would") ] }); +eth.transact({ 'from': eth.keys[1], 'to': nameReg, 'data': [ web3.fromAscii('register'), web3.fromAscii("Gav Would") ] }); env.note('Approve Exchange...') -eth.transact({ 'to': gavCoin, 'data': [ eth.fromAscii('approve'), exchange ] }); +eth.transact({ 'to': gavCoin, 'data': [ web3.fromAscii('approve'), exchange ] }); env.note('Approve Exchange on other address...') -eth.transact({ 'from': eth.keys[1], 'to': gavCoin, 'data': [ eth.fromAscii('approve'), exchange ] }); +eth.transact({ 'from': eth.keys[1], 'to': gavCoin, 'data': [ web3.fromAscii('approve'), exchange ] }); env.note('Make offer 5000GAV/5ETH...') -eth.transact({ 'to': exchange, 'data': [eth.fromAscii('new'), gavCoin, '5000', '0', '5000000000000000000'] }); +eth.transact({ 'to': exchange, 'data': [web3.fromAscii('new'), gavCoin, '5000', '0', '5000000000000000000'] }); env.note('Register gav.eth...') -eth.transact({ 'to': dnsReg, 'data': [eth.fromAscii('register'), eth.fromAscii('gav'), eth.fromAscii('opensecrecy.com')] }); +eth.transact({ 'to': dnsReg, 'data': [web3.fromAscii('register'), web3.fromAscii('gav'), web3.fromAscii('opensecrecy.com')] }); env.note('All done.') From 5b8e26f63d234789f3ed79bb47f8b518c52a433a Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 23 Oct 2014 11:50:24 +0200 Subject: [PATCH 3/4] Whisper fixes. --- exp/main.cpp | 3 +-- libwhisper/Message.cpp | 2 +- libwhisper/Message.h | 1 + libwhisper/WhisperPeer.cpp | 23 +++++++++++++---------- libwhisper/WhisperPeer.h | 2 +- 5 files changed, 17 insertions(+), 14 deletions(-) diff --git a/exp/main.cpp b/exp/main.cpp index 30ef36408..0717ad051 100644 --- a/exp/main.cpp +++ b/exp/main.cpp @@ -95,8 +95,7 @@ int main(int argc, char** argv) } Host ph("Test", NetworkPreferences(listenPort, "", false, true)); - ph.registerCapability(new WhisperHost()); - auto wh = ph.cap(); + auto wh = ph.registerCapability(new WhisperHost()); ph.start(); diff --git a/libwhisper/Message.cpp b/libwhisper/Message.cpp index 04f510917..5d8466a2c 100644 --- a/libwhisper/Message.cpp +++ b/libwhisper/Message.cpp @@ -105,7 +105,7 @@ void Envelope::proveWork(unsigned _ms) // PoW h256 d[2]; d[0] = sha3NoNonce(); - uint32_t& n = *(uint32_t*)&(d[1][30]); + uint32_t& n = *(uint32_t*)&(d[1][28]); unsigned bestBitSet = 0; bytesConstRef chuck(d[0].data(), 64); diff --git a/libwhisper/Message.h b/libwhisper/Message.h index cbe6355be..17ddb3f7f 100644 --- a/libwhisper/Message.h +++ b/libwhisper/Message.h @@ -50,6 +50,7 @@ public: m_ttl = _m[1].toInt(); m_topic = (Topic)_m[2]; m_data = _m[3].toBytes(); + m_nonce = _m[4].toInt(); } operator bool() const { return !!m_expiry; } diff --git a/libwhisper/WhisperPeer.cpp b/libwhisper/WhisperPeer.cpp index 58f9a4cf4..343f7ca1a 100644 --- a/libwhisper/WhisperPeer.cpp +++ b/libwhisper/WhisperPeer.cpp @@ -86,24 +86,27 @@ void WhisperPeer::sendMessages() RLPStream amalg; unsigned n = 0; - Guard l(x_unseen); - while (m_unseen.size()) { - auto p = *m_unseen.begin(); - m_unseen.erase(m_unseen.begin()); - host()->streamMessage(p.second, amalg); - n++; + Guard l(x_unseen); + while (m_unseen.size()) + { + auto p = *m_unseen.begin(); + m_unseen.erase(m_unseen.begin()); + host()->streamMessage(p.second, amalg); + n++; + } } - if (n) + if (!n) + // pause for a bit if no messages to send - this is horrible and broken. + // the message subsystem should really just keep pumping out messages while m_unseen.size() and there's bandwidth for them. + this_thread::sleep_for(chrono::milliseconds(20)); + { RLPStream s; prep(s, MessagesPacket, n).appendRaw(amalg.out(), n); sealAndSend(s); } - else - // just pause if no messages to send - this_thread::sleep_for(chrono::milliseconds(100)); } void WhisperPeer::noteNewMessage(h256 _h, Message const& _m) diff --git a/libwhisper/WhisperPeer.h b/libwhisper/WhisperPeer.h index 3da246562..45d72ba89 100644 --- a/libwhisper/WhisperPeer.h +++ b/libwhisper/WhisperPeer.h @@ -59,7 +59,7 @@ public: WhisperHost* host() const; private: - virtual bool interpret(unsigned _id, RLP const&); + virtual bool interpret(unsigned _id, RLP const&) override; void sendMessages(); From cad2a1579cdca289db2e1e8e17737317fd5d2af5 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 23 Oct 2014 12:35:00 +0200 Subject: [PATCH 4/4] Topic TopicMAsk builders. --- exp/main.cpp | 6 ++-- libwhisper/Common.cpp | 24 +++++++++++++++ libwhisper/Common.h | 62 +++++++++++++++++++++++++++++++++++++- libwhisper/Interface.h | 22 ++------------ libwhisper/WhisperHost.cpp | 4 +-- libwhisper/WhisperHost.h | 3 +- 6 files changed, 94 insertions(+), 27 deletions(-) diff --git a/exp/main.cpp b/exp/main.cpp index 0717ad051..c1c6139a2 100644 --- a/exp/main.cpp +++ b/exp/main.cpp @@ -102,12 +102,12 @@ int main(int argc, char** argv) if (!remoteHost.empty()) ph.connect(remoteHost, remotePort); - /// Only interested in the packet if the lowest bit is 1 - auto w = wh->installWatch(TopicFilter(TopicMasks({{Topic("0000000000000000000000000000000000000000000000000000000000000001"), Topic("0000000000000000000000000000000000000000000000000000000000000001")}}))); + /// Only interested in odd packets + auto w = wh->installWatch(BuildTopicMask()("odd")); for (int i = 0; ; ++i) { - wh->sendRaw(RLPStream().append(i * i).out(), Topic(u256(i))); + wh->sendRaw(RLPStream().append(i * i).out(), BuildTopic(i)(i % 2 ? "odd" : "even")); for (auto i: wh->checkWatch(w)) { auto p = wh->envelope(i).open().payload(); diff --git a/libwhisper/Common.cpp b/libwhisper/Common.cpp index 52bed0742..e4903821c 100644 --- a/libwhisper/Common.cpp +++ b/libwhisper/Common.cpp @@ -21,8 +21,32 @@ #include "Common.h" +#include using namespace std; using namespace dev; using namespace dev::p2p; using namespace dev::shh; +BuildTopic& BuildTopic::shiftBytes(bytes const& _b) +{ + m_parts.push_back(dev::sha3(_b)); + return *this; +} + +h256 TopicFilter::sha3() const +{ + RLPStream s; + fillStream(s); + return dev::sha3(s.out()); +} + +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; + } + return ret; +} diff --git a/libwhisper/Common.h b/libwhisper/Common.h index 49405f00b..1f4c4a17f 100644 --- a/libwhisper/Common.h +++ b/libwhisper/Common.h @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include namespace dev @@ -48,6 +48,8 @@ class WhisperHost; class WhisperPeer; class Whisper; +class Envelope; + enum WhisperPacket { StatusPacket = 0, @@ -59,5 +61,63 @@ enum WhisperPacket using Topic = h256; +class BuildTopic +{ +public: + template BuildTopic(T const& _t) { shift(_t); } + + template BuildTopic& shift(T const& _r) { return shiftBytes(RLPStream().append(_r).out()); } + template BuildTopic& operator()(T const& _t) { return shift(_t); } + + BuildTopic& shiftRaw(h256 const& _part) { m_parts.push_back(_part); return *this; } + + operator Topic() const { return toTopic(); } + 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; +}; + +using TopicMask = std::pair; +using TopicMasks = std::vector; + +class TopicFilter +{ +public: + TopicFilter() {} + TopicFilter(TopicMask const& _m): m_topicMasks(1, _m) {} + TopicFilter(TopicMasks const& _m): m_topicMasks(_m) {} + TopicFilter(RLP const& _r): m_topicMasks((TopicMasks)_r) {} + + void fillStream(RLPStream& _s) const { _s << m_topicMasks; } + h256 sha3() const; + + bool matches(Envelope const& _m) const; + +private: + TopicMasks m_topicMasks; +}; + +class BuildTopicMask: BuildTopic +{ +public: + BuildTopicMask() { shift(); } + template BuildTopicMask(T const& _t) { shift(_t); } + + template BuildTopicMask& shift(T const& _r) { BuildTopic::shift(_r); return *this; } + BuildTopicMask& shiftRaw(h256 const& _h) { BuildTopic::shiftRaw(_h); return *this; } + BuildTopic& shift() { m_parts.push_back(h256()); return *this; } + + BuildTopicMask& operator()() { shift(); return *this; } + template BuildTopicMask& operator()(T const& _t) { shift(_t); return *this; } + + operator TopicMask() const { return toTopicMask(); } + TopicMask toTopicMask() const; +}; + } } diff --git a/libwhisper/Interface.h b/libwhisper/Interface.h index fda070263..3b2ec7267 100644 --- a/libwhisper/Interface.h +++ b/libwhisper/Interface.h @@ -43,25 +43,6 @@ namespace shh Topic mask; };*/ -using TopicMask = std::pair; -using TopicMasks = std::vector; - -class TopicFilter -{ -public: - TopicFilter() {} - TopicFilter(TopicMasks const& _m): m_topicMasks(_m) {} - TopicFilter(RLP const& _r): m_topicMasks((TopicMasks)_r) {} - - void fillStream(RLPStream& _s) const { _s << m_topicMasks; } - h256 sha3() const { RLPStream s; fillStream(s); return dev::sha3(s.out()); } - - bool matches(Envelope const& _m) const; - -private: - TopicMasks m_topicMasks; -}; - struct InstalledFilter { InstalledFilter(TopicFilter const& _f): filter(_f) {} @@ -86,8 +67,9 @@ public: virtual void inject(Envelope const& _m, WhisperPeer* _from = nullptr) = 0; + unsigned installWatch(TopicMask const& _mask) { return installWatch(TopicFilter(_mask)); } virtual unsigned installWatch(TopicFilter const& _filter) = 0; - virtual unsigned installWatch(h256 _filterId) = 0; + virtual unsigned installWatchOnId(h256 _filterId) = 0; virtual void uninstallWatch(unsigned _watchId) = 0; virtual h256s peekWatch(unsigned _watchId) const = 0; virtual h256s checkWatch(unsigned _watchId) = 0; diff --git a/libwhisper/WhisperHost.cpp b/libwhisper/WhisperHost.cpp index 2f3a21d3e..2d9a5e6b6 100644 --- a/libwhisper/WhisperHost.cpp +++ b/libwhisper/WhisperHost.cpp @@ -87,7 +87,7 @@ void WhisperHost::noteChanged(h256 _messageHash, h256 _filter) } } -unsigned WhisperHost::installWatch(h256 _h) +unsigned WhisperHost::installWatchOnId(h256 _h) { auto ret = m_watches.size() ? m_watches.rbegin()->first + 1 : 0; m_watches[ret] = ClientWatch(_h); @@ -104,7 +104,7 @@ unsigned WhisperHost::installWatch(shh::TopicFilter const& _f) if (!m_filters.count(h)) m_filters.insert(make_pair(h, _f)); - return installWatch(h); + return installWatchOnId(h); } void WhisperHost::uninstallWatch(unsigned _i) diff --git a/libwhisper/WhisperHost.h b/libwhisper/WhisperHost.h index cd6746c24..2a8789956 100644 --- a/libwhisper/WhisperHost.h +++ b/libwhisper/WhisperHost.h @@ -50,8 +50,9 @@ public: virtual void inject(Envelope const& _e, WhisperPeer* _from = nullptr); + using Interface::installWatch; virtual unsigned installWatch(TopicFilter const& _filter); - virtual unsigned installWatch(h256 _filterId); + 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; }