2
0
mirror of synced 2025-01-11 09:06:56 +00:00

Set up contract-failed event.

This commit is contained in:
Ben 2024-08-21 13:59:54 +02:00
parent 44dfa39737
commit 87bda475df
No known key found for this signature in database
GPG Key ID: 0F16E812E736C24B
22 changed files with 327 additions and 55 deletions

View File

@ -0,0 +1,21 @@
namespace Utils
{
public static class RollingAverage
{
/// <param name="currentAverage">Value of average before new value is added.</param>
/// <param name="newNumberOfValues">Number of values in average after new value is added.</param>
/// <param name="newValue">New value to be added.</param>
/// <returns>New average value.</returns>
/// <exception cref="Exception">newNumberOfValues must be 1 or greater.</exception>
public static float GetNewAverage(float currentAverage, int newNumberOfValues, float newValue)
{
if (newNumberOfValues < 1) throw new Exception("Should be at least 1 value.");
float n = newNumberOfValues;
var originalValue = currentAverage;
var originalValueWeight = ((n - 1.0f) / n);
var newValueWeight = (1.0f / n);
return (originalValue * originalValueWeight) + (newValue * newValueWeight);
}
}
}

View File

@ -10,6 +10,7 @@ namespace CodexContractsPlugin.ChainMonitor
Request[] requests,
RequestFulfilledEventDTO[] fulfilled,
RequestCancelledEventDTO[] cancelled,
RequestFailedEventDTO[] failed,
SlotFilledEventDTO[] slotFilled,
SlotFreedEventDTO[] slotFreed
)
@ -18,6 +19,7 @@ namespace CodexContractsPlugin.ChainMonitor
Requests = requests;
Fulfilled = fulfilled;
Cancelled = cancelled;
Failed = failed;
SlotFilled = slotFilled;
SlotFreed = slotFreed;
}
@ -26,6 +28,7 @@ namespace CodexContractsPlugin.ChainMonitor
public Request[] Requests { get; }
public RequestFulfilledEventDTO[] Fulfilled { get; }
public RequestCancelledEventDTO[] Cancelled { get; }
public RequestFailedEventDTO[] Failed { get; }
public SlotFilledEventDTO[] SlotFilled { get; }
public SlotFreedEventDTO[] SlotFreed { get; }
@ -37,6 +40,7 @@ namespace CodexContractsPlugin.ChainMonitor
all.AddRange(Requests);
all.AddRange(Fulfilled);
all.AddRange(Cancelled);
all.AddRange(Failed);
all.AddRange(SlotFilled);
all.AddRange(SlotFreed);
return all.ToArray();
@ -60,6 +64,7 @@ namespace CodexContractsPlugin.ChainMonitor
events.GetStorageRequests(),
events.GetRequestFulfilledEvents(),
events.GetRequestCancelledEvents(),
events.GetRequestFailedEvents(),
events.GetSlotFilledEvents(),
events.GetSlotFreedEvents()
);

View File

