Browse Source

Merge branch 'client_ref' of https://github.com/debris/cpp-ethereum into debris-client_ref

cl-refactor
Gav Wood 10 years ago
parent
commit
0f0f97620a
  1. 5
      libethereum/BlockChain.h
  2. 49
      libethereum/Client.cpp
  3. 11
      libethereum/Client.h
  4. 116
      libethereum/ClientBase.cpp
  5. 5
      libethereum/ClientBase.h
  6. 4
      libethereum/Interface.h
  7. 71
      libethereum/LogFilter.cpp
  8. 10
      libethereum/LogFilter.h
  9. 25
      libethereum/Transaction.h
  10. 46
      libethereum/TransactionReceipt.h
  11. 29
      libevm/ExtVMFace.h
  12. 116
      libweb3jsonrpc/JsonHelper.cpp
  13. 7
      libweb3jsonrpc/JsonHelper.h
  14. 37
      libweb3jsonrpc/WebThreeStubServerBase.cpp
  15. 1
      libweb3jsonrpc/WebThreeStubServerBase.h
  16. 6
      libweb3jsonrpc/abstractwebthreestubserver.h
  17. 1
      libweb3jsonrpc/spec.json
  18. 10
      test/libweb3jsonrpc/webthreestubclient.h

5
libethereum/BlockChain.h

@ -153,8 +153,11 @@ public:
BlockReceipts receipts(h256 const& _hash) const { return queryExtras<BlockReceipts, ExtraReceipts>(_hash, m_receipts, x_receipts, NullBlockReceipts); }
BlockReceipts receipts() const { return receipts(currentHash()); }
/// Get the transaction by block hash and index;
TransactionReceipt transactionReceipt(h256 const& _blockHash, unsigned _i) const { return receipts(_blockHash).receipts[_i]; }
/// Get the transaction receipt by transaction hash. Thread-safe.
TransactionReceipt transactionReceipt(h256 const& _transactionHash) const {TransactionAddress ta = queryExtras<TransactionAddress, ExtraTransactionAddress>(_transactionHash, m_transactionAddresses, x_transactionAddresses, NullTransactionAddress); if (!ta) return bytesConstRef(); return receipts(ta.blockHash).receipts[ta.index]; }
TransactionReceipt transactionReceipt(h256 const& _transactionHash) const { TransactionAddress ta = queryExtras<TransactionAddress, ExtraTransactionAddress>(_transactionHash, m_transactionAddresses, x_transactionAddresses, NullTransactionAddress); if (!ta) return bytesConstRef(); return transactionReceipt(ta.blockHash, ta.index); }
/// Get a list of transaction hashes for a given block. Thread-safe.
TransactionHashes transactionHashes(h256 const& _hash) const { auto b = block(_hash); RLP rlp(b); h256s ret; for (auto t: rlp[1]) ret.push_back(sha3(t.data())); return ret; }

49
libethereum/Client.cpp

