func (w *Wallet) txToOutputs(outputs []*wire.TxOut, account uint32, notSend int32, minconf int32,
	randomizeChangeIdx bool) (*txauthor.AuthoredTx, error) {
	chainClient, err := w.requireChainClient()
	if err != nil {
		return nil, err
	}
	return w.txToOutputsInternal(outputs, account, notSend, minconf, chainClient,
		randomizeChangeIdx, w.RelayFee())
}
txToOutputs creates a transaction, selecting previous outputs from an account
with no less than minconf confirmations, and creates a signed transaction
that pays to each of the outputs.
package wallet
import (
	"encoding/binary"
	"errors"
	"fmt"
	"time"
	"github.com/HcashOrg/hcashd/blockchain"
	"github.com/HcashOrg/hcashd/blockchain/stake"
	"github.com/HcashOrg/hcashd/chaincfg"
	"github.com/HcashOrg/hcashd/chaincfg/chainec"
	"github.com/HcashOrg/hcashd/chaincfg/chainhash"
	"github.com/HcashOrg/hcashd/hcashjson"
	"github.com/HcashOrg/hcashd/txscript"
	"github.com/HcashOrg/hcashd/wire"
	"github.com/HcashOrg/hcashutil"
	"github.com/HcashOrg/hcashwallet/apperrors"
	"github.com/HcashOrg/hcashwallet/chain"
	"github.com/HcashOrg/hcashwallet/wallet/internal/txsizes"
	"github.com/HcashOrg/hcashwallet/wallet/txauthor"
	"github.com/HcashOrg/hcashwallet/wallet/txrules"
	"github.com/HcashOrg/hcashwallet/wallet/udb"
	"github.com/HcashOrg/hcashwallet/walletdb"
)
const (
	txOverheadEstimate = 4 + 4 + 4 + 1 + 1 + 1
	sigScriptEstimate = 1 + 73 + 1 + 33 + 1
	txInEstimate = chainhash.HashSize + 4 + 1 + 4 + 16 + 1 + sigScriptEstimate
	pkScriptEstimate = 1 + 1 + 1 + 20 + 1 + 1
	txOutEstimate = 8 + 2 + 1 + pkScriptEstimate
	singleInputTicketSize = 300
	doubleInputTicketSize = 550
	defaultTicketFeeLimits = 0x5800
	maxStandardTxSize = 100000
)
var (
	maxTxSize = chaincfg.MainNetParams.MaxTxSize
)
func estimateTxSize(numInputs, numOutputs int) int {
	return txOverheadEstimate + txInEstimate*numInputs + txOutEstimate*numOutputs
}
func EstimateTxSize(numInputs, numOutputs int) int {
	return estimateTxSize(numInputs, numOutputs)
}
func feeForSize(incr hcashutil.Amount, sz int) hcashutil.Amount {
	return hcashutil.Amount(1+sz/1000) * incr
}
func FeeForSize(incr hcashutil.Amount, sz int) hcashutil.Amount {
	return feeForSize(incr, sz)
}
const EstMaxTicketFeeAmount = 0.1 * 1e8
type extendedOutPoint struct {
	op       *wire.OutPoint
	amt      int64
	pkScript []byte
}
var ErrUnsupportedTransactionType = errors.New("Only P2PKH transactions " +
	"are supported")
var ErrNonPositiveAmount = errors.New("amount is not positive")
var ErrNegativeFee = errors.New("fee is negative")
var ErrSStxNotEnoughFunds = errors.New("not enough to purchase sstx")
var ErrSStxPriceExceedsSpendLimit = errors.New("ticket price exceeds spend limit")
var ErrNoOutsToConsolidate = errors.New("no outputs to consolidate")
var ErrBlockchainReorganizing = errors.New("blockchain is currently " +
	"reorganizing")
