Пример #1
0
        public Wallet(string dataDir, Network network, KeyManager keyManager)
        {
            DataDir    = Guard.NotNullOrEmptyOrWhitespace(nameof(dataDir), dataDir);
            Network    = Guard.NotNull(nameof(network), network);
            KeyManager = Guard.NotNull(nameof(keyManager), keyManager);

            RuntimeParams.SetDataDir(dataDir);
            HandleFiltersLock = new AsyncLock();

            BlockFolderLock = new AsyncLock();
            BlockFolderPath = Path.Combine(dataDir, "Blocks", Network.ToString());
            if (Directory.Exists(BlockFolderPath))
            {
                if (Network == Network.RegTest)
                {
                    Directory.Delete(BlockFolderPath, true);
                    Directory.CreateDirectory(BlockFolderPath);
                }
            }
            else
            {
                Directory.CreateDirectory(BlockFolderPath);
            }
            KeyManager.AssertCleanKeysIndexed();
            KeyManager.AssertLockedInternalKeysIndexed(14);
        }
Пример #2
0
        private volatile bool _disposedValue = false;         // To detect redundant calls

        public RegTestFixture()
        {
            RuntimeParams.SetDataDir(Path.Combine(Common.DataDir, "RegTests", "Backend"));
            RuntimeParams.LoadAsync().GetAwaiter().GetResult();
            var hostedServices = new HostedServices();

            BackendRegTestNode = TestNodeBuilder.CreateAsync(hostedServices, callerFilePath: "RegTests", callerMemberName: "BitcoinCoreData").GetAwaiter().GetResult();

            var testnetBackendDir = EnvironmentHelpers.GetDataDir(Path.Combine("WalletWasabi", "Tests", "RegTests", "Backend"));

            IoHelpers.TryDeleteDirectoryAsync(testnetBackendDir).GetAwaiter().GetResult();
            Thread.Sleep(100);
            Directory.CreateDirectory(testnetBackendDir);
            Thread.Sleep(100);
            var config = new Config(
                BackendRegTestNode.RpcClient.Network,
                BackendRegTestNode.RpcClient.CredentialString.ToString(),
                new IPEndPoint(IPAddress.Loopback, Network.Main.DefaultPort),
                new IPEndPoint(IPAddress.Loopback, Network.TestNet.DefaultPort),
                BackendRegTestNode.P2pEndPoint,
                new IPEndPoint(IPAddress.Loopback, Network.Main.RPCPort),
                new IPEndPoint(IPAddress.Loopback, Network.TestNet.RPCPort),
                BackendRegTestNode.RpcEndPoint);
            var configFilePath = Path.Combine(testnetBackendDir, "Config.json");

            config.SetFilePath(configFilePath);
            config.ToFile();

            var roundConfig         = CreateRoundConfig(Money.Coins(0.1m), Constants.OneDayConfirmationTarget, 0.7, 0.1m, 100, 120, 60, 60, 60, 1, 24, true, 11);
            var roundConfigFilePath = Path.Combine(testnetBackendDir, "CcjRoundConfig.json");

            roundConfig.SetFilePath(roundConfigFilePath);
            roundConfig.ToFile();

            var conf = new ConfigurationBuilder()
                       .AddInMemoryCollection(new[] { new KeyValuePair <string, string>("datadir", testnetBackendDir) })
                       .Build();

            BackendEndPoint       = $"http://localhost:{CryptoHelpers.RandomInt(37130, 37999)}/";
            BackendEndPointUri    = new Uri(BackendEndPoint);
            BackendEndPointApiUri = new Uri(BackendEndPointUri, $"/api/v{Constants.BackendMajorVersion}/");

            BackendHost = Host.CreateDefaultBuilder()
                          .ConfigureWebHostDefaults(webBuilder => webBuilder
                                                    .UseStartup <Startup>()
                                                    .UseConfiguration(conf)
                                                    .UseWebRoot("../../../../WalletWasabi.Backend/wwwroot")
                                                    .UseUrls(BackendEndPoint))
                          .Build();

            Global = (Global)BackendHost.Services.GetService(typeof(Global));
            Global.HostedServices = hostedServices;
            var hostInitializationTask = BackendHost.RunWithTasksAsync();

            Logger.LogInfo($"Started Backend webhost: {BackendEndPoint}");

            var delayTask = Task.Delay(3000);

            Task.WaitAny(delayTask, hostInitializationTask);             // Wait for server to initialize (Without this OSX CI will fail)
        }