@ -407,10 +407,9 @@ void Client::appendFromNewPending(TransactionReceipt const& _receipt, h256Hash&
}
}
void Client::appendFromNewBlock(h256 const& _block, h256Hash& io_changed)
void Client::appendFromBlock(h256 const& _block, BlockPolarity _polarity, h256Hash& io_changed)
{
// TODO: more precise check on whether the txs match.
auto d = bc().info(_block);
auto receipts = bc().receipts(_block).receipts;
Guard l(x_filtersWatches);
@ -419,18 +418,16 @@ void Client::appendFromNewBlock(h256 const& _block, h256Hash& io_changed)
for (pair<h256 const, InstalledFilter>& i: m_filters)
{
// acceptable number & looks like block may contain a matching log entry.
unsigned logIndex = 0;
for (size_t j = 0; j < receipts.size(); j++)
{
logIndex++;
auto tr = receipts[j];
auto m = i.second.filter.matches(tr);
if (m.size())
{
auto transactionHash = transaction(d.hash(), j).sha3();
auto transactionHash = transaction(_block, j).sha3();
// filter catches them
for (LogEntry const& l: m)
i.second.changes.push_back(LocalisedLogEntry(l, d, transactionHash, j, logIndex));
i.second.changes.push_back(LocalisedLogEntry(l, _block, (BlockNumber)bc().number(_block), transactionHash, j, 0, _polarity));
io_changed.insert(i.first);
}
}
@ -562,10 +559,10 @@ void Client::syncTransactionQueue()
h->noteNewTransactions();
}
void Client::onChainChanged(ImportRoute const& _ir)
void Client::onDeadBlocks(h256s const& _blocks, h256Hash& io_changed)
{
// insert transactions that we are declaring the dead part of the chain
for (auto const& h: _ir.deadBlocks)
for (auto const& h: _blocks)
{
clog(ClientTrace) << "Dead block:" << h;
for (auto const& t: bc().transactions(h))
@ -575,23 +572,25 @@ void Client::onChainChanged(ImportRoute const& _ir)
}
}
for (auto const& h: _blocks)
appendFromBlock(h, BlockPolarity::Dead, io_changed);
}
void Client::onNewBlocks(h256s const& _blocks, h256Hash& io_changed)
{
// remove transactions from m_tq nicely rather than relying on out of date nonce later on.
for (auto const& h: _ir.liveBlocks)
for (auto const& h: _blocks)
clog(ClientTrace) << "Live block:" << h;
for (auto const& t: _ir.goodTranactions)
{
clog(ClientTrace) << "Safely dropping transaction " << t.sha3();
m_tq.dropGood(t);
}
if (auto h = m_host.lock())
h->noteNewBlocks();
h256Hash changeds;
for (auto const& h: _ir.liveBlocks)
appendFromNewBlock(h, changeds);
for (auto const& h: _blocks)
appendFromBlock(h, BlockPolarity::Live, io_changed);
}
void Client::restartMining()
{
// RESTART MINING
if (!isMajorSyncing())
@ -624,8 +623,6 @@ void Client::onChainChanged(ImportRoute const& _ir)
DEV_READ_GUARDED(x_working) DEV_WRITE_GUARDED(x_postMine)
m_postMine = m_working;
changeds.insert(PendingChangedFilter);
onPostStateChanged();
}
@ -633,7 +630,19 @@ void Client::onChainChanged(ImportRoute const& _ir)
// we should resync with it manually until we are stricter about what constitutes "knowing".
onTransactionQueueReady();
}
}
void Client::onChainChanged(ImportRoute const& _ir)
{
h256Hash changeds;
onDeadBlocks(_ir.deadBlocks, changeds);
for (auto const& t: _ir.goodTranactions)
{
clog(ClientTrace) << "Safely dropping transaction " << t.sha3();
m_tq.dropGood(t);
}
onNewBlocks(_ir.liveBlocks, changeds);
restartMining();
noteChanged(changeds);
}

11
libethereum/Client.h

@ -220,7 +220,7 @@ protected:
/// Collate the changed filters for the hash of the given block.
/// Insert any filters that are activated into @a o_changed.
void appendFromNewBlock(h256 const& _blockHash, h256Hash& io_changed);
void appendFromBlock(h256 const& _blockHash, BlockPolarity _polarity, h256Hash& io_changed);
/// Record that the set of filters @a _filters have changed.
/// This doesn't actually make any callbacks, but incrememnts some counters in m_watches.
@ -242,6 +242,15 @@ protected:
/// Called when wouldMine(), turboMining(), isChainBad(), forceMining(), pendingTransactions() have changed.
void rejigMining();
/// Called on chain changes
void onDeadBlocks(h256s const& _blocks, h256Hash& io_changed);
/// Called on chain changes
void onNewBlocks(h256s const& _blocks, h256Hash& io_changed);
/// Called after processing blocks by onChainChanged(_ir)
void restartMining();
/// Magically called when the chain has changed. An import route is provided.
/// Called by either submitWork() or in our main thread through syncBlockQueue().
void onChainChanged(ImportRoute const& _ir);

116
libethereum/ClientBase.cpp

