public void PreferSameScript()
    {
        var keys = Enumerable.Range(0, 12)
                   .Select(_ => KeyManager.GenerateNewKey(new SmartLabel("Juan"), KeyState.Clean, false))
                   .ToList();

        var cluster = new Cluster(keys);

        var smartCoins = keys
                         .ConvertAll(key => {
            var coin = BitcoinFactory.CreateSmartCoin(key, 0.2m);
            coin.HdPubKey.Cluster = cluster;
            return(coin);
        });

        smartCoins.Add(BitcoinFactory.CreateSmartCoin(keys[0], 0.11m));

        var selector = new SmartCoinSelector(smartCoins);

        var coinsToSpend = selector.Select(Enumerable.Empty <Coin>(), Money.Coins(0.31m)).Cast <Coin>().ToList();

        Assert.Equal(2, coinsToSpend.Count);
        Assert.Equal(coinsToSpend[0].ScriptPubKey, coinsToSpend[1].ScriptPubKey);
        Assert.Equal(0.31m, coinsToSpend.Sum(x => x.Amount.ToUnit(MoneyUnit.BTC)));
    }
    public void PreferMorePrivateClusterScript()
    {
        var keys1 = Enumerable.Range(0, 5)
                    .Select(_ => KeyManager.GenerateNewKey(new SmartLabel("Juan"), KeyState.Clean, false))
                    .ToList();

        var juanCluster = new Cluster(keys1);

        var coinsKnownByJuan = keys1
                               .ConvertAll(key => {
            var coin = BitcoinFactory.CreateSmartCoin(key, 0.2m);
            coin.HdPubKey.Cluster = juanCluster;
            return(coin);
        });

        var keys2 = Enumerable.Range(0, 2)
                    .Select(_ => KeyManager.GenerateNewKey(new SmartLabel("Juan"), KeyState.Clean, false))
                    .ToList();

        var betoCluster = new Cluster(keys2);

        var coinsKnownByBeto = keys2
                               .ConvertAll(key => {
            var coin = BitcoinFactory.CreateSmartCoin(key, 0.2m);
            coin.HdPubKey.Cluster = betoCluster;
            return(coin);
        });

        var selector     = new SmartCoinSelector(coinsKnownByJuan.Concat(coinsKnownByBeto));
        var coinsToSpend = selector.Select(Enumerable.Empty <Coin>(), Money.Coins(0.3m)).Cast <Coin>().ToList();

        Assert.Equal(2, coinsToSpend.Count);
        Assert.Equal(0.4m, coinsToSpend.Sum(x => x.Amount.ToUnit(MoneyUnit.BTC)));
    }
Example #3
0
    public void SetUsedLabelIncludePrivateFunds()
    {
        var selection = new LabelSelectionViewModel(Money.Parse("1.5"));

        var pockets = new List <Pocket>();

        pockets.AddPocket(1.0M, out _, "Dan");

        var privateCoins = new[]
        {
            BitcoinFactory.CreateSmartCoin(LabelTestExtensions.NewKey(anonymitySet: 999), 0.5m),
            BitcoinFactory.CreateSmartCoin(LabelTestExtensions.NewKey(anonymitySet: 999), 0.5m),
        };
        var coinsView = new CoinsView(privateCoins.ToArray());
        var pocket    = new Pocket((SmartLabel.Empty, coinsView));

        pockets.Add(pocket);

        selection.Reset(pockets.ToArray());

        var output = selection.AutoSelectPockets("Dan");

        selection.SetUsedLabel(output.SelectMany(x => x.Coins), privateThreshold: 10);

        Assert.True(selection.EnoughSelected);
    }
    public void PreferLessCoinsOverExactAmount()
    {
        var keys = Enumerable.Range(0, 10)
                   .Select(_ => KeyManager.GenerateNewKey(new SmartLabel("Juan"), KeyState.Clean, false))
                   .ToList();

        var cluster = new Cluster(keys);

        var smartCoins = keys
                         .Select((key, i) => {
            var coin = BitcoinFactory.CreateSmartCoin(key, 0.1m * (i + 1));
            coin.HdPubKey.Cluster = cluster;
            return(coin);
        })
                         .ToList();

        smartCoins.Add(BitcoinFactory.CreateSmartCoin(keys[0], 0.11m));

        var selector = new SmartCoinSelector(smartCoins);

        var someCoins    = smartCoins.Select(x => x.Coin);
        var coinsToSpend = selector.Select(someCoins, Money.Coins(0.41m));

        var theOnlyOne = Assert.Single(coinsToSpend.Cast <Coin>());

        Assert.Equal(0.5m, theOnlyOne.Amount.ToUnit(MoneyUnit.BTC));
    }
