示例#1
0
 public TumblingState(ILoggerFactory loggerFactory,
                      ConcurrentChain chain,
                      WalletManager walletManager,
                      IWatchOnlyWalletManager watchOnlyWalletManager,
                      Network network,
                      WalletTransactionHandler walletTransactionHandler,
                      WalletSyncManager walletSyncManager,
                      IWalletFeePolicy walletFeePolicy,
                      NodeSettings nodeSettings,
                      IBroadcasterManager broadcasterManager,
                      ConnectionManager connectionManager)
 {
     this.Logger                   = loggerFactory.CreateLogger(this.GetType().FullName);
     this.Chain                    = chain;
     this.WalletManager            = walletManager;
     this.WatchOnlyWalletManager   = watchOnlyWalletManager;
     this.CoinType                 = (CoinType)network.Consensus.CoinType;
     this.WalletTransactionHandler = walletTransactionHandler;
     this.WalletSyncManager        = walletSyncManager;
     this.TumblerNetwork           = network;
     this.WalletFeePolicy          = walletFeePolicy;
     this.NodeSettings             = nodeSettings;
     this.BroadcasterManager       = broadcasterManager;
     this.ConnectionManager        = connectionManager;
 }
示例#2
0
        public void Start_BlockNotChain_ReorgsWalletManagerUsingWallet()
        {
            this.storeSettings.Prune = false;
            this.chain = WalletTestsHelpers.GenerateChainWithHeight(5, Network.PurpleMain);
            this.walletManager.SetupGet(w => w.WalletTipHash)
            .Returns(new uint256(125));                 // try to load non-existing block to get chain to return null.

            var forkBlock     = this.chain.GetBlock(3); // use a block as the fork to recover to.
            var forkBlockHash = forkBlock.Header.GetHash();

            this.walletManager.Setup(w => w.GetFirstWalletBlockLocator())
            .Returns(new Collection <uint256> {
                forkBlockHash
            });

            var walletSyncManager = new WalletSyncManager(this.LoggerFactory.Object, this.walletManager.Object, this.chain, Network.PurpleMain,
                                                          this.blockStoreCache.Object, this.storeSettings, this.nodeLifetime.Object);

            walletSyncManager.Start();

            // verify the walletmanager is reorged using the fork block and it's tip is set to it.
            this.walletManager.Verify(w => w.RemoveBlocks(It.Is <ChainedBlock>(c => c.Header.GetHash() == forkBlockHash)));
            this.walletManager.VerifySet(w => w.WalletTipHash = forkBlockHash);
            Assert.Equal(walletSyncManager.WalletTip.HashBlock.ToString(), forkBlock.HashBlock.ToString());
        }
        public void Start_BlockNotChain_ReorgsWalletManagerUsingWallet()
        {
            this.storeSettings.AmountOfBlocksToKeep = 0;
            this.chainIndexer = WalletTestsHelpers.GenerateChainWithHeight(5, KnownNetworks.StratisMain);
            this.walletManager.SetupGet(w => w.WalletTipHash)
            .Returns(new uint256(125));                                   // try to load non-existing block to get chain to return null.

            ChainedHeader forkBlock     = this.chainIndexer.GetHeader(3); // use a block as the fork to recover to.
            uint256       forkBlockHash = forkBlock.Header.GetHash();

            this.walletManager.Setup(w => w.GetFirstWalletBlockLocator())
            .Returns(new Collection <uint256> {
                forkBlockHash
            });

            var walletSyncManager = new WalletSyncManager(this.LoggerFactory.Object, this.walletManager.Object, this.chainIndexer, KnownNetworks.StratisMain,
                                                          this.blockStore.Object, this.storeSettings, this.signals, this.asyncProvider);

            walletSyncManager.Start();

            // verify the walletmanager is reorged using the fork block and it's tip is set to it.
            this.walletManager.Verify(w => w.RemoveBlocks(It.Is <ChainedHeader>(c => c.Header.GetHash() == forkBlockHash)));
            this.walletManager.VerifySet(w => w.WalletTipHash = forkBlockHash);
            Assert.Equal(walletSyncManager.WalletTip.HashBlock.ToString(), forkBlock.HashBlock.ToString());
        }
        private void SetupMockObjects(ChainIndexer chainIndexer, List <Block> blocks = null)
        {
            this.chainIndexer  = chainIndexer;
            this.storeSettings = new StoreSettings(new NodeSettings(new StraxMain()));
            this.loggerFactory = new LoggerFactory();
            this.walletManager = new Mock <MockWalletManager>(this.Network, this.chainIndexer, this.loggerFactory)
            {
                CallBase = true
            };
            this.blockStore        = new Mock <IBlockStore>();
            this.nodeLifetime      = new Mock <INodeLifetime>();
            this.walletRepository  = Mock.Get(((WalletManager)this.walletManager.Object).WalletRepository);
            this.signals           = new Signals.Signals(new LoggerFactory(), null);
            this.asyncProvider     = new AsyncProvider(new LoggerFactory(), this.signals);
            this.walletSyncManager = new WalletSyncManager(this.LoggerFactory.Object, this.walletManager.Object, this.chainIndexer, this.Network,
                                                           this.blockStore.Object, this.storeSettings, this.signals, this.asyncProvider, this.nodeLifetime.Object);
            this.walletName = "test";
            this.walletTip  = this.chainIndexer.Tip;

            this.walletRepository.Setup(w => w.GetWalletNames()).Returns(() =>
            {
                return((this.walletName == null) ? new List <string> {
                } : new List <string> {
                    this.walletName
                });
            });

            // Mock wallet repository's 'RewindWallet'.
            this.walletRepository.Setup(r => r.RewindWallet(It.IsAny <string>(), It.IsAny <ChainedHeader>())).Returns((string name, ChainedHeader chainedHeader) =>
            {
                var fork = (chainedHeader == null) ? null : this.walletTip.FindFork(chainedHeader);

                // If nothing to do then exit. Tips match.
                if (chainedHeader?.HashBlock == this.walletTip.HashBlock &&
                    chainedHeader?.Height == this.walletTip.Height)
                {
                    return(false, new List <(uint256, DateTimeOffset)>());
                }

                this.walletTip = fork;

                return(true, new List <(uint256, DateTimeOffset)>());
            });

            // Mock wallet repository's 'FindFork'.
            this.walletRepository.Setup(r => r.FindFork(this.walletName, It.IsAny <ChainedHeader>())).Returns((string name, ChainedHeader chainedHeader) =>
            {
                return((this.walletTip == null) ? null : chainedHeader.FindFork(this.walletTip));
            });

            if (blocks != null)
            {
                // Setup blockstore to return blocks on the chain.
                var blockDict = blocks.ToDictionary(b => b.GetHash(), b => b);
                this.blockStore.Setup(b => b.GetBlocks(It.IsAny <List <uint256> >()))
                .Returns((List <uint256> blockHashes) => blockHashes.Select(h => blockDict[h]).ToList());
            }
        }
        public void SyncFromDate_EmptyChain_UpdateUsingGenesisBlock()
        {
            this.chainIndexer = new ChainIndexer(new StraxMain());

            var walletSyncManager = new WalletSyncManager(this.LoggerFactory.Object, this.walletManager.Object, this.chainIndexer, new StraxMain(),
                                                          this.blockStore.Object, this.storeSettings, this.signals, this.asyncProvider, new Mock <INodeLifetime>().Object);

            walletSyncManager.SyncFromDate(new DateTime(1900, 1, 1)); // date before any block.

            Assert.Null(walletSyncManager.WalletTip);
        }
