public async Task AliceDeadlineUpdatedAsync()
    {
        // Alice's deadline is updated by connection confirmation.
        WabiSabiConfig cfg   = new();
        var            round = WabiSabiFactory.CreateRound(cfg);
        var            alice = WabiSabiFactory.CreateAlice(round);

        round.Alices.Add(alice);
        using Arena arena = await ArenaBuilder.From(cfg).CreateAndStartAsync(round);

        var req = WabiSabiFactory.CreateConnectionConfirmationRequest(round);

        Assert.Single(round.Alices);
        DateTimeOffset preDeadline = DateTimeOffset.UtcNow - TimeSpan.FromMilliseconds(1);

        alice.Deadline = preDeadline;
        await arena.ConfirmConnectionAsync(req, CancellationToken.None);

        await arena.TriggerAndWaitRoundAsync(TimeSpan.FromSeconds(21));

        Assert.Single(round.Alices);
        Assert.NotEqual(preDeadline, alice.Deadline);

        await arena.StopAsync(CancellationToken.None);
    }
        public async Task WrongPhaseAsync()
        {
            WabiSabiConfig cfg = new();

            using Arena arena = await WabiSabiFactory.CreateAndStartArenaAsync(cfg);

            var round       = arena.Rounds.First();
            var alice       = WabiSabiFactory.CreateAlice(round);
            var preDeadline = alice.Deadline;

            round.Alices.Add(alice);
            await arena.TriggerAndWaitRoundAsync(TimeSpan.FromSeconds(21)).ConfigureAwait(false);

            var req = WabiSabiFactory.CreateConnectionConfirmationRequest(round);

            foreach (Phase phase in Enum.GetValues(typeof(Phase)))
            {
                if (phase != Phase.InputRegistration && phase != Phase.ConnectionConfirmation)
                {
                    round.SetPhase(phase);
                    var ex = await Assert.ThrowsAsync <WabiSabiProtocolException>(
                        async() => await arena.ConfirmConnectionAsync(req, CancellationToken.None));

                    Assert.Equal(WabiSabiProtocolErrorCode.WrongPhase, ex.ErrorCode);
                }
            }
            Assert.Equal(preDeadline, alice.Deadline);
            Assert.False(alice.ConfirmedConnection);

            await arena.StopAsync(CancellationToken.None);
        }
        public async Task SuccessInConnectionConfirmationPhaseAsync()
        {
            WabiSabiConfig cfg   = new();
            var            round = WabiSabiFactory.CreateRound(cfg);

            round.SetPhase(Phase.ConnectionConfirmation);
            var alice       = WabiSabiFactory.CreateAlice(round);
            var preDeadline = alice.Deadline;

            round.Alices.Add(alice);
            using Arena arena = await WabiSabiFactory.CreateAndStartArenaAsync(cfg, round);

            var req = WabiSabiFactory.CreateConnectionConfirmationRequest(round);

            var resp = await arena.ConfirmConnectionAsync(req, CancellationToken.None);

            Assert.NotNull(resp);
            Assert.NotNull(resp.ZeroAmountCredentials);
            Assert.NotNull(resp.ZeroVsizeCredentials);
            Assert.NotNull(resp.RealAmountCredentials);
            Assert.NotNull(resp.RealVsizeCredentials);
            Assert.Equal(preDeadline, alice.Deadline);
            Assert.True(alice.ConfirmedConnection);

            await arena.StopAsync(CancellationToken.None);
        }
