예제 #1
0
        /// <summary>
        /// Returns estimated value for the final signed transaction.
        /// </summary>
        /// <param name="inputCount">Number of inputs to spend</param>
        /// <param name="outputCount">Number of outputs to receive</param>
        /// <returns>Transaction size</returns>
        public static int GetTransactionSize(int inputCount, int outputCount)
        {
            int c1 = NumberConversions.MakeCompactSize((UInt64)inputCount).Length / 2;
            int c2 = NumberConversions.MakeCompactSize((UInt64)outputCount).Length / 2;

            int inputSize =
                32    //TX hash
                + 4   //output Index
                + 1   //scriptSig length
                + 138 //scriptSig sig
                + 4;  //sequence
            int outputSize =
                8     //Amount
                + 1   //pk_script length
                + 25; //pk_script

            int totalSize =
                4    //Version
                + c1 //TxIn Count
                + inputSize * inputCount
                + c2 //TxOut Count
                + outputSize * outputCount
                + 4; //LockTime

            return((totalSize <= 10) ? 0 : totalSize);
        }
예제 #2
0
        /// <summary>
        /// Creates a Raw Unsigned bitcoin transaction Transaction.
        /// <para/> Sources:
        /// <para/> 1. https://bitcoin.stackexchange.com/questions/32628/redeeming-a-raw-transaction-step-by-step-example-required
        /// <para/> 2. https://bitcoin.org/en/developer-reference#raw-transaction-format
        /// <para/> 3. https://bitcoin.org/en/developer-examples#simple-raw-transaction
        /// </summary>
        /// <param name="txToSpend">List of UTXOs to spend.</param>
        /// <param name="receiveAddr">List of receiving addresses and the amount to be paid to each.</param>
        /// <param name="wallet">Type of the wallet (Electrum does not recognize normal type of scriptSig placeholder).</param>
        /// <returns>Rat unsigned transaction string.</returns>
        public static string CreateRawTx(List <UTXO> txToSpend, List <ReceivingAddress> receiveAddr, UInt32 lockTime, WalletType wallet)
        {
            StringBuilder rawTx = new StringBuilder();

            // 1) 4 byte - version
            UInt32 version = 1;

            rawTx.Append(NumberConversions.IntToHex(version, 4));

            // 2) ? byte - tx_in count (compactSize uint)
            int txInCount = txToSpend.Count;

            rawTx.Append(NumberConversions.MakeCompactSize((UInt64)txInCount));

            for (int i = 0; i < txInCount; i++)
            {
                // 3) 32 byte - TX hash (reverse)
                string txToSend = txToSpend[i].TxHash;
                rawTx.Append(ReverseTx(txToSend));

                // 4) 4 byte - output Index
                UInt32 outputIndex = txToSpend[i].OutIndex;
                rawTx.Append(NumberConversions.IntToHex(outputIndex, 4));

                // 5) ? byte - scriptSig length (compactSize uint) (Maximum value is 10,000 bytes)
                //    Can be from 0 and up. Will be replaced by actual scriptSig with another length.
                //    Format can be different based on the client which will be used for signing.
                if (string.IsNullOrEmpty(txToSpend[i].AddressHash160) && wallet != WalletType.Core)
                {
                    throw new Exception(string.Format("No address was found. Set wallet type to Core."));
                }
                string scriptSig = BuildScript(txToSpend[i].AddressHash160, wallet);
                rawTx.Append(NumberConversions.IntToHex((UInt64)(scriptSig.Length / 2), 1));

                // 6) ? byte - scriptSig which is filled with scriptPubkey temporarily (20 is half the length of address hash160)
                rawTx.Append(scriptSig);

                //7) 4 byte - sequence - max is 0xffffffff - can change for RBF transactions
                // Ref:
                // https://bitcoin.stackexchange.com/questions/2025/what-is-txins-sequence
                UInt32 sequence = UInt32.MaxValue;
                rawTx.Append(NumberConversions.IntToHex(sequence, 4));
            }

            //8) ? byte - tx_out count (compactSize uint)
            int txOutCount = receiveAddr.Count;

            rawTx.Append(NumberConversions.MakeCompactSize((UInt64)txOutCount));

            foreach (var item in receiveAddr)
            {
                //9) 8 byte - amout to transfer
                UInt64 amount = item.PaymentSatoshi;
                rawTx.Append(NumberConversions.IntToHex(amount, 8));

                //10) ? byte - pk_script length (compactSize uint)
                string itemHash     = BitcoinConversions.Base58ToHash160(item.Address);
                string outputScript = BuildScript(itemHash, WalletType.Normal);
                rawTx.Append(NumberConversions.MakeCompactSize((UInt64)outputScript.Length / 2));

                //11) ? byte - pk_script
                rawTx.Append(outputScript);
            }

            //12) 4 byte - lock time
            // * If less than 500 million, locktime is parsed as a block height. The transaction can be added to any block which has this height or higher.
            // * If greater than or equal to 500 million, locktime is parsed using the Unix epoch time format (the number of seconds elapsed since 1970-01-01T00:00 UTC—currently over 1.395 billion). The transaction can be added to any block whose block time is greater than the locktime.
            rawTx.Append(NumberConversions.IntToHex(lockTime, 4));

            return(rawTx.ToString());
        }