public ElementsUtxoData(OutPoint outpoint, ConfidentialAsset asset, long amount) : base(outpoint, amount) { if (asset is null) { throw new ArgumentNullException(nameof(asset)); } if (asset.HasBlinding()) { throw new InvalidOperationException("asset is blinded."); } unblindedAsset = asset.ToHexString(); value = new ConfidentialValue(amount); assetBlindFactor = new BlindFactor(); amountBlindFactor = new BlindFactor(); }
/// <summary> /// get total amount from utxo list on asset. /// </summary> /// <param name="utxoList">utxo list</param> /// <param name="asset">asset</param> /// <returns>asset total amount</returns> public static long GetTotalAmount(ElementsUtxoData[] utxoList, ConfidentialAsset asset) { if ((utxoList is null) || (asset is null)) { return(0); } long amount = 0; foreach (var utxo in utxoList) { if (utxo.GetAsset() == asset.ToHexString()) { amount += utxo.GetAmount(); } } return(amount); }
/// <summary> /// Select coins for elements. /// </summary> /// <param name="utxoList">utxo list</param> /// <param name="targetAssetAmountMap">target amount of asset. Amount more than the specified amount is set in txout. default is 0 (disable).</param> /// <param name="feeAsset">asset by fee</param> /// <param name="txFeeAmount">transaction fee</param> /// <param name="effectiveFeeRate">fee rate</param> /// <param name="exponent">blinding exponent</param> /// <param name="minimumBits">blinding minimum bits</param> /// <param name="longTermFeeRate">long-term fee rate</param> /// <param name="dustFeeRate">dust fee rate</param> /// <param name="knapsackMinChange">knapsack min change value. knapsack logic's threshold. Recommended value is 1.</param> /// <returns>select utxo list.</returns> public ElementsUtxoData[] SelectCoinsForElements( ElementsUtxoData[] utxoList, IDictionary <ConfidentialAsset, long> targetAssetAmountMap, ConfidentialAsset feeAsset, long txFeeAmount, double effectiveFeeRate, int exponent, int minimumBits, double longTermFeeRate, double dustFeeRate, long knapsackMinChange) { if (utxoList is null) { throw new ArgumentNullException(nameof(utxoList)); } if (utxoList.Length <= 0) { throw new InvalidOperationException("utxoList is empty."); } if (targetAssetAmountMap is null) { throw new ArgumentNullException(nameof(targetAssetAmountMap)); } if (targetAssetAmountMap.Count <= 0) { throw new InvalidOperationException("targetAssetAmountMap is empty."); } if (feeAsset is null) { throw new ArgumentNullException(nameof(feeAsset)); } if (feeAsset.HasBlinding()) { throw new InvalidOperationException( "fee asset has blinding. fee asset is unblind only."); } using (var handle = new ErrorHandle()) { var ret = NativeMethods.CfdInitializeCoinSelection( handle.GetHandle(), (uint)utxoList.Length, (uint)targetAssetAmountMap.Count, feeAsset.ToHexString(), txFeeAmount, effectiveFeeRate, longTermFeeRate, dustFeeRate, knapsackMinChange, out IntPtr coinSelectHandle); if (ret != CfdErrorCode.Success) { handle.ThrowError(ret); } try { for (uint index = 0; index < utxoList.Length; ++index) { string desc = (utxoList[index].GetDescriptor() is null) ? "" : utxoList[index].GetDescriptor().ToString(); ret = NativeMethods.CfdAddCoinSelectionUtxoTemplate( handle.GetHandle(), coinSelectHandle, index, utxoList[index].GetOutPoint().GetTxid().ToHexString(), utxoList[index].GetOutPoint().GetVout(), utxoList[index].GetAmount(), utxoList[index].GetAsset(), desc, utxoList[index].GetScriptSigTemplate().ToHexString()); if (ret != CfdErrorCode.Success) { handle.ThrowError(ret); } } long targetAmountAll = 0; uint assetIndex = 0; foreach (var key in targetAssetAmountMap.Keys) { ret = NativeMethods.CfdAddCoinSelectionAmount( handle.GetHandle(), coinSelectHandle, assetIndex, targetAssetAmountMap[key], key.ToHexString()); if (ret != CfdErrorCode.Success) { handle.ThrowError(ret); } ++assetIndex; targetAmountAll += targetAssetAmountMap[key]; } if (exponent >= -1) { ret = NativeMethods.CfdSetOptionCoinSelection(handle.GetHandle(), coinSelectHandle, Exponent, exponent, 0, false); if (ret != CfdErrorCode.Success) { handle.ThrowError(ret); } } if (minimumBits >= 0) { ret = NativeMethods.CfdSetOptionCoinSelection(handle.GetHandle(), coinSelectHandle, MinimumBits, minimumBits, 0, false); if (ret != CfdErrorCode.Success) { handle.ThrowError(ret); } } ret = NativeMethods.CfdFinalizeCoinSelection( handle.GetHandle(), coinSelectHandle, out long utxoFeeAmount); if (ret != CfdErrorCode.Success) { handle.ThrowError(ret); } uint[] collectIndexes = new uint[utxoList.Length]; uint collectCount = 0; if ((utxoFeeAmount > 0) || (targetAmountAll > 0)) { for (uint index = 0; index < utxoList.Length; ++index) { ret = NativeMethods.CfdGetSelectedCoinIndex( handle.GetHandle(), coinSelectHandle, index, out int utxoIndex); if (ret != CfdErrorCode.Success) { handle.ThrowError(ret); } if (utxoIndex < 0) { break; } if (utxoList.Length <= utxoIndex) { throw new InvalidProgramException("utxoIndex maximum over."); } ++collectCount; collectIndexes[index] = (uint)utxoIndex; } } /* * assetIndex = 0; * collectAmountList = new Dictionary<ConfidentialAsset, long>(); * foreach (var key in targetAssetAmountMap.Keys) * { * ret = NativeMethods.CfdGetSelectedCoinAssetAmount( * handle.GetHandle(), coinSelectHandle, assetIndex, * out long collectAmount); * if (ret != CfdErrorCode.Success) * { * handle.ThrowError(ret); * } ++assetIndex; * collectAmountList.Add(key, collectAmount); * } */ ElementsUtxoData[] selectedUtxoList = new ElementsUtxoData[collectCount]; for (uint index = 0; index < collectCount; ++index) { selectedUtxoList[index] = utxoList[collectIndexes[index]]; } lastSelectedUtxoFee = utxoFeeAmount; return(selectedUtxoList); } finally { NativeMethods.CfdFreeCoinSelectionHandle(handle.GetHandle(), coinSelectHandle); } } }