Browse Source

Faster State diffs.

Support canary contract to stop mining.
Manage rude nodes.
cl-refactor
Gav Wood 10 years ago
parent
commit
7bff0d1f7d
  1. 9
      eth/main.cpp
  2. 8
      libdevcore/Log.cpp
  3. 3
      libdevcore/Log.h
  4. 57
      libethereum/Client.cpp
  5. 19
      libethereum/Client.h
  6. 5
      libethereum/ClientBase.cpp
  7. 1
      libethereum/ClientBase.h
  8. 17
      libethereum/EthereumHost.cpp
  9. 7
      libethereum/EthereumHost.h
  10. 14
      libethereum/EthereumPeer.cpp
  11. 10
      libethereum/EthereumPeer.h
  12. 2
      libethereum/Interface.h
  13. 30
      libethereum/State.cpp
  14. 12
      libethereum/State.h

9
eth/main.cpp

@ -138,6 +138,7 @@ void help()
<< " -a,--address <addr> Set the coinbase (mining payout) address to addr (default: auto)." << endl
<< " -m,--mining <on/off/number> Enable mining, optionally for a specified number of blocks (default: off)" << endl
<< " -f,--force-mining Mine even when there are no transactions to mine (default: off)" << endl
<< " --mine-on-wrong-chain Mine even when we know it's the wrong chain (default: off)" << endl
<< " -C,--cpu When mining, use the CPU." << endl
<< " -G,--opencl When mining use the GPU via OpenCL." << endl
<< " --opencl-platform <n> When mining using -G/--opencl use OpenCL platform n (default: 0)." << endl
@ -279,6 +280,7 @@ int main(int argc, char** argv)
bool upnp = true;
WithExisting killChain = WithExisting::Trust;
bool jit = false;
string sentinel;
/// Networking params.
string clientName;
@ -294,6 +296,7 @@ int main(int argc, char** argv)
/// Mining params
unsigned mining = 0;
bool forceMining = false;
bool mineOnWrongChain = false;
Address signingKey;
Address sessionKey;
Address beneficiary = signingKey;
@ -376,6 +379,10 @@ int main(int argc, char** argv)
mode = OperationMode::Export;
filename = argv[++i];
}
else if (arg == "--sentinel" && i + 1 < argc)
sentinel = argv[++i];
else if (arg == "--mine-on-wrong-chain")
mineOnWrongChain = true;
else if (arg == "--format" && i + 1 < argc)
{
string m = argv[++i];
@ -671,6 +678,8 @@ int main(int argc, char** argv)
nodeMode == NodeMode::Full ? set<string>{"eth"/*, "shh"*/} : set<string>(),
netPrefs,
&nodesState);
web3.ethereum()->setMineOnBadChain(mineOnWrongChain);
web3.ethereum()->setSentinel(sentinel);
auto toNumber = [&](string const& s) -> unsigned {
if (s == "latest")

8
libdevcore/Log.cpp

@ -40,6 +40,14 @@ mutex x_logOverride;
/// or equal to the currently output verbosity (g_logVerbosity).
static map<type_info const*, bool> s_logOverride;
bool isLogVisible(std::type_info const* _ch, bool _default)
{
Guard l(x_logOverride);
if (s_logOverride.count(_ch))
return s_logOverride[_ch];
return _default;
}
LogOverrideAux::LogOverrideAux(std::type_info const* _ch, bool _value):
m_ch(_ch)
{

3
libdevcore/Log.h

@ -73,6 +73,9 @@ public:
LogOverride(bool _value): LogOverrideAux(&typeid(Channel), _value) {}
};
bool isChannelVisible(std::type_info const* _ch, bool _default);
template <class Channel> bool isChannelVisible() { return isChannelVisible(&typeid(Channel), Channel::verbosity <= g_logVerbosity); }
/// Temporary changes system's verbosity for specific function. Restores the old verbosity when function returns.
/// Not thread-safe, use with caution!
struct VerbosityHolder

57
libethereum/Client.cpp

@ -310,6 +310,18 @@ Client::~Client()
stopWorking();
}
static const Address c_canary("0x");
bool Client::isChainBad() const
{
return stateAt(c_canary, 0) != 0;
}
bool Client::isUpgradeNeeded() const
{
return stateAt(c_canary, 0) == 2;
}
void Client::setNetworkId(u256 _n)
{
if (auto h = m_host.lock())
@ -552,6 +564,9 @@ ProofOfWork::WorkPackage Client::getWork()
bool oldShould = shouldServeWork();
m_lastGetWork = chrono::system_clock::now();
if (!m_mineOnBadChain && isChainBad())
return ProofOfWork::WorkPackage();
// if this request has made us bother to serve work, prep it now.
if (!oldShould && shouldServeWork())
onPostStateChanged();
@ -709,11 +724,22 @@ bool Client::remoteActive() const
void Client::onPostStateChanged()
{
cnote << "Post state changed";
cnote << "Post state changed.";
rejigMining();
m_remoteWorking = false;
}
void Client::startMining()
{
m_wouldMine = true;
rejigMining();
}
if (m_bq.items().first == 0 && (isMining() || remoteActive()))
void Client::rejigMining()
{
if ((wouldMine() || remoteActive()) && !m_bq.items().first && (!isChainBad() || mineOnBadChain()) /*&& (forceMining() || transactionsWaiting())*/)
{
cnote << "Restarting mining...";
cnote << "Rejigging mining...";
DEV_WRITE_GUARDED(x_working)
m_working.commitToMine(m_bc);
DEV_READ_GUARDED(x_working)
@ -722,20 +748,21 @@ void Client::onPostStateChanged()
m_postMine = m_working;
m_miningInfo = m_postMine.info();
}
m_farm.setWork(m_miningInfo);
Ethash::ensurePrecomputed(m_bc.number());
}
m_remoteWorking = false;
}
if (m_wouldMine)
{
m_farm.setWork(m_miningInfo);
if (m_turboMining)
m_farm.startGPU();
else
m_farm.startCPU();
void Client::startMining()
{
if (m_turboMining)
m_farm.startGPU();
else
m_farm.startCPU();
onPostStateChanged();
m_farm.setWork(m_miningInfo);
Ethash::ensurePrecomputed(m_bc.number());
}
}
if (!m_wouldMine)
m_farm.stop();
}
void Client::noteChanged(h256Hash const& _filters)

