Fixes faulty customization of chain generated DTOs

This commit is contained in:
Ben 2025-07-07 15:53:26 +02:00
parent 60e2d03c62
commit 2ce2da4d46
No known key found for this signature in database
GPG Key ID: 0F16E812E736C24B
20 changed files with 184 additions and 185 deletions

View File

@ -7,7 +7,7 @@ namespace CodexContractsPlugin.ChainMonitor
{
private ChainEvents(
BlockInterval blockInterval,
Request[] requests,
StorageRequestedEventDTO[] requests,
RequestFulfilledEventDTO[] fulfilled,
RequestCancelledEventDTO[] cancelled,
RequestFailedEventDTO[] failed,
@ -30,7 +30,7 @@ namespace CodexContractsPlugin.ChainMonitor
}
public BlockInterval BlockInterval { get; }
public Request[] Requests { get; }
public StorageRequestedEventDTO[] Requests { get; }
public RequestFulfilledEventDTO[] Fulfilled { get; }
public RequestCancelledEventDTO[] Cancelled { get; }
public RequestFailedEventDTO[] Failed { get; }
@ -54,7 +54,7 @@ namespace CodexContractsPlugin.ChainMonitor
{
return new ChainEvents(
events.BlockInterval,
events.GetStorageRequests(),
events.GetStorageRequestedEvents(),
events.GetRequestFulfilledEvents(),
events.GetRequestCancelledEvents(),
events.GetRequestFailedEvents(),

View File

@ -116,25 +116,22 @@ namespace CodexContractsPlugin.ChainMonitor
ApplyTimeImplicitEvents(blockNumber, eventsUtc);
}
private void ApplyEvent(Request request)
private void ApplyEvent(StorageRequestedEventDTO @event)
{
if (requests.Any(r => Equal(r.Request.RequestId, request.RequestId)))
if (requests.Any(r => Equal(r.RequestId, @event.RequestId)))
{
var r = FindRequest(request);
var r = FindRequest(@event);
if (r == null) throw new Exception("ChainState is inconsistent. Received already-known requestId that's not known.");
if (request.Block.BlockNumber != r.Request.Block.BlockNumber) throw new Exception("Same request found in different blocks.");
if (request.Client != r.Request.Client) throw new Exception("Same request belongs to different clients.");
if (request.Content.Cid.ToHex() != r.Request.Content.Cid.ToHex()) throw new Exception("Same request has different CIDs.");
if (@event.Block.BlockNumber != @event.Block.BlockNumber) throw new Exception("Same request found in different blocks.");
log.Log("Received the same request-creation event multiple times.");
return;
}
var newRequest = new ChainStateRequest(log, request, RequestState.New);
var request = contracts.GetRequest(@event.RequestId);
var newRequest = new ChainStateRequest(log, @event.RequestId, @event.Block, request, RequestState.New);
requests.Add(newRequest);
handler.OnNewRequest(new RequestEvent(request.Block, newRequest));
handler.OnNewRequest(new RequestEvent(@event.Block, newRequest));
}
private void ApplyEvent(RequestFulfilledEventDTO @event)
@ -209,22 +206,22 @@ namespace CodexContractsPlugin.ChainMonitor
}
}
private ChainStateRequest? FindRequest(IHasRequestId request)
private ChainStateRequest? FindRequest(IHasBlockAndRequestId hasBoth)
{
var r = requests.SingleOrDefault(r => Equal(r.Request.RequestId, request.RequestId));
var r = requests.SingleOrDefault(r => Equal(r.RequestId, hasBoth.RequestId));
if (r != null) return r;
try
{
var req = contracts.GetRequest(request.RequestId);
var state = contracts.GetRequestState(req);
var newRequest = new ChainStateRequest(log, req, state);
var req = contracts.GetRequest(hasBoth.RequestId);
var state = contracts.GetRequestState(hasBoth.RequestId);
var newRequest = new ChainStateRequest(log, hasBoth.RequestId, hasBoth.Block, req, state);
requests.Add(newRequest);
return newRequest;
}
catch (Exception ex)
{
var msg = $"Failed to get request with id '{request.RequestId.ToHex()}' from chain: {ex}";
var msg = $"Failed to get request with id '{hasBoth.RequestId.ToHex()}' from chain: {ex}";
log.Error(msg);
handler.OnError(msg);
return null;

View File

@ -1,11 +1,15 @@
using CodexContractsPlugin.Marketplace;
using BlockchainUtils;
using CodexContractsPlugin.Marketplace;
using Logging;
using Nethereum.Hex.HexConvertors.Extensions;
using Utils;
namespace CodexContractsPlugin.ChainMonitor
{
public interface IChainStateRequest
{
byte[] RequestId { get; }
public BlockTimeEntry Block { get; }
Request Request { get; }
RequestState State { get; }
DateTime ExpiryUtc { get; }
@ -18,21 +22,27 @@ namespace CodexContractsPlugin.ChainMonitor
{
private readonly ILog log;
public ChainStateRequest(ILog log, Request request, RequestState state)
public ChainStateRequest(ILog log, byte[] requestId, BlockTimeEntry block, Request request, RequestState state)
{
if (requestId == null || requestId.Length != 32) throw new ArgumentException(nameof(requestId));
this.log = log;
RequestId = requestId;
Block = block;
Request = request;
State = state;
ExpiryUtc = request.Block.Utc + TimeSpan.FromSeconds((double)request.Expiry);
FinishedUtc = request.Block.Utc + TimeSpan.FromSeconds((double)request.Ask.Duration);
ExpiryUtc = Block.Utc + TimeSpan.FromSeconds((double)request.Expiry);
FinishedUtc = Block.Utc + TimeSpan.FromSeconds((double)request.Ask.Duration);
Log($"[{request.Block.BlockNumber}] Created as {State}.");
Log($"[{Block.BlockNumber}] Created as {State}.");
Client = new EthAddress(request.Client);
Hosts = new RequestHosts();
}
public byte[] RequestId { get; }
public BlockTimeEntry Block { get; }
public Request Request { get; }
public RequestState State { get; private set; }
public DateTime ExpiryUtc { get; }
@ -48,7 +58,7 @@ namespace CodexContractsPlugin.ChainMonitor
public void Log(string msg)
{
log.Log($"Request '{Request.Id}': {msg}");
log.Log($"Request '{RequestId.ToHex()}': {msg}");
}
}

View File

@ -46,4 +46,48 @@ namespace CodexContractsPlugin.ChainMonitor
{
}
}
public class DoNothingThrowingChainEventHandler : IChainStateChangeHandler
{
public void OnNewRequest(RequestEvent requestEvent)
{
}
public void OnRequestCancelled(RequestEvent requestEvent)
{
}
public void OnRequestFailed(RequestEvent requestEvent)
{
}
public void OnRequestFinished(RequestEvent requestEvent)
{
}
public void OnRequestFulfilled(RequestEvent requestEvent)
{
}
public void OnSlotFilled(RequestEvent requestEvent, EthAddress host, BigInteger slotIndex, bool isRepair)
{
}
public void OnSlotFreed(RequestEvent requestEvent, BigInteger slotIndex)
{
}
public void OnSlotReservationsFull(RequestEvent requestEvent, BigInteger slotIndex)
{
}
public void OnError(string msg)
{
throw new Exception(msg);
}
public void OnProofSubmitted(BlockTimeEntry block, string id)
{
}
}
}

View File

@ -1,4 +1,5 @@
using Logging;
using Nethereum.Hex.HexConvertors.Extensions;
using Utils;
namespace CodexContractsPlugin.ChainMonitor
@ -46,7 +47,7 @@ namespace CodexContractsPlugin.ChainMonitor
{
for (ulong slotIndex = 0; slotIndex < request.Request.Ask.Slots; slotIndex++)
{
var state = contracts.GetProofState(request.Request, slotIndex, lastBlockInPeriod, periodNumber);
var state = contracts.GetProofState(request.RequestId, slotIndex, lastBlockInPeriod, periodNumber);
total++;
if (state.Required)
@ -116,7 +117,7 @@ namespace CodexContractsPlugin.ChainMonitor
var missed = "None";
if (MissedProofs.Length > 0)
{
missed = string.Join("+", MissedProofs.Select(p => $"{p.FormatHost()} missed {p.Request.Request.Id} slot {p.SlotIndex}"));
missed = string.Join("+", MissedProofs.Select(p => $"{p.FormatHost()} missed {p.Request.RequestId.ToHex()} slot {p.SlotIndex}"));
}
return $"Period:{PeriodNumber}=[Slots:{TotalNumSlots},ProofsRequired:{TotalProofsRequired},ProofsMissed:{missed}]";
}

View File

@ -24,12 +24,12 @@ namespace CodexContractsPlugin
ICodexContractsEvents GetEvents(TimeRange timeRange);
ICodexContractsEvents GetEvents(BlockInterval blockInterval);
EthAddress? GetSlotHost(Request storageRequest, decimal slotIndex);
RequestState GetRequestState(Request request);
EthAddress? GetSlotHost(byte[] requestId, decimal slotIndex);
RequestState GetRequestState(byte[] requestId);
Request GetRequest(byte[] requestId);
ulong GetPeriodNumber(DateTime utc);
void WaitUntilNextPeriod();
ProofState GetProofState(Request storageRequest, decimal slotIndex, ulong blockNumber, ulong period);
ProofState GetProofState(byte[] requestId, decimal slotIndex, ulong blockNumber, ulong period);
ICodexContracts WithDifferentGeth(IGethNode node);
}
@ -111,9 +111,9 @@ namespace CodexContractsPlugin
return new CodexContractsEvents(log, gethNode, Deployment, blockInterval);
}
public EthAddress? GetSlotHost(Request storageRequest, decimal slotIndex)
public EthAddress? GetSlotHost(byte[] requestId, decimal slotIndex)
{
var slotId = GetSlotId(storageRequest, slotIndex);
var slotId = GetSlotId(requestId, slotIndex);
var func = new GetHostFunction
{
SlotId = slotId
@ -123,17 +123,22 @@ namespace CodexContractsPlugin
return new EthAddress(address);
}
public RequestState GetRequestState(Request request)
public RequestState GetRequestState(byte[] requestId)
{
if (requestId == null) throw new ArgumentNullException(nameof(requestId));
if (requestId.Length != 32) throw new InvalidDataException(nameof(requestId) + $"{nameof(requestId)} length should be 32 bytes, but was: {requestId.Length}" + requestId.Length);
var func = new RequestStateFunction
{
RequestId = request.RequestId
RequestId = requestId
};
return gethNode.Call<RequestStateFunction, RequestState>(Deployment.MarketplaceAddress, func);
}
public Request GetRequest(byte[] requestId)
{
if (requestId == null) throw new ArgumentNullException(nameof(requestId));
if (requestId.Length != 32) throw new InvalidDataException(nameof(requestId) + $"{nameof(requestId)} length should be 32 bytes, but was: {requestId.Length}" + requestId.Length);
var func = new GetRequestFunction
{
RequestId = requestId
@ -160,9 +165,9 @@ namespace CodexContractsPlugin
Thread.Sleep(TimeSpan.FromSeconds(secondsLeft + 1));
}
public ProofState GetProofState(Request storageRequest, decimal slotIndex, ulong blockNumber, ulong period)
public ProofState GetProofState(byte[] requestId, decimal slotIndex, ulong blockNumber, ulong period)
{
var slotId = GetSlotId(storageRequest, slotIndex);
var slotId = GetSlotId(requestId, slotIndex);
var required = IsProofRequired(slotId, blockNumber);
if (!required) return new ProofState(false, false);
@ -176,11 +181,11 @@ namespace CodexContractsPlugin
return new CodexContractsAccess(log, node, Deployment);
}
private byte[] GetSlotId(Request request, decimal slotIndex)
private byte[] GetSlotId(byte[] requestId, decimal slotIndex)
{
var encoder = new ABIEncode();
var encoded = encoder.GetABIEncoded(
new ABIValue("bytes32", request.RequestId),
new ABIValue("bytes32", requestId),
new ABIValue("uint256", slotIndex.ToBig())
);

View File

@ -11,7 +11,7 @@ namespace CodexContractsPlugin
public interface ICodexContractsEvents
{
BlockInterval BlockInterval { get; }
Request[] GetStorageRequests();
StorageRequestedEventDTO[] GetStorageRequestedEvents();
RequestFulfilledEventDTO[] GetRequestFulfilledEvents();
RequestCancelledEventDTO[] GetRequestCancelledEvents();
RequestFailedEventDTO[] GetRequestFailedEvents();
@ -38,18 +38,10 @@ namespace CodexContractsPlugin
public BlockInterval BlockInterval { get; }
public Request[] GetStorageRequests()
public StorageRequestedEventDTO[] GetStorageRequestedEvents()
{
var events = gethNode.GetEvents<StorageRequestedEventDTO>(deployment.MarketplaceAddress, BlockInterval);
var i = new ContractInteractions(log, gethNode);
return events.Select(e =>
{
var requestEvent = i.GetRequest(deployment.MarketplaceAddress, e.Event.RequestId);
var result = requestEvent.ReturnValue1;
result.Block = GetBlock(e.Log.BlockNumber.ToUlong());
result.RequestId = e.Event.RequestId;
return result;
}).ToArray();
return events.Select(SetBlockOnEvent).ToArray();
}
public RequestFulfilledEventDTO[] GetRequestFulfilledEvents()

View File

@ -17,48 +17,45 @@ namespace CodexContractsPlugin.Marketplace
byte[] RequestId { get; set; }
}
public interface IHasBlockAndRequestId : IHasBlock, IHasRequestId
{
}
public interface IHasSlotIndex
{
ulong SlotIndex { get; set; }
}
public partial class Request : RequestBase, IHasBlock, IHasRequestId
public partial class Request
{
[JsonIgnore]
public BlockTimeEntry Block { get; set; }
public byte[] RequestId { get; set; }
public EthAddress ClientAddress { get { return new EthAddress(Client); } }
[JsonIgnore]
public string Id
{
get
{
return RequestId.ToHex();
}
}
}
public partial class RequestFulfilledEventDTO : IHasBlock, IHasRequestId
public partial class StorageRequestedEventDTO : IHasBlockAndRequestId
{
[JsonIgnore]
public BlockTimeEntry Block { get; set; }
}
public partial class RequestCancelledEventDTO : IHasBlock, IHasRequestId
public partial class RequestFulfilledEventDTO : IHasBlockAndRequestId
{
[JsonIgnore]
public BlockTimeEntry Block { get; set; }
}
public partial class RequestFailedEventDTO : IHasBlock, IHasRequestId
public partial class RequestCancelledEventDTO : IHasBlockAndRequestId
{
[JsonIgnore]
public BlockTimeEntry Block { get; set; }
}
public partial class SlotFilledEventDTO : IHasBlock, IHasRequestId, IHasSlotIndex
public partial class RequestFailedEventDTO : IHasBlockAndRequestId
{
[JsonIgnore]
public BlockTimeEntry Block { get; set; }
}
public partial class SlotFilledEventDTO : IHasBlockAndRequestId, IHasSlotIndex
{
[JsonIgnore]
public BlockTimeEntry Block { get; set; }
@ -70,13 +67,13 @@ namespace CodexContractsPlugin.Marketplace
}
}
public partial class SlotFreedEventDTO : IHasBlock, IHasRequestId, IHasSlotIndex
public partial class SlotFreedEventDTO : IHasBlockAndRequestId, IHasSlotIndex
{
[JsonIgnore]
public BlockTimeEntry Block { get; set; }
}
public partial class SlotReservationsFullEventDTO : IHasBlock, IHasRequestId, IHasSlotIndex
public partial class SlotReservationsFullEventDTO : IHasBlockAndRequestId, IHasSlotIndex
{
[JsonIgnore]
public BlockTimeEntry Block { get; set; }
@ -88,7 +85,7 @@ namespace CodexContractsPlugin.Marketplace
public BlockTimeEntry Block { get; set; }
}
public partial class ReserveSlotFunction : IHasBlock, IHasRequestId, IHasSlotIndex
public partial class ReserveSlotFunction : IHasBlockAndRequestId, IHasSlotIndex
{
[JsonIgnore]
public BlockTimeEntry Block { get; set; }

View File

@ -1,49 +0,0 @@
using CodexContractsPlugin;
using CodexContractsPlugin.ChainMonitor;
using Logging;
namespace CodexReleaseTests.MarketTests
{
public class ChainMonitor
{
private readonly ChainState chainMonitor;
private readonly TimeSpan interval;
private CancellationTokenSource cts = new CancellationTokenSource();
private Task worker = null!;
public ChainMonitor(ILog log, ICodexContracts contracts, DateTime startUtc, TimeSpan interval)
{
chainMonitor = new ChainState(log, contracts, new DoNothingChainEventHandler(), startUtc, true);
this.interval = interval;
}
public void Start()
{
cts = new CancellationTokenSource();
worker = Task.Run(Worker);
}
public void Stop()
{
cts.Cancel();
worker.Wait();
worker = null!;
cts = null!;
}
public PeriodMonitorResult GetPeriodReports()
{
return chainMonitor.PeriodMonitor.GetAndClearReports();
}
private void Worker()
{
while (!cts.IsCancellationRequested)
{
Thread.Sleep(interval);
chainMonitor.Update();
}
}
}
}

View File

@ -35,7 +35,6 @@ namespace CodexReleaseTests.MarketTests
request.WaitForStorageContractStarted();
AssertContractSlotsAreFilledByHosts(request, hosts);
AssertContractIsOnChain(request);
hosts.Stop(waitTillStopped: true);
@ -43,12 +42,6 @@ namespace CodexReleaseTests.MarketTests
var config = GetContracts().Deployment.Config;
request.WaitForContractFailed(config);
Thread.Sleep(GetPeriodDuration());
AssertContractIsOnChain(request);
Thread.Sleep(GetPeriodDuration());
AssertContractIsOnChain(request);
}
private void WaitForSlotFreedEvents()

View File

@ -41,21 +41,13 @@ namespace CodexReleaseTests.MarketTests
WaitForContractStarted(request);
AssertContractSlotsAreFilledByHosts(request, hosts);
AssertContractIsOnChain(request);
request.WaitForStorageContractFinished();
AssertContractIsOnChain(request);
AssertClientHasPaidForContract(pricePerBytePerSecond, client, request, hosts);
AssertHostsWerePaidForContract(pricePerBytePerSecond, request, hosts);
AssertHostsCollateralsAreUnchanged(hosts);
AssertHostAvailabilitiesAreEmpty(hosts);
Thread.Sleep(GetPeriodDuration());
AssertContractIsOnChain(request);
Thread.Sleep(GetPeriodDuration());
AssertContractIsOnChain(request);
}
private IStoragePurchaseContract CreateStorageRequest(ICodexNode client)

View File

@ -1,6 +1,6 @@
using NUnit.Framework;
[assembly: LevelOfParallelism(2)]
[assembly: LevelOfParallelism(3)]
namespace CodexReleaseTests
{
}

View File

@ -41,7 +41,7 @@ namespace CodexReleaseTests.Utils
private void Worker(Action onFailure)
{
var state = new ChainState(log, contracts, new DoNothingChainEventHandler(), startUtc, doProofPeriodMonitoring: true);
var state = new ChainState(log, contracts, new DoNothingThrowingChainEventHandler(), startUtc, doProofPeriodMonitoring: true);
Thread.Sleep(updateInterval);
log.Log("Chain monitoring started");

View File

@ -176,8 +176,7 @@ namespace CodexReleaseTests.Utils
var result = new ChainMonitor(log, contracts, startUtc);
result.Start(() =>
{
log.Error("Failure in chain monitor. No chain updates after this point.");
//Assert.Fail("Failure in chain monitor.");
Assert.Fail("Failure in chain monitor.");
});
return result;
}
@ -363,7 +362,7 @@ namespace CodexReleaseTests.Utils
return Time.Retry(() =>
{
var events = GetContracts().GetEvents(GetTestRunTimeRange());
var submitEvent = events.GetStorageRequests().SingleOrDefault(e => e.RequestId.ToHex(false) == contract.PurchaseId);
var submitEvent = events.GetStorageRequestedEvents().SingleOrDefault(e => e.RequestId.ToHex() == contract.PurchaseId);
if (submitEvent == null)
{
// We're too early.
@ -405,8 +404,8 @@ namespace CodexReleaseTests.Utils
// Check the creation event.
AssertOnChainEvents(events =>
{
var onChainRequests = events.GetStorageRequests();
if (onChainRequests.Any(r => r.Id == contract.PurchaseId)) return;
var onChainRequests = events.GetStorageRequestedEvents();
if (onChainRequests.Any(r => r.RequestId.ToHex() == contract.PurchaseId)) return;
throw new Exception($"OnChain request {contract.PurchaseId} not found...");
}, nameof(AssertContractIsOnChain));

View File

@ -120,7 +120,7 @@ namespace ExperimentalTests.BasicTests
//Thread.Sleep(GethContainerRecipe.BlockInterval * blocks);
AssertBalance(contracts, client, Is.LessThan(clientInitialBalance), "Buyer was not charged for storage.");
Assert.That(contracts.GetRequestState(request), Is.EqualTo(RequestState.Finished));
Assert.That(contracts.GetRequestState(request.RequestId), Is.EqualTo(RequestState.Finished));
}
private TrackedFile CreateFile(ByteSize fileSize)
@ -148,24 +148,25 @@ namespace ExperimentalTests.BasicTests
}, purchase.Expiry + TimeSpan.FromSeconds(10), TimeSpan.FromSeconds(5), "Checking SlotFilled events");
}
private void AssertStorageRequest(Request request, StoragePurchaseRequest purchase, ICodexContracts contracts, ICodexNode buyer)
private void AssertStorageRequest(StorageRequestedEventDTO request, StoragePurchaseRequest purchase, ICodexContracts contracts, ICodexNode buyer)
{
Assert.That(contracts.GetRequestState(request), Is.EqualTo(RequestState.Started));
Assert.That(request.ClientAddress, Is.EqualTo(buyer.EthAddress));
Assert.That(contracts.GetRequestState(request.RequestId), Is.EqualTo(RequestState.Started));
var r = contracts.GetRequest(request.RequestId);
Assert.That(r.ClientAddress, Is.EqualTo(buyer.EthAddress));
Assert.That(request.Ask.Slots, Is.EqualTo(purchase.MinRequiredNumberOfNodes));
}
private Request GetOnChainStorageRequest(ICodexContracts contracts, IGethNode geth)
private StorageRequestedEventDTO GetOnChainStorageRequest(ICodexContracts contracts, IGethNode geth)
{
var events = contracts.GetEvents(GetTestRunTimeRange());
var requests = events.GetStorageRequests();
var requests = events.GetStorageRequestedEvents();
Assert.That(requests.Length, Is.EqualTo(1));
return requests.Single();
}
private void AssertContractSlot(ICodexContracts contracts, Request request, int contractSlotIndex)
private void AssertContractSlot(ICodexContracts contracts, StorageRequestedEventDTO request, int contractSlotIndex)
{
var slotHost = contracts.GetSlotHost(request, contractSlotIndex);
var slotHost = contracts.GetSlotHost(request.RequestId, contractSlotIndex);
Assert.That(slotHost?.Address, Is.Not.Null);
}
}