@ -13,6 +13,7 @@ namespace CodexContractsPlugin.ChainMonitor
void OnRequestFinished(RequestEvent requestEvent);
void OnRequestFulfilled(RequestEvent requestEvent);
void OnRequestCancelled(RequestEvent requestEvent);
void OnRequestFailed(RequestEvent requestEvent);
void OnSlotFilled(RequestEvent requestEvent, EthAddress host, BigInteger slotIndex);
void OnSlotFreed(RequestEvent requestEvent, BigInteger slotIndex);
}
@ -41,15 +42,12 @@ namespace CodexContractsPlugin.ChainMonitor
this.log = new LogPrefixer(log, "(ChainState) ");
this.contracts = contracts;
handler = changeHandler;
StartUtc = startUtc;
TotalSpan = new TimeRange(startUtc, startUtc);
}
public TimeRange TotalSpan { get; private set; }
public IChainStateRequest[] Requests => requests.ToArray();
public DateTime StartUtc { get; }
public void Update()
{
Update(DateTime.UtcNow);
@ -124,6 +122,14 @@ namespace CodexContractsPlugin.ChainMonitor
handler.OnRequestCancelled(new RequestEvent(@event.Block, r));
}
private void ApplyEvent(RequestFailedEventDTO @event)
{
var r = FindRequest(@event.RequestId);
if (r == null) return;
r.UpdateState(@event.Block.BlockNumber, RequestState.Failed);
handler.OnRequestFailed(new RequestEvent(@event.Block, r));
}
private void ApplyEvent(SlotFilledEventDTO @event)
{
var r = FindRequest(@event.RequestId);

View File

@ -0,0 +1,55 @@
using GethPlugin;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Text;
using System.Threading.Tasks;
namespace CodexContractsPlugin.ChainMonitor
{
public class ChainStateChangeHandlerMux : IChainStateChangeHandler
{
public ChainStateChangeHandlerMux(params IChainStateChangeHandler[] handlers)
{
Handlers = handlers.ToList();
}
public List<IChainStateChangeHandler> Handlers { get; } = new List<IChainStateChangeHandler>();
public void OnNewRequest(RequestEvent requestEvent)
{
foreach (var handler in Handlers) handler.OnNewRequest(requestEvent);
}
public void OnRequestCancelled(RequestEvent requestEvent)
{
foreach (var handler in Handlers) handler.OnRequestCancelled(requestEvent);
}
public void OnRequestFailed(RequestEvent requestEvent)
{
foreach (var handler in Handlers) handler.OnRequestFailed(requestEvent);
}
public void OnRequestFinished(RequestEvent requestEvent)
{
foreach (var handler in Handlers) handler.OnRequestFinished(requestEvent);
}
public void OnRequestFulfilled(RequestEvent requestEvent)
{
foreach (var handler in Handlers) handler.OnRequestFulfilled(requestEvent);
}
public void OnSlotFilled(RequestEvent requestEvent, EthAddress host, BigInteger slotIndex)
{
foreach (var handler in Handlers) handler.OnSlotFilled(requestEvent, host, slotIndex);
}
public void OnSlotFreed(RequestEvent requestEvent, BigInteger slotIndex)
{
foreach (var handler in Handlers) handler.OnSlotFreed(requestEvent, slotIndex);
}
}
}

View File

@ -13,6 +13,10 @@ namespace CodexContractsPlugin.ChainMonitor
{
}
public void OnRequestFailed(RequestEvent requestEvent)
{
}
public void OnRequestFinished(RequestEvent requestEvent)
{
}

View File

@ -13,6 +13,7 @@ namespace CodexContractsPlugin
Request[] GetStorageRequests();
RequestFulfilledEventDTO[] GetRequestFulfilledEvents();
RequestCancelledEventDTO[] GetRequestCancelledEvents();
RequestFailedEventDTO[] GetRequestFailedEvents();
SlotFilledEventDTO[] GetSlotFilledEvents();
SlotFreedEventDTO[] GetSlotFreedEvents();
}
@ -71,6 +72,17 @@ namespace CodexContractsPlugin
}).ToArray();
}
public RequestFailedEventDTO[] GetRequestFailedEvents()
{
var events = gethNode.GetEvents<RequestFailedEventDTO>(deployment.MarketplaceAddress, BlockInterval);
return events.Select(e =>
{
var result = e.Event;
result.Block = GetBlock(e.Log.BlockNumber.ToUlong());
return result;
}).ToArray();
}
public SlotFilledEventDTO[] GetSlotFilledEvents()
{
var events = gethNode.GetEvents<SlotFilledEventDTO>(deployment.MarketplaceAddress, BlockInterval);

View File

@ -40,6 +40,12 @@ namespace CodexContractsPlugin.Marketplace
public BlockTimeEntry Block { get; set; }
}
public partial class RequestFailedEventDTO : IHasBlock
{
[JsonIgnore]
public BlockTimeEntry Block { get; set; }
}
public partial class SlotFilledEventDTO : IHasBlock
{
[JsonIgnore]

View File

@ -21,5 +21,16 @@ namespace FrameworkTests.Utils
TimeSpan.FromSeconds(28)
));
}
[Test]
public void Averaging()
{
var first = RollingAverage.GetNewAverage(0.0f, 1, 1.0f);
Assert.That(first, Is.EqualTo(1.0f));
var fifth = RollingAverage.GetNewAverage(5.0f, 5, 0.0f);
var expected = new[] { 5.0f, 5.0f, 5.0f, 5.0f, 0.0f }.Average();
Assert.That(fifth, Is.EqualTo(expected));
}
}
}

View File

@ -0,0 +1,13 @@
namespace MarketInsights
{
public class AppState
{
public AppState(Configuration config)
{
Config = config;
}
public MarketOverview MarketOverview { get; set; } = new ();
public Configuration Config { get; }
}
}

View File

