FATE

December 18, 2024 · View on GitHub

The fast æternity transaction engine.

Design

The high level machine (or the fast æternity transaction engine) has æternity transactions as its basic operations and it operates directly on the state tree of the æternity chain. This is a new paradigm in blockchain virtual machine specifications which makes it possible to create type safe and efficient implementations of the machine.

Every operation is typed and all values are typed (either by being stored in a typed memory or by a tag). Any type violation results in an exception and reverts all state changes. In version 1.0 there will be no catch instruction.

In addition to normal machine instructions, such as ADD, the machine also has support for constructing most of the transactions available on the æternity chain from native low level chain transaction instructions.

The instruction memory is divided into functions and basic blocks. Only basic blocks can be indexed and used as jump destinations.

There are instructions to operate on the chain state tree in a safe and formalized way.

FATE is "functional" in the sense that "updates" of data structures, such as tuples, lists or maps do not change the old values of the structure. Instead a new version is created, unless specific operations to write to the contract store are used.

FATE does have the ability to write the value of an operation back to the same register or stack position as one of the arguments, in effect updating the memory. Thus, any other references to the structure before the operation will have the same structure as before the operation.

Objectives

Type safety

FATE solves some fundamental problems programmers run into when coding for Ethereum: integer overflow, weak type checking and poor data flow. FATE checks all arithmetic operations to keep the right meaning of it. Also you can't implicitly cast types (eg integers to booleans).

In EVM contracts are not typed. When calling a function, EVM will try to find which function you wanted to use by looking at the data that you send into the code. In FATE, you have actual functions and the functions have types - function call has to match the function type.

FATE ultimately makes a safer coding platform for smart contracts.

Rich data types

FATE has more built in data types: like maps, lists.

Faster transactions, smaller code size

Having a higher level instructions makes the code deployed smaller and it reduces the blockchain size. Smaller code and smaller hashes also keeps a blockchain network from clogging up and results in cheaper transactions.

Components

Machine State

  • Current contract: Address
  • Current owner: Address
  • Caller: Address
  • Code: Code of current contract
  • Memory: Several components as defined below
  • CF, current function: Hash of current function
  • CBB, current basic block: Index of current basic block.
  • EC, Execution continuation: A list of instructions left in the current basic block.

Memory

The machine memory is divided into:

  • The chain top (block height, etc)
  • Event stream
  • The account state tree
  • The contract store
  • The execution/code memory
  • Execution stack (push/pop on call/return)
  • Accumulator stack (push/pop on instruction level)
  • Local storage/stack/environment/context (push/pop on let...in...end)

The execution memory

The code to execute is stored in the execution memory. The execution memory is a three level map. The key on the top level is a contract address. The second level is a map from function hashes to a map of basic blocks. The keys in the map of basic blocks are indices to basic blocks (a 0 based, dense enumeration). The values are lists of instructions.

When a contract is called the code of the contract is read from the state tree into the execution memory. At this point the machine implementation can deserialize the serialized version of FATE code into instructions and basic blocks.

The serialization format for FATE code is described in Appendix 1: Fate instruction set and serialization.

The chain

The chain "memory" contains information about the current block and the current iteration. These values are available through special instructions.

  • Beneficiary
  • Timestamp
  • (Block) Height
  • Difficulty
  • Gaslimit
  • Address
  • Balance
  • Caller
  • Value

The contract store

The permanent storage of a contract. Stored in the chain state tree. This is a key value store that is mapped to the contract state by the compiler.

The compiler can choose how to represent the contract state in the store. For instance, save the entire state under a single key (this is how it works in AEVM at the moment), or it could flatten any state records and store each field under a separate key.

The state tree

Contains all accounts, oracles and contracts on the chain. Most values such as account balances can be read directly through specific load instructions. Some values can be changed through transaction instructions.

The local storage

The local storage is a key value store. The key is a an integer. The value can be of any FATE type. The local store is local to a function call.

The accumulator stack

The accumulator stack is a stack of typed values. The top of the stack can be used as an argument to an operation. Values can be pushed to the stack and popped from the stack.

The execution stack

The execution stack contain return addresses as a tuple in the form of {contract address, function hash, and basic block index}.

The event stream

A contract can emit events similar to the EVM.

Types

The machine supports the following types:

  • Integer (signed arbitrary precision integers)
  • Boolean (true | false)
  • Strings (arbitrary size byte arrays)
  • Bytes (fixed size byte arrays)
  • Bits (An arbitrary size bitmap)
  • Address (A pointer into the state tree)
  • Contract Address (A pointer to a contract)
  • Oracle (A pointer to an oracle)
  • Oracle Query (A pointer to an oracle query)
  • Channel (A pointer to a channel)
  • Tuples (a typed series of values)
  • Lists (a list of values of a specific type)
  • Maps (a key value store)
  • Store Map (a key value store mapped to the contract state)
  • Variant Types (a set of tagged and typed values)
  • Type (a representation of a FATE type)

These types can be used as argument and return types of functions and also as the type of the elements in the contract store.

Integer

The type Integer, is used for any integer, infinitely large or small (below zero).

Examples:

 0
 1
-1
589465789334
-51315353513513131656462262

Boolean

The Boolean type only has two values, true or false.

Examples (all of them):

 true
 false

Operations on booleans include:

  • and, or, not
  • conditional jumps

Addresses, Contract Addresses, Oracles, Oracle Querries, Channels

Values of any address type are 32-byte (256-bit) pointers to entities on the chain (Accounts, Oracles, Contracts, etc)

Examples:

<<ak_2HNb8bivUoJTcaxD6VKDy2wPHvTuQgQRJ3dkF9RSyVFqBkMneC>>

Strings

Strings are stored as byte arrays. From VM version FATE_02 they are strictly UTF-8 encoded unicode characters. In particular operations String.to_list and String.from_list ensure that they only contain well formed code points.

Examples:

"Hello world"
"eof"

Bytes

In VM versions FATE_01 and FATE_02 only fixed (size known at compile time) size byte arrays exist. With the change to Strings, making them UTF-8 encoded byte arrays, there is a need for general arbitrary length byte arrays. These are introduced in FATE_03 - and a couple of new operations handling (and converting) byte arrays are added. Technical note: the bytes type was {bytes, N} / bytes(n) - to change as little as possible arbitrary size byte arrays have the type {bytes, -1} / bytes().

Tuples

Tuples have an arity indicating the number of elements in the tuple. Each element in the tuple has a type. The 0-tuple is also sometimes called unit. The maximum number of elements in the tuple is 255 (included).

Examples:

 {}                Type: unit
 {1, 2}            Type: Tuple(Integer, Integer)
 {"foo", 42, true} Type: Tuple(String, Integer, Boolean)

Lists

Lists are monomorphic series of values. Hence lists have a type. There is also an empty list (or Nil).

Examples:

[]                   Type: Nil
[1, 2, 3]            Type: List(Integer)
[true, true, false]  Type: List(Boolean)

Maps

