mirror of
https://github.com/logos-storage/logos-storage-nim-cs-dist-tests.git
synced 2026-01-04 06:23:09 +00:00
Adds proof-period report to chain-events.
This commit is contained in:
parent
c5de3dcb4c
commit
d6cd7762c4
@ -45,7 +45,11 @@
|
||||
private static string? GetEnvVar(List<string> error, string name)
|
||||
{
|
||||
var result = Environment.GetEnvironmentVariable(name);
|
||||
if (string.IsNullOrEmpty(result)) error.Add($"'{name}' is not set.");
|
||||
if (string.IsNullOrEmpty(result))
|
||||
{
|
||||
error.Add($"'{name}' is not set.");
|
||||
return null;
|
||||
}
|
||||
return result.Trim();
|
||||
}
|
||||
}
|
||||
|
||||
@ -50,6 +50,21 @@ namespace NethereumWorkflow
|
||||
return Time.Wait(handler.QueryAsync<TResult>(contractAddress, function));
|
||||
}
|
||||
|
||||
public TResult Call<TFunction, TResult>(string contractAddress, TFunction function, ulong blockNumber) where TFunction : FunctionMessage, new()
|
||||
{
|
||||
log.Debug(typeof(TFunction).ToString());
|
||||
var handler = web3.Eth.GetContractQueryHandler<TFunction>();
|
||||
return Time.Wait(handler.QueryAsync<TResult>(contractAddress, function, new BlockParameter(blockNumber)));
|
||||
}
|
||||
|
||||
public void Call<TFunction>(string contractAddress, TFunction function, ulong blockNumber) where TFunction : FunctionMessage, new()
|
||||
{
|
||||
log.Debug(typeof(TFunction).ToString());
|
||||
var handler = web3.Eth.GetContractQueryHandler<TFunction>();
|
||||
var result = Time.Wait(handler.QueryRawAsync(contractAddress, function, new BlockParameter(blockNumber)));
|
||||
var aaaa = 0;
|
||||
}
|
||||
|
||||
public string SendTransaction<TFunction>(string contractAddress, TFunction function) where TFunction : FunctionMessage, new()
|
||||
{
|
||||
log.Debug();
|
||||
|
||||
@ -46,10 +46,12 @@ namespace CodexContractsPlugin.ChainMonitor
|
||||
this.contracts = contracts;
|
||||
handler = changeHandler;
|
||||
TotalSpan = new TimeRange(startUtc, startUtc);
|
||||
PeriodMonitor = new PeriodMonitor(this.log, contracts);
|
||||
}
|
||||
|
||||
public TimeRange TotalSpan { get; private set; }
|
||||
public IChainStateRequest[] Requests => requests.ToArray();
|
||||
public PeriodMonitor PeriodMonitor { get; }
|
||||
|
||||
public int Update()
|
||||
{
|
||||
@ -88,11 +90,17 @@ namespace CodexContractsPlugin.ChainMonitor
|
||||
{
|
||||
var blockEvents = events.All.Where(e => e.Block.BlockNumber == b).ToArray();
|
||||
ApplyEvents(b, blockEvents, eventUtc);
|
||||
UpdatePeriodMonitor(b, eventUtc);
|
||||
|
||||
eventUtc += spanPerBlock;
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdatePeriodMonitor(ulong blockNumber, DateTime eventUtc)
|
||||
{
|
||||
PeriodMonitor.Update(blockNumber, eventUtc, Requests);
|
||||
}
|
||||
|
||||
private void ApplyEvents(ulong blockNumber, IHasBlock[] blockEvents, DateTime eventsUtc)
|
||||
{
|
||||
foreach (var e in blockEvents)
|
||||
|
||||
@ -0,0 +1,99 @@
|
||||
using Logging;
|
||||
using Utils;
|
||||
|
||||
namespace CodexContractsPlugin.ChainMonitor
|
||||
{
|
||||
public class PeriodMonitor
|
||||
{
|
||||
private readonly ILog log;
|
||||
private readonly ICodexContracts contracts;
|
||||
private readonly List<PeriodReport> reports = new List<PeriodReport>();
|
||||
private ulong? currentPeriod = null;
|
||||
|
||||
public PeriodMonitor(ILog log, ICodexContracts contracts)
|
||||
{
|
||||
this.log = log;
|
||||
this.contracts = contracts;
|
||||
}
|
||||
|
||||
public void Update(ulong blockNumber, DateTime eventUtc, IChainStateRequest[] requests)
|
||||
{
|
||||
var period = contracts.GetPeriodNumber(eventUtc);
|
||||
if (!currentPeriod.HasValue)
|
||||
{
|
||||
currentPeriod = period;
|
||||
return;
|
||||
}
|
||||
if (period == currentPeriod.Value) return;
|
||||
|
||||
CreateReportForPeriod(blockNumber - 1, currentPeriod.Value, requests);
|
||||
currentPeriod = period;
|
||||
}
|
||||
|
||||
public PeriodReport[] GetAndClearReports()
|
||||
{
|
||||
var result = reports.ToArray();
|
||||
reports.Clear();
|
||||
return result;
|
||||
}
|
||||
|
||||
private void CreateReportForPeriod(ulong lastBlockInPeriod, ulong periodNumber, IChainStateRequest[] requests)
|
||||
{
|
||||
log.Log("Creating report for period " + periodNumber);
|
||||
|
||||
ulong total = 0;
|
||||
ulong required = 0;
|
||||
var missed = new List<PeriodProofMissed>();
|
||||
foreach (var request in requests)
|
||||
{
|
||||
for (ulong slotIndex = 0; slotIndex < request.Request.Ask.Slots; slotIndex++)
|
||||
{
|
||||
var state = contracts.GetProofState(request.Request, slotIndex, lastBlockInPeriod, periodNumber);
|
||||
|
||||
total++;
|
||||
if (state.Required)
|
||||
{
|
||||
required++;
|
||||
if (state.Missing)
|
||||
{
|
||||
var idx = Convert.ToInt32(slotIndex);
|
||||
var host = request.Hosts.GetHost(idx);
|
||||
missed.Add(new PeriodProofMissed(host, request, idx));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
reports.Add(new PeriodReport(periodNumber, total, required, missed.ToArray()));
|
||||
}
|
||||
}
|
||||
|
||||
public class PeriodReport
|
||||
{
|
||||
public PeriodReport(ulong periodNumber, ulong totalNumSlots, ulong totalProofsRequired, PeriodProofMissed[] missedProofs)
|
||||
{
|
||||
PeriodNumber = periodNumber;
|
||||
TotalNumSlots = totalNumSlots;
|
||||
TotalProofsRequired = totalProofsRequired;
|
||||
MissedProofs = missedProofs;
|
||||
}
|
||||
|
||||
public ulong PeriodNumber { get; }
|
||||
public ulong TotalNumSlots { get; }
|
||||
public ulong TotalProofsRequired { get; }
|
||||
public PeriodProofMissed[] MissedProofs { get; }
|
||||
}
|
||||
|
||||
public class PeriodProofMissed
|
||||
{
|
||||
public PeriodProofMissed(EthAddress? host, IChainStateRequest request, int slotIndex)
|
||||
{
|
||||
Host = host;
|
||||
Request = request;
|
||||
SlotIndex = slotIndex;
|
||||
}
|
||||
|
||||
public EthAddress? Host { get; }
|
||||
public IChainStateRequest Request { get; }
|
||||
public int SlotIndex { get; }
|
||||
}
|
||||
}
|
||||
@ -3,6 +3,8 @@ using CodexContractsPlugin.Marketplace;
|
||||
using GethPlugin;
|
||||
using Logging;
|
||||
using Nethereum.ABI;
|
||||
using Nethereum.ABI.FunctionEncoding.Attributes;
|
||||
using Nethereum.Contracts;
|
||||
using Nethereum.Hex.HexConvertors.Extensions;
|
||||
using Nethereum.Util;
|
||||
using NethereumWorkflow;
|
||||
@ -26,7 +28,21 @@ namespace CodexContractsPlugin
|
||||
ICodexContractsEvents GetEvents(BlockInterval blockInterval);
|
||||
EthAddress? GetSlotHost(Request storageRequest, decimal slotIndex);
|
||||
RequestState GetRequestState(Request request);
|
||||
ulong GetPeriodNumber(DateTime utc);
|
||||
void WaitUntilNextPeriod();
|
||||
ProofState GetProofState(Request storageRequest, decimal slotIndex, ulong blockNumber, ulong period);
|
||||
}
|
||||
|
||||
public class ProofState
|
||||
{
|
||||
public ProofState(bool required, bool missing)
|
||||
{
|
||||
Required = required;
|
||||
Missing = missing;
|
||||
}
|
||||
|
||||
public bool Required { get; }
|
||||
public bool Missing { get; }
|
||||
}
|
||||
|
||||
[JsonConverter(typeof(StringEnumConverter))]
|
||||
@ -89,19 +105,23 @@ namespace CodexContractsPlugin
|
||||
return new CodexContractsEvents(log, gethNode, Deployment, blockInterval);
|
||||
}
|
||||
|
||||
public EthAddress? GetSlotHost(Request storageRequest, decimal slotIndex)
|
||||
public byte[] GetSlotId(Request request, decimal slotIndex)
|
||||
{
|
||||
var encoder = new ABIEncode();
|
||||
var encoded = encoder.GetABIEncoded(
|
||||
new ABIValue("bytes32", storageRequest.RequestId),
|
||||
new ABIValue("bytes32", request.RequestId),
|
||||
new ABIValue("uint256", slotIndex.ToBig())
|
||||
);
|
||||
|
||||
var hashed = Sha3Keccack.Current.CalculateHash(encoded);
|
||||
return Sha3Keccack.Current.CalculateHash(encoded);
|
||||
}
|
||||
|
||||
public EthAddress? GetSlotHost(Request storageRequest, decimal slotIndex)
|
||||
{
|
||||
var slotId = GetSlotId(storageRequest, slotIndex);
|
||||
var func = new GetHostFunction
|
||||
{
|
||||
SlotId = hashed
|
||||
SlotId = slotId
|
||||
};
|
||||
var address = gethNode.Call<GetHostFunction, string>(Deployment.MarketplaceAddress, func);
|
||||
if (string.IsNullOrEmpty(address)) return null;
|
||||
@ -117,6 +137,15 @@ namespace CodexContractsPlugin
|
||||
return gethNode.Call<RequestStateFunction, RequestState>(Deployment.MarketplaceAddress, func);
|
||||
}
|
||||
|
||||
public ulong GetPeriodNumber(DateTime utc)
|
||||
{
|
||||
DateTimeOffset utco = DateTime.SpecifyKind(utc, DateTimeKind.Utc);
|
||||
var now = utco.ToUnixTimeSeconds();
|
||||
var periodSeconds = (int)Deployment.Config.Proofs.Period;
|
||||
var result = now / periodSeconds;
|
||||
return Convert.ToUInt64(result);
|
||||
}
|
||||
|
||||
public void WaitUntilNextPeriod()
|
||||
{
|
||||
log.Log("Waiting until next proof period...");
|
||||
@ -126,6 +155,52 @@ namespace CodexContractsPlugin
|
||||
Thread.Sleep(TimeSpan.FromSeconds(secondsLeft + 1));
|
||||
}
|
||||
|
||||
public ProofState GetProofState(Request storageRequest, decimal slotIndex, ulong blockNumber, ulong period)
|
||||
{
|
||||
var slotId = GetSlotId(storageRequest, slotIndex);
|
||||
|
||||
var required = IsProofRequired(slotId, blockNumber);
|
||||
if (!required) return new ProofState(false, false);
|
||||
|
||||
var missing = IsProofMissing(slotId, blockNumber, period);
|
||||
return new ProofState(required, missing);
|
||||
}
|
||||
|
||||
private bool IsProofRequired(byte[] slotId, ulong blockNumber)
|
||||
{
|
||||
var func = new IsProofRequiredFunction
|
||||
{
|
||||
Id = slotId
|
||||
};
|
||||
var result = gethNode.Call<IsProofRequiredFunction, IsProofRequiredOutputDTO>(Deployment.MarketplaceAddress, func, blockNumber);
|
||||
return result.ReturnValue1;
|
||||
}
|
||||
|
||||
private bool IsProofMissing(byte[] slotId, ulong blockNumber, ulong period)
|
||||
{
|
||||
try
|
||||
{
|
||||
var funcB = new MarkProofAsMissingFunction
|
||||
{
|
||||
SlotId = slotId,
|
||||
Period = period
|
||||
};
|
||||
gethNode.Call<MarkProofAsMissingFunction>(Deployment.MarketplaceAddress, funcB, blockNumber);
|
||||
}
|
||||
catch (AggregateException exc)
|
||||
{
|
||||
if (exc.InnerExceptions.Count == 1)
|
||||
{
|
||||
if (exc.InnerExceptions[0].GetType() == typeof(SmartContractCustomErrorRevertException))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
throw;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private ContractInteractions StartInteraction()
|
||||
{
|
||||
return new ContractInteractions(log, gethNode);
|
||||
|
||||
File diff suppressed because one or more lines are too long
@ -20,6 +20,8 @@ namespace GethPlugin
|
||||
string SendEth(IHasEthAddress account, Ether eth);
|
||||
string SendEth(EthAddress account, Ether eth);
|
||||
TResult Call<TFunction, TResult>(string contractAddress, TFunction function) where TFunction : FunctionMessage, new();
|
||||
TResult Call<TFunction, TResult>(string contractAddress, TFunction function, ulong blockNumber) where TFunction : FunctionMessage, new();
|
||||
void Call<TFunction>(string contractAddress, TFunction function, ulong blockNumber) where TFunction : FunctionMessage, new();
|
||||
string SendTransaction<TFunction>(string contractAddress, TFunction function) where TFunction : FunctionMessage, new();
|
||||
Transaction GetTransaction(string transactionHash);
|
||||
decimal? GetSyncedBlockNumber();
|
||||
@ -131,6 +133,16 @@ namespace GethPlugin
|
||||
return StartInteraction().Call<TFunction, TResult>(contractAddress, function);
|
||||
}
|
||||
|
||||
public TResult Call<TFunction, TResult>(string contractAddress, TFunction function, ulong blockNumber) where TFunction : FunctionMessage, new()
|
||||
{
|
||||
return StartInteraction().Call<TFunction, TResult>(contractAddress, function, blockNumber);
|
||||
}
|
||||
|
||||
public void Call<TFunction>(string contractAddress, TFunction function, ulong blockNumber) where TFunction : FunctionMessage, new()
|
||||
{
|
||||
StartInteraction().Call(contractAddress, function, blockNumber);
|
||||
}
|
||||
|
||||
public string SendTransaction<TFunction>(string contractAddress, TFunction function) where TFunction : FunctionMessage, new()
|
||||
{
|
||||
return StartInteraction().SendTransaction(contractAddress, function);
|
||||
|
||||
@ -102,6 +102,28 @@ namespace TestNetRewarder
|
||||
errors.Add(msg);
|
||||
}
|
||||
|
||||
public void ProcessPeriodReports(PeriodReport[] periodReports)
|
||||
{
|
||||
var lines = periodReports.Select(FormatPeriodReport).ToList();
|
||||
lines.Insert(0, FormatPeriodReportLine("period", "totalSlots", "required", "missed"));
|
||||
AddBlock(0, "Proof system report", lines.ToArray());
|
||||
}
|
||||
|
||||
private string FormatPeriodReport(PeriodReport report)
|
||||
{
|
||||
return FormatPeriodReportLine(
|
||||
periodNumber: report.PeriodNumber.ToString(),
|
||||
totalSlots: report.TotalNumSlots.ToString(),
|
||||
totalRequired: report.TotalProofsRequired.ToString(),
|
||||
totalMissed: report.MissedProofs.Length.ToString()
|
||||
);
|
||||
}
|
||||
|
||||
private string FormatPeriodReportLine(string periodNumber, string totalSlots, string totalRequired, string totalMissed)
|
||||
{
|
||||
return $"{periodNumber.PadLeft(10)} {totalSlots.PadLeft(10)} {totalRequired.PadLeft(10)} {totalMissed.PadLeft(10)}";
|
||||
}
|
||||
|
||||
private void AddRequestBlock(RequestEvent requestEvent, string eventName, params string[] content)
|
||||
{
|
||||
var blockNumber = $"[{requestEvent.Block.BlockNumber} {FormatDateTime(requestEvent.Block.Utc)}]";
|
||||
|
||||
@ -1,97 +0,0 @@
|
||||
using CodexContractsPlugin;
|
||||
using CodexContractsPlugin.Marketplace;
|
||||
using Newtonsoft.Json;
|
||||
using Utils;
|
||||
|
||||
namespace TestNetRewarder
|
||||
{
|
||||
public class HistoricState
|
||||
{
|
||||
private readonly List<StorageRequest> storageRequests = new List<StorageRequest>();
|
||||
|
||||
public StorageRequest[] StorageRequests { get { return storageRequests.ToArray(); } }
|
||||
|
||||
public void ProcessNewRequests(Request[] requests)
|
||||
{
|
||||
storageRequests.AddRange(requests.Select(r => new StorageRequest(r)));
|
||||
}
|
||||
|
||||
public void UpdateStorageRequests(ICodexContracts contracts)
|
||||
{
|
||||
foreach (var r in storageRequests) r.Update(contracts);
|
||||
}
|
||||
|
||||
public void CleanUpOldRequests()
|
||||
{
|
||||
storageRequests.RemoveAll(r =>
|
||||
r.State == RequestState.Cancelled ||
|
||||
r.State == RequestState.Finished ||
|
||||
r.State == RequestState.Failed
|
||||
);
|
||||
}
|
||||
|
||||
public string EntireString()
|
||||
{
|
||||
return JsonConvert.SerializeObject(StorageRequests);
|
||||
}
|
||||
|
||||
public HistoricState()
|
||||
{
|
||||
}
|
||||
|
||||
public HistoricState(StorageRequest[] requests)
|
||||
{
|
||||
storageRequests.AddRange(requests);
|
||||
}
|
||||
}
|
||||
|
||||
public class StorageRequest
|
||||
{
|
||||
public StorageRequest(Request request)
|
||||
{
|
||||
Request = request;
|
||||
Hosts = Array.Empty<EthAddress>();
|
||||
}
|
||||
|
||||
public Request Request { get; }
|
||||
public EthAddress[] Hosts { get; private set; }
|
||||
public RequestState State { get; private set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public bool RecentlyStarted { get; private set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public bool RecentlyFinished { get; private set; }
|
||||
|
||||
public void Update(ICodexContracts contracts)
|
||||
{
|
||||
var newHosts = GetHosts(contracts);
|
||||
|
||||
var newState = contracts.GetRequestState(Request);
|
||||
|
||||
RecentlyStarted =
|
||||
State == RequestState.New &&
|
||||
newState == RequestState.Started;
|
||||
|
||||
RecentlyFinished =
|
||||
State == RequestState.Started &&
|
||||
newState == RequestState.Finished;
|
||||
|
||||
State = newState;
|
||||
Hosts = newHosts;
|
||||
}
|
||||
|
||||
private EthAddress[] GetHosts(ICodexContracts contracts)
|
||||
{
|
||||
var result = new List<EthAddress>();
|
||||
|
||||
for (decimal i = 0; i < Request.Ask.Slots; i++)
|
||||
{
|
||||
var host = contracts.GetSlotHost(Request, i);
|
||||
if (host != null) result.Add(host);
|
||||
}
|
||||
|
||||
return result.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -14,12 +14,14 @@ namespace TestNetRewarder
|
||||
private readonly Configuration config;
|
||||
private readonly BotClient client;
|
||||
private readonly ILog log;
|
||||
private DateTime lastPeriodUpdateUtc;
|
||||
|
||||
public Processor(Configuration config, BotClient client, ICodexContracts contracts, ILog log)
|
||||
{
|
||||
this.config = config;
|
||||
this.client = client;
|
||||
this.log = log;
|
||||
lastPeriodUpdateUtc = DateTime.UtcNow;
|
||||
|
||||
builder = new RequestBuilder();
|
||||
rewardChecker = new RewardChecker(builder);
|
||||
@ -68,6 +70,7 @@ namespace TestNetRewarder
|
||||
private async Task<int> ProcessEvents(TimeRange timeRange)
|
||||
{
|
||||
var numberOfChainEvents = chainState.Update(timeRange.To);
|
||||
ProcessPeriodUpdate();
|
||||
|
||||
var events = eventsFormatter.GetEvents();
|
||||
var errors = eventsFormatter.GetErrors();
|
||||
@ -79,5 +82,13 @@ namespace TestNetRewarder
|
||||
}
|
||||
return numberOfChainEvents;
|
||||
}
|
||||
|
||||
private void ProcessPeriodUpdate()
|
||||
{
|
||||
if (DateTime.UtcNow < (lastPeriodUpdateUtc + TimeSpan.FromHours(1.0))) return;
|
||||
lastPeriodUpdateUtc = DateTime.UtcNow;
|
||||
|
||||
eventsFormatter.ProcessPeriodReports(chainState.PeriodMonitor.GetAndClearReports());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user