Implements ChainState in CodexContracts plugin
This commit is contained in:
parent
f5da80dc9c
commit
a846d51c0c
|
@ -20,6 +20,7 @@
|
|||
public ulong From { get; }
|
||||
public ulong To { get; }
|
||||
public TimeRange TimeRange { get; }
|
||||
public ulong NumberOfBlocks => To - From;
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
|
|
|
@ -29,6 +29,20 @@ namespace CodexContractsPlugin.ChainMonitor
|
|||
public SlotFilledEventDTO[] SlotFilled { get; }
|
||||
public SlotFreedEventDTO[] SlotFreed { get; }
|
||||
|
||||
public IHasBlock[] All
|
||||
{
|
||||
get
|
||||
{
|
||||
var all = new List<IHasBlock>();
|
||||
all.AddRange(Requests);
|
||||
all.AddRange(Fulfilled);
|
||||
all.AddRange(Cancelled);
|
||||
all.AddRange(SlotFilled);
|
||||
all.AddRange(SlotFreed);
|
||||
return all.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public static ChainEvents FromBlockInterval(ICodexContracts contracts, BlockInterval blockInterval)
|
||||
{
|
||||
return FromContractEvents(contracts.GetEvents(blockInterval));
|
||||
|
|
|
@ -1,7 +1,135 @@
|
|||
namespace CodexContractsPlugin.ChainMonitor
|
||||
using CodexContractsPlugin.Marketplace;
|
||||
using Logging;
|
||||
using System.Numerics;
|
||||
using Utils;
|
||||
|
||||
namespace CodexContractsPlugin.ChainMonitor
|
||||
{
|
||||
public interface IChainStateChangeHandler
|
||||
{
|
||||
void OnNewRequest(IChainStateRequest request);
|
||||
void OnRequestStarted(IChainStateRequest request);
|
||||
void OnRequestFinished(IChainStateRequest request);
|
||||
void OnRequestFulfilled(IChainStateRequest request);
|
||||
void OnRequestCancelled(IChainStateRequest request);
|
||||
void OnSlotFilled(IChainStateRequest request, BigInteger slotIndex);
|
||||
void OnSlotFreed(IChainStateRequest request, BigInteger slotIndex);
|
||||
}
|
||||
|
||||
public class ChainState
|
||||
{
|
||||
private readonly List<ChainStateRequest> requests = new List<ChainStateRequest>();
|
||||
private readonly ILog log;
|
||||
private readonly IChainStateChangeHandler handler;
|
||||
|
||||
private ChainState(ILog log, IChainStateChangeHandler changeHandler, TimeRange timeRange)
|
||||
{
|
||||
this.log = log;
|
||||
handler = changeHandler;
|
||||
TotalSpan = timeRange;
|
||||
}
|
||||
|
||||
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 IChainStateRequest[] Requests => requests.ToArray();
|
||||
|
||||
public void Apply(ChainEvents events)
|
||||
{
|
||||
if (events.BlockInterval.TimeRange.From < TotalSpan.From)
|
||||
throw new Exception("Attempt to update ChainState with set of events from before its current record.");
|
||||
|
||||
log.Log($"ChainState updating: {events.BlockInterval}");
|
||||
|
||||
// Run through each block and apply the events to the state in order.
|
||||
var span = events.BlockInterval.TimeRange.Duration;
|
||||
var numBlocks = events.BlockInterval.NumberOfBlocks;
|
||||
var spanPerBlock = span / numBlocks;
|
||||
|
||||
var eventUtc = events.BlockInterval.TimeRange.From;
|
||||
for (var b = events.BlockInterval.From; b < events.BlockInterval.To; b++)
|
||||
{
|
||||
var blockEvents = events.All.Where(e => e.Block.BlockNumber == b).ToArray();
|
||||
ApplyEvents(blockEvents, eventUtc);
|
||||
|
||||
eventUtc += spanPerBlock;
|
||||
}
|
||||
}
|
||||
|
||||
private void ApplyEvents(IHasBlock[] blockEvents, DateTime eventsUtc)
|
||||
{
|
||||
foreach (var e in blockEvents)
|
||||
{
|
||||
dynamic d = e;
|
||||
ApplyEvent(d);
|
||||
}
|
||||
|
||||
ApplyTimeImplicitEvents(eventsUtc);
|
||||
}
|
||||
|
||||
private void ApplyEvent(Request request)
|
||||
{
|
||||
if (requests.Any(r => Equal(r.Request.RequestId, request.RequestId)))
|
||||
throw new Exception("Received NewRequest event for id that already exists.");
|
||||
|
||||
var newRequest = new ChainStateRequest(log, request, RequestState.New);
|
||||
requests.Add(newRequest);
|
||||
|
||||
handler.OnNewRequest(newRequest);
|
||||
}
|
||||
|
||||
private void ApplyEvent(RequestFulfilledEventDTO request)
|
||||
{
|
||||
var r = FindRequest(request.RequestId);
|
||||
r.UpdateState(RequestState.Started);
|
||||
handler.OnRequestFulfilled(r);
|
||||
}
|
||||
|
||||
private void ApplyEvent(RequestCancelledEventDTO request)
|
||||
{
|
||||
var r = FindRequest(request.RequestId);
|
||||
r.UpdateState(RequestState.Cancelled);
|
||||
handler.OnRequestCancelled(r);
|
||||
}
|
||||
|
||||
private void ApplyEvent(SlotFilledEventDTO request)
|
||||
{
|
||||
var r = FindRequest(request.RequestId);
|
||||
handler.OnSlotFilled(r, request.SlotIndex);
|
||||
}
|
||||
|
||||
private void ApplyEvent(SlotFreedEventDTO request)
|
||||
{
|
||||
var r = FindRequest(request.RequestId);
|
||||
handler.OnSlotFreed(r, request.SlotIndex);
|
||||
}
|
||||
|
||||
private void ApplyTimeImplicitEvents(DateTime eventsUtc)
|
||||
{
|
||||
foreach (var r in requests)
|
||||
{
|
||||
if (r.State == RequestState.Started
|
||||
&& r.FinishedUtc < eventsUtc)
|
||||
{
|
||||
r.UpdateState(RequestState.Finished);
|
||||
handler.OnRequestFinished(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ChainStateRequest FindRequest(byte[] requestId)
|
||||
{
|
||||
return requests.Single(r => Equal(r.Request.RequestId, requestId));
|
||||
}
|
||||
|
||||
private bool Equal(byte[] a, byte[] b)
|
||||
{
|
||||
return a.SequenceEqual(b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
using CodexContractsPlugin.Marketplace;
|
||||
using Logging;
|
||||
|
||||
namespace CodexContractsPlugin.ChainMonitor
|
||||
{
|
||||
public interface IChainStateRequest
|
||||
{
|
||||
Request Request { get; }
|
||||
RequestState State { get; }
|
||||
DateTime ExpiryUtc { get; }
|
||||
DateTime FinishedUtc { get; }
|
||||
}
|
||||
|
||||
public class ChainStateRequest : IChainStateRequest
|
||||
{
|
||||
private readonly ILog log;
|
||||
|
||||
public ChainStateRequest(ILog log, Request request, RequestState state)
|
||||
{
|
||||
this.log = log;
|
||||
Request = request;
|
||||
State = state;
|
||||
|
||||
ExpiryUtc = request.Block.Utc + TimeSpan.FromSeconds((double)request.Expiry);
|
||||
FinishedUtc = request.Block.Utc + TimeSpan.FromSeconds((double)request.Ask.Duration);
|
||||
|
||||
log.Log($"Request created as {State}.");
|
||||
}
|
||||
|
||||
public Request Request { get; }
|
||||
public RequestState State { get; private set; }
|
||||
public DateTime ExpiryUtc { get; }
|
||||
public DateTime FinishedUtc { get; }
|
||||
|
||||
public void UpdateState(RequestState newState)
|
||||
{
|
||||
log.Log($"Request transit: {State} -> {newState}");
|
||||
State = newState;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,7 +5,12 @@ using Newtonsoft.Json;
|
|||
|
||||
namespace CodexContractsPlugin.Marketplace
|
||||
{
|
||||
public partial class Request : RequestBase
|
||||
public interface IHasBlock
|
||||
{
|
||||
BlockTimeEntry Block { get; set; }
|
||||
}
|
||||
|
||||
public partial class Request : RequestBase, IHasBlock
|
||||
{
|
||||
[JsonIgnore]
|
||||
public BlockTimeEntry Block { get; set; }
|
||||
|
@ -14,26 +19,26 @@ namespace CodexContractsPlugin.Marketplace
|
|||
public EthAddress ClientAddress { get { return new EthAddress(Client); } }
|
||||
}
|
||||
|
||||
public partial class RequestFulfilledEventDTO
|
||||
public partial class RequestFulfilledEventDTO : IHasBlock
|
||||
{
|
||||
[JsonIgnore]
|
||||
public BlockTimeEntry Block { get; set; }
|
||||
}
|
||||
|
||||
public partial class RequestCancelledEventDTO
|
||||
public partial class RequestCancelledEventDTO : IHasBlock
|
||||
{
|
||||
[JsonIgnore]
|
||||
public BlockTimeEntry Block { get; set; }
|
||||
}
|
||||
|
||||
public partial class SlotFilledEventDTO
|
||||
public partial class SlotFilledEventDTO : IHasBlock
|
||||
{
|
||||
[JsonIgnore]
|
||||
public BlockTimeEntry Block { get; set; }
|
||||
public EthAddress Host { get; set; }
|
||||
}
|
||||
|
||||
public partial class SlotFreedEventDTO
|
||||
public partial class SlotFreedEventDTO : IHasBlock
|
||||
{
|
||||
[JsonIgnore]
|
||||
public BlockTimeEntry Block { get; set; }
|
||||
|
|
Loading…
Reference in New Issue