Maps are monomorphic key value stores, that is the key is always the same type for all elements in a map and the value has the same type in all mappings in a map. The key can have any type except a map. The value can have any type including a map.

Examples:

#{ (1, "foo"), (2, "bar") }

Type: Map(Integer, String)

#{ ("Fruit prices", #{ ("banana", 42), ("apple", 12)}),
   ("Stock prices", #{("Apple", 142), ("Orange", 112)}) }

Type: Map(String, Map(String, Integer))

Variant Types

The variant type is a type consisting of a list of sizes and a tag (index) where each tag represents a series of values of specified types. For example you could have the Option type which could be None or Some(Integer). The sizes of the variant are 0 and 1 (there are two variants), The value None would be indicated by tag 0. The value Some(42) would be represented by tag 1 followed by the integer 42.

Examples:

  (| [0,1] | 0 | () |)      ;; None
  (| [0,1] | 1 | (42) |)    ;; Some(42)

  (| 4 | 3 | (42, "foo", true) |) ;; Three(42, "foo", true)

Note that the tuple syntax for the elements does not indicate a Fate tuple but a series of values.

TypeRep

A TypeRep is the representation of a type as a value. A TypeRep is one of

  • integer
  • boolean
  • any
  • {list, T}
  • {tuple, Ts}
  • address
  • contract
  • oracle
  • oracle_query
  • channel
  • bits
  • {bytes, N}
  • {map, K, V}
  • string
  • {variant, ListOfVariants}
  • {tvar, N}

where T, K and V are TypeReps, Ts is a list of TypeReps ([T1, T2, ... ]), and ListOfVariants is a list ([]) of tuples of TypeReps ([{tuple, [Ts1]}, {tuple, [Ts2]} ... ]). N is a byte (0...255).

Operations

All operations are typed. An operand can be the accumulator, an immediate, a name, a reference to a field in the state tree, or a reference to the contract state. The operand must be of the right type.

Operands

Operand specifiers are

  • immediate
  • arg
  • var
  • a (accumulator == stack 0)

The specifiers are encoded as

whatbits
immediate11
var10
arg01
stack00

Operand specifiers for operations with 1 to 4 arguments are stored in the byte following the opcode. Operand specifiers for operations with 5 to 8 arguments are stored in the two bytes following the opcode. Note that for many operation the first argument (arg0) is the destination for the operation.

value:arg3arg3arg2arg2arg1arg1arg0arg0
bit:76543210
value:arg8arg7arg6arg6arg5arg5arg4arg4
bit:76543210

Unused arguments should be set to 0.

E.g. an a := immediate + a would have the bit pattern 00 11 00 00.

Each use of the accumulator pops an argument from the stack. Writing to the accumulator pushes a value to the stack.

Operations

Description of operations

NameArgsDescriptionArg typesRes typeAdded in VM version
RETURNReturn from function call, top of stack is return value . The type of the retun value has to match the return type of the function.{}anyFATE_01
RETURNRArg0Push Arg0 and return from function. The type of the retun value has to match the return type of the function.{any}anyFATE_01
CALLArg0Call the function Arg0 with args on stack. The types of the arguments has to match the argument typs of the function.{string}anyFATE_01
CALL_RArg0 Identifier Arg2 Arg3 Arg4Remote call to contract Arg0 and function Arg1 of type Arg2 => Arg3 with value Arg4. The types of the arguments has to match the argument types of the function.{contract,string,typerep,typerep,integer}anyFATE_01
CALL_TArg0Tail call to function Arg0. The types of the arguments has to match the argument typs of the function. And the return type of the called function has to match the type of the current function.{string}anyFATE_01
CALL_GRArg0 Identifier Arg2 Arg3 Arg4 Arg5Remote call with gas cap in Arg4. Otherwise as CALL_R.{contract,string,typerep,typerep,integer,integer}anyFATE_01
JUMPIntegerJump to a basic block. The basic block has to exist in the current function.{integer}noneFATE_01
JUMPIFArg0 IntegerConditional jump to a basic block. If Arg0 then jump to Arg1.{boolean,integer}noneFATE_01
SWITCH_V2Arg0 Integer IntegerConditional jump to a basic block on variant tag.{variant,integer,ingeger}noneFATE_01
SWITCH_V3Arg0 Integer Integer IntegerConditional jump to a basic block on variant tag.{variant,integer,integer,ingeger}noneFATE_01
SWITCH_VNArg0 [Integers]Conditional jump to a basic block on variant tag.{variant,{list,integer}}noneFATE_01
CALL_VALUEArg0The value sent in the current remote call.{}integerFATE_01
PUSHArg0Push argument to stack.{any}anyFATE_01
DUPADuplicate top of stack.{any}anyFATE_01
DUPArg0push Arg0 stack pos on top of stack.{any}anyFATE_01
POPArg0Arg0 := top of stack.{integer}integerFATE_01
INCAIncrement accumulator.{integer}integerFATE_01
INCArg0Increment argument.{integer}integerFATE_01
DECADecrement accumulator.{integer}integerFATE_01
DECArg0Decrement argument.{integer}integerFATE_01
ADDArg0 Arg1 Arg2Arg0 := Arg1 + Arg2.{integer,integer}integerFATE_01
SUBArg0 Arg1 Arg2Arg0 := Arg1 - Arg2.{integer,integer}integerFATE_01
MULArg0 Arg1 Arg2Arg0 := Arg1 * Arg2.{integer,integer}integerFATE_01
DIVArg0 Arg1 Arg2Arg0 := Arg1 / Arg2.{integer,integer}integerFATE_01
MODArg0 Arg1 Arg2Arg0 := Arg1 mod Arg2.{integer,integer}integerFATE_01
POWArg0 Arg1 Arg2Arg0 := Arg1 ^ Arg2.{integer,integer}integerFATE_01
STOREArg0 Arg1Arg0 := Arg1.{any}anyFATE_01
SHA3Arg0 Arg1Arg0 := sha3(Arg1).{any}hashFATE_01
SHA256Arg0 Arg1Arg0 := sha256(Arg1).{any}hashFATE_01
BLAKE2BArg0 Arg1Arg0 := blake2b(Arg1).{any}hashFATE_01
LTArg0 Arg1 Arg2Arg0 := Arg1 < Arg2.{integer,integer}booleanFATE_01
GTArg0 Arg1 Arg2Arg0 := Arg1 > Arg2.{integer,integer}booleanFATE_01
EQArg0 Arg1 Arg2Arg0 := Arg1 = Arg2.{integer,integer}booleanFATE_01
ELTArg0 Arg1 Arg2Arg0 := Arg1 =< Arg2.{integer,integer}booleanFATE_01
EGTArg0 Arg1 Arg2Arg0 := Arg1 >= Arg2.{integer,integer}booleanFATE_01
NEQArg0 Arg1 Arg2Arg0 := Arg1 /= Arg2.{integer,integer}booleanFATE_01
ANDArg0 Arg1 Arg2Arg0 := Arg1 and Arg2.{boolean,boolean}booleanFATE_01
ORArg0 Arg1 Arg2Arg0 := Arg1 or Arg2.{boolean,boolean}booleanFATE_01
NOTArg0 Arg1Arg0 := not Arg1.{boolean}booleanFATE_01
TUPLEArg0 IntegerArg0 := tuple of size = Arg1. Elements on stack.{integer}tupleFATE_01
ELEMENTArg0 Arg1 Arg2Arg1 := element(Arg2, Arg3).{integer,tuple}anyFATE_01
SETELEMENTArg0 Arg1 Arg2 Arg3Arg0 := a new tuple similar to Arg2, but with element number Arg1 replaced by Arg3.{integer,tuple,any}tupleFATE_01
MAP_EMPTYArg0Arg0 := #{}.{}mapFATE_01
MAP_LOOKUPArg0 Arg1 Arg2Arg0 := lookup key Arg2 in map Arg1.{map,any}anyFATE_01
MAP_LOOKUPDArg0 Arg1 Arg2 Arg3Arg0 := lookup key Arg2 in map Arg1 if key exists in map otherwise Arg0 := Arg3.{map,any,any}anyFATE_01
MAP_UPDATEArg0 Arg1 Arg2 Arg3Arg0 := update key Arg2 in map Arg1 with value Arg3.{map,any,any}mapFATE_01
MAP_DELETEArg0 Arg1 Arg2Arg0 := delete key Arg2 from map Arg1.{map,any}mapFATE_01
MAP_MEMBERArg0 Arg1 Arg2Arg0 := true if key Arg2 is in map Arg1.{map,any}booleanFATE_01
MAP_FROM_LISTArg0 Arg1Arg0 := make a map from (key, value) list in Arg1.{{list,{tuple,[any,any]}}}mapFATE_01
MAP_SIZEArg0 Arg1Arg0 := The size of the map Arg1.{map}integerFATE_01
MAP_TO_LISTArg0 Arg1Arg0 := The tuple list representation of the map Arg1.{map}listFATE_01
IS_NILArg0 Arg1Arg0 := true if Arg1 == [].{list}booleanFATE_01
CONSArg0 Arg1 Arg2Arg0 := [Arg1] ++ Arg2.{any,list}listFATE_01
HDArg0 Arg1Arg0 := head of list Arg1.{list}anyFATE_01
TLArg0 Arg1Arg0 := tail of list Arg1.{list}listFATE_01
LENGTHArg0 Arg1Arg0 := length of list Arg1.{list}integerFATE_01
NILArg0Arg0 := [].{}listFATE_01
APPENDArg0 Arg1 Arg2Arg0 := Arg1 ++ Arg2.{list,list}listFATE_01
STR_JOINArg0 Arg1 Arg2Arg0 := string Arg1 followed by string Arg2.{string,string}stringFATE_01
INT_TO_STRArg0 Arg1Arg0 := turn integer Arg1 into a string.{integer}stringFATE_01
ADDR_TO_STRArg0 Arg1Arg0 := turn address Arg1 into a string.{address}stringFATE_01
STR_REVERSEArg0 Arg1Arg0 := the reverse of string Arg1.{string}stringFATE_01
STR_LENGTHArg0 Arg1Arg0 := The length of the string Arg1.{string}integerFATE_01
BYTES_TO_INTArg0 Arg1Arg0 := bytes_to_int(Arg1){bytes}integerFATE_01
BYTES_TO_STRArg0 Arg1Arg0 := bytes_to_str(Arg1){bytes}stringFATE_01
BYTES_CONCATArg0 Arg1 Arg2Arg0 := bytes_concat(Arg1, Arg2){bytes,bytes}bytesFATE_01
BYTES_SPLITArg0 Arg1 Arg2Arg0 := bytes_split(Arg2, Arg1), where Arg2 is the length of the first chunk.{bytes,integer}bytesFATE_01
INT_TO_ADDRArg0 Arg1Arg0 := turn integer Arg1 into an address.{integer}addressFATE_01
VARIANTArg0 Arg1 Arg2 Arg3Arg0 := create a variant of size Arg1 with the tag Arg2 (Arg2 < Arg1) and take Arg3 elements from the stack.{integer,integer,integer}variantFATE_01
VARIANT_TESTArg0 Arg1 Arg2Arg0 := true if variant Arg1 has the tag Arg2.{variant,integer}booleanFATE_01
VARIANT_ELEMENTArg0 Arg1 Arg2Arg0 := element number Arg2 from variant Arg1.{variant,integer}anyFATE_01
BITS_NONEApush an empty bitmap on the stack.{}bitsFATE_01
BITS_NONEArg0Arg0 := empty bitmap.{}bitsFATE_01
BITS_ALLApush a full bitmap on the stack.{}bitsFATE_01
BITS_ALLArg0Arg0 := full bitmap.{}bitsFATE_01
BITS_ALL_NArg0 Arg1Arg0 := bitmap with Arg1 bits set.{integer}bitsFATE_01
BITS_SETArg0 Arg1 Arg2Arg0 := set bit Arg2 of bitmap Arg1.{bits,integer}bitsFATE_01
BITS_CLEARArg0 Arg1 Arg2Arg0 := clear bit Arg2 of bitmap Arg1.{bits,integer}bitsFATE_01
BITS_TESTArg0 Arg1 Arg2Arg0 := true if bit Arg2 of bitmap Arg1 is set.{bits,integer}booleanFATE_01
BITS_SUMArg0 Arg1Arg0 := sum of set bits in bitmap Arg1. Exception if infinit bitmap.{bits}integerFATE_01
BITS_ORArg0 Arg1 Arg2Arg0 := Arg1 v Arg2.{bits,bits}bitsFATE_01
BITS_ANDArg0 Arg1 Arg2Arg0 := Arg1 ^ Arg2.{bits,bits}bitsFATE_01
BITS_DIFFArg0 Arg1 Arg2Arg0 := Arg1 - Arg2.{bits,bits}bitsFATE_01
BALANCEArg0Arg0 := The current contract balance.{}integerFATE_01
ORIGINArg0Arg0 := Address of contract called by the call transaction.{}addressFATE_01
CALLERArg0Arg0 := The address that signed the call transaction.{}addressFATE_01
BLOCKHASHArg0 Arg1Arg0 := The blockhash at height.{integer}variantFATE_01
BENEFICIARYArg0Arg0 := The address of the current beneficiary.{}addressFATE_01
TIMESTAMPArg0Arg0 := The current timestamp. Unreliable, don't use for anything.{}integerFATE_01
GENERATIONArg0Arg0 := The block height of the current generation.{}integerFATE_01
MICROBLOCKArg0Arg0 := The current micro block number.{}integerFATE_01
DIFFICULTYArg0Arg0 := The current difficulty.{}integerFATE_01
GASLIMITArg0Arg0 := The current gaslimit.{}integerFATE_01
GASArg0Arg0 := The amount of gas left.{}integerFATE_01
ADDRESSArg0Arg0 := The current contract address.{}addressFATE_01
GASPRICEArg0Arg0 := The current gas price.{}integerFATE_01
LOG0Arg0Create a log message in the call object.{string}noneFATE_01
LOG1Arg0 Arg1Create a log message with one topic in the call object.{integer,string}noneFATE_01
LOG2Arg0 Arg1 Arg2Create a log message with two topics in the call object.{integer,integer,string}noneFATE_01
LOG3Arg0 Arg1 Arg2 Arg3Create a log message with three topics in the call object.{integer,integer,integer,string}noneFATE_01
LOG4Arg0 Arg1 Arg2 Arg3 Arg4Create a log message with four topics in the call object.{integer,integer,integer,integer,string}noneFATE_01
SPENDArg0 Arg1Transfer Arg1 coins to account Arg0. (If the contract account has at least that many coins.{address,integer}noneFATE_01
ORACLE_REGISTERArg0 Arg1 Arg2 Arg3 Arg4 Arg5 Arg6Arg0 := New oracle with address Arg2, query fee Arg3, TTL Arg4, query type Arg5 and response type Arg6. Arg0 contains delegation signature.{signature,address,integer,variant,typerep,typerep}oracleFATE_01
ORACLE_QUERYArg0 Arg1 Arg2 Arg3 Arg4 Arg5 Arg6 Arg7Arg0 := New oracle query for oracle Arg1, question in Arg2, query fee in Arg3, query TTL in Arg4, response TTL in Arg5. Typereps for checking oracle type is in Arg6 and Arg7.{oracle,any,integer,variant,variant,typerep,typerep}oracle_queryFATE_01
ORACLE_RESPONDArg0 Arg1 Arg2 Arg3 Arg4 Arg5Respond as oracle Arg1 to query in Arg2 with response Arg3. Arg0 contains delegation signature. Typereps for checking oracle type is in Arg4 and Arg5.{signature,oracle,oracle_query,any,typerep,typerep}noneFATE_01
ORACLE_EXTENDArg0 Arg1 Arg2Extend oracle in Arg1 with TTL in Arg2. Arg0 contains delegation signature.{signature,oracle,variant}noneFATE_01
ORACLE_GET_ANSWERArg0 Arg1 Arg2 Arg3 Arg4Arg0 := option variant with answer (if any) from oracle query in Arg1 given by oracle Arg0. Typereps for checking oracle type is in Arg3 and Arg4.{oracle,oracle_query,typerep,typerep}anyFATE_01
ORACLE_GET_QUESTIONArg0 Arg1 Arg2 Arg3 Arg4Arg0 := question in oracle query Arg2 given to oracle Arg1. Typereps for checking oracle type is in Arg3 and Arg4.{oracle,oracle_query,typerep,typerep}anyFATE_01
ORACLE_QUERY_FEEArg0 Arg1Arg0 := query fee for oracle Arg1{oracle}integerFATE_01
AENS_RESOLVEArg0 Arg1 Arg2 Arg3Resolve name in Arg0 with tag Arg1. Arg2 describes the type parameter of the resolved name.{string,string,typerep}variantFATE_01
AENS_PRECLAIMArg0 Arg1 Arg2Preclaim the hash in Arg2 for address in Arg1. Arg0 contains delegation signature.{signature,address,hash}noneFATE_01
AENS_CLAIMArg0 Arg1 Arg2 Arg3 Arg4Attempt to claim the name in Arg2 for address in Arg1 at a price in Arg4. Arg3 contains the salt used to hash the preclaim. Arg0 contains delegation signature.{signature,address,string,integer,integer}noneFATE_01
AENS_UPDATEArg0 Arg1 Arg2 Arg3 Arg4 Arg5Updates name in Arg2 for address in Arg1. Arg3 contains optional ttl (of type Chain.ttl), Arg4 contains optional client_ttl (of type int), Arg5 contains optional pointers (of type map(string, pointee)). Arg0 contains delegation signature.{signature,address,string,variant,variant,variant}noneFATE_01
AENS_TRANSFERArg0 Arg1 Arg2 Arg3Transfer ownership of name Arg3 from account Arg1 to Arg2. Arg0 contains delegation signature.{signature,address,address,string}noneFATE_01
AENS_REVOKEArg0 Arg1 Arg2Revoke the name in Arg2 from owner Arg1. Arg0 contains delegation signature.{signature,address,string}noneFATE_01
BALANCE_OTHERArg0 Arg1Arg0 := The balance of address Arg1.{address}integerFATE_01
VERIFY_SIGArg0 Arg1 Arg2 Arg3Arg0 := verify_sig(Hash, PubKey, Signature){bytes,address,bytes}booleanFATE_01
VERIFY_SIG_SECP256K1Arg0 Arg1 Arg2 Arg3Arg0 := verify_sig_secp256k1(Hash, PubKey, Signature){bytes,bytes,bytes}booleanFATE_01
CONTRACT_TO_ADDRESSArg0 Arg1Arg0 := Arg1 - A no-op type conversion{contract}addressFATE_01
AUTH_TX_HASHArg0If in GA authentication context return Some(TxHash) otherwise None.{}variantFATE_01
ORACLE_CHECKArg0 Arg1 Arg2 Arg3Arg0 := is Arg1 an oracle with the given query (Arg2) and response (Arg3) types{oracle,typerep,typerep}boolFATE_01
ORACLE_CHECK_QUERYArg0 Arg1 Arg2 Arg3 Arg4Arg0 := is Arg2 a query for the oracle Arg1 with the given types (Arg3, Arg4){oracle,oracle_query,typerep,typerep}boolFATE_01
IS_ORACLEArg0 Arg1Arg0 := is Arg1 an oracle{address}boolFATE_01
IS_CONTRACTArg0 Arg1Arg0 := is Arg1 a contract{address}boolFATE_01
IS_PAYABLEArg0 Arg1Arg0 := is Arg1 a payable address{address}boolFATE_01
CREATORArg0Arg0 := contract creator{}addressFATE_01
ECVERIFY_SECP256K1Arg0 Arg1 Arg2 Arg3Arg0 := ecverify_secp256k1(Hash, Addr, Signature){bytes,bytes,bytes}bytesFATE_01
ECRECOVER_SECP256K1Arg0 Arg1 Arg2Arg0 := ecrecover_secp256k1(Hash, Signature){bytes,bytes}bytesFATE_01
ADDRESS_TO_CONTRACTArg0 Arg1Arg0 := Arg1 - A no-op type conversion{address}contractFATE_01
BLS12_381_G1_NEGArg0 Arg1Arg0 := BLS12_381.g1_neg(Arg1) - Negate a G1-value{tuple}tupleFATE_02
BLS12_381_G1_NORMArg0 Arg1Arg0 := BLS12_381.g1_normalize(Arg1) - Normalize a G1-value{tuple}tupleFATE_02
BLS12_381_G1_VALIDArg0 Arg1Arg0 := BLS12_381.g1_valid(Arg1) - Check if G1-value is a valid group member{tuple}boolFATE_02
BLS12_381_G1_IS_ZEROArg0 Arg1Arg0 := BLS12_381.g1_is_zero(Arg1) - Check if G1-value is zero{tuple}boolFATE_02
BLS12_381_G1_ADDArg0 Arg1 Arg2Arg0 := BLS12_381.g1_add(Arg1, Arg2) - Add two G1-values{tuple,tuple}tupleFATE_02
BLS12_381_G1_MULArg0 Arg1 Arg2Arg0 := BLS12_381.g1_mul(Arg1, Arg2) - Scalar multiplication for a G1-value (Arg1), and an Fr-value{tuple,tuple}tupleFATE_02
BLS12_381_G2_NEGArg0 Arg1Arg0 := BLS12_381.g2_neg(Arg1) - Negate a G2-value{tuple}tupleFATE_02
BLS12_381_G2_NORMArg0 Arg1Arg0 := BLS12_381.g2_normalize(Arg1) - Normalize a G2-value{tuple}tupleFATE_02
BLS12_381_G2_VALIDArg0 Arg1Arg0 := BLS12_381.g2_valid(Arg1) - Check if G2-value is a valid group member{tuple}boolFATE_02
BLS12_381_G2_IS_ZEROArg0 Arg1Arg0 := BLS12_381.g2_is_zero(Arg1) - Check if G2-value is zero{tuple}boolFATE_02
BLS12_381_G2_ADDArg0 Arg1 Arg2Arg0 := BLS12_381.g2_add(Arg1, Arg2) - Add two G2-values{tuple,tuple}tupleFATE_02
BLS12_381_G2_MULArg0 Arg1 Arg2Arg0 := BLS12_381.g2_mul(Arg1, Arg2) - Scalar multiplication for a G2-value (Arg2), and an Fr-value{tuple,tuple}tupleFATE_02
BLS12_381_GT_INVArg0 Arg1Arg0 := BLS12_381.gt_inv(Arg1) - Invert a GT-value{tuple}tupleFATE_02
BLS12_381_GT_ADDArg0 Arg1 Arg2Arg0 := BLS12_381.gt_add(Arg1, Arg2) - Add two GT-values{tuple,tuple}tupleFATE_02
BLS12_381_GT_MULArg0 Arg1 Arg2Arg0 := BLS12_381.gt_mul(Arg1, Arg2) - Multiply two GT-values{tuple,tuple}tupleFATE_02
BLS12_381_GT_POWArg0 Arg1 Arg2Arg0 := BLS12_381.gt_pow(Arg1, Arg2) - Scalar exponentiation for a GT-value (Arg2), and an Fr-value{tuple,tuple}tupleFATE_02
BLS12_381_GT_IS_ONEArg0 Arg1Arg0 := BLS12_381.gt_is_one(Arg1) - Check if a GT value is "one"{tuple}boolFATE_02
BLS12_381_PAIRINGArg0 Arg1 Arg2Arg0 := BLS12_381.pairing(Arg1, Arg2) - Find the pairing of a G1-value (Arg1) and a G2-value (Arg2){tuple,tuple}tupleFATE_02
BLS12_381_MILLER_LOOPArg0 Arg1 Arg2Arg0 := BLS12_381.miller_loop(Arg1, Arg2) - Do the Miller-loop step of pairing for a G1-value (Arg1) and a G2-value (Arg2){tuple,tuple}tupleFATE_02
BLS12_381_FINAL_EXPArg0 Arg1Arg0 := BLS12_381.final_exp(Arg1) - Do the final exponentiation in pairing{tuple}tupleFATE_02
BLS12_381_INT_TO_FRArg0 Arg1Arg0 := to_montgomery(Arg1) - Convert (Big)integer to Montgomery representation (32 bytes){tuple}tupleFATE_02
BLS12_381_INT_TO_FPArg0 Arg1Arg0 := to_montgomery(Arg1) - Convert (Big)integer to Montgomery representation (48 bytes){tuple}tupleFATE_02
BLS12_381_FR_TO_INTArg0 Arg1Arg0 := from_montgomery(Arg1) - Convert Montgomery representation (32 bytes) to integer{tuple}tupleFATE_02
BLS12_381_FP_TO_INTArg0 Arg1Arg0 := from_montgomery(Arg1) - Convert Montgomery representation (48 bytes) to integer{tuple}tupleFATE_02
AENS_LOOKUPArg0 Arg1Lookup the name of Arg0. Returns option(AENS.name){string}variantFATE_02
ORACLE_EXPIRYArg0 Arg1Arg0 := expiry block for oracle Arg1{oracle}intFATE_02
AUTH_TXArg0If in GA authentication context return Some(Tx) otherwise None.{}variantFATE_02
STR_TO_LISTArg0 Arg1Arg0 := string converted to list of characters{string}listFATE_02
STR_FROM_LISTArg0 Arg1Arg0 := string converted from list of characters{list}stringFATE_02
STR_TO_UPPERArg0 Arg1Arg0 := to_upper(string){string}stringFATE_02
STR_TO_LOWERArg0 Arg1Arg0 := to_lower(string){string}stringFATE_02
CHAR_TO_INTArg0 Arg1Arg0 := integer representation of UTF-8 character{char}intFATE_02
CHAR_FROM_INTArg0 Arg1Arg0 := Some(UTF-8 character) from integer if valid, None if not valid.{int}variantFATE_02
CALL_PGRArg0 Identifier Arg2 Arg3 Arg4 Arg5 Arg6Potentially protected remote call. Arg5 is protected flag, otherwise as CALL_GR.{contract,string,typerep,typerep,integer,integer,bool}variantFATE_02
CREATEArg0 Arg1 Arg2Deploys a contract with a bytecode Arg1 and value Arg3. The init arguments should be placed on the stack and match the type in Arg2. Writes contract address to the top of the accumulator stack. If an account on the resulting address did exist before the call, the payable flag will be updated.{contract_bytearray,typerep,integer}contractFATE_02
CLONEArg0 Arg1 Arg2 Arg3Clones the contract under Arg1 and deploys it with value of Arg3. The init arguments should be placed on the stack and match the type in Arg2. Writes contract (or None on fail when protected) to the top of the accumulator stack. Does not copy the existing contract's store – it will be initialized by a fresh call to the init function. If an account on the resulting address did exist before the call, the payable flag will be updated.{contract,typerep,integer,bool}anyFATE_02
CLONE_GArg0 Arg1 Arg2 Arg3 Arg4Like CLONE but additionally limits the gas of the init call by Arg3{contract,typerep,integer,integer,bool}anyFATE_02
BYTECODE_HASHArg0 Arg1Arg0 := hash of the deserialized contract's bytecode under address given in Arg1 (or None on fail). Fails on AEVM contracts and contracts deployed before Iris.{contract}variantFATE_02
FEEArg0Arg0 := The fee for the current call tx.{}integerFATE_02
ADDRESS_TO_BYTESArg0 Arg1Arg0 := the fixed size byte representation of the address Arg1{address}bytesFATE_03
POSEIDONArg0 Arg1 Arg2Arg0 := the Poseidon hash of Arg1 and Arg2 - all integers in the BLS12-381 scalar field{integer, integer}integerFATE_03
MULMODArg0 Arg1 Arg2 Arg3Arg0 := (Arg1 * Arg2) mod Arg3{integer, integer, integer}integerFATE_03
BANDArg0 Arg1 Arg2Arg0 := Arg1 & Arg2{integer, integer}integerFATE_03
BORArg0 Arg1 Arg2Arg0 := Arg1Arg2{integer, integer}integer
BXORArg0 Arg1 Arg2Arg0 := Arg1 ^ Arg2{integer, integer}integerFATE_03
BNOTArg0 Arg1Arg0 := ~Arg1{integer}integerFATE_03
BSLArg0 Arg1 Arg2Arg0 := Arg1 << Arg2{integer, integer}integerFATE_03
BSRArg0 Arg1 Arg2Arg0 := Arg1 >> Arg2{integer, integer}integerFATE_03
BYTES_SPLIT_ANYArg0 Arg1 Arg2Arg0 := bytes_split_any(Arg1, Arg2), where a positive Arg2 is the length of the first chunk, and a negative Arg2 is the length of the second chunk. Returns None if byte array is not long enough.{bytes, integer}variantFATE_03
BYTES_SIZEArg0 Arg1Arg0 := bytes_size(Arg1), returns the number of bytes in the byte array.{bytes}integerFATE_03
BYTES_TO_FIXED_SIZEArg0 Arg1 Arg2Arg0 := bytes_to_fixe_size(Arg1, Arg2), returns Some(Arg1') if byte_size(Arg1) == Arg2, None otherwise. The type of Arg1' is bytes(Arg2) but the value is unchanged{bytes, integer}variantFATE_03
INT_TO_BYTESArg0 Arg1 Arg2Arg0 := turn integer Arg1 into a byte array (big endian) length Arg2 (truncating if not fit).{integer, integer}bytesFATE_03
STR_TO_BYTESArg0 Arg1Arg0 := turn string Arg1 into the corresponding byte array.{string}bytesFATE_03
DEACTIVATEMark the current contract for deactivation.{}noneFATE_01
ABORTArg0Abort execution (dont use all gas) with error message in Arg0.{string}noneFATE_01
EXITArg0Abort execution (use upp all gas) with error message in Arg0.{string}noneFATE_01
NOPThe no op. does nothing.{}noneFATE_01

Opcodes, Flags and Gas

OpcodeNameEnds basic blockAllowed in authAllowed offchainGas cost
0x0RETURNtruetruetrue10
0x1RETURNRtruetruetrue10
0x2CALLtruetruetrue10
0x3CALL_Rtruefalsetrue100
0x4CALL_Ttruetruetrue10
0x5CALL_GRtruefalsetrue100
0x6JUMPtruetruetrue10
0x7JUMPIFtruetruetrue10
0x8SWITCH_V2truetruetrue10
0x9SWITCH_V3truetruetrue10
0xaSWITCH_VNtruetruetrue10
0xbCALL_VALUEfalsetruetrue10
0xcPUSHfalsetruetrue10
0xdDUPAfalsetruetrue10
0xeDUPfalsetruetrue10
0xfPOPfalsetruetrue10
0x10INCAfalsetruetrue10
0x11INCfalsetruetrue10
0x12DECAfalsetruetrue10
0x13DECfalsetruetrue10
0x14ADDfalsetruetrue10
0x15SUBfalsetruetrue10
0x16MULfalsetruetrue10
0x17DIVfalsetruetrue10
0x18MODfalsetruetrue10
0x19POWfalsetruetrue10
0x1aSTOREfalsetruetrue10
0x1bSHA3falsetruetrue100
0x1cSHA256falsetruetrue100
0x1dBLAKE2Bfalsetruetrue100
0x1eLTfalsetruetrue10
0x1fGTfalsetruetrue10
0x20EQfalsetruetrue10
0x21ELTfalsetruetrue10
0x22EGTfalsetruetrue10
0x23NEQfalsetruetrue10
0x24ANDfalsetruetrue10
0x25ORfalsetruetrue10
0x26NOTfalsetruetrue10
0x27TUPLEfalsetruetrue10
0x28ELEMENTfalsetruetrue10
0x29SETELEMENTfalsetruetrue10
0x2aMAP_EMPTYfalsetruetrue10
0x2bMAP_LOOKUPfalsetruetrue10
0x2cMAP_LOOKUPDfalsetruetrue10
0x2dMAP_UPDATEfalsetruetrue10
0x2eMAP_DELETEfalsetruetrue10
0x2fMAP_MEMBERfalsetruetrue10
0x30MAP_FROM_LISTfalsetruetrue10
0x31MAP_SIZEfalsetruetrue10
0x32MAP_TO_LISTfalsetruetrue10
0x33IS_NILfalsetruetrue10
0x34CONSfalsetruetrue10
0x35HDfalsetruetrue10
0x36TLfalsetruetrue10
0x37LENGTHfalsetruetrue10
0x38NILfalsetruetrue10
0x39APPENDfalsetruetrue10
0x3aSTR_JOINfalsetruetrue10
0x3bINT_TO_STRfalsetruetrue100
0x3cADDR_TO_STRfalsetruetrue100
0x3dSTR_REVERSEfalsetruetrue100
0x3eSTR_LENGTHfalsetruetrue10
0x3fBYTES_TO_INTfalsetruetrue10
0x40BYTES_TO_STRfalsetruetrue100
0x41BYTES_CONCATfalsetruetrue10
0x42BYTES_SPLITfalsetruetrue10
0x43INT_TO_ADDRfalsetruetrue10
0x44VARIANTfalsetruetrue10
0x45VARIANT_TESTfalsetruetrue10
0x46VARIANT_ELEMENTfalsetruetrue10
0x47BITS_NONEAfalsetruetrue10
0x48BITS_NONEfalsetruetrue10
0x49BITS_ALLAfalsetruetrue10
0x4aBITS_ALLfalsetruetrue10
0x4bBITS_ALL_Nfalsetruetrue10
0x4cBITS_SETfalsetruetrue10
0x4dBITS_CLEARfalsetruetrue10
0x4eBITS_TESTfalsetruetrue10
0x4fBITS_SUMfalsetruetrue10
0x50BITS_ORfalsetruetrue10
0x51BITS_ANDfalsetruetrue10
0x52BITS_DIFFfalsetruetrue10
0x53BALANCEfalsetruetrue10
0x54ORIGINfalsetruetrue10
0x55CALLERfalsetruetrue10
0x56BLOCKHASHfalsetruetrue1000 (iris), 10 (lima)
0x57BENEFICIARYfalsetruetrue10
0x58TIMESTAMPfalsetruetrue10
0x59GENERATIONfalsetruetrue10
0x5aMICROBLOCKfalsetruetrue10
0x5bDIFFICULTYfalsetruetrue10
0x5cGASLIMITfalsetruetrue10
0x5dGASfalsetruetrue10
0x5eADDRESSfalsetruetrue10
0x5fGASPRICEfalsetruetrue10
0x60LOG0falsetruetrue1000
0x61LOG1falsetruetrue1100
0x62LOG2falsetruetrue1200
0x63LOG3falsetruetrue1300
0x64LOG4falsetruetrue1400
0x65SPENDfalsefalsetrue5000 (iris), 100 (lima)
0x66ORACLE_REGISTERfalsefalsefalse10000 (iris), 100 (lima)
0x67ORACLE_QUERYfalsefalsefalse10000 (iris), 100 (lima)
0x68ORACLE_RESPONDfalsefalsefalse10000 (iris), 100 (lima)
0x69ORACLE_EXTENDfalsefalsefalse10000 (iris), 100 (lima)
0x6aORACLE_GET_ANSWERfalsefalsetrue2000 (iris), 100 (lima)
0x6bORACLE_GET_QUESTIONfalsefalsetrue2000 (iris), 100 (lima)
0x6cORACLE_QUERY_FEEfalsefalsetrue2000 (iris), 100 (lima)
0x6dAENS_RESOLVEfalsefalsetrue2000 (iris), 100 (lima)
0x6eAENS_PRECLAIMfalsefalsefalse10000 (iris), 100 (lima)
0x6fAENS_CLAIMfalsefalsefalse10000 (iris), 100 (lima)
0x70AENS_UPDATEfalsefalsefalse10000 (iris), 100 (lima)
0x71AENS_TRANSFERfalsefalsefalse10000 (iris), 100 (lima)
0x72AENS_REVOKEfalsefalsefalse10000 (iris), 100 (lima)
0x73BALANCE_OTHERfalsetruetrue2000 (iris), 50 (lima)
0x74VERIFY_SIGfalsetruetrue1300
0x75VERIFY_SIG_SECP256K1falsetruetrue1300
0x76CONTRACT_TO_ADDRESSfalsetruetrue10
0x77AUTH_TX_HASHfalsetruetrue10
0x78ORACLE_CHECKfalsefalsetrue100
0x79ORACLE_CHECK_QUERYfalsefalsetrue100
0x7aIS_ORACLEfalsefalsetrue100
0x7bIS_CONTRACTfalsefalsetrue100
0x7cIS_PAYABLEfalsefalsetrue100
0x7dCREATORfalsetruetrue10
0x7eECVERIFY_SECP256K1falsetruetrue1300
0x7fECRECOVER_SECP256K1falsetruetrue1300
0x80ADDRESS_TO_CONTRACTfalsetruetrue10
0x81BLS12_381_G1_NEGfalsetruetrue100
0x82BLS12_381_G1_NORMfalsetruetrue100
0x83BLS12_381_G1_VALIDfalsetruetrue2000
0x84BLS12_381_G1_IS_ZEROfalsetruetrue30
0x85BLS12_381_G1_ADDfalsetruetrue100
0x86BLS12_381_G1_MULfalsetruetrue1000
0x87BLS12_381_G2_NEGfalsetruetrue100
0x88BLS12_381_G2_NORMfalsetruetrue100
0x89BLS12_381_G2_VALIDfalsetruetrue2000
0x8aBLS12_381_G2_IS_ZEROfalsetruetrue30
0x8bBLS12_381_G2_ADDfalsetruetrue100
0x8cBLS12_381_G2_MULfalsetruetrue1000
0x8dBLS12_381_GT_INVfalsetruetrue100
0x8eBLS12_381_GT_ADDfalsetruetrue100
0x8fBLS12_381_GT_MULfalsetruetrue100
0x90BLS12_381_GT_POWfalsetruetrue2000
0x91BLS12_381_GT_IS_ONEfalsetruetrue30
0x92BLS12_381_PAIRINGfalsetruetrue12000
0x93BLS12_381_MILLER_LOOPfalsetruetrue5000
0x94BLS12_381_FINAL_EXPfalsetruetrue7000
0x95BLS12_381_INT_TO_FRfalsetruetrue30
0x96BLS12_381_INT_TO_FPfalsetruetrue30
0x97BLS12_381_FR_TO_INTfalsetruetrue30
0x98BLS12_381_FP_TO_INTfalsetruetrue30
0x99AENS_LOOKUPfalsefalsetrue2000
0x9aORACLE_EXPIRYfalsefalsetrue2000
0x9bAUTH_TXfalsetruetrue100
0x9cSTR_TO_LISTfalsetruetrue100
0x9dSTR_FROM_LISTfalsetruetrue100
0x9eSTR_TO_UPPERfalsetruetrue100
0x9fSTR_TO_LOWERfalsetruetrue100
0xa0CHAR_TO_INTfalsetruetrue10
0xa1CHAR_FROM_INTfalsetruetrue10
0xa2CALL_PGRtruefalsetrue100
0xa3CREATEtruefalsetrue10000
0xa4CLONEtruefalsetrue5000
0xa5CLONE_Gtruefalsetrue5000
0xa6BYTECODE_HASHfalsetruetrue100
0xa7FEEfalsetruetrue10
0xa8ADDRESS_TO_BYTESfalsetruetrue10
0xa9POSEIDONfalsetruetrue6000
0xaaMULMODfalsetruetrue10
0xabBANDfalsetruetrue10
0xacBORfalsetruetrue10
0xadBXORfalsetruetrue10
0xaeBNOTfalsetruetrue10
0xafBSLfalsetruetrue10
0xb0BSRfalsetruetrue10
0xb1BYTES_SPLIT_ANYfalsetruetrue10
0xb2BYTES_SIZEfalsetruetrue10
0xb3BYTES_TO_FIXED_SIZEfalsetruetrue10
0xb4INT_TO_BYTESfalsetruetrue10
0xb5STR_TO_BYTESfalsetruetrue10
0xfaDEACTIVATEfalsetruetrue10
0xfbABORTtruetruetrue10
0xfcEXITtruetruetrue10
0xfdNOPfalsetruetrue1

Gas

Each instruction uses the base gas as described in the table above. In addition to the instruction base cost (some) instructions also cost gas in relation to the memory they use. The base cost for memory is one gas per "cell" used. A cell is the memory word of an underlying machine which is defined to be a 64-bit word.

Each use of a a cell is counted and for each 1024 cells used the price is increased by 1. If a contract uses 1024 cells it will cost 1024 gas, if it uses 1025 cells it will cost 1026 gas. Using 2049 cells costs 3072 gas and so on.

When calculating the cell cost the total number of cells used after the instruction is used to determine the price for all new cells used by the instruction. So if you have used 1020 cells and then one instruction uses 5 new cells, then the gas cost for that instruction is 10 and not 6.

Each use of a stack slot (a push) costs gas in the same way and is also counted towards the number of used cells. Each pop of a stack slot does not cost gas and does not decrease the gas cost either but it reduced the count of number of cells in use.

The instructions uses cells in the following way.

ADD, SUB, MUL, DIV, MOD

After the operation is done the size of the absolute value of the result is calculated, and one cell is used per 64 bits that has a 1 set. Integers -18446744073709551615 to 18446744073709551615 uses 1 cell, and integers -340282366920938463463374607431768211456 to -18446744073709551616 and 18446744073709551616 to 340282366920938463463374607431768211456 uses 2 cells, and so on.

POW

The result of the pow instruction is computed recursively and for each step in the recursion the words used are calculated and the operation is aborted if all gas is used up. Given the function words which calculates the number of cells in an integer as described above (1 per 64 bits used). The number of cells are calculated as follows.

pow(a, b)    := pow(a, b, 1)

pow(a, b, r) := r  when b = 0
pow(a, b, r) := cells += words(a) * 2, pow(a*a, b/2, r) when b rem 2 = 0
pow(a, b, r) := cells += words(r) + words(a) * 3, pow(a*a, b/2, r*a)

TUPLE

For creating a tuple you have already payed gas for the elements when you pushed them on the stack with other operations, then the new tuple increase the cell count by the size of the tuple plus 2.

Note that creating the tuple pops the elements from the stack so the cell count only increases by 2 by the make_tuple instruction, but the gas cost is the cost for size+2 cells.

Note also that when calculating cell cost the total number of cells used after the instruction is used to determine the price for all new cells used by the instruction.

SETELEMENT

The number of cells used is the tuple size + 2.

MAP_EMPTY

The cell cost is 2.

MAP_UPDATE

The cell cost is 2.

MAP_FROM_LIST

The cell cost is 2 + length of the list.

MAP_TO_LIST

The cell cost is 2 * length of the list.

CONS

The cell cost is 2.

APPEND

The cell cost is 2 * length of the first list.

STR_JOIN

The cell cost is 1 cell per 8 bytes in the joined string + 1 cell.

INT_TO_STR

The cell cost is 1 cell per 8 bytes in the produced string + 1 cell.

ADDR_TO_STR

The cell cost is 1 cell per 8 bytes in the produced string + 1 cell.

STR_REVERSE

The cell cost is 1 cell per 8 bytes in the produced string + 1 cell.

INT_TO_ADDR

The cell cost is 1 cell per 8 bytes in the produced address + 1 cell.

BITS_NONE, BITS_NONEA, BITS_ALL, BITS_ALLA

The cell cost is 1 cell.

BITS_ALL_N

The cell cost is 1 for every 64 bits used.

BITS_SET, BITS_CLEAR

The cell cost is 1 for every 64 bits used by the resulting bit field.

BYTES_CONCAT

The cell cost is 1 cell per 8 bytes in the produced byte array.

BYTES_TO_STR

The cell cost is 1 cell per 8 bytes in resulting string + 1 cell.

BYTES_SPLIT

The number of cells used is the tuple size which is 2 + 2.

AUTH_TX_HASH

If in auth context the number of cells used is 2 + 2, otherwise the number of cells used is 1 + 2.

VARIANT

The cell cost is two times the length of the list of arities plus one for each element in the variant plus four.

Appendix 1: FATE serialization

A more formal description of the serialization can be found in the general serialization document. Here we will try to describe the serialization more with words.

FATE code is serialized in three chunks:

  1. Code: The code itself.
  2. Symbols: An optional symbol table.
  3. Annotations: Optional additional information.

Each chunk is an RLP encoding of a byte array that is the serialization of the chunk. They all have to be there in the serialization but they can be empty. An empty code chunk is just the RPL encoding of the empty byte array, i.e the byte 128. Symbols and Annotations can be empty but they have to be there as the RLP encoding of the RLP encoding of the empty map i.e. the bytes 130, 47, 0.

An empty FATE contract is encoded as the byte sequence 128, 130, 47, 0, 130, 47, 0.

Appendix 2: Delegation signatures

A couple of FATE operations can perform actions on behalf of a "user", these operations are: AENS_PRECLAIM, AENS_CLAIM, AENS_UPDATE, AENS_TRANSFER, AENS_REVOKE, ORACLE_REGISTER, ORACLE_RESPOND, and ORACLE_EXTEND. The first argument of these operations is a delegation signature - the signature "proves" that the user is allowed to manipulate the object (name or oracle). Naturally, if the contract itself is the owner of the name/oracle the signature is not needed. Otherwise, the user signs (using the private key) data authorizing the operation. Note: it is not possible to make a delegation signature using a generalized account.

There are five different delegation signatures:

  • AENS_PRECLAIM - the user signs: owner account + contract
  • AENS_CLAIM,AENS_UPDATE, AENS_TRANSFER, AENS_REVOKE - the user signs: owner account + name hash + contract
  • AENS wildcard (valid for any name) - the user signs: owner account + contract [New in FATE_03]
  • ORACLE_REGISTER, ORACLE_EXTEND - the user signs: owner account + contract
  • ORACLE_RESPOND - the user signs: query id + contract

To protect about cross network re-use of signatures, the data to be signed is also prefixed with the network id.

From Ceres: Serialized signature data

From Ceres/FATE_03 the material to be signed is more structured; the reason is two-fold, (a) to make it easier for the signer to see the what is signed and why, and (b) to safeguard against spoofing a transaction as a delegation signature (their structure was similar). Note: the semantic data to be signed has not changed from the description above, only the exact bytes to be signed and its structure.

For general information about serialization, RLP encoding, etc, see the general serialization document.

We use the tag 0x1a01 to identify delegation signatures. We use the following tags/types to identify the different delegation signatures:

TagDelegation type
1aens wildcard
2aens name
3aens preclaim
4oracle
5oracle response

For serialization we use a schema similar to chain object serialization with the tags in the table above and version is 1. I.e. S = rlp([tag, vsn] ++ fields) with fields as described below. The complete binary to sign is:

 0x1a01 + <network_id> + S

AENS Wildcard

[ <account>  :: id()
, <contract> :: id() ]

AENS Name

[ <account>  :: id()
, <name>     :: id()
, <contract> :: id() ]

AENS Preclaim

[ <account>  :: id()
, <contract> :: id() ]

Oracle handling

[ <account>  :: id()
, <contract> :: id() ]

Oracle response

[ <query_id> :: id()     %% using id type 'oracle'
, <contract> :: id() ]

Notation

Some notes on notation and definition of terms used in this document.

Bits

Bits are counted from the least significant bit, starting on 0. When bits are written out they are written from the most significant bit to the least significant bit.

Example the number 1 in a byte would be written in binary as:

00000001

And we would say that bit 0 is set to 1. All other bits 1 to 7 are set to 0.

Word size

The word size of the machine is 8 bits (one byte) but each type and instruction uses words of varying sizes, all multiples of bytes though.