diff --git a/Builds/VisualStudio2015/RippleD.vcxproj b/Builds/VisualStudio2015/RippleD.vcxproj index c4c5f47d3a..6eafb27e52 100644 --- a/Builds/VisualStudio2015/RippleD.vcxproj +++ b/Builds/VisualStudio2015/RippleD.vcxproj @@ -3594,6 +3594,12 @@ + + + + True + True + True True @@ -3910,10 +3916,6 @@ True True - - True - True - @@ -3922,30 +3924,6 @@ ..\..\src\websocketpp;%(AdditionalIncludeDirectories) ..\..\src\websocketpp;%(AdditionalIncludeDirectories) - - - - True - True - - - - - True - True - - - - - - - - - - - True - True - diff --git a/Builds/VisualStudio2015/RippleD.vcxproj.filters b/Builds/VisualStudio2015/RippleD.vcxproj.filters index b0fb1b993e..0567e23efc 100644 --- a/Builds/VisualStudio2015/RippleD.vcxproj.filters +++ b/Builds/VisualStudio2015/RippleD.vcxproj.filters @@ -424,12 +424,6 @@ {5DB3CD0B-B361-B301-9562-697CA8A52B68} - - {843C622F-AA52-E6C5-D3EB-D4B6D564B395} - - - {2C910562-8D0A-B115-B829-556779436F2F} - {44780F86-42D3-2F2B-0846-5AEE2CA6D7FE} @@ -4245,6 +4239,12 @@ ripple\shamap + + ripple\test + + + ripple\test\impl + ripple\test\impl @@ -4539,42 +4539,12 @@ ripple\unity - - ripple\unity - ripple\unity ripple\unity - - ripple\unl\tests - - - ripple\unl\tests - - - ripple\unl\tests - - - ripple\unl\tests - - - ripple\unl\tests - - - ripple\unl\tests - - - ripple\unl\tests - - - ripple\unl\tests - - - ripple\unl\tests - ripple\websocket diff --git a/SConstruct b/SConstruct index 8f20670ada..5b707de610 100644 --- a/SConstruct +++ b/SConstruct @@ -884,7 +884,6 @@ def get_classic_sources(toolchain): append_sources(result, *list_sources('src/ripple/rpc', '.cpp')) append_sources(result, *list_sources('src/ripple/shamap', '.cpp')) append_sources(result, *list_sources('src/ripple/test', '.cpp')) - append_sources(result, *list_sources('src/ripple/unl', '.cpp')) if use_shp(toolchain): cc_flags = {'CCFLAGS': ['--system-header-prefix=rocksdb2']} @@ -928,7 +927,6 @@ def get_unity_sources(toolchain): 'src/ripple/unity/rpcx.cpp', 'src/ripple/unity/shamap.cpp', 'src/ripple/unity/test.cpp', - 'src/ripple/unity/unl.cpp', ) if use_shp(toolchain): diff --git a/src/ripple/unl/tests/BasicNetwork.h b/src/ripple/test/BasicNetwork.h similarity index 85% rename from src/ripple/unl/tests/BasicNetwork.h rename to src/ripple/test/BasicNetwork.h index 8095f859d6..a0ddb6ab28 100644 --- a/src/ripple/unl/tests/BasicNetwork.h +++ b/src/ripple/test/BasicNetwork.h @@ -17,8 +17,8 @@ */ //============================================================================== -#ifndef RIPPLE_SIM_BASICNETWORK_H_INCLUDED -#define RIPPLE_SIM_BASICNETWORK_H_INCLUDED +#ifndef RIPPLE_TEST_BASICNETWORK_H_INCLUDED +#define RIPPLE_TEST_BASICNETWORK_H_INCLUDED #include #include @@ -76,7 +76,11 @@ namespace test { of the step, step_one, step_for, and step_until functions to iterate the network, - Peer Concept: + Peer Requirements: + + Peer should be a lightweight type, cheap to copy + and/or move. A good candidate is a simple pointer to + the underlying user defined type in the simulation. Expression Type Requirements ---------- ---- ------------ @@ -87,6 +91,7 @@ namespace test { u == v bool EqualityComparable u < v bool LessThanComparable std::hash

