Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -490,7 +490,7 @@ validators: # validator nodes specification
The `spin-node.sh` triggers genesis generator (`generate-genesis.sh`) which generates the following files based on `validator-config.yaml`:

1. **post-quantum secure validator keypairs** in `genesis/hash-sig-keys` unless already generated or forced with `--forceKeyGen`
2. **config.yaml** - Updated genesis time, `ATTESTATION_COMMITTEE_COUNT`, and `GENESIS_VALIDATORS` with **attestation** and **proposal** public keys per validator (dual-key layout / `hash-sig-cli:devnet4`)
2. **config.yaml** - Updated genesis time, `ATTESTATION_COMMITTEE_COUNT`, and `GENESIS_VALIDATORS` with **attestation** and **proposal** public keys per validator (dual-key layout, 32-byte SSZ pubkeys / `ghcr.io/lambdaclass/hash-sig-cli:0.5.0`)
3. **validators.yaml** - Validator index assignments using round-robin distribution
4. **nodes.yaml** - ENR (Ethereum Node Records) for peer discovery
5. **genesis.json** - Genesis state in JSON format
Expand All @@ -512,7 +512,7 @@ You can also run the generator standalone:

#### Hash-Based Signature (Post-Quantum) Scheme Validator Keys

**Tool's Docker Image**: `HASH_SIG_CLI_IMAGE="blockblaz/hash-sig-cli:devnet4"`
**Tool's Docker Image**: `HASH_SIG_CLI_IMAGE="ghcr.io/lambdaclass/hash-sig-cli:0.5.0"`
**Source**: https://github.com/blockblaz/hash-sig-cli

Using the above docker tool the following files are generated (unless already generated or forced via `--forceKeyGen` flag):
Expand Down Expand Up @@ -710,9 +710,10 @@ The manifest file (`validator-keys-manifest.yaml`) contains metadata about all g
# Hash-Signature Validator Keys Manifest
# Generated by hash-sig-cli

key_scheme: SIGTopLevelTargetSumLifetime32Dim64Base8
key_scheme: XmssTargetSumLifetime32Dim42Base8
hash_function: Poseidon2
encoding: TargetSum
pubkey_bytes: 32
lifetime: 4294967296
log_num_active_epochs: 10
num_active_epochs: 1024
Expand All @@ -732,6 +733,10 @@ validators:
proposer_key_privkey_file: validator_1_proposer_key_sk.ssz

