fate

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.

Last updated