btcd/txscript/address.go
2015-02-05 23:24:53 -06:00

94 lines
2.9 KiB
Go

// Copyright (c) 2013-2015 Conformal Systems LLC.
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package txscript
import (
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcutil"
)
// ExtractPkScriptAddrs returns the type of script, addresses and required
// signatures associated with the passed PkScript. Note that it only works for
// 'standard' transaction script types. Any data such as public keys which are
// invalid are omitted from the results.
func ExtractPkScriptAddrs(pkScript []byte, chainParams *chaincfg.Params) (ScriptClass, []btcutil.Address, int, error) {
var addrs []btcutil.Address
var requiredSigs int
// No valid addresses or required signatures if the script doesn't
// parse.
pops, err := parseScript(pkScript)
if err != nil {
return NonStandardTy, nil, 0, err
}
scriptClass := typeOfScript(pops)
switch scriptClass {
case PubKeyHashTy:
// A pay-to-pubkey-hash script is of the form:
// OP_DUP OP_HASH160 <hash> OP_EQUALVERIFY OP_CHECKSIG
// Therefore the pubkey hash is the 3rd item on the stack.
// Skip the pubkey hash if it's invalid for some reason.
requiredSigs = 1
addr, err := btcutil.NewAddressPubKeyHash(pops[2].data,
chainParams)
if err == nil {
addrs = append(addrs, addr)
}
case PubKeyTy:
// A pay-to-pubkey script is of the form:
// <pubkey> OP_CHECKSIG
// Therefore the pubkey is the first item on the stack.
// Skip the pubkey if it's invalid for some reason.
requiredSigs = 1
addr, err := btcutil.NewAddressPubKey(pops[0].data, chainParams)
if err == nil {
addrs = append(addrs, addr)
}
case ScriptHashTy:
// A pay-to-script-hash script is of the form:
// OP_HASH160 <scripthash> OP_EQUAL
// Therefore the script hash is the 2nd item on the stack.
// Skip the script hash if it's invalid for some reason.
requiredSigs = 1
addr, err := btcutil.NewAddressScriptHashFromHash(pops[1].data,
chainParams)
if err == nil {
addrs = append(addrs, addr)
}
case MultiSigTy:
// A multi-signature script is of the form:
// <numsigs> <pubkey> <pubkey> <pubkey>... <numpubkeys> OP_CHECKMULTISIG
// Therefore the number of required signatures is the 1st item
// on the stack and the number of public keys is the 2nd to last
// item on the stack.
requiredSigs = asSmallInt(pops[0].opcode)
numPubKeys := asSmallInt(pops[len(pops)-2].opcode)
// Extract the public keys while skipping any that are invalid.
addrs = make([]btcutil.Address, 0, numPubKeys)
for i := 0; i < numPubKeys; i++ {
addr, err := btcutil.NewAddressPubKey(pops[i+1].data,
chainParams)
if err == nil {
addrs = append(addrs, addr)
}
}
case NullDataTy:
// Null data transactions have no addresses or required
// signatures.
case NonStandardTy:
// Don't attempt to extract addresses or required signatures for
// nonstandard transactions.
}
return scriptClass, addrs, requiredSigs, nil
}