fix(deploy): report the zero address when the Zoltu factory call fails - #20
fix(deploy): report the zero address when the Zoltu factory call fails#20thedavidmeister wants to merge 1 commit into
Conversation
The EVM copies revert data into a call's output region, so a failed factory call leaves revert bytes exactly where `deployZoltu` reads `deployedAddress`. Read the output buffer only when the call succeeded, so a failed deploy reports the zero address instead of the first twenty bytes of the factory's revert data. Co-Authored-By: Claude <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (3)
Walkthrough
ChangesZoltu failure handling
Estimated code review effort: 2 (Simple) | ~10 minutes 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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 |
|
🤖 ai:vetter |
|
🤖 ai:vetter |
|
👤 human |
Closes #17
deployZolturead its call output buffer unconditionally. The EVM copies revert data into the output region for failed calls too, so a factory call that reverted with at least 20 bytes left the first 20 of those bytes at memory[12, 32)— exactly where the factory's raw 20-byte address would be — and they becamedeployedAddress. All four operator-facing reports on the failure path (the twoconsole2.loglines, the codehash log, and theDeployFailedrevert argument) then showed a fabricated address, with a real code length and codehash for that fabricated address.The buffer is now read only when the call succeeded, so a failed call reports
address(0).DeployFailed's NatSpec states that invariant. The success path is untouched —mstore(0, 0)is still what makes a short return read as zero rather than as stale scratch.Diagnostics-only, as the issue rates it: the guard already short-circuits on
!success, so a failed call could never be mistaken for a successful deployment.The
MockAddressRevertingFactoryfixture is byte-identical (blob4b38fea) to the one on #19, so the two branches merge without an add/add conflict in either order.QA
testDeployZoltuFailedCallReportsZeroAddress— fails on base (mutating the fix back to base's unconditionaldeployedAddress := mload(0)producesDeployFailed(false, 0x7A0D94F55792C434d74a40883C6ed8545E406D12) != DeployFailed(false, 0x0000000000000000000000000000000000000000), reproducing the issue's exact reported value; whole suite 26 passed / 1 failed, the 1 being this test)if success { deployedAddress := mload(0) }→deployedAddress := mload(0)(base) → killed bytestDeployZoltuFailedCallReportsZeroAddress;if success→if iszero(success)→ killed by 8 tests includingtestDeployZoltuFailedCallReportsZeroAddressandtestDeployZoltu(pins both directions of the guard);deployedAddress := mload(0)→deployedAddress := 0→ killed by 7 existing happy-path tests;mstore(0, 0)→mstore(0, not(0))→ killed bytestDeployZoltuRevertsNoFactory(DeployFailed(true, 0xFfFf…FF)), proving the pre-zero stays load-bearing after the fix;call(…, 12, 20)→call(…, 12, 0)→ killed by 7 existing tests; dropping!success ||from the guard → SURVIVED and is provably equivalent post-fix, sincedeployedAddressis assigned only insideif successso!successimpliesdeployedAddress == address(0)and the second term always fires first — no test added for it. Fixture integrity was checked by applying the base-code mutation together withrevert(0, 20)→revert(0, 0)in the mock: the test then passes, so its discriminating power comes specifically from the 20-byte address-shaped revert data. Baseline pinned by commit before the first probe; every mutation restored via VCS; tree verified clean; 27 passed / 0 failed on the restored tree.CALLsemantics — return data is copied into[retOffset, retOffset+min(retSize, returndatasize))for reverted calls as well as successful ones, so bytes in that region after a failure are revert data and not an address. Expected valueaddress(0)is derived fromDeployFailed's own contract (a failed deploy produced no address), not from the implementation's output. The failing-base value0x7A0D…D12is independently known: it is the etched fixture's own address, which the mock reverts with by construction.deployedAddresson the failure path (it lists the four report sites as symptoms of that single read) — covered by guarding the read, which fixes all four sites at their common source.Co-Authored-By: Claude noreply@anthropic.com
Summary by CodeRabbit
Bug Fixes
Tests