Skip to content

Commit 028ff7e

Browse files
committed
fix(e2e): restore over-stripped fallback guards in upgrade-chain.sh (review)
phenix flagged that the gov-authority query lost its `|| true`, so under `set -euo pipefail` a transient kubectl-exec/query failure terminates the script and the fallback + diagnostic become unreachable. Auditing that revealed the carve from the grab-bag had actually dropped ALL 10 of main's `|| true` in this file, not just the intended image-load one — including two more fallback-critical query paths (proposal-id) and four best-effort kubectl scale/wait guards. Reset upgrade-chain.sh to main and re-applied only the intended changes: image load -> kind_load_image (fail loudly, the one deliberate removal), the post-restart per-validator + EVM RPC gates, and the two gov-authority queries converted to the explicit `if ! gov_authority=$(...); then gov_authority=""; fi` form per the review (preserves the fallback explicitly instead of relying on `|| true`). The other seven defensive `|| true` are preserved. Validated on the governance upgrade path (which the earlier hardfork run did not exercise): full gov e2e 5/5 — gov-authority query resolves, proposal submitted/voted 4/4, chain upgrades and resumes, all post-upgrade tests pass. Signed-off-by: puneetmahajan <59960662+puneet2019@users.noreply.github.com>
1 parent a9096f6 commit 028ff7e

2 files changed

Lines changed: 26 additions & 21 deletions

File tree

