public void CanRespondToPong() { if (pos_RPCClientTests.noClient) { return; } using (var tester = new NodeServerTester()) { var toS2 = tester.Node1; toS2.VersionHandshake(); var ping = new PingPayload(); CancellationTokenSource cancel = new CancellationTokenSource(); cancel.CancelAfter(10000); using (var list = toS2.CreateListener()) { toS2.SendMessageAsync(ping); while (true) { var pong = list.ReceivePayload <PongPayload>(cancel.Token); if (ping.Nonce == pong.Nonce) { break; } } } } }
public void CanMaintainConnectionToNodes() { using (NodeServerTester servers = new NodeServerTester(Network.TestNet)) { servers.Server1.InboundNodeConnectionParameters.Services = NodeServices.Network; AddressManagerBehavior behavior = new AddressManagerBehavior(new AddressManager()); behavior.AddressManager.Add(new NetworkAddress(servers.Server1.ExternalEndpoint), IPAddress.Parse("127.0.0.1")); NodeConnectionParameters parameters = new NodeConnectionParameters(); parameters.TemplateBehaviors.Add(behavior); NodesGroup connected = new NodesGroup(Network.TestNet, parameters, new NodeRequirement() { RequiredServices = NodeServices.Network }); connected.AllowSameGroup = true; connected.MaximumNodeConnection = 2; connected.Connect(); TestUtils.Eventually(() => connected.ConnectedNodes.Count == 2); //Server crash abruptly servers.Server1.ConnectedNodes.First().Disconnect(); TestUtils.Eventually(() => connected.ConnectedNodes.Count == 1); //Reconnect ? TestUtils.Eventually(() => connected.ConnectedNodes.Count == 2); //Client crash abruptly connected.ConnectedNodes.First().Disconnect(); TestUtils.Eventually(() => connected.ConnectedNodes.Count == 1); //Reconnect ? TestUtils.Eventually(() => connected.ConnectedNodes.Count == 2); } }
public void CanConnectMultipleTimeToServer() { using (var tester = new NodeServerTester()) { int nodeCount = 0; tester.Server1.NodeAdded += (s, a) => nodeCount++; tester.Server1.NodeRemoved += (s, a) => nodeCount--; var n1 = Node.Connect(tester.Server1.Network, tester.Server1.ExternalEndpoint); n1.VersionHandshake(); Thread.Sleep(100); Assert.Equal(1, nodeCount); n1.PingPong(); var n2 = Node.Connect(tester.Server1.Network, tester.Server1.ExternalEndpoint); n2.VersionHandshake(); Thread.Sleep(100); Assert.Equal(2, nodeCount); n2.PingPong(); n1.PingPong(); Assert.Throws <ProtocolException>(() => n2.VersionHandshake()); Thread.Sleep(100); n2.PingPong(); Assert.Equal(2, nodeCount); n2.Disconnect(); Thread.Sleep(100); Assert.Equal(1, nodeCount); } }
public void CanExchangeFastPingPong() { using (var tester = new NodeServerTester()) { var n1 = tester.Node1; n1.Behaviors.Add(new PingPongBehavior() { PingInterval = TimeSpan.FromSeconds(0.1), TimeoutInterval = TimeSpan.FromSeconds(0.8) }); n1.VersionHandshake(); Assert.Equal(NodeState.HandShaked, n1.State); Assert.True(!n1.Inbound); var n2 = tester.Node2; n2.Behaviors.Add(new PingPongBehavior() { PingInterval = TimeSpan.FromSeconds(0.1), TimeoutInterval = TimeSpan.FromSeconds(0.5) }); Assert.Equal(NodeState.HandShaked, n2.State); Assert.True(n2.Inbound); Thread.Sleep(2000); Assert.Equal(NodeState.HandShaked, n2.State); n1.Behaviors.Clear(); Thread.Sleep(1200); Assert.True(n2.State == NodeState.Disconnecting || n2.State == NodeState.Offline); Assert.StartsWith("Pong timeout", n2.DisconnectReason.Reason, StringComparison.Ordinal); } }
public void CanMaintainChainWithChainBehavior() { using (var node = Node.ConnectToLocal(Network.TestNet)) { var chain = node.GetChain(uint256.Parse("00000000a2424460c992803ed44cfe0c0333e91af04fde9a6a97b468bf1b5f70")); Assert.True(chain.Height == 500); using (var tester = new NodeServerTester(Network.TestNet)) { 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.TestNet)); n2.Behaviors.Add(behavior); TestUtils.Eventually(() => behavior.Chain.Height == 500); var chain2 = n2.GetChain(uint256.Parse("00000000a2424460c992803ed44cfe0c0333e91af04fde9a6a97b468bf1b5f70")); Assert.True(chain2.Height == 500); var chain1 = n1.GetChain(uint256.Parse("00000000a2424460c992803ed44cfe0c0333e91af04fde9a6a97b468bf1b5f70")); Assert.True(chain1.Height == 500); chain1 = n1.GetChain(uint256.Parse("000000008cd4b1bdaa1278e3f1708258f862da16858324e939dc650627cd2e27")); Assert.True(chain1.Height == 499); Thread.Sleep(5000); } } }
public void MaxConnectionLimit() { using (var tester = new NodeServerTester()) { tester.Server1.MaxConnections = 4; Node.Connect(tester.Network, tester.Server1.ExternalEndpoint).VersionHandshake(); Node.Connect(tester.Network, tester.Server1.ExternalEndpoint).VersionHandshake(); Node.Connect(tester.Network, tester.Server1.ExternalEndpoint).VersionHandshake(); Node.Connect(tester.Network, tester.Server1.ExternalEndpoint).VersionHandshake(); TestUtils.Eventually(() => tester.Server1.ConnectedNodes.Count == 4); var connect = Node.Connect(tester.Network, tester.Server1.ExternalEndpoint); try { connect.VersionHandshake(); } catch { } TestUtils.Eventually(() => tester.Server1.ConnectedNodes.Count == 4); TestUtils.Eventually(() => connect.IsConnected == false); } }
public void CanMaintainConnectionToNodes() { using (NodeServerTester servers = new NodeServerTester(Network.TestNet)) { NodesGroup connected = CreateGroup(servers, 2); connected.Connect(); TestUtils.Eventually(() => connected.ConnectedNodes.Count == 2); //Server crash abruptly servers.ConnectedNodes.First().Disconnect(); TestUtils.Eventually(() => connected.ConnectedNodes.Count == 1); //Reconnect ? TestUtils.Eventually(() => connected.ConnectedNodes.Count == 2); //Client crash abruptly connected.ConnectedNodes.First().Disconnect(); TestUtils.Eventually(() => connected.ConnectedNodes.Count == 1); //Reconnect ? TestUtils.Eventually(() => connected.ConnectedNodes.Count == 2); connected.Disconnect(); TestUtils.Eventually(() => connected.ConnectedNodes.Count == 0); } }
public void CanMaintainChainWithChainBehavior() { using (var builder = NodeBuilder.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(Network.RegTest)) { 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); Thread.Sleep(5000); } } }
public void CanReceiveHandshake() { using (var tester = new NodeServerTester()) { var toS2 = tester.Server1.GetNodeByEndpoint(tester.Server2.ExternalEndpoint); toS2.VersionHandshake(); Assert.Equal(NodeState.HandShaked, toS2.State); Thread.Sleep(100); //Let the time to Server2 to add the new node, else the test was failing sometimes. Assert.Equal(NodeState.HandShaked, tester.Server2.GetNodeByEndpoint(toS2.MyVersion.AddressFrom).State); } }
public void CantConnectToYourself() { using (var tester = new NodeServerTester()) { tester.Server2.Nonce = tester.Server1.Nonce; Assert.Throws(typeof(InvalidOperationException), () => { tester.Server1.GetNodeByEndpoint(tester.Server2.ExternalEndpoint).VersionHandshake(); }); } }
public void CanReceiveHandshake() { using (var tester = new NodeServerTester()) { var toS2 = tester.Node1; toS2.VersionHandshake(); Assert.Equal(NodeState.HandShaked, toS2.State); Thread.Sleep(100); //Let the time to Server2 to add the new node, else the test was failing sometimes. Assert.Equal(NodeState.HandShaked, tester.Node2.State); } }
public void CantConnectToYourself() { using (var tester = new NodeServerTester()) { tester.Server2.Nonce = tester.Server1.Nonce; Assert.Throws <InvalidOperationException>(() => { tester.Node1.VersionHandshake(); }); } }
public void UseFilterAddIfKeyPoolSizeIsZero() { using (NodeServerTester servers = new NodeServerTester()) { var chainBuilder = new BlockchainBuilder(); chainBuilder.RealPoW = true; SetupSPVBehavior(servers, chainBuilder); var connected = CreateGroup(servers, 1); Wallet wallet = new Wallet(new WalletCreation() { Network = servers.Network, RootKeys = new[] { new ExtKey().Neuter() }, UseP2SH = true }, keyPoolSize: 0); 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); var script = wallet.GetNextScriptPubKey(new KeyPath("0/1/2")); Thread.Sleep(1000); chainBuilder.GiveMoney(script, Money.Coins(0.001m)); TestUtils.Eventually(() => wallet.GetTransactions().Count == 1); wallet.Disconnect(); TestUtils.Eventually(() => connected.ConnectedNodes.Count == 0); MemoryStream ms = new MemoryStream(); wallet.Save(ms); ms.Position = 0; var wallet2 = Wallet.Load(ms); wallet2.Configure(connected); wallet2.Connect(); var script2 = wallet2.GetNextScriptPubKey(new KeyPath("0/1/2")); Thread.Sleep(1000); Assert.NotEqual(script, script2); Assert.NotNull(wallet2.GetRedeemScript(script)); Assert.NotNull(wallet2.GetRedeemScript(script2)); TestUtils.Eventually(() => connected.ConnectedNodes.Count == 1); var spv = servers.Server1.ConnectedNodes.First().Behaviors.Find <SPVBehavior>(); TestUtils.Eventually(() => spv._Filter != null); chainBuilder.GiveMoney(script2, Money.Coins(0.001m)); TestUtils.Eventually(() => wallet.GetTransactions().Count == 2); chainBuilder.GiveMoney(script, Money.Coins(0.002m)); TestUtils.Eventually(() => wallet.GetTransactions().Count == 3); chainBuilder.FindBlock(); TestUtils.Eventually(() => wallet.GetTransactions().Count == 3 && wallet.GetTransactions().All(t => t.BlockInformation != null)); } }
public void CanRespondToPong() { using (var tester = new NodeServerTester()) { var toS2 = tester.Server1.GetNodeByEndpoint(tester.Server2.ExternalEndpoint); toS2.VersionHandshake(); var ping = new PingPayload(); toS2.SendMessage(ping); var pong = toS2.RecieveMessage <PongPayload>(TimeSpan.FromSeconds(10.0)); Assert.Equal(ping.Nonce, pong.Nonce); } }
private static void SetupSPVBehavior(NodeServerTester servers, BlockchainBuilder chainBuilder) { foreach (var server in new[] { servers.Server1, servers.Server2 }) { server.InboundNodeConnectionParameters.Services = NodeServices.Network; //Simulate SPV compatible server server.InboundNodeConnectionParameters.TemplateBehaviors.Add(new ChainBehavior(chainBuilder.Chain) { AutoSync = false }); server.InboundNodeConnectionParameters.TemplateBehaviors.Add(new SPVBehavior(chainBuilder)); ///////////// } }
public void ServerDisconnectCorrectlyFromDroppingClient() { using (var tester = new NodeServerTester()) { var to2 = tester.Server1.GetNodeByEndpoint(tester.Server2.ExternalEndpoint); to2.VersionHandshake(); Assert.True(tester.Server1.IsConnectedTo(tester.Server2.ExternalEndpoint)); Thread.Sleep(500); Assert.True(tester.Server2.IsConnectedTo(tester.Server1.ExternalEndpoint)); to2.Disconnect(); Assert.False(tester.Server1.IsConnectedTo(tester.Server2.ExternalEndpoint)); Thread.Sleep(500); Assert.False(tester.Server2.IsConnectedTo(tester.Server1.ExternalEndpoint)); } }
public void CantConnectToYourself() { if (pos_RPCClientTests.noClient) { return; } using (var tester = new NodeServerTester()) { tester.Server2.Nonce = tester.Server1.Nonce; Assert.Throws(typeof(InvalidOperationException), () => { tester.Node1.VersionHandshake(); }); } }
private static void SetupSPVBehavior(NodeServerTester servers, BlockchainBuilder chainBuilder) { List <Node> nodes = new List <Node>(); ConcurrentDictionary <uint256, Transaction> receivedTxs = new ConcurrentDictionary <uint256, Transaction>(); foreach (var server in new[] { servers.Server1, servers.Server2 }) { server.InboundNodeConnectionParameters.Services = NodeServices.Network | NodeServices.NODE_BLOOM; //Simulate SPV compatible server server.InboundNodeConnectionParameters.TemplateBehaviors.Add(new ChainBehavior(chainBuilder.Chain) { AutoSync = false }); server.InboundNodeConnectionParameters.TemplateBehaviors.Add(new SPVBehavior(chainBuilder) { Nodes = nodes, _ReceivedTransactions = receivedTxs }); ///////////// } }
public void ServerDisconnectCorrectlyFromDroppingClient() { if (pos_RPCClientTests.noClient) { return; } using (var tester = new NodeServerTester()) { var to2 = tester.Node1; to2.VersionHandshake(); Assert.True(tester.Server1.IsConnectedTo(tester.Server2.ExternalEndpoint)); Thread.Sleep(100); Assert.True(tester.Server2.IsConnectedTo(tester.Server1.ExternalEndpoint)); to2.Disconnect(); Thread.Sleep(100); Assert.False(tester.Server1.IsConnectedTo(tester.Server2.ExternalEndpoint)); Thread.Sleep(100); Assert.False(tester.Server2.IsConnectedTo(tester.Server1.ExternalEndpoint)); } }
private static NodesGroup CreateGroup(NodeServerTester servers, int connections) { AddressManagerBehavior behavior = new AddressManagerBehavior(new AddressManager()); if (connections == 1) { behavior.AddressManager.Add(new NetworkAddress(servers.Server1.ExternalEndpoint), IPAddress.Parse("127.0.0.1")); } if (connections > 1) { behavior.AddressManager.Add(new NetworkAddress(servers.Server2.ExternalEndpoint), IPAddress.Parse("127.0.0.1")); } NodeConnectionParameters parameters = new NodeConnectionParameters(); parameters.TemplateBehaviors.Add(behavior); Wallet.ConfigureDefaultNodeConnectionParameters(parameters); parameters.IsTrusted = true; NodesGroup connected = new NodesGroup(Network.TestNet, parameters); connected.AllowSameGroup = true; connected.MaximumNodeConnection = connections; return(connected); }
public void UseFilterAddIfKeyPoolSizeIsZero() { using(NodeServerTester servers = new NodeServerTester(Network.TestNet)) { var chainBuilder = new BlockchainBuilder(); SetupSPVBehavior(servers, chainBuilder); var connected = CreateGroup(servers, 1); Wallet wallet = new Wallet(new WalletCreation() { Network = Network.TestNet, RootKeys = new[] { new ExtKey().Neuter() }, UseP2SH = true }, keyPoolSize: 0); 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); var script = wallet.GetNextScriptPubKey(new KeyPath("0/1/2")); Thread.Sleep(1000); chainBuilder.GiveMoney(script, Money.Coins(0.001m)); TestUtils.Eventually(() => wallet.GetTransactions().Count == 1); wallet.Disconnect(); TestUtils.Eventually(() => connected.ConnectedNodes.Count == 0); MemoryStream ms = new MemoryStream(); wallet.Save(ms); ms.Position = 0; var wallet2 = Wallet.Load(ms); wallet2.Configure(connected); wallet2.Connect(); var script2 = wallet2.GetNextScriptPubKey(new KeyPath("0/1/2")); Thread.Sleep(1000); Assert.NotEqual(script, script2); Assert.NotNull(wallet2.GetRedeemScript(script)); Assert.NotNull(wallet2.GetRedeemScript(script2)); TestUtils.Eventually(() => connected.ConnectedNodes.Count == 1); var spv = servers.Server1.ConnectedNodes.First().Behaviors.Find<SPVBehavior>(); TestUtils.Eventually(() => spv._Filter != null); chainBuilder.GiveMoney(script2, Money.Coins(0.001m)); TestUtils.Eventually(() => wallet.GetTransactions().Count == 2); chainBuilder.GiveMoney(script, Money.Coins(0.002m)); TestUtils.Eventually(() => wallet.GetTransactions().Count == 3); chainBuilder.FindBlock(); TestUtils.Eventually(() => wallet.GetTransactions().Count == 3 && wallet.GetTransactions().All(t => t.BlockInformation != null)); } }
public void CanMaintainConnectionToNodes() { using(NodeServerTester servers = new NodeServerTester(Network.TestNet)) { NodesGroup connected = CreateGroup(servers, 2); connected.Connect(); TestUtils.Eventually(() => connected.ConnectedNodes.Count == 2); //Server crash abruptly servers.ConnectedNodes.First().Disconnect(); TestUtils.Eventually(() => connected.ConnectedNodes.Count == 1); //Reconnect ? TestUtils.Eventually(() => connected.ConnectedNodes.Count == 2); //Client crash abruptly connected.ConnectedNodes.First().Disconnect(); TestUtils.Eventually(() => connected.ConnectedNodes.Count == 1); //Reconnect ? TestUtils.Eventually(() => connected.ConnectedNodes.Count == 2); connected.Disconnect(); TestUtils.Eventually(() => connected.ConnectedNodes.Count == 0); } }
private static void SetupSPVBehavior(NodeServerTester servers, BlockchainBuilder chainBuilder) { List<Node> nodes = new List<Node>(); ConcurrentDictionary<uint256, Transaction> receivedTxs = new ConcurrentDictionary<uint256, Transaction>(); foreach(var server in new[] { servers.Server1, servers.Server2 }) { server.InboundNodeConnectionParameters.Services = NodeServices.Network; //Simulate SPV compatible server server.InboundNodeConnectionParameters.TemplateBehaviors.Add(new ChainBehavior(chainBuilder.Chain) { AutoSync = false }); server.InboundNodeConnectionParameters.TemplateBehaviors.Add(new SPVBehavior(chainBuilder) { Nodes = nodes, _ReceivedTransactions = receivedTxs }); ///////////// } }
public void CanBroadcastTransaction() { using(NodeServerTester servers = new NodeServerTester(Network.TestNet)) { var notifiedTransactions = new List<WalletTransaction>(); var chainBuilder = new BlockchainBuilder(); SetupSPVBehavior(servers, chainBuilder); var tx = new Transaction(); Wallet wallet = new Wallet(new WalletCreation() { Network = Network.TestNet, RootKeys = new[] { new ExtKey().Neuter() }, UseP2SH = false }, keyPoolSize: 11); NodesGroup connected = CreateGroup(servers, 2); wallet.Configure(connected); wallet.Connect(); AutoResetEvent evt = new AutoResetEvent(false); bool passed = false; bool rejected = false; var broadcasting = wallet.BroadcastTransactionAsync(tx); wallet.TransactionBroadcasted += (t) => { evt.Set(); passed = true; }; wallet.TransactionRejected += (t, r) => { evt.Set(); rejected = true; }; BroadcastHub hub = BroadcastHub.GetBroadcastHub(connected.NodeConnectionParameters); BroadcastHubBehavior behavior = null; while(behavior == null || behavior.AttachedNode.State != NodeState.HandShaked) { behavior = connected.ConnectedNodes.Select(n => n.Behaviors.Find<BroadcastHubBehavior>()).FirstOrDefault(); Thread.Sleep(1); } Assert.Equal(1, behavior.Broadcasts.Count()); Assert.Equal(1, hub.BroadcastingTransactions.Count()); Assert.True(evt.WaitOne(20000)); Assert.True(passed); evt.Reset(); Assert.Equal(0, behavior.Broadcasts.Count()); Assert.Equal(0, hub.BroadcastingTransactions.Count()); Assert.Null(broadcasting.Result); broadcasting = wallet.BroadcastTransactionAsync(tx); Assert.Equal(1, behavior.Broadcasts.Count()); Assert.True(evt.WaitOne(20000)); Assert.True(rejected); Assert.Equal(0, behavior.Broadcasts.Count()); Assert.Equal(0, hub.BroadcastingTransactions.Count()); Assert.NotNull(broadcasting.Result); } }
public void CanBroadcastTransaction() { using (NodeServerTester servers = new NodeServerTester(Network.TestNet)) { var notifiedTransactions = new List <WalletTransaction>(); var chainBuilder = new BlockchainBuilder(); SetupSPVBehavior(servers, chainBuilder); var tx = new Transaction(); Wallet wallet = new Wallet(new WalletCreation() { Network = Network.TestNet, RootKeys = new[] { new ExtKey().Neuter() }, UseP2SH = false }, keyPoolSize: 11); NodesGroup connected = CreateGroup(servers, 2); wallet.Configure(connected); wallet.Connect(); AutoResetEvent evt = new AutoResetEvent(false); bool passed = false; bool rejected = false; var broadcasting = wallet.BroadcastTransactionAsync(tx); wallet.TransactionBroadcasted += (t) => { passed = true; evt.Set(); }; wallet.TransactionRejected += (t, r) => { rejected = true; evt.Set(); }; BroadcastHub hub = BroadcastHub.GetBroadcastHub(connected.NodeConnectionParameters); BroadcastHubBehavior behavior = null; while (behavior == null || behavior.AttachedNode.State != NodeState.HandShaked) { behavior = connected.ConnectedNodes.Select(n => n.Behaviors.Find <BroadcastHubBehavior>()).FirstOrDefault(); Thread.Sleep(1); } if (broadcasting.Status != TaskStatus.RanToCompletion) { Assert.Equal(1, behavior.Broadcasts.Count()); Assert.Equal(1, hub.BroadcastingTransactions.Count()); } Assert.True(evt.WaitOne(20000)); Assert.True(broadcasting.Status == TaskStatus.RanToCompletion); Assert.True(passed); evt.Reset(); Assert.Equal(0, behavior.Broadcasts.Count()); Assert.Equal(0, hub.BroadcastingTransactions.Count()); Assert.Null(broadcasting.Result); broadcasting = wallet.BroadcastTransactionAsync(tx); if (broadcasting.Status != TaskStatus.RanToCompletion) { Assert.Equal(1, behavior.Broadcasts.Count()); } Assert.True(evt.WaitOne(20000)); Assert.True(rejected); Assert.Equal(0, behavior.Broadcasts.Count()); Assert.Equal(0, hub.BroadcastingTransactions.Count()); Assert.NotNull(broadcasting.Result); } }
//[Trait("UnitTest", "UnitTest")] public void CanBroadcastTransaction() { using (NodeServerTester servers = new NodeServerTester()) { var notifiedTransactions = new List <WalletTransaction>(); var chainBuilder = new BlockchainBuilder(); SetupSPVBehavior(servers, chainBuilder); var tx = new Transaction(); Wallet wallet = new Wallet(new WalletCreation() { Network = servers.Network, RootKeys = new[] { new ExtKey().Neuter() }, UseP2SH = false }, keyPoolSize: 11); NodesGroup connected = CreateGroup(servers, 2); wallet.Configure(connected); wallet.Connect(); AutoResetEvent evt = new AutoResetEvent(false); bool passed = false; bool rejected = false; BroadcastHub hub = BroadcastHub.GetBroadcastHub(wallet.Group.NodeConnectionParameters); hub.ManualBroadcast = true; var broadcasting = wallet.BroadcastTransactionAsync(tx); wallet.TransactionBroadcasted += (t) => { passed = true; evt.Set(); }; wallet.TransactionRejected += (t, r) => { rejected = true; evt.Set(); }; while (connected.ConnectedNodes.Count != 2 && connected.ConnectedNodes.All(n => n.State == NodeState.HandShaked)) { Thread.Sleep(10); } var behaviors = connected.ConnectedNodes.Select(n => n.Behaviors.Find <BroadcastHubBehavior>()).ToArray(); TestUtils.Eventually(() => behaviors.All(b => b.Broadcasts.Count() == 1)); Assert.Equal(1, hub.BroadcastingTransactions.Count()); hub.BroadcastTransactions(); Assert.True(evt.WaitOne(20000)); Assert.True(broadcasting.Wait(2000)); Assert.True(passed); evt.Reset(); TestUtils.Eventually(() => behaviors.All(b => b.Broadcasts.Count() == 0)); Assert.Equal(0, hub.BroadcastingTransactions.Count()); Assert.Null(broadcasting.Result); broadcasting = wallet.BroadcastTransactionAsync(tx); TestUtils.Eventually(() => behaviors.All(b => b.Broadcasts.Count() == 1)); hub.BroadcastTransactions(); Assert.True(evt.WaitOne(20000)); Assert.True(broadcasting.Wait(2000)); Assert.True(rejected); TestUtils.Eventually(() => behaviors.All(b => b.Broadcasts.Count() == 0)); Assert.Equal(0, hub.BroadcastingTransactions.Count()); Assert.NotNull(broadcasting.Result); } }
public void CanRespondToPong() { using(var tester = new NodeServerTester()) { var toS2 = tester.Node1; toS2.VersionHandshake(); var ping = new PingPayload(); CancellationTokenSource cancel = new CancellationTokenSource(); cancel.CancelAfter(10000); using(var list = toS2.CreateListener()) { toS2.SendMessageAsync(ping); while(true) { var pong = list.ReceivePayload<PongPayload>(cancel.Token); if(ping.Nonce == pong.Nonce) break; } } } }
public void CanMaintainChainWithChainBehavior() { using(var node = Node.ConnectToLocal(Network.TestNet)) { var chain = node.GetChain(uint256.Parse("00000000a2424460c992803ed44cfe0c0333e91af04fde9a6a97b468bf1b5f70")); Assert.True(chain.Height == 500); using(var tester = new NodeServerTester(Network.TestNet)) { 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.TestNet)); n2.Behaviors.Add(behavior); TestUtils.Eventually(() => behavior.Chain.Height == 500); var chain2 = n2.GetChain(uint256.Parse("00000000a2424460c992803ed44cfe0c0333e91af04fde9a6a97b468bf1b5f70")); Assert.True(chain2.Height == 500); var chain1 = n1.GetChain(uint256.Parse("00000000a2424460c992803ed44cfe0c0333e91af04fde9a6a97b468bf1b5f70")); Assert.True(chain1.Height == 500); chain1 = n1.GetChain(uint256.Parse("000000008cd4b1bdaa1278e3f1708258f862da16858324e939dc650627cd2e27")); Assert.True(chain1.Height == 499); Thread.Sleep(5000); } } }
public void CanSyncWalletCore(WalletCreation creation) { using (NodeServerTester servers = new NodeServerTester(Network.TestNet)) { var notifiedTransactions = new List <WalletTransaction>(); var chainBuilder = new BlockchainBuilder(); SetupSPVBehavior(servers, chainBuilder); NodesGroup connected = CreateGroup(servers, 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); chainBuilder.FindBlock(); TestUtils.Eventually(() => wallet.Chain.Height == 1); for (int i = 0; i < 9; i++) { wallet.GetNextScriptPubKey(); } wallet.GetNextScriptPubKey(); //Should provoke purge TestUtils.Eventually(() => wallet.State == WalletState.Disconnected && wallet.ConnectedNodes == 0); TestUtils.Eventually(() => wallet.ConnectedNodes == 1); TestUtils.Eventually(() => servers.Server1.ConnectedNodes.Count == 1); var spv = servers.Server1.ConnectedNodes.First().Behaviors.Find <SPVBehavior>(); TestUtils.Eventually(() => spv._Filter != null); 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); chainBuilder.GiveMoney(k, Money.Coins(1.0m)); TestUtils.Eventually(() => wallet.GetTransactions().Count == 1 && notifiedTransactions.Count == 1); chainBuilder.FindBlock(); TestUtils.Eventually(() => wallet.GetTransactions().Where(t => t.BlockInformation != null).Count() == 1 && notifiedTransactions.Count == 2); chainBuilder.Broadcast = false; chainBuilder.GiveMoney(k, Money.Coins(1.5m)); chainBuilder.Broadcast = true; chainBuilder.FindBlock(); TestUtils.Eventually(() => wallet.GetTransactions().Summary.Confirmed.TransactionCount == 2 && notifiedTransactions.Count == 3); chainBuilder.Broadcast = false; for (int i = 0; i < 30; i++) { chainBuilder.FindBlock(); } chainBuilder.GiveMoney(k, Money.Coins(0.001m)); chainBuilder.FindBlock(); chainBuilder.Broadcast = true; chainBuilder.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>(); connected.NodeConnectionParameters.TemplateBehaviors.Remove(tracker); tracker.Tracker.Save(ms); ms.Position = 0; 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); var fork = wallet.Chain.FindFork(wallet2._ScanLocation); Assert.True(fork.Height == chainBuilder.Chain.Height); } }
public void CantConnectToYourself() { using(var tester = new NodeServerTester()) { tester.Server2.Nonce = tester.Server1.Nonce; Assert.Throws(typeof(InvalidOperationException), () => { tester.Node1.VersionHandshake(); }); } }
public void CanSyncWallet2() { using (NodeServerTester servers = new NodeServerTester(Network.TestNet)) { var chainBuilder = new BlockchainBuilder(); SetupSPVBehavior(servers, chainBuilder); NodesGroup aliceConnection = CreateGroup(servers, 1); NodesGroup bobConnection = CreateGroup(servers, 1); var aliceKey = new ExtKey(); Wallet alice = new Wallet(new WalletCreation() { Network = Network.TestNet, RootKeys = new[] { aliceKey.Neuter() }, SignatureRequired = 1, UseP2SH = false }, 11); Wallet bob = new Wallet(new WalletCreation() { Network = Network.TestNet, 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(); chainBuilder.GiveMoney(addressAlice, Money.Coins(1.0m)); TestUtils.Eventually(() => aliceConnection.ConnectedNodes.Count == 0); //Purge 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 builder = new TransactionBuilder(); var tx = builder .SetTransactionPolicy(new Policy.StandardTransactionPolicy() { MinRelayTxFee = new FeeRate(0) }) .AddCoins(coins) .AddKeys(keys) .Send(bob.GetNextScriptPubKey(), Money.Coins(0.4m)) .SetChange(alice.GetNextScriptPubKey(true)) .BuildTransaction(true); Assert.True(builder.Verify(tx)); chainBuilder.BroadcastTransaction(tx); //Alice get change TestUtils.Eventually(() => alice.GetTransactions().Count == 2); coins = alice.GetTransactions().GetSpendableCoins(); Assert.True(coins.Single().Amount == Money.Coins(0.6m)); ////// //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), chainBuilder.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 ! chainBuilder.FindBlock(); //Alice send tx to bob coins = alice.GetTransactions().GetSpendableCoins(); keys = coins.Select(c => alice.GetKeyPath(c.ScriptPubKey)) .Select(k => aliceKey.Derive(k)) .ToArray(); builder = new TransactionBuilder(); tx = builder .SetTransactionPolicy(new Policy.StandardTransactionPolicy() { MinRelayTxFee = new FeeRate(0) }) .AddCoins(coins) .AddKeys(keys) .Send(bob.GetNextScriptPubKey(), Money.Coins(0.1m)) .SetChange(alice.GetNextScriptPubKey(true)) .BuildTransaction(true); Assert.True(builder.Verify(tx)); chainBuilder.BroadcastTransaction(tx); //Bob still has coins TestUtils.Eventually(() => bob.GetTransactions().Count == 2); //Bob has both, old and new tx coins = bob.GetTransactions().GetSpendableCoins(); ////// } }
public void CanExchangeFastPingPong() { using(var tester = new NodeServerTester()) { var n1 = tester.Node1; n1.Behaviors.Add(new PingPongBehavior() { PingInterval = TimeSpan.FromSeconds(0.1), TimeoutInterval = TimeSpan.FromSeconds(0.8) }); n1.VersionHandshake(); Assert.Equal(NodeState.HandShaked, n1.State); Assert.True(!n1.Inbound); var n2 = tester.Node2; n2.Behaviors.Add(new PingPongBehavior() { PingInterval = TimeSpan.FromSeconds(0.1), TimeoutInterval = TimeSpan.FromSeconds(0.5) }); Assert.Equal(NodeState.HandShaked, n2.State); Assert.True(n2.Inbound); Thread.Sleep(2000); Assert.Equal(NodeState.HandShaked, n2.State); n1.Behaviors.Clear(); Thread.Sleep(1200); Assert.True(n2.State == NodeState.Disconnecting || n2.State == NodeState.Offline); Assert.True(n2.DisconnectReason.Reason.StartsWith("Pong timeout", StringComparison.Ordinal)); } }
public void CanSyncWalletCore(WalletCreation creation) { using (NodeServerTester servers = new NodeServerTester(Network.TestNet)) { var chainBuilder = new BlockchainBuilder(); //Simulate SPV compatible server servers.Server1.InboundNodeConnectionParameters.Services = NodeServices.Network; servers.Server1.InboundNodeConnectionParameters.TemplateBehaviors.Add(new ChainBehavior(chainBuilder.Chain) { AutoSync = false }); servers.Server1.InboundNodeConnectionParameters.TemplateBehaviors.Add(new SPVBehavior(chainBuilder)); ///////////// //The SPV client does not verify the chain and keep one connection alive with Server1 NodeConnectionParameters parameters = new NodeConnectionParameters(); Wallet.ConfigureDefaultNodeConnectionParameters(parameters); parameters.IsTrusted = true; AddressManagerBehavior addrman = new AddressManagerBehavior(new AddressManager()); addrman.AddressManager.Add(new NetworkAddress(servers.Server1.ExternalEndpoint), IPAddress.Parse("127.0.0.1")); parameters.TemplateBehaviors.Add(addrman); NodesGroup connected = new NodesGroup(Network.TestNet, parameters); connected.AllowSameGroup = true; connected.MaximumNodeConnection = 1; ///////////// Wallet wallet = new Wallet(creation, keyPoolSize: 11); Assert.True(wallet.State == WalletState.Created); wallet.Connect(connected); Assert.True(wallet.State == WalletState.Disconnected); TestUtils.Eventually(() => connected.ConnectedNodes.Count == 1); Assert.True(wallet.State == WalletState.Connected); chainBuilder.FindBlock(); TestUtils.Eventually(() => wallet.Chain.Height == 1); for (int i = 0; i < 9; i++) { wallet.GetNextScriptPubKey(); } wallet.GetNextScriptPubKey(); //Should provoke purge TestUtils.Eventually(() => wallet.State == WalletState.Disconnected && wallet.ConnectedNodes == 0); TestUtils.Eventually(() => wallet.ConnectedNodes == 1); TestUtils.Eventually(() => servers.Server1.ConnectedNodes.Count == 1); var spv = servers.Server1.ConnectedNodes.First().Behaviors.Find <SPVBehavior>(); TestUtils.Eventually(() => spv._Filter != null); var k = wallet.GetNextScriptPubKey(); Assert.Equal(creation.UseP2SH, k.GetDestinationAddress(Network.TestNet) is BitcoinScriptAddress); chainBuilder.GiveMoney(k, Money.Coins(1.0m)); TestUtils.Eventually(() => wallet.GetTransactions().Count == 1); chainBuilder.FindBlock(); TestUtils.Eventually(() => wallet.GetTransactions().Where(t => t.BlockInformation != null).Count() == 1); chainBuilder.Broadcast = false; chainBuilder.GiveMoney(k, Money.Coins(1.5m)); chainBuilder.Broadcast = true; chainBuilder.FindBlock(); TestUtils.Eventually(() => wallet.GetTransactions().Summary.Confirmed.TransactionCount == 2); chainBuilder.Broadcast = false; for (int i = 0; i < 30; i++) { chainBuilder.FindBlock(); } chainBuilder.GiveMoney(k, Money.Coins(0.001m)); chainBuilder.FindBlock(); chainBuilder.Broadcast = true; chainBuilder.FindBlock(); //Sync automatically TestUtils.Eventually(() => wallet.GetTransactions().Summary.Confirmed.TransactionCount == 3); MemoryStream ms = new MemoryStream(); wallet.Save(ms); ms.Position = 0; var wallet2 = Wallet.Load(ms); wallet2.Connect(connected); Assert.Equal(wallet.Created, wallet2.Created); Assert.Equal(wallet.GetNextScriptPubKey(), wallet2.GetNextScriptPubKey()); Assert.True(wallet.GetKnownScripts().Length == wallet2.GetKnownScripts().Length); var fork = wallet.Chain.FindFork(wallet2._ScanLocation); Assert.True(fork.Height == chainBuilder.Chain.Height - 5); } }
private static NodesGroup CreateGroup(NodeServerTester servers, int connections) { AddressManagerBehavior behavior = new AddressManagerBehavior(new AddressManager()); if(connections == 1) { behavior.AddressManager.Add(new NetworkAddress(servers.Server1.ExternalEndpoint), IPAddress.Parse("127.0.0.1")); } if(connections > 1) { behavior.AddressManager.Add(new NetworkAddress(servers.Server2.ExternalEndpoint), IPAddress.Parse("127.0.0.1")); } NodeConnectionParameters parameters = new NodeConnectionParameters(); parameters.TemplateBehaviors.Add(behavior); Wallet.ConfigureDefaultNodeConnectionParameters(parameters); parameters.IsTrusted = true; NodesGroup connected = new NodesGroup(Network.TestNet, parameters); connected.AllowSameGroup = true; connected.MaximumNodeConnection = connections; return connected; }
public void CanReceiveHandshake() { using(var tester = new NodeServerTester()) { var toS2 = tester.Node1; toS2.VersionHandshake(); Assert.Equal(NodeState.HandShaked, toS2.State); Thread.Sleep(100); //Let the time to Server2 to add the new node, else the test was failing sometimes. Assert.Equal(NodeState.HandShaked, tester.Node2.State); } }
public void ServerDisconnectCorrectlyFromDroppingClient() { using(var tester = new NodeServerTester()) { var to2 = tester.Node1; to2.VersionHandshake(); Assert.True(tester.Server1.IsConnectedTo(tester.Server2.ExternalEndpoint)); Thread.Sleep(100); Assert.True(tester.Server2.IsConnectedTo(tester.Server1.ExternalEndpoint)); to2.Disconnect(); Thread.Sleep(100); Assert.False(tester.Server1.IsConnectedTo(tester.Server2.ExternalEndpoint)); Thread.Sleep(100); Assert.False(tester.Server2.IsConnectedTo(tester.Server1.ExternalEndpoint)); } }
public void CanSyncWallet2() { using(NodeServerTester servers = new NodeServerTester(Network.TestNet)) { var chainBuilder = new BlockchainBuilder(); SetupSPVBehavior(servers, chainBuilder); NodesGroup aliceConnection = CreateGroup(servers, 1); NodesGroup bobConnection = CreateGroup(servers, 1); var aliceKey = new ExtKey(); Wallet alice = new Wallet(new WalletCreation() { Network = Network.TestNet, RootKeys = new[] { aliceKey.Neuter() }, SignatureRequired = 1, UseP2SH = false }, 11); Wallet bob = new Wallet(new WalletCreation() { Network = Network.TestNet, 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(); chainBuilder.GiveMoney(addressAlice, Money.Coins(1.0m)); TestUtils.Eventually(() => aliceConnection.ConnectedNodes.Count == 0); //Purge 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 builder = new TransactionBuilder(); var tx = builder .SetTransactionPolicy(new Policy.StandardTransactionPolicy() { MinRelayTxFee = new FeeRate(0) }) .AddCoins(coins) .AddKeys(keys) .Send(bob.GetNextScriptPubKey(), Money.Coins(0.4m)) .SetChange(alice.GetNextScriptPubKey(true)) .BuildTransaction(true); Assert.True(builder.Verify(tx)); chainBuilder.BroadcastTransaction(tx); //Alice get change TestUtils.Eventually(() => alice.GetTransactions().Count == 2); coins = alice.GetTransactions().GetSpendableCoins(); Assert.True(coins.Single().Amount == Money.Coins(0.6m)); ////// //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), chainBuilder.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 ! chainBuilder.FindBlock(); //Alice send tx to bob coins = alice.GetTransactions().GetSpendableCoins(); keys = coins.Select(c => alice.GetKeyPath(c.ScriptPubKey)) .Select(k => aliceKey.Derive(k)) .ToArray(); builder = new TransactionBuilder(); tx = builder .SetTransactionPolicy(new Policy.StandardTransactionPolicy() { MinRelayTxFee = new FeeRate(0) }) .AddCoins(coins) .AddKeys(keys) .Send(bob.GetNextScriptPubKey(), Money.Coins(0.1m)) .SetChange(alice.GetNextScriptPubKey(true)) .BuildTransaction(true); Assert.True(builder.Verify(tx)); chainBuilder.BroadcastTransaction(tx); //Bob still has coins TestUtils.Eventually(() => bob.GetTransactions().Count == 2); //Bob has both, old and new tx coins = bob.GetTransactions().GetSpendableCoins(); ////// } }
private static void SetupSPVBehavior(NodeServerTester servers, BlockchainBuilder chainBuilder) { foreach(var server in new[] { servers.Server1, servers.Server2 }) { server.InboundNodeConnectionParameters.Services = NodeServices.Network; //Simulate SPV compatible server server.InboundNodeConnectionParameters.TemplateBehaviors.Add(new ChainBehavior(chainBuilder.Chain) { AutoSync = false }); server.InboundNodeConnectionParameters.TemplateBehaviors.Add(new SPVBehavior(chainBuilder)); ///////////// } }
public void CanSyncWalletCore(WalletCreation creation) { using(NodeServerTester servers = new NodeServerTester(Network.TestNet)) { var notifiedTransactions = new List<WalletTransaction>(); var chainBuilder = new BlockchainBuilder(); SetupSPVBehavior(servers, chainBuilder); NodesGroup connected = CreateGroup(servers, 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); chainBuilder.FindBlock(); TestUtils.Eventually(() => wallet.Chain.Height == 1); for(int i = 0 ; i < 9 ; i++) { wallet.GetNextScriptPubKey(); } wallet.GetNextScriptPubKey(); //Should provoke purge TestUtils.Eventually(() => wallet.State == WalletState.Disconnected && wallet.ConnectedNodes == 0); TestUtils.Eventually(() => wallet.ConnectedNodes == 1); TestUtils.Eventually(() => servers.Server1.ConnectedNodes.Count == 1); var spv = servers.Server1.ConnectedNodes.First().Behaviors.Find<SPVBehavior>(); TestUtils.Eventually(() => spv._Filter != null); 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); chainBuilder.GiveMoney(k, Money.Coins(1.0m)); TestUtils.Eventually(() => wallet.GetTransactions().Count == 1); Assert.Equal(1, notifiedTransactions.Count); chainBuilder.FindBlock(); TestUtils.Eventually(() => wallet.GetTransactions().Where(t => t.BlockInformation != null).Count() == 1); Assert.Equal(2, notifiedTransactions.Count); chainBuilder.Broadcast = false; chainBuilder.GiveMoney(k, Money.Coins(1.5m)); chainBuilder.Broadcast = true; chainBuilder.FindBlock(); TestUtils.Eventually(() => wallet.GetTransactions().Summary.Confirmed.TransactionCount == 2); Assert.Equal(3, notifiedTransactions.Count); chainBuilder.Broadcast = false; for(int i = 0 ; i < 30 ; i++) { chainBuilder.FindBlock(); } chainBuilder.GiveMoney(k, Money.Coins(0.001m)); chainBuilder.FindBlock(); chainBuilder.Broadcast = true; chainBuilder.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>(); connected.NodeConnectionParameters.TemplateBehaviors.Remove(tracker); tracker.Tracker.Save(ms); ms.Position = 0; 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); var fork = wallet.Chain.FindFork(wallet2._ScanLocation); Assert.True(fork.Height == chainBuilder.Chain.Height); } }
public void CanSyncWalletCore(WalletCreation creation) { using(NodeServerTester servers = new NodeServerTester(Network.TestNet)) { var chainBuilder = new BlockchainBuilder(); //Simulate SPV compatible server servers.Server1.InboundNodeConnectionParameters.Services = NodeServices.Network; servers.Server1.InboundNodeConnectionParameters.TemplateBehaviors.Add(new ChainBehavior(chainBuilder.Chain) { AutoSync = false }); servers.Server1.InboundNodeConnectionParameters.TemplateBehaviors.Add(new SPVBehavior(chainBuilder)); ///////////// //The SPV client does not verify the chain and keep one connection alive with Server1 NodeConnectionParameters parameters = new NodeConnectionParameters(); Wallet.ConfigureDefaultNodeConnectionParameters(parameters); parameters.IsTrusted = true; AddressManagerBehavior addrman = new AddressManagerBehavior(new AddressManager()); addrman.AddressManager.Add(new NetworkAddress(servers.Server1.ExternalEndpoint), IPAddress.Parse("127.0.0.1")); parameters.TemplateBehaviors.Add(addrman); NodesGroup connected = new NodesGroup(Network.TestNet, parameters); connected.AllowSameGroup = true; connected.MaximumNodeConnection = 1; ///////////// Wallet wallet = new Wallet(creation, keyPoolSize: 11); Assert.True(wallet.State == WalletState.Created); wallet.Connect(connected); Assert.True(wallet.State == WalletState.Disconnected); TestUtils.Eventually(() => connected.ConnectedNodes.Count == 1); Assert.True(wallet.State == WalletState.Connected); chainBuilder.FindBlock(); TestUtils.Eventually(() => wallet.Chain.Height == 1); for(int i = 0 ; i < 9 ; i++) { wallet.GetNextScriptPubKey(); } wallet.GetNextScriptPubKey(); //Should provoke purge TestUtils.Eventually(() => wallet.State == WalletState.Disconnected && wallet.ConnectedNodes == 0); TestUtils.Eventually(() => wallet.ConnectedNodes == 1); TestUtils.Eventually(() => servers.Server1.ConnectedNodes.Count == 1); var spv = servers.Server1.ConnectedNodes.First().Behaviors.Find<SPVBehavior>(); TestUtils.Eventually(() => spv._Filter != null); var k = wallet.GetNextScriptPubKey(); Assert.Equal(creation.UseP2SH, k.GetDestinationAddress(Network.TestNet) is BitcoinScriptAddress); chainBuilder.GiveMoney(k, Money.Coins(1.0m)); TestUtils.Eventually(() => wallet.GetTransactions().Count == 1); chainBuilder.FindBlock(); TestUtils.Eventually(() => wallet.GetTransactions().Where(t => t.BlockInformation != null).Count() == 1); chainBuilder.Broadcast = false; chainBuilder.GiveMoney(k, Money.Coins(1.5m)); chainBuilder.Broadcast = true; chainBuilder.FindBlock(); TestUtils.Eventually(() => wallet.GetTransactions().Summary.Confirmed.TransactionCount == 2); chainBuilder.Broadcast = false; for(int i = 0 ; i < 30 ; i++) { chainBuilder.FindBlock(); } chainBuilder.GiveMoney(k, Money.Coins(0.001m)); chainBuilder.FindBlock(); chainBuilder.Broadcast = true; chainBuilder.FindBlock(); //Sync automatically TestUtils.Eventually(() => wallet.GetTransactions().Summary.Confirmed.TransactionCount == 3); MemoryStream ms = new MemoryStream(); wallet.Save(ms); ms.Position = 0; var wallet2 = Wallet.Load(ms); wallet2.Connect(connected); Assert.Equal(wallet.Created, wallet2.Created); Assert.Equal(wallet.GetNextScriptPubKey(), wallet2.GetNextScriptPubKey()); Assert.True(wallet.GetKnownScripts().Length == wallet2.GetKnownScripts().Length); var fork = wallet.Chain.FindFork(wallet2._ScanLocation); Assert.True(fork.Height == chainBuilder.Chain.Height - 5); } }
public void CanConnectMultipleTimeToServer() { using(var tester = new NodeServerTester()) { int nodeCount = 0; tester.Server1.NodeAdded += (s, a) => nodeCount++; tester.Server1.NodeRemoved += (s, a) => nodeCount--; var n1 = Node.Connect(tester.Server1.Network, tester.Server1.ExternalEndpoint); n1.VersionHandshake(); Thread.Sleep(100); Assert.Equal(1, nodeCount); n1.PingPong(); var n2 = Node.Connect(tester.Server1.Network, tester.Server1.ExternalEndpoint); n2.VersionHandshake(); Thread.Sleep(100); Assert.Equal(2, nodeCount); n2.PingPong(); n1.PingPong(); Assert.Throws<ProtocolException>(() => n2.VersionHandshake()); Thread.Sleep(100); n2.PingPong(); Assert.Equal(2, nodeCount); n2.Disconnect(); Thread.Sleep(100); Assert.Equal(1, nodeCount); } }
public void CanMaintainConnectionToNodes() { using(NodeServerTester servers = new NodeServerTester(Network.TestNet)) { servers.Server1.InboundNodeConnectionParameters.Services = NodeServices.Network; AddressManagerBehavior behavior = new AddressManagerBehavior(new AddressManager()); behavior.AddressManager.Add(new NetworkAddress(servers.Server1.ExternalEndpoint), IPAddress.Parse("127.0.0.1")); NodeConnectionParameters parameters = new NodeConnectionParameters(); parameters.TemplateBehaviors.Add(behavior); NodesGroup connected = new NodesGroup(Network.TestNet, parameters, new NodeRequirement() { RequiredServices = NodeServices.Network }); connected.AllowSameGroup = true; connected.MaximumNodeConnection = 2; connected.Connect(); TestUtils.Eventually(() => connected.ConnectedNodes.Count == 2); //Server crash abruptly servers.Server1.ConnectedNodes.First().Disconnect(); TestUtils.Eventually(() => connected.ConnectedNodes.Count == 1); //Reconnect ? TestUtils.Eventually(() => connected.ConnectedNodes.Count == 2); //Client crash abruptly connected.ConnectedNodes.First().Disconnect(); TestUtils.Eventually(() => connected.ConnectedNodes.Count == 1); //Reconnect ? TestUtils.Eventually(() => connected.ConnectedNodes.Count == 2); } }
public void CanRespondToPong() { using(var tester = new NodeServerTester()) { var toS2 = tester.Server1.GetNodeByEndpoint(tester.Server2.ExternalEndpoint); toS2.VersionHandshake(); var ping = new PingPayload(); toS2.SendMessage(ping); var pong = toS2.RecieveMessage<PongPayload>(TimeSpan.FromSeconds(10.0)); Assert.Equal(ping.Nonce, pong.Nonce); } }