txscript: Optimize PushedData.

This converts the PushedData function to make use of the new tokenizer
instead of the far less efficient parseScript thereby significantly
optimizing the function.

Also, the comment is modified to explicitly call out the script version
semantics.

The following is a before and after comparison of extracting the data
from a very large script:

benchmark                 old ns/op     new ns/op     delta
BenchmarkPushedData-8     64837         1790          -97.24%

benchmark                 old allocs     new allocs     delta
BenchmarkPushedData-8     7              6              -14.29%

benchmark                 old bytes     new bytes     delta
BenchmarkPushedData-8     312816        1520          -99.51%
This commit is contained in:
Dave Collins 2019-03-13 01:12:19 -05:00 committed by Olaoluwa Osuntokun
parent c4f6302189
commit 0a4f228dd1
No known key found for this signature in database
GPG key ID: 3BBD59E99B280306

View file

@ -791,20 +791,25 @@ func MultiSigScript(pubkeys []*btcutil.AddressPubKey, nrequired int) ([]byte, er
// PushedData returns an array of byte slices containing any pushed data found // PushedData returns an array of byte slices containing any pushed data found
// in the passed script. This includes OP_0, but not OP_1 - OP_16. // in the passed script. This includes OP_0, but not OP_1 - OP_16.
//
// NOTE: This function is only valid for version 0 scripts. Since the function
// does not accept a script version, the results are undefined for other script
// versions.
func PushedData(script []byte) ([][]byte, error) { func PushedData(script []byte) ([][]byte, error) {
pops, err := parseScript(script) const scriptVersion = 0
if err != nil {
return nil, err
}
var data [][]byte var data [][]byte
for _, pop := range pops { tokenizer := MakeScriptTokenizer(scriptVersion, script)
if pop.data != nil { for tokenizer.Next() {
data = append(data, pop.data) if tokenizer.Data() != nil {
} else if pop.opcode.value == OP_0 { data = append(data, tokenizer.Data())
} else if tokenizer.Opcode() == OP_0 {
data = append(data, nil) data = append(data, nil)
} }
} }
if err := tokenizer.Err(); err != nil {
return nil, err
}
return data, nil return data, nil
} }