Example #1
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);
        }
Example #2
0
        public TargetChainWorker(WorkerConfig workerConfig, Logger logger, IBlockchainRules rules, CoreStorage coreStorage)
            : base("TargetChainWorker", workerConfig.initialNotify, workerConfig.minIdleTime, workerConfig.maxIdleTime, logger)
        {
            this.logger      = logger;
            this.rules       = rules;
            this.coreStorage = coreStorage;

            this.coreStorage.ChainedHeaderAdded += HandleChainedHeaderAdded;
            this.coreStorage.BlockInvalidated   += HandleBlockInvalidated;
        }
Example #3
0
        public TargetChainWorker(WorkerConfig workerConfig, IChainParams chainParams, CoreStorage coreStorage)
            : base("TargetChainWorker", workerConfig.initialNotify, workerConfig.minIdleTime, workerConfig.maxIdleTime)
        {
            this.chainParams = chainParams;
            this.coreStorage = coreStorage;

            this.coreStorage.ChainedHeaderAdded   += HandleChanged;
            this.coreStorage.ChainedHeaderRemoved += HandleChanged;
            this.coreStorage.BlockInvalidated     += HandleChanged;
        }
Example #4
0
        public TestDaemon(Block genesisBlock = null, INinjectModule loggingModule = null, INinjectModule[] storageModules = null)
        {
            // initialize storage folder
            this.baseDirectoryCleanup = TempDirectory.CreateTempDirectory(out this.baseDirectory);

            // initialize kernel
            this.kernel = new StandardKernel();

            // add logging module
            this.kernel.Load(loggingModule ?? new ConsoleLoggingModule());

            // log startup
            this.logger = LogManager.GetCurrentClassLogger();
            this.logger.Info($"Starting up: {DateTime.Now}");

            // initialize test blocks
            this.testBlocks = new TestBlocks(genesisBlock);

            // add storage module
            this.kernel.Load(storageModules ?? new[] { new MemoryStorageModule() });

            // initialize unit test rules, allow validation methods to run
            testBlocks.Rules.ValidateTransactionAction         = null;
            testBlocks.Rules.ValidationTransactionScriptAction = null;
            this.kernel.Bind <ChainType>().ToConstant(ChainType.Regtest);
            this.kernel.Bind <ICoreRules>().ToConstant(testBlocks.Rules);
            this.kernel.Bind <IChainParams>().ToConstant(testBlocks.ChainParams);

            // by default, don't run scripts in unit tests
            testBlocks.Rules.IgnoreScripts = true;

            // initialize the blockchain daemon
            this.kernel.Bind <CoreDaemon>().ToSelf().InSingletonScope();
            this.coreDaemon = this.kernel.Get <CoreDaemon>();
            try
            {
                this.coreStorage = this.coreDaemon.CoreStorage;

                // start the blockchain daemon
                this.coreDaemon.Start();

                // wait for initial work
                this.coreDaemon.WaitForUpdate();

                // verify initial state
                Assert.AreEqual(0, this.coreDaemon.TargetChainHeight);
                Assert.AreEqual(testBlocks.ChainParams.GenesisBlock.Hash, this.coreDaemon.TargetChain.LastBlock.Hash);
                Assert.AreEqual(testBlocks.ChainParams.GenesisBlock.Hash, this.coreDaemon.CurrentChain.LastBlock.Hash);
            }
            catch (Exception)
            {
                this.coreDaemon.Dispose();
                throw;
            }
        }
        public UnconfirmedTxesWorker(WorkerConfig workerConfig, ChainStateWorker chainStateWorker, UnconfirmedTxesBuilder unconfirmedTxesBuilder, CoreStorage coreStorage)
            : base("UnconfirmedTxesWorker", workerConfig.initialNotify, workerConfig.minIdleTime, workerConfig.maxIdleTime)
        {
            this.coreStorage = coreStorage;

            this.chainStateWorker       = chainStateWorker;
            this.unconfirmedTxesBuilder = unconfirmedTxesBuilder;

            this.currentChain = new Lazy <Chain>(() => this.unconfirmedTxesBuilder.Chain);

            this.chainStateWorker.OnChainStateChanged += HandleChanged;
        }
