diff --git a/libethcore/Common.h b/libethcore/Common.h index 131feed4b..64eb6de29 100644 --- a/libethcore/Common.h +++ b/libethcore/Common.h @@ -85,6 +85,10 @@ using BlockNumber = unsigned; static const BlockNumber LatestBlock = (BlockNumber)-2; static const BlockNumber PendingBlock = (BlockNumber)-1; +static const h256 LatestBlockHash = h256(2); +static const h256 EarliestBlockHash = h256(1); +static const h256 PendingBlockHash = h256(0); + enum class RelativeBlock: BlockNumber { diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index da0dfc6c5..480c7f977 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -926,8 +926,8 @@ void BlockChain::checkConsistency() delete it; } -static inline unsigned upow(unsigned a, unsigned b) { while (b-- > 0) a *= a; return a; } -static inline unsigned ceilDiv(unsigned n, unsigned d) { return n / (n + d - 1); } +static inline unsigned upow(unsigned a, unsigned b) { if (!b) return 1; while (--b > 0) a *= a; return a; } +static inline unsigned ceilDiv(unsigned n, unsigned d) { return (n + d - 1) / d; } //static inline unsigned floorDivPow(unsigned n, unsigned a, unsigned b) { return n / upow(a, b); } //static inline unsigned ceilDivPow(unsigned n, unsigned a, unsigned b) { return ceilDiv(n, upow(a, b)); } diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index 4934d4f2a..5f197cfee 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -144,6 +144,7 @@ public: BlockLogBlooms logBlooms() const { return logBlooms(currentHash()); } /// Get the transactions' receipts of a block (or the most recent mined if none given). Thread-safe. + /// receipts are given in the same order are in the same order as the transactions BlockReceipts receipts(h256 const& _hash) const { return queryExtras(_hash, m_receipts, x_receipts, NullBlockReceipts); } BlockReceipts receipts() const { return receipts(currentHash()); } diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index b765787fb..9b125f563 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -428,21 +428,17 @@ void Client::killChain() void Client::clearPending() { - h256Hash changeds; DEV_WRITE_GUARDED(x_postMine) { if (!m_postMine.pending().size()) return; -// for (unsigned i = 0; i < m_postMine.pending().size(); ++i) -// appendFromNewPending(m_postMine.logBloom(i), changeds); - changeds.insert(PendingChangedFilter); m_tq.clear(); DEV_READ_GUARDED(x_preMine) m_postMine = m_preMine; } startMining(); - + h256Hash changeds; noteChanged(changeds); } @@ -465,47 +461,53 @@ static S& filtersStreamOut(S& _out, T const& _fs) return _out; } -void Client::appendFromNewPending(TransactionReceipt const& _receipt, h256Hash& io_changed, h256 _transactionHash) +void Client::appendFromNewPending(TransactionReceipt const& _receipt, h256Hash& io_changed, h256 _sha3) { Guard l(x_filtersWatches); + io_changed.insert(PendingChangedFilter); + m_specialFilters.at(PendingChangedFilter).push_back(_sha3); for (pair& i: m_filters) - if (i.second.filter.envelops(RelativeBlock::Pending, m_bc.number() + 1)) + { + // acceptable number. + auto m = i.second.filter.matches(_receipt); + if (m.size()) { - // acceptable number. - auto m = i.second.filter.matches(_receipt); - if (m.size()) - { - // filter catches them - for (LogEntry const& l: m) - i.second.changes.push_back(LocalisedLogEntry(l, m_bc.number() + 1, _transactionHash)); - io_changed.insert(i.first); - } + // filter catches them + for (LogEntry const& l: m) + i.second.changes.push_back(LocalisedLogEntry(l)); + io_changed.insert(i.first); } + } } void Client::appendFromNewBlock(h256 const& _block, h256Hash& io_changed) { // TODO: more precise check on whether the txs match. auto d = m_bc.info(_block); - auto br = m_bc.receipts(_block); + auto receipts = m_bc.receipts(_block).receipts; Guard l(x_filtersWatches); + io_changed.insert(ChainChangedFilter); + m_specialFilters.at(ChainChangedFilter).push_back(_block); for (pair& i: m_filters) - if (i.second.filter.envelops(RelativeBlock::Latest, d.number) && i.second.filter.matches(d.logBloom)) - // acceptable number & looks like block may contain a matching log entry. - for (size_t j = 0; j < br.receipts.size(); j++) + { + // acceptable number & looks like block may contain a matching log entry. + unsigned logIndex = 0; + for (size_t j = 0; j < receipts.size(); j++) + { + logIndex++; + auto tr = receipts[j]; + auto m = i.second.filter.matches(tr); + if (m.size()) { - auto tr = br.receipts[j]; - auto m = i.second.filter.matches(tr); - if (m.size()) - { - auto transactionHash = transaction(d.hash(), j).sha3(); - // filter catches them - for (LogEntry const& l: m) - i.second.changes.push_back(LocalisedLogEntry(l, (unsigned)d.number, transactionHash)); - io_changed.insert(i.first); - } + auto transactionHash = transaction(d.hash(), j).sha3(); + // filter catches them + for (LogEntry const& l: m) + i.second.changes.push_back(LocalisedLogEntry(l, d, transactionHash, j, logIndex)); + io_changed.insert(i.first); } + } + } } void Client::setForceMining(bool _enable) @@ -643,7 +645,7 @@ void Client::syncTransactionQueue() DEV_READ_GUARDED(x_postMine) for (size_t i = 0; i < newPendingReceipts.size(); i++) appendFromNewPending(newPendingReceipts[i], changeds, m_postMine.pending()[i].sha3()); - changeds.insert(PendingChangedFilter); + // Tell farm about new transaction (i.e. restartProofOfWork mining). onPostStateChanged(); @@ -686,7 +688,6 @@ void Client::onChainChanged(ImportRoute const& _ir) h256Hash changeds; for (auto const& h: _ir.first) appendFromNewBlock(h, changeds); - changeds.insert(ChainChangedFilter); // RESTART MINING @@ -792,15 +793,18 @@ void Client::noteChanged(h256Hash const& _filters) cwatch << "!!!" << w.first << w.second.id.abridged(); w.second.changes += m_filters.at(w.second.id).changes; } - else - { - cwatch << "!!!" << w.first << LogTag::Special << (w.second.id == PendingChangedFilter ? "pending" : w.second.id == ChainChangedFilter ? "chain" : "???"); - w.second.changes.push_back(LocalisedLogEntry(SpecialLogEntry, 0)); - } + else if (m_specialFilters.count(w.second.id)) + for (h256 const& hash: m_specialFilters.at(w.second.id)) + { + cwatch << "!!!" << w.first << LogTag::Special << (w.second.id == PendingChangedFilter ? "pending" : w.second.id == ChainChangedFilter ? "chain" : "???"); + w.second.changes.push_back(LocalisedLogEntry(SpecialLogEntry, hash)); + } } // clear the filters now. for (auto& i: m_filters) i.second.changes.clear(); + for (auto& i: m_specialFilters) + i.second.clear(); } void Client::doWork() diff --git a/libethereum/ClientBase.cpp b/libethereum/ClientBase.cpp index 6a2c76c0b..61bccbc3f 100644 --- a/libethereum/ClientBase.cpp +++ b/libethereum/ClientBase.cpp @@ -171,8 +171,8 @@ LocalisedLogEntries ClientBase::logs(unsigned _watchId) const LocalisedLogEntries ClientBase::logs(LogFilter const& _f) const { LocalisedLogEntries ret; - unsigned begin = min(bc().number() + 1, (unsigned)_f.latest()); - unsigned end = min(bc().number(), min(begin, (unsigned)_f.earliest())); + unsigned begin = min(bc().number() + 1, (unsigned)numberFromHash(_f.latest())); + unsigned end = min(bc().number(), min(begin, (unsigned)numberFromHash(_f.earliest()))); // Handle pending transactions differently as they're not on the block chain. if (begin > bc().number()) @@ -182,11 +182,10 @@ LocalisedLogEntries ClientBase::logs(LogFilter const& _f) const { // Might have a transaction that contains a matching log. TransactionReceipt const& tr = temp.receipt(i); - auto th = temp.pending()[i].sha3(); LogEntries le = _f.matches(tr); if (le.size()) for (unsigned j = 0; j < le.size(); ++j) - ret.insert(ret.begin(), LocalisedLogEntry(le[j], begin, th)); + ret.insert(ret.begin(), LocalisedLogEntry(le[j])); } begin = bc().number(); } @@ -201,20 +200,22 @@ LocalisedLogEntries ClientBase::logs(LogFilter const& _f) const { int total = 0; auto h = bc().numberHash(n); + auto info = bc().info(h); auto receipts = bc().receipts(h).receipts; + unsigned logIndex = 0; for (size_t i = 0; i < receipts.size(); i++) { + logIndex++; TransactionReceipt receipt = receipts[i]; if (_f.matches(receipt.bloom())) { - auto info = bc().info(h); auto th = transaction(info.hash(), i).sha3(); LogEntries le = _f.matches(receipt); if (le.size()) { total += le.size(); for (unsigned j = 0; j < le.size(); ++j) - ret.insert(ret.begin(), LocalisedLogEntry(le[j], n, th)); + ret.insert(ret.begin(), LocalisedLogEntry(le[j], info, th, i, logIndex)); } } @@ -313,6 +314,8 @@ LocalisedLogEntries ClientBase::checkWatch(unsigned _watchId) BlockInfo ClientBase::blockInfo(h256 _hash) const { + if (_hash == PendingBlockHash) + return preMine().info(); return BlockInfo(bc().block(_hash)); } @@ -441,6 +444,24 @@ h256 ClientBase::hashFromNumber(BlockNumber _number) const BlockNumber ClientBase::numberFromHash(h256 _blockHash) const { + if (_blockHash == PendingBlockHash) + return bc().number() + 1; + else if (_blockHash == LatestBlockHash) + return bc().number(); + else if (_blockHash == EarliestBlockHash) + return 0; return bc().number(_blockHash); } +int ClientBase::compareBlockHashes(h256 _h1, h256 _h2) const +{ + BlockNumber n1 = numberFromHash(_h1); + BlockNumber n2 = numberFromHash(_h2); + + if (n1 > n2) { + return 1; + } else if (n1 == n2) { + return 0; + } + return -1; +} diff --git a/libethereum/ClientBase.h b/libethereum/ClientBase.h index b2afe3597..3f8e230c8 100644 --- a/libethereum/ClientBase.h +++ b/libethereum/ClientBase.h @@ -44,7 +44,7 @@ static const h256 PendingChangedFilter = u256(0); static const h256 ChainChangedFilter = u256(1); static const LogEntry SpecialLogEntry = LogEntry(Address(), h256s(), bytes()); -static const LocalisedLogEntry InitialChange(SpecialLogEntry, 0); +static const LocalisedLogEntry InitialChange(SpecialLogEntry); struct ClientWatch { @@ -117,6 +117,7 @@ public: virtual h256 hashFromNumber(BlockNumber _number) const override; virtual BlockNumber numberFromHash(h256 _blockHash) const override; + virtual int compareBlockHashes(h256 _h1, h256 _h2) const override; virtual BlockInfo blockInfo(h256 _hash) const override; virtual BlockDetails blockDetails(h256 _hash) const override; virtual Transaction transaction(h256 _transactionHash) const override; @@ -175,6 +176,8 @@ protected: // filters mutable Mutex x_filtersWatches; ///< Our lock. std::unordered_map m_filters; ///< The dictionary of filters that are active. + std::unordered_map m_specialFilters = std::unordered_map>{{PendingChangedFilter, {}}, {ChainChangedFilter, {}}}; + ///< The dictionary of special filters and their additional data std::map m_watches; ///< Each and every watch - these reference a filter. }; diff --git a/libethereum/Interface.h b/libethereum/Interface.h index 636f73fbf..f631fb43e 100644 --- a/libethereum/Interface.h +++ b/libethereum/Interface.h @@ -137,6 +137,7 @@ public: virtual std::pair transactionLocation(h256 const& _transactionHash) const = 0; virtual h256 hashFromNumber(BlockNumber _number) const = 0; virtual BlockNumber numberFromHash(h256 _blockHash) const = 0; + virtual int compareBlockHashes(h256 _h1, h256 _h2) const = 0; virtual BlockInfo blockInfo(h256 _hash) const = 0; virtual BlockDetails blockDetails(h256 _hash) const = 0; diff --git a/libethereum/LogFilter.cpp b/libethereum/LogFilter.cpp index 21ba9d3ef..6e0fbd709 100644 --- a/libethereum/LogFilter.cpp +++ b/libethereum/LogFilter.cpp @@ -46,33 +46,6 @@ h256 LogFilter::sha3() const return dev::sha3(s.out()); } -static bool isNoLater(RelativeBlock _logBlockRelation, u256 _logBlockNumber, unsigned _latest) -{ - if (_latest == PendingBlock) - return true; - else if (_latest == LatestBlock) - return _logBlockRelation == RelativeBlock::Latest; - else - return _logBlockNumber <= _latest; -} - -static bool isNoEarlier(RelativeBlock _logBlockRelation, u256 _logBlockNumber, unsigned _earliest) -{ - if (_earliest == PendingBlock) - return _logBlockRelation == RelativeBlock::Pending; - else if (_earliest == LatestBlock) - return true; - else - return _logBlockNumber >= _earliest; -} - -bool LogFilter::envelops(RelativeBlock _logBlockRelation, u256 _logBlockNumber) const -{ - return - isNoLater(_logBlockRelation, _logBlockNumber, m_latest) && - isNoEarlier(_logBlockRelation, _logBlockNumber, m_earliest); -} - bool LogFilter::matches(LogBloom _bloom) const { if (m_addresses.size()) diff --git a/libethereum/LogFilter.h b/libethereum/LogFilter.h index 97ff5a3b1..ff33346f8 100644 --- a/libethereum/LogFilter.h +++ b/libethereum/LogFilter.h @@ -45,15 +45,14 @@ class State; class LogFilter { public: - LogFilter(unsigned _earliest = 0, unsigned _latest = PendingBlock): m_earliest(_earliest), m_latest(_latest) {} + LogFilter(h256 _earliest = EarliestBlockHash, h256 _latest = PendingBlockHash): m_earliest(_earliest), m_latest(_latest) {} void streamRLP(RLPStream& _s) const; h256 sha3() const; - unsigned earliest() const { return m_earliest; } - unsigned latest() const { return m_latest; } + h256 earliest() const { return m_earliest; } + h256 latest() const { return m_latest; } - bool envelops(RelativeBlock _logBlockRelation, u256 _logBlockNumber) const; std::vector bloomPossibilities() const; bool matches(LogBloom _bloom) const; bool matches(State const& _s, unsigned _i) const; @@ -61,16 +60,16 @@ public: LogFilter address(Address _a) { m_addresses.insert(_a); return *this; } LogFilter topic(unsigned _index, h256 const& _t) { if (_index < 4) m_topics[_index].insert(_t); return *this; } - LogFilter withEarliest(int _e) { m_earliest = _e; return *this; } - LogFilter withLatest(int _e) { m_latest = _e; return *this; } + LogFilter withEarliest(h256 _e) { m_earliest = _e; return *this; } + LogFilter withLatest(h256 _e) { m_latest = _e; return *this; } friend std::ostream& dev::eth::operator<<(std::ostream& _out, dev::eth::LogFilter const& _s); private: AddressHash m_addresses; std::array m_topics; - unsigned m_earliest = 0; - unsigned m_latest = LatestBlock; + h256 m_earliest = EarliestBlockHash; + h256 m_latest = PendingBlockHash; }; } diff --git a/libevm/ExtVMFace.h b/libevm/ExtVMFace.h index bb102bef3..357292853 100644 --- a/libevm/ExtVMFace.h +++ b/libevm/ExtVMFace.h @@ -63,10 +63,28 @@ using LogEntries = std::vector; struct LocalisedLogEntry: public LogEntry { LocalisedLogEntry() {} - LocalisedLogEntry(LogEntry const& _le, unsigned _number, h256 _transactionHash = h256()): LogEntry(_le), number(_number), transactionHash(_transactionHash) {} - - unsigned number = 0; - h256 transactionHash; + explicit LocalisedLogEntry(LogEntry const& _le): LogEntry(_le) {}; + + explicit LocalisedLogEntry( + LogEntry const& _le, + h256 _special + ): LogEntry(_le), special(_special) {}; + + explicit LocalisedLogEntry( + LogEntry const& _le, + BlockInfo const& _bi, + h256 _th, + unsigned _ti, + unsigned _li + ): LogEntry(_le), blockHash(_bi.hash()), blockNumber((BlockNumber)_bi.number), transactionHash(_th), transactionIndex(_ti), logIndex(_li), mined(true) {}; + + h256 blockHash = h256(); + BlockNumber blockNumber = 0; + h256 transactionHash = h256(); + unsigned transactionIndex = 0; + unsigned logIndex = 0; + bool mined = false; + h256 special = h256(); }; using LocalisedLogEntries = std::vector; diff --git a/libweb3jsonrpc/WebThreeStubServerBase.cpp b/libweb3jsonrpc/WebThreeStubServerBase.cpp index fa07e7dd3..8b7578806 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.cpp +++ b/libweb3jsonrpc/WebThreeStubServerBase.cpp @@ -164,15 +164,33 @@ static Json::Value toJson(dev::eth::Transaction const& _t) static Json::Value toJson(dev::eth::LocalisedLogEntry const& _e) { Json::Value res; - if (_e.transactionHash) + if (_e.topics.size() > 0) { res["data"] = toJS(_e.data); res["address"] = toJS(_e.address); res["topics"] = Json::Value(Json::arrayValue); for (auto const& t: _e.topics) res["topics"].append(toJS(t)); - res["number"] = _e.number; - res["hash"] = toJS(_e.transactionHash); + if (_e.mined) + { + res["type"] = "mined"; + res["blockNumber"] = _e.blockNumber; + res["blockHash"] = toJS(_e.blockHash); + res["logIndex"] = _e.logIndex; + res["transactionHash"] = toJS(_e.transactionHash); + res["transactionIndex"] = _e.transactionIndex; + } + else + { + res["type"] = "pending"; + res["blockNumber"] = Json::Value(Json::nullValue); + res["blockHash"] = Json::Value(Json::nullValue); + res["logIndex"] = Json::Value(Json::nullValue); + res["transactionHash"] = Json::Value(Json::nullValue); + res["transactionIndex"] = Json::Value(Json::nullValue); + } + } else { + res = toJS(_e.special); } return res; } @@ -193,7 +211,7 @@ static Json::Value toJson(map const& _storage) return res; } -static dev::eth::LogFilter toLogFilter(Json::Value const& _json) // commented to avoid warning. Uncomment once in use @ PoC-7. +static dev::eth::LogFilter toLogFilter(Json::Value const& _json) { dev::eth::LogFilter filter; if (!_json.isObject() || _json.empty()) @@ -201,9 +219,44 @@ static dev::eth::LogFilter toLogFilter(Json::Value const& _json) // commented to // check only !empty. it should throw exceptions if input params are incorrect if (!_json["fromBlock"].empty()) - filter.withEarliest(jsToBlockNumber(_json["fromBlock"].asString())); + filter.withEarliest(jsToFixed<32>(_json["fromBlock"].asString())); if (!_json["toBlock"].empty()) - filter.withLatest(jsToBlockNumber(_json["toBlock"].asString())); + filter.withLatest(jsToFixed<32>(_json["toBlock"].asString())); + if (!_json["address"].empty()) + { + if (_json["address"].isArray()) + for (auto i : _json["address"]) + filter.address(jsToAddress(i.asString())); + else + filter.address(jsToAddress(_json["address"].asString())); + } + if (!_json["topics"].empty()) + for (unsigned i = 0; i < _json["topics"].size(); i++) + { + if (_json["topics"][i].isArray()) + { + for (auto t: _json["topics"][i]) + if (!t.isNull()) + filter.topic(i, jsToFixed<32>(t.asString())); + } + else if (!_json["topics"][i].isNull()) // if it is anything else then string, it should and will fail + filter.topic(i, jsToFixed<32>(_json["topics"][i].asString())); + } + return filter; +} + +// TODO: this should be removed once we decide to remove backward compatibility with old log filters +static dev::eth::LogFilter toLogFilter(Json::Value const& _json, Interface const& _client) // commented to avoid warning. Uncomment once in use @ PoC-7. +{ + dev::eth::LogFilter filter; + if (!_json.isObject() || _json.empty()) + return filter; + + // check only !empty. it should throw exceptions if input params are incorrect + if (!_json["fromBlock"].empty()) + filter.withEarliest(_client.hashFromNumber(jsToBlockNumber(_json["fromBlock"].asString()))); + if (!_json["toBlock"].empty()) + filter.withLatest(_client.hashFromNumber(jsToBlockNumber(_json["toBlock"].asString()))); if (!_json["address"].empty()) { if (_json["address"].isArray()) @@ -712,25 +765,25 @@ Json::Value WebThreeStubServerBase::eth_getCompilers() } -string WebThreeStubServerBase::eth_compileLLL(string const& _code) +string WebThreeStubServerBase::eth_compileLLL(string const& _source) { // TODO throw here jsonrpc errors string res; vector errors; - res = toJS(dev::eth::compileLLL(_code, true, &errors)); + res = toJS(dev::eth::compileLLL(_source, true, &errors)); cwarn << "LLL compilation errors: " << errors; return res; } -string WebThreeStubServerBase::eth_compileSerpent(string const& _code) +string WebThreeStubServerBase::eth_compileSerpent(string const& _source) { // TODO throw here jsonrpc errors string res; - (void)_code; + (void)_source; #if ETH_SERPENT || !ETH_TRUE try { - res = toJS(dev::asBytes(::compile(_code))); + res = toJS(dev::asBytes(::compile(_source))); } catch (string err) { @@ -744,32 +797,66 @@ string WebThreeStubServerBase::eth_compileSerpent(string const& _code) return res; } -string WebThreeStubServerBase::eth_compileSolidity(string const& _code) +Json::Value WebThreeStubServerBase::eth_compileSolidity(string const& _source) { // TOOD throw here jsonrpc errors - (void)_code; - string res; + Json::Value res(Json::objectValue); #if ETH_SOLIDITY || !ETH_TRUE dev::solidity::CompilerStack compiler; try { - res = toJS(compiler.compile(_code, true)); + compiler.addSource("source", _source); + compiler.compile(); + + for (string const& name: compiler.getContractNames()) + { + Json::Value contract(Json::objectValue); + contract["code"] = toJS(compiler.getBytecode(name)); + + Json::Value info(Json::objectValue); + info["source"] = _source; + info["language"] = ""; + info["languageVersion"] = ""; + info["compilerVersion"] = ""; + + Json::Reader reader; + reader.parse(compiler.getInterface(name), info["abiDefinition"]); + reader.parse(compiler.getMetadata(name, dev::solidity::DocumentationType::NatspecUser), info["userDoc"]); + reader.parse(compiler.getMetadata(name, dev::solidity::DocumentationType::NatspecDev), info["developerDoc"]); + + contract["info"] = info; + res[name] = contract; + } } catch (dev::Exception const& exception) { ostringstream error; solidity::SourceReferenceFormatter::printExceptionInformation(error, exception, "Error", compiler); cwarn << "Solidity compilation error: " << error.str(); + return Json::Value(Json::objectValue); } catch (...) { cwarn << "Uncought solidity compilation exception"; + return Json::Value(Json::objectValue); } #endif return res; } string WebThreeStubServerBase::eth_newFilter(Json::Value const& _json) +{ + try + { + return toJS(client()->installWatch(toLogFilter(_json, *client()))); + } + catch (...) + { + BOOST_THROW_EXCEPTION(JsonRpcException(Errors::ERROR_RPC_INVALID_PARAMS)); + } +} + +string WebThreeStubServerBase::eth_newFilterEx(Json::Value const& _json) { try { @@ -823,6 +910,22 @@ Json::Value WebThreeStubServerBase::eth_getFilterChanges(string const& _filterId } } +Json::Value WebThreeStubServerBase::eth_getFilterChangesEx(string const& _filterId) +{ + try + { + int id = jsToInt(_filterId); + auto entries = client()->checkWatch(id); + if (entries.size()) + cnote << "FIRING WATCH" << id << entries.size(); + return toJson(entries); + } + catch (...) + { + BOOST_THROW_EXCEPTION(JsonRpcException(Errors::ERROR_RPC_INVALID_PARAMS)); + } +} + Json::Value WebThreeStubServerBase::eth_getFilterLogs(string const& _filterId) { try @@ -835,6 +938,18 @@ Json::Value WebThreeStubServerBase::eth_getFilterLogs(string const& _filterId) } } +Json::Value WebThreeStubServerBase::eth_getFilterLogsEx(string const& _filterId) +{ + try + { + return toJson(client()->logs(jsToInt(_filterId))); + } + catch (...) + { + BOOST_THROW_EXCEPTION(JsonRpcException(Errors::ERROR_RPC_INVALID_PARAMS)); + } +} + Json::Value WebThreeStubServerBase::eth_getLogs(Json::Value const& _json) { try @@ -980,7 +1095,6 @@ string WebThreeStubServerBase::shh_addToGroup(string const& _group, string const string WebThreeStubServerBase::shh_newFilter(Json::Value const& _json) { - try { pair w = toWatch(_json); diff --git a/libweb3jsonrpc/WebThreeStubServerBase.h b/libweb3jsonrpc/WebThreeStubServerBase.h index d90df1445..ec24cb08d 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.h +++ b/libweb3jsonrpc/WebThreeStubServerBase.h @@ -60,8 +60,6 @@ public: /** * @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. */ @@ -105,13 +103,16 @@ public: virtual Json::Value eth_getCompilers(); virtual std::string eth_compileLLL(std::string const& _s); virtual std::string eth_compileSerpent(std::string const& _s); - virtual std::string eth_compileSolidity(std::string const& _code); + virtual Json::Value eth_compileSolidity(std::string const& _code); virtual std::string eth_newFilter(Json::Value const& _json); + virtual std::string eth_newFilterEx(Json::Value const& _json); virtual std::string eth_newBlockFilter(); virtual std::string eth_newPendingTransactionFilter(); virtual bool eth_uninstallFilter(std::string const& _filterId); virtual Json::Value eth_getFilterChanges(std::string const& _filterId); + virtual Json::Value eth_getFilterChangesEx(std::string const& _filterId); virtual Json::Value eth_getFilterLogs(std::string const& _filterId); + virtual Json::Value eth_getFilterLogsEx(std::string const& _filterId); virtual Json::Value eth_getLogs(Json::Value const& _json); virtual Json::Value eth_getWork(); virtual bool eth_submitWork(std::string const& _nonce, std::string const&, std::string const& _mixHash); diff --git a/libweb3jsonrpc/abstractwebthreestubserver.h b/libweb3jsonrpc/abstractwebthreestubserver.h index 6a1a3df10..522d418c1 100644 --- a/libweb3jsonrpc/abstractwebthreestubserver.h +++ b/libweb3jsonrpc/abstractwebthreestubserver.h @@ -45,13 +45,16 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServerbindAndAddMethod(jsonrpc::Procedure("eth_getCompilers", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, NULL), &AbstractWebThreeStubServer::eth_getCompilersI); this->bindAndAddMethod(jsonrpc::Procedure("eth_compileLLL", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_compileLLLI); this->bindAndAddMethod(jsonrpc::Procedure("eth_compileSerpent", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_compileSerpentI); - this->bindAndAddMethod(jsonrpc::Procedure("eth_compileSolidity", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_compileSolidityI); + this->bindAndAddMethod(jsonrpc::Procedure("eth_compileSolidity", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_compileSolidityI); this->bindAndAddMethod(jsonrpc::Procedure("eth_newFilter", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_OBJECT, NULL), &AbstractWebThreeStubServer::eth_newFilterI); + this->bindAndAddMethod(jsonrpc::Procedure("eth_newFilterEx", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_OBJECT, NULL), &AbstractWebThreeStubServer::eth_newFilterExI); this->bindAndAddMethod(jsonrpc::Procedure("eth_newBlockFilter", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_newBlockFilterI); this->bindAndAddMethod(jsonrpc::Procedure("eth_newPendingTransactionFilter", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_newPendingTransactionFilterI); this->bindAndAddMethod(jsonrpc::Procedure("eth_uninstallFilter", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_uninstallFilterI); this->bindAndAddMethod(jsonrpc::Procedure("eth_getFilterChanges", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_getFilterChangesI); + this->bindAndAddMethod(jsonrpc::Procedure("eth_getFilterChangesEx", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_getFilterChangesExI); this->bindAndAddMethod(jsonrpc::Procedure("eth_getFilterLogs", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_getFilterLogsI); + this->bindAndAddMethod(jsonrpc::Procedure("eth_getFilterLogsEx", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_getFilterLogsExI); this->bindAndAddMethod(jsonrpc::Procedure("eth_getLogs", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, "param1",jsonrpc::JSON_OBJECT, NULL), &AbstractWebThreeStubServer::eth_getLogsI); this->bindAndAddMethod(jsonrpc::Procedure("eth_getWork", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, NULL), &AbstractWebThreeStubServer::eth_getWorkI); this->bindAndAddMethod(jsonrpc::Procedure("eth_submitWork", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING,"param3",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_submitWorkI); @@ -227,6 +230,10 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServereth_newFilter(request[0u]); } + inline virtual void eth_newFilterExI(const Json::Value &request, Json::Value &response) + { + response = this->eth_newFilterEx(request[0u]); + } inline virtual void eth_newBlockFilterI(const Json::Value &request, Json::Value &response) { (void)request; @@ -245,10 +252,18 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServereth_getFilterChanges(request[0u].asString()); } + inline virtual void eth_getFilterChangesExI(const Json::Value &request, Json::Value &response) + { + response = this->eth_getFilterChangesEx(request[0u].asString()); + } inline virtual void eth_getFilterLogsI(const Json::Value &request, Json::Value &response) { response = this->eth_getFilterLogs(request[0u].asString()); } + inline virtual void eth_getFilterLogsExI(const Json::Value &request, Json::Value &response) + { + response = this->eth_getFilterLogsEx(request[0u].asString()); + } inline virtual void eth_getLogsI(const Json::Value &request, Json::Value &response) { response = this->eth_getLogs(request[0u]); @@ -364,13 +379,16 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServer const& _accounts WriteGuard l(x_state); Guard fl(x_filtersWatches); m_filters.clear(); + for (auto& i: m_specialFilters) + i.second.clear(); m_watches.clear(); m_stateDB = OverlayDB(); @@ -254,7 +256,7 @@ void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _c h256Set changed; Guard l(x_filtersWatches); for (std::pair& i: m_filters) - if ((unsigned)i.second.filter.latest() > bc().number()) + if (compareBlockHashes(i.second.filter.latest(), bc().currentHash()) > 0) { // acceptable number. auto m = i.second.filter.matches(_state.receipt(_state.pending().size() - 1)); @@ -262,11 +264,12 @@ void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _c { // filter catches them for (LogEntry const& l: m) - i.second.changes.push_back(LocalisedLogEntry(l, bc().number() + 1)); + i.second.changes.push_back(LocalisedLogEntry(l)); changed.insert(i.first); } } changed.insert(dev::eth::PendingChangedFilter); + m_specialFilters.at(dev::eth::PendingChangedFilter).push_back(t.sha3()); noteChanged(changed); } WriteGuard l(x_executions); @@ -281,7 +284,7 @@ void MixClient::mine() bc().import(m_state.blockData(), m_state.db(), ImportRequirements::Default & ~ImportRequirements::ValidNonce); m_state.sync(bc()); m_startState = m_state; - h256Set changed { dev::eth::PendingChangedFilter, dev::eth::ChainChangedFilter }; + h256Set changed { dev::eth::ChainChangedFilter }; noteChanged(changed); } @@ -376,11 +379,14 @@ void MixClient::noteChanged(h256Set const& _filters) { if (m_filters.count(i.second.id)) i.second.changes += m_filters.at(i.second.id).changes; - else - i.second.changes.push_back(LocalisedLogEntry(SpecialLogEntry, 0)); + else if (m_specialFilters.count(i.second.id)) + for (h256 const& hash: m_specialFilters.at(i.second.id)) + i.second.changes.push_back(LocalisedLogEntry(SpecialLogEntry, hash)); } for (auto& i: m_filters) i.second.changes.clear(); + for (auto& i: m_specialFilters) + i.second.clear(); } eth::BlockInfo MixClient::blockInfo() const diff --git a/test/libweb3jsonrpc/webthreestubclient.h b/test/libweb3jsonrpc/webthreestubclient.h index 99fe48034..9123b0671 100644 --- a/test/libweb3jsonrpc/webthreestubclient.h +++ b/test/libweb3jsonrpc/webthreestubclient.h @@ -354,13 +354,13 @@ class WebThreeStubClient : public jsonrpc::Client else throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); } - std::string eth_compileSolidity(const std::string& param1) throw (jsonrpc::JsonRpcException) + Json::Value eth_compileSolidity(const std::string& param1) throw (jsonrpc::JsonRpcException) { Json::Value p; p.append(param1); Json::Value result = this->CallMethod("eth_compileSolidity",p); - if (result.isString()) - return result.asString(); + if (result.isObject()) + return result; else throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); } @@ -374,6 +374,16 @@ class WebThreeStubClient : public jsonrpc::Client else throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); } + std::string eth_newFilterEx(const Json::Value& param1) throw (jsonrpc::JsonRpcException) + { + Json::Value p; + p.append(param1); + Json::Value result = this->CallMethod("eth_newFilterEx",p); + if (result.isString()) + return result.asString(); + else + throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); + } std::string eth_newBlockFilter() throw (jsonrpc::JsonRpcException) { Json::Value p; @@ -414,6 +424,16 @@ class WebThreeStubClient : public jsonrpc::Client else throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); } + Json::Value eth_getFilterChangesEx(const std::string& param1) throw (jsonrpc::JsonRpcException) + { + Json::Value p; + p.append(param1); + Json::Value result = this->CallMethod("eth_getFilterChangesEx",p); + if (result.isArray()) + return result; + else + throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); + } Json::Value eth_getFilterLogs(const std::string& param1) throw (jsonrpc::JsonRpcException) { Json::Value p; @@ -424,6 +444,16 @@ class WebThreeStubClient : public jsonrpc::Client else throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); } + Json::Value eth_getFilterLogsEx(const std::string& param1) throw (jsonrpc::JsonRpcException) + { + Json::Value p; + p.append(param1); + Json::Value result = this->CallMethod("eth_getFilterLogsEx",p); + if (result.isArray()) + return result; + else + throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); + } Json::Value eth_getLogs(const Json::Value& param1) throw (jsonrpc::JsonRpcException) { Json::Value p;