示例#6
0
        public void SyncFromHeight_NoBlockWithGivenHeightOnChain_ThrowsWalletException()
        {
            this.chain = WalletTestsHelpers.GenerateChainWithHeight(1, Network.StratisMain);

            var walletSyncManager = new WalletSyncManager(this.LoggerFactory.Object, this.walletManager.Object, this.chain, Network.StratisMain,
                                                          this.blockStoreCache.Object, this.storeSettings, this.nodeLifetime.Object);

            Assert.Throws <WalletException>(() =>
            {
                walletSyncManager.SyncFromHeight(2);
            });
        }
        public void SyncFromHeight_NoBlockWithGivenHeightOnChain_ThrowsWalletException()
        {
            this.chainIndexer = WalletTestsHelpers.GenerateChainWithHeight(1, KnownNetworks.StratisMain);

            var walletSyncManager = new WalletSyncManager(this.LoggerFactory.Object, this.walletManager.Object, this.chainIndexer, KnownNetworks.StratisMain,
                                                          this.blockStore.Object, this.storeSettings, this.signals, this.asyncProvider);

            Assert.Throws <WalletException>(() =>
            {
                walletSyncManager.SyncFromHeight(2);
            });
        }
示例#8
0
        public void Start_HavingPrunedStoreSetting_ThrowsWalletException()
        {
            this.storeSettings.Prune = true;

            var walletSyncManager = new WalletSyncManager(this.LoggerFactory.Object, this.walletManager.Object, this.chain, Network.StratisMain,
                                                          this.blockStoreCache.Object, this.storeSettings, this.nodeLifetime.Object);

            Assert.Throws <WalletException>(() =>
            {
                walletSyncManager.Start();
            });
        }
        public void Start_HavingPrunedStoreSetting_ThrowsWalletException()
        {
            this.storeSettings.AmountOfBlocksToKeep = 1;
            this.storeSettings.PruningEnabled       = true;

            var walletSyncManager = new WalletSyncManager(this.LoggerFactory.Object, this.walletManager.Object, this.chainIndexer, KnownNetworks.StratisMain,
                                                          this.blockStore.Object, this.storeSettings, this.signals, this.asyncProvider);

            Assert.Throws <WalletException>(() =>
            {
                walletSyncManager.Start();
            });
        }