Example #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;
            }
        }
Example #7
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;
        }
Example #8
0
        public PruningWorker(WorkerConfig workerConfig, CoreStorage coreStorage, ChainStateWorker chainStateWorker, ChainStateBuilder chainStateBuilder, Logger logger, IBlockchainRules rules)
            : base("PruningWorker", workerConfig.initialNotify, workerConfig.minIdleTime, workerConfig.maxIdleTime, logger)
        {
            this.logger            = logger;
            this.coreStorage       = coreStorage;
            this.chainStateWorker  = chainStateWorker;
            this.chainStateBuilder = chainStateBuilder;
            this.rules             = rules;

            this.lastPruneHeight = 0;

            this.Mode = PruningMode.RollbackAndBlocks;
        }
Example #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;
            }
        }
Example #10
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();
        }
Example #11
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>();
        }
Example #12
0
        public BlockValidator(CoreStorage coreStorage, IBlockchainRules rules, Logger logger)
        {
            this.logger      = logger;
            this.coreStorage = coreStorage;
            this.rules       = rules;

            // thread count for i/o task (TxLoader)
            var ioThreadCount = 4;

            // thread count for cpu tasks (TxValidator, ScriptValidator)
            var cpuThreadCount = Environment.ProcessorCount * 2;

            this.txLoader        = new ParallelConsumer <TxWithPrevOutputKeys>("ChainStateBuilder.TxLoader", ioThreadCount, logger);
            this.txValidator     = new ParallelConsumer <TxWithPrevOutputs>("ChainStateBuilder.TxValidator", cpuThreadCount, logger);
            this.scriptValidator = new ParallelConsumer <TxInputWithPrevOutput>("ChainStateBuilder.ScriptValidator", cpuThreadCount, logger);
        }
Example #13
0
        public ChainStateBuilder(Logger logger, IBlockchainRules rules, CoreStorage coreStorage)
        {
            this.logger      = logger;
            this.sha256      = new SHA256Managed();
            this.rules       = rules;
            this.coreStorage = coreStorage;

            this.blockValidator = new BlockValidator(this.coreStorage, this.rules, this.logger);

            this.chainStateCursorHandle = coreStorage.OpenChainStateCursor();
            this.chainStateCursor       = this.chainStateCursorHandle.Item;

            this.chain       = new ChainBuilder(chainStateCursor.ReadChain());
            this.utxoBuilder = new UtxoBuilder(chainStateCursor, logger);

            this.commitLock = new ReaderWriterLockSlim();

            this.stats = new BuilderStats();
        }
Example #14
0
        public MainnetSimulator()
        {
            this.random        = new Random();
            this.blockProvider = new MainnetBlockProvider();

            // initialize kernel
            this.kernel = new StandardKernel();

            // add logging module
            this.kernel.Load(new ConsoleLoggingModule());

            // log startup
            this.logger = kernel.Get <Logger>();
            this.logger.Info("Starting up: {0}".Format2(DateTime.Now));

            // add storage module
            this.kernel.Load(new MemoryStorageModule());

            // add rules module
            this.kernel.Load(new RulesModule(RulesEnum.MainNet));

            // TODO ignore script errors in test daemon until scripting engine is completed
            var rules = this.kernel.Get <IBlockchainRules>();

            rules.IgnoreScriptErrors = true;

            // initialize the blockchain daemon
            this.kernel.Bind <CoreDaemon>().ToSelf().InSingletonScope();
            this.coreDaemon  = this.kernel.Get <CoreDaemon>();
            this.coreStorage = this.coreDaemon.CoreStorage;

            // start the blockchain daemon
            this.coreDaemon.Start();

            // wait for initial work
            this.coreDaemon.WaitForUpdate();

            // verify initial state
            Assert.AreEqual(0, this.coreDaemon.TargetChainHeight);
            Assert.AreEqual(rules.GenesisBlock.Hash, this.coreDaemon.TargetChain.LastBlockHash);
            Assert.AreEqual(rules.GenesisBlock.Hash, this.coreDaemon.CurrentChain.LastBlockHash);
        }
