ops: refactor layer1 for devnet tools#802
Conversation
WalkthroughReplaced legacy L1 beacon/validator stack with a new Layer1 stack (execution, consensus, validator), added genesis generation/start/clean scripts and Makefile targets, introduced many validator keystores/secrets and templates, updated devnet startup to use docker-compose and poll EL readiness and first mined block. (34 words) Changes
Sequence Diagram(s)sequenceDiagram
participant Init as Devnet Init
participant FS as Filesystem
participant Gen as generate-genesis.sh
participant Compose as Docker Compose
participant EL as layer1-el (geth)
participant CL as layer1-cl (beacon)
participant VC as layer1-vc (validator)
participant RPC as JSON-RPC
rect `#dfefff`
Init->>FS: check for genesis.json / jwt
alt missing
Init->>Gen: run generate-genesis.sh
Gen->>FS: write genesis.json, genesis.ssz, configs, keystores
end
end
rect `#e9f7ea`
Init->>Compose: docker-compose up layer1-el, layer1-cl, layer1-vc
Compose->>EL: start geth
Compose->>CL: start beacon (depends on EL)
Compose->>VC: start validator (depends on CL)
end
rect `#ffe9e9`
Init->>EL: poll health / RPC
loop until block > 0
Init->>RPC: eth_blockNumber()
RPC-->>Init: blockNumber
end
Init->>Init: continue devnet startup
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (1)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
🔇 Additional comments (1)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 48
♻️ Duplicate comments (7)
ops/docker/layer1/keystores/layer1/keys/0x8aa5bbee21e98c7b9e7a4c8ea45aa99f89e22992fa4fc2d73869d77da4cc8a05b25b61931ff521986677dd7f7159e8e6/voting-keystore.json (1)
1-1: Same security issue as other keystore files.This keystore file has the same critical security issue noted in the review of the first voting-keystore.json file—cryptographic key material should not be committed to version control, even for devnet purposes.
ops/docker/layer1/keystores/layer1/keys/0x996323af7e545fb6363ace53f1538c7ddc3eb0d985b2479da3ee4ace10cbc393b518bf02d1a2ddb2f5bdf09b473933ea/voting-keystore.json (1)
1-1: Same security issue as other keystore files.This keystore file has the same critical security issue noted in the review of the first voting-keystore.json file—cryptographic key material should not be committed to version control, even for devnet purposes.
ops/docker/layer1/keystores/layer1/keys/0xaaf6c1251e73fb600624937760fef218aace5b253bf068ed45398aeb29d821e4d2899343ddcbbe37cb3f6cf500dff26c/voting-keystore.json (1)
1-1: Same security issue as other keystore files.This keystore file has the same critical security issue noted in the review of the first voting-keystore.json file—cryptographic key material should not be committed to version control, even for devnet purposes.
ops/docker/layer1/keystores/layer1/keys/0xab72cbc6575c3179680a58c0ecd5de46d2678ccbafc016746348ee5688edcb21b4e15bd37c70c508e3ea73103c2d566b/voting-keystore.json (1)
1-1: Same security issue as other keystore files.This keystore file has the same critical security issue noted in the review of the first voting-keystore.json file—cryptographic key material should not be committed to version control, even for devnet purposes.
ops/docker/layer1/keystores/layer1/keys/0x8de5a6200cebb09b2198e69fed84bcd512ec5cf317c5f1ee99aad03d2a9a8564bf3807c08da2664222268d59c34a06e4/voting-keystore.json (1)
1-1: Same weak KDF parameters as other keystores.This keystore has the same
c=2PBKDF2 iteration count. See earlier comments about devnet-only usage.ops/docker/layer1/keystores/layer1/keys/0x81ea9f74ef7d935b807474e38954ae3934856219a23e074954b2e860c5a3c400f9aedb42cd27cb4ceb697ca36d1e58cb/voting-keystore.json (1)
1-1: Keystore follows same pattern.Same considerations as other keystore files in this PR.
ops/docker/layer1/keystores/layer1/keys/0x87231421a08ed28e7d357e2b37a26a458155c8d822d829344bd1029e5d175b5edfaa78f16f784f724a2caef124944c4f/voting-keystore.json (1)
1-1: Keystore configuration consistent with others.Same structure and security considerations as other keystores in this PR.
🧹 Nitpick comments (12)
ops/docker/layer1/keystores/layer1/keys/0xabd12678c73463ecea5867a80caf256d5c5e6ba53ff188b143a4d5be83365ad257edf39eaa1ba8753c4cdf4c632ff99e/voting-keystore.json (1)
1-1: Add trailing newline to the file.JSON files should end with a newline character for consistency with POSIX standards and text editor conventions.
-{"crypto":{"kdf":{"function":"pbkdf2","params":{"dklen":32,"c":2,"prf":"hmac-sha256","salt":"8e4d0293c4cb76bf079c26ffcbec614fdeef98a8dccac7f3625f755677f2561c"},"message":""},"checksum":{"function":"sha256","params":{},"message":"f0775f94d9f44868e103f6f72b147d8f11426120ec951e608e00f518904f67c6"},"cipher":{"function":"aes-128-ctr","params":{"iv":"aa16d15abd4560bce198fe1394741fe9"},"message":"75e717379b4f8c5b1ce255bd5671067687948f3c26392cdf4857c977bb33295c"}},"description":"0xabd12678c73463ecea5867a80caf256d5c5e6ba53ff188b143a4d5be83365ad257edf39eaa1ba8753c4cdf4c632ff99e","pubkey":"abd12678c73463ecea5867a80caf256d5c5e6ba53ff188b143a4d5be83365ad257edf39eaa1ba8753c4cdf4c632ff99e","path":"","uuid":"ca0eeeb8-8a3b-4157-9b4c-43a6e5607269","version":4} \ No newline at end of file +{"crypto":{"kdf":{"function":"pbkdf2","params":{"dklen":32,"c":2,"prf":"hmac-sha256","salt":"8e4d0293c4cb76bf079c26ffcbec614fdeef98a8dccac7f3625f755677f2561c"},"message":""},"checksum":{"function":"sha256","params":{},"message":"f0775f94d9f44868e103f6f72b147d8f11426120ec951e608e00f518904f67c6"},"cipher":{"function":"aes-128-ctr","params":{"iv":"aa16d15abd4560bce198fe1394741fe9"},"message":"75e717379b4f8c5b1ce255bd5671067687948f3c26392cdf4857c977bb33295c"}},"description":"0xabd12678c73463ecea5867a80caf256d5c5e6ba53ff188b143a4d5be83365ad257edf39eaa1ba8753c4cdf4c632ff99e","pubkey":"abd12678c73463ecea5867a80caf256d5c5e6ba53ff188b143a4d5be83365ad257edf39eaa1ba8753c4cdf4c632ff99e","path":"","uuid":"ca0eeeb8-8a3b-4157-9b4c-43a6e5607269","version":4}ops/docker/layer1/keystores/layer1/keys/0xae940a07850cf904b44f31cbf0e44824bae5ec36dcfdb7fad858f2a39dba38de82ca12b0ae939a34fce7a02e4b9789f8/voting-keystore.json (1)
1-1: Weak PBKDF2 key derivation parameters may slow test initialization (optional observation).The KDF uses
"c": 2iterations, which is unusually low compared to standard recommendations (typically 2^18 or higher). For devnet/testing purposes this likely intentionally optimizes for fast key derivation during validator startup, but confirm this aligns with project devnet testing practices.ops/docker/layer1/keystores/layer1/keys/0x96947de9e6068c22a7716656a2755a9551b0b66c2d1a741bf84a088fe1e840e992dc39861bf8ba3e8d5b6d21e8f57e64/voting-keystore.json (1)
1-1: Minor: Add trailing newline to JSON file.The file ends without a trailing newline. While functionally correct, JSON files in repositories should follow the convention of ending with a newline character for consistency and better git diff behavior.
Apply this diff:
-{"crypto":{"kdf":{"function":"pbkdf2","params":{"dklen":32,"c":2,"prf":"hmac-sha256","salt":"63e05898e457ab85e2dee0c8da10fdda630558a0a3900ea09da484be8dbd9967"},"message":""},"checksum":{"function":"sha256","params":{},"message":"936dfff7aaed5a48bbc15e308f4079ea18127803be71a974a2acc60db980bef1"},"cipher":{"function":"aes-128-ctr","params":{"iv":"59357db2000d776034a0c5e89d36cd22"},"message":"75ab389e3d57401013883972c5f23602fc2909cc1c7a2ad8c22bd26f59f56aa1"}},"description":"0x96947de9e6068c22a7716656a2755a9551b0b66c2d1a741bf84a088fe1e840e992dc39861bf8ba3e8d5b6d21e8f57e64","pubkey":"96947de9e6068c22a7716656a2755a9551b0b66c2d1a741bf84a088fe1e840e992dc39861bf8ba3e8d5b6d21e8f57e64","path":"","uuid":"00c54fed-7953-439f-ac28-4d4bad382a41","version":4} +{"crypto":{"kdf":{"function":"pbkdf2","params":{"dklen":32,"c":2,"prf":"hmac-sha256","salt":"63e05898e457ab85e2dee0c8da10fdda630558a0a3900ea09da484be8dbd9967"},"message":""},"checksum":{"function":"sha256","params":{},"message":"936dfff7aaed5a48bbc15e308f4079ea18127803be71a974a2acc60db980bef1"},"cipher":{"function":"aes-128-ctr","params":{"iv":"59357db2000d776034a0c5e89d36cd22"},"message":"75ab389e3d57401013883972c5f23602fc2909cc1c7a2ad8c22bd26f59f56aa1"}},"description":"0x96947de9e6068c22a7716656a2755a9551b0b66c2d1a741bf84a088fe1e840e992dc39861bf8ba3e8d5b6d21e8f57e64","pubkey":"96947de9e6068c22a7716656a2755a9551b0b66c2d1a741bf84a088fe1e840e992dc39861bf8ba3e8d5b6d21e8f57e64","path":"","uuid":"00c54fed-7953-439f-ac28-4d4bad382a41","version":4}ops/docker/layer1/keystores/layer1/keys/0xa03c2a82374e04b2e0594c4ce14fb3f225b46f13188f0d8002a523c7dcfb939ae4856053c2c9c695374d7c3685df1ca5/voting-keystore.json (1)
1-1: Missing trailing newline.The file should end with a newline character for consistency with POSIX text file conventions and to avoid Git warnings.
ops/docker/layer1/keystores/layer1/keys/validator_definitions.yml (1)
1-192: Verify validator configuration for devnet requirements.All 32 validators are configured as enabled. For a devnet environment, confirm this is the intended configuration. Running all validators on a single node may have resource implications.
Additionally, the
descriptionfield duplicates thevoting_public_keyvalue for all entries. Consider whether more descriptive names (e.g., "validator-01", "validator-02") would improve maintainability.ops/docker/layer1/scripts/generate-genesis.sh (1)
97-97: Consider safer pattern for listing files.The current pattern
ls -1 ... | xargscan fail with filenames containing spaces or special characters, though this is unlikely with the specific file patterns used (*.yaml, *.ssz, *.txt).Apply this diff for a more robust approach:
-ls -1 "$GENESIS_DIR"/*.{yaml,ssz,txt} 2>/dev/null | xargs -n 1 basename | head -10 +find "$GENESIS_DIR" -maxdepth 1 \( -name "*.yaml" -o -name "*.ssz" -o -name "*.txt" \) -exec basename {} \; 2>/dev/null | head -10ops/devnet-morph/devnet/__init__.py (1)
380-401: Consider minor refinement to exception handling.The function is well-implemented. The
return Noneon line 398 could be moved to anelseblock for slightly clearer flow, though the current implementation is functional.Apply this diff if you prefer more explicit flow:
result = json.loads(data) if 'result' in result: # Convert hex string (e.g., "0x1") to integer block_number_hex = result['result'] return int(block_number_hex, 16) - return None + else: + return None except Exception as e: log.debug(f'Error calling eth_blockNumber: {e}') return Noneops/docker/layer1/scripts/clean.sh (2)
56-56: Consider safer pattern for find with xargs.The current
find | xargspattern without-print0can fail with filenames containing spaces or newlines, though this is unlikely in practice for database files.Apply this diff for better safety:
- find layer1/keystores/layer1 -name "*.db" -o -name "*.sqlite" -o -name "*.sqlite3" | xargs rm -f 2>/dev/null || true + find layer1/keystores/layer1 \( -name "*.db" -o -name "*.sqlite" -o -name "*.sqlite3" \) -exec rm -f {} + 2>/dev/null || true
67-69: Consider simplifying volume cleanup pipeline.The current
grep | awkpipeline works but could be simplified usinggrep -oorawkalone.Apply this diff for a cleaner approach:
-docker volume ls | grep -E "simple-ethereum-network|layer1-" | awk '{print $2}' | while read volume; do +docker volume ls --format '{{.Name}}' | grep -E "simple-ethereum-network|layer1-" | while read volume; do docker volume rm "$volume" 2>/dev/null || true doneops/docker/docker-compose-4nodes.yml (1)
38-46: Improve readability of the geth initialization and startup command.The geth command at line 46 is a single long line with ~23 flags, making it difficult to read, maintain, and debug. Consider refactoring into a clearer format.
Break the command into a more readable multi-line format:
command: - | mkdir -p /data/geth/execution-data if [ ! -f /data/geth/execution-data/geth/chaindata/CURRENT ]; then echo "Initializing genesis..." geth init --datadir=/data/geth/execution-data /network-configs/genesis.json || exit 1 else echo "Genesis already initialized, skipping init" fi - exec geth --networkid=900 --datadir=/data/geth/execution-data --http --http.addr=0.0.0.0 --http.port=8545 --http.api=admin,engine,net,eth,web3,debug,txpool --http.vhosts=* --http.corsdomain=* --ws --ws.addr=0.0.0.0 --ws.port=8546 --ws.api=admin,engine,net,eth,web3,debug,txpool --ws.origins=* --allow-insecure-unlock --authrpc.port=8551 --authrpc.addr=0.0.0.0 --authrpc.vhosts=* --authrpc.jwtsecret=/jwt/jwtsecret --syncmode=full --miner.gasprice=1 --rpc.allow-unprotected-txs --metrics --metrics.addr=0.0.0.0 --metrics.port=9001 --discovery.port=30303 --port=30303 + exec geth \ + --networkid=900 \ + --datadir=/data/geth/execution-data \ + --http \ + --http.addr=0.0.0.0 \ + --http.port=8545 \ + --http.api=admin,engine,net,eth,web3,debug,txpool \ + --http.vhosts=* \ + --http.corsdomain=* \ + --ws \ + --ws.addr=0.0.0.0 \ + --ws.port=8546 \ + --ws.api=admin,engine,net,eth,web3,debug,txpool \ + --ws.origins=* \ + --allow-insecure-unlock \ + --authrpc.port=8551 \ + --authrpc.addr=0.0.0.0 \ + --authrpc.vhosts=* \ + --authrpc.jwtsecret=/jwt/jwtsecret \ + --syncmode=full \ + --miner.gasprice=1 \ + --rpc.allow-unprotected-txs \ + --metrics \ + --metrics.addr=0.0.0.0 \ + --metrics.port=9001 \ + --discovery.port=30303 \ + --port=30303ops/docker/layer1/docker-compose.yml (1)
24-32: Improve readability of the geth initialization and startup command.The geth command on line 32 is a single long line with multiple flags, making it difficult to read and maintain (same issue as in
docker-compose-4nodes.yml).Break the command into a multi-line format for clarity (see the refactored example in the comment for
docker-compose-4nodes.ymllines 38-46).ops/docker/layer1/keystores/layer1/pubkeys.json (1)
1-1: Add a README or schema documentation.Consider adding a
README.mdor JSON schema file in theops/docker/layer1/keystores/directory explaining:
- The purpose of
pubkeys.json(validator public key registry for Lighthouse)- How this file is generated and maintained
- How downstream systems (genesis generation, validator startup) consume this file
- Expected format and key material lifecycle
This improves maintainability and prevents operational confusion, especially for new contributors working on devnet infrastructure.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (81)
Makefile(2 hunks)ops/devnet-morph/devnet/__init__.py(4 hunks)ops/docker/.env(1 hunks)ops/docker/Makefile.layer1(1 hunks)ops/docker/docker-compose-4nodes.yml(2 hunks)ops/docker/layer1/.gitignore(1 hunks)ops/docker/layer1/configs/values.env.template(1 hunks)ops/docker/layer1/docker-compose.yml(1 hunks)ops/docker/layer1/jwt/jwtsecret(1 hunks)ops/docker/layer1/keystores/layer1-password.txt(1 hunks)ops/docker/layer1/keystores/layer1/keys/0x81ea9f74ef7d935b807474e38954ae3934856219a23e074954b2e860c5a3c400f9aedb42cd27cb4ceb697ca36d1e58cb/voting-keystore.json(1 hunks)ops/docker/layer1/keystores/layer1/keys/0x8419cf00f2783c430dc861a710984d0429d3b3a7f6db849b4f5c05e0d87339704c5c7f5eede6adfc8776d666587b5932/voting-keystore.json(1 hunks)ops/docker/layer1/keystores/layer1/keys/0x84a687ffdf21a0ad754d0164d1e2c03035613ab76359e7f5cf51ea4a425a6ee026725ec0a0dbd336f7dab759596f0bf8/voting-keystore.json(1 hunks)ops/docker/layer1/keystores/layer1/keys/0x87231421a08ed28e7d357e2b37a26a458155c8d822d829344bd1029e5d175b5edfaa78f16f784f724a2caef124944c4f/voting-keystore.json(1 hunks)ops/docker/layer1/keystores/layer1/keys/0x8a8bb292bcc481070d3afdbbc8789e2ab4b29c9603936e6d85f5ff71e23fc5b6d61009f0fa636b5d5b2dc309d39e3d75/voting-keystore.json(1 hunks)ops/docker/layer1/keystores/layer1/keys/0x8aa5bbee21e98c7b9e7a4c8ea45aa99f89e22992fa4fc2d73869d77da4cc8a05b25b61931ff521986677dd7f7159e8e6/voting-keystore.json(1 hunks)ops/docker/layer1/keystores/layer1/keys/0x8d46e9aa0c1986056e407efc7013b7f271027d3c98ce96667faa98074ab0588a61681faf78644c11819a459a95689dab/voting-keystore.json(1 hunks)ops/docker/layer1/keystores/layer1/keys/0x8de5a6200cebb09b2198e69fed84bcd512ec5cf317c5f1ee99aad03d2a9a8564bf3807c08da2664222268d59c34a06e4/voting-keystore.json(1 hunks)ops/docker/layer1/keystores/layer1/keys/0x91709ee06497b9ac049325853d64947290189a8c2322e3a500d91e23ea02dc158b6db63ae558b3b7670357a151cd6071/voting-keystore.json(1 hunks)ops/docker/layer1/keystores/layer1/keys/0x930743bfc7e18d3bd7351eaa74f477505268c1e4e1fd1ca3ccccdefb2595517343bbb8f5589c435c3c39323a4c0080f8/voting-keystore.json(1 hunks)ops/docker/layer1/keystores/layer1/keys/0x96947de9e6068c22a7716656a2755a9551b0b66c2d1a741bf84a088fe1e840e992dc39861bf8ba3e8d5b6d21e8f57e64/voting-keystore.json(1 hunks)ops/docker/layer1/keystores/layer1/keys/0x996323af7e545fb6363ace53f1538c7ddc3eb0d985b2479da3ee4ace10cbc393b518bf02d1a2ddb2f5bdf09b473933ea/voting-keystore.json(1 hunks)ops/docker/layer1/keystores/layer1/keys/0x996d10c3026b9344532b06c70a596f972a1e779a1f6106d3da9f6ba376bbf7ec82d2f52629e5dbf3f7d03b00f6b862af/voting-keystore.json(1 hunks)ops/docker/layer1/keystores/layer1/keys/0xa03c2a82374e04b2e0594c4ce14fb3f225b46f13188f0d8002a523c7dcfb939ae4856053c2c9c695374d7c3685df1ca5/voting-keystore.json(1 hunks)ops/docker/layer1/keystores/layer1/keys/0xa1584dfe1573df8ec88c7b74d76726b4821bfe84bf886dd3c0e3f74c2ea18aa62ca44c871fb1c63971fccf6937e6501f/voting-keystore.json(1 hunks)ops/docker/layer1/keystores/layer1/keys/0xa1d9840eda3036fbf63eeea40146e4548553e6e1b2a653ab349b376f31b367c40d71fb59ff8e94b91daa99c262ec8b52/voting-keystore.json(1 hunks)ops/docker/layer1/keystores/layer1/keys/0xa35c6004f387430c3797ab0157af7b824c8fe106241c7cdeb897d900c0f9e4bb945ff2a6b88cbd10e35ec48aaa554ecb/voting-keystore.json(1 hunks)ops/docker/layer1/keystores/layer1/keys/0xa54fe5c26059ed60b4f0b66ef7b0bf167580504525f83c169507dc812816df41b1da6128341c23977300dffd32a32f41/voting-keystore.json(1 hunks)ops/docker/layer1/keystores/layer1/keys/0xa75ca9447dca3a3745ada36731187ddd1f6a152cf15d7446b785eab381e5c8562c1202a6e7a24080bc6b619a161113db/voting-keystore.json(1 hunks)ops/docker/layer1/keystores/layer1/keys/0xa804e4fa8d1391a9d078aa93985a12503b84ce4f6f1f9e70ab7fca421e1cf972538666299d4c1bfc39327b469b2db7a8/voting-keystore.json(1 hunks)ops/docker/layer1/keystores/layer1/keys/0xaaddb0cb69ca18f14aed7054e98a24df0ff606aeff919d489f7884fd1bd183bcb46ea54bc363146e1a88db36dc20a7a4/voting-keystore.json(1 hunks)ops/docker/layer1/keystores/layer1/keys/0xaaf6c1251e73fb600624937760fef218aace5b253bf068ed45398aeb29d821e4d2899343ddcbbe37cb3f6cf500dff26c/voting-keystore.json(1 hunks)ops/docker/layer1/keystores/layer1/keys/0xab72cbc6575c3179680a58c0ecd5de46d2678ccbafc016746348ee5688edcb21b4e15bd37c70c508e3ea73103c2d566b/voting-keystore.json(1 hunks)ops/docker/layer1/keystores/layer1/keys/0xabd12678c73463ecea5867a80caf256d5c5e6ba53ff188b143a4d5be83365ad257edf39eaa1ba8753c4cdf4c632ff99e/voting-keystore.json(1 hunks)ops/docker/layer1/keystores/layer1/keys/0xac69ae9e6c385a368df71d11ac68f45f05e005306df3c2bf98ed3577708256bd97f8c09d3f72115444077a9bb711d8d1/voting-keystore.json(1 hunks)ops/docker/layer1/keystores/layer1/keys/0xad9222dec71ff8ee6bc0426ffe7b5e66f96738225db281dd20027a1556d089fdebd040abfbc2041d6c1a0d8fdcfce183/voting-keystore.json(1 hunks)ops/docker/layer1/keystores/layer1/keys/0xae5302796cfeca685eaf37ffd5baeb32121f2f07415bee26cc0051ee513ff3932d2c365e3d9f87b0949a5980445cb64c/voting-keystore.json(1 hunks)ops/docker/layer1/keystores/layer1/keys/0xae940a07850cf904b44f31cbf0e44824bae5ec36dcfdb7fad858f2a39dba38de82ca12b0ae939a34fce7a02e4b9789f8/voting-keystore.json(1 hunks)ops/docker/layer1/keystores/layer1/keys/0xafa10af166a0dbf3a25ff86cd6f8e44cccc818c5e70cd70e4e98e226b158f3563450b3fb184d2649adbb11e53080d1ca/voting-keystore.json(1 hunks)ops/docker/layer1/keystores/layer1/keys/0xb27ad13afc8ff30e087797b344c8382bb0a84447549f1b0274059ddd652276e7b148ba8808a10cc45746762957d4efbe/voting-keystore.json(1 hunks)ops/docker/layer1/keystores/layer1/keys/0xb570dde8ee80512e3d031caf22e775c60f7f5a6cbdeb3e52e24cf8c867d38569a53dd19cdc36a03a1bbb3a8d94b03670/voting-keystore.json(1 hunks)ops/docker/layer1/keystores/layer1/keys/0xb72cb106b7bc1ecae219e0ae1830a509ed18a042b56a2779f4033419de69ba8ae8017090caed1f5377bfa68506157360/voting-keystore.json(1 hunks)ops/docker/layer1/keystores/layer1/keys/api-token.txt(1 hunks)ops/docker/layer1/keystores/layer1/keys/validator_definitions.yml(1 hunks)ops/docker/layer1/keystores/layer1/keys/validator_key_cache.json(1 hunks)ops/docker/layer1/keystores/layer1/pubkeys.json(1 hunks)ops/docker/layer1/keystores/layer1/secrets/0x81ea9f74ef7d935b807474e38954ae3934856219a23e074954b2e860c5a3c400f9aedb42cd27cb4ceb697ca36d1e58cb(1 hunks)ops/docker/layer1/keystores/layer1/secrets/0x8419cf00f2783c430dc861a710984d0429d3b3a7f6db849b4f5c05e0d87339704c5c7f5eede6adfc8776d666587b5932(1 hunks)ops/docker/layer1/keystores/layer1/secrets/0x84a687ffdf21a0ad754d0164d1e2c03035613ab76359e7f5cf51ea4a425a6ee026725ec0a0dbd336f7dab759596f0bf8(1 hunks)ops/docker/layer1/keystores/layer1/secrets/0x87231421a08ed28e7d357e2b37a26a458155c8d822d829344bd1029e5d175b5edfaa78f16f784f724a2caef124944c4f(1 hunks)ops/docker/layer1/keystores/layer1/secrets/0x8a8bb292bcc481070d3afdbbc8789e2ab4b29c9603936e6d85f5ff71e23fc5b6d61009f0fa636b5d5b2dc309d39e3d75(1 hunks)ops/docker/layer1/keystores/layer1/secrets/0x8aa5bbee21e98c7b9e7a4c8ea45aa99f89e22992fa4fc2d73869d77da4cc8a05b25b61931ff521986677dd7f7159e8e6(1 hunks)ops/docker/layer1/keystores/layer1/secrets/0x8d46e9aa0c1986056e407efc7013b7f271027d3c98ce96667faa98074ab0588a61681faf78644c11819a459a95689dab(1 hunks)ops/docker/layer1/keystores/layer1/secrets/0x8de5a6200cebb09b2198e69fed84bcd512ec5cf317c5f1ee99aad03d2a9a8564bf3807c08da2664222268d59c34a06e4(1 hunks)ops/docker/layer1/keystores/layer1/secrets/0x91709ee06497b9ac049325853d64947290189a8c2322e3a500d91e23ea02dc158b6db63ae558b3b7670357a151cd6071(1 hunks)ops/docker/layer1/keystores/layer1/secrets/0x930743bfc7e18d3bd7351eaa74f477505268c1e4e1fd1ca3ccccdefb2595517343bbb8f5589c435c3c39323a4c0080f8(1 hunks)ops/docker/layer1/keystores/layer1/secrets/0x96947de9e6068c22a7716656a2755a9551b0b66c2d1a741bf84a088fe1e840e992dc39861bf8ba3e8d5b6d21e8f57e64(1 hunks)ops/docker/layer1/keystores/layer1/secrets/0x996323af7e545fb6363ace53f1538c7ddc3eb0d985b2479da3ee4ace10cbc393b518bf02d1a2ddb2f5bdf09b473933ea(1 hunks)ops/docker/layer1/keystores/layer1/secrets/0x996d10c3026b9344532b06c70a596f972a1e779a1f6106d3da9f6ba376bbf7ec82d2f52629e5dbf3f7d03b00f6b862af(1 hunks)ops/docker/layer1/keystores/layer1/secrets/0xa03c2a82374e04b2e0594c4ce14fb3f225b46f13188f0d8002a523c7dcfb939ae4856053c2c9c695374d7c3685df1ca5(1 hunks)ops/docker/layer1/keystores/layer1/secrets/0xa1584dfe1573df8ec88c7b74d76726b4821bfe84bf886dd3c0e3f74c2ea18aa62ca44c871fb1c63971fccf6937e6501f(1 hunks)ops/docker/layer1/keystores/layer1/secrets/0xa1d9840eda3036fbf63eeea40146e4548553e6e1b2a653ab349b376f31b367c40d71fb59ff8e94b91daa99c262ec8b52(1 hunks)ops/docker/layer1/keystores/layer1/secrets/0xa35c6004f387430c3797ab0157af7b824c8fe106241c7cdeb897d900c0f9e4bb945ff2a6b88cbd10e35ec48aaa554ecb(1 hunks)ops/docker/layer1/keystores/layer1/secrets/0xa54fe5c26059ed60b4f0b66ef7b0bf167580504525f83c169507dc812816df41b1da6128341c23977300dffd32a32f41(1 hunks)ops/docker/layer1/keystores/layer1/secrets/0xa75ca9447dca3a3745ada36731187ddd1f6a152cf15d7446b785eab381e5c8562c1202a6e7a24080bc6b619a161113db(1 hunks)ops/docker/layer1/keystores/layer1/secrets/0xa804e4fa8d1391a9d078aa93985a12503b84ce4f6f1f9e70ab7fca421e1cf972538666299d4c1bfc39327b469b2db7a8(1 hunks)ops/docker/layer1/keystores/layer1/secrets/0xaaddb0cb69ca18f14aed7054e98a24df0ff606aeff919d489f7884fd1bd183bcb46ea54bc363146e1a88db36dc20a7a4(1 hunks)ops/docker/layer1/keystores/layer1/secrets/0xaaf6c1251e73fb600624937760fef218aace5b253bf068ed45398aeb29d821e4d2899343ddcbbe37cb3f6cf500dff26c(1 hunks)ops/docker/layer1/keystores/layer1/secrets/0xab72cbc6575c3179680a58c0ecd5de46d2678ccbafc016746348ee5688edcb21b4e15bd37c70c508e3ea73103c2d566b(1 hunks)ops/docker/layer1/keystores/layer1/secrets/0xabd12678c73463ecea5867a80caf256d5c5e6ba53ff188b143a4d5be83365ad257edf39eaa1ba8753c4cdf4c632ff99e(1 hunks)ops/docker/layer1/keystores/layer1/secrets/0xac69ae9e6c385a368df71d11ac68f45f05e005306df3c2bf98ed3577708256bd97f8c09d3f72115444077a9bb711d8d1(1 hunks)ops/docker/layer1/keystores/layer1/secrets/0xad9222dec71ff8ee6bc0426ffe7b5e66f96738225db281dd20027a1556d089fdebd040abfbc2041d6c1a0d8fdcfce183(1 hunks)ops/docker/layer1/keystores/layer1/secrets/0xae5302796cfeca685eaf37ffd5baeb32121f2f07415bee26cc0051ee513ff3932d2c365e3d9f87b0949a5980445cb64c(1 hunks)ops/docker/layer1/keystores/layer1/secrets/0xae940a07850cf904b44f31cbf0e44824bae5ec36dcfdb7fad858f2a39dba38de82ca12b0ae939a34fce7a02e4b9789f8(1 hunks)ops/docker/layer1/keystores/layer1/secrets/0xafa10af166a0dbf3a25ff86cd6f8e44cccc818c5e70cd70e4e98e226b158f3563450b3fb184d2649adbb11e53080d1ca(1 hunks)ops/docker/layer1/keystores/layer1/secrets/0xb27ad13afc8ff30e087797b344c8382bb0a84447549f1b0274059ddd652276e7b148ba8808a10cc45746762957d4efbe(1 hunks)ops/docker/layer1/keystores/layer1/secrets/0xb570dde8ee80512e3d031caf22e775c60f7f5a6cbdeb3e52e24cf8c867d38569a53dd19cdc36a03a1bbb3a8d94b03670(1 hunks)ops/docker/layer1/keystores/layer1/secrets/0xb72cb106b7bc1ecae219e0ae1830a509ed18a042b56a2779f4033419de69ba8ae8017090caed1f5377bfa68506157360(1 hunks)ops/docker/layer1/scripts/clean.sh(1 hunks)ops/docker/layer1/scripts/generate-genesis.sh(1 hunks)ops/docker/layer1/scripts/start.sh(1 hunks)
🧰 Additional context used
🪛 dotenv-linter (4.0.0)
ops/docker/.env
[warning] 5-5: [UnorderedKey] The L1_ETH_RPC key should go before the NODE_DATA_DIR key
(UnorderedKey)
[warning] 6-6: [UnorderedKey] The L1_BEACON_CHAIN_RPC key should go before the L1_ETH_RPC key
(UnorderedKey)
🪛 Ruff (0.14.3)
ops/devnet-morph/devnet/__init__.py
93-93: Avoid specifying long messages outside the exception class
(TRY003)
93-93: f-string without any placeholders
Remove extraneous f prefix
(F541)
398-398: Consider moving this statement to an else block
(TRY300)
399-399: Do not catch blind exception: Exception
(BLE001)
🪛 Shellcheck (0.11.0)
ops/docker/layer1/scripts/generate-genesis.sh
[warning] 97-97: Use 'find .. -print0 | xargs -0 ..' or 'find .. -exec .. +' to allow non-alphanumeric filenames.
(SC2011)
ops/docker/layer1/scripts/start.sh
[warning] 37-37: i appears unused. Verify use (or export if used externally).
(SC2034)
ops/docker/layer1/scripts/clean.sh
[warning] 56-56: Use 'find .. -print0 | xargs -0 ..' or 'find .. -exec .. +' to allow non-alphanumeric filenames.
(SC2038)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: Analyze (rust)
- GitHub Check: Analyze (go)
🔇 Additional comments (39)
ops/docker/layer1/keystores/layer1/keys/0xa1584dfe1573df8ec88c7b74d76726b4821bfe84bf886dd3c0e3f74c2ea18aa62ca44c871fb1c63971fccf6937e6501f/voting-keystore.json (1)
1-1: Verify keystore storage model and security assumptions.Confirm:
- These keystores are test-only and never to be used with mainnet validators
- The passphrase/password management strategy for these keystores
- Whether alternative approaches (dynamic generation, secrets manager, environment variables) were considered
ops/docker/layer1/keystores/layer1/secrets/0xb72cb106b7bc1ecae219e0ae1830a509ed18a042b56a2779f4033419de69ba8ae8017090caed1f5377bfa68506157360 (1)
1-1: The review comment is based on a factually incorrect premise.The secret files in
ops/docker/layer1/keystores/layer1/secrets/were committed in a previous commit (d110a38: add private layer1 building), not in this PR. Git verification shows:
- All 32 secret files are already tracked in the repository
- There are no staged or unstaged changes to the keystores directory in this PR
git diff HEADshows no modifications to these files- The current branch contains these pre-existing files unmodified
The review comment incorrectly frames this as a new security vulnerability being introduced by this PR and instructs removal/history cleaning of files that this PR is not adding. While the underlying concern about secrets in version control is a legitimate security issue, it is a pre-existing repository condition, not a PR-specific problem. The remediation steps recommended (git rm, BFG, force-push) are misdirected at this PR when the issue originates from a prior commit.
Likely an incorrect or invalid review comment.
ops/docker/layer1/keystores/layer1/secrets/0xaaf6c1251e73fb600624937760fef218aace5b253bf068ed45398aeb29d821e4d2899343ddcbbe37cb3f6cf500dff26c (1)
1-1: ****The file path referenced in the review does not exist. The files are located at
ops/docker/layer1/keystores/layer1/keys/(notsecrets/). While keystores under thekeys/directory are indeed being tracked by Git and exposed, this review comment references a non-existentsecrets/directory path. Verify whether the concern applies to the actualkeys/directory files or whether you intended to reference a different set of files.Likely an incorrect or invalid review comment.
ops/docker/layer1/keystores/layer1/keys/0xad9222dec71ff8ee6bc0426ffe7b5e66f96738225db281dd20027a1556d089fdebd040abfbc2041d6c1a0d8fdcfce183/voting-keystore.json (1)
1-1: Add .gitignore and documentation to prevent accidental production keystore commits.While this appears to be a devnet environment (chain ID 900, hardcoded validator addresses), storing keystores directly in version control without
.gitignoreprotection is risky and undocumented:
- Missing
.gitignore: Keystores are committed without safeguards, creating a foothold for accidentally committing production keystores using the same pattern.- Undocumented strategy: No README or comments in
ops/docker/layer1/explain that keystores are intentionally sourced from the repo for devnet reproducibility. This increases the likelihood of misuse.- Minor: File missing trailing newline (line 1).
Recommended changes:
- Add
keystores/to.gitignoreat the root or ops/docker/ level, with an exception forops/docker/layer1/keystores/(if repo keystores are intentional) or a.gitignore-templatefor reference.- Add a
README.mdor section inops/docker/layer1/documenting: "Keystores are included in this devnet environment for reproducibility and must never be used with real validators or production networks."- Add a pre-commit hook or CI check to prevent non-
layer1/keystores from being committed.- Fix trailing newline on line 1.
ops/docker/layer1/keystores/layer1/keys/0xb27ad13afc8ff30e087797b344c8382bb0a84447549f1b0274059ddd652276e7b148ba8808a10cc45746762957d4efbe/voting-keystore.json (1)
1-1: Confirm whether storing encrypted keystores in git is intentional for this repository.Verification shows that 69 keystore files are committed to the repository and deliberately not excluded by
.gitignore. This is pre-existing architecture (keystores were added in a prior commit, not new in this PR), but no documentation explains the security rationale or acceptable risk level.Before proceeding, confirm:
- Is this intentional for devnet development?
- Should this state be documented (e.g., in a SECURITY policy) to set expectations?
- Is there a separate effort to move keystores out of version control?
ops/docker/layer1/keystores/layer1/keys/0x930743bfc7e18d3bd7351eaa74f477505268c1e4e1fd1ca3ccccdefb2595517343bbb8f5589c435c3c39323a4c0080f8/voting-keystore.json (1)
1-1: Document that pbkdf2 parameters (c=2) are devnet-only to prevent production replication.All voting keystores in
ops/docker/layer1/keystores/use"c": 2for pbkdf2 iterations—this is dangerously weak for production but acceptable for devnet. Sinceops/dockeris marked in.gitignoreas devnet configuration and no production keystores exist elsewhere in the repository, this is not an immediate production risk.However, add documentation (e.g., comment in the keystore directory or a README) explicitly stating these are devnet keystores with intentionally weak parameters, to prevent accidental replication of this pattern in production key generation. Consider regenerating with secure defaults (NIST minimum 10,000, industry standard 262,144+) if these keystores are used in CI/CD or shared environments.
ops/docker/layer1/keystores/layer1/secrets/0xb27ad13afc8ff30e087797b344c8382bb0a84447549f1b0274059ddd652276e7b148ba8808a10cc45746762957d4efbe (1)
1-1: Document these validator secrets as development-only and add safeguards to prevent production misuse.The committed validator secrets are confirmed to be used in a local development network (network ID 900 in docker-compose.yml). However, no documentation, code comments, or environment safeguards currently prevent these secrets from being accidentally used with real validators on a public network.
Add:
- A comment in
validator_definitions.ymland the secrets directory stating "For development/devnet only"- A README in
ops/docker/layer1/explaining this is a local test setup- Consider adding a network validation check in startup scripts to prevent cross-network misuse
ops/docker/layer1/keystores/layer1/keys/0x96947de9e6068c22a7716656a2755a9551b0b66c2d1a741bf84a088fe1e840e992dc39861bf8ba3e8d5b6d21e8f57e64/voting-keystore.json (1)
1-1: Weak pbkdf2 iteration count confirmed across all keystores—requires documentation or regeneration.This concern is valid. All 34 keystores in
ops/docker/layer1/keystores/consistently use"c": 2for pbkdf2 iterations, which provides virtually no brute-force protection on the encrypted key material. While these are clearly devnet/testnet fixtures (referenced in docker-compose.yml and generate-genesis.sh), the weakness combined with lack of security documentation is problematic.Findings:
- Systematic issue: All keystores use
"c": 2(not isolated to one file)- Static artifacts: Keystores are committed to the repository, not dynamically generated (generate-genesis.sh merely references them)
- EIP-2335 context: The spec provides a test vector with
c: 262144but does not mandate a minimum; however, industry best practices strongly recommend much higher values than 2- Missing documentation: No README or security notes explain the devnet-only nature or intentional weakness
Required action:
Either add documentation to
ops/docker/layer1/clarifying these are test-only keystore fixtures with accepted security trade-offs for devnet, OR regenerate keystores with industry-standard iteration counts (e.g.,c: 262144or higher). Committing weak keystores without any security context risks misuse and confusion.ops/docker/layer1/keystores/layer1/keys/0xb72cb106b7bc1ecae219e0ae1830a509ed18a042b56a2779f4033419de69ba8ae8017090caed1f5377bfa68506157360/voting-keystore.json (2)
1-1: Verify: Ensure keystores are appropriately labeled and isolated for development-only use.Per the PR objectives mentioning "devnet tools," verify that clear documentation exists explaining:
- These keystores are for development/testing only
- They should never be used with real funds
- The weak PBKDF2 parameters are intentional for devnet convenience
- A separate, secure process exists for production validator key management
Search the repository for documentation (e.g.,
README.md,SECURITY.md, deployment guides) explaining the Layer 1 keystore strategy and devnet/production separation. If missing, consider adding guidance to prevent misuse.
1-1: Clarify keystore storage strategy and fix .gitignore — keystores are confirmed devnet fixtures but .gitignore rule is not properly applied.These keystores are intentional test fixtures for a devnet setup (confirmed by: 32-validator configuration,
password123credential, docker-compose orchestration inops/docker/layer1/, and only voting keystores without withdrawal variants). They are part of the devnet initialization strategy with genesis generation and container startup scripts in the same directory.However, the global
.gitignoreentrykeystores/is not catchingops/docker/layer1/keystores/. Add an explicit entry toops/docker/layer1/.gitignoreto prevent accidental commits of keystores, or document why these are intentionally tracked. No production keystore management strategy or location was found in the repository—ensure this is addressed in a separate change.ops/docker/layer1/keystores/layer1/keys/0xa54fe5c26059ed60b4f0b66ef7b0bf167580504525f83c169507dc812816df41b1da6128341c23977300dffd32a32f41/voting-keystore.json (1)
1-1: PBKDF2 iteration count is significantly weaker than standard, but appropriate for devnet—verify intent and document.Verification found that all keystores consistently use
c=2iterations, which is 131,072x weaker than the Lighthouse standard of c=262,144. However, this is isolated toops/docker/layer1/keystores/(devnet-only infrastructure) with:
- Hardcoded test password stored in plaintext
- Ephemeral Docker volume mounts
- No production deployment references
This weak iteration count is a technical deviation from best practices, but acceptable for local development. Confirm whether this is intentional and consider adding a comment in the keystore directory documenting that these are devnet-only test fixtures.
ops/docker/layer1/keystores/layer1/secrets/0xa75ca9447dca3a3745ada36731187ddd1f6a152cf15d7446b785eab381e5c8562c1202a6e7a24080bc6b619a161113db (1)
1-1: Validator secret for devnet - ensure test-only usage.This validator keystore secret should only be used in devnet/testing environments. See security considerations in the first secret file review.
ops/docker/layer1/keystores/layer1/secrets/0xac69ae9e6c385a368df71d11ac68f45f05e005306df3c2bf98ed3577708256bd97f8c09d3f72115444077a9bb711d8d1 (1)
1-1: Validator secret for devnet.Hardcoded validator keystore secret. Ensure this is documented as test-only for devnet environments. See detailed security considerations in the first secret file review.
ops/docker/layer1/keystores/layer1/secrets/0x996323af7e545fb6363ace53f1538c7ddc3eb0d985b2479da3ee4ace10cbc393b518bf02d1a2ddb2f5bdf09b473933ea (1)
1-1: Validator secret for devnet.Hardcoded validator keystore secret. Ensure this is documented as test-only for devnet environments. See detailed security considerations in the first secret file review.
ops/docker/layer1/keystores/layer1/secrets/0xaaddb0cb69ca18f14aed7054e98a24df0ff606aeff919d489f7884fd1bd183bcb46ea54bc363146e1a88db36dc20a7a4 (1)
1-1: Validator secret for devnet.Hardcoded validator keystore secret. Ensure this is documented as test-only for devnet environments. See detailed security considerations in the first secret file review.
ops/docker/layer1/keystores/layer1/secrets/0x996d10c3026b9344532b06c70a596f972a1e779a1f6106d3da9f6ba376bbf7ec82d2f52629e5dbf3f7d03b00f6b862af (1)
1-1: Validator secret for devnet.Hardcoded validator keystore secret. Ensure this is documented as test-only for devnet environments. See detailed security considerations in the first secret file review.
ops/docker/.env (1)
5-6: Endpoint updates look correct.The L1 RPC endpoints have been properly updated to reference the new
layer1-elandlayer1-clservices, which aligns with the Layer1 infrastructure refactor described in the PR objectives.ops/docker/layer1/jwt/jwtsecret (1)
1-1: Add clear documentation indicating this JWT secret is for devnet/local development only.The JWT secret is committed to version control as a shared devnet artifact. While this appears intentional (scripts assume pre-existence, clean.sh preserves it, multiple docker nodes share it), the lack of documentation creates security confusion. The .gitignore rule
jwt/inops/docker/layer1/.gitignoreexists but is ineffective.Add to
ops/docker/layer1/jwt/jwtsecretor nearby README:
- Header comment:
# TEST/DEVNET ONLY - DO NOT USE IN PRODUCTION- Documentation explaining this is a shared devnet credential
- Either update .gitignore to properly exclude this, or document why it's intentionally committed
ops/docker/layer1/keystores/layer1/keys/0xa804e4fa8d1391a9d078aa93985a12503b84ce4f6f1f9e70ab7fca421e1cf972538666299d4c1bfc39327b469b2db7a8/voting-keystore.json (1)
1-1: Critically weak KDF iteration count for keystore encryption.The keystore uses only
c=2PBKDF2 iterations, which provides minimal protection against brute-force attacks. Standard production keystores use tens of thousands to millions of iterations.Since this appears to be for devnet/testing purposes based on the PR context, this is acceptable for local development where performance matters more than security. However, ensure these keystores are never used in production or any environment accessible from the internet.
Consider adding a comment or README in the keystores directory clearly indicating these are development-only credentials with weak encryption parameters.
ops/docker/layer1/keystores/layer1/secrets/0xb570dde8ee80512e3d031caf22e775c60f7f5a6cbdeb3e52e24cf8c867d38569a53dd19cdc36a03a1bbb3a8d94b03670 (1)
1-1: Keystore password committed to repository.This file contains a keystore password committed directly to the repository. While acceptable for local devnet development, ensure:
- These credentials are never reused in any non-local environment
- The repository remains private or clearly marked as containing development-only credentials
- Consider documenting in a README that all keystores/secrets are for devnet only
ops/docker/layer1/configs/values.env.template (2)
62-62: Hardcoded premine addresses with substantial balances.Two addresses are configured with 1,000,000,000 ETH each. While appropriate for devnet testing, verify:
- The private keys for these addresses are documented for developer access
- These addresses are not used in any non-devnet environment
- The mnemonic on line 4 likely controls these accounts
24-28: Future fork epochs set to maximum uint64.Fork epochs for GLOAS, EIP7805, and EIP7441 are set to
18446744073709551615(max uint64), effectively disabling them. Confirm this is intentional for the devnet configuration.ops/docker/layer1/keystores/layer1/secrets/0x81ea9f74ef7d935b807474e38954ae3934856219a23e074954b2e860c5a3c400f9aedb42cd27cb4ceb697ca36d1e58cb (1)
1-1: Keystore password in repository.Same security considerations as other secret files in this PR. Acceptable for devnet-only usage.
ops/docker/layer1/scripts/start.sh (1)
1-58: LGTM! Well-structured startup orchestration.The script correctly validates prerequisites, starts the Layer1 services via docker-compose, and includes appropriate readiness checks with clear user feedback. The wait logic with retries is robust.
ops/docker/Makefile.layer1 (1)
1-27: LGTM! Clean Makefile structure.The targets are well-organized, properly declared as PHONY, and include helpful documentation. The delegation to scripts and docker-compose commands is appropriate.
Makefile (2)
150-150: LGTM! Proper dependency chain integration.Adding
devnet-l1-cleanto thedevnet-clean-builddependencies ensures Layer1 cleanup is part of the build-down sequence.
166-168: LGTM! Clean integration of Layer1 cleanup.The new
devnet-l1-cleantarget properly delegates to the cleanup script and is correctly declared as PHONY.ops/docker/layer1/keystores/layer1/keys/0xa1d9840eda3036fbf63eeea40146e4548553e6e1b2a653ab349b376f31b367c40d71fb59ff8e94b91daa99c262ec8b52/voting-keystore.json (1)
1-1: Weak KDF iteration count noted (acceptable for devnet).The keystore uses PBKDF2 with only 2 iterations (
"c":2), which provides minimal protection against brute-force attacks. While this is acceptable for devnet/testing environments where performance is prioritized, ensure this keystore is never used in production.ops/docker/layer1/scripts/generate-genesis.sh (1)
1-86: LGTM! Comprehensive genesis generation workflow.The script properly handles directory setup, template processing, genesis generation via Docker, and thorough verification with clear user feedback. The 20-second buffer for genesis timestamp is reasonable for startup coordination.
ops/devnet-morph/devnet/__init__.py (2)
96-120: LGTM! Well-structured Layer1 startup orchestration.The changes properly integrate the new three-service Layer1 topology (layer1-el, layer1-cl, layer1-vc) with appropriate readiness checks. The block polling logic with 3-minute timeout is reasonable for devnet startup.
271-272: LGTM! Endpoint updates align with new Layer1 topology.The RPC endpoints correctly reference the new service names
layer1-elandlayer1-clinstead of the previousl1andbeacon-chain.ops/docker/layer1/keystores/layer1/keys/0x8419cf00f2783c430dc861a710984d0429d3b3a7f6db849b4f5c05e0d87339704c5c7f5eede6adfc8776d666587b5932/voting-keystore.json (1)
1-1: Weak KDF iteration count noted (acceptable for devnet).The keystore uses PBKDF2 with only 2 iterations (
"c":2), which provides minimal protection against brute-force attacks. While this is acceptable for devnet/testing environments where performance is prioritized, ensure this keystore is never used in production.ops/docker/layer1/scripts/clean.sh (1)
1-87: LGTM! Comprehensive cleanup with good error handling.The script properly resets the Layer1 environment by removing containers, volumes, generated files, and databases while preserving templates and keystores. The permissive error handling (using
|| trueand stderr redirection) is appropriate for a cleanup script. The summary output is helpful for users.ops/docker/docker-compose-4nodes.yml (2)
19-21: Add morph-network to layer1 services for consistency.The layer1 services defined in this file are missing explicit network membership declarations, while
ops/docker/layer1/docker-compose.ymlexplicitly places them onmorph-network. For consistency and to ensure all services communicate on the same network, add network declarations to these services. If they rely on the default network, this should be documented.Are all services (layer1-el, layer1-cl, layer1-vc, and L2 services) intended to share a single network, or should they be on separate networks? This needs clarification to ensure proper inter-service communication.
121-121: Approve the dependency update for layer1 integration.The
morph-geth-0now correctly depends onlayer1-elfor proper startup orchestration. This change ensures the execution layer is ready before L2 nodes attempt to connect.ops/docker/layer1/docker-compose.yml (2)
107-110: Approve network isolation strategy.The explicit
morph-networkbridge network declaration ensures proper isolation and allows services to communicate via container names. This is a good practice for Docker Compose deployments.
89-89: Validator keystore directory structure verified.The layer1-vc service mounts
./keystores/layer1with the correct directory structure in place:
./keystores/layer1/keys/— contains validator key directories (confirmed)./keystores/layer1/secrets/— contains corresponding secret files (confirmed)ops/docker/layer1/keystores/layer1/keys/0x8a8bb292bcc481070d3afdbbc8789e2ab4b29c9603936e6d85f5ff71e23fc5b6d61009f0fa636b5d5b2dc309d39e3d75/voting-keystore.json (1)
1-1: SECURITY: Weak KDF parameters in devnet keystores require documentation.All keystores in
ops/docker/layer1/keystores/consistently use PBKDF2 withc=2iterations, which is cryptographically insufficient. While EIP-2335 does not mandate specific iteration counts, standard Ethereum keystore generators default toc=262144for production use. This configuration adds negligible entropy against brute-force attacks.Given the
/docker/layer1/path structure indicates a devnet setup: confirm whetherc=2was intentional for fast key generation during development. If so, add a comment in the keystore generation documentation stating that these are devnet-only keys and must never be used with mainnet funds or real private keys.ops/docker/layer1/keystores/layer1/pubkeys.json (1)
1-1: No action needed. The review comment's concern about key length variation is incorrect.Verification confirms all 32 public keys in the file are valid, consistently formatted, and have identical length (98 characters:
0x+ 96 hex characters), which is the expected format for BLS public keys in Lighthouse validators. The file requires no corrections.Likely an incorrect or invalid review comment.
| genesis/ | ||
| keystores/ | ||
| configs/ | ||
| jwt/ | ||
|
|
There was a problem hiding this comment.
Contradiction: .gitignore excludes files being committed in this PR.
The .gitignore correctly excludes keystores/ (line 2), yet this PR commits numerous keystore and secret files under ops/docker/layer1/keystores/. This indicates that:
- The keystore files should be generated locally by users running the devnet setup
- Only the generation scripts and documentation should be committed, not the artifacts themselves
Remove all files under the directories listed in this .gitignore from the commit, and ensure the devnet setup documentation explains how to generate them.
| password123 | ||
|
|
There was a problem hiding this comment.
CRITICAL: Remove hardcoded secrets from version control.
This file contains a plaintext password that will be permanently stored in repository history. This is a critical security vulnerability that compromises all validator keystores it protects.
Immediate actions required:
-
Remove from history: Execute a force-push to purge this from git history (or request repository owner to do so):
git filter-branch --tree-filter 'rm -f ops/docker/layer1/keystores/layer1-password.txt' -- --all git push -f -
Regenerate keystores: Since the password is now public, regenerate all affected validator keystores and secrets.
-
Prevent recurrence: Add to
.gitignore:ops/docker/layer1/keystores/layer1-password.txt -
Use proper secrets management: Inject the password at runtime via:
- Environment variables passed to Docker Compose
- Kubernetes secrets (if running on K8s)
- External secrets management system (HashiCorp Vault, AWS Secrets Manager, etc.)
- Docker secrets (for swarm mode)
Do not commit credentials to version control under any circumstances. This file should be git-ignored and provided through secure infrastructure-as-code secrets management.
🤖 Prompt for AI Agents
In ops/docker/layer1/keystores/layer1-password.txt around lines 1 to 2, there is
a hardcoded plaintext password committed to the repository; remove the file from
the working tree and purge it from git history, regenerate any affected
keystores/secrets, add the file path to .gitignore, and switch to injecting the
password at runtime via a secrets manager or environment/secret mechanisms
(e.g., Docker/Kubernetes/HashiCorp Vault) so no credentials are stored in
version control.
| @@ -0,0 +1 @@ | |||
| {"crypto":{"kdf":{"function":"pbkdf2","params":{"dklen":32,"c":2,"prf":"hmac-sha256","salt":"5ccefb67de4aa473b14a6e8924ebe75b7cdf0aa4b5f4eba45b3050638ebdc540"},"message":""},"checksum":{"function":"sha256","params":{},"message":"32f2505d9f610f27419c3e24e379a874f2f24dfa37505933da6faf45e0e2563c"},"cipher":{"function":"aes-128-ctr","params":{"iv":"7d130535cda9c5560abeeeaa28fa91ee"},"message":"db6d4a726e2c501cf130ed3e676881c7c92022f4e7eeb1e15b83bb6751e0fb56"}},"description":"0x8d46e9aa0c1986056e407efc7013b7f271027d3c98ce96667faa98074ab0588a61681faf78644c11819a459a95689dab","pubkey":"8d46e9aa0c1986056e407efc7013b7f271027d3c98ce96667faa98074ab0588a61681faf78644c11819a459a95689dab","path":"","uuid":"5cca9e94-3149-498d-a1f8-3cb50f5fc37d","version":4} No newline at end of file | |||
There was a problem hiding this comment.
Increase PBKDF2 iterations to a safe value.
Line [1]: The PBKDF2 KDF is configured with c: 2, which is effectively no hardening—anyone with this keystore (and the committed password files) can brute-force the secret instantly. Please regenerate all of the new keystore files in this PR with a realistic iteration count (e.g., Lighthouse defaults in the hundreds of thousands) so the private keys remain protected.
🤖 Prompt for AI Agents
ops/docker/layer1/keystores/layer1/keys/0x8d46e9aa0c1986056e407efc7013b7f271027d3c98ce96667faa98074ab0588a61681faf78644c11819a459a95689dab/voting-keystore.json
lines 1: PBKDF2 iterations are set to c: 2 which is insecure; regenerate all
keystore files in this PR using your keystore generation tool/config with a
strong iteration count (e.g., set c to a value in the hundreds of thousands such
as 200000–500000 or follow the concrete project/default recommended value),
replace the committed keystore JSONs with the newly generated ones, ensure the
KDF section reflects the higher c value and verify decryption with the intended
password before committing.
| @@ -0,0 +1 @@ | |||
| {"crypto":{"kdf":{"function":"pbkdf2","params":{"dklen":32,"c":2,"prf":"hmac-sha256","salt":"27b69ffcaf55d9e3884a75298e5a95660d94fc53983d8a86c8aa9f19aa761670"},"message":""},"checksum":{"function":"sha256","params":{},"message":"8045df2eea34e1a326373c042b1802616549b24840183e948c08a931a6ecae9a"},"cipher":{"function":"aes-128-ctr","params":{"iv":"7a51bb36f7de674e8f05f94339acaecf"},"message":"7529f75843df106aa71dd6762e4e852ab35295ceb81e38214af95fd37041086c"}},"description":"0x91709ee06497b9ac049325853d64947290189a8c2322e3a500d91e23ea02dc158b6db63ae558b3b7670357a151cd6071","pubkey":"91709ee06497b9ac049325853d64947290189a8c2322e3a500d91e23ea02dc158b6db63ae558b3b7670357a151cd6071","path":"","uuid":"9c48003a-283e-4614-9647-44e2485b7899","version":4} No newline at end of file | |||
There was a problem hiding this comment.
Keystore files should not be committed to version control.
This file contains encrypted private key material and is being committed to the repository. Even for devnet/testing purposes, committing keystores to git is a security anti-pattern that should be avoided:
- Keystore files should be generated locally or provisioned through secrets management
- The
.gitignorefile added in this PR already excludeskeystores/, yet keystore files are being committed in the same PR - Even with encryption, exposing key material in version control creates unnecessary risk
Additionally, the PBKDF2 iteration count (c=2) is extremely weak—production keystores typically use 100,000+ iterations. While acceptable for devnet, this reinforces that these are test-only artifacts that should not be in the repository.
Recommendation: Remove all keystore and secret files from this commit and document in the README how to generate them locally using the provided scripts (e.g., generate-genesis.sh).
🤖 Prompt for AI Agents
In
ops/docker/layer1/keystores/layer1/keys/0x91709ee06497b9ac049325853d64947290189a8c2322e3a500d91e23ea02dc158b6db63ae558b3b7670357a151cd6071/voting-keystore.json
(lines 1-1): this keystore file containing encrypted private key material must
be removed from the commit and repository; remove the file from the branch (do
not leave secrets in history), ensure keystores/ is listed in .gitignore so
future keystores are never committed, replace any committed keystores with a
non-secret template/placeholder if needed, and add README documentation
explaining how to generate keystores locally using the provided scripts (e.g.,
generate-genesis.sh); additionally, update the generation script to use a secure
PBKDF2 iteration count (e.g., 100,000+) for production defaults while keeping
test artifacts local only.
| @@ -0,0 +1 @@ | |||
| {"crypto":{"kdf":{"function":"pbkdf2","params":{"dklen":32,"c":2,"prf":"hmac-sha256","salt":"586798b1b0983a9cd54b281283ebbe01c25e08482a2fd2c6e00f3d124a1fd5d1"},"message":""},"checksum":{"function":"sha256","params":{},"message":"dd7d2d86d574cf9a6c6f7fe3ac0de9649178a95d44f7575af22e1c500f5a3553"},"cipher":{"function":"aes-128-ctr","params":{"iv":"9009c6c729ec27470ad0bb1eeb8c1227"},"message":"749e1b3c69a7bf4733610a5df95366f15c5bcb9d6182c54c603864293069cd4c"}},"description":"0x930743bfc7e18d3bd7351eaa74f477505268c1e4e1fd1ca3ccccdefb2595517343bbb8f5589c435c3c39323a4c0080f8","pubkey":"930743bfc7e18d3bd7351eaa74f477505268c1e4e1fd1ca3ccccdefb2595517343bbb8f5589c435c3c39323a4c0080f8","path":"","uuid":"d5fa5791-b381-4e34-b5bd-d395a1e3ccc3","version":4} No newline at end of file | |||
There was a problem hiding this comment.
🧩 Analysis chain
Do not commit encrypted keystores with private keys to version control.
Ethereum validator keystores (even when encrypted) should never be committed to the repository. If the repository is ever leaked, exposed, or made public, attackers gain access to encrypted private keys. Combined with weak key derivation parameters (see next comment), this creates a critical security vulnerability.
Please verify:
- Are these keystore files tracked in
.gitignore? - Should they be generated at runtime or loaded from a secure, non-version-controlled location?
- If these are intentional hardcoded devnet credentials, consider generating them dynamically during container initialization.
For devnet environments, keystores can be generated on-the-fly using tools like staking-deposit-cli or similar, eliminating the need to commit them.
I'll verify the security concerns about the committed keystores and their parameters.
🏁 Script executed:
#!/bin/bash
# Check .gitignore for keystores
echo "=== Checking .gitignore for keystores patterns ==="
if [ -f .gitignore ]; then
cat .gitignore | grep -i keystore || echo "No keystore patterns found in .gitignore"
else
echo ".gitignore not found"
fi
# Find all keystore files in the repository
echo -e "\n=== Finding all keystore files ==="
find . -name "*keystore*.json" -type f 2>/dev/null | head -20
# Check if keystores directory exists and its contents
echo -e "\n=== Keystores directory structure ==="
if [ -d ops/docker/layer1/keystores ]; then
find ops/docker/layer1/keystores -type f | head -20
fi
# Check git tracking status
echo -e "\n=== Git status for keystores ==="
git status ops/docker/layer1/keystores 2>/dev/null || echo "Unable to check git status"Length of output: 6591
🏁 Script executed:
#!/bin/bash
# Check the password file
echo "=== Checking layer1-password.txt ==="
if [ -f ops/docker/layer1/keystores/layer1-password.txt ]; then
echo "File exists. Content preview:"
head -c 100 ops/docker/layer1/keystores/layer1-password.txt 2>/dev/null || echo "Unable to read"
echo ""
echo "File size:"
wc -c < ops/docker/layer1/keystores/layer1-password.txt
else
echo "File not found"
fi
# Count total keystores
echo -e "\n=== Total keystore count ==="
find ops/docker/layer1/keystores -name "*voting-keystore.json" -type f | wc -lLength of output: 127
Remove encrypted keystores and password files from version control immediately.
This repository contains 32 committed validator keystores (ops/docker/layer1/keystores/layer1/keys/) with NO .gitignore protection, plus a plain-text password file (ops/docker/layer1/keystores/layer1-password.txt) containing "password123". Combined with dangerously weak pbkdf2 parameters (c=2 iterations), this creates a critical security vulnerability. If this repository is ever leaked or made public, attackers gain immediate access to all Layer 1 validator credentials.
Required actions:
- Add
ops/docker/layer1/keystores/to.gitignoreimmediately - Remove keystores and password file from git history using
git filter-branchorgit filter-repo - Regenerate all validator credentials (these are now compromised)
- Generate keystores at runtime during container initialization instead of committing them
- If credentials must be stored, use a secure secret management system (e.g., HashiCorp Vault, AWS Secrets Manager) separate from version control
For devnet environments, use tooling like staking-deposit-cli to generate keystores dynamically during deployment rather than committing them.
🤖 Prompt for AI Agents
In
ops/docker/layer1/keystores/layer1/keys/0x930743bfc7e18d3bd7351eaa74f477505268c1e4e1fd1ca3ccccdefb2595517343bbb8f5589c435c3c39323a4c0080f8/voting-keystore.json
(line 1), a committed encrypted keystore and accompanying plain-text password
exist in repo history and must be removed: immediately add
ops/docker/layer1/keystores/ to .gitignore and remove
ops/docker/layer1/keystores/ and ops/docker/layer1/keystores/layer1-password.txt
from the current index (git rm --cached) and then purge them from history using
git filter-repo or git filter-branch; after removal, rotate/regenerate all
compromised validator keys and passwords, stop committing keystores (generate
them at container/runtime or use staking-deposit-cli for devnet), and move any
required secrets to a proper secret manager (Vault, AWS Secrets Manager) while
ensuring any new keystores use secure KDF parameters (high iteration
count/scrypt or bcrypt) and delete any local copies of the old password file.
| @@ -0,0 +1 @@ | |||
| rzUo8KPugtBDRv84uGoultyzCdnxIViLekhy6qrZZL0= No newline at end of file | |||
There was a problem hiding this comment.
Filename extension doesn't match content format.
The file is named with a .json extension but contains plain text (a base64-encoded secret) rather than JSON format. This inconsistency could cause confusion for tooling or developers expecting JSON content.
Consider either:
- Renaming to remove the
.jsonextension - Wrapping the content in proper JSON format if required by the validator client
🤖 Prompt for AI Agents
In
ops/docker/layer1/keystores/layer1/secrets/0xabd12678c73463ecea5867a80caf256d5c5e6ba53ff188b143a4d5be83365ad257edf39eaa1ba8753c4cdf4c632ff99e
around line 1, the file is named with a .json extension but contains a plain
base64 string; either rename the file to remove the .json extension (e.g., .txt
or no extension) and update any code/config that references this path, or
convert the file content into valid JSON (for example wrap the base64 value in
an object field like {"secret":"<base64>"}), then validate the consuming
validator/client accepts the chosen format and update any references/tests
accordingly.
Avoid committing secrets to version control, even for devnet.
While this appears to be for development purposes based on the PR title, committing validator keystore passwords directly to the repository poses security risks:
- Secrets in git history are permanent and difficult to fully remove
- Risk of accidental reuse in non-development environments
- Security scanners may flag these as vulnerabilities
- Sets a precedent that could lead to production secrets being committed
Consider these alternatives:
- Generate secrets at deployment time using a script
- Use placeholder values with clear
INSECURE_DEVNET_ONLYmarkers - Document in a README that secrets should be generated locally
- Provide a secret generation script (e.g.,
openssl rand -base64 32)
🤖 Prompt for AI Agents
ops/docker/layer1/keystores/layer1/secrets/0xabd12678c73463ecea5867a80caf256d5c5e6ba53ff188b143a4d5be83365ad257edf39eaa1ba8753c4cdf4c632ff99e
lines 1-1: a private keystore password has been committed; remove the secret and
replace the file content with a clear placeholder such as
INSECURE_DEVNET_ONLY_DO_NOT_COMMIT and instructions to generate a real secret at
deploy time, add the secrets file to .gitignore, add a short README or comments
pointing to a provided secret-generation script (e.g., openssl rand -base64 32)
or environment-variable-based loading, and if this secret has already been
pushed, plan history removal (git-filter-repo or BFG) and rotate any exposed
credentials.
| @@ -0,0 +1 @@ | |||
| VMftlRJfjSD_8oc4maA_pV-IhJRyf1s2jBn_HwK3HjE= No newline at end of file | |||
There was a problem hiding this comment.
🧩 Analysis chain
Verify these are test-only credentials and document accordingly.
This file contains hardcoded cryptographic secrets for validator keystores. While this may be acceptable for devnet/development environments, ensure:
- These credentials are explicitly documented as test-only
- They are never used in production
- Consider adding a README or comment in the directory explaining these are devnet test credentials
🏁 Script executed:
#!/bin/bash
# Check if there's documentation indicating these are test/devnet credentials
echo "Checking for documentation about test credentials..."
fd -t f "README" ops/docker/layer1/keystores/
fd -t f "\.md$" ops/docker/layer1/
# Check if there's a .gitignore that might exclude these (indicating they should be generated)
echo -e "\nChecking .gitignore patterns..."
cat .gitignore 2>/dev/null | grep -i "keystore\|secret\|\.txt" || echo "No matching .gitignore patterns found"
# Check for any scripts that generate these files
echo -e "\nChecking for generation scripts..."
rg -l "generate.*keystore|create.*secret" ops/docker/layer1/scripts/Length of output: 134
I need to gather more context about the repository structure and whether this is explicitly a devnet/test environment. Let me run additional verification:The web search results don't provide specific clarity about this repository context. Let me now run the deeper repository exploration script:
</script>🏁 Script executed:
#!/bin/bash
# Get broader context about the repository
echo "=== Checking repository root documentation ==="
ls -la | grep -i "readme\|contributing\|security\|devnet\|testnet" || echo "No matching files"
echo -e "\n=== Checking for devnet indicators in directory structure ==="
find ops/ -maxdepth 2 -type d | head -20
echo -e "\n=== Checking the full keystore directory structure ==="
find ops/docker/layer1/keystores -type f | head -20
echo -e "\n=== Checking if there's any git-related documentation about these files ==="
git log --oneline -n 20 -- ops/docker/layer1/keystores/ 2>/dev/null | head -10
echo -e "\n=== Checking for any .env or config files that reference testnet ==="
fd -t f "\.(env|config)" . | head -20
echo -e "\n=== Looking for any comments or documentation in nearby files ==="
find ops/docker/layer1 -maxdepth 1 -type f -exec grep -l "test\|devnet\|credential" {} \; 2>/dev/nullLength of output: 4123
🏁 Script executed:
#!/bin/bash
# Check root-level documentation
echo "=== Root documentation files ==="
ls -la *.md *.txt *.rst 2>/dev/null | head -20
echo -e "\n=== Check git history for these files ==="
git log --oneline --all -n 5 -- ops/docker/layer1/keystores/layer1/secrets/ 2>/dev/null || echo "No git history found"
echo -e "\n=== Check directory structure context ==="
ls -la ops/docker/layer1/ 2>/dev/null | head -20
echo -e "\n=== Look for any test/devnet indicators ==="
find ops/ -maxdepth 3 -name "*.sh" -o -name "docker-compose*" | xargs grep -l "devnet\|testnet\|layer1" 2>/dev/null | head -10
echo -e "\n=== Check if there are production credentials elsewhere ==="
rg -l "keystore|secret" ops/ --type yaml --type json --type sh 2>/dev/null | head -10Length of output: 1401
🏁 Script executed:
#!/bin/bash
# Read the README to understand repository purpose
echo "=== README.md content ==="
cat README.md
echo -e "\n=== docker-compose.yml relevant sections ==="
head -50 ops/docker/layer1/docker-compose.yml
echo -e "\n=== Check for SECURITY or other doc files ==="
find . -maxdepth 1 -type f \( -name "SECURITY*" -o -name "*.md" \) 2>/dev/null
echo -e "\n=== Check layer1 .gitignore ==="
cat ops/docker/layer1/.gitignore 2>/dev/null || echo "No .gitignore found"
echo -e "\n=== Check if keystores directory has any README ==="
ls -la ops/docker/layer1/keystores/ 2>/dev/nullLength of output: 3470
🏁 Script executed:
#!/bin/bash
# Verify if keystores are actually tracked by git despite .gitignore rule
echo "=== Is the keystore file tracked by git? ==="
git ls-files ops/docker/layer1/keystores/layer1/secrets/ 2>/dev/null | head -5
echo -e "\n=== Git status of keystores directory ==="
git status ops/docker/layer1/keystores/ 2>/dev/null || echo "Directory not shown in status (likely ignored or clean)"
echo -e "\n=== Check when .gitignore was added ==="
git log -p --all -- ops/docker/layer1/.gitignore 2>/dev/null | head -30
echo -e "\n=== Check if keystores/ is mentioned in top-level .gitignore ==="
cat .gitignore 2>/dev/null | grep -i keystore || echo "Not in top-level .gitignore"Length of output: 995
Remove tracked test credentials from version control and document devnet setup process.
This file contains hardcoded validator secrets that are tracked in the repository despite the .gitignore rule at ops/docker/layer1/.gitignore. While these appear to be test credentials for a devnet Layer1 setup (based on directory structure and git history), they should not be in version control:
- Remove
ops/docker/layer1/keystores/layer1/secrets/*andlayer1-password.txtfrom git history - Add instructions to
ops/docker/layer1/README.md(create if missing) explaining how to generate these test credentials locally - Alternatively, ensure these are generated during container initialization rather than committed
Currently there is no documentation indicating these are test-only, which creates confusion about the credentials' purpose and safety.
🤖 Prompt for AI Agents
In
ops/docker/layer1/keystores/layer1/secrets/0xad9222dec71ff8ee6bc0426ffe7b5e66f96738225db281dd20027a1556d089fdebd040abfbc2041d6c1a0d8fdcfce183
(line 1), remove this tracked test credential from the repository and purge it
from git history (use git filter-repo or BFG to remove
ops/docker/layer1/keystores/layer1/secrets/* and layer1-password.txt from all
commits), update .gitignore to ensure those paths are ignored going forward, and
commit the removal; then add ops/docker/layer1/README.md explaining how to
generate devnet Layer1 keys locally or provide a script/entrypoint hook that
auto-generates these test credentials at container initialization (describe
commands, expected files, and any password handling), and finally rotate any
credentials that may have leaked in CI/dev environments.
| @@ -0,0 +1 @@ | |||
| 1y8B2Q0VKtGC71U5d4hllb7wGSmxM2T8zW_PhOuneB4= No newline at end of file | |||
There was a problem hiding this comment.
Remove committed validator secret immediately.
This file includes raw validator secret material in the repository. Publishing it breaks validator security, violates secret-management policy, and requires an immediate rotate-and-purge of the exposed credentials (including cleaning Git history and re-provisioning the validator). Please delete this artifact from the PR, reissue fresh keys off-repo (e.g., via a secure secrets store), and ensure the compromised secret is revoked before merging.
| @@ -0,0 +1 @@ | |||
| qETVYVop1wqSdueWixO_CDeb29an1pV6pkGs3T8t2oE= No newline at end of file | |||
There was a problem hiding this comment.
Do not commit validator secrets to git.
This file contains a raw validator secret. Even for devnet usage, checking real secrets into version control breaks key hygiene, violates least‑privilege expectations, and risks accidental reuse in other environments. Please drop the concrete value from the repo and replace it with a template (e.g., instructions or an env‑supplied secret) so the secret is provisioned at runtime instead of being published here.
🤖 Prompt for AI Agents
In
ops/docker/layer1/keystores/layer1/secrets/0xae940a07850cf904b44f31cbf0e44824bae5ec36dcfdb7fad858f2a39dba38de82ca12b0ae939a34fce7a02e4b9789f8
(lines 1-1), this file contains a raw validator secret committed to git; remove
the concrete secret value and replace the file with a template or placeholder
plus instructions to load the secret at runtime (e.g., via environment variable,
Docker secret, or external secret manager). Ensure the repo contains no secret
material: delete the value from history if necessary (git rm and rotate keys),
update deployment docs and compose/stack configs to reference the runtime secret
source, and add a gitignored example/template file showing how to provide the
secret without embedding it in version control.
| @@ -0,0 +1 @@ | |||
| GtHF8DbPC-1zy36sQVfRz_eEXcTphPoFcczyfPal6gQ= No newline at end of file | |||
There was a problem hiding this comment.
Do not commit validator secrets to the repository.
This file adds what appears to be a live validator keystore passphrase/secret straight into source control. Even for devnet tooling, shipping real secrets in git is a security exposure (they propagate to forks, caches, CI logs, etc.) and can be mistakenly reused in less-trusted environments. Please strip the actual secret from the repo—e.g., template the file (sample value + instructions) or have the setup scripts generate/populate it locally instead.
🤖 Prompt for AI Agents
In
ops/docker/layer1/keystores/layer1/secrets/0xafa10af166a0dbf3a25ff86cd6f8e70cd70e4e98e226b158f3563450b3fb184d2649adbb11e53080d1ca
around line 1, a real validator keystore secret was committed; remove the secret
value from the repository and replace the file with a templated/sample file
(e.g., placeholder value and usage instructions). Update repository workflow to
generate or populate the real secret locally or via a secure secret manager (or
env var) during setup, add the real-secret path to .gitignore, and add a brief
setup script or docs showing how to create/populate the real keystore. If this
secret was ever used in production or shared, rotate/revoke it immediately and
purge it from git history (use git filter-repo/BFG) to fully remove sensitive
data.
|
|
||
| layer1_dir = pjoin(paths.ops_dir, 'layer1') | ||
| genesis_dir = pjoin(layer1_dir, 'genesis') | ||
| jwt_dir = pjoin(layer1_dir, 'jwt') | ||
|
|
||
| # Check if genesis files exist, if not generate them | ||
| genesis_json = pjoin(genesis_dir, 'genesis.json') | ||
| genesis_ssz = pjoin(genesis_dir, 'genesis.ssz') | ||
| jwt_secret = pjoin(jwt_dir, 'jwtsecret') | ||
|
|
||
| if not os.path.exists(genesis_json) or not os.path.exists(genesis_ssz) or not os.path.exists(jwt_secret): | ||
| log.info('Genesis files not found, generating...') | ||
| generate_script = pjoin(layer1_dir, 'scripts', 'generate-genesis.sh') | ||
| if os.path.exists(generate_script): | ||
| run_command(['bash', generate_script], check=True, cwd=layer1_dir) | ||
| else: | ||
| log.error(f'Genesis generation script not found at {generate_script}') | ||
| raise FileNotFoundError(f'Genesis generation script not found') | ||
|
|
There was a problem hiding this comment.
Fix f-string without placeholders.
Line 93 uses an f-string prefix without any placeholders, which is unnecessary.
Apply this diff:
- raise FileNotFoundError(f'Genesis generation script not found')
+ raise FileNotFoundError('Genesis generation script not found')📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| layer1_dir = pjoin(paths.ops_dir, 'layer1') | |
| genesis_dir = pjoin(layer1_dir, 'genesis') | |
| jwt_dir = pjoin(layer1_dir, 'jwt') | |
| # Check if genesis files exist, if not generate them | |
| genesis_json = pjoin(genesis_dir, 'genesis.json') | |
| genesis_ssz = pjoin(genesis_dir, 'genesis.ssz') | |
| jwt_secret = pjoin(jwt_dir, 'jwtsecret') | |
| if not os.path.exists(genesis_json) or not os.path.exists(genesis_ssz) or not os.path.exists(jwt_secret): | |
| log.info('Genesis files not found, generating...') | |
| generate_script = pjoin(layer1_dir, 'scripts', 'generate-genesis.sh') | |
| if os.path.exists(generate_script): | |
| run_command(['bash', generate_script], check=True, cwd=layer1_dir) | |
| else: | |
| log.error(f'Genesis generation script not found at {generate_script}') | |
| raise FileNotFoundError(f'Genesis generation script not found') | |
| layer1_dir = pjoin(paths.ops_dir, 'layer1') | |
| genesis_dir = pjoin(layer1_dir, 'genesis') | |
| jwt_dir = pjoin(layer1_dir, 'jwt') | |
| # Check if genesis files exist, if not generate them | |
| genesis_json = pjoin(genesis_dir, 'genesis.json') | |
| genesis_ssz = pjoin(genesis_dir, 'genesis.ssz') | |
| jwt_secret = pjoin(jwt_dir, 'jwtsecret') | |
| if not os.path.exists(genesis_json) or not os.path.exists(genesis_ssz) or not os.path.exists(jwt_secret): | |
| log.info('Genesis files not found, generating...') | |
| generate_script = pjoin(layer1_dir, 'scripts', 'generate-genesis.sh') | |
| if os.path.exists(generate_script): | |
| run_command(['bash', generate_script], check=True, cwd=layer1_dir) | |
| else: | |
| log.error(f'Genesis generation script not found at {generate_script}') | |
| raise FileNotFoundError('Genesis generation script not found') |
🧰 Tools
🪛 Ruff (0.14.3)
93-93: Avoid specifying long messages outside the exception class
(TRY003)
93-93: f-string without any placeholders
Remove extraneous f prefix
(F541)
🤖 Prompt for AI Agents
In ops/devnet-morph/devnet/__init__.py around lines 76-94, there's an
unnecessary f-string used on the FileNotFoundError raise (line ~93) that has no
placeholders; change the raise to use a normal string literal (remove the
leading 'f') or alternatively include the missing placeholder (e.g., the
generate_script path) if you intended to show it—update the raise to either
raise FileNotFoundError('Genesis generation script not found') or raise
FileNotFoundError(f'Genesis generation script not found at {generate_script}')
so the f-string usage is either removed or actually contains a placeholder.
| image: gcr.io/prysmaticlabs/prysm/validator:v4.2.1 | ||
| # ========== Layer1 Ethereum Node ========== | ||
| layer1-el: | ||
| image: ethereum/client-go:latest |
There was a problem hiding this comment.
Pin Docker image versions for reproducibility and security.
All layer1 services use latest tags (layer1-el: ethereum/client-go:latest, layer1-cl: sigp/lighthouse:latest, layer1-vc: sigp/lighthouse:latest). Using latest is not reproducible across deployments and poses security risks.
Specify explicit version tags for all images. For example:
- image: ethereum/client-go:latest
+ image: ethereum/client-go:v1.13.0- image: sigp/lighthouse:latest
+ image: sigp/lighthouse:v4.5.0Please consult your project's versioning strategy to determine appropriate versions.
Also applies to: 50-50, 93-93
🤖 Prompt for AI Agents
In ops/docker/docker-compose-4nodes.yml around line 26 (and similarly at lines
50 and 93), the Compose services use the insecure, non-reproducible image tag
"latest"; change each image to an explicit, pinned version tag (e.g.,
ethereum/client-go:<specific-version>, sigp/lighthouse:<specific-version>)
according to our project's versioning policy, update the image fields for
layer1-el, layer1-cl, and layer1-vc to those exact tags, and if needed add an
image digest or comment documenting the chosen versions for future
reproducibility.
| - --disable-packet-filter | ||
| - --execution-endpoints=http://layer1-el:8551 | ||
| - --jwt-secrets=/jwt/jwtsecret | ||
| - --suggested-fee-recipient=0x8943545177806ED17B9F23F0a21ee5948eCaa776 |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
Externalize hardcoded fee recipient address.
The suggested fee recipient 0x8943545177806ED17B9F23F0a21ee5948eCaa776 is hardcoded in both layer1-cl (line 77) and layer1-vc (line 110). This should be configurable via environment variables for flexibility and to avoid duplication.
Define the fee recipient as an environment variable in your .env file (e.g., L1_FEE_RECIPIENT=0x8943545177806ED17B9F23F0a21ee5948eCaa776), then reference it in both services:
- - --suggested-fee-recipient=0x8943545177806ED17B9F23F0a21ee5948eCaa776
+ - --suggested-fee-recipient=${L1_FEE_RECIPIENT}Apply this change to both layer1-cl (line 77) and layer1-vc (line 110).
Also applies to: 110-110
🤖 Prompt for AI Agents
In ops/docker/docker-compose-4nodes.yml around lines 77 and 110, the suggested
fee recipient is hardcoded; remove the literal
0x8943545177806ED17B9F23F0a21ee5948eCaa776 and instead reference an environment
variable (e.g., L1_FEE_RECIPIENT) for both layer1-cl (line 77) and layer1-vc
(line 110); add L1_FEE_RECIPIENT to your .env file (with the current address as
default), ensure the compose file loads that .env (or an env_file) and replace
the flag values with the environment variable reference for both services so
they share the same configurable value.
| export PRESET_BASE=minimal | ||
| export CHAIN_ID=900 | ||
| export DEPOSIT_CONTRACT_ADDRESS=0x00000000219ab540356cBB839Cbe05303d7705Fa | ||
| export EL_AND_CL_MNEMONIC="giant issue aisle success illegal bike spike question tent bar rely arctic volcano long crawl hungry vocal artwork sniff fantasy very lucky have athlete" |
There was a problem hiding this comment.
Hardcoded mnemonic phrase in configuration template.
The mnemonic EL_AND_CL_MNEMONIC is hardcoded in this template. This is a critical security concern if:
- This mnemonic is used anywhere beyond local devnet
- Accounts derived from this mnemonic receive real value
- This template is copied without modification for other environments
Ensure this is clearly documented as a devnet-only mnemonic and add warnings in comments or documentation that this must be changed for any non-local deployment.
🤖 Prompt for AI Agents
In ops/docker/layer1/configs/values.env.template around line 4, the
EL_AND_CL_MNEMONIC is hardcoded — replace this literal mnemonic with a clear
placeholder (e.g., EL_AND_CL_MNEMONIC="<REPLACE_WITH_DEVNET_MNEMONIC>") and add
an inline comment above it stating this value is for local devnet only and must
be replaced for any non-local or production environment; additionally, update
repository docs/README to warn against committing real mnemonics, recommend
using environment-specific secret management (env vars, key vaults, or .env
excluded from VCS), and provide steps to generate or supply a secure mnemonic
for other environments.
| # Note: Kurtosis executes "geth init && geth run" in the same container | ||
| # with datadir=/data/geth/execution-data | ||
| layer1-el: | ||
| image: ethereum/client-go:latest |
There was a problem hiding this comment.
Pin Docker image versions for reproducibility and security.
All layer1 services use latest tags. Using latest is not reproducible across deployments and poses security risks.
Specify explicit version tags for all images:
- image: ethereum/client-go:latest
+ image: ethereum/client-go:v1.13.0- image: sigp/lighthouse:latest
+ image: sigp/lighthouse:v4.5.0Ensure the version tags are consistent across both ops/docker/docker-compose-4nodes.yml and ops/docker/layer1/docker-compose.yml.
Also applies to: 36-36, 81-81
🤖 Prompt for AI Agents
In ops/docker/layer1/docker-compose.yml around lines 8, 36 and 81, replace all
image tags currently set to "latest" with explicit, fixed version tags (use the
specific tested client-go/Geth version your CI or deploys expect), and ensure
the same explicit tags are applied identically in
ops/docker/docker-compose-4nodes.yml; update the three lines to reference the
chosen semantic version (not “latest”), commit both files so deployments are
reproducible and consistent across environments.
| - --disable-packet-filter | ||
| - --execution-endpoints=http://layer1-el:8551 | ||
| - --jwt-secrets=/jwt/jwtsecret | ||
| - --suggested-fee-recipient=0x8943545177806ED17B9F23F0a21ee5948eCaa776 |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
Externalize hardcoded fee recipient address.
The suggested fee recipient 0x8943545177806ED17B9F23F0a21ee5948eCaa776 is hardcoded in both layer1-cl (line 65) and layer1-vc (line 100). This should be configurable via environment variables (same issue as in docker-compose-4nodes.yml).
Define the fee recipient as an environment variable and reference it in both services:
- - --suggested-fee-recipient=0x8943545177806ED17B9F23F0a21ee5948eCaa776
+ - --suggested-fee-recipient=${L1_FEE_RECIPIENT}Apply this change to both layer1-cl (line 65) and layer1-vc (line 100).
Also applies to: 100-100
🤖 Prompt for AI Agents
In ops/docker/layer1/docker-compose.yml around lines 65 and 100, the suggested
fee recipient address is hardcoded; make it configurable by adding an
environment variable (e.g. FEE_RECIPIENT) in the compose file’s top-level or
each service env block and replace the literal
--suggested-fee-recipient=0x8943... occurrences with a reference to that
variable (e.g. --suggested-fee-recipient=${FEE_RECIPIENT}); ensure both
layer1-cl (line 65) and layer1-vc (line 100) use the same env var and update any
.env or documentation to include the new FEE_RECIPIENT entry.
| @@ -0,0 +1 @@ | |||
| {"crypto":{"kdf":{"function":"pbkdf2","params":{"dklen":32,"c":2,"prf":"hmac-sha256","salt":"22c551538a5126f6d8acdfcc7ce8da3e1f31dd3bc6bb18b311c4ebe612cd6953"},"message":""},"checksum":{"function":"sha256","params":{},"message":"b1598d17ff4307d245c8c078e1c150f45e36284ac8a412699530cf02ecc4e513"},"cipher":{"function":"aes-128-ctr","params":{"iv":"657cdbcafd3cb6ab495d90916a42e09c"},"message":"24f00f8db95ccddb572a01c0645227a8d5d314a615904fd6d041428c94b83af7"}},"description":"0x8a8bb292bcc481070d3afdbbc8789e2ab4b29c9603936e6d85f5ff71e23fc5b6d61009f0fa636b5d5b2dc309d39e3d75","pubkey":"8a8bb292bcc481070d3afdbbc8789e2ab4b29c9603936e6d85f5ff71e23fc5b6d61009f0fa636b5d5b2dc309d39e3d75","path":"","uuid":"38b7eba0-0c08-4b88-a6eb-8a6b8ebcc871","version":4} No newline at end of file | |||
There was a problem hiding this comment.
Minor: Add trailing newline to keystore JSON.
POSIX text files should end with a newline character. While functionally correct, this will trigger Git warnings and violates file format standards.
Apply this diff to add a trailing newline:
-{"crypto":{"kdf":{"function":"pbkdf2","params":{"dklen":32,"c":2,"prf":"hmac-sha256","salt":"22c551538a5126f6d8acdfcc7ce8da3e1f31dd3bc6bb18b311c4ebe612cd6953"},"message":""},"checksum":{"function":"sha256","params":{},"message":"b1598d17ff4307d245c8c078e1c150f45e36284ac8a412699530cf02ecc4e513"},"cipher":{"function":"aes-128-ctr","params":{"iv":"657cdbcafd3cb6ab495d90916a42e09c"},"message":"24f00f8db95ccddb572a01c0645227a8d5d314a615904fd6d041428c94b83af7"}},"description":"0x8a8bb292bcc481070d3afdbbc8789e2ab4b29c9603936e6d85f5ff71e23fc5b6d61009f0fa636b5d5b2dc309d39e3d75","pubkey":"8a8bb292bcc481070d3afdbbc8789e2ab4b29c9603936e6d85f5ff71e23fc5b6d61009f0fa636b5d5b2dc309d39e3d75","path":"","uuid":"38b7eba0-0c08-4b88-a6eb-8a6b8ebcc871","version":4}
+{"crypto":{"kdf":{"function":"pbkdf2","params":{"dklen":32,"c":2,"prf":"hmac-sha256","salt":"22c551538a5126f6d8acdfcc7ce8da3e1f31dd3bc6bb18b311c4ebe612cd6953"},"message":""},"checksum":{"function":"sha256","params":{},"message":"b1598d17ff4307d245c8c078e1c150f45e36284ac8a412699530cf02ecc4e513"},"cipher":{"function":"aes-128-ctr","params":{"iv":"657cdbcafd3cb6ab495d90916a42e09c"},"message":"24f00f8db95ccddb572a01c0645227a8d5d314a615904fd6d041428c94b83af7"}},"description":"0x8a8bb292bcc481070d3afdbbc8789e2ab4b29c9603936e6d85f5ff71e23fc5b6d61009f0fa636b5d5b2dc309d39e3d75","pubkey":"8a8bb292bcc481070d3afdbbc8789e2ab4b29c9603936e6d85f5ff71e23fc5b6d61009f0fa636b5d5b2dc309d39e3d75","path":"","uuid":"38b7eba0-0c08-4b88-a6eb-8a6b8ebcc871","version":4}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| {"crypto":{"kdf":{"function":"pbkdf2","params":{"dklen":32,"c":2,"prf":"hmac-sha256","salt":"22c551538a5126f6d8acdfcc7ce8da3e1f31dd3bc6bb18b311c4ebe612cd6953"},"message":""},"checksum":{"function":"sha256","params":{},"message":"b1598d17ff4307d245c8c078e1c150f45e36284ac8a412699530cf02ecc4e513"},"cipher":{"function":"aes-128-ctr","params":{"iv":"657cdbcafd3cb6ab495d90916a42e09c"},"message":"24f00f8db95ccddb572a01c0645227a8d5d314a615904fd6d041428c94b83af7"}},"description":"0x8a8bb292bcc481070d3afdbbc8789e2ab4b29c9603936e6d85f5ff71e23fc5b6d61009f0fa636b5d5b2dc309d39e3d75","pubkey":"8a8bb292bcc481070d3afdbbc8789e2ab4b29c9603936e6d85f5ff71e23fc5b6d61009f0fa636b5d5b2dc309d39e3d75","path":"","uuid":"38b7eba0-0c08-4b88-a6eb-8a6b8ebcc871","version":4} | |
| {"crypto":{"kdf":{"function":"pbkdf2","params":{"dklen":32,"c":2,"prf":"hmac-sha256","salt":"22c551538a5126f6d8acdfcc7ce8da3e1f31dd3bc6bb18b311c4ebe612cd6953"},"message":""},"checksum":{"function":"sha256","params":{},"message":"b1598d17ff4307d245c8c078e1c150f45e36284ac8a412699530cf02ecc4e513"},"cipher":{"function":"aes-128-ctr","params":{"iv":"657cdbcafd3cb6ab495d90916a42e09c"},"message":"24f00f8db95ccddb572a01c0645227a8d5d314a615904fd6d041428c94b83af7"}},"description":"0x8a8bb292bcc481070d3afdbbc8789e2ab4b29c9603936e6d85f5ff71e23fc5b6d61009f0fa636b5d5b2dc309d39e3d75","pubkey":"8a8bb292bcc481070d3afdbbc8789e2ab4b29c9603936e6d85f5ff71e23fc5b6d61009f0fa636b5d5b2dc309d39e3d75","path":"","uuid":"38b7eba0-0c08-4b88-a6eb-8a6b8ebcc871","version":4} |
🤖 Prompt for AI Agents
ops/docker/layer1/keystores/layer1/keys/0x8a8bb292bcc481070d3afdbbc8789e2ab4b29c9603936e6d85f5ff71e23fc5b6d61009f0fa636b5d5b2dc309d39e3d75/voting-keystore.json
lines 1-1: the file is missing a trailing newline which triggers Git/POSIX
warnings; open the JSON file and add a single '\n' at the end of the file
(ensure no other changes to content or whitespace), save and commit so the file
ends with a newline character.
🧩 Analysis chain
SECURITY: Do not commit validator keystores to version control.
Even for devnet/testnet environments, committing encrypted keystores to Git poses significant security risks. Once in Git history, the keystores remain accessible even if later deleted. If the repository is ever exposed or access is compromised, keystores are available for offline brute-force attacks.
Recommended approach:
- Add keystores directory to
.gitignore - Generate keystores dynamically at deployment time or provide them via secure secrets management (environment variables, encrypted vaults, Kubernetes secrets, etc.)
- Document the process for developers to generate their own keystores locally without committing them
Please verify:
- Is there a
.gitignorerule protecting keystore files/directories? - What is the intended secrets management strategy for this devnet setup?
- Are these non-production/throwaway keys created specifically for development?
🏁 Script executed:
#!/bin/bash
# Check for .gitignore rules and keystores directory structure
echo "=== .gitignore files and content ==="
fd -t f '.gitignore' | head -5 | xargs -I {} sh -c 'echo "File: {}"; cat "{}"'
echo ""
echo "=== Keystores directory structure ==="
fd -t f 'voting-keystore.json' -o -t d 'keystores' | head -20
echo ""
echo "=== Check for secrets or deployment documentation ==="
fd -t f '(README|DEPLOY|SECRET|CONFIG|docs)' -e md -e txt -e yml -e yaml | grep -iE '(secret|key|deploy|config)' | head -10Length of output: 383
🏁 Script executed:
#!/bin/bash
# Count keystore files and check project structure
echo "=== Count of voting-keystore.json files ==="
fd -t f 'voting-keystore.json' | wc -l
echo ""
echo "=== Sample of keystore file paths ==="
fd -t f 'voting-keystore.json' | head -5
echo ""
echo "=== Check for trailing newline in the specific file ==="
KEYSTORE_FILE="ops/docker/layer1/keystores/layer1/keys/0x8a8bb292bcc481070d3afdbbc8789e2ab4b29c9603936e6d85f5ff71e23fc5b6d61009f0fa636b5d5b2dc309d39e3d75/voting-keystore.json"
if [ -f "$KEYSTORE_FILE" ]; then
if [ -z "$(tail -c 1 "$KEYSTORE_FILE")" ]; then
echo "File HAS trailing newline"
else
echo "File MISSING trailing newline"
fi
else
echo "File not found: $KEYSTORE_FILE"
fiLength of output: 171
🏁 Script executed:
#!/bin/bash
# Look for deployment, secrets, or key management documentation
echo "=== Searching for deployment/secrets related files ==="
fd -t f . ops/docker | grep -iE '(readme|doc|deploy|secret|compose|dockerfile)' | head -15
echo ""
echo "=== Check docker-compose or deployment scripts ==="
fd -t f '(docker-compose|Dockerfile|entrypoint)' | xargs -I {} sh -c 'echo "=== File: {} ==="; head -20 "{}"' 2>/dev/null | head -60Length of output: 2151
🏁 Script executed:
#!/bin/bash
# Search for comments or docs about key management
echo "=== Search for key/secret management references ==="
rg -i '(keystore|secret|vault|env.*key|key.*management)' --type md --type txt --type yaml --max-count=3 -C 2 | head -50Length of output: 4198
🌐 Web query:
What are the recommended KDF parameters for EIP-2335 Ethereum validator keystores?
💡 Result:
Recommended/commonly used KDF parameters for EIP‑2335 validator keystores:
- scrypt (default used by the deposit CLI): dklen=32, n=262144, r=8, p=1. [1][2]
- PBKDF2‑HMAC‑SHA256 (optional): dklen=32, c (iterations)=262144, prf="hmac‑sha256". [1][2]
(See EIP‑2335 for the keystore format and the staking-deposit-cli documentation/examples for the practical defaults above.) [1][2]
Sources:
[1] EIP‑2335 spec (keystore/KDF module).
[2] staking-deposit-cli / deposit‑cli keystore documentation and examples.
CRITICAL: Do not commit validator keystores to version control, and regenerate with correct KDF parameters.
Adding keystores to Git permanently compromises security. Once in history, they remain accessible even if deleted. Additionally, the keystore uses dangerously weak KDF parameters (c=2 iterations vs. c=262144 required by EIP-2335), making it vulnerable to brute-force attacks.
Required actions:
- Remove this keystore file from the commit
- Add
ops/docker/layer1/keystores/to.gitignore - Regenerate keystores using a proper EIP-2335 compliant tool (e.g., staking-deposit-cli) with correct PBKDF2 parameters (c=262144)
- Document the secure process for developers to generate keystores locally without committing them
- Fix missing trailing newline if file is retained
Alternative: Mount keystores via secrets management (environment variables, encrypted vaults, or Kubernetes secrets) instead of local files.
There was a problem hiding this comment.
Actionable comments posted: 0
♻️ Duplicate comments (2)
ops/docker/docker-compose-4nodes.yml (2)
26-26: [DUPLICATE] Pin Docker image versions for reproducibility and security.As flagged in earlier review(s), all three layer1 services use
latesttags (ethereum/client-go:latest,sigp/lighthouse:latest). This is not reproducible across deployments and poses security risks. Specify explicit version tags according to your project's versioning strategy (e.g.,ethereum/client-go:v1.13.0,sigp/lighthouse:v4.5.0).Also applies to: 50-50, 93-93
78-78: [DUPLICATE] Externalize hardcoded fee recipient address.As flagged in earlier review(s), the suggested fee recipient
0x8943545177806ED17B9F23F0a21ee5948eCaa776is hardcoded in both layer1-cl (line 78) and layer1-vc (line 110). This should be configurable via environment variables to avoid duplication and improve maintainability.Define
L1_FEE_RECIPIENTin your.envfile, then reference it in both services:- - --suggested-fee-recipient=0x8943545177806ED17B9F23F0a21ee5948eCaa776 + - --suggested-fee-recipient=${L1_FEE_RECIPIENT}Also applies to: 110-110
🧹 Nitpick comments (1)
ops/docker/docker-compose-4nodes.yml (1)
52-53: Inconsistentdepends_onusage between Layer1 and L2 services.layer1-cl (line 52) and layer1-vc (line 96) use simple dependency lists, whereas morph-geth-0 (line 121) uses the condition-based format (
service_started). This inconsistency may leave dependent services vulnerable to race conditions if they attempt to connect before upstream services are fully ready.For consistency and reliability, consider adding conditions to all
depends_onblocks:layer1-cl: ... depends_on: - - layer1-el + layer1-el: + condition: service_startedlayer1-vc: ... depends_on: - - layer1-cl + layer1-cl: + condition: service_startedAlso applies to: 96-97
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
ops/docker/docker-compose-4nodes.yml(2 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: Analyze (rust)
- GitHub Check: Analyze (go)
🔇 Additional comments (3)
ops/docker/docker-compose-4nodes.yml (3)
19-21: New Layer1 volumes defined.The addition of dedicated volumes for Layer1 services follows good Docker practices. These persistent volumes ensure data survives container restarts.
25-48: layer1-el execution service setup looks solid.The geth initialization is idempotent—checking for an existing chaindata before initializing genesis is a good safeguard against unnecessary reinitializations on container restarts. Command-line flags (RPC APIs, metrics, etc.) are well-configured for a devnet environment.
121-123: Layer1 dependency on morph-geth-0 established correctly.The update to morph-geth-0's
depends_onblock now correctly references layer1-el with aservice_startedcondition. This ensures the Layer1 execution layer is available before L2 geth starts.
Summary by CodeRabbit
New Features
Chores