Example #5
0
    public static SmartCoin CreateCoin(decimal amount, string label = "", int anonymitySet = 1)
    {
        var coin = BitcoinFactory.CreateSmartCoin(NewKey(label: label, anonymitySet: anonymitySet), amount);

        coin.HdPubKey.SetAnonymitySet(anonymitySet);

        return(coin);
    }
Example #6
0
    public static void AddPocket(this List <Pocket> pockets, decimal amount, out Pocket pocket, params string[] labels)
    {
        var label     = new SmartLabel(labels);
        var coinsView = new CoinsView(new[] { BitcoinFactory.CreateSmartCoin(NewKey(label), amount) });

        pocket = new Pocket((label, coinsView));
        pockets.Add(pocket);
    }
    public async Task AliceTimesoutAsync()
    {
        // Alice times out when its deadline is reached.
        WabiSabiConfig cfg       = new();
        var            round     = WabiSabiFactory.CreateRound(cfg);
        var            km        = ServiceFactory.CreateKeyManager("");
        var            key       = BitcoinFactory.CreateHdPubKey(km);
        var            smartCoin = BitcoinFactory.CreateSmartCoin(key, 10m);
        var            rpc       = WabiSabiFactory.CreatePreconfiguredRpcClient(smartCoin.Coin);

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

        var arenaClient = WabiSabiFactory.CreateArenaClient(arena);

        using RoundStateUpdater roundStateUpdater = new(TimeSpan.FromSeconds(2), arena);
        await roundStateUpdater.StartAsync(CancellationToken.None);

        // Register Alices.
        var keyChain = new KeyChain(km, new Kitchen(""));

        using CancellationTokenSource cancellationTokenSource = new();
        var task = AliceClient.CreateRegisterAndConfirmInputAsync(RoundState.FromRound(round), arenaClient, smartCoin, keyChain, roundStateUpdater, cancellationTokenSource.Token);

        while (round.Alices.Count == 0)
        {
            await Task.Delay(10);
        }

        var alice = Assert.Single(round.Alices);

        alice.Deadline = DateTimeOffset.UtcNow - TimeSpan.FromMilliseconds(1);
        await arena.TriggerAndWaitRoundAsync(TimeSpan.FromSeconds(21));

        Assert.Empty(round.Alices);

        cancellationTokenSource.Cancel();

        try
        {
            await task;
            throw new InvalidOperationException("The operation should throw!");
        }
        catch (Exception exc)
        {
            Assert.True(exc is OperationCanceledException or WabiSabiProtocolException);
        }

        await roundStateUpdater.StopAsync(CancellationToken.None);

        await arena.StopAsync(CancellationToken.None);
    }
