Beispiel #1
0
        public void CanSyncWallet2()
        {
            using (var builder = NodeBuilder.Create())
            {
                NodesGroup aliceConnection = CreateGroup(builder, 1);
                NodesGroup bobConnection   = CreateGroup(builder, new[] { builder.Nodes[0] }, 1);
                builder.Nodes[0].Generate(101);
                var    rpc      = builder.Nodes[0].CreateRPCClient();
                var    aliceKey = new ExtKey();
                Wallet alice    = new Wallet(new WalletCreation()
                {
                    Network           = Network.RegTest,
                    RootKeys          = new[] { aliceKey.Neuter() },
                    SignatureRequired = 1,
                    UseP2SH           = false
                }, 11);
                Wallet bob = new Wallet(new WalletCreation()
                {
                    Network           = Network.RegTest,
                    RootKeys          = new[] { new ExtKey().Neuter() },
                    SignatureRequired = 1,
                    UseP2SH           = false
                }, 11);

                alice.Configure(aliceConnection);
                alice.Connect();

                bob.Configure(bobConnection);
                bob.Connect();

                TestUtils.Eventually(() => aliceConnection.ConnectedNodes.Count == 1);

                //New address tracked
                var addressAlice = alice.GetNextScriptPubKey();
                builder.Nodes[0].GiveMoney(addressAlice, Money.Coins(1.0m));
                TestUtils.Eventually(() => aliceConnection.ConnectedNodes.Count == 1);                 //Reconnect
                //////

                TestUtils.Eventually(() => alice.GetTransactions().Count == 1);

                //Alice send tx to bob
                var coins = alice.GetTransactions().GetSpendableCoins();
                var keys  = coins.Select(c => alice.GetKeyPath(c.ScriptPubKey))
                            .Select(k => aliceKey.Derive(k))
                            .ToArray();
                var txBuilder = new TransactionBuilder();
                var tx        =
                    txBuilder
                    .SetTransactionPolicy(new StandardTransactionPolicy()
                {
                    MinRelayTxFee = new FeeRate(0)
                })
                    .AddCoins(coins)
                    .AddKeys(keys)
                    .Send(bob.GetNextScriptPubKey(), Money.Coins(0.4m))
                    .SetChange(alice.GetNextScriptPubKey(true))
                    .SendFees(Money.Coins(0.0001m))
                    .BuildTransaction(true);

                Assert.True(txBuilder.Verify(tx));

                builder.Nodes[0].Broadcast(tx);

                //Alice get change
                TestUtils.Eventually(() => alice.GetTransactions().Count == 2);
                coins = alice.GetTransactions().GetSpendableCoins();
                Assert.True(coins.Single().Amount == Money.Coins(0.5999m));
                //////

                //Bob get coins
                TestUtils.Eventually(() => bob.GetTransactions().Count == 1);
                coins = bob.GetTransactions().GetSpendableCoins();
                Assert.True(coins.Single().Amount == Money.Coins(0.4m));
                //////


                MemoryStream bobWalletBackup = new MemoryStream();
                bob.Save(bobWalletBackup);
                bobWalletBackup.Position = 0;

                MemoryStream bobTrakerBackup = new MemoryStream();
                bob.Tracker.Save(bobTrakerBackup);
                bobTrakerBackup.Position = 0;

                bob.Disconnect();

                //Restore bob
                bob = Wallet.Load(bobWalletBackup);
                bobConnection.NodeConnectionParameters.TemplateBehaviors.Remove <TrackerBehavior>();
                bobConnection.NodeConnectionParameters.TemplateBehaviors.Add(new TrackerBehavior(Tracker.Load(bobTrakerBackup), alice.Chain));
                /////

                bob.Configure(bobConnection);

                //Bob still has coins
                TestUtils.Eventually(() => bob.GetTransactions().Count == 1);
                coins = bob.GetTransactions().GetSpendableCoins();
                Assert.True(coins.Single().Amount == Money.Coins(0.4m));
                //////

                bob.Connect();
                TestUtils.Eventually(() => bobConnection.ConnectedNodes.Count == 1);

                //New block found !
                builder.Nodes[0].SelectMempoolTransactions();
                builder.Nodes[0].Generate(1);

                //Alice send tx to bob
                coins = alice.GetTransactions().GetSpendableCoins();
                keys  = coins.Select(c => alice.GetKeyPath(c.ScriptPubKey))
                        .Select(k => aliceKey.Derive(k))
                        .ToArray();
                txBuilder = new TransactionBuilder();
                tx        =
                    txBuilder
                    .SetTransactionPolicy(new StandardTransactionPolicy()
                {
                    MinRelayTxFee = new FeeRate(0)
                })
                    .AddCoins(coins)
                    .AddKeys(keys)
                    .Send(bob.GetNextScriptPubKey(), Money.Coins(0.1m))
                    .SetChange(alice.GetNextScriptPubKey(true))
                    .SendFees(Money.Coins(0.0001m))
                    .BuildTransaction(true);

                Assert.True(txBuilder.Verify(tx));

                builder.Nodes[0].Broadcast(tx);

                //Bob still has coins
                TestUtils.Eventually(() => bob.GetTransactions().Count == 2);                 //Bob has both, old and new tx
                coins = bob.GetTransactions().GetSpendableCoins();
                //////
            }
        }
