Example #1
0
        private async Task <MevBlockProducer.MevBlockProducerInfo> CreateProducer(
            IConsensusPlugin consensusPlugin,
            int bundleLimit = 0,
            ITxSource?additionalTxSource = null)
        {
            bool BundleLimitTriggerCondition(BlockProductionEventArgs e)
            {
                // TODO: why we are checking parent and not the currently produced block...?
                BlockHeader?parent = _nethermindApi.BlockTree !.GetProducedBlockParent(e.ParentHeader);

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

                return(false);
            }

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

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

            IBlockProducer producer = await consensusPlugin.InitBlockProducer(trigger, additionalTxSource);

            return(new MevBlockProducer.MevBlockProducerInfo(producer, manualTrigger, new BeneficiaryTracer()));
        }
        public void CheckHealth_returns_expected_results([ValueSource(nameof(CheckHealthTestCases))] CheckHealthTest test)
        {
            IBlockFinder         blockFinder         = Substitute.For <IBlockFinder>();
            ISyncServer          syncServer          = Substitute.For <ISyncServer>();
            IBlockchainProcessor blockchainProcessor = Substitute.For <IBlockchainProcessor>();
            IBlockProducer       blockProducer       = Substitute.For <IBlockProducer>();
            IHealthHintService   healthHintService   = Substitute.For <IHealthHintService>();

            blockchainProcessor.IsProcessingBlocks(Arg.Any <ulong?>()).Returns(test.IsProcessingBlocks);
            blockProducer.IsProducingBlocks(Arg.Any <ulong?>()).Returns(test.IsProducingBlocks);
            syncServer.GetPeerCount().Returns(test.PeerCount);

            BlockHeaderBuilder GetBlockHeader(int blockNumber) => Build.A.BlockHeader.WithNumber(blockNumber);

            blockFinder.Head.Returns(new Block(GetBlockHeader(4).TestObject));
            if (test.IsSyncing)
            {
                blockFinder.FindBestSuggestedHeader().Returns(GetBlockHeader(15).TestObject);
            }
            else
            {
                blockFinder.FindBestSuggestedHeader().Returns(GetBlockHeader(2).TestObject);
            }

            IEthSyncingInfo   ethSyncingInfo    = new EthSyncingInfo(blockFinder);
            NodeHealthService nodeHealthService =
                new(syncServer, blockFinder, blockchainProcessor, blockProducer, new HealthChecksConfig(), healthHintService, ethSyncingInfo, test.IsMining);
            CheckHealthResult result = nodeHealthService.CheckHealth();

            Assert.AreEqual(test.ExpectedHealthy, result.Healthy);
            Assert.AreEqual(test.ExpectedMessage, FormatMessages(result.Messages.Select(x => x.Message)));
            Assert.AreEqual(test.ExpectedLongMessage, FormatMessages(result.Messages.Select(x => x.LongMessage)));
        }
        public void Start()
        {
            for (int index = 0; index < _blockProducers.Length; index++)
            {
                IBlockProducer blockProducer = _blockProducers[index].BlockProducer;
                blockProducer.Start();
            }

            _blockProductionTrigger.TriggerBlockProduction += OnBlockProduction;
        }
        public Task Start()
        {
            for (int index = 0; index < _blockProducers.Length; index++)
            {
                IBlockProducer blockProducer = _blockProducers[index].BlockProducer;
                blockProducer.Start();
            }

            _blockProductionTrigger.TriggerBlockProduction += OnBlockProduction;
            return(Task.CompletedTask);
        }
    public MergeBlockProducer(IBlockProducer?preMergeProducer, IBlockProducer?postMergeBlockProducer, IPoSSwitcher?poSSwitcher)
    {
        _preMergeProducer  = preMergeProducer;
        _eth2BlockProducer = postMergeBlockProducer ?? throw new ArgumentNullException(nameof(postMergeBlockProducer));
        _poSSwitcher       = poSSwitcher ?? throw new ArgumentNullException(nameof(poSSwitcher));
        _poSSwitcher.TerminalBlockReached += OnSwitchHappened;
        if (HasPreMergeProducer)
        {
            _preMergeProducer !.BlockProduced += OnBlockProduced;
        }

        postMergeBlockProducer.BlockProduced += OnBlockProduced;
    }
        public bool IsProducingBlocks(ulong?maxProducingInterval)
        {
            for (int index = 0; index < _blockProducers.Length; index++)
            {
                IBlockProducer blockProducer = _blockProducers[index].BlockProducer;
                if (blockProducer.IsProducingBlocks(maxProducingInterval))
                {
                    return(true);
                }
            }

            return(false);
        }
