rippled
Loading...
Searching...
No Matches
RCLValidations_test.cpp
1#include <test/jtx.h>
2
3#include <xrpld/app/consensus/RCLValidations.h>
4
5#include <xrpl/basics/base_uint.h>
6#include <xrpl/beast/unit_test.h>
7#include <xrpl/ledger/Ledger.h>
8
9namespace xrpl {
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 const config;
61 Rules{config.features},
62 config.FEES.toFees(),
64 env.app().getNodeFamily());
65 history.push_back(prev);
66 for (auto i = 0; i < ((2 * maxAncestors) + 1); ++i)
67 {
68 auto next = std::make_shared<Ledger>(*prev, env.app().getTimeKeeper().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>(*prev, env.app().getTimeKeeper().closeTime());
86 // Force a different hash on the first iteration
87 next->updateSkipList();
88 BEAST_EXPECT(next->read(keylet::fees()));
89 if (forceHash)
90 {
91 next->setImmutable();
92 forceHash = false;
93 }
94
95 altHistory.push_back(next);
96 prev = next;
97 }
98
99 //----------------------------------------------------------------------
100
101 // Empty ledger
102 {
104 BEAST_EXPECT(a.seq() == Seq{0});
105 BEAST_EXPECT(a[Seq{0}] == ID{0});
106 BEAST_EXPECT(a.minSeq() == Seq{0});
107 }
108
109 // Full history ledgers
110 {
111 std::shared_ptr<Ledger const> const ledger = history.back();
112 RCLValidatedLedger const a{ledger, env.journal};
113 BEAST_EXPECT(a.seq() == ledger->header().seq);
114 BEAST_EXPECT(a.minSeq() == a.seq() - maxAncestors);
115 // Ensure the ancestral 256 ledgers have proper ID
116 for (Seq s = a.seq(); s > 0; s--)
117 {
118 if (s >= a.minSeq())
119 {
120 BEAST_EXPECT(a[s] == history[s - 1]->header().hash);
121 }
122 else
123 {
124 BEAST_EXPECT(a[s] == ID{0});
125 }
126 }
127 }
128
129 // Mismatch tests
130
131 // Empty with non-empty
132 {
134
135 for (auto const& ledger : {history.back(), history[maxAncestors - 1]})
136 {
137 RCLValidatedLedger const b{ledger, env.journal};
138 BEAST_EXPECT(mismatch(a, b) == 1);
139 BEAST_EXPECT(mismatch(b, a) == 1);
140 }
141 }
142 // Same chains, different seqs
143 {
144 RCLValidatedLedger const a{history.back(), env.journal};
145 for (Seq s = a.seq(); s > 0; s--)
146 {
147 RCLValidatedLedger const b{history[s - 1], env.journal};
148 if (s >= a.minSeq())
149 {
150 BEAST_EXPECT(mismatch(a, b) == b.seq() + 1);
151 BEAST_EXPECT(mismatch(b, a) == b.seq() + 1);
152 }
153 else
154 {
155 BEAST_EXPECT(mismatch(a, b) == Seq{1});
156 BEAST_EXPECT(mismatch(b, a) == Seq{1});
157 }
158 }
159 }
160 // Different chains, same seqs
161 {
162 // Alt history diverged at history.size()/2
163 for (Seq s = 1; s < history.size(); ++s)
164 {
165 RCLValidatedLedger const a{history[s - 1], env.journal};
166 RCLValidatedLedger const b{altHistory[s - 1], env.journal};
167
168 BEAST_EXPECT(a.seq() == b.seq());
169 if (s <= diverge)
170 {
171 BEAST_EXPECT(a[a.seq()] == b[b.seq()]);
172 BEAST_EXPECT(mismatch(a, b) == a.seq() + 1);
173 BEAST_EXPECT(mismatch(b, a) == a.seq() + 1);
174 }
175 else
176 {
177 BEAST_EXPECT(a[a.seq()] != b[b.seq()]);
178 BEAST_EXPECT(mismatch(a, b) == diverge + 1);
179 BEAST_EXPECT(mismatch(b, a) == diverge + 1);
180 }
181 }
182 }
183 // Different chains, different seqs
184 {
185 // Compare around the divergence point
186 RCLValidatedLedger const a{history[diverge], env.journal};
187 for (Seq offset = diverge / 2; offset < 3 * diverge / 2; ++offset)
188 {
189 RCLValidatedLedger const b{altHistory[offset - 1], env.journal};
190 if (offset <= diverge)
191 {
192 BEAST_EXPECT(mismatch(a, b) == b.seq() + 1);
193 }
194 else
195 {
196 BEAST_EXPECT(mismatch(a, b) == diverge + 1);
197 }
198 }
199 }
200 }
201
202 void
204 {
205 testcase("RCLValidatedLedger LedgerTrie");
206
207 // This test exposes an issue with the limited 256
208 // ancestor hash design of RCLValidatedLedger.
209 // There is only a single chain of validated ledgers
210 // but the 256 gap causes a "split" in the LedgerTrie
211 // due to the lack of ancestry information for a later ledger.
212 // This exposes a bug in which we are unable to remove
213 // support for a ledger hash which is already in the trie.
214
215 using Seq = RCLValidatedLedger::Seq;
216
217 // Max known ancestors for each ledger
218 Seq const maxAncestors = 256;
220
221 // Generate a chain of 256 + 10 ledgers
222 jtx::Env env(*this);
223 auto& j = env.journal;
224 Config const config;
227 Rules{config.features},
228 config.FEES.toFees(),
230 env.app().getNodeFamily());
231 history.push_back(prev);
232 for (auto i = 0; i < (maxAncestors + 10); ++i)
233 {
234 auto next = std::make_shared<Ledger>(*prev, env.app().getTimeKeeper().closeTime());
235 next->updateSkipList();
236 history.push_back(next);
237 prev = next;
238 }
239
241
242 // First, create the single branch trie, with ledgers
243 // separated by exactly 256 ledgers
244 auto ledg_002 = RCLValidatedLedger{history[1], j};
245 auto ledg_258 = RCLValidatedLedger{history[257], j};
246 auto ledg_259 = RCLValidatedLedger{history[258], j};
247
248 trie.insert(ledg_002);
249 trie.insert(ledg_258, 4);
250 // trie.dump(std::cout);
251 // 000000[0,1)(T:0,B:5)
252 // |-AB868A..36C8[1,3)(T:1,B:5)
253 // |-AB868A..37C8[3,259)(T:4,B:4)
254 BEAST_EXPECT(trie.tipSupport(ledg_002) == 1);
255 BEAST_EXPECT(trie.branchSupport(ledg_002) == 5);
256 BEAST_EXPECT(trie.tipSupport(ledg_258) == 4);
257 BEAST_EXPECT(trie.branchSupport(ledg_258) == 4);
258
259 // Move three of the s258 ledgers to s259, which splits the trie
260 // due to the 256 ancestry limit
261 BEAST_EXPECT(trie.remove(ledg_258, 3));
262 trie.insert(ledg_259, 3);
263 trie.getPreferred(1);
264 // trie.dump(std::cout);
265 // 000000[0,1)(T:0,B:5)
266 // |-AB868A..37C9[1,260)(T:3,B:3)
267 // |-AB868A..36C8[1,3)(T:1,B:2)
268 // |-AB868A..37C8[3,259)(T:1,B:1)
269 BEAST_EXPECT(trie.tipSupport(ledg_002) == 1);
270 BEAST_EXPECT(trie.branchSupport(ledg_002) == 2);
271 BEAST_EXPECT(trie.tipSupport(ledg_258) == 1);
272 BEAST_EXPECT(trie.branchSupport(ledg_258) == 1);
273 BEAST_EXPECT(trie.tipSupport(ledg_259) == 3);
274 BEAST_EXPECT(trie.branchSupport(ledg_259) == 3);
275
276 // The last call to trie.getPreferred cycled the children of the root
277 // node to make the new branch the first child (since it has support 3)
278 // then verify the remove call works
279 // past bug: remove had assumed the first child of a node in the trie
280 // which matches is the *only* child in the trie which matches.
281 // This is **NOT** true with the limited 256 ledger ancestry
282 // quirk of RCLValidation and prevents deleting the old support
283 // for ledger 257
284
285 BEAST_EXPECT(trie.remove(RCLValidatedLedger{history[257], env.journal}, 1));
286 trie.insert(RCLValidatedLedger{history[258], env.journal}, 1);
287 trie.getPreferred(1);
288 // trie.dump(std::cout);
289 // 000000[0,1)(T:0,B:5)
290 // |-AB868A..37C9[1,260)(T:4,B:4)
291 // |-AB868A..36C8[1,3)(T:1,B:1)
292 BEAST_EXPECT(trie.tipSupport(ledg_002) == 1);
293 BEAST_EXPECT(trie.branchSupport(ledg_002) == 1);
294 BEAST_EXPECT(trie.tipSupport(ledg_258) == 0);
295 // 258 no longer lives on a tip in the tree, BUT it is an ancestor
296 // of 259 which is a tip and therefore gets it's branchSupport value
297 // implicitly
298 BEAST_EXPECT(trie.branchSupport(ledg_258) == 4);
299 BEAST_EXPECT(trie.tipSupport(ledg_259) == 4);
300 BEAST_EXPECT(trie.branchSupport(ledg_259) == 4);
301 }
302
303public:
304 void
311};
312
313BEAST_DEFINE_TESTSUITE(RCLValidations, app, xrpl);
314
315} // namespace test
316} // namespace xrpl
T back(T... args)
T begin(T... args)
A testsuite class.
Definition suite.h:51
testcase_t testcase
Memberspace for declaring test cases.
Definition suite.h:150
std::unordered_set< uint256, beast::uhash<> > features
Definition Config.h:261
FeeSetup FEES
Definition Config.h:189
Ancestry trie of ledgers.
Definition LedgerTrie.h:324
std::uint32_t tipSupport(Ledger const &ledger) const
Return count of tip support for the specific ledger.
Definition LedgerTrie.h:568
std::uint32_t branchSupport(Ledger const &ledger) const
Return the count of branch support for the specific ledger.
Definition LedgerTrie.h:582
std::optional< SpanTip< Ledger > > getPreferred(Seq const largestIssued) const
Return the preferred ledger ID.
Definition LedgerTrie.h:656
void insert(Ledger const &ledger, std::uint32_t count=1)
Insert and/or increment the support for the given ledger.
Definition LedgerTrie.h:426
bool remove(Ledger const &ledger, std::uint32_t count=1)
Decrease support for a ledger, removing and compressing if possible.
Definition LedgerTrie.h:512
Wraps a ledger instance for use in generic Validations LedgerTrie.
Wrapper over STValidation for generic Validation code.
Rules controlling protocol behavior.
Definition Rules.h:18
virtual TimeKeeper & getTimeKeeper()=0
time_point closeTime() const
Returns the predicted close time, in network time.
Definition TimeKeeper.h:56
time_point now() const override
Returns the current time.
void run() override
Runs the suite.
A transaction testing environment.
Definition Env.h:122
Application & app()
Definition Env.h:259
ManualTimeKeeper & timeKeeper()
Definition Env.h:271
beast::Journal const journal
Definition Env.h:163
T is_same_v
Keylet const & fees() noexcept
The (fixed) index of the object containing the ledger fees.
Definition Indexes.cpp:200
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
std::pair< PublicKey, SecretKey > randomKeyPair(KeyType type)
Create a key pair using secure random numbers.
create_genesis_t const create_genesis
NodeID calcNodeID(PublicKey const &)
Calculate the 160-bit node ID from a node public key.
RCLValidatedLedger::Seq mismatch(RCLValidatedLedger const &a, RCLValidatedLedger const &b)
T push_back(T... args)
T size(T... args)
Fees toFees() const
Convert to a Fees object for use with Ledger construction.
Definition Config.h:64