Skip to content

Base 0.6 decaf genesis file - #4789

Merged
lukaszrzasik merged 1 commit into
release-fffrom
lr/20260807
Aug 7, 2026
Merged

Base 0.6 decaf genesis file#4789
lukaszrzasik merged 1 commit into
release-fffrom
lr/20260807

Conversation

@lukaszrzasik

Copy link
Copy Markdown
Contributor

Closes #<ISSUE_NUMBER>

This PR:

This PR does not:

Key places to review:

@claude

claude Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Claude finished @lukaszrzasik's task in 6m 15s —— View job


Code Review: Base 0.6 decaf genesis file

  • Read PR diff and existing review comments (./tmp/pr-review-comments.json — empty, no prior feedback to dedupe against)
  • Read data/genesis/decaf.toml and compare against mainnet.toml / staging.toml
  • Trace base_version / upgrade_version through genesis validation and node startup
  • Verify the genesis block commitment is unaffected
  • Post review

Summary

The change does what it says: decaf's genesis moves from "base 0.5 + immediate 0.6 upgrade" to "base 0.6, no upgrade". The shape matches the existing precedent in data/genesis/staging.toml (base_version = upgrade_version = "0.6" with no [[upgrade]] table), and Genesis::validate passes — genesis_version (0.2) <= base_version (0.6), and epoch_height, epoch_start_block, drb_difficulty, drb_upgrade_difficulty are all present as required for >= EPOCH_VERSION / >= DRB_AND_HEADER_UPGRADE_VERSION (crates/espresso/node/src/genesis.rs:138-161). test_committed_genesis_files_validate covers this file, so CI will catch any parse/validation regression.

One blocking-ish question about deployment ordering (left inline), plus two smaller observations.

👍 Correctly preserved: the genesis block commitment

Worth calling out explicitly, because it's the thing that would silently fork the chain if it were wrong. genesis_version = "0.2" and [header.chain_config] are untouched, and Header::genesis ignores the Version argument it's handed (_: Version), deriving the genesis header purely from instance_state.genesis_version and genesis_header.chain_config (crates/espresso/types/src/v0/impls/header.rs:1519-1559). So bumping base_version does not rewrite decaf's genesis block — which is exactly why decaf keeps genesis_version = "0.2" where staging (a fresh chain) uses "0.6". Likewise [header.chain_config] correctly omits stake_table_contract and keeps max_block_size = '1mb', unlike staging's. Right call on all three.

Deployment ordering (see inline comment on line 1)

Short version: with {base: 0.6, target: 0.6}, UpgradeLock::deserialize rejects every 0.5-tagged message, and no node on this genesis will ever propose the 0.6 upgrade (set_hotshot_config_parameters no longer runs → UpgradeConfig::default()start_proposing_view = u64::MAX). This file is safe only after decaf has decided the 0.5 → 0.6 upgrade certificate. Since 754db51 — the commit that added that upgrade — is the tip of release-ff, please confirm the intended sequencing in the PR body.

drb_difficulty = 10 is now dead config

drb_difficulty_selector picks drb_upgrade_difficulty for any version >= DRB_AND_HEADER_UPGRADE_VERSION (0.4) and drb_difficulty otherwise (crates/hotshot/types/src/drb.rs:44-54). With base_version = "0.6" decaf can never reach a view below 0.4, so drb_difficulty = 10 is unreachable — but it reads as if decaf runs a trivially-grindable DRB. Both sibling networks avoid this ambiguity by setting the two equal (staging.toml: 5000000000/5000000000; mainnet.toml: 25000000000/25000000000).

Not a functional defect, so entirely your call whether to fold it in here. Fix this →

Two operator-facing side effects of base_version >= NEW_PROTOCOL_VERSION

