Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

New OpCodes

Here we describe the process of adding a new AVM OpCode to go-algorand reference implementation, providing the example of a dummy double OpCode.

The AVM OpCodes are versioned (langspec_v) and can be categorized as:

  • Arithmetic and Logic Operations
  • Byte Array Manipulation
  • Cryptographic Operations
  • Pushing Values on Stack/Heap (Constants, Txn / ASA / App / Account / Global Fields)
  • Control Flow
  • State Access
  • Inner Transactions

OpCode Definition

Most OpCodes logic lives in data/transactions/logic/eval.go folder. Some exceptions are larger families of OpCodes with their own files (e.g., box.go).

For the dummy double OpCode example, let’s define the operator function in data/transactions/logic/eval.go :

func opDouble(cx *EvalContext) error {
    last := len(cx.Stack) - 1
    res, carry := bits.Add64(cx.Stack[last].Uint, cx.Stack[last].Uint, 0)
    if carry > 0 {
        return errors.New("double overflowed")
    }
    cx.Stack[last].Uint = res
    return nil
}

OpCode Spec

OpCodes are included by adding them to opcodes.go with a unique byte value.

Let’s add the new OpSpec value in the OpSpecs array.

The format is {0x01, "sha256", opSHA256, proto("b:b{32}"), 2, costly(35)}.

The arguments may be interpreted as follows:

  • A byte indicating the OpCode number,

  • A string with the identifier of the OpCode,

  • The eval.go function that handles OpCode execution (defined above),

  • A proto structure defined through the proto() function. This indicates the actual signature of the new OpCode.

    • The element before : indicates the values to be popped from the top of the stack,
    • The element after : indicates the values to be pushed to the stack,
    • The letter identifies the type of arguments. In case of byte arrays the length could be expressed as a number in curly brackets.
  • The AVM version where the new OpCode is introduced,

  • The cost of the new OpCode.

For the double dummy OpCode:

var OpSpecs = []OpSpec{
    ...
    // Double OpCode
    {0x75, "double", opDouble, proto("i:i"), 42, detDefault()},
    ...
}

Update LangSpec

Run make from within the data/transactions/logic/ directory to generate an updated language specification (langspec_v) and TEAL docs.

Build Binary

Run make from the root of the go-algorand directory to build new algod binary.

Testing

Tests are organized in the accompanying data/transactions/logic/eval_test.go file.

Let’s test the new OpCode locally by generating a netgoal template and running a new Local Network.

Be sure to set the network’s Consensus Version to future if you’re adding an OpCode to a future AVM version.

OpCode Cost Estimation

Estimate the new OpCode budget (e.g., benchmarking against similar ones).