예제 #1
0
        public BlockRequestWorker(Logger logger, WorkerConfig workerConfig, LocalClient localClient, CoreDaemon blockchainDaemon, ChainedHeaderCache chainedHeaderCache, BlockCache blockCache)
            : base("BlockRequestWorker", workerConfig.initialNotify, workerConfig.minIdleTime, workerConfig.maxIdleTime, logger)
        {
            this.logger             = logger;
            this.localClient        = localClient;
            this.blockchainDaemon   = blockchainDaemon;
            this.chainedHeaderCache = chainedHeaderCache;
            this.blockCache         = blockCache;

            this.allBlockRequests    = new ConcurrentDictionary <UInt256, DateTime>();
            this.blockRequestsByPeer = new ConcurrentDictionary <IPEndPoint, ConcurrentDictionary <UInt256, DateTime> >();
            this.missingBlockQueue   = new SortedList <int, ChainedHeader>();

            this.localClient.OnBlock += HandleBlock;
            this.blockchainDaemon.OnChainStateChanged  += HandleChainStateChanged;
            this.blockchainDaemon.OnTargetChainChanged += HandleTargetChainChanged;
            this.blockCache.OnMissing += HandleBlockMissing;

            this.blockRequestDurationMeasure       = new DurationMeasure(sampleCutoff: TimeSpan.FromMinutes(5));
            this.blockDownloadRateMeasure          = new RateMeasure();
            this.duplicateBlockDownloadRateMeasure = new RateMeasure();

            this.targetChainLookAhead         = 1;
            this.criticalTargetChainLookAhead = 1;

            this.flushWorker = new WorkerMethod("BlockRequestWorker.FlushWorker", FlushWorkerMethod, initialNotify: true, minIdleTime: TimeSpan.Zero, maxIdleTime: TimeSpan.MaxValue, logger: this.logger);
            this.flushQueue  = new ConcurrentQueue <Tuple <RemoteNode, Block> >();
        }
예제 #2
0
        public BlockRequestWorker(WorkerConfig workerConfig, Logger logger, LocalClient localClient, CoreDaemon coreDaemon)
            : base("BlockRequestWorker", workerConfig.initialNotify, workerConfig.minIdleTime, workerConfig.maxIdleTime, logger)
        {
            this.logger      = logger;
            this.localClient = localClient;
            this.coreDaemon  = coreDaemon;
            this.coreStorage = coreDaemon.CoreStorage;

            this.allBlockRequests    = new ConcurrentDictionary <UInt256, BlockRequest>();
            this.blockRequestsByPeer = new ConcurrentDictionary <Peer, ConcurrentDictionary <UInt256, DateTime> >();
            this.missedBlockRequests = new ConcurrentDictionary <UInt256, BlockRequest>();

            this.localClient.OnBlock             += HandleBlock;
            this.coreDaemon.OnChainStateChanged  += HandleChainStateChanged;
            this.coreDaemon.OnTargetChainChanged += HandleTargetChainChanged;
            this.coreStorage.BlockTxesMissed     += HandleBlockTxesMissed;
            this.coreDaemon.BlockMissed          += HandleBlockMissed;

            this.blockRequestDurationMeasure        = new DurationMeasure(sampleCutoff: TimeSpan.FromMinutes(5));
            this.blockDownloadRateMeasure           = new RateMeasure();
            this.duplicateBlockDownloadCountMeasure = new CountMeasure(TimeSpan.FromSeconds(30));

            this.targetChainQueue      = new List <ChainedHeader>();
            this.targetChainQueueIndex = 0;
            this.targetChainLookAhead  = 1;

            this.flushWorker = new WorkerMethod("BlockRequestWorker.FlushWorker", FlushWorkerMethod, initialNotify: true, minIdleTime: TimeSpan.Zero, maxIdleTime: TimeSpan.MaxValue, logger: this.logger);
            this.flushQueue  = new ConcurrentQueue <FlushBlock>();
            this.flushBlocks = new ConcurrentSet <UInt256>();

            this.diagnosticWorker = new WorkerMethod("BlockRequestWorker.DiagnosticWorker", DiagnosticWorkerMethod, initialNotify: true, minIdleTime: TimeSpan.FromSeconds(10), maxIdleTime: TimeSpan.FromSeconds(10), logger: this.logger);
        }
예제 #3
0
 private void StatsWorker(WorkerMethod instance)
 {
     this.logger.Info(
         "UNCONNECTED: {0,3}, PENDING: {1,3}, CONNECTED: {2,3}, BAD: {3,3}, INCOMING: {4,3}, MESSAGES/SEC: {5,6:#,##0}".Format2(
             /*0*/ this.peerWorker.UnconnectedPeersCount,
             /*1*/ this.peerWorker.PendingPeers.Count,
             /*2*/ this.peerWorker.ConnectedPeers.Count,
             /*3*/ this.peerWorker.BadPeers.Count,
             /*4*/ this.peerWorker.IncomingCount,
             /*5*/ this.messageRateMeasure.GetAverage(TimeSpan.FromSeconds(1))));
 }
예제 #4
0
        private Task GcWorker(WorkerMethod instance)
        {
            logger.Info(
                string.Join("\n",
                            new string('-', 80),
                            $"GC Memory:      {(float)GC.GetTotalMemory(false) / 1.MILLION(),10:N2} MB",
                            $"Process Memory: {(float)Process.GetCurrentProcess().PrivateMemorySize64 / 1.MILLION(),10:N2} MB",
                            new string('-', 80)
                            ));

            return(Task.CompletedTask);
        }
