Пример #1
0
        private async Task <bool> StartConnecting()
        {
            return(await Task <bool> .Factory.StartNew(() =>
            {
                try
                {
                    NodeConnectionParameters parameters = new NodeConnectionParameters();
                    //So we find nodes faster
                    parameters.TemplateBehaviors.Add(new AddressManagerBehavior(GetAddressManager()));
                    //So we don't have to load the chain each time we start
                    parameters.TemplateBehaviors.Add(new ChainBehavior(GetChain()));
                    //Tracker knows which scriptPubKey and outpoints to track
                    parameters.TemplateBehaviors.Add(new TrackerBehavior(GetTracker()));

                    var nodeReq = new NodeRequirement()
                    {
                        RequiredServices = NodeServices.Network
                    };
                    _group = new NodesGroup(_wallet.NetworkChoice, parameters, nodeReq);
                    _group.MaximumNodeConnection = MAX_NUM_CONNECTIONS;
                    _group.Connect();
                    _connectionparameters = parameters;
                    return true;
                }
                catch (Exception e)
                {
                    throw e;
                }
            }));
        }
Пример #2
0
        private async void StartConnecting()
        {
            await Task.Factory.StartNew(() =>
            {
                NodeConnectionParameters parameters = new NodeConnectionParameters();
                //So we find nodes faster
                parameters.TemplateBehaviors.Add(new AddressManagerBehavior(this.GetAddressManager()));
                //So we don't have to load the chain each time we start
                parameters.TemplateBehaviors.Add(new ChainBehavior(this.GetChain()));
                //Tracker knows which scriptPubKey and outpoints to track
                parameters.TemplateBehaviors.Add(new TrackerBehavior(this.GetTracker()));
                var nodeReq = new NodeRequirement()
                {
                    RequiredServices = NodeServices.Network
                };
                _group = new NodesGroup(_wallet.NetworkChoice, parameters, nodeReq);
                _group.MaximumNodeConnection = MAX_NUM_CONNECTIONS;
                _group.Connect();
                _connectionparameters = parameters;
            });

            _wallet.Configure(_group);
            _wallet.Connect();
            _wallet.Connected = true;

            PeriodicKick();
            PeriodicSave();
        }
Пример #3
0
        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);
            }
        }
Пример #4
0
        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);
            }
        }
Пример #5
0
        public void CanMaintainConnectionToNodes()
        {
            using (var builder = NodeBuilder.Create())
            {
                NodesGroup connected = CreateGroup(builder, 2);
                connected.Connect();
                TestUtils.Eventually(() => connected.ConnectedNodes.Count == 2);

                //Server crash abruptly
                builder.Nodes[0].Kill(false);
                TestUtils.Eventually(() => connected.ConnectedNodes.Count < 2);
                builder.Nodes[0].Start();
                //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);
            }
        }
Пример #6
0
        public async Task Connect()
        {
            await Task.Factory.StartNew(async() =>
            {
                EndpointInstance = await BusManager.StartServiceBus(Network.Name);
                _nodeGroup       = new NodesGroup(Network, GetNodeConnectionParameters())
                {
                    AllowSameGroup = true,
                };
                _nodeGroup.Requirements.SupportSPV = true;

                foreach (NetworkAddress networkAddress in BootstrapNodes)
                {
                    AddressManager.Add(networkAddress);
                }

                _nodeGroup.Connect();
                _nodeGroup.ConnectedNodes.Added += (s, e) =>
                {
                    var node              = e.Node;
                    node.MessageReceived += RebroadcastEvent;

                    node.MessageReceived += (node1, message) =>
                    {
                        Console.WriteLine("Message Received");
                        SaveChainData();
                    };

                    node.Disconnected += n =>
                    {
                        Console.WriteLine("Disconnected!");
                    };
                };
            });
        }
Пример #7
0
        NodesGroup CreateNodeGroup(ConcurrentChain chain, int startHeight)
        {
            AddressManager manager = new AddressManager();

            manager.Add(new NetworkAddress(NodeEndpoint), IPAddress.Loopback);
            NodesGroup group = new NodesGroup(Network, new NodeConnectionParameters()
            {
                Services          = NodeServices.Nothing,
                IsRelay           = true,
                TemplateBehaviors =
                {
                    new AddressManagerBehavior(manager)
                    {
                        PeersToDiscover = 1,
                        Mode            = AddressManagerBehaviorMode.None
                    },
                    new ExplorerBehavior(this, chain)
                    {
                        StartHeight = startHeight
                    },
                    new ChainBehavior(chain)
                    {
                        CanRespondToGetHeaders = false
                    }
                }
            });

            group.AllowSameGroup        = true;
            group.MaximumNodeConnection = 1;
            group.Connect();
            return(group);
        }
Пример #8
0
        private async void StartConnecting()
        {
            await Task.Factory.StartNew(() =>
            {
                var parameters = new NodeConnectionParameters();
                parameters.TemplateBehaviors.Add(new AddressManagerBehavior(GetAddressManager())); //So we find nodes faster
                parameters.TemplateBehaviors.Add(new ChainBehavior(GetChain()));                   //So we don't have to load the chain each time we start
                parameters.TemplateBehaviors.Add(new TrackerBehavior(GetTracker()));               //Tracker knows which scriptPubKey and outpoints to track, it monitors all your wallets at the same
                if (!_Disposed)
                {
                    _Group = new NodesGroup(App.Network, parameters, new NodeRequirement()
                    {
                        RequiredServices = NodeServices.Network //Needed for SPV
                    });
                    _Group.MaximumNodeConnection = 4;
                    _Group.Connect();
                    _ConnectionParameters = parameters;
                }
            });

            PeriodicSave();
            PeriodicUiUpdate();
            PeriodicKick();

            foreach (var wallet in Wallets)
            {
                wallet.Wallet.Configure(_Group);
                wallet.Wallet.Connect();
            }
        }
Пример #9
0
        private async Task LoadGroup()
        {
            AddressManager manager = new AddressManager();

            manager.Add(new NetworkAddress(_ChainConfiguration.NodeEndpoint), IPAddress.Loopback);
            NodesGroup group = new NodesGroup(_Network.NBitcoinNetwork, new NodeConnectionParameters()
            {
                Services          = NodeServices.Nothing,
                IsRelay           = true,
                TemplateBehaviors =
                {
                    new AddressManagerBehavior(manager)
                    {
                        PeersToDiscover = 1,
                        Mode            = AddressManagerBehaviorMode.None
                    },
                    new ExplorerBehavior(_Repository, _Chain, _AddressPoolService, _EventAggregator)
                    {
                        StartHeight = _ChainConfiguration.StartHeight
                    },
                    new SlimChainBehavior(_Chain),
                    new PingPongBehavior()
                }
            });

            group.AllowSameGroup        = true;
            group.MaximumNodeConnection = 1;

            var task = WaitConnected(group);

            group.Connect();

            try
            {
                await task;
            }
            catch (Exception ex)
            {
                Logs.Configuration.LogError(ex, $"{_Network.CryptoCode}: Failure to connect to the bitcoin node (P2P)");
                throw;
            }
            _Group = group;

            group.ConnectedNodes.Added   += ConnectedNodes_Changed;
            group.ConnectedNodes.Removed += ConnectedNodes_Changed;

            // !Hack. ExplorerBehavior.AttachCore is async and calling the repository.
            // Because the repository is single thread, calling a ping make sure that AttachCore
            // has fully ran.
            // Without this hack, NBXplorer takes sometimes 1 min to go from Synching to Ready state
            await _Repository.Ping();
        }
Пример #10
0
        private async Task LoadGroup()
        {
            AddressManager manager = new AddressManager();

            manager.Add(new NetworkAddress(GetEndpoint()), IPAddress.Loopback);
            NodesGroup group = new NodesGroup(_Network.NBitcoinNetwork, new NodeConnectionParameters()
            {
                Services          = NodeServices.Nothing,
                IsRelay           = true,
                TemplateBehaviors =
                {
                    new AddressManagerBehavior(manager)
                    {
                        PeersToDiscover = 1,
                        Mode            = AddressManagerBehaviorMode.None
                    },
                    new ExplorerBehavior(_Repository, _Chain, _EventAggregator)
                    {
                        StartHeight = _Configuration.ChainConfigurations.First(c => c.CryptoCode == _Network.CryptoCode).StartHeight
                    },
                    new ChainBehavior(_Chain)
                    {
                        CanRespondToGetHeaders = false,
                        SkipPoWCheck           = true,
                        StripHeader            = true
                    },
                    new PingPongBehavior()
                }
            });

            group.AllowSameGroup        = true;
            group.MaximumNodeConnection = 1;

            var task = WaitConnected(group);

            group.Connect();

            try
            {
                await task;
            }
            catch (Exception ex)
            {
                Logs.Configuration.LogError(ex, $"{_Network.CryptoCode}: Failure to connect to the bitcoin node (P2P)");
                throw;
            }
            _Group = group;

            group.ConnectedNodes.Added   += ConnectedNodes_Changed;
            group.ConnectedNodes.Removed += ConnectedNodes_Changed;
        }
Пример #11
0
        private async Task StartConnecting()
        {
            await Task.Factory.StartNew(() =>
            {
                var parameters = new NodeConnectionParameters();
                parameters.TemplateBehaviors.Add(new AddressManagerBehavior(GetAddressManager()));
                parameters.TemplateBehaviors.Add(new ChainBehavior(GetChain()));
                parameters.TemplateBehaviors.Add(new TrackerBehavior(GetTracker()));
                if (!_disposed)
                {
                    _group = new NodesGroup(_settings.Network, parameters, new NodeRequirement()
                    {
                        RequiredServices = NodeServices.Network
                    });
                    _group.MaximumNodeConnection = 4;
                    _group.Connect();
                    _connectionParameters = parameters;
                }
            });

            //   PeriodicSave();


            _logger.Information("Configuring groups");
            _wallet.Configure(_group);
            if (_isNewWallet)
            {
                _logger.Information("New wallet, generating key pool ");
                //_wallet.GetNextScriptPubKey();
                GenerateNewAddress();
                SaveWallet();
            }
            _logger.Information("Connecting Wallet");
            PeriodicKick();
            _wallet.NewWalletTransaction += _wallet_NewWalletTransaction;

            _wallet.Connect();
            _logger.Information("Wallet connected");
            _lastHeight = CurrentHeight;
            //while (!_disposed)
            //{
            //    await Task.Delay(10000);
            //    _logger.Information($"Current Height {CurrentHeight}");
            //    _logger.Information($"Connected Nodes {ConnectedNodes.Count}");
            //    SaveAsync();
            //}
        }
        /// <summary>
        /// Starts and manages a connection to multiple peers in the Bitcoin network.
        /// </summary>
        public void Connect()
        {
            var parameters = new NodeConnectionParameters();

            parameters.TemplateBehaviors.Add(new AddressManagerBehavior(GetAddressManager()));
            parameters.TemplateBehaviors.Add(new ChainBehavior(GetChain()));

            _peers = new NodesGroup(Network.Main, parameters, new NodeRequirement()
            {
                RequiredServices = NodeServices.Network
            });
            _peers.MaximumNodeConnection = 8;
            _peers.Connect();
            _connectionParameters = parameters;

            PeriodicSave();
            PeriodicReconnect();
            PeriodicUpdate();
        }
Пример #13
0
        private void StartCore()
        {
            LogMessageContext.Create("Starting...");

            using (var Servers = new TesterNodeServerSet(3)) {
                Node node1 = Handshake(Servers [0], Servers [1], "node1");
                Node node2 = Handshake(Servers [1], Servers [2], "node2");


                NBitcoin.Protocol.AddressManager addressManager = new NBitcoin.Protocol.AddressManager();

                addressManager.PeersToFind = 4;

                NodeConnectionParameters parameters = new NodeConnectionParameters();
                parameters.TemplateBehaviors.Add(new AddressManagerBehavior(addressManager));

                //	Servers.SeedServerIndex = 2; //TODO

                NodesGroup nodesGroup = new NodesGroup(JsonLoader <Network> .Instance.Value, parameters);
                nodesGroup.AllowSameGroup        = true;          //TODO
                nodesGroup.MaximumNodeConnection = 2;             //TODO


                nodesGroup.Connect();

                Thread.Sleep(20000);                   //TODO

                Console.ForegroundColor = ConsoleColor.Blue;

                LogMessageContext.Create("Found nodes: " + nodesGroup.ConnectedNodes.Count);

                foreach (Node node in nodesGroup.ConnectedNodes)
                {
                    LogMessageContext.Create("Found node: " + node.RemoteSocketAddress + " " + node.RemoteSocketPort);
                }

                LogMessageContext.Create("Stopping");
            }
        }