Example #8
0
        public async Task CreateNewAsync()
        {
            var config = new WabiSabiConfig {
                MaxInputCountByRound = 1
            };
            var       round = WabiSabiFactory.CreateRound(config);
            var       km    = ServiceFactory.CreateKeyManager("");
            var       key   = BitcoinFactory.CreateHdPubKey(km);
            SmartCoin coin1 = BitcoinFactory.CreateSmartCoin(key, Money.Coins(1m));

            var mockRpc = WabiSabiFactory.CreatePreconfiguredRpcClient(coin1.Coin);

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

            await arena.TriggerAndWaitRoundAsync(TimeSpan.FromMinutes(1));

            await using var coordinator = new ArenaRequestHandler(config, new Prison(), arena, mockRpc.Object);
            var wabiSabiApi = new WabiSabiController(coordinator);

            var insecureRandom = new InsecureRandom();
            var roundState     = RoundState.FromRound(round);
            var arenaClient    = new ArenaClient(
                roundState.CreateAmountCredentialClient(insecureRandom),
                roundState.CreateVsizeCredentialClient(insecureRandom),
                wabiSabiApi);

            Assert.Equal(Phase.InputRegistration, arena.Rounds.First().Phase);

            var bitcoinSecret = km.GetSecrets("", coin1.ScriptPubKey).Single().PrivateKey.GetBitcoinSecret(Network.Main);

            var aliceClient = new AliceClient(round.Id, arenaClient, coin1.Coin, round.FeeRate, bitcoinSecret);
            await aliceClient.RegisterInputAsync(CancellationToken.None);

            using RoundStateUpdater roundStateUpdater = new(TimeSpan.FromSeconds(2), wabiSabiApi);
            Task confirmationTask = aliceClient.ConfirmConnectionAsync(
                TimeSpan.FromSeconds(1),
                new long[] { coin1.EffectiveValue(round.FeeRate) },
                new long[] { roundState.MaxVsizeAllocationPerAlice - coin1.ScriptPubKey.EstimateInputVsize() },
                roundStateUpdater,
                CancellationToken.None);

            await arena.TriggerAndWaitRoundAsync(TimeSpan.FromMinutes(1));

            await confirmationTask;

            Assert.Equal(Phase.ConnectionConfirmation, arena.Rounds.First().Phase);
        }
        public async Task CreateNewAsync()
        {
            var config = new WabiSabiConfig {
                MaxInputCountByRound = 1
            };
            var round = WabiSabiFactory.CreateRound(config);

            using Arena arena = await WabiSabiFactory.CreateAndStartArenaAsync(config, round);

            await arena.TriggerAndWaitRoundAsync(TimeSpan.FromMinutes(1));

            var       km       = ServiceFactory.CreateKeyManager("");
            var       key      = BitcoinFactory.CreateHdPubKey(km);
            SmartCoin coin1    = BitcoinFactory.CreateSmartCoin(key, Money.Coins(1m));
            var       outpoint = coin1.OutPoint;

            var mockRpc = new Mock <IRPCClient>();

            mockRpc.Setup(rpc => rpc.GetTxOutAsync(outpoint.Hash, (int)outpoint.N, true))
            .ReturnsAsync(new NBitcoin.RPC.GetTxOutResponse
            {
                IsCoinBase    = false,
                Confirmations = coin1.Height,
                TxOut         = coin1.TxOut,
            });

            await using var coordinator = new ArenaRequestHandler(config, new Prison(), arena, mockRpc.Object);

            CredentialPool amountCredentialPool = new();
            CredentialPool weightCredentialPool = new();
            var            arenaClient          = new ArenaClient(round.AmountCredentialIssuerParameters, round.WeightCredentialIssuerParameters, amountCredentialPool, weightCredentialPool, coordinator, new InsecureRandom());

            Assert.Equal(Phase.InputRegistration, arena.Rounds.First().Value.Phase);

            var bitcoinSecret = km.GetSecrets("", coin1.ScriptPubKey).Single().PrivateKey.GetBitcoinSecret(Network.Main);
            var aliceClient   = await AliceClient.CreateNewAsync(arenaClient, new[] { coin1.Coin }, bitcoinSecret, round.Id, round.Hash, round.FeeRate);

            Task confirmationTask = aliceClient.ConfirmConnectionAsync(TimeSpan.FromSeconds(3), CancellationToken.None);

            await arena.TriggerAndWaitRoundAsync(TimeSpan.FromMinutes(1));

            await confirmationTask;

            Assert.Equal(Phase.ConnectionConfirmation, arena.Rounds.First().Value.Phase);
        }
    public void SelectNonPrivateCoinFromOneCoinSetOfCoins()
    {
        // This test is to make sure that we select the only non-private coin when it is the only coin in the wallet.
        const int AnonymitySet      = 10;
        var       km                = KeyManager.CreateNew(out _, "", Network.Main);
        var       coinsToSelectFrom = Enumerable
                                      .Empty <SmartCoin>()
                                      .Prepend(BitcoinFactory.CreateSmartCoin(BitcoinFactory.CreateHdPubKey(km), Money.Coins(1m), 0, anonymitySet: AnonymitySet - 1))
                                      .ToList();

        var coins = CoinJoinClient.SelectCoinsForRound(
            coins: coinsToSelectFrom,
            CreateMultipartyTransactionParameters(),
            consolidationMode: false,
            anonScoreTarget: AnonymitySet,
            ConfigureRng(1));

        Assert.Single(coins);
    }
    public void SelectNothingFromFullyPrivateSetOfCoins()
    {
        // This test is to make sure no coins are selected when all coins are private.
        const int AnonymitySet      = 10;
        var       km                = KeyManager.CreateNew(out _, "", Network.Main);
        var       coinsToSelectFrom = Enumerable
                                      .Range(0, 10)
                                      .Select(i => BitcoinFactory.CreateSmartCoin(BitcoinFactory.CreateHdPubKey(km), Money.Coins(1m), 0, anonymitySet: AnonymitySet + 1))
                                      .ToList();

        var coins = CoinJoinClient.SelectCoinsForRound(
            coins: coinsToSelectFrom,
            CreateMultipartyTransactionParameters(),
            consolidationMode: false,
            anonScoreTarget: AnonymitySet,
            ConfigureRng(5));

        Assert.Empty(coins);
    }
    public void TwoNonPrivateCoinInSetOfCoins()
    {
        const int MinAnonimitySet = 10;
        var       km = KeyManager.CreateNew(out _, "", Network.Main);
        var       coinsToSelectFrom = Enumerable
                                      .Empty <SmartCoin>()
                                      .Prepend(BitcoinFactory.CreateSmartCoin(BitcoinFactory.CreateHdPubKey(km), Money.Coins(1m), 0, anonymitySet: MinAnonimitySet - 1))
                                      .Prepend(BitcoinFactory.CreateSmartCoin(BitcoinFactory.CreateHdPubKey(km), Money.Coins(1m), 0, anonymitySet: MinAnonimitySet - 1))
                                      .ToList();

        var coins = CoinJoinClient.SelectCoinsForRound(
            coins: coinsToSelectFrom,
            CreateMultipartyTransactionParameters(),
            consolidationMode: false,
            minAnonScoreTarget: MinAnonimitySet,
            ConfigureRng(1));

        Assert.Single(coins);
    }
        public async Task AliceTimesoutAsync()
        {
            // Alice times out when its deadline is reached.
            WabiSabiConfig cfg       = new();
            var            round     = WabiSabiFactory.CreateRound(cfg);
            var            km        = ServiceFactory.CreateKeyManager("");
            var            key       = BitcoinFactory.CreateHdPubKey(km);
            var            smartCoin = BitcoinFactory.CreateSmartCoin(key, 10m);
            var            rpc       = WabiSabiFactory.CreatePreconfiguredRpcClient(smartCoin.Coin);

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

            var arenaClient = WabiSabiFactory.CreateArenaClient(arena);

            using RoundStateUpdater roundStateUpdater = new(TimeSpan.FromSeconds(2), arena);
            await roundStateUpdater.StartAsync(CancellationToken.None);

            // Register Alices.
            using var identificationKey = new Key();
            var esk = km.GetSecrets("", smartCoin.ScriptPubKey).Single();

            using CancellationTokenSource cancellationTokenSource = new();
            var task = AliceClient.CreateRegisterAndConfirmInputAsync(RoundState.FromRound(round), arenaClient, smartCoin, esk.PrivateKey.GetBitcoinSecret(round.Network), identificationKey, roundStateUpdater, cancellationTokenSource.Token);

            while (round.Alices.Count == 0)
            {
                await Task.Delay(10);
            }

            var alice = Assert.Single(round.Alices);

            alice.Deadline = DateTimeOffset.UtcNow - TimeSpan.FromMilliseconds(1);
            await arena.TriggerAndWaitRoundAsync(TimeSpan.FromSeconds(21));

            Assert.Empty(round.Alices);

            cancellationTokenSource.Cancel();
            await Assert.ThrowsAsync <OperationCanceledException>(async() => await task);

            await roundStateUpdater.StopAsync(CancellationToken.None);

            await arena.StopAsync(CancellationToken.None);
        }
    public void SelectTwoNonPrivateCoinsFromTwoCoinsSetOfCoinsConsolidationMode()
    {
        // This test is to make sure that we select more than one non-private coin.
        const int AnonymitySet      = 10;
        var       km                = KeyManager.CreateNew(out _, "", Network.Main);
        var       coinsToSelectFrom = Enumerable
                                      .Empty <SmartCoin>()
                                      .Prepend(BitcoinFactory.CreateSmartCoin(BitcoinFactory.CreateHdPubKey(km), Money.Coins(1m), 0, anonymitySet: AnonymitySet - 1))
                                      .Prepend(BitcoinFactory.CreateSmartCoin(BitcoinFactory.CreateHdPubKey(km), Money.Coins(1m), 0, anonymitySet: AnonymitySet - 1))
                                      .ToList();

        var coins = CoinJoinClient.SelectCoinsForRound(
            coins: coinsToSelectFrom,
            CreateMultipartyTransactionParameters(),
            consolidationMode: true,
            anonScoreTarget: AnonymitySet,
            ConfigureRng(1));

        Assert.Equal(2, coins.Count);
    }
    public void OnlyOneNonPrivateCoinInBigSetOfCoinsConsolidationMode()
    {
        const int MinAnonimitySet = 10;
        var       km = KeyManager.CreateNew(out _, "", Network.Main);
        SmartCoin smallerAnonCoin   = BitcoinFactory.CreateSmartCoin(BitcoinFactory.CreateHdPubKey(km), Money.Coins(1m), 0, anonymitySet: MinAnonimitySet - 1);
        var       coinsToSelectFrom = Enumerable
                                      .Range(0, 10)
                                      .Select(i => BitcoinFactory.CreateSmartCoin(BitcoinFactory.CreateHdPubKey(km), Money.Coins(1m), 0, anonymitySet: MinAnonimitySet + 1))
                                      .Prepend(smallerAnonCoin)
                                      .ToList();

        var coins = CoinJoinClient.SelectCoinsForRound(
            coins: coinsToSelectFrom,
            CreateMultipartyTransactionParameters(),
            consolidationMode: true,
            minAnonScoreTarget: MinAnonimitySet,
            ConfigureRng(5));

        Assert.Contains(smallerAnonCoin, coins);
        Assert.Equal(10, coins.Count);
    }
    public void SelectsOnlyOneCoinWhenPossible()
    {
        var keys = Enumerable.Range(0, 9)
                   .Select(_ => KeyManager.GenerateNewKey(new SmartLabel("Juan"), KeyState.Clean, false));

        var cluster = new Cluster(keys);

        var smartCoins = keys
                         .Select((key, i) => {
            var coin = BitcoinFactory.CreateSmartCoin(key, 0.1m * (i + 1));
            coin.HdPubKey.Cluster = cluster;
            return(coin);
        });

        var selector     = new SmartCoinSelector(smartCoins);
        var coinsToSpend = selector.Select(Enumerable.Empty <Coin>(), Money.Coins(0.3m));

        var theOnlyOne = Assert.Single(coinsToSpend.Cast <Coin>());

        Assert.Equal(0.3m, theOnlyOne.Amount.ToUnit(MoneyUnit.BTC));
    }