예제 #5
0
        public CoreDaemon(ICoreRules rules, IStorageManager storageManager)
        {
            this.rules          = rules;
            this.storageManager = storageManager;
            coreStorage         = new CoreStorage(storageManager);

            // create chain state builder
            chainStateBuilder = new ChainStateBuilder(this.rules, coreStorage, this.storageManager);

            // create unconfirmed txes builder
            unconfirmedTxesBuilder = new UnconfirmedTxesBuilder(this, coreStorage, this.storageManager);

            // create workers
            targetChainWorker = new TargetChainWorker(
                new WorkerConfig(initialNotify: true, minIdleTime: TimeSpan.FromMilliseconds(0), maxIdleTime: TimeSpan.FromSeconds(30)),
                ChainParams, coreStorage);

            chainStateWorker = new ChainStateWorker(
                new WorkerConfig(initialNotify: true, minIdleTime: TimeSpan.FromMilliseconds(0), maxIdleTime: TimeSpan.FromSeconds(5)),
                targetChainWorker, chainStateBuilder, this.rules, coreStorage);

            unconfirmedTxesWorker = new UnconfirmedTxesWorker(
                new WorkerConfig(initialNotify: true, minIdleTime: TimeSpan.FromMilliseconds(0), maxIdleTime: TimeSpan.FromSeconds(5)),
                chainStateWorker, unconfirmedTxesBuilder, coreStorage);

            pruningWorker = new PruningWorker(
                new WorkerConfig(initialNotify: true, minIdleTime: TimeSpan.FromSeconds(0), maxIdleTime: TimeSpan.FromMinutes(5)),
                this, this.storageManager, chainStateWorker);

            defragWorker = new DefragWorker(
                new WorkerConfig(initialNotify: true, minIdleTime: TimeSpan.FromMinutes(5), maxIdleTime: TimeSpan.FromMinutes(5)),
                this.storageManager);

            gcWorker = new WorkerMethod("GC Worker", GcWorker,
                                        initialNotify: true, minIdleTime: TimeSpan.FromMinutes(5), maxIdleTime: TimeSpan.FromMinutes(5));

            utxoScanWorker = new WorkerMethod("UTXO Scan Worker", UtxoScanWorker,
                                              initialNotify: true, minIdleTime: TimeSpan.FromSeconds(60), maxIdleTime: TimeSpan.FromSeconds(60));

            statsWorker = new StatsWorker(
                new WorkerConfig(initialNotify: true, minIdleTime: TimeSpan.FromMinutes(0), maxIdleTime: TimeSpan.MaxValue),
                this);

            // wire events
            chainStateWorker.BlockMissed              += HandleBlockMissed;
            targetChainWorker.OnTargetChainChanged    += HandleTargetChainChanged;
            chainStateWorker.OnChainStateChanged      += HandleChainStateChanged;
            pruningWorker.OnWorkFinished              += defragWorker.NotifyWork;
            unconfirmedTxesBuilder.UnconfirmedTxAdded += RaiseUnconfirmedTxAdded;
            unconfirmedTxesBuilder.TxesConfirmed      += RaiseTxesConfirmed;
            unconfirmedTxesBuilder.TxesUnconfirmed    += RaiseTxesUnconfirmed;
        }
예제 #6
0
        public LocalClient(ChainType type, IKernel kernel, CoreDaemon coreDaemon, INetworkPeerStorage networkPeerStorage)
        {
            this.shutdownToken = new CancellationTokenSource();

            this.type               = type;
            this.kernel             = kernel;
            this.coreDaemon         = coreDaemon;
            this.chainParams        = coreDaemon.ChainParams;
            this.coreStorage        = coreDaemon.CoreStorage;
            this.networkPeerStorage = networkPeerStorage;

            this.messageRateMeasure = new RateMeasure();

            this.headersRequestWorker = new HeadersRequestWorker(
                new WorkerConfig(initialNotify: true, minIdleTime: TimeSpan.FromMilliseconds(50), maxIdleTime: TimeSpan.FromSeconds(5)),
                this, this.coreDaemon);

            this.blockRequestWorker = new BlockRequestWorker(
                new WorkerConfig(initialNotify: true, minIdleTime: TimeSpan.FromMilliseconds(50), maxIdleTime: TimeSpan.FromSeconds(30)),
                this, this.coreDaemon);

            this.peerWorker = new PeerWorker(
                new WorkerConfig(initialNotify: true, minIdleTime: TimeSpan.FromSeconds(1), maxIdleTime: TimeSpan.FromSeconds(1)),
                this, this.coreDaemon, this.headersRequestWorker);

            this.listenWorker = new ListenWorker(this, this.peerWorker);

            this.statsWorker = new WorkerMethod("LocalClient.StatsWorker", StatsWorker, true, TimeSpan.FromSeconds(5), TimeSpan.FromMinutes(5));

            this.peerWorker.PeerHandshakeCompleted += HandlePeerHandshakeCompleted;
            this.peerWorker.PeerDisconnected       += HandlePeerDisconnected;

            this.blockRequestWorker.OnBlockFlushed += HandleBlockFlushed;

            switch (this.Type)
            {
            case ChainType.MainNet:
                Messaging.Port  = 8333;
                Messaging.Magic = Messaging.MAGIC_MAIN;
                break;

            case ChainType.TestNet3:
                Messaging.Port  = 18333;
                Messaging.Magic = Messaging.MAGIC_TESTNET3;
                break;

            case ChainType.Regtest:
                Messaging.Port  = 18444;
                Messaging.Magic = Messaging.MAGIC_COMPARISON_TOOL;
                break;
            }
        }
예제 #7
0
        private Task StatsWorker(WorkerMethod instance)
        {
            logger.Info(string.Join(", ",
                                    $"UNCONNECTED: {this.peerWorker.UnconnectedPeersCount,3}",
                                    $"PENDING: {this.peerWorker.PendingPeers.Count,3}",
                                    $"CONNECTED: {this.peerWorker.ConnectedPeers.Count,3}",
                                    $"BAD: {this.peerWorker.BadPeers.Count,3}",
                                    $"INCOMING: {this.peerWorker.IncomingCount,3}",
                                    $"MESSAGES/SEC: {this.messageRateMeasure.GetAverage(),6:N0}"
                                    ));

            return(Task.CompletedTask);
        }
예제 #8
0
        public MainWindowViewModel(IKernel kernel, WalletMonitor walletMonitor = null)
        {
            this.kernel        = kernel;
            coreDaemon         = kernel.Get <CoreDaemon>();
            coreStorage        = coreDaemon.CoreStorage;
            localClient        = kernel.Get <LocalClient>();
            this.walletMonitor = walletMonitor;

            startTime              = DateTimeOffset.Now;
            runningTimeTimer       = new DispatcherTimer();
            runningTimeTimer.Tick += (sender, e) =>
            {
                var runningTime = (DateTimeOffset.Now - startTime);
                RunningTime = $"{Math.Floor(runningTime.TotalHours):#,#00}:{runningTime:mm':'ss}";
            };
            runningTimeTimer.Interval = TimeSpan.FromMilliseconds(100);
            runningTimeTimer.Start();

            WinningBlockchainHeight = -1;
            CurrentBlockchainHeight = -1;
            DownloadedBlockCount    = -1;
            WalletHeight            = -1;

            updateWorker = new WorkerMethod("",
                                            _ =>
            {
                WinningBlockchainHeight = coreDaemon.TargetChainHeight;
                CurrentBlockchainHeight = coreDaemon.CurrentChain.Height;
                DownloadedBlockCount    = coreStorage.BlockWithTxesCount;

                BlockRate       = coreDaemon.GetBlockRate();
                TransactionRate = coreDaemon.GetTxRate();
                InputRate       = coreDaemon.GetInputRate();

                BlockDownloadRate           = localClient.GetBlockDownloadRate();
                DuplicateBlockDownloadCount = localClient.GetDuplicateBlockDownloadCount();
                BlockMissCount = localClient.GetBlockMissCount();

                if (walletMonitor != null)
                {
                    WalletHeight       = this.walletMonitor.WalletHeight;
                    WalletEntriesCount = this.walletMonitor.EntriesCount;
                    BitBalance         = this.walletMonitor.BitBalance;
                    BtcBalance         = this.walletMonitor.BtcBalance;
                }

                return(Task.CompletedTask);
            },
                                            initialNotify: true, minIdleTime: TimeSpan.FromSeconds(1), maxIdleTime: TimeSpan.FromSeconds(1));
            updateWorker.Start();
        }
예제 #9
0
        public LocalClient(Logger logger, RulesEnum type, IKernel kernel, IBlockchainRules rules, CoreDaemon coreDaemon, NetworkPeerCache networkPeerCache)
        {
            this.shutdownToken = new CancellationTokenSource();

            this.logger           = logger;
            this.type             = type;
            this.kernel           = kernel;
            this.rules            = rules;
            this.coreDaemon       = coreDaemon;
            this.coreStorage      = coreDaemon.CoreStorage;
            this.networkPeerCache = networkPeerCache;

            this.messageRateMeasure = new RateMeasure();

            this.peerWorker = new PeerWorker(
                new WorkerConfig(initialNotify: true, minIdleTime: TimeSpan.FromSeconds(1), maxIdleTime: TimeSpan.FromSeconds(1)),
                this.logger, this, this.coreDaemon);

            this.listenWorker = new ListenWorker(this.logger, this, this.peerWorker);

            this.headersRequestWorker = new HeadersRequestWorker(
                new WorkerConfig(initialNotify: true, minIdleTime: TimeSpan.FromMilliseconds(50), maxIdleTime: TimeSpan.FromSeconds(5)),
                this.logger, this, this.coreDaemon);

            this.blockRequestWorker = new BlockRequestWorker(
                new WorkerConfig(initialNotify: true, minIdleTime: TimeSpan.FromMilliseconds(50), maxIdleTime: TimeSpan.FromSeconds(30)),
                this.logger, this, this.coreDaemon);

            this.statsWorker = new WorkerMethod("LocalClient.StatsWorker", StatsWorker, true, TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(30), this.logger);

            this.peerWorker.PeerConnected    += HandlePeerConnected;
            this.peerWorker.PeerDisconnected += HandlePeerDisconnected;

            switch (this.Type)
            {
            case RulesEnum.MainNet:
                Messaging.Port  = 8333;
                Messaging.Magic = Messaging.MAGIC_MAIN;
                break;

            case RulesEnum.TestNet3:
                Messaging.Port  = 18333;
                Messaging.Magic = Messaging.MAGIC_TESTNET3;
                break;

            case RulesEnum.ComparisonToolTestNet:
                Messaging.Port  = 18444;
                Messaging.Magic = Messaging.MAGIC_COMPARISON_TOOL;
                break;
            }
        }
예제 #10
0
        public HeadersRequestWorker(WorkerConfig workerConfig, LocalClient localClient, CoreDaemon coreDaemon)
            : base("HeadersRequestWorker", workerConfig.initialNotify, workerConfig.minIdleTime, workerConfig.maxIdleTime)
        {
            this.localClient = localClient;
            this.coreDaemon  = coreDaemon;
            this.coreStorage = coreDaemon.CoreStorage;

            this.headersRequestsByPeer = new ConcurrentDictionary <Peer, DateTimeOffset>();

            this.localClient.OnBlockHeaders      += HandleBlockHeaders;
            this.coreDaemon.OnTargetChainChanged += HandleTargetChainChanged;

            this.flushWorker = new WorkerMethod("HeadersRequestWorker.FlushWorker", FlushWorkerMethod, initialNotify: true, minIdleTime: TimeSpan.Zero, maxIdleTime: TimeSpan.MaxValue);
            this.flushQueue  = new ConcurrentQueue <FlushHeaders>();
        }
예제 #11
0
 private void DiagnosticWorkerMethod(WorkerMethod instance)
 {
     this.logger.Info(new string('-', 80));
     this.logger.Info("allBlockRequests.Count: {0:#,##0}".Format2(this.allBlockRequests.Count));
     this.logger.Info("blockRequestsByPeer.InnerCount: {0:#,##0}".Format2(this.blockRequestsByPeer.Sum(x => x.Value.Count)));
     this.logger.Info("targetChainQueue.Count: {0:#,##0}".Format2(this.targetChainQueue.Count));
     this.logger.Info("targetChainQueueIndex: {0:#,##0}".Format2(this.targetChainQueueIndex));
     this.logger.Info("targetChainQueueTime: {0}".Format2(this.targetChainQueueTime));
     this.logger.Info("blockRequestDurationMeasure: {0}".Format2(this.blockRequestDurationMeasure.GetAverage()));
     this.logger.Info("blockDownloadRateMeasure: {0}/s".Format2(this.blockDownloadRateMeasure.GetAverage(TimeSpan.FromSeconds(1))));
     this.logger.Info("duplicateBlockDownloadCountMeasure: {0}/s".Format2(this.duplicateBlockDownloadCountMeasure.GetCount()));
     this.logger.Info("targetChainLookAhead: {0}".Format2(this.targetChainLookAhead));
     this.logger.Info("flushQueue.Count: {0}".Format2(this.flushQueue.Count));
     this.logger.Info("flushBlocks.Count: {0}".Format2(this.flushBlocks.Count));
 }
예제 #12
0
        private void FlushWorkerMethod(WorkerMethod instance)
        {
            var initalCount = this.flushQueue.Count;
            var count       = 0;

            FlushBlock flushBlock;

            while (this.flushQueue.TryDequeue(out flushBlock))
            {
                // cooperative loop
                this.ThrowIfCancelled();

                var peer  = flushBlock.Peer;
                var block = flushBlock.Block;

                if (this.coreStorage.TryAddBlock(block))
                {
                    this.blockDownloadRateMeasure.Tick();
                }
                else
                {
                    this.duplicateBlockDownloadCountMeasure.Tick();
                }

                this.flushBlocks.Remove(block.Hash);

                BlockRequest blockRequest;
                this.allBlockRequests.TryRemove(block.Hash, out blockRequest);

                DateTime requestTime;
                ConcurrentDictionary <UInt256, DateTime> peerBlockRequests;
                if (this.blockRequestsByPeer.TryGetValue(peer, out peerBlockRequests) &&
                    peerBlockRequests.TryRemove(block.Hash, out requestTime))
                {
                    this.blockRequestDurationMeasure.Tick(DateTime.UtcNow - requestTime);
                }

                this.NotifyWork();

                count++;
                if (count > initalCount)
                {
                    break;
                }
            }

            //this.blockCache.Flush();
        }
예제 #13
0
        public HeadersRequestWorker(Logger logger, WorkerConfig workerConfig, LocalClient localClient, CoreDaemon blockchainDaemon, BlockHeaderCache blockHeaderCache)
            : base("HeadersRequestWorker", workerConfig.initialNotify, workerConfig.minIdleTime, workerConfig.maxIdleTime, logger)
        {
            this.logger           = logger;
            this.localClient      = localClient;
            this.blockchainDaemon = blockchainDaemon;
            this.blockHeaderCache = blockHeaderCache;

            this.headersRequestsByPeer = new ConcurrentDictionary <IPEndPoint, DateTime>();

            this.localClient.OnBlockHeaders            += HandleBlockHeaders;
            this.blockchainDaemon.OnTargetChainChanged += HandleTargetChainChanged;

            this.flushWorker = new WorkerMethod("HeadersRequestWorker.FlushWorker", FlushWorkerMethod, initialNotify: true, minIdleTime: TimeSpan.Zero, maxIdleTime: TimeSpan.MaxValue, logger: this.logger);
            this.flushQueue  = new ConcurrentQueue <Tuple <RemoteNode, IImmutableList <BlockHeader> > >();
        }
예제 #14
0
        private Task DiagnosticWorkerMethod(WorkerMethod instance)
        {
            logger.Info(new string('-', 80));
            logger.Info($"allBlockRequests.Count: {this.allBlockRequests.Count:N0}");
            logger.Info($"blockRequestsByPeer.InnerCount: {this.blockRequestsByPeer.Sum(x => x.Value.Count):N0}");
            logger.Info($"targetChainQueue.Count: {this.targetChainQueue.Count:N0}");
            logger.Info($"targetChainQueueIndex: {this.targetChainQueueIndex:N0}");
            logger.Info($"blockRequestDurationMeasure: {this.blockRequestDurationMeasure.GetAverage()}");
            logger.Info($"blockDownloadRateMeasure: {this.blockDownloadRateMeasure.GetAverage()}/s");
            logger.Info($"duplicateBlockDownloadCountMeasure: {this.duplicateBlockDownloadCountMeasure.GetCount()}/s");
            logger.Info($"targetChainLookAhead: {this.targetChainLookAhead}");
            logger.Info($"flushQueue.Count: {this.flushQueue.Count}");
            logger.Info($"flushBlocks.Count: {this.flushBlocks.Count}");

            return(Task.CompletedTask);
        }
예제 #15
0
        public LocalClient(Logger logger, RulesEnum type, IKernel kernel, IBlockchainRules rules, CoreDaemon blockchainDaemon, BlockHeaderCache blockHeaderCache, ChainedHeaderCache chainedHeaderCache, TransactionCache transactionCache, BlockCache blockCache, NetworkPeerCache networkPeerCache)
        {
            this.shutdownToken = new CancellationTokenSource();

            this.logger             = logger;
            this.type               = type;
            this.kernel             = kernel;
            this.rules              = rules;
            this.blockchainDaemon   = blockchainDaemon;
            this.blockHeaderCache   = blockHeaderCache;
            this.chainedHeaderCache = chainedHeaderCache;
            this.transactionCache   = transactionCache;
            this.blockCache         = blockCache;
            this.networkPeerCache   = networkPeerCache;

            this.messageRateMeasure = new RateMeasure();

            this.connectWorker        = new WorkerMethod("LocalClient.ConnectWorker", ConnectWorker, true, TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1), this.logger);
            this.headersRequestWorker = kernel.Get <HeadersRequestWorker>(
                new ConstructorArgument("workerConfig", new WorkerConfig(initialNotify: true, minIdleTime: TimeSpan.FromMilliseconds(50), maxIdleTime: TimeSpan.FromSeconds(30))),
                new ConstructorArgument("localClient", this));
            this.blockRequestWorker = kernel.Get <BlockRequestWorker>(
                new ConstructorArgument("workerConfig", new WorkerConfig(initialNotify: true, minIdleTime: TimeSpan.FromMilliseconds(50), maxIdleTime: TimeSpan.FromSeconds(30))),
                new ConstructorArgument("localClient", this));
            this.statsWorker = new WorkerMethod("LocalClient.StatsWorker", StatsWorker, true, TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(30), this.logger);

            switch (this.Type)
            {
            case RulesEnum.MainNet:
                Messaging.Port  = 8333;
                Messaging.Magic = Messaging.MAGIC_MAIN;
                break;

            case RulesEnum.TestNet3:
                Messaging.Port  = 18333;
                Messaging.Magic = Messaging.MAGIC_TESTNET3;
                break;

            case RulesEnum.ComparisonToolTestNet:
                Messaging.Port  = 18444;
                Messaging.Magic = Messaging.MAGIC_COMPARISON_TOOL;
                break;
            }
        }
예제 #16
0
        private Task UtxoScanWorker(WorkerMethod instance)
        {
            // time taking chain state snapshots
            var stopwatch = Stopwatch.StartNew();
            int chainStateHeight;

            using (var chainState = GetChainState())
            {
                chainStateHeight = chainState.Chain.Height;
            }
            stopwatch.Stop();
            logger.Info($"GetChainState at {chainStateHeight:N0}: {stopwatch.Elapsed.TotalSeconds:N2}s");

            // time enumerating chain state snapshots
            stopwatch = Stopwatch.StartNew();
            using (var chainState = GetChainState())
            {
                chainStateHeight = chainState.Chain.Height;
                chainState.ReadUnspentTransactions().Count();
            }
            stopwatch.Stop();
            logger.Info($"Enumerate chain state at {chainStateHeight:N0}: {stopwatch.Elapsed.TotalSeconds:N2}s");

            //using (var chainStateLocal = this.GetChainState())
            //{
            //    new MethodTimer(logger).Time("UTXO Commitment: {0:N0}".Format2(chainStateLocal.UnspentTxCount), () =>
            //    {
            //        using (var utxoStream = new UtxoStream(logger, chainStateLocal.ReadUnspentTransactions()))
            //        {
            //            var utxoHash = SHA256Pool.ComputeHash(utxoStream);
            //            logger.Info("UXO Commitment Hash: {0}".Format2(utxoHash.ToHexNumberString()));
            //        }
            //    });

            //    //new MethodTimer().Time("Full UTXO Scan: {0:N0}".Format2(chainStateLocal.Utxo.TransactionCount), () =>
            //    //{
            //    //    foreach (var output in chainStateLocal.Utxo.GetUnspentTransactions())
            //    //    {
            //    //    }
            //    //});
            //}

            return(Task.CompletedTask);
        }
예제 #17
0
        private void FlushWorkerMethod(WorkerMethod instance)
        {
            FlushHeaders flushHeaders;

            while (this.flushQueue.TryDequeue(out flushHeaders))
            {
                // cooperative loop
                this.ThrowIfCancelled();

                var peer         = flushHeaders.Peer;
                var blockHeaders = flushHeaders.Headers;

                // chain the downloaded headers
                this.coreStorage.ChainHeaders(blockHeaders);

                DateTime ignore;
                this.headersRequestsByPeer.TryRemove(peer, out ignore);
            }
        }
예제 #18
0
        public BlockRequestWorker(WorkerConfig workerConfig, LocalClient localClient, CoreDaemon coreDaemon)
            : base("BlockRequestWorker", workerConfig.initialNotify, workerConfig.minIdleTime, workerConfig.maxIdleTime)
        {
            this.localClient = localClient;
            this.coreDaemon  = coreDaemon;
            this.coreStorage = coreDaemon.CoreStorage;

            this.allBlockRequests    = new ConcurrentDictionary <UInt256, BlockRequest>();
            this.blockRequestsByPeer = new ConcurrentDictionary <Peer, ConcurrentDictionary <UInt256, DateTimeOffset> >();
            this.missedBlockRequests = new ConcurrentDictionary <UInt256, BlockRequest>();

            this.localClient.OnBlock             += HandleBlock;
            this.coreDaemon.OnChainStateChanged  += HandleChainStateChanged;
            this.coreDaemon.OnTargetChainChanged += HandleTargetChainChanged;
            this.coreDaemon.BlockMissed          += HandleBlockMissed;

            this.blockRequestDurationMeasure        = new DurationMeasure(sampleCutoff: TimeSpan.FromMinutes(5));
            this.blockDownloadRateMeasure           = new RateMeasure();
            this.duplicateBlockDownloadCountMeasure = new CountMeasure(TimeSpan.FromSeconds(30));

            this.targetChainQueue      = new List <ChainedHeader>();
            this.targetChainQueueIndex = 0;
            this.targetChainLookAhead  = 1;

            this.flushWorker = new ActionBlock <FlushBlock>((Action <FlushBlock>)FlushWorkerMethod,
                                                            new ExecutionDataflowBlockOptions {
                MaxDegreeOfParallelism = Environment.ProcessorCount
            });
            this.flushQueue  = new BufferBlock <FlushBlock>();
            this.flushBlocks = new ConcurrentSet <UInt256>();
            this.flushQueue.LinkTo(this.flushWorker, new DataflowLinkOptions {
                PropagateCompletion = true
            });

            this.diagnosticWorker = new WorkerMethod("BlockRequestWorker.DiagnosticWorker", DiagnosticWorkerMethod, initialNotify: true, minIdleTime: TimeSpan.FromSeconds(10), maxIdleTime: TimeSpan.FromSeconds(10));
        }
예제 #19
0
        public CoreDaemon(Logger logger, IKernel kernel, IBlockchainRules rules, IStorageManager storageManager)
        {
            this.logger        = logger;
            this.shutdownToken = new CancellationTokenSource();

            this.kernel         = kernel;
            this.rules          = rules;
            this.storageManager = storageManager;
            this.coreStorage    = new CoreStorage(storageManager, logger);

            // write genesis block out to storage
            this.coreStorage.AddGenesisBlock(this.rules.GenesisChainedHeader);
            this.coreStorage.TryAddBlock(this.rules.GenesisBlock);

            // create chain state builder
            this.chainStateBuilder = new ChainStateBuilder(this.logger, this.rules, this.coreStorage);

            // add genesis block to chain state, if needed
            if (this.chainStateBuilder.Chain.Height < 0)
            {
                this.chainStateBuilder.AddBlock(this.rules.GenesisChainedHeader, this.rules.GenesisBlock.Transactions);
            }

            // create workers
            this.targetChainWorker = new TargetChainWorker(
                new WorkerConfig(initialNotify: true, minIdleTime: TimeSpan.FromMilliseconds(50), maxIdleTime: TimeSpan.FromSeconds(30)),
                this.logger, this.rules, this.coreStorage);

            this.chainStateWorker = new ChainStateWorker(
                new WorkerConfig(initialNotify: true, minIdleTime: TimeSpan.FromMilliseconds(50), maxIdleTime: TimeSpan.FromSeconds(5)),
                this.targetChainWorker, this.chainStateBuilder, this.logger, this.rules, this.coreStorage);

            this.pruningWorker = new PruningWorker(
                new WorkerConfig(initialNotify: true, minIdleTime: TimeSpan.FromSeconds(60), maxIdleTime: TimeSpan.FromMinutes(15)),
                this.coreStorage, this.chainStateWorker, this.chainStateBuilder, this.logger, this.rules);

            this.defragWorker = new DefragWorker(
                new WorkerConfig(initialNotify: true, minIdleTime: TimeSpan.FromMinutes(5), maxIdleTime: TimeSpan.FromMinutes(5)),
                this.coreStorage, this.logger);

            // notify defrag worker after pruning
            this.pruningWorker.OnWorkFinished += this.defragWorker.NotifyWork;

            this.chainStateWorker.BlockMissed += HandleBlockMissed;

            this.targetChainWorker.OnTargetChainChanged +=
                () =>
            {
                var handler = this.OnTargetChainChanged;
                if (handler != null)
                {
                    handler(this, EventArgs.Empty);
                }
            };

            this.chainStateWorker.OnChainStateChanged +=
                () =>
            {
                this.pruningWorker.NotifyWork();
                this.utxoScanWorker.NotifyWork();

                var handler = this.OnChainStateChanged;
                if (handler != null)
                {
                    handler(this, EventArgs.Empty);
                }
            };

            this.gcWorker = new WorkerMethod("GC Worker",
                                             _ =>
            {
                this.logger.Info(
                    string.Join("\n",
                                new string('-', 80),
                                "GC Memory:      {0,10:#,##0.00} MB",
                                "Process Memory: {1,10:#,##0.00} MB",
                                new string('-', 80)
                                )
                    .Format2
                    (
                        /*0*/ (float)GC.GetTotalMemory(false) / 1.MILLION(),
                        /*1*/ (float)Process.GetCurrentProcess().PrivateMemorySize64 / 1.MILLION()
                    ));
            }, initialNotify: true, minIdleTime: TimeSpan.FromSeconds(30), maxIdleTime: TimeSpan.FromSeconds(30), logger: this.logger);

            this.utxoScanWorker = new WorkerMethod("UTXO Scan Worker",
                                                   _ =>
            {
                // time taking chain state snapshots
                var stopwatch = Stopwatch.StartNew();
                int chainStateHeight;
                using (var chainState = this.GetChainState())
                {
                    chainStateHeight = chainState.Chain.Height;
                }
                stopwatch.Stop();
                this.logger.Info("GetChainState at {0:#,##0}: {1:#,##0.00}s".Format2(chainStateHeight, stopwatch.Elapsed.TotalSeconds));

                // time enumerating chain state snapshots
                stopwatch = Stopwatch.StartNew();
                using (var chainState = this.GetChainState())
                {
                    chainStateHeight = chainState.Chain.Height;
                    chainState.ReadUnspentTransactions().Count();
                }
                stopwatch.Stop();
                this.logger.Info("Enumerate chain state at {0:#,##0}: {1:#,##0.00}s".Format2(chainStateHeight, stopwatch.Elapsed.TotalSeconds));

                //using (var chainStateLocal = this.GetChainState())
                //{
                //    new MethodTimer(this.logger).Time("UTXO Commitment: {0:#,##0}".Format2(chainStateLocal.UnspentTxCount), () =>
                //    {
                //        using (var utxoStream = new UtxoStream(this.logger, chainStateLocal.ReadUnspentTransactions()))
                //        {
                //            var sha256 = new SHA256Managed();
                //            var utxoHash = sha256.ComputeHash(utxoStream);
                //            this.logger.Info("UXO Commitment Hash: {0}".Format2(utxoHash.ToHexNumberString()));
                //        }
                //    });

                //    //new MethodTimer().Time("Full UTXO Scan: {0:#,##0}".Format2(chainStateLocal.Utxo.TransactionCount), () =>
                //    //{
                //    //    var sha256 = new SHA256Managed();
                //    //    foreach (var output in chainStateLocal.Utxo.GetUnspentTransactions())
                //    //    {
                //    //    }
                //    //});
                //}
            }, initialNotify: true, minIdleTime: TimeSpan.FromSeconds(60), maxIdleTime: TimeSpan.FromSeconds(60), logger: this.logger);
        }
 /// <summary>
 /// Sets up the background worker.
 /// </summary>
 /// <remarks>
 /// The method passed to this constructor can't have any arguments.
 /// </remarks>
 /// <param name="p_dlgWorker">The method that will do the work.</param>
 public BackgroundWorkerProgressDialog(WorkerMethod p_dlgWorker)
     : this()
 {
     m_wkmWorkMethod = p_dlgWorker;
 }
예제 #21
0
파일: Worker.cs 프로젝트: harlov-va/Horse
        public static void StartShadowTask(WorkerMethod method)
        {
            Thread newThread = new Thread(new ThreadStart(method));

            newThread.Start();
        }
예제 #22
0
 /// <summary>
 ///   Sets up the background worker.
 /// </summary>
 /// <remarks>
 ///   The method passed to this constructor can't have any arguments.
 /// </remarks>
 /// <param name="p_dlgWorker">The method that will do the work.</param>
 public BackgroundWorkerProgressDialog(WorkerMethod p_dlgWorker)
     : this()
 {
     m_wkmWorkMethod = p_dlgWorker;
 }
