Skip to main content

Try it Live

Run Opcode examples in the interactive playground

Validation

Methods for validating opcodes and checking opcode categories.

Opcode Validity

Opcode.isValid(opcode)

Check if byte value is a valid EVM opcode.
import * as Opcode from '@tevm/primitives/Opcode'

Opcode.isValid(0x00)  // true (STOP)
Opcode.isValid(0x01)  // true (ADD)
Opcode.isValid(0x60)  // true (PUSH1)
Opcode.isValid(0xFF)  // true (SELFDESTRUCT)

// Invalid opcodes
Opcode.isValid(0x0C)  // false (undefined)
Opcode.isValid(0x0D)  // false (undefined)
Opcode.isValid(0x21)  // false (undefined, between KECCAK256 and ADDRESS)
Opcode.isValid(0x4B)  // false (undefined, after BLOBBASEFEE)
Parameters:
  • opcode: number - Byte value to check (0x00-0xFF)
Returns: boolean - True if valid EVM opcode Use cases:
  • Validate bytecode before execution
  • Filter out undefined opcodes during disassembly
  • Detect malformed or invalid bytecode
Defined in: primitives/Opcode/BrandedOpcode/isValid.js

Opcode.isValidOpcode(opcode)

Alias for isValid().
const valid = Opcode.isValidOpcode(0x60)  // true
Parameters:
  • opcode: number - Byte value
Returns: boolean - True if valid opcode

Jump Validation

Opcode.isValidJumpDest(bytecode, offset)

Check if offset is a valid JUMPDEST in bytecode.
import * as Opcode from '@tevm/primitives/Opcode'

const bytecode = new Uint8Array([
  0x60, 0x04,     // PUSH1 0x04
  0x56,           // JUMP
  0x5B,           // JUMPDEST (offset 3)
  0x00            // STOP
])

Opcode.isValidJumpDest(bytecode, 3)  // true (valid JUMPDEST)
Opcode.isValidJumpDest(bytecode, 0)  // false (PUSH1, not JUMPDEST)
Opcode.isValidJumpDest(bytecode, 1)  // false (inside PUSH data)
Opcode.isValidJumpDest(bytecode, 99) // false (out of bounds)
Parameters:
  • bytecode: Uint8Array - Contract bytecode
  • offset: number - Program counter offset to check
Returns: boolean - True if offset is valid JUMPDEST Validation rules:
  • Offset must be within bytecode bounds
  • Byte at offset must be JUMPDEST (0x5B)
  • Offset must not be inside PUSH immediate data
Defined in: primitives/Opcode/BrandedOpcode/isValidJumpDest.js

Opcode.isJumpDestination(opcode)

Check if opcode is JUMPDEST (0x5B).
Opcode.isJumpDestination(0x5B)  // true
Opcode.isJumpDestination(0x56)  // false (JUMP, not JUMPDEST)
Parameters:
  • opcode: BrandedOpcode - Opcode to check
Returns: boolean - True if JUMPDEST Defined in: primitives/Opcode/BrandedOpcode/isJumpDestination.js

Category Checks

Opcode.isPush(opcode)

Check if opcode is PUSH0-PUSH32.
import * as Opcode from '@tevm/primitives/Opcode'

Opcode.isPush(0x5F)  // true (PUSH0)
Opcode.isPush(0x60)  // true (PUSH1)
Opcode.isPush(0x7F)  // true (PUSH32)
Opcode.isPush(0x01)  // false (ADD)
Opcode.isPush(0x80)  // false (DUP1)
Parameters:
  • opcode: BrandedOpcode - Opcode to check
Returns: boolean - True if PUSH0-PUSH32 (0x5F-0x7F) Defined in: primitives/Opcode/BrandedOpcode/isPush.js

Opcode.isDup(opcode)

Check if opcode is DUP1-DUP16.
Opcode.isDup(0x80)  // true (DUP1)
Opcode.isDup(0x8F)  // true (DUP16)
Opcode.isDup(0x60)  // false (PUSH1)
Opcode.isDup(0x90)  // false (SWAP1)
Parameters:
  • opcode: BrandedOpcode - Opcode to check
Returns: boolean - True if DUP1-DUP16 (0x80-0x8F) Defined in: primitives/Opcode/BrandedOpcode/isDup.js

Opcode.isSwap(opcode)

Check if opcode is SWAP1-SWAP16.
Opcode.isSwap(0x90)  // true (SWAP1)
Opcode.isSwap(0x9F)  // true (SWAP16)
Opcode.isSwap(0x80)  // false (DUP1)
Opcode.isSwap(0xA0)  // false (LOG0)
Parameters:
  • opcode: BrandedOpcode - Opcode to check
Returns: boolean - True if SWAP1-SWAP16 (0x90-0x9F) Defined in: primitives/Opcode/BrandedOpcode/isSwap.js

Opcode.isLog(opcode)

Check if opcode is LOG0-LOG4.
Opcode.isLog(0xA0)  // true (LOG0)
Opcode.isLog(0xA4)  // true (LOG4)
Opcode.isLog(0xA5)  // false (undefined)
Opcode.isLog(0x9F)  // false (SWAP16)
Parameters:
  • opcode: BrandedOpcode - Opcode to check
Returns: boolean - True if LOG0-LOG4 (0xA0-0xA4) Defined in: primitives/Opcode/BrandedOpcode/isLog.js

Opcode.isJump(opcode)

