Example #1
0
    public async Task RegisterBannedCoinAsync()
    {
        using CancellationTokenSource timeoutCts = new(TimeSpan.FromMinutes(2));

        var bannedOutPoint = BitcoinFactory.CreateOutPoint();

        var httpClient = _apiApplicationFactory.WithWebHostBuilder(builder =>
                                                                   builder.ConfigureServices(services =>
        {
            var inmate = new Inmate(bannedOutPoint, Punishment.LongBanned, DateTimeOffset.UtcNow, uint256.One);
            services.AddScoped <Prison>(_ => new Prison(new[] { inmate }));
        })).CreateClient();

        var apiClient = await _apiApplicationFactory.CreateArenaClientAsync(httpClient);

        var rounds = (await apiClient.GetStatusAsync(RoundStateRequest.Empty, timeoutCts.Token)).RoundStates;
        var round  = rounds.First(x => x.CoinjoinState is ConstructionState);

        // If an output is not in the utxo dataset then it is not unspent, this
        // means that the output is spent or simply doesn't even exist.
        using var signingKey = new Key();
        var ownershipProof = WabiSabiFactory.CreateOwnershipProof(signingKey, round.Id);

        var ex = await Assert.ThrowsAsync <WabiSabiProtocolException>(async() =>
                                                                      await apiClient.RegisterInputAsync(round.Id, bannedOutPoint, ownershipProof, timeoutCts.Token));

        Assert.Equal(WabiSabiProtocolErrorCode.InputLongBanned, ex.ErrorCode);
        var inputBannedData = Assert.IsType <InputBannedExceptionData>(ex.ExceptionData);

        Assert.True(inputBannedData.BannedUntil > DateTimeOffset.UtcNow);
    }
Example #2
0
    public async Task DoesntUpdateAsync(Network network)
    {
        await using var txStore = new AllTransactionStore(PrepareWorkDir(), network);
        await txStore.InitializeAsync(ensureBackwardsCompatibility : false);

        var tx = BitcoinFactory.CreateSmartTransaction();

        Assert.False(txStore.TryUpdate(tx));

        // Assert TryUpdate didn't modify anything.

        Assert.NotNull(txStore.ConfirmedStore);
        Assert.NotNull(txStore.MempoolStore);
        Assert.Empty(txStore.GetTransactions());
        Assert.Empty(txStore.GetTransactionHashes());
        Assert.Empty(txStore.MempoolStore.GetTransactions());
        Assert.Empty(txStore.MempoolStore.GetTransactionHashes());
        Assert.Empty(txStore.ConfirmedStore.GetTransactions());
        Assert.Empty(txStore.ConfirmedStore.GetTransactionHashes());

        uint256 txHash = BitcoinFactory.CreateSmartTransaction().GetHash();

        Assert.False(txStore.Contains(txHash));
        Assert.True(txStore.IsEmpty());
        Assert.False(txStore.TryGetTransaction(txHash, out _));
    }
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));
    }
    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)));
    }
        public async Task ReleasesInmatesAsync()
        {
            var workDir = Common.GetWorkDir();
            await IoHelpers.TryDeleteDirectoryAsync(workDir);

            // Create prison.
            CoordinatorParameters coordinatorParameters = new(workDir);

            coordinatorParameters.RuntimeCoordinatorConfig.ReleaseUtxoFromPrisonAfter = TimeSpan.FromMilliseconds(1);

            using var w = new Warden(coordinatorParameters.UtxoWardenPeriod, coordinatorParameters.PrisonFilePath, coordinatorParameters.RuntimeCoordinatorConfig);
            await w.StartAsync(CancellationToken.None);

            var i1 = new Inmate(BitcoinFactory.CreateOutPoint(), Punishment.Noted, DateTimeOffset.FromUnixTimeSeconds(DateTimeOffset.UtcNow.ToUnixTimeSeconds()), uint256.Zero);
            var i2 = new Inmate(BitcoinFactory.CreateOutPoint(), Punishment.Banned, DateTimeOffset.FromUnixTimeSeconds(DateTimeOffset.UtcNow.ToUnixTimeSeconds()), uint256.Zero);
            var p  = w.Prison;

            p.Punish(i1);
            p.Punish(i2);
            Assert.NotEmpty(p.GetInmates());

            // Wait until releases from prison.
            await w.TriggerAndWaitRoundAsync(TimeSpan.FromSeconds(7));

            Assert.Empty(p.GetInmates());
            await w.StopAsync(CancellationToken.None);
        }
        public void CanMergeSingleOperations()
        {
            var tx = BitcoinFactory.CreateSmartTransaction();

            var append = new Append(tx);
            var unmergedAppendOperations        = new[] { append };
            var mergedOperations                = OperationMerger.Merge(unmergedAppendOperations);
            var expectedOperation               = Assert.Single(mergedOperations);
            var expectedAppendOperationInstance = Assert.IsType <Append>(expectedOperation);
            var expectedTx = Assert.Single(expectedAppendOperationInstance.Transactions);

            Assert.Equal(expectedTx, tx);

            var remove = new Remove(tx.GetHash());
            var unmergedRemoveOperations = new[] { remove };

            mergedOperations  = OperationMerger.Merge(unmergedRemoveOperations);
            expectedOperation = Assert.Single(mergedOperations);
            var expectedRemoveOperationInstance = Assert.IsType <Remove>(expectedOperation);
            var expectedTxHash = Assert.Single(expectedRemoveOperationInstance.Transactions);

            Assert.Equal(expectedTxHash, tx.GetHash());

            var update = new Update(tx);
            var unmergedUpdateOperations = new[] { update };

            mergedOperations  = OperationMerger.Merge(unmergedUpdateOperations);
            expectedOperation = Assert.Single(mergedOperations);
            var expectedUpdateOperationInstance = Assert.IsType <Update>(expectedOperation);

            expectedTx = Assert.Single(expectedUpdateOperationInstance.Transactions);
            Assert.Equal(expectedTx, tx);
        }
