예제 #1
0
        public void WhenInitialize_ThenRefreshLoopIsStarted()
        {
            // Arrange.
            Mock <IWhitelistManager> mockWhitelistManager = new Mock <IWhitelistManager>();

            mockWhitelistManager.Setup(w => w.RefreshWhitelist()).Verifiable("the RefreshWhitelist method should be called on the WhitelistManager");

            IWhitelistManager whitelistManager = mockWhitelistManager.Object;

            Mock <ILogger>        mockLogger        = new Mock <ILogger>();
            Mock <ILoggerFactory> mockLoggerFactory = new Mock <ILoggerFactory>();

            mockLoggerFactory.Setup(l => l.CreateLogger(It.IsAny <string>())).Returns(mockLogger.Object);
            ILoggerFactory loggerFactory = mockLoggerFactory.Object;

            IAsyncLoopFactory asyncLoopFactory = new AsyncLoopFactory(loggerFactory);
            INodeLifetime     nodeLifeTime     = new NodeLifetime();

            IDnsServer dnsServer = new Mock <IDnsServer>().Object;

            CancellationTokenSource source       = new CancellationTokenSource(3000);
            Mock <INodeLifetime>    nodeLifetime = new Mock <INodeLifetime>();

            nodeLifetime.Setup(n => n.StopApplication()).Callback(() => source.Cancel());
            nodeLifetime.Setup(n => n.ApplicationStopping).Returns(source.Token);
            INodeLifetime nodeLifetimeObject = nodeLifetime.Object;

            NodeSettings nodeSettings = NodeSettings.Default();

            nodeSettings.DataDir = Directory.GetCurrentDirectory();
            DataFolder dataFolder = CreateDataFolder(this);

            using (DnsFeature feature = new DnsFeature(dnsServer, whitelistManager, loggerFactory, nodeLifetimeObject, DnsSettings.Load(nodeSettings), nodeSettings, dataFolder, asyncLoopFactory))
            {
                // Act.
                feature.Initialize();
                bool waited = source.Token.WaitHandle.WaitOne(5000);

                // Assert.
                feature.Should().NotBeNull();
                waited.Should().BeTrue();
                mockWhitelistManager.Verify();
            }
        }
        public void Stop_DisposesAsyncLoop()
        {
            var lifetime         = new NodeLifetime();
            var chain            = new Mock <ConcurrentChain>();
            var puller           = new Mock <ILookaheadBlockPuller>();
            var signals          = new Mock <ISignals>();
            var asyncLoop        = new Mock <IAsyncLoop>();
            var asyncLoopFactory = new Mock <IAsyncLoopFactory>();

            asyncLoopFactory.Setup(a => a.Run("Notify", It.IsAny <Func <CancellationToken, Task> >(), It.IsAny <CancellationToken>(), null, null))
            .Returns(asyncLoop.Object);

            var notification = new BlockNotification(this.LoggerFactory.Object, chain.Object, puller.Object, signals.Object, asyncLoopFactory.Object, lifetime);

            notification.Start();
            notification.Stop();

            asyncLoop.Verify(a => a.Dispose());
        }
        public void Given_SyncActionIsCalled_When_AnInvalidBlockHashIsSpecified_Then_AnExceptionIsThrown()
        {
            // Set up
            string           hashLocation     = "notAValidHash";
            var              chain            = new Mock <ChainIndexer>();
            ConsensusManager consensusManager = ConsensusManagerHelper.CreateConsensusManager(this.network);

            var loggerFactory     = new Mock <LoggerFactory>();
            var signals           = new Signals.Signals(loggerFactory.Object, null);
            var nodeLifetime      = new NodeLifetime();
            var asyncProvider     = new AsyncProvider(loggerFactory.Object, signals, nodeLifetime);
            var blockNotification = new Mock <BlockNotification>(this.LoggerFactory.Object, chain.Object, consensusManager, signals, asyncProvider, nodeLifetime);

            // Act
            var notificationController = new NotificationsController(blockNotification.Object, chain.Object);

            // Assert
            Assert.Throws <FormatException>(() => notificationController.SyncFrom(hashLocation));
        }