19
libethereum/Client.h

@ -174,14 +174,26 @@ public:
/// Enable/disable GPU mining.
void setTurboMining(bool _enable = true) { m_turboMining = _enable; if (isMining()) startMining(); }
/// Check to see if we'd mine on an apparently bad chain.
bool mineOnBadChain() const { return m_mineOnBadChain; }
/// Set true if you want to mine even when the canary says you're on the wrong chain.
void setMineOnBadChain(bool _v) { m_mineOnBadChain = _v; }
/// @returns true if the canary says that the chain is bad.
bool isChainBad() const;
/// @returns true if the canary says that the client should be upgraded.
bool isUpgradeNeeded() const;
/// Start mining.
/// NOT thread-safe - call it & stopMining only from a single thread
void startMining() override;
/// Stop mining.
/// NOT thread-safe
void stopMining() override { m_farm.stop(); }
void stopMining() override { m_wouldMine = false; rejigMining(); }
/// Are we mining now?
bool isMining() const override { return m_farm.isMining(); }
/// Are we mining now?
bool wouldMine() const override { return m_wouldMine; }
/// The hashrate...
uint64_t hashrate() const override;
/// Check the progress of the mining.
@ -251,6 +263,9 @@ private:
/// Called when Worker is exiting.
void doneWorking() override;
/// Called when wouldMine(), turboMining(), isChainBad(), forceMining(), pendingTransactions() have changed.
void rejigMining();
/// 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);
@ -308,8 +323,10 @@ private:
Handler m_tqReady;
Handler m_bqReady;
bool m_wouldMine = false; ///< True if we /should/ be mining.
bool m_turboMining = false; ///< Don't squander all of our time mining actually just sleeping.
bool m_forceMining = false; ///< Mine even when there are no transactions pending?
bool m_mineOnBadChain = false; ///< Mine even when the canary says it's a bad chain.
bool m_paranoia = false; ///< Should we be paranoid about our state?
mutable std::chrono::system_clock::time_point m_lastGarbageCollection;

