txscript: Optimize removeOpcodeRaw

This commit is contained in:
Conner Fromknecht 2019-04-19 16:26:22 -07:00 committed by Olaoluwa Osuntokun
parent 30874ff76b
commit a4720f30e5
No known key found for this signature in database
GPG key ID: 3BBD59E99B280306
2 changed files with 42 additions and 4 deletions

View file

@ -269,6 +269,8 @@ func DisasmString(script []byte) (string, error) {
// removeOpcode will remove any opcode matching ``opcode'' from the opcode // removeOpcode will remove any opcode matching ``opcode'' from the opcode
// stream in pkscript // stream in pkscript
//
// DEPRECATED. Use removeOpcodeRaw instead.
func removeOpcode(pkscript []parsedOpcode, opcode byte) []parsedOpcode { func removeOpcode(pkscript []parsedOpcode, opcode byte) []parsedOpcode {
retScript := make([]parsedOpcode, 0, len(pkscript)) retScript := make([]parsedOpcode, 0, len(pkscript))
for _, pop := range pkscript { for _, pop := range pkscript {
@ -279,6 +281,43 @@ func removeOpcode(pkscript []parsedOpcode, opcode byte) []parsedOpcode {
return retScript return retScript
} }
// removeOpcodeRaw will return the script after removing any opcodes that match
// `opcode`. If the opcode does not appear in script, the original script will
// be returned unmodified. Otherwise, a new script will be allocated to contain
// the filtered script. This metehod assumes that the script parses
// successfully.
//
// 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 removeOpcodeRaw(script []byte, opcode byte) []byte {
// Avoid work when possible.
if len(script) == 0 {
return script
}
const scriptVersion = 0
var result []byte
var prevOffset int32
tokenizer := MakeScriptTokenizer(scriptVersion, script)
for tokenizer.Next() {
if tokenizer.Opcode() == opcode {
if result == nil {
result = make([]byte, 0, len(script))
result = append(result, script[:prevOffset]...)
}
} else if result != nil {
result = append(result, script[prevOffset:tokenizer.ByteIndex()]...)
}
prevOffset = tokenizer.ByteIndex()
}
if result == nil {
return script
}
return result
}
// isCanonicalPush returns true if the opcode is either not a push instruction // isCanonicalPush returns true if the opcode is either not a push instruction
// or the data associated with the push instruction uses the smallest // or the data associated with the push instruction uses the smallest
// instruction to do the job. False otherwise. // instruction to do the job. False otherwise.

View file

@ -3981,13 +3981,12 @@ func TestRemoveOpcodes(t *testing.T) {
// tstRemoveOpcode is a convenience function to parse the provided // tstRemoveOpcode is a convenience function to parse the provided
// raw script, remove the passed opcode, then unparse the result back // raw script, remove the passed opcode, then unparse the result back
// into a raw script. // into a raw script.
const scriptVersion = 0
tstRemoveOpcode := func(script []byte, opcode byte) ([]byte, error) { tstRemoveOpcode := func(script []byte, opcode byte) ([]byte, error) {
pops, err := parseScript(script) if err := checkScriptParses(scriptVersion, script); err != nil {
if err != nil {
return nil, err return nil, err
} }
pops = removeOpcode(pops, opcode) return removeOpcodeRaw(script, opcode), nil
return unparseScript(pops)
} }
for _, test := range tests { for _, test := range tests {