private async Task UpdateUTXO(UpdatePSBTRequest update, Repository repo, BitcoinDWaiter rpc) { AnnotatedTransactionCollection txs = null; // First, we check for data in our history foreach (var input in update.PSBT.Inputs.Where(NeedUTXO)) { txs = txs ?? await GetAnnotatedTransactions(repo, ChainProvider.GetChain(repo.Network), new DerivationSchemeTrackedSource(update.DerivationScheme)); if (txs.GetByTxId(input.PrevOut.Hash) is AnnotatedTransaction tx) { if (!tx.Record.Key.IsPruned) { input.NonWitnessUtxo = tx.Record.Transaction; } else { input.WitnessUtxo = tx.Record.ReceivedCoins.FirstOrDefault(c => c.Outpoint.N == input.Index)?.TxOut; } } } // then, we search data in the saved transactions await Task.WhenAll(update.PSBT.Inputs .Where(NeedUTXO) .Select(async(input) => { // If this is not segwit, or we are unsure of it, let's try to grab from our saved transactions if (input.NonWitnessUtxo == null) { var prev = await repo.GetSavedTransactions(input.PrevOut.Hash); if (prev.FirstOrDefault() is Repository.SavedTransaction saved) { input.NonWitnessUtxo = saved.Transaction; } } }).ToArray()); // finally, we check with rpc's txindex if (rpc?.RPCAvailable is true && rpc?.HasTxIndex is true) { var batch = rpc.RPC.PrepareBatch(); var getTransactions = Task.WhenAll(update.PSBT.Inputs .Where(NeedUTXO) .Where(input => input.NonWitnessUtxo == null) .Select(async input => { var tx = await batch.GetRawTransactionAsync(input.PrevOut.Hash, false); if (tx != null) { input.NonWitnessUtxo = tx; } }).ToArray()); await batch.SendBatchAsync(); await getTransactions; } }
private void FillUTXOsInformation(List <UTXO> utxos, AnnotatedTransactionCollection transactions, int currentHeight) { for (int i = 0; i < utxos.Count; i++) { var utxo = utxos[i]; utxo.KeyPath = transactions.GetKeyPath(utxo.ScriptPubKey); utxo.Feature = DerivationStrategyBase.GetFeature(utxo.KeyPath); var txHeight = transactions.GetByTxId(utxo.Outpoint.Hash) .Select(t => t.Height) .Where(h => h.HasValue) .Select(t => t.Value) .Concat(MaxValue) .Min(); var firstSeen = transactions .GetByTxId(utxo.Outpoint.Hash) .Select(o => o.Record.FirstSeen) .FirstOrDefault(); var isUnconf = txHeight == MaxValue[0]; utxo.Confirmations = isUnconf ? 0 : currentHeight - txHeight + 1; utxo.Timestamp = firstSeen; } }
private void FillUTXOsInformation(List <UTXO> utxos, Func <Script[], KeyPath[]> getKeyPaths, AnnotatedTransactionCollection transactionsById, int currentHeight) { var keyPaths = getKeyPaths(utxos.Select(u => u.Output.ScriptPubKey).ToArray()); for (int i = 0; i < utxos.Count; i++) { var utxo = utxos[i]; utxo.KeyPath = keyPaths[i]; var txHeight = transactionsById.GetByTxId(utxo.Outpoint.Hash).Select(r => r.Height).Min(); txHeight = txHeight == MempoolHeight ? currentHeight + 1 : txHeight; utxo.Confirmations = currentHeight - txHeight + 1; } }