Skip to content

EVM Operational Codes

Nevio Vesic edited this page Mar 28, 2024 · 8 revisions

The opcode package in Solgo is a specialized toolkit tailored for the Ethereum ecosystem. It's designed to facilitate the construction, visualization, and analysis of opcode execution trees within the Ethereum Virtual Machine (EVM). These trees represent sequences of instructions, providing a structured view of how opcodes, derived from Solidity code, are executed in sequence on the EVM.

The Ethereum Virtual Machine (EVM) is the runtime environment for executing smart contracts on the Ethereum blockchain. Smart contracts, primarily written in Solidity, are compiled into bytecode, which is a series of opcodes that the EVM can understand and execute. The opcode package in Solgo provides developers with a robust set of tools to work with these opcodes, ensuring a deeper understanding and efficient manipulation of EVM bytecode.

Decompiler Higher Overview

The decompiler.go file in the opcode package of Solgo is pivotal for understanding and working with Ethereum bytecode. It provides tools to decompile Ethereum bytecode into a set of instructions, making it easier to analyze and understand the underlying logic of Solidity smart contracts as they are executed on the Ethereum Virtual Machine (EVM).

Usage

Here's a practical example showcasing the usage of the opcode package:

package main

import (
	"context"
	"encoding/hex"
	"fmt"
	"time"

	"github.com/unpackdev/solgo/opcode"
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
)

func main() {
	currentTick := time.Now()
	defer func() {
		zap.S().Infof("Total time took: %v", time.Since(currentTick))
	}()

	config := zap.NewDevelopmentConfig()
	config.EncoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder
	logger, err := config.Build()
	if err != nil {
		panic(err)
	}

	zap.ReplaceGlobals(logger)

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	bytecode, err := hex.DecodeString("6060604052341561000f57600080fd5b5b6101518061001f6000396000f30060606040")
	if err != nil {
		zap.S().Errorf("Error during decoding bytecode from hex: %v", err)
		return
	}

	decompiler, err := opcode.NewDecompiler(ctx, []byte(bytecode))
	if err != nil {
		zap.S().Errorf("Error during construction of new decompiler: %v", err)
		return
	}

	if err := decompiler.Decompile(); err != nil {
		zap.S().Errorf("Error during decompilation: %v", err)
		return
	}

	// Print the decompiled instructions
	fmt.Println(decompiler.String())
}

Sample Decompilation Response

The following is a sample output of the decompiled instructions:

0x0000 PUSH1 60 // Push 1 byte onto the stack.
0x0002 PUSH1 40 // Push 1 byte onto the stack.
0x0004 MSTORE // Save word to memory.
0x0005 CALLVALUE // Get deposited value by the instruction/transaction responsible for this execution.
0x0006 ISZERO // Checks if the top stack item is zero.
0x0007 PUSH2 000f // Push 2 bytes onto the stack.
0x000a JUMPI // Conditionally alter the program counter.
0x000b PUSH1 00 // Push 1 byte onto the stack.
0x000d DUP1 // Duplicates the 1st stack item.
0x000e REVERT // Halt execution reverting state changes but returning data and remaining gas.
0x000f JUMPDEST // Mark a valid destination for jumps.
0x0010 JUMPDEST // Mark a valid destination for jumps.
0x0011 PUSH2 0151 // Push 2 bytes onto the stack.
0x0014 DUP1 // Duplicates the 1st stack item.
0x0015 PUSH2 001f // Push 2 bytes onto the stack.
0x0018 PUSH1 00 // Push 1 byte onto the stack.
0x001a CODECOPY // Copy code running in current environment to memory.
0x001b PUSH1 00 // Push 1 byte onto the stack.
0x001d RETURN // Halt execution returning output data.
0x001e STOP // Halts execution.
0x001f PUSH1 60 // Push 1 byte onto the stack.
0x0021 PUSH1 40 // Push 1 byte onto the stack.

Total time took to render response is 50.691µs! For larger smart contracts including thousands of instructions it usually takes 3-5 milliseconds to process bytecode including printing it to the stdout.

Future Developments

The opcode package is continuously evolving, and here are some of the anticipated enhancements:

  • Reverser: This tool will reverse-engineer the EVM bytecode, translating it back into a more comprehensible Solidity format.
  • Symbolic Executor: A sophisticated feature enabling the simulation of opcode execution without actual execution on the EVM, proving invaluable for debugging and analysis.