public async Task should_return_invalid_lvh_null_on_invalid_blocks_during_the_sync()
    {
        using MergeTestBlockchain chain = await CreateBlockChain();

        IEngineRpcModule rpc          = CreateEngineModule(chain);
        Keccak?          startingHead = chain.BlockTree.HeadHash;
        BlockHeader      parent       = Build.A.BlockHeader
                                        .WithNumber(1)
                                        .WithHash(TestItem.KeccakA)
                                        .WithNonce(0)
                                        .WithDifficulty(0)
                                        .TestObject;
        Block block = Build.A.Block
                      .WithNumber(2)
                      .WithParent(parent)
                      .WithNonce(0)
                      .WithDifficulty(0)
                      .WithAuthor(Address.Zero)
                      .WithPostMergeFlag(true)
                      .TestObject;
        ExecutionPayloadV1 startingNewPayload = new(block);
        await rpc.engine_newPayloadV1(startingNewPayload);

        ForkchoiceStateV1 forkchoiceStateV1 = new(block.Hash !, startingHead, startingHead);
        ResultWrapper <ForkchoiceUpdatedV1Result> forkchoiceUpdatedResult =
            await rpc.engine_forkchoiceUpdatedV1(forkchoiceStateV1);

        forkchoiceUpdatedResult.Data.PayloadStatus.Status.Should()
        .Be(nameof(PayloadStatusV1.Syncing).ToUpper());

        ExecutionPayloadV1[] requests = CreateBlockRequestBranch(startingNewPayload, TestItem.AddressD, 1);
        foreach (ExecutionPayloadV1 r in requests)
        {
            ResultWrapper <PayloadStatusV1> payloadStatus = await rpc.engine_newPayloadV1(r);

            payloadStatus.Data.Status.Should().Be(nameof(PayloadStatusV1.Syncing).ToUpper());
        }

        ExecutionPayloadV1[] invalidRequests = CreateBlockRequestBranch(requests[0], TestItem.AddressD, 1);
        foreach (ExecutionPayloadV1 r in invalidRequests)
        {
            r.TryGetBlock(out Block? newBlock);
            newBlock !.Header.GasLimit = long.MaxValue; // incorrect gas limit
            newBlock.Header.Hash       = newBlock.CalculateHash();
            ResultWrapper <PayloadStatusV1> payloadStatus = await rpc.engine_newPayloadV1(new ExecutionPayloadV1(newBlock));

            payloadStatus.Data.Status.Should().Be(nameof(PayloadStatusV1.Invalid).ToUpper());
            payloadStatus.Data.LatestValidHash.Should().BeNull();
        }
    }
    public async Task newPayloadV1_can_insert_blocks_from_cache_when_syncing()
    {
        using MergeTestBlockchain chain = await CreateBlockChain();

        IEngineRpcModule rpc          = CreateEngineModule(chain);
        Keccak           startingHead = chain.BlockTree.HeadHash;

        ExecutionPayloadV1 parentBlockRequest = new(Build.A.Block.WithNumber(2).TestObject);

        ExecutionPayloadV1[]            requests = CreateBlockRequestBranch(parentBlockRequest, Address.Zero, 7);
        ResultWrapper <PayloadStatusV1> payloadStatus;

        foreach (ExecutionPayloadV1 r in requests)
        {
            payloadStatus = await rpc.engine_newPayloadV1(r);

            payloadStatus.Data.Status.Should().Be(nameof(PayloadStatusV1.Syncing).ToUpper());
            chain.BeaconSync.IsBeaconSyncHeadersFinished().Should().BeTrue();
            chain.BeaconSync.ShouldBeInBeaconHeaders().Should().BeFalse();
            chain.BeaconPivot.BeaconPivotExists().Should().BeFalse();
        }

        int pivotNum = 3;

        requests[pivotNum].TryGetBlock(out Block? pivotBlock);
        // initiate sync
        ForkchoiceStateV1 forkchoiceStateV1 = new(pivotBlock !.Hash, startingHead, startingHead);
        ResultWrapper <ForkchoiceUpdatedV1Result> forkchoiceUpdatedResult =
            await rpc.engine_forkchoiceUpdatedV1(forkchoiceStateV1);

        forkchoiceUpdatedResult.Data.PayloadStatus.Status.Should()
        .Be(nameof(PayloadStatusV1.Syncing).ToUpper());
        // trigger insertion of blocks in cache into block tree
        payloadStatus = await rpc.engine_newPayloadV1(requests[^ 1]);
    public async Task forkChoiceUpdatedV1_unknown_block_initiates_syncing()
    {
        using MergeTestBlockchain chain = await CreateBlockChain();

        IEngineRpcModule rpc          = CreateEngineModule(chain);
        Keccak?          startingHead = chain.BlockTree.HeadHash;
        BlockHeader      parent       = Build.A.BlockHeader
                                        .WithNumber(1)
                                        .WithHash(TestItem.KeccakA)
                                        .WithNonce(0)
                                        .WithDifficulty(0)
                                        .TestObject;
        Block block = Build.A.Block
                      .WithNumber(2)
                      .WithParent(parent)
                      .WithNonce(0)
                      .WithDifficulty(0)
                      .WithAuthor(Address.Zero)
                      .WithPostMergeFlag(true)
                      .TestObject;
        await rpc.engine_newPayloadV1(new ExecutionPayloadV1(block));

        // sync has not started yet
        chain.BeaconSync.IsBeaconSyncHeadersFinished().Should().BeTrue();
        chain.BeaconSync.IsBeaconSyncFinished(block.Header).Should().BeTrue();
        chain.BeaconSync.ShouldBeInBeaconHeaders().Should().BeFalse();
        chain.BeaconPivot.BeaconPivotExists().Should().BeFalse();
        BlockTreePointers pointers = new()
        {
            BestKnownNumber            = 0,
            BestSuggestedHeader        = chain.BlockTree.Genesis !,
            BestSuggestedBody          = chain.BlockTree.FindBlock(0) !,
            BestKnownBeaconBlock       = 0,
            LowestInsertedHeader       = null,
            LowestInsertedBeaconHeader = null
        };

        AssertBlockTreePointers(chain.BlockTree, pointers);

        ForkchoiceStateV1 forkchoiceStateV1 = new(block.Hash !, startingHead, startingHead);
        ResultWrapper <ForkchoiceUpdatedV1Result> forkchoiceUpdatedResult =
            await rpc.engine_forkchoiceUpdatedV1(forkchoiceStateV1);

        forkchoiceUpdatedResult.Data.PayloadStatus.Status.Should()
        .Be(nameof(PayloadStatusV1.Syncing).ToUpper());

        chain.BeaconSync.ShouldBeInBeaconHeaders().Should().BeTrue();
        chain.BeaconSync.IsBeaconSyncHeadersFinished().Should().BeFalse();
        chain.BeaconSync.IsBeaconSyncFinished(chain.BlockTree.FindBlock(block.Hash)?.Header).Should().BeFalse();
        AssertBeaconPivotValues(chain.BeaconPivot, block.Header);
        pointers.LowestInsertedBeaconHeader = block.Header;
        pointers.BestKnownBeaconBlock       = block.Number;
        pointers.LowestInsertedHeader       = block.Header;
        AssertBlockTreePointers(chain.BlockTree, pointers);
        AssertExecutionStatusNotChangedV1(rpc, block.Hash !, startingHead, startingHead);
    }