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