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. 12
      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. 4
      libethereum/Client.h
  12. 16
      libethereum/CommonNet.h
  13. 142
      libethereum/EthereumHost.cpp
  14. 12
      libethereum/EthereumHost.h
  15. 47
      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> </property>
<addaction name="upnp"/> <addaction name="upnp"/>
<addaction name="usePast"/> <addaction name="usePast"/>
<addaction name="localNetworking"/>
<addaction name="net"/> <addaction name="net"/>
<addaction name="connect"/> <addaction name="connect"/>
</widget> </widget>
@ -1731,6 +1732,14 @@ font-size: 14pt</string>
<string>Reserved Debug 1</string> <string>Reserved Debug 1</string>
</property> </property>
</action> </action>
<action name="localNetworking">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Enable Local Addresses</string>
</property>
</action>
</widget> </widget>
<layoutdefault spacing="6" margin="11"/> <layoutdefault spacing="6" margin="11"/>
<customwidgets> <customwidgets>

5
alethzero/MainWin.cpp

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

12
eth/main.cpp

@ -112,7 +112,8 @@ void help()
<< " -l,--listen <port> Listen on the given port for incoming connected (default: 30303)." << endl << " -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 << " -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 << " -n,--upnp <on/off> Use upnp for NAT (default: on)." << endl
<< " -o,--mode <full/peer> Start a full node or a peer node (Default: full)." << 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 << " -p,--port <port> Connect to remote port (default: 30303)." << endl
<< " -r,--remote <host> Connect to remote host (default: none)." << endl << " -r,--remote <host> Connect to remote host (default: none)." << endl
<< " -s,--secret <secretkeyhex> Set the secret key for use with send command (default: auto)." << endl << " -s,--secret <secretkeyhex> Set the secret key for use with send command (default: auto)." << endl
@ -188,6 +189,7 @@ int main(int argc, char** argv)
#endif #endif
string publicIP; string publicIP;
bool upnp = true; bool upnp = true;
bool useLocal = false;
bool forceMining = false; bool forceMining = false;
string clientName; string clientName;
@ -233,10 +235,12 @@ int main(int argc, char** argv)
upnp = false; upnp = false;
else else
{ {
cerr << "Invalid UPnP option: " << m << endl; cerr << "Invalid -n/--upnp option: " << m << endl;
return -1; return -1;
} }
} }
else if (arg == "-L" || arg == "--local-networking")
useLocal = true;
else if ((arg == "-c" || arg == "--client-name") && i + 1 < argc) else if ((arg == "-c" || arg == "--client-name") && i + 1 < argc)
clientName = argv[++i]; clientName = argv[++i];
else if ((arg == "-a" || arg == "--address" || arg == "--coinbase-address") && i + 1 < argc) else if ((arg == "-a" || arg == "--address" || arg == "--coinbase-address") && i + 1 < argc)
@ -256,7 +260,7 @@ int main(int argc, char** argv)
mining = i; mining = i;
else else
{ {
cerr << "Unknown mining option: " << m << endl; cerr << "Unknown -m/--mining option: " << m << endl;
return -1; return -1;
} }
} }
@ -300,7 +304,7 @@ int main(int argc, char** argv)
cout << credits(); 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); 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); web3.setIdealPeerCount(peers);
eth::Client& c = *web3.ethereum(); eth::Client& c = *web3.ethereum();

2
libdevcore/Common.cpp

