Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ protected virtual bool IsOnMainChainBehindHead(Block newHeadBlock, ForkchoiceSta
return null;
}

protected bool ArePayloadAttributesTimestampAndSlotNumberValid(Block newHeadBlock, ForkchoiceStateV1 forkchoiceState, PayloadAttributes payloadAttributes,
protected virtual bool ArePayloadAttributesTimestampAndSlotNumberValid(Block newHeadBlock, ForkchoiceStateV1 forkchoiceState, PayloadAttributes payloadAttributes,
[NotNullWhen(false)] out ResultWrapper<ForkchoiceUpdatedV1Result>? errorResult)
{
if (newHeadBlock.Timestamp >= payloadAttributes.Timestamp)
Expand Down
54 changes: 54 additions & 0 deletions src/Nethermind/Nethermind.Taiko.Test/TaikoEngineApiTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@

using NUnit.Framework;
using Nethermind.Core;
using Nethermind.Consensus.Producers;
using Nethermind.Merge.Plugin.Handlers;
using System.Threading.Tasks;
using Nethermind.Blockchain;
using Nethermind.Consensus.Processing;
using Nethermind.Consensus;
using Nethermind.Core.Crypto;
using Nethermind.Core.Specs;
using Nethermind.Logging;
using Nethermind.Merge.Plugin.BlockProduction;
Expand Down Expand Up @@ -68,4 +70,56 @@ static void AddBlock(IBlockTree blockTree, Block block)
blockTree.HeadHash.Returns(block.Hash!);
}
}

[TestCase(100ul, 100ul, true, TestName = "Equal timestamps allowed for Pacaya")]
[TestCase(100ul, 101ul, true, TestName = "Greater timestamp allowed")]
[TestCase(100ul, 99ul, false, TestName = "Lesser timestamp rejected")]
public async Task Test_ForkchoiceUpdatedHandler_Allows_Equal_Timestamps(ulong headTimestamp, ulong payloadTimestamp, bool shouldSucceed)
{
IBlockTree blockTree = Substitute.For<IBlockTree>();

Block headBlock = Build.A.Block.WithNumber(1).WithTimestamp(headTimestamp).TestObject;

blockTree.FindBlock(headBlock.Hash!, BlockTreeLookupOptions.DoNotCreateLevelIfMissing).Returns(headBlock);
blockTree.GetInfo(headBlock.Number, headBlock.Hash!).Returns((new BlockInfo(headBlock.Hash!, 0) { WasProcessed = true }, new ChainLevelInfo(true)));
blockTree.Head.Returns(headBlock);
blockTree.HeadHash.Returns(headBlock.Hash!);
blockTree.IsMainChain(headBlock.Header).Returns(true);

TaikoForkchoiceUpdatedHandler handler = new(
blockTree,
Substitute.For<IManualBlockFinalizationManager>(),
Substitute.For<IPoSSwitcher>(),
Substitute.For<IPayloadPreparationService>(),
Substitute.For<IBlockProcessingQueue>(),
Substitute.For<IBlockCacheService>(),
Substitute.For<IInvalidChainTracker>(),
Substitute.For<IMergeSyncController>(),
Substitute.For<IBeaconPivot>(),
Substitute.For<IPeerRefresher>(),
Substitute.For<ISpecProvider>(),
Substitute.For<ISyncPeerPool>(),
new MergeConfig(),
Substitute.For<ILogManager>()
);

PayloadAttributes payloadAttributes = new()
{
Timestamp = payloadTimestamp,
PrevRandao = Keccak.Zero,
SuggestedFeeRecipient = Address.Zero
};

ForkchoiceStateV1 forkchoiceState = new(headBlock.Hash!, headBlock.Hash!, headBlock.Hash!);
ResultWrapper<ForkchoiceUpdatedV1Result> result = await handler.Handle(forkchoiceState, payloadAttributes, 1);

if (shouldSucceed)
{
Assert.That(result.Data.PayloadStatus.Status, Is.EqualTo(PayloadStatus.Valid));
}
else
{
Assert.That(result.Result.Error, Does.Contain("must be greater than or equal to"));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,22 @@ protected override bool IsOnMainChainBehindHead(Block newHeadBlock, ForkchoiceSt
return blockHeader;
}

// Taiko Pacaya allows equal timestamps because multiple L2 blocks can be derived
// from a single L1 block, all sharing the same L1 anchor timestamp.
protected override bool ArePayloadAttributesTimestampAndSlotNumberValid(Block newHeadBlock, ForkchoiceStateV1 forkchoiceState, PayloadAttributes payloadAttributes,
[NotNullWhen(false)] out ResultWrapper<ForkchoiceUpdatedV1Result>? errorResult)
{
if (newHeadBlock.Timestamp > payloadAttributes.Timestamp)
{
string error = $"Payload timestamp {payloadAttributes.Timestamp} must be greater than or equal to block timestamp {newHeadBlock.Timestamp}.";
errorResult = ForkchoiceUpdatedV1Result.Error(error, MergeErrorCodes.InvalidPayloadAttributes);
return false;
}

errorResult = null;
return true;
}

protected override bool TryGetBranch(Block newHeadBlock, out Block[] blocks)
{
// Allow resetting to any block already on the main chain (including genesis)
Expand Down
Loading