public BoostBlockImprovementContextFactory(IManualBlockProductionTrigger blockProductionTrigger, TimeSpan timeout, IBoostRelay boostRelay, IStateReader stateReader)
 {
     _blockProductionTrigger = blockProductionTrigger;
     _timeout     = timeout;
     _boostRelay  = boostRelay;
     _stateReader = stateReader;
 }
 public BoostBlockImprovementContext(
     Block currentBestBlock,
     IManualBlockProductionTrigger blockProductionTrigger,
     TimeSpan timeout,
     BlockHeader parentHeader,
     PayloadAttributes payloadAttributes,
     IBoostRelay boostRelay,
     IStateReader stateReader)
 {
     _boostRelay              = boostRelay;
     _stateReader             = stateReader;
     _cancellationTokenSource = new CancellationTokenSource(timeout);
     CurrentBestBlock         = currentBestBlock;
     ImprovementTask          = StartImprovingBlock(blockProductionTrigger, parentHeader, payloadAttributes, _cancellationTokenSource.Token);
 }
    public async Task forkchoiceUpdatedV1_should_ignore_gas_limit([Values(false, true)] bool relay)
    {
        MergeConfig mergeConfig = new() { Enabled = true, SecondsPerSlot = 1, TerminalTotalDifficulty = "0" };

        using MergeTestBlockchain chain = await CreateBlockChain(mergeConfig);

        IBlockImprovementContextFactory improvementContextFactory;

        if (relay)
        {
            IBoostRelay boostRelay = Substitute.For <IBoostRelay>();
            boostRelay.GetPayloadAttributes(Arg.Any <PayloadAttributes>(), Arg.Any <CancellationToken>())
            .Returns(c => c.Arg <PayloadAttributes>());

            improvementContextFactory = new BoostBlockImprovementContextFactory(chain.BlockProductionTrigger, TimeSpan.FromSeconds(5), boostRelay, chain.StateReader);
        }
        else
        {
            improvementContextFactory = new BlockImprovementContextFactory(chain.BlockProductionTrigger, TimeSpan.FromSeconds(5));
        }

        TimeSpan timePerSlot = TimeSpan.FromSeconds(10);

        chain.PayloadPreparationService = new PayloadPreparationService(
            chain.PostMergeBlockProducer !,
            improvementContextFactory,
            TimerFactory.Default,
            chain.LogManager,
            timePerSlot);

        IEngineRpcModule rpc          = CreateEngineModule(chain);
        Keccak           startingHead = chain.BlockTree.HeadHash;
        UInt256          timestamp    = Timestamper.UnixTime.Seconds;
        Keccak           random       = Keccak.Zero;
        Address          feeRecipient = Address.Zero;

        string payloadId = rpc.engine_forkchoiceUpdatedV1(new ForkchoiceStateV1(startingHead, Keccak.Zero, startingHead),
                                                          new PayloadAttributes {
            Timestamp = timestamp, SuggestedFeeRecipient = feeRecipient, PrevRandao = random, GasLimit = 10_000_000L
        }).Result.Data
                           .PayloadId !;

        ResultWrapper <ExecutionPayloadV1?> response = await rpc.engine_getPayloadV1(Bytes.FromHexString(payloadId));

        ExecutionPayloadV1 executionPayloadV1 = response.Data !;

        executionPayloadV1.GasLimit.Should().Be(4_000_000L);
    }
    public async Task forkchoiceUpdatedV1_should_communicate_with_boost_relay()
    {
        MergeConfig mergeConfig = new() { Enabled = true, SecondsPerSlot = 1, TerminalTotalDifficulty = "0" };

        using MergeTestBlockchain chain = await CreateBlockChain(mergeConfig);

        IBoostRelay boostRelay = Substitute.For <IBoostRelay>();

        boostRelay.GetPayloadAttributes(Arg.Any <PayloadAttributes>(), Arg.Any <CancellationToken>())
        .Returns(c =>
        {
            PayloadAttributes payloadAttributes     = c.Arg <PayloadAttributes>();
            payloadAttributes.SuggestedFeeRecipient = TestItem.AddressA;
            payloadAttributes.PrevRandao            = TestItem.KeccakA;
            payloadAttributes.Timestamp            += 1;
            payloadAttributes.GasLimit = 10_000_000L;
            return(payloadAttributes);
        });

        BoostBlockImprovementContextFactory improvementContextFactory = new(chain.BlockProductionTrigger, TimeSpan.FromSeconds(5), boostRelay, chain.StateReader);
        TimeSpan timePerSlot = TimeSpan.FromSeconds(10);

        chain.PayloadPreparationService = new PayloadPreparationService(
            chain.PostMergeBlockProducer !,
            improvementContextFactory,
            TimerFactory.Default,
            chain.LogManager,
            timePerSlot);

        IEngineRpcModule rpc          = CreateEngineModule(chain);
        Keccak           startingHead = chain.BlockTree.HeadHash;
        UInt256          timestamp    = Timestamper.UnixTime.Seconds;
        Keccak           random       = Keccak.Zero;
        Address          feeRecipient = Address.Zero;

        BoostExecutionPayloadV1?sentItem = null;

        boostRelay.When(b => b.SendPayload(Arg.Any <BoostExecutionPayloadV1>(), Arg.Any <CancellationToken>()))
        .Do(c => sentItem = c.Arg <BoostExecutionPayloadV1>());

        ManualResetEvent wait = new(false);

        chain.PayloadPreparationService.BlockImproved += (_, _) => wait.Set();

        string payloadId = rpc.engine_forkchoiceUpdatedV1(new ForkchoiceStateV1(startingHead, Keccak.Zero, startingHead),
                                                          new PayloadAttributes {
            Timestamp = timestamp, SuggestedFeeRecipient = feeRecipient, PrevRandao = random
        }).Result.Data
                           .PayloadId !;

        await wait.WaitOneAsync(100, CancellationToken.None);

        ResultWrapper <ExecutionPayloadV1?> response = await rpc.engine_getPayloadV1(Bytes.FromHexString(payloadId));

        ExecutionPayloadV1 executionPayloadV1 = response.Data !;

        executionPayloadV1.FeeRecipient.Should().Be(TestItem.AddressA);
        executionPayloadV1.PrevRandao.Should().Be(TestItem.KeccakA);
        executionPayloadV1.GasLimit.Should().Be(10_000_000L);
        executionPayloadV1.Should().BeEquivalentTo(sentItem !.Block);
        sentItem.Profit.Should().Be(0);
    }