/* 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 WebThreeStubServer.cpp * @authors: * Gav Wood * Marek Kotewicz * @date 2014 */ #include "WebThreeStubServer.h" // Make sure boost/asio.hpp is included before windows.h. #include #include #include #include #include #include #include #include #include #include "JsonHelper.h" using namespace std; using namespace dev; using namespace dev::eth; namespace fs = boost::filesystem; 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); } 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_gp(_gp) { auto path = getDataDir() + "/.web3"; fs::create_directories(path); DEV_IGNORE_EXCEPTIONS(fs::permissions(path, fs::owner_all)); ldb::Options o; o.create_if_missing = true; ldb::DB::Open(o, path, &m_db); } std::string WebThreeStubServer::newSession(SessionPermissions const& _p) { std::string s = toBase64(h64::random().ref()); m_sessions[s] = _p; return s; } bool WebThreeStubServer::eth_notePassword(string const& _password) { m_keyMan.notePassword(_password); return true; } #define ADMIN_GUARD requires(_session, Privilege::Admin) Json::Value WebThreeStubServer::admin_eth_blockQueueStatus(string const& _session) { ADMIN_GUARD; 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_GUARD; m_gp.setAsk(jsToU256(_wei)); return true; } bool WebThreeStubServer::admin_eth_setBidPrice(std::string const& _wei, std::string const& _session) { ADMIN_GUARD; m_gp.setBid(jsToU256(_wei)); return true; } dev::eth::BlockChain 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_GUARD; 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_GUARD; return bq().firstUnknown().hex(); } bool WebThreeStubServer::admin_eth_blockQueueRetryUnknown(std::string const& _session) { ADMIN_GUARD; m_web3.ethereum()->retryUnknown(); return true; } Json::Value WebThreeStubServer::admin_eth_allAccounts(std::string const& _session) { ADMIN_GUARD; Json::Value ret; u256 total = 0; u256 pendingtotal = 0; Address beneficiary; for (auto const& address: m_keyMan.accounts()) { auto pending = m_web3.ethereum()->balanceAt(address, PendingBlock); auto latest = m_web3.ethereum()->balanceAt(address, LatestBlock); Json::Value a; if (address == beneficiary) a["beneficiary"] = true; a["address"] = toJS(address); a["balance"] = toJS(latest); a["nicebalance"] = formatBalance(latest); a["pending"] = toJS(pending); a["nicepending"] = formatBalance(pending); ret["accounts"][m_keyMan.accountName(address)] = 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_GUARD; if (!_info.isMember("name")) throw jsonrpc::JsonRpcException("No member found: name"); string name = _info["name"].asString(); auto s = ICAP::createDirect(); 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; 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_GUARD; Address a; h128 uuid = fromUUID(_uuidOrAddress); if (uuid) a = m_keyMan.address(uuid); else if (isHash
(_uuidOrAddress)) a = Address(_uuidOrAddress); else throw jsonrpc::JsonRpcException("Invalid UUID or address"); if (m_setMiningBenefactor) m_setMiningBenefactor(a); else m_web3.ethereum()->setBeneficiary(a); return true; } Json::Value WebThreeStubServer::admin_eth_inspect(std::string const& _address, std::string const& _session) { ADMIN_GUARD; if (!isHash
(_address)) throw jsonrpc::JsonRpcException("Invalid address given."); Json::Value ret; auto h = Address(fromHex(_address)); ret["storage"] = toJson(m_web3.ethereum()->storageAt(h, PendingBlock)); ret["balance"] = toJS(m_web3.ethereum()->balanceAt(h, PendingBlock)); ret["nonce"] = toJS(m_web3.ethereum()->countAt(h, PendingBlock)); ret["code"] = toJS(m_web3.ethereum()->codeAt(h, PendingBlock)); return ret; } h256 WebThreeStubServer::blockHash(std::string const& _blockNumberOrHash) const { if (isHash(_blockNumberOrHash)) return h256(_blockNumberOrHash.substr(_blockNumberOrHash.size() - 64, 64)); try { 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_GUARD; Json::Value ret; PopulationStatistics ps; m_web3.ethereum()->block(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_GUARD; Json::Value ret; auto c = m_web3.ethereum(); if (_txIndex < 0) throw jsonrpc::JsonRpcException("Negative index"); Block block = c->block(blockHash(_blockNumberOrHash)); if ((unsigned)_txIndex < block.pending().size()) { Transaction t = block.pending()[_txIndex]; State state = block.fromPending(_txIndex); Executive e(state, bc(), 0); 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_GUARD; 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(); } dev::eth::Interface* WebThreeStubServer::client() { return m_web3.ethereum(); } std::shared_ptr WebThreeStubServer::face() { return m_web3.whisper(); } dev::WebThreeNetworkFace* WebThreeStubServer::network() { return &m_web3; } dev::WebThreeStubDatabaseFace* WebThreeStubServer::db() { return this; } std::string WebThreeStubServer::get(std::string const& _name, std::string const& _key) { bytes k = sha3(_name).asBytes() + sha3(_key).asBytes(); string ret; m_db->Get(m_readOptions, ldb::Slice((char const*)k.data(), k.size()), &ret); return ret; } void WebThreeStubServer::put(std::string const& _name, std::string const& _key, std::string const& _value) { bytes k = sha3(_name).asBytes() + sha3(_key).asBytes(); m_db->Put(m_writeOptions, ldb::Slice((char const*)k.data(), k.size()), ldb::Slice((char const*)_value.data(), _value.size())); }