Пример #14
0
        public async Task InitializeConnection(Wallet currentWallet)
        {
            await Task.Factory.StartNew(() =>
            {
                var parameters = new NodeConnectionParameters();
                parameters.TemplateBehaviors.Add(new AddressManagerBehavior(addressManagerService.LoadAddressManager()));
                parameters.TemplateBehaviors.Add(new ChainBehavior(chainService.LoadChain().Result));
                parameters.TemplateBehaviors.Add(new TrackerBehavior(trackerService.LoadTracker().Result));

                var group = new NodesGroup(Constants.CurrentNetwork, parameters,
                                           new NodeRequirement {
                    RequiredServices = NodeServices.Network
                })
                {
                    MaximumNodeConnection = 5
                };
                group.Connect();

                currentWallet.Configure(group);
                currentWallet.Connect();
            });
        }
Пример #15
0
        public void ShouldSyncBlockChainAgainstLocal()
        {
            var network = new TestNetwork();

            network.AddSeed(new NetworkAddress(new IPEndPoint(IPAddress.Parse("192.168.2.101"), 9999)));

            var p = new TestTransactionPool();

            p.Add("t1", 1);
            p.Add("t2", 0);
            p.Spend("t2", "t1", 0);

            p.Render();

            var genesisBlock = new TestBlock(p.TakeOut("t1").Value);
            var block1       = new TestBlock(p.TakeOut("t2").Value);

            block1.Parent = genesisBlock;

            genesisBlock.Render();
            block1.Render();

            WithBlockChains(1, genesisBlock.Value.Key, blockChains =>
            {
                //	blockChains[0].HandleNewBlock(genesisBlock.Value.Value);
                //	blockChains[0].HandleNewBlock(block1.Value.Value);


                AutoResetEvent waitForConnection = new AutoResetEvent(false);
                bool connected = false;

                blockChains[0].OnAddedToStore += transaction =>
                {
                    Trace.Information("-- Transaction Received (node server)");
                    //	actionReceiver();
                };

                AddressManager addressManager = new AddressManager();
                addressManager.PeersToFind    = 1;
                NodeConnectionParameters nodesGroupParameters = new NodeConnectionParameters();
//				nodesGroupParameters.AddressFrom = servers[1].ExternalEndpoint;
                nodesGroupParameters.TemplateBehaviors.Add(new AddressManagerBehavior(addressManager));
                nodesGroupParameters.TemplateBehaviors.Add(new ChainBehavior(blockChains[0]));
                nodesGroupParameters.TemplateBehaviors.Add(new BroadcastHubBehavior());
                nodesGroupParameters.TemplateBehaviors.Add(new SPVBehavior(blockChains[0], BroadcastHub.GetBroadcastHub(nodesGroupParameters.TemplateBehaviors)));

                NodesGroup nodesGroup            = new NodesGroup(network, nodesGroupParameters);
                nodesGroup.AllowSameGroup        = true;
                nodesGroup.MaximumNodeConnection = 1;
                nodesGroup.ConnectedNodes.Added += (object sender, NodeEventArgs e) =>
                {
                    Trace.Information("-- Node added to node group");
                    connected = true;
                    waitForConnection.Set();
                };
                nodesGroup.Connect();


                Assert.True(waitForConnection.WaitOne(10000));                 //TODO: use reset events instead of sleep
                Assert.True(connected);



                //TODO
                Thread.Sleep(40000);



                //					actionSender(BroadcastHub.GetBroadcastHub(nodesGroup.NodeConnectionParameters));

                Trace.Information("-- Done");
            });
        }
Пример #16
0
        private void BroadcastTransaction(Action <BroadcastHub> actionSender, Action actionReceiver)
        {
            WithServerSet(2, servers =>
            {
                WithBlockChains(2, null, blockChains =>
                {
                    AutoResetEvent waitForConnection = new AutoResetEvent(false);
                    bool connected = false;

                    servers.SeedServerIndex = 0;

                    AddressManager serverAddressManager = new AddressManager();
                    serverAddressManager.Add(
                        new NetworkAddress(servers[0].ExternalEndpoint),
                        servers[0].ExternalEndpoint.Address
                        );
                    serverAddressManager.Connected(new NetworkAddress(servers[0].ExternalEndpoint));

                    NodeConnectionParameters serverParameters = new NodeConnectionParameters();
                    serverParameters.TemplateBehaviors.Add(new AddressManagerBehavior(serverAddressManager));
                    serverParameters.TemplateBehaviors.Add(new BroadcastHubBehavior());
                    serverParameters.TemplateBehaviors.Add(new SPVBehavior(blockChains[0], BroadcastHub.GetBroadcastHub(serverParameters.TemplateBehaviors)));

                    blockChains[0].OnAddedToMempool += transaction => {
                        Trace.Information("-- Transaction Received (node server)");
                        actionReceiver();
                    };

                    servers[0].InboundNodeConnectionParameters = serverParameters;

                    #region NodeGroup

                    AddressManager addressManager = new AddressManager();
                    addressManager.PeersToFind    = 1;
                    NodeConnectionParameters nodesGroupParameters = new NodeConnectionParameters();
                    nodesGroupParameters.AddressFrom = servers[1].ExternalEndpoint;
                    nodesGroupParameters.TemplateBehaviors.Add(new AddressManagerBehavior(addressManager));
                    nodesGroupParameters.TemplateBehaviors.Add(new BroadcastHubBehavior());
                    nodesGroupParameters.TemplateBehaviors.Add(new SPVBehavior(blockChains[1], BroadcastHub.GetBroadcastHub(nodesGroupParameters.TemplateBehaviors)));

                    blockChains[1].OnAddedToMempool += transaction =>
                    {
                        Trace.Information("-- Transaction Received (node group)");
                    };

                    NodesGroup nodesGroup            = new NodesGroup(servers.Network, nodesGroupParameters);
                    nodesGroup.AllowSameGroup        = true;
                    nodesGroup.MaximumNodeConnection = 1;
                    nodesGroup.ConnectedNodes.Added += (object sender, NodeEventArgs e) =>
                    {
                        Trace.Information("-- Node added to node group");
                        connected = true;
                        waitForConnection.Set();
                    };
                    nodesGroup.Connect();

                    #endregion

                    Assert.True(waitForConnection.WaitOne(10000));                     //TODO: use reset events instead of sleep
                    Assert.True(connected);

                    actionSender(BroadcastHub.GetBroadcastHub(nodesGroup.NodeConnectionParameters));

                    Trace.Information("-- Done");
                });
            });
        }
Пример #17
0
        public void CanHandshakeWithSeveralTemplateBehaviors()
        {
            using (var builder = NodeBuilderEx.Create())
            {
                var node = builder.CreateNode(true);
                node.Generate(101);
                AddressManager manager = new AddressManager();
                manager.Add(new NetworkAddress(node.NodeEndpoint), IPAddress.Loopback);

                var        chain = new SlimChain(builder.Network.GenesisHash);
                NodesGroup group = new NodesGroup(builder.Network, new NodeConnectionParameters()
                {
                    Services          = NodeServices.Nothing,
                    IsRelay           = true,
                    TemplateBehaviors =
                    {
                        new AddressManagerBehavior(manager)
                        {
                            PeersToDiscover = 1,
                            Mode            = AddressManagerBehaviorMode.None
                        },
                        new SlimChainBehavior(chain),
                        new PingPongBehavior()
                    }
                });
                group.AllowSameGroup        = true;
                group.MaximumNodeConnection = 1;
                var connecting = WaitConnected(group);
                try
                {
                    group.Connect();
                    connecting.GetAwaiter().GetResult();
                    Eventually(() =>
                    {
                        Assert.Equal(101, chain.Height);
                    });
                    var ms = new MemoryStream();
                    chain.Save(ms);

                    var chain2 = new SlimChain(chain.Genesis);
                    ms.Position = 0;
                    chain2.Load(ms);
                    Assert.Equal(chain.Tip, chain2.Tip);

                    using (var fs = new FileStream("test.slim.dat", FileMode.Create, FileAccess.Write, FileShare.None, 1024 * 1024))
                    {
                        chain.Save(fs);
                        fs.Flush();
                    }

                    chain.ResetToGenesis();
                    using (var fs = new FileStream("test.slim.dat", FileMode.Open, FileAccess.Read, FileShare.None, 1024 * 1024))
                    {
                        chain.Load(fs);
                    }
                    Assert.Equal(101, chain2.Height);
                    chain.ResetToGenesis();
                }
                finally
                {
                    group.Disconnect();
                }
            }
        }
Пример #18
0
        public void CanHandshakeRestrictNodes()
        {
            using (var builder = NodeBuilderEx.Create())
            {
                var node    = builder.CreateNode(true);
                var manager = new AddressManager();
                manager.Add(new NetworkAddress(node.NodeEndpoint), IPAddress.Loopback);

                var nodesRequirement = new NodeRequirement()
                {
                    MinStartHeight = 100
                };
                var nodeConnectionParameters = new NodeConnectionParameters()
                {
                    TemplateBehaviors =
                    {
                        new AddressManagerBehavior(manager)
                        {
                            PeersToDiscover = 1,
                            Mode            = AddressManagerBehaviorMode.None
                        }
                    }
                };
                var group = new NodesGroup(builder.Network, nodeConnectionParameters, nodesRequirement);
                group.AllowSameGroup = true;
                var connecting = WaitConnected(group);
                try
                {
                    group.Connect();
                    connecting.GetAwaiter().GetResult();
                }
                catch (TaskCanceledException)
                {
                    // It is expected because no node should connect.
                    Assert.Empty(group.ConnectedNodes);                     // but we chack it anyway.
                }
                finally
                {
                    group.Disconnect();
                }

                node.Generate(101);
                group = new NodesGroup(builder.Network, nodeConnectionParameters, nodesRequirement);
                group.AllowSameGroup = true;
                connecting           = WaitConnected(group);
                try
                {
                    group.Connect();
                    connecting.GetAwaiter().GetResult();
                    Eventually(() =>
                    {
                        Assert.NotEmpty(group.ConnectedNodes);
                        Assert.All(group.ConnectedNodes, connectedNode =>
                                   Assert.True(connectedNode.RemoteSocketEndpoint.IsEqualTo(node.NodeEndpoint)));
                    });
                }
                finally
                {
                    group.Disconnect();
                }
            }
        }