Beispiel #2
0
        public void CanGetMerkleRoot()
        {
            using (var builder = NodeBuilder.Create())
            {
                var node = builder.CreateNode(true).CreateNodeClient();
                builder.Nodes[0].Generate(101);
                var rpc = builder.Nodes[0].CreateRPCClient();
                builder.Nodes[0].Split(Money.Coins(50m), 50);
                builder.Nodes[0].SelectMempoolTransactions();
                builder.Nodes[0].Generate(1);
                for (int i = 0; i < 20; i++)
                {
                    rpc.SendToAddress(new Key().PubKey.GetAddress(rpc.Network), Money.Coins(0.5m));
                }
                builder.Nodes[0].SelectMempoolTransactions();
                builder.Nodes[0].Generate(1);
                var block        = builder.Nodes[0].CreateRPCClient().GetBlock(103);
                var knownTx      = block.Transactions[0].GetHash();
                var knownAddress = block.Transactions[0].Outputs[0].ScriptPubKey.GetDestination();
                node.VersionHandshake();
                using (var list = node.CreateListener()
                                  .Where(m => m.Message.Payload is MerkleBlockPayload || m.Message.Payload is TxPayload))
                {
                    BloomFilter filter = new BloomFilter(1, 0.005, 50, BloomFlags.UPDATE_NONE);
                    filter.Insert(knownAddress.ToBytes());
                    node.SendMessageAsync(new FilterLoadPayload(filter));
                    node.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() > 1);
                    Assert.True(tree.GetMatchedTransactions().Contains(knownTx));

                    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 > 1);
                    tree = tree.Trim(knownTx);
                    Assert.True(tree.GetMatchedTransactions().Count() == 1);
                    Assert.True(tree.GetMatchedTransactions().Contains(knownTx));

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

                    var unknownBlock = uint256.Parse("00000000ad262227291eaf90cafdc56a8f8451e2d7653843122c5bb0bf2dfcdd");
                    node.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));
                }
            }
        }