CHANGELOG.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,6 @@ Ref: https://keepachangelog.com/en/1.0.0/
6464
- (types,utils) [#320](https://github.com/mocachain/moca/pull/320) Delete dead ethermint-era files orphaned by the `rpc/`/`x/evm`/`x/erc20` removals: `types/{block,gasmeter,int,protocol,validation,constant}.go`, `types/openapiutil/`, and `utils/eth/eth.go` — every exported symbol verified unreferenced across the repo and all known external consumers (moca-storage-provider, moca-go-sdk, moca-challenger). Externally-used files (`chain_id.go``ParseChainID` is production code in the storage provider's signer — `grn.go`, `s3util`, `resource`, `common`) are untouched.
6565
- (client) [#321](https://github.com/mocachain/moca/pull/321) Delete the dead `client/testnet.go` (579 LOC): an unreferenced near-duplicate of `cmd/mocad/cmd/testnet.go`, which is what the `mocad testnet` command actually wires.
6666
- (types,server) [#322](https://github.com/mocachain/moca/pull/322) Use cosmos/evm's `HasDynamicFeeExtensionOption` and `NewIndexTxCmd` instead of the in-tree copies (semantically identical; both already operated on cosmos/evm's own types) — the only two fork-neutral swaps the five-folder sweep found.
67-
- (e2e) [#324](https://github.com/mocachain/moca/pull/324) Fix the hardfork-upgrade e2e flake ("Chain did not reach height N within 240s"): the new-binary image load into kind could fail silently (`kind load ... || true`) and readiness accepted a single healthy pod as "chain resumed" while 2/3 quorum was still absent. Load images via `docker save | ctr import` with verification (`kind_load_image`), and gate post-restart on every validator's own RPC plus the EVM JSON-RPC (`wait_for_all_validator_rpcs`, `wait_for_evm_rpc_ready`); also delete stale kind clusters on fresh builds so containerd can't serve an old image SHA under the new tag.
6867

6968
- (contracts) [#314](https://github.com/mocachain/moca/pull/314) Slim `contracts/` to what moca actually uses (mirroring cosmos/evm's top-level `contracts/` convention): delete the four ERC20 test doubles (`MinterBurnerDecimals`, `Burnable`, `DirectBalanceManipulation`, `MaliciousDelayed`) — dead since the `x/erc20` removal (#221), available upstream where still needed — plus their `.sol` sources, artifacts, and npm manifest. The moca-specific `ERC721NonTransferable` (bucket/object/group NFT facade the storage keeper mints/burns through) stays put, now pinned by a guard test covering its ABI surface, fixed token/hub addresses, and its intentionally bytecode-less (ABI-only) nature. Slither retargets to `solidity/`; the now-subjectless solhint workflow and broken `lint-contracts` Make targets are removed.
7069

e2e/kind/scripts/upgrade-chain.sh

Lines changed: 26 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -32,21 +32,27 @@ log_info " Image: ${NEW_DOCKER_IMAGE}"
3232
_upgrade_governance() {
3333
log_info "Submitting software-upgrade proposal..."
3434

35-
# Get the gov module authority address
35+
# Get the gov module authority address. Use `if !` (not a bare assignment) so
36+
# a failing query under `set -euo pipefail` falls through to the alternative /
37+
# diagnostic below instead of terminating the script.
3638
local gov_authority=""
37-
gov_authority=$(kubectl exec -n "${K8S_NAMESPACE}" validator-0-0 -c mocad -- \
39+
if ! gov_authority=$(kubectl exec -n "${K8S_NAMESPACE}" validator-0-0 -c mocad -- \
3840
mocad query auth module-account gov \
3941
--node tcp://localhost:26657 \
4042
--home /root/.mocad \
41-
--output json 2>/dev/null | jq -r '.account.base_account.address // .account.value.address // empty' 2>/dev/null)
43+
--output json 2>/dev/null | jq -r '.account.base_account.address // .account.value.address // empty' 2>/dev/null); then
44+
gov_authority=""
45+
fi
4246

4347
if [ -z "$gov_authority" ]; then
4448
log_warn "Could not query gov module address, trying alternative..."
45-
gov_authority=$(kubectl exec -n "${K8S_NAMESPACE}" validator-0-0 -c mocad -- \
49+
if ! gov_authority=$(kubectl exec -n "${K8S_NAMESPACE}" validator-0-0 -c mocad -- \
4650
mocad query auth module-accounts \
4751
--node tcp://localhost:26657 \
4852
--home /root/.mocad \
49-
--output json 2>/dev/null | jq -r '.accounts[] | select(.name=="gov") | .base_account.address // .value.address // empty' 2>/dev/null)
53+
--output json 2>/dev/null | jq -r '.accounts[] | select(.name=="gov") | .base_account.address // .value.address // empty' 2>/dev/null); then
54+
gov_authority=""
55+
fi
5056
fi
5157

5258
if [ -z "$gov_authority" ]; then
@@ -80,7 +86,7 @@ PROPOSAL_EOF
8086

8187
# Write proposal file into the pod
8288
echo "$proposal_json" | kubectl exec -i -n "${K8S_NAMESPACE}" validator-0-0 -c mocad -- \
83-
bash -c "cat > /tmp/upgrade-proposal.json"
89+
bash -c "cat > /tmp/upgrade-proposal.json" || true
8490

8591
# Submit proposal via sync broadcast + wait for inclusion
8692
local submit_out="" submit_hash=""
@@ -110,9 +116,9 @@ PROPOSAL_EOF
110116
--node tcp://localhost:26657 \
111117
--chain-id "${CHAIN_ID}" \
112118
--home /root/.mocad \
113-
--output json 2>&1)
119+
--output json 2>&1) || true
114120

115-
proposal_id=$(echo "$query_out" | jq -r '.proposals[-1].id // .proposals[-1].proposal_id // empty' 2>/dev/null)
121+
proposal_id=$(echo "$query_out" | jq -r '.proposals[-1].id // .proposals[-1].proposal_id // empty' 2>/dev/null) || true
116122

117123
if [ -z "$proposal_id" ]; then
118124
log_error "Could not find upgrade proposal"
@@ -206,9 +212,9 @@ _wait_for_upgrade_halt() {
206212
# Chain halts but doesn't exit — scale down, replace binary, scale back up
207213
log_info "Scaling down validators..."
208214
for ((i = 0; i < NUM_VALIDATORS; i++)); do
209-
kubectl scale statefulset "validator-${i}" --replicas=0 -n "${K8S_NAMESPACE}" 2>/dev/null
215+
kubectl scale statefulset "validator-${i}" --replicas=0 -n "${K8S_NAMESPACE}" 2>/dev/null || true
210216
done
211-
kubectl wait --for=delete pod -l app=validator -n "${K8S_NAMESPACE}" --timeout=60s 2>/dev/null
217+
kubectl wait --for=delete pod -l app=validator -n "${K8S_NAMESPACE}" --timeout=60s 2>/dev/null || true
212218
log_info "All validators stopped"
213219

214220
# Update all validator StatefulSets to use the new image, then scale back up
@@ -218,8 +224,9 @@ _wait_for_upgrade_halt() {
218224
_update_validator_images() {
219225
log_info "Updating validator images to ${NEW_DOCKER_IMAGE}..."
220226

221-
# Load new image into Kind if not already loaded (docker save | ctr import
222-
# — see kind_load_image in lib.sh; avoids buildx desktop-linux quirks)
227+
# Load new image into Kind (docker save | ctr import with verification — see
228+
# kind_load_image in lib.sh; the plain `kind load` silently no-op'd on a
229+
# failed load, leaving validators to restart into a missing/old image).
223230
kind_load_image "${NEW_DOCKER_IMAGE}"
224231

225232
# Patch each validator StatefulSet with the new image
@@ -236,7 +243,7 @@ _update_validator_images() {
236243
# Scale validators back up with new image
237244
log_info "Starting validators with new image..."
238245
for ((i = 0; i < NUM_VALIDATORS; i++)); do
239-
kubectl scale statefulset "validator-${i}" --replicas=1 -n "${K8S_NAMESPACE}" 2>/dev/null
246+
kubectl scale statefulset "validator-${i}" --replicas=1 -n "${K8S_NAMESPACE}" 2>/dev/null || true
240247
done
241248

242249
# Wait for all validators to come back up
@@ -246,21 +253,20 @@ _update_validator_images() {
246253
kubectl wait --for=condition=ready "pod/validator-${i}-0" \
247254
-n "${K8S_NAMESPACE}" --timeout=180s 2>/dev/null || {
248255
log_error "Validator-${i} failed to restart"
249-
kubectl logs -n "${K8S_NAMESPACE}" "validator-${i}-0" --tail=50 2>/dev/null
256+
kubectl logs -n "${K8S_NAMESPACE}" "validator-${i}-0" --tail=50 2>/dev/null || true
250257
return 1
251258
}
252259
done
253260

254261
log_success "All validators restarted with new image"
255262

256-
# Wait for chain to resume producing blocks (NodePort RPC, fast signal)
263+
# Wait for chain to resume producing blocks (NodePort RPC — a single healthy
264+
# pod satisfies this), then gate on EVERY validator's own RPC: a tx broadcast
265+
# routed via kubectl exec to a pod whose RPC isn't yet serving fails with
266+
# empty stderr, and the EVM JSON-RPC can lag the cosmos /status by several
267+
# seconds after a rolling restart ("null response" on the first cast send).
257268
wait_for_chain_ready "http://localhost:26657" 180
258-
# Then poll EACH validator's RPC — wait_for_chain_ready is satisfied by a
259-
# single healthy pod, but a tx broadcast routed via kubectl exec to a pod
260-
# whose RPC isn't yet serving will fail with empty stderr. Belt-and-braces.
261269
wait_for_all_validator_rpcs "$NUM_VALIDATORS" 60
262-
# And the EVM JSON-RPC, which can lag the cosmos /status by several seconds
263-
# after a rolling restart, leading to "null response" on first cast send.
264270
wait_for_evm_rpc_ready "http://localhost:8545" 60
265271
log_success "Chain resumed after upgrade"
266272
}

0 commit comments

Comments
 (0)