Example #1
0
 public static async Task <ColoredTransaction> GetColoredTransactionAsync(this Transaction tx, IColoredTransactionRepository repo)
 {
     try
     {
         return(await ColoredTransaction.FetchColorsAsync(tx, repo).ConfigureAwait(false));
     }
     catch (TransactionNotFoundException)
     {
         return(null);
     }
 }
Example #2
0
 public Task PutAsync(uint256 txId, ColoredTransaction tx)
 {
     if (WriteThrough)
     {
         using (_lock.LockWrite())
         {
             if (!_ColoredTransactions.ContainsKey(txId))
             {
                 _ColoredTransactions.AddOrReplace(txId, tx);
                 EvictIfNecessary(txId);
             }
             else
             {
                 _ColoredTransactions[txId] = tx;
             }
         }
     }
     return(_Inner.PutAsync(txId, tx));
 }
Example #3
0
        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);

                if (ReadThrough)
                {
                    using (_lock.LockWrite())
                    {
                        _ColoredTransactions.AddOrReplace(txId, result);
                        EvictIfNecessary(txId);
                    }
                }
            }
            return(result);
        }
Example #4
0
 public Task PutAsync(uint256 txId, ColoredTransaction tx)
 {
     return(_Repository.PutAsync(GetId(txId), tx));
 }
 public static void Put(this IColoredTransactionRepository repo, uint256 txId, ColoredTransaction tx)
 {
     repo.PutAsync(txId, tx).GetAwaiter().GetResult();
 }
 public Task PutAsync(uint256 txId, ColoredTransaction tx)
 {
     return(_Inner.PutAsync(txId, tx));
 }
 public Task PutAsync(uint256 txId, ColoredTransaction tx)
 {
     return(Task.FromResult <bool>(true));
 }
Example #8
0
        public static async Task <ColoredTransaction> FetchColorsAsync(uint256 txId, Transaction tx, IColoredTransactionRepository repo)
        {
            if (repo == null)
            {
                throw new ArgumentNullException(nameof(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 Bitcoin3 bug, please contact us.");
            }
            return(coloreds.Pop());
        }