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