Пример #3
0
        public async Task InitializeAsync(CancellationToken cancel)
        {
            try
            {
                InitializingChanged?.Invoke(null, true);

                if (!Synchronizer.IsRunning)
                {
                    throw new NotSupportedException($"{nameof(Synchronizer)} is not running.");
                }

                while (!BitcoinStore.IsInitialized)
                {
                    await Task.Delay(100).ConfigureAwait(false);

                    cancel.ThrowIfCancellationRequested();
                }

                await RuntimeParams.LoadAsync();

                using (await HandleFiltersLock.LockAsync())
                {
                    await LoadWalletStateAsync(cancel);
                    await LoadDummyMempoolAsync();
                }
            }
            finally
            {
                InitializingChanged?.Invoke(null, false);
            }
        }
Пример #4
0
        public WalletService(
            BitcoinStore bitcoinStore,
            KeyManager keyManager,
            WasabiSynchronizer syncer,
            CoinJoinClient chaumianClient,
            NodesGroup nodes,
            string workFolderDir,
            ServiceConfiguration serviceConfiguration,
            IFeeProvider feeProvider,
            CoreNode coreNode = null)
        {
            BitcoinStore         = Guard.NotNull(nameof(bitcoinStore), bitcoinStore);
            KeyManager           = Guard.NotNull(nameof(keyManager), keyManager);
            Nodes                = Guard.NotNull(nameof(nodes), nodes);
            Synchronizer         = Guard.NotNull(nameof(syncer), syncer);
            ChaumianClient       = Guard.NotNull(nameof(chaumianClient), chaumianClient);
            ServiceConfiguration = Guard.NotNull(nameof(serviceConfiguration), serviceConfiguration);
            FeeProvider          = Guard.NotNull(nameof(feeProvider), feeProvider);
            CoreNode             = coreNode;

            HandleFiltersLock = new AsyncLock();

            BlocksFolderPath = Path.Combine(workFolderDir, "Blocks", Network.ToString());
            RuntimeParams.SetDataDir(workFolderDir);

            BlockFolderLock = new AsyncLock();

            KeyManager.AssertCleanKeysIndexed();
            KeyManager.AssertLockedInternalKeysIndexed(14);

            TransactionProcessor = new TransactionProcessor(BitcoinStore.TransactionStore, KeyManager, ServiceConfiguration.DustThreshold, ServiceConfiguration.PrivacyLevelStrong);
            Coins = TransactionProcessor.Coins;

            TransactionProcessor.WalletRelevantTransactionProcessed += TransactionProcessor_WalletRelevantTransactionProcessedAsync;

            if (Directory.Exists(BlocksFolderPath))
            {
                if (Synchronizer.Network == Network.RegTest)
                {
                    Directory.Delete(BlocksFolderPath, true);
                    Directory.CreateDirectory(BlocksFolderPath);
                }
            }
            else
            {
                Directory.CreateDirectory(BlocksFolderPath);
            }

            var walletName = "UnnamedWallet";

            if (!string.IsNullOrWhiteSpace(KeyManager.FilePath))
            {
                walletName = Path.GetFileNameWithoutExtension(KeyManager.FilePath);
            }

            BitcoinStore.IndexStore.NewFilter += IndexDownloader_NewFilterAsync;
            BitcoinStore.IndexStore.Reorged   += IndexDownloader_ReorgedAsync;
            BitcoinStore.MempoolService.TransactionReceived += Mempool_TransactionReceived;
        }
