public ConsensusStats( CoinViewStack stack, CoinView coinView, ConsensusLoop consensusLoop, ChainState chainState, ConcurrentChain chain, IConnectionManager connectionManager, ILoggerFactory loggerFactory) { stack = new CoinViewStack(coinView); this.cache = stack.Find <CachedCoinView>(); this.dbreeze = stack.Find <DBreezeCoinView>(); this.bottom = stack.Bottom; this.consensusLoop = consensusLoop; this.lookaheadPuller = this.consensusLoop.Puller as LookaheadBlockPuller; this.lastSnapshot = consensusLoop.Validator.PerformanceCounter.Snapshot(); this.lastSnapshot2 = this.dbreeze?.PerformanceCounter.Snapshot(); this.lastSnapshot3 = this.cache?.PerformanceCounter.Snapshot(); this.chainState = chainState; this.chain = chain; this.connectionManager = connectionManager; this.logger = loggerFactory.CreateLogger(this.GetType().FullName); }
public ConsensusStats( CoinView coinView, IConsensusLoop consensusLoop, IInitialBlockDownloadState initialBlockDownloadState, ConcurrentChain chain, IConnectionManager connectionManager, IDateTimeProvider dateTimeProvider, ILoggerFactory loggerFactory) { CoinViewStack stack = new CoinViewStack(coinView); this.cache = stack.Find <CachedCoinView>(); this.dbreeze = stack.Find <DBreezeCoinView>(); this.bottom = stack.Bottom; this.consensusLoop = consensusLoop; this.lookaheadPuller = this.consensusLoop.Puller as LookaheadBlockPuller; this.lastSnapshot = consensusLoop.ConsensusRules.PerformanceCounter.Snapshot(); this.lastSnapshot2 = this.dbreeze?.PerformanceCounter.Snapshot(); this.lastSnapshot3 = this.cache?.PerformanceCounter.Snapshot(); this.initialBlockDownloadState = initialBlockDownloadState; this.chain = chain; this.connectionManager = connectionManager; this.dateTimeProvider = dateTimeProvider; this.logger = loggerFactory.CreateLogger(this.GetType().FullName); }
public ConsensusStats( ICoinView coinView, IConsensusManager consensusManager, IConsensusRuleEngine consensusRules, IInitialBlockDownloadState initialBlockDownloadState, ConcurrentChain chain, IConnectionManager connectionManager, IDateTimeProvider dateTimeProvider, IBlockPuller blockPuller, ILoggerFactory loggerFactory, INodeLifetime nodeLifetime) { var stack = new CoinViewStack(coinView); this.cache = stack.Find <CachedCoinView>(); this.dbreeze = stack.Find <DBreezeCoinView>(); this.bottom = stack.Bottom; this.consensusManager = consensusManager; this.consensusRules = consensusRules; this.lastSnapshot = consensusRules.PerformanceCounter.Snapshot(); this.lastSnapshot2 = this.dbreeze?.PerformanceCounter.Snapshot(); this.lastSnapshot3 = this.cache?.PerformanceCounter.Snapshot(); this.initialBlockDownloadState = initialBlockDownloadState; this.chain = chain; this.connectionManager = connectionManager; this.dateTimeProvider = dateTimeProvider; this.blockPuller = blockPuller; this.logger = loggerFactory.CreateLogger(this.GetType().FullName); this.nodeLifetime = nodeLifetime; }
public void ValidSomeBlocks() { using (NodeContext ctx = NodeContext.Create(network: Network.Main)) { var network = ctx.Network; var chain = new ConcurrentChain(network.GetGenesis().Header); if (network == NBitcoin.Network.Main) { chain.Load(GetFile("main.data", "https://aois.blob.core.windows.net/public/main.data")); } else { chain.Load(GetFile("test.data", "https://aois.blob.core.windows.net/public/test.data")); } var stack = new CoinViewStack( new CacheCoinView( new PrefetcherCoinView( new BackgroundCommiterCoinView( ctx.PersistentCoinView)))); var cache = stack.Find <CacheCoinView>(); var backgroundCommiter = stack.Find <BackgroundCommiterCoinView>(); ConsensusValidator valid = new ConsensusValidator(network.Consensus); valid.UseConsensusLib = false; Node node = Node.Connect(network, "yournode"); node.VersionHandshake(); var puller = new CustomNodeBlockPuller(chain, node); var lastSnapshot = valid.PerformanceCounter.Snapshot(); var lastSnapshot2 = ctx.PersistentCoinView.PerformanceCounter.Snapshot(); var lastSnapshot3 = cache.PerformanceCounter.Snapshot(); foreach (var block in valid.Run(stack, puller)) { if ((DateTimeOffset.UtcNow - lastSnapshot.Taken) > TimeSpan.FromSeconds(5.0)) { Console.WriteLine(); Console.WriteLine("ActualLookahead :\t" + puller.ActualLookahead + " blocks"); Console.WriteLine("Downloaded Count :\t" + puller.RollingAverageDownloadedCount + " blocks"); Console.WriteLine("CoinViewTip :\t" + backgroundCommiter.Tip.Height); Console.WriteLine("CommitingTip :\t" + backgroundCommiter.CommitingTip.Height); Console.WriteLine("InnerTip :\t" + backgroundCommiter.InnerTip.Height); Console.WriteLine("Cache entries :\t" + cache.CacheEntryCount); var snapshot = valid.PerformanceCounter.Snapshot(); Console.Write(snapshot - lastSnapshot); lastSnapshot = snapshot; var snapshot2 = ctx.PersistentCoinView.PerformanceCounter.Snapshot(); Console.Write(snapshot2 - lastSnapshot2); lastSnapshot2 = snapshot2; var snapshot3 = cache.PerformanceCounter.Snapshot(); Console.Write(snapshot3 - lastSnapshot3); lastSnapshot3 = snapshot3; } } } }
public void Constructor_CoinViewWithoutBackedCoinViews_SetsCoinViewAsTopAndBottom() { var coinView = new NonBackedCoinView(); var stack = new CoinViewStack(coinView); Assert.True(stack.Top is NonBackedCoinView); Assert.True(stack.Bottom is NonBackedCoinView); }
public void Find_CoinViewNotFound_ReturnsNull() { var nonBackedCoinView = new NonBackedCoinView(); var stack = new CoinViewStack(nonBackedCoinView); var coinView = stack.Find <BackedCoinView2>(); Assert.Null(coinView); }
public void Constructor_CoinViewWithBackedCoinViews_SetsTopAndBottom() { var nonBackedCoinView = new NonBackedCoinView(); var backedCoinView2 = new BackedCoinView2(nonBackedCoinView); var backedCoinView1 = new BackedCoinView1(backedCoinView2); var stack = new CoinViewStack(backedCoinView1); Assert.True(stack.Top is BackedCoinView1); Assert.True(stack.Bottom is NonBackedCoinView); }
public void Find_CoinViewWithinStack_ReturnsCoinView() { var nonBackedCoinView = new NonBackedCoinView(); var backedCoinView2 = new BackedCoinView2(nonBackedCoinView, 3); var backedCoinView1 = new BackedCoinView1(backedCoinView2, 4); var stack = new CoinViewStack(backedCoinView1); var coinView = stack.Find <BackedCoinView2>(); Assert.True(coinView is BackedCoinView2); Assert.Equal(3, coinView.OutputCount); }
public void GetElements_NullCoinViewWithinStack_ReturnsNonNullCoinViews() { var backedCoinView2 = new BackedCoinView2(null); var backedCoinView1 = new BackedCoinView1(backedCoinView2); var stack = new CoinViewStack(backedCoinView1); List <CoinView> coinViews = stack.GetElements().ToList(); Assert.Equal(2, coinViews.Count); Assert.True(coinViews[0] is BackedCoinView1); Assert.True(coinViews[1] is BackedCoinView2); }
public void GetElements_CoinViewWithBackedCoinViews_ReturnsStack() { var nonBackedCoinView = new NonBackedCoinView(); var backedCoinView2 = new BackedCoinView2(nonBackedCoinView); var backedCoinView1 = new BackedCoinView1(backedCoinView2); var stack = new CoinViewStack(backedCoinView1); List <CoinView> coinViews = stack.GetElements().ToList(); Assert.Equal(3, coinViews.Count); Assert.True(coinViews[0] is BackedCoinView1); Assert.True(coinViews[1] is BackedCoinView2); Assert.True(coinViews[2] is NonBackedCoinView); }
public ConsensusStats(FullNode fullNode, CoinViewStack stack) { this.fullNode = fullNode; stack = new CoinViewStack(fullNode.CoinView); cache = stack.Find <CachedCoinView>(); dbreeze = stack.Find <DBreezeCoinView>(); bottom = stack.Bottom; lookaheadPuller = fullNode.ConsensusLoop.Puller as LookaheadBlockPuller; lastSnapshot = fullNode.ConsensusLoop.Validator.PerformanceCounter.Snapshot(); lastSnapshot2 = dbreeze?.PerformanceCounter.Snapshot(); lastSnapshot3 = cache?.PerformanceCounter.Snapshot(); }
private Task RunLoop(CancellationToken cancellationToken) { try { var stack = new CoinViewStack(this.coinView); CachedCoinView cache = stack.Find <CachedCoinView>(); var stats = new ConsensusStats(stack, this.coinView, this.consensusLoop, this.chainState, this.chain, this.connectionManager, this.loggerFactory); ChainedBlock lastTip = this.consensusLoop.Tip; foreach (BlockResult block in this.consensusLoop.Execute(cancellationToken)) { if (this.consensusLoop.Tip.FindFork(lastTip) != lastTip) { this.logger.LogInformation("Reorg detected, rewinding from '{0}' to '{1}'.", lastTip.HashBlock, this.consensusLoop.Tip); } lastTip = this.consensusLoop.Tip; cancellationToken.ThrowIfCancellationRequested(); if (block.Error != null) { this.logger.LogError("Block rejected: {0}", block.Error.Message); // Pull again. this.consensusLoop.Puller.SetLocation(this.consensusLoop.Tip); if (block.Error == ConsensusErrors.BadWitnessNonceSize) { this.logger.LogInformation("You probably need witness information, activating witness requirement for peers."); this.connectionManager.AddDiscoveredNodesRequirement(NodeServices.NODE_WITNESS); this.consensusLoop.Puller.RequestOptions(TransactionOptions.Witness); continue; } // Set the PoW chain back to ConsensusLoop.Tip. this.chain.SetTip(this.consensusLoop.Tip); // Since ChainHeadersBehavior check PoW, MarkBlockInvalid can't be spammed. this.logger.LogError("Marking block as invalid."); this.chainState.MarkBlockInvalid(block.Block.GetHash()); } if (block.Error == null) { this.chainState.HighestValidatedPoW = this.consensusLoop.Tip; // We really want to flush if we are at the top of the chain. // Otherwise, we just allow the flush to happen if it is needed. bool forceFlush = this.chain.Tip.HashBlock == block.ChainedBlock?.HashBlock; this.consensusLoop.FlushAsync(forceFlush).GetAwaiter().GetResult(); this.signals.SignalBlock(block.Block); } // TODO: Replace this with a signalling object. if (stats.CanLog) { stats.Log(); } } } catch (Exception ex) { if (ex is OperationCanceledException) { if (this.nodeLifetime.ApplicationStopping.IsCancellationRequested) { return(Task.FromException(ex)); } } // TODO Need to revisit unhandled exceptions in a way that any process can signal an exception has been // thrown so that the node and all the disposables can stop gracefully. this.logger.LogDebug("Exception occurred in consensus loop: {0}", ex.ToString()); this.logger.LogCritical(new EventId(0), ex, "Consensus loop at Tip:{0} unhandled exception {1}", this.consensusLoop.Tip?.Height, ex.ToString()); NLog.LogManager.Flush(); throw; } return(Task.CompletedTask); }
private void RunLoop() { try { var stack = new CoinViewStack(this.coinView); var cache = stack.Find <CachedCoinView>(); var stats = new ConsensusStats(stack, this.coinView, this.consensusLoop, this.chainState, this.chain, this.connectionManager, this.loggerFactory); var cancellationToken = this.nodeLifetime.ApplicationStopping; ChainedBlock lastTip = this.consensusLoop.Tip; foreach (var block in this.consensusLoop.Execute(cancellationToken)) { if (this.consensusLoop.Tip.FindFork(lastTip) != lastTip) { this.logger.LogInformation("Reorg detected, rewinding from " + lastTip.Height + " (" + lastTip.HashBlock + ") to " + this.consensusLoop.Tip.Height + " (" + this.consensusLoop.Tip.HashBlock + ")"); } lastTip = this.consensusLoop.Tip; cancellationToken.ThrowIfCancellationRequested(); if (block.Error != null) { this.logger.LogError("Block rejected: " + block.Error.Message); //Pull again this.consensusLoop.Puller.SetLocation(this.consensusLoop.Tip); if (block.Error == ConsensusErrors.BadWitnessNonceSize) { this.logger.LogInformation("You probably need witness information, activating witness requirement for peers."); this.connectionManager.AddDiscoveredNodesRequirement(NodeServices.NODE_WITNESS); this.consensusLoop.Puller.RequestOptions(TransactionOptions.Witness); continue; } //Set the PoW chain back to ConsensusLoop.Tip this.chain.SetTip(this.consensusLoop.Tip); //Since ChainHeadersBehavior check PoW, MarkBlockInvalid can't be spammed this.logger.LogError("Marking block as invalid"); this.chainState.MarkBlockInvalid(block.Block.GetHash()); } if (block.Error == null) { this.chainState.HighestValidatedPoW = this.consensusLoop.Tip; if (this.chain.Tip.HashBlock == block.ChainedBlock?.HashBlock) { this.consensusLoop.FlushAsync(); } this.signals.SignalBlock(block.Block); } // TODO: replace this with a signalling object if (stats.CanLog) { stats.Log(); } } } catch (Exception ex) { if (ex is OperationCanceledException) { if (this.nodeLifetime.ApplicationStopping.IsCancellationRequested) { return; } } // TODO Need to revisit unhandled exceptions in a way that any process can signal an exception has been // thrown so that the node and all the disposables can stop gracefully. this.logger.LogCritical(new EventId(0), ex, "Consensus loop unhandled exception (Tip:" + this.consensusLoop.Tip?.Height + ")"); throw; } }
public void ValidSomeBlocks() { using (NodeContext ctx = NodeContext.Create(network: Network.Main, clean: false)) { var network = ctx.Network; var chain = new ConcurrentChain(network.GetGenesis().Header); if (network == NBitcoin.Network.Main) { chain.Load(GetFile("main.data", "https://aois.blob.core.windows.net/public/main.data")); } else { chain.Load(GetFile("test.data", "https://aois.blob.core.windows.net/public/test.data")); } //var threads = new CustomThreadPoolTaskScheduler(10, 100, "Parallel Coin Fetcher"); var stack = new CoinViewStack( new CacheCoinView( // PrefetcherCoinView( //new ParallelCoinView(threads, new BackgroundCommiterCoinView( ctx.PersistentCoinView))); //); //new InMemoryCoinView(chain.Genesis)); var bottom = stack.Bottom; var cache = stack.Find <CacheCoinView>(); var backgroundCommiter = stack.Find <BackgroundCommiterCoinView>(); ConsensusValidator valid = new ConsensusValidator(network.Consensus); valid.UseConsensusLib = false; Node node = Node.Connect(network, "yournode"); node.VersionHandshake(); var puller = new CustomNodeBlockPuller(chain, node); var lastSnapshot = valid.PerformanceCounter.Snapshot(); var lastSnapshot2 = ctx.PersistentCoinView.PerformanceCounter.Snapshot(); var lastSnapshot3 = cache == null ? null : cache.PerformanceCounter.Snapshot(); foreach (var block in valid.Run(stack, puller)) { if ((DateTimeOffset.UtcNow - lastSnapshot.Taken) > TimeSpan.FromSeconds(5.0)) { Console.WriteLine(); Console.WriteLine("ActualLookahead :\t" + puller.ActualLookahead + " blocks"); Console.WriteLine("Median Downloaded :\t" + puller.MedianDownloadCount + " blocks"); if (backgroundCommiter != null) { Console.WriteLine("CoinViewTip :\t" + backgroundCommiter.Tip.Height); Console.WriteLine("CommitingTip :\t" + backgroundCommiter.CommitingTip.Height); } Console.WriteLine("Bottom Tip :\t" + bottom.Tip.Height); if (cache != null) { Console.WriteLine("Cache entries :\t" + cache.CacheEntryCount); } var snapshot = valid.PerformanceCounter.Snapshot(); Console.Write(snapshot - lastSnapshot); lastSnapshot = snapshot; var snapshot2 = ctx.PersistentCoinView.PerformanceCounter.Snapshot(); Console.Write(snapshot2 - lastSnapshot2); lastSnapshot2 = snapshot2; if (cache != null) { var snapshot3 = cache.PerformanceCounter.Snapshot(); Console.Write(snapshot3 - lastSnapshot3); lastSnapshot3 = snapshot3; } } } } }
void RunLoop() { try { var stack = new CoinViewStack(CoinView); var cache = stack.Find <CachedCoinView>(); var stats = new ConsensusStats(this, stack); var cancellationToken = this.GlobalCancellation.Cancellation.Token; ChainedBlock lastTip = ConsensusLoop.Tip; foreach (var block in ConsensusLoop.Execute(cancellationToken)) { bool reorg = false; if (ConsensusLoop.Tip.FindFork(lastTip) != lastTip) { reorg = true; Logs.FullNode.LogInformation("Reorg detected, rewinding from " + lastTip.Height + " (" + lastTip.HashBlock + ") to " + ConsensusLoop.Tip.Height + " (" + ConsensusLoop.Tip.HashBlock + ")"); } lastTip = ConsensusLoop.Tip; cancellationToken.ThrowIfCancellationRequested(); if (block.Error != null) { Logs.FullNode.LogError("Block rejected: " + block.Error.Message); //Pull again ConsensusLoop.Puller.SetLocation(ConsensusLoop.Tip); if (block.Error == ConsensusErrors.BadWitnessNonceSize) { Logs.FullNode.LogInformation("You probably need witness information, activating witness requirement for peers."); ConnectionManager.AddDiscoveredNodesRequirement(NodeServices.NODE_WITNESS); ConsensusLoop.Puller.RequestOptions(TransactionOptions.Witness); continue; } //Set the PoW chain back to ConsensusLoop.Tip Chain.SetTip(ConsensusLoop.Tip); //Since ChainBehavior check PoW, MarkBlockInvalid can't be spammed Logs.FullNode.LogError("Marking block as invalid"); _ChainBehaviorState.MarkBlockInvalid(block.ChainedBlock.HashBlock); } if (!reorg && block.Error == null) { _ChainBehaviorState.HighestValidatedPoW = ConsensusLoop.Tip; if (Chain.Tip.HashBlock == block.ChainedBlock?.HashBlock) { var unused = cache.FlushAsync(); } this.Signals.Blocks.Broadcast(block.Block); } // TODO: replace this with a signalling object if (stats.CanLog) { stats.Log(); } } } catch (Exception ex) //TODO: Barbaric clean exit { if (ex is OperationCanceledException) { if (this.GlobalCancellation.Cancellation.IsCancellationRequested) { return; } } if (!IsDisposed) { Logs.FullNode.LogCritical(new EventId(0), ex, "Consensus loop unhandled exception (Tip:" + ConsensusLoop.Tip?.Height + ")"); _UncatchedException = ex; Dispose(); } } }