parsescript.go 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. package parsescript
  2. import (
  3. "fmt"
  4. "github.com/pkt-cash/pktd/btcutil/er"
  5. "github.com/pkt-cash/pktd/txscript/opcode"
  6. "github.com/pkt-cash/pktd/txscript/txscripterr"
  7. )
  8. // opcodeArray holds details about all possible opcodes such as how many bytes
  9. // the opcode and any associated data should take, its human-readable name, and
  10. // the handler function.
  11. var opcodeArray [256]opcode.Opcode
  12. func init() {
  13. for i := 0; i < 256; i++ {
  14. opcodeArray[i] = opcode.MkOpcode(byte(i))
  15. }
  16. }
  17. // ParsedOpcode represents an opcode that has been parsed and includes any
  18. // potential data associated with it.
  19. type ParsedOpcode struct {
  20. Opcode opcode.Opcode
  21. Data []byte
  22. }
  23. // ParseScriptTemplate is the same as ParseScript but allows the passing of the
  24. // template list for testing purposes. When there are parse errors, it returns
  25. // the list of parsed opcodes up to the point of failure along with the error.
  26. func ParseScriptTemplate(script []byte, opcodes map[byte]opcode.Opcode) ([]ParsedOpcode, er.R) {
  27. retScript := make([]ParsedOpcode, 0, len(script))
  28. for i := 0; i < len(script); {
  29. instr := script[i]
  30. op := opcodeArray[instr]
  31. if opcodes == nil {
  32. } else if opp, ok := opcodes[instr]; ok {
  33. op = opp
  34. }
  35. pop := ParsedOpcode{Opcode: op}
  36. // Parse data out of instruction.
  37. switch {
  38. // No additional data. Note that some of the opcodes, notably
  39. // OP_1NEGATE, OP_0, and OP_[1-16] represent the data
  40. // themselves.
  41. case op.Length == 1:
  42. i++
  43. // Data pushes of specific lengths -- OP_DATA_[1-75].
  44. case op.Length > 1:
  45. if len(script[i:]) < op.Length {
  46. str := fmt.Sprintf("opcode %s requires %d "+
  47. "bytes, but script only has %d remaining",
  48. opcode.OpcodeName(op.Value), op.Length, len(script[i:]))
  49. return retScript, txscripterr.ScriptError(txscripterr.ErrMalformedPush,
  50. str)
  51. }
  52. // Slice out the data.
  53. pop.Data = script[i+1 : i+op.Length]
  54. i += op.Length
  55. // Data pushes with parsed lengths -- OP_PUSHDATAP{1,2,4}.
  56. case op.Length < 0:
  57. var l uint
  58. off := i + 1
  59. if len(script[off:]) < -op.Length {
  60. str := fmt.Sprintf("opcode %s requires %d "+
  61. "bytes, but script only has %d remaining",
  62. opcode.OpcodeName(op.Value), -op.Length, len(script[off:]))
  63. return retScript, txscripterr.ScriptError(txscripterr.ErrMalformedPush,
  64. str)
  65. }
  66. // Next -length bytes are little endian length of data.
  67. switch op.Length {
  68. case -1:
  69. l = uint(script[off])
  70. case -2:
  71. l = ((uint(script[off+1]) << 8) |
  72. uint(script[off]))
  73. case -4:
  74. l = ((uint(script[off+3]) << 24) |
  75. (uint(script[off+2]) << 16) |
  76. (uint(script[off+1]) << 8) |
  77. uint(script[off]))
  78. default:
  79. str := fmt.Sprintf("invalid opcode length %d",
  80. op.Length)
  81. return retScript, txscripterr.ScriptError(txscripterr.ErrMalformedPush,
  82. str)
  83. }
  84. // Move offset to beginning of the data.
  85. off += -op.Length
  86. // Disallow entries that do not fit script or were
  87. // sign extended.
  88. if int(l) > len(script[off:]) || int(l) < 0 {
  89. str := fmt.Sprintf("opcode %s pushes %d bytes, "+
  90. "but script only has %d remaining",
  91. opcode.OpcodeName(op.Value), int(l), len(script[off:]))
  92. return retScript, txscripterr.ScriptError(txscripterr.ErrMalformedPush,
  93. str)
  94. }
  95. pop.Data = script[off : off+int(l)]
  96. i += 1 - op.Length + int(l)
  97. }
  98. retScript = append(retScript, pop)
  99. }
  100. return retScript, nil
  101. }
  102. // parseScript preparses the script in bytes into a list of parsedOpcodes while
  103. // applying a number of sanity checks.
  104. func ParseScript(script []byte) ([]ParsedOpcode, er.R) {
  105. return ParseScriptTemplate(script, nil)
  106. }
  107. // IsPushOnly returns true if the script only pushes data, false otherwise.
  108. func IsPushOnly(pops []ParsedOpcode) bool {
  109. // NOTE: This function does NOT verify opcodes directly since it is
  110. // internal and is only called with parsed opcodes for scripts that did
  111. // not have any parse errors. Thus, consensus is properly maintained.
  112. for _, pop := range pops {
  113. // All opcodes up to OP_16 are data push instructions.
  114. // NOTE: This does consider OP_RESERVED to be a data push
  115. // instruction, but execution of OP_RESERVED will fail anyways
  116. // and matches the behavior required by consensus.
  117. if pop.Opcode.Value > opcode.OP_16 {
  118. return false
  119. }
  120. }
  121. return true
  122. }