diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index e88086e0d..848020cbc 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -212,7 +212,7 @@ Main::Main(QWidget *parent) : m_httpConnector.reset(new jsonrpc::HttpServer(SensibleHttpPort, "", "", dev::SensibleHttpThreads)); auto w3ss = new OurWebThreeStubServer(*m_httpConnector, this); m_server.reset(w3ss); - auto sessionKey = w3ss->newSession({true}); + auto sessionKey = w3ss->newSession(SessionPermissions{{Priviledge::Admin}}); connect(&*m_server, SIGNAL(onNewId(QString)), SLOT(addNewId(QString))); m_server->setIdentities(keysAsVector(owned())); m_server->StartListening(); @@ -1922,7 +1922,7 @@ void Main::on_clearPending_triggered() void Main::on_retryUnknown_triggered() { - ethereum()->retryUnkonwn(); + ethereum()->retryUnknown(); } void Main::on_killBlockchain_triggered() @@ -1941,11 +1941,7 @@ void Main::on_net_triggered() { ui->port->setEnabled(!ui->net->isChecked()); ui->clientName->setEnabled(!ui->net->isChecked()); - string n = string("AlethZero/v") + dev::Version; - if (ui->clientName->text().size()) - n += "/" + ui->clientName->text().toStdString(); - n += "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM); - web3()->setClientVersion(n); + web3()->setClientVersion(WebThreeDirect::composeClientVersion("AlethZero", ui->clientName->text().toStdString())); if (ui->net->isChecked()) { web3()->setIdealPeerCount(ui->idealPeers->value()); diff --git a/alethzero/OurWebThreeStubServer.cpp b/alethzero/OurWebThreeStubServer.cpp index 39ab69a19..e18cb55d5 100644 --- a/alethzero/OurWebThreeStubServer.cpp +++ b/alethzero/OurWebThreeStubServer.cpp @@ -33,7 +33,7 @@ OurWebThreeStubServer::OurWebThreeStubServer( jsonrpc::AbstractServerConnector& _conn, Main* _main ): - WebThreeStubServer(_conn, *_main->web3(), make_shared(_main), _main->owned().toVector().toStdVector(), _main->keyManager()), + WebThreeStubServer(_conn, *_main->web3(), make_shared(_main), _main->owned().toVector().toStdVector(), _main->keyManager(), *static_cast(_main->ethereum()->gasPricer().get())), m_main(_main) { } diff --git a/alethzero/OurWebThreeStubServer.h b/alethzero/OurWebThreeStubServer.h index 43985b640..cc950027e 100644 --- a/alethzero/OurWebThreeStubServer.h +++ b/alethzero/OurWebThreeStubServer.h @@ -59,7 +59,7 @@ private: Main* m_main; }; -class OurWebThreeStubServer: public QObject, public WebThreeStubServer +class OurWebThreeStubServer: public QObject, public dev::WebThreeStubServer { Q_OBJECT diff --git a/eth/main.cpp b/eth/main.cpp index 4b23ef62a..382858ae7 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -685,9 +685,8 @@ int main(int argc, char** argv) VMFactory::setKind(jit ? VMKind::JIT : VMKind::Interpreter); auto netPrefs = publicIP.empty() ? NetworkPreferences(listenIP ,listenPort, upnp) : NetworkPreferences(publicIP, listenIP ,listenPort, upnp); auto nodesState = contents((dbPath.size() ? dbPath : getDataDir()) + "/network.rlp"); - std::string clientImplString = "++eth/" + clientName + "v" + dev::Version + "-" + string(DEV_QUOTED(ETH_COMMIT_HASH)).substr(0, 8) + (ETH_CLEAN_REPO ? "" : "*") + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM) + (jit ? "/JIT" : ""); dev::WebThreeDirect web3( - clientImplString, + WebThreeDirect::composeClientVersion("++eth", clientName), dbPath, killChain, nodeMode == NodeMode::Full ? set{"eth"/*, "shh"*/} : set(), @@ -800,7 +799,7 @@ int main(int argc, char** argv) // std::shared_ptr gasPricer = make_shared(u256(double(ether / 1000) / etherPrice), u256(blockFees * 1000)); std::shared_ptr gasPricer = make_shared(askPrice, bidPrice); eth::Client* c = nodeMode == NodeMode::Full ? web3.ethereum() : nullptr; - StructuredLogger::starting(clientImplString, dev::Version); + StructuredLogger::starting(WebThreeDirect::composeClientVersion("++eth", clientName), dev::Version); if (c) { c->setGasPricer(gasPricer); @@ -827,12 +826,12 @@ int main(int argc, char** argv) if (jsonrpc > -1) { jsonrpcConnector = unique_ptr(new jsonrpc::HttpServer(jsonrpc, "", "", SensibleHttpThreads)); - jsonrpcServer = shared_ptr(new WebThreeStubServer(*jsonrpcConnector.get(), web3, make_shared([&](){return web3.ethereum();}, getAccountPassword, keyManager), vector(), keyManager)); + jsonrpcServer = shared_ptr(new WebThreeStubServer(*jsonrpcConnector.get(), web3, make_shared([&](){ return web3.ethereum(); }, getAccountPassword, keyManager), vector(), keyManager, *gasPricer)); jsonrpcServer->StartListening(); if (jsonAdmin.empty()) - jsonAdmin = jsonrpcServer->newSession(SessionPermissions{true}); + jsonAdmin = jsonrpcServer->newSession(SessionPermissions{{Priviledge::Admin}}); else - jsonrpcServer->addSession(jsonAdmin, SessionPermissions{true}); + jsonrpcServer->addSession(jsonAdmin, SessionPermissions{{Priviledge::Admin}}); cout << "JSONRPC Admin Session Key: " << jsonAdmin << endl; } #endif @@ -982,12 +981,12 @@ int main(int argc, char** argv) if (jsonrpc < 0) jsonrpc = SensibleHttpPort; jsonrpcConnector = unique_ptr(new jsonrpc::HttpServer(jsonrpc, "", "", SensibleHttpThreads)); - jsonrpcServer = shared_ptr(new WebThreeStubServer(*jsonrpcConnector.get(), web3, make_shared([&](){ return web3.ethereum(); }, getAccountPassword, keyManager), vector(), keyManager)); + jsonrpcServer = shared_ptr(new WebThreeStubServer(*jsonrpcConnector.get(), web3, make_shared([&](){ return web3.ethereum(); }, getAccountPassword, keyManager), vector(), keyManager, *gasPricer)); jsonrpcServer->StartListening(); if (jsonAdmin.empty()) - jsonAdmin = jsonrpcServer->newSession(SessionPermissions{true}); + jsonAdmin = jsonrpcServer->newSession(SessionPermissions{{Priviledge::Admin}}); else - jsonrpcServer->addSession(jsonAdmin, SessionPermissions{true}); + jsonrpcServer->addSession(jsonAdmin, SessionPermissions{{Priviledge::Admin}}); cout << "JSONRPC Admin Session Key: " << jsonAdmin << endl; } else if (cmd == "jsonstop") @@ -1083,7 +1082,7 @@ int main(int argc, char** argv) } else if (c && cmd == "retryunknown") { - c->retryUnkonwn(); + c->retryUnknown(); } else if (cmd == "peers") { @@ -1520,7 +1519,7 @@ int main(int argc, char** argv) ofstream f; f.open(filename); - dev::eth::State state =c->state(index + 1,c->blockChain().numberHash(block)); + dev::eth::State state = c->state(index + 1,c->blockChain().numberHash(block)); if (index < state.pending().size()) { Executive e(state, c->blockChain(), 0); @@ -1712,7 +1711,7 @@ int main(int argc, char** argv) while (!g_exit) this_thread::sleep_for(chrono::milliseconds(1000)); - StructuredLogger::stopping(clientImplString, dev::Version); + StructuredLogger::stopping(WebThreeDirect::composeClientVersion("++eth", clientName), dev::Version); auto netData = web3.saveNetwork(); if (!netData.empty()) writeFile((dbPath.size() ? dbPath : getDataDir()) + "/network.rlp", netData); diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 31c2e8026..2f742f658 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -879,7 +879,9 @@ State Client::asOf(h256 const& _block) const { try { - return State(m_stateDB, bc(), _block); + State ret(m_stateDB); + ret.populateFromChain(bc(), _block); + return ret; } catch (Exception& ex) { @@ -896,12 +898,36 @@ void Client::prepareForTransaction() State Client::state(unsigned _txi, h256 _block) const { - return State(m_stateDB, m_bc, _block).fromPending(_txi); + try + { + State ret(m_stateDB); + ret.populateFromChain(m_bc, _block); + return ret.fromPending(_txi); + } + catch (Exception& ex) + { + ex << errinfo_block(bc().block(_block)); + onBadBlock(ex); + return State(); + } } -eth::State Client::state(h256 _block) const +State Client::state(h256 const& _block, PopulationStatistics* o_stats) const { - return State(m_stateDB, m_bc, _block); + try + { + State ret(m_stateDB); + PopulationStatistics s = ret.populateFromChain(m_bc, _block); + if (o_stats) + swap(s, *o_stats); + return ret; + } + catch (Exception& ex) + { + ex << errinfo_block(bc().block(_block)); + onBadBlock(ex); + return State(); + } } eth::State Client::state(unsigned _txi) const diff --git a/libethereum/Client.h b/libethereum/Client.h index b70f01155..c8aad1670 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -147,7 +147,7 @@ public: // [PRIVATE API - only relevant for base clients, not available in general] dev::eth::State state(unsigned _txi, h256 _block) const; - dev::eth::State state(h256 _block) const; + dev::eth::State state(h256 const& _block, PopulationStatistics* o_stats = nullptr) const; dev::eth::State state(unsigned _txi) const; /// Get the object representing the current state of Ethereum. @@ -226,7 +226,7 @@ public: /// Kills the blockchain. Just for debug use. void killChain(); /// Retries all blocks with unknown parents. - void retryUnkonwn() { m_bq.retryAllUnknown(); } + void retryUnknown() { m_bq.retryAllUnknown(); } /// Get a report of activity. ActivityReport activityReport() { ActivityReport ret; std::swap(m_report, ret); return ret; } /// Set a JSONRPC server to which we can report bad blocks. diff --git a/libethereum/EthereumHost.cpp b/libethereum/EthereumHost.cpp index 67a21d36a..bacbecc3f 100644 --- a/libethereum/EthereumHost.cpp +++ b/libethereum/EthereumHost.cpp @@ -619,7 +619,7 @@ void EthereumHost::onPeerAborting(EthereumPeer* _peer) if (_peer->isConversing()) { _peer->setIdle(); - if (_peer->isCriticalSyncing()) +// if (_peer->isCriticalSyncing()) _peer->setRude(); continueSync(); } diff --git a/libethereum/EthereumPeer.cpp b/libethereum/EthereumPeer.cpp index 7a30f1ad9..b876bf019 100644 --- a/libethereum/EthereumPeer.cpp +++ b/libethereum/EthereumPeer.cpp @@ -48,7 +48,6 @@ EthereumPeer::EthereumPeer(Session* _s, HostCapabilityFace* _h, unsigned _i, Cap EthereumPeer::~EthereumPeer() { - clog(NetMessageSummary) << "Aborting Sync :-("; abortSync(); } @@ -57,8 +56,15 @@ bool EthereumPeer::isRude() const return repMan().isRude(*session(), name()); } +unsigned EthereumPeer::askOverride() const +{ + bytes const& d = repMan().data(*session(), name()); + return d.empty() ? c_maxBlocksAsk : RLP(d).toInt(RLP::LaisezFaire); +} + void EthereumPeer::setRude() { + repMan().setData(*session(), name(), rlp(askOverride() / 2 + 1)); repMan().noteRude(*session(), name()); session()->addNote("manners", "RUDE"); } @@ -140,7 +146,7 @@ void EthereumPeer::requestHashes(h256 const& _lastHash) void EthereumPeer::requestBlocks() { setAsking(Asking::Blocks); - auto blocks = m_sub.nextFetch(isRude() ? 1 : c_maxBlocksAsk); + auto blocks = m_sub.nextFetch(askOverride()); if (blocks.size()) { RLPStream s; diff --git a/libethereum/EthereumPeer.h b/libethereum/EthereumPeer.h index a12b7a197..e9d29322f 100644 --- a/libethereum/EthereumPeer.h +++ b/libethereum/EthereumPeer.h @@ -91,6 +91,9 @@ public: private: using p2p::Capability::sealAndSend; + /// Figure out the amount of blocks we should be asking for. + unsigned askOverride() const; + /// Interpret an incoming message. virtual bool interpret(unsigned _id, RLP const& _r); diff --git a/libethereum/Executive.h b/libethereum/Executive.h index 4976ce03a..41a8d1961 100644 --- a/libethereum/Executive.h +++ b/libethereum/Executive.h @@ -53,6 +53,8 @@ public: std::string json(bool _styled = false) const; + OnOpFunc onOp() { return [&](uint64_t _steps, Instruction _inst, bigint _newMemSize, bigint _gasCost, bigint _gas, VM* _vm, ExtVMFace const* _extVM) { (*this)(_steps, _inst, _newMemSize, _gasCost, _gas, _vm, _extVM); }; } + private: bool m_showMnemonics = false; std::vector m_lastInst; diff --git a/libethereum/State.cpp b/libethereum/State.cpp index a4b784b6f..f56c12c91 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -115,21 +115,19 @@ State::State(OverlayDB const& _db, BaseState _bs, Address _coinbaseAddress): paranoia("end of normal construction.", true); } -State::State(OverlayDB const& _db, BlockChain const& _bc, h256 _h, ImportRequirements::value _ir): - m_db(_db), - m_state(&m_db), - m_blockReward(c_blockReward) +PopulationStatistics State::populateFromChain(BlockChain const& _bc, h256 const& _h, ImportRequirements::value _ir) { - auto b = _bc.block(_h); - BlockInfo bi(b); + PopulationStatistics ret; - if (!bi) + if (!_bc.isKnown(_h)) { // Might be worth throwing here. cwarn << "Invalid block given for state population: " << _h; - return; + return ret; } + auto b = _bc.block(_h); + BlockInfo bi(b); if (bi.number) { // Non-genesis: @@ -143,10 +141,10 @@ State::State(OverlayDB const& _db, BlockChain const& _bc, h256 _h, ImportRequire m_ourAddress = bi.coinbaseAddress; boost::timer t; auto vb = BlockChain::verifyBlock(b); - cnote << "verifyBlock:" << t.elapsed(); + ret.verify = t.elapsed(); t.restart(); enact(vb, _bc, _ir); - cnote << "enact:" << t.elapsed(); + ret.enact = t.elapsed(); } else { @@ -155,6 +153,8 @@ State::State(OverlayDB const& _db, BlockChain const& _bc, h256 _h, ImportRequire m_state.init(); sync(_bc, _h, bi, _ir); } + + return ret; } State::State(State const& _s): @@ -600,7 +600,7 @@ string State::vmTrace(bytesConstRef _block, BlockChain const& _bc, ImportRequire { StandardTrace st; st.setShowMnemonics(); - execute(lh, Transaction(tr.data(), CheckTransaction::Everything), Permanence::Committed, [&](uint64_t _steps, Instruction _inst, bigint _newMemSize, bigint _gasCost, bigint _gas, VM* _vm, ExtVMFace const* _extVM) { st(_steps, _inst, _newMemSize, _gasCost, _gas, _vm, _extVM); }); + execute(lh, Transaction(tr.data(), CheckTransaction::Everything), Permanence::Committed, st.onOp()); ret += (ret.empty() ? "[" : ",") + st.json(); RLPStream receiptRLP; diff --git a/libethereum/State.h b/libethereum/State.h index 771cdb6bf..3eac63d04 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -123,6 +123,12 @@ enum class Permanence Committed }; +struct PopulationStatistics +{ + double verify; + double enact; +}; + /** * @brief Model of the current state of the ledger. * Maintains current ledger (m_current) as a fast hash-map. This is hashed only when required (i.e. to create or verify a block). @@ -146,9 +152,6 @@ public: /// You can also set the coinbase address. explicit State(OverlayDB const& _db, BaseState _bs = BaseState::PreExisting, Address _coinbaseAddress = Address()); - /// Construct state object from arbitrary point in blockchain. - State(OverlayDB const& _db, BlockChain const& _bc, h256 _hash, ImportRequirements::value _ir = ImportRequirements::Default); - /// Copy state object. State(State const& _s); @@ -157,6 +160,9 @@ public: ~State(); + /// Construct state object from arbitrary point in blockchain. + PopulationStatistics populateFromChain(BlockChain const& _bc, h256 const& _hash, ImportRequirements::value _ir = ImportRequirements::Default); + /// Set the coinbase address for any transactions we do. /// This causes a complete reset of current block. void setAddress(Address _coinbaseAddress) { m_ourAddress = _coinbaseAddress; resetCurrent(); } diff --git a/libevm/ExtVMFace.h b/libevm/ExtVMFace.h index 357292853..f6cab376a 100644 --- a/libevm/ExtVMFace.h +++ b/libevm/ExtVMFace.h @@ -63,12 +63,16 @@ using LogEntries = std::vector; struct LocalisedLogEntry: public LogEntry { LocalisedLogEntry() {} - explicit LocalisedLogEntry(LogEntry const& _le): LogEntry(_le) {}; + explicit LocalisedLogEntry(LogEntry const& _le): LogEntry(_le) {} explicit LocalisedLogEntry( LogEntry const& _le, h256 _special - ): LogEntry(_le), special(_special) {}; + ): + LogEntry(_le), + isSpecial(true), + special(_special) + {} explicit LocalisedLogEntry( LogEntry const& _le, @@ -76,15 +80,24 @@ struct LocalisedLogEntry: public LogEntry 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(); + ): + LogEntry(_le), + blockHash(_bi.hash()), + blockNumber((BlockNumber)_bi.number), + transactionHash(_th), + transactionIndex(_ti), + logIndex(_li), + mined(true) + {} + + h256 blockHash; BlockNumber blockNumber = 0; - h256 transactionHash = h256(); + h256 transactionHash; unsigned transactionIndex = 0; unsigned logIndex = 0; bool mined = false; - h256 special = h256(); + bool isSpecial = false; + h256 special; }; using LocalisedLogEntries = std::vector; diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index 55389ed1b..1482719c6 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -79,6 +79,25 @@ bool ReputationManager::isRude(Session const& _s, std::string const& _sub) const return false; } +void ReputationManager::setData(Session const& _s, std::string const& _sub, bytes const& _data) +{ + DEV_WRITE_GUARDED(x_nodes) + m_nodes[make_pair(_s.id(), _s.info().clientVersion)].subs[_sub].data = _data; +} + +bytes ReputationManager::data(Session const& _s, std::string const& _sub) const +{ + DEV_READ_GUARDED(x_nodes) + { + auto nit = m_nodes.find(make_pair(_s.id(), _s.info().clientVersion)); + if (nit == m_nodes.end()) + return bytes(); + auto sit = nit->second.subs.find(_sub); + return sit == nit->second.subs.end() ? bytes() : sit->second.data; + } + return bytes(); +} + Host::Host(std::string const& _clientVersion, NetworkPreferences const& _n, bytesConstRef _restoreNetwork): Worker("p2p", 0), m_restoreNetwork(_restoreNetwork.toBytes()), diff --git a/libp2p/Host.h b/libp2p/Host.h index e9cae509c..9523d0cca 100644 --- a/libp2p/Host.h +++ b/libp2p/Host.h @@ -83,6 +83,7 @@ struct SubReputation { bool isRude = false; int utility = 0; + bytes data; }; struct Reputation @@ -97,6 +98,8 @@ public: void noteRude(Session const& _s, std::string const& _sub = std::string()); bool isRude(Session const& _s, std::string const& _sub = std::string()) const; + void setData(Session const& _s, std::string const& _sub, bytes const& _data); + bytes data(Session const& _s, std::string const& _subs) const; private: std::unordered_map, Reputation> m_nodes; ///< Nodes that were impolite while syncing. We avoid syncing from these if possible. diff --git a/libtestutils/FixedClient.cpp b/libtestutils/FixedClient.cpp index 052141039..4237415ed 100644 --- a/libtestutils/FixedClient.cpp +++ b/libtestutils/FixedClient.cpp @@ -28,5 +28,7 @@ using namespace dev::test; eth::State FixedClient::asOf(h256 const& _h) const { ReadGuard l(x_stateDB); - return State(m_state.db(), bc(), _h); + State ret(m_state.db()); + ret.populateFromChain(bc(), _h); + return ret; } diff --git a/libweb3jsonrpc/JsonHelper.cpp b/libweb3jsonrpc/JsonHelper.cpp new file mode 100644 index 000000000..0b6cd4a1d --- /dev/null +++ b/libweb3jsonrpc/JsonHelper.cpp @@ -0,0 +1,427 @@ +/* + 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 JsonHelper.cpp + * @authors: + * Gav Wood + * @date 2014 + */ + +#include "JsonHelper.h" + +#include +#include +#include +#include +#include +#include +#include +using namespace std; +using namespace dev; +using namespace eth; + +namespace dev +{ + +Json::Value toJson(unordered_map const& _storage) +{ + Json::Value res(Json::objectValue); + for (auto i: _storage) + res[toJS(i.first)] = toJS(i.second); + return res; +} + +Json::Value toJson(map const& _storage) +{ + Json::Value res(Json::objectValue); + for (auto i: _storage) + res[toJS(i.first)] = toJS(i.second); + return res; +} + +// //////////////////////////////////////////////////////////////////////////////// +// p2p +// //////////////////////////////////////////////////////////////////////////////// +namespace p2p +{ + +Json::Value toJson(p2p::PeerSessionInfo const& _p) +{ + Json::Value ret; + ret["id"] = _p.id.hex(); + ret["clientVersion"] = _p.clientVersion; + ret["host"] = _p.host; + ret["port"] = _p.port; + ret["lastPing"] = (int)chrono::duration_cast(_p.lastPing).count(); + for (auto const& i: _p.notes) + ret["notes"][i.first] = i.second; + for (auto const& i: _p.caps) + ret["caps"][i.first] = (unsigned)i.second; + return ret; +} + +} + +// //////////////////////////////////////////////////////////////////////////////// +// eth +// //////////////////////////////////////////////////////////////////////////////// + +namespace eth +{ + +Json::Value toJson(dev::eth::BlockInfo const& _bi) +{ + Json::Value res; + if (_bi) + { + res["hash"] = toJS(_bi.hash()); + res["parentHash"] = toJS(_bi.parentHash); + res["sha3Uncles"] = toJS(_bi.sha3Uncles); + res["miner"] = toJS(_bi.coinbaseAddress); + res["stateRoot"] = toJS(_bi.stateRoot); + res["transactionsRoot"] = toJS(_bi.transactionsRoot); + res["difficulty"] = toJS(_bi.difficulty); + res["number"] = toJS(_bi.number); + res["gasUsed"] = toJS(_bi.gasUsed); + res["gasLimit"] = toJS(_bi.gasLimit); + res["timestamp"] = toJS(_bi.timestamp); + res["extraData"] = toJS(_bi.extraData); + res["nonce"] = toJS(_bi.nonce); + res["logsBloom"] = toJS(_bi.logBloom); + + res["seedHash"] = toJS(_bi.seedHash()); + res["target"] = toJS(_bi.boundary()); + } + return res; +} + +Json::Value toJson(dev::eth::Transaction const& _t, std::pair _location, BlockNumber _blockNumber) +{ + Json::Value res; + if (_t) + { + res["hash"] = toJS(_t.sha3()); + res["input"] = toJS(_t.data()); + res["to"] = _t.isCreation() ? Json::Value() : toJS(_t.receiveAddress()); + res["from"] = toJS(_t.safeSender()); + res["gas"] = toJS(_t.gas()); + res["gasPrice"] = toJS(_t.gasPrice()); + res["nonce"] = toJS(_t.nonce()); + res["value"] = toJS(_t.value()); + res["blockHash"] = toJS(_location.first); + res["transactionIndex"] = toJS(_location.second); + res["blockNumber"] = toJS(_blockNumber); + } + return res; +} + +Json::Value toJson(dev::eth::BlockInfo const& _bi, BlockDetails const& _bd, UncleHashes const& _us, Transactions const& _ts) +{ + Json::Value res = toJson(_bi); + if (_bi) + { + res["totalDifficulty"] = toJS(_bd.totalDifficulty); + res["uncles"] = Json::Value(Json::arrayValue); + for (h256 h: _us) + res["uncles"].append(toJS(h)); + res["transactions"] = Json::Value(Json::arrayValue); + for (unsigned i = 0; i < _ts.size(); i++) + res["transactions"].append(toJson(_ts[i], std::make_pair(_bi.hash(), i), (BlockNumber)_bi.number)); + } + return res; +} + +Json::Value toJson(dev::eth::BlockInfo const& _bi, BlockDetails const& _bd, UncleHashes const& _us, TransactionHashes const& _ts) +{ + Json::Value res = toJson(_bi); + if (_bi) + { + res["totalDifficulty"] = toJS(_bd.totalDifficulty); + res["uncles"] = Json::Value(Json::arrayValue); + for (h256 h: _us) + res["uncles"].append(toJS(h)); + res["transactions"] = Json::Value(Json::arrayValue); + for (h256 const& t: _ts) + res["transactions"].append(toJS(t)); + } + return res; +} + +Json::Value toJson(dev::eth::TransactionSkeleton const& _t) +{ + Json::Value res; + res["to"] = _t.creation ? Json::Value() : toJS(_t.to); + res["from"] = toJS(_t.from); + res["gas"] = toJS(_t.gas); + res["gasPrice"] = toJS(_t.gasPrice); + res["value"] = toJS(_t.value); + res["data"] = toJS(_t.data, 32); + return res; +} + +Json::Value toJson(dev::eth::TransactionReceipt const& _t) +{ + Json::Value res; + res["stateRoot"] = toJS(_t.stateRoot()); + res["gasUsed"] = toJS(_t.gasUsed()); + res["bloom"] = toJS(_t.bloom()); + res["log"] = dev::toJson(_t.log()); + return res; +} + +Json::Value toJson(dev::eth::Transaction const& _t) +{ + Json::Value res; + res["to"] = _t.isCreation() ? Json::Value() : toJS(_t.to()); + res["from"] = toJS(_t.from()); + res["gas"] = toJS(_t.gas()); + res["gasPrice"] = toJS(_t.gasPrice()); + res["value"] = toJS(_t.value()); + res["data"] = toJS(_t.data(), 32); + res["nonce"] = toJS(_t.nonce()); + res["hash"] = toJS(_t.sha3(WithSignature)); + res["sighash"] = toJS(_t.sha3(WithoutSignature)); + res["r"] = toJS(_t.signature().r); + res["s"] = toJS(_t.signature().s); + res["v"] = toJS(_t.signature().v); + return res; +} + +Json::Value toJson(dev::eth::LocalisedLogEntry const& _e) +{ + Json::Value res; + + if (_e.isSpecial) + res = toJS(_e.special); + else + { + res = toJson(static_cast(_e)); + 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); + } + } + return res; +} + +Json::Value toJson(dev::eth::LogEntry const& _e) +{ + Json::Value res; + 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)); + return res; +} + +TransactionSkeleton toTransactionSkeleton(Json::Value const& _json) +{ + TransactionSkeleton ret; + if (!_json.isObject() || _json.empty()) + return ret; + + if (!_json["from"].empty()) + ret.from = jsToAddress(_json["from"].asString()); + if (!_json["to"].empty() && _json["to"].asString() != "0x") + ret.to = jsToAddress(_json["to"].asString()); + else + ret.creation = true; + + if (!_json["value"].empty()) + ret.value = jsToU256(_json["value"].asString()); + + if (!_json["gas"].empty()) + ret.gas = jsToU256(_json["gas"].asString()); + + if (!_json["gasPrice"].empty()) + ret.gasPrice = jsToU256(_json["gasPrice"].asString()); + + if (!_json["data"].empty()) // ethereum.js has preconstructed the data array + ret.data = jsToBytes(_json["data"].asString()); + + if (!_json["code"].empty()) + ret.data = jsToBytes(_json["code"].asString()); + return ret; +} + +dev::eth::LogFilter toLogFilter(Json::Value const& _json) +{ + 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(jsToFixed<32>(_json["fromBlock"].asString())); + if (!_json["toBlock"].empty()) + 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 +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()) + 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; +} + +} + +// //////////////////////////////////////////////////////////////////////////////////// +// shh +// //////////////////////////////////////////////////////////////////////////////////// + +namespace shh +{ + +Json::Value toJson(h256 const& _h, shh::Envelope const& _e, shh::Message const& _m) +{ + Json::Value res; + res["hash"] = toJS(_h); + res["expiry"] = toJS(_e.expiry()); + res["sent"] = toJS(_e.sent()); + res["ttl"] = toJS(_e.ttl()); + res["workProved"] = toJS(_e.workProved()); + res["topics"] = Json::Value(Json::arrayValue); + for (auto const& t: _e.topic()) + res["topics"].append(toJS(t)); + res["payload"] = toJS(_m.payload()); + res["from"] = toJS(_m.from()); + res["to"] = toJS(_m.to()); + return res; +} + +shh::Message toMessage(Json::Value const& _json) +{ + shh::Message ret; + if (!_json["from"].empty()) + ret.setFrom(jsToPublic(_json["from"].asString())); + if (!_json["to"].empty()) + ret.setTo(jsToPublic(_json["to"].asString())); + if (!_json["payload"].empty()) + ret.setPayload(jsToBytes(_json["payload"].asString())); + return ret; +} + +shh::Envelope toSealed(Json::Value const& _json, shh::Message const& _m, Secret _from) +{ + unsigned ttl = 50; + unsigned workToProve = 50; + shh::BuildTopic bt; + + if (!_json["ttl"].empty()) + ttl = jsToInt(_json["ttl"].asString()); + + if (!_json["workToProve"].empty()) + workToProve = jsToInt(_json["workToProve"].asString()); + + if (!_json["topics"].empty()) + for (auto i: _json["topics"]) + { + if (i.isArray()) + { + for (auto j: i) + if (!j.isNull()) + bt.shift(jsToBytes(j.asString())); + } + else if (!i.isNull()) // if it is anything else then string, it should and will fail + bt.shift(jsToBytes(i.asString())); + } + + return _m.seal(_from, bt, ttl, workToProve); +} + +pair toWatch(Json::Value const& _json) +{ + shh::BuildTopic bt; + Public to; + + if (!_json["to"].empty()) + to = jsToPublic(_json["to"].asString()); + + if (!_json["topics"].empty()) + for (auto i: _json["topics"]) + bt.shift(jsToBytes(i.asString())); + + return make_pair(bt, to); +} + +} + +} diff --git a/libweb3jsonrpc/JsonHelper.h b/libweb3jsonrpc/JsonHelper.h new file mode 100644 index 000000000..d445ad0dc --- /dev/null +++ b/libweb3jsonrpc/JsonHelper.h @@ -0,0 +1,104 @@ +/* + 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 JsonHelper.h + * @authors: + * Gav Wood + * @date 2015 + */ +#pragma once + +#include +#include +#include +#include + +namespace dev +{ + +Json::Value toJson(std::map const& _storage); +Json::Value toJson(std::unordered_map const& _storage); + +namespace p2p +{ + +Json::Value toJson(PeerSessionInfo const& _p); + +} + +namespace eth +{ + +class Transaction; +class BlockDetails; +class Interface; +using Transactions = std::vector; +using UncleHashes = h256s; +using TransactionHashes = h256s; + +Json::Value toJson(BlockInfo const& _bi); +Json::Value toJson(Transaction const& _t, std::pair _location, BlockNumber _blockNumber); +Json::Value toJson(BlockInfo const& _bi, BlockDetails const& _bd, UncleHashes const& _us, Transactions const& _ts); +Json::Value toJson(BlockInfo const& _bi, BlockDetails const& _bd, UncleHashes const& _us, TransactionHashes const& _ts); +Json::Value toJson(TransactionSkeleton const& _t); +Json::Value toJson(Transaction const& _t); +Json::Value toJson(TransactionReceipt const& _t); +Json::Value toJson(LocalisedLogEntry const& _e); +Json::Value toJson(LogEntry const& _e); +TransactionSkeleton toTransactionSkeleton(Json::Value const& _json); +LogFilter toLogFilter(Json::Value const& _json); +LogFilter toLogFilter(Json::Value const& _json, Interface const& _client); // commented to avoid warning. Uncomment once in use @ PoC-7. + +} + +namespace shh +{ + +Json::Value toJson(h256 const& _h, Envelope const& _e, Message const& _m); +Message toMessage(Json::Value const& _json); +Envelope toSealed(Json::Value const& _json, Message const& _m, Secret _from); +std::pair toWatch(Json::Value const& _json); + +} + +template +Json::Value toJson(std::vector const& _es) +{ + Json::Value res(Json::arrayValue); + for (auto const& e: _es) + res.append(toJson(e)); + return res; +} + +template +Json::Value toJson(std::unordered_set const& _es) +{ + Json::Value res(Json::arrayValue); + for (auto const& e: _es) + res.append(toJson(e)); + return res; +} + +template +Json::Value toJson(std::set const& _es) +{ + Json::Value res(Json::arrayValue); + for (auto const& e: _es) + res.append(toJson(e)); + return res; +} + +} diff --git a/libweb3jsonrpc/WebThreeStubServer.cpp b/libweb3jsonrpc/WebThreeStubServer.cpp index 1bef71b59..f62fdd32a 100644 --- a/libweb3jsonrpc/WebThreeStubServer.cpp +++ b/libweb3jsonrpc/WebThreeStubServer.cpp @@ -21,21 +21,25 @@ * @date 2014 */ +#include "WebThreeStubServer.h" // Make sure boost/asio.hpp is included before windows.h. #include #include #include +#include #include +#include #include -#include "WebThreeStubServer.h" +#include "JsonHelper.h" using namespace std; using namespace dev; using namespace dev::eth; -WebThreeStubServer::WebThreeStubServer(jsonrpc::AbstractServerConnector& _conn, WebThreeDirect& _web3, shared_ptr const& _ethAccounts, std::vector const& _shhAccounts, KeyManager& _keyMan): +WebThreeStubServer::WebThreeStubServer(jsonrpc::AbstractServerConnector& _conn, WebThreeDirect& _web3, shared_ptr const& _ethAccounts, std::vector const& _shhAccounts, KeyManager& _keyMan, dev::eth::TrivialGasPricer& _gp): WebThreeStubServerBase(_conn, _ethAccounts, _shhAccounts), m_web3(_web3), - m_keyMan(_keyMan) + m_keyMan(_keyMan), + m_gp(_gp) { auto path = getDataDir() + "/.web3"; boost::filesystem::create_directories(path); @@ -57,23 +61,237 @@ bool WebThreeStubServer::eth_notePassword(string const& _password) return true; } +#define ADMIN requires(_session, Priviledge::Admin) + Json::Value WebThreeStubServer::admin_eth_blockQueueStatus(string const& _session) { + ADMIN; + Json::Value ret; + BlockQueueStatus bqs = m_web3.ethereum()->blockQueue().status(); + ret["importing"] = (int)bqs.importing; + ret["verified"] = (int)bqs.verified; + ret["verifying"] = (int)bqs.verifying; + ret["unverified"] = (int)bqs.unverified; + ret["future"] = (int)bqs.future; + ret["unknown"] = (int)bqs.unknown; + ret["bad"] = (int)bqs.bad; + return ret; +} + +bool WebThreeStubServer::admin_eth_setAskPrice(std::string const& _wei, std::string const& _session) +{ + ADMIN; + m_gp.setAsk(jsToU256(_wei)); + return true; +} + +bool WebThreeStubServer::admin_eth_setBidPrice(std::string const& _wei, std::string const& _session) +{ + ADMIN; + m_gp.setBid(jsToU256(_wei)); + return true; +} + +dev::eth::CanonBlockChain const& WebThreeStubServer::bc() const +{ + return m_web3.ethereum()->blockChain(); +} + +dev::eth::BlockQueue const& WebThreeStubServer::bq() const +{ + return m_web3.ethereum()->blockQueue(); +} + +Json::Value WebThreeStubServer::admin_eth_findBlock(std::string const& _blockHash, std::string const& _session) +{ + ADMIN; + h256 h(_blockHash); + if (bc().isKnown(h)) + return toJson(bc().info(h)); + switch(bq().blockStatus(h)) + { + case QueueStatus::Ready: + return "ready"; + case QueueStatus::Importing: + return "importing"; + case QueueStatus::UnknownParent: + return "unknown parent"; + case QueueStatus::Bad: + return "bad"; + default: + return "unknown"; + } +} + +std::string WebThreeStubServer::admin_eth_blockQueueFirstUnknown(std::string const& _session) +{ + ADMIN; + return bq().firstUnknown().hex(); +} + +bool WebThreeStubServer::admin_eth_blockQueueRetryUnknown(std::string const& _session) +{ + ADMIN; + m_web3.ethereum()->retryUnknown(); + return true; +} + +Json::Value WebThreeStubServer::admin_eth_allAccounts(std::string const& _session) +{ + ADMIN; + Json::Value ret; + u256 total = 0; + u256 pendingtotal = 0; + Address beneficiary; + for (auto const& i: m_keyMan.accountDetails()) + { + auto pending = m_web3.ethereum()->balanceAt(i.first, PendingBlock); + auto latest = m_web3.ethereum()->balanceAt(i.first, LatestBlock); + Json::Value a; + if (i.first == beneficiary) + a["beneficiary"] = true; + a["address"] = toJS(i.first); + a["balance"] = toJS(latest); + a["nicebalance"] = formatBalance(latest); + a["pending"] = toJS(pending); + a["nicepending"] = formatBalance(pending); + ret["accounts"][i.second.first] = a; + total += latest; + pendingtotal += pending; + } + ret["total"] = toJS(total); + ret["nicetotal"] = formatBalance(total); + ret["pendingtotal"] = toJS(pendingtotal); + ret["nicependingtotal"] = formatBalance(pendingtotal); + return ret; +} + +Json::Value WebThreeStubServer::admin_eth_newAccount(Json::Value const& _info, std::string const& _session) +{ + ADMIN; + if (!_info.isMember("name")) + throw jsonrpc::JsonRpcException("No member found: name"); + string name = _info["name"].asString(); + auto s = Secret::random(); + h128 uuid; + if (_info.isMember("password")) + { + string password = _info["password"].asString(); + string hint = _info["passwordHint"].asString(); + uuid = m_keyMan.import(s, name, password, hint); + } + else + uuid = m_keyMan.import(s, name); Json::Value ret; - if (isAdmin(_session)) + ret["account"] = toJS(toAddress(s)); + ret["uuid"] = toUUID(uuid); + return ret; +} + +bool WebThreeStubServer::admin_eth_setMiningBenefactor(std::string const& _uuidOrAddress, std::string const& _session) +{ + ADMIN; + (void)_uuidOrAddress; + return true; +} + +Json::Value WebThreeStubServer::admin_eth_inspect(std::string const& _address, std::string const& _session) +{ + ADMIN; + (void)_address; + return {}; +} + +bool isHex(std::string const& _s) +{ + unsigned i = (_s.size() >= 2 && _s.substr(0, 2) == "0x") ? 2 : 0; + for (; i < _s.size(); ++i) + if (fromHex(_s[i], WhenError::DontThrow) == -1) + return false; + return true; +} + +template bool isHash(std::string const& _hash) +{ + return (_hash.size() == T::size * 2 || (_hash.size() == T::size * 2 + 2 && _hash.substr(0, 2) == "0x")) && isHex(_hash); +} + +h256 WebThreeStubServer::blockHash(std::string const& _blockNumberOrHash) const +{ + if (isHash(_blockNumberOrHash)) + return h256(_blockNumberOrHash.substr(_blockNumberOrHash.size() - 64, 64)); + try { - BlockQueueStatus bqs = m_web3.ethereum()->blockQueue().status(); - ret["importing"] = (int)bqs.importing; - ret["verified"] = (int)bqs.verified; - ret["verifying"] = (int)bqs.verifying; - ret["unverified"] = (int)bqs.unverified; - ret["future"] = (int)bqs.future; - ret["unknown"] = (int)bqs.unknown; - ret["bad"] = (int)bqs.bad; + return bc().numberHash(stoul(_blockNumberOrHash)); } + catch (...) + { + throw jsonrpc::JsonRpcException("Invalid argument"); + } +} + +Json::Value WebThreeStubServer::admin_eth_reprocess(std::string const& _blockNumberOrHash, std::string const& _session) +{ + ADMIN; + Json::Value ret; + PopulationStatistics ps; + m_web3.ethereum()->state(blockHash(_blockNumberOrHash), &ps); + ret["enact"] = ps.enact; + ret["verify"] = ps.verify; + ret["total"] = ps.verify + ps.enact; + return ret; +} + +Json::Value WebThreeStubServer::admin_eth_vmTrace(std::string const& _blockNumberOrHash, int _txIndex, std::string const& _session) +{ + ADMIN; + + Json::Value ret; + + auto c = m_web3.ethereum(); + State state = c->state(_txIndex + 1, blockHash(_blockNumberOrHash)); + + if (_txIndex < 0) + throw jsonrpc::JsonRpcException("Negative index"); + + if ((unsigned)_txIndex < state.pending().size()) + { + Executive e(state, bc(), 0); + Transaction t = state.pending()[_txIndex]; + state = state.fromPending(_txIndex); + try + { + StandardTrace st; + st.setShowMnemonics(); + e.initialize(t); + if (!e.execute()) + e.go(st.onOp()); + e.finalize(); + Json::Reader().parse(st.json(), ret); + } + catch(Exception const& _e) + { + cwarn << diagnostic_information(_e); + } + } + return ret; } +Json::Value WebThreeStubServer::admin_eth_getReceiptByHashAndIndex(std::string const& _blockNumberOrHash, int _txIndex, std::string const& _session) +{ + ADMIN; + if (_txIndex < 0) + throw jsonrpc::JsonRpcException("Negative index"); + auto h = blockHash(_blockNumberOrHash); + if (!bc().isKnown(h)) + throw jsonrpc::JsonRpcException("Invalid/unknown block."); + auto rs = bc().receipts(h); + if ((unsigned)_txIndex >= rs.receipts.size()) + throw jsonrpc::JsonRpcException("Index too large."); + return toJson(rs.receipts[_txIndex]); +} + std::string WebThreeStubServer::web3_clientVersion() { return m_web3.clientVersion(); diff --git a/libweb3jsonrpc/WebThreeStubServer.h b/libweb3jsonrpc/WebThreeStubServer.h index 8bdeb6b7a..ecf8acca0 100644 --- a/libweb3jsonrpc/WebThreeStubServer.h +++ b/libweb3jsonrpc/WebThreeStubServer.h @@ -32,16 +32,19 @@ namespace dev { + class WebThreeDirect; namespace eth { class KeyManager; -} +class TrivialGasPricer; +class CanonBlockChain; +class BlockQueue; } struct SessionPermissions { - bool admin; + std::unordered_set priviledges; }; /** @@ -50,7 +53,7 @@ struct SessionPermissions class WebThreeStubServer: public dev::WebThreeStubServerBase, public dev::WebThreeStubDatabaseFace { public: - WebThreeStubServer(jsonrpc::AbstractServerConnector& _conn, dev::WebThreeDirect& _web3, std::shared_ptr const& _ethAccounts, std::vector const& _shhAccounts, dev::eth::KeyManager& _keyMan); + WebThreeStubServer(jsonrpc::AbstractServerConnector& _conn, dev::WebThreeDirect& _web3, std::shared_ptr const& _ethAccounts, std::vector const& _shhAccounts, dev::eth::KeyManager& _keyMan, dev::eth::TrivialGasPricer& _gp); virtual std::string web3_clientVersion() override; @@ -58,7 +61,7 @@ public: void addSession(std::string const& _session, SessionPermissions const& _p) { m_sessions[_session] = _p; } private: - bool isAdmin(std::string const& _session) const override { auto it = m_sessions.find(_session); return it != m_sessions.end() && it->second.admin; } + virtual bool hasPriviledgeLevel(std::string const& _session, Priviledge _l) const override { auto it = m_sessions.find(_session); return it != m_sessions.end() && it->second.priviledges.count(_l); } virtual dev::eth::Interface* client() override; virtual std::shared_ptr face() override; @@ -68,15 +71,37 @@ private: virtual std::string get(std::string const& _name, std::string const& _key) override; virtual void put(std::string const& _name, std::string const& _key, std::string const& _value) override; - virtual bool eth_notePassword(std::string const& _password); - virtual Json::Value admin_eth_blockQueueStatus(std::string const& _session); + virtual bool eth_notePassword(std::string const& _password) override; + virtual Json::Value admin_eth_blockQueueStatus(std::string const& _session) override; + virtual bool admin_eth_setAskPrice(std::string const& _wei, std::string const& _session) override; + virtual bool admin_eth_setBidPrice(std::string const& _wei, std::string const& _session) override; + + virtual Json::Value admin_eth_findBlock(std::string const& _blockHash, std::string const& _session) override; + virtual std::string admin_eth_blockQueueFirstUnknown(std::string const& _session) override; + virtual bool admin_eth_blockQueueRetryUnknown(std::string const& _session) override; + + virtual Json::Value admin_eth_allAccounts(std::string const& _session) override; + virtual Json::Value admin_eth_newAccount(const Json::Value& _info, std::string const& _session) override; + virtual bool admin_eth_setMiningBenefactor(std::string const& _uuidOrAddress, std::string const& _session) override; + virtual Json::Value admin_eth_inspect(std::string const& _address, std::string const& _session) override; + virtual Json::Value admin_eth_reprocess(std::string const& _blockNumberOrHash, std::string const& _session) override; + virtual Json::Value admin_eth_vmTrace(std::string const& _blockNumberOrHash, int _txIndex, std::string const& _session) override; + virtual Json::Value admin_eth_getReceiptByHashAndIndex(std::string const& _blockNumberOrHash, int _txIndex, std::string const& _session) override; private: + h256 blockHash(std::string const& _blockNumberOrHash) const; + + dev::eth::CanonBlockChain const& bc() const; + dev::eth::BlockQueue const& bq() const; + dev::WebThreeDirect& m_web3; dev::eth::KeyManager& m_keyMan; + dev::eth::TrivialGasPricer& m_gp; leveldb::ReadOptions m_readOptions; leveldb::WriteOptions m_writeOptions; leveldb::DB* m_db; std::unordered_map m_sessions; }; + +} diff --git a/libweb3jsonrpc/WebThreeStubServerBase.cpp b/libweb3jsonrpc/WebThreeStubServerBase.cpp index f88443ee5..99c7e3425 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.cpp +++ b/libweb3jsonrpc/WebThreeStubServerBase.cpp @@ -21,6 +21,8 @@ * @date 2014 */ +#include "WebThreeStubServerBase.h" + // Make sure boost/asio.hpp is included before windows.h. #include @@ -41,13 +43,13 @@ #if ETH_SERPENT || !ETH_TRUE #include #endif -#include "WebThreeStubServerBase.h" #include "AccountHolder.h" - +#include "JsonHelper.h" using namespace std; using namespace jsonrpc; using namespace dev; -using namespace dev::eth; +using namespace eth; +using namespace shh; #if ETH_DEBUG const unsigned dev::SensibleHttpThreads = 1; @@ -56,302 +58,6 @@ const unsigned dev::SensibleHttpThreads = 4; #endif const unsigned dev::SensibleHttpPort = 8545; -static Json::Value toJson(dev::eth::BlockInfo const& _bi) -{ - Json::Value res; - if (_bi) - { - res["hash"] = toJS(_bi.hash()); - res["parentHash"] = toJS(_bi.parentHash); - res["sha3Uncles"] = toJS(_bi.sha3Uncles); - res["miner"] = toJS(_bi.coinbaseAddress); - res["stateRoot"] = toJS(_bi.stateRoot); - res["transactionsRoot"] = toJS(_bi.transactionsRoot); - res["difficulty"] = toJS(_bi.difficulty); - res["number"] = toJS(_bi.number); - res["gasUsed"] = toJS(_bi.gasUsed); - res["gasLimit"] = toJS(_bi.gasLimit); - res["timestamp"] = toJS(_bi.timestamp); - res["extraData"] = toJS(_bi.extraData); - res["nonce"] = toJS(_bi.nonce); - res["logsBloom"] = toJS(_bi.logBloom); - } - return res; -} - -static Json::Value toJson(dev::eth::Transaction const& _t, std::pair _location, BlockNumber _blockNumber) -{ - Json::Value res; - if (_t) - { - res["hash"] = toJS(_t.sha3()); - res["input"] = toJS(_t.data()); - res["to"] = _t.isCreation() ? Json::Value() : toJS(_t.receiveAddress()); - res["from"] = toJS(_t.safeSender()); - res["gas"] = toJS(_t.gas()); - res["gasPrice"] = toJS(_t.gasPrice()); - res["nonce"] = toJS(_t.nonce()); - res["value"] = toJS(_t.value()); - res["blockHash"] = toJS(_location.first); - res["transactionIndex"] = toJS(_location.second); - res["blockNumber"] = toJS(_blockNumber); - } - return res; -} - -static Json::Value toJson(dev::eth::BlockInfo const& _bi, BlockDetails const& _bd, UncleHashes const& _us, Transactions const& _ts) -{ - Json::Value res = toJson(_bi); - if (_bi) - { - res["totalDifficulty"] = toJS(_bd.totalDifficulty); - res["uncles"] = Json::Value(Json::arrayValue); - for (h256 h: _us) - res["uncles"].append(toJS(h)); - res["transactions"] = Json::Value(Json::arrayValue); - for (unsigned i = 0; i < _ts.size(); i++) - res["transactions"].append(toJson(_ts[i], std::make_pair(_bi.hash(), i), (BlockNumber)_bi.number)); - } - return res; -} - -static Json::Value toJson(dev::eth::BlockInfo const& _bi, BlockDetails const& _bd, UncleHashes const& _us, TransactionHashes const& _ts) -{ - Json::Value res = toJson(_bi); - if (_bi) - { - res["totalDifficulty"] = toJS(_bd.totalDifficulty); - res["uncles"] = Json::Value(Json::arrayValue); - for (h256 h: _us) - res["uncles"].append(toJS(h)); - res["transactions"] = Json::Value(Json::arrayValue); - for (h256 const& t: _ts) - res["transactions"].append(toJS(t)); - } - return res; -} - -static Json::Value toJson(dev::eth::TransactionSkeleton const& _t) -{ - Json::Value res; - res["to"] = _t.creation ? Json::Value() : toJS(_t.to); - res["from"] = toJS(_t.from); - res["gas"] = toJS(_t.gas); - res["gasPrice"] = toJS(_t.gasPrice); - res["value"] = toJS(_t.value); - res["data"] = toJS(_t.data, 32); - return res; -} - -static Json::Value toJson(dev::eth::Transaction const& _t) -{ - Json::Value res; - res["to"] = _t.isCreation() ? Json::Value() : toJS(_t.to()); - res["from"] = toJS(_t.from()); - res["gas"] = toJS(_t.gas()); - res["gasPrice"] = toJS(_t.gasPrice()); - res["value"] = toJS(_t.value()); - res["data"] = toJS(_t.data(), 32); - res["nonce"] = toJS(_t.nonce()); - res["hash"] = toJS(_t.sha3(WithSignature)); - res["sighash"] = toJS(_t.sha3(WithoutSignature)); - res["r"] = toJS(_t.signature().r); - res["s"] = toJS(_t.signature().s); - res["v"] = toJS(_t.signature().v); - return res; -} - -static Json::Value toJson(dev::eth::LocalisedLogEntry const& _e) -{ - Json::Value res; - 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)); - 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; -} - -static Json::Value toJson(dev::eth::LocalisedLogEntries const& _es) -{ - Json::Value res(Json::arrayValue); - for (dev::eth::LocalisedLogEntry const& e: _es) - res.append(toJson(e)); - return res; -} - -static Json::Value toJson(map const& _storage) -{ - Json::Value res(Json::objectValue); - for (auto i: _storage) - res[toJS(i.first)] = toJS(i.second); - return res; -} - -static dev::eth::LogFilter toLogFilter(Json::Value const& _json) -{ - 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(jsToFixed<32>(_json["fromBlock"].asString())); - if (!_json["toBlock"].empty()) - 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()) - 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; -} - -static shh::Message toMessage(Json::Value const& _json) -{ - shh::Message ret; - if (!_json["from"].empty()) - ret.setFrom(jsToPublic(_json["from"].asString())); - if (!_json["to"].empty()) - ret.setTo(jsToPublic(_json["to"].asString())); - if (!_json["payload"].empty()) - ret.setPayload(jsToBytes(_json["payload"].asString())); - return ret; -} - -static shh::Envelope toSealed(Json::Value const& _json, shh::Message const& _m, Secret _from) -{ - unsigned ttl = 50; - unsigned workToProve = 50; - shh::BuildTopic bt; - - if (!_json["ttl"].empty()) - ttl = jsToInt(_json["ttl"].asString()); - - if (!_json["workToProve"].empty()) - workToProve = jsToInt(_json["workToProve"].asString()); - - if (!_json["topics"].empty()) - for (auto i: _json["topics"]) - { - if (i.isArray()) - { - for (auto j: i) - if (!j.isNull()) - bt.shift(jsToBytes(j.asString())); - } - else if (!i.isNull()) // if it is anything else then string, it should and will fail - bt.shift(jsToBytes(i.asString())); - } - - return _m.seal(_from, bt, ttl, workToProve); -} - -static pair toWatch(Json::Value const& _json) -{ - shh::BuildTopic bt; - Public to; - - if (!_json["to"].empty()) - to = jsToPublic(_json["to"].asString()); - - if (!_json["topics"].empty()) - for (auto i: _json["topics"]) - bt.shift(jsToBytes(i.asString())); - - return make_pair(bt, to); -} - -static Json::Value toJson(h256 const& _h, shh::Envelope const& _e, shh::Message const& _m) -{ - Json::Value res; - res["hash"] = toJS(_h); - res["expiry"] = toJS(_e.expiry()); - res["sent"] = toJS(_e.sent()); - res["ttl"] = toJS(_e.ttl()); - res["workProved"] = toJS(_e.workProved()); - res["topics"] = Json::Value(Json::arrayValue); - for (auto const& t: _e.topic()) - res["topics"].append(toJS(t)); - res["payload"] = toJS(_m.payload()); - res["from"] = toJS(_m.from()); - res["to"] = toJS(_m.to()); - return res; -} - WebThreeStubServerBase::WebThreeStubServerBase(AbstractServerConnector& _conn, std::shared_ptr const& _ethAccounts, vector const& _sshAccounts): AbstractWebThreeStubServer(_conn), m_ethAccounts(_ethAccounts) @@ -468,7 +174,6 @@ string WebThreeStubServerBase::eth_getBlockTransactionCountByHash(string const& } } - string WebThreeStubServerBase::eth_getBlockTransactionCountByNumber(string const& _blockNumber) { try @@ -517,42 +222,12 @@ string WebThreeStubServerBase::eth_getCode(string const& _address, string const& } } -static TransactionSkeleton toTransaction(Json::Value const& _json) -{ - TransactionSkeleton ret; - if (!_json.isObject() || _json.empty()) - return ret; - - if (!_json["from"].empty()) - ret.from = jsToAddress(_json["from"].asString()); - if (!_json["to"].empty() && _json["to"].asString() != "0x") - ret.to = jsToAddress(_json["to"].asString()); - else - ret.creation = true; - - if (!_json["value"].empty()) - ret.value = jsToU256(_json["value"].asString()); - - if (!_json["gas"].empty()) - ret.gas = jsToU256(_json["gas"].asString()); - - if (!_json["gasPrice"].empty()) - ret.gasPrice = jsToU256(_json["gasPrice"].asString()); - - if (!_json["data"].empty()) // ethereum.js has preconstructed the data array - ret.data = jsToBytes(_json["data"].asString()); - - if (!_json["code"].empty()) - ret.data = jsToBytes(_json["code"].asString()); - return ret; -} - string WebThreeStubServerBase::eth_sendTransaction(Json::Value const& _json) { try { string ret; - TransactionSkeleton t = toTransaction(_json); + TransactionSkeleton t = toTransactionSkeleton(_json); if (!t.from) t.from = m_ethAccounts->defaultTransactAccount(); @@ -578,7 +253,7 @@ string WebThreeStubServerBase::eth_signTransaction(Json::Value const& _json) try { string ret; - TransactionSkeleton t = toTransaction(_json); + TransactionSkeleton t = toTransactionSkeleton(_json); if (!t.from) t.from = m_ethAccounts->defaultTransactAccount(); @@ -627,7 +302,7 @@ string WebThreeStubServerBase::eth_call(Json::Value const& _json, string const& { try { - TransactionSkeleton t = toTransaction(_json); + TransactionSkeleton t = toTransactionSkeleton(_json); if (!t.from) t.from = m_ethAccounts->defaultTransactAccount(); // if (!m_accounts->isRealAccount(t.from)) @@ -798,34 +473,32 @@ string WebThreeStubServerBase::eth_compileSerpent(string const& _source) return res; } +#define ADMIN requires(_session, Priviledge::Admin) + bool WebThreeStubServerBase::admin_web3_setVerbosity(int _v, string const& _session) { - if (!isAdmin(_session)) - return false; + ADMIN; g_logVerbosity = _v; return true; } bool WebThreeStubServerBase::admin_net_start(std::string const& _session) { - if (!isAdmin(_session)) - return false; + ADMIN; network()->startNetwork(); return true; } bool WebThreeStubServerBase::admin_net_stop(std::string const& _session) { - if (!isAdmin(_session)) - return false; + ADMIN; network()->stopNetwork(); return true; } bool WebThreeStubServerBase::admin_net_connect(std::string const& _node, std::string const& _session) { - if (!isAdmin(_session)) - return false; + ADMIN; p2p::NodeId id; bi::tcp::endpoint ep; if (_node.substr(0, 8) == "enode://" && _node.find('@') == 136) @@ -839,25 +512,9 @@ bool WebThreeStubServerBase::admin_net_connect(std::string const& _node, std::st return true; } -Json::Value toJson(p2p::PeerSessionInfo const& _p) -{ - Json::Value ret; - ret["id"] = _p.id.hex(); - ret["clientVersion"] = _p.clientVersion; - ret["host"] = _p.host; - ret["port"] = _p.port; - ret["lastPing"] = (int)chrono::duration_cast(_p.lastPing).count(); - for (auto const& i: _p.notes) - ret["notes"][i.first] = i.second; - for (auto const& i: _p.caps) - ret["caps"][i.first] = (unsigned)i.second; - return ret; -} - Json::Value WebThreeStubServerBase::admin_net_peers(std::string const& _session) { - if (!isAdmin(_session)) - return false; + ADMIN; Json::Value ret; for (p2p::PeerSessionInfo const& i: network()->peers()) ret.append(toJson(i)); @@ -866,8 +523,7 @@ Json::Value WebThreeStubServerBase::admin_net_peers(std::string const& _session) bool WebThreeStubServerBase::admin_eth_setMining(bool _on, std::string const& _session) { - if (!isAdmin(_session)) - return false; + ADMIN; if (_on) client()->startMining(); else @@ -970,8 +626,6 @@ bool WebThreeStubServerBase::eth_uninstallFilter(string const& _filterId) { BOOST_THROW_EXCEPTION(JsonRpcException(Errors::ERROR_RPC_INVALID_PARAMS)); } - - } Json::Value WebThreeStubServerBase::eth_getFilterChanges(string const& _filterId) diff --git a/libweb3jsonrpc/WebThreeStubServerBase.h b/libweb3jsonrpc/WebThreeStubServerBase.h index aaf0a6096..d3e16d0f4 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.h +++ b/libweb3jsonrpc/WebThreeStubServerBase.h @@ -26,6 +26,7 @@ #include #include #include +#include #include #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-parameter" @@ -58,6 +59,26 @@ public: virtual void put(std::string const& _name, std::string const& _key, std::string const& _value) = 0; }; +enum class Priviledge +{ + Admin +}; + +} + +namespace std +{ + +template<> struct hash +{ + size_t operator()(dev::Priviledge _value) const { return (size_t)_value; } +}; + +} + +namespace dev +{ + /** * @brief JSON-RPC api implementation * @todo split these up according to subprotocol (eth, shh, db, p2p, web3) and make it /very/ clear about how to add other subprotocols. @@ -147,25 +168,28 @@ public: virtual Json::Value admin_eth_blockQueueStatus(std::string const& _session) { (void)_session; return Json::Value(); } virtual bool admin_eth_setAskPrice(std::string const& _wei, std::string const& _session) { (void)_wei; (void)_session; return false; } virtual bool admin_eth_setBidPrice(std::string const& _wei, std::string const& _session) { (void)_wei; (void)_session; return false; } - virtual bool admin_eth_setReferencePrice(std::string const& _wei, std::string const& _session) { (void)_wei; (void)_session; return false; } - virtual bool admin_eth_setPriority(int _percent, std::string const& _session) { (void)_percent; (void)_session; return false; } virtual Json::Value admin_eth_findBlock(std::string const& _blockHash, std::string const& _session) { (void)_blockHash; (void)_session; return Json::Value(); } virtual std::string admin_eth_blockQueueFirstUnknown(std::string const& _session) { (void)_session; return ""; } virtual bool admin_eth_blockQueueRetryUnknown(std::string const& _session) { (void)_session; return false; } virtual Json::Value admin_eth_allAccounts(std::string const& _session) { (void)_session; return Json::Value(); } virtual Json::Value admin_eth_newAccount(const Json::Value& _info, std::string const& _session) { (void)_info; (void)_session; return Json::Value(); } - virtual bool admin_eth_setSigningKey(std::string const& _uuidOrAddress, std::string const& _session) { (void)_uuidOrAddress; (void)_session; return false; } virtual bool admin_eth_setMiningBenefactor(std::string const& _uuidOrAddress, std::string const& _session) { (void)_uuidOrAddress; (void)_session; return false; } virtual Json::Value admin_eth_inspect(std::string const& _address, std::string const& _session) { (void)_address; (void)_session; return Json::Value(); } virtual Json::Value admin_eth_reprocess(std::string const& _blockNumberOrHash, std::string const& _session) { (void)_blockNumberOrHash; (void)_session; return Json::Value(); } - virtual Json::Value admin_eth_vmTrace(std::string const& _blockNumberOrHash, std::string const& _txIndex, std::string const& _session) { (void)_blockNumberOrHash; (void)_txIndex; (void)_session; return Json::Value(); } - virtual Json::Value admin_eth_getReceiptByHashAndIndex(std::string const& _blockNumberOrHash, std::string const& _txIndex, std::string const& _session) { (void)_blockNumberOrHash; (void)_txIndex; (void)_session; return Json::Value(); } + virtual Json::Value admin_eth_vmTrace(std::string const& _blockNumberOrHash, int _txIndex, std::string const& _session) { (void)_blockNumberOrHash; (void)_txIndex; (void)_session; return Json::Value(); } + virtual Json::Value admin_eth_getReceiptByHashAndIndex(std::string const& _blockNumberOrHash, int _txIndex, std::string const& _session) { (void)_blockNumberOrHash; (void)_txIndex; (void)_session; return Json::Value(); } + + // TODO REMOVE + virtual bool admin_eth_setReferencePrice(std::string const& _wei, std::string const& _session) { (void)_wei; (void)_session; return false; } + virtual bool admin_eth_setPriority(int _percent, std::string const& _session) { (void)_percent; (void)_session; return false; } + virtual bool admin_eth_setSigningKey(std::string const& _uuidOrAddress, std::string const& _session) { (void)_uuidOrAddress; (void)_session; return false; } void setIdentities(std::vector const& _ids); std::map const& ids() const { return m_shhIds; } protected: - virtual bool isAdmin(std::string const& _session) const { (void)_session; return false; } + void requires(std::string const& _session, Priviledge _l) const { if (!hasPriviledgeLevel(_session, _l)) throw jsonrpc::JsonRpcException("Invalid priviledges"); } + virtual bool hasPriviledgeLevel(std::string const& _session, Priviledge _l) const { (void)_session; (void)_l; return false; } virtual dev::eth::Interface* client() = 0; virtual std::shared_ptr face() = 0; diff --git a/libweb3jsonrpc/abstractwebthreestubserver.h b/libweb3jsonrpc/abstractwebthreestubserver.h index 6b94c31da..82864a61a 100644 --- a/libweb3jsonrpc/abstractwebthreestubserver.h +++ b/libweb3jsonrpc/abstractwebthreestubserver.h @@ -96,8 +96,8 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServerbindAndAddMethod(jsonrpc::Procedure("admin_eth_setMiningBenefactor", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::admin_eth_setMiningBenefactorI); this->bindAndAddMethod(jsonrpc::Procedure("admin_eth_inspect", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::admin_eth_inspectI); this->bindAndAddMethod(jsonrpc::Procedure("admin_eth_reprocess", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::admin_eth_reprocessI); - this->bindAndAddMethod(jsonrpc::Procedure("admin_eth_vmTrace", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING,"param3",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::admin_eth_vmTraceI); - this->bindAndAddMethod(jsonrpc::Procedure("admin_eth_getReceiptByHashAndIndex", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING,"param3",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::admin_eth_getReceiptByHashAndIndexI); + this->bindAndAddMethod(jsonrpc::Procedure("admin_eth_vmTrace", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_INTEGER,"param3",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::admin_eth_vmTraceI); + this->bindAndAddMethod(jsonrpc::Procedure("admin_eth_getReceiptByHashAndIndex", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_INTEGER,"param3",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::admin_eth_getReceiptByHashAndIndexI); } inline virtual void web3_sha3I(const Json::Value &request, Json::Value &response) @@ -455,11 +455,11 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServeradmin_eth_vmTrace(request[0u].asString(), request[1u].asString(), request[2u].asString()); + response = this->admin_eth_vmTrace(request[0u].asString(), request[1u].asInt(), request[2u].asString()); } inline virtual void admin_eth_getReceiptByHashAndIndexI(const Json::Value &request, Json::Value &response) { - response = this->admin_eth_getReceiptByHashAndIndex(request[0u].asString(), request[1u].asString(), request[2u].asString()); + response = this->admin_eth_getReceiptByHashAndIndex(request[0u].asString(), request[1u].asInt(), request[2u].asString()); } virtual std::string web3_sha3(const std::string& param1) = 0; virtual std::string web3_clientVersion() = 0; @@ -545,8 +545,8 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServer #include #include +#include "BuildInfo.h" using namespace std; using namespace dev; using namespace dev::p2p; @@ -72,6 +73,16 @@ WebThreeDirect::~WebThreeDirect() m_ethereum.reset(); } +std::string WebThreeDirect::composeClientVersion(std::string const& _client, std::string const& _clientName) +{ +#if ETH_EVMJIT + char const* jit = "-JIT"; +#else + char const* jit = ""; +#endif + return _client + "v" + dev::Version + "-" + string(DEV_QUOTED(ETH_COMMIT_HASH)).substr(0, 8) + (ETH_CLEAN_REPO ? "" : "*") + "/" + _clientName + "/" DEV_QUOTED(ETH_BUILD_TYPE) "-" DEV_QUOTED(ETH_BUILD_PLATFORM) + jit; +} + p2p::NetworkPreferences const& WebThreeDirect::networkPreferences() const { return m_net.networkPreferences(); diff --git a/libwebthree/WebThree.h b/libwebthree/WebThree.h index ece83abb8..6eefa6a4b 100644 --- a/libwebthree/WebThree.h +++ b/libwebthree/WebThree.h @@ -129,6 +129,8 @@ public: // Misc stuff: + static std::string composeClientVersion(std::string const& _client, std::string const& _name); + std::string const& clientVersion() const { return m_clientVersion; } void setClientVersion(std::string const& _name) { m_clientVersion = _name; } diff --git a/mix/MixClient.cpp b/mix/MixClient.cpp index e2e554cb9..4f5eff8b6 100644 --- a/mix/MixClient.cpp +++ b/mix/MixClient.cpp @@ -296,7 +296,9 @@ ExecutionResult MixClient::execution(unsigned _index) const State MixClient::asOf(h256 const& _block) const { ReadGuard l(x_state); - return State(m_stateDB, bc(), _block); + State ret(m_stateDB); + ret.populateFromChain(bc(), _block); + return ret; } void MixClient::submitTransaction(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, bool _gasAuto) diff --git a/neth/main.cpp b/neth/main.cpp index a6e661d2e..a55c3d559 100644 --- a/neth/main.cpp +++ b/neth/main.cpp @@ -577,10 +577,11 @@ int main(int argc, char** argv) #if ETH_JSONRPC || !ETH_TRUE shared_ptr jsonrpcServer; unique_ptr jsonrpcConnector; + KeyManager km; if (jsonrpc > -1) { jsonrpcConnector = unique_ptr(new jsonrpc::HttpServer(jsonrpc, "", "", SensibleHttpThreads)); - jsonrpcServer = shared_ptr(new WebThreeStubServer(*jsonrpcConnector.get(), web3, make_shared([&](){ return web3.ethereum(); }, vector({us})), vector({us}))); + jsonrpcServer = shared_ptr(new WebThreeStubServer(*jsonrpcConnector.get(), web3, make_shared([&](){ return web3.ethereum(); }, vector({us})), vector({us})), km); jsonrpcServer->setIdentities({us}); jsonrpcServer->StartListening(); } diff --git a/test/libweb3jsonrpc/webthreestubclient.h b/test/libweb3jsonrpc/webthreestubclient.h index 5c74e5a46..175f1958c 100644 --- a/test/libweb3jsonrpc/webthreestubclient.h +++ b/test/libweb3jsonrpc/webthreestubclient.h @@ -884,7 +884,7 @@ class WebThreeStubClient : public jsonrpc::Client else throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); } - Json::Value admin_eth_vmTrace(const std::string& param1, const std::string& param2, const std::string& param3) throw (jsonrpc::JsonRpcException) + Json::Value admin_eth_vmTrace(const std::string& param1, int param2, const std::string& param3) throw (jsonrpc::JsonRpcException) { Json::Value p; p.append(param1); @@ -896,7 +896,7 @@ class WebThreeStubClient : public jsonrpc::Client else throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); } - Json::Value admin_eth_getReceiptByHashAndIndex(const std::string& param1, const std::string& param2, const std::string& param3) throw (jsonrpc::JsonRpcException) + Json::Value admin_eth_getReceiptByHashAndIndex(const std::string& param1, int param2, const std::string& param3) throw (jsonrpc::JsonRpcException) { Json::Value p; p.append(param1);