Example #15
0
        public Simulator(ChainType chainType)
        {
            // initialize kernel
            this.kernel = new StandardKernel();

            // add logging module
            this.kernel.Load(new ConsoleLoggingModule());

            // log startup
            this.logger = LogManager.GetCurrentClassLogger();
            this.logger.Info($"Starting up: {DateTime.Now}");

            this.random        = new Random();
            this.blockProvider = TestBlockProvider.CreateForRules(chainType);

            // add storage module
            this.kernel.Load(new MemoryStorageModule());

            // add rules module
            this.kernel.Load(new RulesModule(chainType));

            // by default, don't run scripts in unit tests
            var rules = this.kernel.Get <ICoreRules>();

            rules.IgnoreScripts = true;

            // initialize the blockchain daemon
            this.kernel.Bind <CoreDaemon>().ToSelf().InSingletonScope();
            this.coreDaemon  = this.kernel.Get <CoreDaemon>();
            this.coreStorage = this.coreDaemon.CoreStorage;

            // start the blockchain daemon
            this.coreDaemon.Start();

            // wait for initial work
            this.coreDaemon.WaitForUpdate();

            // verify initial state
            Assert.AreEqual(0, this.coreDaemon.TargetChainHeight);
            Assert.AreEqual(rules.ChainParams.GenesisBlock.Hash, this.coreDaemon.TargetChain.LastBlock.Hash);
            Assert.AreEqual(rules.ChainParams.GenesisBlock.Hash, this.coreDaemon.CurrentChain.LastBlock.Hash);
        }
Example #16
0
        public ChainStateWorker(WorkerConfig workerConfig, TargetChainWorker targetChainWorker, ChainStateBuilder chainStateBuilder, ICoreRules rules, CoreStorage coreStorage)
            : base("ChainStateWorker", workerConfig.initialNotify, workerConfig.minIdleTime, workerConfig.maxIdleTime)
        {
            this.rules       = rules;
            this.coreStorage = coreStorage;

            this.blockProcessingDurationMeasure = new DurationMeasure(sampleCutoff: TimeSpan.FromMinutes(5));
            this.blockMissCountMeasure          = new CountMeasure(TimeSpan.FromSeconds(30));

            this.targetChainWorker = targetChainWorker;
            this.chainStateBuilder = chainStateBuilder;
            this.currentChain      = new Lazy <Chain>(() => this.chainStateBuilder.Chain);

            this.coreStorage.BlockInvalidated           += HandleChanged;
            this.coreStorage.BlockTxesAdded             += HandleChanged;
            this.coreStorage.BlockTxesRemoved           += HandleChanged;
            this.coreStorage.ChainedHeaderAdded         += HandleChanged;
            this.coreStorage.ChainedHeaderRemoved       += HandleChanged;
            this.targetChainWorker.OnTargetChainChanged += HandleChanged;
        }
Example #17
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));
        }
Example #18
0
        public TestDaemon(Block genesisBlock = null)
        {
            this.random = new Random();

            // initialize kernel
            this.kernel = new StandardKernel();

            // add logging module
            this.kernel.Load(new ConsoleLoggingModule());

            // create the key pair that block rewards will be sent to
            this.txManager = this.kernel.Get <TransactionManager>();
            var keyPair = this.txManager.CreateKeyPair();

            this.coinbasePrivateKey = keyPair.Item1;
            this.coinbasePublicKey  = keyPair.Item2;

            // initialize miner
            this.miner = this.kernel.Get <Miner>();

            // create and mine the genesis block
            this.genesisBlock = genesisBlock ?? MineEmptyBlock(0);

            // log startup
            this.logger = kernel.Get <Logger>();
            this.logger.Info("Starting up: {0}".Format2(DateTime.Now));

            // add storage module
            this.kernel.Load(new MemoryStorageModule());

            // initialize unit test rules
            this.rules = this.kernel.Get <UnitTestRules>();
            this.rules.SetGenesisBlock(this.genesisBlock);
            this.kernel.Bind <RulesEnum>().ToConstant(RulesEnum.TestNet2);
            this.kernel.Bind <IBlockchainRules>().ToConstant(rules);

            // TODO ignore script errors in test daemon until scripting engine is completed
            this.rules.IgnoreScriptErrors = true;

            // initialize the blockchain daemon
            this.kernel.Bind <CoreDaemon>().ToSelf().InSingletonScope();
            this.coreDaemon = this.kernel.Get <CoreDaemon>();
            try
            {
                this.coreStorage = this.coreDaemon.CoreStorage;

                // start the blockchain daemon
                this.coreDaemon.Start();

                // wait for initial work
                this.coreDaemon.WaitForUpdate();

                // verify initial state
                Assert.AreEqual(0, this.coreDaemon.TargetChainHeight);
                Assert.AreEqual(this.genesisBlock.Hash, this.coreDaemon.TargetChain.LastBlockHash);
                Assert.AreEqual(this.genesisBlock.Hash, this.coreDaemon.CurrentChain.LastBlockHash);
            }
            catch (Exception)
            {
                this.coreDaemon.Dispose();
                throw;
            }
        }
