コード例 #1
0
 public void CanGetTransactionsFromMemPool()
 {
     using (var builder = NodeBuilderEx.Create())
     {
         var node = builder.CreateNode();
         node.ConfigParameters.Add("whitelist", "127.0.0.1");
         node.Start();
         var rpc = node.CreateRPCClient();
         rpc.Generate(101);
         rpc.SendToAddress(new Key().PubKey.GetAddress(ScriptPubKeyType.Legacy, Network.RegTest), Money.Coins(1.0m));
         var client = node.CreateNodeClient();
         client.VersionHandshake();
         var transactions = client.GetMempoolTransactions();
         Assert.True(transactions.Length == 1);
     }
 }
コード例 #2
0
        public void CanParseBlock()
        {
            using (var builder = NodeBuilderEx.Create())
            {
                var node = builder.CreateNode();
                builder.StartAll();
                var rpc = node.CreateRPCClient();
                rpc.Generate(10);
                var hash = rpc.GetBestBlockHash();
                var b    = rpc.GetBlock(hash);
                Assert.NotNull(b);
                Assert.Equal(hash, b.GetHash());

                new ConcurrentChain(builder.Network);
            }
        }
コード例 #3
0
 public void CanGetBlockHeader()
 {
     using (var builder = NodeBuilderEx.Create())
     {
         var client = builder.CreateNode().CreateRESTClient();
         var rpc    = builder.Nodes[0].CreateRPCClient();
         builder.StartAll();
         rpc.Generate(2);
         var result  = client.GetBlockHeadersAsync(RegNetGenesisBlock.GetHash(), 3).Result;
         var headers = result.ToArray();
         var last    = headers.Last();
         Assert.Equal(3, headers.Length);
         Assert.Equal(rpc.GetBestBlockHash(), last.GetHash());
         Assert.Equal(headers[1].GetHash(), last.HashPrevBlock);
         Assert.Equal(RegNetGenesisBlock.GetHash(), headers[1].HashPrevBlock);
     }
 }
コード例 #4
0
 public void CanCalculateChainWork()
 {
     using (var builder = NodeBuilderEx.Create())
     {
         var node   = builder.CreateNode();
         var client = node.CreateRESTClient();
         var rpc    = node.CreateRPCClient();
         builder.StartAll();
         var info = client.GetChainInfoAsync().Result;
         Assert.Equal("regtest", info.Chain);
         Assert.Equal(new ChainedBlock(Network.RegTest.GetGenesis().Header, 0).GetChainWork(false), info.ChainWork);
         rpc.Generate(10);
         var chain = node.CreateNodeClient().GetChain();
         info = client.GetChainInfoAsync().Result;
         Assert.Equal(info.ChainWork, chain.Tip.GetChainWork(false));
     }
 }
コード例 #5
0
        public void ThrowsRestApiClientException()
        {
            using (var builder = NodeBuilderEx.Create())
            {
                var client = builder.CreateNode().CreateRESTClient();
                builder.StartAll();
                var unexistingBlockId = uint256.Parse("100000006c02c8ea6e4ff69651f7fcde348fb9d557a06e6957b65552002a7820");
                Assert.Throws <RestApiException>(() => client.GetBlock(unexistingBlockId));

                var txId = uint256.Parse("7569ce92f93f9afd51ffae243e04076be4e5088cf69501aab6de9ede5c331402");
                Assert.Throws <RestApiException>(() => client.GetTransaction(txId));

                var result  = client.GetBlockHeaders(unexistingBlockId, 3);
                var headers = result.ToArray();
                Assert.Empty(headers);
            }
        }
コード例 #6
0
 public void HasCorrectGenesisBlock()
 {
     using (var builder = NodeBuilderEx.Create())
     {
         var rpc = builder.CreateNode().CreateRPCClient();
         builder.StartAll();
         var genesis = rpc.GetBlock(0);
         if (builder.Network == Altcoins.Liquid.Instance.Regtest)
         {
             Assert.Contains(genesis.Transactions.SelectMany(t => t.Outputs).OfType <ElementsTxOut>(), o => o.IsPeggedAsset == true && o.ConfidentialValue.Amount != null && o.ConfidentialValue.Amount != Money.Zero);
         }
         var actual            = genesis.GetHash();
         var calculatedGenesis = builder.Network.GetGenesis().GetHash();
         Assert.Equal(calculatedGenesis, actual);
         Assert.Equal(rpc.GetBlockHash(0), calculatedGenesis);
     }
 }