5
libethereum/ClientBase.cpp

@ -400,17 +400,16 @@ h256s ClientBase::pendingHashes() const
return h256s() + postMine().pendingHashes();
}
StateDiff ClientBase::diff(unsigned _txi, h256 _block) const
{
State st = asOf(_block);
return st.fromPending(_txi).diff(st.fromPending(_txi + 1));
return st.fromPending(_txi).diff(st.fromPending(_txi + 1), true);
}
StateDiff ClientBase::diff(unsigned _txi, BlockNumber _block) const
{
State st = asOf(_block);
return st.fromPending(_txi).diff(st.fromPending(_txi + 1));
return st.fromPending(_txi).diff(st.fromPending(_txi + 1), true);
}
Addresses ClientBase::addresses(BlockNumber _block) const

1
libethereum/ClientBase.h

@ -154,6 +154,7 @@ public:
virtual void startMining() override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::startMining")); }
virtual void stopMining() override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::stopMining")); }
virtual bool isMining() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::isMining")); }
virtual bool wouldMine() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::wouldMine")); }
virtual uint64_t hashrate() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::hashrate")); }
virtual MiningProgress miningProgress() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::miningProgress")); }
virtual ProofOfWork::WorkPackage getWork() override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::getWork")); }

17
libethereum/EthereumHost.cpp

@ -276,6 +276,13 @@ void EthereumHost::estimatePeerHashes(EthereumPeer* _peer)
_peer->m_expectedHashes = blockCount;
}
void EthereumHost::noteRude(p2p::NodeId const& _id, std::string const& _client)
{
cwarn << "RUDE node/client: " << _id << _client;
m_rudeNodes.insert(_id);
m_rudeClients.insert(_client);
}
void EthereumHost::onPeerHashes(EthereumPeer* _peer, h256s const& _hashes)
{
Guard l(x_sync);
@ -574,7 +581,7 @@ void EthereumHost::continueSync(EthereumPeer* _peer)
});
if (otherPeerSync)
{
/// Downloading from other peer with v60 protocol, nothing ese we can do
/// Downloading from other peer with v60 protocol, nothing else we can do
_peer->setIdle();
return;
}
@ -599,6 +606,10 @@ void EthereumHost::continueSync(EthereumPeer* _peer)
bool EthereumHost::peerShouldGrabBlocks(EthereumPeer* _peer) const
{
// Early exit if this peer has proved unreliable.
if (_peer->isRude())
return false;
auto td = _peer->m_totalDifficulty;
auto lh = m_syncingLatestHash;
auto ctd = m_chain.details().totalDifficulty;
@ -611,6 +622,10 @@ bool EthereumHost::peerShouldGrabBlocks(EthereumPeer* _peer) const
bool EthereumHost::peerShouldGrabChain(EthereumPeer* _peer) const
{
// Early exit if this peer has proved unreliable.
if (_peer->isRude())
return false;
h256 c = m_chain.currentHash();
unsigned n = m_chain.number();
u256 td = m_chain.details().totalDifficulty;

7
libethereum/EthereumHost.h

@ -71,7 +71,9 @@ public:
DownloadMan const& downloadMan() const { return m_man; }
bool isSyncing() const { Guard l(x_sync); return isSyncing_UNSAFE(); }
bool isBanned(p2p::NodeId _id) const { return !!m_banned.count(_id); }
bool isBanned(p2p::NodeId const& _id) const { return !!m_banned.count(_id); }
void noteRude(p2p::NodeId const& _id, std::string const& _client);
bool isRude(p2p::NodeId const& _id, std::string const& _client) const { return m_rudeClients.count(_client) && m_rudeNodes.count(_id); }
void noteNewTransactions() { m_newTransactions = true; }
void noteNewBlocks() { m_newBlocks = true; }
@ -147,6 +149,9 @@ private:
h256 m_syncingLatestHash; ///< Latest block's hash, as of the current sync.
u256 m_syncingTotalDifficulty; ///< Latest block's total difficulty, as of the current sync.
h256s m_hashes; ///< List of hashes with unknown block numbers. Used for v60 chain downloading and catching up to a particular unknown
std::unordered_set<p2p::NodeId> m_rudeNodes; ///< Nodes that were impolite while syncing. We avoid syncing from these if possible.
std::unordered_set<std::string> m_rudeClients; ///< Nodes that were impolite while syncing. We avoid syncing from these if possible.
};
}