Пример #19
0
        public async Task TestServicesAsync(string networkString)
        {
            await RuntimeParams.LoadAsync();

            var network          = Network.GetNetwork(networkString);
            var blocksToDownload = new List <uint256>();

            if (network == Network.Main)
            {
                blocksToDownload.Add(new uint256("00000000000000000037c2de35bd85f3e57f14ddd741ce6cee5b28e51473d5d0"));
                blocksToDownload.Add(new uint256("000000000000000000115315a43cb0cdfc4ea54a0e92bed127f4e395e718d8f9"));
                blocksToDownload.Add(new uint256("00000000000000000011b5b042ad0522b69aae36f7de796f563c895714bbd629"));
            }
            else if (network == Network.TestNet)
            {
                blocksToDownload.Add(new uint256("0000000097a664c4084b49faa6fd4417055cb8e5aac480abc31ddc57a8208524"));
                blocksToDownload.Add(new uint256("000000009ed5b82259ecd2aa4cd1f119db8da7a70e7ea78d9c9f603e01f93bcc"));
                blocksToDownload.Add(new uint256("00000000e6da8c2da304e9f5ad99c079df2c3803b49efded3061ecaf206ddc66"));
            }
            else
            {
                throw new NotSupportedNetworkException(network);
            }
            var dataDir = Path.Combine(Global.Instance.DataDir, EnvironmentHelpers.GetCallerFileName());

            BitcoinStore bitcoinStore = new BitcoinStore();
            await bitcoinStore.InitializeAsync(Path.Combine(dataDir, EnvironmentHelpers.GetMethodName()), network);

            var            addressManagerFolderPath = Path.Combine(dataDir, "AddressManager");
            var            addressManagerFilePath   = Path.Combine(addressManagerFolderPath, $"AddressManager{network}.dat");
            var            blocksFolderPath         = Path.Combine(dataDir, "Blocks", network.ToString());
            var            connectionParameters     = new NodeConnectionParameters();
            AddressManager addressManager           = null;

            try
            {
                addressManager = await NBitcoinHelpers.LoadAddressManagerFromPeerFileAsync(addressManagerFilePath);

                Logger.LogInfo($"Loaded {nameof(AddressManager)} from `{addressManagerFilePath}`.");
            }
            catch (DirectoryNotFoundException)
            {
                addressManager = new AddressManager();
            }
            catch (FileNotFoundException)
            {
                addressManager = new AddressManager();
            }
            catch (OverflowException)
            {
                File.Delete(addressManagerFilePath);
                addressManager = new AddressManager();
            }
            catch (FormatException)
            {
                File.Delete(addressManagerFilePath);
                addressManager = new AddressManager();
            }

            connectionParameters.TemplateBehaviors.Add(new AddressManagerBehavior(addressManager));
            connectionParameters.TemplateBehaviors.Add(bitcoinStore.CreateUntrustedP2pBehavior());

            using var nodes = new NodesGroup(network, connectionParameters, requirements: Constants.NodeRequirements);

            KeyManager           keyManager    = KeyManager.CreateNew(out _, "password");
            WasabiSynchronizer   syncer        = new WasabiSynchronizer(network, bitcoinStore, new Uri("http://localhost:12345"), Global.Instance.TorSocks5Endpoint);
            ServiceConfiguration serviceConfig = new ServiceConfiguration(50, 2, 21, 50, new IPEndPoint(IPAddress.Loopback, network.DefaultPort), Money.Coins(Constants.DefaultDustThreshold));
            CachedBlockProvider  blockProvider = new CachedBlockProvider(
                new P2pBlockProvider(nodes, null, syncer, serviceConfig, network),
                new FileSystemBlockRepository(blocksFolderPath, network));

            using Wallet wallet = Wallet.CreateAndRegisterServices(
                      network,
                      bitcoinStore,
                      keyManager,
                      syncer,
                      nodes,
                      dataDir,
                      new ServiceConfiguration(50, 2, 21, 50, new IPEndPoint(IPAddress.Loopback, network.DefaultPort), Money.Coins(Constants.DefaultDustThreshold)),
                      syncer,
                      blockProvider);
            Assert.True(Directory.Exists(blocksFolderPath));

            try
            {
                var mempoolTransactionAwaiter = new EventsAwaiter <SmartTransaction>(
                    h => bitcoinStore.MempoolService.TransactionReceived += h,
                    h => bitcoinStore.MempoolService.TransactionReceived -= h,
                    3);

                var nodeConnectionAwaiter = new EventsAwaiter <NodeEventArgs>(
                    h => nodes.ConnectedNodes.Added += h,
                    h => nodes.ConnectedNodes.Added -= h,
                    3);

                nodes.Connect();

                var downloadTasks = new List <Task <Block> >();
                using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(4));
                foreach (var hash in blocksToDownload)
                {
                    downloadTasks.Add(blockProvider.GetBlockAsync(hash, cts.Token));
                }

                await nodeConnectionAwaiter.WaitAsync(TimeSpan.FromMinutes(3));

                var i         = 0;
                var hashArray = blocksToDownload.ToArray();
                foreach (var block in await Task.WhenAll(downloadTasks))
                {
                    Assert.True(File.Exists(Path.Combine(blocksFolderPath, hashArray[i].ToString())));
                    i++;
                }

                await mempoolTransactionAwaiter.WaitAsync(TimeSpan.FromMinutes(1));
            }
            finally
            {
                // So next test will download the block.
                foreach (var hash in blocksToDownload)
                {
                    await blockProvider.BlockRepository.RemoveAsync(hash, CancellationToken.None);
                }
                if (wallet is { })
Пример #20
0
        private void DumpCoins(BitcoinAddress destination, IEnumerable <Coin> coins, IEnumerable <Key> keys)
        {
            var     total   = coins.Select(u => u.Amount).Sum();
            var     fee     = Money.Zero;
            FeeRate feeRate = null;

            try
            {
                feeRate = RPCClient.EstimateFeeRate(6);                 //BCC having few fees, this will confirm fast
            }
            catch
            {
                if (RPCClient.Network == Network.RegTest)
                {
                    feeRate = new FeeRate(Money.Satoshis(30), 1);
                }
                else
                {
                    Logs.Main.LogWarning("Fee estimation unavailable, you need to wait Bitcoin Core to properly sync and retry to dump");
                    return;
                }
            }
            TransactionBuilder builder = new TransactionBuilder();

            builder.AddCoins(coins);
            builder.Send(destination, total);
            try
            {
                builder.SendEstimatedFees(feeRate);
                builder.BuildTransaction(false);
            }
            catch (NotEnoughFundsException ex)
            {
                fee = (Money)ex.Missing;
            }

            builder = new TransactionBuilder();
            builder.AddKeys(keys.ToArray());
            builder.AddCoins(coins);
            builder.Send(destination, total - fee);
            builder.SendFees(fee);
            var dumpTransaction = builder.BuildTransaction(true, SigHash.ForkId | SigHash.All);

            Logs.Main.LogInformation("Dump transaction created " + dumpTransaction.ToHex());

            Logs.Main.LogInformation("Dump transaction ID " + dumpTransaction.GetHash());
            //repository.lock(coins.select(c => c.outpoint).toarray(), dumptransaction.gethash());
            Thread.Sleep(1000);
            while (true)
            {
                Console.WriteLine("Are you sure to dump " + coins.Select(c => c.Amount).Sum().ToString() + " BCash coin to " + destination.ToString() + " ? (type `yes` to continue)");
                var response = Console.ReadLine();
                if (response.Equals("yes", StringComparison.OrdinalIgnoreCase))
                {
                    break;
                }
            }

            Logs.Main.LogInformation("Connecting to a BCC node...");

            AddressManagerBehavior addrman = new AddressManagerBehavior(new AddressManager());

            addrman.PeersToDiscover = 10;
            addrman.Mode            = AddressManagerBehaviorMode.Discover;
            NodesGroup group = new NodesGroup(RPCClient.Network, new NodeConnectionParameters()
            {
                IsRelay           = false,
                Services          = NodeServices.Nothing | NodeServices.NODE_BITCOIN_CASH,
                TemplateBehaviors = { addrman },
                UserAgent         = "BCCSpliter",
                Advertize         = false
            }, new NodeRequirement()
            {
                RequiredServices = NodeServices.NODE_BITCOIN_CASH
            });

            group.MaximumNodeConnection = 1;

            if (Configuration.BCCEndpoint != null)
            {
                addrman.PeersToDiscover = 1;
                addrman.Mode            = AddressManagerBehaviorMode.None;
                addrman.AddressManager.Add(new NetworkAddress(Configuration.BCCEndpoint), IPAddress.Parse("127.0.0.1"));
                group.CustomGroupSelector = WellKnownGroupSelectors.ByEndpoint;
                group.AllowSameGroup      = true;
            }

            group.ConnectedNodes.Added += (s, e) =>
            {
                Logs.Main.LogInformation("Connected to " + e.Node.RemoteSocketEndpoint);
                Logs.Main.LogInformation("Broadcasting...");
                e.Node.SendMessageAsync(new InvPayload(new InventoryVector(InventoryType.MSG_TX, dumpTransaction.GetHash())));
                e.Node.SendMessageAsync(new TxPayload(dumpTransaction));
                CancellationTokenSource cts = new CancellationTokenSource();
                cts.CancelAfter(10000);
                try
                {
                    e.Node.PingPong(cts.Token);
                }
                catch (Exception ex)
                {
                    Logs.Main.LogWarning("Error while broadcasting transaction, retrying with another node...");
                    e.Node.Disconnect("Error while broadcasting transaction", ex);
                    return;
                }
                Logs.Main.LogInformation("Broadcasted " + dumpTransaction.GetHash());
                group.Disconnect();
                group.Dispose();
            };

            group.Connect();
        }
Пример #21
0
        public async Task Connect(NetworkInfo networkInfo)
        {
            IPAddress ipAddress = null;

            WireSerialization.Instance.Magic = networkInfo.Magic;
            NodeServerTrace.Information($"Magic is {networkInfo.Magic}");

            var natManager = new NATManager(networkInfo.DefaultPort);

#if DEBUG
            if (networkInfo.IsLANHost)
            {
                ipAddress = natManager.InternalIPAddress ?? IPAddress.Loopback;
                networkInfo.PeersToFind = 0;
            }
            else if (networkInfo.IsLANClient)
            {
                var ipAddressStr = (natManager.InternalIPAddress ?? IPAddress.Loopback).ToString();
                networkInfo.PeersToFind = 1;

                if (networkInfo.Seeds.Count == 0 && !networkInfo.Seeds.Contains(ipAddressStr))
                {
                    networkInfo.Seeds.Add(ipAddressStr);
                }
            }
            else
#endif
            if (!string.IsNullOrEmpty(networkInfo.ExternalIPAddress))
            {
                ipAddress = IPAddress.Parse(networkInfo.ExternalIPAddress);
            }
            else if (networkInfo.DisableUPnP)
            {
                StatusMessageProducer.OutboundStatus = OutboundStatusEnum.Disabled;
            }
            else
            {
                StatusMessageProducer.OutboundStatus = OutboundStatusEnum.Initializing;
                await natManager.Init();

                if (natManager.DeviceFound &&
                    natManager.Mapped.Value &&
                    natManager.ExternalIPVerified.HasValue &&
                    natManager.ExternalIPVerified.Value)
                {
                    StatusMessageProducer.OutboundStatus = OutboundStatusEnum.HasValidAddress;
                    ipAddress = natManager.ExternalIPAddress;
                }
                else
                {
                    StatusMessageProducer.OutboundStatus = OutboundStatusEnum.HasInvalidAddress;
                }
            }

            _BroadcastHubBehavior = new BroadcastHubBehavior();
            _MinerBehavior        = new MinerBehavior();

            _NodeConnectionParameters.TemplateBehaviors.Add(_BroadcastHubBehavior);
            _NodeConnectionParameters.TemplateBehaviors.Add(_MinerBehavior);
            _NodeConnectionParameters.TemplateBehaviors.Add(new SPVBehavior(_BlockChain, _BroadcastHubBehavior.BroadcastHub));
            _NodeConnectionParameters.TemplateBehaviors.Add(new ChainBehavior(_BlockChain));

            AddressManagerBehavior.GetAddrman(_NodeConnectionParameters).PeersToFind = networkInfo.PeersToFind;

            if (ipAddress != null)
            {
                _NodeConnectionParameters.TemplateBehaviors.Find <AddressManagerBehavior>().Mode = AddressManagerBehaviorMode.AdvertizeDiscover;                //parameters.Advertize = true;
                _NodeConnectionParameters.AddressFrom = new System.Net.IPEndPoint(ipAddress, networkInfo.DefaultPort);
            }
            else
            {
                _NodeConnectionParameters.TemplateBehaviors.Find <AddressManagerBehavior>().Mode = AddressManagerBehaviorMode.Discover;
            }

            if (ipAddress != null)
            {
                _Server = new Server(ipAddress, networkInfo, _NodeConnectionParameters);
                OwnResource(_Server);

                if (_Server.Start())
                {
                    NodeServerTrace.Information($"Server started at {ipAddress}:{networkInfo.DefaultPort}");
                    StatusMessageProducer.OutboundStatus = OutboundStatusEnum.Accepting;
                }
                else
                {
                    NodeServerTrace.Information($"Could not start server at {ipAddress}:{networkInfo.DefaultPort}");
                }
            }

            if (networkInfo.Seeds.Count == 0)
            {
                NodeServerTrace.Information("No seeds defined");
            }
            else
            {
                _NodesGroup = new NodesGroup(networkInfo, _NodeConnectionParameters);
                OwnResource(_NodesGroup);

                _NodesGroup.AllowSameGroup        = true;          //TODO
                _NodesGroup.MaximumNodeConnection = networkInfo.MaximumNodeConnection;

#if TRACE
                _NodesGroup.ConnectedNodes.Added += (object sender, NodeEventArgs e) =>
                {
                    NodeServerTrace.Information("Peer found: " + e.Node.RemoteSocketAddress + ":" + e.Node.RemoteSocketPort);
                };
#endif

                _NodesGroup.Connect();
            }
        }
Пример #22
0
        public async Task SendTestsAsync()
        {
            (string password, IRPCClient rpc, Network network, _, ServiceConfiguration serviceConfiguration, BitcoinStore bitcoinStore, Backend.Global global) = await Common.InitializeTestEnvironmentAsync(RegTestFixture, 1);

            bitcoinStore.IndexStore.NewFilter += Common.Wallet_NewFilterProcessed;
            // Create the services.
            // 1. Create connection service.
            var nodes = new NodesGroup(global.Config.Network, requirements: Constants.NodeRequirements);

            nodes.ConnectedNodes.Add(await RegTestFixture.BackendRegTestNode.CreateNewP2pNodeAsync());

            // 2. Create mempool service.

            Node node = await RegTestFixture.BackendRegTestNode.CreateNewP2pNodeAsync();

            node.Behaviors.Add(bitcoinStore.CreateUntrustedP2pBehavior());

            // 3. Create wasabi synchronizer service.
            var synchronizer = new WasabiSynchronizer(rpc.Network, bitcoinStore, new Uri(RegTestFixture.BackendEndPoint), null);

            // 4. Create key manager service.
            var keyManager = KeyManager.CreateNew(out _, password);

            // 5. Create wallet service.
            var workDir = Tests.Common.GetWorkDir();

            CachedBlockProvider blockProvider = new CachedBlockProvider(
                new P2pBlockProvider(nodes, null, synchronizer, serviceConfiguration, network),
                bitcoinStore.BlockRepository);

            var walletManager = new WalletManager(network, new WalletDirectories(workDir));

            walletManager.RegisterServices(bitcoinStore, synchronizer, nodes, serviceConfiguration, synchronizer, blockProvider);

            // Get some money, make it confirm.
            var key  = keyManager.GetNextReceiveKey("foo label", out _);
            var key2 = keyManager.GetNextReceiveKey("foo label", out _);
            var txId = await rpc.SendToAddressAsync(key.GetP2wpkhAddress(network), Money.Coins(1m));

            Assert.NotNull(txId);
            await rpc.GenerateAsync(1);

            var txId2 = await rpc.SendToAddressAsync(key2.GetP2wpkhAddress(network), Money.Coins(1m));

            Assert.NotNull(txId2);
            await rpc.GenerateAsync(1);

            try
            {
                Interlocked.Exchange(ref Common.FiltersProcessedByWalletCount, 0);
                nodes.Connect();                                                                              // Start connection service.
                node.VersionHandshake();                                                                      // Start mempool service.
                synchronizer.Start(requestInterval: TimeSpan.FromSeconds(3), TimeSpan.FromSeconds(5), 10000); // Start wasabi synchronizer service.

                // Wait until the filter our previous transaction is present.
                var blockCount = await rpc.GetBlockCountAsync();

                await Common.WaitForFiltersToBeProcessedAsync(TimeSpan.FromSeconds(120), blockCount);

                var wallet = await walletManager.AddAndStartWalletAsync(keyManager);

                var broadcaster = new TransactionBroadcaster(network, bitcoinStore, synchronizer, nodes, walletManager, rpc);

                var waitCount = 0;
                while (wallet.Coins.Sum(x => x.Amount) == Money.Zero)
                {
                    await Task.Delay(1000);

                    waitCount++;
                    if (waitCount >= 21)
                    {
                        Logger.LogInfo("Funding transaction to the wallet did not arrive.");
                        return;                         // Very rarely this test fails. I have no clue why. Probably because all these RegTests are interconnected, anyway let's not bother the CI with it.
                    }
                }

                var scp  = new Key().ScriptPubKey;
                var res2 = wallet.BuildTransaction(password, new PaymentIntent(scp, Money.Coins(0.05m), label: "foo"), FeeStrategy.CreateFromConfirmationTarget(5), allowUnconfirmed: false);

                Assert.NotNull(res2.Transaction);
                Assert.Single(res2.OuterWalletOutputs);
                Assert.Equal(scp, res2.OuterWalletOutputs.Single().ScriptPubKey);
                Assert.Single(res2.InnerWalletOutputs);
                Assert.True(res2.Fee > Money.Satoshis(2 * 100));                 // since there is a sanity check of 2sat/vb in the server
                Assert.InRange(res2.FeePercentOfSent, 0, 1);
                Assert.Single(res2.SpentCoins);
                var spentCoin = Assert.Single(res2.SpentCoins);
                Assert.Contains(new[] { key.P2wpkhScript, key2.P2wpkhScript }, x => x == spentCoin.ScriptPubKey);
                Assert.Equal(Money.Coins(1m), res2.SpentCoins.Single().Amount);
                Assert.False(res2.SpendsUnconfirmed);

                await broadcaster.SendTransactionAsync(res2.Transaction);

                Assert.Contains(res2.InnerWalletOutputs.Single(), wallet.Coins);

                #region Basic

                Script receive      = keyManager.GetNextReceiveKey("Basic", out _).P2wpkhScript;
                Money  amountToSend = wallet.Coins.Where(x => !x.Unavailable).Sum(x => x.Amount) / 2;
                var    res          = wallet.BuildTransaction(password, new PaymentIntent(receive, amountToSend, label: "foo"), FeeStrategy.SevenDaysConfirmationTargetStrategy, allowUnconfirmed: true);

                foreach (SmartCoin coin in res.SpentCoins)
                {
                    Assert.False(coin.CoinJoinInProgress);
                    Assert.True(coin.Confirmed);
                    Assert.Null(coin.SpenderTransactionId);
                    Assert.True(coin.Unspent);
                }

                Assert.Equal(2, res.InnerWalletOutputs.Count());
                Assert.Empty(res.OuterWalletOutputs);
                var activeOutput = res.InnerWalletOutputs.Single(x => x.ScriptPubKey == receive);
                var changeOutput = res.InnerWalletOutputs.Single(x => x.ScriptPubKey != receive);

                Assert.Equal(receive, activeOutput.ScriptPubKey);
                Assert.Equal(amountToSend, activeOutput.Amount);
                if (res.SpentCoins.Sum(x => x.Amount) - activeOutput.Amount == res.Fee)                 // this happens when change is too small
                {
                    Assert.Contains(res.Transaction.Transaction.Outputs, x => x.Value == activeOutput.Amount);
                    Logger.LogInfo($"Change Output: {changeOutput.Amount.ToString(false, true)} {changeOutput.ScriptPubKey.GetDestinationAddress(network)}");
                }
                Logger.LogInfo($"{nameof(res.Fee)}: {res.Fee}");
                Logger.LogInfo($"{nameof(res.FeePercentOfSent)}: {res.FeePercentOfSent} %");
                Logger.LogInfo($"{nameof(res.SpendsUnconfirmed)}: {res.SpendsUnconfirmed}");
                Logger.LogInfo($"Active Output: {activeOutput.Amount.ToString(false, true)} {activeOutput.ScriptPubKey.GetDestinationAddress(network)}");
                Logger.LogInfo($"TxId: {res.Transaction.GetHash()}");

                var foundReceive = false;
                Assert.InRange(res.Transaction.Transaction.Outputs.Count, 1, 2);
                foreach (var output in res.Transaction.Transaction.Outputs)
                {
                    if (output.ScriptPubKey == receive)
                    {
                        foundReceive = true;
                        Assert.Equal(amountToSend, output.Value);
                    }
                }
                Assert.True(foundReceive);

                await broadcaster.SendTransactionAsync(res.Transaction);

                #endregion Basic

                #region SubtractFeeFromAmount

                receive      = keyManager.GetNextReceiveKey("SubtractFeeFromAmount", out _).P2wpkhScript;
                amountToSend = wallet.Coins.Where(x => !x.Unavailable).Sum(x => x.Amount) / 3;
                res          = wallet.BuildTransaction(password, new PaymentIntent(receive, amountToSend, subtractFee: true, label: "foo"), FeeStrategy.SevenDaysConfirmationTargetStrategy, allowUnconfirmed: true);

                Assert.Equal(2, res.InnerWalletOutputs.Count());
                Assert.Empty(res.OuterWalletOutputs);
                activeOutput = res.InnerWalletOutputs.Single(x => x.ScriptPubKey == receive);
                changeOutput = res.InnerWalletOutputs.Single(x => x.ScriptPubKey != receive);

                Assert.Equal(receive, activeOutput.ScriptPubKey);
                Assert.Equal(amountToSend - res.Fee, activeOutput.Amount);
                Assert.Contains(res.Transaction.Transaction.Outputs, x => x.Value == changeOutput.Amount);
                Logger.LogInfo($"{nameof(res.Fee)}: {res.Fee}");
                Logger.LogInfo($"{nameof(res.FeePercentOfSent)}: {res.FeePercentOfSent} %");
                Logger.LogInfo($"{nameof(res.SpendsUnconfirmed)}: {res.SpendsUnconfirmed}");
                Logger.LogInfo($"Active Output: {activeOutput.Amount.ToString(false, true)} {activeOutput.ScriptPubKey.GetDestinationAddress(network)}");
                Logger.LogInfo($"Change Output: {changeOutput.Amount.ToString(false, true)} {changeOutput.ScriptPubKey.GetDestinationAddress(network)}");
                Logger.LogInfo($"TxId: {res.Transaction.GetHash()}");

                foundReceive = false;
                Assert.InRange(res.Transaction.Transaction.Outputs.Count, 1, 2);
                foreach (var output in res.Transaction.Transaction.Outputs)
                {
                    if (output.ScriptPubKey == receive)
                    {
                        foundReceive = true;
                        Assert.Equal(amountToSend - res.Fee, output.Value);
                    }
                }
                Assert.True(foundReceive);

                #endregion SubtractFeeFromAmount

                #region LowFee

                res = wallet.BuildTransaction(password, new PaymentIntent(receive, amountToSend, label: "foo"), FeeStrategy.SevenDaysConfirmationTargetStrategy, allowUnconfirmed: true);

                Assert.Equal(2, res.InnerWalletOutputs.Count());
                Assert.Empty(res.OuterWalletOutputs);
                activeOutput = res.InnerWalletOutputs.Single(x => x.ScriptPubKey == receive);
                changeOutput = res.InnerWalletOutputs.Single(x => x.ScriptPubKey != receive);

                Assert.Equal(receive, activeOutput.ScriptPubKey);
                Assert.Equal(amountToSend, activeOutput.Amount);
                Assert.Contains(res.Transaction.Transaction.Outputs, x => x.Value == changeOutput.Amount);
                Logger.LogInfo($"{nameof(res.Fee)}: {res.Fee}");
                Logger.LogInfo($"{nameof(res.FeePercentOfSent)}: {res.FeePercentOfSent} %");
                Logger.LogInfo($"{nameof(res.SpendsUnconfirmed)}: {res.SpendsUnconfirmed}");
                Logger.LogInfo($"Active Output: {activeOutput.Amount.ToString(false, true)} {activeOutput.ScriptPubKey.GetDestinationAddress(network)}");
                Logger.LogInfo($"Change Output: {changeOutput.Amount.ToString(false, true)} {changeOutput.ScriptPubKey.GetDestinationAddress(network)}");
                Logger.LogInfo($"TxId: {res.Transaction.GetHash()}");

                foundReceive = false;
                Assert.InRange(res.Transaction.Transaction.Outputs.Count, 1, 2);
                foreach (var output in res.Transaction.Transaction.Outputs)
                {
                    if (output.ScriptPubKey == receive)
                    {
                        foundReceive = true;
                        Assert.Equal(amountToSend, output.Value);
                    }
                }
                Assert.True(foundReceive);

                #endregion LowFee

                #region MediumFee

                res = wallet.BuildTransaction(password, new PaymentIntent(receive, amountToSend, label: "foo"), FeeStrategy.OneDayConfirmationTargetStrategy, allowUnconfirmed: true);

                Assert.Equal(2, res.InnerWalletOutputs.Count());
                Assert.Empty(res.OuterWalletOutputs);
                activeOutput = res.InnerWalletOutputs.Single(x => x.ScriptPubKey == receive);
                changeOutput = res.InnerWalletOutputs.Single(x => x.ScriptPubKey != receive);

                Assert.Equal(receive, activeOutput.ScriptPubKey);
                Assert.Equal(amountToSend, activeOutput.Amount);
                Assert.Contains(res.Transaction.Transaction.Outputs, x => x.Value == changeOutput.Amount);
                Logger.LogInfo($"{nameof(res.Fee)}: {res.Fee}");
                Logger.LogInfo($"{nameof(res.FeePercentOfSent)}: {res.FeePercentOfSent} %");
                Logger.LogInfo($"{nameof(res.SpendsUnconfirmed)}: {res.SpendsUnconfirmed}");
                Logger.LogInfo($"Active Output: {activeOutput.Amount.ToString(false, true)} {activeOutput.ScriptPubKey.GetDestinationAddress(network)}");
                Logger.LogInfo($"Change Output: {changeOutput.Amount.ToString(false, true)} {changeOutput.ScriptPubKey.GetDestinationAddress(network)}");
                Logger.LogInfo($"TxId: {res.Transaction.GetHash()}");

                foundReceive = false;
                Assert.InRange(res.Transaction.Transaction.Outputs.Count, 1, 2);
                foreach (var output in res.Transaction.Transaction.Outputs)
                {
                    if (output.ScriptPubKey == receive)
                    {
                        foundReceive = true;
                        Assert.Equal(amountToSend, output.Value);
                    }
                }
                Assert.True(foundReceive);

                #endregion MediumFee

                #region HighFee

                res = wallet.BuildTransaction(password, new PaymentIntent(receive, amountToSend, label: "foo"), FeeStrategy.TwentyMinutesConfirmationTargetStrategy, allowUnconfirmed: true);

                Assert.Equal(2, res.InnerWalletOutputs.Count());
                Assert.Empty(res.OuterWalletOutputs);
                activeOutput = res.InnerWalletOutputs.Single(x => x.ScriptPubKey == receive);
                changeOutput = res.InnerWalletOutputs.Single(x => x.ScriptPubKey != receive);

                Assert.Equal(receive, activeOutput.ScriptPubKey);
                Assert.Equal(amountToSend, activeOutput.Amount);
                Assert.Contains(res.Transaction.Transaction.Outputs, x => x.Value == changeOutput.Amount);
                Logger.LogInfo($"{nameof(res.Fee)}: {res.Fee}");
                Logger.LogInfo($"{nameof(res.FeePercentOfSent)}: {res.FeePercentOfSent} %");
                Logger.LogInfo($"{nameof(res.SpendsUnconfirmed)}: {res.SpendsUnconfirmed}");
                Logger.LogInfo($"Active Output: {activeOutput.Amount.ToString(false, true)} {activeOutput.ScriptPubKey.GetDestinationAddress(network)}");
                Logger.LogInfo($"Change Output: {changeOutput.Amount.ToString(false, true)} {changeOutput.ScriptPubKey.GetDestinationAddress(network)}");
                Logger.LogInfo($"TxId: {res.Transaction.GetHash()}");

                foundReceive = false;
                Assert.InRange(res.Transaction.Transaction.Outputs.Count, 1, 2);
                foreach (var output in res.Transaction.Transaction.Outputs)
                {
                    if (output.ScriptPubKey == receive)
                    {
                        foundReceive = true;
                        Assert.Equal(amountToSend, output.Value);
                    }
                }
                Assert.True(foundReceive);

                Assert.InRange(res.Fee, Money.Zero, res.Fee);
                Assert.InRange(res.Fee, res.Fee, res.Fee);

                await broadcaster.SendTransactionAsync(res.Transaction);

                #endregion HighFee

                #region MaxAmount

                receive = keyManager.GetNextReceiveKey("MaxAmount", out _).P2wpkhScript;

                res = wallet.BuildTransaction(password, new PaymentIntent(receive, MoneyRequest.CreateAllRemaining(), "foo"), FeeStrategy.SevenDaysConfirmationTargetStrategy, allowUnconfirmed: true);

                Assert.Single(res.InnerWalletOutputs);
                Assert.Empty(res.OuterWalletOutputs);
                activeOutput = res.InnerWalletOutputs.Single();

                Assert.Equal(receive, activeOutput.ScriptPubKey);

                Assert.Single(res.Transaction.Transaction.Outputs);
                var maxBuiltTxOutput = res.Transaction.Transaction.Outputs.Single();
                Assert.Equal(receive, maxBuiltTxOutput.ScriptPubKey);
                Assert.Equal(wallet.Coins.Where(x => !x.Unavailable).Sum(x => x.Amount) - res.Fee, maxBuiltTxOutput.Value);

                await broadcaster.SendTransactionAsync(res.Transaction);

                #endregion MaxAmount

                #region InputSelection

                receive = keyManager.GetNextReceiveKey("InputSelection", out _).P2wpkhScript;

                var inputCountBefore = res.SpentCoins.Count();

                res = wallet.BuildTransaction(password, new PaymentIntent(receive, MoneyRequest.CreateAllRemaining(), "foo"), FeeStrategy.SevenDaysConfirmationTargetStrategy,
                                              allowUnconfirmed: true,
                                              allowedInputs: wallet.Coins.Where(x => !x.Unavailable).Select(x => x.OutPoint).Take(1));

                Assert.Single(res.InnerWalletOutputs);
                Assert.Empty(res.OuterWalletOutputs);
                activeOutput = res.InnerWalletOutputs.Single(x => x.ScriptPubKey == receive);

                Assert.True(inputCountBefore >= res.SpentCoins.Count());
                Assert.Equal(res.SpentCoins.Count(), res.Transaction.Transaction.Inputs.Count);

                Assert.Equal(receive, activeOutput.ScriptPubKey);
                Logger.LogInfo($"{nameof(res.Fee)}: {res.Fee}");
                Logger.LogInfo($"{nameof(res.FeePercentOfSent)}: {res.FeePercentOfSent} %");
                Logger.LogInfo($"{nameof(res.SpendsUnconfirmed)}: {res.SpendsUnconfirmed}");
                Logger.LogInfo($"Active Output: {activeOutput.Amount.ToString(false, true)} {activeOutput.ScriptPubKey.GetDestinationAddress(network)}");
                Logger.LogInfo($"TxId: {res.Transaction.GetHash()}");

                Assert.Single(res.Transaction.Transaction.Outputs);

                res = wallet.BuildTransaction(password, new PaymentIntent(receive, MoneyRequest.CreateAllRemaining(), "foo"), FeeStrategy.SevenDaysConfirmationTargetStrategy,
                                              allowUnconfirmed: true,
                                              allowedInputs: new[] { res.SpentCoins.Select(x => x.OutPoint).First() });

                Assert.Single(res.InnerWalletOutputs);
                Assert.Empty(res.OuterWalletOutputs);
                activeOutput = res.InnerWalletOutputs.Single(x => x.ScriptPubKey == receive);

                Assert.Single(res.Transaction.Transaction.Inputs);
                Assert.Single(res.Transaction.Transaction.Outputs);
                Assert.Single(res.SpentCoins);

                #endregion InputSelection

                #region Labeling

                Script receive2 = keyManager.GetNextReceiveKey("foo", out _).P2wpkhScript;
                res = wallet.BuildTransaction(password, new PaymentIntent(receive2, MoneyRequest.CreateAllRemaining(), "my label"), FeeStrategy.SevenDaysConfirmationTargetStrategy, allowUnconfirmed: true);

                Assert.Single(res.InnerWalletOutputs);
                Assert.Equal("foo, my label", res.InnerWalletOutputs.Single().Label);

                amountToSend = wallet.Coins.Where(x => !x.Unavailable).Sum(x => x.Amount) / 3;
                res          = wallet.BuildTransaction(
                    password,
                    new PaymentIntent(
                        new DestinationRequest(new Key(), amountToSend, label: "outgoing"),
                        new DestinationRequest(new Key(), amountToSend, label: "outgoing2")),
                    FeeStrategy.SevenDaysConfirmationTargetStrategy,
                    allowUnconfirmed: true);

                Assert.Single(res.InnerWalletOutputs);
                Assert.Equal(2, res.OuterWalletOutputs.Count());
                IEnumerable <string> change = res.InnerWalletOutputs.Single().Label.Labels;
                Assert.Contains("outgoing", change);
                Assert.Contains("outgoing2", change);

                await broadcaster.SendTransactionAsync(res.Transaction);

                IEnumerable <SmartCoin> unconfirmedCoins      = wallet.Coins.Where(x => x.Height == Height.Mempool).ToArray();
                IEnumerable <string>    unconfirmedCoinLabels = unconfirmedCoins.SelectMany(x => x.Label.Labels).ToArray();
                Assert.Contains("outgoing", unconfirmedCoinLabels);
                Assert.Contains("outgoing2", unconfirmedCoinLabels);
                IEnumerable <string> allKeyLabels = keyManager.GetKeys().SelectMany(x => x.Label.Labels);
                Assert.Contains("outgoing", allKeyLabels);
                Assert.Contains("outgoing2", allKeyLabels);

                Interlocked.Exchange(ref Common.FiltersProcessedByWalletCount, 0);
                await rpc.GenerateAsync(1);

                await Common.WaitForFiltersToBeProcessedAsync(TimeSpan.FromSeconds(120), 1);

                var bestHeight = new Height(bitcoinStore.SmartHeaderChain.TipHeight);
                IEnumerable <string> confirmedCoinLabels = wallet.Coins.Where(x => x.Height == bestHeight).SelectMany(x => x.Label.Labels);
                Assert.Contains("outgoing", confirmedCoinLabels);
                Assert.Contains("outgoing2", confirmedCoinLabels);
                allKeyLabels = keyManager.GetKeys().SelectMany(x => x.Label.Labels);
                Assert.Contains("outgoing", allKeyLabels);
                Assert.Contains("outgoing2", allKeyLabels);

                #endregion Labeling

                #region AllowedInputsDisallowUnconfirmed

                inputCountBefore = res.SpentCoins.Count();

                receive = keyManager.GetNextReceiveKey("AllowedInputsDisallowUnconfirmed", out _).P2wpkhScript;

                var allowedInputs = wallet.Coins.Where(x => !x.Unavailable).Select(x => x.OutPoint).Take(1);
                var toSend        = new PaymentIntent(receive, MoneyRequest.CreateAllRemaining(), "fizz");

                // covers:
                // disallow unconfirmed with allowed inputs
                res = wallet.BuildTransaction(password, toSend, FeeStrategy.TwentyMinutesConfirmationTargetStrategy, false, allowedInputs: allowedInputs);

                activeOutput = res.InnerWalletOutputs.Single(x => x.ScriptPubKey == receive);
                Assert.Single(res.InnerWalletOutputs);
                Assert.Empty(res.OuterWalletOutputs);

                Assert.Equal(receive, activeOutput.ScriptPubKey);
                Logger.LogDebug($"{nameof(res.Fee)}: {res.Fee}");
                Logger.LogDebug($"{nameof(res.FeePercentOfSent)}: {res.FeePercentOfSent} %");
                Logger.LogDebug($"{nameof(res.SpendsUnconfirmed)}: {res.SpendsUnconfirmed}");
                Logger.LogDebug($"Active Output: {activeOutput.Amount.ToString(false, true)} {activeOutput.ScriptPubKey.GetDestinationAddress(network)}");
                Logger.LogDebug($"TxId: {res.Transaction.GetHash()}");

                Assert.True(inputCountBefore >= res.SpentCoins.Count());
                Assert.False(res.SpendsUnconfirmed);

                Assert.Single(res.Transaction.Transaction.Inputs);
                Assert.Single(res.Transaction.Transaction.Outputs);
                Assert.Single(res.SpentCoins);

                Assert.True(inputCountBefore >= res.SpentCoins.Count());
                Assert.Equal(res.SpentCoins.Count(), res.Transaction.Transaction.Inputs.Count);

                #endregion AllowedInputsDisallowUnconfirmed

                #region CustomChange

                // covers:
                // customchange
                // feePc > 1
                var k1 = new Key();
                var k2 = new Key();
                res = wallet.BuildTransaction(
                    password,
                    new PaymentIntent(
                        new DestinationRequest(k1, MoneyRequest.CreateChange()),
                        new DestinationRequest(k2, Money.Coins(0.0003m), label: "outgoing")),
                    FeeStrategy.TwentyMinutesConfirmationTargetStrategy);

                Assert.Contains(k1.ScriptPubKey, res.OuterWalletOutputs.Select(x => x.ScriptPubKey));
                Assert.Contains(k2.ScriptPubKey, res.OuterWalletOutputs.Select(x => x.ScriptPubKey));

                #endregion CustomChange

                #region FeePcHigh

                res = wallet.BuildTransaction(
                    password,
                    new PaymentIntent(new Key(), Money.Coins(0.0003m), label: "outgoing"),
                    FeeStrategy.TwentyMinutesConfirmationTargetStrategy);

                Assert.True(res.FeePercentOfSent > 1);

                var newChangeK = keyManager.GenerateNewKey("foo", KeyState.Clean, isInternal: true);
                res = wallet.BuildTransaction(
                    password,
                    new PaymentIntent(
                        new DestinationRequest(newChangeK.P2wpkhScript, MoneyRequest.CreateChange(), "boo"),
                        new DestinationRequest(new Key(), Money.Coins(0.0003m), label: "outgoing")),
                    FeeStrategy.TwentyMinutesConfirmationTargetStrategy);

                Assert.True(res.FeePercentOfSent > 1);
                Assert.Single(res.OuterWalletOutputs);
                Assert.Single(res.InnerWalletOutputs);
                SmartCoin changeRes = res.InnerWalletOutputs.Single();
                Assert.Equal(newChangeK.P2wpkhScript, changeRes.ScriptPubKey);
                Assert.Equal(newChangeK.Label, changeRes.Label);
                Assert.Equal(KeyState.Clean, newChangeK.KeyState);                 // Still clean, because the tx wasn't yet propagated.

                #endregion FeePcHigh
            }
            finally
            {
                bitcoinStore.IndexStore.NewFilter -= Common.Wallet_NewFilterProcessed;
                await walletManager.RemoveAndStopAllAsync(CancellationToken.None);

                // Dispose wasabi synchronizer service.
                if (synchronizer is { })
Пример #23
0
        public static void Initialize(Config config)
        {
            WalletService  = null;
            ChaumianClient = null;

            Config = Guard.NotNull(nameof(config), config);

            string blindingPubKeyFile = Path.Combine(DataDir, $"BlindingPubKey{Network}.json");

            if (File.Exists(blindingPubKeyFile))
            {
                string blindingPubKeyJson = "";
                blindingPubKeyJson = File.ReadAllText(blindingPubKeyFile);
                BlindingPubKey     = BlindingRsaPubKey.CreateFromJson(blindingPubKeyJson);
            }
            else
            {
                if (Network == Network.Main)
                {
                    BlindingPubKey = new BlindingRsaPubKey(new BigInteger("16421152619146079007287475569112871971988560541093277613438316709041030720662622782033859387192362542996510605015506477964793447620206674394713753349543444988246276357919473682408472170521463339860947351211455351029147665615454176157348164935212551240942809518428851690991984017733153078846480521091423447691527000770982623947706172997649440619968085147635776736938871139581019988225202983052255684151711253254086264386774936200194229277914886876824852466823571396538091430866082004097086602287294474304344865162932126041736158327600847754258634325228417149098062181558798532036659383679712667027126535424484318399849"), new BigInteger("65537"));
                }
                else
                {
                    BlindingPubKey = new BlindingRsaPubKey(new BigInteger("19473594448380717274202325076521698699373476167359253614775896809797414915031772455344343455269320444157176520539924715307970060890094127521516100754263825112231545354422893125394219335109864514907655429499954825469485252969706079992227103439161156022844535556626007277544637236136559868400854764962522288139619969507311597914908752685925185380735570791798593290356424409633800092336087046668579610273133131498947353719917407262847070395909920415822288443947309434039008038907229064999576278651443575362470457496666718250346530518268694562965606704838796709743032825816642704620776596590683042135764246115456630753521"), new BigInteger("65537"));
                }
                Directory.CreateDirectory(DataDir);
                File.WriteAllText(blindingPubKeyFile, BlindingPubKey.ToJson());
            }

            var addressManagerFolderPath = Path.Combine(DataDir, "AddressManager");

            AddressManagerFilePath = Path.Combine(addressManagerFolderPath, $"AddressManager{Network}.dat");
            var blocksFolderPath     = Path.Combine(DataDir, $"Blocks{Network}");
            var connectionParameters = new NodeConnectionParameters();

            AddressManager = null;
            try
            {
                AddressManager = AddressManager.LoadPeerFile(AddressManagerFilePath);
                Logger.LogInfo <AddressManager>($"Loaded {nameof(AddressManager)} from `{AddressManagerFilePath}`.");
            }
            catch (DirectoryNotFoundException ex)
            {
                Logger.LogInfo <AddressManager>($"{nameof(AddressManager)} did not exist at `{AddressManagerFilePath}`. Initializing new one.");
                Logger.LogTrace <AddressManager>(ex);
                AddressManager = new AddressManager();
            }
            catch (FileNotFoundException ex)
            {
                Logger.LogInfo <AddressManager>($"{nameof(AddressManager)} did not exist at `{AddressManagerFilePath}`. Initializing new one.");
                Logger.LogTrace <AddressManager>(ex);
                AddressManager = new AddressManager();
            }

            connectionParameters.TemplateBehaviors.Add(new AddressManagerBehavior(AddressManager));
            MemPoolService = new MemPoolService();
            connectionParameters.TemplateBehaviors.Add(new MemPoolBehavior(MemPoolService));

            Nodes = new NodesGroup(Network, connectionParameters,
                                   new NodeRequirement
            {
                RequiredServices = NodeServices.Network,
                MinVersion       = Constants.ProtocolVersion_WITNESS_VERSION
            });

            var indexFilePath = Path.Combine(DataDir, $"Index{Network}.dat");

            IndexDownloader = new IndexDownloader(Network, indexFilePath, Config.GetCurrentBackendUri());

            Nodes.Connect();
            Logger.LogInfo("Start connecting to nodes...");

            IndexDownloader.Synchronize(requestInterval: TimeSpan.FromSeconds(21));
            Logger.LogInfo("Start synchronizing filters...");
        }
Пример #24
0
        public async Task TestServicesAsync(string networkString)
        {
            var network          = Network.GetNetwork(networkString);
            var blocksToDownload = new HashSet <uint256>();

            if (network == Network.Main)
            {
                blocksToDownload.Add(new uint256("00000000000000000037c2de35bd85f3e57f14ddd741ce6cee5b28e51473d5d0"));
                blocksToDownload.Add(new uint256("000000000000000000115315a43cb0cdfc4ea54a0e92bed127f4e395e718d8f9"));
                blocksToDownload.Add(new uint256("00000000000000000011b5b042ad0522b69aae36f7de796f563c895714bbd629"));
            }
            else if (network == Network.TestNet)
            {
                blocksToDownload.Add(new uint256("0000000097a664c4084b49faa6fd4417055cb8e5aac480abc31ddc57a8208524"));
                blocksToDownload.Add(new uint256("000000009ed5b82259ecd2aa4cd1f119db8da7a70e7ea78d9c9f603e01f93bcc"));
                blocksToDownload.Add(new uint256("00000000e6da8c2da304e9f5ad99c079df2c3803b49efded3061ecaf206ddc66"));
            }
            else
            {
                throw new NotSupportedException(network.ToString());
            }

            var            addressManagerFolderPath = Path.Combine(Global.Instance.DataDir, "AddressManager");
            var            addressManagerFilePath   = Path.Combine(addressManagerFolderPath, $"AddressManager{network}.dat");
            var            blocksFolderPath         = Path.Combine(Global.Instance.DataDir, "Blocks", network.ToString());
            var            connectionParameters     = new NodeConnectionParameters();
            AddressManager addressManager           = null;

            try
            {
                addressManager = AddressManager.LoadPeerFile(addressManagerFilePath);
                Logger.LogInfo <AddressManager>($"Loaded {nameof(AddressManager)} from `{addressManagerFilePath}`.");
            }
            catch (DirectoryNotFoundException ex)
            {
                Logger.LogInfo <AddressManager>($"{nameof(AddressManager)} did not exist at `{addressManagerFilePath}`. Initializing new one.");
                Logger.LogTrace <AddressManager>(ex);
                addressManager = new AddressManager();
            }
            catch (FileNotFoundException ex)
            {
                Logger.LogInfo <AddressManager>($"{nameof(AddressManager)} did not exist at `{addressManagerFilePath}`. Initializing new one.");
                Logger.LogTrace <AddressManager>(ex);
                addressManager = new AddressManager();
            }

            connectionParameters.TemplateBehaviors.Add(new AddressManagerBehavior(addressManager));
            var memPoolService = new MemPoolService();

            connectionParameters.TemplateBehaviors.Add(new MemPoolBehavior(memPoolService));

            var nodes = new NodesGroup(network, connectionParameters, requirements: Helpers.Constants.NodeRequirements);

            BitcoinStore bitcoinStore = new BitcoinStore();
            await bitcoinStore.InitializeAsync(Path.Combine(Global.Instance.DataDir, nameof(TestServicesAsync)), network);

            KeyManager         keyManager    = KeyManager.CreateNew(out _, "password");
            WasabiSynchronizer syncer        = new WasabiSynchronizer(network, bitcoinStore, new Uri("http://localhost:12345"), Global.Instance.TorSocks5Endpoint);
            WalletService      walletService = new WalletService(
                bitcoinStore,
                keyManager,
                syncer,
                new CcjClient(syncer, network, keyManager, new Uri("http://localhost:12345"), Global.Instance.TorSocks5Endpoint),
                memPoolService,
                nodes,
                Global.Instance.DataDir,
                new ServiceConfiguration(50, 2, 21, 50, new IPEndPoint(IPAddress.Loopback, network.DefaultPort), Money.Coins(0.0001m)));

            Assert.True(Directory.Exists(blocksFolderPath));

            try
            {
                nodes.ConnectedNodes.Added         += ConnectedNodes_Added;
                nodes.ConnectedNodes.Removed       += ConnectedNodes_Removed;
                memPoolService.TransactionReceived += MemPoolService_TransactionReceived;

                nodes.Connect();
                // Using the interlocked, not because it makes sense in this context, but to
                // set an example that these values are often concurrency sensitive
                var times = 0;
                while (Interlocked.Read(ref _nodeCount) < 3)
                {
                    if (times > 4200)                     // 7 minutes
                    {
                        throw new TimeoutException($"Connection test timed out.");
                    }
                    await Task.Delay(100);

                    times++;
                }

                times = 0;
                while (Interlocked.Read(ref _mempoolTransactionCount) < 3)
                {
                    if (times > 3000)                     // 3 minutes
                    {
                        throw new TimeoutException($"{nameof(MemPoolService)} test timed out.");
                    }
                    await Task.Delay(100);

                    times++;
                }

                foreach (var hash in blocksToDownload)
                {
                    using (var cts = new CancellationTokenSource(TimeSpan.FromMinutes(3)))
                    {
                        var block = await walletService.GetOrDownloadBlockAsync(hash, cts.Token);

                        Assert.True(File.Exists(Path.Combine(blocksFolderPath, hash.ToString())));
                        Logger.LogInfo <P2pTests>($"Full block is downloaded: {hash}.");
                    }
                }
            }
            finally
            {
                nodes.ConnectedNodes.Added         -= ConnectedNodes_Added;
                nodes.ConnectedNodes.Removed       -= ConnectedNodes_Removed;
                memPoolService.TransactionReceived -= MemPoolService_TransactionReceived;

                // So next test will download the block.
                foreach (var hash in blocksToDownload)
                {
                    await walletService?.DeleteBlockAsync(hash);
                }
                if (walletService != null)
                {
                    await walletService.StopAsync();
                }

                if (Directory.Exists(blocksFolderPath))
                {
                    Directory.Delete(blocksFolderPath, recursive: true);
                }

                IoHelpers.EnsureContainingDirectoryExists(addressManagerFilePath);
                addressManager?.SavePeerFile(addressManagerFilePath, network);
                Logger.LogInfo <P2pTests>($"Saved {nameof(AddressManager)} to `{addressManagerFilePath}`.");
                nodes?.Dispose();

                await syncer?.StopAsync();
            }
        }
Пример #25
0
        public async Task StartAsync()
        {
            if (_Disposed)
            {
                throw new ObjectDisposedException(nameof(NBxplorerInitializer));
            }
            _Starting.Reset();
            try
            {
                if (_Network.IsRegTest)
                {
                    if (await _RPC.GetBlockCountAsync() < 100)
                    {
                        Logs.Configuration.LogInformation($"Less than 100 blocks, mining some block for regtest");
                        await _RPC.GenerateAsync(101);
                    }
                    else
                    {
                        var header = await _RPC.GetBlockHeaderAsync(await _RPC.GetBestBlockHashAsync());

                        if ((DateTimeOffset.UtcNow - header.BlockTime) > TimeSpan.FromSeconds(24 * 60 * 60))
                        {
                            Logs.Configuration.LogInformation($"It has been a while nothing got mined on regtest... mining 10 blocks");
                            await _RPC.GenerateAsync(10);
                        }
                    }
                }

                var cachePath = Path.Combine(_Configuration.DataDir, "chain.dat");
                if (_Configuration.CacheChain && File.Exists(cachePath))
                {
                    Logs.Configuration.LogInformation($"Loading chain from cache...");
                    _Chain.Load(File.ReadAllBytes(cachePath));
                    Logs.Configuration.LogInformation($"Height: " + _Chain.Height);
                }

                var heightBefore = _Chain.Height;
                Logs.Configuration.LogInformation($"Loading chain from node...");
                using (var node = Node.Connect(_Network.Network, _Configuration.NodeEndpoint))
                {
                    var cts = new CancellationTokenSource();
                    cts.CancelAfter(5000);
                    node.VersionHandshake(cts.Token);
                    node.SynchronizeChain(_Chain);
                }
                Logs.Configuration.LogInformation("Height: " + _Chain.Height);

                if (_Configuration.CacheChain && heightBefore != _Chain.Height)
                {
                    Logs.Configuration.LogInformation($"Saving chain to cache...");
                    var ms = new MemoryStream();
                    _Chain.WriteTo(ms);
                    File.WriteAllBytes(cachePath, ms.ToArray());
                    Logs.Configuration.LogInformation($"Saved");
                }


                AddressManager manager = new AddressManager();
                manager.Add(new NetworkAddress(_Configuration.NodeEndpoint), IPAddress.Loopback);
                NodesGroup group = new NodesGroup(_Network.Network, new NodeConnectionParameters()
                {
                    Services          = NodeServices.Nothing,
                    IsRelay           = true,
                    TemplateBehaviors =
                    {
                        new AddressManagerBehavior(manager)
                        {
                            PeersToDiscover = 1,
                            Mode            = AddressManagerBehaviorMode.None
                        },
                        new ExplorerBehavior(_Repository, _Chain, _Invoker, _Events)
                        {
                            StartHeight = _Configuration.StartHeight
                        },
                        new ChainBehavior(_Chain)
                        {
                            CanRespondToGetHeaders = false
                        }
                    }
                });
                group.AllowSameGroup        = true;
                group.MaximumNodeConnection = 1;
                group.Connect();
                _Group = group;
            }
            finally { _Starting.Set(); }
        }
Пример #26
0
        /// <summary>
        /// Connect the wallet with the given connection parameters
        /// </summary>
        /// <param name="group">The group to use</param>
        public void Connect(NodesGroup group)
        {
            if (group == null)
            {
                throw new ArgumentNullException("group");
            }
            if (State != WalletState.Created)
            {
                throw new InvalidOperationException("The wallet is already connecting or connected");
            }
            var parameters = group.NodeConnectionParameters;

            group.Requirements.MinVersion        = ProtocolVersion.PROTOCOL_VERSION;
            group.Requirements.RequiredServices |= NodeServices.Network;

            var chain = parameters.TemplateBehaviors.Find <ChainBehavior>();

            if (chain == null)
            {
                chain = new ChainBehavior(new ConcurrentChain(_Parameters.Network));
                parameters.TemplateBehaviors.Add(chain);
            }
            if (chain.Chain.Genesis.HashBlock != _Parameters.Network.GetGenesis().GetHash())
            {
                throw new InvalidOperationException("ChainBehavior with invalid network chain detected");
            }

            var addrman = parameters.TemplateBehaviors.Find <AddressManagerBehavior>();

            if (addrman == null)
            {
                addrman = new AddressManagerBehavior(new AddressManager());
                parameters.TemplateBehaviors.Add(addrman);
            }

            var tracker = parameters.TemplateBehaviors.Find <TrackerBehavior>();

            if (tracker == null)
            {
                tracker = new TrackerBehavior(new Tracker(), chain.Chain);
                parameters.TemplateBehaviors.Add(tracker);
            }

            _Chain           = chain.Chain;
            _AddressManager  = addrman.AddressManager;
            _Tracker         = tracker.Tracker;
            _TrackerBehavior = tracker;
            _Group           = group;
            if (AddKnownScriptToTracker())
            {
                _Group.Purge("Bloom filter renew");
            }
            _State = WalletState.Disconnected;
            _Group.Connect();
            _Group.ConnectedNodes.Added   += ConnectedNodes_Added;
            _Group.ConnectedNodes.Removed += ConnectedNodes_Added;
            foreach (var node in _Group.ConnectedNodes)
            {
                node.Behaviors.Find <TrackerBehavior>().Scan(_ScanLocation, Created);
            }
        }
Пример #27
0
        public void CanDiscoverPeers()
        {
            int SERVER_COUNT = 4;

            int FIRST_SERVER  = 0;
            int SECOND_SERVER = 1;
            int LAST_SERVER   = 2;
            int NEW_SERVER    = 3;

            var ToBeConnected  = new List <NodeServer>();
            var ToBeDiscovered = new List <Node>();

            WithServerSet(SERVER_COUNT, servers =>
            {
                servers.SeedServerIndex = LAST_SERVER;                 //TODO

                ToBeConnected.Add(servers[FIRST_SERVER]);
                ToBeConnected.Add(servers[SECOND_SERVER]);
                ToBeConnected.Add(servers[LAST_SERVER]);

                ToBeDiscovered.Add(Handshake(servers[FIRST_SERVER], servers[SECOND_SERVER]));
                Trace.Information("Handshake First -> Second");

                ToBeDiscovered.Add(Handshake(servers[SECOND_SERVER], servers[LAST_SERVER]));
                Trace.Information("Handshake Second -> Last");

                #region Setup Parameters for NodeGroup

                AddressManager addressManager = new AddressManager();
                addressManager.PeersToFind    = ToBeConnected.Count * 2;              // nodes answer to GetAddr with random nodes, so keep trying until we get all expected items

                NodeConnectionParameters parameters = new NodeConnectionParameters();
                parameters.TemplateBehaviors.Add(new AddressManagerBehavior(addressManager));

                parameters.AddressFrom = servers[NEW_SERVER].ExternalEndpoint;                 //TODO

                NodesGroup nodesGroup            = new NodesGroup(servers.Network, parameters);
                nodesGroup.AllowSameGroup        = true;                //TODO
                nodesGroup.MaximumNodeConnection = ToBeConnected.Count; //TODO

                #endregion

                nodesGroup.Connect();

                AutoResetEvent waitForDiscoveredAll = new AutoResetEvent(false);
                var discoveredAll = false;

                nodesGroup.ConnectedNodes.Added += (object sender, NodeEventArgs e) =>
                {
                    Console.WriteLine($"\n\n\nPeer found: {e.Node.Peer.Endpoint}\n\n\n");

                    Node node = ToBeDiscovered.Find(n => n.MyVersion.AddressFrom.Equals(e.Node.Peer.Endpoint));

                    if (node != null && ToBeDiscovered.Contains(node))
                    {
                        ToBeDiscovered.Remove(node);

                        if (ToBeDiscovered.Count == 0)
                        {
                            discoveredAll = true;
                            waitForDiscoveredAll.Set();
                        }
                    }
                };

                Assert.True(waitForDiscoveredAll.WaitOne(30000));
                Assert.True(discoveredAll);
            });
        }
Пример #28
0
        static void Main(string[] args)
        {
            var connectionParameters = new NodeConnectionParameters()
            {
                ReceiveBufferSize = 1048576,
                SendBufferSize    = 1048576
            };

            var            addressManagerFilePath = "AddressManager.dat";
            AddressManager addressManager;

            try
            {
                addressManager = AddressManager.LoadPeerFile(addressManagerFilePath);
                Console.WriteLine($"Loaded {nameof(AddressManager)} from `{addressManagerFilePath}`.");
            }
            catch (FileNotFoundException)
            {
                Console.WriteLine($"{nameof(AddressManager)} did not exist at `{addressManagerFilePath}`. Initializing new one.");
                addressManager = new AddressManager();
            }

            connectionParameters.TemplateBehaviors.Add(new AddressManagerBehavior(addressManager));

            var nodes = new NodesGroup(Network.Main, connectionParameters,
                                       new NodeRequirement
            {
                RequiredServices = NodeServices.Network,
                MinVersion       = ProtocolVersion.WITNESS_VERSION
            });

            Console.WriteLine("Start connecting to nodes...");
            nodes.Connect();

            Console.WriteLine();
            Console.WriteLine($"{nameof(connectionParameters)}.{nameof(connectionParameters.AddressFrom)}: {connectionParameters.AddressFrom}");
            Console.WriteLine($"{nameof(connectionParameters)}.{nameof(connectionParameters.IsRelay)}: {connectionParameters.IsRelay}");
            Console.WriteLine($"{nameof(connectionParameters)}.{nameof(connectionParameters.PreferredTransactionOptions)}: {connectionParameters.PreferredTransactionOptions}");
            Console.WriteLine($"{nameof(connectionParameters)}.{nameof(connectionParameters.ReceiveBufferSize)}: {connectionParameters.ReceiveBufferSize}");
            Console.WriteLine($"{nameof(connectionParameters)}.{nameof(connectionParameters.ReuseBuffer)}: {connectionParameters.ReuseBuffer}");
            Console.WriteLine($"{nameof(connectionParameters)}.{nameof(connectionParameters.SendBufferSize)}: {connectionParameters.SendBufferSize}");
            Console.WriteLine($"{nameof(connectionParameters)}.{nameof(connectionParameters.Services)}: {connectionParameters.Services}");
            Console.WriteLine($"{nameof(connectionParameters)}.{nameof(connectionParameters.TemplateBehaviors)}.Count(): {connectionParameters.TemplateBehaviors.Count()}");
            Console.WriteLine($"{nameof(connectionParameters)}.{nameof(connectionParameters.UserAgent)}: {connectionParameters.UserAgent}");
            Console.WriteLine($"{nameof(connectionParameters)}.{nameof(connectionParameters.Version)}: {connectionParameters.Version}");
            Console.WriteLine();

            Console.WriteLine($"{nameof(addressManager)}.{nameof(addressManager.Count)}: {addressManager.Count}");
            Console.WriteLine($"{nameof(addressManager)}.GetAddr().Count(): {addressManager.GetAddr().Count()}");
            Console.WriteLine($"{nameof(addressManager)}.GetSerializedSize(): {addressManager.GetSerializedSize()}");
            Console.WriteLine();

            Console.WriteLine($"{nameof(nodes)}.{nameof(nodes.AllowSameGroup)}: {nodes.AllowSameGroup}");
            Console.WriteLine($"{nameof(nodes)}.{nameof(nodes.ConnectedNodes)}.{nameof(nodes.ConnectedNodes.Count)}: {nodes.ConnectedNodes.Count}");
            Console.WriteLine($"{nameof(nodes)}.{nameof(nodes.MaximumNodeConnection)}: {nodes.MaximumNodeConnection}");
            Console.WriteLine($"{nameof(nodes)}.{nameof(nodes.Requirements)}.{nameof(nodes.Requirements.MinVersion)}: {nodes.Requirements.MinVersion}");
            Console.WriteLine($"{nameof(nodes)}.{nameof(nodes.Requirements)}.{nameof(nodes.Requirements.RequiredServices)}: {nodes.Requirements.RequiredServices}");
            Console.WriteLine($"{nameof(nodes)}.{nameof(nodes.Requirements)}.{nameof(nodes.Requirements.SupportSPV)}: {nodes.Requirements.SupportSPV}");
            Console.WriteLine();

            try
            {
                int i = 0;
                while (i < 42) // 7 minutes
                {
                    Console.WriteLine($"Witing for a connection for {i / (double)6} minutes....");
                    if (nodes.ConnectedNodes.Count >= 1)
                    {
                        Console.WriteLine("SUCCESSFULLY FOUND A CONNECTION");
                        return;
                    }
                    Task.Delay(TimeSpan.FromSeconds(10)).GetAwaiter().GetResult();
                    i++;
                }
                throw new TimeoutException($"DID NOT FIND A CONNECTION within {i / (double)6} minutes.");
            }
            finally
            {
                Console.WriteLine($"Saving {nameof(AddressManager)} to `{addressManagerFilePath}`.");
                addressManager.SavePeerFile(addressManagerFilePath, Network.Main);
                nodes.Dispose();
            }
        }
Пример #29
0
        public async Task BuildTransactionValidationsTestAsync()
        {
            (string password, IRPCClient rpc, Network network, Coordinator coordinator, ServiceConfiguration serviceConfiguration, BitcoinStore bitcoinStore, Backend.Global global) = await Common.InitializeTestEnvironmentAsync(RegTestFixture, 1);

            // Create the services.
            // 1. Create connection service.
            var nodes = new NodesGroup(global.Config.Network, requirements: Constants.NodeRequirements);

            nodes.ConnectedNodes.Add(await RegTestFixture.BackendRegTestNode.CreateNewP2pNodeAsync());

            // 2. Create mempool service.

            Node node = await RegTestFixture.BackendRegTestNode.CreateNewP2pNodeAsync();

            node.Behaviors.Add(bitcoinStore.CreateUntrustedP2pBehavior());

            // 3. Create wasabi synchronizer service.
            var synchronizer = new WasabiSynchronizer(rpc.Network, bitcoinStore, new Uri(RegTestFixture.BackendEndPoint), null);

            // 4. Create key manager service.
            var keyManager = KeyManager.CreateNew(out _, password);

            // 5. Create wallet service.
            var workDir          = Common.GetWorkDir();
            var blocksFolderPath = Path.Combine(workDir, "Blocks", network.ToString());
            CachedBlockProvider blockProvider = new CachedBlockProvider(
                new P2pBlockProvider(nodes, null, synchronizer, serviceConfiguration, network),
                new FileSystemBlockRepository(blocksFolderPath, network));

            using var wallet           = Wallet.CreateAndRegisterServices(network, bitcoinStore, keyManager, synchronizer, nodes, workDir, serviceConfiguration, synchronizer, blockProvider);
            wallet.NewFilterProcessed += Common.Wallet_NewFilterProcessed;

            var scp = new Key().ScriptPubKey;

            var validIntent   = new PaymentIntent(scp, Money.Coins(1));
            var invalidIntent = new PaymentIntent(
                new DestinationRequest(scp, Money.Coins(10 * 1000 * 1000)),
                new DestinationRequest(scp, Money.Coins(12 * 1000 * 1000)));

            Assert.Throws <OverflowException>(() => new PaymentIntent(
                                                  new DestinationRequest(scp, Money.Satoshis(long.MaxValue)),
                                                  new DestinationRequest(scp, Money.Satoshis(long.MaxValue)),
                                                  new DestinationRequest(scp, Money.Satoshis(5))));

            Logger.TurnOff();
            Assert.Throws <ArgumentNullException>(() => wallet.BuildTransaction(null, null, FeeStrategy.CreateFromConfirmationTarget(4)));

            // toSend cannot have a null element
            Assert.Throws <ArgumentNullException>(() => wallet.BuildTransaction(null, new PaymentIntent(new[] { (DestinationRequest)null }), FeeStrategy.CreateFromConfirmationTarget(0)));

            // toSend cannot have a zero element
            Assert.Throws <ArgumentException>(() => wallet.BuildTransaction(null, new PaymentIntent(Array.Empty <DestinationRequest>()), FeeStrategy.SevenDaysConfirmationTargetStrategy));

            // feeTarget has to be in the range 0 to 1008
            Assert.Throws <ArgumentOutOfRangeException>(() => wallet.BuildTransaction(null, validIntent, FeeStrategy.CreateFromConfirmationTarget(-10)));
            Assert.Throws <ArgumentOutOfRangeException>(() => wallet.BuildTransaction(null, validIntent, FeeStrategy.CreateFromConfirmationTarget(2000)));

            // toSend amount sum has to be in range 0 to 2099999997690000
            Assert.Throws <ArgumentOutOfRangeException>(() => wallet.BuildTransaction(null, invalidIntent, FeeStrategy.TwentyMinutesConfirmationTargetStrategy));

            // toSend negative sum amount
            Assert.Throws <ArgumentOutOfRangeException>(() => wallet.BuildTransaction(null, new PaymentIntent(scp, Money.Satoshis(-10000)), FeeStrategy.TwentyMinutesConfirmationTargetStrategy));

            // toSend negative operation amount
            Assert.Throws <ArgumentOutOfRangeException>(() => wallet.BuildTransaction(
                                                            null,
                                                            new PaymentIntent(
                                                                new DestinationRequest(scp, Money.Satoshis(20000)),
                                                                new DestinationRequest(scp, Money.Satoshis(-10000))),
                                                            FeeStrategy.TwentyMinutesConfirmationTargetStrategy));

            // allowedInputs cannot be empty
            Assert.Throws <ArgumentException>(() => wallet.BuildTransaction(null, validIntent, FeeStrategy.TwentyMinutesConfirmationTargetStrategy, allowedInputs: Array.Empty <OutPoint>()));

            // "Only one element can contain the AllRemaining flag.
            Assert.Throws <ArgumentException>(() => wallet.BuildTransaction(
                                                  password,
                                                  new PaymentIntent(
                                                      new DestinationRequest(scp, MoneyRequest.CreateAllRemaining(), "zero"),
                                                      new DestinationRequest(scp, MoneyRequest.CreateAllRemaining(), "zero")),
                                                  FeeStrategy.SevenDaysConfirmationTargetStrategy,
                                                  false));

            // Get some money, make it confirm.
            var txId = await rpc.SendToAddressAsync(keyManager.GetNextReceiveKey("foo", out _).GetP2wpkhAddress(network), Money.Coins(1m));

            // Generate some coins
            await rpc.GenerateAsync(2);

            try
            {
                nodes.Connect();                                                                              // Start connection service.
                node.VersionHandshake();                                                                      // Start mempool service.
                synchronizer.Start(requestInterval: TimeSpan.FromSeconds(3), TimeSpan.FromSeconds(5), 10000); // Start wasabi synchronizer service.

                // Wait until the filter our previous transaction is present.
                var blockCount = await rpc.GetBlockCountAsync();

                await Common.WaitForFiltersToBeProcessedAsync(TimeSpan.FromSeconds(120), blockCount);

                using (var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30)))
                {
                    await wallet.StartAsync(cts.Token);                     // Initialize wallet service.
                }

                // subtract Fee from amount index with no enough money
                var operations = new PaymentIntent(
                    new DestinationRequest(scp, Money.Coins(1m), subtractFee: true),
                    new DestinationRequest(scp, Money.Coins(0.5m)));
                Assert.Throws <InsufficientBalanceException>(() => wallet.BuildTransaction(password, operations, FeeStrategy.TwentyMinutesConfirmationTargetStrategy, false));

                // No enough money (only one confirmed coin, no unconfirmed allowed)
                operations = new PaymentIntent(scp, Money.Coins(1.5m));
                Assert.Throws <InsufficientBalanceException>(() => wallet.BuildTransaction(null, operations, FeeStrategy.TwentyMinutesConfirmationTargetStrategy));

                // No enough money (only one confirmed coin, unconfirmed allowed)
                Assert.Throws <InsufficientBalanceException>(() => wallet.BuildTransaction(null, operations, FeeStrategy.TwentyMinutesConfirmationTargetStrategy, true));

                // Add new money with no confirmation
                var txId2 = await rpc.SendToAddressAsync(keyManager.GetNextReceiveKey("bar", out _).GetP2wpkhAddress(network), Money.Coins(2m));

                await Task.Delay(1000);                 // Wait tx to arrive and get processed.

                // Enough money (one confirmed coin and one unconfirmed coin, unconfirmed are NOT allowed)
                Assert.Throws <InsufficientBalanceException>(() => wallet.BuildTransaction(null, operations, FeeStrategy.TwentyMinutesConfirmationTargetStrategy, false));

                // Enough money (one unconfirmed coin, unconfirmed are allowed)
                var btx       = wallet.BuildTransaction(password, operations, FeeStrategy.TwentyMinutesConfirmationTargetStrategy, true);
                var spentCoin = Assert.Single(btx.SpentCoins);
                Assert.False(spentCoin.Confirmed);

                // Enough money (one confirmed coin and one unconfirmed coin, unconfirmed are allowed)
                operations = new PaymentIntent(scp, Money.Coins(2.5m));
                btx        = wallet.BuildTransaction(password, operations, FeeStrategy.TwentyMinutesConfirmationTargetStrategy, true);
                Assert.Equal(2, btx.SpentCoins.Count());
                Assert.Equal(1, btx.SpentCoins.Count(c => c.Confirmed));
                Assert.Equal(1, btx.SpentCoins.Count(c => !c.Confirmed));

                // Only one operation with AllRemainingFlag

                Assert.Throws <ArgumentException>(() => wallet.BuildTransaction(
                                                      null,
                                                      new PaymentIntent(
                                                          new DestinationRequest(scp, MoneyRequest.CreateAllRemaining()),
                                                          new DestinationRequest(scp, MoneyRequest.CreateAllRemaining())),
                                                      FeeStrategy.TwentyMinutesConfirmationTargetStrategy));

                Logger.TurnOn();

                operations = new PaymentIntent(scp, Money.Coins(0.5m));
                btx        = wallet.BuildTransaction(password, operations, FeeStrategy.TwentyMinutesConfirmationTargetStrategy);
            }
            finally
            {
                await wallet.StopAsync(CancellationToken.None);

                // Dispose wasabi synchronizer service.
                if (synchronizer is { })
Пример #30
0
        public void Listen(ConcurrentChain chain = null)
        {
            ListenerTrace.Info($"Connecting to node {_Configuration.Indexer.Node}");
            var ip = Utils.ParseIpEndpoint(_Configuration.Indexer.Node, Configuration.Indexer.Network.DefaultPort);

            ListenerTrace.Info($"Connecting to node ip {ip.ToString()}");
            var node = Node.Connect(Configuration.Indexer.Network, ip);

            ListenerTrace.Info($"Connected, trying handshake...");
            node.VersionHandshake();
            ListenerTrace.Info($"Hanshaked");
            node.Disconnect();

            _Chain   = new ConcurrentChain(_Configuration.Indexer.Network);
            _Indexer = Configuration.Indexer.CreateIndexer();
            if (chain == null)
            {
                chain = new ConcurrentChain(_Configuration.Indexer.Network);
            }
            _Chain = chain;
            ListenerTrace.Info("Fetching headers from " + _Chain.Tip.Height + " (from azure)");
            var client = Configuration.Indexer.CreateIndexerClient();

            client.SynchronizeChain(chain);
            ListenerTrace.Info("Headers fetched tip " + _Chain.Tip.Height);

            _Disposables.Add(_IndexerScheduler = new CustomThreadPoolTaskScheduler(50, 100, "Indexing Threads"));
            _Indexer.TaskScheduler             = _IndexerScheduler;

            _Group = new NodesGroup(Configuration.Indexer.Network);
            _Disposables.Add(_Group);
            _Group.AllowSameGroup        = true;
            _Group.MaximumNodeConnection = 2;
            AddressManager addrman = new AddressManager();

            addrman.Add(new NetworkAddress(ip), IPAddress.Parse("127.0.0.1"));

            _Group.NodeConnectionParameters.TemplateBehaviors.Add(new AddressManagerBehavior(addrman)
            {
                Mode = AddressManagerBehaviorMode.None
            });
            _Group.NodeConnectionParameters.TemplateBehaviors.Add(new ChainBehavior(_Chain)
            {
                SkipPoWCheck = true
            });
            _Group.NodeConnectionParameters.TemplateBehaviors.Add(new Behavior(this));



            ListenerTrace.Info("Fetching wallet rules...");
            _Wallets = _Configuration.Indexer.CreateIndexerClient().GetAllWalletRules();
            ListenerTrace.Info("Wallet rules fetched");

            ListenerTrace.Info("Fetching wallet subscriptions...");
            _Subscriptions = new SubscriptionCollection(_Configuration.GetSubscriptionsTable().Read());
            ListenerTrace.Info("Subscriptions fetched");
            _Group.Connect();

            ListenerTrace.Info("Fetching transactions to broadcast...");

            _Disposables.Add(
                Configuration
                .Topics
                .BroadcastedTransactions
                .CreateConsumer("listener", true)
                .EnsureSubscriptionExists()
                .OnMessage((tx, ctl) =>
            {
                uint256 hash = null;
                var repo     = Configuration.Indexer.CreateIndexerClient();
                var rejects  = Configuration.GetRejectTable();
                try
                {
                    hash          = tx.Transaction.GetHash();
                    var indexedTx = repo.GetTransaction(hash);
                    ListenerTrace.Info("Broadcasting " + hash);
                    var reject = rejects.ReadOne(hash.ToString());
                    if (reject != null)
                    {
                        ListenerTrace.Info("Abort broadcasting of rejected");
                        return;
                    }

                    if (_Broadcasting.Count > 1000)
                    {
                        _Broadcasting.Clear();
                    }

                    _Broadcasting.TryAdd(hash, tx.Transaction);
                    if (indexedTx == null || !indexedTx.BlockIds.Any(id => Chain.Contains(id)))
                    {
                        var unused = SendMessageAsync(tx.Transaction);
                    }
                    var reschedule = new[]
                    {
                        TimeSpan.FromMinutes(5),
                        TimeSpan.FromMinutes(10),
                        TimeSpan.FromHours(1),
                        TimeSpan.FromHours(6),
                        TimeSpan.FromHours(24),
                    };
                    if (tx.Tried <= reschedule.Length - 1)
                    {
                        ctl.RescheduleIn(reschedule[tx.Tried]);
                        tx.Tried++;
                    }
                }
                catch (Exception ex)
                {
                    if (!_Disposed)
                    {
                        LastException = ex;
                        ListenerTrace.Error("Error for new broadcasted transaction " + hash, ex);
                        throw;
                    }
                }
            }));
            ListenerTrace.Info("Transactions to broadcast fetched");

            _Disposables.Add(_Configuration
                             .Topics
                             .SubscriptionChanges
                             .EnsureSubscriptionExists()
                             .AddUnhandledExceptionHandler(ExceptionOnMessagePump)
                             .OnMessage(c =>
            {
                using (_SubscriptionSlimLock.LockWrite())
                {
                    if (c.Added)
                    {
                        _Subscriptions.Add(c.Subscription);
                    }
                    else
                    {
                        _Subscriptions.Remove(c.Subscription.Id);
                    }
                }
            }));

            _Disposables.Add(_Configuration
                             .Topics
                             .SendNotifications
                             .AddUnhandledExceptionHandler(ExceptionOnMessagePump)
                             .OnMessageAsync((n, act) =>
            {
                return(SendAsync(n, act).ContinueWith(t =>
                {
                    if (!_Disposed)
                    {
                        if (t.Exception != null)
                        {
                            LastException = t.Exception;
                        }
                    }
                }));
            }, new OnMessageOptions()
            {
                MaxConcurrentCalls = 1000,
                AutoComplete       = true,
                AutoRenewTimeout   = TimeSpan.Zero
            }));

            _Disposables.Add(Configuration
                             .Topics
                             .AddedAddresses
                             .CreateConsumer("updater", true)
                             .EnsureSubscriptionExists()
                             .AddUnhandledExceptionHandler(ExceptionOnMessagePump)
                             .OnMessage(evt =>
            {
                if (evt == null)
                {
                    return;
                }
                ListenerTrace.Info("New wallet rule");
                using (_WalletsSlimLock.LockWrite())
                {
                    foreach (var address in evt)
                    {
                        _Wallets.Add(address.CreateWalletRuleEntry());
                    }
                }
            }));
        }