From 49b3f9f61ae38bc4e10117bebc0fefa678ae0264 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Wed, 13 Mar 2019 01:12:27 -0500 Subject: [PATCH] txscript: Optimize ExtractPkScriptAddrs scripthash. This begins the process of converting the ExtractPkScriptAddrs function to use the optimized extraction functions recently introduced as part of the typeOfScript conversion. In order to ease the review process, the detection of each script type will be converted in a separate commit such that the script is only parsed as a fallback for the cases that are not already converted to more efficient variants. In particular, this converts the detection for pay-to-script-hash scripts. --- txscript/standard.go | 38 +++++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/txscript/standard.go b/txscript/standard.go index efcb8004..8461996f 100644 --- a/txscript/standard.go +++ b/txscript/standard.go @@ -1383,16 +1383,40 @@ func GetMultisigMandN(script []byte) (uint8, uint8, error) { return uint8(requiredSigs), uint8(numPubKeys), nil } +// scriptHashToAddrs is a convenience function to attempt to convert the passed +// hash to a pay-to-script-hash address housed within an address slice. It is +// used to consolidate common code. +func scriptHashToAddrs(hash []byte, params *chaincfg.Params) []dcrutil.Address { + // Skip the hash if it's invalid for some reason. + var addrs []dcrutil.Address + addr, err := dcrutil.NewAddressScriptHashFromHash(hash, params) + if err == nil { + addrs = append(addrs, addr) + } + return addrs +} + // 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(version uint16, pkScript []byte, chainParams *chaincfg.Params) (ScriptClass, []dcrutil.Address, int, error) { - if version != DefaultScriptVersion { + if version != 0 { return NonStandardTy, nil, 0, fmt.Errorf("invalid script version") } + // Avoid parsing the script for the cases that already have the able to + // work with raw scripts. + + // Check for pay-to-script-hash. + if hash := extractScriptHash(pkScript); hash != nil { + return ScriptHashTy, scriptHashToAddrs(hash, chainParams), 1, nil + } + + // Fall back to slow path. Ultimately these are intended to be replaced by + // faster variants based on the unparsed raw scripts. + var addrs []dcrutil.Address var requiredSigs int @@ -1509,18 +1533,6 @@ func ExtractPkScriptAddrs(version uint16, pkScript []byte, addrs = append(addrs, localAddrs...) } - 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 := dcrutil.NewAddressScriptHashFromHash(pops[1].data, - chainParams) - if err == nil { - addrs = append(addrs, addr) - } - case MultiSigTy: // A multi-signature script is of the form: // ... OP_CHECKMULTISIG