示例#10
0
        public void SyncFromDate_EmptyChain_UpdateUsingGenesisBlock()
        {
            this.chain = new ConcurrentChain(Network.StratisMain);

            var walletSyncManager = new WalletSyncManager(this.LoggerFactory.Object, this.walletManager.Object, this.chain, Network.StratisMain,
                                                          this.blockStoreCache.Object, this.storeSettings, this.nodeLifetime.Object);

            walletSyncManager.SyncFromDate(new System.DateTime(1900, 1, 1)); // date before any block.

            uint256 expectedHash = this.chain.Genesis.HashBlock;

            Assert.Equal(walletSyncManager.WalletTip.HashBlock, expectedHash);
            this.walletManager.VerifySet(w => w.WalletTipHash = expectedHash);
        }
示例#11
0
        public void SyncFromDate_GivenDateNotMatchingBlocksOnChain_UpdatesUsingFirstBlock()
        {
            this.chain = WalletTestsHelpers.GenerateChainWithHeight(3, Network.StratisMain);

            var walletSyncManager = new WalletSyncManager(this.LoggerFactory.Object, this.walletManager.Object, this.chain, Network.StratisMain,
                                                          this.blockStoreCache.Object, this.storeSettings, this.nodeLifetime.Object);

            walletSyncManager.SyncFromDate(new System.DateTime(1900, 1, 1)); // date before any block.

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

            Assert.Equal(walletSyncManager.WalletTip.HashBlock, expectedHash);
            this.walletManager.VerifySet(w => w.WalletTipHash = expectedHash);
        }
示例#12
0
        public void SyncFromDate_GivenDateMatchingBlocksOnChain_UpdatesUsingClosestBlock()
        {
            this.chain = WalletTestsHelpers.GenerateChainWithHeight(3, Network.StratisMain);

            var walletSyncManager = new WalletSyncManager(this.LoggerFactory.Object, this.walletManager.Object, this.chain, Network.StratisMain,
                                                          this.blockStoreCache.Object, this.storeSettings, this.nodeLifetime.Object);

            walletSyncManager.SyncFromDate(this.chain.GetBlock(3).Header.BlockTime.DateTime.AddDays(2));

            uint256 expectedHash = this.chain.GetBlock(3).HashBlock;

            Assert.Equal(walletSyncManager.WalletTip.HashBlock, expectedHash);
            this.walletManager.VerifySet(w => w.WalletTipHash = expectedHash);
        }
示例#13
0
        public void ProcessTransaction_CallsWalletManager()
        {
            var walletSyncManager = new WalletSyncManager(this.LoggerFactory.Object, this.walletManager.Object, this.chain, Network.StratisMain,
                                                          this.blockStoreCache.Object, this.storeSettings, this.nodeLifetime.Object);

            var transaction = new Transaction
            {
                Version = 15
            };

            walletSyncManager.ProcessTransaction(transaction);

            this.walletManager.Verify(w => w.ProcessTransaction(transaction, null, null, true));
        }
