public void SignTransactionTest() { var keyManager = KeyManager.CreateNew(out _, "", Network.Main); var destinationProvider = new InternalDestinationProvider(keyManager); var keyChain = new KeyChain(keyManager, new Kitchen("")); var coinDestination = destinationProvider.GetNextDestinations(1).First(); var coin = new Coin(BitcoinFactory.CreateOutPoint(), new TxOut(Money.Coins(1.0m), coinDestination)); var ownershipProof = keyChain.GetOwnershipProof(coinDestination, new CoinJoinInputCommitmentData("test", uint256.One)); var transaction = Transaction.Create(Network.Main); // the transaction doesn't contain the input that we request to be signed. Assert.Throws <ArgumentException>(() => keyChain.Sign(transaction, coin, ownershipProof)); transaction.Inputs.Add(coin.Outpoint); var signedTx = keyChain.Sign(transaction, coin, ownershipProof); Assert.True(signedTx.HasWitness); }
public async Task SignTransactionAsync() { WabiSabiConfig config = new(); Round round = WabiSabiFactory.CreateRound(config); var password = "******"; var km = ServiceFactory.CreateKeyManager(password); var keyChain = new KeyChain(km, new Kitchen(password)); var destinationProvider = new InternalDestinationProvider(km); var coins = destinationProvider.GetNextDestinations(2) .Select(dest => ( Coin: new Coin(BitcoinFactory.CreateOutPoint(), new TxOut(Money.Coins(1.0m), dest)), OwnershipProof: keyChain.GetOwnershipProof(dest, new CoinJoinInputCommitmentData("test", uint256.One)))) .ToArray(); Alice alice1 = WabiSabiFactory.CreateAlice(coins[0].Coin, coins[0].OwnershipProof, round: round); round.Alices.Add(alice1); Alice alice2 = WabiSabiFactory.CreateAlice(coins[1].Coin, coins[1].OwnershipProof, round: round); round.Alices.Add(alice2); using Arena arena = await ArenaBuilder.From(config).CreateAndStartAsync(round); var mockRpc = new Mock <IRPCClient>(); using var memoryCache = new MemoryCache(new MemoryCacheOptions()); var idempotencyRequestCache = new IdempotencyRequestCache(memoryCache); using CoinJoinFeeRateStatStore coinJoinFeeRateStatStore = new(config, arena.Rpc); var wabiSabiApi = new WabiSabiController(idempotencyRequestCache, arena, coinJoinFeeRateStatStore); InsecureRandom rnd = InsecureRandom.Instance; var amountClient = new WabiSabiClient(round.AmountCredentialIssuerParameters, rnd, 4300000000000L); var vsizeClient = new WabiSabiClient(round.VsizeCredentialIssuerParameters, rnd, 2000L); var apiClient = new ArenaClient(amountClient, vsizeClient, wabiSabiApi); round.SetPhase(Phase.TransactionSigning); var emptyState = round.Assert <ConstructionState>(); // We can't use ``emptyState.Finalize()` because this is not a valid transaction so we fake it var finalizedEmptyState = new SigningState(round.Parameters, emptyState.Events); // No inputs in the coinjoin. await Assert.ThrowsAsync <ArgumentException>(async() => await apiClient.SignTransactionAsync(round.Id, alice1.Coin, coins[0].OwnershipProof, keyChain, finalizedEmptyState.CreateUnsignedTransaction(), CancellationToken.None)); var oneInput = emptyState.AddInput(alice1.Coin).Finalize(); round.CoinjoinState = oneInput; // Trying to sign coins those are not in the coinjoin. await Assert.ThrowsAsync <InvalidOperationException>(async() => await apiClient.SignTransactionAsync(round.Id, alice2.Coin, coins[1].OwnershipProof, keyChain, oneInput.CreateUnsignedTransaction(), CancellationToken.None)); var twoInputs = emptyState.AddInput(alice1.Coin).AddInput(alice2.Coin).Finalize(); round.CoinjoinState = twoInputs; Assert.False(round.Assert <SigningState>().IsFullySigned); var unsigned = round.Assert <SigningState>().CreateUnsignedTransaction(); await apiClient.SignTransactionAsync(round.Id, alice1.Coin, coins[0].OwnershipProof, keyChain, unsigned, CancellationToken.None); Assert.True(round.Assert <SigningState>().IsInputSigned(alice1.Coin.Outpoint)); Assert.False(round.Assert <SigningState>().IsInputSigned(alice2.Coin.Outpoint)); Assert.False(round.Assert <SigningState>().IsFullySigned); await apiClient.SignTransactionAsync(round.Id, alice2.Coin, coins[1].OwnershipProof, keyChain, unsigned, CancellationToken.None); Assert.True(round.Assert <SigningState>().IsInputSigned(alice2.Coin.Outpoint)); Assert.True(round.Assert <SigningState>().IsFullySigned); }