@ -171,51 +171,67 @@ LocalisedLogEntries ClientBase::logs(LogFilter const& _f) const
// Might have a transaction that contains a matching log.
TransactionReceipt const& tr = temp.receipt(i);
LogEntries le = _f.matches(tr);
if (le.size())
for (unsigned j = 0; j < le.size(); ++j)
ret.insert(ret.begin(), LocalisedLogEntry(le[j]));
for (unsigned j = 0; j < le.size(); ++j)
ret.insert(ret.begin(), LocalisedLogEntry(le[j]));
}
begin = bc().number();
}
// Handle reverted blocks
// There are not so many, so let's iterate over them
h256s blocks;
h256 ancestor;
unsigned ancestorIndex;
tie(blocks, ancestor, ancestorIndex) = bc().treeRoute(_f.earliest(), _f.latest(), false);
for (size_t i = 0; i < ancestorIndex; i++)
prependLogsFromBlock(_f, blocks[i], BlockPolarity::Dead, ret);
// cause end is our earliest block, let's compare it with our ancestor
// if ancestor is smaller let's move our end to it
// example:
//
// 3b -> 2b -> 1b
// -> g
// 3a -> 2a -> 1a
//
// if earliest is at 2a and latest is a 3b, coverting them to numbers
// will give us pair (2, 3)
// and we want to get all logs from 1 (ancestor + 1) to 3
// so we have to move 2a to g + 1
end = min(end, (unsigned)numberFromHash(ancestor) + 1);
// Handle blocks from main chain
set<unsigned> matchingBlocks;
for (auto const& i: _f.bloomPossibilities())
for (auto u: bc().withBlockBloom(i, end, begin))
matchingBlocks.insert(u);
if (!_f.isRangeFilter())
for (auto const& i: _f.bloomPossibilities())
for (auto u: bc().withBlockBloom(i, end, begin))
matchingBlocks.insert(u);
else
// if it is a range filter, we want to get all logs from all blocks in given range
for (unsigned i = end; i <= begin; i++)
matchingBlocks.insert(i);
unsigned falsePos = 0;
for (auto n: matchingBlocks)
{
int total = 0;
auto h = bc().numberHash(n);
auto info = bc().info(h);
auto receipts = bc().receipts(h).receipts;
unsigned logIndex = 0;
for (size_t i = 0; i < receipts.size(); i++)
{
logIndex++;
TransactionReceipt receipt = receipts[i];
if (_f.matches(receipt.bloom()))
{
auto th = transaction(info.hash(), i).sha3();
LogEntries le = _f.matches(receipt);
if (le.size())
{
total += le.size();
for (unsigned j = 0; j < le.size(); ++j)
ret.insert(ret.begin(), LocalisedLogEntry(le[j], info, th, i, logIndex));
}
}
if (!total)
falsePos++;
}
}
prependLogsFromBlock(_f, bc().numberHash(n), BlockPolarity::Live, ret);
cdebug << matchingBlocks.size() << "searched from" << (end - begin) << "skipped; " << falsePos << "false +ves";
reverse(ret.begin(), ret.end());
return ret;
}
void ClientBase::prependLogsFromBlock(LogFilter const& _f, h256 const& _blockHash, BlockPolarity _polarity, LocalisedLogEntries& io_logs) const
{
auto receipts = bc().receipts(_blockHash).receipts;
for (size_t i = 0; i < receipts.size(); i++)
{
TransactionReceipt receipt = receipts[i];
auto th = transaction(_blockHash, i).sha3();
LogEntries le = _f.matches(receipt);
for (unsigned j = 0; j < le.size(); ++j)
io_logs.insert(io_logs.begin(), LocalisedLogEntry(le[j], _blockHash, (BlockNumber)bc().number(_blockHash), th, i, 0, _polarity));
}
}
unsigned ClientBase::installWatch(LogFilter const& _f, Reaping _r)
{
h256 h = _f.sha3();
@ -317,6 +333,12 @@ Transaction ClientBase::transaction(h256 _transactionHash) const
return Transaction(bc().transaction(_transactionHash), CheckTransaction::Cheap);
}
LocalisedTransaction ClientBase::localisedTransaction(h256 const& _transactionHash) const
{
std::pair<h256, unsigned> tl = bc().transactionLocation(_transactionHash);
return localisedTransaction(tl.first, tl.second);
}
Transaction ClientBase::transaction(h256 _blockHash, unsigned _i) const
{
auto bl = bc().block(_blockHash);
@ -327,11 +349,31 @@ Transaction ClientBase::transaction(h256 _blockHash, unsigned _i) const
return Transaction();
}
LocalisedTransaction ClientBase::localisedTransaction(h256 const& _blockHash, unsigned _i) const
{
Transaction t = Transaction(bc().transaction(_blockHash, _i), CheckTransaction::Cheap);
return LocalisedTransaction(t, _blockHash, _i, numberFromHash(_blockHash));
}
TransactionReceipt ClientBase::transactionReceipt(h256 const& _transactionHash) const
{
return bc().transactionReceipt(_transactionHash);
}
LocalisedTransactionReceipt ClientBase::localisedTransactionReceipt(h256 const& _transactionHash) const
{
std::pair<h256, unsigned> tl = bc().transactionLocation(_transactionHash);
Transaction t = Transaction(bc().transaction(tl.first, tl.second), CheckTransaction::Cheap);
TransactionReceipt tr = bc().transactionReceipt(tl.first, tl.second);
return LocalisedTransactionReceipt(
tr,
t.sha3(),
tl.first,
numberFromHash(tl.first),
tl.second,
toAddress(t.from(), t.nonce()));
}
pair<h256, unsigned> ClientBase::transactionLocation(h256 const& _transactionHash) const
{
return bc().transactionLocation(_transactionHash);
@ -479,3 +521,7 @@ bool ClientBase::isKnownTransaction(h256 const& _transactionHash) const
return bc().isKnownTransaction(_transactionHash);
}
bool ClientBase::isKnownTransaction(h256 const& _blockHash, unsigned _i) const
{
return isKnown(_blockHash) && bc().transactions().size() > _i;
}