コード例 #7
0
 public void CanGetMemPool()
 {
     using (var builder = NodeBuilderEx.Create())
     {
         var node = builder.CreateNode();
         var rpc  = node.CreateRPCClient();
         node.ConfigParameters.Add("whitelist", "127.0.0.1");
         node.Start();
         rpc.Generate(102);
         for (int i = 0; i < 2; i++)
         {
             node.CreateRPCClient().SendToAddress(new Key().PubKey.GetAddress(ScriptPubKeyType.Legacy, Network.RegTest), Money.Coins(1.0m));
         }
         var client = node.CreateNodeClient();
         var txIds  = client.GetMempool();
         Assert.True(txIds.Length == 2);
     }
 }
コード例 #8
0
        public void CanSyncWithPoW()
        {
            using (var builder = NodeBuilderEx.Create())
            {
                var node = builder.CreateNode();
                builder.StartAll();
                node.Generate(100);

                var nodeClient = node.CreateNodeClient();
                nodeClient.VersionHandshake();
                ConcurrentChain chain = new ConcurrentChain(builder.Network);
                nodeClient.SynchronizeChain(chain, new Protocol.SynchronizeChainOptions()
                {
                    SkipPoWCheck = false
                });
                Assert.Equal(100, chain.Height);
            }
        }
コード例 #9
0
        public void CanGetBlocksWithProtocol()
        {
            using (var builder = NodeBuilderEx.Create())
            {
                var node = builder.CreateNode(true);
                var rpc  = node.CreateRPCClient();
                rpc.Generate(50);
                var client = node.CreateNodeClient();
                var chain  = client.GetChain();
                var blocks = client.GetBlocks(chain.GetBlock(20).HashBlock).ToArray();
                Assert.Equal(20, blocks.Length);
                Assert.Equal(chain.GetBlock(20).HashBlock, blocks.Last().Header.GetHash());

                blocks = client.GetBlocksFromFork(chain.GetBlock(45)).ToArray();
                Assert.Equal(5, blocks.Length);
                Assert.Equal(chain.GetBlock(50).HashBlock, blocks.Last().Header.GetHash());
                Assert.Equal(chain.GetBlock(46).HashBlock, blocks.First().Header.GetHash());
            }
        }
コード例 #10
0
        public void CanGetChainsConcurrenty()
        {
            using (var builder = NodeBuilderEx.Create())
            {
                bool generating = true;
                var  node       = builder.CreateNode(true);
                var  rpc        = node.CreateRPCClient();
                Task.Run(() =>
                {
                    rpc.Generate(600);
                    generating = false;
                });
                var nodeClient = node.CreateNodeClient();
                nodeClient.PollHeaderDelay = TimeSpan.FromSeconds(2);
                nodeClient.VersionHandshake();
                Random rand = new Random();
                Thread.Sleep(1000);
                var chains =
                    Enumerable.Range(0, 5)
                    .Select(_ => Task.Factory.StartNew(() =>
                {
                    Thread.Sleep(rand.Next(0, 1000));
                    return(nodeClient.GetChain());
                }))
                    .Select(t => t.Result)
                    .ToArray();
                while (generating)
                {
                    SyncAll(nodeClient, rand, chains);
                }
                SyncAll(nodeClient, rand, chains);
                foreach (var c in chains)
                {
                    Assert.Equal(600, c.Height);
                }

                var chainNoHeader = nodeClient.GetChain(new SynchronizeChainOptions()
                {
                    SkipPoWCheck = true, StripHeaders = true
                });
                Assert.False(chainNoHeader.Tip.HasHeader);
            }
        }
