Sets up tests for blocktimefinder.
This commit is contained in:
parent
db37143db6
commit
4fdb310ca4
|
@ -1,22 +1,19 @@
|
||||||
namespace NethereumWorkflow
|
namespace NethereumWorkflow
|
||||||
{
|
{
|
||||||
public partial class BlockTimeFinder
|
public class BlockTimeEntry
|
||||||
{
|
{
|
||||||
public class BlockTimeEntry
|
public BlockTimeEntry(ulong blockNumber, DateTime utc)
|
||||||
{
|
{
|
||||||
public BlockTimeEntry(ulong blockNumber, DateTime utc)
|
BlockNumber = blockNumber;
|
||||||
{
|
Utc = utc;
|
||||||
BlockNumber = blockNumber;
|
}
|
||||||
Utc = utc;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ulong BlockNumber { get; }
|
public ulong BlockNumber { get; }
|
||||||
public DateTime Utc { get; }
|
public DateTime Utc { get; }
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
return $"[{BlockNumber}] @ {Utc.ToString("o")}";
|
return $"[{BlockNumber}] @ {Utc.ToString("o")}";
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,36 +1,33 @@
|
||||||
using Logging;
|
using Logging;
|
||||||
using Nethereum.RPC.Eth.DTOs;
|
|
||||||
using Nethereum.Web3;
|
|
||||||
using Utils;
|
|
||||||
|
|
||||||
namespace NethereumWorkflow
|
namespace NethereumWorkflow
|
||||||
{
|
{
|
||||||
public partial class BlockTimeFinder
|
public class BlockTimeFinder
|
||||||
{
|
{
|
||||||
private const ulong FetchRange = 6;
|
private const ulong FetchRange = 6;
|
||||||
private const int MaxEntries = 1024;
|
private const int MaxEntries = 1024;
|
||||||
private static readonly Dictionary<ulong, BlockTimeEntry> entries = new Dictionary<ulong, BlockTimeEntry>();
|
private static readonly Dictionary<ulong, BlockTimeEntry> entries = new Dictionary<ulong, BlockTimeEntry>();
|
||||||
private readonly Web3 web3;
|
private readonly IWeb3Blocks web3;
|
||||||
private readonly ILog log;
|
private readonly ILog log;
|
||||||
|
|
||||||
public BlockTimeFinder(Web3 web3, ILog log)
|
public BlockTimeFinder(IWeb3Blocks web3, ILog log)
|
||||||
{
|
{
|
||||||
this.web3 = web3;
|
this.web3 = web3;
|
||||||
this.log = log;
|
this.log = log;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ulong GetHighestBlockNumberBefore(DateTime moment)
|
public ulong? GetHighestBlockNumberBefore(DateTime moment)
|
||||||
{
|
{
|
||||||
log.Log("Looking for highest block before " + moment.ToString("o"));
|
log.Debug("Looking for highest block before " + moment.ToString("o"));
|
||||||
AssertMomentIsInPast(moment);
|
AssertMomentIsInPast(moment);
|
||||||
Initialize();
|
Initialize();
|
||||||
|
|
||||||
return GetHighestBlockBefore(moment);
|
return GetHighestBlockBefore(moment);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ulong GetLowestBlockNumberAfter(DateTime moment)
|
public ulong? GetLowestBlockNumberAfter(DateTime moment)
|
||||||
{
|
{
|
||||||
log.Log("Looking for lowest block after " + moment.ToString("o"));
|
log.Debug("Looking for lowest block after " + moment.ToString("o"));
|
||||||
AssertMomentIsInPast(moment);
|
AssertMomentIsInPast(moment);
|
||||||
Initialize();
|
Initialize();
|
||||||
|
|
||||||
|
@ -48,7 +45,7 @@ namespace NethereumWorkflow
|
||||||
closestAfter.Utc > moment &&
|
closestAfter.Utc > moment &&
|
||||||
closestBefore.BlockNumber + 1 == closestAfter.BlockNumber)
|
closestBefore.BlockNumber + 1 == closestAfter.BlockNumber)
|
||||||
{
|
{
|
||||||
log.Log("Found highest-Before: " + closestBefore);
|
log.Debug("Found highest-Before: " + closestBefore);
|
||||||
return closestBefore.BlockNumber;
|
return closestBefore.BlockNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,7 +64,7 @@ namespace NethereumWorkflow
|
||||||
closestAfter.Utc > moment &&
|
closestAfter.Utc > moment &&
|
||||||
closestBefore.BlockNumber + 1 == closestAfter.BlockNumber)
|
closestBefore.BlockNumber + 1 == closestAfter.BlockNumber)
|
||||||
{
|
{
|
||||||
log.Log("Found lowest-after: " + closestAfter);
|
log.Debug("Found lowest-after: " + closestAfter);
|
||||||
return closestAfter.BlockNumber;
|
return closestAfter.BlockNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -223,24 +220,13 @@ namespace NethereumWorkflow
|
||||||
|
|
||||||
private BlockTimeEntry? AddCurrentBlock()
|
private BlockTimeEntry? AddCurrentBlock()
|
||||||
{
|
{
|
||||||
var number = Time.Wait(web3.Eth.Blocks.GetBlockNumber.SendRequestAsync());
|
var blockNumber = web3.GetCurrentBlockNumber();
|
||||||
var blockNumber = number.ToDecimal();
|
|
||||||
return AddBlockNumber(blockNumber);
|
return AddBlockNumber(blockNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
private DateTime? GetTimestampFromBlock(ulong blockNumber)
|
private DateTime? GetTimestampFromBlock(ulong blockNumber)
|
||||||
{
|
{
|
||||||
try
|
return web3.GetTimestampForBlock(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;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
int i = 0;
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private BlockTimeEntry? FindClosestBeforeEntry(DateTime moment)
|
private BlockTimeEntry? FindClosestBeforeEntry(DateTime moment)
|
||||||
|
|
|
@ -3,7 +3,6 @@ using Nethereum.ABI.FunctionEncoding.Attributes;
|
||||||
using Nethereum.Contracts;
|
using Nethereum.Contracts;
|
||||||
using Nethereum.RPC.Eth.DTOs;
|
using Nethereum.RPC.Eth.DTOs;
|
||||||
using Nethereum.Web3;
|
using Nethereum.Web3;
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using Utils;
|
using Utils;
|
||||||
|
|
||||||
namespace NethereumWorkflow
|
namespace NethereumWorkflow
|
||||||
|
@ -88,7 +87,8 @@ namespace NethereumWorkflow
|
||||||
|
|
||||||
public List<EventLog<TEvent>> GetEvents<TEvent>(string address, TimeRange timeRange) where TEvent : IEventDTO, new()
|
public List<EventLog<TEvent>> GetEvents<TEvent>(string address, TimeRange timeRange) where TEvent : IEventDTO, new()
|
||||||
{
|
{
|
||||||
var blockTimeFinder = new BlockTimeFinder(web3, log);
|
var wrapper = new Web3Wrapper(web3, log);
|
||||||
|
var blockTimeFinder = new BlockTimeFinder(wrapper, log);
|
||||||
|
|
||||||
var fromBlock = blockTimeFinder.GetLowestBlockNumberAfter(timeRange.From);
|
var fromBlock = blockTimeFinder.GetLowestBlockNumberAfter(timeRange.From);
|
||||||
var toBlock = blockTimeFinder.GetHighestBlockNumberBefore(timeRange.To);
|
var toBlock = blockTimeFinder.GetHighestBlockNumberBefore(timeRange.To);
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
using Logging;
|
||||||
|
using Nethereum.RPC.Eth.DTOs;
|
||||||
|
using Nethereum.Web3;
|
||||||
|
using Utils;
|
||||||
|
|
||||||
|
namespace NethereumWorkflow
|
||||||
|
{
|
||||||
|
public interface IWeb3Blocks
|
||||||
|
{
|
||||||
|
decimal GetCurrentBlockNumber();
|
||||||
|
DateTime? GetTimestampForBlock(decimal blockNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Web3Wrapper : IWeb3Blocks
|
||||||
|
{
|
||||||
|
private readonly Web3 web3;
|
||||||
|
private readonly ILog log;
|
||||||
|
|
||||||
|
public Web3Wrapper(Web3 web3, ILog log)
|
||||||
|
{
|
||||||
|
this.web3 = web3;
|
||||||
|
this.log = log;
|
||||||
|
}
|
||||||
|
|
||||||
|
public decimal GetCurrentBlockNumber()
|
||||||
|
{
|
||||||
|
var number = Time.Wait(web3.Eth.Blocks.GetBlockNumber.SendRequestAsync());
|
||||||
|
return number.ToDecimal();
|
||||||
|
}
|
||||||
|
|
||||||
|
public DateTime? GetTimestampForBlock(decimal blockNumber)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var block = Time.Wait(web3.Eth.Blocks.GetBlockWithTransactionsByNumber.SendRequestAsync(new BlockParameter(Convert.ToUInt64(blockNumber))));
|
||||||
|
if (block == null) return null;
|
||||||
|
return DateTimeOffset.FromUnixTimeSeconds(Convert.ToInt64(block.Timestamp.ToDecimal())).UtcDateTime;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
log.Error("Exception while getting timestamp for block: " + ex);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,12 +7,14 @@
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Moq" Version="4.20.70" />
|
||||||
<PackageReference Include="nunit" Version="3.13.3" />
|
<PackageReference Include="nunit" Version="3.13.3" />
|
||||||
<PackageReference Include="NUnit3TestAdapter" Version="4.4.2" />
|
<PackageReference Include="NUnit3TestAdapter" Version="4.4.2" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\Framework\NethereumWorkflow\NethereumWorkflow.csproj" />
|
||||||
<ProjectReference Include="..\..\Framework\Utils\Utils.csproj" />
|
<ProjectReference Include="..\..\Framework\Utils\Utils.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,137 @@
|
||||||
|
using Logging;
|
||||||
|
using Moq;
|
||||||
|
using NethereumWorkflow;
|
||||||
|
using NUnit.Framework;
|
||||||
|
|
||||||
|
namespace FrameworkTests.NethereumWorkflow
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class BlockTimeFinderTests
|
||||||
|
{
|
||||||
|
private Mock<IWeb3Blocks> web3 = new Mock<IWeb3Blocks>();
|
||||||
|
private Mock<ILog> log = new Mock<ILog>();
|
||||||
|
private Dictionary<decimal, Block> blocks = new Dictionary<decimal, Block>();
|
||||||
|
private DateTime start = DateTime.Now;
|
||||||
|
|
||||||
|
private BlockTimeFinder finder = null!;
|
||||||
|
|
||||||
|
private void SetupContinuousBlockchain()
|
||||||
|
{
|
||||||
|
start = DateTime.UtcNow.AddDays(-1).AddSeconds(-30);
|
||||||
|
blocks = new Dictionary<decimal, Block>();
|
||||||
|
|
||||||
|
for (var i = 0; i < 30; i++)
|
||||||
|
{
|
||||||
|
decimal d = 100 + i;
|
||||||
|
blocks.Add(d, new Block(d, start + TimeSpan.FromSeconds(i * 2)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[SetUp]
|
||||||
|
public void SetUp()
|
||||||
|
{
|
||||||
|
SetupContinuousBlockchain();
|
||||||
|
|
||||||
|
web3 = new Mock<IWeb3Blocks>();
|
||||||
|
web3.Setup(w => w.GetCurrentBlockNumber()).Returns(blocks.Keys.Max());
|
||||||
|
web3.Setup(w => w.GetTimestampForBlock(It.IsAny<decimal>())).Returns<decimal>(d =>
|
||||||
|
{
|
||||||
|
if (blocks.ContainsKey(d)) return blocks[d].Time;
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
|
||||||
|
finder = new BlockTimeFinder(web3.Object, log.Object);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void FindsMiddleOfChain()
|
||||||
|
{
|
||||||
|
var b1 = blocks[115];
|
||||||
|
var b2 = blocks[116];
|
||||||
|
|
||||||
|
var momentBetween = b1.JustAfter;
|
||||||
|
|
||||||
|
var b1Number = finder.GetHighestBlockNumberBefore(momentBetween);
|
||||||
|
var b2Number = finder.GetLowestBlockNumberAfter(momentBetween);
|
||||||
|
|
||||||
|
Assert.That(b1Number, Is.EqualTo(b1.Number));
|
||||||
|
Assert.That(b2Number, Is.EqualTo(b2.Number));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void FindsFrontOfChain_Lowest()
|
||||||
|
{
|
||||||
|
var first = blocks.First().Value;
|
||||||
|
|
||||||
|
var firstNumber = finder.GetLowestBlockNumberAfter(first.JustBefore);
|
||||||
|
|
||||||
|
Assert.That(firstNumber, Is.EqualTo(first.Number));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void FindsFrontOfChain_Highest()
|
||||||
|
{
|
||||||
|
var first = blocks.First().Value;
|
||||||
|
|
||||||
|
var firstNumber = finder.GetHighestBlockNumberBefore(first.JustAfter);
|
||||||
|
|
||||||
|
Assert.That(firstNumber, Is.EqualTo(first.Number));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void FindsTailOfChain_Lowest()
|
||||||
|
{
|
||||||
|
var last = blocks.Last().Value;
|
||||||
|
|
||||||
|
var lastNumber = finder.GetLowestBlockNumberAfter(last.JustBefore);
|
||||||
|
|
||||||
|
Assert.That(lastNumber, Is.EqualTo(last.Number));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void FindsTailOfChain_Highest()
|
||||||
|
{
|
||||||
|
var last = blocks.Last().Value;
|
||||||
|
|
||||||
|
var lastNumber = finder.GetHighestBlockNumberBefore(last.JustAfter);
|
||||||
|
|
||||||
|
Assert.That(lastNumber, Is.EqualTo(last.Number));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void FailsToFindBlockBeforeFrontOfChain()
|
||||||
|
{
|
||||||
|
var first = blocks.First().Value;
|
||||||
|
|
||||||
|
var notFound = finder.GetHighestBlockNumberBefore(first.Time);
|
||||||
|
|
||||||
|
Assert.That(notFound, Is.Null);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void FailsToFindBlockAfterTailOfChain()
|
||||||
|
{
|
||||||
|
var last = blocks.Last().Value;
|
||||||
|
|
||||||
|
var notFound = finder.GetLowestBlockNumberAfter(last.Time);
|
||||||
|
|
||||||
|
Assert.That(notFound, Is.Null);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Block
|
||||||
|
{
|
||||||
|
public Block(decimal number, DateTime time)
|
||||||
|
{
|
||||||
|
Number = number;
|
||||||
|
Time = time;
|
||||||
|
}
|
||||||
|
|
||||||
|
public decimal Number { get; }
|
||||||
|
public DateTime Time { get; }
|
||||||
|
public DateTime JustBefore { get { return Time.AddSeconds(-1); } }
|
||||||
|
public DateTime JustAfter { get { return Time.AddSeconds(1); } }
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue