rippled
RCLValidations_test.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright 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 
20 #include <ripple/app/consensus/RCLValidations.h>
21 #include <ripple/app/ledger/Ledger.h>
22 #include <ripple/basics/Log.h>
23 #include <ripple/basics/StringUtilities.h>
24 #include <ripple/basics/base_uint.h>
25 #include <ripple/beast/unit_test.h>
26 #include <ripple/ledger/View.h>
27 #include <test/jtx.h>
28 
29 namespace ripple {
30 namespace test {
31 
32 class RCLValidations_test : public beast::unit_test::suite
33 {
34  void
36  {
37  testcase("Change validation trusted status");
38  auto keys = randomKeyPair(KeyType::secp256k1);
39  auto v = std::make_shared<STValidation>(
41  keys.first,
42  keys.second,
43  calcNodeID(keys.first),
44  [&](STValidation& v) { v.setFieldU32(sfLedgerSequence, 123456); });
45 
46  BEAST_EXPECT(v->isTrusted());
47  v->setUntrusted();
48  BEAST_EXPECT(!v->isTrusted());
49 
50  RCLValidation rcv{v};
51  BEAST_EXPECT(!rcv.trusted());
52  rcv.setTrusted();
53  BEAST_EXPECT(rcv.trusted());
54  rcv.setUntrusted();
55  BEAST_EXPECT(!rcv.trusted());
56  }
57 
58  void
60  {
61  testcase("RCLValidatedLedger ancestry");
62 
63  using Seq = RCLValidatedLedger::Seq;
64  using ID = RCLValidatedLedger::ID;
65 
66  // This tests RCLValidatedLedger properly implements the type
67  // requirements of a LedgerTrie ledger, with its added behavior that
68  // only the 256 prior ledger hashes are available to determine ancestry.
69  Seq const maxAncestors = 256;
70 
71  //----------------------------------------------------------------------
72  // Generate two ledger histories that agree on the first maxAncestors
73  // ledgers, then diverge.
74 
76 
77  jtx::Env env(*this);
78  Config config;
79  auto prev = std::make_shared<Ledger const>(
81  config,
83  env.app().getNodeFamily());
84  history.push_back(prev);
85  for (auto i = 0; i < (2 * maxAncestors + 1); ++i)
86  {
87  auto next = std::make_shared<Ledger>(
88  *prev, env.app().timeKeeper().closeTime());
89  next->updateSkipList();
90  history.push_back(next);
91  prev = next;
92  }
93 
94  // altHistory agrees with first half of regular history
95  Seq const diverge = history.size() / 2;
97  history.begin(), history.begin() + diverge);
98  // advance clock to get new ledgers
99  using namespace std::chrono_literals;
100  env.timeKeeper().set(env.timeKeeper().now() + 1200s);
101  prev = altHistory.back();
102  bool forceHash = true;
103  while (altHistory.size() < history.size())
104  {
105  auto next = std::make_shared<Ledger>(
106  *prev, env.app().timeKeeper().closeTime());
107  // Force a different hash on the first iteration
108  next->updateSkipList();
109  BEAST_EXPECT(next->read(keylet::fees()));
110  if (forceHash)
111  {
112  next->setImmutable();
113  forceHash = false;
114  }
115 
116  altHistory.push_back(next);
117  prev = next;
118  }
119 
120  //----------------------------------------------------------------------
121 
122  // Empty ledger
123  {
125  BEAST_EXPECT(a.seq() == Seq{0});
126  BEAST_EXPECT(a[Seq{0}] == ID{0});
127  BEAST_EXPECT(a.minSeq() == Seq{0});
128  }
129 
130  // Full history ledgers
131  {
132  std::shared_ptr<Ledger const> ledger = history.back();
133  RCLValidatedLedger a{ledger, env.journal};
134  BEAST_EXPECT(a.seq() == ledger->info().seq);
135  BEAST_EXPECT(a.minSeq() == a.seq() - maxAncestors);
136  // Ensure the ancestral 256 ledgers have proper ID
137  for (Seq s = a.seq(); s > 0; s--)
138  {
139  if (s >= a.minSeq())
140  BEAST_EXPECT(a[s] == history[s - 1]->info().hash);
141  else
142  BEAST_EXPECT(a[s] == ID{0});
143  }
144  }
145 
146  // Mismatch tests
147 
148  // Empty with non-empty
149  {
151 
152  for (auto ledger : {history.back(), history[maxAncestors - 1]})
153  {
154  RCLValidatedLedger b{ledger, env.journal};
155  BEAST_EXPECT(mismatch(a, b) == 1);
156  BEAST_EXPECT(mismatch(b, a) == 1);
157  }
158  }
159  // Same chains, different seqs
160  {
161  RCLValidatedLedger a{history.back(), env.journal};
162  for (Seq s = a.seq(); s > 0; s--)
163  {
164  RCLValidatedLedger b{history[s - 1], env.journal};
165  if (s >= a.minSeq())
166  {
167  BEAST_EXPECT(mismatch(a, b) == b.seq() + 1);
168  BEAST_EXPECT(mismatch(b, a) == b.seq() + 1);
169  }
170  else
171  {
172  BEAST_EXPECT(mismatch(a, b) == Seq{1});
173  BEAST_EXPECT(mismatch(b, a) == Seq{1});
174  }
175  }
176  }
177  // Different chains, same seqs
178  {
179  // Alt history diverged at history.size()/2
180  for (Seq s = 1; s < history.size(); ++s)
181  {
182  RCLValidatedLedger a{history[s - 1], env.journal};
183  RCLValidatedLedger b{altHistory[s - 1], env.journal};
184 
185  BEAST_EXPECT(a.seq() == b.seq());
186  if (s <= diverge)
187  {
188  BEAST_EXPECT(a[a.seq()] == b[b.seq()]);
189  BEAST_EXPECT(mismatch(a, b) == a.seq() + 1);
190  BEAST_EXPECT(mismatch(b, a) == a.seq() + 1);
191  }
192  else
193  {
194  BEAST_EXPECT(a[a.seq()] != b[b.seq()]);
195  BEAST_EXPECT(mismatch(a, b) == diverge + 1);
196  BEAST_EXPECT(mismatch(b, a) == diverge + 1);
197  }
198  }
199  }
200  // Different chains, different seqs
201  {
202  // Compare around the divergence point
203  RCLValidatedLedger a{history[diverge], env.journal};
204  for (Seq offset = diverge / 2; offset < 3 * diverge / 2; ++offset)
205  {
206  RCLValidatedLedger b{altHistory[offset - 1], env.journal};
207  if (offset <= diverge)
208  {
209  BEAST_EXPECT(mismatch(a, b) == b.seq() + 1);
210  }
211  else
212  {
213  BEAST_EXPECT(mismatch(a, b) == diverge + 1);
214  }
215  }
216  }
217  }
218 
219  void
221  {
222  testcase("RCLValidatedLedger LedgerTrie");
223 
224  // This test exposes an issue with the limited 256
225  // ancestor hash design of RCLValidatedLedger.
226  // There is only a single chain of validated ledgers
227  // but the 256 gap causes a "split" in the LedgerTrie
228  // due to the lack of ancestry information for a later ledger.
229  // This exposes a bug in which we are unable to remove
230  // support for a ledger hash which is already in the trie.
231 
232  using Seq = RCLValidatedLedger::Seq;
233  using ID = RCLValidatedLedger::ID;
234 
235  // Max known ancestors for each ledger
236  Seq const maxAncestors = 256;
238 
239  // Generate a chain of 256 + 10 ledgers
240  jtx::Env env(*this);
241  auto& j = env.journal;
242  Config config;
243  auto prev = std::make_shared<Ledger const>(
245  config,
247  env.app().getNodeFamily());
248  history.push_back(prev);
249  for (auto i = 0; i < (maxAncestors + 10); ++i)
250  {
251  auto next = std::make_shared<Ledger>(
252  *prev, env.app().timeKeeper().closeTime());
253  next->updateSkipList();
254  history.push_back(next);
255  prev = next;
256  }
257 
259 
260  // First, create the single branch trie, with ledgers
261  // separated by exactly 256 ledgers
262  auto ledg_002 = RCLValidatedLedger{history[1], j};
263  auto ledg_258 = RCLValidatedLedger{history[257], j};
264  auto ledg_259 = RCLValidatedLedger{history[258], j};
265 
266  trie.insert(ledg_002);
267  trie.insert(ledg_258, 4);
268  // trie.dump(std::cout);
269  // 000000[0,1)(T:0,B:5)
270  // |-AB868A..36C8[1,3)(T:1,B:5)
271  // |-AB868A..37C8[3,259)(T:4,B:4)
272  BEAST_EXPECT(trie.tipSupport(ledg_002) == 1);
273  BEAST_EXPECT(trie.branchSupport(ledg_002) == 5);
274  BEAST_EXPECT(trie.tipSupport(ledg_258) == 4);
275  BEAST_EXPECT(trie.branchSupport(ledg_258) == 4);
276 
277  // Move three of the s258 ledgers to s259, which splits the trie
278  // due to the 256 ancestory limit
279  BEAST_EXPECT(trie.remove(ledg_258, 3));
280  trie.insert(ledg_259, 3);
281  trie.getPreferred(1);
282  // trie.dump(std::cout);
283  // 000000[0,1)(T:0,B:5)
284  // |-AB868A..37C9[1,260)(T:3,B:3)
285  // |-AB868A..36C8[1,3)(T:1,B:2)
286  // |-AB868A..37C8[3,259)(T:1,B:1)
287  BEAST_EXPECT(trie.tipSupport(ledg_002) == 1);
288  BEAST_EXPECT(trie.branchSupport(ledg_002) == 2);
289  BEAST_EXPECT(trie.tipSupport(ledg_258) == 1);
290  BEAST_EXPECT(trie.branchSupport(ledg_258) == 1);
291  BEAST_EXPECT(trie.tipSupport(ledg_259) == 3);
292  BEAST_EXPECT(trie.branchSupport(ledg_259) == 3);
293 
294  // The last call to trie.getPreferred cycled the children of the root
295  // node to make the new branch the first child (since it has support 3)
296  // then verify the remove call works
297  // past bug: remove had assumed the first child of a node in the trie
298  // which matches is the *only* child in the trie which matches.
299  // This is **NOT** true with the limited 256 ledger ancestory
300  // quirk of RCLValidation and prevents deleting the old support
301  // for ledger 257
302 
303  BEAST_EXPECT(
304  trie.remove(RCLValidatedLedger{history[257], env.journal}, 1));
305  trie.insert(RCLValidatedLedger{history[258], env.journal}, 1);
306  trie.getPreferred(1);
307  // trie.dump(std::cout);
308  // 000000[0,1)(T:0,B:5)
309  // |-AB868A..37C9[1,260)(T:4,B:4)
310  // |-AB868A..36C8[1,3)(T:1,B:1)
311  BEAST_EXPECT(trie.tipSupport(ledg_002) == 1);
312  BEAST_EXPECT(trie.branchSupport(ledg_002) == 1);
313  BEAST_EXPECT(trie.tipSupport(ledg_258) == 0);
314  // 258 no longer lives on a tip in the tree, BUT it is an ancestor
315  // of 259 which is a tip and therefore gets it's branchSupport value
316  // implicitly
317  BEAST_EXPECT(trie.branchSupport(ledg_258) == 4);
318  BEAST_EXPECT(trie.tipSupport(ledg_259) == 4);
319  BEAST_EXPECT(trie.branchSupport(ledg_259) == 4);
320  }
321 
322 public:
323  void
324  run() override
325  {
329  }
330 };
331 
333 
334 } // namespace test
335 } // namespace ripple
ripple::mismatch
RCLValidatedLedger::Seq mismatch(RCLValidatedLedger const &a, RCLValidatedLedger const &b)
Definition: RCLValidations.cpp:98
ripple::LedgerTrie::branchSupport
std::uint32_t branchSupport(Ledger const &ledger) const
Return the count of branch support for the specific ledger.
Definition: LedgerTrie.h:603
std::shared_ptr
STL class.
ripple::calcNodeID
NodeID calcNodeID(PublicKey const &pk)
Calculate the 160-bit node ID from a node public key.
Definition: PublicKey.cpp:303
ripple::test::RCLValidations_test::run
void run() override
Definition: RCLValidations_test.cpp:324
ripple::sfLedgerSequence
const SF_UINT32 sfLedgerSequence
ripple::RCLValidatedLedger::MakeGenesis
Definition: RCLValidations.h:158
std::vector
STL class.
std::vector::size
T size(T... args)
ripple::LedgerTrie::tipSupport
std::uint32_t tipSupport(Ledger const &ledger) const
Return count of tip support for the specific ledger.
Definition: LedgerTrie.h:589
ripple::test::jtx::Env::journal
const beast::Journal journal
Definition: Env.h:144
ripple::test::RCLValidations_test
Definition: RCLValidations_test.cpp:32
ripple::test::jtx::Env::timeKeeper
ManualTimeKeeper & timeKeeper()
Definition: Env.h:253
ripple::test::jtx::Env::app
Application & app()
Definition: Env.h:241
std::vector::back
T back(T... args)
ripple::Application::timeKeeper
virtual TimeKeeper & timeKeeper()=0
ripple::RCLValidation
Wrapper over STValidation for generic Validation code.
Definition: RCLValidations.h:38
ripple::RCLValidatedLedger
Wraps a ledger instance for use in generic Validations LedgerTrie.
Definition: RCLValidations.h:153
ripple::RCLValidatedLedger::ID
LedgerHash ID
Definition: RCLValidations.h:156
ripple::STValidation
Definition: STValidation.h:44
std::vector::push_back
T push_back(T... args)
ripple::test::RCLValidations_test::testLedgerTrieRCLValidatedLedger
void testLedgerTrieRCLValidatedLedger()
Definition: RCLValidations_test.cpp:220
ripple::LedgerTrie::getPreferred
std::optional< SpanTip< Ledger > > getPreferred(Seq const largestIssued) const
Return the preferred ledger ID.
Definition: LedgerTrie.h:677
ripple::LedgerTrie::insert
void insert(Ledger const &ledger, std::uint32_t count=1)
Insert and/or increment the support for the given ledger.
Definition: LedgerTrie.h:449
ripple::Config
Definition: Config.h:89
ripple::test::RCLValidations_test::testRCLValidatedLedger
void testRCLValidatedLedger()
Definition: RCLValidations_test.cpp:59
std::chrono::time_point
ripple::TimeKeeper::closeTime
virtual time_point closeTime() const =0
Returns the close time, in network time.
ripple::KeyType::secp256k1
@ secp256k1
ripple::randomKeyPair
std::pair< PublicKey, SecretKey > randomKeyPair(KeyType type)
Create a key pair using secure random numbers.
Definition: SecretKey.cpp:368
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::LedgerTrie
Ancestry trie of ledgers.
Definition: LedgerTrie.h:346
std::vector::begin
T begin(T... args)
ripple::create_genesis
const create_genesis_t create_genesis
Definition: Ledger.cpp:62
ripple::test::RCLValidations_test::testChangeTrusted
void testChangeTrusted()
Definition: RCLValidations_test.cpp:35
ripple::Validations< RCLValidationsAdaptor >
ripple::keylet::fees
Keylet const & fees() noexcept
The (fixed) index of the object containing the ledger fees.
Definition: Indexes.cpp:171
ripple::LedgerTrie::remove
bool remove(Ledger const &ledger, std::uint32_t count=1)
Decrease support for a ledger, removing and compressing if possible.
Definition: LedgerTrie.h:535
ripple::test::ManualTimeKeeper::now
time_point now() const override
Returns the estimate of wall time, in network time.
Definition: ManualTimeKeeper.cpp:37
ripple::test::ManualTimeKeeper::set
void set(time_point now)
Definition: ManualTimeKeeper.cpp:81
ripple::test::jtx::Env
A transaction testing environment.
Definition: Env.h:116
ripple::test::BEAST_DEFINE_TESTSUITE
BEAST_DEFINE_TESTSUITE(DeliverMin, app, ripple)
ripple::RCLValidatedLedger::Seq
LedgerIndex Seq
Definition: RCLValidations.h:157