diff --git a/ProjectPlugins/CodexContractsPlugin/ChainMonitor/ChainEvents.cs b/ProjectPlugins/CodexContractsPlugin/ChainMonitor/ChainEvents.cs index 6bbfa3cc..983b6177 100644 --- a/ProjectPlugins/CodexContractsPlugin/ChainMonitor/ChainEvents.cs +++ b/ProjectPlugins/CodexContractsPlugin/ChainMonitor/ChainEvents.cs @@ -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(), diff --git a/ProjectPlugins/CodexContractsPlugin/ChainMonitor/ChainState.cs b/ProjectPlugins/CodexContractsPlugin/ChainMonitor/ChainState.cs index 7c112f16..1cca3f4e 100644 --- a/ProjectPlugins/CodexContractsPlugin/ChainMonitor/ChainState.cs +++ b/ProjectPlugins/CodexContractsPlugin/ChainMonitor/ChainState.cs @@ -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; diff --git a/ProjectPlugins/CodexContractsPlugin/ChainMonitor/ChainStateRequest.cs b/ProjectPlugins/CodexContractsPlugin/ChainMonitor/ChainStateRequest.cs index 2fa50e78..8d570775 100644 --- a/ProjectPlugins/CodexContractsPlugin/ChainMonitor/ChainStateRequest.cs +++ b/ProjectPlugins/CodexContractsPlugin/ChainMonitor/ChainStateRequest.cs @@ -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}"); } } diff --git a/ProjectPlugins/CodexContractsPlugin/ChainMonitor/DoNothingChainEventHandler.cs b/ProjectPlugins/CodexContractsPlugin/ChainMonitor/DoNothingChainEventHandler.cs index b7a7f7fa..db21d52d 100644 --- a/ProjectPlugins/CodexContractsPlugin/ChainMonitor/DoNothingChainEventHandler.cs +++ b/ProjectPlugins/CodexContractsPlugin/ChainMonitor/DoNothingChainEventHandler.cs @@ -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) + { + } + } } diff --git a/ProjectPlugins/CodexContractsPlugin/ChainMonitor/PeriodMonitor.cs b/ProjectPlugins/CodexContractsPlugin/ChainMonitor/PeriodMonitor.cs index f140dd97..2fbd9a97 100644 --- a/ProjectPlugins/CodexContractsPlugin/ChainMonitor/PeriodMonitor.cs +++ b/ProjectPlugins/CodexContractsPlugin/ChainMonitor/PeriodMonitor.cs @@ -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}]"; } diff --git a/ProjectPlugins/CodexContractsPlugin/CodexContractsAccess.cs b/ProjectPlugins/CodexContractsPlugin/CodexContractsAccess.cs index e6916328..dcc411cf 100644 --- a/ProjectPlugins/CodexContractsPlugin/CodexContractsAccess.cs +++ b/ProjectPlugins/CodexContractsPlugin/CodexContractsAccess.cs @@ -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(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()) ); diff --git a/ProjectPlugins/CodexContractsPlugin/CodexContractsEvents.cs b/ProjectPlugins/CodexContractsPlugin/CodexContractsEvents.cs index 6adf4ae7..13850767 100644 --- a/ProjectPlugins/CodexContractsPlugin/CodexContractsEvents.cs +++ b/ProjectPlugins/CodexContractsPlugin/CodexContractsEvents.cs @@ -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(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() diff --git a/ProjectPlugins/CodexContractsPlugin/Marketplace/Customizations.cs b/ProjectPlugins/CodexContractsPlugin/Marketplace/Customizations.cs index ff9c98df..7af43cfb 100644 --- a/ProjectPlugins/CodexContractsPlugin/Marketplace/Customizations.cs +++ b/ProjectPlugins/CodexContractsPlugin/Marketplace/Customizations.cs @@ -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; } diff --git a/Tests/CodexReleaseTests/MarketTests/ChainMonitor.cs b/Tests/CodexReleaseTests/MarketTests/ChainMonitor.cs deleted file mode 100644 index 72b9da02..00000000 --- a/Tests/CodexReleaseTests/MarketTests/ChainMonitor.cs +++ /dev/null @@ -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(); - } - } - } -} diff --git a/Tests/CodexReleaseTests/MarketTests/FailTest.cs b/Tests/CodexReleaseTests/MarketTests/FailTest.cs index 61694489..dc278bcd 100644 --- a/Tests/CodexReleaseTests/MarketTests/FailTest.cs +++ b/Tests/CodexReleaseTests/MarketTests/FailTest.cs @@ -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() diff --git a/Tests/CodexReleaseTests/MarketTests/FinishTest.cs b/Tests/CodexReleaseTests/MarketTests/FinishTest.cs index 9d5fad08..6e591929 100644 --- a/Tests/CodexReleaseTests/MarketTests/FinishTest.cs +++ b/Tests/CodexReleaseTests/MarketTests/FinishTest.cs @@ -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) diff --git a/Tests/CodexReleaseTests/Parallelism.cs b/Tests/CodexReleaseTests/Parallelism.cs index 44731c5e..2666122c 100644 --- a/Tests/CodexReleaseTests/Parallelism.cs +++ b/Tests/CodexReleaseTests/Parallelism.cs @@ -1,6 +1,6 @@ using NUnit.Framework; -[assembly: LevelOfParallelism(2)] +[assembly: LevelOfParallelism(3)] namespace CodexReleaseTests { } diff --git a/Tests/CodexReleaseTests/Utils/ChainMonitor.cs b/Tests/CodexReleaseTests/Utils/ChainMonitor.cs index 8b4bd816..cc24ad18 100644 --- a/Tests/CodexReleaseTests/Utils/ChainMonitor.cs +++ b/Tests/CodexReleaseTests/Utils/ChainMonitor.cs @@ -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"); diff --git a/Tests/CodexReleaseTests/Utils/MarketplaceAutoBootstrapDistTest.cs b/Tests/CodexReleaseTests/Utils/MarketplaceAutoBootstrapDistTest.cs index fabf4422..cbc1ea91 100644 --- a/Tests/CodexReleaseTests/Utils/MarketplaceAutoBootstrapDistTest.cs +++ b/Tests/CodexReleaseTests/Utils/MarketplaceAutoBootstrapDistTest.cs @@ -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)); diff --git a/Tests/ExperimentalTests/BasicTests/MarketplaceTests.cs b/Tests/ExperimentalTests/BasicTests/MarketplaceTests.cs index 803f6d72..e8a08304 100644 --- a/Tests/ExperimentalTests/BasicTests/MarketplaceTests.cs +++ b/Tests/ExperimentalTests/BasicTests/MarketplaceTests.cs @@ -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); } } diff --git a/Tools/TestNetRewarder/EventsFormatter.cs b/Tools/TestNetRewarder/EventsFormatter.cs index b44e476e..0f5ee9fa 100644 --- a/Tools/TestNetRewarder/EventsFormatter.cs +++ b/Tools/TestNetRewarder/EventsFormatter.cs @@ -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) diff --git a/Tools/TraceContract/ChainRequestTracker.cs b/Tools/TraceContract/ChainRequestTracker.cs index 9992f367..7e2638ad 100644 --- a/Tools/TraceContract/ChainRequestTracker.cs +++ b/Tools/TraceContract/ChainRequestTracker.cs @@ -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(); } } diff --git a/Tools/TraceContract/ChainTracer.cs b/Tools/TraceContract/ChainTracer.cs index fc69dd14..a4227ab4 100644 --- a/Tools/TraceContract/ChainTracer.cs +++ b/Tools/TraceContract/ChainTracer.cs @@ -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); diff --git a/Tools/TraceContract/Input.cs b/Tools/TraceContract/Input.cs index a0c63a03..b3d31e04 100644 --- a/Tools/TraceContract/Input.cs +++ b/Tools/TraceContract/Input.cs @@ -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; + } + } } } diff --git a/Tools/TraceContract/Output.cs b/Tools/TraceContract/Output.cs index ce38a5da..0a919967 100644 --- a/Tools/TraceContract/Output.cs +++ b/Tools/TraceContract/Output.cs @@ -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); }