@ -27,7 +27,7 @@ using namespace dev;
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 namespace eth
{ {
const unsigned c_protocolVersion = 32; const unsigned c_protocolVersion = 33;
const unsigned c_databaseVersion = 1; const unsigned c_databaseVersion = 1;
static const vector<pair<u256, string>> g_units = 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) 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()) if (_path.empty())
_path = Defaults::get()->m_dbPath; _path = Defaults::get()->m_dbPath;
@ -127,10 +141,6 @@ BlockChain::BlockChain(std::string _path, bool _killExisting)
if (!m_extrasDB) if (!m_extrasDB)
throw DatabaseAlreadyOpen(); 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)) if (!details(m_genesisHash))
{ {
// Insert details of genesis block. // Insert details of genesis block.
@ -150,11 +160,16 @@ BlockChain::BlockChain(std::string _path, bool _killExisting)
cnote << "Opened blockchain DB. Latest: " << currentHash(); cnote << "Opened blockchain DB. Latest: " << currentHash();
} }
BlockChain::~BlockChain() void BlockChain::close()
{ {
cnote << "Closing blockchain DB"; cnote << "Closing blockchain DB";
delete m_extrasDB; delete m_extrasDB;
delete m_db; delete m_db;
m_lastBlockHash = m_genesisHash;
m_details.clear();
m_blooms.clear();
m_traces.clear();
m_cache.clear();
} }
template <class T, class V> template <class T, class V>
@ -245,21 +260,23 @@ h256s BlockChain::import(bytes const& _block, OverlayDB const& _db)
auto newHash = BlockInfo::headerHash(_block); auto newHash = BlockInfo::headerHash(_block);
// Check block doesn't already exist first! // Check block doesn't already exist first!
if (details(newHash)) if (isKnown(newHash))
{ {
clog(BlockChainNote) << newHash << ": Not new."; clog(BlockChainNote) << newHash << ": Not new.";
throw AlreadyHaveBlock(); throw AlreadyHaveBlock();
} }
// Work out its number as the parent's number + 1 // Work out its number as the parent's number + 1
auto pd = details(bi.parentHash); if (!isKnown(bi.parentHash))
if (!pd)
{ {
clog(BlockChainNote) << newHash << ": Unknown parent " << 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. // 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(); throw UnknownParent();
} }
auto pd = details(bi.parentHash);
assert(pd);
// Check it's not crazy // Check it's not crazy
if (bi.timestamp > (u256)time(0)) if (bi.timestamp > (u256)time(0))
{ {
@ -432,6 +449,20 @@ h256Set BlockChain::allUnclesFrom(h256 _parent) const
return ret; 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 bytes BlockChain::block(h256 _hash) const
{ {
if (_hash == m_genesisHash) if (_hash == m_genesisHash)

8
libethereum/BlockChain.h

@ -70,6 +70,8 @@ public:
BlockChain(std::string _path, bool _killExisting = false); BlockChain(std::string _path, bool _killExisting = false);
~BlockChain(); ~BlockChain();
void reopen(std::string _path, bool _killExisting = false) { close(); open(_path, _killExisting); }
/// (Potentially) renders invalid existing bytesConstRef returned by lastBlock. /// (Potentially) renders invalid existing bytesConstRef returned by lastBlock.
/// To be called from main loop every 100ms or so. /// To be called from main loop every 100ms or so.
void process(); void process();
@ -85,6 +87,9 @@ public:
/// @returns the block hashes of any blocks that came into/went out of the canonical block chain. /// @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); 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. /// 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(h256 _hash) const { return queryExtras<BlockDetails, 0>(_hash, m_details, x_details, NullBlockDetails); }
BlockDetails details() const { return details(currentHash()); } 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; h256s treeRoute(h256 _from, h256 _to, h256* o_common = nullptr, bool _pre = true, bool _post = true) const;
private: 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 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 // Check it's not in the future
if (bi.timestamp > (u256)time(0)) if (bi.timestamp > (u256)time(0))
{
m_future.insert(make_pair((unsigned)bi.timestamp, _block.toBytes())); m_future.insert(make_pair((unsigned)bi.timestamp, _block.toBytes()));
cblockq << "OK - queued for future.";
}
else else
{ {
// We now know it. // 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. // 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_unknown.insert(make_pair(bi.parentHash, make_pair(h, _block.toBytes())));
m_unknownSet.insert(h); m_unknownSet.insert(h);
} }
else else
{ {
// If valid, append to blocks. // If valid, append to blocks.
// cnote << "OK - ready for chain insertion."; cblockq << "OK - ready for chain insertion.";
m_ready.push_back(_block.toBytes()); m_ready.push_back(_block.toBytes());
m_readySet.insert(h); m_readySet.insert(h);

5
libethereum/BlockQueue.h

@ -34,7 +34,7 @@ namespace eth
class BlockChain; 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>() #define cblockq dev::LogOutputStream<dev::eth::BlockQueueChannel, true>()
/** /**
@ -64,6 +64,9 @@ public:
/// Get information on the items queued. /// 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()); } 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: private:
void noteReadyWithoutWriteGuard(h256 _b); void noteReadyWithoutWriteGuard(h256 _b);
void notePresentWithoutWriteGuard(bytesConstRef _block); void notePresentWithoutWriteGuard(bytesConstRef _block);

30
libethereum/Client.cpp

@ -99,7 +99,35 @@ void Client::flushTransactions()
void Client::killChain() 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() void Client::clearPending()

4
libethereum/Client.h

@ -271,13 +271,13 @@ private:
BlockChain m_bc; ///< Maintains block database. BlockChain m_bc; ///< Maintains block database.
TransactionQueue m_tq; ///< Maintains a list of incoming transactions not yet in a block on the blockchain. 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). 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. 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. 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. State m_preMine; ///< The present state of the client.
State m_postMine; ///< The state of the client which we're mining (i.e. it'll have all the rewards added). State m_postMine; ///< The state of the client which we're mining (i.e. it'll have all the rewards added).
std::weak_ptr<EthereumHost> m_host; ///< Our Ethereum Host. Don't do anything if we can't lock. std::weak_ptr<EthereumHost> m_host; ///< Our Ethereum Host. Don't do anything if we can't lock.
std::vector<Miner> m_miners; std::vector<Miner> m_miners;
mutable boost::shared_mutex x_miners; mutable boost::shared_mutex x_miners;

16
libethereum/CommonNet.h

@ -33,11 +33,17 @@ namespace dev
namespace eth 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_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_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_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). static const unsigned c_maxBlocksAsk = 128; ///< Maximum number of blocks we ask to receive in Blocks (when using GetChain).
#endif
class OverlayDB; class OverlayDB;
class BlockChain; class BlockChain;
class TransactionQueue; class TransactionQueue;
@ -55,5 +61,13 @@ enum EthereumPacket
BlocksPacket, BlocksPacket,
}; };
enum class Grabbing
{
State,
Hashes,
Chain,
Nothing
};
} }
} }

142
libethereum/EthereumHost.cpp

@ -41,7 +41,7 @@ using namespace p2p;
EthereumHost::EthereumHost(BlockChain const& _ch, TransactionQueue& _tq, BlockQueue& _bq, u256 _networkId): EthereumHost::EthereumHost(BlockChain const& _ch, TransactionQueue& _tq, BlockQueue& _bq, u256 _networkId):
HostCapability<EthereumPeer>(), HostCapability<EthereumPeer>(),
Worker("ethsync"), Worker ("ethsync"),
m_chain (_ch), m_chain (_ch),
m_tq (_tq), m_tq (_tq),
m_bq (_bq), m_bq (_bq),
@ -72,11 +72,11 @@ h256Set EthereumHost::neededBlocks(h256Set const& _exclude)
m_blocksNeeded.erase(it); 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) for (auto i = m_blocksOnWay.begin(); ret.size() < c_maxBlocksAsk && i != m_blocksOnWay.end() && !_exclude.count(*i); ++i)
ret.insert(*i); ret.insert(*i);
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() << "blocks on way."; 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; return ret;
} }
@ -95,6 +95,83 @@ bool EthereumHost::ensureInitialised(TransactionQueue& _tq)
return false; 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() void EthereumHost::noteDoneBlocks()
{ {
if (m_blocksOnWay.empty()) if (m_blocksOnWay.empty())
@ -104,7 +181,7 @@ void EthereumHost::noteDoneBlocks()
clog(NetNote) << "No more blocks coming. Missing" << m_blocksNeeded.size() << "blocks."; clog(NetNote) << "No more blocks coming. Missing" << m_blocksNeeded.size() << "blocks.";
else else
clog(NetNote) << "No more blocks to get."; 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); maintainBlocks(m_bq, h);
// return netChange; // return netChange;
// TODO: Figure out what to do with netChange. // TODO: Figure out what to do with netChange.
(void)netChange;
} }
void EthereumHost::maintainTransactions(TransactionQueue& _tq, h256 _currentHash) 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) void EthereumHost::maintainBlocks(BlockQueue& _bq, h256 _currentHash)
{ {
// Import new blocks // Import new blocks
@ -187,14 +280,8 @@ void EthereumHost::maintainBlocks(BlockQueue& _bq, h256 _currentHash)
m_incomingBlocks.clear(); m_incomingBlocks.clear();
} }
// If we've finished our initial sync... // 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)
Guard l(x_blocksNeeded);
if (m_blocksOnWay.size())
return;
}
// ...send any new blocks.
if (m_latestBlockSent != _currentHash)
{ {
RLPStream ts; RLPStream ts;
EthereumPeer::prep(ts); EthereumPeer::prep(ts);
@ -222,32 +309,3 @@ void EthereumHost::maintainBlocks(BlockQueue& _bq, h256 _currentHash)
m_latestBlockSent = _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();
}

12
libethereum/EthereumHost.h

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

47
libethereum/EthereumPeer.cpp

@ -73,16 +73,35 @@ void EthereumPeer::startInitialSync()
sealAndSend(s); 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(); h256 c = host()->m_chain.currentHash();
unsigned n = host()->m_chain.number(); unsigned n = host()->m_chain.number();
u256 td = max(host()->m_chain.details().totalDifficulty, host()->m_totalDifficultyOfNeeded); 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) if (td > m_totalDifficulty)
{
clogS(NetAllDetail) << "No. Our chain is better.";
m_grabbing = Grabbing::Nothing;
return; // All good - we have the better chain. return; // All good - we have the better chain.
}
// Our chain isn't better - grab theirs. // Our chain isn't better - grab theirs.
{ {
clogS(NetAllDetail) << "Yes. Their chain is better.";
m_grabbing = Grabbing::Hashes;
RLPStream s; RLPStream s;
prep(s).appendList(3); prep(s).appendList(3);
s << GetBlockHashesPacket << m_latestHash << c_maxHashesAsk; s << GetBlockHashesPacket << m_latestHash << c_maxHashesAsk;
@ -94,6 +113,16 @@ void EthereumPeer::startInitialSync()
void EthereumPeer::giveUpOnFetch() void EthereumPeer::giveUpOnFetch()
{ {
clogS(NetNote) << "GIVE UP FETCH; can't get" << toString(m_askedBlocks); 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()) if (m_askedBlocks.size())
{ {
Guard l (host()->x_blocksNeeded); Guard l (host()->x_blocksNeeded);
@ -157,7 +186,7 @@ bool EthereumPeer::interpret(RLP const& _r)
unsigned limit = _r[2].toInt<unsigned>(); unsigned limit = _r[2].toInt<unsigned>();
clogS(NetMessageSummary) << "GetBlockHashes (" << limit << "entries," << later.abridged() << ")"; 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; RLPStream s;
prep(s).appendList(1 + c).append(BlockHashesPacket); prep(s).appendList(1 + c).append(BlockHashesPacket);
@ -169,7 +198,13 @@ bool EthereumPeer::interpret(RLP const& _r)
} }
case BlockHashesPacket: 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) if (_r.itemCount() == 1)
{ {
host()->noteHaveChain(this); host()->noteHaveChain(this);
@ -196,7 +231,7 @@ bool EthereumPeer::interpret(RLP const& _r)
case GetBlocksPacket: case GetBlocksPacket:
{ {
clogS(NetMessageSummary) << "GetBlocks (" << dec << (_r.itemCount() - 1) << "entries)"; clogS(NetMessageSummary) << "GetBlocks (" << dec << (_r.itemCount() - 1) << "entries)";
// TODO: return the requested blocks. // return the requested blocks.
bytes rlp; bytes rlp;
unsigned n = 0; unsigned n = 0;
for (unsigned i = 1; i < _r.itemCount() && i <= c_maxBlocks; ++i) for (unsigned i = 1; i < _r.itemCount() && i <= c_maxBlocks; ++i)
@ -214,7 +249,7 @@ bool EthereumPeer::interpret(RLP const& _r)
} }
case BlocksPacket: 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) if (_r.itemCount() == 1 && !m_askedBlocksChanged)
{ {
@ -302,7 +337,7 @@ void EthereumPeer::continueGettingChain()
else else
{ {
if (m_failedBlocks.size()) if (m_failedBlocks.size())
clogS(NetMessageSummary) << "No blocks left to get. Peer doesn't seem to have" << m_failedBlocks.size() << "of our needed blocks."; clogS(NetMessageSummary) << "No blocks left to get. Peer doesn't seem to have" << m_failedBlocks.size() << "of our needed blocks.";
host()->noteDoneBlocks(); host()->noteDoneBlocks();
} }
} }

4
libethereum/EthereumPeer.h

@ -59,6 +59,8 @@ private:
void sendStatus(); void sendStatus();
void startInitialSync(); void startInitialSync();
void tryGrabbingHashChain();
/// Ensure that we are waiting for a bunch of blocks from our peer. /// Ensure that we are waiting for a bunch of blocks from our peer.
void ensureGettingChain(); void ensureGettingChain();
/// Ensure that we are waiting for a bunch of blocks from our peer. /// Ensure that we are waiting for a bunch of blocks from our peer.
@ -73,6 +75,8 @@ private:
unsigned m_protocolVersion; unsigned m_protocolVersion;
u256 m_networkId; u256 m_networkId;
Grabbing m_grabbing = Grabbing::State;
h256 m_latestHash; ///< Peer's latest block's hash. h256 m_latestHash; ///< Peer's latest block's hash.
u256 m_totalDifficulty; ///< Peer's latest block's total difficulty. u256 m_totalDifficulty; ///< Peer's latest block's total difficulty.
h256s m_neededBlocks; ///< The blocks that we should download from this peer. 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_currentBlock = _s.m_currentBlock;
m_ourAddress = _s.m_ourAddress; m_ourAddress = _s.m_ourAddress;
m_blockReward = _s.m_blockReward; m_blockReward = _s.m_blockReward;
m_lastTx = _s.m_lastTx;
paranoia("after state cloning (assignment op)", true); paranoia("after state cloning (assignment op)", true);
return *this; return *this;
} }
State::~State()
{
}
struct CachedAddressState struct CachedAddressState
{ {
CachedAddressState(std::string const& _rlp, AddressState const* _s, OverlayDB const* _o): rS(_rlp), r(rS), s(_s), o(_o) {} 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. /// Copy state object.
State& operator=(State const& _s); State& operator=(State const& _s);
~State();
/// Set the coinbase address for any transactions we do. /// Set the coinbase address for any transactions we do.
/// This causes a complete reset of current block. /// This causes a complete reset of current block.
void setAddress(Address _coinbaseAddress) { m_ourAddress = _coinbaseAddress; resetCurrent(); } 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 setFuture(std::pair<h256, bytes> const& _t);
void noteGood(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: private:
mutable boost::shared_mutex m_lock; ///< General lock. mutable boost::shared_mutex m_lock; ///< General lock.
std::set<h256> m_known; ///< Hashes of transactions in both sets. 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(); } 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. /// Start the network subsystem.
void startNetwork() { m_net.start(); } void startNetwork() { m_net.start(); }
@ -121,7 +121,6 @@ private:
std::unique_ptr<shh::WhisperHost> m_whisper; ///< Main interface for Whisper ("shh") protocol. 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::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