Neither is a bug, but both are consequences of this one-line change that are worth having on the rollout checklist rather than discovering at restart:

  • A pre-flight diagnostic goes silent. check_cliquenet_info_registered early-returns unless current_version == EPOCH_REWARD_VERSION i.e. exactly 0.5 (crates/espresso/node/src/lib.rs:900-902). Decaf operators who haven't registered their x25519 key / p2p address on-chain previously got a loud tracing::error! at startup with remediation steps (lib.rs:944-951); with base_version = "0.6" that check is skipped entirely and they'll instead just quietly fail to be dialed.
  • ESPRESSO_NODE_CLIQUENET_ADVERTISE_ADDRESS becomes mandatory on the orchestrator bootstrap path. lib.rs:508-513 now hard-errors without it. This only affects a node with empty storage and no config_peers, so existing decaf validators (persisted config) and peer-bootstrapped nodes are unaffected — but a fresh node taking the orchestrator path will fail to start where it previously wouldn't.

Also confirmed as non-issues while tracing this: genesis_epoch_from_version(base) is unchanged (both 0.5 and 0.6 are >= EPOCH_VERSION), [chain_config] already carries the stake_table_contract that the deleted [upgrade.new_protocol.chain_config] supplied, and no other file in the repo pins decaf's base_version.

Not applicable to this PR

Security (no input handling), performance (no queries), and test coverage all fall out of scope for a config-value change — the one relevant test, test_committed_genesis_files_validate, already covers it. I did not attempt to compile or run the test suite: this is a data-only change and a full cargo test build of this workspace far exceeds the time available in this job.
· branch lr/20260807

@lukaszrzasik
lukaszrzasik enabled auto-merge (squash) August 7, 2026 15:47
Comment thread data/genesis/decaf.toml
@@ -1,4 +1,4 @@
base_version = "0.5"
base_version = "0.6"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deployment ordering is load-bearing here

Baking the upgrade into base_version and dropping [[upgrade]] is the right end state, but this file is only safe to roll out after decaf has actually decided the 0.5 → 0.6 upgrade certificate. Two mechanisms make the intermediate state unsafe:

  1. Wire-level version rejection. versions::Upgrade::new(base, upgrade) becomes {base: 0.6, target: 0.6} (crates/espresso/node/src/lib.rs:562). In UpgradeLock::deserialize (crates/hotshot/types/src/message.rs:829-838), any message tagged 0.5 fails self.upgrade.base != version && self.upgrade.target != version and is dropped. And UpgradeLock::version() returns upgrade.base = 0.6 for every view when no decided cert is present, so this node also emits 0.6 for pre-upgrade views. A node on this genesis cannot exchange consensus messages with a network still at 0.5.

  2. No node on this genesis will ever propose the upgrade. With [[upgrade]] gone, upgrade.set_hotshot_config_parameters(&mut network_config.config) (crates/espresso/node/src/lib.rs:543-545) no longer runs, so a node with fresh storage falls back to UpgradeConfig::default()start_proposing_view = u64::MAX (crates/hotshot/types/src/upgrade_config.rs:49). The upgrade-proposal gate at crates/hotshot/task-impls/src/upgrade.rs:370 never fires. If the whole fleet moved to this file before the upgrade decided, the upgrade would simply never happen.

Once the cert is decided, everything lines up: version() short-circuits on cert.data.new_version == self.upgrade.target0.6, so restarted nodes agree with the rest of the network.

Related rollout note: nodes that keep their persisted NetworkConfig retain the stale start_proposing_view = 0 / stop_proposing_view = 1 from the previous genesis (nothing overrides them now). Harmless at decaf's current view height, but it means the effective upgrade window differs between fresh and existing storage.

Could you confirm in the PR description that this lands/deploys only after the decaf 0.6 upgrade has decided? Given 754db51 (the upgrade genesis) is the tip of release-ff, the sequencing isn't obvious from the branch state alone.

@lukaszrzasik
lukaszrzasik merged commit 7193b5b into release-ff Aug 7, 2026
147 checks passed
@lukaszrzasik
lukaszrzasik deleted the lr/20260807 branch August 7, 2026 16:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants