txscript: Optimize IsPayToPubKeyHash

This converts the IsPayToPubKeyHash function to analyze the raw script
instead of using the far less efficient parseScript, thereby
significantly optimization the function.

In order to accomplish this, it introduces two new functions.  The first
one is named extractPubKeyHash and works with the raw script bytes
to simultaneously determine if the script is a pay-to-pubkey-hash script,
and in the case it is, extract and return the hash.  The second new
function is named isPubKeyHashScript and is defined in terms of the
former.

The extract function approach was chosen because it is common for
callers to want to only extract relevant details from a script if the
script is of the specific type.  Extracting those details requires
performing the exact same checks to ensure the script is of the correct
type, so it is more efficient to combine the two into one and define the
type determination in terms of the result so long as the extraction does
not require allocations.

The following is a before and after comparison of analyzing a large
script:

benchmark                         old ns/op     new ns/op     delta
BenchmarkIsPubKeyHashScript-8     62228         0.45          -100.00%

benchmark                         old allocs     new allocs     delta
BenchmarkIsPubKeyHashScript-8     1              0              -100.00%

benchmark                         old bytes     new bytes     delta
BenchmarkIsPubKeyHashScript-8     311299        0             -100.00%
This commit is contained in:
Conner Fromknecht 2021-02-04 14:09:28 -08:00 committed by Olaoluwa Osuntokun
parent 2d2608c34e
commit c771f4fb38
No known key found for this signature in database
GPG key ID: 3BBD59E99B280306
2 changed files with 25 additions and 5 deletions

View file

@ -72,11 +72,7 @@ func IsPayToPubKey(script []byte) bool {
// IsPayToPubKeyHash returns true if the script is in the standard
// pay-to-pubkey-hash (P2PKH) format, false otherwise.
func IsPayToPubKeyHash(script []byte) bool {
pops, err := parseScript(script)
if err != nil {
return false
}
return isPubkeyHash(pops)
return isPubKeyHashScript(script)
}
// IsPayToScriptHash returns true if the script is in the standard

View file

@ -143,6 +143,30 @@ func isPubKeyScript(script []byte) bool {
return extractPubKey(script) != nil
}
// extractPubKeyHash extracts the public key hash from the passed script if it
// is a standard pay-to-pubkey-hash script. It will return nil otherwise.
func extractPubKeyHash(script []byte) []byte {
// A pay-to-pubkey-hash script is of the form:
// OP_DUP OP_HASH160 <20-byte hash> OP_EQUALVERIFY OP_CHECKSIG
if len(script) == 25 &&
script[0] == OP_DUP &&
script[1] == OP_HASH160 &&
script[2] == OP_DATA_20 &&
script[23] == OP_EQUALVERIFY &&
script[24] == OP_CHECKSIG {
return script[3:23]
}
return nil
}
// isPubKeyHashScript returns whether or not the passed script is a standard
// pay-to-pubkey-hash script.
func isPubKeyHashScript(script []byte) bool {
return extractPubKeyHash(script) != nil
}
// isPubkey returns true if the script passed is a pay-to-pubkey transaction,
// false otherwise.
func isPubkey(pops []parsedOpcode) bool {