wallet: include input values during utxo selection and tx validation

When spending a segwit output, the wallet also needs the input value of
the previous output script. Therefore when selecting outputs the input
value is now returned. Additionally when validating newly signed
outputs the input value as also passed into `txscript.Engine`
This commit is contained in:
Olaoluwa Osuntokun 2016-04-25 12:33:37 -07:00
parent cb225e2add
commit 3d464a0bbc

View file

@ -35,8 +35,11 @@ func makeInputSource(eligible []wtxmgr.Credit) txauthor.InputSource {
currentTotal := btcutil.Amount(0) currentTotal := btcutil.Amount(0)
currentInputs := make([]*wire.TxIn, 0, len(eligible)) currentInputs := make([]*wire.TxIn, 0, len(eligible))
currentScripts := make([][]byte, 0, len(eligible)) currentScripts := make([][]byte, 0, len(eligible))
currentInputValues := make([]btcutil.Amount, 0, len(eligible))
return func(target btcutil.Amount) (btcutil.Amount, []*wire.TxIn,
[]btcutil.Amount, [][]byte, error) {
return func(target btcutil.Amount) (btcutil.Amount, []*wire.TxIn, [][]byte, error) {
for currentTotal < target && len(eligible) != 0 { for currentTotal < target && len(eligible) != 0 {
nextCredit := &eligible[0] nextCredit := &eligible[0]
eligible = eligible[1:] eligible = eligible[1:]
@ -44,8 +47,9 @@ func makeInputSource(eligible []wtxmgr.Credit) txauthor.InputSource {
currentTotal += nextCredit.Amount currentTotal += nextCredit.Amount
currentInputs = append(currentInputs, nextInput) currentInputs = append(currentInputs, nextInput)
currentScripts = append(currentScripts, nextCredit.PkScript) currentScripts = append(currentScripts, nextCredit.PkScript)
currentInputValues = append(currentInputValues, nextCredit.Amount)
} }
return currentTotal, currentInputs, currentScripts, nil return currentTotal, currentInputs, currentInputValues, currentScripts, nil
} }
} }
@ -60,6 +64,7 @@ func (s secretSource) GetKey(addr btcutil.Address) (*btcec.PrivateKey, bool, err
if err != nil { if err != nil {
return nil, false, err return nil, false, err
} }
mpka, ok := ma.(waddrmgr.ManagedPubKeyAddress) mpka, ok := ma.(waddrmgr.ManagedPubKeyAddress)
if !ok { if !ok {
e := fmt.Errorf("managed address type for %v is `%T` but "+ e := fmt.Errorf("managed address type for %v is `%T` but "+
@ -78,6 +83,7 @@ func (s secretSource) GetScript(addr btcutil.Address) ([]byte, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
msa, ok := ma.(waddrmgr.ManagedScriptAddress) msa, ok := ma.(waddrmgr.ManagedScriptAddress)
if !ok { if !ok {
e := fmt.Errorf("managed address type for %v is `%T` but "+ e := fmt.Errorf("managed address type for %v is `%T` but "+
@ -124,9 +130,11 @@ func (w *Wallet) txToOutputs(outputs []*wire.TxOut, account uint32, minconf int3
// the imported account, change addresses are created from account 0. // the imported account, change addresses are created from account 0.
var changeAddr btcutil.Address var changeAddr btcutil.Address
if account == waddrmgr.ImportedAddrAccount { if account == waddrmgr.ImportedAddrAccount {
changeAddr, err = w.NewChangeAddress(0) changeAddr, err = w.NewChangeAddress(0,
waddrmgr.WitnessPubKey)
} else { } else {
changeAddr, err = w.NewChangeAddress(account) changeAddr, err = w.NewChangeAddress(account,
waddrmgr.WitnessPubKey)
} }
if err != nil { if err != nil {
return nil, err return nil, err
@ -151,7 +159,7 @@ func (w *Wallet) txToOutputs(outputs []*wire.TxOut, account uint32, minconf int3
return nil, err return nil, err
} }
err = validateMsgTx(tx.Tx, tx.PrevScripts) err = validateMsgTx(tx.Tx, tx.PrevScripts, tx.PrevInputValues)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -221,10 +229,10 @@ func (w *Wallet) findEligibleOutputs(account uint32, minconf int32, bs *waddrmgr
// validateMsgTx verifies transaction input scripts for tx. All previous output // validateMsgTx verifies transaction input scripts for tx. All previous output
// scripts from outputs redeemed by the transaction, in the same order they are // scripts from outputs redeemed by the transaction, in the same order they are
// spent, must be passed in the prevScripts slice. // spent, must be passed in the prevScripts slice.
func validateMsgTx(tx *wire.MsgTx, prevScripts [][]byte) error { func validateMsgTx(tx *wire.MsgTx, prevScripts [][]byte, inputValues []btcutil.Amount) error {
for i, prevScript := range prevScripts { for i, prevScript := range prevScripts {
vm, err := txscript.NewEngine(prevScript, tx, i, vm, err := txscript.NewEngine(prevScript, tx, i,
txscript.StandardVerifyFlags, nil, nil, 0) txscript.StandardVerifyFlags, nil, nil, int64(inputValues[i]))
if err != nil { if err != nil {
return fmt.Errorf("cannot create script engine: %s", err) return fmt.Errorf("cannot create script engine: %s", err)
} }