Skip to content

FATE

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

what bits
immediate 11
var 10
arg 01
stack 00

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: arg3 arg3 arg2 arg2 arg1 arg1 arg0 arg0
bit: 7 6 5 4 3 2 1 0
value: arg8 arg7 arg6 arg6 arg5 arg5 arg4 arg4
bit: 7 6 5 4 3 2 1 0

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

Name Args Description Arg types Res type Added in VM version
RETURN Return from function call, top of stack is return value . The type of the retun value has to match the return type of the function. {} any FATE_01
RETURNR Arg0 Push Arg0 and return from function. The type of the retun value has to match the return type of the function. {any} any FATE_01
CALL Arg0 Call the function Arg0 with args on stack. The types of the arguments has to match the argument typs of the function. {string} any FATE_01
CALL_R Arg0 Identifier Arg2 Arg3 Arg4 Remote 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} any FATE_01
CALL_T Arg0 Tail 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} any FATE_01
CALL_GR Arg0 Identifier Arg2 Arg3 Arg4 Arg5 Remote call with gas cap in Arg4. Otherwise as CALL_R. {contract,string,typerep,typerep,integer,integer} any FATE_01
JUMP Integer Jump to a basic block. The basic block has to exist in the current function. {integer} none FATE_01
JUMPIF Arg0 Integer Conditional jump to a basic block. If Arg0 then jump to Arg1. {boolean,integer} none FATE_01
SWITCH_V2 Arg0 Integer Integer Conditional jump to a basic block on variant tag. {variant,integer,ingeger} none FATE_01
SWITCH_V3 Arg0 Integer Integer Integer Conditional jump to a basic block on variant tag. {variant,integer,integer,ingeger} none FATE_01
SWITCH_VN Arg0 [Integers] Conditional jump to a basic block on variant tag. {variant,{list,integer}} none FATE_01
CALL_VALUE Arg0 The value sent in the current remote call. {} integer FATE_01
PUSH Arg0 Push argument to stack. {any} any FATE_01
DUPA Duplicate top of stack. {any} any FATE_01
DUP Arg0 push Arg0 stack pos on top of stack. {any} any FATE_01
POP Arg0 Arg0 := top of stack. {integer} integer FATE_01
INCA Increment accumulator. {integer} integer FATE_01
INC Arg0 Increment argument. {integer} integer FATE_01
DECA Decrement accumulator. {integer} integer FATE_01
DEC Arg0 Decrement argument. {integer} integer FATE_01
ADD Arg0 Arg1 Arg2 Arg0 := Arg1 + Arg2. {integer,integer} integer FATE_01
SUB Arg0 Arg1 Arg2 Arg0 := Arg1 - Arg2. {integer,integer} integer FATE_01
MUL Arg0 Arg1 Arg2 Arg0 := Arg1 * Arg2. {integer,integer} integer FATE_01
DIV Arg0 Arg1 Arg2 Arg0 := Arg1 / Arg2. {integer,integer} integer FATE_01
MOD Arg0 Arg1 Arg2 Arg0 := Arg1 mod Arg2. {integer,integer} integer FATE_01
POW Arg0 Arg1 Arg2 Arg0 := Arg1 ^ Arg2. {integer,integer} integer FATE_01
STORE Arg0 Arg1 Arg0 := Arg1. {any} any FATE_01
SHA3 Arg0 Arg1 Arg0 := sha3(Arg1). {any} hash FATE_01
SHA256 Arg0 Arg1 Arg0 := sha256(Arg1). {any} hash FATE_01
BLAKE2B Arg0 Arg1 Arg0 := blake2b(Arg1). {any} hash FATE_01
LT Arg0 Arg1 Arg2 Arg0 := Arg1 < Arg2. {integer,integer} boolean FATE_01
GT Arg0 Arg1 Arg2 Arg0 := Arg1 > Arg2. {integer,integer} boolean FATE_01
EQ Arg0 Arg1 Arg2 Arg0 := Arg1 = Arg2. {integer,integer} boolean FATE_01
ELT Arg0 Arg1 Arg2 Arg0 := Arg1 =< Arg2. {integer,integer} boolean FATE_01
EGT Arg0 Arg1 Arg2 Arg0 := Arg1 >= Arg2. {integer,integer} boolean FATE_01
NEQ Arg0 Arg1 Arg2 Arg0 := Arg1 /= Arg2. {integer,integer} boolean FATE_01
AND Arg0 Arg1 Arg2 Arg0 := Arg1 and Arg2. {boolean,boolean} boolean FATE_01
OR Arg0 Arg1 Arg2 Arg0 := Arg1 or Arg2. {boolean,boolean} boolean FATE_01
NOT Arg0 Arg1 Arg0 := not Arg1. {boolean} boolean FATE_01
TUPLE Arg0 Integer Arg0 := tuple of size = Arg1. Elements on stack. {integer} tuple FATE_01
ELEMENT Arg0 Arg1 Arg2 Arg1 := element(Arg2, Arg3). {integer,tuple} any FATE_01
SETELEMENT Arg0 Arg1 Arg2 Arg3 Arg0 := a new tuple similar to Arg2, but with element number Arg1 replaced by Arg3. {integer,tuple,any} tuple FATE_01
MAP_EMPTY Arg0 Arg0 := #{}. {} map FATE_01
MAP_LOOKUP Arg0 Arg1 Arg2 Arg0 := lookup key Arg2 in map Arg1. {map,any} any FATE_01
MAP_LOOKUPD Arg0 Arg1 Arg2 Arg3 Arg0 := lookup key Arg2 in map Arg1 if key exists in map otherwise Arg0 := Arg3. {map,any,any} any FATE_01
MAP_UPDATE Arg0 Arg1 Arg2 Arg3 Arg0 := update key Arg2 in map Arg1 with value Arg3. {map,any,any} map FATE_01
MAP_DELETE Arg0 Arg1 Arg2 Arg0 := delete key Arg2 from map Arg1. {map,any} map FATE_01
MAP_MEMBER Arg0 Arg1 Arg2 Arg0 := true if key Arg2 is in map Arg1. {map,any} boolean FATE_01
MAP_FROM_LIST Arg0 Arg1 Arg0 := make a map from (key, value) list in Arg1. {{list,{tuple,[any,any]}}} map FATE_01
MAP_SIZE Arg0 Arg1 Arg0 := The size of the map Arg1. {map} integer FATE_01
MAP_TO_LIST Arg0 Arg1 Arg0 := The tuple list representation of the map Arg1. {map} list FATE_01
IS_NIL Arg0 Arg1 Arg0 := true if Arg1 == []. {list} boolean FATE_01
CONS Arg0 Arg1 Arg2 Arg0 := [Arg1] ++ Arg2. {any,list} list FATE_01
HD Arg0 Arg1 Arg0 := head of list Arg1. {list} any FATE_01
TL Arg0 Arg1 Arg0 := tail of list Arg1. {list} list FATE_01
LENGTH Arg0 Arg1 Arg0 := length of list Arg1. {list} integer FATE_01
NIL Arg0 Arg0 := []. {} list FATE_01
APPEND Arg0 Arg1 Arg2 Arg0 := Arg1 ++ Arg2. {list,list} list FATE_01
STR_JOIN Arg0 Arg1 Arg2 Arg0 := string Arg1 followed by string Arg2. {string,string} string FATE_01
INT_TO_STR Arg0 Arg1 Arg0 := turn integer Arg1 into a string. {integer} string FATE_01
ADDR_TO_STR Arg0 Arg1 Arg0 := turn address Arg1 into a string. {address} string FATE_01
STR_REVERSE Arg0 Arg1 Arg0 := the reverse of string Arg1. {string} string FATE_01
STR_LENGTH Arg0 Arg1 Arg0 := The length of the string Arg1. {string} integer FATE_01
BYTES_TO_INT Arg0 Arg1 Arg0 := bytes_to_int(Arg1) {bytes} integer FATE_01
BYTES_TO_STR Arg0 Arg1 Arg0 := bytes_to_str(Arg1) {bytes} string FATE_01
BYTES_CONCAT Arg0 Arg1 Arg2 Arg0 := bytes_concat(Arg1, Arg2) {bytes,bytes} bytes FATE_01
BYTES_SPLIT Arg0 Arg1 Arg2 Arg0 := bytes_split(Arg2, Arg1), where Arg2 is the length of the first chunk. {bytes,integer} bytes FATE_01
INT_TO_ADDR Arg0 Arg1 Arg0 := turn integer Arg1 into an address. {integer} address FATE_01
VARIANT Arg0 Arg1 Arg2 Arg3 Arg0 := create a variant of size Arg1 with the tag Arg2 (Arg2 < Arg1) and take Arg3 elements from the stack. {integer,integer,integer} variant FATE_01
VARIANT_TEST Arg0 Arg1 Arg2 Arg0 := true if variant Arg1 has the tag Arg2. {variant,integer} boolean FATE_01
VARIANT_ELEMENT Arg0 Arg1 Arg2 Arg0 := element number Arg2 from variant Arg1. {variant,integer} any FATE_01
BITS_NONEA push an empty bitmap on the stack. {} bits FATE_01
BITS_NONE Arg0 Arg0 := empty bitmap. {} bits FATE_01
BITS_ALLA push a full bitmap on the stack. {} bits FATE_01
BITS_ALL Arg0 Arg0 := full bitmap. {} bits FATE_01
BITS_ALL_N Arg0 Arg1 Arg0 := bitmap with Arg1 bits set. {integer} bits FATE_01
BITS_SET Arg0 Arg1 Arg2 Arg0 := set bit Arg2 of bitmap Arg1. {bits,integer} bits FATE_01
BITS_CLEAR Arg0 Arg1 Arg2 Arg0 := clear bit Arg2 of bitmap Arg1. {bits,integer} bits FATE_01
BITS_TEST Arg0 Arg1 Arg2 Arg0 := true if bit Arg2 of bitmap Arg1 is set. {bits,integer} boolean FATE_01
BITS_SUM Arg0 Arg1 Arg0 := sum of set bits in bitmap Arg1. Exception if infinit bitmap. {bits} integer FATE_01
BITS_OR Arg0 Arg1 Arg2 Arg0 := Arg1 v Arg2. {bits,bits} bits FATE_01
BITS_AND Arg0 Arg1 Arg2 Arg0 := Arg1 ^ Arg2. {bits,bits} bits FATE_01
BITS_DIFF Arg0 Arg1 Arg2 Arg0 := Arg1 - Arg2. {bits,bits} bits FATE_01
BALANCE Arg0 Arg0 := The current contract balance. {} integer FATE_01
ORIGIN Arg0 Arg0 := Address of contract called by the call transaction. {} address FATE_01
CALLER Arg0 Arg0 := The address that signed the call transaction. {} address FATE_01
BLOCKHASH Arg0 Arg1 Arg0 := The blockhash at height. {integer} variant FATE_01
BENEFICIARY Arg0 Arg0 := The address of the current beneficiary. {} address FATE_01
TIMESTAMP Arg0 Arg0 := The current timestamp. Unreliable, don't use for anything. {} integer FATE_01
GENERATION Arg0 Arg0 := The block height of the current generation. {} integer FATE_01
MICROBLOCK Arg0 Arg0 := The current micro block number. {} integer FATE_01
DIFFICULTY Arg0 Arg0 := The current difficulty. {} integer FATE_01
GASLIMIT Arg0 Arg0 := The current gaslimit. {} integer FATE_01
GAS Arg0 Arg0 := The amount of gas left. {} integer FATE_01
ADDRESS Arg0 Arg0 := The current contract address. {} address FATE_01
GASPRICE Arg0 Arg0 := The current gas price. {} integer FATE_01
LOG0 Arg0 Create a log message in the call object. {string} none FATE_01
LOG1 Arg0 Arg1 Create a log message with one topic in the call object. {integer,string} none FATE_01
LOG2 Arg0 Arg1 Arg2 Create a log message with two topics in the call object. {integer,integer,string} none FATE_01
LOG3 Arg0 Arg1 Arg2 Arg3 Create a log message with three topics in the call object. {integer,integer,integer,string} none FATE_01
LOG4 Arg0 Arg1 Arg2 Arg3 Arg4 Create a log message with four topics in the call object. {integer,integer,integer,integer,string} none FATE_01
SPEND Arg0 Arg1 Transfer Arg1 coins to account Arg0. (If the contract account has at least that many coins. {address,integer} none FATE_01
ORACLE_REGISTER Arg0 Arg1 Arg2 Arg3 Arg4 Arg5 Arg6 Arg0 := 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} oracle FATE_01
ORACLE_QUERY Arg0 Arg1 Arg2 Arg3 Arg4 Arg5 Arg6 Arg7 Arg0 := 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_query FATE_01
ORACLE_RESPOND Arg0 Arg1 Arg2 Arg3 Arg4 Arg5 Respond 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} none FATE_01
ORACLE_EXTEND Arg0 Arg1 Arg2 Extend oracle in Arg1 with TTL in Arg2. Arg0 contains delegation signature. {signature,oracle,variant} none FATE_01
ORACLE_GET_ANSWER Arg0 Arg1 Arg2 Arg3 Arg4 Arg0 := 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} any FATE_01
ORACLE_GET_QUESTION Arg0 Arg1 Arg2 Arg3 Arg4 Arg0 := question in oracle query Arg2 given to oracle Arg1. Typereps for checking oracle type is in Arg3 and Arg4. {oracle,oracle_query,typerep,typerep} any FATE_01
ORACLE_QUERY_FEE Arg0 Arg1 Arg0 := query fee for oracle Arg1 {oracle} integer FATE_01
AENS_RESOLVE Arg0 Arg1 Arg2 Arg3 Resolve name in Arg0 with tag Arg1. Arg2 describes the type parameter of the resolved name. {string,string,typerep} variant FATE_01
AENS_PRECLAIM Arg0 Arg1 Arg2 Preclaim the hash in Arg2 for address in Arg1. Arg0 contains delegation signature. {signature,address,hash} none FATE_01
AENS_CLAIM Arg0 Arg1 Arg2 Arg3 Arg4 Attempt 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} none FATE_01
AENS_UPDATE Arg0 Arg1 Arg2 Arg3 Arg4 Arg5 Updates 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} none FATE_01
AENS_TRANSFER Arg0 Arg1 Arg2 Arg3 Transfer ownership of name Arg3 from account Arg1 to Arg2. Arg0 contains delegation signature. {signature,address,address,string} none FATE_01
AENS_REVOKE Arg0 Arg1 Arg2 Revoke the name in Arg2 from owner Arg1. Arg0 contains delegation signature. {signature,address,string} none FATE_01
BALANCE_OTHER Arg0 Arg1 Arg0 := The balance of address Arg1. {address} integer FATE_01
VERIFY_SIG Arg0 Arg1 Arg2 Arg3 Arg0 := verify_sig(Hash, PubKey, Signature) {bytes,address,bytes} boolean FATE_01
VERIFY_SIG_SECP256K1 Arg0 Arg1 Arg2 Arg3 Arg0 := verify_sig_secp256k1(Hash, PubKey, Signature) {bytes,bytes,bytes} boolean FATE_01
CONTRACT_TO_ADDRESS Arg0 Arg1 Arg0 := Arg1 - A no-op type conversion {contract} address FATE_01
AUTH_TX_HASH Arg0 If in GA authentication context return Some(TxHash) otherwise None. {} variant FATE_01
ORACLE_CHECK Arg0 Arg1 Arg2 Arg3 Arg0 := is Arg1 an oracle with the given query (Arg2) and response (Arg3) types {oracle,typerep,typerep} bool FATE_01
ORACLE_CHECK_QUERY Arg0 Arg1 Arg2 Arg3 Arg4 Arg0 := is Arg2 a query for the oracle Arg1 with the given types (Arg3, Arg4) {oracle,oracle_query,typerep,typerep} bool FATE_01
IS_ORACLE Arg0 Arg1 Arg0 := is Arg1 an oracle {address} bool FATE_01
IS_CONTRACT Arg0 Arg1 Arg0 := is Arg1 a contract {address} bool FATE_01
IS_PAYABLE Arg0 Arg1 Arg0 := is Arg1 a payable address {address} bool FATE_01
CREATOR Arg0 Arg0 := contract creator {} address FATE_01
ECVERIFY_SECP256K1 Arg0 Arg1 Arg2 Arg3 Arg0 := ecverify_secp256k1(Hash, Addr, Signature) {bytes,bytes,bytes} bytes FATE_01
ECRECOVER_SECP256K1 Arg0 Arg1 Arg2 Arg0 := ecrecover_secp256k1(Hash, Signature) {bytes,bytes} bytes FATE_01
ADDRESS_TO_CONTRACT Arg0 Arg1 Arg0 := Arg1 - A no-op type conversion {address} contract FATE_01
BLS12_381_G1_NEG Arg0 Arg1 Arg0 := BLS12_381.g1_neg(Arg1) - Negate a G1-value {tuple} tuple FATE_02
BLS12_381_G1_NORM Arg0 Arg1 Arg0 := BLS12_381.g1_normalize(Arg1) - Normalize a G1-value {tuple} tuple FATE_02
BLS12_381_G1_VALID Arg0 Arg1 Arg0 := BLS12_381.g1_valid(Arg1) - Check if G1-value is a valid group member {tuple} bool FATE_02
BLS12_381_G1_IS_ZERO Arg0 Arg1 Arg0 := BLS12_381.g1_is_zero(Arg1) - Check if G1-value is zero {tuple} bool FATE_02
BLS12_381_G1_ADD Arg0 Arg1 Arg2 Arg0 := BLS12_381.g1_add(Arg1, Arg2) - Add two G1-values {tuple,tuple} tuple FATE_02
BLS12_381_G1_MUL Arg0 Arg1 Arg2 Arg0 := BLS12_381.g1_mul(Arg1, Arg2) - Scalar multiplication for a G1-value (Arg1), and an Fr-value {tuple,tuple} tuple FATE_02
BLS12_381_G2_NEG Arg0 Arg1 Arg0 := BLS12_381.g2_neg(Arg1) - Negate a G2-value {tuple} tuple FATE_02
BLS12_381_G2_NORM Arg0 Arg1 Arg0 := BLS12_381.g2_normalize(Arg1) - Normalize a G2-value {tuple} tuple FATE_02
BLS12_381_G2_VALID Arg0 Arg1 Arg0 := BLS12_381.g2_valid(Arg1) - Check if G2-value is a valid group member {tuple} bool FATE_02
BLS12_381_G2_IS_ZERO Arg0 Arg1 Arg0 := BLS12_381.g2_is_zero(Arg1) - Check if G2-value is zero {tuple} bool FATE_02
BLS12_381_G2_ADD Arg0 Arg1 Arg2 Arg0 := BLS12_381.g2_add(Arg1, Arg2) - Add two G2-values {tuple,tuple} tuple FATE_02
BLS12_381_G2_MUL Arg0 Arg1 Arg2 Arg0 := BLS12_381.g2_mul(Arg1, Arg2) - Scalar multiplication for a G2-value (Arg2), and an Fr-value {tuple,tuple} tuple FATE_02
BLS12_381_GT_INV Arg0 Arg1 Arg0 := BLS12_381.gt_inv(Arg1) - Invert a GT-value {tuple} tuple FATE_02
BLS12_381_GT_ADD Arg0 Arg1 Arg2 Arg0 := BLS12_381.gt_add(Arg1, Arg2) - Add two GT-values {tuple,tuple} tuple FATE_02
BLS12_381_GT_MUL Arg0 Arg1 Arg2 Arg0 := BLS12_381.gt_mul(Arg1, Arg2) - Multiply two GT-values {tuple,tuple} tuple FATE_02
BLS12_381_GT_POW Arg0 Arg1 Arg2 Arg0 := BLS12_381.gt_pow(Arg1, Arg2) - Scalar exponentiation for a GT-value (Arg2), and an Fr-value {tuple,tuple} tuple FATE_02
BLS12_381_GT_IS_ONE Arg0 Arg1 Arg0 := BLS12_381.gt_is_one(Arg1) - Check if a GT value is "one" {tuple} bool FATE_02
BLS12_381_PAIRING Arg0 Arg1 Arg2 Arg0 := BLS12_381.pairing(Arg1, Arg2) - Find the pairing of a G1-value (Arg1) and a G2-value (Arg2) {tuple,tuple} tuple FATE_02
BLS12_381_MILLER_LOOP Arg0 Arg1 Arg2 Arg0 := 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} tuple FATE_02
BLS12_381_FINAL_EXP Arg0 Arg1 Arg0 := BLS12_381.final_exp(Arg1) - Do the final exponentiation in pairing {tuple} tuple FATE_02
BLS12_381_INT_TO_FR Arg0 Arg1 Arg0 := to_montgomery(Arg1) - Convert (Big)integer to Montgomery representation (32 bytes) {tuple} tuple FATE_02
BLS12_381_INT_TO_FP Arg0 Arg1 Arg0 := to_montgomery(Arg1) - Convert (Big)integer to Montgomery representation (48 bytes) {tuple} tuple FATE_02
BLS12_381_FR_TO_INT Arg0 Arg1 Arg0 := from_montgomery(Arg1) - Convert Montgomery representation (32 bytes) to integer {tuple} tuple FATE_02
BLS12_381_FP_TO_INT Arg0 Arg1 Arg0 := from_montgomery(Arg1) - Convert Montgomery representation (48 bytes) to integer {tuple} tuple FATE_02
AENS_LOOKUP Arg0 Arg1 Lookup the name of Arg0. Returns option(AENS.name) {string} variant FATE_02
ORACLE_EXPIRY Arg0 Arg1 Arg0 := expiry block for oracle Arg1 {oracle} int FATE_02
AUTH_TX Arg0 If in GA authentication context return Some(Tx) otherwise None. {} variant FATE_02
STR_TO_LIST Arg0 Arg1 Arg0 := string converted to list of characters {string} list FATE_02
STR_FROM_LIST Arg0 Arg1 Arg0 := string converted from list of characters {list} string FATE_02
STR_TO_UPPER Arg0 Arg1 Arg0 := to_upper(string) {string} string FATE_02
STR_TO_LOWER Arg0 Arg1 Arg0 := to_lower(string) {string} string FATE_02
CHAR_TO_INT Arg0 Arg1 Arg0 := integer representation of UTF-8 character {char} int FATE_02
CHAR_FROM_INT Arg0 Arg1 Arg0 := Some(UTF-8 character) from integer if valid, None if not valid. {int} variant FATE_02
CALL_PGR Arg0 Identifier Arg2 Arg3 Arg4 Arg5 Arg6 Potentially protected remote call. Arg5 is protected flag, otherwise as CALL_GR. {contract,string,typerep,typerep,integer,integer,bool} variant FATE_02
CREATE Arg0 Arg1 Arg2 Deploys 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} contract FATE_02
CLONE Arg0 Arg1 Arg2 Arg3 Clones 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} any FATE_02
CLONE_G Arg0 Arg1 Arg2 Arg3 Arg4 Like CLONE but additionally limits the gas of the init call by Arg3 {contract,typerep,integer,integer,bool} any FATE_02
BYTECODE_HASH Arg0 Arg1 Arg0 := 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} variant FATE_02
FEE Arg0 Arg0 := The fee for the current call tx. {} integer FATE_02
ADDRESS_TO_BYTES Arg0 Arg1 Arg0 := the fixed size byte representation of the address Arg1 {address} bytes FATE_03
POSEIDON Arg0 Arg1 Arg2 Arg0 := the Poseidon hash of Arg1 and Arg2 - all integers in the BLS12-381 scalar field {integer, integer} integer FATE_03
MULMOD Arg0 Arg1 Arg2 Arg3 Arg0 := (Arg1 * Arg2) mod Arg3 {integer, integer, integer} integer FATE_03
BAND Arg0 Arg1 Arg2 Arg0 := Arg1 & Arg2 {integer, integer} integer FATE_03
BOR Arg0 Arg1 Arg2 Arg0 := Arg1 Arg2 {integer, integer} integer
BXOR Arg0 Arg1 Arg2 Arg0 := Arg1 ^ Arg2 {integer, integer} integer FATE_03
BNOT Arg0 Arg1 Arg0 := ~Arg1 {integer} integer FATE_03
BSL Arg0 Arg1 Arg2 Arg0 := Arg1 << Arg2 {integer, integer} integer FATE_03
BSR Arg0 Arg1 Arg2 Arg0 := Arg1 >> Arg2 {integer, integer} integer FATE_03
BYTES_SPLIT_ANY Arg0 Arg1 Arg2 Arg0 := 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} variant FATE_03
BYTES_SIZE Arg0 Arg1 Arg0 := bytes_size(Arg1), returns the number of bytes in the byte array. {bytes} integer FATE_03
BYTES_TO_FIXED_SIZE Arg0 Arg1 Arg2 Arg0 := 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} variant FATE_03
INT_TO_BYTES Arg0 Arg1 Arg2 Arg0 := turn integer Arg1 into a byte array (big endian) length Arg2 (truncating if not fit). {integer, integer} bytes FATE_03
STR_TO_BYTES Arg0 Arg1 Arg0 := turn string Arg1 into the corresponding byte array. {string} bytes FATE_03
DEACTIVATE Mark the current contract for deactivation. {} none FATE_01
ABORT Arg0 Abort execution (dont use all gas) with error message in Arg0. {string} none FATE_01
EXIT Arg0 Abort execution (use upp all gas) with error message in Arg0. {string} none FATE_01
NOP The no op. does nothing. {} none FATE_01