var ErrTicketPriceNotSet = errors.New("ticket price not yet established")
type OutputSelectionAlgorithm uint
const (
	OutputSelectionAlgorithmDefault = iota
	OutputSelectionAlgorithmAll
)
func (w *Wallet) NewUnsignedTransaction(outputs []*wire.TxOut, relayFeePerKb hcashutil.Amount, account uint32, minConf int32,
	algo OutputSelectionAlgorithm, changeSource txauthor.ChangeSource) (*txauthor.AuthoredTx, error) {
	var authoredTx *txauthor.AuthoredTx
	var changeSourceUpdates []func(walletdb.ReadWriteTx) error
	err := walletdb.View(w.db, func(dbtx walletdb.ReadTx) error {
		addrmgrNs := dbtx.ReadBucket(waddrmgrNamespaceKey)
		txmgrNs := dbtx.ReadBucket(wtxmgrNamespaceKey)
		_, tipHeight, tipKeyHeight := w.TxStore.MainChainTip(txmgrNs)
		if account != udb.ImportedAddrAccount {
			lastAcct, err := w.Manager.LastAccount(addrmgrNs)
			if err != nil {
				return err
			}
			if account > lastAcct {
				return apperrors.E{
					ErrorCode:   apperrors.ErrAccountNotFound,
					Description: "account not found",
				}
			}
		}
		sourceImpl := w.TxStore.MakeInputSource(txmgrNs, addrmgrNs, account,
			minConf, tipHeight, tipKeyHeight)
		var inputSource txauthor.InputSource
		switch algo {
		case OutputSelectionAlgorithmDefault:
			inputSource = sourceImpl.SelectInputs
		case OutputSelectionAlgorithmAll:
			inputSource = func(hcashutil.Amount) (hcashutil.Amount, []*wire.TxIn, [][]byte, error) {
				total, inputs, prevScripts, err := sourceImpl.SelectInputs(hcashutil.MaxAmount)
				switch err.(type) {
				case txauthor.InputSourceError:
					err = nil
				}
				return total, inputs, prevScripts, err
			}
		default:
			return fmt.Errorf("unrecognized output selection algorithm %d", algo)
		}
		if changeSource == nil {
			persist := w.deferPersistReturnedChild(&changeSourceUpdates)
			changeSource = w.changeSource(persist, account)
		}
		var err error
		authoredTx, err = txauthor.NewUnsignedTransaction(outputs, relayFeePerKb,
			inputSource, changeSource, udb.AcctypeEc)
		return err
	})
	if err != nil {
		return nil, err
	}
	if len(changeSourceUpdates) != 0 {
		err = walletdb.Update(w.db, func(tx walletdb.ReadWriteTx) error {
			for _, up := range changeSourceUpdates {
				err := up(tx)
				if err != nil {
					return err
				}
			}
			return nil
		})
	}
	return authoredTx, err
}
type secretSource struct {
	*udb.Manager
	addrmgrNs walletdb.ReadBucket
	doneFuncs []func()
}
func (s *secretSource) GetKey(addr hcashutil.Address) (chainec.PrivateKey, bool, error) {
	privKey, done, err := s.Manager.PrivateKey(s.addrmgrNs, addr)
	if err != nil {
		return nil, false, err
	}
	s.doneFuncs = append(s.doneFuncs, done)
	return privKey, true, nil
}
func (s *secretSource) GetScript(addr hcashutil.Address) ([]byte, error) {
	script, done, err := s.Manager.RedeemScript(s.addrmgrNs, addr)
	if err != nil {
		return nil, err
	}
	s.doneFuncs = append(s.doneFuncs, done)
	return script, nil
}
type CreatedTx struct {
	MsgTx       *wire.MsgTx
	ChangeAddr  hcashutil.Address
	ChangeIndex int  
	Fee         hcashutil.Amount
}
func (w *Wallet) insertIntoTxMgr(ns walletdb.ReadWriteBucket, msgTx *wire.MsgTx) (*udb.TxRecord, error) {
	rec, err := udb.NewTxRecordFromMsgTx(msgTx, time.Now())
	if err != nil {
		return nil, hcashjson.ErrInternal
	}
	return rec, w.TxStore.InsertMemPoolTx(ns, rec)
}
func (w *Wallet) insertCreditsIntoTxMgr(tx walletdb.ReadWriteTx,
	msgTx *wire.MsgTx, rec *udb.TxRecord) error {
	addrmgrNs := tx.ReadWriteBucket(waddrmgrNamespaceKey)
	txmgrNs := tx.ReadWriteBucket(wtxmgrNamespaceKey)
	for i, output := range msgTx.TxOut {
		_, addrs, _, err := txscript.ExtractPkScriptAddrs(output.Version,
			output.PkScript, w.chainParams)
		if err != nil {
			continue
		}
		for _, addr := range addrs {
			ma, err := w.Manager.Address(addrmgrNs, addr)
			if err == nil {
				err = w.TxStore.AddCredit(txmgrNs, rec, nil,
					uint32(i), ma.Internal(), ma.Account())
				if err != nil {
					return err
				}
				err = w.markUsedAddress(tx, ma)
				if err != nil {
					return err
				}
				log.Debugf("Marked address %v used", addr)
				continue
			}
			code := err.(apperrors.E).ErrorCode
			if code != apperrors.ErrAddressNotFound {
				return err
			}
		}
	}
	return nil
}
func (w *Wallet) insertMultisigOutIntoTxMgr(ns walletdb.ReadWriteBucket, msgTx *wire.MsgTx,
	index uint32) error {
	rec, err := udb.NewTxRecordFromMsgTx(msgTx, time.Now())
	if err != nil {
		return err
	}
	return w.TxStore.AddMultisigOut(ns, rec, nil, index)
}