5
libethereum/ClientBase.h

@ -104,6 +104,7 @@ public:
virtual LocalisedLogEntries logs(unsigned _watchId) const override;
virtual LocalisedLogEntries logs(LogFilter const& _filter) const override;
virtual void prependLogsFromBlock(LogFilter const& _filter, h256 const& _blockHash, BlockPolarity _polarity, LocalisedLogEntries& io_logs) const;
/// Install, uninstall and query watches.
virtual unsigned installWatch(LogFilter const& _filter, Reaping _r = Reaping::Automatic) override;
@ -118,8 +119,11 @@ public:
virtual BlockInfo blockInfo(h256 _hash) const override;
virtual BlockDetails blockDetails(h256 _hash) const override;
virtual Transaction transaction(h256 _transactionHash) const override;
virtual LocalisedTransaction localisedTransaction(h256 const& _transactionHash) const override;
virtual Transaction transaction(h256 _blockHash, unsigned _i) const override;
virtual LocalisedTransaction localisedTransaction(h256 const& _blockHash, unsigned _i) const override;
virtual TransactionReceipt transactionReceipt(h256 const& _transactionHash) const override;
virtual LocalisedTransactionReceipt localisedTransactionReceipt(h256 const& _transactionHash) const override;
virtual std::pair<h256, unsigned> transactionLocation(h256 const& _transactionHash) const override;
virtual Transactions transactions(h256 _blockHash) const override;
virtual TransactionHashes transactionHashes(h256 _blockHash) const override;
@ -148,6 +152,7 @@ public:
virtual bool isKnown(h256 const& _hash) const override;
virtual bool isKnown(BlockNumber _block) const override;
virtual bool isKnownTransaction(h256 const& _transactionHash) const override;
virtual bool isKnownTransaction(h256 const& _blockHash, unsigned _i) const override;
/// TODO: consider moving it to a separate interface

4
libethereum/Interface.h

@ -134,8 +134,11 @@ public:
// [BLOCK QUERY API]
virtual bool isKnownTransaction(h256 const& _transactionHash) const = 0;
virtual bool isKnownTransaction(h256 const& _blockHash, unsigned _i) const = 0;
virtual Transaction transaction(h256 _transactionHash) const = 0;
virtual LocalisedTransaction localisedTransaction(h256 const& _transactionHash) const = 0;
virtual TransactionReceipt transactionReceipt(h256 const& _transactionHash) const = 0;
virtual LocalisedTransactionReceipt localisedTransactionReceipt(h256 const& _transactionHash) const = 0;
virtual std::pair<h256, unsigned> transactionLocation(h256 const& _transactionHash) const = 0;
virtual h256 hashFromNumber(BlockNumber _number) const = 0;
virtual BlockNumber numberFromHash(h256 _blockHash) const = 0;
@ -146,6 +149,7 @@ public:
virtual BlockInfo blockInfo(h256 _hash) const = 0;
virtual BlockDetails blockDetails(h256 _hash) const = 0;
virtual Transaction transaction(h256 _blockHash, unsigned _i) const = 0;
virtual LocalisedTransaction localisedTransaction(h256 const& _blockHash, unsigned _i) const = 0;
virtual BlockInfo uncle(h256 _blockHash, unsigned _i) const = 0;
virtual UncleHashes uncleHashes(h256 _blockHash) const = 0;
virtual unsigned transactionCount(h256 _blockHash) const = 0;

71
libethereum/LogFilter.cpp

