rippled
Loading...
Searching...
No Matches
collectors.h
1//------------------------------------------------------------------------------
2/*
3 This file is part of rippled: https://github.com/ripple/rippled
4 Copyright (c) 2012-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#ifndef RIPPLE_TEST_CSF_COLLECTORS_H_INCLUDED
21#define RIPPLE_TEST_CSF_COLLECTORS_H_INCLUDED
22
23#include <test/csf/Histogram.h>
24#include <test/csf/SimTime.h>
25#include <test/csf/events.h>
26
27#include <xrpl/basics/UnorderedContainers.h>
28
29#include <chrono>
30#include <optional>
31#include <ostream>
32#include <tuple>
33
34namespace ripple {
35namespace test {
36namespace csf {
37
38// A collector is any class that implements
39//
40// on(NodeID, SimTime, Event)
41//
42// for all events emitted by a Peer.
43//
44// This file contains helper functions for composing different collectors
45// and also defines several standard collectors available for simulations.
46
54template <class... Cs>
56{
57 std::tuple<Cs&...> cs;
58
59 template <class C, class E>
60 static void
61 apply(C& c, PeerID who, SimTime when, E e)
62 {
63 c.on(who, when, e);
64 }
65
66 template <std::size_t... Is, class E>
67 static void
70 PeerID who,
71 SimTime when,
72 E e,
74 {
75 (..., apply(std::get<Is>(cs), who, when, e));
76 }
77
78public:
83 Collectors(Cs&... cs_) : cs(std::tie(cs_...))
84 {
85 }
86
87 template <class E>
88 void
89 on(PeerID who, SimTime when, E e)
90 {
91 apply(cs, who, when, e, std::index_sequence_for<Cs...>{});
92 }
93};
94
96template <class... Cs>
97Collectors<Cs...>
99{
100 return Collectors<Cs...>(cs...);
101}
102
111template <class CollectorType>
113{
115
116 CollectorType&
118 {
119 return byNode[who];
120 }
121
122 CollectorType const&
124 {
125 return byNode[who];
126 }
127 template <class E>
128 void
129 on(PeerID who, SimTime when, E const& e)
130 {
131 byNode[who].on(who, when, e);
132 }
133};
134
137{
138 template <class E>
139 void
140 on(PeerID, SimTime, E const& e)
141 {
142 }
143};
144
147{
148 bool init = false;
151
152 template <class E>
153 void
154 on(PeerID, SimTime when, E const& e)
155 {
156 if (!init)
157 {
158 start = when;
159 init = true;
160 }
161 else
162 stop = when;
163 }
164};
165
176{
177 // Counts
181
182 struct Tracker
183 {
188
189 Tracker(Tx tx_, SimTime submitted_) : tx{tx_}, submitted{submitted_}
190 {
191 }
192 };
193
195
199
200 // Ignore most events by default
201 template <class E>
202 void
203 on(PeerID, SimTime when, E const& e)
204 {
205 }
206
207 void
208 on(PeerID who, SimTime when, SubmitTx const& e)
209 {
210 // save first time it was seen
211 if (txs.emplace(e.tx.id(), Tracker{e.tx, when}).second)
212 {
213 submitted++;
214 }
215 }
216
217 void
218 on(PeerID who, SimTime when, AcceptLedger const& e)
219 {
220 for (auto const& tx : e.ledger.txs())
221 {
222 auto it = txs.find(tx.id());
223 if (it != txs.end() && !it->second.accepted)
224 {
225 Tracker& tracker = it->second;
226 tracker.accepted = when;
227 accepted++;
228
229 submitToAccept.insert(*tracker.accepted - tracker.submitted);
230 }
231 }
232 }
233
234 void
236 {
237 for (auto const& tx : e.ledger.txs())
238 {
239 auto it = txs.find(tx.id());
240 if (it != txs.end() && !it->second.validated)
241 {
242 Tracker& tracker = it->second;
243 // Should only validated a previously accepted Tx
244 assert(tracker.accepted);
245
246 tracker.validated = when;
247 validated++;
248 submitToValidate.insert(*tracker.validated - tracker.submitted);
249 }
250 }
251 }
252
253 // Returns the number of txs which were never accepted
255 orphaned() const
256 {
257 return std::count_if(txs.begin(), txs.end(), [](auto const& it) {
258 return !it.second.accepted;
259 });
260 }
261
262 // Returns the number of txs which were never validated
265 {
266 return std::count_if(txs.begin(), txs.end(), [](auto const& it) {
267 return !it.second.validated;
268 });
269 }
270
271 template <class T>
272 void
273 report(SimDuration simDuration, T& log, bool printBreakline = false)
274 {
275 using namespace std::chrono;
276 auto perSec = [&simDuration](std::size_t count) {
277 return double(count) / duration_cast<seconds>(simDuration).count();
278 };
279
280 auto fmtS = [](SimDuration dur) {
281 return duration_cast<duration<float>>(dur).count();
282 };
283
284 if (printBreakline)
285 {
286 log << std::setw(11) << std::setfill('-') << "-" << "-"
287 << std::setw(7) << std::setfill('-') << "-" << "-"
288 << std::setw(7) << std::setfill('-') << "-" << "-"
289 << std::setw(36) << std::setfill('-') << "-" << std::endl;
290 log << std::setfill(' ');
291 }
292
293 log << std::left << std::setw(11) << "TxStats" << "|" << std::setw(7)
294 << "Count" << "|" << std::setw(7) << "Per Sec" << "|"
295 << std::setw(15) << "Latency (sec)" << std::right << std::setw(7)
296 << "10-ile" << std::setw(7) << "50-ile" << std::setw(7) << "90-ile"
297 << std::left << std::endl;
298
299 log << std::setw(11) << std::setfill('-') << "-" << "|" << std::setw(7)
300 << std::setfill('-') << "-" << "|" << std::setw(7)
301 << std::setfill('-') << "-" << "|" << std::setw(36)
302 << std::setfill('-') << "-" << std::endl;
303 log << std::setfill(' ');
304
305 log << std::left << std::setw(11) << "Submit " << "|" << std::right
306 << std::setw(7) << submitted << "|" << std::setw(7)
307 << std::setprecision(2) << perSec(submitted) << "|" << std::setw(36)
308 << "" << std::endl;
309
310 log << std::left << std::setw(11) << "Accept " << "|" << std::right
311 << std::setw(7) << accepted << "|" << std::setw(7)
312 << std::setprecision(2) << perSec(accepted) << "|" << std::setw(15)
313 << std::left << "From Submit" << std::right << std::setw(7)
314 << std::setprecision(2) << fmtS(submitToAccept.percentile(0.1f))
315 << std::setw(7) << std::setprecision(2)
316 << fmtS(submitToAccept.percentile(0.5f)) << std::setw(7)
317 << std::setprecision(2) << fmtS(submitToAccept.percentile(0.9f))
318 << std::endl;
319
320 log << std::left << std::setw(11) << "Validate " << "|" << std::right
321 << std::setw(7) << validated << "|" << std::setw(7)
322 << std::setprecision(2) << perSec(validated) << "|" << std::setw(15)
323 << std::left << "From Submit" << std::right << std::setw(7)
325 << std::setw(7) << std::setprecision(2)
326 << fmtS(submitToValidate.percentile(0.5f)) << std::setw(7)
328 << std::endl;
329
330 log << std::left << std::setw(11) << "Orphan" << "|" << std::right
331 << std::setw(7) << orphaned() << "|" << std::setw(7) << "" << "|"
332 << std::setw(36) << std::endl;
333
334 log << std::left << std::setw(11) << "Unvalidated" << "|" << std::right
335 << std::setw(7) << unvalidated() << "|" << std::setw(7) << "" << "|"
336 << std::setw(43) << std::endl;
337
338 log << std::setw(11) << std::setfill('-') << "-" << "-" << std::setw(7)
339 << std::setfill('-') << "-" << "-" << std::setw(7)
340 << std::setfill('-') << "-" << "-" << std::setw(36)
341 << std::setfill('-') << "-" << std::endl;
342 log << std::setfill(' ');
343 }
344
345 template <class T, class Tag>
346 void
347 csv(SimDuration simDuration,
348 T& log,
349 Tag const& tag,
350 bool printHeaders = false)
351 {
352 using namespace std::chrono;
353 auto perSec = [&simDuration](std::size_t count) {
354 return double(count) / duration_cast<seconds>(simDuration).count();
355 };
356
357 auto fmtS = [](SimDuration dur) {
358 return duration_cast<duration<float>>(dur).count();
359 };
360
361 if (printHeaders)
362 {
363 log << "tag" << "," << "txNumSubmitted" << "," << "txNumAccepted"
364 << "," << "txNumValidated" << "," << "txNumOrphaned" << ","
365 << "txUnvalidated" << "," << "txRateSumbitted" << ","
366 << "txRateAccepted" << "," << "txRateValidated" << ","
367 << "txLatencySubmitToAccept10Pctl" << ","
368 << "txLatencySubmitToAccept50Pctl" << ","
369 << "txLatencySubmitToAccept90Pctl" << ","
370 << "txLatencySubmitToValidatet10Pctl" << ","
371 << "txLatencySubmitToValidatet50Pctl" << ","
372 << "txLatencySubmitToValidatet90Pctl" << std::endl;
373 }
374
375 log << tag
376 << ","
377 // txNumSubmitted
378 << submitted
379 << ","
380 // txNumAccepted
381 << accepted
382 << ","
383 // txNumValidated
384 << validated
385 << ","
386 // txNumOrphaned
387 << orphaned()
388 << ","
389 // txNumUnvalidated
390 << unvalidated()
391 << ","
392 // txRateSubmitted
393 << std::setprecision(2) << perSec(submitted)
394 << ","
395 // txRateAccepted
396 << std::setprecision(2) << perSec(accepted)
397 << ","
398 // txRateValidated
399 << std::setprecision(2) << perSec(validated)
400 << ","
401 // txLatencySubmitToAccept10Pctl
402 << std::setprecision(2) << fmtS(submitToAccept.percentile(0.1f))
403 << ","
404 // txLatencySubmitToAccept50Pctl
405 << std::setprecision(2) << fmtS(submitToAccept.percentile(0.5f))
406 << ","
407 // txLatencySubmitToAccept90Pctl
408 << std::setprecision(2) << fmtS(submitToAccept.percentile(0.9f))
409 << ","
410 // txLatencySubmitToValidate10Pctl
412 << ","
413 // txLatencySubmitToValidate50Pctl
415 << ","
416 // txLatencySubmitToValidate90Pctl
418 << "," << std::endl;
419 }
420};
421
429{
432
433 struct Tracker
434 {
437
438 Tracker(SimTime accepted_) : accepted{accepted_}
439 {
440 }
441 };
442
444
449
450 // Ignore most events by default
451 template <class E>
452 void
453 on(PeerID, SimTime, E const& e)
454 {
455 }
456
457 void
458 on(PeerID who, SimTime when, AcceptLedger const& e)
459 {
460 // First time this ledger accepted
461 if (ledgers_.emplace(e.ledger.id(), Tracker{when}).second)
462 {
463 ++accepted;
464 // ignore jumps?
465 if (e.prior.id() == e.ledger.parentID())
466 {
467 auto const it = ledgers_.find(e.ledger.parentID());
468 if (it != ledgers_.end())
469 {
470 acceptToAccept.insert(when - it->second.accepted);
471 }
472 }
473 }
474 }
475
476 void
478 {
479 // ignore jumps
480 if (e.prior.id() == e.ledger.parentID())
481 {
482 auto const it = ledgers_.find(e.ledger.id());
483 assert(it != ledgers_.end());
484 auto& tracker = it->second;
485 // first time fully validated
486 if (!tracker.fullyValidated)
487 {
489 tracker.fullyValidated = when;
490 acceptToFullyValid.insert(when - tracker.accepted);
491
492 auto const parentIt = ledgers_.find(e.ledger.parentID());
493 if (parentIt != ledgers_.end())
494 {
495 auto& parentTracker = parentIt->second;
496 if (parentTracker.fullyValidated)
497 {
499 when - *parentTracker.fullyValidated);
500 }
501 }
502 }
503 }
504 }
505
508 {
509 return std::count_if(
510 ledgers_.begin(), ledgers_.end(), [](auto const& it) {
511 return !it.second.fullyValidated;
512 });
513 }
514
515 template <class T>
516 void
517 report(SimDuration simDuration, T& log, bool printBreakline = false)
518 {
519 using namespace std::chrono;
520 auto perSec = [&simDuration](std::size_t count) {
521 return double(count) / duration_cast<seconds>(simDuration).count();
522 };
523
524 auto fmtS = [](SimDuration dur) {
525 return duration_cast<duration<float>>(dur).count();
526 };
527
528 if (printBreakline)
529 {
530 log << std::setw(11) << std::setfill('-') << "-" << "-"
531 << std::setw(7) << std::setfill('-') << "-" << "-"
532 << std::setw(7) << std::setfill('-') << "-" << "-"
533 << std::setw(36) << std::setfill('-') << "-" << std::endl;
534 log << std::setfill(' ');
535 }
536
537 log << std::left << std::setw(11) << "LedgerStats" << "|"
538 << std::setw(7) << "Count" << "|" << std::setw(7) << "Per Sec"
539 << "|" << std::setw(15) << "Latency (sec)" << std::right
540 << std::setw(7) << "10-ile" << std::setw(7) << "50-ile"
541 << std::setw(7) << "90-ile" << std::left << std::endl;
542
543 log << std::setw(11) << std::setfill('-') << "-" << "|" << std::setw(7)
544 << std::setfill('-') << "-" << "|" << std::setw(7)
545 << std::setfill('-') << "-" << "|" << std::setw(36)
546 << std::setfill('-') << "-" << std::endl;
547 log << std::setfill(' ');
548
549 log << std::left << std::setw(11) << "Accept " << "|" << std::right
550 << std::setw(7) << accepted << "|" << std::setw(7)
551 << std::setprecision(2) << perSec(accepted) << "|" << std::setw(15)
552 << std::left << "From Accept" << std::right << std::setw(7)
553 << std::setprecision(2) << fmtS(acceptToAccept.percentile(0.1f))
554 << std::setw(7) << std::setprecision(2)
555 << fmtS(acceptToAccept.percentile(0.5f)) << std::setw(7)
556 << std::setprecision(2) << fmtS(acceptToAccept.percentile(0.9f))
557 << std::endl;
558
559 log << std::left << std::setw(11) << "Validate " << "|" << std::right
560 << std::setw(7) << fullyValidated << "|" << std::setw(7)
561 << std::setprecision(2) << perSec(fullyValidated) << "|"
562 << std::setw(15) << std::left << "From Validate " << std::right
563 << std::setw(7) << std::setprecision(2)
564 << fmtS(fullyValidToFullyValid.percentile(0.1f)) << std::setw(7)
566 << fmtS(fullyValidToFullyValid.percentile(0.5f)) << std::setw(7)
569
570 log << std::setw(11) << std::setfill('-') << "-" << "-" << std::setw(7)
571 << std::setfill('-') << "-" << "-" << std::setw(7)
572 << std::setfill('-') << "-" << "-" << std::setw(36)
573 << std::setfill('-') << "-" << std::endl;
574 log << std::setfill(' ');
575 }
576
577 template <class T, class Tag>
578 void
579 csv(SimDuration simDuration,
580 T& log,
581 Tag const& tag,
582 bool printHeaders = false)
583 {
584 using namespace std::chrono;
585 auto perSec = [&simDuration](std::size_t count) {
586 return double(count) / duration_cast<seconds>(simDuration).count();
587 };
588
589 auto fmtS = [](SimDuration dur) {
590 return duration_cast<duration<float>>(dur).count();
591 };
592
593 if (printHeaders)
594 {
595 log << "tag" << "," << "ledgerNumAccepted" << ","
596 << "ledgerNumFullyValidated" << "," << "ledgerRateAccepted"
597 << "," << "ledgerRateFullyValidated" << ","
598 << "ledgerLatencyAcceptToAccept10Pctl" << ","
599 << "ledgerLatencyAcceptToAccept50Pctl" << ","
600 << "ledgerLatencyAcceptToAccept90Pctl" << ","
601 << "ledgerLatencyFullyValidToFullyValid10Pctl" << ","
602 << "ledgerLatencyFullyValidToFullyValid50Pctl" << ","
603 << "ledgerLatencyFullyValidToFullyValid90Pctl" << std::endl;
604 }
605
606 log << tag
607 << ","
608 // ledgerNumAccepted
609 << accepted
610 << ","
611 // ledgerNumFullyValidated
613 << ","
614 // ledgerRateAccepted
615 << std::setprecision(2) << perSec(accepted)
616 << ","
617 // ledgerRateFullyValidated
618 << std::setprecision(2) << perSec(fullyValidated)
619 << ","
620 // ledgerLatencyAcceptToAccept10Pctl
621 << std::setprecision(2) << fmtS(acceptToAccept.percentile(0.1f))
622 << ","
623 // ledgerLatencyAcceptToAccept50Pctl
624 << std::setprecision(2) << fmtS(acceptToAccept.percentile(0.5f))
625 << ","
626 // ledgerLatencyAcceptToAccept90Pctl
627 << std::setprecision(2) << fmtS(acceptToAccept.percentile(0.9f))
628 << ","
629 // ledgerLatencyFullyValidToFullyValid10Pctl
632 << ","
633 // ledgerLatencyFullyValidToFullyValid50Pctl
636 << ","
637 // ledgerLatencyFullyValidToFullyValid90Pctl
640 }
641};
642
649{
651
652 // Ignore most events by default
653 template <class E>
654 void
655 on(PeerID, SimTime, E const& e)
656 {
657 }
658
659 void
660 on(PeerID who, SimTime when, AcceptLedger const& e)
661 {
662 out << when.time_since_epoch().count() << ": Node " << who
663 << " accepted " << "L" << e.ledger.id() << " " << e.ledger.txs()
664 << "\n";
665 }
666
667 void
669 {
670 out << when.time_since_epoch().count() << ": Node " << who
671 << " fully-validated " << "L" << e.ledger.id() << " "
672 << e.ledger.txs() << "\n";
673 }
674};
675
682{
683 struct Jump
684 {
689 };
690
693
694 // Ignore most events by default
695 template <class E>
696 void
697 on(PeerID, SimTime, E const& e)
698 {
699 }
700
701 void
702 on(PeerID who, SimTime when, AcceptLedger const& e)
703 {
704 // Not a direct child -> parent switch
705 if (e.ledger.parentID() != e.prior.id())
706 closeJumps.emplace_back(Jump{who, when, e.prior, e.ledger});
707 }
708
709 void
711 {
712 // Not a direct child -> parent switch
713 if (e.ledger.parentID() != e.prior.id())
714 fullyValidatedJumps.emplace_back(
715 Jump{who, when, e.prior, e.ledger});
716 }
717};
718
719} // namespace csf
720} // namespace test
721} // namespace ripple
722
723#endif
Group of collectors.
Definition: collectors.h:56
static void apply(std::tuple< Cs &... > &cs, PeerID who, SimTime when, E e, std::index_sequence< Is... >)
Definition: collectors.h:68
std::tuple< Cs &... > cs
Definition: collectors.h:57
static void apply(C &c, PeerID who, SimTime when, E e)
Definition: collectors.h:61
void on(PeerID who, SimTime when, E e)
Definition: collectors.h:89
Collectors(Cs &... cs_)
Constructor.
Definition: collectors.h:83
void insert(T const &s)
Insert an sample.
Definition: Histogram.h:55
T percentile(float p) const
Calculate the given percentile of the distribution.
Definition: Histogram.h:112
A ledger is a set of observed transactions and a sequence number identifying the ledger.
Definition: ledgers.h:64
TxSetType const & txs() const
Definition: ledgers.h:214
A single transaction.
Definition: Tx.h:42
ID const & id() const
Definition: Tx.h:56
T count_if(T... args)
T endl(T... args)
T left(T... args)
typename SimClock::duration SimDuration
Definition: SimTime.h:36
typename SimClock::time_point SimTime
Definition: SimTime.h:37
Collectors< Cs... > makeCollectors(Cs &... cs)
Create an instance of Collectors<Cs...>
Definition: collectors.h:98
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
STL namespace.
T setfill(T... args)
T setprecision(T... args)
T setw(T... args)
Peer accepted consensus results.
Definition: events.h:121
Maintain an instance of a Collector per peer.
Definition: collectors.h:113
CollectorType const & operator[](PeerID who) const
Definition: collectors.h:123
void on(PeerID who, SimTime when, E const &e)
Definition: collectors.h:129
std::map< PeerID, CollectorType > byNode
Definition: collectors.h:114
CollectorType & operator[](PeerID who)
Definition: collectors.h:117
Peer fully validated a new ledger.
Definition: events.h:140
Ledger prior
The prior fully validated ledger This is a jump if prior.id() != ledger.parentID()
Definition: events.h:146
Ledger ledger
The new fully validated ledger.
Definition: events.h:142
Saves information about Jumps for closed and fully validated ledgers.
Definition: collectors.h:682
std::vector< Jump > fullyValidatedJumps
Definition: collectors.h:692
void on(PeerID who, SimTime when, AcceptLedger const &e)
Definition: collectors.h:702
void on(PeerID, SimTime, E const &e)
Definition: collectors.h:697
void on(PeerID who, SimTime when, FullyValidateLedger const &e)
Definition: collectors.h:710
std::vector< Jump > closeJumps
Definition: collectors.h:691
std::optional< SimTime > fullyValidated
Definition: collectors.h:436
Tracks the accepted -> validated evolution of ledgers.
Definition: collectors.h:429
void on(PeerID, SimTime, E const &e)
Definition: collectors.h:453
void on(PeerID who, SimTime when, AcceptLedger const &e)
Definition: collectors.h:458
std::size_t unvalidated() const
Definition: collectors.h:507
hash_map< Ledger::ID, Tracker > ledgers_
Definition: collectors.h:443
void report(SimDuration simDuration, T &log, bool printBreakline=false)
Definition: collectors.h:517
void csv(SimDuration simDuration, T &log, Tag const &tag, bool printHeaders=false)
Definition: collectors.h:579
void on(PeerID who, SimTime when, FullyValidateLedger const &e)
Definition: collectors.h:477
Collector which ignores all events.
Definition: collectors.h:137
void on(PeerID, SimTime, E const &e)
Definition: collectors.h:140
Tracks the overall duration of a simulation.
Definition: collectors.h:147
void on(PeerID, SimTime when, E const &e)
Definition: collectors.h:154
Write out stream of ledger activity.
Definition: collectors.h:649
void on(PeerID who, SimTime when, AcceptLedger const &e)
Definition: collectors.h:660
void on(PeerID, SimTime, E const &e)
Definition: collectors.h:655
void on(PeerID who, SimTime when, FullyValidateLedger const &e)
Definition: collectors.h:668
A transaction submitted to a peer.
Definition: events.h:92
Tx tx
The submitted transaction.
Definition: events.h:94
std::optional< SimTime > accepted
Definition: collectors.h:186
std::optional< SimTime > validated
Definition: collectors.h:187
Tracker(Tx tx_, SimTime submitted_)
Definition: collectors.h:189
Tracks the submission -> accepted -> validated evolution of transactions.
Definition: collectors.h:176
std::size_t orphaned() const
Definition: collectors.h:255
hash_map< Tx::ID, Tracker > txs
Definition: collectors.h:194
void on(PeerID who, SimTime when, SubmitTx const &e)
Definition: collectors.h:208
void csv(SimDuration simDuration, T &log, Tag const &tag, bool printHeaders=false)
Definition: collectors.h:347
std::size_t unvalidated() const
Definition: collectors.h:264
void report(SimDuration simDuration, T &log, bool printBreakline=false)
Definition: collectors.h:273
void on(PeerID, SimTime when, E const &e)
Definition: collectors.h:203
void on(PeerID who, SimTime when, FullyValidateLedger const &e)
Definition: collectors.h:235
void on(PeerID who, SimTime when, AcceptLedger const &e)
Definition: collectors.h:218