예제 #4
0
        /// <inheritdoc />
        public void Start()
        {
            this.State = FullNodeState.Starting;

            if (this.State == FullNodeState.Disposing || this.State == FullNodeState.Disposed)
            {
                throw new ObjectDisposedException(nameof(FullNode));
            }

            if (this.Resources != null)
            {
                throw new InvalidOperationException("node has already started.");
            }

            this.Resources               = new List <IDisposable>();
            this.nodeLifetime            = this.Services.ServiceProvider.GetRequiredService <INodeLifetime>() as NodeLifetime;
            this.fullNodeFeatureExecutor = this.Services.ServiceProvider.GetRequiredService <FullNodeFeatureExecutor>();

            if (this.nodeLifetime == null)
            {
                throw new InvalidOperationException($"{nameof(INodeLifetime)} must be set.");
            }

            if (this.fullNodeFeatureExecutor == null)
            {
                throw new InvalidOperationException($"{nameof(FullNodeFeatureExecutor)} must be set.");
            }

            this.logger.LogInformation("Starting node...");

            // Initialize all registered features.
            this.fullNodeFeatureExecutor.Initialize();

            // Initialize peer connection.
            this.ConnectionManager.Initialize();

            // Fire INodeLifetime.Started.
            this.nodeLifetime.NotifyStarted();

            this.StartPeriodicLog();

            this.State = FullNodeState.Started;
        }
        public void SyncFrom_StartHashIsNotNull_GetsBlockBasedOnStartHash_SetsPullerAndTipToPreviousBlock()
        {
            var lifetime = new NodeLifetime();
            var puller   = new Mock <ILookaheadBlockPuller>();
            var signals  = new Mock <ISignals>();

            var blocks = this.CreateBlocks(3);

            var chain = new ConcurrentChain(blocks[0].Header);

            this.AppendBlocksToChain(chain, blocks.Skip(1));

            var notification = new BlockNotification(this.LoggerFactory.Object, chain, puller.Object, signals.Object, new AsyncLoopFactory(new LoggerFactory()), lifetime);

            notification.SyncFrom(blocks[0].GetHash());
            notification.SyncFrom(blocks[2].GetHash());

            Assert.Equal(notification.StartHash, blocks[2].GetHash());
            puller.Verify(p => p.SetLocation(It.Is <ChainedBlock>(b => b.GetHashCode() == chain.GetBlock(1).GetHashCode())));
        }
        public void CallingSyncFromUpdatesStartHashAccordingly()
        {
            var lifetime = new NodeLifetime();
            var chain    = new Mock <ConcurrentChain>();
            var puller   = new Mock <ILookaheadBlockPuller>();
            var signals  = new Mock <ISignals>();

            var notification = new BlockNotification(this.LoggerFactory.Object, chain.Object, puller.Object, signals.Object, new AsyncLoopFactory(new LoggerFactory()), lifetime);

            var blockId1 = new uint256(150);
            var blockId2 = new uint256(151);

            Assert.Null(notification.StartHash);
            notification.SyncFrom(blockId1);

            Assert.NotNull(notification.StartHash);
            Assert.Equal(blockId1, notification.StartHash);

            notification.SyncFrom(blockId2);
            Assert.Equal(blockId2, notification.StartHash);
        }
        public void NotifySetsPullerLocationToBlockMatchingStartHash()
        {
            var startBlockId = new uint256(156);
            var chain        = new Mock <ConcurrentChain>();
            var header       = new BlockHeader();

            chain.Setup(c => c.GetBlock(startBlockId))
            .Returns(new ChainedBlock(header, 0));

            var stub     = new Mock <ILookaheadBlockPuller>();
            var lifetime = new NodeLifetime();

            stub.Setup(s => s.NextBlock(lifetime.ApplicationStopping))
            .Returns((Block)null);

            var notification = new BlockNotification(chain.Object, stub.Object, new Bitcoin.Signals.Signals(), new AsyncLoopFactory(new LoggerFactory()), lifetime);

            notification.Notify();
            notification.SyncFrom(startBlockId);
            notification.SyncFrom(startBlockId);
            stub.Verify(s => s.SetLocation(It.Is <ChainedBlock>(c => c.Height == 0 && c.Header.GetHash() == header.GetHash())));
        }
        public void Given_SyncActionIsCalled_When_QueryParameterIsNullOrEmpty_Then_ReturnBadRequest(string from)
        {
            var chain = new Mock <ChainIndexer>();
            ConsensusManager consensusManager = ConsensusManagerHelper.CreateConsensusManager(this.network);

            var loggerFactory     = new Mock <LoggerFactory>();
            var signals           = new Signals.Signals(loggerFactory.Object, null);
            var nodeLifetime      = new NodeLifetime();
            var asyncProvider     = new AsyncProvider(loggerFactory.Object, signals, nodeLifetime);
            var blockNotification = new Mock <BlockNotification>(this.LoggerFactory.Object, chain.Object, consensusManager, signals, asyncProvider, nodeLifetime);

            var           notificationController = new NotificationsController(blockNotification.Object, chain.Object);
            IActionResult result = notificationController.SyncFrom(from);

            var errorResult   = Assert.IsType <ErrorResult>(result);
            var errorResponse = Assert.IsType <ErrorResponse>(errorResult.Value);

            Assert.Single(errorResponse.Errors);

            ErrorModel error = errorResponse.Errors[0];

            Assert.Equal(400, error.Status);
        }
        public void Notify_WithSync_RunsAndBroadcastsBlocks()
        {
            var lifetime = new NodeLifetime();

            var blocks = this.CreateBlocks(2);

            var chain = new ConcurrentChain(blocks[0].Header);

            this.AppendBlocksToChain(chain, blocks.Skip(1).Take(1));

            var puller = new Mock <ILookaheadBlockPuller>();

            puller.SetupSequence(s => s.NextBlock(lifetime.ApplicationStopping))
            .Returns(new LookaheadResult {
                Block = blocks[0]
            })
            .Returns(new LookaheadResult {
                Block = blocks[1]
            })
            .Returns(null);

            var signals = new Mock <ISignals>();

            var notification = new Mock <BlockNotification>(this.LoggerFactory.Object, chain, puller.Object, signals.Object, new AsyncLoopFactory(new LoggerFactory()), lifetime);

            notification.SetupGet(s => s.StartHash).Returns(blocks[0].GetHash());

            notification.SetupSequence(s => s.ReSync)
            .Returns(false)
            .Returns(false)
            .Returns(true);

            notification.Object.Notify(lifetime.ApplicationStopping);

            signals.Verify(s => s.SignalBlock(It.IsAny <Block>()), Times.Exactly(2));
        }
