Skip to content

Commit

Permalink
txscript: Return witness version and program in one pass
Browse files Browse the repository at this point in the history
  • Loading branch information
cfromknecht committed Feb 5, 2021
1 parent cbc3a2e commit 6702a2b
Showing 1 changed file with 32 additions and 20 deletions.
52 changes: 32 additions & 20 deletions txscript/standard.go
Expand Up @@ -379,25 +379,13 @@ func isWitnessScriptHashScript(script []byte) bool {
return extractWitnessScriptHash(script) != nil
}

// isWitnessProgramScript returns true if the passed script is a witness
// program, and false otherwise. A witness program MUST adhere to the following
// constraints: there must be exactly two pops (program version and the program
// itself), the first opcode MUST be a small integer (0-16), the push data MUST
// be canonical, and finally the size of the push data must be between 2 and 40
// bytes.
//
// The length of the script must be between 4 and 42 bytes. The
// smallest program is the witness version, followed by a data push of
// 2 bytes. The largest allowed witness program has a data push of
// 40-bytes.
//
// 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 isWitnessProgramScript(script []byte) bool {
// extractWitnessProgramInfo returns the version and program if the passed
// script constitutes a valid witness program. The alst return value indicates
// whether or not the script is a valid witness program.
func extractWitnessProgramInfo(script []byte) (int, []byte, bool) {
// Skip parsing if we know the program is invalid based on size.
if len(script) < 4 || len(script) > 42 {
return false
return 0, nil, false
}

const scriptVersion = 0
Expand All @@ -407,21 +395,45 @@ func isWitnessProgramScript(script []byte) bool {
if !tokenizer.Next() ||
!isSmallInt(tokenizer.Opcode()) {

return false
return 0, nil, false
}
version := asSmallInt(tokenizer.Opcode())

// The second opcode must be a canonical data push, the length of the
// data push is bounded to 40 by the initial check on overall script
// length.
if !tokenizer.Next() ||
!isCanonicalPush(tokenizer.Opcode(), tokenizer.Data()) {

return false
return 0, nil, false
}
program := tokenizer.Data()

// The witness program is valid if there are no more opcodes, and we
// terminated without a parsing error.
return tokenizer.Done() && tokenizer.Err() == nil
valid := tokenizer.Done() && tokenizer.Err() == nil

return version, program, valid
}

// isWitnessProgramScript returns true if the passed script is a witness
// program, and false otherwise. A witness program MUST adhere to the following
// constraints: there must be exactly two pops (program version and the program
// itself), the first opcode MUST be a small integer (0-16), the push data MUST
// be canonical, and finally the size of the push data must be between 2 and 40
// bytes.
//
// The length of the script must be between 4 and 42 bytes. The
// smallest program is the witness version, followed by a data push of
// 2 bytes. The largest allowed witness program has a data push of
// 40-bytes.
//
// 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 isWitnessProgramScript(script []byte) bool {
_, _, valid := extractWitnessProgramInfo(script)
return valid
}

// isNullDataScript returns whether or not the passed script is a standard
Expand Down

0 comments on commit 6702a2b

Please sign in to comment.