Better chain state representation
This commit is contained in:
parent
ac7d323201
commit
cc2513bd2f
|
@ -24,7 +24,7 @@ namespace CodexContractsPlugin.ChainMonitor
|
||||||
|
|
||||||
private ChainState(ILog log, IChainStateChangeHandler changeHandler, TimeRange timeRange)
|
private ChainState(ILog log, IChainStateChangeHandler changeHandler, TimeRange timeRange)
|
||||||
{
|
{
|
||||||
this.log = log;
|
this.log = new LogPrefixer(log, "(ChainState) ");
|
||||||
handler = changeHandler;
|
handler = changeHandler;
|
||||||
TotalSpan = timeRange;
|
TotalSpan = timeRange;
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,21 @@ namespace CodexContractsPlugin.ChainMonitor
|
||||||
public TimeRange TotalSpan { get; private set; }
|
public TimeRange TotalSpan { get; private set; }
|
||||||
public IChainStateRequest[] Requests => requests.ToArray();
|
public IChainStateRequest[] Requests => requests.ToArray();
|
||||||
|
|
||||||
public void Apply(ChainEvents events)
|
public void Update(ICodexContracts contracts)
|
||||||
|
{
|
||||||
|
Update(contracts, DateTime.UtcNow);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Update(ICodexContracts contracts, DateTime toUtc)
|
||||||
|
{
|
||||||
|
var span = new TimeRange(TotalSpan.To, toUtc);
|
||||||
|
var events = ChainEvents.FromTimeRange(contracts, span);
|
||||||
|
Apply(events);
|
||||||
|
|
||||||
|
TotalSpan = new TimeRange(TotalSpan.From, span.To);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Apply(ChainEvents events)
|
||||||
{
|
{
|
||||||
if (events.BlockInterval.TimeRange.From < TotalSpan.From)
|
if (events.BlockInterval.TimeRange.From < TotalSpan.From)
|
||||||
throw new Exception("Attempt to update ChainState with set of events from before its current record.");
|
throw new Exception("Attempt to update ChainState with set of events from before its current record.");
|
||||||
|
@ -52,7 +66,7 @@ namespace CodexContractsPlugin.ChainMonitor
|
||||||
var spanPerBlock = span / numBlocks;
|
var spanPerBlock = span / numBlocks;
|
||||||
|
|
||||||
var eventUtc = events.BlockInterval.TimeRange.From;
|
var eventUtc = events.BlockInterval.TimeRange.From;
|
||||||
for (var b = events.BlockInterval.From; b < events.BlockInterval.To; b++)
|
for (var b = events.BlockInterval.From; b <= events.BlockInterval.To; b++)
|
||||||
{
|
{
|
||||||
var blockEvents = events.All.Where(e => e.Block.BlockNumber == b).ToArray();
|
var blockEvents = events.All.Where(e => e.Block.BlockNumber == b).ToArray();
|
||||||
ApplyEvents(blockEvents, eventUtc);
|
ApplyEvents(blockEvents, eventUtc);
|
||||||
|
@ -86,6 +100,7 @@ namespace CodexContractsPlugin.ChainMonitor
|
||||||
private void ApplyEvent(RequestFulfilledEventDTO request)
|
private void ApplyEvent(RequestFulfilledEventDTO request)
|
||||||
{
|
{
|
||||||
var r = FindRequest(request.RequestId);
|
var r = FindRequest(request.RequestId);
|
||||||
|
if (r == null) return;
|
||||||
r.UpdateState(RequestState.Started);
|
r.UpdateState(RequestState.Started);
|
||||||
handler.OnRequestFulfilled(r);
|
handler.OnRequestFulfilled(r);
|
||||||
}
|
}
|
||||||
|
@ -93,6 +108,7 @@ namespace CodexContractsPlugin.ChainMonitor
|
||||||
private void ApplyEvent(RequestCancelledEventDTO request)
|
private void ApplyEvent(RequestCancelledEventDTO request)
|
||||||
{
|
{
|
||||||
var r = FindRequest(request.RequestId);
|
var r = FindRequest(request.RequestId);
|
||||||
|
if (r == null) return;
|
||||||
r.UpdateState(RequestState.Cancelled);
|
r.UpdateState(RequestState.Cancelled);
|
||||||
handler.OnRequestCancelled(r);
|
handler.OnRequestCancelled(r);
|
||||||
}
|
}
|
||||||
|
@ -100,12 +116,16 @@ namespace CodexContractsPlugin.ChainMonitor
|
||||||
private void ApplyEvent(SlotFilledEventDTO request)
|
private void ApplyEvent(SlotFilledEventDTO request)
|
||||||
{
|
{
|
||||||
var r = FindRequest(request.RequestId);
|
var r = FindRequest(request.RequestId);
|
||||||
|
if (r == null) return;
|
||||||
|
r.Log("SlotFilled");
|
||||||
handler.OnSlotFilled(r, request.SlotIndex);
|
handler.OnSlotFilled(r, request.SlotIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ApplyEvent(SlotFreedEventDTO request)
|
private void ApplyEvent(SlotFreedEventDTO request)
|
||||||
{
|
{
|
||||||
var r = FindRequest(request.RequestId);
|
var r = FindRequest(request.RequestId);
|
||||||
|
if (r == null) return;
|
||||||
|
r.Log("SlotFreed");
|
||||||
handler.OnSlotFreed(r, request.SlotIndex);
|
handler.OnSlotFreed(r, request.SlotIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,9 +142,11 @@ namespace CodexContractsPlugin.ChainMonitor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private ChainStateRequest FindRequest(byte[] requestId)
|
private ChainStateRequest? FindRequest(byte[] requestId)
|
||||||
{
|
{
|
||||||
return requests.Single(r => Equal(r.Request.RequestId, requestId));
|
var r = requests.SingleOrDefault(r => Equal(r.Request.RequestId, requestId));
|
||||||
|
if (r == null) log.Log("Unable to find request by ID!");
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool Equal(byte[] a, byte[] b)
|
private bool Equal(byte[] a, byte[] b)
|
||||||
|
|
|
@ -24,7 +24,7 @@ namespace CodexContractsPlugin.ChainMonitor
|
||||||
ExpiryUtc = request.Block.Utc + TimeSpan.FromSeconds((double)request.Expiry);
|
ExpiryUtc = request.Block.Utc + TimeSpan.FromSeconds((double)request.Expiry);
|
||||||
FinishedUtc = request.Block.Utc + TimeSpan.FromSeconds((double)request.Ask.Duration);
|
FinishedUtc = request.Block.Utc + TimeSpan.FromSeconds((double)request.Ask.Duration);
|
||||||
|
|
||||||
log.Log($"Request created as {State}.");
|
log.Log($"Created as {State}.");
|
||||||
}
|
}
|
||||||
|
|
||||||
public Request Request { get; }
|
public Request Request { get; }
|
||||||
|
@ -34,8 +34,13 @@ namespace CodexContractsPlugin.ChainMonitor
|
||||||
|
|
||||||
public void UpdateState(RequestState newState)
|
public void UpdateState(RequestState newState)
|
||||||
{
|
{
|
||||||
log.Log($"Request transit: {State} -> {newState}");
|
Log($"Transit: {State} -> {newState}");
|
||||||
State = newState;
|
State = newState;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Log(string msg)
|
||||||
|
{
|
||||||
|
log.Log($"Request '{Request.Id}': {msg}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,17 @@ namespace CodexContractsPlugin.Marketplace
|
||||||
public byte[] RequestId { get; set; }
|
public byte[] RequestId { get; set; }
|
||||||
|
|
||||||
public EthAddress ClientAddress { get { return new EthAddress(Client); } }
|
public EthAddress ClientAddress { get { return new EthAddress(Client); } }
|
||||||
|
|
||||||
|
[JsonIgnore]
|
||||||
|
public string Id
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var id = "";
|
||||||
|
foreach (var b in RequestId) id += b.ToString();
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public partial class RequestFulfilledEventDTO : IHasBlock
|
public partial class RequestFulfilledEventDTO : IHasBlock
|
||||||
|
|
|
@ -6,6 +6,7 @@ namespace CodexPlugin
|
||||||
{
|
{
|
||||||
public interface IStoragePurchaseContract
|
public interface IStoragePurchaseContract
|
||||||
{
|
{
|
||||||
|
string PurchaseId { get; }
|
||||||
void WaitForStorageContractSubmitted();
|
void WaitForStorageContractSubmitted();
|
||||||
void WaitForStorageContractStarted();
|
void WaitForStorageContractStarted();
|
||||||
void WaitForStorageContractFinished();
|
void WaitForStorageContractFinished();
|
||||||
|
|
|
@ -1,16 +1,13 @@
|
||||||
using CodexContractsPlugin;
|
using CodexContractsPlugin;
|
||||||
using CodexContractsPlugin.ChainMonitor;
|
using CodexContractsPlugin.ChainMonitor;
|
||||||
using CodexContractsPlugin.Marketplace;
|
|
||||||
using CodexDiscordBotPlugin;
|
using CodexDiscordBotPlugin;
|
||||||
using CodexPlugin;
|
using CodexPlugin;
|
||||||
using Core;
|
using Core;
|
||||||
using DiscordRewards;
|
using DiscordRewards;
|
||||||
using GethPlugin;
|
using GethPlugin;
|
||||||
using KubernetesWorkflow.Types;
|
using KubernetesWorkflow.Types;
|
||||||
using Logging;
|
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using TestNetRewarder;
|
|
||||||
using Utils;
|
using Utils;
|
||||||
|
|
||||||
namespace CodexTests.UtilityTests
|
namespace CodexTests.UtilityTests
|
||||||
|
@ -33,9 +30,6 @@ namespace CodexTests.UtilityTests
|
||||||
var contracts = Ci.StartCodexContracts(geth);
|
var contracts = Ci.StartCodexContracts(geth);
|
||||||
var gethInfo = CreateGethInfo(geth, contracts);
|
var gethInfo = CreateGethInfo(geth, contracts);
|
||||||
|
|
||||||
var monitor = new ChainMonitor(contracts, geth, GetTestLog());
|
|
||||||
monitor.Start();
|
|
||||||
|
|
||||||
var botContainer = StartDiscordBot(gethInfo);
|
var botContainer = StartDiscordBot(gethInfo);
|
||||||
|
|
||||||
StartHosts(geth, contracts);
|
StartHosts(geth, contracts);
|
||||||
|
@ -44,49 +38,45 @@ namespace CodexTests.UtilityTests
|
||||||
|
|
||||||
var client = StartClient(geth, contracts);
|
var client = StartClient(geth, contracts);
|
||||||
|
|
||||||
|
|
||||||
var events = ChainEvents.FromTimeRange(contracts, GetTestRunTimeRange());
|
var events = ChainEvents.FromTimeRange(contracts, GetTestRunTimeRange());
|
||||||
var chainState = CodexContractsPlugin.ChainMonitor.ChainState.FromEvents(
|
var chainState = ChainState.FromEvents(
|
||||||
GetTestLog(),
|
GetTestLog(),
|
||||||
events,
|
events,
|
||||||
new DoNothingChainEventHandler());
|
new DoNothingChainEventHandler());
|
||||||
|
|
||||||
|
|
||||||
var apiCalls = new RewardApiCalls(Ci, botContainer);
|
var apiCalls = new RewardApiCalls(Ci, botContainer);
|
||||||
apiCalls.Start(OnCommand);
|
apiCalls.Start(OnCommand);
|
||||||
var rewarderLog = new RewarderLogMonitor(Ci, rewarderContainer.Containers.Single());
|
|
||||||
rewarderLog.Start(l => Log("Rewarder ChainState: " + l));
|
|
||||||
|
|
||||||
var purchaseContract = ClientPurchasesStorage(client);
|
var purchaseContract = ClientPurchasesStorage(client);
|
||||||
|
chainState.Update(contracts);
|
||||||
|
Assert.That(chainState.Requests.Length, Is.EqualTo(1));
|
||||||
|
|
||||||
|
purchaseContract.WaitForStorageContractStarted();
|
||||||
|
chainState.Update(contracts);
|
||||||
|
|
||||||
purchaseContract.WaitForStorageContractFinished();
|
purchaseContract.WaitForStorageContractFinished();
|
||||||
|
|
||||||
rewarderLog.Stop();
|
|
||||||
apiCalls.Stop();
|
|
||||||
monitor.Stop();
|
|
||||||
|
|
||||||
Log("Done!");
|
|
||||||
|
|
||||||
Thread.Sleep(rewarderInterval * 2);
|
Thread.Sleep(rewarderInterval * 2);
|
||||||
|
|
||||||
chainState.Apply(ChainEvents.FromTimeRange(contracts, GetTestRunTimeRange()));
|
apiCalls.Stop();
|
||||||
|
chainState.Update(contracts);
|
||||||
Log("Seen:");
|
|
||||||
foreach (var seen in rewardsSeen)
|
|
||||||
{
|
|
||||||
Log(seen.ToString());
|
|
||||||
}
|
|
||||||
Log("");
|
|
||||||
|
|
||||||
foreach (var r in repo.Rewards)
|
foreach (var r in repo.Rewards)
|
||||||
{
|
{
|
||||||
var seen = rewardsSeen.Any(s => r.RoleId == s);
|
var seen = rewardsSeen.Any(s => r.RoleId == s);
|
||||||
|
|
||||||
Log($"{r.RoleId} = {seen}");
|
Log($"{Lookup(r.RoleId)} = {seen}");
|
||||||
}
|
}
|
||||||
|
|
||||||
Assert.That(repo.Rewards.All(r => rewardsSeen.Contains(r.RoleId)));
|
Assert.That(repo.Rewards.All(r => rewardsSeen.Contains(r.RoleId)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string Lookup(ulong rewardId)
|
||||||
|
{
|
||||||
|
var reward = repo.Rewards.Single(r => r.RoleId == rewardId);
|
||||||
|
return $"({rewardId})'{reward.Message}'";
|
||||||
|
}
|
||||||
|
|
||||||
private void OnCommand(GiveRewardsCommand call)
|
private void OnCommand(GiveRewardsCommand call)
|
||||||
{
|
{
|
||||||
if (call.Averages.Any()) Log($"API call: {call.Averages.Length} average.");
|
if (call.Averages.Any()) Log($"API call: {call.Averages.Length} average.");
|
||||||
|
@ -292,55 +282,6 @@ namespace CodexTests.UtilityTests
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class RewarderLogMonitor
|
|
||||||
{
|
|
||||||
private readonly ContainerFileMonitor monitor;
|
|
||||||
private readonly Dictionary<string, GiveRewardsCommand> commands = new Dictionary<string, GiveRewardsCommand>();
|
|
||||||
|
|
||||||
public RewarderLogMonitor(CoreInterface ci, RunningContainer botContainer)
|
|
||||||
{
|
|
||||||
monitor = new ContainerFileMonitor(ci, botContainer, "/app/datapath/logs/testnetrewarder.log");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Start(Action<string> onCommand)
|
|
||||||
{
|
|
||||||
monitor.Start(l => ProcessLine(l, onCommand));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Stop()
|
|
||||||
{
|
|
||||||
monitor.Stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ProcessLine(string line, Action<string> log)
|
|
||||||
{
|
|
||||||
//$"ChainState=[{JsonConvert.SerializeObject(this)}]" +
|
|
||||||
//$"HistoricState=[{historicState.EntireString()}]";
|
|
||||||
|
|
||||||
//var stateOpenTag = "ChainState=[";
|
|
||||||
//var historicOpenTag = "]HistoricState=[";
|
|
||||||
|
|
||||||
//if (!line.Contains(stateOpenTag)) return;
|
|
||||||
//if (!line.Contains(historicOpenTag)) return;
|
|
||||||
|
|
||||||
//var stateStr = Between(line, stateOpenTag, historicOpenTag);
|
|
||||||
//var historicStr = Between(line, historicOpenTag, "]");
|
|
||||||
|
|
||||||
//var chainState = JsonConvert.DeserializeObject<ChainState>(stateStr);
|
|
||||||
//var historicState = JsonConvert.DeserializeObject<TestNetRewarder.StorageRequest[]>(historicStr)!;
|
|
||||||
//chainState!.Set(new HistoricState(historicState));
|
|
||||||
|
|
||||||
//log(string.Join(",", chainState!.GenerateOverview()));
|
|
||||||
}
|
|
||||||
|
|
||||||
private string Between(string s, string open, string close)
|
|
||||||
{
|
|
||||||
var start = s.IndexOf(open) + open.Length;
|
|
||||||
var end = s.LastIndexOf(close);
|
|
||||||
return s.Substring(start, end - start);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class ContainerFileMonitor
|
public class ContainerFileMonitor
|
||||||
{
|
{
|
||||||
private readonly CoreInterface ci;
|
private readonly CoreInterface ci;
|
||||||
|
@ -395,70 +336,5 @@ namespace CodexTests.UtilityTests
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ChainMonitor
|
|
||||||
{
|
|
||||||
private readonly ICodexContracts contracts;
|
|
||||||
private readonly IGethNode geth;
|
|
||||||
private readonly ILog log;
|
|
||||||
private readonly CancellationTokenSource cts = new CancellationTokenSource();
|
|
||||||
private Task worker = Task.CompletedTask;
|
|
||||||
private DateTime last = DateTime.UtcNow;
|
|
||||||
|
|
||||||
public ChainMonitor(ICodexContracts contracts, IGethNode geth, ILog log)
|
|
||||||
{
|
|
||||||
this.contracts = contracts;
|
|
||||||
this.geth = geth;
|
|
||||||
this.log = log;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Start()
|
|
||||||
{
|
|
||||||
last = DateTime.UtcNow;
|
|
||||||
worker = Task.Run(Worker);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Stop()
|
|
||||||
{
|
|
||||||
cts.Cancel();
|
|
||||||
worker.Wait();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Worker()
|
|
||||||
{
|
|
||||||
while (!cts.IsCancellationRequested)
|
|
||||||
{
|
|
||||||
Thread.Sleep(TimeSpan.FromSeconds(10));
|
|
||||||
if (cts.IsCancellationRequested) return;
|
|
||||||
|
|
||||||
Update();
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Update()
|
|
||||||
{
|
|
||||||
//var start = last;
|
|
||||||
//var stop = DateTime.UtcNow;
|
|
||||||
//last = stop;
|
|
||||||
|
|
||||||
//var range = geth.ConvertTimeRangeToBlockRange(new TimeRange(start, stop));
|
|
||||||
|
|
||||||
|
|
||||||
//throw new Exception();
|
|
||||||
//LogEvents(nameof(contracts.GetStorageRequests), contracts.GetStorageRequests, range);
|
|
||||||
//LogEvents(nameof(contracts.GetRequestFulfilledEvents), contracts.GetRequestFulfilledEvents, range);
|
|
||||||
//LogEvents(nameof(contracts.GetRequestCancelledEvents), contracts.GetRequestCancelledEvents, range);
|
|
||||||
//LogEvents(nameof(contracts.GetSlotFilledEvents), contracts.GetSlotFilledEvents, range);
|
|
||||||
//LogEvents(nameof(contracts.GetSlotFreedEvents), contracts.GetSlotFreedEvents, range);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void LogEvents(string n, Func<BlockInterval, object> f, BlockInterval r)
|
|
||||||
{
|
|
||||||
var a = (object[])f(r);
|
|
||||||
|
|
||||||
a.ToList().ForEach(request => log.Log(n + " - " + JsonConvert.SerializeObject(request)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue