Browse Source

Blocks come down in order (well... unless a peer bugs out).

Peer hash-chains downloaded one-at-once.
KillChain works again.
Local networking option.
Don't resend blocks during sync.
cl-refactor
Gav Wood 10 years ago
parent
commit
0d3f298e45
  1. 9
      alethzero/Main.ui
  2. 5
      alethzero/MainWin.cpp
  3. 10
      eth/main.cpp
  4. 2
      libdevcore/Common.cpp
  5. 2
      libethcore/CommonEth.cpp
  6. 47
      libethereum/BlockChain.cpp
  7. 8
      libethereum/BlockChain.h
  8. 9
      libethereum/BlockQueue.cpp
  9. 5
      libethereum/BlockQueue.h
  10. 30
      libethereum/Client.cpp
  11. 2
      libethereum/Client.h
  12. 16
      libethereum/CommonNet.h
  13. 140
      libethereum/EthereumHost.cpp
  14. 10
      libethereum/EthereumHost.h
  15. 45
      libethereum/EthereumPeer.cpp
  16. 4
      libethereum/EthereumPeer.h
  17. 5
      libethereum/State.cpp
  18. 2
      libethereum/State.h
  19. 2
      libethereum/TransactionQueue.h
  20. 3
      libwebthree/WebThree.h

9
alethzero/Main.ui

@ -132,6 +132,7 @@
</property>
<addaction name="upnp"/>
<addaction name="usePast"/>
<addaction name="localNetworking"/>
<addaction name="net"/>
<addaction name="connect"/>
</widget>
@ -1731,6 +1732,14 @@ font-size: 14pt</string>
<string>Reserved Debug 1</string>
</property>
</action>
<action name="localNetworking">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Enable Local Addresses</string>
</property>
</action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<customwidgets>

5
alethzero/MainWin.cpp

@ -192,7 +192,7 @@ Main::~Main()
dev::p2p::NetworkPreferences Main::netPrefs() const
{
return NetworkPreferences(ui->port->value(), ui->forceAddress->text().toStdString(), ui->upnp->isChecked(), false);
return NetworkPreferences(ui->port->value(), ui->forceAddress->text().toStdString(), ui->upnp->isChecked(), ui->localNetworking->isChecked());
}
void Main::onKeysChanged()
@ -494,6 +494,7 @@ void Main::writeSettings()
s.setValue("upnp", ui->upnp->isChecked());
s.setValue("forceAddress", ui->forceAddress->text());
s.setValue("usePast", ui->usePast->isChecked());
s.setValue("localNetworking", ui->localNetworking->isChecked());
s.setValue("forceMining", ui->forceMining->isChecked());
s.setValue("paranoia", ui->paranoia->isChecked());
s.setValue("showAll", ui->showAll->isChecked());
@ -543,6 +544,7 @@ void Main::readSettings(bool _skipGeometry)
ui->upnp->setChecked(s.value("upnp", true).toBool());
ui->forceAddress->setText(s.value("forceAddress", "").toString());
ui->usePast->setChecked(s.value("usePast", true).toBool());
ui->localNetworking->setChecked(s.value("localNetworking", true).toBool());
ui->forceMining->setChecked(s.value("forceMining", false).toBool());
on_forceMining_triggered();
ui->paranoia->setChecked(s.value("paranoia", false).toBool());
@ -1419,6 +1421,7 @@ void Main::on_killBlockchain_triggered()
writeSettings();
ui->mine->setChecked(false);
ui->net->setChecked(false);
web3()->stopNetwork();
ethereum()->killChain();
m_ethereum->setClient(ethereum());
readSettings(true);

10
eth/main.cpp

