cs-codex-dist-tests/Framework/NethereumWorkflow/BlockUtils/BlockchainBounds.cs

107 lines
3.0 KiB
C#

namespace NethereumWorkflow.BlockUtils
{
public class BlockchainBounds
{
private readonly BlockCache cache;
private readonly IWeb3Blocks web3;
public BlockTimeEntry Genesis { get; private set; } = null!;
public BlockTimeEntry Current { get; private set; } = null!;
public BlockchainBounds(BlockCache cache, IWeb3Blocks web3)
{
this.cache = cache;
this.web3 = web3;
cache.OnCacheCleared += Initialize;
}
public void Initialize()
{
AddCurrentBlock();
LookForGenesisBlock();
if (Current.BlockNumber == Genesis.BlockNumber)
{
throw new Exception("Unsupported condition: Current block is genesis block.");
}
}
private void LookForGenesisBlock()
{
if (Genesis != null)
{
cache.Add(Genesis);
return;
}
var blockTime = web3.GetTimestampForBlock(0);
if (blockTime != null)
{
AddGenesisBlock(0, blockTime.Value);
return;
}
LookForGenesisBlock(0, Current);
}
private void LookForGenesisBlock(ulong lower, BlockTimeEntry upper)
{
if (Genesis != null) return;
var range = upper.BlockNumber - lower;
if (range == 1)
{
var lowTime = web3.GetTimestampForBlock(lower);
if (lowTime != null)
{
AddGenesisBlock(lower, lowTime.Value);
}
else
{
AddGenesisBlock(upper);
}
return;
}
var current = lower + range / 2;
var blockTime = web3.GetTimestampForBlock(current);
if (blockTime != null)
{
var newUpper = cache.Add(current, blockTime.Value);
LookForGenesisBlock(lower, newUpper);
}
else
{
LookForGenesisBlock(current, upper);
}
}
private void AddCurrentBlock()
{
var currentBlockNumber = web3.GetCurrentBlockNumber();
var blockTime = web3.GetTimestampForBlock(currentBlockNumber);
if (blockTime == null) throw new Exception("Unable to get dateTime for current block.");
AddCurrentBlock(currentBlockNumber, blockTime.Value);
}
private void AddCurrentBlock(ulong currentBlockNumber, DateTime dateTime)
{
Current = new BlockTimeEntry(currentBlockNumber, dateTime);
cache.Add(Current);
}
private void AddGenesisBlock(ulong number, DateTime dateTime)
{
AddGenesisBlock(new BlockTimeEntry(number, dateTime));
}
private void AddGenesisBlock(BlockTimeEntry entry)
{
Genesis = entry;
cache.Add(Genesis);
}
}
}