```
`key_scheme` and `pubkey_bytes` are derived from the constants of the XMSS revision the image was
built against, so they report the actual format on disk instead of a fixed label. `generate-genesis.sh`
reads `pubkey_bytes` back to detect a key directory left over from an older image.

(See [hash-sig-cli](https://github.com/blockblaz/hash-sig-cli) for the exact manifest schema.)

## Troubleshooting
Expand Down
2 changes: 1 addition & 1 deletion ansible/roles/ethlambda/defaults/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@
# Note: These are fallback defaults. Actual values are extracted from client-cmds/ethlambda-cmd.sh
# in the tasks/main.yml file. These defaults are used if extraction fails.

ethlambda_docker_image: "ghcr.io/lambdaclass/ethlambda:devnet4"
ethlambda_docker_image: "ghcr.io/lambdaclass/ethlambda:devnet5-leanvm-main"
deployment_mode: docker # docker or binary
2 changes: 1 addition & 1 deletion ansible/roles/ethlambda/tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@

- name: Set docker image and deployment mode from client-cmd.sh
set_fact:
ethlambda_docker_image: "{{ ethlambda_docker_image_raw.stdout | trim | default('ghcr.io/lambdaclass/ethlambda:devnet4') }}"
ethlambda_docker_image: "{{ ethlambda_docker_image_raw.stdout | trim | default('ghcr.io/lambdaclass/ethlambda:devnet5-leanvm-main') }}"
deployment_mode: "{{ ethlambda_deployment_mode_raw.stdout | trim | default('docker') }}"

- name: Extract node configuration from validator-config.yaml
Expand Down
2 changes: 1 addition & 1 deletion client-cmds/ethlambda-cmd.sh
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ node_binary="$binary_path \
$checkpoint_sync_flag"

# Command when running as docker container
node_docker="ghcr.io/lambdaclass/ethlambda:devnet4 \
node_docker="ghcr.io/lambdaclass/ethlambda:devnet5-leanvm-main \
--genesis /config/config.yaml \
--validators /config/annotated_validators.yaml \
--bootnodes /config/nodes.yaml \
Expand Down
38 changes: 32 additions & 6 deletions generate-genesis.sh
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ fi
echo " ✅ docker found: $(which docker)"

# Hash-sig-cli Docker image (separate attester + proposer keys per validator when using dual-key manifest)
HASH_SIG_CLI_IMAGE="blockblaz/hash-sig-cli:latest"
HASH_SIG_CLI_IMAGE="ghcr.io/lambdaclass/hash-sig-cli:0.5.0"
echo " ✅ Using hash-sig-cli Docker image: $HASH_SIG_CLI_IMAGE"

echo ""
Expand Down Expand Up @@ -263,14 +263,13 @@ if [ "$SHOULD_SKIP" == "true" ]; then
echo ""
else
echo " Generating keys for $VALIDATOR_COUNT validators..."
echo " Using scheme: SIGTopLevelTargetSumLifetime32Dim64Base8"
echo " Key directory: $HASH_SIG_KEYS_DIR"
echo ""

# Generate hash-sig keys for all validators using Docker
# Scheme: SIGTopLevelTargetSumLifetime32Dim64Base8
# Generate hash-sig keys for all validators using Docker.
# The signature scheme is whatever the pinned image was built against; it is
# reported back in validator-keys-manifest.yaml rather than assumed here.
# Active epochs: 2^ACTIVE_EPOCH (from validator-config.yaml)
# Total lifetime: 2^32 (4,294,967,296)
# Convert to absolute path for Docker volume mounting
GENESIS_DIR_ABS="$(cd "$GENESIS_DIR" && pwd)"

Expand Down Expand Up @@ -347,14 +346,41 @@ if [ "$DUAL_KEY_MODE" = true ]; then
echo " ❌ Error: Could not read attester/proposer pubkeys from manifest"
exit 1
fi
# Whole bytes only, so the byte count derived below is exact rather than rounded.
for pk in "$ATTEST_PUB" "$PROP_PUB"; do
if [[ ! "$pk" =~ ^0x[0-9a-fA-F]+$ ]]; then
if [[ ! "$pk" =~ ^0x([0-9a-fA-F]{2})+$ ]]; then
echo " ❌ Error: Manifest does not contain hex pubkeys (dual-key mode)"
echo " Found: $pk"
exit 1
fi
done
echo " ✅ Manifest verified - dual-key format (attester + proposer)"

# Cross-check the pubkey length the manifest declares against the pubkeys it holds.
# Key file names did not change when the format moved to leanVM's XMSS, so a key
# directory left over from an older image passes the "keys already exist" check
# above and would otherwise be baked into config.yaml unnoticed.
MANIFEST_KEY_SCHEME=$(yq eval '.key_scheme // ""' "$MANIFEST_FILE" 2>/dev/null)
MANIFEST_PUBKEY_BYTES=$(yq eval '.pubkey_bytes // ""' "$MANIFEST_FILE" 2>/dev/null)
ATTEST_PUB_BYTES=$(( (${#ATTEST_PUB} - 2) / 2 ))
echo " Key scheme: ${MANIFEST_KEY_SCHEME:-<unreported>}"
echo " Public key size: ${ATTEST_PUB_BYTES} bytes"
if [ -z "$MANIFEST_PUBKEY_BYTES" ]; then
echo " ⚠️ Manifest reports no 'pubkey_bytes' - these keys predate hash-sig-cli 0.5.0"
echo " and are in the retired leanSig format. Clients built against leanVM's XMSS"
echo " cannot read them; the genesis below will not start such a devnet."
echo " Regenerate: ./generate-genesis.sh \"$GENESIS_DIR\" --forceKeyGen"
elif [[ ! "$MANIFEST_PUBKEY_BYTES" =~ ^[0-9]+$ ]]; then
# Guard the arithmetic comparison below: a non-numeric value makes `[ -ne ]` fail
# as a condition, which would skip the check instead of reporting anything.
echo " ❌ Error: manifest 'pubkey_bytes' is not a number: $MANIFEST_PUBKEY_BYTES"
echo " The manifest is inconsistent - regenerate it rather than editing it by hand"
exit 1
elif [ "$ATTEST_PUB_BYTES" -ne "$MANIFEST_PUBKEY_BYTES" ]; then
echo " ❌ Error: manifest declares pubkey_bytes=$MANIFEST_PUBKEY_BYTES but its pubkeys are $ATTEST_PUB_BYTES bytes"
echo " The manifest is inconsistent - regenerate it rather than editing it by hand"
exit 1
fi
else
FIRST_PUBKEY=$(yq eval ".validators[0].$PUBKEY_FIELD" "$MANIFEST_FILE" 2>/dev/null)
if [ -z "$FIRST_PUBKEY" ]; then
Expand Down
Loading