Example #9
0
        public async Task SuccessAsync()
        {
            WabiSabiConfig cfg              = new();
            var            round            = WabiSabiFactory.CreateRound(cfg);
            var            initialRemaining = round.RemainingInputVsizeAllocation;
            var            alice            = WabiSabiFactory.CreateAlice(round);

            round.Alices.Add(alice);
            Assert.True(round.RemainingInputVsizeAllocation < initialRemaining);

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

            await using ArenaRequestHandler handler = new(cfg, new Prison(), arena, new MockRpcClient());

            // There's no such alice yet, so success.
            var req = new InputsRemovalRequest(round.Id, BitcoinFactory.CreateUint256());
            await handler.RemoveInputAsync(req, CancellationToken.None);

            // There was the alice we want to remove so success.
            req = new InputsRemovalRequest(round.Id, alice.Id);
            await handler.RemoveInputAsync(req, CancellationToken.None);

            // Ensure that removing an alice freed up the input vsize
            // allocation from the round
            Assert.Equal(initialRemaining, round.RemainingInputVsizeAllocation);

            await arena.StopAsync(CancellationToken.None);
        }
Example #10
0
    public async Task CanInitializeEmptyAsync(Network network)
    {
        var dir = PrepareWorkDir();

        await using var txStore = new AllTransactionStore(dir, network);
        await txStore.InitializeAsync(ensureBackwardsCompatibility : false);

        Assert.NotNull(txStore.ConfirmedStore);
        Assert.NotNull(txStore.MempoolStore);
        Assert.Empty(txStore.GetTransactions());
        Assert.Empty(txStore.GetTransactionHashes());
        Assert.Empty(txStore.MempoolStore.GetTransactions());
        Assert.Empty(txStore.MempoolStore.GetTransactionHashes());
        Assert.Empty(txStore.ConfirmedStore.GetTransactions());
        Assert.Empty(txStore.ConfirmedStore.GetTransactionHashes());

        uint256 txHash = BitcoinFactory.CreateSmartTransaction().GetHash();

        Assert.False(txStore.Contains(txHash));
        Assert.True(txStore.IsEmpty());
        Assert.False(txStore.TryGetTransaction(txHash, out _));

        var mempoolFile    = Path.Combine(dir, "Mempool", "Transactions.dat");
        var txFile         = Path.Combine(dir, "ConfirmedTransactions", Constants.ConfirmedTransactionsVersion, "Transactions.dat");
        var mempoolContent = await File.ReadAllBytesAsync(mempoolFile);

        var txContent = await File.ReadAllBytesAsync(txFile);

        Assert.True(File.Exists(mempoolFile));
        Assert.True(File.Exists(txFile));
        Assert.Empty(mempoolContent);
        Assert.Empty(txContent);
    }
        public async Task NoPrisonSerializationAsync()
        {
            // Don't serialize when there's no change.
            var workDir = Common.GetWorkDir();
            await IoHelpers.TryDeleteDirectoryAsync(workDir);

            // Create prison.
            CoordinatorParameters coordinatorParameters = new(workDir);

            using var w = new Warden(coordinatorParameters.UtxoWardenPeriod, coordinatorParameters.PrisonFilePath, coordinatorParameters.RuntimeCoordinatorConfig);
            await w.StartAsync(CancellationToken.None);

            var i1 = new Inmate(BitcoinFactory.CreateOutPoint(), Punishment.Noted, DateTimeOffset.FromUnixTimeSeconds(DateTimeOffset.UtcNow.ToUnixTimeSeconds()), uint256.Zero);
            var i2 = new Inmate(BitcoinFactory.CreateOutPoint(), Punishment.Banned, DateTimeOffset.FromUnixTimeSeconds(DateTimeOffset.UtcNow.ToUnixTimeSeconds()), uint256.Zero);

            w.Prison.Punish(i1);
            w.Prison.Punish(i2);

            // Wait until serializes.
            await w.TriggerAndWaitRoundAsync(TimeSpan.FromSeconds(7));

            // Make sure it does not serialize again as there was no change.
            File.Delete(w.PrisonFilePath);
            await w.TriggerAndWaitRoundAsync(TimeSpan.FromSeconds(7));

            Assert.False(File.Exists(w.PrisonFilePath));
            await w.StopAsync(CancellationToken.None);
        }
Example #12
0
    public async Task InputRegistrationFullAsync()
    {
        WabiSabiConfig cfg   = new() { MaxInputCountByRound = 3 };
        var            round = WabiSabiFactory.CreateRound(cfg);

        using Key key = new();
        var ownershipProof = WabiSabiFactory.CreateOwnershipProof(key, round.Id);

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

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

        round.Alices.Add(WabiSabiFactory.CreateAlice(round));
        round.Alices.Add(WabiSabiFactory.CreateAlice(round));
        round.Alices.Add(WabiSabiFactory.CreateAlice(round));

        var arenaClient = WabiSabiFactory.CreateArenaClient(arena);
        var ex          = await Assert.ThrowsAsync <WrongPhaseException>(
            async() => await arenaClient.RegisterInputAsync(round.Id, BitcoinFactory.CreateOutPoint(), ownershipProof, CancellationToken.None));

        Assert.Equal(WabiSabiProtocolErrorCode.WrongPhase, ex.ErrorCode);
        Assert.Equal(Phase.InputRegistration, round.Phase);

        await arena.StopAsync(CancellationToken.None);
    }
Example #13
0
    public async Task InputUnconfirmedAsync()
    {
        using Key key = new();
        WabiSabiConfig cfg            = new();
        var            round          = WabiSabiFactory.CreateRound(cfg);
        var            ownershipProof = WabiSabiFactory.CreateOwnershipProof(key, round.Id);

        var mockRpc = new Mock <IRPCClient>();

        mockRpc.Setup(rpc => rpc.GetTxOutAsync(It.IsAny <uint256>(), It.IsAny <int>(), It.IsAny <bool>(), It.IsAny <CancellationToken>()))
        .ReturnsAsync(new NBitcoin.RPC.GetTxOutResponse {
            Confirmations = 0
        });

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

        var arenaClient = WabiSabiFactory.CreateArenaClient(arena);

        var ex = await Assert.ThrowsAsync <WabiSabiProtocolException>(
            async() => await arenaClient.RegisterInputAsync(round.Id, BitcoinFactory.CreateOutPoint(), ownershipProof, CancellationToken.None));

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

        await arena.StopAsync(CancellationToken.None);
    }
