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>(
80  create_genesis, config, std::vector<uint256>{}, env.app().family());
81  history.push_back(prev);
82  for (auto i = 0; i < (2 * maxAncestors + 1); ++i)
83  {
84  auto next = std::make_shared<Ledger>(
85  *prev, env.app().timeKeeper().closeTime());
86  next->updateSkipList();
87  history.push_back(next);
88  prev = next;
89  }
90 
91  // altHistory agrees with first half of regular history
92  Seq const diverge = history.size() / 2;
94  history.begin(), history.begin() + diverge);
95  // advance clock to get new ledgers
96  using namespace std::chrono_literals;
97  env.timeKeeper().set(env.timeKeeper().now() + 1200s);
98  prev = altHistory.back();
99  bool forceHash = true;
100  while (altHistory.size() < history.size())
101  {
102  auto next = std::make_shared<Ledger>(
103  *prev, env.app().timeKeeper().closeTime());
104  // Force a different hash on the first iteration
105  next->updateSkipList();
106  if (forceHash)
107  {
108  next->setImmutable(config);
109  forceHash = false;
110  }
111 
112  altHistory.push_back(next);
113  prev = next;
114  }
115 
116  //----------------------------------------------------------------------
117 
118  // Empty ledger
119  {
121  BEAST_EXPECT(a.seq() == Seq{0});
122  BEAST_EXPECT(a[Seq{0}] == ID{0});
123  BEAST_EXPECT(a.minSeq() == Seq{0});
124  }
125 
126  // Full history ledgers
127  {
128  std::shared_ptr<Ledger const> ledger = history.back();
129  RCLValidatedLedger a{ledger, env.journal};
130  BEAST_EXPECT(a.seq() == ledger->info().seq);
131  BEAST_EXPECT(a.minSeq() == a.seq() - maxAncestors);
132  // Ensure the ancestral 256 ledgers have proper ID
133  for (Seq s = a.seq(); s > 0; s--)
134  {
135  if (s >= a.minSeq())
136  BEAST_EXPECT(a[s] == history[s - 1]->info().hash);
137  else
138  BEAST_EXPECT(a[s] == ID{0});
139  }
140  }
141 
142  // Mismatch tests
143 
144  // Empty with non-empty
145  {
147 
148  for (auto ledger : {history.back(), history[maxAncestors - 1]})
149  {
150  RCLValidatedLedger b{ledger, env.journal};
151  BEAST_EXPECT(mismatch(a, b) == 1);
152  BEAST_EXPECT(mismatch(b, a) == 1);
153  }
154  }
155  // Same chains, different seqs
156  {
157  RCLValidatedLedger a{history.back(), env.journal};
158  for (Seq s = a.seq(); s > 0; s--)
159  {
160  RCLValidatedLedger b{history[s - 1], env.journal};
161  if (s >= a.minSeq())
162  {
163  BEAST_EXPECT(mismatch(a, b) == b.seq() + 1);
164  BEAST_EXPECT(mismatch(b, a) == b.seq() + 1);
165  }
166  else
167  {
168  BEAST_EXPECT(mismatch(a, b) == Seq{1});
169  BEAST_EXPECT(mismatch(b, a) == Seq{1});
170  }
171  }
172  }
173  // Different chains, same seqs
174  {
175  // Alt history diverged at history.size()/2
176  for (Seq s = 1; s < history.size(); ++s)
177  {
178  RCLValidatedLedger a{history[s - 1], env.journal};
179  RCLValidatedLedger b{altHistory[s - 1], env.journal};
180 
181  BEAST_EXPECT(a.seq() == b.seq());
182  if (s <= diverge)
183  {
184  BEAST_EXPECT(a[a.seq()] == b[b.seq()]);
185  BEAST_EXPECT(mismatch(a, b) == a.seq() + 1);
186  BEAST_EXPECT(mismatch(b, a) == a.seq() + 1);
187  }
188  else
189  {
190  BEAST_EXPECT(a[a.seq()] != b[b.seq()]);
191  BEAST_EXPECT(mismatch(a, b) == diverge + 1);
192  BEAST_EXPECT(mismatch(b, a) == diverge + 1);
193  }
194  }
195  }
196  // Different chains, different seqs
197  {
198  // Compare around the divergence point
199  RCLValidatedLedger a{history[diverge], env.journal};
200  for (Seq offset = diverge / 2; offset < 3 * diverge / 2; ++offset)
201  {
202  RCLValidatedLedger b{altHistory[offset - 1], env.journal};
203  if (offset <= diverge)
204  {
205  BEAST_EXPECT(mismatch(a, b) == b.seq() + 1);
206  }
207  else
208  {
209  BEAST_EXPECT(mismatch(a, b) == diverge + 1);
210  }
211  }
212  }
213  }
214 
215  void
217  {
218  testcase("RCLValidatedLedger LedgerTrie");
219 
220  // This test exposes an issue with the limited 256
221  // ancestor hash design of RCLValidatedLedger.
222  // There is only a single chain of validated ledgers
223  // but the 256 gap causes a "split" in the LedgerTrie
224  // due to the lack of ancestry information for a later ledger.
225  // This exposes a bug in which we are unable to remove
226  // support for a ledger hash which is already in the trie.
227 
228  using Seq = RCLValidatedLedger::Seq;
229  using ID = RCLValidatedLedger::ID;
230 
231  // Max known ancestors for each ledger
232  Seq const maxAncestors = 256;
234 
235  // Generate a chain of 256 + 10 ledgers
236  jtx::Env env(*this);
237  auto& j = env.journal;
238  Config config;
239  auto prev = std::make_shared<Ledger const>(
240  create_genesis, config, std::vector<uint256>{}, env.app().family());
241  history.push_back(prev);
242  for (auto i = 0; i < (maxAncestors + 10); ++i)
243  {
244  auto next = std::make_shared<Ledger>(
245  *prev, env.app().timeKeeper().closeTime());
246  next->updateSkipList();
247  history.push_back(next);
248  prev = next;
249  }
250 
252 
253  // First, create the single branch trie, with ledgers
254  // separated by exactly 256 ledgers
255  auto ledg_002 = RCLValidatedLedger{history[1], j};
256  auto ledg_258 = RCLValidatedLedger{history[257], j};
257  auto ledg_259 = RCLValidatedLedger{history[258], j};
258 
259  trie.insert(ledg_002);
260  trie.insert(ledg_258, 4);
261  // trie.dump(std::cout);
262  // 000000[0,1)(T:0,B:5)
263  // |-AB868A..36C8[1,3)(T:1,B:5)
264  // |-AB868A..37C8[3,259)(T:4,B:4)
265  BEAST_EXPECT(trie.tipSupport(ledg_002) == 1);
266  BEAST_EXPECT(trie.branchSupport(ledg_002) == 5);
267  BEAST_EXPECT(trie.tipSupport(ledg_258) == 4);
268  BEAST_EXPECT(trie.branchSupport(ledg_258) == 4);
269 
270  // Move three of the s258 ledgers to s259, which splits the trie
271  // due to the 256 ancestory limit
272  BEAST_EXPECT(trie.remove(ledg_258, 3));
273  trie.insert(ledg_259, 3);
274  trie.getPreferred(1);
275  // trie.dump(std::cout);
276  // 000000[0,1)(T:0,B:5)
277  // |-AB868A..37C9[1,260)(T:3,B:3)
278  // |-AB868A..36C8[1,3)(T:1,B:2)
279  // |-AB868A..37C8[3,259)(T:1,B:1)
280  BEAST_EXPECT(trie.tipSupport(ledg_002) == 1);
281  BEAST_EXPECT(trie.branchSupport(ledg_002) == 2);
282  BEAST_EXPECT(trie.tipSupport(ledg_258) == 1);
283  BEAST_EXPECT(trie.branchSupport(ledg_258) == 1);
284  BEAST_EXPECT(trie.tipSupport(ledg_259) == 3);
285  BEAST_EXPECT(trie.branchSupport(ledg_259) == 3);
286 
287  // The last call to trie.getPreferred cycled the children of the root
288  // node to make the new branch the first child (since it has support 3)
289  // then verify the remove call works
290  // past bug: remove had assumed the first child of a node in the trie
291  // which matches is the *only* child in the trie which matches.
292  // This is **NOT** true with the limited 256 ledger ancestory
293  // quirk of RCLValidation and prevents deleting the old support
294  // for ledger 257
295 
296  BEAST_EXPECT(
297  trie.remove(RCLValidatedLedger{history[257], env.journal}, 1));
298  trie.insert(RCLValidatedLedger{history[258], env.journal}, 1);
299  trie.getPreferred(1);
300  // trie.dump(std::cout);
301  // 000000[0,1)(T:0,B:5)
302  // |-AB868A..37C9[1,260)(T:4,B:4)
303  // |-AB868A..36C8[1,3)(T:1,B:1)
304  BEAST_EXPECT(trie.tipSupport(ledg_002) == 1);
305  BEAST_EXPECT(trie.branchSupport(ledg_002) == 1);
306  BEAST_EXPECT(trie.tipSupport(ledg_258) == 0);
307  // 258 no longer lives on a tip in the tree, BUT it is an ancestor
308  // of 259 which is a tip and therefore gets it's branchSupport value
309  // implicitly
310  BEAST_EXPECT(trie.branchSupport(ledg_258) == 4);
311  BEAST_EXPECT(trie.tipSupport(ledg_259) == 4);
312  BEAST_EXPECT(trie.branchSupport(ledg_259) == 4);
313  }
314 
315 public:
316  void
317  run() override
318  {
322  }
323 };
324 
326 
327 } // namespace test
328 } // 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:317
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:32
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:216
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:59
ripple::sfLedgerSequence
const SF_U32 sfLedgerSequence(access, STI_UINT32, 6, "LedgerSequence")
Definition: SField.h:357
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:35
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