public static ColoredTransaction Get(this IColoredTransactionRepository repo, uint256 txId) { try { return(repo.GetAsync(txId).Result); } catch (AggregateException aex) { ExceptionDispatchInfo.Capture(aex.InnerException).Throw(); return(null); } }
public async Task <ColoredTransaction> GetAsync(uint256 txId) { ColoredTransaction result = null; bool found; using (@lock.LockRead()) { found = _ColoredTransactions.TryGetValue(txId, out result); } if (!found) { result = await _Inner.GetAsync(txId).ConfigureAwait(false); using (@lock.LockWrite()) { _ColoredTransactions.AddOrReplace(txId, result); } } return(result); }
public static Task <ColoredTransaction> GetAsync(this IColoredTransactionRepository repo, string txId) { return(repo.GetAsync(uint256.Parse(txId))); }
public static async Task<ColoredTransaction> FetchColorsAsync(uint256 txId, Transaction tx, IColoredTransactionRepository repo) { if(repo == null) throw new ArgumentNullException("repo"); if(txId == null) { if(tx == null) throw new ArgumentException("txId or tx should be different of null"); txId = tx.GetHash(); } //The following code is to prevent recursion of FetchColors that would fire a StackOverflow if the origin of traded asset were deep in the transaction dependency tree var colored = await repo.GetAsync(txId).ConfigureAwait(false); if(colored != null) return colored; Stack<ColoredFrame> frames = new Stack<ColoredFrame>(); Stack<ColoredTransaction> coloreds = new Stack<ColoredTransaction>(); frames.Push(new ColoredFrame() { TransactionId = txId, Transaction = tx }); while(frames.Count != 0) { var frame = frames.Pop(); colored = frame.PreviousTransactions != null ? null : await repo.GetAsync(frame.TransactionId).ConfigureAwait(false); //Already known if(colored != null) { coloreds.Push(colored); continue; } frame.Transaction = frame.Transaction ?? await repo.Transactions.GetAsync(frame.TransactionId).ConfigureAwait(false); if(frame.Transaction == null) throw new TransactionNotFoundException("Transaction " + frame.TransactionId + " not found in transaction repository", frame.TransactionId); if(frame.PreviousTransactions == null) { if(!frame.Transaction.HasValidColoredMarker() && frame.TransactionId != txId) //We care about destroyed asset, if this is the requested transaction { coloreds.Push(new ColoredTransaction()); continue; } frame.PreviousTransactions = new ColoredTransaction[frame.Transaction.Inputs.Count]; await BulkLoadIfCached(frame.Transaction, repo).ConfigureAwait(false); frames.Push(frame); for(int i = 0 ; i < frame.Transaction.Inputs.Count ; i++) { frames.Push(new ColoredFrame() { TransactionId = frame.Transaction.Inputs[i].PrevOut.Hash }); } frame.Transaction = frame.TransactionId == txId ? frame.Transaction : null; //Do not waste memory, will refetch later continue; } else { for(int i = 0 ; i < frame.Transaction.Inputs.Count ; i++) { frame.PreviousTransactions[i] = coloreds.Pop(); } } Script issuanceScriptPubkey = null; if(HasIssuance(frame.Transaction)) { var txIn = frame.Transaction.Inputs[0]; var previous = await repo.Transactions.GetAsync(txIn.PrevOut.Hash).ConfigureAwait(false); if(previous == null) { throw new TransactionNotFoundException("An open asset transaction is issuing assets, but it needs a parent transaction in the TransactionRepository to know the address of the issued asset (missing : " + txIn.PrevOut.Hash + ")", txIn.PrevOut.Hash); } if(txIn.PrevOut.N < previous.Outputs.Count) issuanceScriptPubkey = previous.Outputs[txIn.PrevOut.N].ScriptPubKey; } List<ColoredCoin> spentCoins = new List<ColoredCoin>(); for(int i = 0 ; i < frame.Transaction.Inputs.Count ; i++) { var txIn = frame.Transaction.Inputs[i]; var entry = frame.PreviousTransactions[i].GetColoredEntry(txIn.PrevOut.N); if(entry != null) spentCoins.Add(new ColoredCoin(entry.Asset, new Coin(txIn.PrevOut, new TxOut()))); } colored = new ColoredTransaction(frame.TransactionId, frame.Transaction, spentCoins.ToArray(), issuanceScriptPubkey); coloreds.Push(colored); await repo.PutAsync(frame.TransactionId, colored).ConfigureAwait(false); } if(coloreds.Count != 1) throw new InvalidOperationException("Colored stack length != 1, this is a NBitcoin bug, please contact us."); return coloreds.Pop(); }
public static async Task <ColoredTransaction> FetchColorsAsync(uint256 txId, Transaction tx, IColoredTransactionRepository repo) { if (repo == null) { throw new ArgumentNullException("repo"); } if (txId == null) { if (tx == null) { throw new ArgumentException("txId or tx should be different of null"); } txId = tx.GetHash(); } //The following code is to prevent recursion of FetchColors that would fire a StackOverflow if the origin of traded asset were deep in the transaction dependency tree var colored = await repo.GetAsync(txId).ConfigureAwait(false); if (colored != null) { return(colored); } Stack <ColoredFrame> frames = new Stack <ColoredFrame>(); Stack <ColoredTransaction> coloreds = new Stack <ColoredTransaction>(); frames.Push(new ColoredFrame() { TransactionId = txId, Transaction = tx }); while (frames.Count != 0) { var frame = frames.Pop(); colored = frame.PreviousTransactions != null ? null : await repo.GetAsync(frame.TransactionId).ConfigureAwait(false); //Already known if (colored != null) { coloreds.Push(colored); continue; } frame.Transaction = frame.Transaction ?? await repo.Transactions.GetAsync(frame.TransactionId).ConfigureAwait(false); if (frame.Transaction == null) { throw new TransactionNotFoundException("Transaction " + frame.TransactionId + " not found in transaction repository", frame.TransactionId); } if (frame.PreviousTransactions == null) { if (frame.Transaction.IsCoinBase || (!frame.Transaction.HasValidColoredMarker() && frame.TransactionId != txId)) //We care about destroyed asset, if this is the requested transaction { coloreds.Push(new ColoredTransaction()); continue; } frame.PreviousTransactions = new ColoredTransaction[frame.Transaction.Inputs.Count]; await BulkLoadIfCached(frame.Transaction, repo).ConfigureAwait(false); frames.Push(frame); for (int i = 0; i < frame.Transaction.Inputs.Count; i++) { frames.Push(new ColoredFrame() { TransactionId = frame.Transaction.Inputs[i].PrevOut.Hash }); } frame.Transaction = frame.TransactionId == txId ? frame.Transaction : null; //Do not waste memory, will refetch later continue; } else { for (int i = 0; i < frame.Transaction.Inputs.Count; i++) { frame.PreviousTransactions[i] = coloreds.Pop(); } } Script issuanceScriptPubkey = null; if (HasIssuance(frame.Transaction)) { var txIn = frame.Transaction.Inputs[0]; var previous = await repo.Transactions.GetAsync(txIn.PrevOut.Hash).ConfigureAwait(false); if (previous == null) { throw new TransactionNotFoundException("An open asset transaction is issuing assets, but it needs a parent transaction in the TransactionRepository to know the address of the issued asset (missing : " + txIn.PrevOut.Hash + ")", txIn.PrevOut.Hash); } if (txIn.PrevOut.N < previous.Outputs.Count) { issuanceScriptPubkey = previous.Outputs[txIn.PrevOut.N].ScriptPubKey; } } List <ColoredCoin> spentCoins = new List <ColoredCoin>(); for (int i = 0; i < frame.Transaction.Inputs.Count; i++) { var txIn = frame.Transaction.Inputs[i]; var entry = frame.PreviousTransactions[i].GetColoredEntry(txIn.PrevOut.N); if (entry != null) { spentCoins.Add(new ColoredCoin(entry.Asset, new Coin(txIn.PrevOut, new TxOut()))); } } colored = new ColoredTransaction(frame.TransactionId, frame.Transaction, spentCoins.ToArray(), issuanceScriptPubkey); coloreds.Push(colored); await repo.PutAsync(frame.TransactionId, colored).ConfigureAwait(false); } if (coloreds.Count != 1) { throw new InvalidOperationException("Colored stack length != 1, this is a NBitcoin bug, please contact us."); } return(coloreds.Pop()); }
public static ColoredTransaction Get(this IColoredTransactionRepository repo, uint256 txId) { return(repo.GetAsync(txId).GetAwaiter().GetResult()); }
public Task <ColoredTransaction> GetAsync(uint256 txId) { return(Request("c" + txId.ToString(), () => _Inner.GetAsync(txId))); }
public static async Task<ColoredTransaction> FetchColorsAsync(uint256 txId, Transaction tx, IColoredTransactionRepository repo) { if(repo == null) throw new ArgumentNullException("repo"); repo = EnsureCachedRepository(repo); ColoredTransaction result = null; if(txId != null) { result = await repo.GetAsync(txId).ConfigureAwait(false); } else { if(tx == null) throw new ArgumentException("txId or tx should be different of null"); txId = tx.GetHash(); result = await repo.GetAsync(txId).ConfigureAwait(false); } if(result != null) return result; if(tx == null) { tx = await repo.Transactions.GetAsync(txId).ConfigureAwait(false); if(tx == null) throw new TransactionNotFoundException("Transaction " + txId + " not found in transaction repository", txId); } ColoredTransaction lastColored = null; //The following code is to prevent recursion of FetchColors that would fire a StackOverflow if the origin of traded asset were deep in the transaction dependency tree HashSet<uint256> invalidColored = new HashSet<uint256>(); Stack<Tuple<uint256, Transaction>> ancestors = new Stack<Tuple<uint256, Transaction>>(); ancestors.Push(Tuple.Create(txId, tx)); while(ancestors.Count != 0) { var peek = ancestors.Peek(); txId = peek.Item1; tx = peek.Item2; bool isComplete = true; if(!tx.HasValidColoredMarker() && ancestors.Count != 1) { invalidColored.Add(txId); ancestors.Pop(); continue; } var parentsToResolve = Enumerable .Range(0, tx.Inputs.Count) .Select(async i => { var txin = tx.Inputs[i]; var color = await repo.GetAsync(txin.PrevOut.Hash).ConfigureAwait(false); if(color == null && !invalidColored.Contains(txin.PrevOut.Hash)) { var prevTx = await repo.Transactions.GetAsync(txin.PrevOut.Hash).ConfigureAwait(false); if(prevTx == null) throw new TransactionNotFoundException("Transaction " + txin.PrevOut.Hash + " not found in transaction repository", txId); return Tuple.Create(txin.PrevOut.Hash, prevTx); } return null; }).ToArray(); foreach(var parent in parentsToResolve) { var toResolve = await parent.ConfigureAwait(false); if(toResolve != null) { ancestors.Push(toResolve); isComplete = false; } } if(isComplete) { lastColored = await FetchColorsWithAncestorsSolved(txId, tx, (CachedColoredTransactionRepository)repo).ConfigureAwait(false); await repo.PutAsync(txId, lastColored).ConfigureAwait(false); ancestors.Pop(); } } return lastColored; }
public static async Task <ColoredTransaction> FetchColorsAsync(uint256 txId, Transaction tx, IColoredTransactionRepository repo) { if (repo == null) { throw new ArgumentNullException("repo"); } repo = EnsureCachedRepository(repo); ColoredTransaction result = null; if (txId != null) { result = await repo.GetAsync(txId).ConfigureAwait(false); } else { if (tx == null) { throw new ArgumentException("txId or tx should be different of null"); } txId = tx.GetHash(); result = await repo.GetAsync(txId).ConfigureAwait(false); } if (result != null) { return(result); } if (tx == null) { tx = await repo.Transactions.GetAsync(txId).ConfigureAwait(false); if (tx == null) { throw new TransactionNotFoundException("Transaction " + txId + " not found in transaction repository", txId); } } ColoredTransaction lastColored = null; //The following code is to prevent recursion of FetchColors that would fire a StackOverflow if the origin of traded asset were deep in the transaction dependency tree HashSet <uint256> invalidColored = new HashSet <uint256>(); Stack <Tuple <uint256, Transaction> > ancestors = new Stack <Tuple <uint256, Transaction> >(); ancestors.Push(Tuple.Create(txId, tx)); while (ancestors.Count != 0) { var peek = ancestors.Peek(); txId = peek.Item1; tx = peek.Item2; bool isComplete = true; if (!tx.HasValidColoredMarker() && ancestors.Count != 1) { invalidColored.Add(txId); ancestors.Pop(); continue; } var parentsToResolve = Enumerable .Range(0, tx.Inputs.Count) .Select(async i => { var txin = tx.Inputs[i]; var color = await repo.GetAsync(txin.PrevOut.Hash).ConfigureAwait(false); if (color == null && !invalidColored.Contains(txin.PrevOut.Hash)) { var prevTx = await repo.Transactions.GetAsync(txin.PrevOut.Hash).ConfigureAwait(false); if (prevTx == null) { throw new TransactionNotFoundException("Transaction " + txin.PrevOut.Hash + " not found in transaction repository", txId); } return(Tuple.Create(txin.PrevOut.Hash, prevTx)); } return(null); }).ToArray(); foreach (var parent in parentsToResolve) { var toResolve = await parent.ConfigureAwait(false); if (toResolve != null) { ancestors.Push(toResolve); isComplete = false; } } if (isComplete) { lastColored = await FetchColorsWithAncestorsSolved(txId, tx, (CachedColoredTransactionRepository)repo).ConfigureAwait(false); await repo.PutAsync(txId, lastColored).ConfigureAwait(false); ancestors.Pop(); } } return(lastColored); }