diff --git a/src/test/consensus/SteppingCsf_test.cpp b/src/test/consensus/SteppingCsf_test.cpp index e489692e3d..3cb59e8f6d 100644 --- a/src/test/consensus/SteppingCsf_test.cpp +++ b/src/test/consensus/SteppingCsf_test.cpp @@ -4,6 +4,7 @@ // cases keep the same scenario intent but run real Application/LedgerMaster/ // PeerImp/JobQueue code through SteppingNetwork. //------------------------------------------------------------------------------ +#include #include #include #include @@ -26,84 +27,14 @@ class SteppingCsf_test : public beast::unit_test::suite { // Xahaud's acquisition timeline; semantic lag/fork and replay checks below // are retained alongside this target-specific snapshot. - static constexpr std::uint64_t kSlowMinorityFingerprint = - 0x25ec64d383356379ull; - static constexpr std::uint64_t kHubNetworkFingerprint = - 0x182601635f5b0308ull; - static constexpr std::uint64_t kDisputeFingerprint = 0x297cf7d89bfd08f7ull; + static constexpr auto kSlowMinorityFingerprint = + goldens::dsf::kSlowMinorityFingerprint; + static constexpr auto kHubNetworkFingerprint = + goldens::dsf::kHubNetworkFingerprint; + static constexpr auto kDisputeFingerprint = + goldens::dsf::kDisputeFingerprint; - struct KProfiledDisputeSample - { - std::uint32_t k = 0; - std::uint64_t fingerprint = 0; - std::uint64_t events = 0; - std::uint64_t weightedEvents = 0; - std::size_t steps = 0; - std::size_t beats = 0; - std::uint32_t minValidated = 0; - std::uint32_t maxValidated = 0; - std::uint32_t forkCheckedSeqs = 0; - std::uint32_t target = 0; - std::uint32_t acceptedSeq = 0; - std::uint32_t txASeq = 0; - std::uint32_t txBSeq = 0; - std::uint64_t clampHits = 0; - std::int64_t requestedMs = 0; - std::int64_t consumedMs = 0; - // Highest virtual time one beat consumed. A pinned 2000 is that - // observed maximum, not a fixed per-beat budget. - std::int64_t maxConsumedBeatMs = 0; - std::int64_t schedulerMs = 0; - std::uint64_t heartbeatEvents = 0; - std::uint64_t deliverEvents = 0; - std::uint64_t jobEvents = 0; - std::uint64_t timerEvents = 0; - std::uint32_t firstClampWeight = 0; - bool submittedA = false; - bool submittedB = false; - bool forkFree = false; - bool converged = false; - bool exactlyOneAccepted = false; - bool acceptedSetVerified = false; - // Availability before any verification-only backfill. False when - // no transaction was accepted, or its historical ledger is missing. - bool historyReadyAtSnapshot = false; - // Beats of K=0 continuation that reached the target. 0 when recovery - // was not needed, or when it ran and still missed the target. - std::uint32_t recoveryBeats = 0; - // PRNG base passed to seedPrng before the nodes exist. - static constexpr std::uint64_t kDefaultSeed = 0xFAB1E5EED0000000ull; - std::uint64_t seed = kDefaultSeed; - // Not part of operator==. True only when the profiled loop stopped - // because the heartbeat ceiling was reached. - bool heartbeatBudgetStop = false; - - [[nodiscard]] bool - operator==(KProfiledDisputeSample const& o) const - { - return k == o.k && fingerprint == o.fingerprint && - events == o.events && weightedEvents == o.weightedEvents && - steps == o.steps && beats == o.beats && - minValidated == o.minValidated && - maxValidated == o.maxValidated && - forkCheckedSeqs == o.forkCheckedSeqs && target == o.target && - acceptedSeq == o.acceptedSeq && txASeq == o.txASeq && - txBSeq == o.txBSeq && clampHits == o.clampHits && - requestedMs == o.requestedMs && consumedMs == o.consumedMs && - maxConsumedBeatMs == o.maxConsumedBeatMs && - schedulerMs == o.schedulerMs && - heartbeatEvents == o.heartbeatEvents && - deliverEvents == o.deliverEvents && jobEvents == o.jobEvents && - timerEvents == o.timerEvents && - firstClampWeight == o.firstClampWeight && - submittedA == o.submittedA && submittedB == o.submittedB && - forkFree == o.forkFree && converged == o.converged && - exactlyOneAccepted == o.exactlyOneAccepted && - acceptedSetVerified == o.acceptedSetVerified && - historyReadyAtSnapshot == o.historyReadyAtSnapshot && - recoveryBeats == o.recoveryBeats && seed == o.seed; - } - }; + using KProfiledDisputeSample = goldens::dsf::KProfiledDisputeSample; struct SubmittedTx { @@ -265,6 +196,9 @@ class SteppingCsf_test : public beast::unit_test::suite auto const fingerprint = net.traceFingerprint(); log << " slow-minority fingerprint 0x" << std::hex << fingerprint << std::dec << ", traceCount=" << net.traceCount() << std::endl; + if (goldens::dsf::goldensPrint(*this)) + goldens::dsf::printScalar( + *this, "kSlowMinorityFingerprint", fingerprint); BEAST_EXPECT(fingerprint == kSlowMinorityFingerprint); std::vector payload; @@ -357,6 +291,9 @@ class SteppingCsf_test : public beast::unit_test::suite auto const fingerprint = net.traceFingerprint(); log << " hub-network fingerprint 0x" << std::hex << fingerprint << std::dec << ", traceCount=" << net.traceCount() << std::endl; + if (goldens::dsf::goldensPrint(*this)) + goldens::dsf::printScalar( + *this, "kHubNetworkFingerprint", fingerprint); BEAST_EXPECT(fingerprint == kHubNetworkFingerprint); std::vector payload; @@ -498,6 +435,9 @@ class SteppingCsf_test : public beast::unit_test::suite log << " dispute fingerprint 0x" << std::hex << fingerprint << std::dec << ", traceCount=" << net.traceCount() << ", acceptedSeq=" << acceptedSeq << std::endl; + if (goldens::dsf::goldensPrint(*this)) + goldens::dsf::printScalar( + *this, "kDisputeFingerprint", fingerprint); BEAST_EXPECT(fingerprint == kDisputeFingerprint); std::vector payload; @@ -814,106 +754,15 @@ class SteppingCsf_test : public beast::unit_test::suite // K=3, and recovers in 6 beats with pacing off. It is not converged // and it is not a liveness proof. No consensus policy is changed to // fit a snapshot. - std::array const kExpected = {{ - {0, 0xa61437b6610a4709ull, - 2645, 0, - 1152, 0, - 11, 11, - 10, 11, - 8, 8, - 0, 0, - 0, 0, - 0, 63030, - 0, 0, - 0, 0, - 0, true, - true, true, - true, true, - true, true}, - {1, 0xf550e0ee4830bfbbull, - 2656, 2597, - 1163, 15, - 11, 11, - 10, 11, - 8, 8, - 0, 10, - 12985, 12900, - 1880, 66820, - 75, 708, - 348, 30, - 2, true, - true, true, - true, true, - true, true}, - {2, 0x7ebab2bea882f6c9ull, - 2792, 2995, - 1299, 29, - 11, 11, - 10, 11, - 9, 9, - 0, 28, - 29950, 29410, - 2000, 80430, - 140, 576, - 539, 42, - 2, true, - true, true, - true, true, - true, true}, - {3, 0xcd1f86fa48e0a973ull, - 6001, 10918, - 4508, 160, - 10, 10, - 9, 11, - 10, 0, - 10, 160, - 163770, 161000, - 2000, 212020, - 770, 910, - 2674, 152, - 3, true, - true, true, - false, true, - true, true, - 6}, - {3, 0x555c80e47cc1cc21ull, - 3130, 3706, - 1637, 54, - 11, 11, - 10, 11, - 10, 0, - 10, 53, - 55590, 54615, - 2000, 105635, - 265, 630, - 699, 41, - 3, true, - true, true, - true, true, - true, true, - 0, 0x1000000000000001ull}, - {4, 0x4e11c349617aca71ull, - 5012, 8345, - 3519, 160, - 8, 8, - 7, 11, - 0, 0, - 0, 160, - 166900, 161000, - 2000, 212020, - 735, 605, - 2044, 133, - 2, true, - true, true, - false, false, - false, false}, - }}; + auto const& kExpected = goldens::dsf::kProfiledDispute; bool sawResolvedUnderPressure = false; bool sawSaturatedUnresolved = false; for (auto const& expected : kExpected) { auto const first = runProfiledDispute(expected.k, expected.seed); + if (goldens::dsf::goldensPrint(*this)) + goldens::dsf::printDispute(*this, first); BEAST_EXPECT(first == expected); BEAST_EXPECT(first.submittedA); BEAST_EXPECT(first.submittedB); diff --git a/src/test/consensus/SteppingTraffic_test.cpp b/src/test/consensus/SteppingTraffic_test.cpp index 84dc256346..e81b2ac4a8 100644 --- a/src/test/consensus/SteppingTraffic_test.cpp +++ b/src/test/consensus/SteppingTraffic_test.cpp @@ -6,6 +6,7 @@ // XRP payments through the local submission path, and replay the whole // tx-bearing timeline bit-for-bit. //------------------------------------------------------------------------------ +#include #include #include #include @@ -28,13 +29,12 @@ class SteppingTraffic_test : public beast::unit_test::suite { using Payload = std::optional>; - static constexpr std::uint64_t kTrafficSeed = 0x5452414646494331ull; - static constexpr std::uint64_t kTrafficFingerprint = 0xc0dad1d188726d9dull; - static constexpr std::uint64_t kTrafficEvents = 1448; - static constexpr std::uint64_t kTrafficPayloadFingerprint = - // Payload includes xahaud ledger/transaction hashes. Keep the donor - // event-order pin above and the independent semantic/replay checks. - 0xd77bfa4d445420e3ull; + static constexpr auto kTrafficSeed = goldens::dsf::kTrafficSeed; + static constexpr auto kTrafficFingerprint = + goldens::dsf::kTrafficFingerprint; + static constexpr auto kTrafficEvents = goldens::dsf::kTrafficEvents; + static constexpr auto kTrafficPayloadFingerprint = + goldens::dsf::kTrafficPayloadFingerprint; static std::uint64_t payloadFingerprint(std::vector const& payload) @@ -190,6 +190,15 @@ class SteppingTraffic_test : public beast::unit_test::suite auto const content = payloadFingerprint(*payload); log << " traffic content observed: fingerprint 0x" << std::hex << content << std::dec << std::endl; + if (goldens::dsf::goldensPrint(*this)) + { + goldens::dsf::printScalar( + *this, "kTrafficFingerprint", net.traceFingerprint()); + goldens::dsf::printScalar( + *this, "kTrafficEvents", net.traceCount()); + goldens::dsf::printScalar( + *this, "kTrafficPayloadFingerprint", content); + } BEAST_EXPECT(net.traceFingerprint() == kTrafficFingerprint); BEAST_EXPECT(net.traceCount() == kTrafficEvents); BEAST_EXPECT(content == kTrafficPayloadFingerprint); diff --git a/src/test/consensus/SteppingTrust_test.cpp b/src/test/consensus/SteppingTrust_test.cpp index 5f2f7711db..fb5d6485d0 100644 --- a/src/test/consensus/SteppingTrust_test.cpp +++ b/src/test/consensus/SteppingTrust_test.cpp @@ -1,6 +1,7 @@ //------------------------------------------------------------------------------ // SteppingTrust -- per-node UNL shapes in the real stepping harness. //------------------------------------------------------------------------------ +#include #include #include #include @@ -23,67 +24,7 @@ class SteppingTrust_test : public beast::unit_test::suite { static constexpr std::uint32_t kForkPeers = 10; - struct KProfiledForkCell - { - std::uint32_t overlap = 0; - std::uint32_t k = 0; - std::uint64_t fingerprint = 0; - std::uint64_t events = 0; - std::uint64_t weightedEvents = 0; - std::size_t steps = 0; - std::size_t beats = 0; - std::uint32_t minValidated = 0; - std::uint32_t maxValidated = 0; - std::uint32_t forkCheckedSeqs = 0; - std::uint32_t target = 0; - std::uint32_t divergentSeq = 0; - std::uint32_t agreedSeq = 0; - std::uint32_t txASeq = 0; - std::uint32_t txBSeq = 0; - std::uint64_t clampHits = 0; - std::int64_t requestedMs = 0; - std::int64_t consumedMs = 0; - std::int64_t maxConsumedBeatMs = 0; - std::int64_t schedulerMs = 0; - std::uint64_t heartbeatEvents = 0; - std::uint64_t deliverEvents = 0; - std::uint64_t jobEvents = 0; - std::uint64_t timerEvents = 0; - std::uint32_t firstClampWeight = 0; - bool submittedA = false; - bool submittedB = false; - bool forkFree = false; - bool forked = false; - bool safeResolved = false; - bool unresolved = false; - bool saturated = false; - std::int64_t unitCostMs = 5; - - [[nodiscard]] bool - operator==(KProfiledForkCell const& o) const - { - return overlap == o.overlap && k == o.k && - fingerprint == o.fingerprint && events == o.events && - weightedEvents == o.weightedEvents && steps == o.steps && - beats == o.beats && minValidated == o.minValidated && - maxValidated == o.maxValidated && - forkCheckedSeqs == o.forkCheckedSeqs && target == o.target && - divergentSeq == o.divergentSeq && agreedSeq == o.agreedSeq && - txASeq == o.txASeq && txBSeq == o.txBSeq && - clampHits == o.clampHits && requestedMs == o.requestedMs && - consumedMs == o.consumedMs && - maxConsumedBeatMs == o.maxConsumedBeatMs && - schedulerMs == o.schedulerMs && - heartbeatEvents == o.heartbeatEvents && - deliverEvents == o.deliverEvents && jobEvents == o.jobEvents && - timerEvents == o.timerEvents && - firstClampWeight == o.firstClampWeight && - submittedA == o.submittedA && submittedB == o.submittedB && - forkFree == o.forkFree && forked == o.forked && - safeResolved == o.safeResolved && unresolved == o.unresolved && - saturated == o.saturated && unitCostMs == o.unitCostMs; - } - }; + using KProfiledForkCell = goldens::dsf::KProfiledForkCell; struct ForkShape { @@ -983,107 +924,7 @@ class SteppingTrust_test : public beast::unit_test::suite // Retain the donor's K axis with its 5ms unit. Extra explicitly // labelled 1ms cells also exercise progress under lighter pressure. // A sample is identified by overlap, K AND unitCostMs. - std::array const kExpected = {{ - {0, 0, 0x56ce6480b4972d74ull, - 3488, 0, 2060, - 0, 8, 8, - 7, 8, 5, - 0, 5, 5, - 0, 0, 0, - 0, 54020, 0, - 0, 0, 0, - 0, true, true, - false, true, false, - false, false, 5}, - {0, 1, 0x5bcaa0a57392b44bull, - 3475, 4585, 2047, - 12, 8, 8, - 7, 8, 5, - 0, 5, 5, - 0, 4585, 4585, - 790, 54345, 120, - 1312, 613, 0, - 0, true, true, - false, true, false, - false, false, 1}, - {0, 1, 0x66349c6e0ba11e57ull, - 3776, 5322, 2348, - 26, 8, 8, - 7, 8, 6, - 0, 6, 6, - 25, 26610, 26385, - 2000, 68395, 250, - 1161, 878, 57, - 2, true, true, - false, true, false, - false, true, 5}, - {4, 0, 0xdc05a22afd9269d0ull, - 6153, 0, 4218, - 0, 8, 8, - 7, 8, 0, - 5, 5, 0, - 0, 0, 0, - 0, 55020, 0, - 0, 0, 0, - 0, true, true, - true, false, true, - false, false, 5}, - {4, 1, 0x7872f20cdb7ec1c9ull, - 6231, 9698, 4296, - 14, 8, 8, - 7, 8, 0, - 5, 5, 0, - 6, 9698, 9687, - 1643, 56548, 140, - 2884, 1248, 22, - 3, true, true, - true, false, true, - false, true, 1}, - {4, 1, 0x7797f687638895d9ull, - 14855, 32488, 12920, - 160, 5, 5, - 4, 8, 0, - 0, 0, 0, - 160, 162440, 161000, - 2000, 203010, 1490, - 2839, 8140, 449, - 2, true, true, - true, false, false, - true, true, 5}, - {6, 0, 0xc54816e93aff2fd2ull, - 6147, 0, 4108, - 0, 8, 8, - 7, 8, 0, - 5, 5, 0, - 0, 0, 0, - 0, 54020, 0, - 0, 0, 0, - 0, true, true, - true, false, true, - false, false, 5}, - {6, 1, 0x63e402b833368e31ull, - 6292, 9487, 4253, - 15, 8, 8, - 7, 8, 0, - 5, 5, 0, - 7, 9487, 9472, - 1635, 57612, 150, - 2952, 1133, 16, - 3, true, true, - true, false, true, - false, true, 1}, - {6, 1, 0xf49350dbcf9e3c9cull, - 6477, 10070, 4438, - 49, 8, 8, - 7, 8, 0, - 6, 6, 0, - 48, 50350, 49935, - 2000, 91945, 480, - 2156, 1676, 124, - 2, true, true, - true, false, true, - false, true, 5}, - }}; + auto const& kExpected = goldens::dsf::kProfiledFork; bool sawForkUnderPressureControl = false; bool sawSafeBaseline = false; @@ -1095,6 +936,8 @@ class SteppingTrust_test : public beast::unit_test::suite expected.overlap, expected.k, std::chrono::milliseconds{expected.unitCostMs}); + if (goldens::dsf::goldensPrint(*this)) + goldens::dsf::printFork(*this, cell); BEAST_EXPECT(cell == expected); BEAST_EXPECT(cell.submittedA); BEAST_EXPECT(cell.submittedB); diff --git a/src/test/consensus/goldens/dsf.h b/src/test/consensus/goldens/dsf.h new file mode 100644 index 0000000000..ca01de9fc5 --- /dev/null +++ b/src/test/consensus/goldens/dsf.h @@ -0,0 +1,474 @@ +//------------------------------------------------------------------------------ +/* + Per-lineage golden manifest for the dsf stepping suites. + + lineage: dsf + seed base: 0xFAB1E5EED0000000 (harness default) + resolving K=3 seed: 0x1000000000000001 + topology: dispute and traffic are 5 validators, mesh. + Trust fork cells are N=10 with the overlap in the row. + pacing: profiled dispute K in {0,1,2,3,3,4}, unitCost 5ms, + heartbeat budget 160. The second K=3 row uses the + resolving seed. Trust fork cells vary overlap, K and + unitCostMs (5 or 1) as stored in each row. + RNG mapping: c527e0a721 (engine-range randomU64 plus the zero-bit + group fix) + captured at: 3f27fbcd5b + The numbers are unchanged since 020db70424. + platforms: macOS libc++ captured the rows. Linux libstdc++ + reconfirmed the donor suites, including the K=3 + rows, at 3f27fbcd5b. + + Outcome-bearing (the assertion is the whole row, not only the hash): + kProfiledDispute, kProfiledFork. + Pure event-order pins (a hash or a count, no outcome table): + kSlowMinorityFingerprint, kHubNetworkFingerprint, + kDisputeFingerprint, kTrafficFingerprint, kTrafficEvents, + kTrafficPayloadFingerprint. + + Regeneration: --unittest-arg=goldens=print with one of + SteppingCsf, SteppingTrust, or SteppingTraffic. Each prints GOLDEN + lines from the observed values. Review that diff; do not treat it as + automatic. The pinned 2000 values are the highest virtual time one + beat consumed, not a fixed per-beat budget. +*/ +//============================================================================== + +#ifndef XRPL_TEST_CONSENSUS_GOLDENS_DSF_H_INCLUDED +#define XRPL_TEST_CONSENSUS_GOLDENS_DSF_H_INCLUDED + +#include + +#include +#include +#include +#include + +namespace ripple::test::goldens::dsf { + +inline constexpr std::uint64_t kSeedBase = 0xFAB1E5EED0000000ull; +inline constexpr std::uint64_t kResolvingSeed = 0x1000000000000001ull; +inline constexpr char kRngMapping[] = "c527e0a721"; +inline constexpr char kCapturedAt[] = "3f27fbcd5b"; + +inline constexpr std::uint64_t kSlowMinorityFingerprint = 0x25ec64d383356379ull; +inline constexpr std::uint64_t kHubNetworkFingerprint = 0x182601635f5b0308ull; +inline constexpr std::uint64_t kDisputeFingerprint = 0x297cf7d89bfd08f7ull; + +inline constexpr std::uint64_t kTrafficSeed = 0x5452414646494331ull; +inline constexpr std::uint64_t kTrafficFingerprint = 0xc0dad1d188726d9dull; +inline constexpr std::uint64_t kTrafficEvents = 1448; +inline constexpr std::uint64_t kTrafficPayloadFingerprint = + 0xd77bfa4d445420e3ull; + +struct KProfiledDisputeSample +{ + std::uint32_t k = 0; + std::uint64_t fingerprint = 0; + std::uint64_t events = 0; + std::uint64_t weightedEvents = 0; + std::size_t steps = 0; + std::size_t beats = 0; + std::uint32_t minValidated = 0; + std::uint32_t maxValidated = 0; + std::uint32_t forkCheckedSeqs = 0; + std::uint32_t target = 0; + std::uint32_t acceptedSeq = 0; + std::uint32_t txASeq = 0; + std::uint32_t txBSeq = 0; + std::uint64_t clampHits = 0; + std::int64_t requestedMs = 0; + std::int64_t consumedMs = 0; + // Highest virtual time one beat consumed. A pinned 2000 is that + // observed maximum, not a fixed per-beat budget. + std::int64_t maxConsumedBeatMs = 0; + std::int64_t schedulerMs = 0; + std::uint64_t heartbeatEvents = 0; + std::uint64_t deliverEvents = 0; + std::uint64_t jobEvents = 0; + std::uint64_t timerEvents = 0; + std::uint32_t firstClampWeight = 0; + bool submittedA = false; + bool submittedB = false; + bool forkFree = false; + bool converged = false; + bool exactlyOneAccepted = false; + bool acceptedSetVerified = false; + // Availability before any verification-only backfill. False when + // no transaction was accepted, or its historical ledger is missing. + bool historyReadyAtSnapshot = false; + // Beats of K=0 continuation that reached the target. 0 when recovery + // was not needed, or when it ran and still missed the target. + std::uint32_t recoveryBeats = 0; + // PRNG base passed to seedPrng before the nodes exist. + static constexpr std::uint64_t kDefaultSeed = kSeedBase; + std::uint64_t seed = kDefaultSeed; + // Not part of operator==. True only when the profiled loop stopped + // because the heartbeat ceiling was reached. + bool heartbeatBudgetStop = false; + + [[nodiscard]] bool + operator==(KProfiledDisputeSample const& o) const + { + return k == o.k && fingerprint == o.fingerprint && events == o.events && + weightedEvents == o.weightedEvents && steps == o.steps && + beats == o.beats && minValidated == o.minValidated && + maxValidated == o.maxValidated && + forkCheckedSeqs == o.forkCheckedSeqs && target == o.target && + acceptedSeq == o.acceptedSeq && txASeq == o.txASeq && + txBSeq == o.txBSeq && clampHits == o.clampHits && + requestedMs == o.requestedMs && consumedMs == o.consumedMs && + maxConsumedBeatMs == o.maxConsumedBeatMs && + schedulerMs == o.schedulerMs && + heartbeatEvents == o.heartbeatEvents && + deliverEvents == o.deliverEvents && jobEvents == o.jobEvents && + timerEvents == o.timerEvents && + firstClampWeight == o.firstClampWeight && + submittedA == o.submittedA && submittedB == o.submittedB && + forkFree == o.forkFree && converged == o.converged && + exactlyOneAccepted == o.exactlyOneAccepted && + acceptedSetVerified == o.acceptedSetVerified && + historyReadyAtSnapshot == o.historyReadyAtSnapshot && + recoveryBeats == o.recoveryBeats && seed == o.seed; + } +}; + +inline constexpr std::array kProfiledDispute = {{ + {0, 0xa61437b6610a4709ull, + 2645, 0, + 1152, 0, + 11, 11, + 10, 11, + 8, 8, + 0, 0, + 0, 0, + 0, 63030, + 0, 0, + 0, 0, + 0, true, + true, true, + true, true, + true, true}, + {1, 0xf550e0ee4830bfbbull, + 2656, 2597, + 1163, 15, + 11, 11, + 10, 11, + 8, 8, + 0, 10, + 12985, 12900, + 1880, 66820, + 75, 708, + 348, 30, + 2, true, + true, true, + true, true, + true, true}, + {2, 0x7ebab2bea882f6c9ull, + 2792, 2995, + 1299, 29, + 11, 11, + 10, 11, + 9, 9, + 0, 28, + 29950, 29410, + 2000, 80430, + 140, 576, + 539, 42, + 2, true, + true, true, + true, true, + true, true}, + {3, 0xcd1f86fa48e0a973ull, + 6001, 10918, + 4508, 160, + 10, 10, + 9, 11, + 10, 0, + 10, 160, + 163770, 161000, + 2000, 212020, + 770, 910, + 2674, 152, + 3, true, + true, true, + false, true, + true, true, + 6}, + {3, 0x555c80e47cc1cc21ull, + 3130, 3706, + 1637, 54, + 11, 11, + 10, 11, + 10, 0, + 10, 53, + 55590, 54615, + 2000, 105635, + 265, 630, + 699, 41, + 3, true, + true, true, + true, true, + true, true, + 0, 0x1000000000000001ull}, + {4, 0x4e11c349617aca71ull, + 5012, 8345, + 3519, 160, + 8, 8, + 7, 11, + 0, 0, + 0, 160, + 166900, 161000, + 2000, 212020, + 735, 605, + 2044, 133, + 2, true, + true, true, + false, false, + false, false}, +}}; + +struct KProfiledForkCell +{ + std::uint32_t overlap = 0; + std::uint32_t k = 0; + std::uint64_t fingerprint = 0; + std::uint64_t events = 0; + std::uint64_t weightedEvents = 0; + std::size_t steps = 0; + std::size_t beats = 0; + std::uint32_t minValidated = 0; + std::uint32_t maxValidated = 0; + std::uint32_t forkCheckedSeqs = 0; + std::uint32_t target = 0; + std::uint32_t divergentSeq = 0; + std::uint32_t agreedSeq = 0; + std::uint32_t txASeq = 0; + std::uint32_t txBSeq = 0; + std::uint64_t clampHits = 0; + std::int64_t requestedMs = 0; + std::int64_t consumedMs = 0; + std::int64_t maxConsumedBeatMs = 0; + std::int64_t schedulerMs = 0; + std::uint64_t heartbeatEvents = 0; + std::uint64_t deliverEvents = 0; + std::uint64_t jobEvents = 0; + std::uint64_t timerEvents = 0; + std::uint32_t firstClampWeight = 0; + bool submittedA = false; + bool submittedB = false; + bool forkFree = false; + bool forked = false; + bool safeResolved = false; + bool unresolved = false; + bool saturated = false; + std::int64_t unitCostMs = 5; + + [[nodiscard]] bool + operator==(KProfiledForkCell const& o) const + { + return overlap == o.overlap && k == o.k && + fingerprint == o.fingerprint && events == o.events && + weightedEvents == o.weightedEvents && steps == o.steps && + beats == o.beats && minValidated == o.minValidated && + maxValidated == o.maxValidated && + forkCheckedSeqs == o.forkCheckedSeqs && target == o.target && + divergentSeq == o.divergentSeq && agreedSeq == o.agreedSeq && + txASeq == o.txASeq && txBSeq == o.txBSeq && + clampHits == o.clampHits && requestedMs == o.requestedMs && + consumedMs == o.consumedMs && + maxConsumedBeatMs == o.maxConsumedBeatMs && + schedulerMs == o.schedulerMs && + heartbeatEvents == o.heartbeatEvents && + deliverEvents == o.deliverEvents && jobEvents == o.jobEvents && + timerEvents == o.timerEvents && + firstClampWeight == o.firstClampWeight && + submittedA == o.submittedA && submittedB == o.submittedB && + forkFree == o.forkFree && forked == o.forked && + safeResolved == o.safeResolved && unresolved == o.unresolved && + saturated == o.saturated && unitCostMs == o.unitCostMs; + } +}; + +inline constexpr std::array kProfiledFork = {{ + {0, 0, 0x56ce6480b4972d74ull, + 3488, 0, 2060, + 0, 8, 8, + 7, 8, 5, + 0, 5, 5, + 0, 0, 0, + 0, 54020, 0, + 0, 0, 0, + 0, true, true, + false, true, false, + false, false, 5}, + {0, 1, 0x5bcaa0a57392b44bull, + 3475, 4585, 2047, + 12, 8, 8, + 7, 8, 5, + 0, 5, 5, + 0, 4585, 4585, + 790, 54345, 120, + 1312, 613, 0, + 0, true, true, + false, true, false, + false, false, 1}, + {0, 1, 0x66349c6e0ba11e57ull, + 3776, 5322, 2348, + 26, 8, 8, + 7, 8, 6, + 0, 6, 6, + 25, 26610, 26385, + 2000, 68395, 250, + 1161, 878, 57, + 2, true, true, + false, true, false, + false, true, 5}, + {4, 0, 0xdc05a22afd9269d0ull, + 6153, 0, 4218, + 0, 8, 8, + 7, 8, 0, + 5, 5, 0, + 0, 0, 0, + 0, 55020, 0, + 0, 0, 0, + 0, true, true, + true, false, true, + false, false, 5}, + {4, 1, 0x7872f20cdb7ec1c9ull, + 6231, 9698, 4296, + 14, 8, 8, + 7, 8, 0, + 5, 5, 0, + 6, 9698, 9687, + 1643, 56548, 140, + 2884, 1248, 22, + 3, true, true, + true, false, true, + false, true, 1}, + {4, 1, 0x7797f687638895d9ull, + 14855, 32488, 12920, + 160, 5, 5, + 4, 8, 0, + 0, 0, 0, + 160, 162440, 161000, + 2000, 203010, 1490, + 2839, 8140, 449, + 2, true, true, + true, false, false, + true, true, 5}, + {6, 0, 0xc54816e93aff2fd2ull, + 6147, 0, 4108, + 0, 8, 8, + 7, 8, 0, + 5, 5, 0, + 0, 0, 0, + 0, 54020, 0, + 0, 0, 0, + 0, true, true, + true, false, true, + false, false, 5}, + {6, 1, 0x63e402b833368e31ull, + 6292, 9487, 4253, + 15, 8, 8, + 7, 8, 0, + 5, 5, 0, + 7, 9487, 9472, + 1635, 57612, 150, + 2952, 1133, 16, + 3, true, true, + true, false, true, + false, true, 1}, + {6, 1, 0xf49350dbcf9e3c9cull, + 6477, 10070, 4438, + 49, 8, 8, + 7, 8, 0, + 6, 6, 0, + 48, 50350, 49935, + 2000, 91945, 480, + 2156, 1676, 124, + 2, true, true, + true, false, true, + false, true, 5}, +}}; + +[[nodiscard]] inline bool +goldensPrint(beast::unit_test::suite const& s) +{ + return s.arg().find("goldens=print") != std::string::npos; +} + +inline void +printDispute(beast::unit_test::suite& s, KProfiledDisputeSample const& r) +{ + s.log << "GOLDEN-DISPUTE" + << " k=" << r.k << " seed=0x" << std::hex << r.seed << std::dec + << " fp=0x" << std::hex << r.fingerprint << std::dec + << " events=" << r.events << " weightedEvents=" << r.weightedEvents + << " steps=" << r.steps << " beats=" << r.beats + << " minValidated=" << r.minValidated + << " maxValidated=" << r.maxValidated + << " forkCheckedSeqs=" << r.forkCheckedSeqs << " target=" << r.target + << " acceptedSeq=" << r.acceptedSeq << " txASeq=" << r.txASeq + << " txBSeq=" << r.txBSeq << " clampHits=" << r.clampHits + << " requestedMs=" << r.requestedMs << " consumedMs=" << r.consumedMs + << " maxBeatMs=" << r.maxConsumedBeatMs + << " schedulerMs=" << r.schedulerMs + << " heartbeat=" << r.heartbeatEvents + << " deliver=" << r.deliverEvents << " job=" << r.jobEvents + << " timer=" << r.timerEvents + << " firstClampWeight=" << r.firstClampWeight + << " submitted=" << r.submittedA << "/" << r.submittedB + << " forkFree=" << r.forkFree << " converged=" << r.converged + << " exactlyOneAccepted=" << r.exactlyOneAccepted + << " acceptedSetVerified=" << r.acceptedSetVerified + << " historyReady=" << r.historyReadyAtSnapshot + << " recoveryBeats=" << r.recoveryBeats << std::endl; +} + +inline void +printFork(beast::unit_test::suite& s, KProfiledForkCell const& r) +{ + s.log << "GOLDEN-FORK" + << " overlap=" << r.overlap << " k=" << r.k + << " unitMs=" << r.unitCostMs << " fp=0x" << std::hex << r.fingerprint + << std::dec << " events=" << r.events + << " weightedEvents=" << r.weightedEvents << " steps=" << r.steps + << " beats=" << r.beats << " minValidated=" << r.minValidated + << " maxValidated=" << r.maxValidated + << " forkCheckedSeqs=" << r.forkCheckedSeqs << " target=" << r.target + << " divergentSeq=" << r.divergentSeq << " agreedSeq=" << r.agreedSeq + << " txASeq=" << r.txASeq << " txBSeq=" << r.txBSeq + << " clampHits=" << r.clampHits << " requestedMs=" << r.requestedMs + << " consumedMs=" << r.consumedMs + << " maxBeatMs=" << r.maxConsumedBeatMs + << " schedulerMs=" << r.schedulerMs + << " heartbeat=" << r.heartbeatEvents + << " deliver=" << r.deliverEvents << " job=" << r.jobEvents + << " timer=" << r.timerEvents + << " firstClampWeight=" << r.firstClampWeight + << " submitted=" << r.submittedA << "/" << r.submittedB + << " forkFree=" << r.forkFree << " forked=" << r.forked + << " safeResolved=" << r.safeResolved + << " unresolved=" << r.unresolved << " saturated=" << r.saturated + << std::endl; +} + +inline void +printScalar( + beast::unit_test::suite& s, + char const* name, + std::uint64_t observed) +{ + auto const decimal = std::string(name).find("Events") != std::string::npos; + s.log << "GOLDEN-SCALAR " << name << "="; + if (decimal) + s.log << observed; + else + s.log << "0x" << std::hex << observed << std::dec; + s.log << std::endl; +} + +} // namespace ripple::test::goldens::dsf + +#endif