Example #17
0
    public void SetUsedLabelIgnoreCase()
    {
        var selection = new LabelSelectionViewModel(Money.Parse("1.0"));

        var pockets = new List <Pocket>();

        pockets.AddPocket(1.0M, out var pocket1, "Dan");
        pockets.AddPocket(1.0M, out var pocket2, "Lucas");

        selection.Reset(pockets.ToArray());

        var output = selection.AutoSelectPockets("Dan");

        Assert.Contains(pocket1, output);
        Assert.DoesNotContain(pocket2, output);

        var hdpk     = LabelTestExtensions.NewKey("dan");
        var usedCoin = BitcoinFactory.CreateSmartCoin(hdpk, 1.0M);

        selection.SetUsedLabel(new[] { usedCoin }, privateThreshold: 10);

        Assert.Contains(selection.GetLabel("Lucas"), selection.LabelsBlackList);
        Assert.Contains(selection.GetLabel("Dan"), selection.LabelsWhiteList);
    }
Example #18
0
        public async Task RegisterOutputTestAsync()
        {
            var config = new WabiSabiConfig {
                MaxInputCountByRound = 1
            };
            var       round = WabiSabiFactory.CreateRound(config);
            var       km    = ServiceFactory.CreateKeyManager("");
            var       key   = BitcoinFactory.CreateHdPubKey(km);
            SmartCoin coin1 = BitcoinFactory.CreateSmartCoin(key, Money.Coins(2m));

            var mockRpc = WabiSabiFactory.CreatePreconfiguredRpcClient(coin1.Coin);

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

            await arena.TriggerAndWaitRoundAsync(TimeSpan.FromMinutes(1));

            ZeroCredentialPool zeroAmountCredential = new();
            ZeroCredentialPool zeroVsizeCredential  = new();

            await using var coordinator = new ArenaRequestHandler(config, new Prison(), arena, mockRpc.Object);
            var insecureRandom   = new InsecureRandom();
            var wabiSabiApi      = new WabiSabiController(coordinator);
            var roundState       = RoundState.FromRound(round);
            var aliceArenaClient = new ArenaClient(
                roundState.CreateAmountCredentialClient(zeroAmountCredential, insecureRandom),
                roundState.CreateVsizeCredentialClient(zeroVsizeCredential, insecureRandom),
                wabiSabiApi);
            var bobArenaClient = new ArenaClient(
                roundState.CreateAmountCredentialClient(zeroAmountCredential, insecureRandom),
                roundState.CreateVsizeCredentialClient(zeroVsizeCredential, insecureRandom),
                wabiSabiApi);

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

            var bitcoinSecret = km.GetSecrets("", coin1.ScriptPubKey).Single().PrivateKey.GetBitcoinSecret(Network.Main);

            var aliceClient = new AliceClient(round.Id, aliceArenaClient, coin1.Coin, round.FeeRate, bitcoinSecret);
            await aliceClient.RegisterInputAsync(CancellationToken.None);

            Task confirmationTask = aliceClient.ConfirmConnectionAsync(TimeSpan.FromSeconds(1), roundState.MaxVsizeAllocationPerAlice, CancellationToken.None);

            await arena.TriggerAndWaitRoundAsync(TimeSpan.FromMinutes(1));

            await confirmationTask;

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

            await arena.TriggerAndWaitRoundAsync(TimeSpan.FromMinutes(1));

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

            using var destinationKey = new Key();
            var destination = destinationKey.PubKey.WitHash.ScriptPubKey;

            var bobClient = new BobClient(round.Id, bobArenaClient);

            await bobClient.RegisterOutputAsync(Money.Coins(0.25m), destination, aliceClient.RealAmountCredentials, aliceClient.RealVsizeCredentials, CancellationToken.None);

            var bob = Assert.Single(round.Bobs);

            Assert.Equal(destination, bob.Script);
            Assert.Equal(25_000_000, bob.CredentialAmount);
        }
