public WalletJob(Safe safeToTrack, HttpClientHandler handler = null, bool trackDefaultSafe = true, params SafeAccount[] accountsToTrack) { _creationHeight = Height.Unknown; _tracker = null; Safe = safeToTrack; CurrentNetwork = safeToTrack.Network; MemPoolJob.Enabled = false; _qBitClient = new QBitNinjaClient(safeToTrack.Network); _httpClient = new HttpClient(); if (handler != null) { _qBitClient.SetHttpMessageHandler(handler); _httpClient = new HttpClient(handler); } if (accountsToTrack == null || !accountsToTrack.Any()) { SafeAccounts = new ConcurrentHashSet <SafeAccount>(); } else { SafeAccounts = new ConcurrentHashSet <SafeAccount>(accountsToTrack); } TracksDefaultSafe = trackDefaultSafe; State = WalletState.NotStarted; Directory.CreateDirectory(WorkFolderPath); Tracker.TrackedTransactions.CollectionChanged += delegate { UpdateSafeTracking(); }; _connectionParameters = new NodeConnectionParameters(); //So we find nodes faster _connectionParameters.TemplateBehaviors.Add(new AddressManagerBehavior(AddressManager)); //So we don't have to load the chain each time we start _connectionParameters.TemplateBehaviors.Add(new ChainBehavior(HeaderChain)); UpdateSafeTracking(); Nodes = new NodesGroup(Safe.Network, _connectionParameters, new NodeRequirement { RequiredServices = NodeServices.Network, MinVersion = ProtocolVersion.SENDHEADERS_VERSION }); var bp = new NodesBlockPuller(HeaderChain, Nodes.ConnectedNodes); _connectionParameters.TemplateBehaviors.Add(new NodesBlockPuller.NodesBlockPullerBehavior(bp)); Nodes.NodeConnectionParameters = _connectionParameters; BlockPuller = (LookaheadBlockPuller)bp; MemPoolJob.Synced += delegate { State = WalletState.Synced; var trackedMemPoolTransactions = Tracker.TrackedTransactions.Where(x => x.Height == Height.MemPool); foreach (var tx in trackedMemPoolTransactions) { // If we are tracking a tx that is malleated or fall out of mempool (too long to confirm) then stop tracking if (!MemPoolJob.Transactions.Contains(tx.GetHash())) { Tracker.TrackedTransactions.TryRemove(tx); Debug.WriteLine($"Transaction fall out of MemPool: {tx.GetHash()}"); } } Debug.WriteLine("MemPool updated"); }; MemPoolJob.NewTransaction += MemPoolJob_NewTransaction; Nodes.ConnectedNodes.Removed += delegate { OnConnectedNodeCountChanged(); }; Nodes.ConnectedNodes.Added += delegate { OnConnectedNodeCountChanged(); }; Tracker.BestHeightChanged += delegate { OnBestHeightChanged(); }; }
public static void Main(string[] args) { Directory.CreateDirectory(SpvFolderPath); // TestNet addresses, first time used //var a1 = BitcoinAddress.Create("2Mz3BiReit6sNrSh9EMuhwUnhtqf2B35HpN"); // testnet, 1088037 //var a2 = BitcoinAddress.Create("mwiSUHLGngZd849Sz3TE6kRb7fHjJCuwKe"); // testnet, 1088031 //var a3 = BitcoinAddress.Create("muE3Z5Lhdk3WerqVevH49htmV96HJu4RLJ"); // testnet, 1088031 //LocalPartialChain.Track(a1.ScriptPubKey); //LocalPartialChain.Track(a2.ScriptPubKey); //LocalPartialChain.Track(a3.ScriptPubKey); //Console.WriteLine($"Tracking {a1}"); //Console.WriteLine($"Tracking {a2}"); //Console.WriteLine($"Tracking {a3}"); _connectionParameters = new NodeConnectionParameters(); //So we find nodes faster _connectionParameters.TemplateBehaviors.Add(new AddressManagerBehavior(AddressManager)); //So we don't have to load the chain each time we start _connectionParameters.TemplateBehaviors.Add(new ChainBehavior(LocalSpvChain)); _nodes = new NodesGroup(Network, _connectionParameters, new NodeRequirement { RequiredServices = NodeServices.Network, MinVersion = ProtocolVersion.SENDHEADERS_VERSION }); var bp = new NodesBlockPuller(LocalSpvChain, _nodes.ConnectedNodes); _connectionParameters.TemplateBehaviors.Add(new NodesBlockPuller.NodesBlockPullerBehavior(bp)); _nodes.NodeConnectionParameters = _connectionParameters; BlockPuller = (LookaheadBlockPuller)bp; MemPoolJob memPool = new MemPoolJob(_nodes, LocalPartialChain); Console.WriteLine("Start connecting to nodes..."); _nodes.Connect(); CancellationTokenSource cts = new CancellationTokenSource(); var t1 = ReportConnectedNodeCountAsync(cts.Token); var t2 = ReportHeightAsync(cts.Token); var t3 = PeriodicSaveAsync(TimeSpan.FromMinutes(3), cts.Token); var t4 = BlockPullerJobAsync(cts.Token); //var t5 = ReportTransactionsWhenAllBlocksDownAsync(cts.Token); var t6 = memPool.StartAsync(cts.Token); var t7 = ReportMemPoolStateAsync(memPool, cts.Token); //ReportTransactions(); Console.WriteLine("Press a key to exit..."); Console.ReadKey(); Console.WriteLine("Exiting..."); cts.Cancel(); Task.WhenAll(t1, t2, t3, t4, t6, t7).Wait(); //, t5, t6).Wait(); SaveAllAsync().Wait(); _nodes.Dispose(); }