예제 #10
0
        public void AddTimeData_WithSmallSampleSet_TurnsWarningOnAndSwitchesSyncOff()
        {
            // Samples to be inserted to the state.
            // Columns meanings: isInbound, isUsed, isWarningOn, isSyncOff, timeOffsetSample, peerAddress
            var samples = new List <object[]>
            {
                // First group of samples does not affect adjusted time, so difference should be ~0 ms.
                new object[] { false, true, false, false, TimeSpan.FromSeconds(TimeSyncBehaviorState.TimeOffsetWarningThresholdSeconds + 1), IPAddress.Parse("1.2.3.41"), },
                new object[] { false, true, false, false, TimeSpan.FromSeconds(TimeSyncBehaviorState.TimeOffsetWarningThresholdSeconds + 2), IPAddress.Parse("1.2.3.42"), },
                new object[] { false, true, false, false, TimeSpan.FromSeconds(TimeSyncBehaviorState.TimeOffsetWarningThresholdSeconds + 3), IPAddress.Parse("1.2.3.43"), },

                // The next sample turns on the warning.
                new object[] { false, true, true, false, TimeSpan.FromSeconds(TimeSyncBehaviorState.TimeOffsetWarningThresholdSeconds + 4), IPAddress.Parse("1.2.3.44"), },

                // It can't be turned off.
                new object[] { false, true, true, false, TimeSpan.FromSeconds(3), IPAddress.Parse("1.2.3.45"), },
                new object[] { false, true, true, false, TimeSpan.FromSeconds(4), IPAddress.Parse("1.2.3.46"), },

                // Add more samples.
                new object[] { false, true, true, false, TimeSpan.FromSeconds(-TimeSyncBehaviorState.MaxTimeOffsetSeconds - 10), IPAddress.Parse("1.2.3.47"), },
                new object[] { false, true, true, false, TimeSpan.FromSeconds(-TimeSyncBehaviorState.MaxTimeOffsetSeconds - 11), IPAddress.Parse("1.2.3.48"), },
                new object[] { false, true, true, false, TimeSpan.FromSeconds(-TimeSyncBehaviorState.MaxTimeOffsetSeconds - 12), IPAddress.Parse("1.2.3.49"), },
                new object[] { false, true, true, false, TimeSpan.FromSeconds(-TimeSyncBehaviorState.MaxTimeOffsetSeconds - 13), IPAddress.Parse("1.2.31.4"), },
                new object[] { false, true, true, false, TimeSpan.FromSeconds(-TimeSyncBehaviorState.MaxTimeOffsetSeconds - 14), IPAddress.Parse("1.2.32.4"), },
                new object[] { false, true, true, false, TimeSpan.FromSeconds(-TimeSyncBehaviorState.MaxTimeOffsetSeconds - 15), IPAddress.Parse("1.2.33.4"), },

                // Now the feature should be turned off.
                new object[] { true, true, true, true, TimeSpan.FromSeconds(-TimeSyncBehaviorState.MaxTimeOffsetSeconds - 16), IPAddress.Parse("1.2.33.4"), },

                // No more samples should be accepted now.
                new object[] { false, false, true, true, TimeSpan.FromSeconds(2), IPAddress.Parse("1.2.34.4"), },
                new object[] { false, false, true, true, TimeSpan.FromSeconds(1), IPAddress.Parse("1.2.35.4"), },
            };

            var dateTimeProvider = DateTimeProvider.Default;
            var lifetime         = new NodeLifetime();
            var loggerFactory    = new LoggerFactory();
            var asyncLoopFactory = new AsyncLoopFactory(loggerFactory);
            var state            = new TimeSyncBehaviorState(dateTimeProvider, lifetime, asyncLoopFactory, loggerFactory);

            for (int i = 0; i < samples.Count; i++)
            {
                bool      isInbound        = (bool)samples[i][0];
                bool      isUsed           = (bool)samples[i][1];
                bool      isWarningOn      = (bool)samples[i][2];
                bool      isSyncOff        = (bool)samples[i][3];
                TimeSpan  timeOffsetSample = (TimeSpan)samples[i][4];
                IPAddress peerAddress      = (IPAddress)samples[i][5];

                bool used = state.AddTimeData(peerAddress, timeOffsetSample, isInbound);
                Assert.Equal(isUsed, used);

                Assert.Equal(isWarningOn, state.IsSystemTimeOutOfSync);
                Assert.Equal(isSyncOff, state.SwitchedOffLimitReached);
                Assert.Equal(isSyncOff, state.SwitchedOff);

                if (state.SwitchedOff)
                {
                    DateTime adjustedTime = dateTimeProvider.GetAdjustedTime();
                    DateTime normalTime   = dateTimeProvider.GetUtcNow();
                    TimeSpan diff         = adjustedTime - normalTime;
                    Assert.True(Math.Abs(diff.TotalMilliseconds) < TimeEpsilonMs);
                }
            }
        }