Example #7
0
        private async Task AssertIsProducingBlocks(IBlockProducer blockProducer)
        {
            Assert.AreEqual(false, blockProducer.IsProducingBlocks(null));
            blockProducer.Start();
            Assert.AreEqual(true, blockProducer.IsProducingBlocks(null));
            Thread.Sleep(5000);
            Assert.AreEqual(false, blockProducer.IsProducingBlocks(1));
            Assert.AreEqual(true, blockProducer.IsProducingBlocks(1000));
            Assert.AreEqual(true, blockProducer.IsProducingBlocks(null));
            await blockProducer.StopAsync();

            Assert.AreEqual(false, blockProducer.IsProducingBlocks(null));
        }
        public Task StopAsync()
        {
            _blockProductionTrigger.TriggerBlockProduction -= OnBlockProduction;

            IList <Task> stopTasks = new List <Task>();

            for (int index = 0; index < _blockProducers.Length; index++)
            {
                IBlockProducer blockProducer = _blockProducers[index].BlockProducer;
                stopTasks.Add(blockProducer.StopAsync());
            }

            return(Task.WhenAll(stopTasks));
        }
            protected override IBlockProducer CreateTestBlockProducer(TxPoolTxSource txPoolTxSource, ISealer sealer,
                                                                      ITransactionComparerProvider transactionComparerProvider)
            {
                MiningConfig miningConfig = new() { MinGasPrice = UInt256.One };

                SpecProvider.UpdateMergeTransitionInfo(1, 0);

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

                UserOperationTxSource = new(UserOperationTxBuilder, UserOperationPool, UserOperationSimulator, SpecProvider, State, Signer, LogManager.GetClassLogger());

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

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

                IBlockProducer blockProducer =
                    CreatePostMergeBlockProducer(BlockProductionTrigger, UserOperationTxSource);

                blockProducer.BlockProduced += OnBlockProduced;

                return(blockProducer);
            }
            protected override IBlockProducer CreateTestBlockProducer(TxPoolTxSource txPoolTxSource, ISealer sealer, ITransactionComparerProvider transactionComparerProvider)
            {
                SealEngine = new MergeSealEngine(SealEngine, PoSSwitcher, SealValidator, LogManager);
                IBlockProducer preMergeBlockProducer =
                    base.CreateTestBlockProducer(txPoolTxSource, sealer, transactionComparerProvider);
                MiningConfig miningConfig = new() { Enabled = true, MinGasPrice = 0 };
                TargetAdjustedGasLimitCalculator targetAdjustedGasLimitCalculator = new(SpecProvider, miningConfig);

                EthSyncingInfo = new EthSyncingInfo(BlockTree);
                PostMergeBlockProducerFactory?blockProducerFactory = new(
                    SpecProvider,
                    SealEngine,
                    Timestamper,
                    miningConfig,
                    LogManager,
                    targetAdjustedGasLimitCalculator);

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


                BlockProducerEnv       blockProducerEnv       = blockProducerEnvFactory.Create();
                PostMergeBlockProducer?postMergeBlockProducer = blockProducerFactory.Create(
                    blockProducerEnv, BlockProductionTrigger);

                PostMergeBlockProducer = postMergeBlockProducer;
                PayloadPreparationService ??= new PayloadPreparationService(
                    postMergeBlockProducer,
                    new BlockImprovementContextFactory(BlockProductionTrigger, TimeSpan.FromSeconds(MergeConfig.SecondsPerSlot)),
                    TimerFactory.Default,
                    LogManager,
                    TimeSpan.FromSeconds(MergeConfig.SecondsPerSlot));
                return(new MergeBlockProducer(preMergeBlockProducer, postMergeBlockProducer, PoSSwitcher));
            }
Example #11
0
        private void InitBlockProducers()
        {
            if (_initConfig.IsMining)
            {
                IReadOnlyDbProvider minerDbProvider   = new ReadOnlyDbProvider(_dbProvider, false);
                ReadOnlyBlockTree   readOnlyBlockTree = new ReadOnlyBlockTree(_blockTree);
                ReadOnlyChain       producerChain     = new ReadOnlyChain(readOnlyBlockTree, _blockValidator, _rewardCalculator,
                                                                          _specProvider, minerDbProvider, _recoveryStep, _logManager, _txPool, _receiptStorage);

                switch (_chainSpec.SealEngineType)
                {
                case SealEngineType.Clique:
                {
                    if (_logger.IsWarn)
                    {
                        _logger.Warn("Starting Clique block producer & sealer");
                    }
                    CliqueConfig cliqueConfig = new CliqueConfig();
                    cliqueConfig.BlockPeriod = _chainSpec.Clique.Period;
                    cliqueConfig.Epoch       = _chainSpec.Clique.Epoch;
                    _blockProducer           = new CliqueBlockProducer(_txPool, producerChain.Processor,
                                                                       _blockTree, _timestamper, _cryptoRandom, producerChain.ReadOnlyStateProvider, _snapshotManager, (CliqueSealer)_sealer, _nodeKey.Address, cliqueConfig, _logManager);
                    break;
                }

                case SealEngineType.NethDev:
                {
                    if (_logger.IsWarn)
                    {
                        _logger.Warn("Starting Dev block producer & sealer");
                    }
                    _blockProducer = new DevBlockProducer(_txPool, producerChain.Processor, _blockTree,
                                                          _timestamper, _logManager);
                    break;
                }

                default:
                    throw new NotSupportedException($"Mining in {_chainSpec.SealEngineType} mode is not supported");
                }

                _blockProducer.Start();
            }
        }
