// Copyright (c) 2013-2014 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. package btcscript import ( "github.com/conformal/btcnet" "github.com/conformal/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, net *btcnet.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 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, net) if err == nil { addrs = append(addrs, addr) } case PubKeyTy: // A pay-to-pubkey script is of the form: // 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, net) if err == nil { addrs = append(addrs, addr) } case ScriptHashTy: // A pay-to-script-hash script is of the form: // OP_HASH160 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, net) if err == nil { addrs = append(addrs, addr) } case MultiSigTy: // A multi-signature script is of the form: // ... 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, net) 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 }