Пример #5
0
        public Wallet(
            Network network,
            BitcoinStore bitcoinStore,
            KeyManager keyManager,
            WasabiSynchronizer syncer,
            NodesGroup nodes,
            string workFolderDir,
            ServiceConfiguration serviceConfiguration,
            IFeeProvider feeProvider,
            CoreNode coreNode = null)
        {
            Network              = Guard.NotNull(nameof(network), network);
            BitcoinStore         = Guard.NotNull(nameof(bitcoinStore), bitcoinStore);
            KeyManager           = Guard.NotNull(nameof(keyManager), keyManager);
            Nodes                = Guard.NotNull(nameof(nodes), nodes);
            Synchronizer         = Guard.NotNull(nameof(syncer), syncer);
            ServiceConfiguration = Guard.NotNull(nameof(serviceConfiguration), serviceConfiguration);
            FeeProvider          = Guard.NotNull(nameof(feeProvider), feeProvider);
            CoreNode             = coreNode;

            ChaumianClient    = new CoinJoinClient(Synchronizer, Network, keyManager);
            HandleFiltersLock = new AsyncLock();

            BlocksFolderPath = Path.Combine(workFolderDir, "Blocks", Network.ToString());
            RuntimeParams.SetDataDir(workFolderDir);

            BlockFolderLock = new AsyncLock();

            KeyManager.AssertCleanKeysIndexed();
            KeyManager.AssertLockedInternalKeysIndexed(14);

            TransactionProcessor = new TransactionProcessor(BitcoinStore.TransactionStore, KeyManager, ServiceConfiguration.DustThreshold, ServiceConfiguration.PrivacyLevelStrong);
            Coins = TransactionProcessor.Coins;

            TransactionProcessor.WalletRelevantTransactionProcessed += TransactionProcessor_WalletRelevantTransactionProcessedAsync;
            ChaumianClient.OnDequeue += ChaumianClient_OnDequeue;

            if (Directory.Exists(BlocksFolderPath))
            {
                if (Network == Network.RegTest)
                {
                    Directory.Delete(BlocksFolderPath, true);
                    Directory.CreateDirectory(BlocksFolderPath);
                }
            }
            else
            {
                Directory.CreateDirectory(BlocksFolderPath);
            }

            BitcoinStore.IndexStore.NewFilter += IndexDownloader_NewFilterAsync;
            BitcoinStore.IndexStore.Reorged   += IndexDownloader_ReorgedAsync;
            BitcoinStore.MempoolService.TransactionReceived += Mempool_TransactionReceived;

            State = WalletState.Initialized;
        }
Пример #6
0
    public Wallet(string dataDir, Network network, KeyManager keyManager)
    {
        Guard.NotNullOrEmptyOrWhitespace(nameof(dataDir), dataDir);
        Network    = Guard.NotNull(nameof(network), network);
        KeyManager = Guard.NotNull(nameof(keyManager), keyManager);

        RuntimeParams.SetDataDir(dataDir);
        HandleFiltersLock = new AsyncLock();

        KeyManager.AssertCleanKeysIndexed();
    }
Пример #7
0
    public static async Task LoadAsync()
    {
        try
        {
            if (!File.Exists(FilePath))
            {
                var file = new RuntimeParams();
                await file.SaveAsync().ConfigureAwait(false);
            }

            string jsonString = await File.ReadAllTextAsync(FilePath, Encoding.UTF8).ConfigureAwait(false);

            InternalInstance = JsonConvert.DeserializeObject <RuntimeParams>(jsonString);
            return;
        }
        catch (Exception ex)
        {
            Logger.LogInfo($"Could not load {nameof(RuntimeParams)}: {ex}.");
        }
        InternalInstance = new RuntimeParams();
    }
