// fundTx attempts to fund a transaction sending amt bitcoin. The coins are // selected such that the final amount spent pays enough fees as dictated by // the passed fee rate. The passed fee rate should be expressed in // satoshis-per-byte. // // NOTE: The memWallet's mutex must be held when this function is called. func (m *memWallet) fundTx(tx *wire.MsgTx, amt btcutil.Amount, feeRate btcutil.Amount) error { const ( // spendSize is the largest number of bytes of a sigScript // which spends a p2pkh output: OP_DATA_73 <sig> OP_DATA_33 <pubkey> spendSize = 1 + 73 + 1 + 33 ) var ( amtSelected btcutil.Amount txSize int ) for outPoint, utxo := range m.utxos { // Skip any outputs that are still currently immature or are // currently locked. if !utxo.isMature(m.currentHeight) || utxo.isLocked { continue } amtSelected += utxo.value // Add the selected output to the transaction, updating the // current tx size while accounting for the size of the future // sigScript. tx.AddTxIn(wire.NewTxIn(&outPoint, nil, nil)) txSize = tx.SerializeSize() + spendSize*len(tx.TxIn) // Calculate the fee required for the txn at this point // observing the specified fee rate. If we don't have enough // coins from he current amount selected to pay the fee, then // continue to grab more coins. reqFee := btcutil.Amount(txSize * int(feeRate)) if amtSelected-reqFee < amt { continue } // If we have any change left over, then add an additional // output to the transaction reserved for change. changeVal := amtSelected - amt - reqFee if changeVal > 0 { addr, err := m.newAddress() if err != nil { return err } pkScript, err := txscript.PayToAddrScript(addr) if err != nil { return err } changeOutput := &wire.TxOut{ Value: int64(changeVal), PkScript: pkScript, } tx.AddTxOut(changeOutput) } return nil } // If we've reached this point, then coin selection failed due to an // insufficient amount of coins. return fmt.Errorf("not enough funds for coin selection") }