예제 #23
0
        public CoreDaemon(Logger logger, IKernel kernel, IBlockchainRules rules, BlockHeaderCache blockHeaderCache, ChainedHeaderCache chainedHeaderCache, BlockTxHashesCache blockTxHashesCache, TransactionCache transactionCache, BlockCache blockCache)
        {
            this.logger        = logger;
            this.shutdownToken = new CancellationTokenSource();

            this.kernel             = kernel;
            this.rules              = rules;
            this.blockHeaderCache   = blockHeaderCache;
            this.chainedHeaderCache = chainedHeaderCache;
            this.blockTxHashesCache = blockTxHashesCache;
            this.transactionCache   = transactionCache;
            this.blockCache         = blockCache;

            // write genesis block out to storage
            this.blockHeaderCache[this.rules.GenesisBlock.Hash]           = this.rules.GenesisBlock.Header;
            this.blockCache[this.rules.GenesisBlock.Hash]                 = this.rules.GenesisBlock;
            this.chainedHeaderCache[this.rules.GenesisChainedHeader.Hash] = this.rules.GenesisChainedHeader;

            // wire up cache events
            this.blockHeaderCache.OnAddition       += OnBlockHeaderAddition;
            this.blockHeaderCache.OnModification   += OnBlockHeaderModification;
            this.blockCache.OnAddition             += OnBlockAddition;
            this.blockCache.OnModification         += OnBlockModification;
            this.blockTxHashesCache.OnAddition     += OnBlockTxHashesAddition;
            this.blockTxHashesCache.OnModification += OnBlockTxHashesModification;
            this.chainedHeaderCache.OnAddition     += OnChainedHeaderAddition;
            this.chainedHeaderCache.OnModification += OnChainedHeaderModification;

            // create chain state builder
            this.chainStateBuilder =
                this.kernel.Get <ChainStateBuilder>(
                    new ConstructorArgument("chain", Chain.CreateForGenesisBlock(this.rules.GenesisChainedHeader).ToBuilder()),
                    new ConstructorArgument("parentUtxo", Utxo.CreateForGenesisBlock(this.rules.GenesisBlock.Hash)));

            this.chainStateLock = new ReaderWriterLockSlim();

            // create workers
            this.chainingWorker = kernel.Get <ChainingWorker>(
                new ConstructorArgument("workerConfig", new WorkerConfig(initialNotify: true, minIdleTime: TimeSpan.FromSeconds(0), maxIdleTime: TimeSpan.FromSeconds(30))));

            this.targetChainWorker = kernel.Get <TargetChainWorker>(
                new ConstructorArgument("workerConfig", new WorkerConfig(initialNotify: true, minIdleTime: TimeSpan.FromSeconds(0), maxIdleTime: TimeSpan.FromSeconds(30))));

            this.chainStateWorker = kernel.Get <ChainStateWorker>(
                new ConstructorArgument("workerConfig", new WorkerConfig(initialNotify: true, minIdleTime: TimeSpan.Zero, maxIdleTime: TimeSpan.FromSeconds(5))),
                new ConstructorArgument("getTargetChain", (Func <Chain>)(() => this.targetChainWorker.TargetChain)),
                new ConstructorArgument("targetChainWorker", this.targetChainWorker),
                new ConstructorArgument("chainStateBuilder", this.chainStateBuilder));

            this.targetChainWorker.OnTargetBlockChanged +=
                () =>
            {
                var handler = this.OnTargetBlockChanged;
                if (handler != null)
                {
                    handler(this, EventArgs.Empty);
                }
            };

            this.targetChainWorker.OnTargetChainChanged +=
                () =>
            {
                this.chainStateWorker.NotifyWork();

                var handler = this.OnTargetChainChanged;
                if (handler != null)
                {
                    handler(this, EventArgs.Empty);
                }
            };

            this.chainStateWorker.OnChainStateChanged +=
                () =>
            {
                this.utxoScanWorker.NotifyWork();

                //TODO once fully synced, this should save off the immutable snapshot immediately
                //TODO this will allow there to always be an active chain state once synced
                this.chainStateLock.DoWrite(() =>
                                            this.chainState = null);

                var handler = this.OnChainStateChanged;
                if (handler != null)
                {
                    handler(this, EventArgs.Empty);
                }
            };

            this.gcWorker = new WorkerMethod("GC Worker",
                                             () =>
            {
                this.logger.Info(
                    string.Join("\n",
                                new string('-', 80),
                                "GC Memory:      {0,10:#,##0.00} MB",
                                "Process Memory: {1,10:#,##0.00} MB",
                                new string('-', 80)
                                )
                    .Format2
                    (
                        /*0*/ (float)GC.GetTotalMemory(false) / 1.MILLION(),
                        /*1*/ (float)Process.GetCurrentProcess().PrivateMemorySize64 / 1.MILLION()
                    ));
            }, initialNotify: true, minIdleTime: TimeSpan.FromSeconds(30), maxIdleTime: TimeSpan.FromSeconds(30), logger: this.logger);

            this.utxoScanWorker = new WorkerMethod("UTXO Scan Worker",
                                                   () =>
            {
                var chainStateLocal = this.GetChainState();
                if (chainStateLocal == null)
                {
                    return;
                }

                new MethodTimer().Time("Full UTXO Scan: {0:#,##0}".Format2(chainStateLocal.Utxo.OutputCount), () =>
                {
                    var sha256 = new SHA256Managed();
                    foreach (var output in chainStateLocal.Utxo.GetUnspentOutputs())
                    {
                        if (new UInt256(sha256.ComputeDoubleHash(output.Value.ScriptPublicKey.ToArray())) == UInt256.Zero)
                        {
                        }
                    }
                });
            }, initialNotify: true, minIdleTime: TimeSpan.Zero, maxIdleTime: TimeSpan.MaxValue, logger: this.logger);
        }