Example #19
0
 public DefragWorker(WorkerConfig workerConfig, CoreStorage coreStorage, Logger logger)
     : base("DefragWorker", workerConfig.initialNotify, workerConfig.minIdleTime, workerConfig.maxIdleTime, logger)
 {
     this.logger      = logger;
     this.coreStorage = coreStorage;
 }
Example #20
0
        private void TestRollback(ITestStorageProvider provider)
        {
            ConsoleLoggingModule.Configure();
            var logger = LogManager.GetCurrentClassLogger();

            var blockCount = 10.THOUSAND();
            var checkUtxoHashFrequencey = 1000;

            var blockProvider = new TestNet3BlockProvider();
            var blocks        = blockProvider.ReadBlocks().Take(blockCount).ToList();

            var genesisBlock  = blocks[0];
            var genesisHeader = new ChainedHeader(genesisBlock.Header, height: 0, totalWork: 0, dateSeen: DateTimeOffset.Now);
            var genesisChain  = Chain.CreateForGenesisBlock(genesisHeader);

            var chainParams = new Testnet3Params();
            var rules       = new CoreRules(chainParams)
            {
                IgnoreScripts      = true,
                IgnoreSignatures   = true,
                IgnoreScriptErrors = true
            };

            using (var storageManager = provider.OpenStorageManager())
                using (var coreStorage = new CoreStorage(storageManager))
                    using (var chainStateBuilder = new ChainStateBuilder(rules, coreStorage, storageManager))
                    {
                        // add blocks to storage
                        coreStorage.AddGenesisBlock(ChainedHeader.CreateForGenesisBlock(blocks[0].Header));
                        foreach (var block in blocks)
                        {
                            coreStorage.TryAddBlock(block);
                        }

                        // store empty utxo hash
                        var expectedUtxoHashes = new List <UInt256>();
                        using (var chainState = chainStateBuilder.ToImmutable())
                            expectedUtxoHashes.Add(UtxoCommitment.ComputeHash(chainState));

                        // calculate utxo forward and store its state at each step along the way
                        for (var blockIndex = 0; blockIndex < blocks.Count; blockIndex++)
                        {
                            logger.Info($"Adding: {blockIndex:N0}");

                            var block         = blocks[blockIndex];
                            var chainedHeader = new ChainedHeader(block.Header, blockIndex, 0, DateTimeOffset.Now);

                            chainStateBuilder.AddBlockAsync(chainedHeader, block.Transactions.Select(
                                                                (tx, txIndex) => BlockTx.Create(txIndex, tx))).Wait();

                            if (blockIndex % checkUtxoHashFrequencey == 0 || blockIndex == blocks.Count - 1)
                            {
                                using (var chainState = chainStateBuilder.ToImmutable())
                                    expectedUtxoHashes.Add(UtxoCommitment.ComputeHash(chainState));
                            }
                        }

                        // verify the utxo state before rolling back
                        var expectedLastUtxoHash = UInt256.ParseHex("5f155c7d8a5c850d5fb2566aec5110caa40e270184126d17022ae9780fd65fd9");
                        Assert.AreEqual(expectedLastUtxoHash, expectedUtxoHashes.Last());
                        expectedUtxoHashes.RemoveAt(expectedUtxoHashes.Count - 1);

                        // roll utxo backwards and validate its state at each step along the way
                        for (var blockIndex = blocks.Count - 1; blockIndex >= 0; blockIndex--)
                        {
                            logger.Info($"Rolling back: {blockIndex:N0}");

                            var block         = blocks[blockIndex];
                            var chainedHeader = new ChainedHeader(block.Header, blockIndex, 0, DateTimeOffset.Now);
                            var blockTxes     = block.Transactions.Select((tx, txIndex) => BlockTx.Create(txIndex, tx));

                            chainStateBuilder.RollbackBlock(chainedHeader, blockTxes);

                            if ((blockIndex - 1) % checkUtxoHashFrequencey == 0 || blockIndex == 0)
                            {
                                var expectedUtxoHash = expectedUtxoHashes.Last();
                                expectedUtxoHashes.RemoveAt(expectedUtxoHashes.Count - 1);

                                using (var chainState = chainStateBuilder.ToImmutable())
                                    Assert.AreEqual(expectedUtxoHash, UtxoCommitment.ComputeHash(chainState));
                            }
                        }

                        // verify chain state was rolled all the way back
                        Assert.AreEqual(-1, chainStateBuilder.Chain.Height);
                        Assert.AreEqual(0, expectedUtxoHashes.Count);

                        // calculate utxo forward again
                        for (var blockIndex = 0; blockIndex < blocks.Count; blockIndex++)
                        {
                            logger.Info($"Adding: {blockIndex:N0}");

                            var block         = blocks[blockIndex];
                            var chainedHeader = new ChainedHeader(block.Header, blockIndex, 0, DateTimeOffset.Now);

                            chainStateBuilder.AddBlockAsync(chainedHeader, block.Transactions.Select(
                                                                (tx, txIndex) => BlockTx.Create(txIndex, tx))).Wait();
                        }

                        // verify final utxo state again
                        using (var chainState = chainStateBuilder.ToImmutable())
                            Assert.AreEqual(expectedLastUtxoHash, UtxoCommitment.ComputeHash(chainState));
                    }
        }
