public async Task <UTXOChanges> GetUTXOs( string cryptoCode, [ModelBinder(BinderType = typeof(DestinationModelBinder))] DerivationStrategyBase extPubKey, [ModelBinder(BinderType = typeof(BookmarksModelBinding))] HashSet <Bookmark> confirmedBookmarks = null, [ModelBinder(BinderType = typeof(BookmarksModelBinding))] HashSet <Bookmark> unconfirmedBookmarks = null, bool longPolling = false) { unconfirmedBookmarks = unconfirmedBookmarks ?? new HashSet <Bookmark>(); confirmedBookmarks = confirmedBookmarks ?? new HashSet <Bookmark>(); if (extPubKey == null) { throw new ArgumentNullException(nameof(extPubKey)); } var network = GetNetwork(cryptoCode); var chain = ChainProvider.GetChain(network); var repo = RepositoryProvider.GetRepository(network); var waitingTransaction = longPolling ? WaitingTransaction(extPubKey) : Task.FromResult(false); UTXOChanges changes = null; while (true) { changes = new UTXOChanges(); changes.CurrentHeight = chain.Height; var transactions = GetAnnotatedTransactions(repo, chain, extPubKey); Func <Script[], bool[]> matchScript = (scripts) => scripts.Select(s => transactions.GetKeyPath(s) != null).ToArray(); var states = UTXOStateResult.CreateStates(matchScript, unconfirmedBookmarks, transactions.UnconfirmedTransactions.Values.Select(c => c.Record.Transaction), confirmedBookmarks, transactions.ConfirmedTransactions.Values.Select(c => c.Record.Transaction)); changes.Confirmed = SetUTXOChange(states.Confirmed); changes.Unconfirmed = SetUTXOChange(states.Unconfirmed, states.Confirmed.Actual); FillUTXOsInformation(changes.Confirmed.UTXOs, transactions, changes.CurrentHeight); FillUTXOsInformation(changes.Unconfirmed.UTXOs, transactions, changes.CurrentHeight); if (changes.HasChanges || !(await waitingTransaction)) { break; } waitingTransaction = Task.FromResult(false); //next time, will not wait } changes.DerivationStrategy = extPubKey; return(changes); }
public async Task <FileContentResult> Sync( [ModelBinder(BinderType = typeof(DestinationModelBinder))] DerivationStrategyBase extPubKey, [ModelBinder(BinderType = typeof(UInt256ModelBinding))] uint256 confHash = null, [ModelBinder(BinderType = typeof(UInt256ModelBinding))] uint256 unconfHash = null, bool noWait = false) { if (extPubKey == null) { throw new ArgumentNullException(nameof(extPubKey)); } var waitingTransaction = noWait ? Task.FromResult(false) : WaitingTransaction(extPubKey); UTXOChanges changes = null; var getKeyPaths = GetKeyPaths(extPubKey); var matchScript = MatchKeyPaths(getKeyPaths); while (true) { changes = new UTXOChanges(); changes.CurrentHeight = Chain.Height; var transactions = GetAnnotatedTransactions(extPubKey); var unconf = transactions.Where(tx => tx.Height == MempoolHeight); var conf = transactions.Where(tx => tx.Height != MempoolHeight); conf = conf.TopologicalSort(DependsOn(conf.ToList())).ToList(); unconf = unconf.OrderByDescending(t => t.Record.Inserted) .TopologicalSort(DependsOn(unconf.ToList())).ToList(); var states = UTXOStateResult.CreateStates(matchScript, unconfHash, unconf.Select(c => c.Record.Transaction), confHash, conf.Select(c => c.Record.Transaction)); var conflicted = states.Unconfirmed.Actual.Conflicts .SelectMany(c => c.Value) .SelectMany(txid => transactions.GetByTxId(txid)) .Where(a => a.Height == MempoolHeight) .Select(a => a.Record) .Distinct() .ToList(); if (conflicted.Count != 0) { Logs.Explorer.LogInformation($"Clean {conflicted.Count} conflicted transactions"); if (Logs.Explorer.IsEnabled(LogLevel.Debug)) { foreach (var conflict in conflicted) { Logs.Explorer.LogDebug($"Transaction {conflict.Transaction.GetHash()} is conflicted"); } } Repository.CleanTransactions(extPubKey, conflicted); } changes.Confirmed = SetUTXOChange(states.Confirmed); changes.Unconfirmed = SetUTXOChange(states.Unconfirmed, states.Confirmed.Actual); FillUTXOsInformation(changes.Confirmed.UTXOs, getKeyPaths, transactions, changes.CurrentHeight); FillUTXOsInformation(changes.Unconfirmed.UTXOs, getKeyPaths, transactions, changes.CurrentHeight); if (changes.HasChanges || !(await waitingTransaction)) { break; } waitingTransaction = Task.FromResult(false); //next time, will not wait } return(new FileContentResult(changes.ToBytes(), "application/octet-stream")); }