@ -46,6 +46,18 @@ h256 LogFilter::sha3() const
return dev::sha3(s.out());
}
bool LogFilter::isRangeFilter() const
{
if (m_addresses.size())
return false;
for (auto const& t: m_topics)
if (t.size())
return false;
return true;
}
bool LogFilter::matches(LogBloom _bloom) const
{
if (m_addresses.size())
@ -77,14 +89,67 @@ vector<LogBloom> LogFilter::bloomPossibilities() const
{
// return combination of each of the addresses/topics
vector<LogBloom> ret;
// TODO proper combinatorics.
for (auto i: m_addresses)
ret.push_back(LogBloom().shiftBloom<3>(dev::sha3(i)));
// | every address with every topic
for (auto const& i: m_addresses)
{
// 1st case, there are addresses and topics
//
// m_addresses = [a0, a1];
// m_topics = [[t0], [t1a, t1b], [], []];
//
// blooms = [
// a0 | t0, a0 | t1a | t1b,
// a1 | t0, a1 | t1a | t1b
// ]
//
for (auto const& t: m_topics)
if (t.size())
{
LogBloom b = LogBloom().shiftBloom<3>(dev::sha3(i));
for (auto const &j: t)
b = b.shiftBloom<3>(dev::sha3(j));
ret.push_back(b);
}
}
// 2nd case, there are no topics
//
// m_addresses = [a0, a1];
// m_topics = [[t0], [t1a, t1b], [], []];
//
// blooms = [a0, a1];
//
if (!ret.size())
for (auto const& i: m_addresses)
ret.push_back(LogBloom().shiftBloom<3>(dev::sha3(i)));
// 3rd case, there are no addresses, at least create blooms from topics
//
// m_addresses = [];
// m_topics = [[t0], [t1a, t1b], [], []];
//
// blooms = [t0, t1a | t1b];
//
if (!m_addresses.size())
for (auto const& t: m_topics)
if (t.size())
{
LogBloom b;
for (auto const &j: t)
b = b.shiftBloom<3>(dev::sha3(j));
ret.push_back(b);
}
return ret;
}
LogEntries LogFilter::matches(TransactionReceipt const& _m) const
{
// there are no addresses or topics to filter
if (isRangeFilter())
return _m.log();
LogEntries ret;
if (matches(_m.bloom()))
for (LogEntry const& e: _m.log())

10
libethereum/LogFilter.h

@ -50,10 +50,20 @@ public:
void streamRLP(RLPStream& _s) const;
h256 sha3() const;
/// hash of earliest block which should be filtered
h256 earliest() const { return m_earliest; }
/// hash of latest block which should be filtered
h256 latest() const { return m_latest; }
/// Range filter is a filter which doesn't care about addresses or topics
/// Matches are all entries from earliest to latest
/// @returns true if addresses and topics are unspecified
bool isRangeFilter() const;
/// @returns bloom possibilities for all addresses and topics
std::vector<LogBloom> bloomPossibilities() const;
bool matches(LogBloom _bloom) const;
bool matches(State const& _s, unsigned _i) const;
LogEntries matches(TransactionReceipt const& _r) const;

25
libethereum/Transaction.h

@ -130,5 +130,30 @@ private:
/// Nice name for vector of Transaction.
using Transactions = std::vector<Transaction>;
class LocalisedTransaction: public Transaction
{
public:
LocalisedTransaction(
Transaction const& _t,
h256 const& _blockHash,
unsigned _transactionIndex,
BlockNumber _blockNumber = 0
):
Transaction(_t),
m_blockHash(_blockHash),
m_transactionIndex(_transactionIndex),
m_blockNumber(_blockNumber)
{}
h256 const& blockHash() const { return m_blockHash; }
unsigned transactionIndex() const { return m_transactionIndex; }
BlockNumber blockNumber() const { return m_blockNumber; }
private:
h256 m_blockHash;
unsigned m_transactionIndex;
BlockNumber m_blockNumber;
};
}
}

46
libethereum/TransactionReceipt.h

@ -58,5 +58,51 @@ using TransactionReceipts = std::vector<TransactionReceipt>;
std::ostream& operator<<(std::ostream& _out, eth::TransactionReceipt const& _r);
class LocalisedTransactionReceipt: public TransactionReceipt
{
public:
LocalisedTransactionReceipt(
TransactionReceipt const& _t,
h256 const& _hash,
h256 const& _blockHash,
BlockNumber _blockNumber,
unsigned _transactionIndex,
Address const& _contractAddress = Address()
):
TransactionReceipt(_t),
m_hash(_hash),
m_blockHash(_blockHash),
m_blockNumber(_blockNumber),
m_transactionIndex(_transactionIndex),
m_contractAddress(_contractAddress)
{
LogEntries entries = log();
for (unsigned i = 0; i < entries.size(); i++)
m_localisedLogs.push_back(LocalisedLogEntry(
entries[i],
m_blockHash,
m_blockNumber,
m_hash,
m_transactionIndex,
i
));
}
h256 const& hash() const { return m_hash; }
h256 const& blockHash() const { return m_blockHash; }
BlockNumber blockNumber() const { return m_blockNumber; }
unsigned transactionIndex() const { return m_transactionIndex; }
Address const& contractAddress() const { return m_contractAddress; }
LocalisedLogEntries const& localisedLogs() const { return m_localisedLogs; };
private:
h256 m_hash;
h256 m_blockHash;
BlockNumber m_blockNumber;
unsigned m_transactionIndex = 0;
Address m_contractAddress;
LocalisedLogEntries m_localisedLogs;
};
}
}

29
libevm/ExtVMFace.h

