lbcwallet/wallet/multisig.go
Roy Lee 202374ebd8 [lbry] fork from btcsuite to lbryio
1. btcd -> lbcd
2. btcwallet -> lbcallet
3. btcutil -> lbcutil
2022-05-24 10:31:06 -07:00

114 lines
3.3 KiB
Go

// Copyright (c) 2017 The btcsuite developers
// Copyright (c) 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 (
"errors"
"github.com/lbryio/lbcd/txscript"
btcutil "github.com/lbryio/lbcutil"
"github.com/lbryio/lbcwallet/waddrmgr"
"github.com/lbryio/lbcwallet/walletdb"
)
// MakeMultiSigScript creates a multi-signature script that can be redeemed with
// nRequired signatures of the passed keys and addresses. If the address is a
// P2PKH address, the associated pubkey is looked up by the wallet if possible,
// otherwise an error is returned for a missing pubkey.
//
// This function only works with pubkeys and P2PKH addresses derived from them.
func (w *Wallet) MakeMultiSigScript(addrs []btcutil.Address, nRequired int) ([]byte, error) {
pubKeys := make([]*btcutil.AddressPubKey, len(addrs))
var dbtx walletdb.ReadTx
var addrmgrNs walletdb.ReadBucket
defer func() {
if dbtx != nil {
_ = dbtx.Rollback()
}
}()
// The address list will made up either of addreseses (pubkey hash), for
// which we need to look up the keys in wallet, straight pubkeys, or a
// mixture of the two.
for i, addr := range addrs {
switch addr := addr.(type) {
default:
return nil, errors.New("cannot make multisig script for " +
"a non-secp256k1 public key or P2PKH address")
case *btcutil.AddressPubKey:
pubKeys[i] = addr
case *btcutil.AddressPubKeyHash:
if dbtx == nil {
var err error
dbtx, err = w.db.BeginReadTx()
if err != nil {
return nil, err
}
addrmgrNs = dbtx.ReadBucket(waddrmgrNamespaceKey)
}
addrInfo, err := w.Manager.Address(addrmgrNs, addr)
if err != nil {
return nil, err
}
serializedPubKey := addrInfo.(waddrmgr.ManagedPubKeyAddress).
PubKey().SerializeCompressed()
pubKeyAddr, err := btcutil.NewAddressPubKey(
serializedPubKey, w.chainParams)
if err != nil {
return nil, err
}
pubKeys[i] = pubKeyAddr
}
}
return txscript.MultiSigScript(pubKeys, nRequired)
}
// ImportP2SHRedeemScript adds a P2SH redeem script to the wallet.
func (w *Wallet) ImportP2SHRedeemScript(script []byte) (*btcutil.AddressScriptHash, error) {
var p2shAddr *btcutil.AddressScriptHash
err := walletdb.Update(w.db, func(tx walletdb.ReadWriteTx) error {
addrmgrNs := tx.ReadWriteBucket(waddrmgrNamespaceKey)
// TODO(oga) blockstamp current block?
bs := &waddrmgr.BlockStamp{
Hash: *w.ChainParams().GenesisHash,
Height: 0,
}
// As this is a regular P2SH script, we'll import this into the
// BIP0044 scope.
bip44Mgr, err := w.Manager.FetchScopedKeyManager(
waddrmgr.KeyScopeBIP0084,
)
if err != nil {
return err
}
addrInfo, err := bip44Mgr.ImportScript(addrmgrNs, script, bs)
if err != nil {
// Don't care if it's already there, but still have to
// set the p2shAddr since the address manager didn't
// return anything useful.
if waddrmgr.IsError(err, waddrmgr.ErrDuplicateAddress) {
// This function will never error as it always
// hashes the script to the correct length.
p2shAddr, _ = btcutil.NewAddressScriptHash(script,
w.chainParams)
return nil
}
return err
}
p2shAddr = addrInfo.Address().(*btcutil.AddressScriptHash)
return nil
})
return p2shAddr, err
}