Beispiel #3
0
        // todo: revisit this test when fixing the node tests
        //[Fact]
        //[Trait("CoreBeta", "CoreBeta")]
        public void CanAskCmpctBlock()
        {
            var alice   = new BitcoinSecret("KypycJyxP5yA4gSedEBRse5q5f8RwYKG8xi8z4SRe2rdaioL3YNc").PrivateKey;
            var satoshi = new BitcoinSecret("KypycJyxP5yA4gSedEBRse5q5f8RwYKG8xi8z4SRe2rdaioL3YNc").ToNetwork(Network.RegTest);

            using (var builder = NodeBuilder.Create(version: "C:\\Bitcoin\\bitcoind.exe"))
            {
                var now = new DateTimeOffset(2015, 07, 18, 0, 0, 0, TimeSpan.Zero);
                builder.ConfigParameters.Add("mocktime", Utils.DateTimeToUnixTime(now).ToString());
                var bitcoind  = builder.CreateNode(false);
                var bitcoind2 = builder.CreateNode(false);
                builder.StartAll();

                bitcoind.SetMinerSecret(satoshi);
                bitcoind.MockTime = now;

                bitcoind2.SetMinerSecret(satoshi);
                bitcoind2.MockTime = now;

                var rpc = bitcoind.CreateRPCClient();
                rpc.AddNode(bitcoind2.Endpoint, true);

                var client1 = bitcoind.CreateNodeClient(new NodeConnectionParameters()
                {
                    Version = ProtocolVersion.SHORT_IDS_BLOCKS_VERSION
                });
                using (var listener = client1.CreateListener())
                {
                    client1.VersionHandshake();
                    var sendCmpct = listener.ReceivePayload <SendCmpctPayload>();
                    Assert.Equal(1U, sendCmpct.Version);
                    Assert.Equal(false, sendCmpct.PreferHeaderAndIDs);

                    //Announcement
                    client1.SendMessage(new SendCmpctPayload(false));
                    bitcoind.Generate(1);
                    var inv = listener.ReceivePayload <InvPayload>();
                    Assert.True(inv.First().Type == InventoryType.MSG_BLOCK);

                    //Request block
                    inv.First().Type = InventoryType.MSG_CMPCT_BLOCK;
                    client1.SendMessage(new GetDataPayload(inv.First()));
                    var blk = listener.ReceivePayload <CmpctBlockPayload>();

                    //Request transaction
                    var getTxn = new GetBlockTxnPayload();
                    getTxn.BlockId = blk.Header.GetHash();
                    getTxn.Indices.Add(0);
                    client1.SendMessage(getTxn);
                    var blockTxn = listener.ReceivePayload <BlockTxnPayload>();
                    Assert.True(blockTxn.BlockId == blk.Header.GetHash());
                    Assert.True(blockTxn.Transactions[0].GetHash() == blk.PrefilledTransactions[0].Transaction.GetHash());

                    bitcoind.Generate(100);
                    var tx      = bitcoind.GiveMoney(alice.ScriptPubKey, Money.Coins(1), false);
                    var lastBlk = bitcoind.Generate(1)[0];

                    while (true)
                    {
                        var invv = listener.ReceivePayload <InvPayload>().First();
                        if (invv.Hash == lastBlk.GetHash())
                        {
                            invv.Type = InventoryType.MSG_CMPCT_BLOCK;
                            client1.SendMessage(new GetDataPayload(invv));
                            break;
                        }
                    }

                    blk = listener.ReceivePayload <CmpctBlockPayload>();
                    Assert.Equal(1, blk.ShortIds.Count);
                    Assert.Equal(blk.ShortIds[0], blk.GetShortID(tx.GetHash()));

                    //Let the node know which is the last block that we know
                    client1.SendMessage(new InvPayload(new InventoryVector(InventoryType.MSG_BLOCK, blk.Header.GetHash())));
                    bitcoind.Generate(1);
                    inv = listener.ReceivePayload <InvPayload>();
                    inv.First().Type = InventoryType.MSG_CMPCT_BLOCK;
                    client1.SendMessage(new GetDataPayload(inv.First()));
                    blk = listener.ReceivePayload <CmpctBlockPayload>();

                    //Prefer being notified with cmpctblock
                    client1.SendMessage(new SendCmpctPayload(true));
                    //Let the node know which is the last block that we know
                    client1.SendMessage(new InvPayload(new InventoryVector(InventoryType.MSG_BLOCK, blk.Header.GetHash())));
                    bitcoind.Generate(1);
                    blk = listener.ReceivePayload <CmpctBlockPayload>();

                    //The node ask to connect to use in high bandwidth mode
                    var blocks = bitcoind.Generate(1, broadcast: false);
                    client1.SendMessage(new HeadersPayload(blocks[0].Header));
                    var cmpct = listener.ReceivePayload <SendCmpctPayload>();                    //Should become one of the three high bandwidth node
                    Assert.True(cmpct.PreferHeaderAndIDs);
                    var getdata = listener.ReceivePayload <GetDataPayload>();
                    Assert.True(getdata.Inventory[0].Type == InventoryType.MSG_CMPCT_BLOCK);
                    client1.SendMessage(new CmpctBlockPayload(blocks[0]));

                    //Should be able to get a compact block with Inv
                    blocks = bitcoind.Generate(1, broadcast: false);
                    client1.SendMessage(new InvPayload(blocks[0]));
                    getdata = listener.ReceivePayload <GetDataPayload>();
                    Assert.True(getdata.Inventory[0].Type == InventoryType.MSG_CMPCT_BLOCK);
                    client1.SendMessage(new CmpctBlockPayload(blocks[0]));


                    //Send as prefilled transaction 0 and 2
                    var tx1 = bitcoind.GiveMoney(satoshi.ScriptPubKey, Money.Coins(1.0m), broadcast: false);
                    var tx2 = bitcoind.GiveMoney(satoshi.ScriptPubKey, Money.Coins(2.0m), broadcast: false);
                    var tx3 = bitcoind.GiveMoney(satoshi.ScriptPubKey, Money.Coins(3.0m), broadcast: false);
                    blocks = bitcoind.Generate(1, broadcast: false);
                    Assert.True(blocks[0].Transactions.Count == 4);
                    var cmpctBlk = new CmpctBlockPayload();
                    cmpctBlk.Nonce  = RandomUtils.GetUInt64();
                    cmpctBlk.Header = blocks[0].Header;
                    cmpctBlk.PrefilledTransactions.Add(new PrefilledTransaction()
                    {
                        Index = 0, Transaction = blocks[0].Transactions[0]
                    });
                    cmpctBlk.PrefilledTransactions.Add(new PrefilledTransaction()
                    {
                        Index = 2, Transaction = blocks[0].Transactions[2]
                    });
                    cmpctBlk.AddTransactionShortId(blocks[0].Transactions[1]);
                    cmpctBlk.AddTransactionShortId(blocks[0].Transactions[3]);
                    client1.SendMessage(cmpctBlk);

                    //Check that node ask for 1 and 3
                    var gettxn = listener.ReceivePayload <GetBlockTxnPayload>();
                    Assert.Equal(2, gettxn.Indices.Count);
                    Assert.Equal(1, gettxn.Indices[0]);
                    Assert.Equal(3, gettxn.Indices[1]);

                    client1.SendMessage(new BlockTxnPayload()
                    {
                        BlockId      = blocks[0].GetHash(),
                        Transactions =
                        {
                            blocks[0].Transactions[1],
                            blocks[0].Transactions[3],
                        }
                    });

                    //Both nodes updated ?
                    var chain1 = client1.GetChain();
                    Assert.Equal(blocks[0].GetHash(), chain1.Tip.HashBlock);
                    using (var client2 = bitcoind2.CreateNodeClient())
                    {
                        client2.VersionHandshake();
                        var chain2 = client2.GetChain();
                        Assert.Equal(chain1.Tip.HashBlock, chain2.Tip.HashBlock);
                    }

                    //Block with coinbase only
                    blocks = bitcoind.Generate(1, broadcast: false);
                    client1.SendMessage(new CmpctBlockPayload(blocks[0]));
                    client1.SynchronizeChain(chain1);
                    Assert.Equal(chain1.Tip.HashBlock, blocks[0].GetHash());
                }
            }
        }