示例#14
0
        public void SyncFromHeight_BlockWithHeightOnChain_UpdatesWalletTipOnWalletAndWalletSyncManagers()
        {
            this.chain = WalletTestsHelpers.GenerateChainWithHeight(3, Network.StratisMain);

            var walletSyncManager = new WalletSyncManager(this.LoggerFactory.Object, this.walletManager.Object, this.chain, Network.StratisMain,
                                                          this.blockStoreCache.Object, this.storeSettings, this.nodeLifetime.Object);

            walletSyncManager.SyncFromHeight(2);

            uint256 expectedHash = this.chain.GetBlock(2).HashBlock;

            Assert.Equal(walletSyncManager.WalletTip.HashBlock, expectedHash);
            this.walletManager.VerifySet(w => w.WalletTipHash = expectedHash);
        }
        public void SyncFromHeight_BlockWithHeightOnChain_UpdatesWalletTipOnWalletAndWalletSyncManagers()
        {
            this.chainIndexer = WalletTestsHelpers.GenerateChainWithHeight(3, KnownNetworks.StratisMain);

            var walletSyncManager = new WalletSyncManager(this.LoggerFactory.Object, this.walletManager.Object, this.chainIndexer, KnownNetworks.StratisMain,
                                                          this.blockStore.Object, this.storeSettings, this.signals, this.asyncProvider);

            walletSyncManager.SyncFromHeight(2);

            uint256 expectedHash = this.chainIndexer.GetHeader(2).HashBlock;

            Assert.Equal(walletSyncManager.WalletTip.HashBlock, expectedHash);
            this.walletManager.VerifySet(w => w.WalletTipHash = expectedHash);
        }
        public void SyncFromDate_EmptyChain_UpdateUsingGenesisBlock()
        {
            this.chainIndexer = new ChainIndexer(KnownNetworks.StratisMain);

            var walletSyncManager = new WalletSyncManager(this.LoggerFactory.Object, this.walletManager.Object, this.chainIndexer, KnownNetworks.StratisMain,
                                                          this.blockStore.Object, this.storeSettings, this.signals, this.asyncProvider);

            walletSyncManager.SyncFromDate(new DateTime(1900, 1, 1)); // date before any block.

            uint256 expectedHash = this.chainIndexer.Genesis.HashBlock;

            Assert.Equal(walletSyncManager.WalletTip.HashBlock, expectedHash);
            this.walletManager.VerifySet(w => w.WalletTipHash = expectedHash);
        }
        public void SyncFromDate_GivenDateNotMatchingBlocksOnChain_UpdatesUsingFirstBlock()
        {
            this.chainIndexer = WalletTestsHelpers.GenerateChainWithHeight(3, KnownNetworks.StratisMain);

            var walletSyncManager = new WalletSyncManager(this.LoggerFactory.Object, this.walletManager.Object, this.chainIndexer, KnownNetworks.StratisMain,
                                                          this.blockStore.Object, this.storeSettings, this.signals, this.asyncProvider);

            walletSyncManager.SyncFromDate(new DateTime(1900, 1, 1)); // date before any block.

            uint256 expectedHash = this.chainIndexer.GetHeader(1).HashBlock;

            Assert.Equal(walletSyncManager.WalletTip.HashBlock, expectedHash);
            this.walletManager.VerifySet(w => w.WalletTipHash = expectedHash);
        }
        public void ProcessTransaction_CallsWalletManager()
        {
            var walletSyncManager = new WalletSyncManager(this.LoggerFactory.Object, this.walletManager.Object, this.chainIndexer, KnownNetworks.StratisMain,
                                                          this.blockStore.Object, this.storeSettings, this.signals, this.asyncProvider);

            var transaction = new Transaction
            {
                Version = 15
            };

            walletSyncManager.ProcessTransaction(transaction);

            this.walletManager.Verify(w => w.ProcessTransaction(transaction, null, null, true));
        }
        public void Start_BlockOnChain_DoesNotReorgWalletManager()
        {
            this.storeSettings.AmountOfBlocksToKeep = 0;
            this.chainIndexer = WalletTestsHelpers.PrepareChainWithBlock();
            this.walletManager.Setup(w => w.WalletTipHash)
            .Returns(this.chainIndexer.Tip.Header.GetHash());

            var walletSyncManager = new WalletSyncManager(this.LoggerFactory.Object, this.walletManager.Object, this.chainIndexer, KnownNetworks.StratisMain,
                                                          this.blockStore.Object, this.storeSettings, this.signals, this.asyncProvider);

            walletSyncManager.Start();

            this.walletManager.Verify(w => w.GetFirstWalletBlockLocator(), Times.Exactly(0));
            this.walletManager.Verify(w => w.RemoveBlocks(It.IsAny <ChainedHeader>()), Times.Exactly(0));
        }
