wip
This commit is contained in:
parent
d3488dc907
commit
c38a2242ba
|
@ -20,37 +20,29 @@ namespace CodexContractsPlugin.ChainMonitor
|
||||||
{
|
{
|
||||||
private readonly List<ChainStateRequest> requests = new List<ChainStateRequest>();
|
private readonly List<ChainStateRequest> requests = new List<ChainStateRequest>();
|
||||||
private readonly ILog log;
|
private readonly ILog log;
|
||||||
|
private readonly ICodexContracts contracts;
|
||||||
private readonly IChainStateChangeHandler handler;
|
private readonly IChainStateChangeHandler handler;
|
||||||
|
|
||||||
private ChainState(ILog log, IChainStateChangeHandler changeHandler, TimeRange timeRange)
|
public ChainState(ILog log, ICodexContracts contracts, IChainStateChangeHandler changeHandler, DateTime startUtc)
|
||||||
{
|
{
|
||||||
this.log = new LogPrefixer(log, "(ChainState) ");
|
this.log = new LogPrefixer(log, "(ChainState) ");
|
||||||
|
this.contracts = contracts;
|
||||||
handler = changeHandler;
|
handler = changeHandler;
|
||||||
TotalSpan = timeRange;
|
StartUtc = startUtc;
|
||||||
}
|
TotalSpan = new TimeRange(startUtc, startUtc);
|
||||||
|
|
||||||
public static ChainState FromTimeRange(ILog log, ICodexContracts contracts, TimeRange timeRange, IChainStateChangeHandler changeHandler)
|
|
||||||
{
|
|
||||||
var events = ChainEvents.FromTimeRange(contracts, timeRange);
|
|
||||||
return FromEvents(log, events, changeHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ChainState FromEvents(ILog log, ChainEvents events, IChainStateChangeHandler changeHandler)
|
|
||||||
{
|
|
||||||
var state = new ChainState(log, changeHandler, events.BlockInterval.TimeRange);
|
|
||||||
state.Apply(events);
|
|
||||||
return state;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public TimeRange TotalSpan { get; private set; }
|
public TimeRange TotalSpan { get; private set; }
|
||||||
public IChainStateRequest[] Requests => requests.ToArray();
|
public IChainStateRequest[] Requests => requests.ToArray();
|
||||||
|
|
||||||
public void Update(ICodexContracts contracts)
|
public DateTime StartUtc { get; }
|
||||||
|
|
||||||
|
public void Update()
|
||||||
{
|
{
|
||||||
Update(contracts, DateTime.UtcNow);
|
Update(DateTime.UtcNow);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Update(ICodexContracts contracts, DateTime toUtc)
|
public void Update(DateTime toUtc)
|
||||||
{
|
{
|
||||||
var span = new TimeRange(TotalSpan.To, toUtc);
|
var span = new TimeRange(TotalSpan.To, toUtc);
|
||||||
var events = ChainEvents.FromTimeRange(contracts, span);
|
var events = ChainEvents.FromTimeRange(contracts, span);
|
||||||
|
|
|
@ -6,9 +6,8 @@ using Utils;
|
||||||
|
|
||||||
namespace TestNetRewarder
|
namespace TestNetRewarder
|
||||||
{
|
{
|
||||||
public class ChainState
|
public class Keepers
|
||||||
{
|
{
|
||||||
private HistoricState historicState;
|
|
||||||
private readonly string[] colorIcons = new[]
|
private readonly string[] colorIcons = new[]
|
||||||
{
|
{
|
||||||
"🔴",
|
"🔴",
|
||||||
|
@ -32,155 +31,5 @@ namespace TestNetRewarder
|
||||||
"🔶",
|
"🔶",
|
||||||
"🔷"
|
"🔷"
|
||||||
};
|
};
|
||||||
|
|
||||||
public ChainState(HistoricState historicState, ICodexContracts contracts, BlockInterval blockRange)
|
|
||||||
{
|
|
||||||
this.historicState = historicState;
|
|
||||||
|
|
||||||
throw new Exception("This is getting a rewrite");
|
|
||||||
|
|
||||||
//NewRequests = contracts.GetStorageRequests(blockRange);
|
|
||||||
//historicState.CleanUpOldRequests();
|
|
||||||
//historicState.ProcessNewRequests(NewRequests);
|
|
||||||
//historicState.UpdateStorageRequests(contracts);
|
|
||||||
|
|
||||||
//StartedRequests = historicState.StorageRequests.Where(r => r.RecentlyStarted).ToArray();
|
|
||||||
//FinishedRequests = historicState.StorageRequests.Where(r => r.RecentlyFinished).ToArray();
|
|
||||||
//RequestFulfilledEvents = contracts.GetRequestFulfilledEvents(blockRange);
|
|
||||||
//RequestCancelledEvents = contracts.GetRequestCancelledEvents(blockRange);
|
|
||||||
//SlotFilledEvents = contracts.GetSlotFilledEvents(blockRange);
|
|
||||||
//SlotFreedEvents = contracts.GetSlotFreedEvents(blockRange);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ChainState(
|
|
||||||
Request[] newRequests,
|
|
||||||
RequestFulfilledEventDTO[] requestFulfilledEvents,
|
|
||||||
RequestCancelledEventDTO[] requestCancelledEvents,
|
|
||||||
SlotFilledEventDTO[] slotFilledEvents,
|
|
||||||
SlotFreedEventDTO[] slotFreedEvents)
|
|
||||||
{
|
|
||||||
NewRequests = newRequests;
|
|
||||||
RequestFulfilledEvents = requestFulfilledEvents;
|
|
||||||
RequestCancelledEvents = requestCancelledEvents;
|
|
||||||
SlotFilledEvents = slotFilledEvents;
|
|
||||||
SlotFreedEvents = slotFreedEvents;
|
|
||||||
|
|
||||||
historicState = new HistoricState();
|
|
||||||
StartedRequests = Array.Empty<StorageRequest>();
|
|
||||||
FinishedRequests = Array.Empty<StorageRequest>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Request[] NewRequests { get; }
|
|
||||||
[JsonIgnore]
|
|
||||||
public StorageRequest[] AllRequests => historicState.StorageRequests;
|
|
||||||
[JsonIgnore]
|
|
||||||
public StorageRequest[] StartedRequests { get; private set; }
|
|
||||||
[JsonIgnore]
|
|
||||||
public StorageRequest[] FinishedRequests { get; private set; }
|
|
||||||
public RequestFulfilledEventDTO[] RequestFulfilledEvents { get; }
|
|
||||||
public RequestCancelledEventDTO[] RequestCancelledEvents { get; }
|
|
||||||
public SlotFilledEventDTO[] SlotFilledEvents { get; }
|
|
||||||
public SlotFreedEventDTO[] SlotFreedEvents { get; }
|
|
||||||
|
|
||||||
public string EntireString()
|
|
||||||
{
|
|
||||||
return
|
|
||||||
$"ChainState=[{JsonConvert.SerializeObject(this)}]" +
|
|
||||||
$"HistoricState=[{historicState.EntireString()}]";
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Set(HistoricState h)
|
|
||||||
{
|
|
||||||
historicState = h;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string[] GenerateOverview()
|
|
||||||
{
|
|
||||||
var entries = new List<StringBlockNumberPair>();
|
|
||||||
|
|
||||||
entries.AddRange(NewRequests.Select(ToPair));
|
|
||||||
entries.AddRange(RequestFulfilledEvents.Select(ToPair));
|
|
||||||
entries.AddRange(RequestCancelledEvents.Select(ToPair));
|
|
||||||
entries.AddRange(SlotFilledEvents.Select(ToPair));
|
|
||||||
entries.AddRange(SlotFreedEvents.Select(ToPair));
|
|
||||||
entries.AddRange(FinishedRequests.Select(ToPair));
|
|
||||||
|
|
||||||
entries.Sort(new StringUtcComparer());
|
|
||||||
|
|
||||||
return entries.Select(ToLine).ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
private StringBlockNumberPair ToPair(Request r)
|
|
||||||
{
|
|
||||||
return new StringBlockNumberPair("NewRequest", JsonConvert.SerializeObject(r), r.Block, r.RequestId);
|
|
||||||
}
|
|
||||||
|
|
||||||
public StringBlockNumberPair ToPair(StorageRequest r)
|
|
||||||
{
|
|
||||||
return new StringBlockNumberPair("FinishedRequest", JsonConvert.SerializeObject(r), r.Request.Block, r.Request.RequestId);
|
|
||||||
}
|
|
||||||
|
|
||||||
private StringBlockNumberPair ToPair(RequestFulfilledEventDTO r)
|
|
||||||
{
|
|
||||||
return new StringBlockNumberPair("Fulfilled", JsonConvert.SerializeObject(r), r.Block, r.RequestId);
|
|
||||||
}
|
|
||||||
|
|
||||||
private StringBlockNumberPair ToPair(RequestCancelledEventDTO r)
|
|
||||||
{
|
|
||||||
return new StringBlockNumberPair("Cancelled", JsonConvert.SerializeObject(r), r.Block, r.RequestId);
|
|
||||||
}
|
|
||||||
|
|
||||||
private StringBlockNumberPair ToPair(SlotFilledEventDTO r)
|
|
||||||
{
|
|
||||||
return new StringBlockNumberPair("SlotFilled", JsonConvert.SerializeObject(r), r.Block, r.RequestId);
|
|
||||||
}
|
|
||||||
|
|
||||||
private StringBlockNumberPair ToPair(SlotFreedEventDTO r)
|
|
||||||
{
|
|
||||||
return new StringBlockNumberPair("SlotFreed", JsonConvert.SerializeObject(r), r.Block, r.RequestId);
|
|
||||||
}
|
|
||||||
|
|
||||||
private string ToLine(StringBlockNumberPair pair)
|
|
||||||
{
|
|
||||||
var nl = Environment.NewLine;
|
|
||||||
var colorIcon = GetColorIcon(pair.RequestId);
|
|
||||||
return $"{colorIcon} {pair.Block} ({pair.Name}){nl}" +
|
|
||||||
$"```json{nl}" +
|
|
||||||
$"{pair.Str}{nl}" +
|
|
||||||
$"```";
|
|
||||||
}
|
|
||||||
|
|
||||||
private string GetColorIcon(byte[] requestId)
|
|
||||||
{
|
|
||||||
var index = requestId[0] % colorIcons.Length;
|
|
||||||
return colorIcons[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
public class StringBlockNumberPair
|
|
||||||
{
|
|
||||||
public StringBlockNumberPair(string name, string str, BlockTimeEntry block, byte[] requestId)
|
|
||||||
{
|
|
||||||
Name = name;
|
|
||||||
Str = str;
|
|
||||||
Block = block;
|
|
||||||
RequestId = requestId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Name { get; }
|
|
||||||
public string Str { get; }
|
|
||||||
public BlockTimeEntry Block { get; }
|
|
||||||
public byte[] RequestId { get; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class StringUtcComparer : IComparer<StringBlockNumberPair>
|
|
||||||
{
|
|
||||||
public int Compare(StringBlockNumberPair? x, StringBlockNumberPair? y)
|
|
||||||
{
|
|
||||||
if (x == null && y == null) return 0;
|
|
||||||
if (x == null) return 1;
|
|
||||||
if (y == null) return -1;
|
|
||||||
return x.Block.BlockNumber.CompareTo(y.Block.BlockNumber);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,5 +40,14 @@ namespace TestNetRewarder
|
||||||
return TimeSpan.FromMinutes(IntervalMinutes);
|
return TimeSpan.FromMinutes(IntervalMinutes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public DateTime HistoryStartUtc
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (CheckHistoryTimestamp == 0) throw new Exception("'check-history' unix timestamp is required. Set it to the start/launch moment of the testnet.");
|
||||||
|
return DateTimeOffset.FromUnixTimeSeconds(CheckHistoryTimestamp).UtcDateTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
using CodexContractsPlugin.Marketplace;
|
using CodexContractsPlugin.ChainMonitor;
|
||||||
|
using CodexContractsPlugin.Marketplace;
|
||||||
using DiscordRewards;
|
using DiscordRewards;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
|
|
||||||
namespace TestNetRewarder
|
namespace TestNetRewarder
|
||||||
{
|
{
|
||||||
public class MarketTracker
|
public class MarketTracker : IChainStateChangeHandler
|
||||||
{
|
{
|
||||||
private readonly List<ChainState> buffer = new List<ChainState>();
|
private readonly List<ChainState> buffer = new List<ChainState>();
|
||||||
|
|
||||||
|
@ -120,5 +121,40 @@ namespace TestNetRewarder
|
||||||
}
|
}
|
||||||
return Array.Empty<int>();
|
return Array.Empty<int>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void OnNewRequest(IChainStateRequest request)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnRequestStarted(IChainStateRequest request)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnRequestFinished(IChainStateRequest request)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnRequestFulfilled(IChainStateRequest request)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnRequestCancelled(IChainStateRequest request)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnSlotFilled(IChainStateRequest request, BigInteger slotIndex)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnSlotFreed(IChainStateRequest request, BigInteger slotIndex)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,39 +1,37 @@
|
||||||
using DiscordRewards;
|
using CodexContractsPlugin;
|
||||||
|
using CodexContractsPlugin.ChainMonitor;
|
||||||
|
using DiscordRewards;
|
||||||
using GethPlugin;
|
using GethPlugin;
|
||||||
using Logging;
|
using Logging;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
using System.Numerics;
|
||||||
using Utils;
|
using Utils;
|
||||||
|
|
||||||
namespace TestNetRewarder
|
namespace TestNetRewarder
|
||||||
{
|
{
|
||||||
public class Processor
|
public class Processor : ITimeSegmentHandler, IChainStateChangeHandler
|
||||||
{
|
{
|
||||||
private static readonly HistoricState historicState = new HistoricState();
|
private readonly RewardChecker rewardChecker = new RewardChecker();
|
||||||
private static readonly RewardRepo rewardRepo = new RewardRepo();
|
private readonly MarketTracker marketTracker = new MarketTracker();
|
||||||
private static readonly MarketTracker marketTracker = new MarketTracker();
|
private readonly ChainState chainState;
|
||||||
|
private readonly Configuration config;
|
||||||
private readonly ILog log;
|
private readonly ILog log;
|
||||||
private BlockInterval? lastBlockRange;
|
private BlockInterval? lastBlockRange;
|
||||||
|
|
||||||
public Processor(ILog log)
|
public Processor(Configuration config, ICodexContracts contracts, ILog log)
|
||||||
{
|
{
|
||||||
|
this.config = config;
|
||||||
this.log = log;
|
this.log = log;
|
||||||
|
|
||||||
|
chainState = new ChainState(log, contracts, this, config.HistoryStartUtc);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task ProcessTimeSegment(TimeRange timeRange)
|
public async Task OnNewSegment(TimeRange timeRange)
|
||||||
{
|
{
|
||||||
var connector = GethConnector.GethConnector.Initialize(log);
|
|
||||||
if (connector == null) throw new Exception("Invalid Geth information");
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var blockRange = connector.GethNode.ConvertTimeRangeToBlockRange(timeRange);
|
chainState.Update(timeRange.To);
|
||||||
if (!IsNewBlockRange(blockRange))
|
|
||||||
{
|
|
||||||
log.Log($"Block range {blockRange} was previously processed. Skipping...");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var chainState = new ChainState(historicState, connector.CodexContracts, blockRange);
|
|
||||||
await ProcessChainState(chainState);
|
await ProcessChainState(chainState);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
@ -43,19 +41,6 @@ namespace TestNetRewarder
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool IsNewBlockRange(BlockInterval blockRange)
|
|
||||||
{
|
|
||||||
if (lastBlockRange == null ||
|
|
||||||
lastBlockRange.From != blockRange.From ||
|
|
||||||
lastBlockRange.To != blockRange.To)
|
|
||||||
{
|
|
||||||
lastBlockRange = blockRange;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task ProcessChainState(ChainState chainState)
|
private async Task ProcessChainState(ChainState chainState)
|
||||||
{
|
{
|
||||||
log.Log(chainState.EntireString());
|
log.Log(chainState.EntireString());
|
||||||
|
@ -92,57 +77,39 @@ namespace TestNetRewarder
|
||||||
return marketTracker.ProcessChainState(chainState);
|
return marketTracker.ProcessChainState(chainState);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<bool> SendRewardsCommand(List<RewardUsersCommand> outgoingRewards, MarketAverage[] marketAverages, string[] eventsOverview)
|
public void OnNewRequest(IChainStateRequest request)
|
||||||
{
|
{
|
||||||
var cmd = new GiveRewardsCommand
|
throw new NotImplementedException();
|
||||||
{
|
|
||||||
Rewards = outgoingRewards.ToArray(),
|
|
||||||
Averages = marketAverages.ToArray(),
|
|
||||||
EventsOverview = eventsOverview
|
|
||||||
};
|
|
||||||
|
|
||||||
log.Debug("Sending rewards: " + JsonConvert.SerializeObject(cmd));
|
|
||||||
return await Program.BotClient.SendRewards(cmd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ProcessReward(List<RewardUsersCommand> outgoingRewards, RewardConfig reward, ChainState chainState)
|
public void OnRequestStarted(IChainStateRequest request)
|
||||||
{
|
{
|
||||||
var winningAddresses = PerformCheck(reward, chainState);
|
throw new NotImplementedException();
|
||||||
foreach (var win in winningAddresses)
|
|
||||||
{
|
|
||||||
log.Log($"Address '{win.Address}' wins '{reward.Message}'");
|
|
||||||
}
|
|
||||||
if (winningAddresses.Any())
|
|
||||||
{
|
|
||||||
outgoingRewards.Add(new RewardUsersCommand
|
|
||||||
{
|
|
||||||
RewardId = reward.RoleId,
|
|
||||||
UserAddresses = winningAddresses.Select(a => a.Address).ToArray()
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private EthAddress[] PerformCheck(RewardConfig reward, ChainState chainState)
|
public void OnRequestFinished(IChainStateRequest request)
|
||||||
{
|
{
|
||||||
var check = GetCheck(reward.CheckConfig);
|
throw new NotImplementedException();
|
||||||
return check.Check(chainState).Distinct().ToArray();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private ICheck GetCheck(CheckConfig config)
|
public void OnRequestFulfilled(IChainStateRequest request)
|
||||||
{
|
{
|
||||||
switch (config.Type)
|
throw new NotImplementedException();
|
||||||
{
|
}
|
||||||
case CheckType.FilledSlot:
|
|
||||||
return new FilledAnySlotCheck();
|
|
||||||
case CheckType.FinishedSlot:
|
|
||||||
return new FinishedSlotCheck(config.MinSlotSize, config.MinDuration);
|
|
||||||
case CheckType.PostedContract:
|
|
||||||
return new PostedContractCheck(config.MinNumberOfHosts, config.MinSlotSize, config.MinDuration);
|
|
||||||
case CheckType.StartedContract:
|
|
||||||
return new StartedContractCheck(config.MinNumberOfHosts, config.MinSlotSize, config.MinDuration);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Exception("Unknown check type: " + config.Type);
|
public void OnRequestCancelled(IChainStateRequest request)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnSlotFilled(IChainStateRequest request, BigInteger slotIndex)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnSlotFreed(IChainStateRequest request, BigInteger slotIndex)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using ArgsUniform;
|
using ArgsUniform;
|
||||||
using Logging;
|
using Logging;
|
||||||
|
using Nethereum.Model;
|
||||||
using Utils;
|
using Utils;
|
||||||
|
|
||||||
namespace TestNetRewarder
|
namespace TestNetRewarder
|
||||||
|
@ -27,8 +28,11 @@ namespace TestNetRewarder
|
||||||
new ConsoleLog()
|
new ConsoleLog()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
var connector = GethConnector.GethConnector.Initialize(Log);
|
||||||
|
if (connector == null) throw new Exception("Invalid Geth information");
|
||||||
|
|
||||||
BotClient = new BotClient(Config, Log);
|
BotClient = new BotClient(Config, Log);
|
||||||
processor = new Processor(Log);
|
processor = new Processor(Config, connector.CodexContracts, Log);
|
||||||
|
|
||||||
EnsurePath(Config.DataPath);
|
EnsurePath(Config.DataPath);
|
||||||
EnsurePath(Config.LogPath);
|
EnsurePath(Config.LogPath);
|
||||||
|
@ -41,12 +45,12 @@ namespace TestNetRewarder
|
||||||
EnsureGethOnline();
|
EnsureGethOnline();
|
||||||
|
|
||||||
Log.Log("Starting TestNet Rewarder...");
|
Log.Log("Starting TestNet Rewarder...");
|
||||||
var segmenter = new TimeSegmenter(Log, Config);
|
var segmenter = new TimeSegmenter(Log, Config, processor);
|
||||||
|
|
||||||
while (!CancellationToken.IsCancellationRequested)
|
while (!CancellationToken.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
await EnsureBotOnline();
|
await EnsureBotOnline();
|
||||||
await segmenter.WaitForNextSegment(processor.ProcessTimeSegment);
|
await segmenter.ProcessNextSegment();
|
||||||
await Task.Delay(100, CancellationToken);
|
await Task.Delay(100, CancellationToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,102 @@
|
||||||
|
using CodexContractsPlugin.ChainMonitor;
|
||||||
|
using DiscordRewards;
|
||||||
|
using GethPlugin;
|
||||||
|
using Nethereum.Model;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
|
namespace TestNetRewarder
|
||||||
|
{
|
||||||
|
public class RewardChecker : IChainStateChangeHandler
|
||||||
|
{
|
||||||
|
private static readonly RewardRepo rewardRepo = new RewardRepo();
|
||||||
|
|
||||||
|
private async Task<bool> SendRewardsCommand(List<RewardUsersCommand> outgoingRewards, MarketAverage[] marketAverages, string[] eventsOverview)
|
||||||
|
{
|
||||||
|
var cmd = new GiveRewardsCommand
|
||||||
|
{
|
||||||
|
Rewards = outgoingRewards.ToArray(),
|
||||||
|
Averages = marketAverages.ToArray(),
|
||||||
|
EventsOverview = eventsOverview
|
||||||
|
};
|
||||||
|
|
||||||
|
log.Debug("Sending rewards: " + JsonConvert.SerializeObject(cmd));
|
||||||
|
return await Program.BotClient.SendRewards(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ProcessReward(List<RewardUsersCommand> outgoingRewards, RewardConfig reward, ChainState chainState)
|
||||||
|
{
|
||||||
|
var winningAddresses = PerformCheck(reward, chainState);
|
||||||
|
foreach (var win in winningAddresses)
|
||||||
|
{
|
||||||
|
log.Log($"Address '{win.Address}' wins '{reward.Message}'");
|
||||||
|
}
|
||||||
|
if (winningAddresses.Any())
|
||||||
|
{
|
||||||
|
outgoingRewards.Add(new RewardUsersCommand
|
||||||
|
{
|
||||||
|
RewardId = reward.RoleId,
|
||||||
|
UserAddresses = winningAddresses.Select(a => a.Address).ToArray()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private EthAddress[] PerformCheck(RewardConfig reward, ChainState chainState)
|
||||||
|
{
|
||||||
|
var check = GetCheck(reward.CheckConfig);
|
||||||
|
return check.Check(chainState).Distinct().ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
private ICheck GetCheck(CheckConfig config)
|
||||||
|
{
|
||||||
|
switch (config.Type)
|
||||||
|
{
|
||||||
|
case CheckType.FilledSlot:
|
||||||
|
return new FilledAnySlotCheck();
|
||||||
|
case CheckType.FinishedSlot:
|
||||||
|
return new FinishedSlotCheck(config.MinSlotSize, config.MinDuration);
|
||||||
|
case CheckType.PostedContract:
|
||||||
|
return new PostedContractCheck(config.MinNumberOfHosts, config.MinSlotSize, config.MinDuration);
|
||||||
|
case CheckType.StartedContract:
|
||||||
|
return new StartedContractCheck(config.MinNumberOfHosts, config.MinSlotSize, config.MinDuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Exception("Unknown check type: " + config.Type);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnNewRequest(IChainStateRequest request)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnRequestStarted(IChainStateRequest request)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnRequestFinished(IChainStateRequest request)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnRequestFulfilled(IChainStateRequest request)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnRequestCancelled(IChainStateRequest request)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnSlotFilled(IChainStateRequest request, BigInteger slotIndex)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnSlotFreed(IChainStateRequest request, BigInteger slotIndex)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,51 +3,60 @@ using Utils;
|
||||||
|
|
||||||
namespace TestNetRewarder
|
namespace TestNetRewarder
|
||||||
{
|
{
|
||||||
|
public interface ITimeSegmentHandler
|
||||||
|
{
|
||||||
|
Task OnNewSegment(TimeRange timeRange);
|
||||||
|
}
|
||||||
|
|
||||||
public class TimeSegmenter
|
public class TimeSegmenter
|
||||||
{
|
{
|
||||||
private readonly ILog log;
|
private readonly ILog log;
|
||||||
|
private readonly ITimeSegmentHandler handler;
|
||||||
private readonly TimeSpan segmentSize;
|
private readonly TimeSpan segmentSize;
|
||||||
private DateTime start;
|
private DateTime latest;
|
||||||
|
|
||||||
public TimeSegmenter(ILog log, Configuration configuration)
|
public TimeSegmenter(ILog log, Configuration configuration, ITimeSegmentHandler handler)
|
||||||
{
|
{
|
||||||
this.log = log;
|
this.log = log;
|
||||||
|
this.handler = handler;
|
||||||
if (configuration.IntervalMinutes < 0) configuration.IntervalMinutes = 1;
|
if (configuration.IntervalMinutes < 0) configuration.IntervalMinutes = 1;
|
||||||
if (configuration.CheckHistoryTimestamp == 0) throw new Exception("'check-history' unix timestamp is required. Set it to the start/launch moment of the testnet.");
|
|
||||||
|
|
||||||
segmentSize = configuration.Interval;
|
segmentSize = configuration.Interval;
|
||||||
start = DateTimeOffset.FromUnixTimeSeconds(configuration.CheckHistoryTimestamp).UtcDateTime;
|
latest = configuration.HistoryStartUtc;
|
||||||
|
|
||||||
log.Log("Starting time segments at " + start);
|
log.Log("Starting time segments at " + latest);
|
||||||
log.Log("Segment size: " + Time.FormatDuration(segmentSize));
|
log.Log("Segment size: " + Time.FormatDuration(segmentSize));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task WaitForNextSegment(Func<TimeRange, Task> onSegment)
|
public async Task ProcessNextSegment()
|
||||||
{
|
{
|
||||||
var now = DateTime.UtcNow;
|
var end = latest + segmentSize;
|
||||||
var end = start + segmentSize;
|
var waited = await WaitUntilTimeSegmentInPast(end);
|
||||||
var waited = false;
|
|
||||||
if (end > now)
|
|
||||||
{
|
|
||||||
// Wait for the entire time segment to be in the past.
|
|
||||||
var delay = end - now;
|
|
||||||
waited = true;
|
|
||||||
log.Log($"Waiting till time segment is in the past... {Time.FormatDuration(delay)}");
|
|
||||||
await Task.Delay(delay, Program.CancellationToken);
|
|
||||||
}
|
|
||||||
await Task.Delay(TimeSpan.FromSeconds(3), Program.CancellationToken);
|
|
||||||
|
|
||||||
if (Program.CancellationToken.IsCancellationRequested) return;
|
if (Program.CancellationToken.IsCancellationRequested) return;
|
||||||
|
|
||||||
var postfix = "(Catching up...)";
|
var postfix = "(Catching up...)";
|
||||||
if (waited) postfix = "(Real-time)";
|
if (waited) postfix = "(Real-time)";
|
||||||
|
log.Log($"Time segment [{latest} to {end}] {postfix}");
|
||||||
|
|
||||||
|
var range = new TimeRange(latest, end);
|
||||||
|
latest = end;
|
||||||
|
|
||||||
log.Log($"Time segment [{start} to {end}] {postfix}");
|
await handler.OnNewSegment(range);
|
||||||
var range = new TimeRange(start, end);
|
}
|
||||||
start = end;
|
|
||||||
|
|
||||||
await onSegment(range);
|
private async Task<bool> WaitUntilTimeSegmentInPast(DateTime end)
|
||||||
|
{
|
||||||
|
await Task.Delay(TimeSpan.FromSeconds(3), Program.CancellationToken);
|
||||||
|
|
||||||
|
var now = DateTime.UtcNow;
|
||||||
|
while (end > now)
|
||||||
|
{
|
||||||
|
var delay = (end - now) + TimeSpan.FromSeconds(3);
|
||||||
|
await Task.Delay(delay, Program.CancellationToken);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue