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