public async Task <IBlockProducer> InitBlockProducer(IConsensusPlugin consensusPlugin)
        {
            if (!Enabled)
            {
                throw new InvalidOperationException("Plugin is disabled");
            }

            _nethermindApi.BlockProducerEnvFactory.TransactionsExecutorFactory = new MevBlockProducerTransactionsExecutorFactory(_nethermindApi.SpecProvider !, _nethermindApi.LogManager);

            int megabundleProducerCount = _mevConfig.GetTrustedRelayAddresses().Any() ? 1 : 0;
            List <MevBlockProducer.MevBlockProducerInfo> blockProducers =
                new(_mevConfig.MaxMergedBundles + megabundleProducerCount + 1);

            // Add non-mev block
            MevBlockProducer.MevBlockProducerInfo standardProducer = await CreateProducer(consensusPlugin);

            blockProducers.Add(standardProducer);

            // Try blocks with all bundle numbers <= MaxMergedBundles
            for (int bundleLimit = 1; bundleLimit <= _mevConfig.MaxMergedBundles; bundleLimit++)
            {
                BundleSelector bundleSelector = new(BundlePool, bundleLimit);
                MevBlockProducer.MevBlockProducerInfo bundleProducer = await CreateProducer(consensusPlugin, bundleLimit, new BundleTxSource(bundleSelector, _nethermindApi.Timestamper));

                blockProducers.Add(bundleProducer);
            }

            if (megabundleProducerCount > 0)
            {
                MegabundleSelector megabundleSelector = new(BundlePool);
                MevBlockProducer.MevBlockProducerInfo bundleProducer = await CreateProducer(consensusPlugin, 0, new BundleTxSource(megabundleSelector, _nethermindApi.Timestamper));

                blockProducers.Add(bundleProducer);
            }

            return(new MevBlockProducer(consensusPlugin.DefaultBlockProductionTrigger, _nethermindApi.LogManager, blockProducers.ToArray()));
        }
            protected override IBlockProducer CreateTestBlockProducer(TxPoolTxSource txPoolTxSource, ISealer sealer,
                                                                      ITransactionComparerProvider transactionComparerProvider)
            {
                MiningConfig miningConfig = new() { MinGasPrice = UInt256.One };

                SpecProvider.UpdateMergeTransitionInfo(1, 0);

                BlockProducerEnvFactory blockProducerEnvFactory = new(
                    DbProvider,
                    BlockTree,
                    ReadOnlyTrieStore,
                    SpecProvider,
                    BlockValidator,
                    NoBlockRewards.Instance,
                    ReceiptStorage,
                    BlockPreprocessorStep,
                    TxPool,
                    transactionComparerProvider,
                    miningConfig,
                    LogManager)
                {
                    TransactionsExecutorFactory =
                        new MevBlockProducerTransactionsExecutorFactory(SpecProvider, LogManager)
                };

                PostMergeBlockProducer CreatePostMergeBlockProducer(IBlockProductionTrigger blockProductionTrigger,
                                                                    ITxSource?txSource = null)
                {
                    BlockProducerEnv blockProducerEnv = blockProducerEnvFactory.Create(txSource);

                    return(new PostMergeBlockProducerFactory(SpecProvider, SealEngine, Timestamper, miningConfig,
                                                             LogManager).Create(
                               blockProducerEnv, blockProductionTrigger, txSource));
                }

                MevBlockProducer.MevBlockProducerInfo CreateProducer(int bundleLimit = 0,
                                                                     ITxSource?additionalTxSource = null)
                {
                    // TODO: this could be simplified a lot of the parent was not retrieved, not sure why do we need the parent here
                    bool BundleLimitTriggerCondition(BlockProductionEventArgs e)
                    {
                        // TODO: why do we need this parent? later we use only the current block number
                        BlockHeader?parent = BlockTree.GetProducedBlockParent(e.ParentHeader);

                        if (parent is not null)
                        {
                            // ToDo resolved conflict parent.Timestamp?
                            IEnumerable <MevBundle> bundles = BundlePool.GetBundles(parent.Number + 1, parent.Timestamp);
                            return(bundles.Count() >= bundleLimit);
                        }

                        return(false);
                    }

                    IManualBlockProductionTrigger manualTrigger = new BuildBlocksWhenRequested();
                    IBlockProductionTrigger       trigger       = manualTrigger;

                    if (bundleLimit != 0)
                    {
                        trigger = new TriggerWithCondition(manualTrigger, BundleLimitTriggerCondition);
                    }

                    IBlockProducer producer = CreatePostMergeBlockProducer(trigger, additionalTxSource);

                    return(new MevBlockProducer.MevBlockProducerInfo(producer, manualTrigger, new BeneficiaryTracer()));
                }

                int megabundleProducerCount = _relayAddresses.Any() ? 1 : 0;
                List <MevBlockProducer.MevBlockProducerInfo> blockProducers =
                    new(_maxMergedBundles + megabundleProducerCount + 1);

                // Add non-mev block
                MevBlockProducer.MevBlockProducerInfo standardProducer = CreateProducer();
                blockProducers.Add(standardProducer);

                // Try blocks with all bundle numbers <= maxMergedBundles
                for (int bundleLimit = 1; bundleLimit <= _maxMergedBundles; bundleLimit++)
                {
                    BundleSelector bundleSelector = new(BundlePool, bundleLimit);
                    BundleTxSource bundleTxSource = new(bundleSelector, Timestamper);
                    MevBlockProducer.MevBlockProducerInfo bundleProducer = CreateProducer(bundleLimit, bundleTxSource);
                    blockProducers.Add(bundleProducer);
                }

                if (megabundleProducerCount > 0)
                {
                    MegabundleSelector megabundleSelector = new(BundlePool);
                    BundleTxSource     megabundleTxSource = new(megabundleSelector, Timestamper);
                    MevBlockProducer.MevBlockProducerInfo bundleProducer = CreateProducer(0, megabundleTxSource);
                    blockProducers.Add(bundleProducer);
                }

                MevBlockProducer blockProducer = new MevBlockProducer(BlockProductionTrigger, LogManager, blockProducers.ToArray());

                blockProducer.BlockProduced += OnBlockProduced;
                return(blockProducer);
            }
            protected override IBlockProducer CreateTestBlockProducer(TxPoolTxSource txPoolTxSource, ISealer sealer, ITransactionComparerProvider transactionComparerProvider)
            {
                MiningConfig miningConfig = new() { MinGasPrice = UInt256.One };

                BlockProducerEnvFactory blockProducerEnvFactory = new(
                    DbProvider,
                    BlockTree,
                    ReadOnlyTrieStore,
                    SpecProvider,
                    BlockValidator,
                    NoBlockRewards.Instance,
                    ReceiptStorage,
                    BlockPreprocessorStep,
                    TxPool,
                    transactionComparerProvider,
                    miningConfig,
                    LogManager)
                {
                    TransactionsExecutorFactory = new MevBlockProducerTransactionsExecutorFactory(SpecProvider, LogManager)
                };

                Eth2BlockProducer CreateEth2BlockProducer(IBlockProductionTrigger blockProductionTrigger, ITxSource?txSource = null) =>
                new Eth2TestBlockProducerFactory(GasLimitCalculator, txSource).Create(
                    blockProducerEnvFactory,
                    BlockTree,
                    blockProductionTrigger,
                    SpecProvider,
                    Signer,
                    Timestamper,
                    miningConfig,
                    LogManager);

                MevBlockProducer.MevBlockProducerInfo CreateProducer(int bundleLimit = 0, ITxSource?additionalTxSource = null)
                {
                    bool BundleLimitTriggerCondition(BlockProductionEventArgs e)
                    {
                        BlockHeader?parent = BlockTree.GetProducedBlockParent(e.ParentHeader);

                        if (parent is not null)
                        {
                            IEnumerable <MevBundle> bundles = BundlePool.GetBundles(parent, Timestamper);
                            return(bundles.Count() >= bundleLimit);
                        }

                        return(false);
                    }

                    IManualBlockProductionTrigger manualTrigger = new BuildBlocksWhenRequested();
                    IBlockProductionTrigger       trigger       = manualTrigger;

                    if (bundleLimit != 0)
                    {
                        trigger = new TriggerWithCondition(manualTrigger, BundleLimitTriggerCondition);
                    }

                    IBlockProducer producer = CreateEth2BlockProducer(trigger, additionalTxSource);

                    return(new MevBlockProducer.MevBlockProducerInfo(producer, manualTrigger, new BeneficiaryTracer()));
                }

                int megabundleProducerCount = _relayAddresses.Any() ? 1 : 0;
                List <MevBlockProducer.MevBlockProducerInfo> blockProducers =
                    new(_maxMergedBundles + megabundleProducerCount + 1);

                // Add non-mev block
                MevBlockProducer.MevBlockProducerInfo standardProducer = CreateProducer();
                blockProducers.Add(standardProducer);

                // Try blocks with all bundle numbers <= maxMergedBundles
                for (int bundleLimit = 1; bundleLimit <= _maxMergedBundles; bundleLimit++)
                {
                    BundleSelector bundleSelector = new(BundlePool, bundleLimit);
                    BundleTxSource bundleTxSource = new(bundleSelector, Timestamper);
                    MevBlockProducer.MevBlockProducerInfo bundleProducer = CreateProducer(bundleLimit, bundleTxSource);
                    blockProducers.Add(bundleProducer);
                }

                if (megabundleProducerCount > 0)
                {
                    MegabundleSelector megabundleSelector = new(BundlePool);
                    BundleTxSource     megabundleTxSource = new(megabundleSelector, Timestamper);
                    MevBlockProducer.MevBlockProducerInfo bundleProducer = CreateProducer(0, megabundleTxSource);
                    blockProducers.Add(bundleProducer);
                }

                return(new MevBlockProducer(BlockProductionTrigger, LogManager, blockProducers.ToArray()));
            }