æternity consensus protocol
Last updated
Was this helpful?
Last updated
Was this helpful?
This document defines the æternity consensus protocol.
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in .
x || y
, x concatenated with y
A blockchain is a specific instance of a distributed ledger made up from
blocks, which are arranged as a tree with the root of the tree being thegenesis block
. Each node in this tree has exactly one parent
but can have
multiple children. Blocks specify their parent via the prev_hash
field in
the block header, with the genesis block having a prev_hash
of all 0
.
At any point, the block height
is the distance from the current valid top
block to the genesis block. The genesis block has height zero.
A valid block here means valid according to the consensus rules described below.
We use temporary random leader to build the tree of blocks.
In order to find the best valid chain given a tree of blocks, every node operator in the network sums the amount of work (see Proof of Work) done on each chain. The best valid chain is then the chain that has the most work done. Any ties here will be resolved by the time a block was received at, i.e. it will prefer the block it received first.
Bitcoin NG introduces two types of blocks:
Key Blocks - Key Blocks carry a Public Key of a leader and Proof-of-Work evidence and associated metadata
Micro Blocks - Micro Blocks carry transactions confirmed by a leader and associated metadata
There may be 0-N
Micro Blocks between two Key Blocks. Micro Blocks are small
and they are produced very often i.e. every three seconds.
The genesis block is special in the sense that it does not have a parent and contains the initial state of the æternity blockchain. Part of initial state is generated from the distribution of the æternity ERC20 token on the Ethereum blockchain.
The genesis block is a key block.
æternity follows the "fat protocol" approach, which means that the protocol itself has many features built in, as opposed to e.g. Ethereum, which maps any functionality beyond basic transactions changing the state of an account to smart contracts.
Prefix defaults to ae_mainnet
(binary()
) and it is configurable via
node config. The prefix is not part of a serialized transaction. We add it
only for signature. Consider changing the id in case of forking the blockchain
network, in order to lower danger of replay attacks.
Note: After the Lima protocol upgrade it is allowed to sign either the full serialized object, or the hash of the serialized object; prefixed with the network id in either case.
Note: For the inner transaction of a PayingFor the network id should be
extended to <network id>-inner_tx
in order to make the inner transaction
not replayable on-chain.
Proof of work is used for leader election, which happens via key blocks in Bitcoin-NG. Micro blocks do not require any proof of work.
Each account holds a balance, and can be of any one of the following types.
The address is a public key. It has an increasing nonce. It authorizes a transaction by signing it.
Available from the Fortuna consensus protocol version.
The peer-to-peer network is not part of the consensus and will be described in a separate document.
We use the following denominations:
Blake2b (256 bits digest) and ed25519
EDDSA (curve 25519), signature is 64 bytes.
PROTOCOL_VERSION
Name
Minimum height at which protocol is effective
1
Roma
0 (genesis)
2
Minerva
47800
3
Fortuna
90800
4
Lima
161150
5
Iris
441444
The consensus protocol version number in each block is monotonically increasing in the chain of blocks.
the timestamp of a key block MUST be smaller than now() + 9m
the timestamp of a key block MUST be bigger than:
the median timestamp of the last 11 blocks (if height >= 12)
the timestamp of the genesis block (if height <= 11)
the version MUST match the expected PROTOCOL_VERSION
the pow_evidence
MUST be valid
MUST have 0 <= nonce <= MAX_NONCE
txs_hash MUST be correct root hash of the merkle tree of all transactions.
TODO: fill in missing rules
an optional info field is added to the key header
the presence of the info field MUST be marked by setting the info field flag to 1
the absence of the info field MUST be marked by setting the info field flag to 0
the info field, if present, is uninterpreted, but included in the block hash (i,e., it is under consensus).
the timestamp of a micro block MUST be smaller than now() + 9m
if the previous block is a micro block:
the timestamp MUST be bigger than or equal to the timestamp of the previous block + 3s
if the previous block is a key block:
the timestamp MUST be bigger than the timestamp of the previous block
the version MUST match the expected PROTOCOL_VERSION
the signature must be a valid signature produced by the issuer of the previous key block
the sum of gas of transactions in a micro block MUST be lower or equal to the gas limit per micro block
TODO: fill in missing rules
Signed transaction
MUST have valid signature from private key belonging to sender
.
Generic account meta transaction
Each (on-chain) transaction has the following fields:
Fee. It MUST be at least the gas for the transaction multiplied by the
minimal gas price, which (after MINERVA hard fork height) is1000000
(*10^-18) aettos. (Before MINERVA hard fork height it was1
(*10^-18) aettos.)
Time to live (TTL). The last generation where the transaction is valid. 0 means it is valid forever (and is the default value in many places).
Note: There is also a node configurable minimum gas price - this is the
minimum gas price a node accepts and is not under consensus. This value is
higher than or equal to the minimal gas price as dictated by consensus. For
contract transactions (Create, Call, GAAttach, GAMeta), the minimum applies to
both the Fee
and the GasPrice
.
Available from protocol version 5, Iris release. The tx
field size
depends on the size of the inner transaction.
Note: When signing the inner transaction the network id should be extended
to <network id>-inner_tx
in order to make the inner transaction not
replayable on-chain.
In order to control the size and the number of transactions in a micro block, each transaction has a gas. The sum of gas of all the transactions cannot exceed the gas limit per micro block, which is 6 000 000.
The gas of a transaction is the sum of:
the base gas;
other gas components, such as gas proportional to the byte size of the transaction or relative TTL, gas needed for contract execution.
Note on "other gas components" - up until Iris the micro block gas limit was computed towards the static (upper) gas limit of a transaction. From Ceres the micro block gas limit is computed towards the actual used gas. This mainly affects contract calls (and GA Meta transactions) where the gas limit can be overestimated which pre-Ceres would cause micro blocks to be under-utilized.
Spend
BaseGas
Proportional to the byte size of the transaction, specifically: byte_size(SpendTx) * GasPerByte
Oracle register
BaseGas
Proportional to oracle TTL argument TTL
(interpreted as relative), specifically: ceiling(32000 * RelativeTTL / floor(60 * 24 * 365 / key_block_interval))
and the byte size of the transaction, specifically: byte_size(OracleRegisterTx) * GasPerByte
Oracle query
BaseGas
Proportional to oracle query TTL argument QTTL
(interpreted as relative), specifically: ceiling(32000 * RelativeTTL / floor(60 * 24 * 365 / key_block_interval))
and the byte size of the transaction, specifically: byte_size(OracleQueryTx) * GasPerByte
Oracle respond
BaseGas
Proportional to oracle response TTL argument RTTL
in oracle query (as found in the oracle query in the state, and interpreted as relative), specifically: ceiling(32000 * RelativeTTL / floor(60 * 24 * 365 / key_block_interval))
and the byte size of the transaction, specifically: byte_size(OracleRespondTx) * GasPerByte
Oracle extend
BaseGas
Proportional to oracle TTL argument TTL
(interpreted as relative), specifically: ceiling(32000 * RelativeTTL / floor(60 * 24 * 365 / key_block_interval))
and the byte size of the transaction, specifically: byte_size(OracleExtendTx) * GasPerByte
Name preclaim
BaseGas
Proportional to the byte size of the transaction, specifically: byte_size(NamePreclaimTx) * GasPerByte
Name claim
BaseGas
Proportional to the byte size of the transaction, specifically: byte_size(NameClaimTx) * GasPerByte
Name update
BaseGas
Proportional to the byte size of the transaction, specifically: byte_size(NameUpdateTx) * GasPerByte
Name transfer
BaseGas
Proportional to the byte size of the transaction, specifically: byte_size(NameTransferTx) * GasPerByte
Name revoke
BaseGas
Proportional to the byte size of the transaction, specifically: byte_size(NameRevokeTx) * GasPerByte
Channel create
BaseGas
Proportional to the byte size of the transaction, specifically: byte_size(ChannelCreateTx) * GasPerByte
Channel deposit
BaseGas
Proportional to the byte size of the transaction, specifically: byte_size(ChannelDepositTx) * GasPerByte
Channel withdraw
BaseGas
Proportional to the byte size of the transaction, specifically: byte_size(ChannelWithdrawTx) * GasPerByte
Channel settle
BaseGas
Proportional to the byte size of the transaction, specifically: byte_size(ChannelSettleTx) * GasPerByte
Channel slash
BaseGas
Proportional to the byte size of the transaction, specifically: byte_size(ChannelSlashTx) * GasPerByte
Channel close solo
BaseGas
Proportional to the byte size of the transaction, specifically: byte_size(ChannelCloseSoloTx) * GasPerByte
Channel close mutual
BaseGas
Proportional to the byte size of the transaction, specifically: byte_size(ChannelCloseMutualTx) * GasPerByte
Channel snapshot solo
BaseGas
Proportional to the byte size of the transaction, specifically: byte_size(ChannelSnapshotSoloTx) * GasPerByte
Channel force progress
BaseGas
before Fortuna and 30 * BaseGas
from Fortuna on
Proportional to the byte size of the transaction, specifically: byte_size(ChannelForceProgressTx) * GasPerByte
. It may also include gas for contract execution.
Channel offchain
0
0
Contract create
5 * BaseGas
Proportional to the byte size of the transaction, specifically: byte_size(ContractCreateTx) * GasPerByte
. It also includes gas for contract execution.
Contract call (FATE)
12 * BaseGas
Proportional to the byte size of the transaction, specifically: byte_size(ContractCallTx) * GasPerByte
. It also includes gas for contract execution.
Contract call (AEVM)
30 * BaseGas
Proportional to the byte size of the transaction, specifically: byte_size(ContractCallTx) * GasPerByte
. It also includes gas for contract execution.
GA Attach
5 * BaseGas
Proportional to the byte size of the transaction, specifically: byte_size(GAAttachTx) * GasPerByte
. It also includes gas for execution of the init function.
GA Meta
5 * BaseGas
Fortuna and Lima : Proportional to the byte size of the transaction, specifically: byte_size(GAMetaTx) * GasPerByte
. It also includes gas for execution of the authentication function + recursively gas corresponding to the wrapped transaction(s) (excluding the byte size portion - in order not to account for the size of wrapped transactions multiple times).
5 * BaseGas
From Iris : Proportional to the byte size of GAMeta part of transaction, specifically: (byte_size(GAMetaTx) - byte_size(InnerTx)) * GasPerByte
. It also includes gas for execution of the authentication function + recursively gas corresponding to the wrapped transaction(s)
PayingFor
BaseGas / 5
Proportional to the byte size of the PayingFor part of the transaction, specifically: (byte_size(PayingForTx) - byte_size(InnerTx)) * GasPerByte
.
BaseGas
is 15 000.
GasPerByte
is 20.
Note byte_size(<TxType>)
is the size of the serialized transaction without the signature.
Current defaults:
For the purpose of computing a proof of work puzzle solution, the evidence and
nonce are set to [0] * 42
and 0
respectively, since neither are available
before the puzzle has been solved.
When a node receives a new key block it must repeat the process, setting evidence and nonce to all 0, in order to be able to validate the proof of work.
The default key
for cuckoo is 80 bytes long. The nonce
here is expressed
in little-endian notation, to keep consistent with cuckoo cycle, which does
the same. Note that both the hashed header and the nonce are base64 encoded.
This means that the hashed header is 44 bytes long, and the nonce is 12 bytes.
A valid solution MUST:
be encoded according to the solution encoding rules
form a cycle (TODO: make this more precise)
only contain micrononces < 2^EDGEBITS - 1
have micrononces in ascending order
pass the difficulty check
Since EDGEBITS < 32
, we can encode an edge as a 32bit integer, otherwise
it would have to be 64 bits. Therefore a solution is currently [u32; 42]
.
For further control, a difficulty target 0 < T < 2^256 is introduced, and we impose the additional constraint that the Blake2b 256 bit digest of the cycle nonces in ascending order be less than T, thus reducing the success probability by a factor of 2^256.
Thus we adopt the target notion from Bitcoin and also use the same way to express it.
The target threshold relates to another value: the difficulty. This is proportional to the hardness of the PoW task:
a floating point value.
Bitcoin uses 0x00000000FFFF0000000000000000000000000000000000000000000000000000
as Difficulty 1 target (0x1d00ffff
in scientific notation, see below). For
Cuckoo Cycle we need a lighter filtering of solutions than for SHA-256 as the
basic algorithm is much slower than a simple hash generation, so we use the
largest possible value: 0xFFFF000000000000000000000000000000000000000000000000000000000000
(0x2100ffff
in scientific notation) as difficulty 1.
We store the current target threshold in the block header in scientific notation. Difficulty is used to select the winning fork of new blocks: the difficulty of a chain of blocks is the sum of the difficulty of each block.
Some concepts:
The basic idea of the algorithm is to estimate the current network capacity
based on the N
(= 17) previous blocks and use that to set the new
target:
We can estimate the network capacity used to mine a given block i
as
The estimated capacity across all N
blocks is then the weighted (by time)
average of the estimated capacities for each block. Note, since MiningTime[i]
require Time[i - 1]
and we do not use the genesis block timestamp in target
adjustment we cannot start using the target estimation until block N + 2 (= 19)
.
Where FTL = Future Time Limit - i.e. the time a block is allowed to be
"from the future". We use 9 minutes (540 s) i.e. 3 times the DesiredTimeBetweenBlocks
.
Now, the problem is that we can't do any floating point arithmetic (to ensure the calculation can be verified by other nodes), so we pick a reasonably big integer K (= HIGHEST_TARGET * 2^32) and compute
Then
This document depends on that describes rules for building blockchain.
Key Blocks are generated by miners. New coins are . Micro Blocks are generated by miners who become leaders by mining Key Blocks.
We sign serialized transaction (or the hash of the serialized transaction - from Lima hard-fork) prefixed with the id of the network. See definition for details.
is the algorithm used for proof of work. It was designed to prevent the dynamics that have developed in Bitcoin and similar systems, where the mining operations are dominated by special purpose hardware. The problem being solved is that of finding cycles in a bipartite graph.
For the actual wire format please consult the document.
Please refer to the .
Please refer to the .
Key generation is done according to , note that we have 64-byte secret keys that consists of the seed concatenated with the public key in order to The public key is 32 byte.
Block/header
Header
Block
For the actual wire format please consult the document.
Please refer to the .
Please refer to the .
Please refer to the .
Please refer to the .
Please refer to the .
Please refer to the .
is used as the proof of work
algorithm. Solutions take the form of arrays length l
, where l
is the length
(PROOFSIZE
) of the cycle in the bipartite graph. The size of the graph is denoted
by EDGEBITS
. The difficulty
of a graph with M
nodes and N
edges is based on the ratio M/N
, with the standard
implementation being fixed at M/N = 1/2
. Please refer to the for more details. These indices are referred to as micrononces
, not
to be confused with the nonce included in the header itself.
This graph is generated by hashing every edge i in (0..N)
twice with a keyed hash
function h
(). The key
used for these operations
is the hash of a block header plus a nonce. The first node belonging to every edge is
given by hashing h(key, index*2)
and the second by h(key, index*2+1)
.
See :
Integers represented in scientific notation:2^24 * <base-2 exponent + 3> + the first 3 most significant bytes
(i.e.,
the ).
The + 3 corresponds to the length of the significand (i.e., the int value is0.<significand> * 8^<exponent>
).
https://en.bitcoin.it/wiki/Difficulty#How_is_difficulty_stored_in_blocks.3F)
To get a good trade-off between response time and stability we use a variant of. That means we compute a tempered TotalTime (total solve time in algorithm description):