コード例 #1
0
        public async Task <bool> EnsureColoredTransactionLoadedAsync(IColoredTransactionRepository repository)
        {
            if (ColoredTransaction != null)
            {
                this.UpdateToColoredCoins();
                return(true);
            }
            if (!(repository is CachedColoredTransactionRepository))
            {
                repository = new CachedColoredTransactionRepository(repository);
            }
            var tx = await repository.Transactions.GetAsync(TransactionId).ConfigureAwait(false);

            if (tx == null)
            {
                return(false);
            }
            try
            {
                var color = await tx.GetColoredTransactionAsync(repository).ConfigureAwait(false);

                if (color == null)
                {
                    return(false);
                }
                ColoredTransaction = color;
                this.UpdateToColoredCoins();
                return(true);
            }
            catch (TransactionNotFoundException)
            {
                return(false);
            }
        }
コード例 #2
0
		public CachedColoredTransactionRepository(IColoredTransactionRepository inner)
		{
			if(inner == null)
				throw new ArgumentNullException("inner");
			_Inner = inner;
			_InnerTransactionRepository = new CachedTransactionRepository(inner.Transactions);
		}
コード例 #3
0
        private static async Task <bool> BulkLoadIfCached(Transaction transaction, IColoredTransactionRepository repo)
        {
            if (!(repo is CachedColoredTransactionRepository))
            {
                return(false);
            }
            var hasIssuance = HasIssuance(transaction);

            repo = new NoDuplicateColoredTransactionRepository(repo); //prevent from having concurrent request to the same transaction id
            var all = Enumerable
                      .Range(0, transaction.Inputs.Count)
                      .Select(async i =>
            {
                var txId   = transaction.Inputs[i].PrevOut.Hash;
                var result = await repo.GetAsync(txId).ConfigureAwait(false);
                if (result == null || (i == 0 && hasIssuance))
                {
                    await repo.Transactions.GetAsync(txId).ConfigureAwait(false);
                }
            })
                      .ToArray();
            await Task.WhenAll(all).ConfigureAwait(false);

            return(true);
        }
コード例 #4
0
 public NoDuplicateColoredTransactionRepository(IColoredTransactionRepository inner)
 {
     if (inner == null)
     {
         throw new ArgumentNullException("inner");
     }
     _Inner = inner;
 }
コード例 #5
0
 public CachedColoredTransactionRepository(IColoredTransactionRepository inner)
 {
     if (inner == null)
     {
         throw new ArgumentNullException("inner");
     }
     _Inner = inner;
     _InnerTransactionRepository = new CachedTransactionRepository(inner.Transactions);
 }
コード例 #6
0
 private static IColoredTransactionRepository EnsureCachedRepository(IColoredTransactionRepository repo)
 {
     if (repo is CachedColoredTransactionRepository)
     {
         return(repo);
     }
     repo = new CachedColoredTransactionRepository(repo);
     return(repo);
 }
コード例 #7
0
 public CachedColoredTransactionRepository(IColoredTransactionRepository inner)
 {
     if (inner == null)
     {
         throw new ArgumentNullException("inner");
     }
     this._Inner                = inner;
     this.Transactions          = new CachedTransactionRepository(inner.Transactions);
     this.MaxCachedTransactions = 1000;
 }
コード例 #8
0
ファイル: Coin.cs プロジェクト: SerafinTech/NBitcoin
        public static IEnumerable <ColoredCoin> Find(uint256 txId, Transaction tx, IColoredTransactionRepository repo)
        {
            if (txId == null)
            {
                txId = tx.GetHash();
            }
            var colored = tx.GetColoredTransaction(repo);

            return(Find(txId, tx, colored));
        }
コード例 #9
0
ファイル: Extensions.cs プロジェクト: woutersmit/NBitcoin
		public static async Task<ColoredTransaction> GetColoredTransactionAsync(this Transaction tx, IColoredTransactionRepository repo)
		{
			try
			{
				return await ColoredTransaction.FetchColorsAsync(tx, repo).ConfigureAwait(false);
			}
			catch(TransactionNotFoundException)
			{
				return null;
			}
		}
