fix(devnet): re-deploy contracts when artifacts outpace running chain#383
Open
fix(devnet): re-deploy contracts when artifacts outpace running chain#383
Conversation
Five backticks inside JS comments at lines 742, 868, 881, 898, 899 were not escaped, so bash interpreted them as command substitution inside the surrounding `node -e "..."` double-quoted string. On every `devnet start` this produced noisy errors like: scripts/devnet.sh: line 694: continue: only meaningful in a `for'... scripts/devnet.sh: line 694: nonce++: command not found scripts/devnet.sh: line 694: syntax error near unexpected token `idId' The text was inside JS `//` comments so the staking script still ran, but the diagnostics drowned out real failures (e.g. the stale-bytecode revert this commit's sibling fixes). Lines 730-733 and 768 already use `\`` correctly; these five were oversights. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
When hardhat is left running across edits to .sol sources, the on-chain bytecode lags the recompiled artifacts on disk. The next `devnet start` short-circuits in `start_hardhat` (alive PID), then `deploy_contracts` skips on the still-present `.devnet/hardhat/deployed` marker, so daemons connect to addresses whose code predates the latest source. View methods added since that deploy revert with "function selector not recognized"; ethers surfaces this as `require(false)` (no return data, no fallback). On a 6-node devnet this manifests as `0/4 core node(s) staked` because the staking loop's `CSS.getNodeStakeV10` probe fails for every node. Detect the mismatch by comparing artifact mtimes to the marker. If any contract artifact JSON is newer than the marker, kill the running hardhat so the existing fresh-start path (which clears the marker plus `localhost_contracts.json` + `hardhat_contracts.json`) runs and `deploy_contracts` re-deploys onto a fresh chain. No-op when artifacts are unchanged. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
| kill -0 "$stale_pid" 2>/dev/null || break | ||
| sleep 1 | ||
| done | ||
| rm -f "$pidfile" |
There was a problem hiding this comment.
🟡 Issue: This restart path removes hardhat.pid and immediately starts a replacement even if the old Hardhat process is still alive after the 5s wait. On a slow shutdown, the new hardhat node can fail to bind :$HARDHAT_PORT, turning the stale-artifact recovery into a flaky devnet start. Re-check kill -0 after the loop and either keep waiting/escalate the kill or return non-zero before deleting the pidfile and launching a new node.
5 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Two fixes to
scripts/devnet.shso a long-running Hardhat node doesn't silently serve stale bytecode after a contract recompile.1. Stale-bytecode guard in
start_hardhatWhen Hardhat is left running across edits to
.solsources, on-chain bytecode lags the recompiled artifacts on disk. Nextdevnet startshort-circuits on the alive PID, thendeploy_contractsskips on the still-present.devnet/hardhat/deployedmarker. Daemons connect to addresses whose code predates the latest source; view methods added since that deploy revert with "function selector was not recognized." Ethers surfaces this asrequire(false)with no return data, masking the real cause.On a 6-node devnet this manifested as
FATAL: only 0/4 core node(s) stakedbecause the staking loop'sCSS.getNodeStakeV10probe failed for every node.The fix compares artifact JSON mtimes to the marker. If any artifact is newer, kill Hardhat so the existing fresh-start path (clears marker +
localhost_contracts.json+hardhat_contracts.json) fires anddeploy_contractsredeploys onto a fresh chain. No-op when artifacts are unchanged — keeps the fast path intact for the common edit-nothing-restart-devnet flow.2. Escape backticks in
node -eJS commentsFive JS comments inside the staking heredoc (lines 742, 868, 881, 898, 899) had unescaped backticks (
`continue`,`nonce++`,`EVMChainAdapter.ensureProfile()`,`getNodeStakeV10(idId)`,`balanceOf(opSigner.address)`). Bash command-substituted them inside the surroundingnode -e "..."double-quoted string, so everydevnet startprinted:Text was inside
//comments so the staking script still ran, but the diagnostic noise drowned out real failures (e.g. the stale-bytecode revert above). Lines 730-733 and 768 already use ``` correctly; these five were oversights.Test plan
bash -n scripts/devnet.shsyntax checkdevnet stop && devnet start 6no longer prints bash backtick errorsdevnet start— stale-bytecode guard fires, contracts redeployed freshstart_hardhatshort-circuits with no marker mtime check overheadOut of scope
A pre-existing nonce race between the daemon's
ensureProfile()auto-stake and the bootstrap script's stake loop (both target the same op wallet within seconds of each other) was masked by the bash syntax errors. With these fixes the race surfaces asStake failed for node N: nonce has already been used. Filing separately — not introduced by this PR.🤖 Generated with Claude Code