From 1d16e1556fc4ffe0c57c1781fc77aa3ac236f64a Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 4 Nov 2014 18:11:06 +0000 Subject: [PATCH] Ready for move to log entries in JS API. --- libdevcore/FixedHash.h | 5 ++ libdevcrypto/Common.h | 3 + libdevcrypto/SHA3.h | 3 + libethereum/MessageFilter.cpp | 55 ++++++++++++++++ libethereum/MessageFilter.h | 34 ++++++++++ libethereum/State.cpp | 3 +- libevm/ExtVMFace.h | 20 ++++-- libweb3jsonrpc/WebThreeStubServer.cpp | 71 ++++++++++++++++++--- libweb3jsonrpc/WebThreeStubServer.h | 4 +- libweb3jsonrpc/abstractwebthreestubserver.h | 7 -- libweb3jsonrpc/spec.json | 1 - 11 files changed, 181 insertions(+), 25 deletions(-) diff --git a/libdevcore/FixedHash.h b/libdevcore/FixedHash.h index 02d199f62..2353a100c 100644 --- a/libdevcore/FixedHash.h +++ b/libdevcore/FixedHash.h @@ -163,6 +163,11 @@ public: return (*this |= _h.template nbloom()); } + template inline bool containsBloom(FixedHash const& _h) + { + return contains(_h.template nbloom()); + } + template inline FixedHash nbloom() const { static const unsigned c_bloomBits = M * 8; diff --git a/libdevcrypto/Common.h b/libdevcrypto/Common.h index 7f2a8192e..4b4d34d87 100644 --- a/libdevcrypto/Common.h +++ b/libdevcrypto/Common.h @@ -50,6 +50,9 @@ using Address = h160; /// A vector of Ethereum addresses. using Addresses = h160s; +/// A vector of Ethereum addresses. +using AddressSet = std::set; + /// A vector of secrets. using Secrets = h256s; diff --git a/libdevcrypto/SHA3.h b/libdevcrypto/SHA3.h index 1575ab29c..7aa4db246 100644 --- a/libdevcrypto/SHA3.h +++ b/libdevcrypto/SHA3.h @@ -56,6 +56,9 @@ inline h256 sha3(bytes const& _input) { return sha3(bytesConstRef((bytes*)&_inpu /// Calculate SHA3-256 hash of the given input (presented as a binary-filled string), returning as a 256-bit hash. inline h256 sha3(std::string const& _input) { return sha3(bytesConstRef(_input)); } +/// Calculate SHA3-256 hash of the given input (presented as a FixedHash), returns a 256-bit hash. +template inline h256 sha3(FixedHash const& _input) { return sha3(_input.ref()); } + extern h256 EmptySHA3; extern h256 EmptyListSHA3; diff --git a/libethereum/MessageFilter.cpp b/libethereum/MessageFilter.cpp index fc6af1308..88f1a24f9 100644 --- a/libethereum/MessageFilter.cpp +++ b/libethereum/MessageFilter.cpp @@ -149,3 +149,58 @@ bool MessageFilter::matches(Manifest const& _m, vector _p, Address _o, return ret; } + + + +void LogFilter::streamRLP(RLPStream& _s) const +{ + _s.appendList(6) << m_addresses << m_topics << m_earliest << m_latest << m_max << m_skip; +} + +h256 LogFilter::sha3() const +{ + RLPStream s; + streamRLP(s); + return dev::sha3(s.out()); +} + +bool LogFilter::matches(LogBloom _bloom) const +{ + if (m_addresses.size()) + { + for (auto i: m_addresses) + if (_bloom.containsBloom<3>(dev::sha3(i))) + goto OK1; + return false; + } + OK1: + if (m_topics.size()) + { + for (auto i: m_topics) + if (_bloom.containsBloom<3>(dev::sha3(i))) + goto OK2; + return false; + } + OK2: + return true; +} + +bool LogFilter::matches(State const& _s, unsigned _i) const +{ + return matches(_s.receipt(_i)).size() > 0; +} + +LogEntries LogFilter::matches(TransactionReceipt const& _m) const +{ + LogEntries ret; + for (LogEntry const& e: _m.log()) + { + if (!m_addresses.empty() && !m_addresses.count(e.address)) + continue; + for (auto const& t: m_topics) + if (!e.topics.count(t)) + continue; + ret.push_back(e); + } + return ret; +} diff --git a/libethereum/MessageFilter.h b/libethereum/MessageFilter.h index 83cbb7237..5602d7a17 100644 --- a/libethereum/MessageFilter.h +++ b/libethereum/MessageFilter.h @@ -25,6 +25,7 @@ #include #include #include "PastMessage.h" +#include "TransactionReceipt.h" namespace dev { @@ -72,5 +73,38 @@ private: unsigned m_skip; }; +class LogFilter +{ +public: + LogFilter(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 streamRLP(RLPStream& _s) const; + h256 sha3() const; + + int earliest() const { return m_earliest; } + int latest() const { return m_latest; } + unsigned max() const { return m_max; } + unsigned skip() const { return m_skip; } + bool matches(LogBloom _bloom) const; + bool matches(State const& _s, unsigned _i) const; + LogEntries matches(TransactionReceipt const& _r) const; + + LogFilter address(Address _a) { m_addresses.insert(_a); return *this; } + LogFilter from(Address _a) { return topic(u256((u160)_a) + 1); } + LogFilter topic(h256 const& _t) { m_topics.insert(_t); return *this; } + LogFilter withMax(unsigned _m) { m_max = _m; return *this; } + LogFilter withSkip(unsigned _m) { m_skip = _m; return *this; } + LogFilter withEarliest(int _e) { m_earliest = _e; return *this; } + LogFilter withLatest(int _e) { m_latest = _e; return *this; } + +private: + AddressSet m_addresses; + h256Set m_topics; + int m_earliest = 0; + int m_latest = -1; + unsigned m_max; + unsigned m_skip; +}; + } } diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 51f5901c5..cd1a7f541 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -791,7 +791,8 @@ h256 State::oldBloom() const LogBloom State::logBloom() const { LogBloom ret; - ret.shiftBloom<3>(sha3(m_currentBlock.coinbaseAddress.ref())); + auto sa = sha3(m_currentBlock.coinbaseAddress.ref()); + ret.shiftBloom<3>(sa); for (TransactionReceipt const& i: m_receipts) ret |= i.bloom(); return ret; diff --git a/libevm/ExtVMFace.h b/libevm/ExtVMFace.h index 1b1ae7455..9f662087c 100644 --- a/libevm/ExtVMFace.h +++ b/libevm/ExtVMFace.h @@ -36,27 +36,35 @@ namespace dev namespace eth { +template inline std::set toSet(std::vector const& _ts) +{ + std::set ret; + for (auto const& t: _ts) + ret.insert(t); + return ret; +} + 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)) {} + LogEntry(RLP const& _r) { address = (Address)_r[0]; topics = (h256Set)_r[1]; data = (bytes)_r[2]; } + LogEntry(Address const& _address, h256s const& _ts, bytes&& _d): address(_address), topics(toSet(_ts)), data(std::move(_d)) {} - void streamRLP(RLPStream& _s) const { _s.appendList(3) << from << topics << data; } + void streamRLP(RLPStream& _s) const { _s.appendList(3) << address << topics << data; } LogBloom bloom() const { LogBloom ret; - ret.shiftBloom<3, 32>(sha3(from.ref())); + ret.shiftBloom<3, 32>(sha3(address.ref())); for (auto t: topics) ret.shiftBloom<3, 32>(sha3(t.ref())); return ret; } - Address from; - h256s topics; + Address address; + h256Set topics; bytes data; }; diff --git a/libweb3jsonrpc/WebThreeStubServer.cpp b/libweb3jsonrpc/WebThreeStubServer.cpp index e7eb62e04..4ac048ee9 100644 --- a/libweb3jsonrpc/WebThreeStubServer.cpp +++ b/libweb3jsonrpc/WebThreeStubServer.cpp @@ -97,6 +97,24 @@ static Json::Value toJson(dev::eth::Transaction const& _t) return res; } +static Json::Value toJson(dev::eth::LogEntry const& _e) +{ + Json::Value res; + res["data"] = jsFromBinary(_e.data); + res["address"] = toJS(_e.address); + for (auto const& t: _e.topics) + res["topics"].append(toJS(t)); + return res; +} + +static Json::Value toJson(dev::eth::LogEntries const& _es) +{ + Json::Value res; + for (dev::eth::LogEntry const& e: _es) + res.append(toJson(e)); + return res; +} + static dev::eth::MessageFilter toMessageFilter(Json::Value const& _json) { dev::eth::MessageFilter filter; @@ -123,9 +141,9 @@ static dev::eth::MessageFilter toMessageFilter(Json::Value const& _json) { if (_json["to"].isArray()) for (auto i : _json["to"]) - filter.from(jsToAddress(i.asString())); + filter.to(jsToAddress(i.asString())); else - filter.from(jsToAddress(_json["to"].asString())); + filter.to(jsToAddress(_json["to"].asString())); } if (!_json["altered"].empty()) { @@ -143,6 +161,48 @@ static dev::eth::MessageFilter toMessageFilter(Json::Value const& _json) return filter; } +static dev::eth::LogFilter toLogFilter(Json::Value const& _json) +{ + dev::eth::LogFilter filter; + if (!_json.isObject() || _json.empty()) + return filter; + + if (!_json["earliest"].empty()) + filter.withEarliest(_json["earliest"].asInt()); + if (!_json["latest"].empty()) + filter.withLatest(_json["lastest"].asInt()); + if (!_json["max"].empty()) + filter.withMax(_json["max"].asInt()); + if (!_json["skip"].empty()) + filter.withSkip(_json["skip"].asInt()); + if (!_json["from"].empty()) + { + if (_json["from"].isArray()) + for (auto i : _json["from"]) + filter.from(jsToAddress(i.asString())); + else + filter.from(jsToAddress(_json["from"].asString())); + } + if (!_json["address"].empty()) + { + if (_json["address"].isArray()) + for (auto i : _json["address"]) + filter.address(jsToAddress(i.asString())); + else + filter.from(jsToAddress(_json["address"].asString())); + } + if (!_json["topics"].empty()) + { + if (_json["topics"].isArray()) + for (auto i: _json["topics"]) + if (i.isString()) + filter.topic(jsToU256(i.asString())); + else if(_json["topics"].isString()) + filter.topic(jsToU256(_json["topics"].asString())); + } + return filter; +} + static shh::Message toMessage(Json::Value const& _json) { shh::Message ret; @@ -252,13 +312,6 @@ std::shared_ptr WebThreeStubServer::face() const return m_web3.whisper(); } -std::string WebThreeStubServer::account() -{ - if (!m_accounts.empty()) - return toJS(m_accounts.begin()->first); - return ""; -} - Json::Value WebThreeStubServer::accounts() { Json::Value ret(Json::arrayValue); diff --git a/libweb3jsonrpc/WebThreeStubServer.h b/libweb3jsonrpc/WebThreeStubServer.h index b18faf95a..33163b75e 100644 --- a/libweb3jsonrpc/WebThreeStubServer.h +++ b/libweb3jsonrpc/WebThreeStubServer.h @@ -56,13 +56,14 @@ class Interface; * @brief JSON-RPC api implementation * @todo filters should work on unsigned instead of int * unsigned are not supported in json-rpc-cpp and there are bugs with double in json-rpc-cpp version 0.2.1 + * @todo split these up according to subprotocol (eth, shh, db, p2p, web3) and make it /very/ clear about how to add other subprotocols. + * @todo modularise everything so additional subprotocols don't need to change this file. */ class WebThreeStubServer: public AbstractWebThreeStubServer { public: WebThreeStubServer(jsonrpc::AbstractServerConnector* _conn, dev::WebThreeDirect& _web3, std::vector const& _accounts); - virtual std::string account(); virtual Json::Value accounts(); virtual std::string addToGroup(std::string const& _group, std::string const& _who); virtual std::string balanceAt(std::string const& _address); @@ -109,6 +110,7 @@ public: void setAccounts(std::vector const& _accounts); void setIdentities(std::vector const& _ids); std::map const& ids() const { return m_ids; } + private: dev::eth::Interface* client() const; std::shared_ptr face() const; diff --git a/libweb3jsonrpc/abstractwebthreestubserver.h b/libweb3jsonrpc/abstractwebthreestubserver.h index ac6893933..66b9ff77d 100644 --- a/libweb3jsonrpc/abstractwebthreestubserver.h +++ b/libweb3jsonrpc/abstractwebthreestubserver.h @@ -13,7 +13,6 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServer(conn) { - this->bindAndAddMethod(new jsonrpc::Procedure("account", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::accountI); this->bindAndAddMethod(new jsonrpc::Procedure("accounts", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, NULL), &AbstractWebThreeStubServer::accountsI); this->bindAndAddMethod(new jsonrpc::Procedure("addToGroup", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::addToGroupI); this->bindAndAddMethod(new jsonrpc::Procedure("balanceAt", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::balanceAtI); @@ -59,11 +58,6 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServeraccount(); - } - inline virtual void accountsI(const Json::Value& request, Json::Value& response) { response = this->accounts(); @@ -275,7 +269,6 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServer