Exemple #1
0
        public SignRawTransactionResponse SignRawTransaction(SignRawTransactionRequest request)
        {
            #region default values

            if (request.Inputs.Count == 0)
            {
                request.Inputs = null;
            }

            if (string.IsNullOrWhiteSpace(request.SigHashType))
            {
                request.SigHashType = SigHashType.All;
            }

            if (request.PrivateKeys.Count == 0)
            {
                request.PrivateKeys = null;
            }

            #endregion

            return(_rpcConnector.MakeRequest <SignRawTransactionResponse>(RpcMethods.signrawtransaction, request.RawTransactionHex, request.Inputs, request.PrivateKeys, request.SigHashType));
        }
Exemple #2
0
 public Task <SignRawTransactionResponse> SignRawTransactionWithWalletAsync(SignRawTransactionRequest request)
 {
     throw new NotImplementedException();
 }
Exemple #3
0
        static void Main(string[] args)
        {
            string username    = ConfigurationManager.AppSettings.Get("username");
            string password    = ConfigurationManager.AppSettings.Get("password");
            string wallet_url  = ConfigurationManager.AppSettings.Get("wallet_url");
            string wallet_port = ConfigurationManager.AppSettings.Get("wallet_port");


            RpcMethods rpc = new RpcMethods(username, password, wallet_url, wallet_port);


            try
            {
                //string toaddr = "oTw4kEvB3MWrN97ujWb6JAs3ye574DvuKV";
                //string fromaddr = "oWVv5huYoVsicv9wLqDSt9hKTYERchm2DY";
                //string response = Call_Service_Get("http://localhost:53722/FloAPI.svc/listunspentbyaddress/"+ fromaddr);
                //JObject objapi = JObject.Parse(response);
                //JArray arrunspent = JArray.Parse(objapi["result"].ToString());
                //decimal amtosent = 2.65m;
                //decimal fee = 0.0001m;
                //decimal bal = 0.0m;



                //CreateRawTransactionRequest req1 = new CreateRawTransactionRequest();
                //List<CreateRawTransactionInput> inputs1 = new List<CreateRawTransactionInput>();

                //foreach (JObject o in arrunspent.Children<JObject>())
                //{
                //    CreateRawTransactionInput input1 = new CreateRawTransactionInput();
                //    string tid = o["txid"].ToString();
                //    string vout = o["vout"].ToString();
                //    string scriptPubKey = o["scriptPubKey"].ToString();
                //    decimal amt = Convert.ToDecimal(o["amount"].ToString());
                //    input1.txid = tid;
                //    input1.vout = Convert.ToInt32(vout);
                //    input1.scriptPubKey = scriptPubKey;
                //    inputs1.Add(input1);

                //    bal += amt;
                //    if(bal >= (amtosent+fee))
                //    {
                //        break;
                //    }

                //}
                //decimal change = bal - (amtosent + fee);
                //Dictionary<string, decimal> output1 = new Dictionary<string, decimal>();
                //output1.Add(toaddr, amtosent);
                //output1.Add(fromaddr, change);

                //req1.Inputs = inputs1;
                //req1.Outputs = output1;
                //req1.floData = "Test Raw Transaction API";
                //req1.locktime = 0;
                //req1.replaceable = false;
                //string rawreqjson = JsonConvert.SerializeObject(req1);

                //string rawresp = Call_Service_Post(rawreqjson, "http://localhost:53722/FloAPI.svc/createrawtransaction","text/plain");

                //JObject objraw1 = JObject.Parse(rpc.CreateRawTransaction(req1));

                //string rawHex1 = "";

                //if (string.IsNullOrEmpty(objraw1["error"].ToString()))
                //{
                //    Console.WriteLine("Raw Transaction : " + objraw1["result"]);
                //    rawHex1 = objraw1["result"].ToString();
                //}
                //else
                //{
                //    Console.WriteLine("Raw Transaction Error : " + objraw1["error"]);
                //}

                //string responsepriv = Call_Service_Get("http://localhost:53722/FloAPI.svc/dumpprivkey/" + fromaddr);
                //JObject objpriv = JObject.Parse(responsepriv);
                //string privkey1 = objpriv["result"].ToString();
                //List<string> privkeys1 = new List<string>();
                //privkeys1.Add(privkey1);


                //SignRawTransactionRequest signreq1 = new SignRawTransactionRequest();
                //signreq1.Inputs = inputs1;
                //signreq1.PrivateKeys = privkeys1;
                //signreq1.RawTransactionHex = rawHex1;
                //signreq1.SigHashType = "ALL";

                //string signjson = JsonConvert.SerializeObject(signreq1);

                //string signresp = Call_Service_Post(signjson,"http://localhost:53722/FloAPI.svc/signrawtransaction","application/json");
                //JObject objsign1 = JObject.Parse(signresp);
                //string signHex1 = "";

                //if (string.IsNullOrEmpty(objsign1["error"].ToString()))
                //{
                //    Console.WriteLine("Sign Raw Transaction : " + objsign1["result"]);
                //    signHex1 = objsign1["result"]["hex"].ToString();
                //}
                //else
                //{
                //    Console.WriteLine("Sign Raw Transaction Error : " + objsign1["error"]);
                //}

                //SendRawTransactionRequest sendreq = new SendRawTransactionRequest();
                //sendreq.signedHex = signHex1;
                //string sendreq1 = JsonConvert.SerializeObject(sendreq);

                //string sendresp1 = Call_Service_Post(sendreq1,"http://localhost:53722/FloAPI.svc/sendrawtransaction","application/json");
                //JObject objsend1 = JObject.Parse(sendresp1);

                //string txid = "";

                //if (string.IsNullOrEmpty(objsend1["error"].ToString()))
                //{
                //    Console.WriteLine("Sign Raw Transaction : " + objsend1["result"]);
                //    txid = objsend1["result"].ToString();
                //}
                //else
                //{
                //    Console.WriteLine("Sign Raw Transaction Error : " + objsend1["error"]);
                //}



                JArray jarrlu = new JArray();
                jarrlu.Add("");
                //jarrlu.Add("oHQMHm1eFz3PLgTPWPcYYDNvrB4G241Atd");
                //List Unspent
                JObject objlu = JObject.Parse(rpc.ListUnspent(jarrlu));

                if (string.IsNullOrEmpty(objlu["error"].ToString()))
                {
                    Console.WriteLine("Get Info : " + objlu["result"]);
                }
                else
                {
                    Console.WriteLine("Get Info Error : " + objlu["error"]);
                }

                CreateRawTransactionRequest req   = new CreateRawTransactionRequest();
                CreateRawTransactionInput   input = new CreateRawTransactionInput();
                input.txid         = "5b30f0bf684b90ccc2a3f8cef896b0ed155c9b785fbaf9fca1c1272dc40af4bd";
                input.vout         = 0;
                input.scriptPubKey = "76a914ac73b43a12d4ef3a2e71384ae3e35460cf4e91df88ac";
                List <CreateRawTransactionInput> inputs = new List <CreateRawTransactionInput>();
                inputs.Add(input);

                Dictionary <string, decimal> output = new Dictionary <string, decimal>();
                output.Add("oJsvAWvNWZ1jk3fV1BpaWHR3wPrYVaVxwZ", 1.0m);
                output.Add("oYbD4joh3G6d3k3wKbFtBQfgq9BPFxzWPn", 181.4795m);

                req.Inputs      = inputs;
                req.Outputs     = output;
                req.floData     = "Test Raw Transaction";
                req.locktime    = 0;
                req.replaceable = false;
                JObject objraw = JObject.Parse(rpc.CreateRawTransaction(req));

                string rawHex = "";

                if (string.IsNullOrEmpty(objraw["error"].ToString()))
                {
                    Console.WriteLine("Raw Transaction : " + objraw["result"]);
                    rawHex = objraw["result"].ToString();
                }
                else
                {
                    Console.WriteLine("Raw Transaction Error : " + objraw["error"]);
                }

                string        privkey  = "cTd24uWL7Sb6KsJXZzwBQR3mkyg2baEzHJNEhkgBmXPpFxy1Ypf9";
                List <string> privkeys = new List <string>();
                privkeys.Add(privkey);

                SignRawTransactionRequest signreq = new SignRawTransactionRequest();
                signreq.Inputs            = inputs;
                signreq.PrivateKeys       = privkeys;
                signreq.RawTransactionHex = rawHex;
                signreq.SigHashType       = "ALL";

                JObject objsign = JObject.Parse(rpc.SignRawTransaction(signreq));

                string signHex = "";

                if (string.IsNullOrEmpty(objsign["error"].ToString()))
                {
                    Console.WriteLine("Sign Raw Transaction : " + objsign["result"]);
                    signHex = objsign["result"]["hex"].ToString();
                }
                else
                {
                    Console.WriteLine("Sign Raw Transaction Error : " + objsign["error"]);
                }

                JObject objsend = JObject.Parse(rpc.SendRawTransaction(signHex));
                string  txid1   = "";

                if (string.IsNullOrEmpty(objsend["error"].ToString()))
                {
                    Console.WriteLine("Sign Raw Transaction : " + objsend["result"]);
                    txid1 = objsend["result"].ToString();
                }
                else
                {
                    Console.WriteLine("Sign Raw Transaction Error : " + objsend["error"]);
                }



                //Get Info
                JObject obj = JObject.Parse(rpc.GetInfo());

                if (string.IsNullOrEmpty(obj["error"].ToString()))
                {
                    Console.WriteLine("Get Info : " + obj["result"]);
                }
                else
                {
                    Console.WriteLine("Get Info Error : " + obj["error"]);
                }

                obj = JObject.Parse(rpc.Preciousblock("31300e805d4f949e455f20f045162290c920b76e14ec6e614c2c8d5bd4fe119e"));

                if (string.IsNullOrEmpty(obj["error"].ToString()))
                {
                    Console.WriteLine("Get Memory Info : " + obj["result"]);
                }
                else
                {
                    Console.WriteLine("Get Memory Info Error : " + obj["error"]);
                }

                //Get Help

                obj = JObject.Parse(rpc.Help("getinfo"));

                if (string.IsNullOrEmpty(obj["error"].ToString()))
                {
                    Console.WriteLine("Get Help : " + obj["result"]);
                }
                else
                {
                    Console.WriteLine("Get Help Error : " + obj["error"]);
                }

                //Get Balance

                obj = JObject.Parse(rpc.GetBalance(""));

                if (string.IsNullOrEmpty(obj["error"].ToString()))
                {
                    Console.WriteLine("Balance : " + obj["result"]);
                }
                else
                {
                    Console.WriteLine("Get Balance Error : " + obj["error"]);
                }

                //Get Wallet Info
                obj = JObject.Parse(rpc.GetWalletInfo());

                if (string.IsNullOrEmpty(obj["error"].ToString()))
                {
                    Console.WriteLine("Wallet Info : " + obj["result"]);
                }
                else
                {
                    Console.WriteLine("Wallet Info Error : " + obj["error"]);
                }

                //Test

                var jsonObject = new JObject();
                jsonObject.Add("oQDkguVz7CW2eEYCWD2G636tWCg23YcnRx", 1.2);
                jsonObject.Add("oXRrzwxUMcpxHCQWP4T1MQAocudWDzL1UJ", 0.2);

                var job1 = new JObject();
                var job2 = new JObject();
                job1.Add("txid", "b1aa06d72323ae923784d80ebb890c286d963d37901d73806fa2a4fff91865f3");
                job1.Add("vout", 1);
                job2.Add("txid", "b1aa06d72323ae923784d80ebb890c286d963d37901d73806fa2a4fff91865f4");
                job2.Add("vout", 2);

                //create raw transaction
                var jarr = new JArray();
                jarr.Add(job1);
                jarr.Add(job2);

                //obj = JObject.Parse(rpc.CreateRawTransaction(jarr, jsonObject));

                //if (string.IsNullOrEmpty(obj["error"].ToString()))
                //{
                //    Console.WriteLine("Create Raw Transaction : " + obj["result"]);
                //}
                //else
                //{
                //    Console.WriteLine("Error : " + obj["error"]);
                //}

                //decode raw transaction
                obj = JObject.Parse(rpc.DecodeRawTransaction("0200000002f36518f9ffa4a26f80731d90373d966d280c89bb0ed8843792ae2323d706aab10100000000fffffffff46518f9ffa4a26f80731d90373d966d280c89bb0ed8843792ae2323d706aab10200000000ffffffff02000e2707000000001976a91450a3f1d1f0d046af51cc150a6d4c33b37b7daf3988ac002d3101000000001976a9149fb715b93dac58ff46cdafd43c34762109ca604388ac0000000000"));

                if (string.IsNullOrEmpty(obj["error"].ToString()))
                {
                    Console.WriteLine("Decode Raw Transaction : " + obj["result"]);
                }
                else
                {
                    Console.WriteLine("Error : " + obj["error"]);
                }

                //create multi sig
                jarr = new JArray();
                jarr.Add("oYbD4joh3G6d3k3wKbFtBQfgq9BPFxzWPn");
                jarr.Add("oJsvAWvNWZ1jk3fV1BpaWHR3wPrYVaVxwZ");

                obj = JObject.Parse(rpc.AddMultisigAddress(2, jarr));

                if (string.IsNullOrEmpty(obj["error"].ToString()))
                {
                    Console.WriteLine("Add Multisig : " + obj["result"]);
                }
                else
                {
                    Console.WriteLine("Error : " + obj["error"]);
                }



                //obj = JObject.Parse(rpc.SendMany("AbhijeetTest", jsonObject));

                //if (string.IsNullOrEmpty(obj["error"].ToString()))
                //{
                //    Console.WriteLine("Send To Many : " + obj["result"]);
                //}
                //else
                //{
                //    Console.WriteLine("Error : " + obj["error"]);
                //}


                //Get Wallet Info
                obj = JObject.Parse(rpc.SubmitBlock("123456ffggg"));

                if (string.IsNullOrEmpty(obj["error"].ToString()))
                {
                    Console.WriteLine("Wallet Info : " + obj["result"]);
                }
                else
                {
                    Console.WriteLine("Wallet Info Error : " + obj["error"]);
                }
            }
            catch (RpcInternalServerErrorException exception)
            {
                var errorCode    = 0;
                var errorMessage = string.Empty;

                if (exception.RpcErrorCode.GetHashCode() != 0)
                {
                    errorCode    = exception.RpcErrorCode.GetHashCode();
                    errorMessage = exception.RpcErrorCode.ToString();
                }

                Console.WriteLine("[Failed] {0} {1} {2}", exception.Message, errorCode != 0 ? "Error code: " + errorCode : string.Empty, !string.IsNullOrWhiteSpace(errorMessage) ? errorMessage : string.Empty);
            }
            catch (Exception exception)
            {
                Console.WriteLine("[Failed]\n\nPlease check your configuration and make sure that the daemon is up and running and that it is synchronized. \n\nException: " + exception);
            }

            Console.Read();
        }
Exemple #4
0
 public virtual async Task <SignRawTransactionResponse> SignRawTransactionWithWalletAsync(SignRawTransactionRequest request)
 {
     return(await Rpc.SignRawTransactionWithWalletAsync(request).ConfigureAwait(false));
 }
    public async Task BuildTransactionReorgsTestAsync()
    {
        (string password, IRPCClient rpc, Network network, _, ServiceConfiguration serviceConfiguration, BitcoinStore bitcoinStore, Backend.Global global) = await Common.InitializeTestEnvironmentAsync(RegTestFixture, 1);

        bitcoinStore.IndexStore.NewFilter += Common.Wallet_NewFilterProcessed;
        // Create the services.
        // 1. Create connection service.
        NodesGroup nodes = new(global.Config.Network, requirements : Constants.NodeRequirements);

        nodes.ConnectedNodes.Add(await RegTestFixture.BackendRegTestNode.CreateNewP2pNodeAsync());

        // 2. Create mempool service.
        Node node = await RegTestFixture.BackendRegTestNode.CreateNewP2pNodeAsync();

        node.Behaviors.Add(bitcoinStore.CreateUntrustedP2pBehavior());

        // 3. Create wasabi synchronizer service.
        using HttpClientFactory httpClientFactory = new(torEndPoint : null, backendUriGetter : () => new Uri(RegTestFixture.BackendEndPoint));
        WasabiSynchronizer synchronizer = new(bitcoinStore, httpClientFactory);
        HybridFeeProvider  feeProvider  = new(synchronizer, null);

        // 4. Create key manager service.
        var keyManager = KeyManager.CreateNew(out _, password, network);

        // 5. Create wallet service.
        var workDir = Helpers.Common.GetWorkDir();
        CachedBlockProvider blockProvider = new(
            new P2pBlockProvider(nodes, null, httpClientFactory, serviceConfiguration, network),
            bitcoinStore.BlockRepository);
        WalletManager walletManager = new(network, workDir, new WalletDirectories(network, workDir));

        walletManager.RegisterServices(bitcoinStore, synchronizer, serviceConfiguration, feeProvider, blockProvider);

        var baseTip = await rpc.GetBestBlockHashAsync();

        // Generate script
        using var k = new Key();
        var scp = k.PubKey.GetAddress(ScriptPubKeyType.Legacy, Network.Main);

        // Get some money, make it confirm.
        var key         = keyManager.GetNextReceiveKey("foo label", out _);
        var fundingTxId = await rpc.SendToAddressAsync(key.GetP2wpkhAddress(network), Money.Coins(0.1m));

        // Generate some coins
        await rpc.GenerateAsync(2);

        try
        {
            nodes.Connect();                                                     // Start connection service.
            node.VersionHandshake();                                             // Start mempool service.
            synchronizer.Start(requestInterval: TimeSpan.FromSeconds(3), 10000); // Start wasabi synchronizer service.
            await feeProvider.StartAsync(CancellationToken.None);

            // Wait until the filter our previous transaction is present.
            var blockCount = await rpc.GetBlockCountAsync();

            await Common.WaitForFiltersToBeProcessedAsync(TimeSpan.FromSeconds(120), blockCount);

            using var wallet = await walletManager.AddAndStartWalletAsync(keyManager);

            var coin = Assert.Single(wallet.Coins);
            Assert.True(coin.Confirmed);
            TransactionBroadcaster broadcaster = new(network, bitcoinStore, httpClientFactory, walletManager);
            broadcaster.Initialize(nodes, rpc);

            // Send money before reorg.
            PaymentIntent operations = new(scp, Money.Coins(0.011m));
            var           btx1       = wallet.BuildTransaction(password, operations, FeeStrategy.TwentyMinutesConfirmationTargetStrategy);
            await broadcaster.SendTransactionAsync(btx1.Transaction);

            var coin2 = Assert.Single(wallet.Coins);
            Assert.NotEqual(coin, coin2);
            Assert.False(coin2.Confirmed);

            operations = new PaymentIntent(scp, Money.Coins(0.012m));
            var btx2 = wallet.BuildTransaction(password, operations, FeeStrategy.TwentyMinutesConfirmationTargetStrategy, allowUnconfirmed: true);
            await broadcaster.SendTransactionAsync(btx2.Transaction);

            var coin3 = Assert.Single(wallet.Coins);
            Assert.NotEqual(coin2, coin3);
            Assert.False(coin3.Confirmed);

            // Test synchronization after fork.
            // Invalidate the blocks containing the funding transaction
            var tip = await rpc.GetBestBlockHashAsync();

            await rpc.InvalidateBlockAsync(tip);             // Reorg 1

            tip = await rpc.GetBestBlockHashAsync();

            await rpc.InvalidateBlockAsync(tip);             // Reorg 2

            // Generate three new blocks (replace the previous invalidated ones)
            Interlocked.Exchange(ref Common.FiltersProcessedByWalletCount, 0);
            await rpc.GenerateAsync(3);

            await Common.WaitForFiltersToBeProcessedAsync(TimeSpan.FromSeconds(120), 3);

            await Task.Delay(100);             // Wait for tx processing.

            var coin4 = Assert.Single(wallet.Coins);
            Assert.Equal(coin3, coin4);
            Assert.True(coin.Confirmed);
            Assert.True(coin2.Confirmed);
            Assert.True(coin3.Confirmed);
            Assert.True(coin4.Confirmed);

            // Send money after reorg.
            // When we invalidate a block, the transactions set in the invalidated block
            // are reintroduced when we generate a new block through the rpc call
            operations = new PaymentIntent(scp, Money.Coins(0.013m));
            var btx3 = wallet.BuildTransaction(password, operations, FeeStrategy.TwentyMinutesConfirmationTargetStrategy);
            await broadcaster.SendTransactionAsync(btx3.Transaction);

            var coin5 = Assert.Single(wallet.Coins);
            Assert.NotEqual(coin4, coin5);
            Assert.False(coin5.Confirmed);

            operations = new PaymentIntent(scp, Money.Coins(0.014m));
            var btx4 = wallet.BuildTransaction(password, operations, FeeStrategy.TwentyMinutesConfirmationTargetStrategy, allowUnconfirmed: true);
            await broadcaster.SendTransactionAsync(btx4.Transaction);

            var coin6 = Assert.Single(wallet.Coins);
            Assert.NotEqual(coin5, coin6);
            Assert.False(coin6.Confirmed);

            // Test synchronization after fork with different transactions.
            // Create a fork that invalidates the blocks containing the funding transaction
            Interlocked.Exchange(ref Common.FiltersProcessedByWalletCount, 0);
            await rpc.InvalidateBlockAsync(baseTip);

            try
            {
                await rpc.AbandonTransactionAsync(fundingTxId);
            }
            catch
            {
                if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
                {
                    throw;
                }
                return;                 // Occassionally this fails on Linux or OSX, I have no idea why.
            }
            // Spend the inputs of the tx so we know
            var success = bitcoinStore.TransactionStore.TryGetTransaction(fundingTxId, out var invalidSmartTransaction);
            Assert.True(success);
            var invalidCoin = Assert.Single(((CoinsRegistry)wallet.Coins).AsAllCoinsView().CreatedBy(invalidSmartTransaction !.GetHash()));
            Assert.NotNull(invalidCoin.SpenderTransaction);
            Assert.True(invalidCoin.Confirmed);

            var overwriteTx = Transaction.Create(network);
            overwriteTx.Inputs.AddRange(invalidSmartTransaction.Transaction.Inputs);
            var  walletAddress = keyManager.GetNextReceiveKey("foo", out _).GetP2wpkhAddress(network);
            bool onAddress     = false;
            foreach (var invalidOutput in invalidSmartTransaction.Transaction.Outputs)
            {
                if (onAddress)
                {
                    overwriteTx.Outputs.Add(new TxOut(invalidOutput.Value, new Key().GetAddress(ScriptPubKeyType.Segwit, network)));
                }
                else
                {
                    overwriteTx.Outputs.Add(new TxOut(invalidOutput.Value, walletAddress));
                    onAddress = true;
                }
            }
            var srtxwwreq = new SignRawTransactionRequest();
            srtxwwreq.Transaction = overwriteTx;
            var srtxwwres = await rpc.SignRawTransactionWithWalletAsync(srtxwwreq);

            var eventAwaiter = new EventAwaiter <ProcessedResult>(
                h => wallet.TransactionProcessor.WalletRelevantTransactionProcessed += h,
                h => wallet.TransactionProcessor.WalletRelevantTransactionProcessed -= h);
            await rpc.SendRawTransactionAsync(srtxwwres.SignedTransaction);

            await rpc.GenerateAsync(10);

            await Common.WaitForFiltersToBeProcessedAsync(TimeSpan.FromSeconds(120), 10);

            var eventArgs = await eventAwaiter.WaitAsync(TimeSpan.FromSeconds(21));

            var doubleSpend = Assert.Single(eventArgs.SuccessfullyDoubleSpentCoins);
            Assert.Equal(invalidCoin.TransactionId, doubleSpend.TransactionId);

            var curBlockHash = await rpc.GetBestBlockHashAsync();

            blockCount = await rpc.GetBlockCountAsync();

            Assert.Equal(bitcoinStore.SmartHeaderChain.TipHash, curBlockHash);
            Assert.Equal((int)bitcoinStore.SmartHeaderChain.TipHeight, blockCount);

            // Make sure the funding transaction is not in any block of the chain
            while (curBlockHash != rpc.Network.GenesisHash)
            {
                var block = await rpc.GetBlockAsync(curBlockHash);

                if (block.Transactions.Any(tx => tx.GetHash() == fundingTxId))
                {
                    throw new Exception($"Transaction found in block at height {blockCount} hash: {block.GetHash()}");
                }
                curBlockHash = block.Header.HashPrevBlock;
                blockCount--;
            }

            // Get some money, make it confirm.
            // this is necessary because we are in a fork now.
            eventAwaiter = new EventAwaiter <ProcessedResult>(
                h => wallet.TransactionProcessor.WalletRelevantTransactionProcessed += h,
                h => wallet.TransactionProcessor.WalletRelevantTransactionProcessed -= h);
            fundingTxId = await rpc.SendToAddressAsync(key.GetP2wpkhAddress(network), Money.Coins(1m), replaceable : true);

            eventArgs = await eventAwaiter.WaitAsync(TimeSpan.FromSeconds(21));

            Assert.Equal(fundingTxId, eventArgs.NewlyReceivedCoins.Single().TransactionId);
            Assert.Contains(fundingTxId, wallet.Coins.Select(x => x.TransactionId));

            var fundingBumpTxId = await rpc.BumpFeeAsync(fundingTxId);

            await Task.Delay(2000);             // Waits for the funding transaction get to the mempool.

            Assert.Contains(fundingBumpTxId.TransactionId, wallet.Coins.Select(x => x.TransactionId));
            Assert.DoesNotContain(fundingTxId, wallet.Coins.Select(x => x.TransactionId));
            Assert.Single(wallet.Coins.Where(x => x.TransactionId == fundingBumpTxId.TransactionId));

            // Confirm the coin
            Interlocked.Exchange(ref Common.FiltersProcessedByWalletCount, 0);
            await rpc.GenerateAsync(1);

            await Common.WaitForFiltersToBeProcessedAsync(TimeSpan.FromSeconds(120), 1);

            Assert.Single(wallet.Coins.Where(x => x.Confirmed && x.TransactionId == fundingBumpTxId.TransactionId));
        }
        finally
        {
            bitcoinStore.IndexStore.NewFilter -= Common.Wallet_NewFilterProcessed;
            await walletManager.RemoveAndStopAllAsync(CancellationToken.None);

            await synchronizer.StopAsync();

            await feeProvider.StopAsync(CancellationToken.None);

            nodes?.Dispose();
            node?.Disconnect();
        }
    }