public void CanDownloadLastBlocks() { using (var builder = NodeBuilder.Create()) { var node = builder.CreateNode(true).CreateNodeClient(); builder.Nodes[0].Generate(150); var chain = node.GetChain(); Assert.True(node.PeerVersion.StartHeight <= chain.Height); var subChain = chain.ToEnumerable(true).Take(100).Select(s => s.HashBlock).ToArray(); var begin = node.Counter.Snapshot(); var blocks = node.GetBlocks(subChain).Select(_ => 1).ToList(); var end = node.Counter.Snapshot(); var diff = end - begin; Assert.True(diff.Start == begin.Taken); Assert.True(diff.Taken == end.Taken); Assert.True(diff.TotalReadenBytes == end.TotalReadenBytes - begin.TotalReadenBytes); Assert.True(diff.TotalWrittenBytes == end.TotalWrittenBytes - begin.TotalWrittenBytes); Assert.True(blocks.Count == 100); } }
public void CanGetChainsConcurrenty() { using (var builder = NodeBuilder.Create()) { bool generating = true; builder.CreateNode(true); Task.Run(() => { builder.Nodes[0].Generate(600); generating = false; }); var node = builder.Nodes[0].CreateNodeClient(); node.PollHeaderDelay = TimeSpan.FromSeconds(2); node.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(node.GetChain()); })) .Select(t => t.Result) .ToArray(); while (generating) { SyncAll(node, rand, chains); } SyncAll(node, rand, chains); foreach (var c in chains) { Assert.Equal(600, c.Height); } } }
public void CanImportMultiAddresses() { // Test cases borrowed from: https://github.com/bitcoin/bitcoin/blob/master/test/functional/importmulti.py using (var builder = NodeBuilder.Create()) { var rpc = builder.CreateNode().CreateRPCClient(); builder.StartAll(); Key key; RPCException response; List <ImportMultiAddress> multiAddresses; Network network = Network.RegTest; // 20 total test cases #region Bitcoin Address Console.WriteLine("Should import an address"); key = new Key(); multiAddresses = new List <ImportMultiAddress> { new ImportMultiAddress { ScriptPubKey = new ImportMultiAddress.ScriptPubKeyObject { Address = key.PubKey.GetAddress(network) }, Timestamp = Utils.UnixTimeToDateTime(0) } }; rpc.ImportMulti(multiAddresses.ToArray(), false); #endregion #region ScriptPubKey + internal Console.WriteLine("Should import a scriptPubKey with internal flag"); key = new Key(); multiAddresses = new List <ImportMultiAddress> { new ImportMultiAddress { ScriptPubKey = new ImportMultiAddress.ScriptPubKeyObject(key.ScriptPubKey), Internal = true } }; rpc.ImportMulti(multiAddresses.ToArray(), false); #endregion #region ScriptPubKey + !internal Console.WriteLine("Should not import a scriptPubKey without internal flag"); key = new Key(); multiAddresses = new List <ImportMultiAddress> { new ImportMultiAddress { ScriptPubKey = new ImportMultiAddress.ScriptPubKeyObject { ScriptPubKey = key.ScriptPubKey }, } }; response = Assert.Throws <RPCException>(() => rpc.ImportMulti(multiAddresses.ToArray(), false)); Assert.Equal(response.RPCCode, RPCErrorCode.RPC_INVALID_PARAMETER); Assert.Equal(response.Message, "Internal must be set for hex scriptPubKey"); #endregion #region Address + Public key + !internal Console.WriteLine("Should import an address with public key"); key = new Key(); multiAddresses = new List <ImportMultiAddress> { new ImportMultiAddress { ScriptPubKey = new ImportMultiAddress.ScriptPubKeyObject(key.PubKey.GetAddress(network)), PubKeys = new string[] { key.PubKey.ToString() } } }; rpc.ImportMulti(multiAddresses.ToArray(), false); #endregion #region ScriptPubKey + Public key + internal Console.WriteLine("Should import a scriptPubKey with internal and with public key"); key = new Key(); multiAddresses = new List <ImportMultiAddress> { new ImportMultiAddress { ScriptPubKey = new ImportMultiAddress.ScriptPubKeyObject { ScriptPubKey = key.ScriptPubKey }, PubKeys = new string[] { key.PubKey.ToString() }, Internal = true } }; rpc.ImportMulti(multiAddresses.ToArray(), false); #endregion #region ScriptPubKey + Public key + !internal // Console.WriteLine("Should not import a scriptPubKey without internal and with public key"); key = new Key(); multiAddresses = new List <ImportMultiAddress> { new ImportMultiAddress { ScriptPubKey = new ImportMultiAddress.ScriptPubKeyObject { ScriptPubKey = key.ScriptPubKey }, PubKeys = new string[] { key.PubKey.ToString() } } }; response = Assert.Throws <RPCException>(() => rpc.ImportMulti(multiAddresses.ToArray(), false)); Assert.Equal(response.RPCCode, RPCErrorCode.RPC_INVALID_PARAMETER); Assert.Equal(response.Message, "Internal must be set for hex scriptPubKey"); #endregion #region Address + Private key + !watchonly // Console.WriteLine("Should import an address with private key"); key = new Key(); multiAddresses = new List <ImportMultiAddress> { new ImportMultiAddress { ScriptPubKey = new ImportMultiAddress.ScriptPubKeyObject { Address = key.PubKey.GetAddress(network) }, Keys = new string[] { key.GetWif(network).ToString() } } }; rpc.ImportMulti(multiAddresses.ToArray(), false); Console.WriteLine("Should not import an address with private key if is already imported"); multiAddresses = new List <ImportMultiAddress> { new ImportMultiAddress { ScriptPubKey = new ImportMultiAddress.ScriptPubKeyObject { Address = key.PubKey.GetAddress(network) }, Keys = new string[] { key.GetWif(network).ToString() } } }; response = Assert.Throws <RPCException>(() => rpc.ImportMulti(multiAddresses.ToArray(), false)); //Assert.False(response.Result[0].Value<bool>()); #endregion #region Address + Private key + watchonly Console.WriteLine("Should not import an address with private key and with watchonly"); key = new Key(); multiAddresses = new List <ImportMultiAddress> { new ImportMultiAddress { ScriptPubKey = new ImportMultiAddress.ScriptPubKeyObject { Address = key.PubKey.GetAddress(network) }, Keys = new string[] { key.GetWif(network).ToString() }, WatchOnly = true } }; response = Assert.Throws <RPCException>(() => rpc.ImportMulti(multiAddresses.ToArray(), false)); Assert.Equal(response.RPCCode, RPCErrorCode.RPC_INVALID_PARAMETER); Assert.Equal(response.Message, "Incompatibility found between watchonly and keys"); #endregion #region ScriptPubKey + Private key + internal Console.WriteLine("Should import a scriptPubKey with internal and with private key"); key = new Key(); multiAddresses = new List <ImportMultiAddress> { new ImportMultiAddress { ScriptPubKey = new ImportMultiAddress.ScriptPubKeyObject { ScriptPubKey = key.ScriptPubKey }, Keys = new string[] { key.GetWif(network).ToString() }, Internal = true } }; rpc.ImportMulti(multiAddresses.ToArray(), false); #endregion #region ScriptPubKey + Private key + !internal Console.WriteLine("Should not import a scriptPubKey without internal and with private key"); key = new Key(); multiAddresses = new List <ImportMultiAddress> { new ImportMultiAddress { ScriptPubKey = new ImportMultiAddress.ScriptPubKeyObject { ScriptPubKey = key.ScriptPubKey }, Keys = new string[] { key.GetWif(network).ToString() } } }; response = Assert.Throws <RPCException>(() => rpc.ImportMulti(multiAddresses.ToArray(), false)); #endregion #region P2SH address //Blocked : Dependent on implementation of rpc.CreateMultiSig() #endregion #region P2SH + Redeem script //Blocked : Dependent on implementation of rpc.CreateMultiSig() #endregion #region P2SH + Redeem script + Private Keys + !Watchonly //Blocked : Dependent on implementation of rpc.CreateMultiSig() #endregion #region P2SH + Redeem script + Private Keys + Watchonly //Blocked : Dependent on implementation of rpc.CreateMultiSig() #endregion #region Address + Public key + !Internal + Wrong pubkey Console.WriteLine("Should not import an address with a wrong public key"); key = new Key(); multiAddresses = new List <ImportMultiAddress> { new ImportMultiAddress { ScriptPubKey = new ImportMultiAddress.ScriptPubKeyObject { Address = key.PubKey.GetAddress(network) }, PubKeys = new string[] { new Key().PubKey.ToString() } } }; response = Assert.Throws <RPCException>(() => rpc.ImportMulti(multiAddresses.ToArray(), false)); Assert.Equal(response.RPCCode, RPCErrorCode.RPC_INVALID_ADDRESS_OR_KEY); Assert.Equal(response.Message, "Consistency check failed"); #endregion #region ScriptPubKey + Public key + internal + Wrong pubkey Console.WriteLine("Should not import a scriptPubKey with internal and with a wrong public key"); key = new Key(); multiAddresses = new List <ImportMultiAddress> { new ImportMultiAddress { ScriptPubKey = new ImportMultiAddress.ScriptPubKeyObject { ScriptPubKey = key.ScriptPubKey }, PubKeys = new string[] { new Key().PubKey.ToString() }, Internal = true } }; response = Assert.Throws <RPCException>(() => rpc.ImportMulti(multiAddresses.ToArray(), false)); Assert.Equal(response.RPCCode, RPCErrorCode.RPC_INVALID_ADDRESS_OR_KEY); Assert.Equal(response.Message, "Consistency check failed"); #endregion #region Address + Private key + !watchonly + Wrong private key Console.WriteLine("Should not import an address with a wrong private key"); key = new Key(); multiAddresses = new List <ImportMultiAddress> { new ImportMultiAddress { ScriptPubKey = new ImportMultiAddress.ScriptPubKeyObject { Address = key.PubKey.GetAddress(network) }, Keys = new string[] { new Key().GetWif(network).ToString() } } }; response = Assert.Throws <RPCException>(() => rpc.ImportMulti(multiAddresses.ToArray(), false)); Assert.Equal(response.RPCCode, RPCErrorCode.RPC_INVALID_ADDRESS_OR_KEY); Assert.Equal(response.Message, "Consistency check failed"); #endregion #region ScriptPubKey + Private key + internal + Wrong private key Console.WriteLine("Should not import a scriptPubKey with internal and with a wrong private key"); key = new Key(); multiAddresses = new List <ImportMultiAddress> { new ImportMultiAddress { ScriptPubKey = new ImportMultiAddress.ScriptPubKeyObject { ScriptPubKey = key.ScriptPubKey }, Keys = new string[] { new Key().GetWif(network).ToString() }, Internal = true } }; response = Assert.Throws <RPCException>(() => rpc.ImportMulti(multiAddresses.ToArray(), false)); Assert.Equal(response.RPCCode, RPCErrorCode.RPC_INVALID_ADDRESS_OR_KEY); Assert.Equal(response.Message, "Consistency check failed"); #endregion #region Importing existing watch only address with new timestamp should replace saved timestamp. //TODO #endregion #region restart nodes to check for proper serialization/deserialization of watch only address //TODO #endregion } }
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)); } } }
// 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()); } } }
public void CanImportMultiAddresses() { // Test cases borrowed from: https://github.com/bitcoin/bitcoin/blob/master/test/functional/importmulti.py using (var builder = NodeBuilder.Create(version: "0.15.1")) { var rpc = builder.CreateNode().CreateRPCClient(); builder.StartAll(); Key key; List <ImportMultiAddress> multiAddresses; RPCResponse response; Network network = Network.RegTest; // 20 total test cases #region Bitcoin Address Console.WriteLine("Should import an address"); key = new Key(); multiAddresses = new List <ImportMultiAddress> { new ImportMultiAddress { ScriptPubKey = new ImportMultiAddress.ScriptPubKeyObject { Address = key.PubKey.GetAddress(network).ToString() }, Timestamp = "now" } }; response = rpc.ImportMulti(multiAddresses.ToArray(), false); Assert.True(response.Result[0]["success"].Value <bool>()); Console.WriteLine("Should not import an invalid address"); multiAddresses = new List <ImportMultiAddress> { new ImportMultiAddress { ScriptPubKey = new ImportMultiAddress.ScriptPubKeyObject { Address = "not valid address" }, Timestamp = DateTimeOffset.Now.AddDays(-1) } }; response = rpc.ImportMulti(multiAddresses.ToArray(), false); Assert.False(response.Result[0]["success"].Value <bool>()); #endregion #region ScriptPubKey + internal Console.WriteLine("Should import a scriptPubKey with internal flag"); key = new Key(); multiAddresses = new List <ImportMultiAddress> { new ImportMultiAddress { ScriptPubKey = new ImportMultiAddress.ScriptPubKeyObject { ScriptPubKey = key.ScriptPubKey.ToHex() }, Timestamp = "now", Internal = true } }; response = rpc.ImportMulti(multiAddresses.ToArray(), false); Assert.True(response.Result[0]["success"].Value <bool>()); #endregion #region ScriptPubKey + !internal Console.WriteLine("Should not import a scriptPubKey without internal flag"); key = new Key(); multiAddresses = new List <ImportMultiAddress> { new ImportMultiAddress { ScriptPubKey = new ImportMultiAddress.ScriptPubKeyObject { ScriptPubKey = key.ScriptPubKey.ToHex() }, Timestamp = "now" } }; response = rpc.ImportMulti(multiAddresses.ToArray(), false); Assert.False(response.Result[0]["success"].Value <bool>()); Assert.Equal(response.Result[0]["error"]["code"].Value <int>(), -8); Assert.Equal(response.Result[0]["error"]["message"].Value <string>(), "Internal must be set for hex scriptPubKey"); #endregion #region Address + Public key + !internal Console.WriteLine("Should import an address with public key"); key = new Key(); multiAddresses = new List <ImportMultiAddress> { new ImportMultiAddress { ScriptPubKey = new ImportMultiAddress.ScriptPubKeyObject { Address = key.PubKey.GetAddress(network).ToString() }, Timestamp = "now", PubKeys = new string[] { key.PubKey.ToString() } } }; response = rpc.ImportMulti(multiAddresses.ToArray(), false); Assert.True(response.Result[0]["success"].Value <bool>()); #endregion #region ScriptPubKey + Public key + internal Console.WriteLine("Should import a scriptPubKey with internal and with public key"); key = new Key(); multiAddresses = new List <ImportMultiAddress> { new ImportMultiAddress { ScriptPubKey = new ImportMultiAddress.ScriptPubKeyObject { ScriptPubKey = key.ScriptPubKey.ToHex() }, Timestamp = "now", PubKeys = new string[] { key.PubKey.ToString() }, Internal = true } }; response = rpc.ImportMulti(multiAddresses.ToArray(), false); Assert.True(response.Result[0]["success"].Value <bool>()); #endregion #region ScriptPubKey + Public key + !internal Console.WriteLine("Should not import a scriptPubKey without internal and with public key"); key = new Key(); multiAddresses = new List <ImportMultiAddress> { new ImportMultiAddress { ScriptPubKey = new ImportMultiAddress.ScriptPubKeyObject { ScriptPubKey = key.ScriptPubKey.ToHex() }, Timestamp = "now", PubKeys = new string[] { key.PubKey.ToString() } } }; response = rpc.ImportMulti(multiAddresses.ToArray(), false); Assert.False(response.Result[0]["success"].Value <bool>()); Assert.Equal(response.Result[0]["error"]["code"].Value <int>(), -8); Assert.Equal(response.Result[0]["error"]["message"].Value <string>(), "Internal must be set for hex scriptPubKey"); #endregion #region Address + Private key + !watchonly Console.WriteLine("Should import an address with private key"); key = new Key(); multiAddresses = new List <ImportMultiAddress> { new ImportMultiAddress { ScriptPubKey = new ImportMultiAddress.ScriptPubKeyObject { Address = key.PubKey.GetAddress(network).ToString() }, Timestamp = "now", Keys = new string[] { key.GetWif(network).ToString() } } }; response = rpc.ImportMulti(multiAddresses.ToArray(), false); Assert.True(response.Result[0]["success"].Value <bool>()); Console.WriteLine("Should not import an address with private key if is already imported"); multiAddresses = new List <ImportMultiAddress> { new ImportMultiAddress { ScriptPubKey = new ImportMultiAddress.ScriptPubKeyObject { Address = key.PubKey.GetAddress(network).ToString() }, Timestamp = "now", Keys = new string[] { key.GetWif(network).ToString() } } }; response = rpc.ImportMulti(multiAddresses.ToArray(), false); //Assert.False(response.Result[0].Value<bool>()); Assert.False(response.Result[0]["success"].Value <bool>()); #endregion #region Address + Private key + watchonly Console.WriteLine("Should not import an address with private key and with watchonly"); key = new Key(); multiAddresses = new List <ImportMultiAddress> { new ImportMultiAddress { ScriptPubKey = new ImportMultiAddress.ScriptPubKeyObject { Address = key.PubKey.GetAddress(network).ToString() }, Timestamp = "now", Keys = new string[] { key.GetWif(network).ToString() }, WatchOnly = true } }; response = rpc.ImportMulti(multiAddresses.ToArray(), false); Assert.False(response.Result[0]["success"].Value <bool>()); Assert.Equal(response.Result[0]["error"]["code"].Value <int>(), -8); Assert.Equal(response.Result[0]["error"]["message"].Value <string>(), "Incompatibility found between watchonly and keys"); #endregion #region ScriptPubKey + Private key + internal Console.WriteLine("Should import a scriptPubKey with internal and with private key"); key = new Key(); multiAddresses = new List <ImportMultiAddress> { new ImportMultiAddress { ScriptPubKey = new ImportMultiAddress.ScriptPubKeyObject { ScriptPubKey = key.ScriptPubKey.ToHex() }, Timestamp = "now", Keys = new string[] { key.GetWif(network).ToString() }, Internal = true } }; response = rpc.ImportMulti(multiAddresses.ToArray(), false); Assert.True(response.Result[0]["success"].Value <bool>()); #endregion #region ScriptPubKey + Private key + !internal Console.WriteLine("Should not import a scriptPubKey without internal and with private key"); key = new Key(); multiAddresses = new List <ImportMultiAddress> { new ImportMultiAddress { ScriptPubKey = new ImportMultiAddress.ScriptPubKeyObject { ScriptPubKey = key.ScriptPubKey.ToHex() }, Timestamp = "now", Keys = new string[] { key.GetWif(network).ToString() } } }; response = rpc.ImportMulti(multiAddresses.ToArray(), false); Assert.False(response.Result[0]["success"].Value <bool>()); #endregion #region P2SH address //Blocked : Dependent on implementation of rpc.CreateMultiSig() #endregion #region P2SH + Redeem script //Blocked : Dependent on implementation of rpc.CreateMultiSig() #endregion #region P2SH + Redeem script + Private Keys + !Watchonly //Blocked : Dependent on implementation of rpc.CreateMultiSig() #endregion #region P2SH + Redeem script + Private Keys + Watchonly //Blocked : Dependent on implementation of rpc.CreateMultiSig() #endregion #region Address + Public key + !Internal + Wrong pubkey Console.WriteLine("Should not import an address with a wrong public key"); key = new Key(); multiAddresses = new List <ImportMultiAddress> { new ImportMultiAddress { ScriptPubKey = new ImportMultiAddress.ScriptPubKeyObject { Address = key.PubKey.GetAddress(network).ToString() }, Timestamp = "now", PubKeys = new string[] { new Key().PubKey.ToString() } } }; response = rpc.ImportMulti(multiAddresses.ToArray(), false); Assert.False(response.Result[0]["success"].Value <bool>()); Assert.Equal(response.Result[0]["error"]["code"].Value <int>(), -5); Assert.Equal(response.Result[0]["error"]["message"].Value <string>(), "Consistency check failed"); #endregion #region ScriptPubKey + Public key + internal + Wrong pubkey Console.WriteLine("Should not import a scriptPubKey with internal and with a wrong public key"); key = new Key(); multiAddresses = new List <ImportMultiAddress> { new ImportMultiAddress { ScriptPubKey = new ImportMultiAddress.ScriptPubKeyObject { ScriptPubKey = key.ScriptPubKey.ToHex() }, Timestamp = "now", PubKeys = new string[] { new Key().PubKey.ToString() }, Internal = true } }; response = rpc.ImportMulti(multiAddresses.ToArray(), false); Assert.False(response.Result[0]["success"].Value <bool>()); Assert.Equal(response.Result[0]["error"]["code"].Value <int>(), -5); Assert.Equal(response.Result[0]["error"]["message"].Value <string>(), "Consistency check failed"); #endregion #region Address + Private key + !watchonly + Wrong private key Console.WriteLine("Should not import an address with a wrong private key"); key = new Key(); multiAddresses = new List <ImportMultiAddress> { new ImportMultiAddress { ScriptPubKey = new ImportMultiAddress.ScriptPubKeyObject { Address = key.PubKey.GetAddress(network).ToString() }, Timestamp = "now", Keys = new string[] { new Key().GetWif(network).ToString() } } }; response = rpc.ImportMulti(multiAddresses.ToArray(), false); Assert.False(response.Result[0]["success"].Value <bool>()); Assert.Equal(response.Result[0]["error"]["code"].Value <int>(), -5); Assert.Equal(response.Result[0]["error"]["message"].Value <string>(), "Consistency check failed"); #endregion #region ScriptPubKey + Private key + internal + Wrong private key Console.WriteLine("Should not import a scriptPubKey with internal and with a wrong private key"); key = new Key(); multiAddresses = new List <ImportMultiAddress> { new ImportMultiAddress { ScriptPubKey = new ImportMultiAddress.ScriptPubKeyObject { ScriptPubKey = key.ScriptPubKey.ToHex() }, Timestamp = "now", Keys = new string[] { new Key().GetWif(network).ToString() }, Internal = true } }; response = rpc.ImportMulti(multiAddresses.ToArray(), false); Assert.False(response.Result[0]["success"].Value <bool>()); Assert.Equal(response.Result[0]["error"]["code"].Value <int>(), -5); Assert.Equal(response.Result[0]["error"]["message"].Value <string>(), "Consistency check failed"); #endregion #region Importing existing watch only address with new timestamp should replace saved timestamp. //TODO #endregion #region restart nodes to check for proper serialization/deserialization of watch only address //TODO #endregion } }
public static NodeBuilder Create([CallerMemberName] string caller = null) { //var builder = NodeBuilder.Create(NodeDownloadData.Litecoin.v0_17_1, Altcoins.Litecoin.Instance.Regtest, caller); //var builder = NodeBuilder.Create(NodeDownloadData.Viacoin.v0_15_1, Altcoins.Viacoin.Instance.Regtest, caller); //var builder = NodeBuilder.Create(NodeDownloadData.BCash.v0_16_2, Altcoins.BCash.Instance.Regtest, caller); //var builder = NodeBuilder.Create(NodeDownloadData.Dogecoin.v1_10_0, Altcoins.Dogecoin.Instance.Regtest, caller); //var builder = NodeBuilder.Create(NodeDownloadData.Verge.v6_0_2, Altcoins.Verge.Instance.Regtest, caller); //var builder = NodeBuilder.Create(NodeDownloadData.Dash.v0_13_0, Altcoins.Dash.Instance.Regtest, caller); //var builder = NodeBuilder.Create(NodeDownloadData.Terracoin.v0_12_2, Altcoins.Terracoin.Instance.Regtest, caller); //var builder = NodeBuilder.Create(NodeDownloadData.BGold.v0_15_0, Altcoins.BGold.Instance.Regtest, caller); //var builder = NodeBuilder.Create(NodeDownloadData.Polis.v1_4_3, Altcoins.Polis.Instance.Regtest, caller); //var builder = NodeBuilder.Create(NodeDownloadData.Monoeci.v0_12_2_3, Altcoins.Monoeci.Instance.Regtest, caller); //var builder = NodeBuilder.Create(NodeDownloadData.Colossus.v1_1_1, Altcoins.Colossus.Instance.Regtest, caller); //var builder = NodeBuilder.Create(NodeDownloadData.GoByte.v0_12_2_4, Altcoins.GoByte.Instance.Regtest, caller); //var builder = NodeBuilder.Create(NodeDownloadData.Monacoin.v0_15_1, Altcoins.Monacoin.Regtest, caller); //var builder = NodeBuilder.Create(NodeDownloadData.Feathercoin.v0_16_0, Altcoins.AltNetworkSets.Feathercoin.Regtest, caller); //var builder = NodeBuilder.Create(NodeDownloadData.Ufo.v0_16_0, Altcoins.AltNetworkSets.Ufo.Regtest, caller); //var builder = NodeBuilder.Create(NodeDownloadData.Groestlcoin.v2_19_1, Altcoins.AltNetworkSets.Groestlcoin.Regtest, caller); //var builder = NodeBuilder.Create(NodeDownloadData.Mogwai.v0_12_2, Altcoins.AltNetworkSets.Mogwai.Regtest, caller); //var builder = NodeBuilder.Create(NodeDownloadData.Dystem.v1_0_9_9, Altcoins.Dystem.Instance.Regtest, caller); //var builder = NodeBuilder.Create(NodeDownloadData.Bitcoinplus.v2_7_0, Altcoins.AltNetworkSets.Bitcoinplus.Regtest, caller); //var builder = NodeBuilder.Create(NodeDownloadData.Liquid.v3_14_1_21, Altcoins.AltNetworkSets.Liquid.Regtest, caller); //var builder = NodeBuilder.Create(NodeDownloadData.Bitcore.v0_90_9_1, Altcoins.Bitcore.Instance.Regtest, caller); //var builder = NodeBuilder.Create(NodeDownloadData.Gincoin.v1_1_0_0, Altcoins.Gincoin.Instance.Regtest, caller); //var builder = NodeBuilder.Create(NodeDownloadData.Koto.v2_0_0, Altcoins.Koto.Regtest, caller); //var builder = NodeBuilder.Create(NodeDownloadData.Chaincoin.v0_16_4 , Altcoins.AltNetworkSets.Chaincoin.Regtest, caller); //var builder = NodeBuilder.Create(NodeDownloadData.Stratis.v3_0_0, Altcoins.AltNetworkSets.Stratis.Regtest, caller); //var builder = NodeBuilder.Create(NodeDownloadData.ZCoin.v0_13_8_3, Altcoins.ZCoin.Instance.Regtest, caller); //var builder = NodeBuilder.Create(NodeDownloadData.DogeCash.v5_1_1, Altcoins.DogeCash.Instance.Regtest, caller); //var builder = NodeBuilder.Create(NodeDownloadData.Elements.v0_18_1_1, Altcoins.AltNetworkSets.Liquid.Regtest, caller); //var builder = NodeBuilder.Create(NodeDownloadData.Argoneum.v1_4_1, Altcoins.Argoneum.Instance.Regtest, caller); //var builder = NodeBuilder.Create(NodeDownloadData.Qtum.v0_18_3, Altcoins.Qtum.Instance.Regtest, caller); //var builder = NodeBuilder.Create(NodeDownloadData.MonetaryUnit.v2_1_6, Altcoins.MonetaryUnit.Instance.Regtest, caller); var builder = NodeBuilder.Create(NodeDownloadData.Blocknet.v4_3_0, Altcoins.Blocknet.Instance.Regtest, caller); //var builder = Create(NodeDownloadData.Bitcoin.v0_19_0_1, caller); //var builder = Create(NodeDownloadData.Bitcoin.v0_20_0, caller); return(builder); }
public void CanSyncWalletCore(NodeBuilder builder, CoreNode walletNode, WalletCreation creation) { var rpc = builder.Nodes[0].CreateRPCClient(); var notifiedTransactions = new List <WalletTransaction>(); NodesGroup connected = CreateGroup(builder, new List <CoreNode>(new[] { walletNode }), 1); Wallet wallet = new Wallet(creation, keyPoolSize: 11); wallet.NewWalletTransaction += (s, a) => notifiedTransactions.Add(a); Assert.True(wallet.State == WalletState.Created); wallet.Configure(connected); wallet.Connect(); Assert.True(wallet.State == WalletState.Disconnected); TestUtils.Eventually(() => connected.ConnectedNodes.Count == 1); Assert.True(wallet.State == WalletState.Connected); TestUtils.Eventually(() => wallet.Chain.Height == rpc.GetBlockCount()); for (int i = 0; i < 9; i++) { wallet.GetNextScriptPubKey(); } wallet.GetNextScriptPubKey(); //Should provoke purge TestUtils.Eventually(() => wallet.State == WalletState.Disconnected && wallet.ConnectedNodes == 0); Thread.Sleep(100); TestUtils.Eventually(() => wallet.ConnectedNodes == 1); var k = wallet.GetNextScriptPubKey(); Assert.NotNull(wallet.GetKeyPath(k)); if (creation.UseP2SH) { var p2sh = k.GetDestinationAddress(Network.TestNet) as BitcoinScriptAddress; Assert.NotNull(p2sh); var redeem = wallet.GetRedeemScript(p2sh); Assert.NotNull(redeem); Assert.Equal(redeem.Hash, p2sh.Hash); } Assert.Equal(creation.UseP2SH, k.GetDestinationAddress(Network.TestNet) is BitcoinScriptAddress); builder.Nodes[0].GiveMoney(k, Money.Coins(1.0m)); TestUtils.Eventually(() => wallet.GetTransactions().Count == 1 && notifiedTransactions.Count == 1); builder.Nodes[0].FindBlock(); TestUtils.Eventually(() => wallet.GetTransactions().Where(t => t.BlockInformation != null).Count() == 1 && notifiedTransactions.Count == 2); builder.Nodes[0].GiveMoney(k, Money.Coins(1.5m), false); builder.Nodes[0].FindBlock(); TestUtils.Eventually(() => wallet.GetTransactions().Summary.Confirmed.TransactionCount == 2 && notifiedTransactions.Count == 3); builder.Nodes[0].FindBlock(30); Assert.True(wallet.GetTransactions().Summary.Confirmed.TransactionCount == 2); builder.Nodes[0].GiveMoney(k, Money.Coins(0.001m), false); Assert.True(wallet.GetTransactions().Summary.Confirmed.TransactionCount == 2); builder.Nodes[0].FindBlock(1, false); Assert.True(wallet.GetTransactions().Summary.Confirmed.TransactionCount == 2); builder.Nodes[0].FindBlock(); //Sync automatically TestUtils.Eventually(() => wallet.GetTransactions().Summary.Confirmed.TransactionCount == 3); //Save and restore wallet MemoryStream ms = new MemoryStream(); wallet.Save(ms); ms.Position = 0; var wallet2 = Wallet.Load(ms); ////// //Save and restore tracker ms = new MemoryStream(); var tracker = connected.NodeConnectionParameters.TemplateBehaviors.Find <TrackerBehavior>(); tracker.Tracker.Save(ms); ms.Position = 0; connected = CreateGroup(builder, new List <CoreNode>(new[] { walletNode }), 1); tracker = new TrackerBehavior(Tracker.Load(ms), wallet.Chain); connected.NodeConnectionParameters.TemplateBehaviors.Add(tracker); ////// wallet2.Configure(connected); wallet2.Connect(); Assert.Equal(wallet.Created, wallet2.Created); Assert.Equal(wallet.GetNextScriptPubKey(), wallet2.GetNextScriptPubKey()); Assert.True(wallet.GetKnownScripts().Length == wallet2.GetKnownScripts().Length); TestUtils.Eventually(() => wallet2.GetTransactions().Summary.Confirmed.TransactionCount == 3); //TestUtils.Eventually(() => //{ // var fork = wallet.Chain.FindFork(wallet2._ScanLocation); // return fork.Height == rpc.GetBlockCount(); //}); wallet2.Disconnect(); wallet.Disconnect(); connected.Disconnect(); }
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 Policy.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 Policy.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(); ////// } }