Example #12
0
        private async Task InitBlockchain()
        {
            /* spec */
            if (_chainSpec.ChainId == RopstenSpecProvider.Instance.ChainId)
            {
                _specProvider = RopstenSpecProvider.Instance;
            }
            else if (_chainSpec.ChainId == MainNetSpecProvider.Instance.ChainId)
            {
                _specProvider = MainNetSpecProvider.Instance;
            }
            else if (_chainSpec.ChainId == RinkebySpecProvider.Instance.ChainId)
            {
                _specProvider = RinkebySpecProvider.Instance;
            }
            else if (_chainSpec.ChainId == GoerliSpecProvider.Instance.ChainId)
            {
                _specProvider = GoerliSpecProvider.Instance;
            }
            else if (_chainSpec.ChainId == SturebySpecProvider.Instance.ChainId)
            {
                _specProvider = SturebySpecProvider.Instance;
            }
            else
            {
                _specProvider = new SingleReleaseSpecProvider(LatestRelease.Instance, _chainSpec.ChainId);
            }

            /* sync */
            IDbConfig dbConfig = _configProvider.GetConfig <IDbConfig>();

            foreach (PropertyInfo propertyInfo in typeof(IDbConfig).GetProperties())
            {
                if (_logger.IsDebug)
                {
                    _logger.Debug($"DB {propertyInfo.Name}: {propertyInfo.GetValue(dbConfig)}");
                }
            }

            _dbProvider = HiveEnabled
                ? (IDbProvider) new MemDbProvider()
                : new RocksDbProvider(_initConfig.BaseDbPath, dbConfig, _logManager, _initConfig.StoreTraces, _initConfig.StoreReceipts);

            _ethereumEcdsa   = new EthereumEcdsa(_specProvider, _logManager);
            _transactionPool = new TransactionPool(
                new PersistentTransactionStorage(_dbProvider.PendingTxsDb, _specProvider),
                new PendingTransactionThresholdValidator(_initConfig.ObsoletePendingTransactionInterval,
                                                         _initConfig.RemovePendingTransactionInterval), new Timestamp(),
                _ethereumEcdsa, _specProvider, _logManager, _initConfig.RemovePendingTransactionInterval,
                _initConfig.PeerNotificationThreshold);
            _receiptStorage = new PersistentReceiptStorage(_dbProvider.ReceiptsDb, _specProvider);

//            IDbProvider debugRecorder = new RocksDbProvider(Path.Combine(_dbBasePath, "debug"), dbConfig);
//            _dbProvider = new RpcDbProvider(_jsonSerializer, new BasicJsonRpcClient(KnownRpcUris.NethVm1, _jsonSerializer, _logManager), _logManager, debugRecorder);

//            IDbProvider debugReader = new ReadOnlyDbProvider(new RocksDbProvider(Path.Combine(_dbBasePath, "debug"), dbConfig));
//            _dbProvider = debugReader;

            _blockTree = new BlockTree(
                _dbProvider.BlocksDb,
                _dbProvider.BlockInfosDb,
                _specProvider,
                _transactionPool,
                _logManager);

            _recoveryStep = new TxSignaturesRecoveryStep(_ethereumEcdsa, _transactionPool);

            CliqueConfig cliqueConfig = null;

            _snapshotManager = null;
            switch (_chainSpec.SealEngineType)
            {
            case SealEngineType.None:
                _sealer           = NullSealEngine.Instance;
                _sealValidator    = NullSealEngine.Instance;
                _rewardCalculator = NoBlockRewards.Instance;
                break;

            case SealEngineType.Clique:
                _rewardCalculator        = NoBlockRewards.Instance;
                cliqueConfig             = new CliqueConfig();
                cliqueConfig.BlockPeriod = _chainSpec.CliquePeriod;
                cliqueConfig.Epoch       = _chainSpec.CliqueEpoch;
                _snapshotManager         = new SnapshotManager(cliqueConfig, _dbProvider.BlocksDb, _blockTree, _ethereumEcdsa, _logManager);
                _sealValidator           = new CliqueSealValidator(cliqueConfig, _snapshotManager, _logManager);
                _recoveryStep            = new CompositeDataRecoveryStep(_recoveryStep, new AuthorRecoveryStep(_snapshotManager));
                if (_initConfig.IsMining)
                {
                    _sealer = new CliqueSealer(new BasicWallet(_nodeKey), cliqueConfig, _snapshotManager, _nodeKey.Address, _logManager);
                }
                else
                {
                    _sealer = NullSealEngine.Instance;
                }
                break;

            case SealEngineType.NethDev:
                _sealer           = NullSealEngine.Instance;
                _sealValidator    = NullSealEngine.Instance;
                _rewardCalculator = NoBlockRewards.Instance;
                break;

            case SealEngineType.Ethash:
                _rewardCalculator = new RewardCalculator(_specProvider);
                var difficultyCalculator = new DifficultyCalculator(_specProvider);
                if (_initConfig.IsMining)
                {
                    _sealer = new EthashSealer(new Ethash(_logManager), _logManager);
                }
                else
                {
                    _sealer = NullSealEngine.Instance;
                }

                _sealValidator = new EthashSealValidator(_logManager, difficultyCalculator, new Ethash(_logManager));
                break;

            default:
                throw new NotSupportedException($"Seal engine type {_chainSpec.SealEngineType} is not supported in Nethermind");
            }

            /* validation */
            var headerValidator = new HeaderValidator(
                _blockTree,
                _sealValidator,
                _specProvider,
                _logManager);

            var ommersValidator = new OmmersValidator(
                _blockTree,
                headerValidator,
                _logManager);

            var txValidator = new TransactionValidator(
                new SignatureValidator(_specProvider.ChainId));

            _blockValidator = new BlockValidator(
                txValidator,
                headerValidator,
                ommersValidator,
                _specProvider,
                _logManager);

            var stateTree = new StateTree(_dbProvider.StateDb);

            var stateProvider = new StateProvider(
                stateTree,
                _dbProvider.CodeDb,
                _logManager);

            _stateProvider = stateProvider;

            var storageProvider = new StorageProvider(
                _dbProvider.StateDb,
                stateProvider,
                _logManager);

            _transactionPoolInfoProvider = new TransactionPoolInfoProvider(stateProvider);

            /* blockchain processing */
            var blockhashProvider = new BlockhashProvider(
                _blockTree);

            var virtualMachine = new VirtualMachine(
                stateProvider,
                storageProvider,
                blockhashProvider,
                _logManager);

            var transactionProcessor = new TransactionProcessor(
                _specProvider,
                stateProvider,
                storageProvider,
                virtualMachine,
                _logManager);

            _blockProcessor = new BlockProcessor(
                _specProvider,
                _blockValidator,
                _rewardCalculator,
                transactionProcessor,
                _dbProvider.StateDb,
                _dbProvider.CodeDb,
                _dbProvider.TraceDb,
                stateProvider,
                storageProvider,
                _transactionPool,
                _receiptStorage,
                _logManager);

            _blockchainProcessor = new BlockchainProcessor(
                _blockTree,
                _blockProcessor,
                _recoveryStep,
                _logManager,
                _initConfig.StoreReceipts,
                _initConfig.StoreTraces);

            // create shared objects between discovery and peer manager
            IStatsConfig statsConfig = _configProvider.GetConfig <IStatsConfig>();

            _nodeStatsManager = new NodeStatsManager(statsConfig, _logManager, !statsConfig.CaptureNodeStatsEventHistory);

            if (_initConfig.IsMining)
            {
                IReadOnlyDbProvider minerDbProvider = new ReadOnlyDbProvider(_dbProvider, false);
                AlternativeChain    producerChain   = new AlternativeChain(_blockTree, _blockValidator, _rewardCalculator,
                                                                           _specProvider, minerDbProvider, _recoveryStep, _logManager, _transactionPool, _receiptStorage);

                switch (_chainSpec.SealEngineType)
                {
                case SealEngineType.Clique:
                {
                    // TODO: need to introduce snapshot provider for clique and pass it here instead of CliqueSealEngine
                    if (_logger.IsWarn)
                    {
                        _logger.Warn("Starting Clique block producer & sealer");
                    }
                    _blockProducer = new CliqueBlockProducer(_transactionPool, producerChain.Processor,
                                                             _blockTree, _timestamp, _cryptoRandom, producerChain.StateProvider, _snapshotManager, (CliqueSealer)_sealer, _nodeKey.Address, cliqueConfig, _logManager);
                    break;
                }

                case SealEngineType.NethDev:
                {
                    if (_logger.IsWarn)
                    {
                        _logger.Warn("Starting Dev block producer & sealer");
                    }
                    _blockProducer = new DevBlockProducer(_transactionPool, producerChain.Processor, _blockTree,
                                                          _timestamp, _logManager);
                    break;
                }

                default:
                    throw new NotSupportedException($"Mining in {_chainSpec.SealEngineType} mode is not supported");
                }

                _blockProducer.Start();
            }

            if (!HiveEnabled)
            {
                _blockchainProcessor.Start();
                LoadGenesisBlock(_chainSpec, string.IsNullOrWhiteSpace(_initConfig.GenesisHash) ? null : new Keccak(_initConfig.GenesisHash), _blockTree, stateProvider, _specProvider);
                if (_initConfig.ProcessingEnabled)
                {
#pragma warning disable 4014
                    LoadBlocksFromDb();
#pragma warning restore 4014
                }
                else
                {
                    if (_logger.IsWarn)
                    {
                        _logger.Warn($"Shutting down processor due to {nameof(InitConfig)}.{nameof(InitConfig.ProcessingEnabled)} set to false");
                    }
                    await _blockchainProcessor.StopAsync();
                }
            }

            await InitializeNetwork(
                _receiptStorage,
                _sealValidator,
                txValidator);
        }
            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()));
            }
