123 lines
3.8 KiB
C#

using CodexContractsPlugin;
using CodexContractsPlugin.ChainMonitor;
using CodexContractsPlugin.Marketplace;
using Logging;
using Nethereum.Hex.HexConvertors.Extensions;
using Utils;
namespace TraceContract
{
public class ChainTracer
{
private readonly ILog log;
private readonly ICodexContracts contracts;
private readonly Input input;
private readonly Output output;
public ChainTracer(ILog log, ICodexContracts contracts, Input input, Output output)
{
this.log = log;
this.contracts = contracts;
this.input = input;
this.output = output;
}
public TimeRange TraceChainTimeline()
{
log.Log("Querying blockchain...");
var request = GetRequest();
if (request == null) throw new Exception("Failed to find the purchase in the last week of transactions.");
log.Log($"Request started at {request.Block.Utc}");
var contractEnd = RunToContractEnd(request);
var requestTimeline = new TimeRange(request.Block.Utc.AddMinutes(-1.0), contractEnd.AddMinutes(1.0));
log.Log($"Request timeline: {requestTimeline.From} -> {requestTimeline.To}");
// For this timeline, we log all the calls to reserve-slot.
var events = contracts.GetEvents(requestTimeline);
events.GetReserveSlotCalls(call =>
{
if (IsThisRequest(call.RequestId))
{
output.LogReserveSlotCall(call);
log.Log("Found reserve-slot call for slotIndex " + call.SlotIndex);
}
});
log.Log("Writing blockchain output...");
output.WriteContractEvents();
return requestTimeline;
}
private DateTime RunToContractEnd(Request request)
{
var utc = request.Block.Utc.AddMinutes(-1.0);
var tracker = new ChainRequestTracker(output, input.PurchaseId);
var ignoreLog = new NullLog();
var chainState = new ChainState(ignoreLog, contracts, tracker, utc, false);
while (!tracker.IsFinished)
{
utc += TimeSpan.FromHours(1.0);
if (utc > DateTime.UtcNow)
{
log.Log("Caught up to present moment without finding contract end.");
return DateTime.UtcNow;
}
log.Log($"Querying up to {utc}");
chainState.Update(utc);
}
return tracker.FinishUtc;
}
private Request? GetRequest()
{
var request = FindRequest(LastHour());
if (request == null) request = FindRequest(LastDay());
if (request == null) request = FindRequest(LastWeek());
return request;
}
private Request? FindRequest(TimeRange timeRange)
{
var events = contracts.GetEvents(timeRange);
var requests = events.GetStorageRequests();
foreach (var r in requests)
{
if (IsThisRequest(r.RequestId))
{
return r;
}
}
return null;
}
private bool IsThisRequest(byte[] requestId)
{
return requestId.ToHex().ToLowerInvariant() == input.PurchaseId.ToLowerInvariant();
}
private static TimeRange LastHour()
{
return new TimeRange(DateTime.UtcNow.AddHours(-1.0), DateTime.UtcNow);
}
private static TimeRange LastDay()
{
return new TimeRange(DateTime.UtcNow.AddDays(-1.0), DateTime.UtcNow);
}
private static TimeRange LastWeek()
{
return new TimeRange(DateTime.UtcNow.AddDays(-7.0), DateTime.UtcNow);
}
}
}