From 82fde74c36aa350981e88d827521d4409ff80ce7 Mon Sep 17 00:00:00 2001 From: Ben Date: Wed, 13 Aug 2025 13:54:33 +0200 Subject: [PATCH] improves proof period monitoring --- .../ChainMonitor/PeriodMonitor.cs | 47 ++++++++++--------- .../CodexContractsAccess.cs | 11 +++-- .../MarketTests/RepairTest.cs | 13 ++++- Tests/CodexReleaseTests/Utils/ChainMonitor.cs | 2 +- Tests/ExperimentalTests/CodexDistTest.cs | 5 ++ Tools/TestNetRewarder/EventsFormatter.cs | 2 +- 6 files changed, 52 insertions(+), 28 deletions(-) diff --git a/ProjectPlugins/CodexContractsPlugin/ChainMonitor/PeriodMonitor.cs b/ProjectPlugins/CodexContractsPlugin/ChainMonitor/PeriodMonitor.cs index 2fbd9a97..fe75e89a 100644 --- a/ProjectPlugins/CodexContractsPlugin/ChainMonitor/PeriodMonitor.cs +++ b/ProjectPlugins/CodexContractsPlugin/ChainMonitor/PeriodMonitor.cs @@ -41,8 +41,8 @@ namespace CodexContractsPlugin.ChainMonitor private void CreateReportForPeriod(ulong lastBlockInPeriod, ulong periodNumber, IChainStateRequest[] requests) { ulong total = 0; - ulong required = 0; - var missed = new List(); + var required = new List(); + var missed = new List(); foreach (var request in requests) { for (ulong slotIndex = 0; slotIndex < request.Request.Ask.Slots; slotIndex++) @@ -52,17 +52,19 @@ namespace CodexContractsPlugin.ChainMonitor total++; if (state.Required) { - required++; + var idx = Convert.ToInt32(slotIndex); + var host = request.Hosts.GetHost(idx); + var proof = new PeriodProof(host, request, idx); + + required.Add(proof); if (state.Missing) { - var idx = Convert.ToInt32(slotIndex); - var host = request.Hosts.GetHost(idx); - missed.Add(new PeriodProofMissed(host, request, idx)); + missed.Add(proof); } } } } - var report = new PeriodReport(periodNumber, total, required, missed.ToArray()); + var report = new PeriodReport(periodNumber, total, required.ToArray(), missed.ToArray()); log.Log($"Period report: {report}"); reports.Add(report); } @@ -87,45 +89,48 @@ namespace CodexContractsPlugin.ChainMonitor private void CalcStats() { - IsEmpty = Reports.All(r => r.TotalProofsRequired == 0); + IsEmpty = Reports.All(r => r.ProofsRequired.Length == 0); if (Reports.Length == 0) return; PeriodLow = Reports.Min(r => r.PeriodNumber); PeriodHigh = Reports.Max(r => r.PeriodNumber); AverageNumSlots = Reports.Average(r => Convert.ToSingle(r.TotalNumSlots)); - AverageNumProofsRequired = Reports.Average(r => Convert.ToSingle(r.TotalProofsRequired)); + AverageNumProofsRequired = Reports.Average(r => Convert.ToSingle(r.ProofsRequired.Length)); } } public class PeriodReport { - public PeriodReport(ulong periodNumber, ulong totalNumSlots, ulong totalProofsRequired, PeriodProofMissed[] missedProofs) + public PeriodReport(ulong periodNumber, ulong totalNumSlots, PeriodProof[] proofsRequired, PeriodProof[] missedProofs) { PeriodNumber = periodNumber; TotalNumSlots = totalNumSlots; - TotalProofsRequired = totalProofsRequired; + ProofsRequired = proofsRequired; MissedProofs = missedProofs; } public ulong PeriodNumber { get; } public ulong TotalNumSlots { get; } - public ulong TotalProofsRequired { get; } - public PeriodProofMissed[] MissedProofs { get; } + public PeriodProof[] ProofsRequired { get; } + public PeriodProof[] MissedProofs { get; } public override string ToString() { - var missed = "None"; - if (MissedProofs.Length > 0) - { - missed = string.Join("+", MissedProofs.Select(p => $"{p.FormatHost()} missed {p.Request.RequestId.ToHex()} slot {p.SlotIndex}")); - } - return $"Period:{PeriodNumber}=[Slots:{TotalNumSlots},ProofsRequired:{TotalProofsRequired},ProofsMissed:{missed}]"; + var required = Describe(ProofsRequired); + var missed = Describe(MissedProofs); + return $"Period:{PeriodNumber}=[Slots:{TotalNumSlots},ProofsRequired:{required},ProofsMissed:{missed}]"; + } + + private string Describe(PeriodProof[] proofs) + { + if (proofs.Length == 0) return "None"; + return string.Join("+", proofs.Select(p => $"{p.FormatHost()} - {p.Request.RequestId.ToHex()} slot {p.SlotIndex}")); } } - public class PeriodProofMissed + public class PeriodProof { - public PeriodProofMissed(EthAddress? host, IChainStateRequest request, int slotIndex) + public PeriodProof(EthAddress? host, IChainStateRequest request, int slotIndex) { Host = host; Request = request; diff --git a/ProjectPlugins/CodexContractsPlugin/CodexContractsAccess.cs b/ProjectPlugins/CodexContractsPlugin/CodexContractsAccess.cs index a5770ee2..8c089e0f 100644 --- a/ProjectPlugins/CodexContractsPlugin/CodexContractsAccess.cs +++ b/ProjectPlugins/CodexContractsPlugin/CodexContractsAccess.cs @@ -172,7 +172,7 @@ namespace CodexContractsPlugin var required = IsProofRequired(slotId, blockNumber); if (!required) return new ProofState(false, false); - var missing = IsProofMissing(slotId, blockNumber, period); + var missing = IsProofMissing(slotId, period, blockNumber); return new ProofState(required, missing); } @@ -202,16 +202,19 @@ namespace CodexContractsPlugin return result.ReturnValue1; } - private bool IsProofMissing(byte[] slotId, ulong blockNumber, ulong period) + private bool IsProofMissing(byte[] slotId, ulong period, ulong blockNumber) { try { - var funcB = new MarkProofAsMissingFunction + var func = new CanMarkProofAsMissingFunction { SlotId = slotId, Period = period }; - gethNode.Call(Deployment.MarketplaceAddress, funcB, blockNumber); + + var result = gethNode.Call(Deployment.MarketplaceAddress, func, blockNumber); + + var a = 0; } catch (AggregateException exc) { diff --git a/Tests/CodexReleaseTests/MarketTests/RepairTest.cs b/Tests/CodexReleaseTests/MarketTests/RepairTest.cs index 8b823286..63f9d2cc 100644 --- a/Tests/CodexReleaseTests/MarketTests/RepairTest.cs +++ b/Tests/CodexReleaseTests/MarketTests/RepairTest.cs @@ -22,7 +22,7 @@ namespace CodexReleaseTests.MarketTests Assert.That(purchaseParams.Nodes, Is.LessThan(NumberOfHosts)); } - protected override int NumberOfHosts => 5; + protected override int NumberOfHosts => 6; protected override int NumberOfClients => 1; protected override ByteSize HostAvailabilitySize => purchaseParams.SlotSize.Multiply(1.1); // Each host can hold 1 slot. protected override TimeSpan HostAvailabilityMaxDuration => TimeSpan.FromDays(5.0); @@ -47,6 +47,17 @@ namespace CodexReleaseTests.MarketTests client.Stop(waitTillStopped: true); + // Hold this situation + Log("Holding initial situation to ensure contract is stable..."); + var config = GetContracts().Deployment.Config; + WaitAndCheckNodesStaysAlive(config.PeriodDuration * 5, hosts); + + if (contract.GetStatus() == null || + contract.GetStatus()!.State == StoragePurchaseState.Failed) + { + Assert.Fail("Contract did not survive waiting period."); + } + for (var i = 0; i < numFailures; i++) { Log($"Failure step: {i}"); diff --git a/Tests/CodexReleaseTests/Utils/ChainMonitor.cs b/Tests/CodexReleaseTests/Utils/ChainMonitor.cs index 9a2a7683..7b229c9f 100644 --- a/Tests/CodexReleaseTests/Utils/ChainMonitor.cs +++ b/Tests/CodexReleaseTests/Utils/ChainMonitor.cs @@ -71,7 +71,7 @@ namespace CodexReleaseTests.Utils if (reports.IsEmpty) return; var slots = reports.Reports.Sum(r => Convert.ToInt32(r.TotalNumSlots)); - var required = reports.Reports.Sum(r => Convert.ToInt32(r.TotalProofsRequired)); + var required = reports.Reports.Sum(r => Convert.ToInt32(r.ProofsRequired.Length)); var missed = reports.Reports.Sum(r => r.MissedProofs.Length); log.Log($"Proof report: Slots={slots} Required={required} Missed={missed}"); diff --git a/Tests/ExperimentalTests/CodexDistTest.cs b/Tests/ExperimentalTests/CodexDistTest.cs index 273128ea..cca488aa 100644 --- a/Tests/ExperimentalTests/CodexDistTest.cs +++ b/Tests/ExperimentalTests/CodexDistTest.cs @@ -127,6 +127,11 @@ namespace CodexTests WaitAndCheckNodesStaysAlive(duration, nodes.ToArray()); } + public void WaitAndCheckNodesStaysAlive(TimeSpan duration, List nodes) + { + WaitAndCheckNodesStaysAlive(duration, nodes.ToArray()); + } + public void WaitAndCheckNodesStaysAlive(TimeSpan duration, params ICodexNode[] nodes) { Log($"{nameof(WaitAndCheckNodesStaysAlive)} {Time.FormatDuration(duration)}..."); diff --git a/Tools/TestNetRewarder/EventsFormatter.cs b/Tools/TestNetRewarder/EventsFormatter.cs index 0f5ee9fa..a7b6c8aa 100644 --- a/Tools/TestNetRewarder/EventsFormatter.cs +++ b/Tools/TestNetRewarder/EventsFormatter.cs @@ -178,7 +178,7 @@ namespace TestNetRewarder } } - private void DescribeMissedProof(List lines, PeriodProofMissed missedProof) + private void DescribeMissedProof(List lines, PeriodProof missedProof) { lines.Add($"[{missedProof.FormatHost()}] missed proof for {FormatRequestId(missedProof.Request)} (slotIndex: {missedProof.SlotIndex})"); }