decred.org/dcrwallet/v3@v3.1.0/wallet/multisig.go (about)

     1  // Copyright (c) 2016 The Decred developers
     2  // Use of this source code is governed by an ISC
     3  // license that can be found in the LICENSE file.
     4  
     5  package wallet
     6  
     7  import (
     8  	"context"
     9  
    10  	"decred.org/dcrwallet/v3/errors"
    11  	"decred.org/dcrwallet/v3/wallet/txrules"
    12  	"decred.org/dcrwallet/v3/wallet/txsizes"
    13  	"decred.org/dcrwallet/v3/wallet/udb"
    14  	"decred.org/dcrwallet/v3/wallet/walletdb"
    15  	"github.com/decred/dcrd/txscript/v4/stdaddr"
    16  	"github.com/decred/dcrd/wire"
    17  )
    18  
    19  // FetchP2SHMultiSigOutput fetches information regarding a wallet's P2SH
    20  // multi-signature output.
    21  func (w *Wallet) FetchP2SHMultiSigOutput(ctx context.Context, outPoint *wire.OutPoint) (*P2SHMultiSigOutput, error) {
    22  	const op errors.Op = "wallet.FetchP2SHMultiSigOutput"
    23  
    24  	var (
    25  		mso          *udb.MultisigOut
    26  		redeemScript []byte
    27  	)
    28  	err := walletdb.View(ctx, w.db, func(tx walletdb.ReadTx) error {
    29  		addrmgrNs := tx.ReadBucket(waddrmgrNamespaceKey)
    30  		txmgrNs := tx.ReadBucket(wtxmgrNamespaceKey)
    31  		var err error
    32  
    33  		mso, err = w.txStore.GetMultisigOutput(txmgrNs, outPoint)
    34  		if err != nil {
    35  			return err
    36  		}
    37  
    38  		addr, _ := stdaddr.NewAddressScriptHashV0FromHash(mso.ScriptHash[:], w.chainParams)
    39  		redeemScript, err = w.manager.RedeemScript(addrmgrNs, addr)
    40  		return err
    41  	})
    42  	if err != nil {
    43  		return nil, errors.E(op, err)
    44  	}
    45  
    46  	p2shAddr, err := stdaddr.NewAddressScriptHashV0FromHash(
    47  		mso.ScriptHash[:], w.chainParams)
    48  	if err != nil {
    49  		return nil, err
    50  	}
    51  
    52  	multiSigOutput := P2SHMultiSigOutput{
    53  		OutPoint:     *mso.OutPoint,
    54  		OutputAmount: mso.Amount,
    55  		ContainingBlock: BlockIdentity{
    56  			Hash:   mso.BlockHash,
    57  			Height: int32(mso.BlockHeight),
    58  		},
    59  		P2SHAddress:  p2shAddr,
    60  		RedeemScript: redeemScript,
    61  		M:            mso.M,
    62  		N:            mso.N,
    63  		Redeemer:     nil,
    64  	}
    65  
    66  	if mso.Spent {
    67  		multiSigOutput.Redeemer = &OutputRedeemer{
    68  			TxHash:     mso.SpentBy,
    69  			InputIndex: mso.SpentByIndex,
    70  		}
    71  	}
    72  
    73  	return &multiSigOutput, nil
    74  }
    75  
    76  // PrepareRedeemMultiSigOutTxOutput estimates the tx value for a MultiSigOutTx
    77  // output and adds it to msgTx.
    78  func (w *Wallet) PrepareRedeemMultiSigOutTxOutput(msgTx *wire.MsgTx, p2shOutput *P2SHMultiSigOutput, pkScript *[]byte) error {
    79  	const op errors.Op = "wallet.PrepareRedeemMultiSigOutTxOutput"
    80  
    81  	scriptSizes := make([]int, 0, len(msgTx.TxIn))
    82  	// generate the script sizes for the inputs
    83  	for range msgTx.TxIn {
    84  		scriptSizes = append(scriptSizes, txsizes.RedeemP2SHSigScriptSize)
    85  	}
    86  
    87  	// estimate the output fee
    88  	txOut := wire.NewTxOut(0, *pkScript)
    89  	feeSize := txsizes.EstimateSerializeSize(scriptSizes, []*wire.TxOut{txOut}, 0)
    90  	feeEst := txrules.FeeForSerializeSize(w.RelayFee(), feeSize)
    91  	if feeEst >= p2shOutput.OutputAmount {
    92  		return errors.E(op, errors.Errorf("estimated fee %v is above output value %v",
    93  			feeEst, p2shOutput.OutputAmount))
    94  	}
    95  
    96  	toReceive := p2shOutput.OutputAmount - feeEst
    97  	// set the output value and add to the tx
    98  	txOut.Value = int64(toReceive)
    99  	msgTx.AddTxOut(txOut)
   100  	return nil
   101  }