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 (link).
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
byteindicating the OpCode number, -
A
stringwith the identifier of the OpCode, -
The
eval.gofunction that handles OpCode execution (defined above), -
A
protostructure defined through theproto()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
bytearrays the length could be expressed as a number in curly brackets.
- The element before
-
The AVM
versionwhere the new OpCode is introduced, -
The
costof 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
futureif you’re adding an OpCode to a future AVM version.
OpCode Cost Estimation
Estimate the new OpCode budget (e.g., benchmarking against similar ones).