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