@ -112,6 +112,7 @@ void help()
<< " -l,--listen <port> Listen on the given port for incoming connected (default: 30303)." << endl
<< " -m,--mining <on/off/number> Enable mining, optionally for a specified number of blocks (Default: off)" << endl
<< " -n,--upnp <on/off> Use upnp for NAT (default: on)." << endl
<< " -L,--local-networking Use peers whose addresses are local." << endl
<< " -o,--mode <full/peer> Start a full node or a peer node (Default: full)." << endl
<< " -p,--port <port> Connect to remote port (default: 30303)." << endl
<< " -r,--remote <host> Connect to remote host (default: none)." << endl
@ -188,6 +189,7 @@ int main(int argc, char** argv)
#endif
string publicIP;
bool upnp = true;
bool useLocal = false;
bool forceMining = false;
string clientName;
@ -233,10 +235,12 @@ int main(int argc, char** argv)
upnp = false;
else
{
cerr << "Invalid UPnP option: " << m << endl;
cerr << "Invalid -n/--upnp option: " << m << endl;
return -1;
}
}
else if (arg == "-L" || arg == "--local-networking")
useLocal = true;
else if ((arg == "-c" || arg == "--client-name") && i + 1 < argc)
clientName = argv[++i];
else if ((arg == "-a" || arg == "--address" || arg == "--coinbase-address") && i + 1 < argc)
@ -256,7 +260,7 @@ int main(int argc, char** argv)
mining = i;
else
{
cerr << "Unknown mining option: " << m << endl;
cerr << "Unknown -m/--mining option: " << m << endl;
return -1;
}
}
@ -300,7 +304,7 @@ int main(int argc, char** argv)
cout << credits();
NetworkPreferences netPrefs(listenPort, publicIP, upnp, false);
NetworkPreferences netPrefs(listenPort, publicIP, upnp, useLocal);
dev::WebThreeDirect web3("Ethereum(++)/" + clientName + "v" + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM), dbPath, false, mode == NodeMode::Full ? set<string>{"eth", "shh"} : set<string>{}, netPrefs);
web3.setIdealPeerCount(peers);
eth::Client& c = *web3.ethereum();

2
libdevcore/Common.cpp

@ -27,7 +27,7 @@ using namespace dev;
namespace dev
{
char const* Version = "0.6.8b";
char const* Version = "0.6.8c";
}

2
libethcore/CommonEth.cpp

