func AddAllInputScripts(tx *wire.MsgTx, prevPkScripts [][]byte, inputValues []bchutil.Amount,
	secrets SecretsSource) error {
	inputs := tx.TxIn
	chainParams := secrets.ChainParams()
	if len(inputs) != len(prevPkScripts) {
		return errors.New("tx.TxIn and prevPkScripts slices must " +
			"have equal length")
	}
	for i := range inputs {
		pkScript := prevPkScripts[i]
		_, addrs, _, err := txscript.ExtractPkScriptAddrs(pkScript,
			chainParams)
		if err != nil {
			return err
		}
		privKey, compressed, err := secrets.GetKey(addrs[0])
		if err != nil {
			return err
		}
		script, err := txscript.SignatureScript(tx, i, int64(inputValues[i].ToUnit(bchutil.AmountSatoshi)),
			pkScript, txscript.SigHashAll, privKey, compressed)
		if err != nil {
			return err
		}
		inputs[i].SignatureScript = script
	}
	return nil
}
AddAllInputScripts modifies a transaction by adding inputs scripts for each input.
Previous output scripts being redeemed by each input are passed in prevPkScripts
and the slice length must match the number of inputs.  Private keys and redeem
scripts are looked up using a SecretsSource based on the previous output script.
package txauthor
import (
	"errors"
	"github.com/gcash/bchd/chaincfg"
	"github.com/gcash/bchd/txscript"
	"github.com/gcash/bchd/wire"
	"github.com/gcash/bchutil"
	"github.com/gcash/bchwallet/wallet/txrules"
	h "github.com/gcash/bchwallet/internal/helpers"
	"github.com/gcash/bchwallet/wallet/txsizes"
)
type InputSource func(target bchutil.Amount) (total bchutil.Amount, inputs []*wire.TxIn,
	inputValues []bchutil.Amount, scripts [][]byte, err error)
type InputSourceError interface {
	error
	InputSourceError()
}
type insufficientFundsError struct{}
func (insufficientFundsError) InputSourceError() {}
func (insufficientFundsError) Error() string {
	return "insufficient funds available to construct transaction"
}
type AuthoredTx struct {
	Tx              *wire.MsgTx
	PrevScripts     [][]byte
	PrevInputValues []bchutil.Amount
	TotalInput      bchutil.Amount
	ChangeIndex     int  
}
type ChangeSource func() ([]byte, error)
func NewUnsignedTransaction(outputs []*wire.TxOut, relayFeePerKb bchutil.Amount,
	fetchInputs InputSource, fetchChange ChangeSource) (*AuthoredTx, error) {
	targetAmount := h.SumOutputValues(outputs)
	estimatedSize := txsizes.EstimateSerializeSize(0, outputs, true)
	targetFee := txrules.FeeForSerializeSize(relayFeePerKb, estimatedSize)
	for {
		inputAmount, inputs, inputValues, scripts, err := fetchInputs(targetAmount + targetFee)
		if err != nil {
			return nil, err
		}
		if inputAmount < targetAmount+targetFee {
			return nil, insufficientFundsError{}
		}
		maxSignedSize := txsizes.EstimateSerializeSize(len(inputs), outputs, true)
		maxRequiredFee := txrules.FeeForSerializeSize(relayFeePerKb, maxSignedSize)
		remainingAmount := inputAmount - targetAmount
		if remainingAmount < maxRequiredFee {
			targetFee = maxRequiredFee
			continue
		}
		unsignedTransaction := &wire.MsgTx{
			Version:  wire.TxVersion,
			TxIn:     inputs,
			TxOut:    outputs,
			LockTime: 0,
		}
		changeIndex := -1
		changeAmount := inputAmount - targetAmount - maxRequiredFee
		if changeAmount != 0 && !txrules.IsDustAmount(changeAmount,
			txsizes.P2PKHPkScriptSize, relayFeePerKb) {
			changeScript, err := fetchChange()
			if err != nil {
				return nil, err
			}
			if len(changeScript) > txsizes.P2PKHPkScriptSize {
				return nil, errors.New("fee estimation requires change " +
					"scripts no larger than P2PKH output scripts")
			}
			change := wire.NewTxOut(int64(changeAmount), changeScript)
			l := len(outputs)
			unsignedTransaction.TxOut = append(outputs[:l:l], change)
			changeIndex = l
		}
		return &AuthoredTx{
			Tx:              unsignedTransaction,
			PrevScripts:     scripts,
			PrevInputValues: inputValues,
			TotalInput:      inputAmount,
			ChangeIndex:     changeIndex,
		}, nil
	}
}
func RandomizeOutputPosition(outputs []*wire.TxOut, index int) int {
	r := cprng.Int31n(int32(len(outputs)))
	outputs[r], outputs[index] = outputs[index], outputs[r]
	return int(r)
}
func (tx *AuthoredTx) RandomizeChangePosition() {
	tx.ChangeIndex = RandomizeOutputPosition(tx.Tx.TxOut, tx.ChangeIndex)
}
type SecretsSource interface {
	txscript.KeyDB
	txscript.ScriptDB
	ChainParams() *chaincfg.Params
}