<commit_before>// Copyright (c) 2013-2016 The btcsuite developers
// Copyright (c) 2015-2016 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package wallet

import (
	"crypto/rand"
	"errors"
	"fmt"
	"time"

	"github.com/btcsuite/golangcrypto/ripemd160"

	"github.com/decred/dcrd/blockchain/stake"
	"github.com/decred/dcrd/chaincfg"
	"github.com/decred/dcrd/chaincfg/chainec"
	"github.com/decred/dcrd/chaincfg/chainhash"
	"github.com/decred/dcrd/dcrjson"
	"github.com/decred/dcrd/txscript"
	"github.com/decred/dcrd/wire"
	"github.com/decred/dcrutil"
	"github.com/decred/dcrwallet/chain"
	"github.com/decred/dcrwallet/waddrmgr"
	"github.com/decred/dcrwallet/wallet/txauthor"
	"github.com/decred/dcrwallet/wallet/txrules"
	"github.com/decred/dcrwallet/wtxmgr"
)

// --------------------------------------------------------------------------------
// Constants and simple functions

const (
	// All transactions have 4 bytes for version, 4 bytes of locktime,
	// 4 bytes of expiry, and 2 varints for the number of inputs and
	// outputs, and 1 varint for the witnesses.
	txOverheadEstimate = 4 + 4 + 4 + 1 + 1 + 1

	// A worst case signature script to redeem a P2PKH output for a
	// compressed pubkey has 73 bytes of the possible DER signature
	// (with no leading 0 bytes for R and S), 65 bytes of serialized pubkey,
	// and data push opcodes for both, plus one byte for the hash type flag
	// appended to the end of the signature.
	sigScriptEstimate = 1 + 73 + 1 + 65 + 1

	// A best case tx input serialization cost is 32 bytes of sha, 4 bytes
	// of output index, 1 byte for tree, 4 bytes of sequence, 12 bytes for
	// fraud proof, and the estimated signature script size.
	txInEstimate = 32 + 4 + 1 + 12 + 4 + sigScriptEstimate

	// sstxTicketCommitmentEstimate =
	// - version + amount +
	// OP_SSTX OP_DUP OP_HASH160 OP_DATA_20 OP_EQUALVERIFY OP_CHECKSIG
	sstxTicketCommitmentEstimate = 2 + 8 + 1 + 1 + 1 + 1 + 20 + 1 + 1

	// sstxSubsidyCommitmentEstimate =
	// version + amount + OP_RETURN OP_DATA_30
	sstxSubsidyCommitmentEstimate = 2 + 8 + 2 + 30

	// sstxChangeOutputEstimate =
	// version + amount + OP_SSTXCHANGE OP_DUP OP_HASH160 OP_DATA_20
	//	OP_EQUALVERIFY OP_CHECKSIG
	sstxChangeOutputEstimate = 2 + 8 + 1 + 1 + 1 + 1 + 20 + 1 + 1

	// A P2PKH pkScript contains the following bytes:
	//  - OP_DUP
	//  - OP_HASH160
	//  - OP_DATA_20 + 20 bytes of pubkey hash
	//  - OP_EQUALVERIFY
	//  - OP_CHECKSIG
	pkScriptEstimate = 1 + 1 + 1 + 20 + 1 + 1

	// pkScriptEstimateSS is the estimated size of a ticket P2PKH output script.
	pkScriptEstimateSS = 1 + 1 + 1 + 1 + 20 + 1 + 1

	// txOutEstimate is a best case tx output serialization cost is 8 bytes
	// of value, two bytes of version, one byte of varint, and the pkScript
	// size.
	txOutEstimate = 8 + 2 + 1 + pkScriptEstimate

	// ssTxOutEsimate is the estimated size of a P2PKH ticket output.
	ssTxOutEsimate = 8 + 2 + 1 + pkScriptEstimateSS

	// singleInputTicketSize is the typical size of a normal P2PKH ticket
	// in bytes when the ticket has one input, rounded up.
	singleInputTicketSize = 300

	// doubleInputTicketSize is the typical size of a normal P2PKH ticket
	// in bytes when the ticket has two inputs, rounded up.
	doubleInputTicketSize = 550

	// defaultTicketFeeLimits is the default byte string for the default
	// fee limits imposed on a ticket.
	defaultTicketFeeLimits = 0x5800
)

var (
	// maxTxSize is the maximum size of a transaction we can
	// build with the wallet.
	maxTxSize = chaincfg.MainNetParams.MaximumBlockSize - 75000
)

func estimateTxSize(numInputs, numOutputs int) int {
	return txOverheadEstimate + txInEstimate*numInputs + txOutEstimate*numOutputs
}

// EstimateTxSize is the exported version of estimateTxSize which provides
// an estimate of the tx size based on the number of inputs, outputs, and some
// assumed overhead.
func EstimateTxSize(numInputs, numOutputs int) int {
	return estimateTxSize(numInputs, numOutputs)
}

func estimateSSTxSize(numInputs int) int {
	return txOverheadEstimate + txInEstimate*numInputs +
		sstxTicketCommitmentEstimate +
		(sstxSubsidyCommitmentEstimate+
			sstxChangeOutputEstimate)*numInputs
}

func feeForSize(incr dcrutil.Amount, sz int) dcrutil.Amount {
	return dcrutil.Amount(1+sz/1000) * incr
}

// FeeForSize is the exported version of feeForSize which returns a fee
// based on the provided feeIncrement and provided size.
func FeeForSize(incr dcrutil.Amount, sz int) dcrutil.Amount {
	return feeForSize(incr, sz)
}

// DefaultTicketFeeIncrement is the default minimum stake transaction fees per KB (0.01
// coin, measured in atoms).
const DefaultTicketFeeIncrement dcrutil.Amount = 1e6

// EstMaxTicketFeeAmount is the estimated max ticket fee to be used for size
// calculation for eligible utxos for ticket purchasing.
const EstMaxTicketFeeAmount = 0.1 * 1e8

// extendedOutPoint is a UTXO with an amount.
type extendedOutPoint struct {
	op       *wire.OutPoint
	amt      int64
	pkScript []byte
}

// --------------------------------------------------------------------------------
// Error Handling

// ErrUnsupportedTransactionType represents an error where a transaction
// cannot be signed as the API only supports spending P2PKH outputs.
var ErrUnsupportedTransactionType = errors.New("Only P2PKH transactions " +
	"are supported")

// ErrNonPositiveAmount represents an error where an amount is
// not positive (either negative, or zero).
var ErrNonPositiveAmount = errors.New("amount is not positive")

// ErrNegativeFee represents an error where a fee is erroneously
// negative.
var ErrNegativeFee = errors.New("fee is negative")

// ErrSStxNotEnoughFunds indicates that not enough funds were available in the
// wallet to purchase a ticket.
var ErrSStxNotEnoughFunds = errors.New("not enough to purchase sstx")

// ErrSStxPriceExceedsSpendLimit indicates that the current ticket price exceeds
// the specified spend maximum spend limit.
var ErrSStxPriceExceedsSpendLimit = errors.New("ticket price exceeds spend limit")

