Gav Wood
10 years ago
9 changed files with 658 additions and 841 deletions
@ -0,0 +1,402 @@ |
|||
/*
|
|||
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 <http://www.gnu.org/licenses/>.
|
|||
*/ |
|||
/** @file ClientBase.cpp
|
|||
* @author Gav Wood <i@gavwood.com> |
|||
* @author Marek Kotewicz <marek@ethdev.com> |
|||
* @date 2015 |
|||
*/ |
|||
|
|||
#include <libdevcore/StructuredLogger.h> |
|||
#include "ClientBase.h" |
|||
#include "BlockChain.h" |
|||
#include "Executive.h" |
|||
|
|||
using namespace std; |
|||
using namespace dev; |
|||
using namespace dev::eth; |
|||
|
|||
State ClientBase::asOf(BlockNumber _h) const |
|||
{ |
|||
if (_h == PendingBlock) |
|||
return postMine(); |
|||
else if (_h == LatestBlock) |
|||
return preMine(); |
|||
return asOf(bc().numberHash(_h)); |
|||
} |
|||
|
|||
void ClientBase::submitTransaction(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice) |
|||
{ |
|||
prepareForTransaction(); |
|||
|
|||
u256 n = postMine().transactionsFrom(toAddress(_secret)); |
|||
Transaction t(_value, _gasPrice, _gas, _dest, _data, n, _secret); |
|||
m_tq.attemptImport(t.rlp()); |
|||
|
|||
StructuredLogger::transactionReceived(t.sha3().abridged(), t.sender().abridged()); |
|||
cnote << "New transaction " << t; |
|||
} |
|||
|
|||
Address ClientBase::submitTransaction(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas, u256 _gasPrice) |
|||
{ |
|||
prepareForTransaction(); |
|||
|
|||
u256 n = postMine().transactionsFrom(toAddress(_secret)); |
|||
Transaction t(_endowment, _gasPrice, _gas, _init, n, _secret); |
|||
m_tq.attemptImport(t.rlp()); |
|||
|
|||
StructuredLogger::transactionReceived(t.sha3().abridged(), t.sender().abridged()); |
|||
cnote << "New transaction " << t; |
|||
|
|||
return right160(sha3(rlpList(t.sender(), t.nonce()))); |
|||
} |
|||
|
|||
// TODO: remove try/catch, allow exceptions
|
|||
ExecutionResult ClientBase::call(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber) |
|||
{ |
|||
ExecutionResult ret; |
|||
try |
|||
{ |
|||
State temp = asOf(_blockNumber); |
|||
u256 n = temp.transactionsFrom(toAddress(_secret)); |
|||
Transaction t(_value, _gasPrice, _gas, _dest, _data, n, _secret); |
|||
ret = temp.execute(bc(), t.rlp(), Permanence::Reverted); |
|||
} |
|||
catch (...) |
|||
{ |
|||
// TODO: Some sort of notification of failure.
|
|||
} |
|||
return ret; |
|||
} |
|||
|
|||
ExecutionResult ClientBase::create(Secret _secret, u256 _value, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber) |
|||
{ |
|||
ExecutionResult ret; |
|||
try |
|||
{ |
|||
State temp = asOf(_blockNumber); |
|||
u256 n = temp.transactionsFrom(toAddress(_secret)); |
|||
// cdebug << "Nonce at " << toAddress(_secret) << " pre:" << m_preMine.transactionsFrom(toAddress(_secret)) << " post:" << m_postMine.transactionsFrom(toAddress(_secret));
|
|||
|
|||
Transaction t(_value, _gasPrice, _gas, _data, n, _secret); |
|||
ret = temp.execute(bc(), t.rlp(), Permanence::Reverted); |
|||
} |
|||
catch (...) |
|||
{ |
|||
// TODO: Some sort of notification of failure.
|
|||
} |
|||
return ret; |
|||
} |
|||
|
|||
u256 ClientBase::balanceAt(Address _a, BlockNumber _block) const |
|||
{ |
|||
return asOf(_block).balance(_a); |
|||
} |
|||
|
|||
u256 ClientBase::countAt(Address _a, BlockNumber _block) const |
|||
{ |
|||
return asOf(_block).transactionsFrom(_a); |
|||
} |
|||
|
|||
u256 ClientBase::stateAt(Address _a, u256 _l, BlockNumber _block) const |
|||
{ |
|||
return asOf(_block).storage(_a, _l); |
|||
} |
|||
|
|||
bytes ClientBase::codeAt(Address _a, BlockNumber _block) const |
|||
{ |
|||
return asOf(_block).code(_a); |
|||
} |
|||
|
|||
map<u256, u256> ClientBase::storageAt(Address _a, BlockNumber _block) const |
|||
{ |
|||
return asOf(_block).storage(_a); |
|||
} |
|||
|
|||
// TODO: remove try/catch, allow exceptions
|
|||
LocalisedLogEntries ClientBase::logs(unsigned _watchId) const |
|||
{ |
|||
LogFilter f; |
|||
try |
|||
{ |
|||
Guard l(x_filtersWatches); |
|||
f = m_filters.at(m_watches.at(_watchId).id).filter; |
|||
} |
|||
catch (...) |
|||
{ |
|||
return LocalisedLogEntries(); |
|||
} |
|||
return logs(f); |
|||
} |
|||
|
|||
LocalisedLogEntries ClientBase::logs(LogFilter const& _f) const |
|||
{ |
|||
LocalisedLogEntries ret; |
|||
unsigned begin = min<unsigned>(bc().number() + 1, (unsigned)_f.latest()); |
|||
unsigned end = min(bc().number(), min(begin, (unsigned)_f.earliest())); |
|||
|
|||
// Handle pending transactions differently as they're not on the block chain.
|
|||
if (begin > bc().number()) |
|||
{ |
|||
State temp = postMine(); |
|||
for (unsigned i = 0; i < temp.pending().size(); ++i) |
|||
{ |
|||
// Might have a transaction that contains a matching log.
|
|||
TransactionReceipt const& tr = temp.receipt(i); |
|||
auto th = temp.pending()[i].sha3(); |
|||
LogEntries le = _f.matches(tr); |
|||
if (le.size()) |
|||
for (unsigned j = 0; j < le.size(); ++j) |
|||
ret.insert(ret.begin(), LocalisedLogEntry(le[j], begin, th)); |
|||
} |
|||
begin = bc().number(); |
|||
} |
|||
|
|||
set<unsigned> matchingBlocks; |
|||
for (auto const& i: _f.bloomPossibilities()) |
|||
for (auto u: bc().withBlockBloom(i, end, begin)) |
|||
matchingBlocks.insert(u); |
|||
|
|||
unsigned falsePos = 0; |
|||
for (auto n: matchingBlocks) |
|||
{ |
|||
int total = 0; |
|||
auto h = bc().numberHash(n); |
|||
auto receipts = bc().receipts(h).receipts; |
|||
for (size_t i = 0; i < receipts.size(); i++) |
|||
{ |
|||
TransactionReceipt receipt = receipts[i]; |
|||
if (_f.matches(receipt.bloom())) |
|||
{ |
|||
auto info = bc().info(h); |
|||
auto th = transaction(info.hash, i).sha3(); |
|||
LogEntries le = _f.matches(receipt); |
|||
if (le.size()) |
|||
{ |
|||
total += le.size(); |
|||
for (unsigned j = 0; j < le.size(); ++j) |
|||
ret.insert(ret.begin(), LocalisedLogEntry(le[j], n, th)); |
|||
} |
|||
} |
|||
|
|||
if (!total) |
|||
falsePos++; |
|||
} |
|||
} |
|||
|
|||
cdebug << matchingBlocks.size() << "searched from" << (end - begin) << "skipped; " << falsePos << "false +ves"; |
|||
return ret; |
|||
} |
|||
|
|||
unsigned ClientBase::installWatch(LogFilter const& _f, Reaping _r) |
|||
{ |
|||
h256 h = _f.sha3(); |
|||
{ |
|||
Guard l(x_filtersWatches); |
|||
if (!m_filters.count(h)) |
|||
{ |
|||
cwatch << "FFF" << _f << h.abridged(); |
|||
m_filters.insert(make_pair(h, _f)); |
|||
} |
|||
} |
|||
return installWatch(h, _r); |
|||
} |
|||
|
|||
unsigned ClientBase::installWatch(h256 _h, Reaping _r) |
|||
{ |
|||
unsigned ret; |
|||
{ |
|||
Guard l(x_filtersWatches); |
|||
ret = m_watches.size() ? m_watches.rbegin()->first + 1 : 0; |
|||
m_watches[ret] = ClientWatch(_h, _r); |
|||
cwatch << "+++" << ret << _h.abridged(); |
|||
} |
|||
auto ch = logs(ret); |
|||
if (ch.empty()) |
|||
ch.push_back(InitialChange); |
|||
{ |
|||
Guard l(x_filtersWatches); |
|||
swap(m_watches[ret].changes, ch); |
|||
} |
|||
return ret; |
|||
} |
|||
|
|||
bool ClientBase::uninstallWatch(unsigned _i) |
|||
{ |
|||
cwatch << "XXX" << _i; |
|||
|
|||
Guard l(x_filtersWatches); |
|||
|
|||
auto it = m_watches.find(_i); |
|||
if (it == m_watches.end()) |
|||
return false; |
|||
auto id = it->second.id; |
|||
m_watches.erase(it); |
|||
|
|||
auto fit = m_filters.find(id); |
|||
if (fit != m_filters.end()) |
|||
if (!--fit->second.refCount) |
|||
{ |
|||
cwatch << "*X*" << fit->first << ":" << fit->second.filter; |
|||
m_filters.erase(fit); |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
LocalisedLogEntries ClientBase::peekWatch(unsigned _watchId) const |
|||
{ |
|||
Guard l(x_filtersWatches); |
|||
|
|||
cwatch << "peekWatch" << _watchId; |
|||
auto& w = m_watches.at(_watchId); |
|||
cwatch << "lastPoll updated to " << chrono::duration_cast<chrono::seconds>(chrono::system_clock::now().time_since_epoch()).count(); |
|||
w.lastPoll = chrono::system_clock::now(); |
|||
return w.changes; |
|||
} |
|||
|
|||
LocalisedLogEntries ClientBase::checkWatch(unsigned _watchId) |
|||
{ |
|||
Guard l(x_filtersWatches); |
|||
LocalisedLogEntries ret; |
|||
|
|||
cwatch << "checkWatch" << _watchId; |
|||
auto& w = m_watches.at(_watchId); |
|||
cwatch << "lastPoll updated to " << chrono::duration_cast<chrono::seconds>(chrono::system_clock::now().time_since_epoch()).count(); |
|||
std::swap(ret, w.changes); |
|||
w.lastPoll = chrono::system_clock::now(); |
|||
|
|||
return ret; |
|||
} |
|||
|
|||
h256 ClientBase::hashFromNumber(unsigned _number) const |
|||
{ |
|||
return bc().numberHash(_number); |
|||
} |
|||
|
|||
BlockInfo ClientBase::blockInfo(h256 _hash) const |
|||
{ |
|||
return BlockInfo(bc().block(_hash)); |
|||
} |
|||
|
|||
BlockDetails ClientBase::blockDetails(h256 _hash) const |
|||
{ |
|||
return bc().details(_hash); |
|||
} |
|||
|
|||
Transaction ClientBase::transaction(h256 _transactionHash) const |
|||
{ |
|||
return Transaction(bc().transaction(_transactionHash), CheckSignature::Range); |
|||
} |
|||
|
|||
Transaction ClientBase::transaction(h256 _blockHash, unsigned _i) const |
|||
{ |
|||
auto bl = bc().block(_blockHash); |
|||
RLP b(bl); |
|||
if (_i < b[1].itemCount()) |
|||
return Transaction(b[1][_i].data(), CheckSignature::Range); |
|||
else |
|||
return Transaction(); |
|||
} |
|||
|
|||
Transactions ClientBase::transactions(h256 _blockHash) const |
|||
{ |
|||
auto bl = bc().block(_blockHash); |
|||
RLP b(bl); |
|||
Transactions res; |
|||
for (unsigned i = 0; i < b[1].itemCount(); i++) |
|||
res.emplace_back(b[1][i].data(), CheckSignature::Range); |
|||
return res; |
|||
} |
|||
|
|||
TransactionHashes ClientBase::transactionHashes(h256 _blockHash) const |
|||
{ |
|||
return bc().transactionHashes(_blockHash); |
|||
} |
|||
|
|||
BlockInfo ClientBase::uncle(h256 _blockHash, unsigned _i) const |
|||
{ |
|||
auto bl = bc().block(_blockHash); |
|||
RLP b(bl); |
|||
if (_i < b[2].itemCount()) |
|||
return BlockInfo::fromHeader(b[2][_i].data()); |
|||
else |
|||
return BlockInfo(); |
|||
} |
|||
|
|||
UncleHashes ClientBase::uncleHashes(h256 _blockHash) const |
|||
{ |
|||
return bc().uncleHashes(_blockHash); |
|||
} |
|||
|
|||
unsigned ClientBase::transactionCount(h256 _blockHash) const |
|||
{ |
|||
auto bl = bc().block(_blockHash); |
|||
RLP b(bl); |
|||
return b[1].itemCount(); |
|||
} |
|||
|
|||
unsigned ClientBase::uncleCount(h256 _blockHash) const |
|||
{ |
|||
auto bl = bc().block(_blockHash); |
|||
RLP b(bl); |
|||
return b[2].itemCount(); |
|||
} |
|||
|
|||
unsigned ClientBase::number() const |
|||
{ |
|||
return bc().number(); |
|||
} |
|||
|
|||
Transactions ClientBase::pending() const |
|||
{ |
|||
return postMine().pending(); |
|||
} |
|||
|
|||
|
|||
StateDiff ClientBase::diff(unsigned _txi, h256 _block) const |
|||
{ |
|||
State st = asOf(_block); |
|||
return st.fromPending(_txi).diff(st.fromPending(_txi + 1)); |
|||
} |
|||
|
|||
StateDiff ClientBase::diff(unsigned _txi, BlockNumber _block) const |
|||
{ |
|||
State st = asOf(_block); |
|||
return st.fromPending(_txi).diff(st.fromPending(_txi + 1)); |
|||
} |
|||
|
|||
Addresses ClientBase::addresses(BlockNumber _block) const |
|||
{ |
|||
Addresses ret; |
|||
for (auto const& i: asOf(_block).addresses()) |
|||
ret.push_back(i.first); |
|||
return ret; |
|||
} |
|||
|
|||
u256 ClientBase::gasLimitRemaining() const |
|||
{ |
|||
return postMine().gasLimitRemaining(); |
|||
} |
|||
|
|||
void ClientBase::setAddress(Address _us) |
|||
{ |
|||
preMine().setAddress(_us); |
|||
} |
|||
|
|||
Address ClientBase::address() const |
|||
{ |
|||
return preMine().address(); |
|||
} |
@ -0,0 +1,167 @@ |
|||
/*
|
|||
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 <http://www.gnu.org/licenses/>.
|
|||
*/ |
|||
/** @file ClientBase.h
|
|||
* @author Gav Wood <i@gavwood.com> |
|||
* @author Marek Kotewicz <marek@ethdev.com> |
|||
* @date 2015 |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
#include <chrono> |
|||
#include "Interface.h" |
|||
#include "LogFilter.h" |
|||
|
|||
namespace dev { |
|||
|
|||
namespace eth { |
|||
|
|||
struct InstalledFilter |
|||
{ |
|||
InstalledFilter(LogFilter const& _f): filter(_f) {} |
|||
|
|||
LogFilter filter; |
|||
unsigned refCount = 1; |
|||
LocalisedLogEntries changes; |
|||
}; |
|||
|
|||
static const h256 PendingChangedFilter = u256(0); |
|||
static const h256 ChainChangedFilter = u256(1); |
|||
|
|||
static const LogEntry SpecialLogEntry = LogEntry(Address(), h256s(), bytes()); |
|||
static const LocalisedLogEntry InitialChange(SpecialLogEntry, 0); |
|||
|
|||
struct ClientWatch |
|||
{ |
|||
ClientWatch(): lastPoll(std::chrono::system_clock::now()) {} |
|||
explicit ClientWatch(h256 _id, Reaping _r): id(_id), lastPoll(_r == Reaping::Automatic ? std::chrono::system_clock::now() : std::chrono::system_clock::time_point::max()) {} |
|||
|
|||
h256 id; |
|||
LocalisedLogEntries changes = LocalisedLogEntries{ InitialChange }; |
|||
mutable std::chrono::system_clock::time_point lastPoll = std::chrono::system_clock::now(); |
|||
}; |
|||
|
|||
struct WatchChannel: public LogChannel { static const char* name() { return "(o)"; } static const int verbosity = 7; }; |
|||
#define cwatch dev::LogOutputStream<dev::eth::WatchChannel, true>() |
|||
struct WorkInChannel: public LogChannel { static const char* name() { return ">W>"; } static const int verbosity = 16; }; |
|||
struct WorkOutChannel: public LogChannel { static const char* name() { return "<W<"; } static const int verbosity = 16; }; |
|||
struct WorkChannel: public LogChannel { static const char* name() { return "-W-"; } static const int verbosity = 16; }; |
|||
#define cwork dev::LogOutputStream<dev::eth::WorkChannel, true>() |
|||
#define cworkin dev::LogOutputStream<dev::eth::WorkInChannel, true>() |
|||
#define cworkout dev::LogOutputStream<dev::eth::WorkOutChannel, true>() |
|||
|
|||
class ClientBase: public dev::eth::Interface |
|||
{ |
|||
public: |
|||
ClientBase() {} |
|||
virtual ~ClientBase() {} |
|||
|
|||
/// Submits the given message-call transaction.
|
|||
virtual void submitTransaction(Secret _secret, u256 _value, Address _dest, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo) override; |
|||
|
|||
/// Submits a new contract-creation transaction.
|
|||
/// @returns the new contract's address (assuming it all goes through).
|
|||
virtual Address submitTransaction(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas = 10000, u256 _gasPrice = 10 * szabo) override; |
|||
|
|||
/// Makes the given call. Nothing is recorded into the state.
|
|||
virtual ExecutionResult call(Secret _secret, u256 _value, Address _dest, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo, BlockNumber _blockNumber = PendingBlock) override; |
|||
|
|||
virtual ExecutionResult create(Secret _secret, u256 _value, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo, BlockNumber _blockNumber = PendingBlock) override; |
|||
|
|||
using Interface::balanceAt; |
|||
using Interface::countAt; |
|||
using Interface::stateAt; |
|||
using Interface::codeAt; |
|||
using Interface::storageAt; |
|||
|
|||
virtual u256 balanceAt(Address _a, BlockNumber _block) const override; |
|||
virtual u256 countAt(Address _a, BlockNumber _block) const override; |
|||
virtual u256 stateAt(Address _a, u256 _l, BlockNumber _block) const override; |
|||
virtual bytes codeAt(Address _a, BlockNumber _block) const override; |
|||
virtual std::map<u256, u256> storageAt(Address _a, BlockNumber _block) const override; |
|||
|
|||
virtual LocalisedLogEntries logs(unsigned _watchId) const override; |
|||
virtual LocalisedLogEntries logs(LogFilter const& _filter) const override; |
|||
|
|||
/// Install, uninstall and query watches.
|
|||
virtual unsigned installWatch(LogFilter const& _filter, Reaping _r = Reaping::Automatic) override; |
|||
virtual unsigned installWatch(h256 _filterId, Reaping _r = Reaping::Automatic) override; |
|||
virtual bool uninstallWatch(unsigned _watchId) override; |
|||
virtual LocalisedLogEntries peekWatch(unsigned _watchId) const override; |
|||
virtual LocalisedLogEntries checkWatch(unsigned _watchId) override; |
|||
|
|||
virtual h256 hashFromNumber(unsigned _number) const override; |
|||
virtual eth::BlockInfo blockInfo(h256 _hash) const override; |
|||
virtual eth::BlockDetails blockDetails(h256 _hash) const override; |
|||
virtual eth::Transaction transaction(h256 _transactionHash) const override; |
|||
virtual eth::Transaction transaction(h256 _blockHash, unsigned _i) const override; |
|||
virtual eth::Transactions transactions(h256 _blockHash) const override; |
|||
virtual eth::TransactionHashes transactionHashes(h256 _blockHash) const override; |
|||
virtual eth::BlockInfo uncle(h256 _blockHash, unsigned _i) const override; |
|||
virtual eth::UncleHashes uncleHashes(h256 _blockHash) const override; |
|||
virtual unsigned transactionCount(h256 _blockHash) const override; |
|||
virtual unsigned uncleCount(h256 _blockHash) const override; |
|||
virtual unsigned number() const override; |
|||
virtual eth::Transactions pending() const override; |
|||
|
|||
using Interface::diff; |
|||
virtual StateDiff diff(unsigned _txi, h256 _block) const override; |
|||
virtual StateDiff diff(unsigned _txi, BlockNumber _block) const override; |
|||
|
|||
using Interface::addresses; |
|||
virtual Addresses addresses(BlockNumber _block) const override; |
|||
virtual u256 gasLimitRemaining() const override; |
|||
|
|||
/// Set the coinbase address
|
|||
virtual void setAddress(Address _us) override; |
|||
|
|||
/// Get the coinbase address
|
|||
virtual Address address() const override; |
|||
|
|||
/// TODO: consider moving it to a separate interface
|
|||
|
|||
virtual void setMiningThreads(unsigned _threads) override { (void)_threads; BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::setMiningThreads")); } |
|||
virtual unsigned miningThreads() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::miningThreads")); } |
|||
virtual void startMining() override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::startMining")); } |
|||
virtual void stopMining() override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::stopMining")); } |
|||
virtual bool isMining() override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::isMining")); } |
|||
virtual eth::MineProgress miningProgress() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::miningProgress")); } |
|||
virtual std::pair<h256, u256> getWork() override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::getWork")); } |
|||
virtual bool submitWork(eth::ProofOfWork::Proof const&) override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::submitWork")); } |
|||
|
|||
State asOf(BlockNumber _h) const; |
|||
|
|||
protected: |
|||
/// The interface that must be implemented in any class deriving this.
|
|||
/// {
|
|||
virtual BlockChain const& bc() const = 0; |
|||
virtual State asOf(h256 const& _h) const = 0; |
|||
virtual State preMine() const = 0; |
|||
virtual State postMine() const = 0; |
|||
virtual void prepareForTransaction() = 0; |
|||
/// }
|
|||
|
|||
TransactionQueue m_tq; ///< Maintains a list of incoming transactions not yet in a block on the blockchain.
|
|||
|
|||
// filters
|
|||
mutable Mutex x_filtersWatches; ///< Our lock.
|
|||
std::map<h256, InstalledFilter> m_filters; ///< The dictionary of filters that are active.
|
|||
std::map<unsigned, ClientWatch> m_watches; ///< Each and every watch - these reference a filter.
|
|||
|
|||
}; |
|||
|
|||
}} |
Loading…
Reference in new issue