Example #19
0
    public async Task RegisterOutputTestAsync()
    {
        var config = new WabiSabiConfig {
            MaxInputCountByRound = 1
        };
        var       round = WabiSabiFactory.CreateRound(config);
        var       km    = ServiceFactory.CreateKeyManager("");
        var       key   = BitcoinFactory.CreateHdPubKey(km);
        SmartCoin coin1 = BitcoinFactory.CreateSmartCoin(key, Money.Coins(2m));

        var mockRpc = WabiSabiFactory.CreatePreconfiguredRpcClient(coin1.Coin);

        using Arena arena = await ArenaBuilder.From(config).With(mockRpc).CreateAndStartAsync(round);

        await arena.TriggerAndWaitRoundAsync(TimeSpan.FromMinutes(1));

        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 insecureRandom   = InsecureRandom.Instance;
        var            roundState       = RoundState.FromRound(round);
        var            aliceArenaClient = new ArenaClient(
            roundState.CreateAmountCredentialClient(insecureRandom),
            roundState.CreateVsizeCredentialClient(insecureRandom),
            wabiSabiApi);
        var bobArenaClient = new ArenaClient(
            roundState.CreateAmountCredentialClient(insecureRandom),
            roundState.CreateVsizeCredentialClient(insecureRandom),
            wabiSabiApi);

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

        using RoundStateUpdater roundStateUpdater = new(TimeSpan.FromSeconds(2), wabiSabiApi);
        await roundStateUpdater.StartAsync(CancellationToken.None);

        var keyChain = new KeyChain(km, new Kitchen(""));
        var task     = AliceClient.CreateRegisterAndConfirmInputAsync(RoundState.FromRound(round), aliceArenaClient, coin1, keyChain, roundStateUpdater, CancellationToken.None);

        do
        {
            await arena.TriggerAndWaitRoundAsync(TimeSpan.FromMinutes(1));
        }while (round.Phase != Phase.ConnectionConfirmation);

        var aliceClient = await task;

        await arena.TriggerAndWaitRoundAsync(TimeSpan.FromMinutes(1));

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

        using var destinationKey = new Key();
        var destination = destinationKey.PubKey.WitHash.ScriptPubKey;

        var bobClient = new BobClient(round.Id, bobArenaClient);

        await bobClient.RegisterOutputAsync(
            destination,
            aliceClient.IssuedAmountCredentials.Take(ProtocolConstants.CredentialNumber),
            aliceClient.IssuedVsizeCredentials.Take(ProtocolConstants.CredentialNumber),
            CancellationToken.None);

        var bob = Assert.Single(round.Bobs);

        Assert.Equal(destination, bob.Script);

        var credentialAmountSum = aliceClient.IssuedAmountCredentials.Take(ProtocolConstants.CredentialNumber).Sum(x => x.Value);

        Assert.Equal(credentialAmountSum, bob.CredentialAmount);
    }