예제 #11
0
        /// <summary>
        /// Creates a transaction to transfers funds from an old federation to a new federation.
        /// </summary>
        /// <param name="isSideChain">Indicates whether the <paramref name="network"/> is the sidechain.</param>
        /// <param name="network">The network that we are creating the recovery transaction for.</param>
        /// <param name="counterChainNetwork">The counterchain network.</param>
        /// <param name="dataDirPath">The root folder containing the old federation.</param>
        /// <param name="redeemScript">The new redeem script.</param>
        /// <param name="password">The password required to generate transactions using the federation wallet.</param>
        /// <param name="txTime">Any deposits beyond this UTC date will be ignored when selecting coin inputs.</param>
        /// <returns>A funds recovery transaction that moves funds to the new redeem script.</returns>
        public FundsRecoveryTransactionModel CreateFundsRecoveryTransaction(bool isSideChain, Network network, Network counterChainNetwork, string dataDirPath, Script redeemScript, string password, DateTime txTime)
        {
            var model = new FundsRecoveryTransactionModel()
            {
                Network = network, IsSideChain = isSideChain, RedeemScript = redeemScript
            };

            // Get the old redeem script from the wallet file.
            PayToMultiSigTemplateParameters multisigParams = PayToMultiSigTemplate.Instance.ExtractScriptPubKeyParameters(redeemScript);
            string           theChain          = isSideChain ? "sidechain" : "mainchain";
            var              nodeSettings      = new NodeSettings(network, args: new string[] { $"datadir={dataDirPath}", $"redeemscript={redeemScript}", $"-{theChain}" });
            var              walletFileStorage = new FileStorage <FederationWallet>(nodeSettings.DataFolder.WalletPath);
            FederationWallet wallet            = walletFileStorage.LoadByFileName("multisig_wallet.json");
            Script           oldRedeemScript   = wallet.MultiSigAddress.RedeemScript;
            PayToMultiSigTemplateParameters oldMultisigParams = PayToMultiSigTemplate.Instance.ExtractScriptPubKeyParameters(oldRedeemScript);

            model.oldMultisigAddress = oldRedeemScript.Hash.GetAddress(network);
            model.newMultisigAddress = redeemScript.Hash.GetAddress(network);

            // Create dummy inputs to avoid errors when constructing FederatedPegSettings.
            var extraArgs = new Dictionary <string, string>();

            extraArgs[FederatedPegSettings.FederationIpsParam] = oldMultisigParams.PubKeys.Select(p => "0.0.0.0".ToIPEndPoint(nodeSettings.Network.DefaultPort)).Join(",");
            var privateKey = Key.Parse(wallet.EncryptedSeed, password, network);

            extraArgs[FederatedPegSettings.PublicKeyParam] = privateKey.PubKey.ToHex(network);
            (new TextFileConfiguration(extraArgs.Select(i => $"{i.Key}={i.Value}").ToArray())).MergeInto(nodeSettings.ConfigReader);

            model.PubKey = privateKey.PubKey;

            var dBreezeSerializer = new DBreezeSerializer(network.Consensus.ConsensusFactory);
            var blockStore        = new BlockRepository(network, nodeSettings.DataFolder, nodeSettings.LoggerFactory, dBreezeSerializer);

            blockStore.Initialize();

            var           chain        = new ChainRepository(nodeSettings.DataFolder, nodeSettings.LoggerFactory, dBreezeSerializer);
            Block         genesisBlock = network.GetGenesis();
            ChainedHeader tip          = chain.LoadAsync(new ChainedHeader(genesisBlock.Header, genesisBlock.GetHash(), 0)).GetAwaiter().GetResult();
            var           chainIndexer = new ChainIndexer(network, tip);

            var nodeLifetime = new NodeLifetime();
            IDateTimeProvider dateTimeProvider = DateTimeProvider.Default;
            var federatedPegSettings           = new FederatedPegSettings(nodeSettings);
            var opReturnDataReader             = new OpReturnDataReader(nodeSettings.LoggerFactory, new CounterChainNetworkWrapper(counterChainNetwork));
            var walletFeePolicy = new WalletFeePolicy(nodeSettings);

            var walletManager = new FederationWalletManager(nodeSettings.LoggerFactory, network, chainIndexer, nodeSettings.DataFolder, walletFeePolicy,
                                                            new AsyncProvider(nodeSettings.LoggerFactory, new Signals(nodeSettings.LoggerFactory, new DefaultSubscriptionErrorHandler(nodeSettings.LoggerFactory)), nodeLifetime), nodeLifetime,
                                                            dateTimeProvider, federatedPegSettings, new WithdrawalExtractor(nodeSettings.LoggerFactory, federatedPegSettings, opReturnDataReader, network), blockStore);

            walletManager.Start();
            walletManager.EnableFederationWallet(password);

            if (!walletManager.IsFederationWalletActive())
            {
                throw new ArgumentException($"Could not activate the federation wallet on {network}.");
            }

            // Retrieves the unspent outputs in deterministic order.
            List <Stratis.Features.FederatedPeg.Wallet.UnspentOutputReference> coinRefs = walletManager.GetSpendableTransactionsInWallet().ToList();

            // Exclude coins (deposits) beyond the transaction (switch-over) time!
            coinRefs = coinRefs.Where(r => r.Transaction.CreationTime < txTime).ToList();
            if (!coinRefs.Any())
            {
                throw new ArgumentException($"There are no coins to recover from the federation wallet on {network}.");
            }

            Money fee = federatedPegSettings.GetWithdrawalTransactionFee(coinRefs.Count());

            var builder = new TransactionBuilder(network);

            builder.AddKeys(privateKey);
            builder.AddCoins(coinRefs.Select(c => ScriptCoin.Create(network, c.Transaction.Id, (uint)c.Transaction.Index, c.Transaction.Amount, c.Transaction.ScriptPubKey, oldRedeemScript)));

            // Split the coins into multiple outputs.
            Money     amount         = coinRefs.Sum(r => r.Transaction.Amount) - fee;
            const int numberOfSplits = 10;
            Money     splitAmount    = new Money((long)amount / numberOfSplits);
            var       recipients     = new List <Stratis.Features.FederatedPeg.Wallet.Recipient>();

            for (int i = 0; i < numberOfSplits; i++)
            {
                Money sendAmount = (i != (numberOfSplits - 1)) ? splitAmount : amount - splitAmount * (numberOfSplits - 1);

                builder.Send(redeemScript.PaymentScript, sendAmount);
            }

            builder.SetTimeStamp((uint)(new DateTimeOffset(txTime)).ToUnixTimeSeconds());
            builder.CoinSelector = new DeterministicCoinSelector();
            builder.SendFees(fee);

            model.tx = builder.BuildTransaction(true);

            File.WriteAllText(Path.Combine(dataDirPath, $"{network.Name}_{model.PubKey.ToHex(network).Substring(0, 8)}.hex"), model.tx.ToHex(network));

            // Merge our transaction with other transactions which have been placed in the data folder.
            Transaction oldTransaction = model.tx;
            string      namePattern    = $"{network.Name}_*.hex";
            int         sigCount       = 1;

            foreach (string fileName in Directory.EnumerateFiles(dataDirPath, namePattern))
            {
                Transaction incomingPartialTransaction = network.CreateTransaction(File.ReadAllText(fileName));

                // Don't merge with self.
                if (incomingPartialTransaction.GetHash() == oldTransaction.GetHash())
                {
                    continue;
                }

                // Transaction times must match.
                if (incomingPartialTransaction is PosTransaction && incomingPartialTransaction.Time != model.tx.Time)
                {
                    Console.WriteLine($"The locally generated transaction is time-stamped differently from the transaction contained in '{fileName}'. The imported signature can't be used.");
                    continue;
                }

                // Combine signatures.
                Transaction newTransaction = SigningUtils.CheckTemplateAndCombineSignatures(builder, model.tx, new[] { incomingPartialTransaction });

                if (oldTransaction.GetHash() == newTransaction.GetHash())
                {
                    Console.WriteLine($"The locally generated transaction is not similar to '{fileName}'. The imported signature can't be used.");
                    continue;
                }

                model.tx = newTransaction;
                sigCount++;
            }

            Console.WriteLine($"{sigCount} of {multisigParams.SignatureCount} signatures collected for {network.Name}.");

            if (sigCount >= multisigParams.SignatureCount)
            {
                if (builder.Verify(model.tx))
                {
                    // Write the transaction to file.
                    File.WriteAllText(Path.Combine(dataDirPath, $"{(txTime > DateTime.Now ? "Preliminary " : "")}{network.Name}Recovery.txt"), model.tx.ToHex(network));
                }
                else
                {
                    Console.WriteLine("Could not verify the transaction.");
                }
            }

            // Stop the wallet manager to release the database folder.
            nodeLifetime.StopApplication();
            walletManager.Stop();

            return(model);
        }
