Skip to content

Commit

Permalink
txscript: Optimize IsUnspendable.
Browse files Browse the repository at this point in the history
This converts the IsUnspendable function to make use of a combination of
raw script analysis and the new tokenizer instead of the far less
efficient parseScript thereby significantly optimizing the function.

It is important to note that this new implementation intentionally has a
semantic difference from the existing implementation in that it will now
report scripts that are larger than the max allowed script size are
unspendable as well.

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

Note: this function was recently optimized in master, so the gains here
are less noticable than other optimizations.

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

benchmark                    old ns/op     new ns/op     delta
BenchmarkIsUnspendable-8     656           584           -10.98%

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

benchmark                    old bytes     new bytes     delta
BenchmarkIsUnspendable-8     1             0             -100.00%
  • Loading branch information
davecgh authored and cfromknecht committed Feb 5, 2021
1 parent 75b614c commit 6635382
Showing 1 changed file with 10 additions and 7 deletions.
17 changes: 10 additions & 7 deletions txscript/script.go
Original file line number Diff line number Diff line change
Expand Up @@ -917,15 +917,18 @@ func checkScriptParses(scriptVersion uint16, script []byte) error {
// IsUnspendable returns whether the passed public key script is unspendable, or
// guaranteed to fail at execution. This allows inputs to be pruned instantly
// when entering the UTXO set.
//
// 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 IsUnspendable(pkScript []byte) bool {
// Not provably unspendable
if len(pkScript) == 0 {
return false
}
firstOpcode, err := checkScriptTemplateParseable(pkScript, &opcodeArray)
if err != nil {
// The script is unspendable if starts with OP_RETURN or is guaranteed to
// fail at execution due to being larger than the max allowed script size.
if len(pkScript) > 0 && pkScript[0] == OP_RETURN {
return true
}

return firstOpcode != nil && *firstOpcode == OP_RETURN
// The script is unspendable if it is guaranteed to fail at execution.
const scriptVersion = 0
return checkScriptParses(scriptVersion, pkScript) != nil
}

0 comments on commit 6635382

Please sign in to comment.