diff --git a/ProjectPlugins/CodexContractsPlugin/CodexContractsEvents.cs b/ProjectPlugins/CodexContractsPlugin/CodexContractsEvents.cs index 3fd07634..e2d8a11a 100644 --- a/ProjectPlugins/CodexContractsPlugin/CodexContractsEvents.cs +++ b/ProjectPlugins/CodexContractsPlugin/CodexContractsEvents.cs @@ -4,8 +4,6 @@ using GethPlugin; using Logging; using Nethereum.Contracts; using Nethereum.Hex.HexTypes; -using Nethereum.RPC.Eth.DTOs; -using Nethereum.Web3; using Utils; namespace CodexContractsPlugin @@ -105,7 +103,11 @@ namespace CodexContractsPlugin public ReserveSlotFunction[] GetReserveSlotCalls() { var result = new List(); - gethNode.IterateFunctionCalls(BlockInterval, result.Add); + gethNode.IterateFunctionCalls(BlockInterval, (b, fn) => + { + fn.Block = b; + result.Add(fn); + }); return result.ToArray(); } diff --git a/ProjectPlugins/CodexContractsPlugin/Marketplace/Customizations.cs b/ProjectPlugins/CodexContractsPlugin/Marketplace/Customizations.cs index a93df5d1..222dc631 100644 --- a/ProjectPlugins/CodexContractsPlugin/Marketplace/Customizations.cs +++ b/ProjectPlugins/CodexContractsPlugin/Marketplace/Customizations.cs @@ -15,6 +15,11 @@ namespace CodexContractsPlugin.Marketplace byte[] RequestId { get; set; } } + public interface IHasSlotIndex + { + ulong SlotIndex { get; set; } + } + public partial class Request : RequestBase, IHasBlock, IHasRequestId { [JsonIgnore] @@ -51,20 +56,20 @@ namespace CodexContractsPlugin.Marketplace public BlockTimeEntry Block { get; set; } } - public partial class SlotFilledEventDTO : IHasBlock, IHasRequestId + public partial class SlotFilledEventDTO : IHasBlock, IHasRequestId, IHasSlotIndex { [JsonIgnore] public BlockTimeEntry Block { get; set; } public EthAddress Host { get; set; } } - public partial class SlotFreedEventDTO : IHasBlock, IHasRequestId + public partial class SlotFreedEventDTO : IHasBlock, IHasRequestId, IHasSlotIndex { [JsonIgnore] public BlockTimeEntry Block { get; set; } } - public partial class SlotReservationsFullEventDTO : IHasBlock, IHasRequestId + public partial class SlotReservationsFullEventDTO : IHasBlock, IHasRequestId, IHasSlotIndex { [JsonIgnore] public BlockTimeEntry Block { get; set; } @@ -75,5 +80,11 @@ namespace CodexContractsPlugin.Marketplace [JsonIgnore] public BlockTimeEntry Block { get; set; } } + + public partial class ReserveSlotFunction : IHasBlock, IHasRequestId, IHasSlotIndex + { + [JsonIgnore] + public BlockTimeEntry Block { get; set; } + } } #pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. diff --git a/ProjectPlugins/GethPlugin/GethNode.cs b/ProjectPlugins/GethPlugin/GethNode.cs index e94a5e09..cfd0af37 100644 --- a/ProjectPlugins/GethPlugin/GethNode.cs +++ b/ProjectPlugins/GethPlugin/GethNode.cs @@ -31,7 +31,7 @@ namespace GethPlugin List> GetEvents(string address, TimeRange timeRange) where TEvent : IEventDTO, new(); BlockInterval ConvertTimeRangeToBlockRange(TimeRange timeRange); BlockTimeEntry GetBlockForNumber(ulong number); - void IterateFunctionCalls(BlockInterval blockInterval, Action onCall) where TFunc : FunctionMessage, new(); + void IterateFunctionCalls(BlockInterval blockInterval, Action onCall) where TFunc : FunctionMessage, new(); } public class DeploymentGethNode : BaseGethNode, IGethNode @@ -189,7 +189,7 @@ namespace GethPlugin return StartInteraction().GetBlockWithTransactions(number); } - public void IterateFunctionCalls(BlockInterval blockRange, Action onCall) where TFunc : FunctionMessage, new() + public void IterateFunctionCalls(BlockInterval blockRange, Action onCall) where TFunc : FunctionMessage, new() { var i = StartInteraction(); for (var blkI = blockRange.From; blkI <= blockRange.To; blkI++) @@ -201,7 +201,11 @@ namespace GethPlugin if (t.IsTransactionForFunctionMessage()) { var func = t.DecodeTransactionToFunctionMessage(); - if (func != null) onCall(func); + if (func != null) + { + var b = GetBlockForNumber(blkI); + onCall(b, func); + } } } } diff --git a/Tests/CodexReleaseTests/MarketTests/MarketplaceAutoBootstrapDistTest.cs b/Tests/CodexReleaseTests/MarketTests/MarketplaceAutoBootstrapDistTest.cs index 146cc993..39d2e1b3 100644 --- a/Tests/CodexReleaseTests/MarketTests/MarketplaceAutoBootstrapDistTest.cs +++ b/Tests/CodexReleaseTests/MarketTests/MarketplaceAutoBootstrapDistTest.cs @@ -271,7 +271,7 @@ namespace CodexReleaseTests.MarketTests Log($"Request '{requestId}' failed to start. There were {calls.Length} hosts who called reserve-slot for it:"); foreach (var c in calls) { - Log($" - Host: {c.FromAddress} RequestId: {c.RequestId.ToHex()} SlotIndex: {c.SlotIndex}"); + Log($" - {c.Block.Utc} Host: {c.FromAddress} RequestId: {c.RequestId.ToHex()} SlotIndex: {c.SlotIndex}"); } } } diff --git a/TraceContract/Config.cs b/TraceContract/Config.cs new file mode 100644 index 00000000..8f52e7cf --- /dev/null +++ b/TraceContract/Config.cs @@ -0,0 +1,11 @@ +namespace TraceContract +{ + public class Config + { + public string RpcEndpoint { get; } = "https://rpc.testnet.codex.storage"; + public int GethPort { get; } = 443; + public string MarketplaceAddress { get; } = "0xDB2908d724a15d05c0B6B8e8441a8b36E67476d3"; + public string TokenAddress { get; } = "0x34a22f3911De437307c6f4485931779670f78764"; + public string Abi { get; } = @"[{""inputs"":[{""components"":[{""components"":[{""internalType"":""uint8"",""name"":""repairRewardPercentage"",""type"":""uint8""},{""internalType"":""uint8"",""name"":""maxNumberOfSlashes"",""type"":""uint8""},{""internalType"":""uint16"",""name"":""slashCriterion"",""type"":""uint16""},{""internalType"":""uint8"",""name"":""slashPercentage"",""type"":""uint8""}],""internalType"":""struct CollateralConfig"",""name"":""collateral"",""type"":""tuple""},{""components"":[{""internalType"":""uint256"",""name"":""period"",""type"":""uint256""},{""internalType"":""uint256"",""name"":""timeout"",""type"":""uint256""},{""internalType"":""uint8"",""name"":""downtime"",""type"":""uint8""},{""internalType"":""string"",""name"":""zkeyHash"",""type"":""string""}],""internalType"":""struct ProofConfig"",""name"":""proofs"",""type"":""tuple""}],""internalType"":""struct MarketplaceConfig"",""name"":""configuration"",""type"":""tuple""},{""internalType"":""contract IERC20"",""name"":""token_"",""type"":""address""},{""internalType"":""contract IGroth16Verifier"",""name"":""verifier"",""type"":""address""}],""stateMutability"":""nonpayable"",""type"":""constructor""},{""anonymous"":false,""inputs"":[{""indexed"":false,""internalType"":""SlotId"",""name"":""id"",""type"":""bytes32""}],""name"":""ProofSubmitted"",""type"":""event""},{""anonymous"":false,""inputs"":[{""indexed"":true,""internalType"":""RequestId"",""name"":""requestId"",""type"":""bytes32""}],""name"":""RequestCancelled"",""type"":""event""},{""anonymous"":false,""inputs"":[{""indexed"":true,""internalType"":""RequestId"",""name"":""requestId"",""type"":""bytes32""}],""name"":""RequestFailed"",""type"":""event""},{""anonymous"":false,""inputs"":[{""indexed"":true,""internalType"":""RequestId"",""name"":""requestId"",""type"":""bytes32""}],""name"":""RequestFulfilled"",""type"":""event""},{""anonymous"":false,""inputs"":[{""indexed"":true,""internalType"":""RequestId"",""name"":""requestId"",""type"":""bytes32""},{""indexed"":false,""internalType"":""uint256"",""name"":""slotIndex"",""type"":""uint256""}],""name"":""SlotFilled"",""type"":""event""},{""anonymous"":false,""inputs"":[{""indexed"":true,""internalType"":""RequestId"",""name"":""requestId"",""type"":""bytes32""},{""indexed"":false,""internalType"":""uint256"",""name"":""slotIndex"",""type"":""uint256""}],""name"":""SlotFreed"",""type"":""event""},{""anonymous"":false,""inputs"":[{""indexed"":false,""internalType"":""RequestId"",""name"":""requestId"",""type"":""bytes32""},{""components"":[{""internalType"":""uint64"",""name"":""slots"",""type"":""uint64""},{""internalType"":""uint256"",""name"":""slotSize"",""type"":""uint256""},{""internalType"":""uint256"",""name"":""duration"",""type"":""uint256""},{""internalType"":""uint256"",""name"":""proofProbability"",""type"":""uint256""},{""internalType"":""uint256"",""name"":""reward"",""type"":""uint256""},{""internalType"":""uint256"",""name"":""collateral"",""type"":""uint256""},{""internalType"":""uint64"",""name"":""maxSlotLoss"",""type"":""uint64""}],""indexed"":false,""internalType"":""struct Ask"",""name"":""ask"",""type"":""tuple""},{""indexed"":false,""internalType"":""uint256"",""name"":""expiry"",""type"":""uint256""}],""name"":""StorageRequested"",""type"":""event""},{""inputs"":[],""name"":""config"",""outputs"":[{""components"":[{""components"":[{""internalType"":""uint8"",""name"":""repairRewardPercentage"",""type"":""uint8""},{""internalType"":""uint8"",""name"":""maxNumberOfSlashes"",""type"":""uint8""},{""internalType"":""uint16"",""name"":""slashCriterion"",""type"":""uint16""},{""internalType"":""uint8"",""name"":""slashPercentage"",""type"":""uint8""}],""internalType"":""struct CollateralConfig"",""name"":""collateral"",""type"":""tuple""},{""components"":[{""internalType"":""uint256"",""name"":""period"",""type"":""uint256""},{""internalType"":""uint256"",""name"":""timeout"",""type"":""uint256""},{""internalType"":""uint8"",""name"":""downtime"",""type"":""uint8""},{""internalType"":""string"",""name"":""zkeyHash"",""type"":""string""}],""internalType"":""struct ProofConfig"",""name"":""proofs"",""type"":""tuple""}],""internalType"":""struct MarketplaceConfig"",""name"":"""",""type"":""tuple""}],""stateMutability"":""view"",""type"":""function""},{""inputs"":[{""internalType"":""RequestId"",""name"":""requestId"",""type"":""bytes32""},{""internalType"":""uint256"",""name"":""slotIndex"",""type"":""uint256""},{""components"":[{""components"":[{""internalType"":""uint256"",""name"":""x"",""type"":""uint256""},{""internalType"":""uint256"",""name"":""y"",""type"":""uint256""}],""internalType"":""struct G1Point"",""name"":""a"",""type"":""tuple""},{""components"":[{""components"":[{""internalType"":""uint256"",""name"":""real"",""type"":""uint256""},{""internalType"":""uint256"",""name"":""imag"",""type"":""uint256""}],""internalType"":""struct Fp2Element"",""name"":""x"",""type"":""tuple""},{""components"":[{""internalType"":""uint256"",""name"":""real"",""type"":""uint256""},{""internalType"":""uint256"",""name"":""imag"",""type"":""uint256""}],""internalType"":""struct Fp2Element"",""name"":""y"",""type"":""tuple""}],""internalType"":""struct G2Point"",""name"":""b"",""type"":""tuple""},{""components"":[{""internalType"":""uint256"",""name"":""x"",""type"":""uint256""},{""internalType"":""uint256"",""name"":""y"",""type"":""uint256""}],""internalType"":""struct G1Point"",""name"":""c"",""type"":""tuple""}],""internalType"":""struct Groth16Proof"",""name"":""proof"",""type"":""tuple""}],""name"":""fillSlot"",""outputs"":[],""stateMutability"":""nonpayable"",""type"":""function""},{""inputs"":[{""internalType"":""SlotId"",""name"":""slotId"",""type"":""bytes32""}],""name"":""freeSlot"",""outputs"":[],""stateMutability"":""nonpayable"",""type"":""function""},{""inputs"":[{""internalType"":""SlotId"",""name"":""slotId"",""type"":""bytes32""}],""name"":""getActiveSlot"",""outputs"":[{""components"":[{""components"":[{""internalType"":""address"",""name"":""client"",""type"":""address""},{""components"":[{""internalType"":""uint64"",""name"":""slots"",""type"":""uint64""},{""internalType"":""uint256"",""name"":""slotSize"",""type"":""uint256""},{""internalType"":""uint256"",""name"":""duration"",""type"":""uint256""},{""internalType"":""uint256"",""name"":""proofProbability"",""type"":""uint256""},{""internalType"":""uint256"",""name"":""reward"",""type"":""uint256""},{""internalType"":""uint256"",""name"":""collateral"",""type"":""uint256""},{""internalType"":""uint64"",""name"":""maxSlotLoss"",""type"":""uint64""}],""internalType"":""struct Ask"",""name"":""ask"",""type"":""tuple""},{""components"":[{""internalType"":""string"",""name"":""cid"",""type"":""string""},{""internalType"":""bytes32"",""name"":""merkleRoot"",""type"":""bytes32""}],""internalType"":""struct Content"",""name"":""content"",""type"":""tuple""},{""internalType"":""uint256"",""name"":""expiry"",""type"":""uint256""},{""internalType"":""bytes32"",""name"":""nonce"",""type"":""bytes32""}],""internalType"":""struct Request"",""name"":""request"",""type"":""tuple""},{""internalType"":""uint256"",""name"":""slotIndex"",""type"":""uint256""}],""internalType"":""struct Marketplace.ActiveSlot"",""name"":"""",""type"":""tuple""}],""stateMutability"":""view"",""type"":""function""},{""inputs"":[{""internalType"":""SlotId"",""name"":""id"",""type"":""bytes32""}],""name"":""getChallenge"",""outputs"":[{""internalType"":""bytes32"",""name"":"""",""type"":""bytes32""}],""stateMutability"":""view"",""type"":""function""},{""inputs"":[{""internalType"":""SlotId"",""name"":""slotId"",""type"":""bytes32""}],""name"":""getHost"",""outputs"":[{""internalType"":""address"",""name"":"""",""type"":""address""}],""stateMutability"":""view"",""type"":""function""},{""inputs"":[{""internalType"":""SlotId"",""name"":""id"",""type"":""bytes32""}],""name"":""getPointer"",""outputs"":[{""internalType"":""uint8"",""name"":"""",""type"":""uint8""}],""stateMutability"":""view"",""type"":""function""},{""inputs"":[{""internalType"":""RequestId"",""name"":""requestId"",""type"":""bytes32""}],""name"":""getRequest"",""outputs"":[{""components"":[{""internalType"":""address"",""name"":""client"",""type"":""address""},{""components"":[{""internalType"":""uint64"",""name"":""slots"",""type"":""uint64""},{""internalType"":""uint256"",""name"":""slotSize"",""type"":""uint256""},{""internalType"":""uint256"",""name"":""duration"",""type"":""uint256""},{""internalType"":""uint256"",""name"":""proofProbability"",""type"":""uint256""},{""internalType"":""uint256"",""name"":""reward"",""type"":""uint256""},{""internalType"":""uint256"",""name"":""collateral"",""type"":""uint256""},{""internalType"":""uint64"",""name"":""maxSlotLoss"",""type"":""uint64""}],""internalType"":""struct Ask"",""name"":""ask"",""type"":""tuple""},{""components"":[{""internalType"":""string"",""name"":""cid"",""type"":""string""},{""internalType"":""bytes32"",""name"":""merkleRoot"",""type"":""bytes32""}],""internalType"":""struct Content"",""name"":""content"",""type"":""tuple""},{""internalType"":""uint256"",""name"":""expiry"",""type"":""uint256""},{""internalType"":""bytes32"",""name"":""nonce"",""type"":""bytes32""}],""internalType"":""struct Request"",""name"":"""",""type"":""tuple""}],""stateMutability"":""view"",""type"":""function""},{""inputs"":[{""internalType"":""SlotId"",""name"":""id"",""type"":""bytes32""}],""name"":""isProofRequired"",""outputs"":[{""internalType"":""bool"",""name"":"""",""type"":""bool""}],""stateMutability"":""view"",""type"":""function""},{""inputs"":[{""internalType"":""SlotId"",""name"":""slotId"",""type"":""bytes32""},{""internalType"":""Periods.Period"",""name"":""period"",""type"":""uint256""}],""name"":""markProofAsMissing"",""outputs"":[],""stateMutability"":""nonpayable"",""type"":""function""},{""inputs"":[{""internalType"":""SlotId"",""name"":""slotId"",""type"":""bytes32""}],""name"":""missingProofs"",""outputs"":[{""internalType"":""uint256"",""name"":"""",""type"":""uint256""}],""stateMutability"":""view"",""type"":""function""},{""inputs"":[],""name"":""myRequests"",""outputs"":[{""internalType"":""RequestId[]"",""name"":"""",""type"":""bytes32[]""}],""stateMutability"":""view"",""type"":""function""},{""inputs"":[],""name"":""mySlots"",""outputs"":[{""internalType"":""SlotId[]"",""name"":"""",""type"":""bytes32[]""}],""stateMutability"":""view"",""type"":""function""},{""inputs"":[{""internalType"":""RequestId"",""name"":""requestId"",""type"":""bytes32""}],""name"":""requestEnd"",""outputs"":[{""internalType"":""uint256"",""name"":"""",""type"":""uint256""}],""stateMutability"":""view"",""type"":""function""},{""inputs"":[{""internalType"":""RequestId"",""name"":""requestId"",""type"":""bytes32""}],""name"":""requestExpiry"",""outputs"":[{""internalType"":""uint256"",""name"":"""",""type"":""uint256""}],""stateMutability"":""view"",""type"":""function""},{""inputs"":[{""internalType"":""RequestId"",""name"":""requestId"",""type"":""bytes32""}],""name"":""requestState"",""outputs"":[{""internalType"":""enum RequestState"",""name"":"""",""type"":""uint8""}],""stateMutability"":""view"",""type"":""function""},{""inputs"":[{""components"":[{""internalType"":""address"",""name"":""client"",""type"":""address""},{""components"":[{""internalType"":""uint64"",""name"":""slots"",""type"":""uint64""},{""internalType"":""uint256"",""name"":""slotSize"",""type"":""uint256""},{""internalType"":""uint256"",""name"":""duration"",""type"":""uint256""},{""internalType"":""uint256"",""name"":""proofProbability"",""type"":""uint256""},{""internalType"":""uint256"",""name"":""reward"",""type"":""uint256""},{""internalType"":""uint256"",""name"":""collateral"",""type"":""uint256""},{""internalType"":""uint64"",""name"":""maxSlotLoss"",""type"":""uint64""}],""internalType"":""struct Ask"",""name"":""ask"",""type"":""tuple""},{""components"":[{""internalType"":""string"",""name"":""cid"",""type"":""string""},{""internalType"":""bytes32"",""name"":""merkleRoot"",""type"":""bytes32""}],""internalType"":""struct Content"",""name"":""content"",""type"":""tuple""},{""internalType"":""uint256"",""name"":""expiry"",""type"":""uint256""},{""internalType"":""bytes32"",""name"":""nonce"",""type"":""bytes32""}],""internalType"":""struct Request"",""name"":""request"",""type"":""tuple""}],""name"":""requestStorage"",""outputs"":[],""stateMutability"":""nonpayable"",""type"":""function""},{""inputs"":[{""internalType"":""SlotId"",""name"":""slotId"",""type"":""bytes32""}],""name"":""slotState"",""outputs"":[{""internalType"":""enum SlotState"",""name"":"""",""type"":""uint8""}],""stateMutability"":""view"",""type"":""function""},{""inputs"":[{""internalType"":""SlotId"",""name"":""id"",""type"":""bytes32""},{""components"":[{""components"":[{""internalType"":""uint256"",""name"":""x"",""type"":""uint256""},{""internalType"":""uint256"",""name"":""y"",""type"":""uint256""}],""internalType"":""struct G1Point"",""name"":""a"",""type"":""tuple""},{""components"":[{""components"":[{""internalType"":""uint256"",""name"":""real"",""type"":""uint256""},{""internalType"":""uint256"",""name"":""imag"",""type"":""uint256""}],""internalType"":""struct Fp2Element"",""name"":""x"",""type"":""tuple""},{""components"":[{""internalType"":""uint256"",""name"":""real"",""type"":""uint256""},{""internalType"":""uint256"",""name"":""imag"",""type"":""uint256""}],""internalType"":""struct Fp2Element"",""name"":""y"",""type"":""tuple""}],""internalType"":""struct G2Point"",""name"":""b"",""type"":""tuple""},{""components"":[{""internalType"":""uint256"",""name"":""x"",""type"":""uint256""},{""internalType"":""uint256"",""name"":""y"",""type"":""uint256""}],""internalType"":""struct G1Point"",""name"":""c"",""type"":""tuple""}],""internalType"":""struct Groth16Proof"",""name"":""proof"",""type"":""tuple""}],""name"":""submitProof"",""outputs"":[],""stateMutability"":""nonpayable"",""type"":""function""},{""inputs"":[],""name"":""token"",""outputs"":[{""internalType"":""contract IERC20"",""name"":"""",""type"":""address""}],""stateMutability"":""view"",""type"":""function""},{""inputs"":[{""internalType"":""SlotId"",""name"":""id"",""type"":""bytes32""}],""name"":""willProofBeRequired"",""outputs"":[{""internalType"":""bool"",""name"":"""",""type"":""bool""}],""stateMutability"":""view"",""type"":""function""},{""inputs"":[{""internalType"":""RequestId"",""name"":""requestId"",""type"":""bytes32""}],""name"":""withdrawFunds"",""outputs"":[],""stateMutability"":""nonpayable"",""type"":""function""}]"; + } +} diff --git a/TraceContract/Output.cs b/TraceContract/Output.cs new file mode 100644 index 00000000..124b2796 --- /dev/null +++ b/TraceContract/Output.cs @@ -0,0 +1,18 @@ +using CodexContractsPlugin; +using CodexContractsPlugin.Marketplace; + +namespace TraceContract +{ + public class Output + { + public void LogRequest(Request request) + { + throw new NotImplementedException(); + } + + public void LogEventOrCall(T[] calls) where T : IHasRequestId, IHasBlock + { + throw new NotImplementedException(); + } + } +} diff --git a/TraceContract/Program.cs b/TraceContract/Program.cs new file mode 100644 index 00000000..41c4cfd7 --- /dev/null +++ b/TraceContract/Program.cs @@ -0,0 +1,169 @@ +using BlockchainUtils; +using CodexContractsPlugin; +using CodexContractsPlugin.Marketplace; +using Core; +using GethPlugin; +using Logging; +using Nethereum.Hex.HexConvertors.Extensions; +using Utils; + +namespace TraceContract +{ + public class Input + { + public string PurchaseId { get; } = "a7fe97dc32216aba0cbe74b87beb3f919aa116090dd5e0d48085a1a6b0080e82"; + } + + public class Program + { + public static void Main(string[] args) + { + var p = new Program(); + p.Run(); + } + + private readonly ILog log = new ConsoleLog(); + private readonly Input input = new(); + private readonly Output output = new(); + private readonly Config config = new(); + + private void Run() + { + try + { + TracePurchase(); + } + catch (Exception exc) + { + log.Error(exc.ToString()); + } + } + + private void TracePurchase() + { + Log("Setting up..."); + var contracts = ConnectCodexContracts(); + + var chainTracer = new ChainTracer(log, contracts, input, output); + chainTracer.TraceChainTimeline(); + + Log("Done"); + } + + private ICodexContracts ConnectCodexContracts() + { + ProjectPlugin.Load(); + ProjectPlugin.Load(); + + var entryPoint = new EntryPoint(log, new KubernetesWorkflow.Configuration(null, TimeSpan.FromMinutes(1.0), TimeSpan.FromSeconds(10.0), "_Unused!_"), Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)); + entryPoint.Announce(); + var ci = entryPoint.CreateInterface(); + + var account = EthAccountGenerator.GenerateNew(); + var blockCache = new BlockCache(); + var geth = new CustomGethNode(log, blockCache, config.RpcEndpoint, config.GethPort, account.PrivateKey); + + var deployment = new CodexContractsDeployment( + config: new CodexContractsPlugin.Marketplace.MarketplaceConfig(), + marketplaceAddress: config.MarketplaceAddress, + abi: config.Abi, + tokenAddress: config.TokenAddress + ); + return ci.WrapCodexContractsDeployment(geth, deployment); + } + + private void Log(string msg) + { + log.Log(msg); + } + } + + 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 void TraceChainTimeline() + { + var request = GetRequest(); + if (request == null) throw new Exception("Failed to find the purchase in the last week of transactions."); + output.LogRequest(request); + + var requestTimeRange = new TimeRange(request.Block.Utc.AddMinutes(-1.0), DateTime.UtcNow); + var events = contracts.GetEvents(requestTimeRange); + + // Log calls to reserve slot for request + var calls = Filter(events.GetReserveSlotCalls()); + output.LogEventOrCall(calls); + + // log all events. + var fulls = events.GetSlotReservationsFullEvents(); + output.LogEventOrCall(Filter(fulls)); + + } + + private T[] Filter(T[] calls) where T : IHasRequestId + { + return calls.Where(c => IsThisRequest(c.RequestId)).ToArray(); + } + + 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 TimeRange LastHour() + { + return new TimeRange(DateTime.UtcNow.AddHours(-1.0), DateTime.UtcNow); + } + + private TimeRange LastDay() + { + return new TimeRange(DateTime.UtcNow.AddDays(-1.0), DateTime.UtcNow); + } + + private TimeRange LastWeek() + { + return new TimeRange(DateTime.UtcNow.AddDays(-7.0), DateTime.UtcNow); + } + + private void Log(string msg) + { + log.Log(msg); + } + } +} diff --git a/TraceContract/TraceContract.csproj b/TraceContract/TraceContract.csproj new file mode 100644 index 00000000..3bcdeedb --- /dev/null +++ b/TraceContract/TraceContract.csproj @@ -0,0 +1,16 @@ + + + + Exe + net8.0 + enable + enable + + + + + + + + + diff --git a/cs-codex-dist-testing.sln b/cs-codex-dist-testing.sln index 9b1c0977..18dd9a2e 100644 --- a/cs-codex-dist-testing.sln +++ b/cs-codex-dist-testing.sln @@ -86,6 +86,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodexClient", "ProjectPlugi EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebUtils", "Framework\WebUtils\WebUtils.csproj", "{372C9E5D-5453-4D45-9948-E9324E21AD65}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TraceContract", "TraceContract\TraceContract.csproj", "{6F4C72D7-4B6E-45FD-93C6-2099CBE5B2AC}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -232,6 +234,10 @@ Global {372C9E5D-5453-4D45-9948-E9324E21AD65}.Debug|Any CPU.Build.0 = Debug|Any CPU {372C9E5D-5453-4D45-9948-E9324E21AD65}.Release|Any CPU.ActiveCfg = Release|Any CPU {372C9E5D-5453-4D45-9948-E9324E21AD65}.Release|Any CPU.Build.0 = Release|Any CPU + {6F4C72D7-4B6E-45FD-93C6-2099CBE5B2AC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6F4C72D7-4B6E-45FD-93C6-2099CBE5B2AC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6F4C72D7-4B6E-45FD-93C6-2099CBE5B2AC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6F4C72D7-4B6E-45FD-93C6-2099CBE5B2AC}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -272,6 +278,7 @@ Global {4648B5AA-A0A7-44BA-89BC-2FD57370943C} = {81AE04BC-CBFA-4E6F-B039-8208E9AFAAE7} {9AF12703-29AF-416D-9781-204223D6D0E5} = {8F1F1C2A-E313-4E0C-BE40-58FB0BA91124} {372C9E5D-5453-4D45-9948-E9324E21AD65} = {81AE04BC-CBFA-4E6F-B039-8208E9AFAAE7} + {6F4C72D7-4B6E-45FD-93C6-2099CBE5B2AC} = {7591C5B3-D86E-4AE4-8ED2-B272D17FE7E3} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {237BF0AA-9EC4-4659-AD9A-65DEB974250C}