Пример #8
0
        public async Task TestServicesAsync(string networkString)
        {
            await RuntimeParams.LoadAsync();

            var network          = Network.GetNetwork(networkString);
            var blocksToDownload = new List <uint256>();

            if (network == Network.Main)
            {
                blocksToDownload.Add(new uint256("00000000000000000037c2de35bd85f3e57f14ddd741ce6cee5b28e51473d5d0"));
                blocksToDownload.Add(new uint256("000000000000000000115315a43cb0cdfc4ea54a0e92bed127f4e395e718d8f9"));
                blocksToDownload.Add(new uint256("00000000000000000011b5b042ad0522b69aae36f7de796f563c895714bbd629"));
            }
            else if (network == Network.TestNet)
            {
                blocksToDownload.Add(new uint256("0000000097a664c4084b49faa6fd4417055cb8e5aac480abc31ddc57a8208524"));
                blocksToDownload.Add(new uint256("000000009ed5b82259ecd2aa4cd1f119db8da7a70e7ea78d9c9f603e01f93bcc"));
                blocksToDownload.Add(new uint256("00000000e6da8c2da304e9f5ad99c079df2c3803b49efded3061ecaf206ddc66"));
            }
            else
            {
                throw new NotSupportedNetworkException(network);
            }
            var dataDir = Path.Combine(Global.Instance.DataDir, EnvironmentHelpers.GetCallerFileName());

            BitcoinStore bitcoinStore = new BitcoinStore();
            await bitcoinStore.InitializeAsync(Path.Combine(dataDir, EnvironmentHelpers.GetMethodName()), network);

            var            addressManagerFolderPath = Path.Combine(dataDir, "AddressManager");
            var            addressManagerFilePath   = Path.Combine(addressManagerFolderPath, $"AddressManager{network}.dat");
            var            blocksFolderPath         = Path.Combine(dataDir, "Blocks", network.ToString());
            var            connectionParameters     = new NodeConnectionParameters();
            AddressManager addressManager           = null;

            try
            {
                addressManager = await NBitcoinHelpers.LoadAddressManagerFromPeerFileAsync(addressManagerFilePath);

                Logger.LogInfo($"Loaded {nameof(AddressManager)} from `{addressManagerFilePath}`.");
            }
            catch (DirectoryNotFoundException)
            {
                addressManager = new AddressManager();
            }
            catch (FileNotFoundException)
            {
                addressManager = new AddressManager();
            }
            catch (OverflowException)
            {
                File.Delete(addressManagerFilePath);
                addressManager = new AddressManager();
            }
            catch (FormatException)
            {
                File.Delete(addressManagerFilePath);
                addressManager = new AddressManager();
            }

            connectionParameters.TemplateBehaviors.Add(new AddressManagerBehavior(addressManager));
            connectionParameters.TemplateBehaviors.Add(bitcoinStore.CreateUntrustedP2pBehavior());

            using var nodes = new NodesGroup(network, connectionParameters, requirements: Constants.NodeRequirements);

            KeyManager           keyManager    = KeyManager.CreateNew(out _, "password");
            WasabiSynchronizer   syncer        = new WasabiSynchronizer(network, bitcoinStore, new Uri("http://localhost:12345"), Global.Instance.TorSocks5Endpoint);
            ServiceConfiguration serviceConfig = new ServiceConfiguration(50, 2, 21, 50, new IPEndPoint(IPAddress.Loopback, network.DefaultPort), Money.Coins(Constants.DefaultDustThreshold));
            CachedBlockProvider  blockProvider = new CachedBlockProvider(
                new P2pBlockProvider(nodes, null, syncer, serviceConfig, network),
                new FileSystemBlockRepository(blocksFolderPath, network));

            using Wallet wallet = Wallet.CreateAndRegisterServices(
                      network,
                      bitcoinStore,
                      keyManager,
                      syncer,
                      nodes,
                      dataDir,
                      new ServiceConfiguration(50, 2, 21, 50, new IPEndPoint(IPAddress.Loopback, network.DefaultPort), Money.Coins(Constants.DefaultDustThreshold)),
                      syncer,
                      blockProvider);
            Assert.True(Directory.Exists(blocksFolderPath));

            try
            {
                var mempoolTransactionAwaiter = new EventsAwaiter <SmartTransaction>(
                    h => bitcoinStore.MempoolService.TransactionReceived += h,
                    h => bitcoinStore.MempoolService.TransactionReceived -= h,
                    3);

                var nodeConnectionAwaiter = new EventsAwaiter <NodeEventArgs>(
                    h => nodes.ConnectedNodes.Added += h,
                    h => nodes.ConnectedNodes.Added -= h,
                    3);

                nodes.Connect();

                var downloadTasks = new List <Task <Block> >();
                using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(4));
                foreach (var hash in blocksToDownload)
                {
                    downloadTasks.Add(blockProvider.GetBlockAsync(hash, cts.Token));
                }

                await nodeConnectionAwaiter.WaitAsync(TimeSpan.FromMinutes(3));

                var i         = 0;
                var hashArray = blocksToDownload.ToArray();
                foreach (var block in await Task.WhenAll(downloadTasks))
                {
                    Assert.True(File.Exists(Path.Combine(blocksFolderPath, hashArray[i].ToString())));
                    i++;
                }

                await mempoolTransactionAwaiter.WaitAsync(TimeSpan.FromMinutes(1));
            }
            finally
            {
                // So next test will download the block.
                foreach (var hash in blocksToDownload)
                {
                    await blockProvider.BlockRepository.RemoveAsync(hash, CancellationToken.None);
                }
                if (wallet is { })
Пример #9
0
        public async Task TestServicesAsync(string networkString)
        {
            await RuntimeParams.LoadAsync();

            var network          = Network.GetNetwork(networkString);
            var blocksToDownload = new HashSet <uint256>();

            if (network == Network.Main)
            {
                blocksToDownload.Add(new uint256("00000000000000000037c2de35bd85f3e57f14ddd741ce6cee5b28e51473d5d0"));
                blocksToDownload.Add(new uint256("000000000000000000115315a43cb0cdfc4ea54a0e92bed127f4e395e718d8f9"));
                blocksToDownload.Add(new uint256("00000000000000000011b5b042ad0522b69aae36f7de796f563c895714bbd629"));
            }
            else if (network == Network.TestNet)
            {
                blocksToDownload.Add(new uint256("0000000097a664c4084b49faa6fd4417055cb8e5aac480abc31ddc57a8208524"));
                blocksToDownload.Add(new uint256("000000009ed5b82259ecd2aa4cd1f119db8da7a70e7ea78d9c9f603e01f93bcc"));
                blocksToDownload.Add(new uint256("00000000e6da8c2da304e9f5ad99c079df2c3803b49efded3061ecaf206ddc66"));
            }
            else
            {
                throw new NotSupportedException($"{nameof(Network)} not supported: {network}.");
            }

            var            addressManagerFolderPath = Path.Combine(Global.Instance.DataDir, "AddressManager");
            var            addressManagerFilePath   = Path.Combine(addressManagerFolderPath, $"AddressManager{network}.dat");
            var            blocksFolderPath         = Path.Combine(Global.Instance.DataDir, "Blocks", network.ToString());
            var            connectionParameters     = new NodeConnectionParameters();
            AddressManager addressManager           = null;

            try
            {
                addressManager = await NBitcoinHelpers.LoadAddressManagerFromPeerFileAsync(addressManagerFilePath);

                Logger.LogInfo <AddressManager>($"Loaded {nameof(AddressManager)} from `{addressManagerFilePath}`.");
            }
            catch (DirectoryNotFoundException)
            {
                addressManager = new AddressManager();
            }
            catch (FileNotFoundException)
            {
                addressManager = new AddressManager();
            }
            catch (OverflowException)
            {
                File.Delete(addressManagerFilePath);
                addressManager = new AddressManager();
            }
            catch (FormatException)
            {
                File.Delete(addressManagerFilePath);
                addressManager = new AddressManager();
            }

            connectionParameters.TemplateBehaviors.Add(new AddressManagerBehavior(addressManager));
            var mempoolService = new MempoolService();

            connectionParameters.TemplateBehaviors.Add(new MempoolBehavior(mempoolService));

            var nodes = new NodesGroup(network, connectionParameters, requirements: Constants.NodeRequirements);

            BitcoinStore bitcoinStore = new BitcoinStore();
            await bitcoinStore.InitializeAsync(Path.Combine(Global.Instance.DataDir, EnvironmentHelpers.GetMethodName()), network);

            KeyManager         keyManager    = KeyManager.CreateNew(out _, "password");
            WasabiSynchronizer syncer        = new WasabiSynchronizer(network, bitcoinStore, new Uri("http://localhost:12345"), Global.Instance.TorSocks5Endpoint);
            WalletService      walletService = new WalletService(
                bitcoinStore,
                keyManager,
                syncer,
                new CcjClient(syncer, network, keyManager, new Uri("http://localhost:12345"), Global.Instance.TorSocks5Endpoint),
                mempoolService,
                nodes,
                Global.Instance.DataDir,
                new ServiceConfiguration(50, 2, 21, 50, new IPEndPoint(IPAddress.Loopback, network.DefaultPort), Money.Coins(0.0001m)));

            Assert.True(Directory.Exists(blocksFolderPath));

            try
            {
                mempoolService.TransactionReceived += MempoolService_TransactionReceived;

                nodes.Connect();
                var times = 0;
                while (nodes.ConnectedNodes.Count < 3)
                {
                    if (times > 4200)                     // 7 minutes
                    {
                        throw new TimeoutException("Connection test timed out.");
                    }
                    await Task.Delay(100);

                    times++;
                }

                times = 0;
                while (Interlocked.Read(ref _mempoolTransactionCount) < 3)
                {
                    if (times > 3000)                     // 3 minutes
                    {
                        throw new TimeoutException($"{nameof(MempoolService)} test timed out.");
                    }
                    await Task.Delay(100);

                    times++;
                }

                foreach (var hash in blocksToDownload)
                {
                    using (var cts = new CancellationTokenSource(TimeSpan.FromMinutes(3)))
                    {
                        var block = await walletService.FetchBlockAsync(hash, cts.Token);

                        Assert.True(File.Exists(Path.Combine(blocksFolderPath, hash.ToString())));
                        Logger.LogInfo <P2pTests>($"Full block is downloaded: {hash}.");
                    }
                }
            }
            finally
            {
                nodes.ConnectedNodes.Added         -= ConnectedNodes_Added;
                nodes.ConnectedNodes.Removed       -= ConnectedNodes_Removed;
                mempoolService.TransactionReceived -= MempoolService_TransactionReceived;

                // So next test will download the block.
                foreach (var hash in blocksToDownload)
                {
                    await walletService?.DeleteBlockAsync(hash);
                }
                if (walletService != null)
                {
                    await walletService.StopAsync();
                }

                if (Directory.Exists(blocksFolderPath))
                {
                    Directory.Delete(blocksFolderPath, recursive: true);
                }

                IoHelpers.EnsureContainingDirectoryExists(addressManagerFilePath);
                addressManager?.SavePeerFile(addressManagerFilePath, network);
                Logger.LogInfo <P2pTests>($"Saved {nameof(AddressManager)} to `{addressManagerFilePath}`.");
                nodes?.Dispose();

                await syncer?.StopAsync();
            }
        }