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