14
libethereum/EthereumPeer.cpp

@ -40,6 +40,8 @@ EthereumPeer::EthereumPeer(Session* _s, HostCapabilityFace* _h, unsigned _i, Cap
m_hashSub(host()->hashDownloadMan()),
m_peerCapabilityVersion(_cap.second)
{
m_isRude = host()->isRude(session()->id(), session()->info().clientVersion);
session()->addNote("manners", m_isRude ? "RUDE" : "nice");
m_syncHashNumber = host()->chain().number() + 1;
requestStatus();
}
@ -52,8 +54,16 @@ EthereumPeer::~EthereumPeer()
void EthereumPeer::abortSync()
{
if (isSyncing())
setIdle();
if (m_asking != Asking::Nothing)
setRude();
setIdle();
}
void EthereumPeer::setRude()
{
m_isRude = true;
host()->noteRude(session()->id(), session()->info().clientVersion);
session()->addNote("manners", m_isRude ? "RUDE" : "nice");
}
EthereumHost* EthereumPeer::host() const

10
libethereum/EthereumPeer.h

@ -82,6 +82,12 @@ public:
/// Request blocks. Uses block download manager.
void requestBlocks();
/// Check if this node is rude.
bool isRude() const { return m_isRude; }
/// Set that it's a rude node.
void setRude();
private:
using p2p::Capability::sealAndSend;
@ -101,7 +107,7 @@ private:
void setAsking(Asking _g);
/// Do we presently need syncing with this peer?
bool needsSyncing() const { return !!m_latestHash; }
bool needsSyncing() const { return !isRude() && !!m_latestHash; }
/// Are we presently syncing with this peer?
bool isSyncing() const;
@ -145,6 +151,8 @@ private:
h256Hash m_knownBlocks; ///< Blocks that the peer already knows about (that don't need to be sent to them).
Mutex x_knownTransactions;
h256Hash m_knownTransactions; ///< Transactions that the peer already knows of.
bool m_isRude; ///< True if this node has been rude in the past.
};
}

2
libethereum/Interface.h

@ -196,6 +196,8 @@ public:
virtual void stopMining() = 0;
/// Are we mining now?
virtual bool isMining() const = 0;
/// Would we like to mine now?
virtual bool wouldMine() const = 0;
/// Current hash rate.
virtual uint64_t hashrate() const = 0;

30
libethereum/State.cpp

