github.com/lbryio/lbcd@v0.22.119/txscript/opcode_test.go (about)

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