Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
3 changes: 2 additions & 1 deletion .github/workflows/ci-surge.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
&& !startsWith(github.head_ref, 'release-please') }}
name: Integration tests
runs-on: [ubuntu-latest]
timeout-minutes: 45
timeout-minutes: 20
env:
SURGE_TAIKO_MONO_DIR: surge-taiko-mono
PACAYA_FORK_TAIKO_MONO_DIR: pacaya-fork-taiko-mono
Expand Down Expand Up @@ -149,6 +149,7 @@ jobs:
fi

- name: Run integration tests
timeout-minutes: 15
working-directory: >-
${{ env.SURGE_TAIKO_MONO_DIR }}/packages/taiko-client
env:
Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/ci-taiko.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
&& !startsWith(github.head_ref, 'release-please') }}
name: Integration tests
runs-on: [ubuntu-latest]
timeout-minutes: 45
timeout-minutes: 20
env:
TAIKO_MONO_DIR: taiko-mono
PACAYA_FORK_TAIKO_MONO_DIR: pacaya-fork-taiko-mono
Expand Down Expand Up @@ -149,6 +149,7 @@ jobs:
fi

- name: Run integration tests
timeout-minutes: 15
working-directory: >-
${{ env.TAIKO_MONO_DIR }}/packages/taiko-client
env:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -288,12 +288,15 @@ protected virtual bool IsOnMainChainBehindHead(Block newHeadBlock, ForkchoiceSta
return null;
}

protected virtual bool IsPayloadTimestampValid(Block newHeadBlock, PayloadAttributes payloadAttributes)
=> payloadAttributes.Timestamp > newHeadBlock.Timestamp;

protected bool ArePayloadAttributesTimestampAndSlotNumberValid(Block newHeadBlock, ForkchoiceStateV1 forkchoiceState, PayloadAttributes payloadAttributes,
[NotNullWhen(false)] out ResultWrapper<ForkchoiceUpdatedV1Result>? errorResult)
{
if (newHeadBlock.Timestamp >= payloadAttributes.Timestamp)
if (!IsPayloadTimestampValid(newHeadBlock, payloadAttributes))
{
string error = $"Payload timestamp {payloadAttributes.Timestamp} must be greater than block timestamp {newHeadBlock.Timestamp}.";
string error = $"Invalid payload timestamp {payloadAttributes.Timestamp} for block timestamp {newHeadBlock.Timestamp}.";
errorResult = ForkchoiceUpdatedV1Result.Error(error, MergeErrorCodes.InvalidPayloadAttributes);
return false;
}
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("Invalid payload timestamp"));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,11 @@ protected override bool IsOnMainChainBehindHead(Block newHeadBlock, ForkchoiceSt
return blockHeader;
}

// Taiko 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 IsPayloadTimestampValid(Block newHeadBlock, PayloadAttributes payloadAttributes)
=> payloadAttributes.Timestamp >= newHeadBlock.Timestamp;

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