コード例 #10
0
        public static ColoredTransaction FetchColors(uint256 txId, Transaction tx, IColoredTransactionRepository repo)
        {
            txId = txId ?? tx.GetHash();
            var result = repo.Get(txId);

            if (result != null)
            {
                return(result);
            }

            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
            repo = EnsureCachedRepository(repo);
            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;
                }

                for (int i = 0; i < tx.Inputs.Count; i++)
                {
                    var txin = tx.Inputs[i];
                    if (repo.Get(txin.PrevOut.Hash) == null && !invalidColored.Contains(txin.PrevOut.Hash))
                    {
                        var prevTx = repo.Transactions.Get(txin.PrevOut.Hash);
                        if (prevTx == null)
                        {
                            throw new TransactionNotFoundException("Transaction " + txin.PrevOut.Hash + " not found in transaction repository", txId);
                        }
                        ancestors.Push(Tuple.Create(txin.PrevOut.Hash, prevTx));
                        isComplete = false;
                    }
                }
                if (isComplete)
                {
                    lastColored = FetchColorsWithAncestorsSolved(txId, tx, repo);
                    ancestors.Pop();
                }
            }

            return(lastColored);
        }
コード例 #11
0
 public static void Put(this IColoredTransactionRepository repo, uint256 txId, ColoredTransaction tx)
 {
     try
     {
         repo.PutAsync(txId, tx).Wait();
     }
     catch (AggregateException aex)
     {
         ExceptionDispatchInfo.Capture(aex.InnerException).Throw();
     }
 }
コード例 #12
0
ファイル: Extensions.cs プロジェクト: woutersmit/NBitcoin
		public static ColoredTransaction GetColoredTransaction(this Transaction tx, IColoredTransactionRepository repo)
		{
			try
			{
				return tx.GetColoredTransactionAsync(repo).Result;
			}
			catch(AggregateException aex)
			{
				ExceptionDispatchInfo.Capture(aex.InnerException).Throw();
				return null;
			}
		}
コード例 #13
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);
     }
 }
コード例 #14
0
 public static ColoredTransaction FetchColors(uint256 txId, Transaction tx, IColoredTransactionRepository repo)
 {
     try
     {
         return(FetchColorsAsync(txId, tx, repo).Result);
     }
     catch (AggregateException aex)
     {
         ExceptionDispatchInfo.Capture(aex.InnerException).Throw();
         return(null);
     }
 }
コード例 #15
0
 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);
     }
 }
コード例 #16
0
ファイル: Extensions.cs プロジェクト: PlumpMath/LushCoin
 public static ColoredTransaction GetColoredTransaction(this Transaction tx, IColoredTransactionRepository repo)
 {
     try
     {
         return(tx.GetColoredTransactionAsync(repo).Result);
     }
     catch (AggregateException aex)
     {
         ExceptionDispatchInfo.Capture(aex.InnerException).Throw();
         return(null);
     }
 }
コード例 #17
0
        public static ColoredTransaction FetchColors(uint256 txId, IColoredTransactionRepository repo)
        {
            if (repo == null)
            {
                throw new ArgumentNullException("repo");
            }
            repo = EnsureCachedRepository(repo);
            var colored = repo.Get(txId);

            if (colored != null)
            {
                return(colored);
            }
            var tx = repo.Transactions.Get(txId);

            if (tx == null)
            {
                throw new TransactionNotFoundException("Transaction " + txId + " not found in transaction repository", txId);
            }
            return(FetchColors(txId, tx, repo));
        }
コード例 #18
0
ファイル: ColoredTransaction.cs プロジェクト: knocte/NBitcoin
		private static async Task<bool> BulkLoadIfCached(Transaction transaction, IColoredTransactionRepository repo)
		{
			if(!(repo is CachedColoredTransactionRepository))
				return false;
			var hasIssuance = HasIssuance(transaction);
			repo = new NoDuplicateColoredTransactionRepository(repo); //prevent from having concurrent request to the same transaction id
			var all = Enumerable
				.Range(0, transaction.Inputs.Count)
				.Select(async i =>
				{
					var txId = transaction.Inputs[i].PrevOut.Hash;
					var result = await repo.GetAsync(txId).ConfigureAwait(false);
					if(result == null || (i == 0 && hasIssuance))
						await repo.Transactions.GetAsync(txId).ConfigureAwait(false);
				})
				.ToArray();
			await Task.WhenAll(all).ConfigureAwait(false);
			return true;
		}
コード例 #19
0
ファイル: ColoredTransaction.cs プロジェクト: knocte/NBitcoin
		public static Task<ColoredTransaction> FetchColorsAsync(Transaction tx, IColoredTransactionRepository repo)
		{
			return FetchColorsAsync(null, tx, repo);
		}
コード例 #20
0
ファイル: Coin.cs プロジェクト: woutersmit/NBitcoin
		public static IEnumerable<ColoredCoin> Find(uint256 txId, Transaction tx, IColoredTransactionRepository repo)
		{
			if(txId == null)
				txId = tx.GetHash();
			var colored = tx.GetColoredTransaction(repo);
			return Find(txId, tx, colored);
		}
コード例 #21
0
ファイル: ColoredTransaction.cs プロジェクト: knocte/NBitcoin
		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();
		}