Example #15
0
        private async Task InitBlockchain()
        {
            /* spec */
            if (_chainSpec.ChainId == RopstenSpecProvider.Instance.ChainId)
            {
                _specProvider = RopstenSpecProvider.Instance;
            }
            else if (_chainSpec.ChainId == MainNetSpecProvider.Instance.ChainId)
            {
                _specProvider = MainNetSpecProvider.Instance;
            }
            else if (_chainSpec.ChainId == RinkebySpecProvider.Instance.ChainId)
            {
                _specProvider = RinkebySpecProvider.Instance;
            }
            else if (_chainSpec.ChainId == GoerliSpecProvider.Instance.ChainId)
            {
                _specProvider = GoerliSpecProvider.Instance;
            }
            else if (_chainSpec.ChainId == SturebySpecProvider.Instance.ChainId)
            {
                _specProvider = SturebySpecProvider.Instance;
            }
            else
            {
                _specProvider = new SingleReleaseSpecProvider(LatestRelease.Instance, _chainSpec.ChainId);
            }

            /* sync */
            IDbConfig dbConfig = _configProvider.GetConfig <IDbConfig>();

            foreach (PropertyInfo propertyInfo in typeof(IDbConfig).GetProperties())
            {
                _logger.Info($"DB {propertyInfo.Name}: {propertyInfo.GetValue(dbConfig)}");
            }

            _dbProvider = HiveEnabled
                ? (IDbProvider) new MemDbProvider()
                : new RocksDbProvider(_initConfig.BaseDbPath, dbConfig, _logManager);

            _ethereumSigner  = new EthereumSigner(_specProvider, _logManager);
            _transactionPool = new TransactionPool(
                new PersistentTransactionStorage(_dbProvider.PendingTxsDb, _specProvider),
                new PendingTransactionThresholdValidator(_initConfig.ObsoletePendingTransactionInterval,
                                                         _initConfig.RemovePendingTransactionInterval), new Timestamp(),
                _ethereumSigner, _logManager, _initConfig.RemovePendingTransactionInterval,
                _initConfig.PeerNotificationThreshold);
            _receiptStorage = new PersistentReceiptStorage(_dbProvider.ReceiptsDb, _specProvider);

//            IDbProvider debugRecorder = new RocksDbProvider(Path.Combine(_dbBasePath, "debug"), dbConfig);
//            _dbProvider = new RpcDbProvider(_jsonSerializer, new BasicJsonRpcClient(KnownRpcUris.NethVm1, _jsonSerializer, _logManager), _logManager, debugRecorder);

//            IDbProvider debugReader = new ReadOnlyDbProvider(new RocksDbProvider(Path.Combine(_dbBasePath, "debug"), dbConfig));
//            _dbProvider = debugReader;

            /* blockchain */
            _blockTree = new BlockTree(
                _dbProvider.BlocksDb,
                _dbProvider.BlockInfosDb,
                _specProvider,
                _transactionPool,
                _logManager);

            var cliqueConfig = new CliqueConfig(15, 30000);
            var clique       = new CliqueSealEngine(cliqueConfig, _ethereumSigner, _nodeKey, _dbProvider.BlocksDb, _blockTree,
                                                    _logManager);

            clique.CanSeal = _initConfig.IsMining;

            // TODO: read seal engine from ChainSpec
            _sealEngine =
                (_specProvider is MainNetSpecProvider) ? ConfigureSealEngine() :
                (_specProvider is RopstenSpecProvider) ? ConfigureSealEngine() :
                (_specProvider is SturebySpecProvider) ? ConfigureSealEngine() :
                (_specProvider is RinkebySpecProvider) ? clique :
                (_specProvider is GoerliSpecProvider) ? (ISealEngine)clique :
                NullSealEngine.Instance;

            _rewardCalculator = (_sealEngine is CliqueSealEngine)
                ? (IRewardCalculator) new NoBlockRewards()
                : new RewardCalculator(_specProvider);

            /* validation */
            var headerValidator = new HeaderValidator(
                _blockTree,
                _sealEngine,
                _specProvider,
                _logManager);

            var ommersValidator = new OmmersValidator(
                _blockTree,
                headerValidator,
                _logManager);

            var txValidator = new TransactionValidator(
                new SignatureValidator(_specProvider.ChainId));

            _blockValidator = new BlockValidator(
                txValidator,
                headerValidator,
                ommersValidator,
                _specProvider,
                _logManager);

            var stateTree = new StateTree(_dbProvider.StateDb);

            var stateProvider = new StateProvider(
                stateTree,
                _dbProvider.CodeDb,
                _logManager);

            _stateProvider = stateProvider;

            var storageProvider = new StorageProvider(
                _dbProvider.StateDb,
                stateProvider,
                _logManager);

            _transactionPoolInfoProvider = new TransactionPoolInfoProvider(stateProvider);

            /* blockchain processing */
            var blockhashProvider = new BlockhashProvider(
                _blockTree);

            var virtualMachine = new VirtualMachine(
                stateProvider,
                storageProvider,
                blockhashProvider,
                _logManager);

            var transactionProcessor = new TransactionProcessor(
                _specProvider,
                stateProvider,
                storageProvider,
                virtualMachine,
                _logManager);

            var txRecoveryStep = new TxSignaturesRecoveryStep(_ethereumSigner, _transactionPool);

            _recoveryStep = _sealEngine is CliqueSealEngine
                ? new CompositeDataRecoveryStep(txRecoveryStep, new AuthorRecoveryStep(clique))
                : (IBlockDataRecoveryStep)txRecoveryStep;

            _blockProcessor = new BlockProcessor(
                _specProvider,
                _blockValidator,
                _rewardCalculator,
                transactionProcessor,
                _dbProvider.StateDb,
                _dbProvider.CodeDb,
                _dbProvider.TraceDb,
                stateProvider,
                storageProvider,
                _transactionPool,
                _receiptStorage,
                _logManager);

            _blockchainProcessor = new BlockchainProcessor(
                _blockTree,
                _blockProcessor,
                _recoveryStep,
                _logManager,
                true,
                true);

            // create shared objects between discovery and peer manager
            _nodeFactory       = new NodeFactory(_logManager);
            _nodeStatsProvider =
                new NodeStatsProvider(_configProvider.GetConfig <IStatsConfig>(), _nodeFactory, _logManager);

            var jsonSerializer = new JsonSerializer(
                _logManager);

            var encrypter = new AesEncrypter(
                _configProvider,
                _logManager);

            _keyStore = new FileKeyStore(
                _configProvider,
                jsonSerializer,
                encrypter,
                _cryptoRandom,
                _logManager);

            if (_initConfig.IsMining)
            {
                IReadOnlyDbProvider minerDbProvider = new ReadOnlyDbProvider(_dbProvider, false);
                AlternativeChain    producerChain   = new AlternativeChain(_blockTree, _blockValidator, _rewardCalculator,
                                                                           _specProvider, minerDbProvider, _recoveryStep, _logManager, _transactionPool, _receiptStorage);

                if (_sealEngine is CliqueSealEngine engine)
                {
                    // TODO: need to introduce snapshot provider for clique and pass it here instead of CliqueSealEngine
                    if (_logger.IsWarn)
                    {
                        _logger.Warn("Starting Clique block producer & sealer");
                    }
                    _blockProducer = new CliqueBlockProducer(_transactionPool, producerChain.Processor, _blockTree,
                                                             producerChain.StateProvider, _timestamp, _cryptoRandom, engine, cliqueConfig, _nodeKey.Address,
                                                             _logManager);
                }
                else
                {
                    if (_logger.IsWarn)
                    {
                        _logger.Warn("Starting Dev block producer & sealer");
                    }
                    _blockProducer = new DevBlockProducer(_transactionPool, producerChain.Processor, _blockTree,
                                                          _timestamp, _logManager);
                }

                _blockProducer.Start();
            }

            if (!HiveEnabled)
            {
                _blockchainProcessor.Start();
                LoadGenesisBlock(_chainSpec, string.IsNullOrWhiteSpace(_initConfig.GenesisHash) ?
                                 null : new Keccak(_initConfig.GenesisHash), _blockTree, stateProvider, _specProvider);
                if (_initConfig.ProcessingEnabled)
                {
#pragma warning disable 4014
                    LoadBlocksFromDb();
#pragma warning restore 4014
                }
                else
                {
                    if (_logger.IsWarn)
                    {
                        _logger.Warn($"Shutting down processor due to {nameof(InitConfig)}.{nameof(InitConfig.ProcessingEnabled)} set to false");
                    }
                    await _blockchainProcessor.StopAsync();
                }
            }

            await InitializeNetwork(
                _receiptStorage,
                headerValidator,
                txValidator);
        }
 public ProducedBlockSuggester(IBlockTree blockTree, IBlockProducer blockProducer)
 {
     _blockTree     = blockTree;
     _blockProducer = blockProducer;
     _blockProducer.BlockProduced += OnBlockProduced;
 }