Example #21
0
 public RevalidateWorker(Logger logger, CoreStorage coreStorage)
     : base("RevalidateWorker", initialNotify: false, minIdleTime: TimeSpan.Zero, maxIdleTime: TimeSpan.MaxValue, logger: logger)
 {
     this.logger      = logger;
     this.coreStorage = coreStorage;
 }
Example #22
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);
        }
Example #23
0
        private void TestRollback(ITestStorageProvider provider)
        {
            var logger = LogManager.CreateNullLogger();
            var sha256 = new SHA256Managed();

            var blockProvider = new MainnetBlockProvider();
            var blocks        = Enumerable.Range(0, 500).Select(x => blockProvider.GetBlock(x)).ToList();

            var genesisBlock  = blocks[0];
            var genesisHeader = new ChainedHeader(genesisBlock.Header, height: 0, totalWork: 0);
            var genesisChain  = Chain.CreateForGenesisBlock(genesisHeader);

            var rules = new MainnetRules(logger);

            using (var storageManager = provider.OpenStorageManager())
                using (var coreStorage = new CoreStorage(storageManager, logger))
                    using (var chainStateBuilder = new ChainStateBuilder(logger, rules, coreStorage))
                    {
                        // add blocks to storage
                        coreStorage.AddGenesisBlock(ChainedHeader.CreateForGenesisBlock(blocks[0].Header));
                        foreach (var block in blocks)
                        {
                            coreStorage.TryAddBlock(block);
                        }

                        // calculate utxo forward and store its state at each step along the way
                        var expectedUtxos = new List <List <UnspentTx> >();
                        for (var blockIndex = 0; blockIndex < blocks.Count; blockIndex++)
                        {
                            var block         = blocks[blockIndex];
                            var chainedHeader = new ChainedHeader(block.Header, blockIndex, 0);

                            chainStateBuilder.AddBlock(chainedHeader, block.Transactions);

                            using (var chainState = chainStateBuilder.ToImmutable())
                            {
                                expectedUtxos.Add(chainState.ReadUnspentTransactions().ToList());
                            }
                        }

                        // verify the utxo state before rolling back
                        //TODO verify the UTXO hash hard-coded here is correct
                        var expectedUtxoHash = UInt256.Parse("609eb5882e0b71a707fb876c844fbfe6b4579e04eb27c7c0cefbb7478bac737b", NumberStyles.HexNumber);
                        using (var utxoStream = new UtxoStream(logger, expectedUtxos.Last()))
                        {
                            var utxoHash = new UInt256(sha256.ComputeDoubleHash(utxoStream));
                            Assert.AreEqual(expectedUtxoHash, utxoHash);
                        }
                        expectedUtxos.RemoveAt(expectedUtxos.Count - 1);

                        // roll utxo backwards and validate its state at each step along the way
                        for (var blockIndex = blocks.Count - 1; blockIndex >= 1; blockIndex--)
                        {
                            var block         = blocks[blockIndex];
                            var chainedHeader = new ChainedHeader(block.Header, blockIndex, 0);
                            var blockTxes     = block.Transactions.Select((tx, txIndex) => new BlockTx(txIndex, 0, tx.Hash, /*pruned:*/ false, tx));

                            chainStateBuilder.RollbackBlock(chainedHeader, blockTxes);

                            var expectedUtxo = expectedUtxos.Last();
                            expectedUtxos.RemoveAt(expectedUtxos.Count - 1);

                            List <UnspentTx> actualUtxo;
                            using (var chainState = chainStateBuilder.ToImmutable())
                            {
                                actualUtxo = chainState.ReadUnspentTransactions().ToList();
                            }

                            CollectionAssert.AreEqual(expectedUtxo, actualUtxo, "UTXO differs at height: {0}".Format2(blockIndex));
                        }
                    }
        }
