diff --git a/Framework/NethereumWorkflow/BlockTimeFinder.cs b/Framework/NethereumWorkflow/BlockTimeFinder.cs index acc8b1c..0d429f5 100644 --- a/Framework/NethereumWorkflow/BlockTimeFinder.cs +++ b/Framework/NethereumWorkflow/BlockTimeFinder.cs @@ -1,4 +1,5 @@ -using Nethereum.RPC.Eth.DTOs; +using Logging; +using Nethereum.RPC.Eth.DTOs; using Nethereum.Web3; using Utils; @@ -16,30 +17,48 @@ namespace NethereumWorkflow public ulong BlockNumber { get; } public DateTime Utc { get; } + + public override string ToString() + { + return $"[{BlockNumber}] @ {Utc.ToString("o")}"; + } } private const ulong FetchRange = 6; private const int MaxEntries = 1024; private readonly Web3 web3; + private readonly ILog log; private static readonly Dictionary entries = new Dictionary(); - public BlockTimeFinder(Web3 web3) + public BlockTimeFinder(Web3 web3, ILog log) { this.web3 = web3; + this.log = log; } public ulong GetHighestBlockNumberBefore(DateTime moment) { + log.Log("Looking for highest block before " + moment.ToString("o")); AssertMomentIsInPast(moment); Initialize(); var closestBefore = FindClosestBeforeEntry(moment); var closestAfter = FindClosestAfterEntry(moment); - + + if (closestBefore == null || closestAfter == null) + { + FetchBlocksAround(moment); + return GetHighestBlockNumberBefore(moment); + } + + log.Log("Closest before: " + closestBefore); + log.Log("Closest after: " + closestAfter); + if (closestBefore.Utc < moment && closestAfter.Utc > moment && closestBefore.BlockNumber + 1 == closestAfter.BlockNumber) { + log.Log("Found highest-Before: " + closestBefore); return closestBefore.BlockNumber; } @@ -49,16 +68,27 @@ namespace NethereumWorkflow public ulong GetLowestBlockNumberAfter(DateTime moment) { + log.Log("Looking for lowest block after " + moment.ToString("o")); AssertMomentIsInPast(moment); Initialize(); var closestBefore = FindClosestBeforeEntry(moment); var closestAfter = FindClosestAfterEntry(moment); + if (closestBefore == null || closestAfter == null) + { + FetchBlocksAround(moment); + return GetLowestBlockNumberAfter(moment); + } + + log.Log("Closest before: " + closestBefore); + log.Log("Closest after: " + closestAfter); + if (closestBefore.Utc < moment && closestAfter.Utc > moment && closestBefore.BlockNumber + 1 == closestAfter.BlockNumber) { + log.Log("Found lowest-after: " + closestAfter); return closestAfter.BlockNumber; } @@ -68,6 +98,8 @@ namespace NethereumWorkflow private void FetchBlocksAround(DateTime moment) { + log.Log("Fetching..."); + var timePerBlock = EstimateTimePerBlock(); EnsureRecentBlockIfNecessary(moment, timePerBlock); @@ -79,11 +111,36 @@ namespace NethereumWorkflow double numberOfBlocksDifference = secondsDifference / secondsPerBlock; var blockDifference = Convert.ToUInt64(numberOfBlocksDifference); + if (blockDifference < 1) blockDifference = 1; - var fetchStart = (max - blockDifference) - (FetchRange / 2); - for (ulong i = 0; i < FetchRange; i++) + var fetchUp = FetchRange; + var fetchDown = FetchRange; + var target = max - blockDifference; + log.Log("up - target: " + target); + while (fetchUp > 0) { - AddBlockNumber(fetchStart + i); + if (!entries.ContainsKey(target)) + { + var newBlock = AddBlockNumber(target); + if (newBlock != null) fetchUp--; + else fetchUp = 0; + } + target++; + //if (target >= max) fetchUp = 0; + } + + target = max - blockDifference - 1; + log.Log("down - target: " + target); + while (fetchDown > 0) + { + if (!entries.ContainsKey(target)) + { + var newBlock = AddBlockNumber(target); + if (newBlock != null) fetchDown--; + else fetchDown = 0; + } + target--; + //if (target <= 0) fetchDown = 0; } } @@ -95,7 +152,7 @@ namespace NethereumWorkflow while (moment > latest.Utc) { var newBlock = AddCurrentBlock(); - if (newBlock.BlockNumber == latest.BlockNumber) + if (newBlock == null || newBlock.BlockNumber == latest.BlockNumber) { maxRetry--; if (maxRetry == 0) throw new Exception("Unable to fetch recent block after 10x tries."); @@ -104,12 +161,12 @@ namespace NethereumWorkflow } } - private BlockTimeEntry AddBlockNumber(decimal blockNumber) + private BlockTimeEntry? AddBlockNumber(decimal blockNumber) { return AddBlockNumber(Convert.ToUInt64(blockNumber)); } - private BlockTimeEntry AddBlockNumber(ulong blockNumber) + private BlockTimeEntry? AddBlockNumber(ulong blockNumber) { if (entries.ContainsKey(blockNumber)) { @@ -123,7 +180,9 @@ namespace NethereumWorkflow } var time = GetTimestampFromBlock(blockNumber); - var entry = new BlockTimeEntry(blockNumber, time); + if (time == null) return null; + var entry = new BlockTimeEntry(blockNumber, time.Value); + log.Log("Found block " + entry.BlockNumber + " at " + entry.Utc.ToString("o")); entries.Add(blockNumber, entry); return entry; } @@ -157,46 +216,49 @@ namespace NethereumWorkflow if (moment > DateTime.UtcNow) throw new Exception("Moment must be UTC and must be in the past."); } - private BlockTimeEntry AddCurrentBlock() + private BlockTimeEntry? AddCurrentBlock() { var number = Time.Wait(web3.Eth.Blocks.GetBlockNumber.SendRequestAsync()); var blockNumber = number.ToDecimal(); return AddBlockNumber(blockNumber); } - private DateTime GetTimestampFromBlock(ulong blockNumber) + private DateTime? GetTimestampFromBlock(ulong blockNumber) { var block = Time.Wait(web3.Eth.Blocks.GetBlockWithTransactionsByNumber.SendRequestAsync(new BlockParameter(blockNumber))); + if (block == null) return null; return DateTimeOffset.FromUnixTimeSeconds(Convert.ToInt64(block.Timestamp.ToDecimal())).UtcDateTime; } - private BlockTimeEntry FindClosestBeforeEntry(DateTime moment) + private BlockTimeEntry? FindClosestBeforeEntry(DateTime moment) { - var result = entries.Values.First(); - var highestTime = result.Utc; - + BlockTimeEntry? result = null; foreach (var entry in entries.Values) { - if (entry.Utc > highestTime && entry.Utc < moment) + if (result == null) { - highestTime = entry.Utc; - result = entry; + if (entry.Utc < moment) result = entry; + } + else + { + if (entry.Utc > result.Utc && entry.Utc < moment) result = entry; } } return result; } - private BlockTimeEntry FindClosestAfterEntry(DateTime moment) + private BlockTimeEntry? FindClosestAfterEntry(DateTime moment) { - var result = entries.Values.First(); - var lowestTime = result.Utc; - + BlockTimeEntry? result = null; foreach (var entry in entries.Values) { - if (entry.Utc < lowestTime && entry.Utc > moment) + if (result == null) { - lowestTime = entry.Utc; - result = entry; + if (entry.Utc > moment) result = entry; + } + else + { + if (entry.Utc < result.Utc && entry.Utc > moment) result = entry; } } return result; diff --git a/Framework/NethereumWorkflow/NethereumInteraction.cs b/Framework/NethereumWorkflow/NethereumInteraction.cs index 48a62f2..172e9ce 100644 --- a/Framework/NethereumWorkflow/NethereumInteraction.cs +++ b/Framework/NethereumWorkflow/NethereumInteraction.cs @@ -79,14 +79,12 @@ namespace NethereumWorkflow } } - public List> GetEvents(string address, DateTime from, DateTime to) where TEvent : IEventDTO, new() + public List> GetEvents(string address, TimeRange timeRange) where TEvent : IEventDTO, new() { - if (from >= to) throw new Exception("Time range is invalid."); + var blockTimeFinder = new BlockTimeFinder(web3, log); - var blockTimeFinder = new BlockTimeFinder(web3); - - var fromBlock = blockTimeFinder.GetLowestBlockNumberAfter(from); - var toBlock = blockTimeFinder.GetHighestBlockNumberBefore(to); + var fromBlock = blockTimeFinder.GetLowestBlockNumberAfter(timeRange.From); + var toBlock = blockTimeFinder.GetHighestBlockNumberBefore(timeRange.To); return GetEvents(address, fromBlock, toBlock); } diff --git a/Framework/Utils/TimeRange.cs b/Framework/Utils/TimeRange.cs new file mode 100644 index 0000000..35578d1 --- /dev/null +++ b/Framework/Utils/TimeRange.cs @@ -0,0 +1,24 @@ +namespace Utils +{ + public class TimeRange + { + public TimeRange(DateTime from, DateTime to) + { + if (from < to) + { + From = from; + To = to; + } + else + { + From = to; + To = from; + } + Duration = To - From; + } + + public DateTime From { get; } + public DateTime To { get; } + public TimeSpan Duration { get; } + } +} diff --git a/ProjectPlugins/CodexContractsPlugin/CodexContractsAccess.cs b/ProjectPlugins/CodexContractsPlugin/CodexContractsAccess.cs index be22f3e..b111492 100644 --- a/ProjectPlugins/CodexContractsPlugin/CodexContractsAccess.cs +++ b/ProjectPlugins/CodexContractsPlugin/CodexContractsAccess.cs @@ -1,5 +1,6 @@ using GethPlugin; using Logging; +using Utils; namespace CodexContractsPlugin { @@ -12,6 +13,8 @@ namespace CodexContractsPlugin string MintTestTokens(EthAddress ethAddress, TestToken testTokens); TestToken GetTestTokenBalance(IHasEthAddress owner); TestToken GetTestTokenBalance(EthAddress ethAddress); + + void GetStorageRequests(TimeRange range); } public class CodexContractsAccess : ICodexContracts @@ -30,8 +33,7 @@ namespace CodexContractsPlugin public bool IsDeployed() { - var interaction = new ContractInteractions(log, gethNode); - return !string.IsNullOrEmpty(interaction.GetTokenName(Deployment.TokenAddress)); + return !string.IsNullOrEmpty(StartInteraction().GetTokenName(Deployment.TokenAddress)); } public string MintTestTokens(IHasEthAddress owner, TestToken testTokens) @@ -41,8 +43,7 @@ namespace CodexContractsPlugin public string MintTestTokens(EthAddress ethAddress, TestToken testTokens) { - var interaction = new ContractInteractions(log, gethNode); - return interaction.MintTestTokens(ethAddress, testTokens.Amount, Deployment.TokenAddress); + return StartInteraction().MintTestTokens(ethAddress, testTokens.Amount, Deployment.TokenAddress); } public TestToken GetTestTokenBalance(IHasEthAddress owner) @@ -52,9 +53,19 @@ namespace CodexContractsPlugin public TestToken GetTestTokenBalance(EthAddress ethAddress) { - var interaction = new ContractInteractions(log, gethNode); - var balance = interaction.GetBalance(Deployment.TokenAddress, ethAddress.Address); + var balance = StartInteraction().GetBalance(Deployment.TokenAddress, ethAddress.Address); return balance.TestTokens(); } + + public void GetStorageRequests(TimeRange timeRange) + { + var events = gethNode.GetEvents(Deployment.MarketplaceAddress, timeRange); + var iii = 0; + } + + private ContractInteractions StartInteraction() + { + return new ContractInteractions(log, gethNode); + } } } diff --git a/ProjectPlugins/GethPlugin/GethNode.cs b/ProjectPlugins/GethPlugin/GethNode.cs index 126792e..9ec5e76 100644 --- a/ProjectPlugins/GethPlugin/GethNode.cs +++ b/ProjectPlugins/GethPlugin/GethNode.cs @@ -4,6 +4,7 @@ using Logging; using Nethereum.ABI.FunctionEncoding.Attributes; using Nethereum.Contracts; using NethereumWorkflow; +using Utils; namespace GethPlugin { @@ -22,7 +23,7 @@ namespace GethPlugin bool IsContractAvailable(string abi, string contractAddress); GethBootstrapNode GetBootstrapRecord(); List> GetEvents(string address, ulong fromBlockNumber, ulong toBlockNumber) where TEvent : IEventDTO, new(); - List> GetEvents(string address, DateTime from, DateTime to) where TEvent : IEventDTO, new(); + List> GetEvents(string address, TimeRange timeRange) where TEvent : IEventDTO, new(); } public class DeploymentGethNode : BaseGethNode, IGethNode @@ -141,9 +142,9 @@ namespace GethPlugin return StartInteraction().GetEvents(address, fromBlockNumber, toBlockNumber); } - public List> GetEvents(string address, DateTime from, DateTime to) where TEvent : IEventDTO, new() + public List> GetEvents(string address, TimeRange timeRange) where TEvent : IEventDTO, new() { - return StartInteraction().GetEvents(address, from, to); + return StartInteraction().GetEvents(address, timeRange); } protected abstract NethereumInteraction StartInteraction(); diff --git a/Tests/CodexTests/BasicTests/ExampleTests.cs b/Tests/CodexTests/BasicTests/ExampleTests.cs index 3976d46..59993dd 100644 --- a/Tests/CodexTests/BasicTests/ExampleTests.cs +++ b/Tests/CodexTests/BasicTests/ExampleTests.cs @@ -95,7 +95,9 @@ namespace CodexTests.BasicTests AssertBalance(contracts, seller, Is.GreaterThan(sellerInitialBalance), "Seller was not paid for storage."); AssertBalance(contracts, buyer, Is.LessThan(buyerInitialBalance), "Buyer was not charged for storage."); - CheckLogForErrors(seller, buyer); + //CheckLogForErrors(seller, buyer); + + contracts.GetStorageRequests(new TimeRange(Get().TestStart, DateTime.UtcNow)); } [Test] diff --git a/Tests/DistTestCore/TestLifecycle.cs b/Tests/DistTestCore/TestLifecycle.cs index 45cfff4..3ed08bb 100644 --- a/Tests/DistTestCore/TestLifecycle.cs +++ b/Tests/DistTestCore/TestLifecycle.cs @@ -11,7 +11,6 @@ namespace DistTestCore public class TestLifecycle : IK8sHooks { private const string TestsType = "dist-tests"; - private readonly DateTime testStart; private readonly EntryPoint entryPoint; private readonly Dictionary metadata; private readonly List runningContainers = new List(); @@ -21,7 +20,7 @@ namespace DistTestCore Log = log; Configuration = configuration; TimeSet = timeSet; - testStart = DateTime.UtcNow; + TestStart = DateTime.UtcNow; entryPoint = new EntryPoint(log, configuration.GetK8sConfiguration(timeSet, this, testNamespace), configuration.GetFileManagerFolder(), timeSet); metadata = entryPoint.GetPluginMetadata(); @@ -30,6 +29,7 @@ namespace DistTestCore log.WriteLogTag(); } + public DateTime TestStart { get; } public TestLog Log { get; } public Configuration Configuration { get; } public ITimeSet TimeSet { get; } @@ -60,7 +60,7 @@ namespace DistTestCore public TimeSpan GetTestDuration() { - return DateTime.UtcNow - testStart; + return DateTime.UtcNow - TestStart; } public void OnContainersStarted(RunningContainers rc)