V1.1.0-BEDROCK-GENESIS-BLOCK
| Field | Value |
|---|---|
| Name | [1.1.0] Bedrock Genesis Block |
| Slug | 222 |
| Status | deprecated |
| Type | RFC |
| Category | Standards Track |
| Editor | David Rusu [email protected] |
| Contributors | Filip Dimitrijevic [email protected] |
Timeline
- 2026-05-28 —
d45eed2— Chore: mirror blochain specs into github/mdbook (#347)
Revision History
| Version | Changes | Date |
|---|---|---|
| 1.0.0 | Initial revision. | 2026-02-12 |
| 1.1.0 | added [RFC] Make Ledger Transaction an Operation renamed Nomos to Logos Blockchain remove notions of DA minor fix in gas price | 2026-03-27 |
Introduction
The Genesis Block defines the starting state for the Bedrock chain, including the initial bedrock service providers, LGO token distribution and protocol parameters. Its design draws from best practices in the Ouroboros family of protocols (notably Praos and Genesis), as well as privacy and resilience advances from Cryptarchia and related research. The Genesis Block is the root of trust for all subsequent protocol operations and must be constructed in a way that is deterministic, verifiable, and robust against long-range or bootstrap attacks.
Overview
The Genesis Block establishes the initializing values for the various protocols and services. This includes the initial token distribution, initial nodes participating in Blend Network and the result of running the epoch nonce ceremony.
The block body is a single Mantle Transaction (see [1.4.0] Mantle) containing a Transfer Operation distributing the notes to initial token holders. The bedrock services are initialized through SDP_DECLARE Operations embedded in the Mantle Transactions Operations list and protocol initializing constants are encoded through a CHANNEL_INSCRIBE Operation also embedded in the Operations list.
Not all protocol constants are encoded in the Genesis block. The principle we use to decide whether a value should be in the Genesis block or not is whether it is a value that is derived from blockchain activity or whether it is updated through a protocol update (hard / soft fork). For example, the epoch nonce is updated through normal blockchain Operations and therefore it should be specified in the Genesis block. Gas constants are only changed through protocol updates and hard forks and therefore they will be hardcoded in the node implementation.
Genesis Block Data Structure
The Genesis Block is composed of the Genesis Block Header and the Genesis Mantle Transaction (there is a single transaction in the genesis block). The Mantle Transaction contains all information necessary for initializing Bedrock Services and Cryptarchia state, as well as distributing the initial tokens to stakeholders.
Initial Token Distribution
Initial tokens will be distributed through a Transfer Operation containing zero inputs and one output note for each initial stakeholder. Note that since the Ledger is transparent, the initial stake allocation is visible to everyone. Those wishing to hide their initial stake may opt to subdivide their note into a few different notes of equal value.
In order to participate in the Cryptarchia lottery, stakeholders must generate their note keys in accordance with the Proof of Leadership protocol specified at [1.1.0] Proof of Leadership - Protocol.
The initial state of the Ledger will be derived through normal execution of this Transfer Operation, that is, each outputs note ID will be added to the unspent notes set.
Example
STAKE_DISTRIBUTION = Transfer(
inputs=[],
outputs=[
Note(value=1000, public_key=STAKE_HOLDER_0_PK),
Note(value=2000, public_key=STAKE_HOLDER_1_PK),
Note(value=1500, public_key=STAKE_HOLDER_2_PK),
# ...
]
)
Initial Service Declarations
Blend Network MUST initialize its set of providers. This is done through a set of SDP_DECLARE Operations in the Genesis Mantle Transaction.
Blend enforces a minimal network size for the service to be active. Thus, in order to have an active Blend service at Genesis, we MUST have at least as many declarations in the Genesis block to meet Blend services minimal network size [1.0.0] Blend Protocol - Minimal Network Size.
Example
BLEND_DECLARATIONS = [
Declaration(
msg=DeclarationMessage(
ServiceType.BLEND, ["ip://1.1.1.1:3000"], PROVIDER_ID_0, ZK_ID_0
),
locked_note_id=STAKE_DISTRIBUTION_TX.output_note_id(0)
),
# ... 32 total declarations
]
SERVICE_DECLARATIONS = BLEND_DECLARATIONS
Cryptarchia Parameters
Cryptarchia is initialized with the following parameters:
- genesis_time: ISO 8601 encoded timestamp. Cryptarchia uses slots as a measure of time offset from some start time. This timestamp must be agreed upon by all nodes in order to have a common clock.
- chain_id: string. It is useful to differentiate testnets from mainnet. To avoid confusion, we place the chain ID in the Genesis block to guarantee that the networks are disjoint.
- genesis_epoch_nonce: 32 bytes, hex encoded. The initial source of randomness for the Cryptarchia lottery. The process for selecting this value is described in detail at Epoch Nonce Ceremony.
These parameters are encoded in the Genesis block as an inscription sent to the null channel.
Example
from datetime import datetime
CHAIN_ID = "logos-blockchain-mainnet"
GENESIS_TIME = "2026-01-05T19:20:35+00:00"
GENESIS_EPOCH_NONCE = "abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890"
chain_id_enc = CHAIN_ID.encode("utf-8")
chain_id_len = len(chain_id_enc).to_bytes(8, "little")
genesis_time = int(datetime.fromisoformat(GENESIS_TIME).timestamp()).to_bytes(8, "little")
genesis_epoch_nonce = bytes.fromhex(GENESIS_EPOCH_NONCE)
inscription = chain_id_len + chain_id_enc + genesis_time + genesis_epoch_nonce
# >>> inscription.hex()
# '0d000000000000006e6f6d6f732d6d61696e6e6574030f5c6900000000abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890'
CRYPTARCHIA_INSCRIPTION = Inscribe(
channel=bytes(32),
inscription=inscription
parent=bytes(32),
signer=Ed25519PublicKey_ZERO,
)
Epoch Nonce Ceremony
The initial epoch nonce value governs the Cryptarchia lottery randomness for the first epoch. It must be revealed AFTER the initial stake distribution has been frozen. This is done to prevent any stakeholders from gaining an unfair advantage from prior knowledge of the lottery randomness.
The protocol for generating the initial randomness nonce can be found below.
- Schedule Epoch Nonce Ceremony Event: We must fix well in advance when this epoch nonce ceremony will take place, let t denote the time of the Epoch Nonce Ceremony, broadcast t widely. The STAKE_DISTRIBUTION must be finalized before t to ensure a fair Cryptarchia slot lottery.
- Randomness Collection:
We collect the entropy from multiple randomness sources:
Entropy Source Details Bitcoin block hash immediately after time t, denoted as . Block hash can be found on blockchain.com s bitcoin block explorer, e.g. https://www.blockchain.com/explorer/blocks/btc/905030 Ethereum block hash immediately after time t, denoted as . Block hash can be found in the more details section of when viewing a block on etherscan, e.g. https://etherscan.io/block/22894116 DRAND beacon value for the round immediately after t, denoted as . Use the default beacon, and find the round number corresponding to t. https://api.drand.sh/v2/beacons/default/rounds/1234 - Randomness Derivation: Once all above entropy contributions, i.e., are collected, then we can compute the initial epoch randomness as: where is a collision-resistant zkhash function.
Genesis Mantle Transaction
The initial stake distribution, service declarations and Cryptarchia inscription are components of the Genesis Mantle Transaction. This is the single transaction that forms the body of the Genesis block.
GENESIS_MANTLE_TX = MantleTx(
ops=[STAKE_DISTRIBUTION, CRYPTARCHIA_INSCRIPTION] + SERVICE_DECLARATIONS,
permanent_storage_gas_price=0,
execution_gas_price=0
)
Block Header Fields
The Genesis Block header fields are set to the following values:
- bedrock_version: Protocol version (e.g., 1).
- parent_block: 0 (as this is the first block).
- slot: 0 (the Genesis slot).
- block_root: Block Merkle root over the (single) initial transaction.
- proof_of_leadership: Stubbed leadership proof.
- leader_voucher: 0 (as there is no leader block reward for the initial block).
- entropy_contribution: 0 (no entropy is provided through the initial PoL).
- proof: Null Groth16Proof, all values are set to zero.
- leader_key: Null PublicKey.
Example
GENESIS_HEADER = Header(
bedrock_version=1,
parent_block=0,
slot=0,
block_root=block_merkle_root([GENESIS_MANTLE_TX]),
proof_of_leadership=ProofOfLeadership(
leader_voucher=bytes(32),
entropy_contribution=bytes(32),
proof=Groth16Proof(G1_ZERO, G2_ZERO, G1_ZERO),
leader_key=Ed25519PublicKey_ZERO,
)
)
# distribute NMO to all stakeholders
STAKE_DISTRIBUTION = Transfer(
inputs=[],
outputs=[
Note(value=1000, public_key=STAKE_HOLDER_0_PK),
Note(value=2000, public_key=STAKE_HOLDER_1_PK),
Note(value=1500, public_key=STAKE_HOLDER_2_PK),
# ...
]
)
# set Cryptarchia parameters
CRYPTARCHIA_PARAMS = {
"chain_id": "logos-mainnet",
"genesis_time": "2026-01-05T19:20:35Z",
"genesis_epoch_nonce": "abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890",
}
CRYPTARCHIA_INSCRIPTION = Inscribe(
channel=bytes(32),
inscription=json.dumps(CRYPTARCHIA_PARAMS).encode("utf-8"),
parent=bytes(32),
signer=Ed25519PublicKey_ZERO,
)
# service declarations
BLEND_DECLARATIONS = [
Declaration(
msg=DeclarationMessage(ServiceType.BLEND, ["ip://1.1.1.1:3000"], PROVIDER_ID_0, ZK_ID_0),
locked_note_id=STAKE_DISTRIBUTION.output_note_id(0)
),
# ... more declarations
]
SERVICE_DECLARATIONS = BLEND_DECLARATIONS
# build the genesis Mantle Transaction
GENESIS_MANTLE_TX = MantleTx(
ops=[STAKE_DISTRIBUTION, CRYPTARCHIA_INSCRIPTION] + SERVICE_DECLARATIONS,
permanent_storage_gas_price=0,
execution_gas_price=0
)
GENESIS_HEADER = Header(
bedrock_version=1,
parent_block=bytes(32),
slot=0,
block_root=block_merkle_root([GENESIS_MANTLE_TX]),
proof_of_leadership=ProofOfLeadership(
leader_voucher=bytes(32),
entropy_contribution=bytes(32),
proof=Groth16Proof(G1.ZERO, G2.ZERO, G1.ZERO),
leader_key=Ed25519PublicKey_ZERO,
)
)
GENESIS_BLOCK = (GENESIS_HEADER, [GENESIS_MANTLE_TX])
Sample Genesis Block
Initializing Bedrock
Bedrock is initialized by executing the Mantle Transaction without validating the Mantle Operations. No validation or execution is done for the Genesis block header; in particular, processing of proof_of_leadership is skipped.
Mantle Ledger Initialization
The Transfer Operation should be executed without checking that the transaction is balanced. However, other validations are checked, e.g. that output note values are positive and smaller than the maximum allowed value. The result of normal transfer execution adds all outputs to the Ledger.
Cryptarchia Initialization
The Mantle Transaction contains an inscription sent to the null channel containing the parameters for initializing Cryptarchia.
The Cryptarchia slot clock is initialized to genesis_time, LIB is set to the Genesis block and the epoch state is then initialized:
Initial Epoch State
Cryptarchia progresses in epochs where the variables governing the lottery are fixed for the duration of an epoch and the activity during that epoch is used to derive the values of those variables for the next epoch. These variables taken together are called the Epoch State. (see [1.0.2] Cryptarchia Protocol - Epoch State).
To initialize the Epoch State, we derive the epoch variables from the genesis block.
- : the epoch nonce is taken directly from the genesis_epoch_nonce.
- : Eligible leader commitment is set to the the Ledger Root over all notes from the initial token distribution. The derivation of this root is specified in [1.1.0] Proof of Leadership - Ledger Root.
- : The initial estimate of total stake will be the total tokens distributed at genesis.
Bedrock Services Initialization
Blend network is initialized through normal Mantle Transaction execution. The SDP_DECLARE Operations in the Genesis Mantle Transaction will create the initial set of providers in each service.
During normal operations, Blend services would wait until a block is deep enough to be finalized, but for the Genesis block, we consider it finalized by definition and so Blend will immediately use the provider set without the usual finalization delay.
References
- Ouroboros Praos: https://eprint.iacr.org/2017/573.pdf
- Ouroboros Genesis: https://eprint.iacr.org/2018/378.pdf
- Ouroboros Crypsinous: https://eprint.iacr.org/2018/1132.pdf
- Cardano Shelley Genesis File Format: https://cardano-course.gitbook.io/cardano-course/handbook/protocol-parameters-and-configuration-files/shelley-genesis-file
- Cardano CIP-16 Key Serialisation: https://cips.cardano.org/cip/CIP-16