@ -0,0 +1,71 @@
using CodexContractsPlugin.ChainMonitor;
using GethPlugin;
using System.Numerics;
using Utils;
namespace MarketInsights
{
public class AverageHistory
{
public readonly List<MarketTimeSegment> contributions = new List<MarketTimeSegment>();
}
public class ContributionBuilder : IChainStateChangeHandler
{
private readonly MarketTimeSegment segment = new MarketTimeSegment();
public void OnNewRequest(RequestEvent requestEvent)
{
AddRequestToAverage(segment.Submitted, requestEvent);
}
public void OnRequestCancelled(RequestEvent requestEvent)
{
AddRequestToAverage(segment.Expired, requestEvent);
}
public void OnRequestFailed(RequestEvent requestEvent)
{
AddRequestToAverage(segment.Failed, requestEvent);
}
public void OnRequestFinished(RequestEvent requestEvent)
{
AddRequestToAverage(segment.Finished, requestEvent);
}
public void OnRequestFulfilled(RequestEvent requestEvent)
{
AddRequestToAverage(segment.Started, requestEvent);
}
public void OnSlotFilled(RequestEvent requestEvent, EthAddress host, BigInteger slotIndex)
{
}
public void OnSlotFreed(RequestEvent requestEvent, BigInteger slotIndex)
{
}
private void AddRequestToAverage(ContractAverages average, RequestEvent requestEvent)
{
average.Number++;
average.Price = GetNewAverage(average.Price, average.Number, requestEvent.Request.Request.Ask.Reward);
average.Size = GetNewAverage(average.Size, average.Number, requestEvent.Request.Request.Ask.SlotSize);
average.Duration = GetNewAverage(average.Duration, average.Number, requestEvent.Request.Request.Ask.Duration);
average.Collateral = GetNewAverage(average.Collateral, average.Number, requestEvent.Request.Request.Ask.Collateral);
average.ProofProbability = GetNewAverage(average.ProofProbability, average.Number, requestEvent.Request.Request.Ask.ProofProbability);
}
private float GetNewAverage(float currentAverage, int newNumberOfValues, BigInteger newValue)
{
return GetNewAverage(currentAverage, newNumberOfValues, (float)newValue);
}
private float GetNewAverage(float currentAverage, int newNumberOfValues, float newValue)
{
return RollingAverage.GetNewAverage(currentAverage, newNumberOfValues, newValue);
}
}
}

View File

@ -0,0 +1,37 @@
using ArgsUniform;
namespace MarketInsights
{
public class Configuration
{
[Uniform("interval-minutes", "im", "INTERVALMINUTES", true, "time in minutes between updates.")]
public int UpdateIntervalMinutes { get; set; } = 10;
[Uniform("max-random-seconds", "mrs", "MAXRANDOMSECONDS", false, "maximum random number of seconds added to update delay.")]
public int MaxRandomIntervalSeconds { get; set; } = 120;
[Uniform("check-history", "ch", "CHECKHISTORY", true, "Unix epoc timestamp of a moment in history on which processing begins. Should be 'launch of the testnet'.")]
public int CheckHistoryTimestamp { get; set; } = 0;
/// <summary>
/// 6 = 1h
/// 144 = 24h
/// 2520 = 1 week
/// 10080 = 4 weeks
/// </summary>
[Uniform("timesegments", "ts", "TIMESEGMENTS", false, "Semi-colon separated integers. Each represents a multiple of intervals, for which a market timesegment will be generated.")]
public string TimeSegments { get; set; } = "6;144;2520;10080";
[Uniform("fullhistory", "fh", "FULLHISTORY", false, "When not zero, market timesegment for 'entire history' will be included.")]
public int FullHistory { get; set; } = 1;
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;
}
}
}
}

View File

@ -6,13 +6,20 @@ namespace MarketInsights.Controllers
[Route("[controller]")]
public class MarketController : ControllerBase
{
private readonly AppState appState;
public MarketController(AppState appState)
{
this.appState = appState;
}
/// <summary>
/// Gets the most recent market overview.
/// </summary>
[HttpGet]
public MarketOverview Get()
{
return new MarketOverview();
return appState.MarketOverview;
}
}
}

View File

@ -16,4 +16,9 @@
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Framework\ArgsUniform\ArgsUniform.csproj" />
<ProjectReference Include="..\..\ProjectPlugins\CodexContractsPlugin\CodexContractsPlugin.csproj" />
</ItemGroup>
</Project>

View File