Example #14
0
    public async Task InputImmatureAsync()
    {
        using Key key = new();
        WabiSabiConfig cfg            = new();
        var            round          = WabiSabiFactory.CreateRound(cfg);
        var            ownershipProof = WabiSabiFactory.CreateOwnershipProof(key, round.Id);

        var rpc    = WabiSabiFactory.CreatePreconfiguredRpcClient();
        var rpcCfg = rpc.SetupSequence(rpc => rpc.GetTxOutAsync(It.IsAny <uint256>(), It.IsAny <int>(), It.IsAny <bool>(), It.IsAny <CancellationToken>()));

        foreach (var i in Enumerable.Range(1, 100))
        {
            rpcCfg = rpcCfg.ReturnsAsync(new NBitcoin.RPC.GetTxOutResponse {
                Confirmations = i, IsCoinBase = true
            });
        }
        using Arena arena = await ArenaBuilder.From(cfg).With(rpc).CreateAndStartAsync(round);

        var arenaClient = WabiSabiFactory.CreateArenaClient(arena);

        var req = WabiSabiFactory.CreateInputRegistrationRequest(round: round);

        foreach (var i in Enumerable.Range(1, 100))
        {
            var ex = await Assert.ThrowsAsync <WabiSabiProtocolException>(
                async() => await arenaClient.RegisterInputAsync(round.Id, BitcoinFactory.CreateOutPoint(), ownershipProof, CancellationToken.None));

            Assert.Equal(WabiSabiProtocolErrorCode.InputImmature, ex.ErrorCode);
        }

        await arena.StopAsync(CancellationToken.None);
    }
Example #15
0
    public async Task RemoveInputAsyncTestAsync()
    {
        var config = new WabiSabiConfig();
        var round  = WabiSabiFactory.CreateRound(config);

        round.SetPhase(Phase.ConnectionConfirmation);
        var fundingTx = BitcoinFactory.CreateSmartTransaction(ownOutputCount: 1);
        var coin      = fundingTx.WalletOutputs.First().Coin;
        var alice     = new Alice(coin, new OwnershipProof(), round, Guid.NewGuid(), false);

        round.Alices.Add(alice);

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

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

        var apiClient = new ArenaClient(null !, null !, wabiSabiApi);

        round.SetPhase(Phase.InputRegistration);

        await apiClient.RemoveInputAsync(round.Id, alice.Id, CancellationToken.None);

        Assert.Empty(round.Alices);
    }