예제 #12
0
        public BlockStoreTests()
        {
            this.network = new StraxMain();
            this.repositoryTipHashAndHeight = new HashHeightPair(this.network.GenesisHash, 0);

            var nodeSettings = new NodeSettings(this.network, args: new [] { $"-datadir={TestBase.GetTestDirectoryPath(this)}" });

            this.storeSettings = new StoreSettings(nodeSettings);

            this.random = new Random();

            this.listOfSavedBlocks = new Dictionary <uint256, Block>
            {
                { uint256.One, Block.Parse(this.testBlockHex, this.network.Consensus.ConsensusFactory) }
            };

            this.chainIndexer = CreateChain(10);

            this.nodeLifetime = new NodeLifetime();

            this.blockRepositoryMock = new Mock <IBlockRepository>();

            this.blockRepositoryMock.Setup(x => x.TxIndex).Returns(this.storeSettings.TxIndex);

            this.blockRepositoryMock.Setup(x => x.PutBlocks(It.IsAny <HashHeightPair>(), It.IsAny <List <Block> >()))
            .Callback((HashHeightPair newTip, List <Block> blocks) =>
            {
                this.repositoryTipHashAndHeight = newTip;
                this.repositorySavesCount++;
                this.repositoryTotalBlocksSaved += blocks.Count;
            });

            this.blockRepositoryMock.Setup(x => x.Delete(It.IsAny <HashHeightPair>(), It.IsAny <List <uint256> >()))
            .Callback((HashHeightPair newTip, List <uint256> blocks) =>
            {
                this.repositoryTotalBlocksDeleted += blocks.Count;
            });

            this.blockRepositoryMock.Setup(x => x.GetBlock(It.IsAny <uint256>()))
            .Returns((uint256 hash) =>
            {
                Block block = null;

                if (this.listOfSavedBlocks.ContainsKey(hash))
                {
                    block = this.listOfSavedBlocks[hash];
                }

                return(block);
            });

            this.blockRepositoryMock.Setup(x => x.TipHashAndHeight).Returns(() =>
            {
                return(this.repositoryTipHashAndHeight);
            });

            this.chainState = new ChainState();
            this.initialBlockDownloadState = new Mock <IInitialBlockDownloadState>();

            var blockStoreFlushCondition = new BlockStoreQueueFlushCondition(this.chainState, this.initialBlockDownloadState.Object);

            this.loggerFactory = new LoggerFactory();
            this.signals       = new Signals.Signals(this.loggerFactory, null);
            this.asyncProvider = new AsyncProvider(this.loggerFactory, this.signals);

            this.blockStoreQueue = new BlockStoreQueue(this.chainIndexer, this.chainState, blockStoreFlushCondition, this.storeSettings,
                                                       this.blockRepositoryMock.Object, this.loggerFactory, new Mock <INodeStats>().Object, this.asyncProvider, new Mock <IInitialBlockDownloadState>().Object);
        }
