Пример #1
0
// MakeSecp256k1MultiSigScript 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 secp256k1 pubkeys and P2PKH addresses derived
// from them.
func (w *Wallet) MakeSecp256k1MultiSigScript(secp256k1Addrs []dcrutil.Address, nRequired int) ([]byte, error) {
	secp256k1PubKeys := make([]*dcrutil.AddressSecpPubKey, len(secp256k1Addrs))

	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 secp256k1Addrs {
		switch addr := addr.(type) {
		default:
			return nil, errors.New("cannot make multisig script for " +
				"a non-secp256k1 public key or P2PKH address")

		case *dcrutil.AddressSecpPubKey:
			secp256k1PubKeys[i] = addr

		case *dcrutil.AddressPubKeyHash:
			if addr.DSA(w.chainParams) != chainec.ECTypeSecp256k1 {
				return nil, errors.New("cannot make multisig " +
					"script for a non-secp256k1 P2PKH address")
			}

			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().Serialize()

			pubKeyAddr, err := dcrutil.NewAddressSecpPubKey(
				serializedPubKey, w.chainParams)
			if err != nil {
				return nil, err
			}
			secp256k1PubKeys[i] = pubKeyAddr
		}
	}

	return txscript.MultiSigScript(secp256k1PubKeys, nRequired)
}