public static bool HasIssuance(Transaction tx) { if (tx.Inputs.Count == 0) { return(false); } uint markerPos = 0; ColorMarker marker = ColorMarker.Get(tx, out markerPos); if (marker == null) { return(false); } if (!marker.HasValidQuantitiesCount(tx)) { return(false); } for (uint i = 0; i < markerPos; i++) { ulong quantity = i >= marker.Quantities.Length ? 0 : marker.Quantities[i]; if (quantity != 0) { return(true); } } return(false); }
public static bool HasValidColorMarker(Transaction tx) { if (tx.Inputs.Count == 0 || tx.IsCoinBase) { return(false); } ColorMarker marker = Get(tx); if (marker == null) { return(false); } //If there are more items in the asset quantity list than the number of colorable outputs, the transaction is deemed invalid, and all outputs are uncolored. return(marker.HasValidQuantitiesCount(tx)); }
public ColoredTransaction(uint256 txId, Transaction tx, ColoredCoin[] spentCoins, Script issuanceScriptPubkey) : this() { if (tx == null) { throw new ArgumentNullException("tx"); } if (spentCoins == null) { throw new ArgumentNullException("spentCoins"); } if (tx.IsCoinBase || tx.Inputs.Count == 0) { return; } txId = txId ?? tx.GetHash(); var previousAssetQueue = new Queue <ColoredEntry>(); for (uint i = 0; i < tx.Inputs.Count; i++) { TxIn txin = tx.Inputs[i]; ColoredCoin prevAsset = spentCoins.FirstOrDefault(s => s.Outpoint == txin.PrevOut); if (prevAsset != null) { var input = new ColoredEntry() { Index = i, Asset = prevAsset.Amount }; previousAssetQueue.Enqueue(input); this.Inputs.Add(input); } } uint markerPos = 0; ColorMarker marker = ColorMarker.Get(tx, out markerPos); if (marker == null) { return; } this.Marker = marker; if (!marker.HasValidQuantitiesCount(tx)) { return; } AssetId issuedAsset = null; for (uint i = 0; i < markerPos; i++) { var entry = new ColoredEntry(); entry.Index = i; entry.Asset = new AssetMoney(entry.Asset.Id, i >= marker.Quantities.Length ? 0 : marker.Quantities[i]); if (entry.Asset.Quantity == 0) { continue; } if (issuedAsset == null) { TxIn txIn = tx.Inputs.FirstOrDefault(); if (txIn == null) { continue; } if (issuanceScriptPubkey == null) { throw new ArgumentException("The transaction has an issuance detected, but issuanceScriptPubkey is null.", "issuanceScriptPubkey"); } issuedAsset = issuanceScriptPubkey.Hash.ToAssetId(); } entry.Asset = new AssetMoney(issuedAsset, entry.Asset.Quantity); this.Issuances.Add(entry); } long 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 = new AssetMoney(entry.Asset.Id, (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) { this.Transfers.Clear(); this.Issuances.Clear(); return; } entry.Asset = new AssetMoney(previousAssetQueue.Peek().Asset.Id, entry.Asset.Quantity); long remaining = entry.Asset.Quantity; while (remaining != 0) { if (previousAssetQueue.Count == 0 || previousAssetQueue.Peek().Asset.Id != entry.Asset.Id) { this.Transfers.Clear(); this.Issuances.Clear(); return; } long assertPart = Math.Min(previousAssetQueue.Peek().Asset.Quantity - used, remaining); remaining = remaining - assertPart; used += assertPart; if (used == previousAssetQueue.Peek().Asset.Quantity) { previousAssetQueue.Dequeue(); used = 0; } } this.Transfers.Add(entry); } }