Example #16
0
    public async Task InputCanBeNotedAsync()
    {
        using Key key = new();
        var outpoint = BitcoinFactory.CreateOutPoint();

        WabiSabiConfig cfg   = new();
        var            round = WabiSabiFactory.CreateRound(cfg);

        Prison prison = new();

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

        prison.Punish(outpoint, Punishment.Noted, uint256.One);

        var ownershipProof = WabiSabiFactory.CreateOwnershipProof(key);

        var arenaClient = WabiSabiFactory.CreateArenaClient(arena);

        var ex = await Assert.ThrowsAsync <WabiSabiProtocolException>(
            async() => await arenaClient.RegisterInputAsync(round.Id, outpoint, ownershipProof, CancellationToken.None));

        Assert.NotEqual(WabiSabiProtocolErrorCode.InputBanned, ex.ErrorCode);

        await arena.StopAsync(CancellationToken.None);
    }
        public async Task RegisterCoinIdempotencyAsync()
        {
            using var signingKey = new Key();
            var coinToRegister = new Coin(
                BitcoinFactory.CreateOutPoint(),
                new TxOut(Money.Coins(1), signingKey.PubKey.WitHash.ScriptPubKey));

            var httpClient = _apiApplicationFactory.WithWebHostBuilder(builder =>
            {
                builder.ConfigureServices(services =>
                {
                    var rpc             = BitcoinFactory.GetMockMinimalRpc();
                    rpc.OnGetTxOutAsync = (_, _, _) => new()
                    {
                        Confirmations    = 101,
                        IsCoinBase       = false,
                        ScriptPubKeyType = "witness_v0_keyhash",
                        TxOut            = coinToRegister.TxOut
                    };
                    services.AddScoped <IRPCClient>(s => rpc);
                });
            }).CreateClient();

            var apiClient = await _apiApplicationFactory.CreateArenaClientAsync(new StuttererHttpClient(httpClient));

            var rounds = await apiClient.GetStatusAsync(CancellationToken.None);

            var round = rounds.First(x => x.CoinjoinState is ConstructionState);

            var response = await apiClient.RegisterInputAsync(round.Id, coinToRegister.Outpoint, signingKey, CancellationToken.None);

            Assert.NotEqual(uint256.Zero, response.Value);
        }
Example #18
0
        public async Task WrongPhaseAsync()
        {
            WabiSabiConfig cfg = new();

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

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

            var round = arena.Rounds.First();

            var req = new InputsRemovalRequest(round.Id, BitcoinFactory.CreateUint256());

            foreach (Phase phase in Enum.GetValues(typeof(Phase)))
            {
                if (phase != Phase.InputRegistration)
                {
                    round.SetPhase(phase);
                    await using ArenaRequestHandler handler = new(cfg, new Prison(), arena, new MockRpcClient());
                    var ex = await Assert.ThrowsAsync <WabiSabiProtocolException>(async() => await handler.RemoveInputAsync(req, CancellationToken.None));

                    Assert.Equal(WabiSabiProtocolErrorCode.WrongPhase, ex.ErrorCode);
                }
            }

            await arena.StopAsync(CancellationToken.None);
        }
Example #19
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);
    }
