opcode_test.go raw

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