public void TestAddOutdated()
        {
            NodeAddressCollection addressCollection = new NodeAddressCollection();

            NodeAddress address1 = new NodeAddress(IPAddress.Parse("192.168.0.1"), 8333);
            NodeAddress address2 = new NodeAddress(IPAddress.Parse("192.168.0.2"), 8333);

            DateTime baseDate = DateTime.UtcNow;

            addressCollection.Add(address1);
            addressCollection.Add(address2);

            addressCollection.Reject(address1);
            addressCollection.Reject(address2);

            Assert.That(addressCollection.GetNewestUntested(10), Is.EqualTo(new List<NodeAddress>()));
            Assert.That(addressCollection.GetOldestRejected(10), Is.EqualTo(new List<NodeAddress> {address1, address2}));

            SystemTime.Override(baseDate.AddMonths(1));

            addressCollection.Add(address2);

            Assert.That(addressCollection.GetNewestUntested(10), Is.EqualTo(new List<NodeAddress> {address2}));
            Assert.That(addressCollection.GetOldestRejected(10), Is.EqualTo(new List<NodeAddress>()));
        }
        public void TestBannedTransitions()
        {
            NodeAddressCollection addressCollection = new NodeAddressCollection();

            NodeAddress address0 = new NodeAddress(IPAddress.Parse("192.168.0.9"), 8333);
            NodeAddress address1 = new NodeAddress(IPAddress.Parse("192.168.0.1"), 8333);
            NodeAddress address2 = new NodeAddress(IPAddress.Parse("192.168.0.2"), 8333);
            NodeAddress address3 = new NodeAddress(IPAddress.Parse("192.168.0.3"), 8333);
            NodeAddress address4 = new NodeAddress(IPAddress.Parse("192.168.0.4"), 8333);

            addressCollection.Add(address0);
            addressCollection.Add(address1);
            addressCollection.Add(address2);
            addressCollection.Add(address3);
            addressCollection.Add(address4);

            addressCollection.Ban(address0);
            addressCollection.Ban(address1);
            addressCollection.Ban(address2);
            addressCollection.Ban(address3);
            addressCollection.Ban(address4);

            Assert.That(addressCollection.GetNewestBanned(10), Is.EqualTo(new List<NodeAddress> {address4, address3, address2, address1, address0}));

            addressCollection.Add(address1);
            addressCollection.Reject(address2);
            addressCollection.Ban(address3);
            addressCollection.Confirm(address4);

            Assert.That(addressCollection.GetNewestUntested(10), Is.EqualTo(new List<NodeAddress>()));
            Assert.That(addressCollection.GetOldestRejected(10), Is.EqualTo(new List<NodeAddress>()));
            Assert.That(addressCollection.GetNewestBanned(10), Is.EqualTo(new List<NodeAddress> {address3, address4, address2, address1, address0}));
            Assert.That(addressCollection.GetNewestConfirmed(10), Is.EqualTo(new List<NodeAddress>()));
            Assert.That(addressCollection.GetOldestTemporaryRejected(10), Is.EqualTo(new List<NodeAddress>()));
        }
        public void Start()
        {
            blockchain.Init();

            //todo: review the order in which services and listener start/stop, dispose created entities when start fails
            services.CreateServices(this, cancellationTokenSource.Token);

            addressCollection = new NodeAddressCollection();
            connectionCollection = new NodeConnectionCollection(cancellationTokenSource.Token);
            //todo: review, maybe registering event handler is a responsibility of nodeDiscoveryService
            //todo: connectionCollection.Changed += nodeDiscoveryService.Signal; - signal nodeDiscoveryService to connect to new nodes (is it its responsibility?)

            //todo: discover own external address? (it seems useless without external port)
            //todo: use setting to specify port and operating mode
            listener = new BitcoinConnectionListener(IPAddress.Any, 8333, HandleIncomingConnection);
            listener.Start();

            services.Start();

            Started = true;
        }