diff --git a/exp/main.cpp b/exp/main.cpp index 7406a883d..d79fbb973 100644 --- a/exp/main.cpp +++ b/exp/main.cpp @@ -25,19 +25,24 @@ #include #include #include - +#endif #include #include #include +#include +#if 0 #include #include "BuildInfo.h" +#endif using namespace std; using namespace eth; +#if 0 +#if 0 namespace qi = boost::spirit::qi; namespace px = boost::phoenix; namespace sp = boost::spirit; -#if 0 + class ASTSymbol: public string { public: @@ -291,5 +296,8 @@ int main(int, char**) killBigints(out); cout << endl; #endif + + cnote << RLP(fromHex("f837c0c0b4600160003556601359506301000000600035040f6018590060005660805460016080530160005760003560805760203560003557")); + cnote << toHex(RLPStream(1).append(bytes(54, 0)).out()); return 0; } diff --git a/iethxi/EthereumMacOSXBundleInfo.plist.in b/iethxi/EthereumMacOSXBundleInfo.plist.in new file mode 100644 index 000000000..684ad7908 --- /dev/null +++ b/iethxi/EthereumMacOSXBundleInfo.plist.in @@ -0,0 +1,38 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${MACOSX_BUNDLE_EXECUTABLE_NAME} + CFBundleGetInfoString + ${MACOSX_BUNDLE_INFO_STRING} + CFBundleIconFile + ${MACOSX_BUNDLE_ICON_FILE} + CFBundleIdentifier + ${MACOSX_BUNDLE_GUI_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleLongVersionString + ${MACOSX_BUNDLE_LONG_VERSION_STRING} + CFBundleName + ${MACOSX_BUNDLE_BUNDLE_NAME} + CFBundlePackageType + APPL + CFBundleShortVersionString + ${MACOSX_BUNDLE_SHORT_VERSION_STRING} + CFBundleSignature + ???? + CFBundleVersion + ${MACOSX_BUNDLE_BUNDLE_VERSION} + CSResourcesFileMapped + + LSRequiresCarbon + + NSHumanReadableCopyright + ${MACOSX_BUNDLE_COPYRIGHT} + NSHighResolutionCapable + + + diff --git a/iethxi/Simple.qml b/iethxi/Simple.qml new file mode 100644 index 000000000..ac9dc5e37 --- /dev/null +++ b/iethxi/Simple.qml @@ -0,0 +1,9 @@ +import QtQuick.Controls 1.1 + +ApplicationWindow { + title: "My App" + Button { + text: "Push Me" + anchors.centerIn: parent + } +} diff --git a/libethcore/BlockInfo.cpp b/libethcore/BlockInfo.cpp index 0b56c6c85..55026f670 100644 --- a/libethcore/BlockInfo.cpp +++ b/libethcore/BlockInfo.cpp @@ -71,6 +71,8 @@ h256 BlockInfo::headerHash(bytesConstRef _block) void BlockInfo::populateFromHeader(RLP const& _header, bool _checkNonce) { + hash = eth::sha3(_header.data()); + int field = 0; try { @@ -106,10 +108,9 @@ void BlockInfo::populateFromHeader(RLP const& _header, bool _checkNonce) void BlockInfo::populate(bytesConstRef _block, bool _checkNonce) { - hash = eth::sha3(_block); - RLP root(_block); RLP header = root[0]; + if (!header.isList()) throw InvalidBlockFormat(0, header.data()); populateFromHeader(header, _checkNonce); @@ -171,7 +172,7 @@ u256 BlockInfo::calculateDifficulty(BlockInfo const& _parent) const if (!parentHash) return c_genesisDifficulty; else - return timestamp >= _parent.timestamp + 9 ? _parent.difficulty - (_parent.difficulty >> 10) : (_parent.difficulty + (_parent.difficulty >> 10)); + return timestamp >= _parent.timestamp + 5 ? _parent.difficulty - (_parent.difficulty >> 10) : (_parent.difficulty + (_parent.difficulty >> 10)); } void BlockInfo::verifyParent(BlockInfo const& _parent) const diff --git a/libethcore/CommonEth.cpp b/libethcore/CommonEth.cpp index db1c9c636..b63ade94e 100644 --- a/libethcore/CommonEth.cpp +++ b/libethcore/CommonEth.cpp @@ -29,7 +29,7 @@ using namespace eth; //#define ETH_ADDRESS_DEBUG 1 -const unsigned eth::c_protocolVersion = 28; +const unsigned eth::c_protocolVersion = 30; const unsigned eth::c_databaseVersion = 1; static const vector> g_units = diff --git a/libethential/Common.cpp b/libethential/Common.cpp index c64d3cb97..2f6feb9e5 100644 --- a/libethential/Common.cpp +++ b/libethential/Common.cpp @@ -27,6 +27,6 @@ using namespace eth; namespace eth { -char const* EthVersion = "0.6.6"; +char const* EthVersion = "0.6.8"; } diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index d345271a9..97d69eb41 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -165,6 +165,16 @@ bool contains(T const& _t, V const& _v) return false; } +inline string toString(h256s const& _bs) +{ + ostringstream out; + out << "[ "; + for (auto i: _bs) + out << i.abridged() << ", "; + out << "]"; + return out.str(); +} + h256s BlockChain::sync(BlockQueue& _bq, OverlayDB const& _stateDB, unsigned _max) { vector blocks; @@ -183,7 +193,7 @@ h256s BlockChain::sync(BlockQueue& _bq, OverlayDB const& _stateDB, unsigned _max } catch (UnknownParent) { - cwarn << "Unknown parent of block!!!" << eth::sha3(block).abridged(); + cwarn << "Unknown parent of block!!!" << BlockInfo::headerHash(block).abridged(); _bq.import(&block, *this); } catch (...){} @@ -223,7 +233,7 @@ h256s BlockChain::import(bytes const& _block, OverlayDB const& _db) throw; } #endif - auto newHash = eth::sha3(_block); + auto newHash = BlockInfo::headerHash(_block); // Check block doesn't already exist first! if (details(newHash)) @@ -320,20 +330,18 @@ h256s BlockChain::import(bytes const& _block, OverlayDB const& _db) m_lastBlockHash = newHash; } m_extrasDB->Put(m_writeOptions, ldb::Slice("best"), ldb::Slice((char const*)&newHash, 32)); - clog(BlockChainNote) << " Imported and best. Has" << (details(bi.parentHash).children.size() - 1) << "siblings. Route:"; - for (auto r: ret) - clog(BlockChainNote) << r.abridged(); + clog(BlockChainNote) << " Imported and best" << td << ". Has" << (details(bi.parentHash).children.size() - 1) << "siblings. Route:" << toString(ret); } else { - clog(BlockChainNote) << " Imported but not best (oTD:" << details(last).totalDifficulty << ", TD:" << td << ")"; + clog(BlockChainNote) << " Imported but not best (oTD:" << details(last).totalDifficulty << " > TD:" << td << ")"; } return ret; } h256s BlockChain::treeRoute(h256 _from, h256 _to, h256* o_common, bool _pre, bool _post) const { - cdebug << "treeRoute" << _from.abridged() << "..." << _to.abridged(); +// cdebug << "treeRoute" << _from.abridged() << "..." << _to.abridged(); if (!_from || !_to) { return h256s(); @@ -342,14 +350,14 @@ h256s BlockChain::treeRoute(h256 _from, h256 _to, h256* o_common, bool _pre, boo h256s back; unsigned fn = details(_from).number; unsigned tn = details(_to).number; - cdebug << "treeRoute" << fn << "..." << tn; +// cdebug << "treeRoute" << fn << "..." << tn; while (fn > tn) { if (_pre) ret.push_back(_from); _from = details(_from).parent; fn--; - cdebug << "from:" << fn << _from.abridged(); +// cdebug << "from:" << fn << _from.abridged(); } while (fn < tn) { @@ -357,7 +365,7 @@ h256s BlockChain::treeRoute(h256 _from, h256 _to, h256* o_common, bool _pre, boo back.push_back(_to); _to = details(_to).parent; tn--; - cdebug << "to:" << tn << _to.abridged(); +// cdebug << "to:" << tn << _to.abridged(); } while (_from != _to) { @@ -371,7 +379,7 @@ h256s BlockChain::treeRoute(h256 _from, h256 _to, h256* o_common, bool _pre, boo back.push_back(_to); fn--; tn--; - cdebug << "from:" << fn << _from.abridged() << "; to:" << tn << _to.abridged(); +// cdebug << "from:" << fn << _from.abridged() << "; to:" << tn << _to.abridged(); } if (o_common) *o_common = _from; @@ -408,7 +416,7 @@ h256Set BlockChain::allUnclesFrom(h256 _parent) const h256 p = _parent; for (unsigned i = 0; i < 6 && p != m_genesisHash; ++i, p = details(p).parent) { - ret.insert(sha3(RLP(block(p))[0].data())); + ret.insert(p); // TODO: check: should this be details(p).parent? for (auto i: RLP(block(p))[2]) ret.insert(sha3(i.data())); } diff --git a/libethereum/BlockQueue.cpp b/libethereum/BlockQueue.cpp index 3f636b102..1aca07847 100644 --- a/libethereum/BlockQueue.cpp +++ b/libethereum/BlockQueue.cpp @@ -31,13 +31,18 @@ using namespace eth; bool BlockQueue::import(bytesConstRef _block, BlockChain const& _bc) { // Check if we already know this block. - h256 h = sha3(_block); + h256 h = BlockInfo::headerHash(_block); + + cnote << "Queuing block" << h.abridged() << "for import..."; UpgradableGuard l(m_lock); if (m_readySet.count(h) || m_drainingSet.count(h) || m_futureSet.count(h)) + { // Already know about this one. + cnote << "Already known."; return false; + } // VERIFY: populates from the block and checks the block is internally coherent. BlockInfo bi; @@ -56,15 +61,20 @@ bool BlockQueue::import(bytesConstRef _block, BlockChain const& _bc) return false; } #endif - auto newHash = eth::sha3(_block); // Check block doesn't already exist first! - if (_bc.details(newHash)) + if (_bc.details(h)) + { + cnote << "Already known in chain."; return false; + } // Check it's not crazy - if (bi.timestamp > (u256)time(0)) + if (bi.timestamp > (u256)time(0) + 10) + { + cnote << "Invalid timestamp."; return false; + } { UpgradeGuard ul(l); @@ -73,12 +83,14 @@ bool BlockQueue::import(bytesConstRef _block, BlockChain const& _bc) if (!m_readySet.count(bi.parentHash) && !m_drainingSet.count(bi.parentHash) && !_bc.details(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."; m_future.insert(make_pair(bi.parentHash, make_pair(h, _block.toBytes()))); m_futureSet.insert(h); } else { // If valid, append to blocks. +// cnote << "OK - ready for chain insertion."; m_ready.push_back(_block.toBytes()); m_readySet.insert(h); diff --git a/libethereum/EthereumHost.cpp b/libethereum/EthereumHost.cpp index beb7a6fbd..2c2e327d5 100644 --- a/libethereum/EthereumHost.cpp +++ b/libethereum/EthereumHost.cpp @@ -367,22 +367,27 @@ void EthereumHost::connect(bi::tcp::endpoint const& _ep) }); } -h256Set EthereumHost::neededBlocks() +h256Set EthereumHost::neededBlocks(h256Set const& _exclude) { Guard l(x_blocksNeeded); h256Set ret; if (m_blocksNeeded.size()) { - while (ret.size() < c_maxBlocksAsk && m_blocksNeeded.size()) - { - ret.insert(m_blocksNeeded.back()); - m_blocksOnWay.insert(m_blocksNeeded.back()); - m_blocksNeeded.pop_back(); - } + int s = m_blocksNeeded.size() - 1; + for (; ret.size() < c_maxBlocksAsk && s < (int)m_blocksNeeded.size() && s >= 0; --s) + if (!_exclude.count(m_blocksNeeded[s])) + { + auto it = m_blocksNeeded.begin() + s; + ret.insert(*it); + m_blocksOnWay.insert(*it); + m_blocksNeeded.erase(it); + } } - else - for (auto i = m_blocksOnWay.begin(); ret.size() < c_maxBlocksAsk && i != m_blocksOnWay.end(); ++i) + if (!ret.size()) + 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."; return ret; } @@ -416,6 +421,17 @@ bool EthereumHost::ensureInitialised(TransactionQueue& _tq) return false; } +void EthereumHost::noteDoneBlocks() +{ + clog(NetNote) << "Peer given up on blocks fetch."; + if (m_blocksOnWay.empty()) + { + // Done our chain-get. + clog(NetNote) << "No more blocks coming. Missing" << m_blocksNeeded.size() << "blocks."; + m_latestBlockSent = m_chain->currentHash(); + } +} + bool EthereumHost::noteBlock(h256 _hash, bytesConstRef _data) { Guard l(x_blocksNeeded); @@ -504,8 +520,14 @@ void EthereumHost::maintainBlocks(BlockQueue& _bq, h256 _currentHash) m_incomingBlocks.clear(); } - // Send any new blocks. - if (_currentHash != m_latestBlockSent) + // If we've finished our initial sync... + { + Guard l(x_blocksNeeded); + if (m_blocksOnWay.size()) + return; + } + // ...send any new blocks. + if (m_latestBlockSent != _currentHash) { RLPStream ts; EthereumSession::prep(ts); @@ -516,6 +538,7 @@ void EthereumHost::maintainBlocks(BlockQueue& _bq, h256 _currentHash) bs += m_chain->block(h); ++c; } + clog(NetNote) << "Sending" << c << "new blocks (current is" << _currentHash << ", was" << m_latestBlockSent << ")"; ts.appendList(1 + c).append(BlocksPacket).appendRaw(bs, c); bytes b; ts.swapOut(b); @@ -529,8 +552,8 @@ void EthereumHost::maintainBlocks(BlockQueue& _bq, h256 _currentHash) p->send(&b); p->m_knownBlocks.clear(); } + m_latestBlockSent = _currentHash; } - m_latestBlockSent = _currentHash; } void EthereumHost::growPeers() @@ -574,7 +597,7 @@ void EthereumHost::noteHaveChain(std::shared_ptr const& _from) if (_from->m_neededBlocks.empty()) return; - clog(NetNote) << "Hash-chain COMPLETE:" << log2((double)_from->m_totalDifficulty) << "vs" << log2((double)m_chain->details().totalDifficulty) << "," << log2((double)m_totalDifficultyOfNeeded) << ";" << _from->m_neededBlocks.size() << " blocks, ends" << _from->m_neededBlocks.back().abridged(); + 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) { @@ -596,7 +619,7 @@ void EthereumHost::noteHaveChain(std::shared_ptr const& _from) Guard l(x_peers); for (auto const& i: m_peers) if (shared_ptr p = i.second.lock()) - p->ensureGettingChain(); + p->restartGettingChain(); } } diff --git a/libethereum/EthereumHost.h b/libethereum/EthereumHost.h index bbe0d8b86..9a9f83b1b 100644 --- a/libethereum/EthereumHost.h +++ b/libethereum/EthereumHost.h @@ -113,6 +113,8 @@ private: bool noteBlock(h256 _hash, bytesConstRef _data); /// Session has finished getting the chain of hashes. void noteHaveChain(std::shared_ptr const& _who); + /// Called when the peer can no longer provide us with any needed blocks. + void noteDoneBlocks(); /// Called when the session has provided us with a new peer we can connect to. void noteNewPeers() {} @@ -129,7 +131,7 @@ private: /// Get a bunch of needed blocks. /// Removes them from our list of needed blocks. /// @returns empty if there's no more blocks left to fetch, otherwise the blocks to fetch. - h256Set neededBlocks(); + h256Set neededBlocks(h256Set const& _exclude); /// Check to see if the network peer-state initialisation has happened. virtual bool isInitialised() const { return m_latestBlockSent; } diff --git a/libethereum/EthereumSession.cpp b/libethereum/EthereumSession.cpp index fd0002967..a04ccf0a3 100644 --- a/libethereum/EthereumSession.cpp +++ b/libethereum/EthereumSession.cpp @@ -56,7 +56,7 @@ EthereumSession::~EthereumSession() catch (...){} } -string toString(h256s const& _bs) +inline string toString(h256s const& _bs) { ostringstream out; out << "[ "; @@ -75,6 +75,7 @@ void EthereumSession::giveUpOnFetch() m_server->m_blocksNeeded.reserve(m_server->m_blocksNeeded.size() + m_askedBlocks.size()); for (auto i: m_askedBlocks) { + m_failedBlocks.insert(i); m_server->m_blocksOnWay.erase(i); m_server->m_blocksNeeded.push_back(i); } @@ -109,8 +110,9 @@ bool EthereumSession::interpret(RLP const& _r) m_id = _r[6].toHash(); m_totalDifficulty = _r[7].toInt(); m_latestHash = _r[8].toHash(); + auto genesisHash = _r[9].toHash(); - clogS(NetMessageSummary) << "Hello: " << clientVersion << "V[" << m_protocolVersion << "/" << m_networkId << "]" << m_id.abridged() << showbase << hex << m_caps << dec << m_listenPort; + clogS(NetMessageSummary) << "Hello: " << clientVersion << "V[" << m_protocolVersion << "/" << m_networkId << "/" << genesisHash.abridged() << "]" << m_id.abridged() << showbase << hex << m_caps << dec << m_listenPort; if (m_server->havePeer(m_id)) { @@ -120,6 +122,12 @@ bool EthereumSession::interpret(RLP const& _r) return false; } + if (genesisHash != m_server->m_chain->genesisHash()) + { + disconnect(WrongGenesis); + return false; + } + if (m_protocolVersion != EthereumHost::protocolVersion() || m_networkId != m_server->networkId() || !m_id) { disconnect(IncompatibleProtocol); @@ -301,17 +309,17 @@ bool EthereumSession::interpret(RLP const& _r) break; clogS(NetMessageSummary) << "Blocks (" << dec << (_r.itemCount() - 1) << " entries)"; - if (_r.itemCount() == 1) + if (_r.itemCount() == 1 && !m_askedBlocksChanged) { // Couldn't get any from last batch - probably got to this peer's latest block - just give up. giveUpOnFetch(); - break; } + m_askedBlocksChanged = false; unsigned used = 0; for (unsigned i = 1; i < _r.itemCount(); ++i) { - auto h = sha3(_r[i].data()); + auto h = BlockInfo::headerHash(_r[i].data()); if (m_server->noteBlock(h, _r[i].data())) used++; m_askedBlocks.erase(h); @@ -324,7 +332,7 @@ bool EthereumSession::interpret(RLP const& _r) { for (unsigned i = 1; i < _r.itemCount(); ++i) { - auto h = sha3(_r[i].data()); + auto h = BlockInfo::headerHash(_r[i].data()); BlockInfo bi(_r[i].data()); if (!m_server->m_chain->details(bi.parentHash) && !m_knownBlocks.count(bi.parentHash)) { @@ -339,7 +347,7 @@ bool EthereumSession::interpret(RLP const& _r) } } clogS(NetMessageSummary) << dec << knownParents << " known parents, " << unknownParents << "unknown, " << used << "used."; - ensureGettingChain(); + continueGettingChain(); break; } case GetTransactionsPacket: @@ -355,10 +363,30 @@ bool EthereumSession::interpret(RLP const& _r) return true; } +void EthereumSession::restartGettingChain() +{ + if (m_askedBlocks.size()) + { + m_askedBlocksChanged = true; // So that we continue even if the Ask's reply is empty. + m_askedBlocks.clear(); // So that we restart once we get the Ask's reply. + m_failedBlocks.clear(); + } + else + ensureGettingChain(); +} + void EthereumSession::ensureGettingChain() +{ + if (m_askedBlocks.size()) + return; // Already asked & waiting for some. + + continueGettingChain(); +} + +void EthereumSession::continueGettingChain() { if (!m_askedBlocks.size()) - m_askedBlocks = m_server->neededBlocks(); + m_askedBlocks = m_server->neededBlocks(m_failedBlocks); if (m_askedBlocks.size()) { @@ -370,7 +398,10 @@ void EthereumSession::ensureGettingChain() sealAndSend(s); } else - clogS(NetMessageSummary) << "No blocks left to get."; + { + clogS(NetMessageSummary) << "No blocks left to get. Peer doesn't seem to have " << m_failedBlocks.size() << "of our needed blocks."; + m_server->noteDoneBlocks(); + } } void EthereumSession::ping() @@ -513,7 +544,7 @@ void EthereumSession::start() { RLPStream s; prep(s); - s.appendList(9) << HelloPacket + s.appendList(10) << HelloPacket << (uint)EthereumHost::protocolVersion() << m_server->networkId() << m_server->m_clientVersion @@ -521,7 +552,8 @@ void EthereumSession::start() << m_server->m_public.port() << m_server->m_key.pub() << m_server->m_chain->details().totalDifficulty - << m_server->m_chain->currentHash(); + << m_server->m_chain->currentHash() + << m_server->m_chain->genesisHash(); sealAndSend(s); ping(); getPeers(); diff --git a/libethereum/EthereumSession.h b/libethereum/EthereumSession.h index ca44179c6..2a7e31155 100644 --- a/libethereum/EthereumSession.h +++ b/libethereum/EthereumSession.h @@ -60,6 +60,10 @@ private: /// 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. + void continueGettingChain(); + /// Now getting a different chain so we need to make sure we restart. + void restartGettingChain(); void giveUpOnFetch(); @@ -97,8 +101,10 @@ private: 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. + h256Set m_failedBlocks; ///< Blocks that the peer doesn't seem to have. h256Set m_askedBlocks; ///< The blocks for which we sent the last GetBlocks for but haven't received a corresponding Blocks. + bool m_askedBlocksChanged = true; std::chrono::steady_clock::time_point m_ping; std::chrono::steady_clock::time_point m_connect; diff --git a/libethereum/Transaction.cpp b/libethereum/Transaction.cpp index 9968683fe..ef89971c5 100644 --- a/libethereum/Transaction.cpp +++ b/libethereum/Transaction.cpp @@ -27,7 +27,7 @@ using namespace std; using namespace eth; -#define ETH_ADDRESS_DEBUG 1 +#define ETH_ADDRESS_DEBUG 0 Transaction::Transaction(bytesConstRef _rlpData, bool _checkSender) { diff --git a/libethereumx/CMakeLists.txt b/libethereumx/CMakeLists.txt index d510fc8d0..1c74bf2c3 100644 --- a/libethereumx/CMakeLists.txt +++ b/libethereumx/CMakeLists.txt @@ -17,6 +17,7 @@ file(GLOB HEADERS "*.h") include_directories(..) +target_link_libraries(${EXECUTABLE} ethereum) target_link_libraries(${EXECUTABLE} evm) target_link_libraries(${EXECUTABLE} lll) target_link_libraries(${EXECUTABLE} ethcore) diff --git a/libethereumx/Ethereum.cpp b/libethereumx/Ethereum.cpp index 75971f42a..a7725abb5 100644 --- a/libethereumx/Ethereum.cpp +++ b/libethereumx/Ethereum.cpp @@ -63,63 +63,67 @@ void Ethereum::startServer() { } -void Client::flushTransactions() +void Ethereum::flushTransactions() { } -std::vector Client::peers() +std::vector Ethereum::peers() { return std::vector(); } -size_t Client::peerCount() const +size_t Ethereum::peerCount() const { return 0; } -void Client::connect(std::string const& _seedHost, unsigned short _port) +void Ethereum::connect(std::string const& _seedHost, unsigned short _port) { } -void Client::transact(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice) +void Ethereum::transact(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice) { } -bytes Client::call(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice) +bytes Ethereum::call(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice) { return bytes(); } -Address Client::transact(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas, u256 _gasPrice) +Address Ethereum::transact(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas, u256 _gasPrice) { return Address(); } -void Client::inject(bytesConstRef _rlp) +void Ethereum::inject(bytesConstRef _rlp) { } -u256 Client::balanceAt(Address _a, int _block) const +u256 Ethereum::balanceAt(Address _a, int _block) const { return u256(); } -std::map Client::storageAt(Address _a, int _block) const +PastMessages Ethereum::messages(MessageFilter const& _filter) const +{ +} + +std::map Ethereum::storageAt(Address _a, int _block) const { return std::map(); } -u256 Client::countAt(Address _a, int _block) const +u256 Ethereum::countAt(Address _a, int _block) const { return u256(); } -u256 Client::stateAt(Address _a, u256 _l, int _block) const +u256 Ethereum::stateAt(Address _a, u256 _l, int _block) const { return u256(); } -bytes Client::codeAt(Address _a, int _block) const +bytes Ethereum::codeAt(Address _a, int _block) const { return bytes(); } diff --git a/libethnet/Common.h b/libethnet/Common.h index 099fe085f..64bc20370 100644 --- a/libethnet/Common.h +++ b/libethnet/Common.h @@ -37,6 +37,7 @@ namespace eth bool isPrivateAddress(bi::address _addressToCheck); +class RLP; class PeerHost; class PeerSession; @@ -88,4 +89,55 @@ struct PeerInfo class UPnP; +class PeerCapability; + +class HostCapabilityFace +{ +public: + HostCapabilityFace(PeerHost*) {} + virtual ~HostCapabilityFace() {} + + virtual std::string name() const = 0; + virtual PeerCapability* newPeerCapability(PeerSession* _s) = 0; +}; + +template +class HostCapability: public HostCapabilityFace +{ +public: + HostCapability(PeerHost* _h): m_host(_h) {} + virtual ~HostCapability() {} + + static std::string staticName() { return PeerCap::name(); } + + PeerHost* host() const { return m_host; } + +protected: + virtual std::string name() const { return PeerCap::name(); } + virtual PeerCapability* newPeerCapability(PeerSession* _s) { return new PeerCap(_s); } + +private: + PeerHost* m_host; +}; + +class PeerCapability +{ + friend class PeerSession; + +public: + PeerCapability(PeerSession* _s): m_session(_s) {} + virtual ~PeerCapability() {} + + /// Must return the capability name. + static std::string name() { return ""; } + + PeerSession* session() const { return m_session; } + +protected: + virtual bool interpret(RLP const&) = 0; + +private: + PeerSession* m_session; +}; + } diff --git a/libethnet/PeerHost.cpp b/libethnet/PeerHost.cpp index 54e42d470..d5ca05cc4 100644 --- a/libethnet/PeerHost.cpp +++ b/libethnet/PeerHost.cpp @@ -52,13 +52,12 @@ static const set c_rejectAddresses = { {bi::address_v6::from_string("::")} }; -PeerHost::PeerHost(std::string const& _clientVersion, u256 _networkId, unsigned short _port, string const& _publicAddress, bool _upnp): +PeerHost::PeerHost(std::string const& _clientVersion, unsigned short _port, string const& _publicAddress, bool _upnp): m_clientVersion(_clientVersion), m_listenPort(_port), m_acceptor(m_ioService, bi::tcp::endpoint(bi::tcp::v4(), _port)), m_socket(m_ioService), - m_key(KeyPair::create()), - m_networkId(_networkId) + m_key(KeyPair::create()) { populateAddresses(); determinePublic(_publicAddress, _upnp); @@ -66,13 +65,12 @@ PeerHost::PeerHost(std::string const& _clientVersion, u256 _networkId, unsigned clog(NetNote) << "Id:" << toHex(m_key.address().ref().cropped(0, 4)); } -PeerHost::PeerHost(std::string const& _clientVersion, u256 _networkId, string const& _publicAddress, bool _upnp): +PeerHost::PeerHost(std::string const& _clientVersion, string const& _publicAddress, bool _upnp): m_clientVersion(_clientVersion), m_listenPort(0), m_acceptor(m_ioService, bi::tcp::endpoint(bi::tcp::v4(), 0)), m_socket(m_ioService), - m_key(KeyPair::create()), - m_networkId(_networkId) + m_key(KeyPair::create()) { m_listenPort = m_acceptor.local_endpoint().port(); @@ -83,13 +81,12 @@ PeerHost::PeerHost(std::string const& _clientVersion, u256 _networkId, string co clog(NetNote) << "Id:" << toHex(m_key.address().ref().cropped(0, 4)); } -PeerHost::PeerHost(std::string const& _clientVersion, u256 _networkId): +PeerHost::PeerHost(std::string const& _clientVersion): m_clientVersion(_clientVersion), m_listenPort(0), m_acceptor(m_ioService, bi::tcp::endpoint(bi::tcp::v4(), 0)), m_socket(m_ioService), - m_key(KeyPair::create()), - m_networkId(_networkId) + m_key(KeyPair::create()) { // populate addresses. populateAddresses(); @@ -101,10 +98,20 @@ PeerHost::~PeerHost() disconnectPeers(); } +unsigned PeerHost::protocolVersion() const +{ + return 0; +} + void PeerHost::registerPeer(std::shared_ptr _s) { - Guard l(x_peers); - m_peers[_s->m_id] = _s; + { + Guard l(x_peers); + m_peers[_s->m_id] = _s; + } + for (auto const& i: _s->m_caps) + if (haveCapability(i)) + _s->m_capabilities.push_back(shared_ptr(m_capabilities[i]->newPeerCapability(_s.get()))); } void PeerHost::disconnectPeers() @@ -293,7 +300,7 @@ void PeerHost::ensureAccepting() } catch (...){} bi::address remoteAddress = m_socket.remote_endpoint().address(); // Port defaults to 0 - we let the hello tell us which port the peer listens to - auto p = std::make_shared(this, std::move(m_socket), m_networkId, remoteAddress); + auto p = std::make_shared(this, std::move(m_socket), remoteAddress); p->start(); } catch (std::exception const& _e) @@ -341,7 +348,7 @@ void PeerHost::connect(bi::tcp::endpoint const& _ep) } else { - auto p = make_shared(this, std::move(*s), m_networkId, _ep.address(), _ep.port()); + auto p = make_shared(this, std::move(*s), _ep.address(), _ep.port()); clog(NetConnect) << "Connected to " << _ep; p->start(); } diff --git a/libethnet/PeerHost.h b/libethnet/PeerHost.h index b23b1d1ee..f44d202eb 100644 --- a/libethnet/PeerHost.h +++ b/libethnet/PeerHost.h @@ -47,11 +47,11 @@ class PeerHost public: /// Start server, listening for connections on the given port. - PeerHost(std::string const& _clientVersion, u256 _networkId, unsigned short _port, std::string const& _publicAddress = std::string(), bool _upnp = true); + PeerHost(std::string const& _clientVersion, unsigned short _port, std::string const& _publicAddress = std::string(), bool _upnp = true); /// Start server, listening for connections on a system-assigned port. - PeerHost(std::string const& _clientVersion, u256 _networkId, std::string const& _publicAddress = std::string(), bool _upnp = true); + PeerHost(std::string const& _clientVersion, std::string const& _publicAddress = std::string(), bool _upnp = true); /// Start server, but don't listen. - PeerHost(std::string const& _clientVersion, u256 _networkId); + PeerHost(std::string const& _clientVersion); /// Will block on network process events. virtual ~PeerHost(); @@ -59,8 +59,11 @@ public: /// Closes all peers. void disconnectPeers(); - virtual u256 networkId() { return m_networkId; } - virtual unsigned protocolVersion() { return 0; } + /// Basic peer network protocol version. + unsigned protocolVersion() const; + + /// Register a peer-capability; all new peer connections will have this capability. + template void registerCapability() { m_capabilities[T::name()] = std::shared_ptr(new T(this)); } /// Connect to a peer explicitly. void connect(std::string const& _addr, unsigned short _port = 30303) noexcept; @@ -97,6 +100,9 @@ public: void registerPeer(std::shared_ptr _s); + bool haveCapability(std::string const& _name) const { return m_capabilities.count(_name); } + std::vector caps() const { std::vector ret; for (auto const& i: m_capabilities) ret.push_back(i.first); return ret; } + protected: /// Called when the session has provided us with a new peer we can connect to. void noteNewPeers() {} @@ -124,8 +130,6 @@ protected: bi::tcp::endpoint m_public; KeyPair m_key; - u256 m_networkId; - mutable std::mutex x_peers; mutable std::map> m_peers; // mutable because we flush zombie entries (null-weakptrs) as regular maintenance from a const method. @@ -139,6 +143,8 @@ protected: std::vector m_addresses; std::vector m_peerAddresses; + std::map> m_capabilities; + bool m_accepting = false; }; diff --git a/libethnet/PeerSession.cpp b/libethnet/PeerSession.cpp index a08357dc0..c2b8ba757 100644 --- a/libethnet/PeerSession.cpp +++ b/libethnet/PeerSession.cpp @@ -30,10 +30,9 @@ using namespace eth; #define clogS(X) eth::LogOutputStream(false) << "| " << std::setw(2) << m_socket.native_handle() << "] " -PeerSession::PeerSession(PeerHost* _s, bi::tcp::socket _socket, u256 _rNId, bi::address _peerAddress, unsigned short _peerPort): +PeerSession::PeerSession(PeerHost* _s, bi::tcp::socket _socket, bi::address _peerAddress, unsigned short _peerPort): m_server(_s), m_socket(std::move(_socket)), - m_reqNetworkId(_rNId), m_listenPort(_peerPort), m_rating(0) { @@ -45,6 +44,9 @@ PeerSession::PeerSession(PeerHost* _s, bi::tcp::socket _socket, u256 _rNId, bi:: PeerSession::~PeerSession() { // Read-chain finished for one reason or another. + for (auto& i: m_capabilities) + i.reset(); + try { if (m_socket.is_open()) @@ -65,7 +67,7 @@ bi::tcp::endpoint PeerSession::endpoint() const return bi::tcp::endpoint(); } -bool PeerSession::preInterpret(RLP const& _r) +bool PeerSession::interpret(RLP const& _r) { clogS(NetRight) << _r; switch (_r[0].toInt()) @@ -73,13 +75,12 @@ bool PeerSession::preInterpret(RLP const& _r) case HelloPacket: { m_protocolVersion = _r[1].toInt(); - m_networkId = _r[2].toInt(); - auto clientVersion = _r[3].toString(); - m_caps = _r[4].toInt(); - m_listenPort = _r[5].toInt(); - m_id = _r[6].toHash(); + auto clientVersion = _r[2].toString(); + m_caps = _r[3].toVector(); + m_listenPort = _r[4].toInt(); + m_id = _r[5].toHash(); - clogS(NetMessageSummary) << "Hello: " << clientVersion << "V[" << m_protocolVersion << "/" << m_networkId << "]" << m_id.abridged() << showbase << hex << m_caps << dec << m_listenPort; + clogS(NetMessageSummary) << "Hello: " << clientVersion << "V[" << m_protocolVersion << "]" << m_id.abridged() << showbase << hex << m_caps << dec << m_listenPort; if (m_server->havePeer(m_id)) { @@ -89,7 +90,7 @@ bool PeerSession::preInterpret(RLP const& _r) return false; } - if (m_protocolVersion != m_server->protocolVersion() || m_networkId != m_server->networkId() || !m_id) + if (m_protocolVersion != m_server->protocolVersion() || !m_id) { disconnect(IncompatibleProtocol); return false; @@ -103,7 +104,6 @@ bool PeerSession::preInterpret(RLP const& _r) } m_server->registerPeer(shared_from_this()); - onNewPeer(); break; } case DisconnectPacket: @@ -179,7 +179,10 @@ bool PeerSession::preInterpret(RLP const& _r) } break; default: - return interpret(_r); + for (auto const& i: m_capabilities) + if (i->interpret(_r)) + return true; + return false; } return true; } @@ -326,8 +329,8 @@ void PeerSession::start() prep(s); s.appendList(9) << HelloPacket << m_server->protocolVersion() - << m_server->networkId() << m_server->m_clientVersion + << m_server->caps() << m_server->m_public.port() << m_server->m_key.pub(); sealAndSend(s); @@ -390,7 +393,7 @@ void PeerSession::doRead() else { RLP r(data.cropped(8)); - if (!preInterpret(r)) + if (!interpret(r)) { // error dropped(); diff --git a/libethnet/PeerSession.h b/libethnet/PeerSession.h index f2f4bced7..f51511e04 100644 --- a/libethnet/PeerSession.h +++ b/libethnet/PeerSession.h @@ -42,7 +42,7 @@ class PeerSession: public std::enable_shared_from_this friend class PeerHost; public: - PeerSession(PeerHost* _server, bi::tcp::socket _socket, u256 _rNId, bi::address _peerAddress, unsigned short _peerPort = 0); + PeerSession(PeerHost* _server, bi::tcp::socket _socket, bi::address _peerAddress, unsigned short _peerPort = 0); virtual ~PeerSession(); void start(); @@ -55,9 +55,6 @@ public: bi::tcp::endpoint endpoint() const; ///< for other peers to connect to. protected: - virtual bool interpret(RLP const& _r); - virtual void onNewPeer(); - static RLPStream& prep(RLPStream& _s); void sealAndSend(RLPStream& _s); void sendDestroy(bytes& _msg); @@ -71,7 +68,7 @@ private: void write(); void getPeers(); - bool preInterpret(RLP const& _r); + bool interpret(RLP const& _r); /// @returns true iff the _msg forms a valid message for sending or receiving on the network. static bool checkPacket(bytesConstRef _msg); @@ -88,10 +85,8 @@ private: bytes m_incoming; uint m_protocolVersion; - u256 m_networkId; - u256 m_reqNetworkId; unsigned short m_listenPort; ///< Port that the remote client is listening on for connections. Useful for giving to peers. - uint m_caps; + std::vector m_caps; std::chrono::steady_clock::time_point m_ping; std::chrono::steady_clock::time_point m_connect; @@ -99,6 +94,8 @@ private: uint m_rating; + std::vector> m_capabilities; + bool m_willBeDeleted = false; ///< True if we already posted a deleter on the strand. }; diff --git a/third/alethzero.icns b/third/alethzero.icns new file mode 100644 index 000000000..105afb3d7 Binary files /dev/null and b/third/alethzero.icns differ diff --git a/windows/LibEthereum.vcxproj b/windows/LibEthereum.vcxproj index 95277bbfa..c806de064 100644 --- a/windows/LibEthereum.vcxproj +++ b/windows/LibEthereum.vcxproj @@ -41,15 +41,16 @@ + + + - - - + @@ -100,15 +101,16 @@ + + + - - - +