Inheritance: ICoreStorage, IDisposable
Exemplo n.º 1
0
        public TargetChainWorker(WorkerConfig workerConfig, IBlockchainRules rules, CoreStorage coreStorage)
            : base("TargetChainWorker", workerConfig.initialNotify, workerConfig.minIdleTime, workerConfig.maxIdleTime)
        {
            this.rules = rules;
            this.coreStorage = coreStorage;

            this.coreStorage.ChainedHeaderAdded += HandleChainedHeaderAdded;
            this.coreStorage.BlockInvalidated += HandleBlockInvalidated;
        }
Exemplo n.º 2
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;
        }
Exemplo n.º 3
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;
            }
        }
Exemplo n.º 4
0
        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;
        }
Exemplo n.º 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;
        }
Exemplo n.º 6
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>();
        }
Exemplo n.º 7
0
        public ChainStateWorker(WorkerConfig workerConfig, TargetChainWorker targetChainWorker, ChainStateBuilder chainStateBuilder, IBlockchainRules 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.targetChainWorker.OnTargetChainChanged += HandleChanged;
        }
Exemplo n.º 8
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);
        }
Exemplo n.º 9
0
        public CoreDaemon(IBlockchainRules rules, IStorageManager storageManager)
        {
            this.rules = rules;
            this.storageManager = storageManager;
            this.coreStorage = new CoreStorage(storageManager);

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

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

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

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

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

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

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

            // wire events
            this.chainStateWorker.BlockMissed += HandleBlockMissed;
            this.targetChainWorker.OnTargetChainChanged += HandleTargetChainChanged;
            this.chainStateWorker.OnChainStateChanged += HandleChainStateChanged;
            this.pruningWorker.OnWorkFinished += this.defragWorker.NotifyWork;
        }
Exemplo n.º 10
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));
            }
        }