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)); }
/// <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)); }
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); } } }
/// <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); }
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); }
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); }