View File

@ -2,6 +2,7 @@
using CodexContractsPlugin.ChainMonitor;
using CodexContractsPlugin.Marketplace;
using DiscordRewards;
using Nethereum.Hex.HexConvertors.Extensions;
using System.Globalization;
using System.Numerics;
using Utils;
@ -237,14 +238,15 @@ namespace TestNetRewarder
private string FormatRequestId(IChainStateRequest request)
{
return FormatRequestId(request.Request.Id);
return FormatRequestId(request.RequestId);
}
private string FormatRequestId(string id)
private string FormatRequestId(byte[] id)
{
var str = id.ToHex();
return
$"({emojiMaps.StringToEmojis(id, 3)})" +
$"`{id}`";
$"({emojiMaps.StringToEmojis(str, 3)})" +
$"`{str}`";
}
private string BytesToHexString(byte[] bytes)

View File

@ -1,6 +1,7 @@
using System.Numerics;
using BlockchainUtils;
using CodexContractsPlugin.ChainMonitor;
using Nethereum.Hex.HexConvertors.Extensions;
using Utils;
namespace TraceContract
@ -96,7 +97,7 @@ namespace TraceContract
private bool IsMyRequest(RequestEvent requestEvent)
{
return requestId == requestEvent.Request.Request.Id.ToLowerInvariant();
return requestId == requestEvent.Request.RequestId.ToHex().ToLowerInvariant();
}
}

