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