-
Notifications
You must be signed in to change notification settings - Fork 168
feat: add an option to create zetaclient dry node for tesntet/mainnet #4453
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
| GitGuardian id | GitGuardian status | Secret | Commit | Filename | |
|---|---|---|---|---|---|
| 22859303 | Triggered | Generic High Entropy Secret | 23c4b44 | contrib/localnet/zetaclientd/dry-zetaclient/zetaclient_config.json | View secret |
🛠 Guidelines to remediate hardcoded secrets
- Understand the implications of revoking this secret by investigating where it is used in your code.
- Replace and store your secret safely. Learn here the best practices.
- Revoke and rotate this secret.
- If possible, rewrite git history. Rewriting git history is not a trivial act. You might completely break other contributing developers' workflow and you risk accidentally deleting legitimate data.
To avoid such incidents in the future consider
- following these best practices for managing and storing secrets including API keys and other credentials
- install secret detection on pre-commit to catch secret before it leaves your machine and ease remediation.
🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.
|
Important Review skippedAuto incremental reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the You can disable this status message by setting the Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. 📝 WalkthroughWalkthroughThis PR introduces infrastructure to support dry-run ZetaClient testing against live testnet and mainnet networks. It adds three new Python orchestration scripts for snapshot management, zetaclient dry-mode startup, and live node initialization, updates Docker configuration to include testnet and mainnet node services, modifies the Makefile with new build targets and conditional variables, and removes the legacy devnet snapshot script. Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Areas requiring additional attention:
Pre-merge checks and finishing touches❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
🧹 Nitpick comments (12)
contrib/localnet/orchestrator/start-zetae2e.sh (1)
230-230: Consider moving hardcoded address to configuration.This address deviates from the pattern established by other funding calls in this script, which use
fund_eth_from_configto read addresses fromconfig.yml. Hardcoding the zetaclient dry hotkey address reduces maintainability and introduces inconsistency.Consider adding the dry hotkey address to
config.ymland using:-fund_eth "0x8E3C1898776e80A19a37546920AcE1935cCEE08E" "10000" "zetaclient dry hotkey" +fund_eth_from_config '.additional_accounts.zetaclient_dry_hotkey.evm_address' 10000 "zetaclient dry hotkey"contrib/localnet/scripts_python/start-zetacored-livenode.py (2)
30-36: Improve error handling in helper functions.The
run()function returns a boolean indicating success, but the return value is ignored by most callers (e.g., lines 42, 60, 61, 66, 67). This could mask failures during node initialization or snapshot setup.Either consistently check return values or let the exception propagate:
def run(cmd, check=True): - return subprocess.run(cmd, shell=True, check=check).returncode == 0 + result = subprocess.run(cmd, shell=True, check=check) + if check and result.returncode != 0: + sys.exit(1) + return result.returncode == 0
76-96: External IP lookup lacks timeout and robust error handling.The
curlcommand toicanhazip.commay hang or fail in isolated network environments. While there is a fallback to127.0.0.1, consider adding a timeout to prevent indefinite blocking.- ip = subprocess.run("curl -4 -s icanhazip.com", shell=True, capture_output=True, text=True) + ip = subprocess.run("curl -4 -s --connect-timeout 5 icanhazip.com", shell=True, capture_output=True, text=True)contrib/localnet/scripts_python/download_snapshot.py (3)
63-71: Large file downloads lack progress indication and read timeout.Snapshot files can be several gigabytes. Without progress indication, users may assume the script has hung. Additionally, the timeout parameter only covers connection establishment, not the entire read operation.
Consider adding a progress indicator and explicit read timeout:
def download_file(url, dest_path): """Download file with progress indication.""" response = requests.get(url, stream=True, timeout=(30, 300)) # (connect, read) response.raise_for_status() total_size = int(response.headers.get('content-length', 0)) downloaded = 0 with open(dest_path, 'wb') as f: for chunk in response.iter_content(chunk_size=8192 * 128): if chunk: f.write(chunk) downloaded += len(chunk) if total_size: pct = (downloaded / total_size) * 100 print(f"\r Progress: {pct:.1f}%", end="", flush=True) if total_size: print() # newline after progress
76-82: Remove extraneous f-string prefixes.Lines 76 and 82 use f-strings without any placeholder variables.
def extract_archive(archive_path, dest_dir): """Extract lz4 archive.""" - print(f" Extracting archive...") + print(" Extracting archive...") subprocess.run( f'lz4 -dc "{archive_path}" | tar -C "{dest_dir}/" -xf -', shell=True, check=True ) - print(f" Extraction complete.") + print(" Extraction complete.")
151-160: Consider using more specific exception handling.Catching a broad
Exceptioncan mask unexpected errors and make debugging difficult.try: snapshot_json = requests.get(snapshot_url, timeout=30).json() snapshot_data = snapshot_json['snapshots'][0] snapshot_link = snapshot_data['link'] snapshot_filename = snapshot_data['filename'] expected_md5 = snapshot_data.get('checksums', {}).get('md5') print(f" Snapshot: {snapshot_filename}") - except Exception as e: + except (requests.RequestException, KeyError, IndexError) as e: print(f" Error fetching snapshot info: {e}") sys.exit(1)contrib/localnet/scripts_python/start-zetaclient-dry.py (3)
141-144: Remove unused exception variable.The variable
eis captured but never used. Replace with anonymous capture for clarity.- except subprocess.CalledProcessError as e: + except subprocess.CalledProcessError: if check: raise return None
147-175: Consider adding a timeout or maximum retry count.This infinite loop will block indefinitely if
zetacorenever becomes available. While acceptable for interactive local development, adding a configurable timeout (e.g., via environment variable) would improve debuggability and prevent CI hangs.Additionally, logging caught exceptions rather than silently passing would aid troubleshooting.
280-298: Infinite polling loop without timeout.Same concern as
wait_for_zetacore: this could hang indefinitely. Consider extracting a common retry utility with configurable timeout.contrib/localnet/docker-compose.yml (2)
271-300: Missing profile may cause unintended startup.The
testnet-nodeservice has noprofilesdefined, meaning it will start with anydocker compose upcommand in this directory. Other optional services likezetaclient-dryuse profiles to prevent accidental startup.Consider adding a profile to align with other optional services:
testnet-node: image: zetanode:latest container_name: testnet-node hostname: testnet-node + profiles: + - testnet + - all entrypoint: python3 -u /root/start-zetacored-livenode.py
302-331: Same profile concern applies to mainnet-node.Like
testnet-node, this service lacks a profile definition. Consider adding amainnetprofile for consistency.mainnet-node: image: zetanode:latest container_name: mainnet-node hostname: mainnet-node + profiles: + - mainnet + - all entrypoint: python3 -u /root/start-zetacored-livenode.pyMakefile (1)
626-628: Missing zetanode image dependency.The
zetaclient-drytarget assumes azetanode:latestimage exists but does not build it. If invoked standalone without first runningtestnet-nodeormainnet-node, this will fail.Consider either adding a dependency or documenting the prerequisite:
# Start dry run zetaclientd in dry mode zetaclient-dry: + @$(MAKE) zetanode cd contrib/localnet/ && ZETACORE_HOST=$(ZETACORE_HOST) $(DOCKER) compose -p localnet -f docker-compose.yml up -d zetaclient-dryAlternatively, document in the target comment that
zetanodeimage must exist.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (9)
Dockerfile-localnet(2 hunks)Makefile(4 hunks)changelog.md(1 hunks)contrib/devnet/download_snapshot.py(0 hunks)contrib/localnet/docker-compose.yml(2 hunks)contrib/localnet/orchestrator/start-zetae2e.sh(1 hunks)contrib/localnet/scripts_python/download_snapshot.py(1 hunks)contrib/localnet/scripts_python/start-zetaclient-dry.py(1 hunks)contrib/localnet/scripts_python/start-zetacored-livenode.py(1 hunks)
💤 Files with no reviewable changes (1)
- contrib/devnet/download_snapshot.py
🧰 Additional context used
📓 Path-based instructions (1)
**/*.sh
⚙️ CodeRabbit configuration file
Review the shell scripts, point out issues relative to security, performance, and maintainability.
Files:
contrib/localnet/orchestrator/start-zetae2e.sh
🧠 Learnings (5)
📚 Learning: 2024-11-27T22:01:49.732Z
Learnt from: gartnera
Repo: zeta-chain/node PR: 3228
File: zetaclient/orchestrator/orchestrator.go:388-401
Timestamp: 2024-11-27T22:01:49.732Z
Learning: When reviewing code changes in `zetaclient/orchestrator/orchestrator.go`, avoid suggesting refactoring that is unrelated to the current PR.
Applied to files:
contrib/localnet/orchestrator/start-zetae2e.sh
📚 Learning: 2024-11-27T22:02:48.034Z
Learnt from: gartnera
Repo: zeta-chain/node PR: 3228
File: cmd/zetaclientd/start.go:222-231
Timestamp: 2024-11-27T22:02:48.034Z
Learning: In the `zetaclient` codebase, port numbers like `26657` are hardcoded, and changing them to be configurable via the config struct is considered unrelated refactoring.
Applied to files:
changelog.md
📚 Learning: 2025-05-30T16:31:30.275Z
Learnt from: skosito
Repo: zeta-chain/node PR: 3939
File: go.mod:52-52
Timestamp: 2025-05-30T16:31:30.275Z
Learning: The ethermint dependency updates in the zeta-chain/node repository are typically moves between feature branches and main branch of the same fork, not breaking API changes. CI status should be verified before assuming compilation issues.
Applied to files:
changelog.md
📚 Learning: 2024-07-11T13:10:39.153Z
Learnt from: lumtis
Repo: zeta-chain/node PR: 2459
File: e2e/config/config.go:285-293
Timestamp: 2024-07-11T13:10:39.153Z
Learning: Tests should not be suggested in the `e2e` package for the `zeta-chain/node` repository.
Applied to files:
changelog.md
📚 Learning: 2025-09-21T17:54:21.110Z
Learnt from: kingpinXD
Repo: zeta-chain/node PR: 4225
File: Makefile:383-385
Timestamp: 2025-09-21T17:54:21.110Z
Learning: In upgrade tests, docker-compose-upgrade.yml is used specifically to build older versions of zetacored and zetaclientd, while docker-compose.yml handles the newer version configuration. Environment variables like USE_ZETAE2E_ANTE are intended for the newer version and don't need to be propagated to the upgrade compose file.
Applied to files:
contrib/localnet/docker-compose.ymlMakefile
🧬 Code graph analysis (3)
contrib/localnet/scripts_python/start-zetacored-livenode.py (1)
contrib/localnet/scripts_python/download_snapshot.py (1)
main(122-212)
contrib/localnet/scripts_python/download_snapshot.py (2)
contrib/localnet/scripts_python/start-zetaclient-dry.py (2)
run_command(130-144)main(311-329)contrib/localnet/scripts_python/start-zetacored-livenode.py (2)
run(30-31)main(99-111)
contrib/localnet/scripts_python/start-zetaclient-dry.py (1)
contrib/localnet/scripts_python/start-zetacored-livenode.py (2)
run(30-31)main(99-111)
🪛 Ruff (0.14.6)
contrib/localnet/scripts_python/start-zetacored-livenode.py
1-1: Shebang is present but file is not executable
(EXE001)
31-31: subprocess call with shell=True identified, security issue
(S602)
35-35: subprocess call with shell=True identified, security issue
(S602)
77-77: subprocess call with shell=True seems safe, but may be changed in the future; consider rewriting without shell
(S602)
77-77: Starting a process with a partial executable path
(S607)
111-111: Starting a process without a shell
(S606)
contrib/localnet/scripts_python/download_snapshot.py
56-56: subprocess call: check for execution of untrusted input
(S603)
76-76: f-string without any placeholders
Remove extraneous f prefix
(F541)
77-77: subprocess call with shell=True identified, security issue
(S602)
82-82: f-string without any placeholders
Remove extraneous f prefix
(F541)
87-87: Probable use of insecure hash functions in hashlib: md5
(S324)
158-158: Do not catch blind exception: Exception
(BLE001)
169-169: Do not catch blind exception: Exception
(BLE001)
contrib/localnet/scripts_python/start-zetaclient-dry.py
1-1: Shebang is present but file is not executable
(EXE001)
110-110: Consider moving this statement to an else block
(TRY300)
132-132: subprocess call with shell=True identified, security issue
(S602)
141-141: Local variable e is assigned to but never used
Remove assignment to unused variable e
(F841)
153-153: subprocess call with shell=True identified, security issue
(S602)
171-172: try-except-pass detected, consider logging the exception
(S110)
171-171: Do not catch blind exception: Exception
(BLE001)
191-192: try-except-pass detected, consider logging the exception
(S110)
191-191: Do not catch blind exception: Exception
(BLE001)
265-265: Avoid specifying long messages outside the exception class
(TRY003)
270-270: Avoid specifying long messages outside the exception class
(TRY003)
305-305: Starting a process without a shell
(S606)
306-306: Starting a process with a partial executable path
(S607)
⏰ 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). (1)
- GitHub Check: Cursor Bugbot
🔇 Additional comments (15)
changelog.md (1)
7-8: LGTM!The changelog entry is correctly formatted and appropriately placed under the Unreleased/Features section.
Dockerfile-localnet (2)
37-37: LGTM!The additional packages (
wget,lz4,python3-requests) are required dependencies for the new snapshot download functionality.
57-60: LGTM!Appropriate additions for copying the snapshot download script and setting executable permissions for both shell and Python scripts.
contrib/localnet/scripts_python/start-zetaclient-dry.py (6)
37-39: Security: Hardcoded mnemonic exposed in source code.This mnemonic is committed to the repository and grants control over address
zeta13c7p3xrhd6q2rx3h235jpt8pjdwvacyw6twpax. While this appears intended for dry/read-only mode testing, hardcoding secrets in source is a security anti-pattern.Confirm this key holds no real value and is exclusively for local testing. Consider documenting this explicitly or sourcing from an environment variable for production-like deployments.
104-112: LGTM!The socket-based port checking logic is correct. The socket is properly closed before returning the result.
253-257: Mnemonic visible in process list during key import.The mnemonic is passed via shell command, making it briefly visible in the process table. For a dry-mode test key with no real value, this is acceptable. For production scenarios, consider using
input_dataparameter instead.
301-308: LGTM!Using
os.execlpto replace the Python process withzetaclientdis the correct pattern for container entrypoints. The password file approach aligns with other zetaclient startup scripts.
311-329: LGTM!The orchestration flow is well-structured with clear sequential steps: validate environment, wait for dependencies, configure, and start. The ordering ensures proper initialization.
66-92: Public RPC endpoints may have rate limits.The testnet and mainnet configurations use public RPC endpoints from services like
publicnode.comandblastapi.io. These typically have rate limits. For sustained dry-mode operation, consider documenting this limitation or providing a mechanism to override endpoints via environment variables.contrib/localnet/docker-compose.yml (2)
257-269: LGTM!The
zetaclient-dryservice configuration correctly:
- Uses the new Python entrypoint
- Passes
ZETACORE_HOSTwith a sensible default- Mounts the script as read-only
635-636: LGTM!The new volumes for testnet and mainnet data persistence are correctly defined.
Makefile (4)
4-4: LGTM!Changing
NODE_VERSIONto use conditional assignment (?=) allows external override, which is essential for the new node targets that need to build withOLD_VERSION.
590-602: LGTM!The mainnet node targets correctly:
- Build
zetanodewithOLD_VERSIONto match production- Use explicit project name
-p localnetfor isolation- Provide force-download variant for snapshot refresh
608-620: LGTM!The testnet node targets mirror the mainnet structure appropriately.
164-166: LGTM!The
download-snapshottarget correctly references the new Python script location and provides a sensible default chain ID.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Comment @cursor review or bugbot run to trigger another review on this PR
ws4charlie
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looks good
hazim1093
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've tested it out by running it in a container and using the zetaclient dry script as in the docker-compose file.
Great work 🎊

Description
The host needs the following ports open
When using these the dry zetaclient can be attached to any of these nodes via
NOTE : adding new scripts in Python instad of shell as we move towards reafactoring to use python as the main scripting language #4372
Closes
#4450
How Has This Been Tested?
Note
Add dry-mode zetaclient and live testnet/mainnet node workflows with snapshot caching, new Python entrypoints/scripts, and supporting Makefile/Docker/Docker Compose updates.
zetaclient-dryto Python entrypointstart-zetaclient-dry.py; addZETACORE_HOSTenv and mount scripts.testnet-nodeandmainnet-nodeservices with ports, healthchecks, volumes, and snapshot caching mounts; define new volumestestnet_dataandmainnet_data.NODE_VERSIONto env override; updatedownload-snapshotto usecontrib/localnet/scripts_python/download_snapshot.pywith--chain-id.mainnet-node,mainnet-node-force,mainnet-node-stop,testnet-node,testnet-node-force,testnet-node-stop, andzetaclient-dry.wget,lz4,python3-requests); copy new Python snapshot script; chmod Python files.scripts_python/download_snapshot.py: unified snapshot downloader (testnet/mainnet) with checksum, extract, cache.scripts_python/start-zetacored-livenode.py: bootstraps a live ZetaCore node from cached snapshot and network configs.scripts_python/start-zetaclient-dry.py: initializes/configureszetaclientdin dry mode against a providedZETACORE_HOST.zetaclient-dry.contrib/devnet/download_snapshot.py(replaced by new localnet script).Written by Cursor Bugbot for commit a41185b. Configure here.
Summary by CodeRabbit
Release Notes
✏️ Tip: You can customize this high-level summary in your review settings.