diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index cf26df6fb..d22f7d873 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -232,12 +232,9 @@ void Client::appendFromNewBlock(h256 _block, h256Set& o_changed) const void Client::setForceMining(bool _enable) { m_forceMining = _enable; - if (!m_host.lock()) - { - ReadGuard l(x_miners); - for (auto& m: m_miners) - m.noteStateChange(); - } + ReadGuard l(x_miners); + for (auto& m: m_miners) + m.noteStateChange(); } void Client::setMiningThreads(unsigned _threads) @@ -550,6 +547,20 @@ bytes Client::codeAt(Address _a, int _block) const return asOf(_block).code(_a); } +Transaction Client::transaction(h256 _blockHash, unsigned _i) const +{ + auto bl = m_bc.block(_blockHash); + RLP b(bl); + return Transaction(b[1][_i].data()); +} + +BlockInfo Client::uncle(h256 _blockHash, unsigned _i) const +{ + auto bl = m_bc.block(_blockHash); + RLP b(bl); + return BlockInfo::fromHeader(b[2][_i].data()); +} + PastMessages Client::messages(MessageFilter const& _f) const { PastMessages ret; diff --git a/libethereum/Client.h b/libethereum/Client.h index d00bf53ba..e7bbc1ca3 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -119,23 +119,23 @@ public: explicit Client(p2p::Host* _host, std::string const& _dbPath = std::string(), bool _forceClean = false, u256 _networkId = 0); /// Destructor. - ~Client(); + virtual ~Client(); /// Submits the given message-call transaction. - void transact(Secret _secret, u256 _value, Address _dest, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo); + virtual void transact(Secret _secret, u256 _value, Address _dest, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo); /// Submits a new contract-creation transaction. /// @returns the new contract's address (assuming it all goes through). - Address transact(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas = 10000, u256 _gasPrice = 10 * szabo); + virtual Address transact(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas = 10000, u256 _gasPrice = 10 * szabo); /// Injects the RLP-encoded transaction given by the _rlp into the transaction queue directly. - void inject(bytesConstRef _rlp); + virtual void inject(bytesConstRef _rlp); /// Blocks until all pending transactions have been processed. - void flushTransactions(); + virtual void flushTransactions(); /// Makes the given call. Nothing is recorded into the state. - bytes call(Secret _secret, u256 _value, Address _dest, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo); + virtual bytes call(Secret _secret, u256 _value, Address _dest, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo); // Informational stuff @@ -147,20 +147,20 @@ public: using Interface::codeAt; using Interface::storageAt; - u256 balanceAt(Address _a, int _block) const; - u256 countAt(Address _a, int _block) const; - u256 stateAt(Address _a, u256 _l, int _block) const; - bytes codeAt(Address _a, int _block) const; - std::map storageAt(Address _a, int _block) const; + virtual u256 balanceAt(Address _a, int _block) const; + virtual u256 countAt(Address _a, int _block) const; + virtual u256 stateAt(Address _a, u256 _l, int _block) const; + virtual bytes codeAt(Address _a, int _block) const; + virtual std::map storageAt(Address _a, int _block) const; - unsigned installWatch(MessageFilter const& _filter); - unsigned installWatch(h256 _filterId); - void uninstallWatch(unsigned _watchId); - bool peekWatch(unsigned _watchId) const { std::lock_guard l(m_filterLock); try { return m_watches.at(_watchId).changes != 0; } catch (...) { return false; } } - bool checkWatch(unsigned _watchId) { std::lock_guard l(m_filterLock); bool ret = false; try { ret = m_watches.at(_watchId).changes != 0; m_watches.at(_watchId).changes = 0; } catch (...) {} return ret; } + virtual unsigned installWatch(MessageFilter const& _filter); + virtual unsigned installWatch(h256 _filterId); + virtual void uninstallWatch(unsigned _watchId); + virtual bool peekWatch(unsigned _watchId) const { std::lock_guard l(m_filterLock); try { return m_watches.at(_watchId).changes != 0; } catch (...) { return false; } } + virtual bool checkWatch(unsigned _watchId) { std::lock_guard l(m_filterLock); bool ret = false; try { ret = m_watches.at(_watchId).changes != 0; m_watches.at(_watchId).changes = 0; } catch (...) {} return ret; } - PastMessages messages(unsigned _watchId) const { try { std::lock_guard l(m_filterLock); return messages(m_filters.at(m_watches.at(_watchId).id).filter); } catch (...) { return PastMessages(); } } - PastMessages messages(MessageFilter const& _filter) const; + virtual PastMessages messages(unsigned _watchId) const { try { std::lock_guard l(m_filterLock); return messages(m_filters.at(m_watches.at(_watchId).id).filter); } catch (...) { return PastMessages(); } } + virtual PastMessages messages(MessageFilter const& _filter) const; // [EXTRA API]: @@ -169,19 +169,25 @@ public: /// Get a map containing each of the pending transactions. /// @TODO: Remove in favour of transactions(). - Transactions pending() const { return m_postMine.pending(); } + virtual Transactions pending() const { return m_postMine.pending(); } + + virtual h256 hashFromNumber(unsigned _number) const { return m_bc.numberHash(_number); } + virtual BlockInfo blockInfo(h256 _hash) const { return BlockInfo(m_bc.block(_hash)); } + virtual BlockDetails blockDetails(h256 _hash) const { return m_bc.details(_hash); } + virtual Transaction transaction(h256 _blockHash, unsigned _i) const; + virtual BlockInfo uncle(h256 _blockHash, unsigned _i) const; /// Differences between transactions. using Interface::diff; - StateDiff diff(unsigned _txi, h256 _block) const; - StateDiff diff(unsigned _txi, int _block) const; + virtual StateDiff diff(unsigned _txi, h256 _block) const; + virtual StateDiff diff(unsigned _txi, int _block) const; /// Get a list of all active addresses. using Interface::addresses; - std::vector
addresses(int _block) const; + virtual std::vector
addresses(int _block) const; /// Get the remaining gas limit in this block. - u256 gasLimitRemaining() const { return m_postMine.gasLimitRemaining(); } + virtual u256 gasLimitRemaining() const { return m_postMine.gasLimitRemaining(); } // [PRIVATE API - only relevant for base clients, not available in general] @@ -210,23 +216,23 @@ public: void setTurboMining(bool _enable = true) { m_turboMining = _enable; } /// Set the coinbase address. - void setAddress(Address _us) { m_preMine.setAddress(_us); } + virtual void setAddress(Address _us) { m_preMine.setAddress(_us); } /// Get the coinbase address. - Address address() const { return m_preMine.address(); } + virtual Address address() const { return m_preMine.address(); } /// Stops mining and sets the number of mining threads (0 for automatic). - void setMiningThreads(unsigned _threads = 0); + virtual void setMiningThreads(unsigned _threads = 0); /// Get the effective number of mining threads. - unsigned miningThreads() const { ReadGuard l(x_miners); return m_miners.size(); } + virtual unsigned miningThreads() const { ReadGuard l(x_miners); return m_miners.size(); } /// Start mining. /// NOT thread-safe - call it & stopMining only from a single thread - void startMining() { startWorking(); ReadGuard l(x_miners); for (auto& m: m_miners) m.start(); } + virtual void startMining() { startWorking(); ReadGuard l(x_miners); for (auto& m: m_miners) m.start(); } /// Stop mining. /// NOT thread-safe - void stopMining() { ReadGuard l(x_miners); for (auto& m: m_miners) m.stop(); } + virtual void stopMining() { ReadGuard l(x_miners); for (auto& m: m_miners) m.stop(); } /// Are we mining now? - bool isMining() { ReadGuard l(x_miners); return m_miners.size() && m_miners[0].isRunning(); } + virtual bool isMining() { ReadGuard l(x_miners); return m_miners.size() && m_miners[0].isRunning(); } /// Check the progress of the mining. - MineProgress miningProgress() const; + virtual MineProgress miningProgress() const; /// Get and clear the mining history. std::list miningHistory(); diff --git a/libethereum/Interface.h b/libethereum/Interface.h index a5df3e5b1..7ae650590 100644 --- a/libethereum/Interface.h +++ b/libethereum/Interface.h @@ -29,6 +29,7 @@ #include "MessageFilter.h" #include "Transaction.h" #include "AccountDiff.h" +#include "BlockDetails.h" #include "Miner.h" namespace dev @@ -95,7 +96,13 @@ public: virtual bool peekWatch(unsigned _watchId) const = 0; virtual bool checkWatch(unsigned _watchId) = 0; - // TODO: Block query API. + // [BLOCK QUERY API] + + virtual h256 hashFromNumber(unsigned _number) const = 0; + virtual BlockInfo blockInfo(h256 _hash) const = 0; + virtual BlockDetails blockDetails(h256 _hash) const = 0; + virtual Transaction transaction(h256 _blockHash, unsigned _i) const = 0; + virtual BlockInfo uncle(h256 _blockHash, unsigned _i) const = 0; // [EXTRA API]: diff --git a/libp2p/Session.h b/libp2p/Session.h index 0498ede9b..2103d6db6 100644 --- a/libp2p/Session.h +++ b/libp2p/Session.h @@ -110,6 +110,7 @@ private: unsigned m_rating; std::map> m_capabilities; + std::set m_knownPeers; bool m_willBeDeleted = false; ///< True if we already posted a deleter on the strand. }; diff --git a/libqethereum/QEthereum.cpp b/libqethereum/QEthereum.cpp index 262835553..a244b9c9b 100644 --- a/libqethereum/QEthereum.cpp +++ b/libqethereum/QEthereum.cpp @@ -336,6 +336,93 @@ static QString toJson(dev::eth::PastMessages const& _pms) return QString::fromUtf8(QJsonDocument(jsonArray).toJson()); } +static QString toJson(dev::eth::BlockInfo const& _bi, dev::eth::BlockDetails const& _bd) +{ + QJsonObject v; + v["hash"] = toQJS(_bi.hash); + + v["parentHash"] = toQJS(_bi.parentHash); + v["sha3Uncles"] = toQJS(_bi.sha3Uncles); + v["miner"] = toQJS(_bi.coinbaseAddress); + v["stateRoot"] = toQJS(_bi.stateRoot); + v["transactionsRoot"] = toQJS(_bi.transactionsRoot); + v["difficulty"] = toQJS(_bi.difficulty); + v["number"] = (int)_bi.number; + v["minGasPrice"] = toQJS(_bi.minGasPrice); + v["gasLimit"] = (int)_bi.gasLimit; + v["gasUsed"] = (int)_bi.gasUsed; + v["timestamp"] = (int)_bi.timestamp; + v["extraData"] = ::fromBinary(_bi.extraData); + v["nonce"] = toQJS(_bi.nonce); + + QJsonArray children; + for (auto c: _bd.children) + children.append(toQJS(c)); + v["children"] = children; + v["totalDifficulty"] = toQJS(_bd.totalDifficulty); + v["bloom"] = toQJS(_bd.bloom); + return QString::fromUtf8(QJsonDocument(v).toJson()); +} + +static QString toJson(dev::eth::BlockInfo const& _bi) +{ + QJsonObject v; + v["hash"] = toQJS(_bi.hash); + + v["parentHash"] = toQJS(_bi.parentHash); + v["sha3Uncles"] = toQJS(_bi.sha3Uncles); + v["miner"] = toQJS(_bi.coinbaseAddress); + v["stateRoot"] = toQJS(_bi.stateRoot); + v["transactionsRoot"] = toQJS(_bi.transactionsRoot); + v["difficulty"] = toQJS(_bi.difficulty); + v["number"] = (int)_bi.number; + v["minGasPrice"] = toQJS(_bi.minGasPrice); + v["gasLimit"] = (int)_bi.gasLimit; + v["gasUsed"] = (int)_bi.gasUsed; + v["timestamp"] = (int)_bi.timestamp; + v["extraData"] = ::fromBinary(_bi.extraData); + v["nonce"] = toQJS(_bi.nonce); + + return QString::fromUtf8(QJsonDocument(v).toJson()); +} + +static QString toJson(dev::eth::Transaction const& _bi) +{ + QJsonObject v; + v["hash"] = toQJS(_bi.sha3()); + + v["input"] = ::fromBinary(_bi.data); + v["to"] = toQJS(_bi.receiveAddress); + v["from"] = toQJS(_bi.sender()); + v["gas"] = (int)_bi.gas; + v["gasPrice"] = toQJS(_bi.gasPrice); + v["nonce"] = toQJS(_bi.nonce); + v["value"] = toQJS(_bi.value); + + return QString::fromUtf8(QJsonDocument(v).toJson()); +} + +QString QEthereum::getUncle(QString _numberOrHash, int _i) const +{ + auto n = toU256(_numberOrHash); + auto h = n < m_client->number() ? m_client->hashFromNumber((unsigned)n) : ::toFixed<32>(_numberOrHash); + return m_client ? toJson(m_client->uncle(h, _i)) : ""; +} + +QString QEthereum::getTransaction(QString _numberOrHash, int _i) const +{ + auto n = toU256(_numberOrHash); + auto h = n < m_client->number() ? m_client->hashFromNumber((unsigned)n) : ::toFixed<32>(_numberOrHash); + return m_client ? toJson(m_client->transaction(h, _i)) : ""; +} + +QString QEthereum::getBlock(QString _numberOrHash) const +{ + auto n = toU256(_numberOrHash); + auto h = n < m_client->number() ? m_client->hashFromNumber((unsigned)n) : ::toFixed<32>(_numberOrHash); + return m_client ? toJson(m_client->blockInfo(h), m_client->blockDetails(h)) : ""; +} + QString QEthereum::getMessages(QString _json) const { return m_client ? toJson(m_client->messages(toMessageFilter(_json))) : ""; diff --git a/libqethereum/QEthereum.h b/libqethereum/QEthereum.h index 83ee53d43..94519e040 100644 --- a/libqethereum/QEthereum.h +++ b/libqethereum/QEthereum.h @@ -148,6 +148,10 @@ public: Q_INVOKABLE QString/*dev::u256*/ stateAt(QString/*dev::Address*/ _a, QString/*dev::u256*/ _p) const; Q_INVOKABLE QString/*dev::u256*/ codeAt(QString/*dev::Address*/ _a) const; + Q_INVOKABLE QString/*json*/ getBlock(QString _numberOrHash/*unsigned if < number(), hash otherwise*/) const; + Q_INVOKABLE QString/*json*/ getTransaction(QString _numberOrHash/*unsigned if < number(), hash otherwise*/, int _index) const; + Q_INVOKABLE QString/*json*/ getUncle(QString _numberOrHash/*unsigned if < number(), hash otherwise*/, int _index) const; + Q_INVOKABLE QString/*json*/ getMessages(QString _attribs/*json*/) const; Q_INVOKABLE QString doCreate(QString _secret, QString _amount, QString _init, QString _gas, QString _gasPrice); @@ -255,20 +259,12 @@ private: frame->addToJavaScriptWindowObject("shh", eth, QWebFrame::ScriptOwnership); \ frame->evaluateJavaScript("eth.makeWatch = function(a) { var ww = eth.newWatch(a); var ret = { w: ww }; ret.uninstall = function() { eth.killWatch(w); }; ret.changed = function(f) { eth.watchChanged.connect(function(nw) { if (nw == ww) f() }); }; ret.messages = function() { return JSON.parse(eth.watchMessages(this.w)) }; return ret; }"); \ frame->evaluateJavaScript("eth.watch = function(a) { return eth.makeWatch(JSON.stringify(a)) }"); \ - frame->evaluateJavaScript("eth.watchChain = function() { env.warn('THIS CALL IS DEPRECATED. USE eth.watch('chain') INSTEAD.'); return eth.makeWatch('chain') }"); \ - frame->evaluateJavaScript("eth.watchPending = function() { env.warn('THIS CALL IS DEPRECATED. USE eth.watch('pending') INSTEAD.'); return eth.makeWatch('pending') }"); \ - frame->evaluateJavaScript("eth.create = function(s, v, c, g, p, f) { env.warn('THIS CALL IS DEPRECATED. USE eth.transact INSTEAD.'); var v = eth.doCreate(s, v, c, g, p); if (f) f(v) }"); \ - frame->evaluateJavaScript("eth.transact = function(a_s, f_v, t, d, g, p, f) { if (t == null) { var r = eth.doTransact(JSON.stringify(a_s)); if (f_v) f_v(r); } else { env.warn('THIS FORM OF THIS CALL IS DEPRECATED.'); eth.doTransact(a_s, f_v, t, d, g, p); if (f) f() } }"); \ + frame->evaluateJavaScript("eth.transact = function(a, f) { var r = eth.doTransact(JSON.stringify(a)); if (f) f(r); }"); \ frame->evaluateJavaScript("eth.call = function(a, f) { var ret = eth.doCallJson(JSON.stringify(a)); if (f) f(ret); return ret; }"); \ frame->evaluateJavaScript("eth.messages = function(a) { return JSON.parse(eth.getMessages(JSON.stringify(a))); }"); \ - frame->evaluateJavaScript("eth.transactions = function(a) { env.warn('THIS CALL IS DEPRECATED. USE eth.messages INSTEAD.'); return JSON.parse(eth.getMessages(JSON.stringify(a))); }"); \ - frame->evaluateJavaScript("String.prototype.pad = function(l, r) { env.warn('THIS CALL IS DEPRECATED. USE eth.* INSTEAD.'); return eth.pad(this, l, r) }"); \ - frame->evaluateJavaScript("String.prototype.bin = function() { env.warn('THIS CALL IS DEPRECATED. USE eth.* INSTEAD.'); return eth.toAscii(this) }"); \ - frame->evaluateJavaScript("String.prototype.unbin = function(l) { env.warn('THIS CALL IS DEPRECATED. USE eth.* INSTEAD.'); return eth.fromAscii(this) }"); \ - frame->evaluateJavaScript("String.prototype.unpad = function(l) { env.warn('THIS CALL IS DEPRECATED. USE eth.* INSTEAD.'); return eth.unpad(this) }"); \ - frame->evaluateJavaScript("String.prototype.dec = function() { env.warn('THIS CALL IS DEPRECATED. USE eth.* INSTEAD.'); return eth.toDecimal(this) }"); \ - frame->evaluateJavaScript("String.prototype.fix = function() { env.warn('THIS CALL IS DEPRECATED. USE eth.* INSTEAD.'); return eth.toFixed(this) }"); \ - frame->evaluateJavaScript("String.prototype.sha3 = function() { env.warn('THIS CALL IS DEPRECATED. USE eth.* INSTEAD.'); return eth.sha3old(this) }"); \ + frame->evaluateJavaScript("eth.block = function(a) { return JSON.parse(eth.getBlock(a)); }"); \ + frame->evaluateJavaScript("eth.transaction = function(a) { return JSON.parse(eth.getTransaction(a)); }"); \ + frame->evaluateJavaScript("eth.uncle = function(a) { return JSON.parse(eth.getUncle(a)); }"); \ frame->evaluateJavaScript("shh.makeWatch = function(a) { var ww = shh.newWatch(a); var ret = { w: ww }; ret.uninstall = function() { shh.killWatch(w); }; ret.changed = function(f) { shh.watchChanged.connect(function(nw) { if (nw == ww) f() }); }; ret.messages = function() { return JSON.parse(shh.watchMessages(this.w)) }; return ret; }"); \ frame->evaluateJavaScript("shh.watch = function(a) { return shh.makeWatch(JSON.stringify(a)) }"); \ }