rippled
Loading...
Searching...
No Matches
RCLValidations_test.cpp
1#include <test/jtx.h>
2
3#include <xrpld/app/consensus/RCLValidations.h>
4#include <xrpld/app/ledger/Ledger.h>
5
6#include <xrpl/basics/base_uint.h>
7#include <xrpl/beast/unit_test.h>
8
9namespace ripple {
10namespace test {
11
13{
14 void
16 {
17 testcase("Change validation trusted status");
21 keys.first,
22 keys.second,
23 calcNodeID(keys.first),
24 [&](STValidation& v) { v.setFieldU32(sfLedgerSequence, 123456); });
25
26 BEAST_EXPECT(v->isTrusted());
27 v->setUntrusted();
28 BEAST_EXPECT(!v->isTrusted());
29
30 RCLValidation rcv{v};
31 BEAST_EXPECT(!rcv.trusted());
32 rcv.setTrusted();
33 BEAST_EXPECT(rcv.trusted());
34 rcv.setUntrusted();
35 BEAST_EXPECT(!rcv.trusted());
36 }
37
38 void
40 {
41 testcase("RCLValidatedLedger ancestry");
42
43 using Seq = RCLValidatedLedger::Seq;
44 using ID = RCLValidatedLedger::ID;
45
46 // This tests RCLValidatedLedger properly implements the type
47 // requirements of a LedgerTrie ledger, with its added behavior that
48 // only the 256 prior ledger hashes are available to determine ancestry.
49 Seq const maxAncestors = 256;
50
51 //----------------------------------------------------------------------
52 // Generate two ledger histories that agree on the first maxAncestors
53 // ledgers, then diverge.
54
56
57 jtx::Env env(*this);
58 Config config;
61 config,
63 env.app().getNodeFamily());
64 history.push_back(prev);
65 for (auto i = 0; i < (2 * maxAncestors + 1); ++i)
66 {
67 auto next = std::make_shared<Ledger>(
68 *prev, env.app().timeKeeper().closeTime());
69 next->updateSkipList();
70 history.push_back(next);
71 prev = next;
72 }
73
74 // altHistory agrees with first half of regular history
75 Seq const diverge = history.size() / 2;
77 history.begin(), history.begin() + diverge);
78 // advance clock to get new ledgers
79 using namespace std::chrono_literals;
80 env.timeKeeper().set(env.timeKeeper().now() + 1200s);
81 prev = altHistory.back();
82 bool forceHash = true;
83 while (altHistory.size() < history.size())
84 {
85 auto next = std::make_shared<Ledger>(
86 *prev, env.app().timeKeeper().closeTime());
87 // Force a different hash on the first iteration
88 next->updateSkipList();
89 BEAST_EXPECT(next->read(keylet::fees()));
90 if (forceHash)
91 {
92 next->setImmutable();
93 forceHash = false;
94 }
95
96 altHistory.push_back(next);
97 prev = next;
98 }
99
100 //----------------------------------------------------------------------
101
102 // Empty ledger
103 {
105 BEAST_EXPECT(a.seq() == Seq{0});
106 BEAST_EXPECT(a[Seq{0}] == ID{0});
107 BEAST_EXPECT(a.minSeq() == Seq{0});
108 }
109
110 // Full history ledgers
111 {
112 std::shared_ptr<Ledger const> ledger = history.back();
113 RCLValidatedLedger a{ledger, env.journal};
114 BEAST_EXPECT(a.seq() == ledger->info().seq);
115 BEAST_EXPECT(a.minSeq() == a.seq() - maxAncestors);
116 // Ensure the ancestral 256 ledgers have proper ID
117 for (Seq s = a.seq(); s > 0; s--)
118 {
119 if (s >= a.minSeq())
120 BEAST_EXPECT(a[s] == history[s - 1]->info().hash);
121 else
122 BEAST_EXPECT(a[s] == ID{0});
123 }
124 }
125
126 // Mismatch tests
127
128 // Empty with non-empty
129 {
131
132 for (auto ledger : {history.back(), history[maxAncestors - 1]})
133 {
134 RCLValidatedLedger b{ledger, env.journal};
135 BEAST_EXPECT(mismatch(a, b) == 1);
136 BEAST_EXPECT(mismatch(b, a) == 1);
137 }
138 }
139 // Same chains, different seqs
140 {
141 RCLValidatedLedger a{history.back(), env.journal};
142 for (Seq s = a.seq(); s > 0; s--)
143 {
144 RCLValidatedLedger b{history[s - 1], env.journal};
145 if (s >= a.minSeq())
146 {
147 BEAST_EXPECT(mismatch(a, b) == b.seq() + 1);
148 BEAST_EXPECT(mismatch(b, a) == b.seq() + 1);
149 }
150 else
151 {
152 BEAST_EXPECT(mismatch(a, b) == Seq{1});
153 BEAST_EXPECT(mismatch(b, a) == Seq{1});
154 }
155 }
156 }
157 // Different chains, same seqs
158 {
159 // Alt history diverged at history.size()/2
160 for (Seq s = 1; s < history.size(); ++s)
161 {
162 RCLValidatedLedger a{history[s - 1], env.journal};
163 RCLValidatedLedger b{altHistory[s - 1], env.journal};
164
165 BEAST_EXPECT(a.seq() == b.seq());
166 if (s <= diverge)
167 {
168 BEAST_EXPECT(a[a.seq()] == b[b.seq()]);
169 BEAST_EXPECT(mismatch(a, b) == a.seq() + 1);
170 BEAST_EXPECT(mismatch(b, a) == a.seq() + 1);
171 }
172 else
173 {
174 BEAST_EXPECT(a[a.seq()] != b[b.seq()]);
175 BEAST_EXPECT(mismatch(a, b) == diverge + 1);
176 BEAST_EXPECT(mismatch(b, a) == diverge + 1);
177 }
178 }
179 }
180 // Different chains, different seqs
181 {
182 // Compare around the divergence point
183 RCLValidatedLedger a{history[diverge], env.journal};
184 for (Seq offset = diverge / 2; offset < 3 * diverge / 2; ++offset)
185 {
186 RCLValidatedLedger b{altHistory[offset - 1], env.journal};
187 if (offset <= diverge)
188 {
189 BEAST_EXPECT(mismatch(a, b) == b.seq() + 1);
190 }
191 else
192 {
193 BEAST_EXPECT(mismatch(a, b) == diverge + 1);
194 }
195 }
196 }
197 }
198
199 void
201 {
202 testcase("RCLValidatedLedger LedgerTrie");
203
204 // This test exposes an issue with the limited 256
205 // ancestor hash design of RCLValidatedLedger.
206 // There is only a single chain of validated ledgers
207 // but the 256 gap causes a "split" in the LedgerTrie
208 // due to the lack of ancestry information for a later ledger.
209 // This exposes a bug in which we are unable to remove
210 // support for a ledger hash which is already in the trie.
211
212 using Seq = RCLValidatedLedger::Seq;
213
214 // Max known ancestors for each ledger
215 Seq const maxAncestors = 256;
217
218 // Generate a chain of 256 + 10 ledgers
219 jtx::Env env(*this);
220 auto& j = env.journal;
221 Config config;
224 config,
226 env.app().getNodeFamily());
227 history.push_back(prev);
228 for (auto i = 0; i < (maxAncestors + 10); ++i)
229 {
230 auto next = std::make_shared<Ledger>(
231 *prev, env.app().timeKeeper().closeTime());
232 next->updateSkipList();
233 history.push_back(next);
234 prev = next;
235 }
236
238
239 // First, create the single branch trie, with ledgers
240 // separated by exactly 256 ledgers
241 auto ledg_002 = RCLValidatedLedger{history[1], j};
242 auto ledg_258 = RCLValidatedLedger{history[257], j};
243 auto ledg_259 = RCLValidatedLedger{history[258], j};
244
245 trie.insert(ledg_002);
246 trie.insert(ledg_258, 4);
247 // trie.dump(std::cout);
248 // 000000[0,1)(T:0,B:5)
249 // |-AB868A..36C8[1,3)(T:1,B:5)
250 // |-AB868A..37C8[3,259)(T:4,B:4)
251 BEAST_EXPECT(trie.tipSupport(ledg_002) == 1);
252 BEAST_EXPECT(trie.branchSupport(ledg_002) == 5);
253 BEAST_EXPECT(trie.tipSupport(ledg_258) == 4);
254 BEAST_EXPECT(trie.branchSupport(ledg_258) == 4);
255
256 // Move three of the s258 ledgers to s259, which splits the trie
257 // due to the 256 ancestory limit
258 BEAST_EXPECT(trie.remove(ledg_258, 3));
259 trie.insert(ledg_259, 3);
260 trie.getPreferred(1);
261 // trie.dump(std::cout);
262 // 000000[0,1)(T:0,B:5)
263 // |-AB868A..37C9[1,260)(T:3,B:3)
264 // |-AB868A..36C8[1,3)(T:1,B:2)
265 // |-AB868A..37C8[3,259)(T:1,B:1)
266 BEAST_EXPECT(trie.tipSupport(ledg_002) == 1);
267 BEAST_EXPECT(trie.branchSupport(ledg_002) == 2);
268 BEAST_EXPECT(trie.tipSupport(ledg_258) == 1);
269 BEAST_EXPECT(trie.branchSupport(ledg_258) == 1);
270 BEAST_EXPECT(trie.tipSupport(ledg_259) == 3);
271 BEAST_EXPECT(trie.branchSupport(ledg_259) == 3);
272
273 // The last call to trie.getPreferred cycled the children of the root
274 // node to make the new branch the first child (since it has support 3)
275 // then verify the remove call works
276 // past bug: remove had assumed the first child of a node in the trie
277 // which matches is the *only* child in the trie which matches.
278 // This is **NOT** true with the limited 256 ledger ancestory
279 // quirk of RCLValidation and prevents deleting the old support
280 // for ledger 257
281
282 BEAST_EXPECT(
283 trie.remove(RCLValidatedLedger{history[257], env.journal}, 1));
284 trie.insert(RCLValidatedLedger{history[258], env.journal}, 1);
285 trie.getPreferred(1);
286 // trie.dump(std::cout);
287 // 000000[0,1)(T:0,B:5)
288 // |-AB868A..37C9[1,260)(T:4,B:4)
289 // |-AB868A..36C8[1,3)(T:1,B:1)
290 BEAST_EXPECT(trie.tipSupport(ledg_002) == 1);
291 BEAST_EXPECT(trie.branchSupport(ledg_002) == 1);
292 BEAST_EXPECT(trie.tipSupport(ledg_258) == 0);
293 // 258 no longer lives on a tip in the tree, BUT it is an ancestor
294 // of 259 which is a tip and therefore gets it's branchSupport value
295 // implicitly
296 BEAST_EXPECT(trie.branchSupport(ledg_258) == 4);
297 BEAST_EXPECT(trie.tipSupport(ledg_259) == 4);
298 BEAST_EXPECT(trie.branchSupport(ledg_259) == 4);
299 }
300
301public:
302 void
309};
310
311BEAST_DEFINE_TESTSUITE(RCLValidations, app, ripple);
312
313} // namespace test
314} // namespace ripple
T back(T... args)
T begin(T... args)
A testsuite class.
Definition suite.h:52
testcase_t testcase
Memberspace for declaring test cases.
Definition suite.h:152
virtual TimeKeeper & timeKeeper()=0
Ancestry trie of ledgers.
Definition LedgerTrie.h:332
std::uint32_t tipSupport(Ledger const &ledger) const
Return count of tip support for the specific ledger.
Definition LedgerTrie.h:578
void insert(Ledger const &ledger, std::uint32_t count=1)
Insert and/or increment the support for the given ledger.
Definition LedgerTrie.h:434
std::optional< SpanTip< Ledger > > getPreferred(Seq const largestIssued) const
Return the preferred ledger ID.
Definition LedgerTrie.h:666
std::uint32_t branchSupport(Ledger const &ledger) const
Return the count of branch support for the specific ledger.
Definition LedgerTrie.h:592
bool remove(Ledger const &ledger, std::uint32_t count=1)
Decrease support for a ledger, removing and compressing if possible.
Definition LedgerTrie.h:522
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:57
time_point now() const override
Returns the current time.
void run() override
Runs the suite.
A transaction testing environment.
Definition Env.h:102
Application & app()
Definition Env.h:242
beast::Journal const journal
Definition Env.h:143
ManualTimeKeeper & timeKeeper()
Definition Env.h:254
T is_same_v
Keylet const & fees() noexcept
The (fixed) index of the object containing the ledger fees.
Definition Indexes.cpp:203
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:6
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:32
std::pair< PublicKey, SecretKey > randomKeyPair(KeyType type)
Create a key pair using secure random numbers.
T push_back(T... args)
T size(T... args)