コード例 #22
0
 public static ColoredTransaction GetColoredTransaction(this Transaction tx, IColoredTransactionRepository repo)
 {
     return(tx.GetColoredTransactionAsync(repo).GetAwaiter().GetResult());
 }
コード例 #23
0
 public static ColoredTransaction FetchColors(uint256 txId, Transaction tx, IColoredTransactionRepository repo)
 {
     return(FetchColorsAsync(txId, tx, repo).GetAwaiter().GetResult());
 }
コード例 #24
0
 public static ColoredTransaction FetchColors(Transaction tx, IColoredTransactionRepository repo)
 {
     return(FetchColors(null, tx, repo));
 }
コード例 #25
0
ファイル: ColoredTransaction.cs プロジェクト: knocte/NBitcoin
		public static ColoredTransaction FetchColors(uint256 txId, IColoredTransactionRepository repo)
		{
			return FetchColors(txId, null, repo);
		}
コード例 #26
0
        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);
        }
コード例 #27
0
 public static Task <ColoredTransaction> FetchColorsAsync(Transaction tx, IColoredTransactionRepository repo)
 {
     return(FetchColorsAsync(null, tx, repo));
 }
コード例 #28
0
        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());
        }
コード例 #29
0
 public static ColoredTransaction Get(this IColoredTransactionRepository repo, uint256 txId)
 {
     return(repo.GetAsync(txId).GetAwaiter().GetResult());
 }
コード例 #30
0
 public static ColoredTransaction FetchColors(uint256 txId, IColoredTransactionRepository repo)
 {
     return(FetchColors(txId, null, repo));
 }
コード例 #31
0
ファイル: ColoredTransaction.cs プロジェクト: knocte/NBitcoin
		public static ColoredTransaction FetchColors(Transaction tx, IColoredTransactionRepository repo)
		{
			return FetchColors(null, tx, repo);
		}
コード例 #32
0
 public static Task <ColoredTransaction> GetAsync(this IColoredTransactionRepository repo, string txId)
 {
     return(repo.GetAsync(uint256.Parse(txId)));
 }
コード例 #33
0
ファイル: ColoredTransaction.cs プロジェクト: knocte/NBitcoin
		public static Task<ColoredTransaction> FetchColorsAsync(uint256 txId, IColoredTransactionRepository repo)
		{
			return FetchColorsAsync(txId, null, repo);
		}
コード例 #34
0
		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;
		}
コード例 #35
0
ファイル: ColoredTransaction.cs プロジェクト: knocte/NBitcoin
		public static ColoredTransaction FetchColors(uint256 txId, Transaction tx, IColoredTransactionRepository repo)
		{
			try
			{
				return FetchColorsAsync(txId, tx, repo).Result;
			}
			catch(AggregateException aex)
			{
				ExceptionDispatchInfo.Capture(aex.InnerException).Throw();
				return null;
			}
		}
コード例 #36
0
		private static IColoredTransactionRepository EnsureCachedRepository(IColoredTransactionRepository repo)
		{
			if(repo is CachedColoredTransactionRepository)
				return repo;
			repo = new CachedColoredTransactionRepository(new NoDuplicateColoredTransactionRepository(repo));
			return repo;
		}
コード例 #37
0
ファイル: Coin.cs プロジェクト: SerafinTech/NBitcoin
 public static IEnumerable <ColoredCoin> Find(Transaction tx, IColoredTransactionRepository repo)
 {
     return(Find(null, tx, repo));
 }
コード例 #38
0
 public static void Put(this IColoredTransactionRepository repo, uint256 txId, ColoredTransaction tx)
 {
     repo.PutAsync(txId, tx).GetAwaiter().GetResult();
 }
コード例 #39
0
 public static ColoredTransaction Get(this IColoredTransactionRepository repo, string txId)
 {
     return(repo.Get(uint256.Parse(txId)));
 }
コード例 #40
0
ファイル: Coin.cs プロジェクト: woutersmit/NBitcoin
		public static IEnumerable<ColoredCoin> Find(Transaction tx, IColoredTransactionRepository repo)
		{
			return Find(null, tx, repo);
		}
コード例 #41
0
 public static Task <ColoredTransaction> FetchColorsAsync(uint256 txId, IColoredTransactionRepository repo)
 {
     return(FetchColorsAsync(txId, null, repo));
 }