示例#20
0
        public void Start_BlockOnChain_DoesNotReorgWalletManager()
        {
            this.storeSettings.Prune = false;
            this.chain = WalletTestsHelpers.PrepareChainWithBlock();
            this.walletManager.Setup(w => w.WalletTipHash)
            .Returns(this.chain.Tip.Header.GetHash());

            var walletSyncManager = new WalletSyncManager(this.LoggerFactory.Object, this.walletManager.Object, this.chain, Network.StratisMain,
                                                          this.blockStoreCache.Object, this.storeSettings, this.nodeLifetime.Object);

            walletSyncManager.Start();

            this.walletManager.Verify(w => w.GetFirstWalletBlockLocator(), Times.Exactly(0));
            this.walletManager.Verify(w => w.RemoveBlocks(It.IsAny <ChainedHeader>()), Times.Exactly(0));
        }
示例#21
0
        public TumbleBitManager(ILoggerFactory loggerFactory, WalletManager walletManager, WatchOnlyWalletManager watchOnlyWalletManager, ConcurrentChain chain, Network network, Signals signals, WalletTransactionHandler walletTransactionHandler, BlockStoreManager blockStoreManager, MempoolManager mempoolManager, WalletSyncManager walletSyncManager)
        {
            this.walletManager            = walletManager;
            this.watchOnlyWalletManager   = watchOnlyWalletManager;
            this.walletSyncManager        = walletSyncManager;
            this.walletTransactionHandler = walletTransactionHandler;
            this.chain             = chain;
            this.signals           = signals;
            this.network           = network;
            this.loggerFactory     = loggerFactory;
            this.logger            = loggerFactory.CreateLogger(this.GetType().FullName);
            this.blockStoreManager = blockStoreManager;
            this.mempoolManager    = mempoolManager;

            this.tumblingState = new TumblingState(loggerFactory, this.chain, this.walletManager, this.watchOnlyWalletManager, this.network, this.walletTransactionHandler, this.blockStoreManager, this.mempoolManager, this.walletSyncManager);
        }
示例#22
0
 public TumblingState(ILoggerFactory loggerFactory,
                      ConcurrentChain chain,
                      WalletManager walletManager,
                      WatchOnlyWalletManager watchOnlyWalletManager,
                      Network network,
                      WalletTransactionHandler walletTransactionHandler,
                      BlockStoreManager blockStoreManager,
                      MempoolManager mempoolManager,
                      WalletSyncManager walletSyncManager)
 {
     this.logger                   = loggerFactory.CreateLogger(this.GetType().FullName);
     this.chain                    = chain;
     this.walletManager            = walletManager;
     this.watchOnlyWalletManager   = watchOnlyWalletManager;
     this.coinType                 = (CoinType)network.Consensus.CoinType;
     this.walletTransactionHandler = walletTransactionHandler;
     this.blockStoreManager        = blockStoreManager;
     this.mempoolManager           = mempoolManager;
     this.walletSyncManager        = walletSyncManager;
 }