コード例 #11
0
 public void CanCancelConnection()
 {
     using (var builder = NodeBuilderEx.Create())
     {
         var node = builder.CreateNode(true);
         CancellationTokenSource cts = new CancellationTokenSource();
         cts.Cancel();
         try
         {
             var client = Node.Connect(Network.RegTest, "127.0.0.1:" + node.ProtocolPort.ToString(), new NodeConnectionParameters()
             {
                 ConnectCancellation = cts.Token
             });
             Assert.False(true, "Should have thrown");
         }
         catch (OperationCanceledException)
         {
         }
     }
 }
コード例 #12
0
        public void SynchronizeChainSurviveReorg()
        {
            using (var builder = NodeBuilderEx.Create())
            {
                ConcurrentChain chain = new ConcurrentChain(Network.RegTest);
                var             node1 = builder.CreateNode(true);
                node1.Generate(10);
                node1.CreateNodeClient().SynchronizeChain(chain);
                Assert.Equal(10, chain.Height);


                var node2 = builder.CreateNode(true);
                node2.Generate(12);

                var node2c = node2.CreateNodeClient();
                node2c.PollHeaderDelay = TimeSpan.FromSeconds(2);
                node2c.SynchronizeChain(chain);
                Assert.Equal(12, chain.Height);
            }
        }
コード例 #13
0
        public void DoesRPCCapabilitiesWellAdvertised()
        {
            using (var builder = NodeBuilderEx.Create())
            {
                var node = builder.CreateNode();
                builder.StartAll();
                node.Generate(builder.Network.Consensus.CoinbaseMaturity + 1);
                var rpc = node.CreateRPCClient();
                rpc.ScanRPCCapabilities();
                Assert.NotNull(rpc.Capabilities);

                CheckCapabilities(rpc, "getnetworkinfo", rpc.Capabilities.SupportGetNetworkInfo);
                CheckCapabilities(rpc, "scantxoutset", rpc.Capabilities.SupportScanUTXOSet);
                CheckCapabilities(rpc, "signrawtransactionwithkey", rpc.Capabilities.SupportSignRawTransactionWith);
                CheckCapabilities(rpc, "estimatesmartfee", rpc.Capabilities.SupportEstimateSmartFee);

                try
                {
                    var address = rpc.GetNewAddress(new GetNewAddressRequest()
                    {
                        AddressType = AddressType.Bech32
                    });
                    // If this fail, rpc support segwit bug you said it does not
                    Assert.Equal(rpc.Capabilities.SupportSegwit, address.ScriptPubKey.IsScriptType(ScriptType.Witness));
                    if (rpc.Capabilities.SupportSegwit)
                    {
                        Assert.True(builder.Network.Consensus.SupportSegwit, "The node RPC support segwit, but Network.Consensus.SupportSegwit is set to false");
                        rpc.SendToAddress(address, Money.Coins(1.0m));
                    }
                    else
                    {
                        Assert.False(builder.Network.Consensus.SupportSegwit, "The node RPC does not support segwit, but Network.Consensus.SupportSegwit is set to true (This error can be normal if you are using a old node version)");
                    }
                }
                catch (RPCException) when(!rpc.Capabilities.SupportSegwit)
                {
                }
            }
        }
コード例 #14
0
        public void CanCalculateTransactionHash()
        {
            using (var builder = NodeBuilderEx.Create())
            {
                var rpc = builder.CreateNode().CreateRPCClient();
                builder.StartAll();
                var blockHash = rpc.Generate(1)[0];
                var block     = rpc.GetBlock(blockHash);

                Transaction walletTx = null;
                try
                {
                    walletTx = rpc.GetRawTransaction(block.Transactions[0].GetHash(), block.GetHash());
                }
                // Some nodes does not support the blockid
                catch
                {
                    walletTx = rpc.GetRawTransaction(block.Transactions[0].GetHash());
                }
                Assert.Equal(walletTx.ToHex(), block.Transactions[0].ToHex());
            }
        }
コード例 #15
0
        public void CanParseAddress()
        {
            using (var builder = NodeBuilderEx.Create())
            {
                var node = builder.CreateNode();
                builder.StartAll();
                var addr  = node.CreateRPCClient().SendCommand(RPC.RPCOperations.getnewaddress).Result.ToString();
                var addr2 = BitcoinAddress.Create(addr, builder.Network).ToString();
                Assert.Equal(addr, addr2);

                var address = (BitcoinAddress) new Key().PubKey.GetAddress(ScriptPubKeyType.Legacy, builder.Network);

                // Test normal address
                var isValid = ((JObject)node.CreateRPCClient().SendCommand("validateaddress", address.ToString()).Result)["isvalid"].Value <bool>();
                Assert.True(isValid);

                // Test p2sh
                address = new Key().PubKey.ScriptPubKey.Hash.ScriptPubKey.GetDestinationAddress(builder.Network);
                isValid = ((JObject)node.CreateRPCClient().SendCommand("validateaddress", address.ToString()).Result)["isvalid"].Value <bool>();
                Assert.True(isValid);
            }
        }
コード例 #16
0
 public async Task CanMaskExceptionThrownByMessageReceivers()
 {
     using (var builder = NodeBuilderEx.Create())
     {
         var node = builder.CreateNode();
         var rpc  = node.CreateRPCClient();
         node.Start();
         var nodeClient = node.CreateNodeClient();
         TaskCompletionSource <bool> ok = new TaskCompletionSource <bool>();
         nodeClient.VersionHandshake();
         nodeClient.UncaughtException += (s, m) =>
         {
             ok.TrySetResult(m.GetType() == typeof(Exception) && m.Message == "test");
         };
         nodeClient.MessageReceived += (s, m) =>
         {
             throw new Exception("test");
         };
         nodeClient.SendMessage(new PingPayload());
         Assert.True(await ok.Task);
     }
 }
コード例 #17
0
        public void CanMaintainChainWithChainBehavior()
        {
            using (var builder = NodeBuilderEx.Create())
            {
                var node = builder.CreateNode(true).CreateNodeClient();
                builder.Nodes[0].Generate(600);
                var rpc   = builder.Nodes[0].CreateRPCClient();
                var chain = node.GetChain(rpc.GetBlockHash(500));
                Assert.True(chain.Height == 500);
                using (var tester = new NodeServerTester())
                {
                    var n1 = tester.Node1;
                    n1.Behaviors.Add(new ChainBehavior(chain));
                    n1.VersionHandshake();
                    Assert.True(n1.MyVersion.StartHeight == 500);
                    var n2 = tester.Node2;
                    Assert.True(n2.MyVersion.StartHeight == 0);
                    Assert.True(n2.PeerVersion.StartHeight == 500);
                    Assert.True(n1.State == NodeState.HandShaked);
                    Assert.True(n2.State == NodeState.HandShaked);
                    var behavior = new ChainBehavior(new ConcurrentChain(Network.RegTest));
                    n2.Behaviors.Add(behavior);
                    TestUtils.Eventually(() => behavior.Chain.Height == 500);
                    var chain2 = n2.GetChain(rpc.GetBlockHash(500));
                    Assert.True(chain2.Height == 500);
                    var chain1 = n1.GetChain(rpc.GetBlockHash(500));
                    Assert.True(chain1.Height == 500);
                    chain1 = n1.GetChain(rpc.GetBlockHash(499));
                    Assert.True(chain1.Height == 499);

                    //Should not broadcast above HighestValidatorPoW
                    n1.Behaviors.Find <ChainBehavior>().SharedState.HighestValidatedPoW = chain1.GetBlock(300);
                    chain1 = n2.GetChain(rpc.GetBlockHash(499));
                    Assert.True(chain1.Height == 300);
                }
            }
        }