示例#4
0
    public async Task SuccessInInputRegistrationPhaseAsync()
    {
        WabiSabiConfig cfg         = new();
        var            round       = WabiSabiFactory.CreateRound(cfg);
        var            alice       = WabiSabiFactory.CreateAlice(round);
        var            preDeadline = alice.Deadline;

        round.Alices.Add(alice);
        using Arena arena = await ArenaBuilder.From(cfg).CreateAndStartAsync(round);

        var req = WabiSabiFactory.CreateConnectionConfirmationRequest(round);
        var minAliceDeadline = DateTimeOffset.UtcNow + cfg.ConnectionConfirmationTimeout * 0.9;

        var resp = await arena.ConfirmConnectionAsync(req, CancellationToken.None);

        Assert.NotNull(resp);
        Assert.NotNull(resp.ZeroAmountCredentials);
        Assert.NotNull(resp.ZeroVsizeCredentials);
        Assert.Null(resp.RealAmountCredentials);
        Assert.Null(resp.RealVsizeCredentials);
        Assert.NotEqual(preDeadline, alice.Deadline);
        Assert.True(minAliceDeadline <= alice.Deadline);
        Assert.False(alice.ConfirmedConnection);

        await arena.StopAsync(CancellationToken.None);
    }
        public async Task RoundNotFoundAsync()
        {
            var cfg = new WabiSabiConfig();
            var nonExistingRound = WabiSabiFactory.CreateRound(cfg);

            using Arena arena = await WabiSabiFactory.CreateAndStartArenaAsync();

            var req = WabiSabiFactory.CreateConnectionConfirmationRequest(nonExistingRound);

            var ex = await Assert.ThrowsAsync <WabiSabiProtocolException>(
                async() => await arena.ConfirmConnectionAsync(req, CancellationToken.None));

            Assert.Equal(WabiSabiProtocolErrorCode.RoundNotFound, ex.ErrorCode);

            await arena.StopAsync(CancellationToken.None);
        }
        public async Task TimeoutSufficientPeersAsync()
        {
            WabiSabiConfig cfg = new()
            {
                MaxInputCountByRound           = 2,
                MinInputCountByRoundMultiplier = 1,
                TransactionSigningTimeout      = TimeSpan.Zero,
                OutputRegistrationTimeout      = TimeSpan.Zero
            };
            var mockRpc = new MockRpcClient();

            mockRpc.OnSendRawTransactionAsync = _ => throw new RPCException(RPCErrorCode.RPC_TRANSACTION_REJECTED, "", null);

            using Arena arena = await WabiSabiFactory.CreateAndStartArenaAsync(cfg, mockRpc);

            // Create the round.
            await arena.TriggerAndWaitRoundAsync(TimeSpan.FromSeconds(21));

            var round = Assert.Single(arena.Rounds).Value;

            // Register Alices.
            using Key key1 = new();
            using Key key2 = new();
            var irreq1 = WabiSabiFactory.CreateInputsRegistrationRequest(key1, round);
            var irres1 = await arena.RegisterInputAsync(
                irreq1.RoundId,
                irreq1.InputRoundSignaturePairs.ToDictionary(x => new Coin(x.Input, new TxOut(Money.Coins(1), key1.PubKey.GetSegwitAddress(Network.Main))), x => x.RoundSignature),
                irreq1.ZeroAmountCredentialRequests,
                irreq1.ZeroWeightCredentialRequests);

            var irreq2 = WabiSabiFactory.CreateInputsRegistrationRequest(key2, round);
            var irres2 = await arena.RegisterInputAsync(
                irreq2.RoundId,
                irreq2.InputRoundSignaturePairs.ToDictionary(x => new Coin(x.Input, new TxOut(Money.Coins(1), key2.PubKey.GetSegwitAddress(Network.Main))), x => x.RoundSignature),
                irreq2.ZeroAmountCredentialRequests,
                irreq2.ZeroWeightCredentialRequests);

            await arena.TriggerAndWaitRoundAsync(TimeSpan.FromSeconds(21));

            Assert.Equal(Phase.ConnectionConfirmation, round.Phase);
            var alice1 = round.Alices.Single(x => x.Id == irres1.AliceId);
            var alice2 = round.Alices.Single(x => x.Id == irres2.AliceId);

            // Confirm connections.
            var ccresps = new List <(ConnectionConfirmationResponse resp, WabiSabiClient amountClient, WabiSabiClient weightClient, Guid aliceId)>();
            var ccreq1  = WabiSabiFactory.CreateConnectionConfirmationRequest(round, irres1);
            var ccresp1 = await arena.ConfirmConnectionAsync(ccreq1.request);

            ccresps.Add((ccresp1, ccreq1.amountClient, ccreq1.weightClient, irres2.AliceId));
            ccreq1.amountClient.HandleResponse(ccresp1.RealAmountCredentials !, ccreq1.amountValidation);
            ccreq1.weightClient.HandleResponse(ccresp1.RealWeightCredentials !, ccreq1.weightValidation);

            var ccreq2  = WabiSabiFactory.CreateConnectionConfirmationRequest(round, irres2);
            var ccresp2 = await arena.ConfirmConnectionAsync(ccreq2.request);

            ccresps.Add((ccresp2, ccreq2.amountClient, ccreq2.weightClient, irres1.AliceId));
            ccreq2.amountClient.HandleResponse(ccresp2.RealAmountCredentials !, ccreq2.amountValidation);
            ccreq2.weightClient.HandleResponse(ccresp2.RealWeightCredentials !, ccreq2.weightValidation);
            await arena.TriggerAndWaitRoundAsync(TimeSpan.FromSeconds(21));

            Assert.Equal(Phase.OutputRegistration, round.Phase);

            // Register outputs.
            foreach (var orreq in WabiSabiFactory.CreateOutputRegistrationRequests(round, ccresps))
            {
                var orresp = await arena.RegisterOutputAsync(orreq);
            }

            // Make sure not all alices signed.
            var alice3 = WabiSabiFactory.CreateAlice();

            alice3.ConfirmedConnection = true;
            round.Alices.Add(alice3);
            await arena.TriggerAndWaitRoundAsync(TimeSpan.FromSeconds(21));

            Assert.Equal(Phase.TransactionSigning, round.Phase);

            var signedCoinJoin = round.Coinjoin.Clone();
            var coin1          = alice1.Coins.First();
            var coin2          = alice2.Coins.First();
            var idx1           = signedCoinJoin.Inputs.IndexOf(signedCoinJoin.Inputs.Single(x => x.PrevOut == coin1.Outpoint));
            var idx2           = signedCoinJoin.Inputs.IndexOf(signedCoinJoin.Inputs.Single(x => x.PrevOut == coin2.Outpoint));

            signedCoinJoin.Sign(key1.GetBitcoinSecret(Network.Main), coin1);
            var txsigreq1 = new TransactionSignaturesRequest(round.Id, new[] { new InputWitnessPair((uint)idx1, signedCoinJoin.Inputs[idx1].WitScript) });

            signedCoinJoin.Sign(key2.GetBitcoinSecret(Network.Main), coin2);
            var txsigreq2 = new TransactionSignaturesRequest(round.Id, new[] { new InputWitnessPair((uint)idx2, signedCoinJoin.Inputs[idx2].WitScript) });

            await arena.SignTransactionAsync(txsigreq1);

            await arena.SignTransactionAsync(txsigreq2);

            await arena.TriggerAndWaitRoundAsync(TimeSpan.FromSeconds(21));

            Assert.DoesNotContain(round.Id, arena.Rounds.Keys);
            Assert.Single(arena.Rounds.Where(x => x.Value.IsBlameRound));
            var badOutpoint = alice3.Coins.Select(x => x.Outpoint).First();

            Assert.Contains(badOutpoint, arena.Prison.GetInmates().Select(x => x.Utxo));

            var blameRound = arena.Rounds.Single(x => x.Value.IsBlameRound).Value;

            Assert.True(blameRound.IsBlameRound);
            Assert.NotNull(blameRound.BlameOf);
            Assert.Equal(round.Id, blameRound.BlameOf?.Id);

            var whitelist = blameRound.BlameWhitelist;

            Assert.Contains(alice1.Coins.Select(x => x.Outpoint).First(), whitelist);
            Assert.Contains(alice2.Coins.Select(x => x.Outpoint).First(), whitelist);
            Assert.DoesNotContain(badOutpoint, whitelist);

            await arena.StopAsync(CancellationToken.None);
        }
    }
        public async Task EveryoneSignedAsync()
        {
            WabiSabiConfig cfg = new()
            {
                MaxInputCountByRound           = 2,
                MinInputCountByRoundMultiplier = 0.5
            };

            using Arena arena = await WabiSabiFactory.CreateAndStartArenaAsync(cfg);

            // Create the round.
            await arena.TriggerAndWaitRoundAsync(TimeSpan.FromSeconds(21));

            var round = Assert.Single(arena.Rounds).Value;

            // Register Alices.
            using Key key1 = new();
            using Key key2 = new();
            var irreq1 = WabiSabiFactory.CreateInputsRegistrationRequest(key1, round);
            var irres1 = await arena.RegisterInputAsync(
                irreq1.RoundId,
                irreq1.InputRoundSignaturePairs.ToDictionary(x => new Coin(x.Input, new TxOut(Money.Coins(1), key1.PubKey.GetSegwitAddress(Network.Main))), x => x.RoundSignature),
                irreq1.ZeroAmountCredentialRequests,
                irreq1.ZeroWeightCredentialRequests);

            var irreq2 = WabiSabiFactory.CreateInputsRegistrationRequest(key2, round);
            var irres2 = await arena.RegisterInputAsync(
                irreq2.RoundId,
                irreq2.InputRoundSignaturePairs.ToDictionary(x => new Coin(x.Input, new TxOut(Money.Coins(1), key2.PubKey.GetSegwitAddress(Network.Main))), x => x.RoundSignature),
                irreq2.ZeroAmountCredentialRequests,
                irreq2.ZeroWeightCredentialRequests);

            await arena.TriggerAndWaitRoundAsync(TimeSpan.FromSeconds(21));

            Assert.Equal(Phase.ConnectionConfirmation, round.Phase);
            var alice1 = round.Alices.Single(x => x.Id == irres1.AliceId);
            var alice2 = round.Alices.Single(x => x.Id == irres2.AliceId);

            // Confirm connections.
            var ccresps = new List <(ConnectionConfirmationResponse resp, WabiSabiClient amountClient, WabiSabiClient weightClient, Guid aliceId)>();
            var ccreq1  = WabiSabiFactory.CreateConnectionConfirmationRequest(round, irres1);
            var ccresp1 = await arena.ConfirmConnectionAsync(ccreq1.request);

            ccresps.Add((ccresp1, ccreq1.amountClient, ccreq1.weightClient, irres2.AliceId));
            ccreq1.amountClient.HandleResponse(ccresp1.RealAmountCredentials !, ccreq1.amountValidation);
            ccreq1.weightClient.HandleResponse(ccresp1.RealWeightCredentials !, ccreq1.weightValidation);

            var ccreq2  = WabiSabiFactory.CreateConnectionConfirmationRequest(round, irres2);
            var ccresp2 = await arena.ConfirmConnectionAsync(ccreq2.request);

            ccresps.Add((ccresp2, ccreq2.amountClient, ccreq2.weightClient, irres1.AliceId));
            ccreq2.amountClient.HandleResponse(ccresp2.RealAmountCredentials !, ccreq2.amountValidation);
            ccreq2.weightClient.HandleResponse(ccresp2.RealWeightCredentials !, ccreq2.weightValidation);
            await arena.TriggerAndWaitRoundAsync(TimeSpan.FromSeconds(21));

            Assert.Equal(Phase.OutputRegistration, round.Phase);

            // Register outputs.
            foreach (var orreq in WabiSabiFactory.CreateOutputRegistrationRequests(round, ccresps))
            {
                var orresp = await arena.RegisterOutputAsync(orreq);
            }
            await arena.TriggerAndWaitRoundAsync(TimeSpan.FromSeconds(21));

            Assert.Equal(Phase.TransactionSigning, round.Phase);

            var signedCoinJoin = round.Coinjoin.Clone();
            var coin1          = alice1.Coins.First();
            var coin2          = alice2.Coins.First();
            var idx1           = signedCoinJoin.Inputs.IndexOf(signedCoinJoin.Inputs.Single(x => x.PrevOut == coin1.Outpoint));
            var idx2           = signedCoinJoin.Inputs.IndexOf(signedCoinJoin.Inputs.Single(x => x.PrevOut == coin2.Outpoint));

            signedCoinJoin.Sign(key1.GetBitcoinSecret(Network.Main), coin1);
            var txsigreq1 = new TransactionSignaturesRequest(round.Id, new[] { new InputWitnessPair((uint)idx1, signedCoinJoin.Inputs[idx1].WitScript) });

            signedCoinJoin.Sign(key2.GetBitcoinSecret(Network.Main), coin2);
            var txsigreq2 = new TransactionSignaturesRequest(round.Id, new[] { new InputWitnessPair((uint)idx2, signedCoinJoin.Inputs[idx2].WitScript) });

            await arena.SignTransactionAsync(txsigreq1);

            await arena.SignTransactionAsync(txsigreq2);

            await arena.TriggerAndWaitRoundAsync(TimeSpan.FromSeconds(21));

            Assert.Equal(Phase.TransactionBroadcasting, round.Phase);

            await arena.StopAsync(CancellationToken.None);
        }
        public async Task AlicesSpentAsync()
        {
            WabiSabiConfig cfg = new()
            {
                MaxInputCountByRound           = 2,
                MinInputCountByRoundMultiplier = 0.5
            };
            var mockRpc = new MockRpcClient();

            mockRpc.OnSendRawTransactionAsync = _ => throw new RPCException(RPCErrorCode.RPC_TRANSACTION_REJECTED, "", null);
            mockRpc.OnGetTxOutAsync ??= (_, _, _) => null;

            using Arena arena = await WabiSabiFactory.CreateAndStartArenaAsync(cfg, mockRpc);

            // Create the round.
            await arena.TriggerAndWaitRoundAsync(TimeSpan.FromSeconds(21));

            var round = Assert.Single(arena.Rounds).Value;

            // Register Alices.
            using Key key1 = new();
            using Key key2 = new();
            var irreq1 = WabiSabiFactory.CreateInputsRegistrationRequest(key1, round);
            var irres1 = await arena.RegisterInputAsync(
                irreq1.RoundId,
                irreq1.InputRoundSignaturePairs.ToDictionary(x => new Coin(x.Input, new TxOut(Money.Coins(1), key1.PubKey.GetSegwitAddress(Network.Main))), x => x.RoundSignature),
                irreq1.ZeroAmountCredentialRequests,
                irreq1.ZeroWeightCredentialRequests);

            var irreq2 = WabiSabiFactory.CreateInputsRegistrationRequest(key2, round);
            var irres2 = await arena.RegisterInputAsync(
                irreq2.RoundId,
                irreq2.InputRoundSignaturePairs.ToDictionary(x => new Coin(x.Input, new TxOut(Money.Coins(1), key2.PubKey.GetSegwitAddress(Network.Main))), x => x.RoundSignature),
                irreq2.ZeroAmountCredentialRequests,
                irreq2.ZeroWeightCredentialRequests);

            await arena.TriggerAndWaitRoundAsync(TimeSpan.FromSeconds(21));

            Assert.Equal(Phase.ConnectionConfirmation, round.Phase);
            var alice1 = round.Alices.Single(x => x.Id == irres1.AliceId);
            var alice2 = round.Alices.Single(x => x.Id == irres2.AliceId);

            // Confirm connections.
            var ccresps = new List <(ConnectionConfirmationResponse resp, WabiSabiClient amountClient, WabiSabiClient weightClient, Guid aliceId)>();
            var ccreq1  = WabiSabiFactory.CreateConnectionConfirmationRequest(round, irres1);
            var ccresp1 = await arena.ConfirmConnectionAsync(ccreq1.request);

            ccresps.Add((ccresp1, ccreq1.amountClient, ccreq1.weightClient, irres2.AliceId));
            ccreq1.amountClient.HandleResponse(ccresp1.RealAmountCredentials !, ccreq1.amountValidation);
            ccreq1.weightClient.HandleResponse(ccresp1.RealWeightCredentials !, ccreq1.weightValidation);

            var ccreq2  = WabiSabiFactory.CreateConnectionConfirmationRequest(round, irres2);
            var ccresp2 = await arena.ConfirmConnectionAsync(ccreq2.request);

            ccresps.Add((ccresp2, ccreq2.amountClient, ccreq2.weightClient, irres1.AliceId));
            ccreq2.amountClient.HandleResponse(ccresp2.RealAmountCredentials !, ccreq2.amountValidation);
            ccreq2.weightClient.HandleResponse(ccresp2.RealWeightCredentials !, ccreq2.weightValidation);
            await arena.TriggerAndWaitRoundAsync(TimeSpan.FromSeconds(21));

            Assert.Equal(Phase.OutputRegistration, round.Phase);

            // Register outputs.
            foreach (var orreq in WabiSabiFactory.CreateOutputRegistrationRequests(round, ccresps))
            {
                var orresp = await arena.RegisterOutputAsync(orreq);
            }
            await arena.TriggerAndWaitRoundAsync(TimeSpan.FromSeconds(21));

            Assert.Equal(Phase.TransactionSigning, round.Phase);

            var signedCoinJoin = round.Coinjoin.Clone();
            var coin1          = alice1.Coins.First();
            var coin2          = alice2.Coins.First();
            var idx1           = signedCoinJoin.Inputs.IndexOf(signedCoinJoin.Inputs.Single(x => x.PrevOut == coin1.Outpoint));
            var idx2           = signedCoinJoin.Inputs.IndexOf(signedCoinJoin.Inputs.Single(x => x.PrevOut == coin2.Outpoint));

            signedCoinJoin.Sign(key1.GetBitcoinSecret(Network.Main), coin1);
            var txsigreq1 = new TransactionSignaturesRequest(round.Id, new[] { new InputWitnessPair((uint)idx1, signedCoinJoin.Inputs[idx1].WitScript) });

            signedCoinJoin.Sign(key2.GetBitcoinSecret(Network.Main), coin2);
            var txsigreq2 = new TransactionSignaturesRequest(round.Id, new[] { new InputWitnessPair((uint)idx2, signedCoinJoin.Inputs[idx2].WitScript) });

            await arena.SignTransactionAsync(txsigreq1);

            await arena.SignTransactionAsync(txsigreq2);

            await arena.TriggerAndWaitRoundAsync(TimeSpan.FromSeconds(21));

            Assert.DoesNotContain(round.Id, arena.Rounds.Keys);

            // There should be no inmate, because we aren't punishing spenders with banning
            // as there's no reason to ban already spent UTXOs,
            // the cost of spending the UTXO is the punishment instead.
            Assert.Empty(arena.Prison.GetInmates());

            await arena.StopAsync(CancellationToken.None);
        }
