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