Check if opcode is JUMP or JUMPI.
Opcode.isJump(0x56)  // true (JUMP)
Opcode.isJump(0x57)  // true (JUMPI)
Opcode.isJump(0x5B)  // false (JUMPDEST)
Opcode.isJump(0x00)  // false (STOP)
Parameters:
  • opcode: BrandedOpcode - Opcode to check
Returns: boolean - True if JUMP (0x56) or JUMPI (0x57) Defined in: primitives/Opcode/BrandedOpcode/isJump.js

Opcode.isTerminating(opcode)

Check if opcode terminates execution.
Opcode.isTerminating(0x00)  // true (STOP)
Opcode.isTerminating(0xF3)  // true (RETURN)
Opcode.isTerminating(0xFD)  // true (REVERT)
Opcode.isTerminating(0xFE)  // true (INVALID)
Opcode.isTerminating(0xFF)  // true (SELFDESTRUCT)
Opcode.isTerminating(0x01)  // false (ADD)
Parameters:
  • opcode: BrandedOpcode - Opcode to check
Returns: boolean - True if STOP, RETURN, REVERT, INVALID, or SELFDESTRUCT Terminating opcodes:
  • STOP (0x00) - Halts execution
  • RETURN (0xF3) - Returns from call
  • REVERT (0xFD) - Reverts state changes
  • INVALID (0xFE) - Invalid opcode trap
  • SELFDESTRUCT (0xFF) - Destroys contract
Defined in: primitives/Opcode/BrandedOpcode/isTerminating.js

Opcode.isTerminator(opcode)

Alias for isTerminating().
const terminates = Opcode.isTerminator(0xF3)  // true

Validation Patterns

Validate Bytecode

function validateBytecode(bytecode: Uint8Array): string[] {
  const errors: string[] = []
  const instructions = Opcode.parse(bytecode)

  for (const inst of instructions) {
    if (!Opcode.isValid(inst.opcode)) {
      errors.push(`Invalid opcode 0x${inst.opcode.toString(16)} at offset ${inst.offset}`)
    }
  }

  return errors
}

Check Jump Safety

function hasUnsafeJumps(bytecode: Uint8Array): boolean {
  const instructions = Opcode.parse(bytecode)
  const validDests = Opcode.jumpDests(bytecode)

  for (const inst of instructions) {
    if (Opcode.isJump(inst.opcode)) {
      // In real analysis, would need symbolic execution to get jump target
      // This is simplified
      if (validDests.size === 0) {
        return true  // Has jumps but no valid destinations
      }
    }
  }

  return false
}

Categorize Instructions

interface InstructionCategories {
  push: number
  dup: number
  swap: number
  log: number
  jump: number
  terminating: number
  other: number
}

function categorizeInstructions(bytecode: Uint8Array): InstructionCategories {
  const instructions = Opcode.parse(bytecode)
  const categories: InstructionCategories = {
    push: 0,
    dup: 0,
    swap: 0,
    log: 0,
    jump: 0,
    terminating: 0,
    other: 0
  }

  for (const inst of instructions) {
    if (Opcode.isPush(inst.opcode)) categories.push++
    else if (Opcode.isDup(inst.opcode)) categories.dup++
    else if (Opcode.isSwap(inst.opcode)) categories.swap++
    else if (Opcode.isLog(inst.opcode)) categories.log++
    else if (Opcode.isJump(inst.opcode)) categories.jump++
    else if (Opcode.isTerminating(inst.opcode)) categories.terminating++
    else categories.other++
  }

  return categories
}

Find Invalid Opcodes

function findInvalidOpcodes(bytecode: Uint8Array): number[] {
  const instructions = Opcode.parse(bytecode)
  const invalidOffsets: number[] = []

  for (const inst of instructions) {
    if (!Opcode.isValid(inst.opcode)) {
      invalidOffsets.push(inst.offset)
    }
  }

  return invalidOffsets
}

Validate PUSH Consistency

function validatePushInstructions(bytecode: Uint8Array): boolean {
  const instructions = Opcode.parse(bytecode)

  for (const inst of instructions) {
    if (Opcode.isPush(inst.opcode)) {
      const expectedBytes = Opcode.pushBytes(inst.opcode)

      // PUSH0 has no immediate
      if (expectedBytes === 0 && inst.immediate !== undefined) {
        return false
      }

      // Other PUSHes must have immediate data
      if (expectedBytes > 0) {
        if (!inst.immediate || inst.immediate.length !== expectedBytes) {
          return false
        }
      }
    }
  }

  return true
}

Check for Unreachable Code

function findUnreachableCode(bytecode: Uint8Array): Set<number> {
  const instructions = Opcode.parse(bytecode)
  const reachable = new Set<number>([0])  // Start is reachable

  for (const inst of instructions) {
    if (!reachable.has(inst.offset)) {
      continue  // Skip unreachable instructions
    }

    // Next instruction is reachable unless this terminates
    if (!Opcode.isTerminating(inst.opcode)) {
      // Find next instruction offset
      const nextOffset = inst.offset + 1 + (inst.immediate?.length ?? 0)
      reachable.add(nextOffset)
    }

    // JUMP/JUMPI make destinations reachable (would need symbolic execution for actual targets)
  }

  const unreachable = new Set<number>()
  for (const inst of instructions) {
    if (!reachable.has(inst.offset)) {
      unreachable.add(inst.offset)
    }
  }

  return unreachable
}

See Also