Example #1
0
    public async Task StartParticipatingAsync(CancellationToken cancellationToken)
    {
        ThrowIfDisposed();
        var apiClient = new WabiSabiHttpApiClient(HttpClientFactory.NewHttpClientWithDefaultCircuit());

        using var roundStateUpdater = new RoundStateUpdater(TimeSpan.FromSeconds(3), apiClient);
        await roundStateUpdater.StartAsync(cancellationToken).ConfigureAwait(false);

        var coinJoinClient = new CoinJoinClient(
            HttpClientFactory,
            Wallet,
            Wallet,
            roundStateUpdater,
            consolidationMode: true);

        // Run the coinjoin client task.
        var walletHdPubKey = new HdPubKey(Wallet.PubKey, KeyPath.Parse("m/84'/0/0/0/0"), SmartLabel.Empty, KeyState.Clean);

        walletHdPubKey.SetAnonymitySet(1);         // bug if not settled

        if (SplitTransaction is null)
        {
            throw new InvalidOperationException($"{nameof(GenerateCoinsAsync)} has to be called first.");
        }

        var smartCoins = SplitTransaction.Transaction.Outputs.AsIndexedOutputs()
                         .Select(x => new SmartCoin(SplitTransaction, x.N, walletHdPubKey))
                         .ToList();

        // Run the coinjoin client task.
        await coinJoinClient.StartCoinJoinAsync(smartCoins, cancellationToken).ConfigureAwait(false);

        await roundStateUpdater.StopAsync(cancellationToken).ConfigureAwait(false);
    }
        public async Task SoloCoinJoinTest()
        {
            const int InputCount = 2;

            // At the end of the test a coinjoin transaction has to be created and broadcasted.
            var transactionCompleted = new TaskCompletionSource <Transaction>();

            // Total test timeout.
            using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(120));
            cts.Token.Register(() => transactionCompleted.TrySetCanceled(), useSynchronizationContext: false);

            // Create a key manager and use it to create two fake coins.
            var keyManager = KeyManager.CreateNew(out var _, password: "");

            keyManager.AssertCleanKeysIndexed();
            var coins = keyManager.GetKeys()
                        .Take(InputCount)
                        .Select(x => new Coin(
                                    BitcoinFactory.CreateOutPoint(),
                                    new TxOut(Money.Coins(1), x.P2wpkhScript)))
                        .ToArray();

            var httpClient = _apiApplicationFactory.WithWebHostBuilder(builder =>
            {
                builder.ConfigureServices(services =>
                {
                    var rpc = BitcoinFactory.GetMockMinimalRpc();

                    // Make the coordinator to believe that those two coins are real and
                    // that they exist in the blockchain with many confirmations.
                    rpc.OnGetTxOutAsync = (txId, idx, _) => new()
                    {
                        Confirmations    = 101,
                        IsCoinBase       = false,
                        ScriptPubKeyType = "witness_v0_keyhash",
                        TxOut            = coins.Single(x => x.Outpoint.Hash == txId && x.Outpoint.N == idx).TxOut
                    };

                    // Make the coordinator believe that the transaction is being
                    // broadcasted using the RPC interface. Once we receive this tx
                    // (the `SendRawTransationAsync` was invoked) we stop waiting
                    // and finish the waiting tasks to finish the test successfully.
                    rpc.OnSendRawTransactionAsync = (tx) =>
                    {
                        transactionCompleted.SetResult(tx);
                        return(tx.GetHash());
                    };

                    // Instruct the coodinator DI container to use these two scoped
                    // services to build everything (wabisabi controller, arena, etc)
                    services.AddScoped <IRPCClient>(s => rpc);
                    services.AddScoped <WabiSabiConfig>(s => new WabiSabiConfig {
                        MaxInputCountByRound = InputCount
                    });
                });
            }).CreateClient();

            // Create the coinjoin client
            var apiClient = _apiApplicationFactory.CreateWabiSabiHttpApiClient(httpClient);

            using var roundStateUpdater = new RoundStateUpdater(TimeSpan.FromSeconds(1), apiClient);
            await roundStateUpdater.StartAsync(CancellationToken.None);

            var kitchen = new Kitchen();

            kitchen.Cook("");

            var coinJoinClient = new CoinJoinClient(apiClient, coins, kitchen, keyManager, roundStateUpdater);

            // Run the coinjoin client task.
            await coinJoinClient.StartCoinJoinAsync(cts.Token);

            var boadcastedTx = await transactionCompleted.Task.ConfigureAwait(false);             // wait for the transaction to be broadcasted.

            Assert.NotNull(boadcastedTx);

            await roundStateUpdater.StopAsync(CancellationToken.None);
        }