diff --git a/ProjectPlugins/CodexContractsPlugin/CodexContractsAccess.cs b/ProjectPlugins/CodexContractsPlugin/CodexContractsAccess.cs index a4140e3..97083fe 100644 --- a/ProjectPlugins/CodexContractsPlugin/CodexContractsAccess.cs +++ b/ProjectPlugins/CodexContractsPlugin/CodexContractsAccess.cs @@ -20,7 +20,7 @@ namespace CodexContractsPlugin TestToken GetTestTokenBalance(EthAddress ethAddress); Request[] GetStorageRequests(TimeRange timeRange); - EthAddress GetSlotHost(Request storageRequest, decimal slotIndex); + EthAddress? GetSlotHost(Request storageRequest, decimal slotIndex); RequestState GetRequestState(Request request); RequestFulfilledEventDTO[] GetRequestFulfilledEvents(TimeRange timeRange); RequestCancelledEventDTO[] GetRequestCancelledEvents(TimeRange timeRange); @@ -138,7 +138,7 @@ namespace CodexContractsPlugin }).ToArray(); } - public EthAddress GetSlotHost(Request storageRequest, decimal slotIndex) + public EthAddress? GetSlotHost(Request storageRequest, decimal slotIndex) { var encoder = new ABIEncode(); var encoded = encoder.GetABIEncoded( @@ -152,7 +152,9 @@ namespace CodexContractsPlugin { SlotId = hashed }; - return new EthAddress(gethNode.Call(Deployment.MarketplaceAddress, func)); + var address = gethNode.Call(Deployment.MarketplaceAddress, func); + if (string.IsNullOrEmpty(address)) return null; + return new EthAddress(address); } public RequestState GetRequestState(Request request) diff --git a/TestNetRewarder/ChainState.cs b/TestNetRewarder/ChainState.cs new file mode 100644 index 0000000..13356fc --- /dev/null +++ b/TestNetRewarder/ChainState.cs @@ -0,0 +1,35 @@ +using CodexContractsPlugin; +using CodexContractsPlugin.Marketplace; +using Utils; + +namespace TestNetRewarder +{ + public class ChainState + { + private readonly HistoricState historicState; + + public ChainState(HistoricState historicState, ICodexContracts contracts, TimeRange timeRange) + { + NewRequests = contracts.GetStorageRequests(timeRange); + historicState.ProcessNewRequests(NewRequests); + historicState.UpdateStorageRequests(contracts); + + StartedRequests = historicState.StorageRequests.Where(r => r.RecentlyStarted).ToArray(); + FinishedRequests = historicState.StorageRequests.Where(r => r.RecentlyFininshed).ToArray(); + RequestFulfilledEvents = contracts.GetRequestFulfilledEvents(timeRange); + RequestCancelledEvents = contracts.GetRequestCancelledEvents(timeRange); + SlotFilledEvents = contracts.GetSlotFilledEvents(timeRange); + SlotFreedEvents = contracts.GetSlotFreedEvents(timeRange); + this.historicState = historicState; + } + + public Request[] NewRequests { get; } + public StorageRequest[] AllRequests => historicState.StorageRequests; + public StorageRequest[] StartedRequests { get; private set; } + public StorageRequest[] FinishedRequests { get; private set; } + public RequestFulfilledEventDTO[] RequestFulfilledEvents { get; } + public RequestCancelledEventDTO[] RequestCancelledEvents { get; } + public SlotFilledEventDTO[] SlotFilledEvents { get; } + public SlotFreedEventDTO[] SlotFreedEvents { get; } + } +} diff --git a/TestNetRewarder/Checks.cs b/TestNetRewarder/Checks.cs new file mode 100644 index 0000000..e82c225 --- /dev/null +++ b/TestNetRewarder/Checks.cs @@ -0,0 +1,105 @@ +using GethPlugin; +using NethereumWorkflow; +using Utils; + +namespace TestNetRewarder +{ + public interface ICheck + { + EthAddress[] Check(ChainState state); + } + + public class FilledAnySlotCheck : ICheck + { + public EthAddress[] Check(ChainState state) + { + return state.SlotFilledEvents.Select(e => e.Host).ToArray(); + } + } + + public class FinishedSlotCheck : ICheck + { + private readonly ByteSize minSize; + private readonly TimeSpan minDuration; + + public FinishedSlot(ByteSize minSize, TimeSpan minDuration) + { + this.minSize = minSize; + this.minDuration = minDuration; + } + + public EthAddress[] Check(ChainState state) + { + return state.FinishedRequests + .Where(r => + MeetsSizeRequirement(r) && + MeetsDurationRequirement(r)) + .SelectMany(r => r.Hosts) + .ToArray(); + } + + private bool MeetsSizeRequirement(StorageRequest r) + { + var slotSize = r.Request.Ask.SlotSize.ToDecimal(); + decimal min = minSize.SizeInBytes; + return slotSize >= min; + } + + private bool MeetsDurationRequirement(StorageRequest r) + { + var duration = TimeSpan.FromSeconds((double)r.Request.Ask.Duration); + return duration >= minDuration; + } + } + + public class PostedContractCheck : ICheck + { + public EthAddress[] Check(ChainState state) + { + return state.NewRequests.Select(r => r.ClientAddress).ToArray(); + } + } + + public class StartedContractCheck : ICheck + { + private readonly ulong minNumberOfHosts; + private readonly ByteSize minSlotSize; + private readonly TimeSpan minDuration; + + public StartedContract(ulong minNumberOfHosts, ByteSize minSlotSize, TimeSpan minDuration) + { + this.minNumberOfHosts = minNumberOfHosts; + this.minSlotSize = minSlotSize; + this.minDuration = minDuration; + } + + public EthAddress[] Check(ChainState state) + { + return state.StartedRequests + .Where(r => + MeetsNumSlotsRequirement(r) && + MeetsSizeRequirement(r) && + MeetsDurationRequirement(r)) + .Select(r => r.Request.ClientAddress) + .ToArray(); + } + + private bool MeetsNumSlotsRequirement(StorageRequest r) + { + return r.Request.Ask.Slots >= minNumberOfHosts; + } + + private bool MeetsSizeRequirement(StorageRequest r) + { + var slotSize = r.Request.Ask.SlotSize.ToDecimal(); + decimal min = minSlotSize.SizeInBytes; + return slotSize >= min; + } + + private bool MeetsDurationRequirement(StorageRequest r) + { + var duration = TimeSpan.FromSeconds((double)r.Request.Ask.Duration); + return duration >= minDuration; + } + } +} diff --git a/TestNetRewarder/HistoricState.cs b/TestNetRewarder/HistoricState.cs new file mode 100644 index 0000000..b1ac699 --- /dev/null +++ b/TestNetRewarder/HistoricState.cs @@ -0,0 +1,68 @@ +using CodexContractsPlugin; +using CodexContractsPlugin.Marketplace; +using GethPlugin; + +namespace TestNetRewarder +{ + public class HistoricState + { + private readonly List storageRequests = new List(); + + 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 class StorageRequest + { + public StorageRequest(Request request) + { + Request = request; + Hosts = Array.Empty(); + } + + public Request Request { get; } + public EthAddress[] Hosts { get; private set; } + public RequestState State { get; private set; } + public bool RecentlyStarted { get; private set; } + public bool RecentlyFininshed { get; private set; } + + public void Update(ICodexContracts contracts) + { + Hosts = GetHosts(contracts); + + var newState = contracts.GetRequestState(Request); + + RecentlyStarted = + State == RequestState.New && + newState == RequestState.Started; + + RecentlyFininshed = + State == RequestState.Started && + newState == RequestState.Finished; + + State = newState; + } + + private EthAddress[] GetHosts(ICodexContracts contracts) + { + var result = new List(); + + for (decimal i = 0; i < Request.Ask.Slots; i++) + { + var host = contracts.GetSlotHost(Request, i); + if (host != null) result.Add(host); + } + + return result.ToArray(); + } + } +} diff --git a/TestNetRewarder/Program.cs b/TestNetRewarder/Program.cs index e813005..01945c7 100644 --- a/TestNetRewarder/Program.cs +++ b/TestNetRewarder/Program.cs @@ -1,4 +1,7 @@ using ArgsUniform; +using CodexContractsPlugin.Marketplace; +using CodexContractsPlugin; +using GethPlugin; using Logging; using Utils; @@ -49,18 +52,16 @@ namespace TestNetRewarder var connector = GethConnector.GethConnector.Initialize(Log); if (connector == null) return; - var newRequests = connector.CodexContracts.GetStorageRequests(range); - foreach (var request in newRequests) - { - for (ulong i = 0; i < request.Ask.Slots; i++) - { - var host = connector.CodexContracts.GetSlotHost(request, i); - } - } - var newSlotsFilled = connector.CodexContracts.GetSlotFilledEvents(range); - var newSlotsFreed = connector.CodexContracts.GetSlotFreedEvents(range); - - // can we get them all? + //Request[] GetStorageRequests(TimeRange timeRange); + //EthAddress GetSlotHost(Request storageRequest, decimal slotIndex); + //RequestState GetRequestState(Request request); + //RequestFulfilledEventDTO[] GetRequestFulfilledEvents(TimeRange timeRange); + //RequestCancelledEventDTO[] GetRequestCancelledEvents(TimeRange timeRange); + //SlotFilledEventDTO[] GetSlotFilledEvents(TimeRange timeRange); + //SlotFreedEventDTO[] GetSlotFreedEvents(TimeRange timeRange); + + + } catch (Exception ex) {