From 92d3765de9a088b5cb13d91be027944dd2748893 Mon Sep 17 00:00:00 2001 From: Martin Kourim Date: Wed, 12 Aug 2026 12:52:26 +0200 Subject: [PATCH] fix(scripts): handle genesis extraConfig from cardano-cli 11.2 cardano-cli >= PR #1384 writes initial funds and staking into the new "extraConfig" field (ledger's streaming data injection) and leaves the legacy "initialFunds"/"staking" fields empty. Nodes built with cardano-ledger-shelley < 1.19 silently ignore "extraConfig", so the cluster would start with an empty UTxO set. Detect "extraConfig" support in the node binary and move the data back to the legacy fields when the node cannot parse it. The slow (Byron funds) setup drops "extraConfig" unconditionally, as it never wants Shelley initial funds. --- .../scripts/common/common-start-fast | 76 +++++++++++++++++++ .../scripts/common/common-start-slow | 6 +- 2 files changed, 81 insertions(+), 1 deletion(-) diff --git a/src/cardonnay_scripts/scripts/common/common-start-fast b/src/cardonnay_scripts/scripts/common/common-start-fast index 2854948..c68d6f8 100644 --- a/src/cardonnay_scripts/scripts/common/common-start-fast +++ b/src/cardonnay_scripts/scripts/common/common-start-fast @@ -123,6 +123,80 @@ initialize_globals() { fi } +# Compatibility shim for cardano-cli >= PR #1384, which writes initial funds and +# staking into the Shelley genesis "extraConfig" (ledger's streaming data injection; +# unrelated to the cost-models "extraConfig" in the Alonzo genesis) and leaves the +# legacy "initialFunds"/"staking" fields empty. Nodes built with +# cardano-ledger-shelley < 1.19 silently ignore "extraConfig", which would start +# the cluster with an empty UTxO set and no registered pools. +# Remove both functions and their call site once nodes without "extraConfig" +# support are no longer tested. + +# Check whether the node's ledger can parse "extraConfig" in Shelley genesis. +# The "ShelleyExtraConfig" string is present in the data section (Show instance, +# JSON parser name) only when cardano-ledger-shelley >= 1.19 is linked in, so this +# tests the feature itself rather than the node version. +node_supports_genesis_injection() { + local node_bin rc=0 + + node_bin="$(command -v cardano-node)" || { + echo "cardano-node not found on PATH, line $LINENO in ${BASH_SOURCE[0]}" >&2 + exit 1 + } + + grep -a -q "ShelleyExtraConfig" "$node_bin" || rc="$?" + if [ "$rc" -gt 1 ]; then + echo "Failed to inspect '$node_bin', line $LINENO in ${BASH_SOURCE[0]}" >&2 + exit 1 + fi + return "$rc" +} + +# Move "extraConfig" injection data in the Shelley genesis back to the legacy +# "initialFunds"/"staking" fields when the node cannot parse "extraConfig". +# The two formats are equivalent for embedded data, and the ledger errors out +# when both sources are populated, so "extraConfig" must be removed after the move. +# Only the embedded ("data") injection shape can be downgraded; fail loudly on any +# other shape (e.g. file-based injection) or unknown "extraConfig" fields, rather +# than leave "extraConfig" in place for the node to silently ignore. Absent or +# empty injection entries keep the legacy field values. +downgrade_genesis_injection() { + local genesis="${1:?Usage: downgrade_genesis_injection }" + + if node_supports_genesis_injection; then + return 0 + fi + + jq ' + def unknown_fields: keys - ["initialFunds", "stakePools", "stakeCredentials"]; + + def inj_data(f): + if f == null or f == {} then null + elif (f | type) == "object" and (f | keys) == ["data"] and f.data != null then f.data + else error("cannot downgrade extraConfig: only embedded \"data\" injection is supported") + end; + + # An absent "extraConfig" is null as well, and deleting it is then a no-op. + if .extraConfig == null then del(.extraConfig) + elif (.extraConfig | type) != "object" + then error("cannot downgrade extraConfig: expected an object, got \(.extraConfig | type)") + elif (.extraConfig | unknown_fields) != [] + then error("cannot downgrade extraConfig: unexpected fields \(.extraConfig | unknown_fields)") + else + .initialFunds = (inj_data(.extraConfig.initialFunds) // .initialFunds // {}) + | .staking.pools = (inj_data(.extraConfig.stakePools) // .staking.pools // {}) + | .staking.stake = (inj_data(.extraConfig.stakeCredentials) // .staking.stake // {}) + | del(.extraConfig) + end + ' "$genesis" > "${genesis}.tmp" \ + || { + rm -f "${genesis}.tmp" + echo "Failed to downgrade extraConfig in '$genesis', line $LINENO in ${BASH_SOURCE[0]}" >&2 + exit 1 + } + mv "${genesis}.tmp" "$genesis" +} + create_genesis() { local start_time_shelley start_time @@ -178,6 +252,8 @@ create_genesis() { .protocolParams.protocolVersion.major = $prot_ver | .maxLovelaceSupply = $max_supply ' "${STATE_CLUSTER}/create_staked/genesis.json" > "${STATE_CLUSTER}/shelley/genesis.json" + + downgrade_genesis_injection "${STATE_CLUSTER}/shelley/genesis.json" rm -f "${STATE_CLUSTER}/create_staked/genesis.json" mv "$STATE_CLUSTER"/create_staked/genesis*.json "${STATE_CLUSTER}/shelley/" diff --git a/src/cardonnay_scripts/scripts/common/common-start-slow b/src/cardonnay_scripts/scripts/common/common-start-slow index 8f6e108..c0df8d2 100644 --- a/src/cardonnay_scripts/scripts/common/common-start-slow +++ b/src/cardonnay_scripts/scripts/common/common-start-slow @@ -180,7 +180,11 @@ create_genesis() { "${STATE_CLUSTER}/shelley/genesis.dijkstra.json" fi - jq '.initialFunds = {}' \ + # Shelley initial funds are not used in this setup (funds come from Byron). + # Newer cardano-cli (>= PR #1384) writes initial funds into "extraConfig" + # (ledger's streaming data injection) instead of "initialFunds", so drop + # that field as well. + jq '.initialFunds = {} | del(.extraConfig)' \ "${STATE_CLUSTER}/shelley/genesis.json" > "${STATE_CLUSTER}/shelley/genesis.tmp.json" mv -f "${STATE_CLUSTER}/shelley/genesis.tmp.json" "${STATE_CLUSTER}/shelley/genesis.json" }