Sets up tests for blocktimefinder.
This commit is contained in:
parent
db37143db6
commit
4fdb310ca4
|
@ -1,22 +1,19 @@
|
|||
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 DateTime Utc { get; }
|
||||
public ulong BlockNumber { get; }
|
||||
public DateTime Utc { get; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"[{BlockNumber}] @ {Utc.ToString("o")}";
|
||||
}
|
||||
public override string ToString()
|
||||
{
|
||||
return $"[{BlockNumber}] @ {Utc.ToString("o")}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,36 +1,33 @@
|
|||
using Logging;
|
||||
using Nethereum.RPC.Eth.DTOs;
|
||||
using Nethereum.Web3;
|
||||
using Utils;
|
||||
|
||||
namespace NethereumWorkflow
|
||||
{
|
||||
public partial class BlockTimeFinder
|
||||
public class BlockTimeFinder
|
||||
{
|
||||
private const ulong FetchRange = 6;
|
||||
private const int MaxEntries = 1024;
|
||||
private static readonly Dictionary<ulong, BlockTimeEntry> entries = new Dictionary<ulong, BlockTimeEntry>();
|
||||
private readonly Web3 web3;
|
||||
private readonly IWeb3Blocks web3;
|
||||
private readonly ILog log;
|
||||
|
||||
public BlockTimeFinder(Web3 web3, ILog log)
|
||||
public BlockTimeFinder(IWeb3Blocks web3, ILog log)
|
||||
{
|
||||
this.web3 = web3;
|
||||
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);
|
||||
Initialize();
|
||||
|
||||
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);
|
||||
Initialize();
|
||||
|
||||
|
@ -48,7 +45,7 @@ namespace NethereumWorkflow
|
|||
closestAfter.Utc > moment &&
|
||||
closestBefore.BlockNumber + 1 == closestAfter.BlockNumber)
|
||||
{
|
||||
log.Log("Found highest-Before: " + closestBefore);
|
||||
log.Debug("Found highest-Before: " + closestBefore);
|
||||
return closestBefore.BlockNumber;
|
||||
}
|
||||
|
||||
|
@ -67,7 +64,7 @@ namespace NethereumWorkflow
|
|||
closestAfter.Utc > moment &&
|
||||
closestBefore.BlockNumber + 1 == closestAfter.BlockNumber)
|
||||
{
|
||||
log.Log("Found lowest-after: " + closestAfter);
|
||||
log.Debug("Found lowest-after: " + closestAfter);
|
||||
return closestAfter.BlockNumber;
|
||||
}
|
||||
|
||||
|
@ -223,24 +220,13 @@ namespace NethereumWorkflow
|
|||
|
||||
private BlockTimeEntry? AddCurrentBlock()
|
||||
{
|
||||
var number = Time.Wait(web3.Eth.Blocks.GetBlockNumber.SendRequestAsync());
|
||||
var blockNumber = number.ToDecimal();
|
||||
var blockNumber = web3.GetCurrentBlockNumber();
|
||||
return AddBlockNumber(blockNumber);
|
||||
}
|
||||
|
||||
private DateTime? GetTimestampFromBlock(ulong blockNumber)
|
||||
{
|
||||
try
|
||||
{
|
||||
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;
|
||||
}
|
||||
return web3.GetTimestampForBlock(blockNumber);
|
||||
}
|
||||
|
||||
private BlockTimeEntry? FindClosestBeforeEntry(DateTime moment)
|
||||
|
|
|
@ -3,7 +3,6 @@ using Nethereum.ABI.FunctionEncoding.Attributes;
|
|||
using Nethereum.Contracts;
|
||||
using Nethereum.RPC.Eth.DTOs;
|
||||
using Nethereum.Web3;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Utils;
|
||||
|
||||
namespace NethereumWorkflow
|
||||
|
@ -88,7 +87,8 @@ namespace NethereumWorkflow
|
|||
|
||||
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 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>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Moq" Version="4.20.70" />
|
||||
<PackageReference Include="nunit" Version="3.13.3" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.4.2" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Framework\NethereumWorkflow\NethereumWorkflow.csproj" />
|
||||
<ProjectReference Include="..\..\Framework\Utils\Utils.csproj" />
|
||||
</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