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
|
// IsNullData returns true if the passed script is a null data script, false
|
||||||
// otherwise.
|
// otherwise.
|
||||||
func IsNullData(script []byte) bool {
|
func IsNullData(script []byte) bool {
|
||||||
pops, err := parseScript(script)
|
const scriptVersion = 0
|
||||||
if err != nil {
|
return isNullDataScript(scriptVersion, script)
|
||||||
return false
|
|
||||||
}
|
|
||||||
return isNullData(pops)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExtractWitnessProgramInfo attempts to extract the witness program version,
|
// ExtractWitnessProgramInfo attempts to extract the witness program version,
|
||||||
|
|
|
@ -461,6 +461,41 @@ func isNullData(pops []parsedOpcode) bool {
|
||||||
len(pops[1].data) <= MaxDataCarrierSize
|
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
|
// scriptType returns the type of the script being inspected from the known
|
||||||
// standard types.
|
// standard types.
|
||||||
func typeOfScript(pops []parsedOpcode) ScriptClass {
|
func typeOfScript(pops []parsedOpcode) ScriptClass {
|
||||||
|
|
Loading…
Reference in a new issue