Skip to content

Commit 9ee4576

Browse files
dvilelafclaude
andcommitted
fix: rotate RPC on GS013 to escape stale node immediately
GS013 errors are caused by RPC nodes returning stale state that makes the Safe simulation fail. Previously the retry path just waited through exponential backoff (up to 63s) on the same stale node. Now we trigger RPC rotation immediately so the next attempt hits a fresh node, reducing GS013 recovery from ~30-60s to ~2-5s. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent b76737b commit 9ee4576

3 files changed

Lines changed: 10 additions & 6 deletions

File tree

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "iwa"
3-
version = "0.7.7"
3+
version = "0.7.8"
44
description = "A secure, modular, and plugin-based framework for crypto agents and ops"
55
readme = "README.md"
66
requires-python = ">=3.12,<4.0"

src/iwa/core/services/safe_executor.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -292,15 +292,19 @@ def _handle_execution_failure(
292292
)
293293
return safe_tx, False, is_fee_error
294294

295-
# GS013 = inner call reverted while safeTxGas=0 and gasPrice=0.
296-
# This can be transient (RPC returning stale chain state, marketplace
297-
# contract in a temporary state). Allow retry with backoff.
295+
# GS013 = RPC provider returning stale state that makes the Safe
296+
# simulation fail. The diagnosis eth.call always succeeds because
297+
# with_retry() may already use a different node. Fix: rotate RPC
298+
# immediately so the next _execute_attempt hits a fresh node instead
299+
# of waiting through exponential backoff against the same stale node.
298300
if classification["is_gs013_inner_revert"]:
299301
SAFE_TX_STATS["gs013_inner_revert_retries"] += 1
302+
SAFE_TX_STATS["rpc_rotations"] += 1
300303
self._diagnose_inner_revert(safe_tx, operation_name)
304+
self.chain_interface._handle_rpc_error(error)
301305
logger.warning(
302306
f"[{operation_name}] GS013 inner call revert (attempt {attempt + 1}), "
303-
f"retrying: {safe_error}{reason_suffix}"
307+
f"rotating RPC and retrying: {safe_error}{reason_suffix}"
304308
)
305309
return safe_tx, True, is_fee_error
306310

uv.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)