private static void WriteEntry(Network network, JArray inputs, ColoredEntry entry) { JProperty index = new JProperty("index", entry.Index); JProperty asset = new JProperty("asset", entry.Asset.Id.GetWif(network).ToString()); JProperty quantity = new JProperty("quantity", entry.Asset.Quantity); inputs.Add(new JObject(index, asset, quantity)); }
public async Task <ColoredTransaction> GetAsync(uint256 txId) { try { ColoredTransaction result = new ColoredTransaction(); String url = _network == Network.Main ? String.Format("https://api.coinprism.com/v1/transactions/{0}", txId) : String.Format("https://testnet.api.coinprism.com/v1/transactions/{0}", txId); HttpWebRequest req = HttpWebRequest.CreateHttp(url); req.Method = "GET"; #if !NOCUSTOMSSLVALIDATION if (_network == Network.TestNet) { req.ServerCertificateValidationCallback += (a, b, c, d) => true; } #endif using (var response = await req.GetResponseAsync().ConfigureAwait(false)) { var writer = new StreamReader(response.GetResponseStream()); var str = await writer.ReadToEndAsync().ConfigureAwait(false); var json = JObject.Parse(str); var inputs = json["inputs"] as JArray; if (inputs != null) { for (int i = 0; i < inputs.Count; i++) { if (inputs[i]["asset_id"].Value <string>() == null) { continue; } var entry = new ColoredEntry(); entry.Index = (uint)i; entry.Asset = new AssetMoney( new BitcoinAssetId(inputs[i]["asset_id"].ToString(), null).AssetId, inputs[i]["asset_quantity"].Value <ulong>()); result.Inputs.Add(entry); } } var outputs = json["outputs"] as JArray; if (outputs != null) { bool issuance = true; for (int i = 0; i < outputs.Count; i++) { var marker = ColorMarker.TryParse(new Script(Encoders.Hex.DecodeData(outputs[i]["script"].ToString()))); if (marker != null) { issuance = false; result.Marker = marker; continue; } if (outputs[i]["asset_id"].Value <string>() == null) { continue; } ColoredEntry entry = new ColoredEntry(); entry.Index = (uint)i; entry.Asset = new AssetMoney( new BitcoinAssetId(outputs[i]["asset_id"].ToString(), null).AssetId, outputs[i]["asset_quantity"].Value <ulong>() ); if (issuance) { result.Issuances.Add(entry); } else { result.Transfers.Add(entry); } } } return(result); } } catch (WebException ex) { try { var error = JObject.Parse(new StreamReader(ex.Response.GetResponseStream()).ReadToEnd()); if (error["ErrorCode"].ToString() == "InvalidTransactionHash") { return(null); } throw new CoinprismException(error["ErrorCode"].ToString()); } catch (CoinprismException) { throw; } catch { } throw; } }
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(); Queue <ColoredEntry> previousAssetQueue = new Queue <ColoredEntry>(); for (uint i = 0; i < tx.Inputs.Count; i++) { var txin = tx.Inputs[i]; var prevAsset = spentCoins.FirstOrDefault(s => s.Outpoint == txin.PrevOut); if (prevAsset != null) { var input = new ColoredEntry() { Index = i, Asset = prevAsset.Amount }; previousAssetQueue.Enqueue(input); Inputs.Add(input); } } uint markerPos = 0; var marker = ColorMarker.Get(tx, out markerPos); if (marker == null) { return; } 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) { var 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); 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) { Transfers.Clear(); Issuances.Clear(); return; } entry.Asset = new AssetMoney(previousAssetQueue.Peek().Asset.Id, entry.Asset.Quantity); var remaining = entry.Asset.Quantity; while (remaining != 0) { if (previousAssetQueue.Count == 0 || previousAssetQueue.Peek().Asset.Id != entry.Asset.Id) { Transfers.Clear(); Issuances.Clear(); return; } 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; } } Transfers.Add(entry); } }