public void Start_WalletTipNotOnChain_ReorgNotHavingEarliestWalletHeight_StartsSyncFromForkBlockTime()
        {
            this.chain = WalletTestsHelpers.GenerateChainWithHeight(3, this.network);
            this.walletManager.Setup(w => w.ContainsWallets)
            .Returns(true);
            this.walletManager.SetupGet(w => w.WalletTipHash)
            .Returns(new uint256(15));
            this.walletManager.Setup(w => w.GetEarliestWalletHeight())
            .Returns((int?)null);
            this.walletManager.Setup(w => w.GetOldestWalletCreationTime())
            .Returns(new DateTimeOffset(new DateTime(2017, 2, 1)));
            this.walletManager.Setup(w => w.GetFirstWalletBlockLocator())
            .Returns(new List <uint256>()
            {
                this.chain.Genesis.HashBlock
            });

            var lightWalletSyncManager = new LightWalletSyncManager(this.LoggerFactory.Object, this.walletManager.Object, this.chain, this.network,
                                                                    this.blockNotification.Object, this.signals.Object, this.nodeLifetime.Object, this.asyncLoopFactory.Object, this.consensusManager.Object);

            lightWalletSyncManager.Start();

            // verify that the walletmanager removes blocks using the block locator.
            this.walletManager.Verify(v => v.RemoveBlocks(It.Is <ChainedHeader>(c => c.HashBlock == this.chain.Genesis.HashBlock)));

            // verify that the sync is started using the first block.
            uint256 expectedBlockHash = this.chain.GetBlock(1).HashBlock;

            this.blockNotification.Verify(b => b.SyncFrom(expectedBlockHash));
            Assert.Equal(lightWalletSyncManager.WalletTip.HashBlock, expectedBlockHash);
            this.walletManager.VerifySet(b => b.WalletTipHash = expectedBlockHash);
        }
        public void Start_StartsBlockAndTransactionObserver()
        {
            var lightWalletSyncManager = new LightWalletSyncManager(this.LoggerFactory.Object, this.walletManager.Object, this.chain, this.network,
                                                                    this.blockNotification.Object, this.signals.Object, this.nodeLifetime.Object, this.asyncLoopFactory.Object, this.consensusManager.Object);

            lightWalletSyncManager.Start();

            this.signals.Verify(s => s.SubscribeForBlocksConnected(It.IsAny <IObserver <ChainedHeaderBlock> >()), Times.Exactly(1));
            this.signals.Verify(s => s.SubscribeForTransactions(It.IsAny <IObserver <Transaction> >()), Times.Exactly(1));
        }
        public void SyncFromHeight_NegativeHeight_ThrowsWalletException()
        {
            Assert.Throws <WalletException>(() =>
            {
                this.chain = new ConcurrentChain(this.network);
                var lightWalletSyncManager = new LightWalletSyncManager(this.LoggerFactory.Object, this.walletManager.Object, this.chain, this.network,
                                                                        this.blockNotification.Object, this.signals.Object, this.nodeLifetime.Object, this.asyncLoopFactory.Object, this.consensusManager.Object);

                lightWalletSyncManager.SyncFromHeight(-1);
            });
        }
        public void Start_WithoutWalletsLoadedOnWalletManager_SetsWalletTipToChainTip()
        {
            this.chain = WalletTestsHelpers.GenerateChainWithHeight(3, this.network);
            this.walletManager.Setup(w => w.ContainsWallets)
            .Returns(false);
            var lightWalletSyncManager = new LightWalletSyncManager(this.LoggerFactory.Object, this.walletManager.Object, this.chain, this.network,
                                                                    this.blockNotification.Object, this.signals.Object, this.nodeLifetime.Object, this.asyncLoopFactory.Object, this.consensusManager.Object);

            lightWalletSyncManager.Start();

            Assert.Equal(lightWalletSyncManager.WalletTip.HashBlock, this.chain.Tip.HashBlock);
        }
        public void ProcessTransaction_CallsWalletManager()
        {
            var lightWalletSyncManager = new LightWalletSyncManager(this.LoggerFactory.Object, this.walletManager.Object, this.chain, this.network,
                                                                    this.blockNotification.Object, this.signals.Object, this.nodeLifetime.Object, this.asyncLoopFactory.Object, this.consensusManager.Object);

            var transaction = new Transaction()
            {
                Version = 15
            };

            lightWalletSyncManager.ProcessTransaction(transaction);

            this.walletManager.Verify(w => w.ProcessTransaction(transaction, null, null, true));
        }
        public void SyncFromDate_ChainTipAfterGivenDate_StartsSyncFromHeightAtTime()
        {
            this.chain = WalletTestsHelpers.GenerateChainWithHeight(3, this.network);
            var lightWalletSyncManager = new LightWalletSyncManager(this.LoggerFactory.Object, this.walletManager.Object, this.chain, this.network,
                                                                    this.blockNotification.Object, this.signals.Object, this.nodeLifetime.Object, this.asyncLoopFactory.Object, this.consensusManager.Object);

            lightWalletSyncManager.SyncFromDate(this.chain.GetBlock(1).Header.BlockTime.DateTime);

            uint256 expectedBlockHash = this.chain.GetBlock(1).HashBlock;

            this.blockNotification.Verify(b => b.SyncFrom(expectedBlockHash));
            Assert.Equal(lightWalletSyncManager.WalletTip.HashBlock, expectedBlockHash);
            this.walletManager.VerifySet(b => b.WalletTipHash = expectedBlockHash);
        }
        public void Start_WalletTipOnChain_HavingEarliestWalletHeight_StartsSyncFromEarliestHeight()
        {
            this.chain = WalletTestsHelpers.GenerateChainWithHeight(3, this.network);
            this.walletManager.Setup(w => w.ContainsWallets)
            .Returns(true);
            this.walletManager.Setup(w => w.WalletTipHash)
            .Returns(this.chain.GetBlock(2).HashBlock);
            this.walletManager.Setup(w => w.GetEarliestWalletHeight())
            .Returns(1);

            var lightWalletSyncManager = new LightWalletSyncManager(this.LoggerFactory.Object, this.walletManager.Object, this.chain, this.network,
                                                                    this.blockNotification.Object, this.signals.Object, this.nodeLifetime.Object, this.asyncLoopFactory.Object, this.consensusManager.Object);

            lightWalletSyncManager.Start();

            Assert.Equal(lightWalletSyncManager.WalletTip.HashBlock, this.chain.GetBlock(1).HashBlock);
            this.blockNotification.Verify(b => b.SyncFrom(this.chain.GetBlock(1).HashBlock));
        }
        public void SyncFromDate_EmptyChain_StartsAsyncLoopToCatchup()
        {
            this.chain = new ConcurrentChain(this.network);
            var lightWalletSyncManager = new LightWalletSyncManager(this.LoggerFactory.Object, this.walletManager.Object, this.chain, this.network,
                                                                    this.blockNotification.Object, this.signals.Object, this.nodeLifetime.Object, this.asyncLoopFactory.Object, this.consensusManager.Object);

            lightWalletSyncManager.SyncFromDate(new DateTime(2017, 1, 1));

            this.asyncLoopFactory.Verify(
                a => a.RunUntil(
                    "LightWalletSyncManager.SyncFromDate",
                    It.IsAny <CancellationToken>(),
                    It.IsAny <Func <bool> >(),
                    It.IsAny <Action>(),
                    It.IsAny <Action <Exception> >(),
                    TimeSpans.FiveSeconds));
            this.nodeLifetime.VerifyGet(n => n.ApplicationStopping);
        }
        public void SyncFromDate_ChainTipBeforeGivenDate_StartsAsyncLoopToCatchupChain()
        {
            var asyncLoop = new Mock <IAsyncLoop>();

            this.chain = WalletTestsHelpers.GenerateChainWithHeight(2, this.network);
            var lightWalletSyncManager = new LightWalletSyncManager(this.LoggerFactory.Object, this.walletManager.Object, this.chain, this.network,
                                                                    this.blockNotification.Object, this.signals.Object, this.nodeLifetime.Object, this.asyncLoopFactory.Object, this.consensusManager.Object);

            lightWalletSyncManager.SyncFromDate(this.chain.Tip.Header.BlockTime.DateTime.AddDays(15));

            this.asyncLoopFactory.Verify(
                a => a.RunUntil(
                    "LightWalletSyncManager.SyncFromDate",
                    It.IsAny <CancellationToken>(),
                    It.IsAny <Func <bool> >(),
                    It.IsAny <Action>(),
                    It.IsAny <Action <Exception> >(),
                    TimeSpans.FiveSeconds));
            this.nodeLifetime.VerifyGet(n => n.ApplicationStopping);
        }
        public void Stop_DisposesDependencies()
        {
            this.chain = WalletTestsHelpers.GenerateChainWithHeight(1, this.network);
            var blockSub = new Mock <IDisposable>();
            var transSub = new Mock <IDisposable>();

            this.signals.Setup(s => s.SubscribeForBlocksConnected(It.IsAny <BlockObserver>()))
            .Returns(blockSub.Object);
            this.signals.Setup(s => s.SubscribeForTransactions(It.IsAny <TransactionObserver>()))
            .Returns(transSub.Object);
            this.walletManager.SetupGet(w => w.ContainsWallets)
            .Returns(false);

            var asyncLoop = new Mock <IAsyncLoop>();

            this.asyncLoopFactory.Setup(
                a => a.RunUntil(
                    "LightWalletSyncManager.SyncFromHeight",
                    It.IsAny <CancellationToken>(),
                    It.IsAny <Func <bool> >(),
                    It.IsAny <Action>(),
                    It.IsAny <Action <Exception> >(),
                    TimeSpans.FiveSeconds))
            .Returns(asyncLoop.Object);

            var lightWalletSyncManager = new LightWalletSyncManager(this.LoggerFactory.Object, this.walletManager.Object, this.chain, this.network,
                                                                    this.blockNotification.Object, this.signals.Object, this.nodeLifetime.Object, this.asyncLoopFactory.Object, this.consensusManager.Object);

            lightWalletSyncManager.Start();
            lightWalletSyncManager.SyncFromHeight(3);
            lightWalletSyncManager.Stop();

            asyncLoop.Verify(b => b.Dispose());
            blockSub.Verify(b => b.Dispose());
            transSub.Verify(b => b.Dispose());
        }
        public void Start_HavingWalletsAndEmptyChain_StartsSyncFromGenesisBlock()
        {
            this.chain = new ConcurrentChain(this.network);
            this.walletManager.Setup(w => w.ContainsWallets)
            .Returns(true);
            this.walletManager.SetupGet(w => w.WalletTipHash)
            .Returns(this.chain.Genesis.HashBlock);
            this.walletManager.Setup(w => w.GetEarliestWalletHeight())
            .Returns((int?)null);
            this.walletManager.Setup(w => w.GetOldestWalletCreationTime())
            .Returns(new DateTimeOffset(new DateTime(2000, 1, 1)));

            var lightWalletSyncManager = new LightWalletSyncManager(this.LoggerFactory.Object, this.walletManager.Object, this.chain, this.network,
                                                                    this.blockNotification.Object, this.signals.Object, this.nodeLifetime.Object, this.asyncLoopFactory.Object, this.consensusManager.Object);

            lightWalletSyncManager.Start();

            // verify that the sync is started using genesis block
            uint256 expectedBlockHash = this.chain.Genesis.HashBlock;

            this.blockNotification.Verify(b => b.SyncFrom(expectedBlockHash));
            Assert.Equal(lightWalletSyncManager.WalletTip.HashBlock, expectedBlockHash);
            this.walletManager.VerifySet(b => b.WalletTipHash = expectedBlockHash);
        }