class std::hash is defined for P + ! u bool true if u is not-a-peer */ template class BasicNetwork @@ -96,7 +101,7 @@ public: using clock_type = beast::manual_clock< - std::chrono::system_clock>; + std::chrono::steady_clock>; using duration = typename clock_type::duration; @@ -129,8 +134,8 @@ private: struct msg : by_to_hook, by_from_hook, by_when_hook { - Peer* to; - Peer* from; + Peer to; + Peer from; time_point when; msg (msg const&) = delete; @@ -138,7 +143,8 @@ private: virtual ~msg() = default; virtual void operator()() const = 0; - msg (Peer* from_, Peer* to_, time_point when_) + msg (Peer const& from_, Peer const& to_, + time_point when_) : to(to_), from(from_), when(when_) { } @@ -160,14 +166,14 @@ private: msg_impl (msg_impl const&) = delete; msg_impl& operator= (msg_impl const&) = delete; - msg_impl (Peer* from_, Peer* to_, + msg_impl (Peer const& from_, Peer const& to_, time_point when_, Handler&& h) : msg (from_, to_, when_) , h_ (std::move(h)) { } - msg_impl (Peer* from_, Peer* to_, + msg_impl (Peer const& from_, Peer const& to_, time_point when_, Handler const& h) : msg (from_, to_, when_) , h_ (h) @@ -197,10 +203,10 @@ private: boost::intrusive::make_multiset>::type; - std::unordered_map by_to_; - std::unordered_map by_from_; - by_when_set by_when_; qalloc alloc_; + by_when_set by_when_; + std::unordered_map by_to_; + std::unordered_map by_from_; public: using iterator = @@ -225,14 +231,14 @@ private: template typename by_when_set::iterator - emplace (Peer* from, Peer* to, + emplace (Peer const& from, Peer const& to, time_point when, Handler&& h); void erase (iterator iter); void - remove (Peer* from, Peer* to); + remove (Peer const& from, Peer const& to); }; struct link_type @@ -240,8 +246,7 @@ private: bool inbound; duration delay; - link_type (bool inbound_, - duration delay_) + link_type (bool inbound_, duration delay_) : inbound (inbound_) , delay (delay_) { @@ -249,15 +254,17 @@ private: }; using links_type = - boost::container::flat_map; + boost::container::flat_map; class link_transform; qalloc alloc_; queue_type queue_; - clock_type clock_; + // VFALCO This is an ugly wart, aged containers + // want a non-const reference to a clock. + clock_type mutable clock_; std::mt19937_64 rng_; - std::unordered_map links_; + std::unordered_map links_; public: BasicNetwork (BasicNetwork const&) = delete; @@ -273,6 +280,10 @@ public: qalloc const& alloc() const; + /** Return the clock. */ + clock_type& + clock() const; + /** Return the current network time. @note The epoch is unspecified @@ -311,7 +322,7 @@ public: @return `true` if a new connection was established */ bool - connect (Peer& from, Peer& to, + connect (Peer const& from, Peer const& to, duration const& delay = std::chrono::seconds{0}); /** Break a link. @@ -327,7 +338,7 @@ public: @return `true` if a connection was broken. */ bool - disconnect (Peer& peer1, Peer& peer2); + disconnect (Peer const& peer1, Peer const& peer2); /** Return the range of active links. @@ -335,7 +346,7 @@ public: */ boost::transformed_range< link_transform, links_type> - links (Peer& from); + links (Peer const& from); /** Send a message to a peer. @@ -357,7 +368,8 @@ public: */ template void - send (Peer& from, Peer& to, Function&& f); + send (Peer const& from, Peer const& to, + Function&& f); // Used to cancel timers struct cancel_token; @@ -409,7 +421,7 @@ public: */ template void - bfs (Peer& start, Function&& f); + bfs (Peer const& start, Function&& f); /** Run the network for up to one message. @@ -514,7 +526,7 @@ template template auto BasicNetwork::queue_type::emplace( - Peer* from, Peer* to, time_point when, + Peer const& from, Peer const& to, time_point when, Handler&& h) -> typename by_when_set::iterator { @@ -554,42 +566,26 @@ BasicNetwork::queue_type::erase( template void BasicNetwork::queue_type::remove( - Peer* from, Peer* to) + Peer const& from, Peer const& to) { { auto& list = by_to_[to]; for(auto iter = list.begin(); iter != list.end();) { - if (iter->from == from) - { - auto& m = *iter; - iter = list.erase(iter); - m.~msg(); - alloc_.dealloc(&m, 1); - } - else - { - ++iter; - } + auto& m = *iter++; + if (m.from == from) + erase(by_when_.iterator_to(m)); } } { - auto& list = by_from_[from]; + auto& list = by_to_[from]; for(auto iter = list.begin(); iter != list.end();) { - if (iter->to == to) - { - auto& m = *iter; - iter = list.erase(iter); - m.~msg(); - alloc_.dealloc(&m, 1); - } - else - { - ++iter; - } + auto& m = *iter++; + if (m.from == to) + erase(by_when_.iterator_to(m)); } } } @@ -601,7 +597,7 @@ class BasicNetwork::link_transform { private: BasicNetwork& net_; - Peer& from_; + Peer from_; public: using argument_type = @@ -610,13 +606,14 @@ public: class result_type { public: - Peer& to; + Peer to; bool inbound; result_type (result_type const&) = default; - result_type (BasicNetwork& net, Peer& from, - Peer& to_, bool inbound_) + result_type (BasicNetwork& net, + Peer const& from, Peer const& to_, + bool inbound_) : to(to_) , inbound(inbound_) , net_(net) @@ -630,18 +627,19 @@ public: The connection is removed at both ends. */ - void + bool disconnect() const { - net_.disconnect(from_, to); + return net_.disconnect(from_, to); } private: BasicNetwork& net_; - Peer& from_; + Peer from_; }; - link_transform (BasicNetwork& net, Peer& from) + link_transform (BasicNetwork& net, + Peer const& from) : net_(net) , from_(from) { @@ -651,7 +649,7 @@ public: operator()(argument_type const& v) const { return result_type(net_, from_, - *v.first, v.second.inbound); + v.first, v.second.inbound); } }; @@ -702,6 +700,16 @@ BasicNetwork::alloc() const } template +inline +auto +BasicNetwork::clock() const -> + clock_type& +{ + return clock_; +} + +template +inline auto BasicNetwork::now() const -> time_point @@ -730,16 +738,17 @@ BasicNetwork::rand( template bool BasicNetwork::connect( - Peer& from, Peer& to, duration const& delay) + Peer const& from, Peer const& to, + duration const& delay) { - if (&to == &from) + if (to == from) return false; using namespace std; - if (! links_[&from].emplace(&to, + if (! links_[from].emplace(to, link_type{ false, delay }).second) return false; - auto const result = links_[&to].emplace( - &from, link_type{ true, delay }); + auto const result = links_[to].emplace( + from, link_type{ true, delay }); (void)result; assert(result.second); return true; @@ -748,27 +757,27 @@ BasicNetwork::connect( template bool BasicNetwork::disconnect( - Peer& peer1, Peer& peer2) + Peer const& peer1, Peer const& peer2) { - if (links_[&peer1].erase(&peer2) == 0) + if (links_[peer1].erase(peer2) == 0) return false; auto const n = - links_[&peer2].erase(&peer1); + links_[peer2].erase(peer1); (void)n; assert(n); - queue_.remove(&peer1, &peer2); + queue_.remove(peer1, peer2); return true; } template inline auto -BasicNetwork::links(Peer& from) -> +BasicNetwork::links(Peer const& from) -> boost::transformed_range< link_transform, links_type> { return boost::adaptors::transform( - links_[&from], + links_[from], link_transform{ *this, from }); } @@ -777,12 +786,13 @@ template inline void BasicNetwork::send( - Peer& from, Peer& to, Function&& f) + Peer const& from, Peer const& to, + Function&& f) { using namespace std; auto const iter = - links_[&from].find(&to); - queue_.emplace(&from, &to, + links_[from].find(to); + queue_.emplace(from, to, clock_.now() + iter->second.delay, forward(f)); } @@ -852,14 +862,14 @@ bool BasicNetwork::step_until( time_point const& until) { - // VFALCO This routine needs optimize + // VFALCO This routine needs optimizing if(queue_.empty()) { clock_.set(until); return false; } auto iter = queue_.begin(); - if (iter->when > until) + if(iter->when > until) { clock_.set(until); return true; @@ -882,28 +892,27 @@ bool BasicNetwork::step_for( std::chrono::duration const& amount) { - return step_until( - clock_.now() + amount); + return step_until(now() + amount); } template template void BasicNetwork::bfs( - Peer& start, Function&& f) + Peer const& start, Function&& f) { - std::deque> q; - std::unordered_set seen; - q.emplace_back(&start, 0); - seen.insert(&start); + std::deque> q; + std::unordered_set seen; + q.emplace_back(start, 0); + seen.insert(start); while(! q.empty()) { auto v = q.front(); q.pop_front(); - f(v.second, *v.first); + f(v.second, v.first); for(auto const& link : links_[v.first]) { - auto w = link.first; + auto const& w = link.first; if (seen.count(w) == 0) { q.emplace_back(w, v.second + 1); diff --git a/src/ripple/test/impl/BasicNetwork_test.cpp b/src/ripple/test/impl/BasicNetwork_test.cpp new file mode 100644 index 0000000000..22b3085ba3 --- /dev/null +++ b/src/ripple/test/impl/BasicNetwork_test.cpp @@ -0,0 +1,133 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012-2015 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#include +#include +#include +#include +#include + +namespace ripple { +namespace test { + +class BasicNetwork_test : public beast::unit_test::suite +{ +public: + struct Peer + { + int id; + std::set set; + + Peer (Peer const&) = default; + Peer (Peer&&) = default; + + explicit Peer(int id_) + : id(id_) + { + } + + template + void start(Net& net) + { + using namespace std::chrono_literals; + auto t = net.timer(1s, + [&]{ set.insert(0); }); + if (id == 0) + { + for(auto const& link : net.links(this)) + net.send(this, link.to, + [&, to = link.to] + { + to->receive(net, this, 1); + }); + } + else + { + net.cancel(t); + } + } + + template + void receive(Net& net, Peer* from, int m) + { + set.insert(m); + ++m; + if (m < 5) + { + for(auto const& link : net.links(this)) + net.send(this, link.to, + [&, mm = m, to = link.to] + { + to->receive(net, this, mm); + }); + } + } + }; + + void run() override + { + using namespace std::chrono_literals; + std::vector pv; + pv.emplace_back(0); + pv.emplace_back(1); + pv.emplace_back(2); + BasicNetwork net; + expect(net.rand(0, 1) == 0); + expect(! net.connect(&pv[0], &pv[0])); + expect(net.connect(&pv[0], &pv[1], 1s)); + expect(net.connect(&pv[1], &pv[2], 1s)); + expect(! net.connect(&pv[0], &pv[1])); + std::size_t diameter = 0; + net.bfs(&pv[0], + [&](auto d, Peer*) + { diameter = std::max(d, diameter); }); + expect(diameter == 2); + for(auto& peer : pv) + peer.start(net); + expect(net.step_for(0s)); + expect(net.step_for(1s)); + expect(net.step()); + expect(! net.step()); + expect(! net.step_for(1s)); + net.send(&pv[0], &pv[1], []{}); + net.send(&pv[1], &pv[0], []{}); + expect(net.disconnect(&pv[0], &pv[1])); + expect(! net.disconnect(&pv[0], &pv[1])); + for(;;) + { + auto const links = net.links(&pv[1]); + if(links.empty()) + break; + expect(links[0].disconnect()); + } + expect(pv[0].set == + std::set({0, 2, 4})); + expect(pv[1].set == + std::set({1, 3})); + expect(pv[2].set == + std::set({2, 4})); + net.timer(0s, []{}); + } +}; + +BEAST_DEFINE_TESTSUITE(BasicNetwork, test, ripple) + +} // test +} // ripple + diff --git a/src/ripple/unity/test.cpp b/src/ripple/unity/test.cpp index ed85cb1d8b..788c3dd017 100644 --- a/src/ripple/unity/test.cpp +++ b/src/ripple/unity/test.cpp @@ -48,4 +48,5 @@ #include #include +#include #include diff --git a/src/ripple/unity/unl.cpp b/src/ripple/unity/unl.cpp deleted file mode 100644 index db6b01ff65..0000000000 --- a/src/ripple/unity/unl.cpp +++ /dev/null @@ -1,24 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#include - -#include -#include -#include diff --git a/src/ripple/unl/README.md b/src/ripple/unl/README.md deleted file mode 100644 index 22c7824565..0000000000 --- a/src/ripple/unl/README.md +++ /dev/null @@ -1,62 +0,0 @@ -# Validators - -The Validators module has these responsibilities: - -- Provide an administrative interface for maintaining the list _Source_ - locations. -- Report performance statistics on _Source_ locations -- Report performance statistics on _validators_ provided by _Source_ locations. -- Choose a suitable random subset of observed _Validators_ to become the - _Chosen Validators_ set. -- Update the _Chosen Validators_ set as needed to meet performance requirements. - -## Description - -The consensus process used by the Ripple payment protocol requires that ledger -hashes be signed by _Validators_, producing a _Validation_. The integrity of -the process is mathematically assured when each node chooses a random subset -of _Validators_ to trust, where each _Validator_ is a public verifiable entity -that is independent. Or more specifically, no entity should be in control of -any significant number of _validators_ chosen by each node. - -The list of _Validators_ a node chooses to trust is called the _Chosen -Validators_. The **Validators** module implements business logic to automate the -selection of _Chosen Validators_ by allowing the administrator to provide one -or more trusted _Sources_, from which _Validators_ are learned. Performance -statistics are tracked for these _Validators_, and the module chooses a -suitable subset from which to form the _Chosen Validators_ list. - -The module looks for these criteria to determine suitability: - -- Different validators are not controlled by the same entity. -- Each validator participates in a majority of ledgers. -- A validator does not sign ledgers that fail the consensus process. - -## Terms - - - - - - - - - - - - - - - - - - -
Chosen ValidatorsA set of validators chosen by the Validators module. This is the new term - for what was formerly known as the Unique Node List. -
SourceA trusted source of validator descriptors. Examples: the rippled - configuration file, a local text file, or a trusted URL such - as https://ripple.com/validators.txt. -
ValidationA closed ledger hash signed by a validator. -
ValidatorA publicly verifiable entity which signs ledger hashes with its private - key, and makes its public key available through out of band means. -
diff --git a/src/ripple/unl/tests/Consensus_test.cpp b/src/ripple/unl/tests/Consensus_test.cpp deleted file mode 100644 index dcfa3d1e44..0000000000 --- a/src/ripple/unl/tests/Consensus_test.cpp +++ /dev/null @@ -1,48 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#include -#include -#include -#include -#include -#include -#include - -namespace ripple { -namespace test { - -class Consensus_test : public beast::unit_test::suite -{ -public: - void - run() - { - Sim4::run(log); - //Sim3::run(log); - //Sim2::run(log); - //Sim1::run(log); - pass(); - } -}; - -BEAST_DEFINE_TESTSUITE_MANUAL(Consensus,sim,ripple); - -} -} diff --git a/src/ripple/unl/tests/Network_test.cpp b/src/ripple/unl/tests/Network_test.cpp deleted file mode 100644 index d0bbf90dac..0000000000 --- a/src/ripple/unl/tests/Network_test.cpp +++ /dev/null @@ -1,217 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace ripple { -namespace test { - -class Net_test : public beast::unit_test::suite -{ -public: - struct Ping - { - int hops = 0; - }; - - struct InstantPeer - { - using Peer = InstantPeer; - bool set = false; - int hops = 0; - - InstantPeer() = default; - - template - std::chrono::seconds - delay(Net&) const - { - return {}; - } - - template - void - send (Net& net, Peer& from, Message&& m) - { - net.send (from, *this, - [&, m]() { receive(net, from, m); }); - } - - template - void - receive (Net& net, Peer& from, Ping p) - { - if (set) - return; - ++p.hops; - set = true; - hops = p.hops; - for(auto& link : net.links(*this)) - link.to.send(net, *this, p); - } - }; - - struct LatencyPeer - { - using Peer = LatencyPeer; - int hops = 0; - bool set = false; - - LatencyPeer() = default; - - template - std::chrono::milliseconds - delay(Net& net) const - { - using namespace std::chrono; - return milliseconds(net.rand(5, 200)); - } - - template - void - send (Net& net, Peer& from, Message&& m) - { - net.send (from, *this, - [&, m]() { receive(net, from, m); }); - } - - template - void - receive (Net& net, Peer& from, Ping p) - { - if (set) - return; - ++p.hops; - set = true; - hops = p.hops; - for(auto& link : net.links(*this)) - link.to.send(net, *this, p); - } - }; - - template - struct Network : BasicNetwork - { - static std::size_t const nPeer = 10000; - static std::size_t const nDegree = 10; - - std::vector pv; - std::mt19937_64 rng; - - Network() - { - pv.resize(nPeer); - for (auto& peer : pv) - for (auto i = 0; i < nDegree; ++i) - connect_one(peer); - } - - // Return int in range [0, n) - std::size_t - rand (std::size_t n) - { - return std::uniform_int_distribution< - std::size_t>(0, n - 1)(rng); - } - - // Return int in range [base, base+n) - std::size_t - rand (std::size_t base, std::size_t n) - { - return std::uniform_int_distribution< - std::size_t>(base, base + n - 1)(rng); - } - - // Add one random connection - void - connect_one (Peer& peer) - { - using namespace std::chrono; - for(;;) - if (this->connect(peer, pv[rand(pv.size())], - peer.delay(*this))) - break; - } - }; - - template - void - testDiameter(std::string const& name) - { - using Net = Network; - using namespace std::chrono; - log << name << ":"; - Net net; - net.pv[0].set = true; - net.pv[0].hops = 0; - for(auto& link : net.links(net.pv[0])) - link.to.send(net, net.pv[0], Ping{}); - net.step(); - std::size_t reach = 0; - std::vector dist; - std::vector hops; - std::vector degree; - for(auto& peer : net.pv) - { - hops.resize(std::max( - peer.hops + 1, hops.size())); - ++hops[peer.hops]; - } - net.bfs(net.pv[0], - [&](std::size_t d, Peer& peer) - { - ++reach; - dist.resize(std::max( - d + 1, dist.size())); - ++dist[d]; - auto const n = net.links(peer).size(); - degree.resize(std::max( - n + 1, degree.size())); - ++degree[n]; - }); - log << "reach: " << net.pv.size(); - log << "size: " << reach; - log << "hops: " << seq_string(hops); - log << "dist: " << seq_string(dist); - log << "degree: " << seq_string(degree); - log << "diameter: " << diameter(dist); - log << "hop diam: " << diameter(hops); - } - - void - run() - { - testDiameter("InstantPeer"); - testDiameter("LatencyPeer"); - pass(); - } -}; - -BEAST_DEFINE_TESTSUITE_MANUAL(Net,sim,ripple); - -} -} diff --git a/src/ripple/unl/tests/Sim1.h b/src/ripple/unl/tests/Sim1.h deleted file mode 100644 index 6e5bd95e8b..0000000000 --- a/src/ripple/unl/tests/Sim1.h +++ /dev/null @@ -1,376 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_UNL_SIM1_H_INCLUDED -#define RIPPLE_UNL_SIM1_H_INCLUDED - -#include -#include -#include -#include -#include -#include - -namespace ripple { -namespace test { - -struct Sim1 -{ - struct Config - { - }; - - static int const nPeer = 100; // # of peers - static int const nDegree = 10; // outdegree - static int const nTrial = 10; // number of trials - static int const nRound = 1; // number of rounds - static int const nUNLMin = 20; - static int const nUNLMax = 30; - - using clock_type = std::chrono::system_clock; - - struct Network; - - // A round of consensus. - // Each round consists of a series of votes, - // terminating when a supermajority is reached. - class Round - { - public: - static int const nPercent = 80; // % of agreement - - int id_; - bool consensus_ = false; - std::unordered_map> pos_; - std::size_t count_ = 0; - clock_type::time_point t0_; - - public: - // Create a new round with initial position - Round (int id, bool value, - clock_type::time_point now) - : id_ (id) - , t0_ (now) - { - pos_.emplace(std::make_pair(id, - std::make_pair(0, value))); - } - - // Returns our value - bool - value() const - { - auto const iter = pos_.find(id_); - return iter->second.second; - } - - // Return our position - // This increments the sequence number - std::pair - pos() - { - auto const iter = pos_.find(id_); - return { ++iter->second.first, - iter->second.second }; - } - - // Update a peer's position - // Return `true` if we should relay - bool - receive (int id, - std::size_t seq, bool value) - { - if (id == id_) - return false; - auto const result = pos_.emplace( - std::make_pair(id, - std::make_pair(seq, value))); - if (! result.second && seq <= - result.first->second.first) - return false; - result.first->second.first = seq; - result.first->second.second = value; - return true; - } - - // Update our position - // Return `true` if we changed our position - template - bool - update (UNL const& unl, - clock_type::time_point const& now) - { - if (consensus_) - return false; - ++count_; - std::array v; - v.fill(0); - for(auto const& p : pos_) - if (p.first == id_ || - unl.count(p.first) > 0) - ++v[p.second.second]; - using namespace std::chrono; - auto const iter = pos_.find(id_); - auto const super = - ((unl.size() * nPercent) + 50) / 100; - if (v[0] >= super || v[1] >= super) - consensus_ = true; - // agree to disagree - v[0] += duration_cast( - now - t0_).count() / 250; - if (v[0] >= v[1]) - { - if (iter->second.second != false) - { - iter->second.second = false; - return true; - } - } - else - { - if (iter->second.second != true) - { - iter->second.second = true; - return true; - } - } - return false; - } - }; - - //-------------------------------------------------------------------------- - - class Peer - { - private: - struct PosMsg - { - int id; - std::size_t seq; - bool value; // position - }; - - public: - int id_; - std::set unl_; - Config const& config_; - boost::optional round_; - std::chrono::milliseconds delay_; - Network& net_; - - Peer (int id, Config const& config, - Network& net) - : id_(id) - , config_ (config) - , delay_(std::chrono::milliseconds( - net.rand(5, 50))) - , net_(net) - { - auto const size = net_.rand( - nUNLMin, nUNLMax + 1); - while(unl_.size() < size) - { - unl_.insert(net_.rand(nPeer)); - unl_.erase(id_); - } - } - - // Called to begin the round - void - start() - { - round_.emplace(id_, - !(id_%3), net_.now()); - ++round_->count_; - PosMsg m; - m.id = id_; - std::tie(m.seq, m.value) = - round_->pos(); - broadcast(m); - using namespace std::chrono; - net_.timer(milliseconds( - 700 + net_.rand(700)), - [=]() { timer(); }); - } - - void - receive (Peer& from, PosMsg const& m) - { - if (round_->receive(m.id, - m.seq, m.value)) - relay(from, m); - else - ++net_.dup; - } - - void - timer() - { - if (round_->update(unl_, net_.now())) - { - PosMsg m; - m.id = id_; - std::tie(m.seq, m.value) = - round_->pos(); - broadcast(m); - } - if (round_->consensus_) - return; - using namespace std::chrono; - net_.timer(milliseconds(700), - [=]() { timer(); }); - } - - //---------------------------------------------------------------------- - - // Send a message to this peer - template - void - send (Peer& from, Message&& m) - { - ++net_.sent; - using namespace std::chrono; - net_.send (from, *this, - [&, m]() { receive(from, m); }); - } - - // Broadcast a message to all links - template - void - broadcast (Message const& m) - { - for(auto& link : net_.links(*this)) - link.to.send(*this, m); - } - - // Relay a message to all links - template - void - relay (Peer& from, Message const& m) - { - for(auto& link : net_.links(*this)) - if (&link.to != &from) - link.to.send(*this, m); - } - }; - - //-------------------------------------------------------------------------- - - struct Network : BasicNetwork - { - std::size_t dup = 0; // total dup - std::size_t sent = 0; // total sent - std::vector pv; - - Network (std::size_t seed, - Config const& config) - { - this->rng().seed(seed); - using namespace std; - using namespace std::chrono; - pv.reserve(nPeer); - for(std::size_t id = 0; id < nPeer; ++id) - pv.emplace_back(id, config, *this); - for(auto& peer : pv) - for(int i = 0; i < nDegree; ++i) - connect_one(peer); - } - - // Add one random connection - void - connect_one(Peer& from) - { - using namespace std::chrono; - auto const delay = from.delay_ + - milliseconds(rand(5, 200)); - for(;;) - if (connect(from, - pv[rand(pv.size())], delay)) - break; - } - - template - void - report (std::chrono::milliseconds ms, Log& log) - { - std::array n; - std::vector count; - n.fill(0); - std::size_t consensus = 0; - for(auto const& p : pv) - { - ++n[p.round_->value()]; - ++nth(count, p.round_->count_); - if (p.round_->consensus_) - ++consensus; - } - log << - n[1] << "/" << n[0] << ", " << - "consensus: " << consensus << " in " << - ms.count() << "ms, " << - "sent: " << sent << ", " << - "dup: " << dup << ", " << - "count: " << seq_string(count); - } - - // Execute a round of consensus - template - void - round (Log& log) - { - using namespace std::chrono; - for(int i = 0; i < nPeer; ++i) - pv[i].start(); - auto const t0 = now(); -#if 0 - do - { - report(duration_cast< - milliseconds>(now() - t0), log); - } - while (step_for(milliseconds(50))); -#else - step(); -#endif - report(duration_cast< - milliseconds>(now() - t0), log); - } - }; - - template - static - void - run (Log& log) - { - log << "Sim1" << ":"; - Config config; - for(auto i = 1; i <= nTrial; ++i) - { - Network net(i, config); - for(auto j = 1; j <= nRound; ++j) - net.round(log); - } - } -}; - -} // test -} // ripple - -#endif diff --git a/src/ripple/unl/tests/Sim2.h b/src/ripple/unl/tests/Sim2.h deleted file mode 100644 index 5fb8f0ec0c..0000000000 --- a/src/ripple/unl/tests/Sim2.h +++ /dev/null @@ -1,434 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_UNL_SIM2_H_INCLUDED -#define RIPPLE_UNL_SIM2_H_INCLUDED - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace ripple { -namespace test { - -template -struct Sim2 -{ - struct Config - { - }; - - static int const nPeer = 100; // # of peers - static int const nDegree = 10; // outdegree - static int const nTrial = 1000000; // number of trials - static int const nRound = 1; // number of rounds - static int const nUNLMin = 20; - static int const nUNLMax = 30; - static int const nPos = 10; - - using NodeKey = int; // identifies a consensus participant - using ItemKey = int; // identifies a ballot item - using ItemSet = boost::container::flat_set; - using clock_type = std::chrono::system_clock; - - struct Network; - - struct PosMsg - { - NodeKey id; - std::size_t seq; - ItemSet items; - bool last; - }; - - // A round of consensus. - // Each round consists of a series of votes, - // terminating when a supermajority is reached. - class Round - { - private: - int thresh_ = 50; - - public: - struct Pos - { - ItemSet items; - bool last = false; - std::size_t seq = 0; - }; - - int id_; - bool failed_ = false; - bool consensus_ = false; - std::unordered_map pos_; - std::size_t count_ = 0; - clock_type::time_point t0_; - Log& log_; - - public: - // Create a new round with initial position - Round (NodeKey id, ItemSet&& pos, - clock_type::time_point now, Log& log) - : id_ (id) - , t0_ (now) - , log_ (log) - { - using namespace std; - pos_[id].items = std::move(pos); - } - - std::shared_ptr - posMsg() - { - auto const iter = pos_.find(id_); - auto m = std::make_shared(); - m->id = id_; - m->seq = ++iter->second.seq; - m->items = iter->second.items; - m->last = consensus_; - return m; - } - - ItemSet const& - items() const - { - return pos_.find(id_)->second.items; - } - - // Update a peer's position - // Return `true` if we should relay - bool - receive (PosMsg const& m) - { - if (m.id == id_) - return false; - using namespace std; - auto& pos = pos_[m.id]; - if (m.seq <= pos.seq) - return false; - pos.seq = m.seq; - pos.last = m.last; - pos.items = m.items; - return true; - } - - // Update our position - // Returns `true` if we changed our position - template - bool - update (UNL const& unl, - clock_type::time_point const& now) - { - if (consensus_) - return false; - // count votes per item from unl - boost::container::flat_map< - ItemKey, std::size_t> votes; - for(auto const& pos : pos_) - { - if (! unl.count(pos.first)) - continue; - for(auto const& item : pos.second.items) - { - auto const result = - votes.emplace(item, 1); - if (! result.second) - ++result.first->second; - } - } - // calculate our new position - ItemSet items; - { - auto const needed = - (thresh_ * unl.size() + 50) / 100; - for(auto const& v : votes) - if (v.second >= needed) - items.insert(v.first); - thresh_ += 5; - } - // see if we reached a consensus - std::size_t most = 0; - std::size_t agree = 0; - for(auto const& pos : pos_) - { - if (! unl.count(pos.first)) - continue; - if (pos.second.items == items) - ++agree; - else if (! pos.second.last) - ++most; - } - //{ - auto const needed = - (80 * unl.size() + 50) / 100; - if (agree >= needed) - { - consensus_ = true; - } - else if (agree + most < needed) - { - failed_ = true; - consensus_ = true; - } - //} - if (now.time_since_epoch() >= - std::chrono::seconds(7)) - { - log_ << - "agree = " << agree << - ", most = " << most << - ", needed = " << needed << - ", thresh_ = " << thresh_ << - ", items.size() = " << items.size(); - } - auto const iter = pos_.find(id_); - if (! consensus_ && - iter->second.items == items) - return false; - iter->second.items = items; - return true; - } - }; - - //-------------------------------------------------------------------------- - - class Peer - { - private: - //beast::aged_unordered_map< - - public: - NodeKey id_; - std::set unl_; - Config const& config_; - boost::optional round_; - std::chrono::milliseconds delay_; - Network& net_; - - Peer (int id, Config const& config, - Network& net) - : id_ (id) - , config_ (config) - , delay_ (std::chrono::milliseconds( - net.rand(5, 50))) - , net_ (net) - { - auto const size = 1 + net_.rand( - nUNLMin, nUNLMax + 1); - unl_.insert(id_); // self - while(unl_.size() < size) - unl_.insert(net_.rand(nPeer)); - } - - // Called to begin the round - void - start() - { - { - ItemSet pos; - for(int i = 0; i < nPos; ++i) - if (net_.rand(2)) - pos.insert(i); - round_.emplace(id_, std::move(pos), - net_.now(), net_.log); - } - broadcast(round_->posMsg()); - using namespace std::chrono; - net_.timer(milliseconds( - 700 + net_.rand(700)), - [=]() { timer(); }); - } - - void - receive (Peer& from, - std::shared_ptr const& m) - { - if (round_->receive(*m)) - relay(from, m); - else - ++net_.dup; - } - - void - timer() - { - if (round_->update(unl_, net_.now())) - broadcast(round_->posMsg()); - if (round_->consensus_) - return; - using namespace std::chrono; - net_.timer(milliseconds(700), - [=]() { timer(); }); - } - - //---------------------------------------------------------------------- - - // Send a message to this peer - template - void - send (Peer& from, - std::shared_ptr const& m) - { - ++net_.sent; - net_.send (from, *this, - [&, m]() { receive(from, m); }); - } - - // Broadcast a message to all links - template - void - broadcast (std::shared_ptr< - Message const> const& m) - { - for(auto& link : net_.links(*this)) - link.to.send(*this, m); - } - - // Relay a message to all links - template - void - relay (Peer& from, - std::shared_ptr const& m) - { - for(auto& link : net_.links(*this)) - if (&link.to != &from) - link.to.send(*this, m); - } - }; - - //-------------------------------------------------------------------------- - - struct Network : BasicNetwork - { - std::size_t dup = 0; // total dup - std::size_t sent = 0; // total sent - std::vector pv; - Log& log; - - Network (std::size_t seed, - Config const& config, Log& log_) - : log (log_) - { - this->rng.seed(seed); - using namespace std; - using namespace std::chrono; - pv.reserve(nPeer); - for(std::size_t id = 0; id < nPeer; ++id) - pv.emplace_back(id, config, *this); - for(auto& peer : pv) - for(int i = 0; i < nDegree; ++i) - connect_one(peer); - } - - // Add one random connection - void - connect_one(Peer& from) - { - using namespace std::chrono; - auto const delay = from.delay_ + - milliseconds(this->rand(5, 200)); - for(;;) - if (connect(from, - pv[this->rand(pv.size())], delay)) - break; - } - - void - report (std::size_t n, - std::chrono::milliseconds ms, Log& log) - { - std::size_t failed = 0; - std::size_t consensus = 0; - std::vector hist; - hist.resize(nPos); - for(auto const& p : pv) - { - hist_accum(hist, p.round_->items()); - if (p.round_->consensus_) - ++consensus; - if (p.round_->failed_) - ++failed; - } - log << - ((n > 0) ? "#" + std::to_string(n) + " " : "") << - seq_string(hist, 3) << " " << - "consensus: " << consensus - failed << " in " << - ms.count() << "ms, " << - "sent: " << sent << ", " << - "dup: " << dup; - } - - // Execute a round of consensus - void - round (std::size_t n) - { - using namespace std::chrono; - for(int i = 0; i < nPeer; ++i) - pv[i].start(); - auto const t0 = this->now(); - #if 0 - do - { - report(0, duration_cast< - milliseconds>(now() - t0), log); - } - while (this->step_for(milliseconds(50))); - #else - this->step(); - #endif - report(n, duration_cast< - milliseconds>(this->now() - t0), log); - } - }; - - static - void - run (Log& log) - { - log << "Sim2" << ":"; - Config config; - for(auto i = 1; i <= nTrial; ++i) - { - //log << "Trial " << i; - Network net(i, config, log); - for(auto j = 1; j <= nRound; ++j) - net.round(i); - //log << "\n"; - } - } -}; - -} // test -} // ripple - -#endif - -/* - -Try limiting threshold to 80 -Try slower increase of threshold -Increase UNL sizes - -*/ diff --git a/src/ripple/unl/tests/Sim3.h b/src/ripple/unl/tests/Sim3.h deleted file mode 100644 index ce2fd2d8c0..0000000000 --- a/src/ripple/unl/tests/Sim3.h +++ /dev/null @@ -1,512 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_UNL_SIM3_H_INCLUDED -#define RIPPLE_UNL_SIM3_H_INCLUDED - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace ripple { -namespace test { - -template -struct Sim3 -{ - struct Config - { - int unl; - int peers = 100; - int trial = 100; - }; - - static int const nDegree = 10; // outdegree - static int const nItem = 10; // number of items - static int const nUpdateMS = 700; - - using NodeKey = int; // identifies a consensus participant - using ItemKey = int; // identifies a ballot item - using ItemSet = boost::container::flat_set; - using clock_type = std::chrono::system_clock; - using millis = std::chrono::milliseconds; - - class Network; - - struct PosMsg - { - NodeKey id; - std::size_t seq; - ItemSet items; - bool last; - }; - - // A round of consensus. - // Each round consists of a series of votes, - // terminating when a supermajority is reached. - class Round - { - private: - int thresh_ = 50; - - public: - struct Pos - { - ItemSet items; - bool last = false; - std::size_t seq = 0; - }; - - NodeKey id_; - bool failed_ = false; - bool consensus_ = false; - std::unordered_map pos_; - std::size_t count_ = 0; - clock_type::time_point t0_; - Log& log_; - - public: - // Create a new round with initial position - Round (NodeKey id, ItemSet&& pos, - clock_type::time_point now, Log& log) - : id_ (id) - , t0_ (now) - , log_ (log) - { - using namespace std; - pos_[id].items = std::move(pos); - } - - std::shared_ptr - posMsg() - { - auto const iter = pos_.find(id_); - auto m = std::make_shared(); - m->id = id_; - m->seq = ++iter->second.seq; - m->items = iter->second.items; - m->last = consensus_; - return m; - } - - ItemSet const& - items() const - { - return pos_.find(id_)->second.items; - } - - // Update a peer's position - // Return `true` if we should relay - bool - receive (PosMsg const& m) - { - if (m.id == id_) - return false; - auto& pos = pos_[m.id]; - if (m.seq <= pos.seq) - return false; - pos.seq = m.seq; - pos.last = m.last; - pos.items = m.items; - return true; - } - - // Update our position - // Returns `true` if we changed our position - template - bool - update (UNL const& unl, - clock_type::time_point const& now) - { - if (consensus_) - return false; - // count votes per item from unl - boost::container::flat_map< - ItemKey, std::size_t> votes; - for(auto const& pos : pos_) - { - if (! unl.count(pos.first)) - continue; - for(auto const& item : pos.second.items) - { - auto const result = - votes.emplace(item, 1); - if (! result.second) - ++result.first->second; - } - } - // calculate our new position - ItemSet items; - { - auto const needed = - (thresh_ * unl.size() + 50) / 100; - for(auto const& v : votes) - if (v.second >= needed) - items.insert(v.first); - #if 1 - thresh_ += 5; - #endif - #if 0 - // This causes occasional byzantine - // failure in a large number of nodes - if (thresh_ > 80) - thresh_ = 80; - #endif - } - // see if we reached a consensus - std::size_t most = 0; - std::size_t agree = 0; - for(auto const& pos : pos_) - { - if (! unl.count(pos.first)) - continue; - if (pos.first == id_ || - pos.second.items == items) - ++agree; - else if (! pos.second.last) - ++most; - } - { - auto const needed = - (80 * unl.size() + 50) / 100; - if (agree >= needed) - { - consensus_ = true; - } - else if (agree + most < needed) - { - failed_ = true; - consensus_ = true; - } - } - auto const iter = pos_.find(id_); - if (! consensus_ && - iter->second.items == items) - return false; - iter->second.items = items; - return true; - } - }; - - //-------------------------------------------------------------------------- - - class Peer - { - private: - //beast::aged_unordered_map< - - public: - NodeKey id_; - std::set unl_; - Config const& config_; - boost::optional round_; - millis delay_; - Network& net_; - - Peer (int id, Config const& config, - Network& net) - : id_ (id) - , config_ (config) - , delay_ (millis( - net.rand(5, 50))) - , net_ (net) - { - unl_.insert(id_); // self - while(unl_.size() <= config_.unl) - unl_.insert(net_.rand(config_.peers)); - } - - // Called to begin the round - void - start() - { - { - ItemSet pos; - for(int i = 0; i < nItem; ++i) - if (net_.rand(2)) - pos.insert(i); - round_.emplace(id_, std::move(pos), - net_.now(), net_.log); - } - broadcast(round_->posMsg()); - using namespace std::chrono; - net_.timer(milliseconds( - nUpdateMS + net_.rand(nUpdateMS)), - [=]() { timer(); }); - } - - void - receive (Peer& from, - std::shared_ptr const& m) - { - if (round_->receive(*m)) - relay(from, m); - else - ++net_.dup; - } - - void - timer() - { - if (round_->update(unl_, net_.now())) - broadcast(round_->posMsg()); - if (round_->consensus_) - return; - using namespace std::chrono; - net_.timer(milliseconds(nUpdateMS), - [=]() { timer(); }); - } - - //---------------------------------------------------------------------- - - // Send a message to this peer - template - void - send (Peer& from, - std::shared_ptr const& m) - { - ++net_.sent; - net_.send (from, *this, - [&, m]() { receive(from, m); }); - } - - // Broadcast a message to all links - template - void - broadcast (std::shared_ptr< - Message const> const& m) - { - for(auto& link : net_.links(*this)) - link.to.send(*this, m); - } - - // Relay a message to all links - template - void - relay (Peer& from, - std::shared_ptr const& m) - { - for(auto& link : net_.links(*this)) - if (&link.to != &from) - link.to.send(*this, m); - } - }; - - //-------------------------------------------------------------------------- - - // The result of one round - struct Result - { - std::size_t elapsed; - std::size_t failure = 0; - std::size_t consensus = 0; - std::set sets; - }; - - // The results of several rounds - struct Results - { - std::size_t rounds = 0; - std::size_t perfect = 0; - std::vector elapsed; - std::vector failure; - std::vector consensus; - - void - aggregate (Result const& result) - { - ++rounds; - perfect += result.sets.size() == 1; - elapsed.push_back(result.elapsed); - failure.push_back(result.failure); - consensus.push_back(result.consensus); - } - }; - - struct Report - { - std::size_t perfect; - std::size_t elapsed_min; - std::size_t elapsed_max; - - Report (Results& results, Config const& config) - { - perfect = results.perfect; -#if 0 - std::sort( - results.elapsed.begin(), results.elapsed.end()); - std::sort( - results.consensus.begin(), results.consensus.end(), - std::greater{}); -#endif - elapsed_min = results.elapsed.front(); - elapsed_max = results.elapsed.back(); - } - }; - - class Network : public BasicNetwork - { - private: - Config const& config_; - - public: - std::size_t dup = 0; // total dup - std::size_t sent = 0; // total sent - std::vector pv; - Log& log; - - Network (std::size_t seed, - Config const& config, Log& log_) - : config_ (config) - , log (log_) - { - this->rng.seed(seed); - using namespace std; - using namespace std::chrono; - pv.reserve(config.peers); - for(std::size_t id = 0; id < config_.peers; ++id) - pv.emplace_back(id, config, *this); - for(auto& peer : pv) - for(int i = 0; i < nDegree; ++i) - connect_one(peer); - } - - // Add one random connection - void - connect_one(Peer& from) - { - using namespace std::chrono; - auto const delay = from.delay_ + - milliseconds(this->rand(5, 200)); - for(;;) - if (connect(from, - pv[this->rand(pv.size())], delay)) - break; - } - - // Execute one round of consensus - Result - run() - { - Result result; - using namespace std::chrono; - for(int i = 0; i < config_.peers; ++i) - pv[i].start(); - auto const t0 = this->now(); - this->step(); - result.elapsed = duration_cast< - millis>(this->now() - t0).count(); - for(auto const& p : pv) - { - if (p.round_->failed_) - ++result.failure; - if (p.round_->consensus_) - { - ++result.consensus; - result.sets.insert(p.round_->items()); - } - } - return result; - } - }; - - static - void - report (Log& log, Result const& result, - Config const& config) - { - log << - result.elapsed << "\t" << - result.failure << "\t" << - result.consensus << "\t" << - result.sets.size(); - ; - } - - static - void - report (Log& log, Report const& report, - Config const& config) - { - log << - report.perfect << "\t" << - report.elapsed_min << "\t" << - report.elapsed_max << "\t" << - config.peers << "\t" << - config.unl << "\t" << - config.trial - ; - } - - static - void - run (Log& log) - { - log << "Sim3" << ":"; -#if 1 - log << - "perfect\t" << - "elapsed_min\t" << - "elapsed_max\t" << - "peers\t" << - "unl\t" << - "trial\t" - ; -#else - log << - "elapsed\t" << - "failure\t" << - "consensus\t" << - "positions\t" - ; -#endif - for (int unl = 40; unl > 5; --unl) - { - Results results; - Config config; - config.unl = unl; - for(auto i = 1; i <= config.trial; ++i) - { - Network net(i, config, log); - //report(log, net.run(), config); - results.aggregate(net.run()); - } - report(log, Report(results, config), config); - } - } -}; - -} // test -} // ripple - -#endif - -/* - -Try limiting threshold to 80 -Try slower increase of threshold -Increase UNL sizes - -*/ diff --git a/src/ripple/unl/tests/Sim4.h b/src/ripple/unl/tests/Sim4.h deleted file mode 100644 index 7504db591f..0000000000 --- a/src/ripple/unl/tests/Sim4.h +++ /dev/null @@ -1,607 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_UNL_SIM4_H_INCLUDED -#define RIPPLE_UNL_SIM4_H_INCLUDED - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace ripple { -namespace test { - -template -struct Sim4 -{ - struct Config - { - int unl = 20; - int peers = 100; - int trials = 100; - int rounds = 1; - }; - - static int const nDegree = 10; // outdegree - static int const nItem = 10; // number of items - enum - { - nUpdateMS = 700 - }; - - using NodeKey = int; // identifies a consensus participant - using ItemKey = int; // identifies a ballot item - using ItemSet = boost::container::flat_set; - using clock_type = std::chrono::system_clock; - using millis = std::chrono::milliseconds; - - struct Network; - - struct TxMsg - { - ItemKey id; - }; - - struct PosMsg - { - NodeKey id; - std::size_t ord; - std::size_t seq; - ItemSet items; - bool last; - }; - - // A pool of items - // This is the equivalent of the "open ledger" - class Pool - { - private: - ItemSet items_; - - public: - // Insert an item into the pool - void - insert (ItemKey id) - { - items_.insert(id); - } - - // Returns the items in the pool - ItemSet const& - items() const - { - return items_; - } - }; - - // A round of consensus. - // Each round consists of a series of votes, - // terminating when a supermajority is reached. - struct Round - { - struct Pos - { - ItemSet items; - bool last = false; - std::size_t seq = 0; - }; - - int id_; - Log& log_; - std::size_t ord_; - clock_type::time_point t0_; - - int thresh_ = 50; - bool failed_ = false; - bool consensus_ = false; - std::size_t count_ = 0; - std::unordered_map pos_; - - // Create a new round with initial position - Round (NodeKey id, std::size_t ord, - ItemSet const& items, - clock_type::time_point now, - Log& log) - : id_ (id) - , log_ (log) - , ord_ (ord) - , t0_ (now) - { - using namespace std; - pos_[id].items = items; - } - - std::shared_ptr - posMsg() - { - auto const iter = pos_.find(id_); - auto m = std::make_shared(); - m->id = id_; - m->seq = ++iter->second.seq; - m->items = iter->second.items; - m->last = consensus_; - return m; - } - - ItemSet const& - items() const - { - return pos_.find(id_)->second.items; - } - - // Update a peer's position - // Return `true` if we should relay - bool - receive (PosMsg const& m) - { - if (m.id == id_) - return false; - using namespace std; - auto& pos = pos_[m.id]; - if (m.seq <= pos.seq) - return false; - pos.seq = m.seq; - pos.last = m.last; - pos.items = m.items; - return true; - } - - // Update our position - // Returns `true` if we changed our position - template - bool - update (UNL const& unl, - clock_type::time_point const& now) - { - if (consensus_) - return false; - // count votes per item from unl - boost::container::flat_map< - ItemKey, std::size_t> votes; - for(auto const& pos : pos_) - { - if (! unl.count(pos.first)) - continue; - for(auto const& item : pos.second.items) - { - auto const result = - votes.emplace(item, 1); - if (! result.second) - ++result.first->second; - } - } - // calculate our new position - ItemSet items; - { - auto const needed = - (thresh_ * unl.size() + 50) / 100; - for(auto const& v : votes) - if (v.second >= needed) - items.insert(v.first); - thresh_ += 5; - } - // see if we reached a consensus - std::size_t most = 0; - std::size_t agree = 0; - for(auto const& pos : pos_) - { - if (! unl.count(pos.first)) - continue; - if (pos.first == id_ || - pos.second.items == items) - ++agree; - else if (! pos.second.last) - ++most; - } - { - auto const needed = - (80 * unl.size() + 50) / 100; - if (agree >= needed) - { - consensus_ = true; - } - else if (agree + most < needed) - { - failed_ = true; - consensus_ = true; - } - } - auto const iter = pos_.find(id_); - if (! consensus_ && - iter->second.items == items) - return false; - iter->second.items = items; - return true; - } - }; - - //-------------------------------------------------------------------------- - - struct Peer - { - //beast::aged_unordered_map< - - NodeKey id_; - std::size_t ord_ = 0; - std::set unl_; - Config const& config_; - boost::optional round_; - millis delay_; - Network& net_; - Pool pool_; - std::unordered_map> item_tab_; - - Peer (int id, Config const& config, - Network& net) - : id_ (id) - , config_ (config) - , delay_ (millis( - net.rand(5, 50))) - , net_ (net) - { - unl_.insert(id_); // self - while(unl_.size() <= config_.unl) - unl_.insert(net_.rand(config_.peers)); - } - - void - init() - { - net_.timer(millis(2000), - [&]() { on_close(); }); - } - - // Broadcast a new item - void - inject (ItemKey id) - { - item_tab_[id].insert(this); - TxMsg m; - m.id = id; - broadcast(m); - } - - // Closes the pool and starts the round - void - on_close() - { - round_.emplace(id_, ++ord_, pool_.items(), - net_.now(), net_.log); - broadcast(round_->posMsg()); - net_.timer(millis( - nUpdateMS + net_.rand(nUpdateMS)), - [=]() { on_update(); }); - } - - // Updates our position during the round - void - on_update() - { - if (round_->update(unl_, net_.now())) - broadcast(round_->posMsg()); - if (round_->consensus_) - return; - using namespace std::chrono; - net_.timer(millis(nUpdateMS), - [=]() { on_update(); }); - } - - // Called when a transaction is received - void - receive (Peer& from, TxMsg const& m) - { - auto& seen = item_tab_[m.id]; - if(! seen.empty()) - { - ++net_.dup; - return; - } - seen.insert(&from); - net_.timer(net_.now() + - millis(net_.rand(200, 600)), - [&, m]() - { - pool_.insert(m.id); - for(auto& link : net_.links(*this)) - if (seen.count(&link.to) == 0) - link.to.send(*this, m); - }); - } - - // Called when a position is received - void - receive (Peer& from, - std::shared_ptr const& m) - { - if (round_->receive(*m)) - relay(from, m); - else - ++net_.dup; - } - - //---------------------------------------------------------------------- - - // Send a message to this peer - template - void - send (Peer& from, Message const& m) - { - ++net_.sent; - net_.send (from, *this, - [&, m]() { receive(from, m); }); - } - - // Send a message to this peer - template - void - send (Peer& from, - std::shared_ptr const& m) - { - ++net_.sent; - net_.send (from, *this, - [&, m]() { receive(from, m); }); - } - - // Broadcast a message to all links - template - void - broadcast (std::shared_ptr< - Message const> const& m) - { - for(auto& link : net_.links(*this)) - link.to.send(*this, m); - } - - // Broadcast a message to all links - template - void - broadcast (Message const& m) - { - for(auto& link : net_.links(*this)) - link.to.send(*this, m); - } - - // Relay a message to all links - template - void - relay (Peer& from, - std::shared_ptr const& m) - { - for(auto& link : net_.links(*this)) - if (&link.to != &from) - link.to.send(*this, m); - } - - // Relay a message to all links - template - void - relay (Peer& from, Message const& m) - { - for(auto& link : net_.links(*this)) - if (&link.to != &from) - link.to.send(*this, m); - } - }; - - //-------------------------------------------------------------------------- - - // The result of one round - struct Result - { - std::size_t elapsed; - std::size_t failure = 0; - std::size_t consensus = 0; - std::set sets; - }; - - // The results of several rounds - struct Results - { - std::size_t rounds = 0; - std::size_t perfect = 0; - std::vector elapsed; - std::vector failure; - std::vector consensus; - - void - aggregate (Result const& result) - { - ++rounds; - perfect += result.sets.size() == 1; - elapsed.push_back(result.elapsed); - failure.push_back(result.failure); - consensus.push_back(result.consensus); - } - }; - - struct Report - { - std::size_t perfect; - std::size_t elapsed_min; - std::size_t elapsed_max; - - Report (Results& results, Config const& config) - { - perfect = results.perfect; -#if 0 - std::sort( - results.elapsed.begin(), results.elapsed.end()); - std::sort( - results.consensus.begin(), results.consensus.end(), - std::greater{}); -#endif - elapsed_min = results.elapsed.front(); - elapsed_max = results.elapsed.back(); - } - }; - - class Network : public BasicNetwork - { - private: - Config const& config_; - ItemKey seq_ = 0; - - public: - std::size_t dup = 0; // total dup - std::size_t sent = 0; // total sent - std::vector pv; - Log& log; - - Network (std::size_t seed, - Config const& config, Log& log_) - : config_ (config) - , log (log_) - { - this->rng().seed(seed); - using namespace std; - using namespace std::chrono; - pv.reserve(config.peers); - for(std::size_t id = 0; id < config_.peers; ++id) - pv.emplace_back(id, config, *this); - for(auto& peer : pv) - for(int i = 0; i < nDegree; ++i) - connect_one(peer); - } - - // Add one random connection - void - connect_one(Peer& from) - { - using namespace std::chrono; - auto const delay = from.delay_ + - milliseconds(this->rand(5, 200)); - for(;;) - if (this->connect(from, - pv[this->rand(pv.size())], delay)) - break; - } - - void - report (std::size_t n, - millis ms, Log& log) - { - std::size_t failed = 0; - std::size_t consensus = 0; - std::set unique; - for(auto const& p : pv) - { - if (! p.round_) - continue; - unique.insert(p.round_->items()); - if (p.round_->consensus_) - ++consensus; - if (p.round_->failed_) - ++failed; - } - log << - n << "\t" << - unique.size() << "\t" << - consensus << "\t" << - failed << "\t" << - ms.count() << "ms\t" << - sent << "\t" << - dup; - } - - // Inject a random item - void - inject() - { - pv[this->rand(pv.size())].inject(++seq_); - } - - void - on_timer() - { - inject(); - if(this->now().time_since_epoch() <= - std::chrono::seconds(4)) - this->timer(millis(250), - [&]() { on_timer(); }); - } - - // Execute a round of consensus - void - run (std::size_t n) - { - using namespace std::chrono; - for(int i = 0; i < config_.peers; ++i) - pv[i].init(); - inject(); - this->timer(millis(250), - [&]() { on_timer(); }); - auto const t0 = this->now(); - #if 0 - do - { - report(n, duration_cast< - milliseconds>(now() - t0), log); - } - while (this->step_for(milliseconds(50))); - #else - this->step(); - #endif - report(n, duration_cast< - milliseconds>(this->now() - t0), log); - } - }; - - static - void - run (Log& log) - { - log << "Sim4" << ":"; - log << - "n\t" << - "unique\t" << - "consensus\t" << - "failed\t" << - "time\t" << - "sent\t" << - "dup"; - Config config; - for(auto i = 1; i <= config.trials; ++i) - { - Network net(i, config, log); - for(auto j = 1; j <= config.rounds; ++j) - net.run(i); - } - } -}; - -} // test -} // ripple - -#endif - -/* - -Try limiting threshold to 80 -Try slower increase of threshold -Increase UNL sizes - -*/ diff --git a/src/ripple/unl/tests/SlotPeer_test.cpp b/src/ripple/unl/tests/SlotPeer_test.cpp deleted file mode 100644 index 609a0785cd..0000000000 --- a/src/ripple/unl/tests/SlotPeer_test.cpp +++ /dev/null @@ -1,382 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace ripple { -namespace test { - -struct Config -{ - static int const nStep = 100; // # of steps - static int const nPeer = 1001; // # of peers - static int const nDegree = 10; // outdegree - static int const nChurn = 5; // churn per step - static int const nValidator = 100; // # of validators - static int const nTrusted = 5; // # of trusted validators - static int const nAllowed = 5; // # of allowed validators - static int const nTrustedUplinks = 3; // # of uplinks for trusted - static int const nAllowedUplinks = 1; // # of uplinks for allowed - - class Network; - class Peer; - - struct Policy - { - struct Slot - { - std::unordered_set up; - std::unordered_set down; - }; - - std::unordered_set allowed; - std::unordered_map slots; - - // Returns a slot or nullptr - template - Slot* - get (int id, Peer& from, - Links const& links) - { - auto iter = slots.find(id); - if (iter != slots.end()) - return &iter->second; - if (id > nTrusted && - allowed.size() >= nAllowed) - return nullptr; - if (id > nTrusted) - allowed.insert(id); - auto& slot = slots[id]; - for(auto& link : links) - if (&link.to != &from) - slot.down.insert(&link.to); - return &slot; - } - - // Returns `true` accepting Peer as uplink - bool - uplink (int id, Peer& from, Slot& slot) - { - if (slot.up.count(&from) > 0) - return true; - if (id <= nTrusted) - { - if (slot.up.size() >= nTrustedUplinks) - return false; - slot.up.insert(&from); - return true; - } - if (slot.up.size() >= nAllowedUplinks) - return false; - slot.up.insert(&from); - return true; - } - - // Squelch a downlink - void - squelch (int id, Peer& from) - { - auto iter = slots.find(id); - if (iter == slots.end()) - return; - iter->second.down.erase(&from); - } - - // Unsquelch a downlink - void - unsquelch (int id, Peer& from) - { - auto iter = slots.find(id); - if (iter == slots.end()) - return; - iter->second.down.insert(&from); - } - - // Called when we hear a validation - void - heard (int id, int seq) - { - } - }; - - //-------------------------------------------------------------------------- - - class Peer - { - private: - Network& net_; - - public: - struct ValMsg - { - int id; - int seq; - ValMsg (int id_, int seq_) - : id(id_), seq(seq_) { } - }; - - struct SquelchMsg - { - int id; - SquelchMsg (int id_) - : id(id_) { } - }; - - struct UnsquelchMsg - { - int id; - UnsquelchMsg (int id_) - : id(id_) { } - }; - - int id = 0; // validator id or 0 - int seq = 0; - Policy policy; - std::map seen; - std::chrono::milliseconds delay; - - Peer (int id_, Network& net) - : net_ (net) - , id (id_) - , delay (std::chrono::milliseconds( - net.rand(5, 50))) - { - } - - // Called when a peer disconnects - void - disconnect (Peer& from) - { - std::vector v; - for(auto const& item : policy.slots) - if (item.second.up.count(&from) > 0) - v.push_back(item.first); - for(auto id : v) - for(auto& link : net_.links(*this)) - link.to.send(*this, - UnsquelchMsg{ id }); - } - - // Broadcast a validation - void - broadcast() - { - broadcast(ValMsg{ id, ++seq }); - } - - // Receive a validation - void - receive (Peer& from, ValMsg const& m) - { - if (m.id == id) - { - ++nth(net_.dup, m.id - 1); - return from.send(*this, - SquelchMsg(m.id)); - } - auto slot = policy.get( - m.id, from, net_.links(*this)); - if (! slot || ! policy.uplink( - m.id, from, *slot)) - return from.send(*this, - SquelchMsg(m.id)); - auto& last = seen[m.id]; - if (last >= m.seq) - { - ++nth(net_.dup, m.id - 1); - return; - } - last = m.seq; - policy.heard(m.id, m.seq); - ++nth(net_.heard, m.id - 1); - for(auto peer : slot->down) - peer->send(*this, m); - } - - // Receive a squelch message - void - receive (Peer& from, SquelchMsg const& m) - { - policy.squelch (m.id, from); - } - - // Receive an unsquelch message - void - receive (Peer& from, UnsquelchMsg const& m) - { - policy.unsquelch (m.id, from); - } - - //---------------------------------------------------------------------- - - // Send a message to this peer - template - void - send (Peer& from, Message&& m) - { - ++net_.sent; - using namespace std::chrono; - net_.send (from, *this, - [&, m]() { receive(from, m); }); - } - - // Broadcast a message to all links - template - void - broadcast (Message const& m) - { - for(auto& link : net_.links(*this)) - link.to.send(*this, m); - } - }; - - //-------------------------------------------------------------------------- - - class Network : public BasicNetwork - { - public: - std::size_t sent = 0; - std::vector pv; - std::vector heard; - std::vector dup; - - Network() - { - using namespace std; - using namespace std::chrono; - pv.reserve(nPeer); - for(std::size_t id = 1; id <=nPeer; ++id) - pv.emplace_back( - id <= nValidator ? id : 0, *this); - for (auto& peer : pv) - for (auto i = 0; i < nDegree; ++i) - connect_one(peer); - } - - // Add one random connection - void - connect_one(Peer& from) - { - using namespace std::chrono; - auto const delay = from.delay + - milliseconds(rand(5, 200)); - for(;;) - if (connect(from, - pv[rand(pv.size())], delay)) - break; - } - - // Redo one random connection - void - churn_one() - { - auto& peer = pv[rand(pv.size())]; - auto const link = links(peer)[ - rand(links(peer).size())]; - link.disconnect(); - link.to.disconnect(peer); - peer.disconnect(link.to); - // preserve outbound counts, otherwise - // the outdegree invariant will break. - if (link.inbound) - connect_one (link.to); - else - connect_one (peer); - } - - // Redo several random connections - void - churn() - { - auto n = nChurn; - while(n--) - churn_one(); - } - - // Iterate the network - template - void - run (Log& log) - { - for (int i = nStep; i--;) - { - churn(); - for(int j = 0; j < nValidator; ++j) - pv[j].broadcast(); - step(); - } - } - }; -}; - -//------------------------------------------------------------------------------ - -class SlotPeer_test : public beast::unit_test::suite -{ -public: - void - test(std::string const& name) - { - log << name << ":"; - using Peer = Config::Peer; - using Network = Config::Network; - Network net; - net.run(log); - std::size_t reach = 0; - std::vector dist; - std::vector degree; - net.bfs(net.pv[0], - [&](std::size_t d, Peer& peer) - { - ++reach; - ++nth(dist, d); - ++nth(degree, net.links(peer).size()); - }); - log << "reach: " << net.pv.size(); - log << "size: " << reach; - log << "sent: " << net.sent; - log << "diameter: " << diameter(dist); - log << "dist: " << seq_string(dist); - log << "heard: " << seq_string(net.heard); - log << "dup: " << seq_string(net.dup); - log << "degree: " << seq_string(degree); - } - - void - run() - { - test("SlotPeer"); - pass(); - } -}; - -BEAST_DEFINE_TESTSUITE_MANUAL(SlotPeer,sim,ripple); - -} -} diff --git a/src/ripple/unl/tests/metrics.h b/src/ripple/unl/tests/metrics.h deleted file mode 100644 index eb1342fe85..0000000000 --- a/src/ripple/unl/tests/metrics.h +++ /dev/null @@ -1,100 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_SIM_METRICS_H_INCLUDED -#define RIPPLE_SIM_METRICS_H_INCLUDED - -#include -#include -#include - -namespace ripple { -namespace test { - -template -std::string -seq_string (FwdRange const& r, int width = 0) -{ - std::stringstream ss; - auto iter = std::begin(r); - if (iter == std::end(r)) - return ss.str(); - ss << std::setw(width) << *iter++; - while(iter != std::end(r)) - ss << ", " << - std::setw(width) << *iter++; - return ss.str(); -} - -template -typename FwdRange::value_type -seq_sum (FwdRange const& r) -{ - typename FwdRange::value_type sum = 0; - for (auto const& n : r) - sum += n; - return sum; -} - -template -double -diameter (RanRange const& r) -{ - if (r.empty()) - return 0; - if (r.size() == 1) - return r.front(); - auto h0 = *(r.end() - 2); - auto h1 = r.back(); - return (r.size() - 2) + - double(h1) / (h0 + h1); -} - -template -typename Container::value_type& -nth (Container& c, std::size_t n) -{ - c.resize(std::max(c.size(), n + 1)); - return c[n]; -} - -template -void -hist_accum (Hist& h, FwdRange const& r) -{ - for(auto const& v : r) - ++nth(h, v); -} - -//------------------------------------------------------------------------------ - -template -inline -std::string -pad (std::string s, std::size_t n) -{ - if (s.size() < n) - s.insert(0, n - s.size(), ' '); - return s; -} - -} // test -} // ripple - -#endif