示例#9
0
 public async Task <ConnectionConfirmationResponse> ConfirmConnectionAsync(ConnectionConfirmationRequest request, CancellationToken cancellationToken)
 {
     return(await IdempotencyRequestCache.GetCachedResponseAsync(request, action : (request, token) => Arena.ConfirmConnectionAsync(request, token), cancellationToken));
 }
示例#10
0
        public async Task SomeBobsRegisteredTimeoutAsync()
        {
            WabiSabiConfig cfg = new()
            {
                MaxInputCountByRound           = 2,
                MinInputCountByRoundMultiplier = 0.5,
                OutputRegistrationTimeout      = TimeSpan.Zero
            };

            using Arena arena = await WabiSabiFactory.CreateAndStartArenaAsync(cfg);

            // Create the round.
            await arena.TriggerAndWaitRoundAsync(TimeSpan.FromSeconds(21));

            var round = Assert.Single(arena.Rounds).Value;

            // Register Alices.
            using Key key1 = new();
            var irreq1 = WabiSabiFactory.CreateInputsRegistrationRequest(key1, round);
            var irres1 = await arena.RegisterInputAsync(
                irreq1.RoundId,
                irreq1.InputRoundSignaturePairs.ToDictionary(x => new Coin(x.Input, new TxOut(Money.Coins(1), key1.PubKey.GetSegwitAddress(Network.Main))), x => x.RoundSignature),
                irreq1.ZeroAmountCredentialRequests,
                irreq1.ZeroVsizeCredentialRequests);

            using Key key2 = new();
            var irreq2 = WabiSabiFactory.CreateInputsRegistrationRequest(key2, round);
            var irres2 = await arena.RegisterInputAsync(
                irreq2.RoundId,
                irreq2.InputRoundSignaturePairs.ToDictionary(x => new Coin(x.Input, new TxOut(Money.Coins(1), key2.PubKey.GetSegwitAddress(Network.Main))), x => x.RoundSignature),
                irreq2.ZeroAmountCredentialRequests,
                irreq2.ZeroVsizeCredentialRequests);

            await arena.TriggerAndWaitRoundAsync(TimeSpan.FromSeconds(21));

            Assert.Equal(Phase.ConnectionConfirmation, round.Phase);

            // Confirm connections.
            var ccresps = new List <(ConnectionConfirmationResponse resp, WabiSabiClient amountClient, WabiSabiClient vsizeClient, Guid aliceId)>();

            var ccreq1  = WabiSabiFactory.CreateConnectionConfirmationRequest(round, irres1);
            var ccresp1 = await arena.ConfirmConnectionAsync(ccreq1.request);

            ccresps.Add((ccresp1, ccreq1.amountClient, ccreq1.vsizeClient, irres2.AliceId));
            ccreq1.amountClient.HandleResponse(ccresp1.RealAmountCredentials !, ccreq1.amountValidation);
            ccreq1.vsizeClient.HandleResponse(ccresp1.RealVsizeCredentials !, ccreq1.vsizeValidation);

            var ccreq2  = WabiSabiFactory.CreateConnectionConfirmationRequest(round, irres2);
            var ccresp2 = await arena.ConfirmConnectionAsync(ccreq2.request);

            ccresps.Add((ccresp2, ccreq2.amountClient, ccreq2.vsizeClient, irres1.AliceId));
            ccreq2.amountClient.HandleResponse(ccresp2.RealAmountCredentials !, ccreq2.amountValidation);
            ccreq2.vsizeClient.HandleResponse(ccresp2.RealVsizeCredentials !, ccreq2.vsizeValidation);

            await arena.TriggerAndWaitRoundAsync(TimeSpan.FromSeconds(21));

            Assert.Equal(Phase.OutputRegistration, round.Phase);

            // Register outputs.
            var orresp = await arena.RegisterOutputAsync(WabiSabiFactory.CreateOutputRegistrationRequests(round, ccresps).First());

            await arena.TriggerAndWaitRoundAsync(TimeSpan.FromSeconds(21));

            Assert.Equal(Phase.TransactionSigning, round.Phase);
            Assert.Equal(2, round.Coinjoin.Inputs.Count);
            Assert.Equal(2, round.Coinjoin.Outputs.Count);
            Assert.Contains(cfg.BlameScript, round.Coinjoin.Outputs.Select(x => x.ScriptPubKey));

            await arena.StopAsync(CancellationToken.None);
        }
        public async Task IncorrectRequestedAmountCredentialsAsync()
        {
            WabiSabiConfig cfg   = new();
            var            round = WabiSabiFactory.CreateRound(cfg);

            round.SetPhase(Phase.ConnectionConfirmation);
            var alice = WabiSabiFactory.CreateAlice(round);

            round.Alices.Add(alice);
            using Arena arena = await WabiSabiFactory.CreateAndStartArenaAsync(cfg, round);

            var incorrectAmountCredentials = WabiSabiFactory.CreateRealCredentialRequests(round, Money.Coins(3), null).amountRequest;
            var req = WabiSabiFactory.CreateConnectionConfirmationRequest(round) with {
                RealAmountCredentialRequests = incorrectAmountCredentials
            };

            var ex = await Assert.ThrowsAsync <WabiSabiProtocolException>(async() => await arena.ConfirmConnectionAsync(req, CancellationToken.None));

            Assert.Equal(WabiSabiProtocolErrorCode.IncorrectRequestedAmountCredentials, ex.ErrorCode);
            Assert.False(alice.ConfirmedConnection);

            await arena.StopAsync(CancellationToken.None);
        }
 public Task <ConnectionConfirmationResponse> ConfirmConnectionAsync(ConnectionConfirmationRequest request, CancellationToken cancellationToken)
 => arena.ConfirmConnectionAsync(request);