示例#23
0
        public TumbleBitManager(
            ILoggerFactory loggerFactory,
            NodeSettings nodeSettings,
            IWalletManager walletManager,
            IWatchOnlyWalletManager watchOnlyWalletManager,
            ConcurrentChain chain,
            Network network,
            Signals signals,
            IWalletTransactionHandler walletTransactionHandler,
            IWalletSyncManager walletSyncManager,
            IWalletFeePolicy walletFeePolicy,
            IBroadcasterManager broadcasterManager,
            FullNode fullNode,
            ConfigurationOptionWrapper <string> registrationStoreDirectory)
        {
            this.walletManager            = walletManager as WalletManager;
            this.watchOnlyWalletManager   = watchOnlyWalletManager;
            this.walletSyncManager        = walletSyncManager as WalletSyncManager;
            this.walletTransactionHandler = walletTransactionHandler as WalletTransactionHandler;
            this.chain              = chain;
            this.signals            = signals;
            this.network            = network;
            this.nodeSettings       = nodeSettings;
            this.loggerFactory      = loggerFactory;
            this.logger             = loggerFactory.CreateLogger(this.GetType().FullName);
            this.walletFeePolicy    = walletFeePolicy;
            this.broadcasterManager = broadcasterManager;
            this.fullNode           = fullNode;

            if (registrationStoreDirectory.Value != null)
            {
                this.registrationStore = new RegistrationStore(registrationStoreDirectory.Value);
            }
            else
            {
                this.registrationStore = new RegistrationStore(this.nodeSettings.DataDir);
            }

            this.tumblingState = new TumblingState(
                this.loggerFactory,
                this.chain,
                this.walletManager,
                this.watchOnlyWalletManager,
                this.network,
                this.walletTransactionHandler,
                this.walletSyncManager,
                this.walletFeePolicy,
                this.nodeSettings,
                this.broadcasterManager);

            // Load saved state e.g. previously selected server
            if (File.Exists(this.tumblingState.GetStateFilePath()))
            {
                try
                {
                    this.tumblingState.LoadStateFromMemory();
                }
                catch (NullReferenceException)
                {
                    // The file appears to get corrupted sometimes, not clear why
                    // May be if the node is not shut down correctly
                }
            }

            this.tumblingState.Save();

            // Remove the progress file from previous session as it is now stale
            ProgressInfo.RemoveProgressFile();
        }
示例#24
0
        public TumbleBitManager(
            ILoggerFactory loggerFactory,
            NodeSettings nodeSettings,
            IWalletManager walletManager,
            IWatchOnlyWalletManager watchOnlyWalletManager,
            ConcurrentChain chain,
            Network network,
            Signals signals,
            IWalletTransactionHandler walletTransactionHandler,
            IWalletSyncManager walletSyncManager,
            IWalletFeePolicy walletFeePolicy,
            IBroadcasterManager broadcasterManager,
            FullNode fullNode,
            ConfigurationOptionWrapper <string>[] configurationOptions)
        {
            this.walletManager            = walletManager as WalletManager;
            this.watchOnlyWalletManager   = watchOnlyWalletManager;
            this.walletSyncManager        = walletSyncManager as WalletSyncManager;
            this.walletTransactionHandler = walletTransactionHandler as WalletTransactionHandler;
            this.chain              = chain;
            this.signals            = signals;
            this.network            = network;
            this.nodeSettings       = nodeSettings;
            this.loggerFactory      = loggerFactory;
            this.logger             = loggerFactory.CreateLogger(this.GetType().FullName);
            this.walletFeePolicy    = walletFeePolicy;
            this.broadcasterManager = broadcasterManager;
            this.connectionManager  = fullNode.ConnectionManager as ConnectionManager;
            this.fullNode           = fullNode;

            foreach (var option in configurationOptions)
            {
                if (option.Name.Equals("RegistrationStoreDirectory"))
                {
                    if (option.Value != null)
                    {
                        this.registrationStore = new RegistrationStore(option.Value);
                    }
                    else
                    {
                        this.registrationStore = new RegistrationStore(this.nodeSettings.DataDir);
                    }
                }

                if (option.Name.Equals("MasterNodeUri"))
                {
                    if (option.Value != null)
                    {
                        this.TumblerAddress = option.Value;
                    }
                }
            }

            this.tumblingState = new TumblingState(
                this.loggerFactory,
                this.chain,
                this.walletManager,
                this.watchOnlyWalletManager,
                this.network,
                this.walletTransactionHandler,
                this.walletSyncManager,
                this.walletFeePolicy,
                this.nodeSettings,
                this.broadcasterManager,
                this.connectionManager);

            // Load saved state e.g. previously selected server
            if (File.Exists(this.tumblingState.GetStateFilePath()))
            {
                try
                {
                    this.tumblingState.LoadStateFromMemory();
                }
                catch (NullReferenceException)
                {
                    // The file appears to get corrupted sometimes, not clear why
                    // May be if the node is not shut down correctly
                }
            }

            this.tumblingState.Save();

            // If there was a server address saved, that means we were previously
            // connected to it, and should try to reconnect to it by default when
            // the connect method is invoked by the UI
            if ((this.TumblerAddress == null) && (this.tumblingState.TumblerUri != null))
            {
                this.TumblerAddress = this.tumblingState.TumblerUri.ToString();
            }

            // Remove the progress file from previous session as it is now stale
            ProgressInfo.RemoveProgressFile();
        }