@ -36,6 +36,13 @@ namespace dev
namespace eth
{
enum class BlockPolarity
{
Unknown,
Dead,
Live
};
struct LogEntry
{
LogEntry() {}
@ -76,17 +83,20 @@ struct LocalisedLogEntry: public LogEntry
explicit LocalisedLogEntry(
LogEntry const& _le,
BlockInfo const& _bi,
h256 _th,
unsigned _ti,
unsigned _li
h256 const& _blockHash,
BlockNumber _blockNumber,
h256 const& _transactionHash,
unsigned _transactionIndex,
unsigned _logIndex,
BlockPolarity _polarity = BlockPolarity::Unknown
):
LogEntry(_le),
blockHash(_bi.hash()),
blockNumber((BlockNumber)_bi.number()),
transactionHash(_th),
transactionIndex(_ti),
logIndex(_li),
blockHash(_blockHash),
blockNumber(_blockNumber),
transactionHash(_transactionHash),
transactionIndex(_transactionIndex),
logIndex(_logIndex),
polarity(_polarity),
mined(true)
{}
@ -95,6 +105,7 @@ struct LocalisedLogEntry: public LogEntry
h256 transactionHash;
unsigned transactionIndex = 0;
unsigned logIndex = 0;
BlockPolarity polarity = BlockPolarity::Unknown;
bool mined = false;
bool isSpecial = false;
h256 special;

116
libweb3jsonrpc/JsonHelper.cpp

@ -183,30 +183,17 @@ Json::Value toJson(dev::eth::TransactionReceipt const& _t)
return res;
}
Json::Value toJson(dev::eth::TransactionReceipt const& _tr, std::pair<h256, unsigned> _location, BlockNumber _blockNumber, Transaction const& _t)
Json::Value toJson(dev::eth::LocalisedTransactionReceipt const& _t)
{
Json::Value res;
h256 h = _t.sha3();
res["transactionHash"] = toJS(h);
res["transactionIndex"] = _location.second;
res["blockHash"] = toJS(_location.first);
res["blockNumber"] = _blockNumber;
res["cumulativeGasUsed"] = toJS(_tr.gasUsed()); // TODO: check if this is fine
res["gasUsed"] = toJS(_tr.gasUsed());
res["contractAddress"] = toJS(toAddress(_t.from(), _t.nonce()));
res["logs"] = Json::Value(Json::arrayValue);
for (unsigned i = 0; i < _tr.log().size(); i++)
{
LogEntry e = _tr.log()[i];
Json::Value l = toJson(e);
l["type"] = "mined";
l["blockNumber"] = _blockNumber;
l["blockHash"] = toJS(_location.first);
l["logIndex"] = i;
l["transactionHash"] = toJS(h);
l["transactionIndex"] = _location.second;
res["logs"].append(l);
}
res["transactionHash"] = toJS(_t.hash());
res["transactionIndex"] = _t.transactionIndex();
res["blockHash"] = toJS(_t.blockHash());
res["blockNumber"] = _t.blockNumber();
res["cumulativeGasUsed"] = toJS(_t.gasUsed()); // TODO: check if this is fine
res["gasUsed"] = toJS(_t.gasUsed());
res["contractAddress"] = toJS(_t.contractAddress());
res["logs"] = dev::toJson(_t.localisedLogs());
return res;
}
@ -228,6 +215,26 @@ Json::Value toJson(dev::eth::Transaction const& _t)
return res;
}
Json::Value toJson(dev::eth::LocalisedTransaction const& _t)
{
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(_t.blockHash());
res["transactionIndex"] = toJS(_t.transactionIndex());
res["blockNumber"] = toJS(_t.blockNumber());
}
return res;
}
Json::Value toJson(dev::eth::LocalisedLogEntry const& _e)
{
Json::Value res;
@ -237,6 +244,7 @@ Json::Value toJson(dev::eth::LocalisedLogEntry const& _e)
else
{
res = toJson(static_cast<dev::eth::LogEntry const&>(_e));
res["polarity"] = _e.polarity == BlockPolarity::Live ? true : false;
if (_e.mined)
{
res["type"] = "mined";
@ -270,6 +278,70 @@ Json::Value toJson(dev::eth::LogEntry const& _e)
return res;
}
Json::Value toJson(std::unordered_map<h256, dev::eth::LocalisedLogEntries> const& _entriesByBlock, vector<h256> const& _order)
{
Json::Value res(Json::arrayValue);
for (auto const& i: _order)
{
auto entries = _entriesByBlock.at(i);
Json::Value currentBlock(Json::objectValue);
LocalisedLogEntry entry = entries[0];
if (entry.mined)
{
currentBlock["blockNumber"] = entry.blockNumber;
currentBlock["blockHash"] = toJS(entry.blockHash);
currentBlock["type"] = "mined";
}
else
currentBlock["type"] = "pending";
currentBlock["polarity"] = entry.polarity == BlockPolarity::Live ? true : false;
currentBlock["logs"] = Json::Value(Json::arrayValue);
for (LocalisedLogEntry const& e: entries)
{
Json::Value log(Json::objectValue);
log["logIndex"] = e.logIndex;
log["transactionIndex"] = e.transactionIndex;
log["transactionHash"] = toJS(e.transactionHash);
log["address"] = toJS(e.address);
log["data"] = toJS(e.data);
log["topics"] = Json::Value(Json::arrayValue);
for (auto const& t: e.topics)
log["topics"].append(toJS(t));
currentBlock["logs"].append(log);
}
res.append(currentBlock);
}
return res;
}
Json::Value toJsonByBlock(LocalisedLogEntries const& _entries)
{
vector<h256> order;
unordered_map <h256, LocalisedLogEntries> entriesByBlock;
for (dev::eth::LocalisedLogEntry const& e: _entries)
{
if (e.isSpecial) // skip special log
continue;
if (entriesByBlock.count(e.blockHash) == 0)
{
entriesByBlock[e.blockHash] = LocalisedLogEntries();
order.push_back(e.blockHash);
}
entriesByBlock[e.blockHash].push_back(e);
}
return toJson(entriesByBlock, order);
}
TransactionSkeleton toTransactionSkeleton(Json::Value const& _json)
{
TransactionSkeleton ret;

7
libweb3jsonrpc/JsonHelper.h

@ -44,6 +44,7 @@ namespace eth
{
class Transaction;
class LocalisedTransaction;
struct BlockDetails;
class Interface;
using Transactions = std::vector<Transaction>;
@ -57,11 +58,13 @@ Json::Value toJson(BlockInfo const& _bi, BlockDetails const& _bd, UncleHashes co
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(LocalisedTransaction const& _t);
Json::Value toJson(TransactionReceipt const& _t);
//TODO: wrap these params into one structure eg. "LocalisedTransactionReceipt"
Json::Value toJson(TransactionReceipt const& _tr, std::pair<h256, unsigned> _location, BlockNumber _blockNumber, Transaction const& _t);
Json::Value toJson(LocalisedTransactionReceipt const& _t);
Json::Value toJson(LocalisedLogEntry const& _e);
Json::Value toJson(LogEntry const& _e);
Json::Value toJson(std::unordered_map<h256, LocalisedLogEntries> const& _entriesByBlock);
Json::Value toJsonByBlock(LocalisedLogEntries const& _entries);
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.

37
libweb3jsonrpc/WebThreeStubServerBase.cpp

@ -380,8 +380,7 @@ Json::Value WebThreeStubServerBase::eth_getTransactionByHash(string const& _tran
if (!client()->isKnownTransaction(h))
return Json::Value(Json::nullValue);
auto l = client()->transactionLocation(h);
return toJson(client()->transaction(h), l, client()->numberFromHash(l.first));
return toJson(client()->localisedTransaction(h));
}
catch (...)
{
@ -395,8 +394,10 @@ Json::Value WebThreeStubServerBase::eth_getTransactionByBlockHashAndIndex(string
{
h256 bh = jsToFixed<32>(_blockHash);
unsigned ti = jsToInt(_transactionIndex);
Transaction t = client()->transaction(bh, ti);
return toJson(t, make_pair(bh, ti), client()->numberFromHash(bh));
if (!client()->isKnownTransaction(bh, ti))
return Json::Value(Json::nullValue);
return toJson(client()->localisedTransaction(bh, ti));
}
catch (...)
{
@ -409,9 +410,12 @@ Json::Value WebThreeStubServerBase::eth_getTransactionByBlockNumberAndIndex(stri
try
{
BlockNumber bn = jsToBlockNumber(_blockNumber);
h256 bh = client()->hashFromNumber(bn);
unsigned ti = jsToInt(_transactionIndex);
Transaction t = client()->transaction(bn, ti);
return toJson(t, make_pair(client()->hashFromNumber(bn), ti), bn);
if (!client()->isKnownTransaction(bh, ti))
return Json::Value(Json::nullValue);
return toJson(client()->localisedTransaction(bh, ti));
}
catch (...)
{
@ -427,8 +431,7 @@ Json::Value WebThreeStubServerBase::eth_getTransactionReceipt(string const& _tra
if (!client()->isKnownTransaction(h))
return Json::Value(Json::nullValue);
auto l = client()->transactionLocation(h);
return toJson(client()->transactionReceipt(h), l, client()->numberFromHash(l.first), client()->transaction(h));
return toJson(client()->localisedTransactionReceipt(h));
}
catch (...)
{
@ -686,7 +689,7 @@ Json::Value WebThreeStubServerBase::eth_getFilterChangesEx(string const& _filter
auto entries = client()->checkWatch(id);
if (entries.size())
cnote << "FIRING WATCH" << id << entries.size();
return toJson(entries);
return toJsonByBlock(entries);
}
catch (...)
{
@ -710,7 +713,7 @@ Json::Value WebThreeStubServerBase::eth_getFilterLogsEx(string const& _filterId)
{
try
{
return toJson(client()->logs(jsToInt(_filterId)));
return toJsonByBlock(client()->logs(jsToInt(_filterId)));
}
catch (...)
{
@ -722,7 +725,19 @@ Json::Value WebThreeStubServerBase::eth_getLogs(Json::Value const& _json)
{
try
{
return toJson(client()->logs(toLogFilter(_json)));
return toJson(client()->logs(toLogFilter(_json, *client())));
}
catch (...)
{
BOOST_THROW_EXCEPTION(JsonRpcException(Errors::ERROR_RPC_INVALID_PARAMS));
}
}
Json::Value WebThreeStubServerBase::eth_getLogsEx(Json::Value const& _json)
{
try
{
return toJsonByBlock(client()->logs(toLogFilter(_json)));
}
catch (...)
{

1
libweb3jsonrpc/WebThreeStubServerBase.h

@ -136,6 +136,7 @@ public:
virtual Json::Value eth_getFilterLogs(std::string const& _filterId);
virtual Json::Value eth_getFilterLogsEx(std::string const& _filterId);
virtual Json::Value eth_getLogs(Json::Value const& _json);
virtual Json::Value eth_getLogsEx(Json::Value const& _json);
virtual Json::Value eth_getWork();
virtual bool eth_submitWork(std::string const& _nonce, std::string const&, std::string const& _mixHash);
virtual std::string eth_register(std::string const& _address);

6
libweb3jsonrpc/abstractwebthreestubserver.h

@ -57,6 +57,7 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServer<AbstractWebThr
this->bindAndAddMethod(jsonrpc::Procedure("eth_getFilterLogs", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_getFilterLogsI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_getFilterLogsEx", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_getFilterLogsExI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_getLogs", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, "param1",jsonrpc::JSON_OBJECT, NULL), &AbstractWebThreeStubServer::eth_getLogsI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_getLogsEx", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, "param1",jsonrpc::JSON_OBJECT, NULL), &AbstractWebThreeStubServer::eth_getLogsExI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_getWork", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, NULL), &AbstractWebThreeStubServer::eth_getWorkI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_submitWork", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING,"param3",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_submitWorkI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_register", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_registerI);
@ -296,6 +297,10 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServer<AbstractWebThr
{
response = this->eth_getLogs(request[0u]);
}
inline virtual void eth_getLogsExI(const Json::Value &request, Json::Value &response)
{
response = this->eth_getLogsEx(request[0u]);
}
inline virtual void eth_getWorkI(const Json::Value &request, Json::Value &response)
{
(void)request;
@ -511,6 +516,7 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServer<AbstractWebThr
virtual Json::Value eth_getFilterLogs(const std::string& param1) = 0;
virtual Json::Value eth_getFilterLogsEx(const std::string& param1) = 0;
virtual Json::Value eth_getLogs(const Json::Value& param1) = 0;
virtual Json::Value eth_getLogsEx(const Json::Value& param1) = 0;
virtual Json::Value eth_getWork() = 0;
virtual bool eth_submitWork(const std::string& param1, const std::string& param2, const std::string& param3) = 0;
virtual std::string eth_register(const std::string& param1) = 0;

1
libweb3jsonrpc/spec.json

@ -46,6 +46,7 @@
{ "name": "eth_getFilterLogs", "params": [""], "order": [], "returns": []},
{ "name": "eth_getFilterLogsEx", "params": [""], "order": [], "returns": []},
{ "name": "eth_getLogs", "params": [{}], "order": [], "returns": []},
{ "name": "eth_getLogsEx", "params": [{}], "order": [], "returns": []},
{ "name": "eth_getWork", "params": [], "order": [], "returns": []},
{ "name": "eth_submitWork", "params": ["", "", ""], "order": [], "returns": true},
{ "name": "eth_register", "params": [""], "order": [], "returns": ""},

10
test/libweb3jsonrpc/webthreestubclient.h

@ -474,6 +474,16 @@ class WebThreeStubClient : public jsonrpc::Client
else
throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString());
}
Json::Value eth_getLogsEx(const Json::Value& param1) throw (jsonrpc::JsonRpcException)
{
Json::Value p;
p.append(param1);
Json::Value result = this->CallMethod("eth_getLogsEx",p);
if (result.isArray())
return result;
else
throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString());
}
Json::Value eth_getWork() throw (jsonrpc::JsonRpcException)
{
Json::Value p;

Loading…
Cancel
Save