diff --git a/CMakeLists.txt b/CMakeLists.txt index 21f327425..fe83eb378 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,11 +5,17 @@ set(CMAKE_AUTOMOC ON) cmake_policy(SET CMP0015 NEW) -set(ETH_VERSION 0.2.3) +set(ETH_VERSION 0.2.6) set(ETH_BUILD_TYPE ${CMAKE_BUILD_TYPE}) -set(TARGET_PLATFORM CACHE STRING "linux") +# Default HEADLESS to 0. +set(HEADLESS CACHE BOOL 0) +if ("x${HEADLESS}" STREQUAL "x") + set(HEADLESS 0) +endif () +# Default TARGET_PLATFORM to "linux". +set(TARGET_PLATFORM CACHE STRING "linux") if ("x${TARGET_PLATFORM}" STREQUAL "x") set(TARGET_PLATFORM "linux") endif () @@ -141,4 +147,10 @@ add_subdirectory(secp256k1) add_subdirectory(libethereum) add_subdirectory(test) add_subdirectory(eth) -add_subdirectory(alethzero) +if (NOT HEADLESS) + add_subdirectory(alethzero) +endif () + +unset(HEADLESS CACHE) +#unset(TARGET_PLATFORM CACHE) + diff --git a/TODO b/TODO index 67db641b2..ea09bbc3d 100644 --- a/TODO +++ b/TODO @@ -7,12 +7,21 @@ Crypto stuff: - kFromMessage - Check all the tweak instructions. -Better handling of corrupt blocks. -- Kill DB & restart. - Network: -- Crypto on network. TLS? +- *** Exponential backoff on bad connection. +- NotInChain will be very bad for new peers - it'll run through until the genesis. + - Check how many it has first. +- Crypto on network - use id as public key? - Make work with IPv6 +- Peers rated. + - Useful/useless - new blocks/transactions or useful peers? + - Solid communications? +- Strategy for peer suggestion? + +THREAD-SAFETY +- BlockChain +- TransactionQueue +- State CLI client - Implement CLI option "--help". @@ -23,22 +32,24 @@ General: - Move over to new system. - Remove block chain on protocol change (i.e. store protocol with block chain). - Robustness - Remove aborts - Recover from all exceptions. +- Store version alongside BC DB. +- Better handling of corrupt blocks. + - Kill DB & restart. -### Gav +GUI +- Make address/block chain list model-based, JIT populated. +- Make everything else model-based +- Qt/QML class. -For PoC2: +For PoC3: +- Shared contract acceptence tests. - Use mining state for nonce. - -Network: -- NotInChain will be very bad for new peers - it'll run through until the genesis. - - Check how many it has first. - BUG: need to discard transactions if nonce too old, even when not mining. + ### Marko Ubuntu builds diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 33a3158d7..7f5847009 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -24,7 +24,7 @@ Main::Main(QWidget *parent) : { setWindowFlags(Qt::Window); ui->setupUi(this); - g_logPost = [=](std::string const& s, char const*) { ui->log->addItem(QString::fromStdString(s)); }; + g_logPost = [=](std::string const& s, char const* c) { simpleDebugOut(s, c); ui->log->addItem(QString::fromStdString(s)); }; m_client = new Client("AlethZero"); readSettings(); @@ -142,13 +142,12 @@ void Main::refresh() ui->accounts->addItem(QString("%1 @ %2").arg(formatBalance(i.second).c_str()).arg(asHex(i.first.asArray()).c_str())); ui->transactionQueue->clear(); - for (pair const& i: m_client->transactionQueue().transactions()) + for (pair const& i: m_client->pending()) { - Transaction t(i.second); ui->transactionQueue->addItem(QString("%1 @ %2 <- %3") - .arg(formatBalance(t.value).c_str()) - .arg(asHex(t.receiveAddress.asArray()).c_str()) - .arg(asHex(t.sender().asArray()).c_str()) ); + .arg(formatBalance(i.second.value).c_str()) + .arg(asHex(i.second.receiveAddress.asArray()).c_str()) + .arg(asHex(i.second.sender().asArray()).c_str()) ); } ui->transactions->clear(); diff --git a/eth/main.cpp b/eth/main.cpp index d2399aeb8..37e643b68 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -6,13 +6,13 @@ the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - Foobar is distributed in the hope that it will be useful, + cpp-ethereum is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with Foobar. If not, see . + along with cpp-ethereum. If not, see . */ /** @file main.cpp * @author Gav Wood @@ -352,12 +352,12 @@ int main(int argc, char** argv) cout << "Address: " << endl << asHex(us.address().asArray()) << endl; c.startNetwork(listenPort, remoteHost, remotePort, mode, peers, publicIP, upnp); eth::uint n = c.blockChain().details().number; + if (mining) + c.startMining(); while (true) { - if (c.blockChain().details().number - n >= mining) + if (c.blockChain().details().number - n == mining) c.stopMining(); - else - c.startMining(); this_thread::sleep_for(chrono::milliseconds(100)); } } diff --git a/libethereum/AddressState.cpp b/libethereum/AddressState.cpp index 49adf882a..a61b6b881 100644 --- a/libethereum/AddressState.cpp +++ b/libethereum/AddressState.cpp @@ -6,13 +6,13 @@ the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - Foobar is distributed in the hope that it will be useful, + cpp-ethereum is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with Foobar. If not, see . + along with cpp-ethereum. If not, see . */ /** @file AddressState.cpp * @author Gav Wood diff --git a/libethereum/AddressState.h b/libethereum/AddressState.h index 8b063c3ac..6aec2aaac 100644 --- a/libethereum/AddressState.h +++ b/libethereum/AddressState.h @@ -6,13 +6,13 @@ the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - Foobar is distributed in the hope that it will be useful, + cpp-ethereum is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with Foobar. If not, see . + along with cpp-ethereum. If not, see . */ /** @file AddressState.h * @author Gav Wood diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 146d09f0a..991839557 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -6,13 +6,13 @@ the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - Foobar is distributed in the hope that it will be useful, + cpp-ethereum is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with Foobar. If not, see . + along with cpp-ethereum. If not, see . */ /** @file BlockChain.cpp * @author Gav Wood @@ -168,19 +168,21 @@ void BlockChain::import(bytes const& _block, Overlay const& _db) auto tdIncrease = s.playback(&_block, bi, biParent, biGrandParent, true); td = pd.totalDifficulty + tdIncrease; -#if !NDEBUG +#if PARANOIA checkConsistency(); #endif // All ok - insert into DB - m_details[newHash] = BlockDetails((uint)pd.number + 1, td, bi.parentHash, {}); - m_detailsDB->Put(m_writeOptions, ldb::Slice((char const*)&newHash, 32), (ldb::Slice)eth::ref(m_details[newHash].rlp())); + { + lock_guard l(m_lock); + m_details[newHash] = BlockDetails((uint)pd.number + 1, td, bi.parentHash, {}); + m_details[bi.parentHash].children.push_back(newHash); + } - m_details[bi.parentHash].children.push_back(newHash); + m_detailsDB->Put(m_writeOptions, ldb::Slice((char const*)&newHash, 32), (ldb::Slice)eth::ref(m_details[newHash].rlp())); m_detailsDB->Put(m_writeOptions, ldb::Slice((char const*)&bi.parentHash, 32), (ldb::Slice)eth::ref(m_details[bi.parentHash].rlp())); - m_db->Put(m_writeOptions, ldb::Slice((char const*)&newHash, 32), (ldb::Slice)ref(_block)); -#if !NDEBUG +#if PARANOIA checkConsistency(); #endif } @@ -193,15 +195,15 @@ void BlockChain::import(bytes const& _block, Overlay const& _db) // cnote << "Parent " << bi.parentHash << " has " << details(bi.parentHash).children.size() << " children."; // This might be the new last block... - if (td > m_details[m_lastBlockHash].totalDifficulty) + if (td > details(m_lastBlockHash).totalDifficulty) { m_lastBlockHash = newHash; m_detailsDB->Put(m_writeOptions, ldb::Slice("best"), ldb::Slice((char const*)&newHash, 32)); - clog(BlockChainNote) << " Imported and best. Has" << details(bi.parentHash).children.size() << "siblings."; + clog(BlockChainNote) << " Imported and best. Has" << (details(bi.parentHash).children.size() - 1) << "siblings."; } else { - clog(BlockChainNote) << " Imported but not best (oTD:" << m_details[m_lastBlockHash].totalDifficulty << ", TD:" << td << ")"; + clog(BlockChainNote) << " Imported but not best (oTD:" << details(m_lastBlockHash).totalDifficulty << ", TD:" << td << ")"; } } @@ -230,14 +232,26 @@ bytesConstRef BlockChain::block(h256 _hash) const if (_hash == m_genesisHash) return &m_genesisBlock; - m_db->Get(m_readOptions, ldb::Slice((char const*)&_hash, 32), &m_cache[_hash]); - return bytesConstRef(&m_cache[_hash]); + string d; + m_db->Get(m_readOptions, ldb::Slice((char const*)&_hash, 32), &d); + + { + lock_guard l(m_lock); + swap(m_cache[_hash], d); + return bytesConstRef(&m_cache[_hash]); + } } BlockDetails const& BlockChain::details(h256 _h) const { - auto it = m_details.find(_h); - if (it == m_details.end()) + std::map::const_iterator it; + bool fetchRequired; + { + lock_guard l(m_lock); + it = m_details.find(_h); + fetchRequired = (it == m_details.end()); + } + if (fetchRequired) { std::string s; m_detailsDB->Get(m_readOptions, ldb::Slice((char const*)&_h, 32), &s); @@ -246,8 +260,11 @@ BlockDetails const& BlockChain::details(h256 _h) const // cout << "Not found in DB: " << _h << endl; return NullBlockDetails; } - bool ok; - tie(it, ok) = m_details.insert(make_pair(_h, BlockDetails(RLP(s)))); + { + lock_guard l(m_lock); + bool ok; + tie(it, ok) = m_details.insert(make_pair(_h, BlockDetails(RLP(s)))); + } } return it->second; } diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index f3e7a6693..8ad0cb8b8 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -6,13 +6,13 @@ the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - Foobar is distributed in the hope that it will be useful, + cpp-ethereum is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with Foobar. If not, see . + along with cpp-ethereum. If not, see . */ /** @file BlockChain.h * @author Gav Wood @@ -21,6 +21,7 @@ #pragma once +#include #include "Common.h" #include "AddressState.h" namespace ldb = leveldb; @@ -82,17 +83,14 @@ public: BlockDetails const& details(h256 _hash) const; BlockDetails const& details() const { return details(currentHash()); } - /// Get a given block (RLP format). + /// Get a given block (RLP format). Thread-safe. bytesConstRef block(h256 _hash) const; bytesConstRef block() const { return block(currentHash()); } - /// Get a given block (RLP format). + /// Get a given block (RLP format). Thread-safe. h256 currentHash() const { return m_lastBlockHash; } - /// Get the coinbase address of a given block. - Address coinbaseAddress(h256 _hash) const; - Address coinbaseAddress() const { return coinbaseAddress(currentHash()); } - + /// Get the hash of the genesis block. h256 genesisHash() const { return m_genesisHash; } std::vector> interestQueue() { std::vector> ret; swap(ret, m_interestQueue); return ret; } @@ -105,6 +103,7 @@ private: /// Get fully populated from disk DB. mutable std::map m_details; mutable std::map m_cache; + mutable std::mutex m_lock; /// The queue of transactions that have happened that we're interested in. std::map m_interest; diff --git a/libethereum/BlockInfo.cpp b/libethereum/BlockInfo.cpp index 9b97f250e..c5f00eab4 100644 --- a/libethereum/BlockInfo.cpp +++ b/libethereum/BlockInfo.cpp @@ -6,13 +6,13 @@ the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - Foobar is distributed in the hope that it will be useful, + cpp-ethereum is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with Foobar. If not, see . + along with cpp-ethereum. If not, see . */ /** @file BlockInfo.cpp * @author Gav Wood diff --git a/libethereum/BlockInfo.h b/libethereum/BlockInfo.h index 26d5497a9..28685d2d4 100644 --- a/libethereum/BlockInfo.h +++ b/libethereum/BlockInfo.h @@ -6,13 +6,13 @@ the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - Foobar is distributed in the hope that it will be useful, + cpp-ethereum is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with Foobar. If not, see . + along with cpp-ethereum. If not, see . */ /** @file BlockInfo.h * @author Gav Wood diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 607487f31..08811a188 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -6,13 +6,13 @@ the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - Foobar is distributed in the hope that it will be useful, + cpp-ethereum is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with Foobar. If not, see . + along with cpp-ethereum. If not, see . */ /** @file Client.cpp * @author Gav Wood @@ -42,6 +42,7 @@ Client::Client(std::string const& _clientVersion, Address _us, std::string const // TODO: currently it contains keys for *all* blocks. Make it remove old ones. m_s.sync(m_bc); m_s.sync(m_tq); + m_mined = m_s; m_changed = true; static const char* c_threadName = "eth"; @@ -68,7 +69,7 @@ void Client::startNetwork(short _listenPort, std::string const& _seedHost, short m_net = new PeerServer(m_clientVersion, m_bc, 0, _listenPort, _mode, _publicIP, _upnp); m_net->setIdealPeerCount(_peers); if (_seedHost.size()) - m_net->connect(_seedHost, _port); + connect(_seedHost, _port); } void Client::connect(std::string const& _seedHost, short _port) @@ -111,15 +112,19 @@ void Client::transact(Secret _secret, Address _dest, u256 _amount, u256s _data) void Client::work() { - m_lock.lock(); bool changed = false; // Process network events. // Synchronise block chain with network. // Will broadcast any of our (new) transactions and blocks, and collect & add any of their (new) transactions and blocks. if (m_net) - if (m_net->process(m_bc, m_tq, m_stateDB)) + { + m_net->process(); + + lock_guard l(m_lock); + if (m_net->sync(m_bc, m_tq, m_stateDB)) changed = true; + } // Synchronise state to block chain. // This should remove any transactions on our queue that are included within our state. @@ -127,18 +132,28 @@ void Client::work() // This might mean reverting to an earlier state and replaying some blocks, or, (worst-case: // if there are no checkpoints before our fork) reverting to the genesis block and replaying // all blocks. - // Resynchronise state with block chain & trans - if (m_s.sync(m_bc)) + // Resynchronise state with block chain & trans { - changed = true; - m_mined = m_s; + lock_guard l(m_lock); + if (m_s.sync(m_bc)) + { + changed = true; + m_miningStarted = true; // need to re-commit to mine. + if (!m_doMine) + m_mined = m_s; + } + if (m_mined.sync(m_tq)) + { + changed = true; + m_miningStarted = true; + } } - m_lock.unlock(); if (m_doMine) { if (m_miningStarted) { + lock_guard l(m_lock); m_mined = m_s; m_mined.sync(m_tq); m_mined.commitToMine(m_bc); @@ -155,10 +170,9 @@ void Client::work() if (mineInfo.completed) { // Import block. - m_lock.lock(); + lock_guard l(m_lock); m_bc.attemptImport(m_mined.blockData(), m_stateDB); m_mineProgress.best = 0; - m_lock.unlock(); m_changed = true; m_miningStarted = true; // need to re-commit to mine. } diff --git a/libethereum/Client.h b/libethereum/Client.h index f117d6537..fb5718dbd 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -6,13 +6,13 @@ the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - Foobar is distributed in the hope that it will be useful, + cpp-ethereum is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with Foobar. If not, see . + along with cpp-ethereum. If not, see . */ /** @file Client.h * @author Gav Wood @@ -93,8 +93,8 @@ public: State const& state() const { return m_s; } /// Get the object representing the current canonical blockchain. BlockChain const& blockChain() const { return m_bc; } - /// Get the object representing the transaction queue. - TransactionQueue const& transactionQueue() const { return m_tq; } + /// Get a map containing each of the pending transactions. + std::map const& pending() const { return m_mined.pending(); } void setClientVersion(std::string const& _name) { m_clientVersion = _name; } diff --git a/libethereum/Common.cpp b/libethereum/Common.cpp index 1efb953c3..639f14d47 100644 --- a/libethereum/Common.cpp +++ b/libethereum/Common.cpp @@ -6,13 +6,13 @@ the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - Foobar is distributed in the hope that it will be useful, + cpp-ethereum is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with Foobar. If not, see . + along with cpp-ethereum. If not, see . */ /** @file Common.cpp * @author Gav Wood diff --git a/libethereum/Common.h b/libethereum/Common.h index da6786d5f..20e2d94b6 100644 --- a/libethereum/Common.h +++ b/libethereum/Common.h @@ -6,13 +6,13 @@ the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - Foobar is distributed in the hope that it will be useful, + cpp-ethereum is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with Foobar. If not, see . + along with cpp-ethereum. If not, see . */ /** @file Common.h * @author Gav Wood @@ -67,6 +67,18 @@ using u160Set = std::set; template inline void toBigEndian(T _val, Out& o_out); template inline T fromBigEndian(In const& _bytes); +/// Convert a series of bytes to the corresponding string of hex duplets. +/// @param _w specifies the width of each of the elements. Defaults to two - enough to represent a byte. +/// @example asHex("A\x69") == "4169" +template +std::string asHex(_T const& _data, int _w = 2) +{ + std::ostringstream ret; + for (auto i: _data) + ret << std::hex << std::setfill('0') << std::setw(_w) << (int)(typename std::make_unsigned::type)i; + return ret.str(); +} + template class FixedHash { @@ -97,6 +109,8 @@ public: FixedHash operator&(FixedHash const& _c) const { return FixedHash(*this) &= _c; } FixedHash& operator~() { for (auto i = 0; i < N; ++i) m_data[i] = ~m_data[i]; return *this; } + std::string abridged() const { return asHex(ref().cropped(0, 4)); } + byte& operator[](unsigned _i) { return m_data[_i]; } byte operator[](unsigned _i) const { return m_data[_i]; } @@ -252,18 +266,6 @@ inline bytes asBytes(std::string const& _b) return bytes((byte const*)_b.data(), (byte const*)(_b.data() + _b.size())); } -/// Convert a series of bytes to the corresponding string of hex duplets. -/// @param _w specifies the width of each of the elements. Defaults to two - enough to represent a byte. -/// @example asHex("A\x69") == "4169" -template -std::string asHex(_T const& _data, int _w = 2) -{ - std::ostringstream ret; - for (auto i: _data) - ret << std::hex << std::setfill('0') << std::setw(_w) << (int)(typename std::make_unsigned::type)i; - return ret.str(); -} - /// Trims a given number of elements from the front of a collection. /// Only works for POD element types. template diff --git a/libethereum/Defaults.cpp b/libethereum/Defaults.cpp index 6a09f5e6b..477bb87a7 100644 --- a/libethereum/Defaults.cpp +++ b/libethereum/Defaults.cpp @@ -6,13 +6,13 @@ the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - Foobar is distributed in the hope that it will be useful, + cpp-ethereum is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with Foobar. If not, see . + along with cpp-ethereum. If not, see . */ /** @file Defaults.cpp * @author Gav Wood diff --git a/libethereum/Defaults.h b/libethereum/Defaults.h index b2b617899..ce0c27a42 100644 --- a/libethereum/Defaults.h +++ b/libethereum/Defaults.h @@ -6,13 +6,13 @@ the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - Foobar is distributed in the hope that it will be useful, + cpp-ethereum is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with Foobar. If not, see . + along with cpp-ethereum. If not, see . */ /** @file Defaults.h * @author Gav Wood diff --git a/libethereum/FileSystem.cpp b/libethereum/FileSystem.cpp index 0633f3755..f345641e1 100644 --- a/libethereum/FileSystem.cpp +++ b/libethereum/FileSystem.cpp @@ -6,13 +6,13 @@ the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - Foobar is distributed in the hope that it will be useful, + cpp-ethereum is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with Foobar. If not, see . + along with cpp-ethereum. If not, see . */ /** @file FileSystem.cpp * @authors diff --git a/libethereum/FileSystem.h b/libethereum/FileSystem.h index a08fd6110..a6ce93fb0 100644 --- a/libethereum/FileSystem.h +++ b/libethereum/FileSystem.h @@ -6,13 +6,13 @@ the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - Foobar is distributed in the hope that it will be useful, + cpp-ethereum is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with Foobar. If not, see . + along with cpp-ethereum. If not, see . */ /** @file FileSystem.h * @authors diff --git a/libethereum/MemTrie.cpp b/libethereum/MemTrie.cpp index e0b398208..7d2f9f54c 100644 --- a/libethereum/MemTrie.cpp +++ b/libethereum/MemTrie.cpp @@ -6,13 +6,13 @@ the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - Foobar is distributed in the hope that it will be useful, + cpp-ethereum is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with Foobar. If not, see . + along with cpp-ethereum. If not, see . */ /** @file MemTrie.cpp * @author Gav Wood diff --git a/libethereum/MemTrie.h b/libethereum/MemTrie.h index b1cf93963..d956c1d8a 100644 --- a/libethereum/MemTrie.h +++ b/libethereum/MemTrie.h @@ -6,13 +6,13 @@ the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - Foobar is distributed in the hope that it will be useful, + cpp-ethereum is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with Foobar. If not, see . + along with cpp-ethereum. If not, see . */ /** @file MemTrie.h * @author Gav Wood diff --git a/libethereum/PeerNetwork.cpp b/libethereum/PeerNetwork.cpp index 66d74a8df..935f46a47 100644 --- a/libethereum/PeerNetwork.cpp +++ b/libethereum/PeerNetwork.cpp @@ -6,13 +6,13 @@ the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - Foobar is distributed in the hope that it will be useful, + cpp-ethereum is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with Foobar. If not, see . + along with cpp-ethereum. If not, see . */ /** @file PeerNetwork.cpp * @authors: @@ -45,9 +45,9 @@ using namespace eth; static const int c_protocolVersion = 4; -static const eth::uint c_maxHashes = 256; ///< Maximum number of hashes GetChain will ever send. -static const eth::uint c_maxBlocks = 128; ///< Maximum number of blocks Blocks will ever send. BUG: if this gets too big (e.g. 2048) stuff starts going wrong. -static const eth::uint c_maxBlocksAsk = 2048; ///< Maximum number of blocks we ask to receive in Blocks (when using GetChain). +static const eth::uint c_maxHashes = 32; ///< Maximum number of hashes GetChain will ever send. +static const eth::uint c_maxBlocks = 32; ///< Maximum number of blocks Blocks will ever send. BUG: if this gets too big (e.g. 2048) stuff starts going wrong. +static const eth::uint c_maxBlocksAsk = 256; ///< Maximum number of blocks we ask to receive in Blocks (when using GetChain). // Addresses we will skip during network interface discovery // Use a vector as the list is small @@ -107,6 +107,23 @@ bi::tcp::endpoint PeerSession::endpoint() const return bi::tcp::endpoint(); } +static std::string reasonOf(int _r) +{ + switch (_r) + { + case DisconnectRequested: return "Disconnect was requested."; + case TCPError: return "Low-level TCP communication error."; + case BadProtocol: return "Data format error."; + case UselessPeer: return "Peer had no use for this node."; + case TooManyPeers: return "Peer had too many connections."; + case DuplicatePeer: return "Peer was already connected."; + case WrongGenesis: return "Disagreement over genesis block."; + case IncompatibleProtocol: return "Peer protocol versions are incompatible."; + case ClientQuit: return "Peer is exiting."; + default: return "Unknown reason."; + } +} + // TODO: BUG! 256 -> work out why things start to break with big packet sizes -> g.t. ~370 blocks. bool PeerSession::interpret(RLP const& _r) @@ -123,16 +140,19 @@ bool PeerSession::interpret(RLP const& _r) m_listenPort = _r[5].toInt(); m_id = _r[6].toHash(); - clogS(NetMessageSummary) << "Hello: " << clientVersion << "V[" << m_protocolVersion << "/" << m_networkId << "]" << asHex(m_id.ref().cropped(0, 4)) << showbase << hex << m_caps << dec << m_listenPort; + clogS(NetMessageSummary) << "Hello: " << clientVersion << "V[" << m_protocolVersion << "/" << m_networkId << "]" << m_id.abridged() << showbase << hex << m_caps << dec << m_listenPort; - if (m_server->m_peers.count(m_id) || !m_id) - { - // Already connected. - disconnect(DuplicatePeer); - } - m_server->m_peers[m_id] = shared_from_this(); + if (m_server->m_peers.count(m_id)) + if (auto l = m_server->m_peers[m_id].lock()) + if (l.get() != this && l->isOpen()) + { + // Already connected. + cwarn << "Already have peer id" << m_id.abridged() << "at" << l->endpoint() << "rather than" << endpoint(); + disconnect(DuplicatePeer); + return false; + } - if (m_protocolVersion != c_protocolVersion || m_networkId != m_reqNetworkId) + if (m_protocolVersion != c_protocolVersion || m_networkId != m_reqNetworkId || !m_id) { disconnect(IncompatibleProtocol); return false; @@ -145,15 +165,22 @@ bool PeerSession::interpret(RLP const& _r) return false; } + m_server->m_peers[m_id] = shared_from_this(); + // Grab their block chain off them. { + clogS(NetAllDetail) << "Want chain. Latest:" << m_server->m_latestBlockSent << ", number:" << m_server->m_chain->details(m_server->m_latestBlockSent).number; unsigned count = std::min(c_maxHashes, m_server->m_chain->details(m_server->m_latestBlockSent).number + 1); RLPStream s; prep(s).appendList(2 + count); s << GetChainPacket; auto h = m_server->m_latestBlockSent; for (unsigned i = 0; i < count; ++i, h = m_server->m_chain->details(h).parent) + { + clogS(NetAllDetail) << " " << i << ":" << h; s << h; + } + s << c_maxBlocksAsk; sealAndSend(s); s.clear(); @@ -167,18 +194,7 @@ bool PeerSession::interpret(RLP const& _r) { string reason = "Unspecified"; if (_r[1].isInt()) - switch (_r[1].toInt()) - { - case DisconnectRequested: reason = "Disconnect was requested."; break; - case TCPError: reason = "Low-level TCP communication error."; break; - case BadProtocol: reason = "Data format error."; break; - case UselessPeer: reason = "Peer had no use for this node."; break; - case TooManyPeers: reason = "Peer had too many connections."; break; - case DuplicatePeer: reason = "Peer was already connected."; break; - case WrongGenesis: reason = "Disagreement over genesis block."; break; - case IncompatibleProtocol: reason = "Peer protocol versions are incompatible."; break; - case ClientQuit: reason = "Peer is exiting."; break; - } + reason = reasonOf(_r[1].toInt()); clogS(NetMessageSummary) << "Disconnect (reason: " << reason << ")"; if (m_socket.is_open()) @@ -244,9 +260,10 @@ bool PeerSession::interpret(RLP const& _r) goto CONTINUE; } for (auto i: m_server->m_incomingPeers) - if (i.second == ep) + if (i.second.first == ep) goto CONTINUE; - m_server->m_incomingPeers[id] = ep; + m_server->m_incomingPeers[id] = make_pair(ep, 0); + m_server->m_freePeers.push_back(id); clogS(NetMessageDetail) << "New peer: " << ep << "(" << id << ")"; CONTINUE:; } @@ -340,8 +357,13 @@ bool PeerSession::interpret(RLP const& _r) uint n = latestNumber; for (; n > startNumber; n--, h = m_server->m_chain->details(h).parent) {} - for (uint i = 0; h != parent && n > endNumber && i < count; ++i, --n, h = m_server->m_chain->details(h).parent) + for (uint i = 0; i < count; ++i, --n, h = m_server->m_chain->details(h).parent) { + if (h == parent || n == endNumber) + { + cwarn << "BUG! Couldn't create the reply for GetChain!"; + return true; + } clogS(NetAllDetail) << " " << dec << i << " " << h; s.appendRaw(m_server->m_chain->block(h)); } @@ -443,16 +465,38 @@ void PeerSession::sealAndSend(RLPStream& _s) sendDestroy(b); } +bool PeerSession::checkPacket(bytesConstRef _msg) +{ + if (_msg.size() < 8) + return false; + if (!(_msg[0] == 0x22 && _msg[1] == 0x40 && _msg[2] == 0x08 && _msg[3] == 0x91)) + return false; + uint32_t len = ((_msg[4] * 256 + _msg[5]) * 256 + _msg[6]) * 256 + _msg[7]; + if (_msg.size() != len + 8) + return false; + RLP r(_msg.cropped(8)); + if (r.actualSize() != len) + return false; + return true; +} + void PeerSession::sendDestroy(bytes& _msg) { clogS(NetLeft) << RLP(bytesConstRef(&_msg).cropped(8)); std::shared_ptr buffer = std::make_shared(); swap(*buffer, _msg); - assert((*buffer)[0] == 0x22); + if (!checkPacket(bytesConstRef(&*buffer))) + { + cwarn << "INVALID PACKET CONSTRUCTED!"; + + } ba::async_write(m_socket, ba::buffer(*buffer), [=](boost::system::error_code ec, std::size_t length) { if (ec) + { + cwarn << "Error sending: " << ec.message(); dropped(); + } // cbug << length << " bytes written (EC: " << ec << ")"; }); } @@ -461,11 +505,17 @@ void PeerSession::send(bytesConstRef _msg) { clogS(NetLeft) << RLP(_msg.cropped(8)); std::shared_ptr buffer = std::make_shared(_msg.toBytes()); - assert((*buffer)[0] == 0x22); + if (!checkPacket(_msg)) + { + cwarn << "INVALID PACKET CONSTRUCTED!"; + } ba::async_write(m_socket, ba::buffer(*buffer), [=](boost::system::error_code ec, std::size_t length) { if (ec) + { + cwarn << "Error sending: " << ec.message(); dropped(); + } // cbug << length << " bytes written (EC: " << ec << ")"; }); } @@ -487,26 +537,19 @@ void PeerSession::dropped() void PeerSession::disconnect(int _reason) { + clogS(NetNote) << "Disconnecting (reason:" << reasonOf(_reason) << ")"; if (m_socket.is_open()) { if (m_disconnect == chrono::steady_clock::time_point::max()) { RLPStream s; prep(s); - s.appendList(1) << DisconnectPacket << _reason; + s.appendList(2) << DisconnectPacket << _reason; sealAndSend(s); m_disconnect = chrono::steady_clock::now(); } else - { - if (m_socket.is_open()) - try { - clogS(NetNote) << "Closing " << m_socket.remote_endpoint(); - } catch (...){} - else - clogS(NetNote) << "Remote closed on" << m_socket.native_handle(); - m_socket.close(); - } + dropped(); } } @@ -514,7 +557,7 @@ void PeerSession::start() { RLPStream s; prep(s); - s.appendList(m_server->m_public.port() ? 6 : 5) << HelloPacket << (uint)c_protocolVersion << (uint)m_server->m_requiredNetworkId << m_server->m_clientVersion << (m_server->m_mode == NodeMode::Full ? 0x07 : m_server->m_mode == NodeMode::PeerServer ? 0x01 : 0) << m_server->m_public.port() << m_server->m_key.pub(); + s.appendList(7) << HelloPacket << (uint)c_protocolVersion << (uint)m_server->m_requiredNetworkId << m_server->m_clientVersion << (m_server->m_mode == NodeMode::Full ? 0x07 : m_server->m_mode == NodeMode::PeerServer ? 0x01 : 0) << m_server->m_public.port() << m_server->m_key.pub(); sealAndSend(s); ping(); @@ -528,7 +571,10 @@ void PeerSession::doRead() m_socket.async_read_some(boost::asio::buffer(m_data), [this, self](boost::system::error_code ec, std::size_t length) { if (ec) + { + cwarn << "Error reading: " << ec.message(); dropped(); + } else { try @@ -546,17 +592,31 @@ void PeerSession::doRead() else { uint32_t len = fromBigEndian(bytesConstRef(m_incoming.data() + 4, 4)); - if (m_incoming.size() - 8 < len) + uint32_t tlen = len + 8; + if (m_incoming.size() < tlen) break; // enough has come in. // cerr << "Received " << len << ": " << asHex(bytesConstRef(m_incoming.data() + 8, len)) << endl; - RLP r(bytesConstRef(m_incoming.data() + 8, len)); - if (!interpret(r)) - // error - break; - memmove(m_incoming.data(), m_incoming.data() + len + 8, m_incoming.size() - (len + 8)); - m_incoming.resize(m_incoming.size() - (len + 8)); + auto data = bytesConstRef(m_incoming.data(), tlen); + if (!checkPacket(data)) + { + cerr << "Received " << len << ": " << asHex(bytesConstRef(m_incoming.data() + 8, len)) << endl; + cwarn << "INVALID MESSAGE RECEIVED"; + disconnect(BadProtocol); + } + else + { + RLP r(data.cropped(8)); + if (!interpret(r)) + { + // error + dropped(); + return; + } + } + memmove(m_incoming.data(), m_incoming.data() + tlen, m_incoming.size() - tlen); + m_incoming.resize(m_incoming.size() - tlen); } } doRead(); @@ -765,12 +825,25 @@ void PeerServer::ensureAccepting() } m_accepting = false; - if (m_mode == NodeMode::PeerServer || m_peers.size() < m_idealPeerCount) + if (m_mode == NodeMode::PeerServer || m_peers.size() < m_idealPeerCount * 2) ensureAccepting(); }); } } +void PeerServer::connect(std::string const& _addr, uint _port) noexcept +{ + try + { + connect(bi::tcp::endpoint(bi::address::from_string(_addr), _port)); + } + catch (exception const& e) + { + // Couldn't connect + clog(NetNote) << "Bad host " << _addr << " (" << e.what() << ")"; + } +} + void PeerServer::connect(bi::tcp::endpoint const& _ep) { clog(NetNote) << "Attempting connection to " << _ep; @@ -780,6 +853,15 @@ void PeerServer::connect(bi::tcp::endpoint const& _ep) if (ec) { clog(NetNote) << "Connection refused to " << _ep << " (" << ec.message() << ")"; + for (auto i = m_incomingPeers.begin(); i != m_incomingPeers.end(); ++i) + if (i->second.first == _ep && i->second.second < 3) + { + m_freePeers.push_back(i->first); + goto OK; + } + // for-else + clog(NetNote) << "Giving up."; + OK:; } else { @@ -791,17 +873,10 @@ void PeerServer::connect(bi::tcp::endpoint const& _ep) }); } -bool PeerServer::process(BlockChain& _bc) +bool PeerServer::sync() { bool ret = false; - m_ioService.poll(); - - auto n = chrono::steady_clock::now(); - bool fullProcess = (n > m_lastFullProcess + chrono::seconds(1)); - if (fullProcess) - m_lastFullProcess = n; - - if (fullProcess) + if (isInitialised()) for (auto i = m_peers.begin(); i != m_peers.end();) { auto p = i->second.lock(); @@ -817,10 +892,8 @@ bool PeerServer::process(BlockChain& _bc) return ret; } -bool PeerServer::process(BlockChain& _bc, TransactionQueue& _tq, Overlay& _o) +bool PeerServer::ensureInitialised(BlockChain& _bc, TransactionQueue& _tq) { - bool ret = false; - if (m_latestBlockSent == h256()) { // First time - just initialise. @@ -830,14 +903,16 @@ bool PeerServer::process(BlockChain& _bc, TransactionQueue& _tq, Overlay& _o) for (auto const& i: _tq.transactions()) m_transactionsSent.insert(i.first); m_lastPeersRequest = chrono::steady_clock::time_point::min(); - m_lastFullProcess = chrono::steady_clock::time_point::min(); - ret = true; + return true; } + return false; +} - auto n = chrono::steady_clock::now(); - bool fullProcess = (n > m_lastFullProcess + chrono::seconds(1)); +bool PeerServer::sync(BlockChain& _bc, TransactionQueue& _tq, Overlay& _o) +{ + bool ret = ensureInitialised(_bc, _tq); - if (process(_bc)) + if (sync()) ret = true; if (m_mode == NodeMode::Full) @@ -850,118 +925,118 @@ bool PeerServer::process(BlockChain& _bc, TransactionQueue& _tq, Overlay& _o) m_incomingTransactions.clear(); // Send any new transactions. - if (fullProcess) + for (auto j: m_peers) + if (auto p = j.second.lock()) + { + bytes b; + uint n = 0; + for (auto const& i: _tq.transactions()) + if ((!m_transactionsSent.count(i.first) && !p->m_knownTransactions.count(i.first)) || p->m_requireTransactions) + { + b += i.second; + ++n; + m_transactionsSent.insert(i.first); + } + if (n) + { + RLPStream ts; + PeerSession::prep(ts); + ts.appendList(n + 1) << TransactionsPacket; + ts.appendRaw(b, n).swapOut(b); + seal(b); + p->send(&b); + } + p->m_knownTransactions.clear(); + p->m_requireTransactions = false; + } + + // Send any new blocks. + auto h = _bc.currentHash(); + if (h != m_latestBlockSent) { + // TODO: find where they diverge and send complete new branch. + RLPStream ts; + PeerSession::prep(ts); + ts.appendList(2) << BlocksPacket; + bytes b; + ts.appendRaw(_bc.block(_bc.currentHash())).swapOut(b); + seal(b); for (auto j: m_peers) if (auto p = j.second.lock()) { - bytes b; - uint n = 0; - for (auto const& i: _tq.transactions()) - if ((!m_transactionsSent.count(i.first) && !p->m_knownTransactions.count(i.first)) || p->m_requireTransactions) - { - b += i.second; - ++n; - m_transactionsSent.insert(i.first); - } - if (n) - { - RLPStream ts; - PeerSession::prep(ts); - ts.appendList(n + 1) << TransactionsPacket; - ts.appendRaw(b, n).swapOut(b); - seal(b); + if (!p->m_knownBlocks.count(_bc.currentHash())) p->send(&b); - } - p->m_knownTransactions.clear(); - p->m_requireTransactions = false; + p->m_knownBlocks.clear(); } + } + m_latestBlockSent = h; - // Send any new blocks. - auto h = _bc.currentHash(); - if (h != m_latestBlockSent) - { - // TODO: find where they diverge and send complete new branch. - RLPStream ts; - PeerSession::prep(ts); - ts.appendList(2) << BlocksPacket; - bytes b; - ts.appendRaw(_bc.block(_bc.currentHash())).swapOut(b); - seal(b); - for (auto j: m_peers) - if (auto p = j.second.lock()) + for (int accepted = 1, n = 0; accepted; ++n) + { + accepted = 0; + + if (m_incomingBlocks.size()) + for (auto it = prev(m_incomingBlocks.end());; --it) + { + try { - if (!p->m_knownBlocks.count(_bc.currentHash())) - p->send(&b); - p->m_knownBlocks.clear(); + _bc.import(*it, _o); + it = m_incomingBlocks.erase(it); + ++accepted; + ret = true; } - } - m_latestBlockSent = h; - - for (int accepted = 1, n = 0; accepted; ++n) - { - accepted = 0; - - if (m_incomingBlocks.size()) - for (auto it = prev(m_incomingBlocks.end());; --it) + catch (UnknownParent) { - try - { - _bc.import(*it, _o); - it = m_incomingBlocks.erase(it); - ++accepted; - ret = true; - } - catch (UnknownParent) - { - // Don't (yet) know its parent. Leave it for later. - m_unknownParentBlocks.push_back(*it); - it = m_incomingBlocks.erase(it); - } - catch (...) - { - // Some other error - erase it. - it = m_incomingBlocks.erase(it); - } - - if (it == m_incomingBlocks.begin()) - break; + // Don't (yet) know its parent. Leave it for later. + m_unknownParentBlocks.push_back(*it); + it = m_incomingBlocks.erase(it); } - if (!n && accepted) - { - for (auto i: m_unknownParentBlocks) - m_incomingBlocks.push_back(i); - m_unknownParentBlocks.clear(); + catch (...) + { + // Some other error - erase it. + it = m_incomingBlocks.erase(it); + } + + if (it == m_incomingBlocks.begin()) + break; } + if (!n && accepted) + { + for (auto i: m_unknownParentBlocks) + m_incomingBlocks.push_back(i); + m_unknownParentBlocks.clear(); } + } - // Connect to additional peers - while (m_peers.size() < m_idealPeerCount) + // Connect to additional peers + while (m_peers.size() < m_idealPeerCount) + { + if (m_freePeers.empty()) { - if (m_incomingPeers.empty()) + if (chrono::steady_clock::now() > m_lastPeersRequest + chrono::seconds(10)) { - if (chrono::steady_clock::now() > m_lastPeersRequest + chrono::seconds(10)) - { - RLPStream s; - bytes b; - (PeerSession::prep(s).appendList(1) << GetPeersPacket).swapOut(b); - seal(b); - for (auto const& i: m_peers) - if (auto p = i.second.lock()) - if (p->isOpen()) - p->send(&b); - m_lastPeersRequest = chrono::steady_clock::now(); - } + RLPStream s; + bytes b; + (PeerSession::prep(s).appendList(1) << GetPeersPacket).swapOut(b); + seal(b); + for (auto const& i: m_peers) + if (auto p = i.second.lock()) + if (p->isOpen()) + p->send(&b); + m_lastPeersRequest = chrono::steady_clock::now(); + } - if (!m_accepting) - ensureAccepting(); + if (!m_accepting) + ensureAccepting(); - break; - } - connect(m_incomingPeers.begin()->second); - m_incomingPeers.erase(m_incomingPeers.begin()); + break; } + + auto x = time(0) % m_freePeers.size(); + m_incomingPeers[m_freePeers[x]].second++; + connect(m_incomingPeers[m_freePeers[x]].first); + m_freePeers.erase(m_freePeers.begin() + x); } } @@ -969,29 +1044,26 @@ bool PeerServer::process(BlockChain& _bc, TransactionQueue& _tq, Overlay& _o) // restricts your freedom but does so fairly. and that's the value proposition. // guarantees that everyone else respect the rules of the system. (i.e. obeys laws). - if (fullProcess) - { - // We'll keep at most twice as many as is ideal, halfing what counts as "too young to kill" until we get there. - for (uint old = 15000; m_peers.size() > m_idealPeerCount * 2 && old > 100; old /= 2) - while (m_peers.size() > m_idealPeerCount) - { - // look for worst peer to kick off - // first work out how many are old enough to kick off. - shared_ptr worst; - unsigned agedPeers = 0; - for (auto i: m_peers) - if (auto p = i.second.lock()) - if ((m_mode != NodeMode::PeerServer || p->m_caps != 0x01) && chrono::steady_clock::now() > p->m_connect + chrono::milliseconds(old)) // don't throw off new peers; peer-servers should never kick off other peer-servers. - { - ++agedPeers; - if ((!worst || p->m_rating < worst->m_rating || (p->m_rating == worst->m_rating && p->m_connect > worst->m_connect))) // kill older ones - worst = p; - } - if (!worst || agedPeers <= m_idealPeerCount) - break; - worst->disconnect(TooManyPeers); - } - } + // We'll keep at most twice as many as is ideal, halfing what counts as "too young to kill" until we get there. + for (uint old = 15000; m_peers.size() > m_idealPeerCount * 2 && old > 100; old /= 2) + while (m_peers.size() > m_idealPeerCount) + { + // look for worst peer to kick off + // first work out how many are old enough to kick off. + shared_ptr worst; + unsigned agedPeers = 0; + for (auto i: m_peers) + if (auto p = i.second.lock()) + if ((m_mode != NodeMode::PeerServer || p->m_caps != 0x01) && chrono::steady_clock::now() > p->m_connect + chrono::milliseconds(old)) // don't throw off new peers; peer-servers should never kick off other peer-servers. + { + ++agedPeers; + if ((!worst || p->m_rating < worst->m_rating || (p->m_rating == worst->m_rating && p->m_connect > worst->m_connect))) // kill older ones + worst = p; + } + if (!worst || agedPeers <= m_idealPeerCount) + break; + worst->disconnect(TooManyPeers); + } return ret; } @@ -1033,6 +1105,11 @@ void PeerServer::restorePeers(bytesConstRef _b) { for (auto i: RLP(_b)) { - m_incomingPeers.insert(make_pair((Public)i[2], bi::tcp::endpoint(bi::address_v4(i[0].toArray()), i[1].toInt()))); + auto k = (Public)i[2]; + if (!m_incomingPeers.count(k)) + { + m_incomingPeers.insert(make_pair(k, make_pair(bi::tcp::endpoint(bi::address_v4(i[0].toArray()), i[1].toInt()), 0))); + m_freePeers.push_back(k); + } } } diff --git a/libethereum/PeerNetwork.h b/libethereum/PeerNetwork.h index 9553120fa..9edfe0cb6 100644 --- a/libethereum/PeerNetwork.h +++ b/libethereum/PeerNetwork.h @@ -6,13 +6,13 @@ the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - Foobar is distributed in the hope that it will be useful, + cpp-ethereum is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with Foobar. If not, see . + along with cpp-ethereum. If not, see . */ /** @file PeerNetwork.h * @author Gav Wood @@ -109,6 +109,9 @@ private: void doWrite(std::size_t length); 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); + static RLPStream& prep(RLPStream& _s); void sealAndSend(RLPStream& _s); void sendDestroy(bytes& _msg); @@ -158,14 +161,17 @@ public: ~PeerServer(); /// Connect to a peer explicitly. - void connect(std::string const& _addr, uint _port = 30303) { connect(bi::tcp::endpoint(bi::address::from_string(_addr), _port)); } + void connect(std::string const& _addr, uint _port = 30303) noexcept; void connect(bi::tcp::endpoint const& _ep); /// Sync with the BlockChain. It might contain one of our mined blocks, we might have new candidates from the network. + bool sync(BlockChain& _bc, TransactionQueue&, Overlay& _o); + bool sync(); + /// Conduct I/O, polling, syncing, whatever. /// Ideally all time-consuming I/O is done in a background thread or otherwise asynchronously, but you get this call every 100ms or so anyway. - bool process(BlockChain& _bc, TransactionQueue&, Overlay& _o); - bool process(BlockChain& _bc); + /// This won't touch alter the blockchain. + void process() { if (isInitialised()) m_ioService.poll(); } /// Set ideal number of peers. void setIdealPeerCount(unsigned _n) { m_idealPeerCount = _n; } @@ -192,6 +198,12 @@ private: void populateAddresses(); void determinePublic(std::string const& _publicAddress, bool _upnp); void ensureAccepting(); + + /// Check to see if the network peer-state initialisation has happened. + bool isInitialised() const { return m_latestBlockSent; } + /// Initialises the network peer-state, doing the stuff that needs to be once-only. @returns true if it really was first. + bool ensureInitialised(BlockChain& _bc, TransactionQueue& _tq); + std::map potentialPeers(); std::string m_clientVersion; @@ -214,7 +226,8 @@ private: std::vector m_incomingTransactions; std::vector m_incomingBlocks; std::vector m_unknownParentBlocks; - std::map m_incomingPeers; + std::vector m_freePeers; + std::map> m_incomingPeers; h256 m_latestBlockSent; std::set m_transactionsSent; @@ -222,8 +235,6 @@ private: std::chrono::steady_clock::time_point m_lastPeersRequest; unsigned m_idealPeerCount = 5; - std::chrono::steady_clock::time_point m_lastFullProcess; - std::vector m_addresses; std::vector m_peerAddresses; diff --git a/libethereum/RLP.cpp b/libethereum/RLP.cpp index 54b1f213a..3cc0cb5eb 100644 --- a/libethereum/RLP.cpp +++ b/libethereum/RLP.cpp @@ -6,13 +6,13 @@ the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - Foobar is distributed in the hope that it will be useful, + cpp-ethereum is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with Foobar. If not, see . + along with cpp-ethereum. If not, see . */ /** @file RLP.cpp * @author Gav Wood diff --git a/libethereum/RLP.h b/libethereum/RLP.h index 86163f0af..df047dfb4 100644 --- a/libethereum/RLP.h +++ b/libethereum/RLP.h @@ -6,13 +6,13 @@ the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - Foobar is distributed in the hope that it will be useful, + cpp-ethereum is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with Foobar. If not, see . + along with cpp-ethereum. If not, see . */ /** @file RLP.h * @author Gav Wood @@ -229,14 +229,14 @@ public: /// @returns the data payload. Valid for all types. bytesConstRef payload() const { return isSingleByte() ? m_data.cropped(0, 1) : m_data.cropped(1 + lengthSize()); } + /// @returns the theoretical size of this item. + /// @note Under normal circumstances, is equivalent to m_data.size() - use that unless you know it won't work. + uint actualSize() const; + private: /// Single-byte data payload. bool isSingleByte() const { return !isNull() && m_data[0] < c_rlpDataImmLenStart; } - /// @returns the theoretical size of this item; if it's a list, will require a deep traversal which could take a while. - /// @note Under normal circumstances, is equivalent to m_data.size() - use that unless you know it won't work. - uint actualSize() const; - /// @returns the bytes used to encode the length of the data. Valid for all types. uint lengthSize() const { if (isData() && m_data[0] > c_rlpDataIndLenZero) return m_data[0] - c_rlpDataIndLenZero; if (isList() && m_data[0] > c_rlpListIndLenZero) return m_data[0] - c_rlpListIndLenZero; return 0; } diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 44b51ed15..42242d6d7 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -6,13 +6,13 @@ the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - Foobar is distributed in the hope that it will be useful, + cpp-ethereum is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with Foobar. If not, see . + along with cpp-ethereum. If not, see . */ /** @file State.cpp * @author Gav Wood @@ -274,6 +274,29 @@ void State::resetCurrent() m_state.setRoot(m_currentBlock.stateRoot); } +bool State::cull(TransactionQueue& _tq) const +{ + bool ret = false; + auto ts = _tq.transactions(); + for (auto const& i: ts) + if (!m_transactions.count(i.first)) + try + { + Transaction t(i.second); + if (t.nonce <= transactionsFrom(t.sender())) + { + _tq.drop(i.first); + ret = true; + } + } + catch (...) + { + _tq.drop(i.first); + ret = true; + } + return ret; +} + bool State::sync(TransactionQueue& _tq) { // TRANSACTIONS diff --git a/libethereum/State.h b/libethereum/State.h index 1338e3adc..a75acf131 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -6,13 +6,13 @@ the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - Foobar is distributed in the hope that it will be useful, + cpp-ethereum is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with Foobar. If not, see . + along with cpp-ethereum. If not, see . */ /** @file State.h * @author Gav Wood @@ -119,6 +119,8 @@ public: /// Sync our transactions, killing those from the queue that we have and assimilating those that we don't. bool sync(TransactionQueue& _tq); + /// Like sync but only operate on _tq, killing the invalid/old ones. + bool cull(TransactionQueue& _tq) const; /// Execute a given transaction. void execute(bytes const& _rlp) { return execute(&_rlp); } @@ -158,6 +160,9 @@ public: /// The hash of the root of our state tree. h256 rootHash() const { return m_state.root(); } + /// Get the list of pending transactions. + std::map const& pending() const { return m_transactions; } + /// Finalise the block, applying the earned rewards. void applyRewards(Addresses const& _uncleAddresses); diff --git a/libethereum/Transaction.cpp b/libethereum/Transaction.cpp index 9e0ecd976..893433cc7 100644 --- a/libethereum/Transaction.cpp +++ b/libethereum/Transaction.cpp @@ -6,13 +6,13 @@ the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - Foobar is distributed in the hope that it will be useful, + cpp-ethereum is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with Foobar. If not, see . + along with cpp-ethereum. If not, see . */ /** @file Transaction.cpp * @author Gav Wood diff --git a/libethereum/Transaction.h b/libethereum/Transaction.h index bacd125f8..8a0a86a79 100644 --- a/libethereum/Transaction.h +++ b/libethereum/Transaction.h @@ -6,13 +6,13 @@ the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - Foobar is distributed in the hope that it will be useful, + cpp-ethereum is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with Foobar. If not, see . + along with cpp-ethereum. If not, see . */ /** @file Transaction.h * @author Gav Wood diff --git a/libethereum/TransactionQueue.cpp b/libethereum/TransactionQueue.cpp index f5774dd02..2b908d8b2 100644 --- a/libethereum/TransactionQueue.cpp +++ b/libethereum/TransactionQueue.cpp @@ -6,13 +6,13 @@ the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - Foobar is distributed in the hope that it will be useful, + cpp-ethereum is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with Foobar. If not, see . + along with cpp-ethereum. If not, see . */ /** @file TransactionQueue.cpp * @author Gav Wood diff --git a/libethereum/TransactionQueue.h b/libethereum/TransactionQueue.h index 4028e7eaf..8f2ccaef1 100644 --- a/libethereum/TransactionQueue.h +++ b/libethereum/TransactionQueue.h @@ -6,13 +6,13 @@ the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - Foobar is distributed in the hope that it will be useful, + cpp-ethereum is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with Foobar. If not, see . + along with cpp-ethereum. If not, see . */ /** @file TransactionQueue.h * @author Gav Wood diff --git a/libethereum/TrieCommon.cpp b/libethereum/TrieCommon.cpp index 956fafc29..7fee4af45 100644 --- a/libethereum/TrieCommon.cpp +++ b/libethereum/TrieCommon.cpp @@ -6,13 +6,13 @@ the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - Foobar is distributed in the hope that it will be useful, + cpp-ethereum is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with Foobar. If not, see . + along with cpp-ethereum. If not, see . */ /** @file TrieCommon.cpp * @author Gav Wood diff --git a/libethereum/TrieCommon.h b/libethereum/TrieCommon.h index 57ff54b12..4fdef1aee 100644 --- a/libethereum/TrieCommon.h +++ b/libethereum/TrieCommon.h @@ -6,13 +6,13 @@ the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - Foobar is distributed in the hope that it will be useful, + cpp-ethereum is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with Foobar. If not, see . + along with cpp-ethereum. If not, see . */ /** @file TrieCommon.h * @author Gav Wood diff --git a/libethereum/TrieDB.cpp b/libethereum/TrieDB.cpp index 666069e7b..7160fe5b5 100644 --- a/libethereum/TrieDB.cpp +++ b/libethereum/TrieDB.cpp @@ -6,13 +6,13 @@ the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - Foobar is distributed in the hope that it will be useful, + cpp-ethereum is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with Foobar. If not, see . + along with cpp-ethereum. If not, see . */ /** @file TrieDB.cpp * @author Gav Wood diff --git a/libethereum/TrieDB.h b/libethereum/TrieDB.h index 51ad9b8a8..802162ec8 100644 --- a/libethereum/TrieDB.h +++ b/libethereum/TrieDB.h @@ -6,13 +6,13 @@ the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - Foobar is distributed in the hope that it will be useful, + cpp-ethereum is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with Foobar. If not, see . + along with cpp-ethereum. If not, see . */ /** @file TrieDB.h * @author Gav Wood diff --git a/libethereum/TrieHash.cpp b/libethereum/TrieHash.cpp index 40f63bb58..bbe5c1fe7 100644 --- a/libethereum/TrieHash.cpp +++ b/libethereum/TrieHash.cpp @@ -6,13 +6,13 @@ the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - Foobar is distributed in the hope that it will be useful, + cpp-ethereum is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with Foobar. If not, see . + along with cpp-ethereum. If not, see . */ /** @file TrieHash.cpp * @author Gav Wood diff --git a/libethereum/TrieHash.h b/libethereum/TrieHash.h index a6d4f98cd..bf3b557f2 100644 --- a/libethereum/TrieHash.h +++ b/libethereum/TrieHash.h @@ -6,13 +6,13 @@ the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - Foobar is distributed in the hope that it will be useful, + cpp-ethereum is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with Foobar. If not, see . + along with cpp-ethereum. If not, see . */ /** @file TrieHash.h * @author Gav Wood diff --git a/libethereum/UPnP.cpp b/libethereum/UPnP.cpp index c70177421..9f6ed4e95 100644 --- a/libethereum/UPnP.cpp +++ b/libethereum/UPnP.cpp @@ -6,13 +6,13 @@ the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - Foobar is distributed in the hope that it will be useful, + cpp-ethereum is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with Foobar. If not, see . + along with cpp-ethereum. If not, see . */ /** @file UPnP.cpp * @authors: diff --git a/libethereum/UPnP.h b/libethereum/UPnP.h index f5cdcd576..bb51c96d1 100644 --- a/libethereum/UPnP.h +++ b/libethereum/UPnP.h @@ -6,13 +6,13 @@ the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - Foobar is distributed in the hope that it will be useful, + cpp-ethereum is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with Foobar. If not, see . + along with cpp-ethereum. If not, see . */ /** @file UPnP.h * @authors: diff --git a/test/crypto.cpp b/test/crypto.cpp index 83a735c70..d01ccee08 100644 --- a/test/crypto.cpp +++ b/test/crypto.cpp @@ -6,13 +6,13 @@ the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - Foobar is distributed in the hope that it will be useful, + cpp-ethereum is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with Foobar. If not, see . + along with cpp-ethereum. If not, see . */ /** @file crypto.cpp * @author Gav Wood diff --git a/test/dagger.cpp b/test/dagger.cpp index efc635659..ba2d143ac 100644 --- a/test/dagger.cpp +++ b/test/dagger.cpp @@ -6,13 +6,13 @@ the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - Foobar is distributed in the hope that it will be useful, + cpp-ethereum is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with Foobar. If not, see . + along with cpp-ethereum. If not, see . */ /** @file dagger.cpp * @author Gav Wood diff --git a/test/hexPrefix.cpp b/test/hexPrefix.cpp index cd45cf8dc..a579f3f02 100644 --- a/test/hexPrefix.cpp +++ b/test/hexPrefix.cpp @@ -6,13 +6,13 @@ the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - Foobar is distributed in the hope that it will be useful, + cpp-ethereum is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with Foobar. If not, see . + along with cpp-ethereum. If not, see . */ /** @file main.cpp * @author Gav Wood diff --git a/test/main.cpp b/test/main.cpp index 68daeddb9..356ed70fc 100644 --- a/test/main.cpp +++ b/test/main.cpp @@ -6,13 +6,13 @@ the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - Foobar is distributed in the hope that it will be useful, + cpp-ethereum is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with Foobar. If not, see . + along with cpp-ethereum. If not, see . */ /** @file main.cpp * @author Gav Wood diff --git a/test/peer.cpp b/test/peer.cpp index c2d1de17c..3f97b69da 100644 --- a/test/peer.cpp +++ b/test/peer.cpp @@ -6,13 +6,13 @@ the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - Foobar is distributed in the hope that it will be useful, + cpp-ethereum is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with Foobar. If not, see . + along with cpp-ethereum. If not, see . */ /** @file peer.cpp * @author Gav Wood @@ -56,7 +56,7 @@ int peerTest(int argc, char** argv) for (int i = 0; ; ++i) { this_thread::sleep_for(chrono::milliseconds(100)); - pn.process(ch); + pn.sync(); if (!(i % 10)) pn.pingAll(); } diff --git a/test/rlp.cpp b/test/rlp.cpp index 8e36771a5..744c3d33c 100644 --- a/test/rlp.cpp +++ b/test/rlp.cpp @@ -6,13 +6,13 @@ the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - Foobar is distributed in the hope that it will be useful, + cpp-ethereum is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with Foobar. If not, see . + along with cpp-ethereum. If not, see . */ /** @file rlp.cpp * @author Gav Wood diff --git a/test/state.cpp b/test/state.cpp index 64bd37acc..8cd5f9ff3 100644 --- a/test/state.cpp +++ b/test/state.cpp @@ -6,13 +6,13 @@ the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - Foobar is distributed in the hope that it will be useful, + cpp-ethereum is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with Foobar. If not, see . + along with cpp-ethereum. If not, see . */ /** @file state.cpp * @author Gav Wood diff --git a/test/trie.cpp b/test/trie.cpp index 8fe596a7f..85416c2c1 100644 --- a/test/trie.cpp +++ b/test/trie.cpp @@ -6,13 +6,13 @@ the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - Foobar is distributed in the hope that it will be useful, + cpp-ethereum is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with Foobar. If not, see . + along with cpp-ethereum. If not, see . */ /** @file trie.cpp * @author Gav Wood