Example #20
0
        public async Task RegisterOutputTestAsync()
        {
            var config = new WabiSabiConfig {
                MaxInputCountByRound = 1
            };
            var       round = WabiSabiFactory.CreateRound(config);
            var       km    = ServiceFactory.CreateKeyManager("");
            var       key   = BitcoinFactory.CreateHdPubKey(km);
            SmartCoin coin1 = BitcoinFactory.CreateSmartCoin(key, Money.Coins(2m));

            var mockRpc = WabiSabiFactory.CreatePreconfiguredRpcClient(coin1.Coin);

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

            await arena.TriggerAndWaitRoundAsync(TimeSpan.FromMinutes(1));

            await using var coordinator = new ArenaRequestHandler(config, new Prison(), arena, mockRpc.Object);
            var insecureRandom   = new InsecureRandom();
            var wabiSabiApi      = new WabiSabiController(coordinator);
            var roundState       = RoundState.FromRound(round);
            var aliceArenaClient = new ArenaClient(
                roundState.CreateAmountCredentialClient(insecureRandom),
                roundState.CreateVsizeCredentialClient(insecureRandom),
                wabiSabiApi);
            var bobArenaClient = new ArenaClient(
                roundState.CreateAmountCredentialClient(insecureRandom),
                roundState.CreateVsizeCredentialClient(insecureRandom),
                wabiSabiApi);

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

            var bitcoinSecret = km.GetSecrets("", coin1.ScriptPubKey).Single().PrivateKey.GetBitcoinSecret(Network.Main);

            using RoundStateUpdater roundStateUpdater = new(TimeSpan.FromSeconds(2), wabiSabiApi);
            await roundStateUpdater.StartAsync(CancellationToken.None);

            var task = AliceClient.CreateRegisterAndConfirmInputAsync(RoundState.FromRound(round), aliceArenaClient, coin1, bitcoinSecret, roundStateUpdater, CancellationToken.None);

            do
            {
                await arena.TriggerAndWaitRoundAsync(TimeSpan.FromMinutes(1));
            }while (round.Phase != Phase.ConnectionConfirmation);

            var aliceClient = await task;

            await arena.TriggerAndWaitRoundAsync(TimeSpan.FromMinutes(1));

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

            using var destinationKey = new Key();
            var destination = destinationKey.PubKey.WitHash.ScriptPubKey;

            var bobClient = new BobClient(round.Id, bobArenaClient);

            await bobClient.RegisterOutputAsync(
                destination,
                aliceClient.IssuedAmountCredentials.Take(ProtocolConstants.CredentialNumber),
                aliceClient.IssuedVsizeCredentials.Take(ProtocolConstants.CredentialNumber),
                CancellationToken.None);

            var bob = Assert.Single(round.Bobs);

            Assert.Equal(destination, bob.Script);

            var credentialAmountSum = aliceClient.IssuedAmountCredentials.Take(ProtocolConstants.CredentialNumber).Sum(x => x.Value);

            Assert.Equal(credentialAmountSum, bob.CredentialAmount);
        }