rippled
ledgers.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2012-2017 Ripple Labs Inc
5 
6  Permission to use, copy, modify, and/or distribute this software for any
7  purpose with or without fee is hereby granted, provided that the above
8  copyright notice and this permission notice appear in all copies.
9 
10  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18 //==============================================================================
19 #include <test/csf/ledgers.h>
20 #include <algorithm>
21 
22 #include <sstream>
23 
24 namespace ripple {
25 namespace test {
26 namespace csf {
27 
28 Ledger::Instance const Ledger::genesis;
29 
32 {
34  res["id"] = static_cast<ID::value_type>(id());
35  res["seq"] = static_cast<Seq::value_type>(seq());
36  return res;
37 }
38 
39 bool
40 Ledger::isAncestor(Ledger const& ancestor) const
41 {
42  if (ancestor.seq() < seq())
43  return operator[](ancestor.seq()) == ancestor.id();
44  return false;
45 }
46 
49 {
50  if(s > seq())
51  return {};
52  if(s== seq())
53  return id();
54  return instance_->ancestors[static_cast<Seq::value_type>(s)];
55 
56 }
57 
59 mismatch(Ledger const& a, Ledger const& b)
60 {
61  using Seq = Ledger::Seq;
62 
63  // end is 1 past end of range
64  Seq start{0};
65  Seq end = std::min(a.seq() + Seq{1}, b.seq() + Seq{1});
66 
67  // Find mismatch in [start,end)
68  // Binary search
69  Seq count = end - start;
70  while(count > Seq{0})
71  {
72  Seq step = count/Seq{2};
73  Seq curr = start + step;
74  if(a[curr] == b[curr])
75  {
76  // go to second half
77  start = ++curr;
78  count -= step + Seq{1};
79  }
80  else
81  count = step;
82  }
83  return start;
84 }
85 
87 {
89 }
90 
93 {
94  return Ledger::ID{static_cast<Ledger::ID::value_type>(instances_.size())};
95 }
96 
97 Ledger
99  Ledger const& parent,
100  TxSetType const& txs,
101  NetClock::duration closeTimeResolution,
102  NetClock::time_point const& consensusCloseTime)
103 {
104  using namespace std::chrono_literals;
105  Ledger::Instance next(*parent.instance_);
106  next.txs.insert(txs.begin(), txs.end());
107  next.seq = parent.seq() + Ledger::Seq{1};
108  next.closeTimeResolution = closeTimeResolution;
109  next.closeTimeAgree = consensusCloseTime != NetClock::time_point{};
110  if(next.closeTimeAgree)
111  next.closeTime = effCloseTime(
112  consensusCloseTime, closeTimeResolution, parent.closeTime());
113  else
114  next.closeTime = parent.closeTime() + 1s;
115 
116  next.parentCloseTime = parent.closeTime();
117  next.parentID = parent.id();
118  next.ancestors.push_back(parent.id());
119 
120  auto it = instances_.left.find(next);
121  if (it == instances_.left.end())
122  {
123  using Entry = InstanceMap::left_value_type;
124  it = instances_.left.insert(Entry{next, nextID()}).first;
125  }
126  return Ledger(it->second, &(it->first));
127 }
128 
129 boost::optional<Ledger>
131 {
132  auto const it = instances_.right.find(id);
133  if(it != instances_.right.end())
134  {
135  return Ledger(it->first, &(it->second));
136  }
137  return boost::none;
138 }
139 
140 
143 {
144  // Tips always maintains the Ledgers with largest sequence number
145  // along all known chains.
146  std::vector<Ledger> tips;
147  tips.reserve(ledgers.size());
148 
149  for (Ledger const & ledger : ledgers)
150  {
151  // Three options,
152  // 1. ledger is on a new branch
153  // 2. ledger is on a branch that we have seen tip for
154  // 3. ledger is the new tip for a branch
155  bool found = false;
156  for (auto idx = 0; idx < tips.size() && !found; ++idx)
157  {
158  bool const idxEarlier = tips[idx].seq() < ledger.seq();
159  Ledger const & earlier = idxEarlier ? tips[idx] : ledger;
160  Ledger const & later = idxEarlier ? ledger : tips[idx] ;
161  if (later.isAncestor(earlier))
162  {
163  tips[idx] = later;
164  found = true;
165  }
166  }
167 
168  if(!found)
169  tips.push_back(ledger);
170 
171  }
172  // The size of tips is the number of branches
173  return tips.size();
174 }
175 } // namespace csf
176 } // namespace test
177 } // namespace ripple
ripple::test::csf::Ledger::getJson
Json::Value getJson() const
Definition: ledgers.cpp:31
sstream
ripple::test::csf::LedgerOracle::InstanceEntry
InstanceMap::value_type InstanceEntry
Definition: ledgers.h:238
ripple::test::csf::LedgerOracle::lookup
boost::optional< Ledger > lookup(Ledger::ID const &id) const
Find the ledger with the given ID.
Definition: ledgers.cpp:130
ripple::test::csf::TxSetType
boost::container::flat_set< Tx > TxSetType
Definition: Tx.h:67
ripple::test::csf::LedgerOracle::nextID
Ledger::ID nextID() const
Definition: ledgers.cpp:92
std::vector::reserve
T reserve(T... args)
ripple::test::csf::mismatch
Ledger::Seq mismatch(Ledger const &a, Ledger const &b)
Definition: ledgers.cpp:59
ripple::test::csf::LedgerOracle::accept
Ledger accept(Ledger const &curr, TxSetType const &txs, NetClock::duration closeTimeResolution, NetClock::time_point const &consensusCloseTime)
Accept the given txs and generate a new ledger.
Definition: ledgers.cpp:98
std::vector
STL class.
std::set::size
T size(T... args)
ripple::test::csf::Ledger::Instance
Definition: ledgers.h:73
std::chrono::duration
ripple::test::csf::Ledger::Instance::ancestors
std::vector< Ledger::ID > ancestors
IDs of this ledgers ancestors.
Definition: ledgers.h:101
ripple::test::csf::Ledger
A ledger is a set of observed transactions and a sequence number identifying the ledger.
Definition: ledgers.h:58
ripple::test::csf::Ledger::seq
Seq seq() const
Definition: ledgers.h:163
ripple::test::csf::LedgerOracle::LedgerOracle
LedgerOracle()
Definition: ledgers.cpp:86
ripple::test::csf::LedgerOracle::instances_
InstanceMap instances_
Definition: ledgers.h:241
algorithm
std::vector::push_back
T push_back(T... args)
Json::objectValue
@ objectValue
object value (collection of name/value pairs).
Definition: json_value.h:45
ripple::test::csf::Ledger::operator[]
ID operator[](Seq seq) const
Return the id of the ancestor with the given seq (if exists/known)
Definition: ledgers.cpp:48
std::chrono::time_point
std::uint32_t
std::min
T min(T... args)
ripple::test::csf::Ledger::closeTime
NetClock::time_point closeTime() const
Definition: ledgers.h:181
ripple::test::jtx::seq
Set the sequence number on a JTx.
Definition: seq.h:32
ripple::test::csf::Ledger::id
ID id() const
Definition: ledgers.h:157
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::test::csf::Ledger::genesis
static const Instance genesis
Definition: ledgers.h:139
ripple::test::csf::LedgerOracle::branches
std::size_t branches(std::set< Ledger > const &ledgers) const
Determine the number of distinct branches for the set of ledgers.
Definition: ledgers.cpp:142
ripple::test::csf::Ledger::isAncestor
bool isAncestor(Ledger const &ancestor) const
Determine whether ancestor is really an ancestor of this ledger.
Definition: ledgers.cpp:40
ripple::test::csf::Ledger::Seq
tagged_integer< std::uint32_t, SeqTag > Seq
Definition: ledgers.h:64
std::size_t
ripple::test::csf::Ledger::instance_
Instance const * instance_
Definition: ledgers.h:229
ripple::tagged_integer< std::uint32_t, IdTag >
std::set
STL class.
ripple::effCloseTime
std::chrono::time_point< Clock, Duration > effCloseTime(std::chrono::time_point< Clock, Duration > closeTime, std::chrono::duration< Rep, Period > resolution, std::chrono::time_point< Clock, Duration > priorCloseTime)
Calculate the effective ledger close time.
Definition: LedgerTiming.h:151
Json::Value
Represents a JSON value.
Definition: json_value.h:141