// ErrNoOutsToConsolidate indicates that there were no outputs available
// to compress.
var ErrNoOutsToConsolidate = errors.New("no outputs to consolidate")

// ErrBlockchainReorganizing indicates that the blockchain is currently
// reorganizing.
var ErrBlockchainReorganizing = errors.New("blockchain is currently " +
	"reorganizing")

// ErrTicketPriceNotSet indicates that the wallet was recently connected
// and that the ticket price has not yet been set.
var ErrTicketPriceNotSet = errors.New("ticket price not yet established")

// --------------------------------------------------------------------------------
// Transaction creation

// secretSource is an implementation of txauthor.SecretSource for the wallet's
// address manager.
type secretSource struct {
	*waddrmgr.Manager
}

func (s secretSource) GetKey(addr dcrutil.Address) (chainec.PrivateKey, bool, error) {
	ma, err := s.Address(addr)
	if err != nil {
		return nil, false, err
	}
	mpka, ok := ma.(waddrmgr.ManagedPubKeyAddress)
	if !ok {
		e := fmt.Errorf("managed address type for %v is `%T` but "+
			"want waddrmgr.ManagedPubKeyAddress", addr, ma)
		return nil, false, e
	}
	privKey, err := mpka.PrivKey()
	if err != nil {
		return nil, false, err
	}
	return privKey, ma.Compressed(), nil
}

func (s secretSource) GetScript(addr dcrutil.Address) ([]byte, error) {
	ma, err := s.Address(addr)
	if err != nil {
		return nil, err
	}
	msa, ok := ma.(waddrmgr.ManagedScriptAddress)
	if !ok {
		e := fmt.Errorf("managed address type for %v is `%T` but "+
			"want waddrmgr.ManagedScriptAddress", addr, ma)
		return nil, e
	}
	return msa.Script()
}

// CreatedTx holds the state of a newly-created transaction and the change
// output (if one was added).
type CreatedTx struct {
	MsgTx       *wire.MsgTx
	ChangeAddr  dcrutil.Address
	ChangeIndex int // negative if no change
	Fee         dcrutil.Amount
}

// insertIntoTxMgr inserts a newly created transaction into the tx store
// as unconfirmed.
func (w *Wallet) insertIntoTxMgr(msgTx *wire.MsgTx) (*wtxmgr.TxRecord, error) {
	// Create transaction record and insert into the db.
	rec, err := wtxmgr.NewTxRecordFromMsgTx(msgTx, time.Now())
	if err != nil {
		return nil, dcrjson.ErrInternal
	}

	return rec, w.TxStore.InsertTx(rec, nil)
}

func (w *Wallet) insertCreditsIntoTxMgr(msgTx *wire.MsgTx,
	rec *wtxmgr.TxRecord) error {
	// Check every output to determine whether it is controlled by a wallet
	// key.  If so, mark the output as a credit.
	for i, output := range msgTx.TxOut {
		_, addrs, _, err := txscript.ExtractPkScriptAddrs(output.Version,
			output.PkScript, w.chainParams)
		if err != nil {
			// Non-standard outputs are skipped.
			continue
		}
		for _, addr := range addrs {
			ma, err := w.Manager.Address(addr)
			if err == nil {
				// TODO: Credits should be added with the
				// account they belong to, so wtxmgr is able to
				// track per-account balances.
				err = w.TxStore.AddCredit(rec, nil, uint32(i),
					ma.Internal(), ma.Account())
				if err != nil {
					return err
				}
				err = w.Manager.MarkUsed(addr)
				if err != nil {
					return err
				}
				log.Debugf("Marked address %v used", addr)
				continue
			}

			// Missing addresses are skipped.  Other errors should
			// be propagated.
			code := err.(waddrmgr.ManagerError).ErrorCode
			if code != waddrmgr.ErrAddressNotFound {
				return err
			}
		}
	}

	return nil
}

// insertMultisigOutIntoTxMgr inserts a multisignature output into the
// transaction store database.
func (w *Wallet) insertMultisigOutIntoTxMgr(msgTx *wire.MsgTx,
	index uint32) error {
	// Create transaction record and insert into the db.
	rec, err := wtxmgr.NewTxRecordFromMsgTx(msgTx, time.Now())
	if err != nil {
		return dcrjson.ErrInternal
	}

	return w.TxStore.AddMultisigOut(rec, nil, index)
}

// TxToOutputs is the exported version of txToOutputs that does all relevant
// locking to ensure the safety of the wallet state to generate a transaction.
// It then calls txToOutputs to generate a transaction.
func (w *Wallet) TxToOutputs(outputs []*wire.TxOut, account uint32, minconf int32,
	randomizeChangeIdx bool) (atx *txauthor.AuthoredTx, err error) {
	// Address manager must be unlocked to compose transaction.  Grab
	// the unlock if possible (to prevent future unlocks), or return the
	// error if already locked.
	heldUnlock, err := w.HoldUnlock()
	if err != nil {
		return nil, err
	}
	defer heldUnlock.Release()

	chainClient, err := w.requireChainClient()
	if err != nil {
		return nil, err
	}

	isReorganizing, _ := chainClient.GetReorganizing()
	if isReorganizing {
		return nil, ErrBlockchainReorganizing
	}

	// Initialize the address pool for use. If we
	// are using an imported account, loopback to
	// the default account to create change.
	var pool *addressPool
	if account == waddrmgr.ImportedAddrAccount {
		err := w.CheckAddressPoolsInitialized(waddrmgr.DefaultAccountNum)
		if err != nil {
			return nil, err
		}
		pool = w.addrPools[waddrmgr.DefaultAccountNum].internal
	} else {
		err := w.CheckAddressPoolsInitialized(account)
		if err != nil {
			return nil, err
		}
		pool = w.addrPools[account].internal
	}
	changeAddrUsed := false
	txSucceeded := false
	pool.mutex.Lock()
	defer pool.mutex.Unlock()
	defer func() {
		if txSucceeded && changeAddrUsed {
			pool.BatchFinish()
		} else {
			pool.BatchRollback()
		}
	}()

	atx, err = w.txToOutputs(outputs, account, minconf, pool, chainClient,
		randomizeChangeIdx, w.RelayFee())
	txSucceeded = atx != nil

	return atx, err
}

// txToOutputs creates a signed transaction which includes each output from
// outputs.  Previous outputs to reedeem are chosen from the passed account's
// UTXO set and minconf policy. An additional output may be added to return
// change to the wallet.  An appropriate fee is included based on the wallet's
// current relay fee.  The wallet must be unlocked to create the transaction.
// The address pool passed must be locked and engaged in an address pool
// batch call.
//
// Decred: This func also sends the transaction, and if successful, inserts it
// into the database, rather than delegating this work to the caller as
// btcwallet does.
func (w *Wallet) txToOutputs(outputs []*wire.TxOut, account uint32, minconf int32,
	pool *addressPool, chainClient *chain.RPCClient, randomizeChangeIdx bool,
	txFee dcrutil.Amount) (atx *txauthor.AuthoredTx, err error) {

	// The change address is pulled here rather than after
	// MakeInputSource is called because MakeInputSource
	// accesses the database in a way that deadlocks other
	// packages that also access the database like waddmgr.
	// Because the address pool occasionally makes calls
	// to the address manager to replenish the address pool,
	// calling the address function after MakeInputSource
	// and before inputSource.CloseTransaction() will
	// sometimes cause a lockup.
	changeAddrUsed := false
	changeAddr, err := pool.getNewAddress()
	if err != nil {
		return nil, err
	}
	changeSource := func() ([]byte, error) {
		changeAddrUsed = true
		return txscript.PayToAddrScript(changeAddr)
	}

	// Get current block's height and hash.
	bs, err := chainClient.BlockStamp()
	if err != nil {
		return nil, err
	}

	inputSource := w.TxStore.MakeInputSource(account, minconf, bs.Height)
	tx, err := txauthor.NewUnsignedTransaction(outputs, txFee,
		inputSource.SelectInputs, changeSource)
	closeErr := inputSource.CloseTransaction()
	if closeErr != nil {
		log.Errorf("Failed to close view: %v", closeErr)
	}
	if err != nil {
		return nil, err
	}

	// Randomize change position, if change exists, before signing.  This
	// doesn't affect the serialize size, so the change amount will still be
	// valid.
	if tx.ChangeIndex >= 0 && randomizeChangeIdx {
		tx.RandomizeChangePosition()
	}

	err = tx.AddAllInputScripts(secretSource{w.Manager})
	if err != nil {
		return nil, err
	}

	err = validateMsgTx(tx.Tx, tx.PrevScripts)
	if err != nil {
		return nil, err
	}

	if tx.ChangeIndex >= 0 && account == waddrmgr.ImportedAddrAccount {
		changeAmount := dcrutil.Amount(tx.Tx.TxOut[tx.ChangeIndex].Value)
		log.Warnf("Spend from imported account produced change: moving"+
			" %v from imported account into default account.", changeAmount)
	}

	_, err = chainClient.SendRawTransaction(tx.Tx, w.AllowHighFees)
	if err != nil {
		return nil, err
	}

	// Create transaction record and insert into the db.
	rec, err := wtxmgr.NewTxRecordFromMsgTx(tx.Tx, time.Now())
	if err != nil {
		return nil, fmt.Errorf("Cannot create record for created transaction: %v",
			err)
	}
	err = w.TxStore.InsertTx(rec, nil)
	if err != nil {
		return nil, fmt.Errorf("Error adding sent tx history: %v", err)
	}
	err = w.insertCreditsIntoTxMgr(tx.Tx, rec)
	if err != nil {
		return nil, err
	}

	return tx, nil
}

// constructMultiSigScript create a multisignature output script from a
// given list of public keys.
func constructMultiSigScript(keys []dcrutil.AddressSecpPubKey,
	nRequired int) ([]byte, error) {
	keysesPrecious := make([]*dcrutil.AddressSecpPubKey, len(keys))

	return txscript.MultiSigScript(keysesPrecious, nRequired)
}

// txToMultisig spends funds to a multisig output, partially signs the
// transaction, then returns fund
func (w *Wallet) txToMultisig(account uint32, amount dcrutil.Amount,
	pubkeys []*dcrutil.AddressSecpPubKey, nRequired int8,
	minconf int32) (*CreatedTx, dcrutil.Address, []byte, error) {
	txToMultisigError :=
		func(err error) (*CreatedTx, dcrutil.Address, []byte, error) {
			return nil, nil, nil, err
		}

	// Initialize the address pool for use. If we
	// are using an imported account, loopback to
	// the default account to create change.
	var pool *addressPool
	if account == waddrmgr.ImportedAddrAccount {
		err := w.CheckAddressPoolsInitialized(waddrmgr.DefaultAccountNum)
		if err != nil {
			return txToMultisigError(err)
		}
		pool = w.addrPools[waddrmgr.DefaultAccountNum].internal
	} else {
		err := w.CheckAddressPoolsInitialized(account)
		if err != nil {
			return txToMultisigError(err)
		}
		pool = w.addrPools[account].internal
	}
	txSucceeded := false
	pool.mutex.Lock()
	defer pool.mutex.Unlock()
	defer func() {
		if txSucceeded {
			pool.BatchFinish()
		} else {
			pool.BatchRollback()
		}
	}()
	addrFunc := pool.getNewAddress

	chainClient, err := w.requireChainClient()
	if err != nil {
		return txToMultisigError(err)
	}

	isReorganizing, _ := chainClient.GetReorganizing()
	if isReorganizing {
		return txToMultisigError(err)
	}

	// Address manager must be unlocked to compose transaction.  Grab
	// the unlock if possible (to prevent future unlocks), or return the
	// error if already locked.
	heldUnlock, err := w.HoldUnlock()
	if err != nil {
		return txToMultisigError(err)
	}
	defer heldUnlock.Release()

	// Get current block's height and hash.
	bs, err := chainClient.BlockStamp()
	if err != nil {
		return txToMultisigError(err)
	}

	// Add in some extra for fees. TODO In the future, make a better
	// fee estimator.
	var feeEstForTx dcrutil.Amount
	switch {
	case w.chainParams == &chaincfg.MainNetParams:
		feeEstForTx = 5e7
	case w.chainParams == &chaincfg.TestNetParams:
		feeEstForTx = 5e7
	default:
		feeEstForTx = 3e4
	}
	amountRequired := amount + feeEstForTx

	// Instead of taking reward addresses by arg, just create them now  and
	// automatically find all eligible outputs from all current utxos.
	eligible, err := w.findEligibleOutputsAmount(account, minconf,
		amountRequired, bs)
	if err != nil {
		return txToMultisigError(err)
	}
	if eligible == nil {
		return txToMultisigError(
			fmt.Errorf("Not enough funds to send to multisig address"))
	}

	msgtx := wire.NewMsgTx()

	// Fill out inputs.
	var forSigning []wtxmgr.Credit
	totalInput := dcrutil.Amount(0)
	numInputs := 0
	for _, e := range eligible {
		msgtx.AddTxIn(wire.NewTxIn(&e.OutPoint, nil))
		totalInput += e.Amount
		forSigning = append(forSigning, e)

		numInputs++
	}

	// Insert a multi-signature output, then insert this P2SH
	// hash160 into the address manager and the transaction
	// manager.
	totalOutput := dcrutil.Amount(0)
	msScript, err := txscript.MultiSigScript(pubkeys, int(nRequired))
	if err != nil {
		return txToMultisigError(err)
	}
	_, err = w.Manager.ImportScript(msScript, bs)
	if err != nil {
		// We don't care if we've already used this address.
		if err.(waddrmgr.ManagerError).ErrorCode !=
			waddrmgr.ErrDuplicateAddress {
			return txToMultisigError(err)
		}
	}
	err = w.TxStore.InsertTxScript(msScript)
	if err != nil {
		return txToMultisigError(err)
	}
	scAddr, err := dcrutil.NewAddressScriptHash(msScript, w.chainParams)
	if err != nil {
		return txToMultisigError(err)
	}
	p2shScript, err := txscript.PayToAddrScript(scAddr)
	if err != nil {
		return txToMultisigError(err)
	}
	txout := wire.NewTxOut(int64(amount), p2shScript)
	msgtx.AddTxOut(txout)
	totalOutput += amount

	// Add change if we need it. The case in which
	// totalInput == amount+feeEst is skipped because
	// we don't need to add a change output in this
	// case.
	feeSize := estimateTxSize(numInputs, 2)
	feeIncrement := w.RelayFee()

	feeEst := feeForSize(feeIncrement, feeSize)

	if totalInput < amount+feeEst {
		return txToMultisigError(fmt.Errorf("Not enough funds to send to " +
			"multisig address after accounting for fees"))
	}
	if totalInput > amount+feeEst {
		changeAddr, err := addrFunc()
		if err != nil {
			return txToMultisigError(err)
		}
		change := totalInput - (amount + feeEst)
		pkScript, err := txscript.PayToAddrScript(changeAddr)
		if err != nil {
			return txToMultisigError(
				fmt.Errorf("cannot create txout script: %s", err))
		}
		msgtx.AddTxOut(wire.NewTxOut(int64(change), pkScript))
	}

	if err = signMsgTx(msgtx, forSigning, w.Manager,
		w.chainParams); err != nil {
		return txToMultisigError(err)
	}

	_, err = chainClient.SendRawTransaction(msgtx, w.AllowHighFees)
	if err != nil {
		return txToMultisigError(err)
	}

	// Request updates from dcrd for new transactions sent to this
	// script hash address.
	utilAddrs := make([]dcrutil.Address, 1)
	utilAddrs[0] = scAddr
	if err := chainClient.NotifyReceived(utilAddrs); err != nil {
		return txToMultisigError(err)
	}

	err = w.insertMultisigOutIntoTxMgr(msgtx, 0)
	if err != nil {
		return txToMultisigError(err)
	}

	ctx := &CreatedTx{
		MsgTx:       msgtx,
		ChangeAddr:  nil,
		ChangeIndex: -1,
	}

	return ctx, scAddr, msScript, nil
}