View File

@ -3,6 +3,7 @@ using CodexContractsPlugin.ChainMonitor;
using CodexContractsPlugin.Marketplace;
using Logging;
using Nethereum.Hex.HexConvertors.Extensions;
using Nethereum.Model;
using Utils;
namespace TraceContract
@ -28,10 +29,12 @@ namespace TraceContract
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 creationEvent = FindRequestCreationEvent();
var requestTimeline = new TimeRange(request.Block.Utc.AddMinutes(-1.0), contractEnd.AddMinutes(1.0));
log.Log($"Request started at {creationEvent.Block.Utc}");
var contractEnd = RunToContractEnd(creationEvent);
var requestTimeline = new TimeRange(creationEvent.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.
@ -52,7 +55,7 @@ namespace TraceContract
return requestTimeline;
}
private DateTime RunToContractEnd(Request request)
private DateTime RunToContractEnd(StorageRequestedEventDTO request)
{
var utc = request.Block.Utc.AddMinutes(-1.0);
var tracker = new ChainRequestTracker(output, input.PurchaseId);
@ -78,35 +81,35 @@ namespace TraceContract
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 Request? GetRequest()
{
return contracts.GetRequest(input.RequestId);
}
public StorageRequestedEventDTO FindRequestCreationEvent()
{
var range = new TimeRange(DateTime.UtcNow - TimeSpan.FromHours(3.0), DateTime.UtcNow);
var limit = DateTime.UtcNow - TimeSpan.FromDays(30);
while (range.From > limit)
{
var events = contracts.GetEvents(range);
foreach (var r in events.GetStorageRequestedEvents())
{
if (r.RequestId.ToHex() == input.RequestId.ToHex()) return r;
}
range = new TimeRange(range.From - TimeSpan.FromHours(3.0), range.From);
}
throw new Exception("Unable to find storage request creation event on-chain after (limit) " + Time.FormatTimestamp(limit));
}
private static TimeRange LastHour()
{
return new TimeRange(DateTime.UtcNow.AddHours(-1.0), DateTime.UtcNow);

View File

@ -1,4 +1,6 @@
namespace TraceContract
using Nethereum.Hex.HexConvertors.Extensions;
namespace TraceContract
{
public class Input
{
@ -17,5 +19,15 @@
//"066df09a3a2e2587cfd577a0e96186c915b113d02b331b06e56f808494cff2b4";
}
}
public byte[] RequestId
{
get
{
var r = PurchaseId.HexToByteArray();
if (r == null || r.Length != 32) throw new ArgumentException(nameof(PurchaseId));
return r;
}
}
}
}

View File

@ -50,8 +50,7 @@ namespace TraceContract
public void LogRequestCreated(RequestEvent requestEvent)
{
var r = requestEvent.Request.Request;
var msg = $"Storage request created: '{r.Id}' = {Environment.NewLine}${JsonConvert.SerializeObject(r, Formatting.Indented)}{Environment.NewLine}";
var msg = $"Storage request created: '{requestEvent.Request.RequestId}' = {Environment.NewLine}${JsonConvert.SerializeObject(requestEvent.Request.Request, Formatting.Indented)}{Environment.NewLine}";
Add(requestEvent.Block, msg);
}