@ -34,7 +34,7 @@ namespace dev
namespace eth
{
const unsigned c_protocolVersion = 32;
const unsigned c_protocolVersion = 33;
const unsigned c_databaseVersion = 1;
static const vector<pair<u256, string>> g_units =

47
libethereum/BlockChain.cpp

@ -108,6 +108,20 @@ bytes BlockChain::createGenesisBlock()
}
BlockChain::BlockChain(std::string _path, bool _killExisting)
{
// Initialise with the genesis as the last block on the longest chain.
m_genesisHash = BlockChain::genesis().hash;
m_genesisBlock = BlockChain::createGenesisBlock();
open(_path, _killExisting);
}
BlockChain::~BlockChain()
{
close();
}
void BlockChain::open(std::string _path, bool _killExisting)
{
if (_path.empty())
_path = Defaults::get()->m_dbPath;
@ -127,10 +141,6 @@ BlockChain::BlockChain(std::string _path, bool _killExisting)
if (!m_extrasDB)
throw DatabaseAlreadyOpen();
// Initialise with the genesis as the last block on the longest chain.
m_genesisHash = BlockChain::genesis().hash;
m_genesisBlock = BlockChain::createGenesisBlock();
if (!details(m_genesisHash))
{
// Insert details of genesis block.
@ -150,11 +160,16 @@ BlockChain::BlockChain(std::string _path, bool _killExisting)
cnote << "Opened blockchain DB. Latest: " << currentHash();
}
BlockChain::~BlockChain()
void BlockChain::close()
{
cnote << "Closing blockchain DB";
delete m_extrasDB;
delete m_db;
m_lastBlockHash = m_genesisHash;
m_details.clear();
m_blooms.clear();
m_traces.clear();
m_cache.clear();
}
template <class T, class V>
@ -245,21 +260,23 @@ h256s BlockChain::import(bytes const& _block, OverlayDB const& _db)
auto newHash = BlockInfo::headerHash(_block);
// Check block doesn't already exist first!
if (details(newHash))
if (isKnown(newHash))
{
clog(BlockChainNote) << newHash << ": Not new.";
throw AlreadyHaveBlock();
}
// Work out its number as the parent's number + 1
auto pd = details(bi.parentHash);
if (!pd)
if (!isKnown(bi.parentHash))
{
clog(BlockChainNote) << newHash << ": Unknown parent " << bi.parentHash;
// We don't know the parent (yet) - discard for now. It'll get resent to us if we find out about its ancestry later on.
throw UnknownParent();
}
auto pd = details(bi.parentHash);
assert(pd);
// Check it's not crazy
if (bi.timestamp > (u256)time(0))
{
@ -432,6 +449,20 @@ h256Set BlockChain::allUnclesFrom(h256 _parent) const
return ret;
}
bool BlockChain::isKnown(h256 _hash) const
{
if (_hash == m_genesisHash)
return true;
{
ReadGuard l(x_cache);
if (m_cache.count(_hash))
return true;
}
string d;
m_db->Get(m_readOptions, ldb::Slice((char const*)&_hash, 32), &d);
return d.size();
}
bytes BlockChain::block(h256 _hash) const
{
if (_hash == m_genesisHash)

8
libethereum/BlockChain.h

@ -70,6 +70,8 @@ public:
BlockChain(std::string _path, bool _killExisting = false);
~BlockChain();
void reopen(std::string _path, bool _killExisting = false) { close(); open(_path, _killExisting); }
/// (Potentially) renders invalid existing bytesConstRef returned by lastBlock.
/// To be called from main loop every 100ms or so.
void process();
@ -85,6 +87,9 @@ public:
/// @returns the block hashes of any blocks that came into/went out of the canonical block chain.
h256s import(bytes const& _block, OverlayDB const& _stateDB);
/// Returns true if the given block is known (though not necessarily a part of the canon chain).
bool isKnown(h256 _hash) const;
/// Get the familial details concerning a block (or the most recent mined if none given). Thread-safe.
BlockDetails details(h256 _hash) const { return queryExtras<BlockDetails, 0>(_hash, m_details, x_details, NullBlockDetails); }
BlockDetails details() const { return details(currentHash()); }
@ -143,6 +148,9 @@ public:
h256s treeRoute(h256 _from, h256 _to, h256* o_common = nullptr, bool _pre = true, bool _post = true) const;
private:
void open(std::string _path, bool _killExisting = false);
void close();
template<class T, unsigned N> T queryExtras(h256 _h, std::map<h256, T>& _m, boost::shared_mutex& _x, T const& _n) const
{
{

9
libethereum/BlockQueue.cpp

@ -74,21 +74,24 @@ bool BlockQueue::import(bytesConstRef _block, BlockChain const& _bc)
// Check it's not in the future
if (bi.timestamp > (u256)time(0))
{
m_future.insert(make_pair((unsigned)bi.timestamp, _block.toBytes()));
cblockq << "OK - queued for future.";
}
else
{
// We now know it.
if (!m_readySet.count(bi.parentHash) && !m_drainingSet.count(bi.parentHash) && !_bc.details(bi.parentHash))
if (!m_readySet.count(bi.parentHash) && !m_drainingSet.count(bi.parentHash) && !_bc.isKnown(bi.parentHash))
{
// We don't know the parent (yet) - queue it up for later. It'll get resent to us if we find out about its ancestry later on.
// cnote << "OK - queued for future.";
cblockq << "OK - queued as unknown parent:" << bi.parentHash.abridged();
m_unknown.insert(make_pair(bi.parentHash, make_pair(h, _block.toBytes())));
m_unknownSet.insert(h);
}
else
{
// If valid, append to blocks.
// cnote << "OK - ready for chain insertion.";
cblockq << "OK - ready for chain insertion.";
m_ready.push_back(_block.toBytes());
m_readySet.insert(h);

5
libethereum/BlockQueue.h

@ -34,7 +34,7 @@ namespace eth
class BlockChain;
struct BlockQueueChannel: public LogChannel { static const char* name() { return "[]Q"; } static const int verbosity = 7; };
struct BlockQueueChannel: public LogChannel { static const char* name() { return "[]Q"; } static const int verbosity = 4; };
#define cblockq dev::LogOutputStream<dev::eth::BlockQueueChannel, true>()
/**
@ -64,6 +64,9 @@ public:
/// Get information on the items queued.
std::pair<unsigned, unsigned> items() const { ReadGuard l(m_lock); return std::make_pair(m_ready.size(), m_unknown.size()); }
/// Clear everything.
void clear() { WriteGuard l(m_lock); m_readySet.clear(); m_drainingSet.clear(); m_ready.clear(); m_unknownSet.clear(); m_unknown.clear(); m_future.clear(); }
private:
void noteReadyWithoutWriteGuard(h256 _b);
void notePresentWithoutWriteGuard(bytesConstRef _block);

30
libethereum/Client.cpp

@ -99,7 +99,35 @@ void Client::flushTransactions()
void Client::killChain()
{
// TODO
bool wasMining = isMining();
if (wasMining)
stopMining();
stopWorking();
m_tq.clear();
m_bq.clear();
m_miners.clear();
m_preMine = State();
m_postMine = State();
{
WriteGuard l(x_stateDB);
m_stateDB = OverlayDB();
m_stateDB = State::openDB(Defaults::dbPath(), true);
}
m_bc.reopen(Defaults::dbPath(), true);
m_preMine = State(Address(), m_stateDB);
m_postMine = State(Address(), m_stateDB);
if (auto h = m_host.lock())
h->reset();
doWork();
startWorking();
if (wasMining)
startMining();
}
void Client::clearPending()

2
libethereum/Client.h

@ -271,7 +271,7 @@ private:
BlockChain m_bc; ///< Maintains block database.
TransactionQueue m_tq; ///< Maintains a list of incoming transactions not yet in a block on the blockchain.
BlockQueue m_bq; ///< Maintains a list of incoming blocks not yet on the blockchain (to be imported).
// TODO: remove in favour of copying m_stateDB as required and thread-safing/copying State. Have a good think about what state objects there should be. Probably want 4 (pre, post, mining, user-visible).
mutable boost::shared_mutex x_stateDB; ///< Lock on the state DB, effectively a lock on m_postMine.
OverlayDB m_stateDB; ///< Acts as the central point for the state database, so multiple States can share it.
State m_preMine; ///< The present state of the client.

16
libethereum/CommonNet.h

@ -33,11 +33,17 @@ namespace dev
namespace eth
{
#if ETH_DEBUG
static const unsigned c_maxHashes = 4; ///< Maximum number of hashes BlockHashes will ever send.
static const unsigned c_maxHashesAsk = 4; ///< Maximum number of hashes GetBlockHashes will ever ask for.
static const unsigned c_maxBlocks = 2; ///< Maximum number of blocks Blocks will ever send.
static const unsigned c_maxBlocksAsk = 2; ///< Maximum number of blocks we ask to receive in Blocks (when using GetChain).
#else
static const unsigned c_maxHashes = 256; ///< Maximum number of hashes BlockHashes will ever send.
static const unsigned c_maxHashesAsk = 256; ///< Maximum number of hashes GetBlockHashes will ever ask for.
static const unsigned c_maxBlocks = 128; ///< Maximum number of blocks Blocks will ever send.
static const unsigned c_maxBlocksAsk = 128; ///< Maximum number of blocks we ask to receive in Blocks (when using GetChain).
#endif
class OverlayDB;
class BlockChain;
class TransactionQueue;
@ -55,5 +61,13 @@ enum EthereumPacket
BlocksPacket,
};
enum class Grabbing
{
State,
Hashes,
Chain,
Nothing
};
}
}

140
libethereum/EthereumHost.cpp

@ -72,11 +72,11 @@ h256Set EthereumHost::neededBlocks(h256Set const& _exclude)
m_blocksNeeded.erase(it);
}
}
if (!ret.size())
if (ret.empty())
for (auto i = m_blocksOnWay.begin(); ret.size() < c_maxBlocksAsk && i != m_blocksOnWay.end() && !_exclude.count(*i); ++i)
ret.insert(*i);
clog(NetMessageSummary) << "Asking for" << ret.size() << "blocks that we don't yet have." << m_blocksNeeded.size() << "blocks still needed," << m_blocksOnWay.size() << "blocks on way.";
if (ret.size())
clog(NetMessageSummary) << "Asking for" << ret.size() << "blocks that we don't yet have." << m_blocksNeeded.size() << "blocks still needed," << m_blocksOnWay.size() << "total blocks on way.";
return ret;
}
@ -95,6 +95,83 @@ bool EthereumHost::ensureInitialised(TransactionQueue& _tq)
return false;
}
void EthereumHost::noteHavePeerState(EthereumPeer* _who)
{
clog(NetAllDetail) << "Have peer state.";
// if already downloading hash-chain, ignore.
if (m_grabbing != Grabbing::Nothing)
{
clog(NetAllDetail) << "Already downloading chain. Just set to help out.";
_who->restartGettingChain();
return;
}
// otherwise check to see if we should be downloading...
_who->tryGrabbingHashChain();
}
void EthereumHost::updateGrabbing(Grabbing _g)
{
m_grabbing = _g;
if (_g == Grabbing::Nothing)
readyForSync();
else if (_g == Grabbing::Chain)
for (auto j: peers())
j->cap<EthereumPeer>()->restartGettingChain();
}
void EthereumHost::noteHaveChain(EthereumPeer* _from)
{
auto td = _from->m_totalDifficulty;
if (_from->m_neededBlocks.empty())
{
_from->m_grabbing = Grabbing::Nothing;
updateGrabbing(Grabbing::Nothing);
return;
}
clog(NetNote) << "Hash-chain COMPLETE:" << _from->m_totalDifficulty << "vs" << m_chain.details().totalDifficulty << "," << m_totalDifficultyOfNeeded << ";" << _from->m_neededBlocks.size() << " blocks, ends" << _from->m_neededBlocks.back().abridged();
if ((m_totalDifficultyOfNeeded && (td < m_totalDifficultyOfNeeded || (td == m_totalDifficultyOfNeeded && m_latestBlockSent == _from->m_latestHash))) || td < m_chain.details().totalDifficulty || (td == m_chain.details().totalDifficulty && m_chain.currentHash() == _from->m_latestHash))
{
clog(NetNote) << "Difficulty of hashchain not HIGHER. Ignoring.";
_from->m_grabbing = Grabbing::Nothing;
updateGrabbing(Grabbing::Nothing);
return;
}
clog(NetNote) << "Difficulty of hashchain HIGHER. Replacing fetch queue [latest now" << _from->m_latestHash.abridged() << ", was" << m_latestBlockSent.abridged() << "]";
// Looks like it's the best yet for total difficulty. Set to download.
{
Guard l(x_blocksNeeded);
m_blocksNeeded = _from->m_neededBlocks;
m_blocksOnWay.clear();
m_totalDifficultyOfNeeded = td;
m_latestBlockSent = _from->m_latestHash;
}
_from->m_grabbing = Grabbing::Chain;
updateGrabbing(Grabbing::Chain);
}
void EthereumHost::readyForSync()
{
// start grabbing next hash chain if there is one.
for (auto j: peers())
{
j->cap<EthereumPeer>()->tryGrabbingHashChain();
if (j->cap<EthereumPeer>()->m_grabbing == Grabbing::Hashes)
{
m_grabbing = Grabbing::Hashes;
return;
}
}
clog(NetNote) << "No more peers to sync with.";
}
void EthereumHost::noteDoneBlocks()
{
if (m_blocksOnWay.empty())
@ -104,7 +181,7 @@ void EthereumHost::noteDoneBlocks()
clog(NetNote) << "No more blocks coming. Missing" << m_blocksNeeded.size() << "blocks.";
else
clog(NetNote) << "No more blocks to get.";
m_latestBlockSent = m_chain.currentHash();
updateGrabbing(Grabbing::Nothing);
}
}
@ -129,6 +206,7 @@ void EthereumHost::doWork()
maintainBlocks(m_bq, h);
// return netChange;
// TODO: Figure out what to do with netChange.
(void)netChange;
}
void EthereumHost::maintainTransactions(TransactionQueue& _tq, h256 _currentHash)
@ -175,6 +253,21 @@ void EthereumHost::maintainTransactions(TransactionQueue& _tq, h256 _currentHash
}
}
void EthereumHost::reset()
{
m_grabbing = Grabbing::Nothing;
m_incomingTransactions.clear();
m_incomingBlocks.clear();
m_totalDifficultyOfNeeded = 0;
m_blocksNeeded.clear();
m_blocksOnWay.clear();
m_latestBlockSent = h256();
m_transactionsSent.clear();
}
void EthereumHost::maintainBlocks(BlockQueue& _bq, h256 _currentHash)
{
// Import new blocks
@ -187,14 +280,8 @@ void EthereumHost::maintainBlocks(BlockQueue& _bq, h256 _currentHash)
m_incomingBlocks.clear();
}
// If we've finished our initial sync...
{
Guard l(x_blocksNeeded);
if (m_blocksOnWay.size())
return;
}
// ...send any new blocks.
if (m_latestBlockSent != _currentHash)
// If we've finished our initial sync send any new blocks.
if (m_grabbing == Grabbing::Nothing && m_chain.details(m_latestBlockSent) && m_chain.details(m_latestBlockSent).totalDifficulty < m_chain.details(_currentHash).totalDifficulty)
{
RLPStream ts;
EthereumPeer::prep(ts);
@ -222,32 +309,3 @@ void EthereumHost::maintainBlocks(BlockQueue& _bq, h256 _currentHash)
m_latestBlockSent = _currentHash;
}
}
void EthereumHost::noteHaveChain(EthereumPeer* _from)
{
auto td = _from->m_totalDifficulty;
if (_from->m_neededBlocks.empty())
return;
clog(NetNote) << "Hash-chain COMPLETE:" << _from->m_totalDifficulty << "vs" << m_chain.details().totalDifficulty << "," << m_totalDifficultyOfNeeded << ";" << _from->m_neededBlocks.size() << " blocks, ends" << _from->m_neededBlocks.back().abridged();
if ((m_totalDifficultyOfNeeded && td < m_totalDifficultyOfNeeded) || td < m_chain.details().totalDifficulty)
{
clog(NetNote) << "Difficulty of hashchain LOWER. Ignoring.";
return;
}
clog(NetNote) << "Difficulty of hashchain HIGHER. Replacing fetch queue.";
// Looks like it's the best yet for total difficulty. Set to download.
{
Guard l(x_blocksNeeded);
m_blocksNeeded = _from->m_neededBlocks;
m_blocksOnWay.clear();
m_totalDifficultyOfNeeded = td;
}
for (auto j: peers())
j->cap<EthereumPeer>()->restartGettingChain();
}

10
libethereum/EthereumHost.h

@ -185,7 +185,10 @@ public:
u256 networkId() const { return m_networkId; }
void setNetworkId(u256 _n) { m_networkId = _n; }
void reset();
private:
void noteHavePeerState(EthereumPeer* _who);
/// Session wants to pass us a block that we might not have.
/// @returns true if we didn't have it.
bool noteBlock(h256 _hash, bytesConstRef _data);
@ -217,12 +220,17 @@ private:
virtual void onStarting() { startWorking(); }
virtual void onStopping() { stopWorking(); }
void readyForSync();
void updateGrabbing(Grabbing _g);
BlockChain const& m_chain;
TransactionQueue& m_tq; ///< Maintains a list of incoming transactions not yet in a block on the blockchain.
BlockQueue& m_bq; ///< Maintains a list of incoming blocks not yet on the blockchain (to be imported).
u256 m_networkId;
Grabbing m_grabbing = Grabbing::Nothing;
mutable std::recursive_mutex m_incomingLock;
std::vector<bytes> m_incomingTransactions;
std::vector<bytes> m_incomingBlocks;
@ -233,7 +241,7 @@ private:
h256Set m_blocksOnWay;
h256 m_latestBlockSent;
std::set<h256> m_transactionsSent;
h256Set m_transactionsSent;
};
}

45
libethereum/EthereumPeer.cpp

@ -73,16 +73,35 @@ void EthereumPeer::startInitialSync()
sealAndSend(s);
}
host()->noteHavePeerState(this);
}
void EthereumPeer::tryGrabbingHashChain()
{
// if already done this, then ignore.
if (m_grabbing != Grabbing::State)
{
clogS(NetAllDetail) << "Already synced with this peer.";
return;
}
h256 c = host()->m_chain.currentHash();
unsigned n = host()->m_chain.number();
u256 td = max(host()->m_chain.details().totalDifficulty, host()->m_totalDifficultyOfNeeded);
clogS(NetAllDetail) << "Initial sync. Latest:" << c.abridged() << ", number:" << n << ", TD: max(" << host()->m_chain.details().totalDifficulty << "," << host()->m_totalDifficultyOfNeeded << ") versus " << m_totalDifficulty;
clogS(NetAllDetail) << "Attempt chain-grab? Latest:" << c.abridged() << ", number:" << n << ", TD: max(" << host()->m_chain.details().totalDifficulty << "," << host()->m_totalDifficultyOfNeeded << ") versus " << m_totalDifficulty;
if (td > m_totalDifficulty)
{
clogS(NetAllDetail) << "No. Our chain is better.";
m_grabbing = Grabbing::Nothing;
return; // All good - we have the better chain.
}
// Our chain isn't better - grab theirs.
{
clogS(NetAllDetail) << "Yes. Their chain is better.";
m_grabbing = Grabbing::Hashes;
RLPStream s;
prep(s).appendList(3);
s << GetBlockHashesPacket << m_latestHash << c_maxHashesAsk;
@ -94,6 +113,16 @@ void EthereumPeer::startInitialSync()
void EthereumPeer::giveUpOnFetch()
{
clogS(NetNote) << "GIVE UP FETCH; can't get" << toString(m_askedBlocks);
// a bit overkill given that the other nodes may yet have the needed blocks, but better to be safe than sorry.
if (m_grabbing == Grabbing::Chain)
{
m_grabbing = Grabbing::Nothing;
host()->updateGrabbing(Grabbing::Nothing);
}
// NOTE: need to notify of giving up on chain-hashes, too, altering state as necessary.
if (m_askedBlocks.size())
{
Guard l (host()->x_blocksNeeded);
@ -157,7 +186,7 @@ bool EthereumPeer::interpret(RLP const& _r)
unsigned limit = _r[2].toInt<unsigned>();
clogS(NetMessageSummary) << "GetBlockHashes (" << limit << "entries," << later.abridged() << ")";
unsigned c = min<unsigned>(host()->m_chain.number(later), limit);
unsigned c = min<unsigned>(max<unsigned>(1, host()->m_chain.number(later)) - 1, limit);
RLPStream s;
prep(s).appendList(1 + c).append(BlockHashesPacket);
@ -169,7 +198,13 @@ bool EthereumPeer::interpret(RLP const& _r)
}
case BlockHashesPacket:
{
clogS(NetMessageSummary) << "BlockHashes (" << dec << (_r.itemCount() - 1) << "entries)";
clogS(NetMessageSummary) << "BlockHashes (" << dec << (_r.itemCount() - 1) << "entries)" << (_r.itemCount() - 1 ? "" : ": NoMoreHashes");
if (m_grabbing != Grabbing::Hashes)
{
cwarn << "Peer giving us hashes when we didn't ask for them.";
break;
}
if (_r.itemCount() == 1)
{
host()->noteHaveChain(this);
@ -196,7 +231,7 @@ bool EthereumPeer::interpret(RLP const& _r)
case GetBlocksPacket:
{
clogS(NetMessageSummary) << "GetBlocks (" << dec << (_r.itemCount() - 1) << "entries)";
// TODO: return the requested blocks.
// return the requested blocks.
bytes rlp;
unsigned n = 0;
for (unsigned i = 1; i < _r.itemCount() && i <= c_maxBlocks; ++i)
@ -214,7 +249,7 @@ bool EthereumPeer::interpret(RLP const& _r)
}
case BlocksPacket:
{
clogS(NetMessageSummary) << "Blocks (" << dec << (_r.itemCount() - 1) << "entries)";
clogS(NetMessageSummary) << "Blocks (" << dec << (_r.itemCount() - 1) << "entries)" << (_r.itemCount() - 1 ? "" : ": NoMoreBlocks");
if (_r.itemCount() == 1 && !m_askedBlocksChanged)
{

4
libethereum/EthereumPeer.h

@ -59,6 +59,8 @@ private:
void sendStatus();
void startInitialSync();
void tryGrabbingHashChain();
/// Ensure that we are waiting for a bunch of blocks from our peer.
void ensureGettingChain();
/// Ensure that we are waiting for a bunch of blocks from our peer.
@ -73,6 +75,8 @@ private:
unsigned m_protocolVersion;
u256 m_networkId;
Grabbing m_grabbing = Grabbing::State;
h256 m_latestHash; ///< Peer's latest block's hash.
u256 m_totalDifficulty; ///< Peer's latest block's total difficulty.
h256s m_neededBlocks; ///< The blocks that we should download from this peer.

5
libethereum/State.cpp

@ -152,10 +152,15 @@ State& State::operator=(State const& _s)
m_currentBlock = _s.m_currentBlock;
m_ourAddress = _s.m_ourAddress;
m_blockReward = _s.m_blockReward;
m_lastTx = _s.m_lastTx;
paranoia("after state cloning (assignment op)", true);
return *this;
}
State::~State()
{
}
struct CachedAddressState
{
CachedAddressState(std::string const& _rlp, AddressState const* _s, OverlayDB const* _o): rS(_rlp), r(rS), s(_s), o(_o) {}

2
libethereum/State.h

@ -90,6 +90,8 @@ public:
/// Copy state object.
State& operator=(State const& _s);
~State();
/// Set the coinbase address for any transactions we do.
/// This causes a complete reset of current block.
void setAddress(Address _coinbaseAddress) { m_ourAddress = _coinbaseAddress; resetCurrent(); }

2
libethereum/TransactionQueue.h

@ -52,6 +52,8 @@ public:
void setFuture(std::pair<h256, bytes> const& _t);
void noteGood(std::pair<h256, bytes> const& _t);
void clear() { WriteGuard l(m_lock); m_known.clear(); m_current.clear(); m_unknown.clear(); }
private:
mutable boost::shared_mutex m_lock; ///< General lock.
std::set<h256> m_known; ///< Hashes of transactions in both sets.

3
libwebthree/WebThree.h

@ -106,7 +106,7 @@ public:
bool haveNetwork() const { return m_net.isStarted(); }
void setNetworkPreferences(p2p::NetworkPreferences const& _n) { auto had = haveNetwork(); if (had) stopNetwork(); m_netPrefs = _n; if (had) startNetwork(); }
void setNetworkPreferences(p2p::NetworkPreferences const& _n) { auto had = haveNetwork(); if (had) stopNetwork(); m_net.setNetworkPreferences(_n); if (had) startNetwork(); }
/// Start the network subsystem.
void startNetwork() { m_net.start(); }
@ -121,7 +121,6 @@ private:
std::unique_ptr<shh::WhisperHost> m_whisper; ///< Main interface for Whisper ("shh") protocol.
p2p::Host m_net; ///< Should run in background and send us events when blocks found and allow us to send blocks as required.
p2p::NetworkPreferences m_netPrefs;
};

Loading…
Cancel
Save