@ -158,6 +158,7 @@ State::State(State const& _s):
m_transactions(_s.m_transactions),
m_receipts(_s.m_receipts),
m_transactionSet(_s.m_transactionSet),
m_touched(_s.m_touched),
m_cache(_s.m_cache),
m_previousBlock(_s.m_previousBlock),
m_currentBlock(_s.m_currentBlock),
@ -206,7 +207,7 @@ State::~State()
{
}
StateDiff State::diff(State const& _c) const
StateDiff State::diff(State const& _c, bool _quick) const
{
StateDiff ret;
@ -217,10 +218,20 @@ StateDiff State::diff(State const& _c) const
auto trie = SecureTrieDB<Address, OverlayDB>(const_cast<OverlayDB*>(&m_db), rootHash());
auto trieD = SecureTrieDB<Address, OverlayDB>(const_cast<OverlayDB*>(&_c.m_db), _c.rootHash());
for (auto i: trie)
ads.insert(i.first), trieAds.insert(i.first);
for (auto i: trieD)
ads.insert(i.first), trieAdsD.insert(i.first);
if (_quick)
{
trieAds = m_touched;
trieAdsD = _c.m_touched;
(ads += m_touched) += _c.m_touched;
}
else
{
for (auto i: trie)
ads.insert(i.first), trieAds.insert(i.first);
for (auto i: trieD)
ads.insert(i.first), trieAdsD.insert(i.first);
}
for (auto i: m_cache)
ads.insert(i.first);
for (auto i: _c.m_cache)
@ -272,7 +283,7 @@ void State::ensureCached(std::unordered_map<Address, Account>& _cache, Address _
void State::commit()
{
dev::eth::commit(m_cache, m_db, m_state);
m_touched += dev::eth::commit(m_cache, m_db, m_state);
m_cache.clear();
}
@ -450,6 +461,7 @@ void State::resetCurrent()
m_receipts.clear();
m_transactionSet.clear();
m_cache.clear();
m_touched.clear();
m_currentBlock = BlockInfo();
m_currentBlock.coinbaseAddress = m_ourAddress;
m_currentBlock.timestamp = max(m_previousBlock.timestamp + 1, (u256)time(0));
@ -1219,8 +1231,10 @@ ExecutionResult State::execute(LastHashes const& _lh, Transaction const& _t, Per
if (!e.execute())
#if ETH_VMTRACE
{
(void)_onOp;
e.go(e.simpleTrace());
if (isChannelVisible<VMTraceChannel>())
e.go(e.simpleTrace());
else
e.go(_onOp);
}
#else
e.go(_onOp);

12
libethereum/State.h

@ -310,10 +310,12 @@ public:
State fromPending(unsigned _i) const;
/// @returns the StateDiff caused by the pending transaction of index @a _i.
StateDiff pendingDiff(unsigned _i) const { return fromPending(_i).diff(fromPending(_i + 1)); }
StateDiff pendingDiff(unsigned _i) const { return fromPending(_i).diff(fromPending(_i + 1), true); }
/// @return the difference between this state (origin) and @a _c (destination).
StateDiff diff(State const& _c) const;
/// @param _quick if true doesn't check all addresses possible (/very/ slow for a full chain)
/// but rather only those touched by the transactions in creating the two States.
StateDiff diff(State const& _c, bool _quick = false) const;
/// Sync our state with the block chain.
/// This basically involves wiping ourselves if we've been superceded and rebuilding from the transaction queue.
@ -387,6 +389,7 @@ private:
TransactionReceipts m_receipts; ///< The corresponding list of transaction receipts.
h256Hash m_transactionSet; ///< The set of transaction hashes that we've included in the state.
OverlayDB m_lastTx;
AddressHash m_touched; ///< Tracks all addresses touched by transactions so far.
mutable std::unordered_map<Address, Account> m_cache; ///< Our address cache. This stores the states of each address that has (or at least might have) been changed.
@ -410,8 +413,9 @@ private:
std::ostream& operator<<(std::ostream& _out, State const& _s);
template <class DB>
void commit(std::unordered_map<Address, Account> const& _cache, DB& _db, SecureTrieDB<Address, DB>& _state)
AddressHash commit(std::unordered_map<Address, Account> const& _cache, DB& _db, SecureTrieDB<Address, DB>& _state)
{
AddressHash ret;
for (auto const& i: _cache)
if (i.second.isDirty())
{
@ -450,7 +454,9 @@ void commit(std::unordered_map<Address, Account> const& _cache, DB& _db, SecureT
_state.insert(i.first, &s.out());
}
ret.insert(i.first);
}
return ret;
}
}

Loading…
Cancel
Save