Example #24
0
        public MainWindowViewModel(IKernel kernel, WalletMonitor walletMonitor = null)
        {
            this.dispatcher = Dispatcher.CurrentDispatcher;

            this.kernel      = kernel;
            this.coreDaemon  = kernel.Get <CoreDaemon>();
            this.coreStorage = this.coreDaemon.CoreStorage;
            this.localClient = kernel.Get <LocalClient>();

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

            this.ratesTimer  = new DispatcherTimer();
            ratesTimer.Tick += (sender, e) =>
            {
                this.BlockRate                   = this.coreDaemon.GetBlockRate(TimeSpan.FromSeconds(1));
                this.TransactionRate             = this.coreDaemon.GetTxRate(TimeSpan.FromSeconds(1));
                this.InputRate                   = this.coreDaemon.GetInputRate(TimeSpan.FromSeconds(1));
                this.BlockDownloadRate           = this.localClient.GetBlockDownloadRate(TimeSpan.FromSeconds(1));
                this.DuplicateBlockDownloadCount = this.localClient.GetDuplicateBlockDownloadCount();
                this.BlockMissCount              = this.localClient.GetBlockMissCount();
            };
            ratesTimer.Interval = TimeSpan.FromSeconds(1);
            ratesTimer.Start();

            this.viewChain = this.coreDaemon.CurrentChain;

            this.WinningBlockchainHeight = this.coreDaemon.TargetChainHeight;
            this.CurrentBlockchainHeight = this.coreDaemon.CurrentChain.Height;
            this.DownloadedBlockCount    = this.coreStorage.BlockWithTxesCount;

            this.coreStorage.BlockTxesAdded +=
                (chainedHeader) =>
                DownloadedBlockCount = this.coreStorage.BlockWithTxesCount;

            this.coreStorage.BlockTxesRemoved +=
                (blockHash) =>
                DownloadedBlockCount = this.coreStorage.BlockWithTxesCount;

            this.coreDaemon.OnTargetChainChanged +=
                (sender, block) =>
                WinningBlockchainHeight = this.coreDaemon.TargetChainHeight;

            this.coreDaemon.OnChainStateChanged +=
                (sender, chainState) =>
                CurrentBlockchainHeight = this.coreDaemon.CurrentChain.Height;

            if (walletMonitor != null)
            {
                this.walletMonitor = walletMonitor;
                this.WalletEntries = new ObservableCollection <WalletEntry>();
                this.walletMonitor.OnEntryAdded += HandleOnWalletEntryAdded;
            }
        }