예제 #1
0
        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));
            }
        }
예제 #2
0
        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);
            }
        }
예제 #3
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);
         }
     }
 }
예제 #4
0
        public void CanRespondToPong()
        {
            if (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;
                        }
                    }
                }
            }
        }
예제 #5
0
 public void CantConnectToYourself()
 {
     using (var tester = new NodeServerTester())
     {
         tester.Server2.Nonce = tester.Server1.Nonce;
         Assert.Throws(typeof(InvalidOperationException), () =>
         {
             tester.Node1.VersionHandshake();
         });
     }
 }
예제 #6
0
 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);
     }
 }
예제 #7
0
        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));
            }
        }
예제 #8
0
 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));
     }
 }
예제 #9
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 | 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
                });
                /////////////
            }
        }
예제 #10
0
        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;
            servers.AddDisposable(connected);
            return(connected);
        }
예제 #11
0
        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);
            }
        }