コード例 #42
0
 public async Task<bool> EnsureColoredTransactionLoadedAsync(IColoredTransactionRepository repository)
 {
     if(ColoredTransaction != null)
     {
         this.UpdateToColoredCoins();
         return true;
     }
     if(!(repository is CachedColoredTransactionRepository))
         repository = new CachedColoredTransactionRepository(repository);
     var tx = await repository.Transactions.GetAsync(TransactionId).ConfigureAwait(false);
     if(tx == null)
         return false;
     try
     {
         var color = await tx.GetColoredTransactionAsync(repository).ConfigureAwait(false);
         if(color == null)
             return false;
         ColoredTransaction = color;
         this.UpdateToColoredCoins();
         return true;
     }
     catch(TransactionNotFoundException)
     {
         return false;
     }
 }
コード例 #43
0
ファイル: Extensions.cs プロジェクト: RupeshDada/NBitcoin
 public static ColoredTransaction GetColoredTransaction(this Transaction tx, IColoredTransactionRepository repo)
 {
     return(ColoredTransaction.FetchColors(tx, repo));
 }
コード例 #44
0
        private static ColoredTransaction FetchColorsWithAncestorsSolved(uint256 txId, Transaction tx, IColoredTransactionRepository repo)
        {
            ColoredTransaction colored = new ColoredTransaction();

            Queue <ColoredEntry> previousAssetQueue = new Queue <ColoredEntry>();

            for (uint i = 0; i < tx.Inputs.Count; i++)
            {
                var txin        = tx.Inputs[i];
                var prevColored = repo.Get(txin.PrevOut.Hash);
                if (prevColored == null)
                {
                    continue;
                }
                var prevAsset = prevColored.GetColoredEntry(txin.PrevOut.N);
                if (prevAsset != null)
                {
                    var input = new ColoredEntry()
                    {
                        Index = i,
                        Asset = prevAsset.Asset
                    };
                    previousAssetQueue.Enqueue(input);
                    colored.Inputs.Add(input);
                }
            }

            uint markerPos = 0;
            var  marker    = ColorMarker.Get(tx, out markerPos);

            if (marker == null)
            {
                repo.Put(txId, colored);
                return(colored);
            }
            colored.Marker = marker;
            if (!marker.HasValidQuantitiesCount(tx))
            {
                repo.Put(txId, colored);
                return(colored);
            }

            AssetId issuedAsset = null;

            for (uint i = 0; i < markerPos; i++)
            {
                var entry = new ColoredEntry();
                entry.Index          = i;
                entry.Asset.Quantity = i >= marker.Quantities.Length ? 0 : marker.Quantities[i];
                if (entry.Asset.Quantity == 0)
                {
                    continue;
                }

                if (issuedAsset == null)
                {
                    var txIn = tx.Inputs.FirstOrDefault();
                    if (txIn == null)
                    {
                        continue;
                    }
                    var prev = repo.Transactions.Get(txIn.PrevOut.Hash);
                    if (prev == null)
                    {
                        throw new TransactionNotFoundException("This 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);
                    }
                    issuedAsset = prev.Outputs[(int)txIn.PrevOut.N].ScriptPubKey.Hash.ToAssetId();
                }
                entry.Asset.Id = issuedAsset;
                colored.Issuances.Add(entry);
            }

            ulong used = 0;

            for (uint i = markerPos + 1; i < tx.Outputs.Count; i++)
            {
                var entry = new ColoredEntry();
                entry.Index = i;
                //If there are less items in the  asset quantity list  than the number of colorable outputs (all the outputs except the marker output), the outputs in excess receive an asset quantity of zero.
                entry.Asset.Quantity = (i - 1) >= marker.Quantities.Length ? 0 : marker.Quantities[i - 1];
                if (entry.Asset.Quantity == 0)
                {
                    continue;
                }

                //If there are less asset units in the input sequence than in the output sequence, the transaction is considered invalid and all outputs are uncolored.
                if (previousAssetQueue.Count == 0)
                {
                    colored.Transfers.Clear();
                    colored.Issuances.Clear();
                    repo.Put(txId, colored);
                    return(colored);
                }
                entry.Asset.Id = previousAssetQueue.Peek().Asset.Id;
                var remaining = entry.Asset.Quantity;
                while (remaining != 0)
                {
                    if (previousAssetQueue.Count == 0 || previousAssetQueue.Peek().Asset.Id != entry.Asset.Id)
                    {
                        colored.Transfers.Clear();
                        colored.Issuances.Clear();
                        repo.Put(txId, colored);
                        return(colored);
                    }
                    var assertPart = Math.Min(previousAssetQueue.Peek().Asset.Quantity - used, remaining);
                    remaining = remaining - assertPart;
                    used     += assertPart;
                    if (used == previousAssetQueue.Peek().Asset.Quantity)
                    {
                        previousAssetQueue.Dequeue();
                        used = 0;
                    }
                }
                colored.Transfers.Add(entry);
            }
            repo.Put(txId, colored);
            return(colored);
        }