Opcodes, Flags and Gas

Opcode Name Ends basic block Allowed in auth Allowed offchain Gas cost
0x0 RETURN true true true 10
0x1 RETURNR true true true 10
0x2 CALL true true true 10
0x3 CALL_R true false true 100
0x4 CALL_T true true true 10
0x5 CALL_GR true false true 100
0x6 JUMP true true true 10
0x7 JUMPIF true true true 10
0x8 SWITCH_V2 true true true 10
0x9 SWITCH_V3 true true true 10
0xa SWITCH_VN true true true 10
0xb CALL_VALUE false true true 10
0xc PUSH false true true 10
0xd DUPA false true true 10
0xe DUP false true true 10
0xf POP false true true 10
0x10 INCA false true true 10
0x11 INC false true true 10
0x12 DECA false true true 10
0x13 DEC false true true 10
0x14 ADD false true true 10
0x15 SUB false true true 10
0x16 MUL false true true 10
0x17 DIV false true true 10
0x18 MOD false true true 10
0x19 POW false true true 10
0x1a STORE false true true 10
0x1b SHA3 false true true 100
0x1c SHA256 false true true 100
0x1d BLAKE2B false true true 100
0x1e LT false true true 10
0x1f GT false true true 10
0x20 EQ false true true 10
0x21 ELT false true true 10
0x22 EGT false true true 10
0x23 NEQ false true true 10
0x24 AND false true true 10
0x25 OR false true true 10
0x26 NOT false true true 10
0x27 TUPLE false true true 10
0x28 ELEMENT false true true 10
0x29 SETELEMENT false true true 10
0x2a MAP_EMPTY false true true 10
0x2b MAP_LOOKUP false true true 10
0x2c MAP_LOOKUPD false true true 10
0x2d MAP_UPDATE false true true 10
0x2e MAP_DELETE false true true 10
0x2f MAP_MEMBER false true true 10
0x30 MAP_FROM_LIST false true true 10
0x31 MAP_SIZE false true true 10
0x32 MAP_TO_LIST false true true 10
0x33 IS_NIL false true true 10
0x34 CONS false true true 10
0x35 HD false true true 10
0x36 TL false true true 10
0x37 LENGTH false true true 10
0x38 NIL false true true 10
0x39 APPEND false true true 10
0x3a STR_JOIN false true true 10
0x3b INT_TO_STR false true true 100
0x3c ADDR_TO_STR false true true 100
0x3d STR_REVERSE false true true 100
0x3e STR_LENGTH false true true 10
0x3f BYTES_TO_INT false true true 10
0x40 BYTES_TO_STR false true true 100
0x41 BYTES_CONCAT false true true 10
0x42 BYTES_SPLIT false true true 10
0x43 INT_TO_ADDR false true true 10
0x44 VARIANT false true true 10
0x45 VARIANT_TEST false true true 10
0x46 VARIANT_ELEMENT false true true 10
0x47 BITS_NONEA false true true 10
0x48 BITS_NONE false true true 10
0x49 BITS_ALLA false true true 10
0x4a BITS_ALL false true true 10
0x4b BITS_ALL_N false true true 10
0x4c BITS_SET false true true 10
0x4d BITS_CLEAR false true true 10
0x4e BITS_TEST false true true 10
0x4f BITS_SUM false true true 10
0x50 BITS_OR false true true 10
0x51 BITS_AND false true true 10
0x52 BITS_DIFF false true true 10
0x53 BALANCE false true true 10
0x54 ORIGIN false true true 10
0x55 CALLER false true true 10
0x56 BLOCKHASH false true true 1000 (iris), 10 (lima)
0x57 BENEFICIARY false true true 10
0x58 TIMESTAMP false true true 10
0x59 GENERATION false true true 10
0x5a MICROBLOCK false true true 10
0x5b DIFFICULTY false true true 10
0x5c GASLIMIT false true true 10
0x5d GAS false true true 10
0x5e ADDRESS false true true 10
0x5f GASPRICE false true true 10
0x60 LOG0 false true true 1000
0x61 LOG1 false true true 1100
0x62 LOG2 false true true 1200
0x63 LOG3 false true true 1300
0x64 LOG4 false true true 1400
0x65 SPEND false false true 5000 (iris), 100 (lima)
0x66 ORACLE_REGISTER false false false 10000 (iris), 100 (lima)
0x67 ORACLE_QUERY false false false 10000 (iris), 100 (lima)
0x68 ORACLE_RESPOND false false false 10000 (iris), 100 (lima)
0x69 ORACLE_EXTEND false false false 10000 (iris), 100 (lima)
0x6a ORACLE_GET_ANSWER false false true 2000 (iris), 100 (lima)
0x6b ORACLE_GET_QUESTION false false true 2000 (iris), 100 (lima)
0x6c ORACLE_QUERY_FEE false false true 2000 (iris), 100 (lima)
0x6d AENS_RESOLVE false false true 2000 (iris), 100 (lima)
0x6e AENS_PRECLAIM false false false 10000 (iris), 100 (lima)
0x6f AENS_CLAIM false false false 10000 (iris), 100 (lima)
0x70 AENS_UPDATE false false false 10000 (iris), 100 (lima)
0x71 AENS_TRANSFER false false false 10000 (iris), 100 (lima)
0x72 AENS_REVOKE false false false 10000 (iris), 100 (lima)
0x73 BALANCE_OTHER false true true 2000 (iris), 50 (lima)
0x74 VERIFY_SIG false true true 1300
0x75 VERIFY_SIG_SECP256K1 false true true 1300
0x76 CONTRACT_TO_ADDRESS false true true 10
0x77 AUTH_TX_HASH false true true 10
0x78 ORACLE_CHECK false false true 100
0x79 ORACLE_CHECK_QUERY false false true 100
0x7a IS_ORACLE false false true 100
0x7b IS_CONTRACT false false true 100
0x7c IS_PAYABLE false false true 100
0x7d CREATOR false true true 10
0x7e ECVERIFY_SECP256K1 false true true 1300
0x7f ECRECOVER_SECP256K1 false true true 1300
0x80 ADDRESS_TO_CONTRACT false true true 10
0x81 BLS12_381_G1_NEG false true true 100
0x82 BLS12_381_G1_NORM false true true 100
0x83 BLS12_381_G1_VALID false true true 2000
0x84 BLS12_381_G1_IS_ZERO false true true 30
0x85 BLS12_381_G1_ADD false true true 100
0x86 BLS12_381_G1_MUL false true true 1000
0x87 BLS12_381_G2_NEG false true true 100
0x88 BLS12_381_G2_NORM false true true 100
0x89 BLS12_381_G2_VALID false true true 2000
0x8a BLS12_381_G2_IS_ZERO false true true 30
0x8b BLS12_381_G2_ADD false true true 100
0x8c BLS12_381_G2_MUL false true true 1000
0x8d BLS12_381_GT_INV false true true 100
0x8e BLS12_381_GT_ADD false true true 100
0x8f BLS12_381_GT_MUL false true true 100
0x90 BLS12_381_GT_POW false true true 2000
0x91 BLS12_381_GT_IS_ONE false true true 30
0x92 BLS12_381_PAIRING false true true 12000
0x93 BLS12_381_MILLER_LOOP false true true 5000
0x94 BLS12_381_FINAL_EXP false true true 7000
0x95 BLS12_381_INT_TO_FR false true true 30
0x96 BLS12_381_INT_TO_FP false true true 30
0x97 BLS12_381_FR_TO_INT false true true 30
0x98 BLS12_381_FP_TO_INT false true true 30
0x99 AENS_LOOKUP false false true 2000
0x9a ORACLE_EXPIRY false false true 2000
0x9b AUTH_TX false true true 100
0x9c STR_TO_LIST false true true 100
0x9d STR_FROM_LIST false true true 100
0x9e STR_TO_UPPER false true true 100
0x9f STR_TO_LOWER false true true 100
0xa0 CHAR_TO_INT false true true 10
0xa1 CHAR_FROM_INT false true true 10
0xa2 CALL_PGR true false true 100
0xa3 CREATE true false true 10000
0xa4 CLONE true false true 5000
0xa5 CLONE_G true false true 5000
0xa6 BYTECODE_HASH false true true 100
0xa7 FEE false true true 10
0xa8 ADDRESS_TO_BYTES false true true 10
0xa9 POSEIDON false true true 6000
0xaa MULMOD false true true 10
0xab BAND false true true 10
0xac BOR false true true 10
0xad BXOR false true true 10
0xae BNOT false true true 10
0xaf BSL false true true 10
0xb0 BSR false true true 10
0xb1 BYTES_SPLIT_ANY false true true 10
0xb2 BYTES_SIZE false true true 10
0xb3 BYTES_TO_FIXED_SIZE false true true 10
0xb4 INT_TO_BYTES false true true 10
0xb5 STR_TO_BYTES false true true 10
0xfa DEACTIVATE false true true 10
0xfb ABORT true true true 10
0xfc EXIT true true true 10
0xfd NOP false true true 1

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:

Tag Delegation type
1 aens wildcard
2 aens name
3 aens preclaim
4 oracle
5 oracle 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.