コード例 #18
0
        public void CanHandshakeWithSeveralTemplateBehaviors()
        {
            using (var builder = NodeBuilderEx.Create())
            {
                var node = builder.CreateNode(true);
                node.Generate(101);
                AddressManager manager = new AddressManager();
                manager.Add(new NetworkAddress(node.NodeEndpoint), IPAddress.Loopback);

                var        chain = new SlimChain(builder.Network.GenesisHash);
                NodesGroup group = new NodesGroup(builder.Network, new NodeConnectionParameters()
                {
                    Services          = NodeServices.Nothing,
                    IsRelay           = true,
                    TemplateBehaviors =
                    {
                        new AddressManagerBehavior(manager)
                        {
                            PeersToDiscover = 1,
                            Mode            = AddressManagerBehaviorMode.None
                        },
                        new SlimChainBehavior(chain),
                        new PingPongBehavior()
                    }
                });
                group.AllowSameGroup        = true;
                group.MaximumNodeConnection = 1;
                var connecting = WaitConnected(group);
                try
                {
                    group.Connect();
                    connecting.GetAwaiter().GetResult();
                    Eventually(() =>
                    {
                        Assert.Equal(101, chain.Height);
                    });
                    var ms = new MemoryStream();
                    chain.Save(ms);

                    var chain2 = new SlimChain(chain.Genesis);
                    ms.Position = 0;
                    chain2.Load(ms);
                    Assert.Equal(chain.Tip, chain2.Tip);

                    using (var fs = new FileStream("test.slim.dat", FileMode.Create, FileAccess.Write, FileShare.None, 1024 * 1024))
                    {
                        chain.Save(fs);
                        fs.Flush();
                    }

                    chain.ResetToGenesis();
                    using (var fs = new FileStream("test.slim.dat", FileMode.Open, FileAccess.Read, FileShare.None, 1024 * 1024))
                    {
                        chain.Load(fs);
                    }
                    Assert.Equal(101, chain2.Height);
                    chain.ResetToGenesis();
                }
                finally
                {
                    group.Disconnect();
                }
            }
        }
コード例 #19
0
        public void CanSignPSBTWithRootAndAccountKey()
        {
            using (var nodeBuilder = NodeBuilderEx.Create())
            {
                var rpc = nodeBuilder.CreateNode().CreateRPCClient();
                nodeBuilder.StartAll();
                rpc.Generate(102);
                uint hardenedFlag = 0U;
retry:
                var masterKey = new ExtKey();
                var accountKeyPath = new RootedKeyPath(masterKey, new KeyPath("49'/0'/0'"));
                var accountKey     = masterKey.Derive(accountKeyPath);
                var addresses      = Enumerable.Range(0, 5)
                                     .Select(i =>
                {
                    var addressPath     = new KeyPath(new uint[] { 0U | hardenedFlag, (uint)i | hardenedFlag });
                    var fullAddressPath = accountKeyPath.Derive(addressPath);
                    var address         = accountKey.Derive(addressPath).GetPublicKey().WitHash.GetAddress(nodeBuilder.Network);
                    return(new
                    {
                        FullAddressPath = fullAddressPath,
                        AddressPath = addressPath,
                        Address = address
                    });
                }).ToList();

                var changeAddress = addresses.Last();
                addresses = addresses.Take(addresses.Count - 1).ToList();


                // Fund the addresses
                var coins = addresses.Select(async kra =>
                {
                    var id = await rpc.SendToAddressAsync(kra.Address, Money.Coins(1));
                    var tx = await rpc.GetRawTransactionAsync(id);
                    return(tx.Outputs.AsCoins().Where(o => o.ScriptPubKey == kra.Address.ScriptPubKey).Single());
                }).Select(t => t.Result).ToArray();


                var destination = new Key().ScriptPubKey;
                var amount      = new Money(1, MoneyUnit.BTC);

                var builder = Network.Main.CreateTransactionBuilder();

                var fee = new Money(100_000L);
                var partiallySignedTx = builder
                                        .AddCoins(coins)
                                        .Send(destination, amount)
                                        .SetChange(changeAddress.Address)
                                        .SendFees(fee)
                                        .BuildPSBT(false);
                partiallySignedTx.AddKeyPath(masterKey, addresses.Concat(new[] { changeAddress }).Select(a => a.FullAddressPath.KeyPath).ToArray());
                var expectedBalance = -amount - fee;
                var actualBalance   = partiallySignedTx.GetBalance(ScriptPubKeyType.Segwit, accountKey, accountKeyPath);
                Assert.Equal(expectedBalance, actualBalance);

                actualBalance = partiallySignedTx.GetBalance(ScriptPubKeyType.Segwit, masterKey);
                Assert.Equal(expectedBalance, actualBalance);
                Assert.Equal(Money.Zero, partiallySignedTx.GetBalance(ScriptPubKeyType.Legacy, masterKey));
                // You can sign with accountKey and keypath
                var memento = partiallySignedTx.Clone();

                partiallySignedTx.SignAll(ScriptPubKeyType.Segwit, accountKey, accountKeyPath);
                Assert.True(partiallySignedTx.Inputs.All(i => i.PartialSigs.Count == 1));
                partiallySignedTx.Finalize();

                var partiallySignedTx2 = memento;

                // Or you can sign with the masterKey
                partiallySignedTx2.SignAll(ScriptPubKeyType.Segwit, masterKey);
                Assert.True(partiallySignedTx2.Inputs.All(i => i.PartialSigs.Count == 1));
                partiallySignedTx2.Finalize();

                Assert.Equal(partiallySignedTx, partiallySignedTx2);

                var signedTx = partiallySignedTx.ExtractTransaction();
                rpc.SendRawTransaction(signedTx);
                var errors = builder.Check(signedTx);
                Assert.Empty(errors);

                if (hardenedFlag == 0)
                {
                    hardenedFlag = 0x80000000;
                    goto retry;
                }
            }
        }
コード例 #20
0
        public void CanBuildSegwitP2SHMultisigTransactionsWithPSBT()
        {
            using (var nodeBuilder = NodeBuilderEx.Create())
            {
                var rpc = nodeBuilder.CreateNode().CreateRPCClient();
                nodeBuilder.StartAll();
                rpc.Generate(102);

                // Build the keys and addresses
                var masterKeys         = Enumerable.Range(0, 3).Select(_ => new ExtKey()).ToArray();
                var keyRedeemAddresses = Enumerable.Range(0, 4)
                                         .Select(i => masterKeys.Select(m => m.Derive(i, false)).ToArray())
                                         .Select(keys =>
                                                 (
                                                     Keys: keys.Select(k => k.PrivateKey).ToArray(),
                                                     Redeem: PayToMultiSigTemplate.Instance.GenerateScriptPubKey(keys.Length, keys.Select(k => k.PrivateKey.PubKey).ToArray()))
                                                 ).Select(_ =>
                                                          (
                                                              Keys: _.Keys,
                                                              Redeem: _.Redeem,
                                                              Address: _.Redeem.WitHash.ScriptPubKey.Hash.ScriptPubKey.GetDestinationAddress(nodeBuilder.Network)
                                                          ));


                // Fund the addresses
                var scriptCoins = keyRedeemAddresses.Select(async kra =>
                {
                    var id = await rpc.SendToAddressAsync(kra.Address, Money.Coins(1));
                    var tx = await rpc.GetRawTransactionAsync(id);
                    return(tx.Outputs.AsCoins().Where(o => o.ScriptPubKey == kra.Address.ScriptPubKey)
                           .Select(c => c.ToScriptCoin(kra.Redeem)).Single());
                }).Select(t => t.Result).ToArray();


                var destination   = new Key().ScriptPubKey;
                var amount        = new Money(1, MoneyUnit.BTC);
                var redeemScripts = keyRedeemAddresses.Select(kra => kra.Redeem).ToArray();
                var privateKeys   = keyRedeemAddresses.SelectMany(kra => kra.Keys).ToArray();


                var builder           = Network.Main.CreateTransactionBuilder();
                var rate              = new FeeRate(Money.Satoshis(1), 1);
                var partiallySignedTx = builder
                                        .AddCoins(scriptCoins)
                                        .AddKeys(privateKeys[0])
                                        .Send(destination, amount)
                                        .SubtractFees()
                                        .SetChange(new Key().ScriptPubKey)
                                        .SendEstimatedFees(rate)
                                        .BuildPSBT(true);

                Assert.True(partiallySignedTx.Inputs.All(i => i.PartialSigs.Count == 1));

                partiallySignedTx = PSBT.Load(partiallySignedTx.ToBytes(), Network.Main);

                Network.Main.CreateTransactionBuilder()
                .AddKeys(privateKeys[1], privateKeys[2])
                .SignPSBT(partiallySignedTx);

                Assert.True(partiallySignedTx.Inputs.All(i => i.PartialSigs.Count == 3));
                partiallySignedTx.Finalize();

                var signedTx = partiallySignedTx.ExtractTransaction();
                rpc.SendRawTransaction(signedTx);
                var errors = builder.Check(signedTx);
                Assert.Empty(errors);
            }
        }