Example #20
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 #21
0
        public void EmptyPrison()
        {
            var p = new Prison();

            Assert.Empty(p.GetInmates());
            Assert.Equal(0, p.CountInmates().noted);
            Assert.Equal(0, p.CountInmates().banned);
            Assert.False(p.TryGet(BitcoinFactory.CreateOutPoint(), out _));
        }
    public async Task CanHandleConfirmationAsync()
    {
        var coreNode = await TestNodeBuilder.CreateAsync();

        using HostedServices services = new();
        services.Register <MempoolMirror>(() => new MempoolMirror(TimeSpan.FromSeconds(2), coreNode.RpcClient, coreNode.P2pNode), "Mempool Mirror");
        try
        {
            var rpc     = coreNode.RpcClient;
            var network = rpc.Network;
            await services.StartAllAsync();

            var mempoolInstance = services.Get <MempoolMirror>();

            var walletName = "RandomWalletName";
            await rpc.CreateWalletAsync(walletName);

            var spendAmount = new Money(0.0004m, MoneyUnit.BTC);

            await rpc.GenerateAsync(101);

            var rpcMempoolBeforeSend = await rpc.GetRawMempoolAsync();

            var localMempoolBeforeSend = mempoolInstance.GetMempoolHashes();
            Assert.Equal(rpcMempoolBeforeSend.Length, localMempoolBeforeSend.Count);

            await rpc.SendToAddressAsync(BitcoinFactory.CreateBitcoinAddress(network), spendAmount);

            while (!(await rpc.GetRawMempoolAsync()).Any())
            {
                await Task.Delay(50);
            }

            await mempoolInstance.TriggerAndWaitRoundAsync(TimeSpan.FromSeconds(7));

            var localMempoolAfterSend = mempoolInstance.GetMempoolHashes();
            Assert.Equal(1, localMempoolAfterSend.Count);
            Assert.Single(localMempoolAfterSend);

            await rpc.GenerateAsync(1);

            while ((await rpc.GetRawMempoolAsync()).Any())
            {
                await Task.Delay(50);
            }
            await mempoolInstance.TriggerAndWaitRoundAsync(TimeSpan.FromSeconds(7));

            var localMempoolAfterBlockMined = mempoolInstance.GetMempoolHashes();
            Assert.Empty(localMempoolAfterBlockMined);
        }
        finally
        {
            await services.StopAllAsync();

            await coreNode.TryStopAsync();
        }
    }
    public async Task CanHandleTheSameTxSentManyTimesAsync()
    {
        var coreNode = await TestNodeBuilder.CreateAsync();

        using HostedServices services = new();
        services.Register <MempoolMirror>(() => new MempoolMirror(TimeSpan.FromSeconds(2), coreNode.RpcClient, coreNode.P2pNode), "Mempool Mirror");
        try
        {
            var rpc     = coreNode.RpcClient;
            var network = rpc.Network;
            await services.StartAllAsync();

            var mempoolInstance = services.Get <MempoolMirror>();

            var walletName = "RandomWalletName";
            await rpc.CreateWalletAsync(walletName);

            using var k1 = new Key();
            var blockIds = await rpc.GenerateToAddressAsync(1, k1.PubKey.WitHash.GetAddress(network));

            var block = await rpc.GetBlockAsync(blockIds[0]);

            var coinBaseTx = block.Transactions[0];

            var tx = Transaction.Create(network);
            tx.Inputs.Add(coinBaseTx, 0);
            tx.Outputs.Add(Money.Coins(49.9999m), BitcoinFactory.CreateBitcoinAddress(network));
            tx.Sign(k1.GetBitcoinSecret(network), coinBaseTx.Outputs.AsCoins().First());
            var valid = tx.Check();

            await rpc.GenerateAsync(101);

            for (int i = 0; i < 5; i++)
            {
                await rpc.SendRawTransactionAsync(tx);
            }

            while (!(await rpc.GetRawMempoolAsync()).Any())
            {
                await Task.Delay(50);
            }

            await mempoolInstance.TriggerAndWaitRoundAsync(TimeSpan.FromSeconds(7));

            var localMempoolHashes = mempoolInstance.GetMempoolHashes();

            Assert.Single(localMempoolHashes);
            Assert.Contains(tx.GetHash(), localMempoolHashes);
        }
        finally
        {
            await services.StopAllAsync();

            await coreNode.TryStopAsync();
        }
    }
    public void ManyInManyOut()
    {
        var analyser = ServiceFactory.CreateBlockchainAnalyzer();
        var tx       = BitcoinFactory.CreateSmartTransaction(3, 3, 0, 0);

        analyser.Analyze(tx);

        Assert.Empty(tx.WalletInputs);
        Assert.Empty(tx.WalletOutputs);
    }
