txscript: Optimize IsNullData
This converts the IsNullData function to analyze the raw script instead of using the far less efficient parseScript, thereby significantly optimizing the function. The following is a before and after comparison of analyzing a large script: benchmark old ns/op new ns/op delta BenchmarkIsNullDataScript-8 62495 2.65 -100.00% benchmark old allocs new allocs delta BenchmarkIsNullDataScript-8 1 0 -100.00% benchmark old bytes new bytes delta BenchmarkIsNullDataScript-8 311299 0 -100.00%
This commit is contained in:
parent
4878db49cf
commit
b4f144ad8c
2 changed files with 37 additions and 5 deletions
|
@ -154,11 +154,8 @@ func isWitnessProgram(pops []parsedOpcode) bool {
|
|||
// IsNullData returns true if the passed script is a null data script, false
|
||||
// otherwise.
|
||||
func IsNullData(script []byte) bool {
|
||||
pops, err := parseScript(script)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return isNullData(pops)
|
||||
const scriptVersion = 0
|
||||
return isNullDataScript(scriptVersion, script)
|
||||
}
|
||||
|
||||
// ExtractWitnessProgramInfo attempts to extract the witness program version,
|
||||
|
|
|
@ -461,6 +461,41 @@ func isNullData(pops []parsedOpcode) bool {
|
|||
len(pops[1].data) <= MaxDataCarrierSize
|
||||
}
|
||||
|
||||
// isNullDataScript returns whether or not the passed script is a standard
|
||||
// null data script.
|
||||
//
|
||||
// NOTE: This function is only valid for version 0 scripts. It will always
|
||||
// return false for other script versions.
|
||||
func isNullDataScript(scriptVersion uint16, script []byte) bool {
|
||||
// The only currently supported script version is 0.
|
||||
if scriptVersion != 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
// A null script is of the form:
|
||||
// OP_RETURN <optional data>
|
||||
//
|
||||
// Thus, it can either be a single OP_RETURN or an OP_RETURN followed by a
|
||||
// data push up to MaxDataCarrierSize bytes.
|
||||
|
||||
// The script can't possibly be a a null data script if it doesn't start
|
||||
// with OP_RETURN. Fail fast to avoid more work below.
|
||||
if len(script) < 1 || script[0] != OP_RETURN {
|
||||
return false
|
||||
}
|
||||
|
||||
// Single OP_RETURN.
|
||||
if len(script) == 1 {
|
||||
return true
|
||||
}
|
||||
|
||||
// OP_RETURN followed by data push up to MaxDataCarrierSize bytes.
|
||||
tokenizer := MakeScriptTokenizer(scriptVersion, script[1:])
|
||||
return tokenizer.Next() && tokenizer.Done() &&
|
||||
(isSmallInt(tokenizer.Opcode()) || tokenizer.Opcode() <= OP_PUSHDATA4) &&
|
||||
len(tokenizer.Data()) <= MaxDataCarrierSize
|
||||
}
|
||||
|
||||
// scriptType returns the type of the script being inspected from the known
|
||||
// standard types.
|
||||
func typeOfScript(pops []parsedOpcode) ScriptClass {
|
||||
|
|
Loading…
Reference in a new issue