rippled
Loading...
Searching...
No Matches
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 <test/jtx.h>
21
22#include <xrpld/app/consensus/RCLValidations.h>
23#include <xrpld/app/ledger/Ledger.h>
24
25#include <xrpl/basics/base_uint.h>
26#include <xrpl/beast/unit_test.h>
27
28namespace ripple {
29namespace test {
30
32{
33 void
35 {
36 testcase("Change validation trusted status");
40 keys.first,
41 keys.second,
42 calcNodeID(keys.first),
43 [&](STValidation& v) { v.setFieldU32(sfLedgerSequence, 123456); });
44
45 BEAST_EXPECT(v->isTrusted());
46 v->setUntrusted();
47 BEAST_EXPECT(!v->isTrusted());
48
49 RCLValidation rcv{v};
50 BEAST_EXPECT(!rcv.trusted());
51 rcv.setTrusted();
52 BEAST_EXPECT(rcv.trusted());
53 rcv.setUntrusted();
54 BEAST_EXPECT(!rcv.trusted());
55 }
56
57 void
59 {
60 testcase("RCLValidatedLedger ancestry");
61
62 using Seq = RCLValidatedLedger::Seq;
63 using ID = RCLValidatedLedger::ID;
64
65 // This tests RCLValidatedLedger properly implements the type
66 // requirements of a LedgerTrie ledger, with its added behavior that
67 // only the 256 prior ledger hashes are available to determine ancestry.
68 Seq const maxAncestors = 256;
69
70 //----------------------------------------------------------------------
71 // Generate two ledger histories that agree on the first maxAncestors
72 // ledgers, then diverge.
73
75
76 jtx::Env env(*this);
77 Config config;
80 config,
82 env.app().getNodeFamily());
83 history.push_back(prev);
84 for (auto i = 0; i < (2 * maxAncestors + 1); ++i)
85 {
86 auto next = std::make_shared<Ledger>(
87 *prev, env.app().timeKeeper().closeTime());
88 next->updateSkipList();
89 history.push_back(next);
90 prev = next;
91 }
92
93 // altHistory agrees with first half of regular history
94 Seq const diverge = history.size() / 2;
96 history.begin(), history.begin() + diverge);
97 // advance clock to get new ledgers
98 using namespace std::chrono_literals;
99 env.timeKeeper().set(env.timeKeeper().now() + 1200s);
100 prev = altHistory.back();
101 bool forceHash = true;
102 while (altHistory.size() < history.size())
103 {
104 auto next = std::make_shared<Ledger>(
105 *prev, env.app().timeKeeper().closeTime());
106 // Force a different hash on the first iteration
107 next->updateSkipList();
108 BEAST_EXPECT(next->read(keylet::fees()));
109 if (forceHash)
110 {
111 next->setImmutable();
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
233 // Max known ancestors for each ledger
234 Seq const maxAncestors = 256;
236
237 // Generate a chain of 256 + 10 ledgers
238 jtx::Env env(*this);
239 auto& j = env.journal;
240 Config config;
243 config,
245 env.app().getNodeFamily());
246 history.push_back(prev);
247 for (auto i = 0; i < (maxAncestors + 10); ++i)
248 {
249 auto next = std::make_shared<Ledger>(
250 *prev, env.app().timeKeeper().closeTime());
251 next->updateSkipList();
252 history.push_back(next);
253 prev = next;
254 }
255
257
258 // First, create the single branch trie, with ledgers
259 // separated by exactly 256 ledgers
260 auto ledg_002 = RCLValidatedLedger{history[1], j};
261 auto ledg_258 = RCLValidatedLedger{history[257], j};
262 auto ledg_259 = RCLValidatedLedger{history[258], j};
263
264 trie.insert(ledg_002);
265 trie.insert(ledg_258, 4);
266 // trie.dump(std::cout);
267 // 000000[0,1)(T:0,B:5)
268 // |-AB868A..36C8[1,3)(T:1,B:5)
269 // |-AB868A..37C8[3,259)(T:4,B:4)
270 BEAST_EXPECT(trie.tipSupport(ledg_002) == 1);
271 BEAST_EXPECT(trie.branchSupport(ledg_002) == 5);
272 BEAST_EXPECT(trie.tipSupport(ledg_258) == 4);
273 BEAST_EXPECT(trie.branchSupport(ledg_258) == 4);
274
275 // Move three of the s258 ledgers to s259, which splits the trie
276 // due to the 256 ancestory limit
277 BEAST_EXPECT(trie.remove(ledg_258, 3));
278 trie.insert(ledg_259, 3);
279 trie.getPreferred(1);
280 // trie.dump(std::cout);
281 // 000000[0,1)(T:0,B:5)
282 // |-AB868A..37C9[1,260)(T:3,B:3)
283 // |-AB868A..36C8[1,3)(T:1,B:2)
284 // |-AB868A..37C8[3,259)(T:1,B:1)
285 BEAST_EXPECT(trie.tipSupport(ledg_002) == 1);
286 BEAST_EXPECT(trie.branchSupport(ledg_002) == 2);
287 BEAST_EXPECT(trie.tipSupport(ledg_258) == 1);
288 BEAST_EXPECT(trie.branchSupport(ledg_258) == 1);
289 BEAST_EXPECT(trie.tipSupport(ledg_259) == 3);
290 BEAST_EXPECT(trie.branchSupport(ledg_259) == 3);
291
292 // The last call to trie.getPreferred cycled the children of the root
293 // node to make the new branch the first child (since it has support 3)
294 // then verify the remove call works
295 // past bug: remove had assumed the first child of a node in the trie
296 // which matches is the *only* child in the trie which matches.
297 // This is **NOT** true with the limited 256 ledger ancestory
298 // quirk of RCLValidation and prevents deleting the old support
299 // for ledger 257
300
301 BEAST_EXPECT(
302 trie.remove(RCLValidatedLedger{history[257], env.journal}, 1));
303 trie.insert(RCLValidatedLedger{history[258], env.journal}, 1);
304 trie.getPreferred(1);
305 // trie.dump(std::cout);
306 // 000000[0,1)(T:0,B:5)
307 // |-AB868A..37C9[1,260)(T:4,B:4)
308 // |-AB868A..36C8[1,3)(T:1,B:1)
309 BEAST_EXPECT(trie.tipSupport(ledg_002) == 1);
310 BEAST_EXPECT(trie.branchSupport(ledg_002) == 1);
311 BEAST_EXPECT(trie.tipSupport(ledg_258) == 0);
312 // 258 no longer lives on a tip in the tree, BUT it is an ancestor
313 // of 259 which is a tip and therefore gets it's branchSupport value
314 // implicitly
315 BEAST_EXPECT(trie.branchSupport(ledg_258) == 4);
316 BEAST_EXPECT(trie.tipSupport(ledg_259) == 4);
317 BEAST_EXPECT(trie.branchSupport(ledg_259) == 4);
318 }
319
320public:
321 void
328};
329
330BEAST_DEFINE_TESTSUITE(RCLValidations, app, ripple);
331
332} // namespace test
333} // namespace ripple
T back(T... args)
T begin(T... args)
A testsuite class.
Definition suite.h:55
testcase_t testcase
Memberspace for declaring test cases.
Definition suite.h:155
virtual TimeKeeper & timeKeeper()=0
Ancestry trie of ledgers.
Definition LedgerTrie.h:351
std::uint32_t tipSupport(Ledger const &ledger) const
Return count of tip support for the specific ledger.
Definition LedgerTrie.h:597
void insert(Ledger const &ledger, std::uint32_t count=1)
Insert and/or increment the support for the given ledger.
Definition LedgerTrie.h:453
std::optional< SpanTip< Ledger > > getPreferred(Seq const largestIssued) const
Return the preferred ledger ID.
Definition LedgerTrie.h:685
std::uint32_t branchSupport(Ledger const &ledger) const
Return the count of branch support for the specific ledger.
Definition LedgerTrie.h:611
bool remove(Ledger const &ledger, std::uint32_t count=1)
Decrease support for a ledger, removing and compressing if possible.
Definition LedgerTrie.h:541
Wraps a ledger instance for use in generic Validations LedgerTrie.
Wrapper over STValidation for generic Validation code.
time_point closeTime() const
Returns the predicted close time, in network time.
Definition TimeKeeper.h:76
time_point now() const override
Returns the current time.
void run() override
Runs the suite.
A transaction testing environment.
Definition Env.h:121
Application & app()
Definition Env.h:261
beast::Journal const journal
Definition Env.h:162
ManualTimeKeeper & timeKeeper()
Definition Env.h:273
T is_same_v
Keylet const & fees() noexcept
The (fixed) index of the object containing the ledger fees.
Definition Indexes.cpp:222
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:25
RCLValidatedLedger::Seq mismatch(RCLValidatedLedger const &a, RCLValidatedLedger const &b)
NodeID calcNodeID(PublicKey const &)
Calculate the 160-bit node ID from a node public key.
create_genesis_t const create_genesis
Definition Ledger.cpp:51
std::pair< PublicKey, SecretKey > randomKeyPair(KeyType type)
Create a key pair using secure random numbers.
T push_back(T... args)
T size(T... args)