Beispiel #1
0
        List <TransactionInformationMatch> ToMatch(AnnotatedTransactionCollection txs,
                                                   List <TxOut> outputs,
                                                   DerivationStrategyBase derivation,
                                                   Repository.TransactionMiniKeyInformation[] keyInformations)
        {
            var result = new List <TransactionInformationMatch>();

            for (int i = 0; i < outputs.Count; i++)
            {
                if (outputs[i] == null)
                {
                    continue;
                }
                var keyPath = txs.GetKeyPath(outputs[i].ScriptPubKey);
                if (keyPath == null)
                {
                    continue;
                }

                result.Add(new TransactionInformationMatch()
                {
                    Index = i, KeyPath = keyPath, Value = outputs[i].Value
                });
            }
            return(result);
        }
        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;
            }
        }
Beispiel #3
0
        private AnnotatedTransactionCollection GetAnnotatedTransactions(Repository repo, ConcurrentChain chain, DerivationStrategyBase extPubKey)
        {
            var annotatedTransactions = new AnnotatedTransactionCollection(repo
                                                                           .GetTransactions(extPubKey)
                                                                           .Select(t => new AnnotatedTransaction(t, chain))
                                                                           .ToList());

            CleanConflicts(repo, extPubKey, annotatedTransactions);
            return(annotatedTransactions);
        }
Beispiel #4
0
 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;
     }
 }
Beispiel #5
0
        List <TransactionInformationMatch> ToMatch(AnnotatedTransactionCollection txs,
                                                   List <TxOut> outputs,
                                                   TrackedSource derivation)
        {
            var result = new List <TransactionInformationMatch>();

            for (int i = 0; i < outputs.Count; i++)
            {
                if (outputs[i] == null)
                {
                    continue;
                }
                if (!IsMatching(derivation, outputs[i].ScriptPubKey, txs))
                {
                    continue;
                }
                var keyPath = txs.GetKeyPath(outputs[i].ScriptPubKey);
                result.Add(new TransactionInformationMatch()
                {
                    Index = i, KeyPath = keyPath, Value = outputs[i].Value
                });
            }
            return(result);
        }
Beispiel #6
0
        private void CleanConflicts(Repository repo, DerivationStrategyBase extPubKey, AnnotatedTransactionCollection transactions)
        {
            var cleaned = transactions.DuplicatedTransactions.Where(c => (DateTimeOffset.UtcNow - c.Record.Inserted) > TimeSpan.FromDays(1.0)).Select(c => c.Record).ToArray();

            if (cleaned.Length != 0)
            {
                foreach (var tx in cleaned)
                {
                    _EventAggregator.Publish(new EvictedTransactionEvent(tx.Transaction.GetHash()));
                }
                repo.CleanTransactions(extPubKey, cleaned.ToList());
            }
        }
Beispiel #7
0
        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;
            }
        }