Skip to content

Commit

Permalink
Merge/continous block improvement (#4488)
Browse files Browse the repository at this point in the history
* Make Payload Production continuous improving block while in slot.

* Remove whitespace

* Change timings for more reliable tests

* Comments + better naming

* Move to DateTimeOffset

* Add more logs

* Review improvements

* Move to TimeSpan's

* Fix merging master
  • Loading branch information
LukaszRozmej authored and rubo committed Oct 13, 2022
1 parent 8f26979 commit c21b094
Show file tree
Hide file tree
Showing 14 changed files with 642 additions and 307 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,41 +32,42 @@ private class DelayBlockImprovementContextFactory : IBlockImprovementContextFact
{
private readonly IManualBlockProductionTrigger _productionTrigger;
private readonly TimeSpan _timeout;
private readonly int _delay;
private readonly TimeSpan _delay;

public DelayBlockImprovementContextFactory(IManualBlockProductionTrigger productionTrigger, TimeSpan timeout, int delay)
public DelayBlockImprovementContextFactory(IManualBlockProductionTrigger productionTrigger, TimeSpan timeout, TimeSpan delay)
{
_productionTrigger = productionTrigger;
_timeout = timeout;
_delay = delay;
}

public IBlockImprovementContext StartBlockImprovementContext(Block currentBestBlock, BlockHeader parentHeader, PayloadAttributes payloadAttributes) =>
new DelayBlockImprovementContext(currentBestBlock, _productionTrigger, _timeout, parentHeader, payloadAttributes, _delay);
public IBlockImprovementContext StartBlockImprovementContext(Block currentBestBlock, BlockHeader parentHeader, PayloadAttributes payloadAttributes, DateTimeOffset startDateTime) =>
new DelayBlockImprovementContext(currentBestBlock, _productionTrigger, _timeout, parentHeader, payloadAttributes, _delay, startDateTime);
}

private class DelayBlockImprovementContext : IBlockImprovementContext
{
private CancellationTokenSource? _cancellationTokenSource;

public DelayBlockImprovementContext(
Block currentBestBlock,
public DelayBlockImprovementContext(Block currentBestBlock,
IManualBlockProductionTrigger blockProductionTrigger,
TimeSpan timeout,
BlockHeader parentHeader,
PayloadAttributes payloadAttributes,
int delay)
TimeSpan delay,
DateTimeOffset startDateTime)
{
_cancellationTokenSource = new CancellationTokenSource(timeout);
CurrentBestBlock = currentBestBlock;
StartDateTime = startDateTime;
ImprovementTask = BuildBlock(blockProductionTrigger, parentHeader, payloadAttributes, delay, _cancellationTokenSource.Token);
}

private async Task<Block?> BuildBlock(
IManualBlockProductionTrigger blockProductionTrigger,
BlockHeader parentHeader,
PayloadAttributes payloadAttributes,
int delay,
TimeSpan delay,
CancellationToken cancellationToken)
{
Block? block = await blockProductionTrigger.BuildBlock(parentHeader, cancellationToken, NullBlockTracer.Instance, payloadAttributes);
Expand All @@ -80,11 +81,13 @@ public DelayBlockImprovementContext(
}

public Task<Block?> ImprovementTask { get; }

public Block? CurrentBestBlock { get; private set; }
public bool Disposed { get; private set; }
public DateTimeOffset StartDateTime { get; }

public void Dispose()
{
Disposed = true;
CancellationTokenExtensions.CancelDisposeAndClear(ref _cancellationTokenSource);
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
// Copyright (c) 2021 Demerzel Solutions Limited
// This file is part of the Nethermind library.
//
//
// The Nethermind library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
//
// The Nethermind library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
//
// You should have received a copy of the GNU Lesser General Public License
// along with the Nethermind. If not, see <http://www.gnu.org/licenses/>.
//
//

using System;
using System.Collections.Generic;
Expand Down Expand Up @@ -59,12 +59,10 @@ private void AssertExecutionStatusChanged(IEngineRpcModule rpc, Keccak headBlock
private (UInt256, UInt256) AddTransactions(MergeTestBlockchain chain, ExecutionPayloadV1 executePayloadRequest,
PrivateKey from, Address to, uint count, int value, out BlockHeader parentHeader)
{
Transaction[] transactions = BuildTransactions(chain, executePayloadRequest.ParentHash, from, to, count, value,
out Account accountFrom, out parentHeader);
Transaction[] transactions = BuildTransactions(chain, executePayloadRequest.ParentHash, from, to, count, value, out Account accountFrom, out parentHeader);
executePayloadRequest.SetTransactions(transactions);
UInt256 totalValue = ((int)(count * value)).GWei();
return (accountFrom.Balance - totalValue,
chain.StateReader.GetBalance(parentHeader.StateRoot!, to) + totalValue);
return (accountFrom.Balance - totalValue, chain.StateReader.GetBalance(parentHeader.StateRoot!, to) + totalValue);
}

private Transaction[] BuildTransactions(MergeTestBlockchain chain, Keccak parentHash, PrivateKey from,
Expand All @@ -82,11 +80,10 @@ Transaction BuildTransaction(uint index, Account senderAccount) =>
.TestObject;

parentHeader = chain.BlockTree.FindHeader(parentHash, BlockTreeLookupOptions.None)!;
Account account = chain.StateReader.GetAccount(parentHeader.StateRoot!, @from.Address)!;
Account account = chain.StateReader.GetAccount(parentHeader.StateRoot!, from.Address)!;
accountFrom = account;

return Enumerable.Range(0, (int)count)
.Select(i => BuildTransaction((uint)i, account)).ToArray();
return Enumerable.Range(0, (int)count).Select(i => BuildTransaction((uint)i, account)).ToArray();
}

private ExecutionPayloadV1 CreateParentBlockRequestOnHead(IBlockTree blockTree)
Expand Down Expand Up @@ -141,8 +138,7 @@ private static ExecutionPayloadV1[] CreateBlockRequestBranch(ExecutionPayloadV1
private Block? RunForAllBlocksInBranch(IBlockTree blockTree, Keccak blockHash, Func<Block, bool> shouldStop,
bool requireCanonical)
{
BlockTreeLookupOptions options =
requireCanonical ? BlockTreeLookupOptions.RequireCanonical : BlockTreeLookupOptions.None;
BlockTreeLookupOptions options = requireCanonical ? BlockTreeLookupOptions.RequireCanonical : BlockTreeLookupOptions.None;
Block? current = blockTree.FindBlock(blockHash, options);
while (current is not null && !shouldStop(current))
{
Expand All @@ -160,8 +156,7 @@ private static TestCaseData GetNewBlockRequestBadDataTestCase<T>(
Action<ExecutionPayloadV1> wrongValueSetter = r => setter(r, wrongValue);
return new TestCaseData(wrongValueSetter)
{
TestName =
$"executePayload_rejects_incorrect_{propertyAccess.GetName().ToLower()}({wrongValue?.ToString()})"
TestName = $"executePayload_rejects_incorrect_{propertyAccess.GetName().ToLower()}({wrongValue?.ToString()})"
};
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// Copyright (c) 2021 Demerzel Solutions Limited
// This file is part of the Nethermind library.
//
// The Nethermind library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The Nethermind library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the Nethermind. If not, see <http://www.gnu.org/licenses/>.
//

using System;
using System.Threading;
using System.Threading.Tasks;
using Nethermind.Consensus.Producers;
using Nethermind.Core;
using Nethermind.Core.Extensions;
using Nethermind.Evm.Tracing;
using Nethermind.Merge.Plugin.BlockProduction;

namespace Nethermind.Merge.Plugin.Test;

public partial class EngineModuleTests
{
private class MockBlockImprovementContextFactory : IBlockImprovementContextFactory
{
public IBlockImprovementContext StartBlockImprovementContext(Block currentBestBlock, BlockHeader parentHeader, PayloadAttributes payloadAttributes, DateTimeOffset startDateTime) =>
new MockBlockImprovementContext(currentBestBlock, startDateTime);
}

private class MockBlockImprovementContext : IBlockImprovementContext
{
public MockBlockImprovementContext(Block currentBestBlock, DateTimeOffset startDateTime)
{
CurrentBestBlock = currentBestBlock;
StartDateTime = startDateTime;
ImprovementTask = Task.FromResult((Block?)currentBestBlock);
}

public void Dispose() => Disposed = true;
public Task<Block?> ImprovementTask { get; }
public Block? CurrentBestBlock { get; }
public bool Disposed { get; private set; }
public DateTimeOffset StartDateTime { get; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// Copyright (c) 2021 Demerzel Solutions Limited
// This file is part of the Nethermind library.
//
// The Nethermind library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The Nethermind library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the Nethermind. If not, see <http://www.gnu.org/licenses/>.
//

using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Nethermind.Consensus.Producers;
using Nethermind.Core;
using Nethermind.Core.Extensions;
using Nethermind.Evm.Tracing;
using Nethermind.Merge.Plugin.BlockProduction;

namespace Nethermind.Merge.Plugin.Test;

public partial class EngineModuleTests
{
private class StoringBlockImprovementContextFactory : IBlockImprovementContextFactory
{
private readonly IBlockImprovementContextFactory _blockImprovementContextFactory;
public IList<IBlockImprovementContext> CreatedContexts { get; } = new List<IBlockImprovementContext>();

public event EventHandler<ImprovementStartedEventArgs>? ImprovementStarted;

public StoringBlockImprovementContextFactory(IBlockImprovementContextFactory blockImprovementContextFactory)
{
_blockImprovementContextFactory = blockImprovementContextFactory;
}

public IBlockImprovementContext StartBlockImprovementContext(Block currentBestBlock, BlockHeader parentHeader, PayloadAttributes payloadAttributes, DateTimeOffset startDateTime)
{
IBlockImprovementContext blockImprovementContext = _blockImprovementContextFactory.StartBlockImprovementContext(currentBestBlock, parentHeader, payloadAttributes, startDateTime);
CreatedContexts.Add(blockImprovementContext);
Task.Run(() => ImprovementStarted?.Invoke(this, new ImprovementStartedEventArgs(blockImprovementContext)));
return blockImprovementContext;
}
}

private class ImprovementStartedEventArgs : EventArgs
{
public IBlockImprovementContext BlockImprovementContext { get; }

public ImprovementStartedEventArgs(IBlockImprovementContext blockImprovementContext)
{
BlockImprovementContext = blockImprovementContext;
}
}
}
Loading

0 comments on commit c21b094

Please sign in to comment.