opcode_test.go 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. // Copyright (c) 2013-2017 The btcsuite developers
  2. // Use of this source code is governed by an ISC
  3. // license that can be found in the LICENSE file.
  4. package txscript
  5. import (
  6. "bytes"
  7. "fmt"
  8. "strconv"
  9. "strings"
  10. "testing"
  11. "github.com/pkt-cash/pktd/txscript/opcode"
  12. "github.com/pkt-cash/pktd/txscript/parsescript"
  13. "github.com/pkt-cash/pktd/txscript/txscripterr"
  14. )
  15. // TestOpcodeDisabled tests the opcodeDisabled function manually because all
  16. // disabled opcodes result in a script execution failure when executed normally,
  17. // so the function is not called under normal circumstances.
  18. func TestOpcodeDisabled(t *testing.T) {
  19. tests := []byte{
  20. opcode.OP_CAT, opcode.OP_SUBSTR, opcode.OP_LEFT, opcode.OP_RIGHT, opcode.OP_INVERT,
  21. opcode.OP_AND, opcode.OP_OR, opcode.OP_2MUL, opcode.OP_2DIV, opcode.OP_MUL, opcode.OP_DIV, opcode.OP_MOD,
  22. opcode.OP_LSHIFT, opcode.OP_RSHIFT,
  23. }
  24. for _, opcodeVal := range tests {
  25. pop := parsescript.ParsedOpcode{Opcode: opcode.MkOpcode(byte(opcodeVal)), Data: nil}
  26. err := opcodeDisabled(&pop, nil)
  27. if !txscripterr.ErrDisabledOpcode.Is(err) {
  28. t.Errorf("opcodeDisabled: unexpected error - got %v, "+
  29. "want %v", err, txscripterr.ErrDisabledOpcode)
  30. continue
  31. }
  32. }
  33. }
  34. // TestOpcodeDisasm tests the print function for all opcodes in both the oneline
  35. // and full modes to ensure it provides the expected disassembly.
  36. func TestOpcodeDisasm(t *testing.T) {
  37. // First, test the oneline disassembly.
  38. // The expected strings for the data push opcodes are replaced in the
  39. // test loops below since they involve repeating bytes. Also, the
  40. // OP_NOP# and OP_UNKNOWN# are replaced below too, since it's easier
  41. // than manually listing them here.
  42. oneBytes := []byte{0x01}
  43. oneStr := "01"
  44. expectedStrings := [256]string{
  45. 0x00: "0", 0x4f: "-1",
  46. 0x50: "OP_RESERVED", 0x61: "OP_NOP", 0x62: "OP_VER",
  47. 0x63: "OP_IF", 0x64: "OP_NOTIF", 0x65: "OP_VERIF",
  48. 0x66: "OP_VOTE", 0x67: "OP_ELSE", 0x68: "OP_ENDIF",
  49. 0x69: "OP_VERIFY", 0x6a: "OP_RETURN", 0x6b: "OP_TOALTSTACK",
  50. 0x6c: "OP_FROMALTSTACK", 0x6d: "OP_2DROP", 0x6e: "OP_2DUP",
  51. 0x6f: "OP_3DUP", 0x70: "OP_2OVER", 0x71: "OP_2ROT",
  52. 0x72: "OP_2SWAP", 0x73: "OP_IFDUP", 0x74: "OP_DEPTH",
  53. 0x75: "OP_DROP", 0x76: "OP_DUP", 0x77: "OP_NIP",
  54. 0x78: "OP_OVER", 0x79: "OP_PICK", 0x7a: "OP_ROLL",
  55. 0x7b: "OP_ROT", 0x7c: "OP_SWAP", 0x7d: "OP_TUCK",
  56. 0x7e: "OP_CAT", 0x7f: "OP_SUBSTR", 0x80: "OP_LEFT",
  57. 0x81: "OP_RIGHT", 0x82: "OP_SIZE", 0x83: "OP_INVERT",
  58. 0x84: "OP_AND", 0x85: "OP_OR", 0x86: "OP_XOR",
  59. 0x87: "OP_EQUAL", 0x88: "OP_EQUALVERIFY", 0x89: "OP_RESERVED1",
  60. 0x8a: "OP_RESERVED2", 0x8b: "OP_1ADD", 0x8c: "OP_1SUB",
  61. 0x8d: "OP_2MUL", 0x8e: "OP_2DIV", 0x8f: "OP_NEGATE",
  62. 0x90: "OP_ABS", 0x91: "OP_NOT", 0x92: "OP_0NOTEQUAL",
  63. 0x93: "OP_ADD", 0x94: "OP_SUB", 0x95: "OP_MUL", 0x96: "OP_DIV",
  64. 0x97: "OP_MOD", 0x98: "OP_LSHIFT", 0x99: "OP_RSHIFT",
  65. 0x9a: "OP_BOOLAND", 0x9b: "OP_BOOLOR", 0x9c: "OP_NUMEQUAL",
  66. 0x9d: "OP_NUMEQUALVERIFY", 0x9e: "OP_NUMNOTEQUAL",
  67. 0x9f: "OP_LESSTHAN", 0xa0: "OP_GREATERTHAN",
  68. 0xa1: "OP_LESSTHANOREQUAL", 0xa2: "OP_GREATERTHANOREQUAL",
  69. 0xa3: "OP_MIN", 0xa4: "OP_MAX", 0xa5: "OP_WITHIN",
  70. 0xa6: "OP_RIPEMD160", 0xa7: "OP_SHA1", 0xa8: "OP_SHA256",
  71. 0xa9: "OP_HASH160", 0xaa: "OP_HASH256", 0xab: "OP_CODESEPARATOR",
  72. 0xac: "OP_CHECKSIG", 0xad: "OP_CHECKSIGVERIFY",
  73. 0xae: "OP_CHECKMULTISIG", 0xaf: "OP_CHECKMULTISIGVERIFY",
  74. 0xfa: "OP_SMALLINTEGER", 0xfb: "OP_PUBKEYS",
  75. 0xfd: "OP_PUBKEYHASH", 0xfe: "OP_PUBKEY",
  76. 0xff: "OP_INVALIDOPCODE",
  77. }
  78. for opcodeVal, expectedStr := range expectedStrings {
  79. var data []byte
  80. switch {
  81. // OP_DATA_1 through OP_DATA_65 display the pushed data.
  82. case opcodeVal >= 0x01 && opcodeVal < 0x4c:
  83. data = bytes.Repeat(oneBytes, opcodeVal)
  84. expectedStr = strings.Repeat(oneStr, opcodeVal)
  85. // OP_PUSHDATA1.
  86. case opcodeVal == 0x4c:
  87. data = bytes.Repeat(oneBytes, 1)
  88. expectedStr = strings.Repeat(oneStr, 1)
  89. // OP_PUSHDATA2.
  90. case opcodeVal == 0x4d:
  91. data = bytes.Repeat(oneBytes, 2)
  92. expectedStr = strings.Repeat(oneStr, 2)
  93. // OP_PUSHDATA4.
  94. case opcodeVal == 0x4e:
  95. data = bytes.Repeat(oneBytes, 3)
  96. expectedStr = strings.Repeat(oneStr, 3)
  97. // OP_1 through OP_16 display the numbers themselves.
  98. case opcodeVal >= 0x51 && opcodeVal <= 0x60:
  99. val := byte(opcodeVal - (0x51 - 1))
  100. data = []byte{val}
  101. expectedStr = strconv.Itoa(int(val))
  102. // OP_NOP1 through OP_NOP10.
  103. case opcodeVal >= 0xb0 && opcodeVal <= 0xb9:
  104. switch opcodeVal {
  105. case 0xb1:
  106. // OP_NOP2 is an alias of OP_CHECKLOCKTIMEVERIFY
  107. expectedStr = "OP_CHECKLOCKTIMEVERIFY"
  108. case 0xb2:
  109. // OP_NOP3 is an alias of OP_CHECKSEQUENCEVERIFY
  110. expectedStr = "OP_CHECKSEQUENCEVERIFY"
  111. default:
  112. val := byte(opcodeVal - (0xb0 - 1))
  113. expectedStr = "OP_NOP" + strconv.Itoa(int(val))
  114. }
  115. // OP_UNKNOWN#.
  116. case opcodeVal >= 0xba && opcodeVal <= 0xf9 || opcodeVal == 0xfc:
  117. expectedStr = "OP_UNKNOWN" + strconv.Itoa(int(opcodeVal))
  118. }
  119. pop := parsescript.ParsedOpcode{Opcode: opcode.MkOpcode(byte(opcodeVal)), Data: data}
  120. gotStr := popPrint(&pop, true)
  121. if gotStr != expectedStr {
  122. t.Errorf("pop.print (opcode %x): Unexpected disasm "+
  123. "string - got %v, want %v", opcodeVal, gotStr,
  124. expectedStr)
  125. continue
  126. }
  127. }
  128. // Now, replace the relevant fields and test the full disassembly.
  129. expectedStrings[0x00] = "OP_0"
  130. expectedStrings[0x4f] = "OP_1NEGATE"
  131. for opcodeVal, expectedStr := range expectedStrings {
  132. var data []byte
  133. switch {
  134. // OP_DATA_1 through OP_DATA_65 display the opcode followed by
  135. // the pushed data.
  136. case opcodeVal >= 0x01 && opcodeVal < 0x4c:
  137. data = bytes.Repeat(oneBytes, opcodeVal)
  138. expectedStr = fmt.Sprintf("OP_DATA_%d 0x%s", opcodeVal,
  139. strings.Repeat(oneStr, opcodeVal))
  140. // OP_PUSHDATA1.
  141. case opcodeVal == 0x4c:
  142. data = bytes.Repeat(oneBytes, 1)
  143. expectedStr = fmt.Sprintf("OP_PUSHDATA1 0x%02x 0x%s",
  144. len(data), strings.Repeat(oneStr, 1))
  145. // OP_PUSHDATA2.
  146. case opcodeVal == 0x4d:
  147. data = bytes.Repeat(oneBytes, 2)
  148. expectedStr = fmt.Sprintf("OP_PUSHDATA2 0x%04x 0x%s",
  149. len(data), strings.Repeat(oneStr, 2))
  150. // OP_PUSHDATA4.
  151. case opcodeVal == 0x4e:
  152. data = bytes.Repeat(oneBytes, 3)
  153. expectedStr = fmt.Sprintf("OP_PUSHDATA4 0x%08x 0x%s",
  154. len(data), strings.Repeat(oneStr, 3))
  155. // OP_1 through OP_16.
  156. case opcodeVal >= 0x51 && opcodeVal <= 0x60:
  157. val := byte(opcodeVal - (0x51 - 1))
  158. data = []byte{val}
  159. expectedStr = "OP_" + strconv.Itoa(int(val))
  160. // OP_NOP1 through OP_NOP10.
  161. case opcodeVal >= 0xb0 && opcodeVal <= 0xb9:
  162. switch opcodeVal {
  163. case 0xb1:
  164. // OP_NOP2 is an alias of OP_CHECKLOCKTIMEVERIFY
  165. expectedStr = "OP_CHECKLOCKTIMEVERIFY"
  166. case 0xb2:
  167. // OP_NOP3 is an alias of OP_CHECKSEQUENCEVERIFY
  168. expectedStr = "OP_CHECKSEQUENCEVERIFY"
  169. default:
  170. val := byte(opcodeVal - (0xb0 - 1))
  171. expectedStr = "OP_NOP" + strconv.Itoa(int(val))
  172. }
  173. // OP_UNKNOWN#.
  174. case opcodeVal >= 0xba && opcodeVal <= 0xf9 || opcodeVal == 0xfc:
  175. expectedStr = "OP_UNKNOWN" + strconv.Itoa(int(opcodeVal))
  176. }
  177. pop := parsescript.ParsedOpcode{Opcode: opcode.MkOpcode(byte(opcodeVal)), Data: data}
  178. gotStr := popPrint(&pop, false)
  179. if gotStr != expectedStr {
  180. t.Errorf("pop.print (opcode %x): Unexpected disasm "+
  181. "string - got %v, want %v", opcodeVal, gotStr,
  182. expectedStr)
  183. continue
  184. }
  185. }
  186. }