コード例 #21
0
        public void CanGetMerkleRoot()
        {
            using (var builder = NodeBuilderEx.Create())
            {
                var node       = builder.CreateNode(true);
                var rpc        = node.CreateRPCClient();
                var nodeClient = node.CreateNodeClient();
                rpc.Generate(101);

                List <TxDestination> knownAddresses = new List <TxDestination>();
                var batch = rpc.PrepareBatch();
                for (int i = 0; i < 20; i++)
                {
                    var address = (BitcoinPubKeyAddress) new Key().PubKey.GetAddress(ScriptPubKeyType.Legacy, rpc.Network);
                    knownAddresses.Add(address.Hash);
#pragma warning disable CS4014
                    batch.SendToAddressAsync(address, Money.Coins(0.5m));
#pragma warning restore CS4014
                }
                batch.SendBatch();
                knownAddresses = knownAddresses.Take(10).ToList();
                var blockId = rpc.Generate(1)[0];
                var block   = rpc.GetBlock(blockId);
                Assert.Equal(21, block.Transactions.Count);
                var knownTx = block.Transactions[1].GetHash();
                nodeClient.VersionHandshake();
                using (var list = nodeClient.CreateListener()
                                  .Where(m => m.Message.Payload is MerkleBlockPayload || m.Message.Payload is TxPayload))
                {
                    BloomFilter filter = new BloomFilter(1, 0.0001, 50, BloomFlags.UPDATE_NONE);
                    foreach (var a in knownAddresses)
                    {
                        filter.Insert(a.ToBytes());
                    }
                    nodeClient.SendMessageAsync(new FilterLoadPayload(filter));
                    nodeClient.SendMessageAsync(new GetDataPayload(new InventoryVector(InventoryType.MSG_FILTERED_BLOCK, block.GetHash())));
                    var merkle = list.ReceivePayload <MerkleBlockPayload>();
                    var tree   = merkle.Object.PartialMerkleTree;
                    Assert.True(tree.Check(block.Header.HashMerkleRoot));
                    Assert.True(tree.GetMatchedTransactions().Count() >= 10);
                    Assert.Contains(knownTx, tree.GetMatchedTransactions());

                    List <Transaction> matched = new List <Transaction>();
                    for (int i = 0; i < tree.GetMatchedTransactions().Count(); i++)
                    {
                        matched.Add(list.ReceivePayload <TxPayload>().Object);
                    }
                    Assert.True(matched.Count >= 10);
                    tree = tree.Trim(knownTx);
                    Assert.True(tree.GetMatchedTransactions().Count() == 1);
                    Assert.Contains(knownTx, tree.GetMatchedTransactions());

                    Action act = () =>
                    {
                        foreach (var match in matched)
                        {
                            Assert.True(filter.IsRelevantAndUpdate(match));
                        }
                    };
                    act();
                    filter = filter.Clone();
                    act();

                    var unknownBlock = uint256.Parse("00000000ad262227291eaf90cafdc56a8f8451e2d7653843122c5bb0bf2dfcdd");
                    nodeClient.SendMessageAsync(new GetDataPayload(new InventoryVector(InventoryType.MSG_FILTERED_BLOCK, Network.RegTest.GetGenesis().GetHash())));

                    merkle = list.ReceivePayload <MerkleBlockPayload>();
                    tree   = merkle.Object.PartialMerkleTree;
                    Assert.True(tree.Check(merkle.Object.Header.HashMerkleRoot));
                    Assert.True(!tree.GetMatchedTransactions().Contains(knownTx));
                }
            }
        }