Example #25
0
 public void AddressReusePunishment()
 {
     // If there's reuse in input and output side, then output side didn't gain, nor lose anonymity.
     var analyser = ServiceFactory.CreateBlockchainAnalyzer();
     var km       = ServiceFactory.CreateKeyManager();
     var reuse    = BitcoinFactory.CreateHdPubKey(km);
     var tx       = BitcoinFactory.CreateSmartTransaction(
         9,
         Enumerable.Repeat(Money.Coins(1m), 9),
         new[] { (Money.Coins(1.1m), 100, BitcoinFactory.CreateHdPubKey(km)) },
    public void WholeCoinReceive()
    {
        var analyser = ServiceFactory.CreateBlockchainAnalyzer();
        var tx       = BitcoinFactory.CreateSmartTransaction(1, 0, 0, 1);

        analyser.Analyze(tx);

        var coin = Assert.Single(tx.WalletOutputs);

        Assert.Equal(1, coin.HdPubKey.AnonymitySet);
    }
        public async Task CanDoOperationsAsync()
        {
            await using var txStore = new TransactionStoreMock();
            var network = Network.Main;
            await txStore.InitializeAsync(network);

            Assert.True(txStore.IsEmpty());

            var stx       = BitcoinFactory.CreateSmartTransaction();
            var operation = txStore.TryAddOrUpdate(stx);

            Assert.True(operation.isAdded);
            Assert.False(operation.isUpdated);
            var isRemoved = txStore.TryRemove(stx.GetHash(), out SmartTransaction removed);

            Assert.True(isRemoved);
            Assert.Equal(stx, removed);
            operation = txStore.TryAddOrUpdate(stx);
            Assert.True(operation.isAdded);
            Assert.False(operation.isUpdated);
            operation = txStore.TryAddOrUpdate(stx);
            Assert.False(operation.isAdded);
            Assert.False(operation.isUpdated);

            operation = txStore.TryAddOrUpdate(
                new SmartTransaction(
                    stx.Transaction,
                    height: stx.Height,
                    stx.BlockHash,
                    stx.BlockIndex,
                    "totally random new label",
                    stx.IsReplacement,
                    stx.FirstSeen));
            Assert.False(operation.isAdded);
            Assert.True(operation.isUpdated);

            operation = txStore.TryAddOrUpdate(stx);
            Assert.False(operation.isAdded);
            Assert.False(operation.isUpdated);

            Assert.False(txStore.IsEmpty());
            Assert.True(txStore.TryGetTransaction(stx.GetHash(), out SmartTransaction sameStx));
            Assert.True(txStore.Contains(stx.GetHash()));
            Assert.Equal(stx, sameStx);

            txStore.TryRemove(stx.GetHash(), out _);
            Assert.True(txStore.IsEmpty());
            Assert.Empty(txStore.GetTransactions());
            txStore.TryAddOrUpdate(stx);

            txStore.TryAddOrUpdate(stx);
            Assert.Single(txStore.GetTransactions());
            Assert.Single(txStore.GetTransactionHashes());
        }
Example #28
0
        public async Task RoundNotFoundAsync()
        {
            using Arena arena = await WabiSabiFactory.CreateAndStartArenaAsync();

            await using ArenaRequestHandler handler = new(new WabiSabiConfig(), new Prison(), arena, new MockRpcClient());
            var req = new InputsRemovalRequest(uint256.Zero, BitcoinFactory.CreateUint256());
            var ex  = await Assert.ThrowsAsync <WabiSabiProtocolException>(async() => await handler.RemoveInputAsync(req, CancellationToken.None));

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

            await arena.StopAsync(CancellationToken.None);
        }
Example #29
0
        public static PSBT GenerateRandomTransaction()
        {
            var key = new Key();
            var tx  =
                Network.Main.CreateTransactionBuilder()
                .AddCoins(Coin(0.5m, key.PubKey.WitHash.ScriptPubKey))
                .AddKeys(key)
                .Send(BitcoinFactory.CreateScript(), Money.Coins(0.5m))
                .BuildPSBT(true);

            tx.Finalize();
            return(tx);
        }
Example #30
0
        public async Task RoundNotFoundAsync()
        {
            using Key key     = new();
            using Arena arena = await WabiSabiFactory.CreateAndStartArenaAsync(new(), WabiSabiFactory.CreatePreconfiguredRpcClient());

            var arenaClient = WabiSabiFactory.CreateArenaClient(arena);
            var ex          = await Assert.ThrowsAsync <WabiSabiProtocolException>(
                async() => await arenaClient.RegisterInputAsync(uint256.Zero, BitcoinFactory.CreateOutPoint(), key, CancellationToken.None));

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

            await arena.StopAsync(CancellationToken.None);
        }