Example #17
0
        private async Task InitBlockchain()
        {
            _specProvider = new ChainSpecBasedSpecProvider(_chainSpec);

            Account.AccountStartNonce = _chainSpec.Parameters.AccountStartNonce;

            /* sync */
            IDbConfig dbConfig = _configProvider.GetConfig <IDbConfig>();

            _syncConfig = _configProvider.GetConfig <ISyncConfig>();

            foreach (PropertyInfo propertyInfo in typeof(IDbConfig).GetProperties())
            {
                if (_logger.IsDebug)
                {
                    _logger.Debug($"DB {propertyInfo.Name}: {propertyInfo.GetValue(dbConfig)}");
                }
            }

            _dbProvider = HiveEnabled
                ? (IDbProvider) new MemDbProvider()
                : new RocksDbProvider(_initConfig.BaseDbPath, dbConfig, _logManager, _initConfig.StoreTraces, _initConfig.StoreReceipts || _syncConfig.DownloadReceiptsInFastSync);

            _ethereumEcdsa = new EthereumEcdsa(_specProvider, _logManager);
            _txPool        = new TxPool(
                new PersistentTxStorage(_dbProvider.PendingTxsDb, _specProvider),
                Timestamp.Default,
                _ethereumEcdsa,
                _specProvider,
                _txPoolConfig, _logManager);
            var _rc7FixDb = _initConfig.EnableRc7Fix ? _dbProvider.HeadersDb : NullDb.Instance;

            _receiptStorage = new PersistentReceiptStorage(_dbProvider.ReceiptsDb, _rc7FixDb, _specProvider, _logManager);

//            IDbProvider debugRecorder = new RocksDbProvider(Path.Combine(_dbBasePath, "debug"), dbConfig);
//            _dbProvider = new RpcDbProvider(_jsonSerializer, new BasicJsonRpcClient(KnownRpcUris.NethVm1, _jsonSerializer, _logManager), _logManager, debugRecorder);

//            IDbProvider debugReader = new ReadOnlyDbProvider(new RocksDbProvider(Path.Combine(_dbBasePath, "debug"), dbConfig));
//            _dbProvider = debugReader;

            _blockTree = new BlockTree(
                _dbProvider.BlocksDb,
                _dbProvider.HeadersDb,
                _dbProvider.BlockInfosDb,
                _specProvider,
                _txPool,
                _syncConfig,
                _logManager);

            _recoveryStep = new TxSignaturesRecoveryStep(_ethereumEcdsa, _txPool, _logManager);

            CliqueConfig cliqueConfig = null;

            _snapshotManager = null;
            switch (_chainSpec.SealEngineType)
            {
            case SealEngineType.None:
                _sealer           = NullSealEngine.Instance;
                _sealValidator    = NullSealEngine.Instance;
                _rewardCalculator = NoBlockRewards.Instance;
                break;

            case SealEngineType.Clique:
                _rewardCalculator        = NoBlockRewards.Instance;
                cliqueConfig             = new CliqueConfig();
                cliqueConfig.BlockPeriod = _chainSpec.Clique.Period;
                cliqueConfig.Epoch       = _chainSpec.Clique.Epoch;
                _snapshotManager         = new SnapshotManager(cliqueConfig, _dbProvider.BlocksDb, _blockTree, _ethereumEcdsa, _logManager);
                _sealValidator           = new CliqueSealValidator(cliqueConfig, _snapshotManager, _logManager);
                _recoveryStep            = new CompositeDataRecoveryStep(_recoveryStep, new AuthorRecoveryStep(_snapshotManager));
                if (_initConfig.IsMining)
                {
                    _sealer = new CliqueSealer(new BasicWallet(_nodeKey), cliqueConfig, _snapshotManager, _nodeKey.Address, _logManager);
                }
                else
                {
                    _sealer = NullSealEngine.Instance;
                }

                break;

            case SealEngineType.NethDev:
                _sealer           = NullSealEngine.Instance;
                _sealValidator    = NullSealEngine.Instance;
                _rewardCalculator = NoBlockRewards.Instance;
                break;

            case SealEngineType.Ethash:
                _rewardCalculator = new RewardCalculator(_specProvider);
                var difficultyCalculator = new DifficultyCalculator(_specProvider);
                if (_initConfig.IsMining)
                {
                    _sealer = new EthashSealer(new Ethash(_logManager), _logManager);
                }
                else
                {
                    _sealer = NullSealEngine.Instance;
                }

                _sealValidator = new EthashSealValidator(_logManager, difficultyCalculator, new Ethash(_logManager));
                break;

            default:
                throw new NotSupportedException($"Seal engine type {_chainSpec.SealEngineType} is not supported in Nethermind");
            }

            /* validation */
            _headerValidator = new HeaderValidator(
                _blockTree,
                _sealValidator,
                _specProvider,
                _logManager);

            var ommersValidator = new OmmersValidator(
                _blockTree,
                _headerValidator,
                _logManager);

            var txValidator = new TxValidator(_specProvider.ChainId);

            _blockValidator = new BlockValidator(
                txValidator,
                _headerValidator,
                ommersValidator,
                _specProvider,
                _logManager);

            var stateProvider = new StateProvider(
                _dbProvider.StateDb,
                _dbProvider.CodeDb,
                _logManager);

            _stateProvider = stateProvider;

            var storageProvider = new StorageProvider(
                _dbProvider.StateDb,
                stateProvider,
                _logManager);

            _txPoolInfoProvider = new TxPoolInfoProvider(stateProvider);

            _transactionPoolInfoProvider = new TxPoolInfoProvider(stateProvider);

            /* blockchain processing */
            var blockhashProvider = new BlockhashProvider(
                _blockTree, _logManager);

            var virtualMachine = new VirtualMachine(
                stateProvider,
                storageProvider,
                blockhashProvider,
                _logManager);

            var transactionProcessor = new TransactionProcessor(
                _specProvider,
                stateProvider,
                storageProvider,
                virtualMachine,
                _logManager);

            _blockProcessor = new BlockProcessor(
                _specProvider,
                _blockValidator,
                _rewardCalculator,
                transactionProcessor,
                _dbProvider.StateDb,
                _dbProvider.CodeDb,
                _dbProvider.TraceDb,
                stateProvider,
                storageProvider,
                _txPool,
                _receiptStorage,
                _logManager);

            _blockchainProcessor = new BlockchainProcessor(
                _blockTree,
                _blockProcessor,
                _recoveryStep,
                _logManager,
                _initConfig.StoreReceipts,
                _initConfig.StoreTraces);

            // create shared objects between discovery and peer manager
            IStatsConfig statsConfig = _configProvider.GetConfig <IStatsConfig>();

            _nodeStatsManager = new NodeStatsManager(statsConfig, _logManager);

            if (_initConfig.IsMining)
            {
                IReadOnlyDbProvider minerDbProvider = new ReadOnlyDbProvider(_dbProvider, false);
                AlternativeChain    producerChain   = new AlternativeChain(_blockTree, _blockValidator, _rewardCalculator,
                                                                           _specProvider, minerDbProvider, _recoveryStep, _logManager, _txPool, _receiptStorage);

                switch (_chainSpec.SealEngineType)
                {
                case SealEngineType.Clique:
                {
                    if (_logger.IsWarn)
                    {
                        _logger.Warn("Starting Clique block producer & sealer");
                    }
                    _blockProducer = new CliqueBlockProducer(_txPool, producerChain.Processor,
                                                             _blockTree, _timestamp, _cryptoRandom, producerChain.StateProvider, _snapshotManager, (CliqueSealer)_sealer, _nodeKey.Address, cliqueConfig, _logManager);
                    break;
                }

                case SealEngineType.NethDev:
                {
                    if (_logger.IsWarn)
                    {
                        _logger.Warn("Starting Dev block producer & sealer");
                    }
                    _blockProducer = new DevBlockProducer(_txPool, producerChain.Processor, _blockTree,
                                                          _timestamp, _logManager);
                    break;
                }

                default:
                    throw new NotSupportedException($"Mining in {_chainSpec.SealEngineType} mode is not supported");
                }

                _blockProducer.Start();
            }

            _blockchainProcessor.Start();
            LoadGenesisBlock(_chainSpec, string.IsNullOrWhiteSpace(_initConfig.GenesisHash) ? null : new Keccak(_initConfig.GenesisHash), _blockTree, stateProvider, _specProvider);
            if (_initConfig.ProcessingEnabled)
            {
#pragma warning disable 4014
                LoadBlocksFromDb();
#pragma warning restore 4014
            }
            else
            {
                if (_logger.IsWarn)
                {
                    _logger.Warn($"Shutting down the blockchain processor due to {nameof(InitConfig)}.{nameof(InitConfig.ProcessingEnabled)} set to false");
                }
                await _blockchainProcessor.StopAsync();
            }

            if (HiveEnabled)
            {
                await InitHive();
            }

            if (HiveEnabled)
            {
                await InitHive();
            }

            var producers = new List <IProducer>();
            if (_initConfig.PubSubEnabled)
            {
                var kafkaProducer = await PrepareKafkaProducer(_blockTree, _configProvider.GetConfig <IKafkaConfig>());

                producers.Add(kafkaProducer);
            }

            var grpcClientConfig = _configProvider.GetConfig <IGrpcClientConfig>();
            if (grpcClientConfig.Enabled)
            {
                var grpcProducer = new GrpcProducer(_grpcClient, _logManager);
                producers.Add(grpcProducer);
            }

            ISubscription subscription;
            if (producers.Any())
            {
                subscription = new Subscription(producers, _blockProcessor, _logManager);
            }
            else
            {
                subscription = new EmptySubscription();
            }

            _disposeStack.Push(subscription);
            _dataBridge = new DataBridge(subscription, _receiptStorage, _blockTree, _logManager);
            _dataBridge.Start();

            await InitializeNetwork();
        }