/// <summary> /// Deserialize the transaction hex string. /// </summary> /// <param name="tx">Transaction hex string</param> /// <returns>Bitcoin Transaction</returns> public static BitcoinTransaction DecodeRawTx(string tx) { BitcoinTransaction btx = new BitcoinTransaction(); int index = 0; // 1) 4 byte - version string version = tx.Substring(index, 8); btx.Version = (UInt32)NumberConversions.HexToUInt(version); index += 8; // 2) ? byte - tx_in count (CompactSize uint) btx.TxInCount = NumberConversions.ReadCompactSize(tx, ref index); bool isSigned = true; bool isRbf = false; // Initialize the array btx.TxInList = new TxIn[btx.TxInCount]; for (UInt64 i = 0; i < btx.TxInCount; i++) { TxIn temp = new TxIn(); // 3) 32 byte - TX hash (reverse) temp.TxId = tx.Substring(index, 64); temp.TxId = ReverseTx(temp.TxId); index += 64; // 4) 4 byte - output Index string outIndex = tx.Substring(index, 8); temp.OutIndex = (UInt32)NumberConversions.HexToUInt(outIndex); index += 8; // 5) ? byte - scriptSig length (CompactSize uint) (Maximum value is 10,000 bytes) string scriptSigLength = tx.Substring(index, 2); temp.ScriptSigLength = (int)NumberConversions.ReadCompactSize(tx, ref index); // 6) ? byte - scriptSig or a placeholder for unsigned (can be empty too) temp.ScriptSig = tx.Substring(index, temp.ScriptSigLength * 2); index += temp.ScriptSigLength * 2; //7) 4 byte - sequence - max is 0xffffffff - can change for RBF transactions string sequence = tx.Substring(index, 8); temp.Sequence = (UInt32)NumberConversions.HexToUInt(sequence); index += 8; btx.TxInList[i] = temp; // Check to see if all the inputs are signed if (temp.ScriptSigLength <= 25) { isSigned = false; } // Check for opt-in Replace By Fee if (temp.Sequence != UInt32.MaxValue) { isRbf = true; } } // Set transaction sign and RBF status. btx.Status = (isSigned) ? BitcoinTransaction.TxStatus.Signed : BitcoinTransaction.TxStatus.Unsigned; btx.IsRbf = isRbf; //8) ? byte - tx_out count (compactSize uint) btx.TxOutCount = NumberConversions.ReadCompactSize(tx, ref index); // Initialize the array btx.TxOutList = new TxOut[btx.TxOutCount]; for (UInt64 i = 0; i < btx.TxOutCount; i++) { TxOut temp = new TxOut(); //9) 8 byte - amout to transfer string amount = tx.Substring(index, 16); temp.Amount = NumberConversions.HexToUInt(amount); index += 16; //10) ? byte - pk_script length (compactSize uint) string pkScriptLength = tx.Substring(index, 2); temp.PkScriptLength = (Int32)NumberConversions.HexToUInt(pkScriptLength); index += 2; //11) ? byte - pk_script temp.PkScript = tx.Substring(index, temp.PkScriptLength * 2); index += temp.PkScriptLength * 2; btx.TxOutList[i] = temp; } //12) 4 byte - lock time string lockTime = tx.Substring(index, 8); btx.LockTime = (UInt32)NumberConversions.HexToUInt(lockTime); index += 8; // If the transaction is signed, then it has a TxId if (isSigned) { btx.TxId = BitcoinConversions.GetTxId(tx); } return(btx); }