@ -2,6 +2,11 @@
{
public class MarketOverview
{
/// <summary>
/// Moment when overview was last updated.
/// </summary>
public DateTime LastUpdatedUtc { get; set; }
public MarketTimeSegment[] TimeSegments { get; set; } = Array.Empty<MarketTimeSegment>();
}

View File

@ -1,4 +1,4 @@
using ArgsUniform;
using Microsoft.Extensions.Options;
using System.Reflection;
@ -8,9 +8,15 @@ namespace MarketInsights
{
public static void Main(string[] args)
{
var uniformArgs = new ArgsUniform<Configuration>(PrintHelp, args);
var config = uniformArgs.Parse(true);
var appState = new AppState(config);
var updater = new Updater(appState);
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddSingleton(appState);
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
@ -34,10 +40,15 @@ namespace MarketInsights
app.UseAuthorization();
app.MapControllers();
updater.Run();
app.Run();
}
private static void PrintHelp()
{
Console.WriteLine("WebAPI for generating market overview for Codex network. Comes with OpenAPI swagger endpoint.");
}
}
}

View File

@ -0,0 +1,35 @@

namespace MarketInsights
{
public class Updater
{
private readonly AppState appState;
private readonly Tracker[] trackers;
public Updater(AppState appState)
{
this.appState = appState;
trackers = CreateTrackers();
}
private Tracker[] CreateTrackers()
{
var tokens = appState.Config.TimeSegments.Split(";", StringSplitOptions.RemoveEmptyEntries);
var nums = tokens.Select(t => Convert.ToInt32(t)).ToArray();
return nums.Select(n => new Tracker(n)).ToArray();
}
public void Run()
{
}
}
public class Tracker
{
public Tracker(int numberOfSegments)
{
}
}
}

View File

@ -1,46 +0,0 @@
using CodexContractsPlugin.ChainMonitor;
using GethPlugin;
using System.Numerics;
namespace TestNetRewarder
{
public class ChainChangeMux : IChainStateChangeHandler
{
private readonly IChainStateChangeHandler[] handlers;
public ChainChangeMux(params IChainStateChangeHandler[] handlers)
{
this.handlers = handlers;
}
public void OnNewRequest(RequestEvent requestEvent)
{
foreach (var handler in handlers) handler.OnNewRequest(requestEvent);
}
public void OnRequestCancelled(RequestEvent requestEvent)
{
foreach (var handler in handlers) handler.OnRequestCancelled(requestEvent);
}
public void OnRequestFinished(RequestEvent requestEvent)
{
foreach (var handler in handlers) handler.OnRequestFinished(requestEvent);
}
public void OnRequestFulfilled(RequestEvent requestEvent)
{
foreach (var handler in handlers) handler.OnRequestFulfilled(requestEvent);
}
public void OnSlotFilled(RequestEvent requestEvent, EthAddress host, BigInteger slotIndex)
{
foreach (var handler in handlers) handler.OnSlotFilled(requestEvent, host, slotIndex);
}
public void OnSlotFreed(RequestEvent requestEvent, BigInteger slotIndex)
{
foreach (var handler in handlers) handler.OnSlotFreed(requestEvent, slotIndex);
}
}
}

View File

@ -44,6 +44,11 @@ namespace TestNetRewarder
AddRequestBlock(requestEvent, "Cancelled");
}
public void OnRequestFailed(RequestEvent requestEvent)
{
AddRequestBlock(requestEvent, "Failed");
}
public void OnRequestFinished(RequestEvent requestEvent)
{
AddRequestBlock(requestEvent, "Finished");

View File

@ -70,5 +70,10 @@ namespace TestNetRewarder
}
return Array.Empty<int>();
}
public void OnRequestFailed(RequestEvent requestEvent)
{
throw new NotImplementedException("being removed");
}
}
}

View File

@ -25,7 +25,7 @@ namespace TestNetRewarder
marketTracker = new MarketTracker(config, log);
eventsFormatter = new EventsFormatter();
var handler = new ChainChangeMux(
var handler = new ChainStateChangeHandlerMux(
rewardChecker.Handler,
marketTracker,
eventsFormatter

View File

@ -34,6 +34,10 @@ namespace TestNetRewarder
{
}
public void OnRequestFailed(RequestEvent requestEvent)
{
}
public void OnRequestFinished(RequestEvent requestEvent)
{
if (MeetsRequirements(CheckType.HostFinishedSlot, requestEvent))

View File

@ -9,7 +9,7 @@ namespace TestNetRewarder
{
var repo = new RewardRepo();
var checks = repo.Rewards.Select(r => new RewardCheck(r, giver)).ToArray();
Handler = new ChainChangeMux(checks);
Handler = new ChainStateChangeHandlerMux(checks);
}
public IChainStateChangeHandler Handler { get; }