예제 #13
0
        public BlockStoreTests()
        {
            this.network = KnownNetworks.StratisMain;
            this.repositoryTipHashAndHeight = new HashHeightPair(this.network.GenesisHash, 0);

            var serializer = new DBreezeSerializer();

            serializer.Initialize(new StratisMain());

            this.random = new Random();

            this.listOfSavedBlocks = new Dictionary <uint256, Block>();
            this.listOfSavedBlocks.Add(uint256.One, Block.Parse(this.testBlockHex, KnownNetworks.StratisMain));

            this.chain = CreateChain(10);

            this.nodeLifetime = new NodeLifetime();

            this.blockRepositoryMock = new Mock <IBlockRepository>();
            this.blockRepositoryMock.Setup(x => x.PutAsync(It.IsAny <HashHeightPair>(), It.IsAny <List <Block> >()))
            .Returns((HashHeightPair newTip, List <Block> blocks) =>
            {
                this.repositoryTipHashAndHeight = newTip;
                this.repositorySavesCount++;
                this.repositoryTotalBlocksSaved += blocks.Count;
                return(Task.CompletedTask);
            });

            this.blockRepositoryMock.Setup(x => x.DeleteAsync(It.IsAny <HashHeightPair>(), It.IsAny <List <uint256> >()))
            .Returns((HashHeightPair newTip, List <uint256> blocks) =>
            {
                this.repositoryTotalBlocksDeleted += blocks.Count;
                return(Task.CompletedTask);
            });

            this.blockRepositoryMock.Setup(x => x.GetBlockAsync(It.IsAny <uint256>()))
            .Returns((uint256 hash) =>
            {
                Block block = null;

                if (this.listOfSavedBlocks.ContainsKey(hash))
                {
                    block = this.listOfSavedBlocks[hash];
                }

                return(Task.FromResult(block));
            });

            this.blockRepositoryMock.Setup(x => x.TipHashAndHeight).Returns(() =>
            {
                return(this.repositoryTipHashAndHeight);
            });

            this.chainState = new ChainState();
            this.initialBlockDownloadState = new Mock <IInitialBlockDownloadState>();

            var blockStoreFlushCondition = new BlockStoreQueueFlushCondition(this.chainState, this.initialBlockDownloadState.Object);

            this.blockStoreQueue = new BlockStoreQueue(this.chain, this.chainState, blockStoreFlushCondition, new StoreSettings(NodeSettings.Default(this.network)),
                                                       this.blockRepositoryMock.Object, new LoggerFactory(), new Mock <INodeStats>().Object);
        }