示例#13
0
    public async Task AliceNotFoundAsync()
    {
        WabiSabiConfig cfg   = new();
        var            round = WabiSabiFactory.CreateRound(cfg);

        using Arena arena = await ArenaBuilder.From(cfg).CreateAndStartAsync(round);

        var req = WabiSabiFactory.CreateConnectionConfirmationRequest(round);
        var ex  = await Assert.ThrowsAsync <WabiSabiProtocolException>(async() => await arena.ConfirmConnectionAsync(req, CancellationToken.None));

        Assert.Equal(WabiSabiProtocolErrorCode.AliceNotFound, ex.ErrorCode);

        await arena.StopAsync(CancellationToken.None);
    }
        public async Task DoesntSwitchImmaturelyAsync()
        {
            WabiSabiConfig cfg = new()
            {
                MaxInputCountByRound           = 2,
                MinInputCountByRoundMultiplier = 0.5
            };

            using Arena arena = await WabiSabiFactory.CreateAndStartArenaAsync(cfg);

            // Create the round.
            await arena.TriggerAndWaitRoundAsync(TimeSpan.FromSeconds(21));

            var round = Assert.Single(arena.Rounds).Value;

            // Register Alices.
            using Key key1 = new();
            var irreq1 = WabiSabiFactory.CreateInputsRegistrationRequest(key1, round);
            var irres1 = await arena.RegisterInputAsync(
                irreq1.RoundId,
                irreq1.InputRoundSignaturePairs.ToDictionary(x => new Coin(x.Input, new TxOut(Money.Coins(1), key1.PubKey.GetSegwitAddress(Network.Main))), x => x.RoundSignature),
                irreq1.ZeroAmountCredentialRequests,
                irreq1.ZeroWeightCredentialRequests);

            using Key key2 = new();
            var irreq2 = WabiSabiFactory.CreateInputsRegistrationRequest(key2, round);
            var irres2 = await arena.RegisterInputAsync(
                irreq2.RoundId,
                irreq2.InputRoundSignaturePairs.ToDictionary(x => new Coin(x.Input, new TxOut(Money.Coins(1), key2.PubKey.GetSegwitAddress(Network.Main))), x => x.RoundSignature),
                irreq2.ZeroAmountCredentialRequests,
                irreq2.ZeroWeightCredentialRequests);

            await arena.TriggerAndWaitRoundAsync(TimeSpan.FromSeconds(21));

            Assert.Equal(Phase.ConnectionConfirmation, round.Phase);

            // Confirm connections.
            var ccresps      = new List <(ConnectionConfirmationResponse resp, WabiSabiClient amountClient, WabiSabiClient weightClient, Guid aliceId)>();
            var ugliSolution = false;

            foreach (var ccreq in WabiSabiFactory.CreateConnectionConfirmationRequests(round, irres1, irres2))
            {
                var ccresp = await arena.ConfirmConnectionAsync(ccreq.request);

                ccresps.Add((ccresp, ccreq.amountClient, ccreq.weightClient, ugliSolution ? irres1.AliceId : irres2.AliceId));
                ugliSolution = true;
                ccreq.amountClient.HandleResponse(ccresp.RealAmountCredentials !, ccreq.amountValidation);
                ccreq.weightClient.HandleResponse(ccresp.RealWeightCredentials !, ccreq.weightValidation);
            }
            await arena.TriggerAndWaitRoundAsync(TimeSpan.FromSeconds(21));

            Assert.Equal(Phase.OutputRegistration, round.Phase);

            // Register outputs.
            var orresp = await arena.RegisterOutputAsync(WabiSabiFactory.CreateOutputRegistrationRequests(round, ccresps).First());

            await arena.TriggerAndWaitRoundAsync(TimeSpan.FromSeconds(21));

            Assert.Equal(Phase.OutputRegistration, round.Phase);

            await arena.StopAsync(CancellationToken.None);
        }
    }