// validateMsgTx verifies transaction input scripts for tx.  All previous output
// scripts from outputs redeemed by the transaction, in the same order they are
// spent, must be passed in the prevScripts slice.
func validateMsgTx(tx *wire.MsgTx, prevScripts [][]byte) error {
	for i, prevScript := range prevScripts {
		vm, err := txscript.NewEngine(prevScript, tx, i,
			txscript.StandardVerifyFlags, txscript.DefaultScriptVersion, nil)
		if err != nil {
			return fmt.Errorf("cannot create script engine: %s", err)
		}
		err = vm.Execute()
		if err != nil {
			return fmt.Errorf("cannot validate transaction: %s", err)
		}
	}
	return nil
}

func validateMsgTxCredits(tx *wire.MsgTx, prevCredits []wtxmgr.Credit) error {
	prevScripts := make([][]byte, 0, len(prevCredits))
	for _, c := range prevCredits {
		prevScripts = append(prevScripts, c.PkScript)
	}
	return validateMsgTx(tx, prevScripts)
}

// compressWallet compresses all the utxos in a wallet into a single change
// address. For use when it becomes dusty.
func (w *Wallet) compressWallet(maxNumIns int, account uint32) (*chainhash.Hash,
	error) {
	chainClient, err := w.requireChainClient()
	if err != nil {
		return nil, err
	}

	isReorganizing, _ := chainClient.GetReorganizing()
	if isReorganizing {
		return nil, ErrBlockchainReorganizing
	}

	// Get current block's height and hash.
	bs, err := chainClient.BlockStamp()
	if err != nil {
		return nil, err
	}

	// Initialize the address pool for use. If we
	// are using an imported account, loopback to
	// the default account to create change.
	var pool *addressPool
	if account == waddrmgr.ImportedAddrAccount {
		err := w.CheckAddressPoolsInitialized(waddrmgr.DefaultAccountNum)
		if err != nil {
			return nil, err
		}
		pool = w.addrPools[waddrmgr.DefaultAccountNum].internal
	} else {
		err := w.CheckAddressPoolsInitialized(account)
		if err != nil {
			return nil, err
		}
		pool = w.addrPools[account].internal
	}
	txSucceeded := false
	pool.mutex.Lock()
	defer pool.mutex.Unlock()
	defer func() {
		if txSucceeded {
			pool.BatchFinish()
		} else {
			pool.BatchRollback()
		}
	}()
	addrFunc := pool.getNewAddress

	minconf := int32(1)
	eligible, err := w.findEligibleOutputs(account, minconf, bs)
	if err != nil {
		return nil, err
	}

	if len(eligible) == 0 {
		return nil, ErrNoOutsToConsolidate
	}

	txInCount := len(eligible)
	if maxNumIns < txInCount {
		txInCount = maxNumIns
	}

	// Get an initial fee estimate based on the number of selected inputs
	// and added outputs, with no change.
	szEst := estimateTxSize(txInCount, 1)
	var feeIncrement dcrutil.Amount
	feeIncrement = w.RelayFee()

	feeEst := feeForSize(feeIncrement, szEst)

	msgtx := wire.NewMsgTx()

	// Add the txins using all the eligible outputs.
	totalAdded := dcrutil.Amount(0)
	count := 0
	var forSigning []wtxmgr.Credit
	for _, e := range eligible {
		if count >= maxNumIns {
			break
		}
		msgtx.AddTxIn(wire.NewTxIn(&e.OutPoint, nil))
		totalAdded += e.Amount
		forSigning = append(forSigning, e)

		count++
	}

	outputAmt := totalAdded - feeEst

	changeAddr, err := addrFunc()
	if err != nil {
		return nil, err
	}

	pkScript, err := txscript.PayToAddrScript(changeAddr)
	if err != nil {
		return nil, fmt.Errorf("cannot create txout script: %s", err)
	}
	msgtx.AddTxOut(wire.NewTxOut(int64(outputAmt), pkScript))

	if err = signMsgTx(msgtx, forSigning, w.Manager,
		w.chainParams); err != nil {
		return nil, err
	}
	if err := validateMsgTxCredits(msgtx, forSigning); err != nil {
		return nil, err
	}

	txSha, err := chainClient.SendRawTransaction(msgtx, w.AllowHighFees)
	if err != nil {
		return nil, err
	}
	txSucceeded = true<commit_msg>wallet: limit the tx size with compressWallet/consolidate. (#327)<commit_after>// Copyright (c) 2013-2016 The btcsuite developers
// Copyright (c) 2015-2016 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package wallet

import (
	"crypto/rand"
	"errors"
	"fmt"
	"time"

	"github.com/btcsuite/golangcrypto/ripemd160"

	"github.com/decred/dcrd/blockchain/stake"
	"github.com/decred/dcrd/chaincfg"
	"github.com/decred/dcrd/chaincfg/chainec"
	"github.com/decred/dcrd/chaincfg/chainhash"
	"github.com/decred/dcrd/dcrjson"
	"github.com/decred/dcrd/txscript"
	"github.com/decred/dcrd/wire"
	"github.com/decred/dcrutil"
	"github.com/decred/dcrwallet/chain"
	"github.com/decred/dcrwallet/waddrmgr"
	"github.com/decred/dcrwallet/wallet/txauthor"
	"github.com/decred/dcrwallet/wallet/txrules"
	"github.com/decred/dcrwallet/wtxmgr"
)

// --------------------------------------------------------------------------------
// Constants and simple functions

const (
	// All transactions have 4 bytes for version, 4 bytes of locktime,
	// 4 bytes of expiry, and 2 varints for the number of inputs and
	// outputs, and 1 varint for the witnesses.
	txOverheadEstimate = 4 + 4 + 4 + 1 + 1 + 1

	// A worst case signature script to redeem a P2PKH output for a
	// compressed pubkey has 73 bytes of the possible DER signature
	// (with no leading 0 bytes for R and S), 65 bytes of serialized pubkey,
	// and data push opcodes for both, plus one byte for the hash type flag
	// appended to the end of the signature.
	sigScriptEstimate = 1 + 73 + 1 + 65 + 1

	// A best case tx input serialization cost is chainhash.HashSize, 4 bytes
	// of output index, 1 byte for tree, 4 bytes of sequence, 16 bytes for
	// fraud proof, and the estimated signature script size.
	txInEstimate = chainhash.HashSize + 4 + 1 + 8 + 4 + 4 + sigScriptEstimate

	// sstxTicketCommitmentEstimate =
	// - version + amount +
	// OP_SSTX OP_DUP OP_HASH160 OP_DATA_20 OP_EQUALVERIFY OP_CHECKSIG
	sstxTicketCommitmentEstimate = 2 + 8 + 1 + 1 + 1 + 1 + 20 + 1 + 1

	// sstxSubsidyCommitmentEstimate =
	// version + amount + OP_RETURN OP_DATA_30
	sstxSubsidyCommitmentEstimate = 2 + 8 + 2 + 30

	// sstxChangeOutputEstimate =
	// version + amount + OP_SSTXCHANGE OP_DUP OP_HASH160 OP_DATA_20
	//	OP_EQUALVERIFY OP_CHECKSIG
	sstxChangeOutputEstimate = 2 + 8 + 1 + 1 + 1 + 1 + 20 + 1 + 1

	// A P2PKH pkScript contains the following bytes:
	//  - OP_DUP
	//  - OP_HASH160
	//  - OP_DATA_20 + 20 bytes of pubkey hash
	//  - OP_EQUALVERIFY
	//  - OP_CHECKSIG
	pkScriptEstimate = 1 + 1 + 1 + 20 + 1 + 1

	// pkScriptEstimateSS is the estimated size of a ticket P2PKH output script.
	pkScriptEstimateSS = 1 + 1 + 1 + 1 + 20 + 1 + 1

	// txOutEstimate is a best case tx output serialization cost is 8 bytes
	// of value, two bytes of version, one byte of varint, and the pkScript
	// size.
	txOutEstimate = 8 + 2 + 1 + pkScriptEstimate

	// ssTxOutEsimate is the estimated size of a P2PKH ticket output.
	ssTxOutEsimate = 8 + 2 + 1 + pkScriptEstimateSS

	// singleInputTicketSize is the typical size of a normal P2PKH ticket
	// in bytes when the ticket has one input, rounded up.
	singleInputTicketSize = 300

	// doubleInputTicketSize is the typical size of a normal P2PKH ticket
	// in bytes when the ticket has two inputs, rounded up.
	doubleInputTicketSize = 550

	// defaultTicketFeeLimits is the default byte string for the default
	// fee limits imposed on a ticket.
	defaultTicketFeeLimits = 0x5800

	// maxStandardTxSize is the maximum size allowed for transactions that
	// are considered standard and will therefore be relayed and considered
	// for mining.
	// TODO: import from dcrd.
	maxStandardTxSize = 100000
)

var (
	// maxTxSize is the maximum size of a transaction we can
	// build with the wallet.
	maxTxSize = chaincfg.MainNetParams.MaximumBlockSize - 75000
)

func estimateTxSize(numInputs, numOutputs int) int {
	return txOverheadEstimate + txInEstimate*numInputs + txOutEstimate*numOutputs
}

// EstimateTxSize is the exported version of estimateTxSize which provides
// an estimate of the tx size based on the number of inputs, outputs, and some
// assumed overhead.
func EstimateTxSize(numInputs, numOutputs int) int {
	return estimateTxSize(numInputs, numOutputs)
}

func estimateSSTxSize(numInputs int) int {
	return txOverheadEstimate + txInEstimate*numInputs +
		sstxTicketCommitmentEstimate +
		(sstxSubsidyCommitmentEstimate+
			sstxChangeOutputEstimate)*numInputs
}

func feeForSize(incr dcrutil.Amount, sz int) dcrutil.Amount {
	return dcrutil.Amount(1+sz/1000) * incr
}

// FeeForSize is the exported version of feeForSize which returns a fee
// based on the provided feeIncrement and provided size.
func FeeForSize(incr dcrutil.Amount, sz int) dcrutil.Amount {
	return feeForSize(incr, sz)
}

// DefaultTicketFeeIncrement is the default minimum stake transaction fees per KB (0.01
// coin, measured in atoms).
const DefaultTicketFeeIncrement dcrutil.Amount = 1e6

// EstMaxTicketFeeAmount is the estimated max ticket fee to be used for size
// calculation for eligible utxos for ticket purchasing.
const EstMaxTicketFeeAmount = 0.1 * 1e8

// extendedOutPoint is a UTXO with an amount.
type extendedOutPoint struct {
	op       *wire.OutPoint
	amt      int64
	pkScript []byte
}

// --------------------------------------------------------------------------------
// Error Handling

// ErrUnsupportedTransactionType represents an error where a transaction
// cannot be signed as the API only supports spending P2PKH outputs.
var ErrUnsupportedTransactionType = errors.New("Only P2PKH transactions " +
	"are supported")

// ErrNonPositiveAmount represents an error where an amount is
// not positive (either negative, or zero).
var ErrNonPositiveAmount = errors.New("amount is not positive")

// ErrNegativeFee represents an error where a fee is erroneously
// negative.
var ErrNegativeFee = errors.New("fee is negative")

// ErrSStxNotEnoughFunds indicates that not enough funds were available in the
// wallet to purchase a ticket.
var ErrSStxNotEnoughFunds = errors.New("not enough to purchase sstx")

// ErrSStxPriceExceedsSpendLimit indicates that the current ticket price exceeds
// the specified spend maximum spend limit.
var ErrSStxPriceExceedsSpendLimit = errors.New("ticket price exceeds spend limit")

// ErrNoOutsToConsolidate indicates that there were no outputs available
// to compress.
var ErrNoOutsToConsolidate = errors.New("no outputs to consolidate")

// ErrBlockchainReorganizing indicates that the blockchain is currently
// reorganizing.
var ErrBlockchainReorganizing = errors.New("blockchain is currently " +
	"reorganizing")

// ErrTicketPriceNotSet indicates that the wallet was recently connected
// and that the ticket price has not yet been set.
var ErrTicketPriceNotSet = errors.New("ticket price not yet established")

// --------------------------------------------------------------------------------
// Transaction creation

// secretSource is an implementation of txauthor.SecretSource for the wallet's
// address manager.
type secretSource struct {
	*waddrmgr.Manager
}

func (s secretSource) GetKey(addr dcrutil.Address) (chainec.PrivateKey, bool, error) {
	ma, err := s.Address(addr)
	if err != nil {
		return nil, false, err
	}
	mpka, ok := ma.(waddrmgr.ManagedPubKeyAddress)
	if !ok {
		e := fmt.Errorf("managed address type for %v is `%T` but "+
			"want waddrmgr.ManagedPubKeyAddress", addr, ma)
		return nil, false, e
	}
	privKey, err := mpka.PrivKey()
	if err != nil {
		return nil, false, err
	}
	return privKey, ma.Compressed(), nil
}

func (s secretSource) GetScript(addr dcrutil.Address) ([]byte, error) {
	ma, err := s.Address(addr)
	if err != nil {
		return nil, err
	}
	msa, ok := ma.(waddrmgr.ManagedScriptAddress)
	if !ok {
		e := fmt.Errorf("managed address type for %v is `%T` but "+
			"want waddrmgr.ManagedScriptAddress", addr, ma)
		return nil, e
	}
	return msa.Script()
}

// CreatedTx holds the state of a newly-created transaction and the change
// output (if one was added).
type CreatedTx struct {
	MsgTx       *wire.MsgTx
	ChangeAddr  dcrutil.Address
	ChangeIndex int // negative if no change
	Fee         dcrutil.Amount
}

// insertIntoTxMgr inserts a newly created transaction into the tx store
// as unconfirmed.
func (w *Wallet) insertIntoTxMgr(msgTx *wire.MsgTx) (*wtxmgr.TxRecord, error) {
	// Create transaction record and insert into the db.
	rec, err := wtxmgr.NewTxRecordFromMsgTx(msgTx, time.Now())
	if err != nil {
		return nil, dcrjson.ErrInternal
	}

	return rec, w.TxStore.InsertTx(rec, nil)
}

func (w *Wallet) insertCreditsIntoTxMgr(msgTx *wire.MsgTx,
	rec *wtxmgr.TxRecord) error {
	// Check every output to determine whether it is controlled by a wallet
	// key.  If so, mark the output as a credit.
	for i, output := range msgTx.TxOut {
		_, addrs, _, err := txscript.ExtractPkScriptAddrs(output.Version,
			output.PkScript, w.chainParams)
		if err != nil {
			// Non-standard outputs are skipped.
			continue
		}
		for _, addr := range addrs {
			ma, err := w.Manager.Address(addr)
			if err == nil {
				// TODO: Credits should be added with the
				// account they belong to, so wtxmgr is able to
				// track per-account balances.
				err = w.TxStore.AddCredit(rec, nil, uint32(i),
					ma.Internal(), ma.Account())
				if err != nil {
					return err
				}
				err = w.Manager.MarkUsed(addr)
				if err != nil {
					return err
				}
				log.Debugf("Marked address %v used", addr)
				continue
			}

			// Missing addresses are skipped.  Other errors should
			// be propagated.
			code := err.(waddrmgr.ManagerError).ErrorCode
			if code != waddrmgr.ErrAddressNotFound {
				return err
			}
		}
	}

	return nil
}

// insertMultisigOutIntoTxMgr inserts a multisignature output into the
// transaction store database.
func (w *Wallet) insertMultisigOutIntoTxMgr(msgTx *wire.MsgTx,
	index uint32) error {
	// Create transaction record and insert into the db.
	rec, err := wtxmgr.NewTxRecordFromMsgTx(msgTx, time.Now())
	if err != nil {
		return dcrjson.ErrInternal
	}

	return w.TxStore.AddMultisigOut(rec, nil, index)
}

// TxToOutputs is the exported version of txToOutputs that does all relevant
// locking to ensure the safety of the wallet state to generate a transaction.
// It then calls txToOutputs to generate a transaction.
func (w *Wallet) TxToOutputs(outputs []*wire.TxOut, account uint32, minconf int32,
	randomizeChangeIdx bool) (atx *txauthor.AuthoredTx, err error) {
	// Address manager must be unlocked to compose transaction.  Grab
	// the unlock if possible (to prevent future unlocks), or return the
	// error if already locked.
	heldUnlock, err := w.HoldUnlock()
	if err != nil {
		return nil, err
	}
	defer heldUnlock.Release()

	chainClient, err := w.requireChainClient()
	if err != nil {
		return nil, err
	}

	isReorganizing, _ := chainClient.GetReorganizing()
	if isReorganizing {
		return nil, ErrBlockchainReorganizing
	}

	// Initialize the address pool for use. If we
	// are using an imported account, loopback to
	// the default account to create change.
	var pool *addressPool
	if account == waddrmgr.ImportedAddrAccount {
		err := w.CheckAddressPoolsInitialized(waddrmgr.DefaultAccountNum)
		if err != nil {
			return nil, err
		}
		pool = w.addrPools[waddrmgr.DefaultAccountNum].internal
	} else {
		err := w.CheckAddressPoolsInitialized(account)
		if err != nil {
			return nil, err
		}
		pool = w.addrPools[account].internal
	}
	changeAddrUsed := false
	txSucceeded := false
	pool.mutex.Lock()
	defer pool.mutex.Unlock()
	defer func() {
		if txSucceeded && changeAddrUsed {
			pool.BatchFinish()
		} else {
			pool.BatchRollback()
		}
	}()

	atx, err = w.txToOutputs(outputs, account, minconf, pool, chainClient,
		randomizeChangeIdx, w.RelayFee())
	txSucceeded = atx != nil

	return atx, err
}

// txToOutputs creates a signed transaction which includes each output from
// outputs.  Previous outputs to reedeem are chosen from the passed account's
// UTXO set and minconf policy. An additional output may be added to return
// change to the wallet.  An appropriate fee is included based on the wallet's
// current relay fee.  The wallet must be unlocked to create the transaction.
// The address pool passed must be locked and engaged in an address pool
// batch call.
//
// Decred: This func also sends the transaction, and if successful, inserts it
// into the database, rather than delegating this work to the caller as
// btcwallet does.
func (w *Wallet) txToOutputs(outputs []*wire.TxOut, account uint32, minconf int32,
	pool *addressPool, chainClient *chain.RPCClient, randomizeChangeIdx bool,
	txFee dcrutil.Amount) (atx *txauthor.AuthoredTx, err error) {

	// The change address is pulled here rather than after
	// MakeInputSource is called because MakeInputSource
	// accesses the database in a way that deadlocks other
	// packages that also access the database like waddmgr.
	// Because the address pool occasionally makes calls
	// to the address manager to replenish the address pool,
	// calling the address function after MakeInputSource
	// and before inputSource.CloseTransaction() will
	// sometimes cause a lockup.
	changeAddrUsed := false
	changeAddr, err := pool.getNewAddress()
	if err != nil {
		return nil, err
	}
	changeSource := func() ([]byte, error) {
		changeAddrUsed = true
		return txscript.PayToAddrScript(changeAddr)
	}

	// Get current block's height and hash.
	bs, err := chainClient.BlockStamp()
	if err != nil {
		return nil, err
	}

	inputSource := w.TxStore.MakeInputSource(account, minconf, bs.Height)
	tx, err := txauthor.NewUnsignedTransaction(outputs, txFee,
		inputSource.SelectInputs, changeSource)
	closeErr := inputSource.CloseTransaction()
	if closeErr != nil {
		log.Errorf("Failed to close view: %v", closeErr)
	}
	if err != nil {
		return nil, err
	}

	// Randomize change position, if change exists, before signing.  This
	// doesn't affect the serialize size, so the change amount will still be
	// valid.
	if tx.ChangeIndex >= 0 && randomizeChangeIdx {
		tx.RandomizeChangePosition()
	}

	err = tx.AddAllInputScripts(secretSource{w.Manager})
	if err != nil {
		return nil, err
	}

	err = validateMsgTx(tx.Tx, tx.PrevScripts)
	if err != nil {
		return nil, err
	}

	if tx.ChangeIndex >= 0 && account == waddrmgr.ImportedAddrAccount {
		changeAmount := dcrutil.Amount(tx.Tx.TxOut[tx.ChangeIndex].Value)
		log.Warnf("Spend from imported account produced change: moving"+
			" %v from imported account into default account.", changeAmount)
	}

	_, err = chainClient.SendRawTransaction(tx.Tx, w.AllowHighFees)
	if err != nil {
		return nil, err
	}

	// Create transaction record and insert into the db.
	rec, err := wtxmgr.NewTxRecordFromMsgTx(tx.Tx, time.Now())
	if err != nil {
		return nil, fmt.Errorf("Cannot create record for created transaction: %v",
			err)
	}
	err = w.TxStore.InsertTx(rec, nil)
	if err != nil {
		return nil, fmt.Errorf("Error adding sent tx history: %v", err)
	}
	err = w.insertCreditsIntoTxMgr(tx.Tx, rec)
	if err != nil {
		return nil, err
	}

	return tx, nil
}

// constructMultiSigScript create a multisignature output script from a
// given list of public keys.
func constructMultiSigScript(keys []dcrutil.AddressSecpPubKey,
	nRequired int) ([]byte, error) {
	keysesPrecious := make([]*dcrutil.AddressSecpPubKey, len(keys))

	return txscript.MultiSigScript(keysesPrecious, nRequired)
}

// txToMultisig spends funds to a multisig output, partially signs the
// transaction, then returns fund
func (w *Wallet) txToMultisig(account uint32, amount dcrutil.Amount,
	pubkeys []*dcrutil.AddressSecpPubKey, nRequired int8,
	minconf int32) (*CreatedTx, dcrutil.Address, []byte, error) {
	txToMultisigError :=
		func(err error) (*CreatedTx, dcrutil.Address, []byte, error) {
			return nil, nil, nil, err
		}

	// Initialize the address pool for use. If we
	// are using an imported account, loopback to
	// the default account to create change.
	var pool *addressPool
	if account == waddrmgr.ImportedAddrAccount {
		err := w.CheckAddressPoolsInitialized(waddrmgr.DefaultAccountNum)
		if err != nil {
			return txToMultisigError(err)
		}
		pool = w.addrPools[waddrmgr.DefaultAccountNum].internal
	} else {
		err := w.CheckAddressPoolsInitialized(account)
		if err != nil {
			return txToMultisigError(err)
		}
		pool = w.addrPools[account].internal
	}
	txSucceeded := false
	pool.mutex.Lock()
	defer pool.mutex.Unlock()
	defer func() {
		if txSucceeded {
			pool.BatchFinish()
		} else {
			pool.BatchRollback()
		}
	}()
	addrFunc := pool.getNewAddress

	chainClient, err := w.requireChainClient()
	if err != nil {
		return txToMultisigError(err)
	}

	isReorganizing, _ := chainClient.GetReorganizing()
	if isReorganizing {
		return txToMultisigError(err)
	}

	// Address manager must be unlocked to compose transaction.  Grab
	// the unlock if possible (to prevent future unlocks), or return the
	// error if already locked.
	heldUnlock, err := w.HoldUnlock()
	if err != nil {
		return txToMultisigError(err)
	}
	defer heldUnlock.Release()

	// Get current block's height and hash.
	bs, err := chainClient.BlockStamp()
	if err != nil {
		return txToMultisigError(err)
	}

	// Add in some extra for fees. TODO In the future, make a better
	// fee estimator.
	var feeEstForTx dcrutil.Amount
	switch {
	case w.chainParams == &chaincfg.MainNetParams:
		feeEstForTx = 5e7
	case w.chainParams == &chaincfg.TestNetParams:
		feeEstForTx = 5e7
	default:
		feeEstForTx = 3e4
	}
	amountRequired := amount + feeEstForTx

	// Instead of taking reward addresses by arg, just create them now  and
	// automatically find all eligible outputs from all current utxos.
	eligible, err := w.findEligibleOutputsAmount(account, minconf,
		amountRequired, bs)
	if err != nil {
		return txToMultisigError(err)
	}
	if eligible == nil {
		return txToMultisigError(
			fmt.Errorf("Not enough funds to send to multisig address"))
	}

	msgtx := wire.NewMsgTx()

	// Fill out inputs.
	var forSigning []wtxmgr.Credit
	totalInput := dcrutil.Amount(0)
	numInputs := 0
	for _, e := range eligible {
		msgtx.AddTxIn(wire.NewTxIn(&e.OutPoint, nil))
		totalInput += e.Amount
		forSigning = append(forSigning, e)

		numInputs++
	}

	// Insert a multi-signature output, then insert this P2SH
	// hash160 into the address manager and the transaction
	// manager.
	totalOutput := dcrutil.Amount(0)
	msScript, err := txscript.MultiSigScript(pubkeys, int(nRequired))
	if err != nil {
		return txToMultisigError(err)
	}
	_, err = w.Manager.ImportScript(msScript, bs)
	if err != nil {
		// We don't care if we've already used this address.
		if err.(waddrmgr.ManagerError).ErrorCode !=
			waddrmgr.ErrDuplicateAddress {
			return txToMultisigError(err)
		}
	}
	err = w.TxStore.InsertTxScript(msScript)
	if err != nil {
		return txToMultisigError(err)
	}
	scAddr, err := dcrutil.NewAddressScriptHash(msScript, w.chainParams)
	if err != nil {
		return txToMultisigError(err)
	}
	p2shScript, err := txscript.PayToAddrScript(scAddr)
	if err != nil {
		return txToMultisigError(err)
	}
	txout := wire.NewTxOut(int64(amount), p2shScript)
	msgtx.AddTxOut(txout)
	totalOutput += amount

	// Add change if we need it. The case in which
	// totalInput == amount+feeEst is skipped because
	// we don't need to add a change output in this
	// case.
	feeSize := estimateTxSize(numInputs, 2)
	feeIncrement := w.RelayFee()

	feeEst := feeForSize(feeIncrement, feeSize)

	if totalInput < amount+feeEst {
		return txToMultisigError(fmt.Errorf("Not enough funds to send to " +
			"multisig address after accounting for fees"))
	}
	if totalInput > amount+feeEst {
		changeAddr, err := addrFunc()
		if err != nil {
			return txToMultisigError(err)
		}
		change := totalInput - (amount + feeEst)
		pkScript, err := txscript.PayToAddrScript(changeAddr)
		if err != nil {
			return txToMultisigError(
				fmt.Errorf("cannot create txout script: %s", err))
		}
		msgtx.AddTxOut(wire.NewTxOut(int64(change), pkScript))
	}

	if err = signMsgTx(msgtx, forSigning, w.Manager,
		w.chainParams); err != nil {
		return txToMultisigError(err)
	}

	_, err = chainClient.SendRawTransaction(msgtx, w.AllowHighFees)
	if err != nil {
		return txToMultisigError(err)
	}

	// Request updates from dcrd for new transactions sent to this
	// script hash address.
	utilAddrs := make([]dcrutil.Address, 1)
	utilAddrs[0] = scAddr
	if err := chainClient.NotifyReceived(utilAddrs); err != nil {
		return txToMultisigError(err)
	}

	err = w.insertMultisigOutIntoTxMgr(msgtx, 0)
	if err != nil {
		return txToMultisigError(err)
	}

	ctx := &CreatedTx{
		MsgTx:       msgtx,
		ChangeAddr:  nil,
		ChangeIndex: -1,
	}

	return ctx, scAddr, msScript, nil
}

// validateMsgTx verifies transaction input scripts for tx.  All previous output
// scripts from outputs redeemed by the transaction, in the same order they are
// spent, must be passed in the prevScripts slice.
func validateMsgTx(tx *wire.MsgTx, prevScripts [][]byte) error {
	for i, prevScript := range prevScripts {
		vm, err := txscript.NewEngine(prevScript, tx, i,
			txscript.StandardVerifyFlags, txscript.DefaultScriptVersion, nil)
		if err != nil {
			return fmt.Errorf("cannot create script engine: %s", err)
		}
		err = vm.Execute()
		if err != nil {
			return fmt.Errorf("cannot validate transaction: %s", err)
		}
	}
	return nil
}

func validateMsgTxCredits(tx *wire.MsgTx, prevCredits []wtxmgr.Credit) error {
	prevScripts := make([][]byte, 0, len(prevCredits))
	for _, c := range prevCredits {
		prevScripts = append(prevScripts, c.PkScript)
	}
	return validateMsgTx(tx, prevScripts)
}

// compressWallet compresses all the utxos in a wallet into a single change
// address. For use when it becomes dusty.
func (w *Wallet) compressWallet(maxNumIns int, account uint32) (*chainhash.Hash,
	error) {
	chainClient, err := w.requireChainClient()
	if err != nil {
		return nil, err
	}

	isReorganizing, _ := chainClient.GetReorganizing()
	if isReorganizing {
		return nil, ErrBlockchainReorganizing
	}

	// Get current block's height and hash.
	bs, err := chainClient.BlockStamp()
	if err != nil {
		return nil, err
	}

	// Initialize the address pool for use. If we
	// are using an imported account, loopback to
	// the default account to create change.
	var pool *addressPool
	if account == waddrmgr.ImportedAddrAccount {
		err := w.CheckAddressPoolsInitialized(waddrmgr.DefaultAccountNum)
		if err != nil {
			return nil, err
		}
		pool = w.addrPools[waddrmgr.DefaultAccountNum].internal
	} else {
		err := w.CheckAddressPoolsInitialized(account)
		if err != nil {
			return nil, err
		}
		pool = w.addrPools[account].internal
	}
	txSucceeded := false
	pool.mutex.Lock()
	defer pool.mutex.Unlock()
	defer func() {
		if txSucceeded {
			pool.BatchFinish()
		} else {
			pool.BatchRollback()
		}
	}()
	addrFunc := pool.getNewAddress

	minconf := int32(1)
	eligible, err := w.findEligibleOutputs(account, minconf, bs)
	if err != nil {
		return nil, err
	}

	if len(eligible) == 0 {
		return nil, ErrNoOutsToConsolidate
	}

	txInCount := len(eligible)
	if maxNumIns < txInCount {
		txInCount = maxNumIns
	}

	// Get an initial fee estimate based on the number of selected inputs
	// and added outputs, with no change.
	szEst := estimateTxSize(txInCount, 1)
	var feeIncrement dcrutil.Amount
	feeIncrement = w.RelayFee()

	feeEst := feeForSize(feeIncrement, szEst)

	changeAddr, err := addrFunc()
	if err != nil {
		return nil, err
	}
	pkScript, err := txscript.PayToAddrScript(changeAddr)
	if err != nil {
		return nil, fmt.Errorf("cannot create txout script: %s", err)
	}
	msgtx := wire.NewMsgTx()
	msgtx.AddTxOut(wire.NewTxOut(0, pkScript))
	msgTxSize := msgtx.SerializeSize()
	maximumTxSize := maxTxSize
	if w.chainParams.Net == wire.MainNet {
		maximumTxSize = maxStandardTxSize
	}

	// Add the txins using all the eligible outputs.
	totalAdded := dcrutil.Amount(0)
	count := 0
	var forSigning []wtxmgr.Credit
	for _, e := range eligible {
		if count >= maxNumIns {
			break
		}
		// Add the size of a wire.OutPoint
		msgTxSize += txInEstimate
		if msgTxSize > maximumTxSize {
			break
		}
		msgtx.AddTxIn(wire.NewTxIn(&e.OutPoint, nil))
		totalAdded += e.Amount
		forSigning = append(forSigning, e)

		count++
	}

	msgtx.TxOut[0].Value = int64(totalAdded - feeEst)

	if err = signMsgTx(msgtx, forSigning, w.Manager,
		w.chainParams); err != nil {
		return nil, err
	}
	if err := validateMsgTxCredits(msgtx, forSigning); err != nil {
		return nil, err
	}

	txSha, err := chainClient.SendRawTransaction(msgtx, w.AllowHighFees)
	if err != nil {
		return nil, err
	}
	txSucceeded = true
{'fraction_non_alphanumeric': 0.10872960420862275, 'fraction_numerical': 0.009062512843697341, 'mean_word_length': 3.650960527573354, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 12, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 9, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5960260', 'n_tokens_mistral': 16982, 'n_tokens_neox': 15920, 'n_words': 5036}