Skip to content
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

bug(forge)!: strip "revert: " from vm.expectRevert reason #10144

Open
wants to merge 5 commits into
base: master
Choose a base branch
from

Conversation

Hugoo
Copy link
Contributor

@Hugoo Hugoo commented Mar 20, 2025

Closes #10040

Solution

Please see the conv. here: #10040 (comment)

There is something to decide about backward compatibility + side effects

PR Checklist

  • Added Tests
  • Added Documentation
  • Breaking changes

@Hugoo Hugoo marked this pull request as ready for review March 20, 2025 19:12
mattsse
mattsse previously approved these changes Mar 20, 2025
Copy link
Member

@mattsse mattsse left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this lgtm,

pending @grandizzy

@grandizzy
Copy link
Collaborator

Thank you, makes sense. please fix the fmt issue

@Hugoo
Copy link
Contributor Author

Hugoo commented Mar 21, 2025

@grandizzy done - sry my IDE was not set with +nightly

zerosnacks
zerosnacks previously approved these changes Mar 21, 2025
@grandizzy
Copy link
Collaborator

grandizzy commented Mar 21, 2025

@Hugoo looks like the newly added testExpectRevertWithEncodedErrorPrefix test fails here https://github.com/foundry-rs/foundry/actions/runs/13993716850/job/39183491974#step:12:664 could you please check? (you can cargo test test_cheats_local_default locally) Thank you!


// When using vm.expectRevert(abi.encodeWithSignature("Error(string)", "A"));, the expected
// reason starts with "revert: " We strip redundant `revert: ` prefix from the revert reason
let expected = &expected.replace("revert: ", "");
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had to do the check here because I need the decoded "actual" value.

It relies on the &decoder.decode which has: Note that this is just a best-effort guess, and should not be relied upon for anything other than user output.

I can add a specific check for this 0x08c379a0: the function selector for Error(string) (i.e., keccak256("Error(string)")[:4] above but i think it adds overload but lmk what you think.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To avoid relying purely on best-effort decoding, good to add a check for the 0x08c379a0 selector (Error(string)), which is the most common revert pattern. This keeps decoding accurate without affecting performance much.

@Hugoo
Copy link
Contributor Author

Hugoo commented Mar 21, 2025

I had a few weird cases, if I log like this:

println!("expected decoded: {} - expected reason: {}", expected, &stringify(expected_reason));
println!("actual decoded: {} - actual reason: {}", actual, &stringify(actual_revert.as_slice()));

When the revert message is a short string, revert("A") -> it gets decoded as EvmError: Revert from the known_contracts

function testExpectRevertWithEncodedErrorPrefix() public {
        Reverter reverter = new Reverter();
        vm.expectRevert(abi.encodeWithSignature("Error(string)", "A"));
        reverter.revertWithMessage("A");
}
expected decoded: revert: A - expected reason: 0x08c379a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000014100000000000000000000000000000000000000000000000000000000000000

actual decoded: EvmError: Revert - actual reason: A ❌

If not, then it is decoded correctly:

function testExpectRevertWithEncodedErrorPrefix() public {
        Reverter reverter = new Reverter();
        vm.expectRevert(abi.encodeWithSignature("Error(string)", "randomString"));
        reverter.revertWithMessage("randomString");
}
expected decoded: revert: randomString - expected reason: 0x08c379a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000c72616e646f6d537472696e670000000000000000000000000000000000000000
actual decoded: randomString - actual reason: randomString ✅

Try adding this to: testdata/default/cheats/ExpectRevert.t.sol

function testExpectRevertShortString() public {
        Reverter reverter = new Reverter();
        vm.expectRevert("A");
        reverter.revertWithMessage("A");
    }

Error:

Error (6675): Member "expectRevert" not unique after argument-dependent lookup in contract Vm.
  --> default/cheats/ExpectRevert.t.sol:89:9:
   |
89 |         vm.expectRevert("A");

There might be some contract conflicts and the decoder matchs it when decoding, I'm not sure I didn't have much time to look more into it.

@grandizzy grandizzy self-assigned this Mar 25, 2025
@jenpaff jenpaff added this to the v1.1.0 milestone Mar 25, 2025
Copy link
Contributor Author

@Hugoo Hugoo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice @grandizzy thanks for handling the rest of this PR 🫡

@grandizzy
Copy link
Collaborator

nice @grandizzy thanks for handling the rest of this PR 🫡

np! yeah, still checking what would be the best way as this will be an breaking change, will update comments when ready

@grandizzy grandizzy force-pushed the revert-string branch 2 times, most recently from e419cd0 to fec971f Compare March 27, 2025 13:18
- match on ContractError:Revert
- move checks before split first chunk / EvmError
@grandizzy grandizzy added T-bug Type: bug C-forge Command: forge T-likely-breaking Type: requires changes that can be breaking labels Mar 27, 2025
@grandizzy
Copy link
Collaborator

nice @grandizzy thanks for handling the rest of this PR 🫡

I added logic in RevertDecoder to try decoding as Revert and changed the order of checks - that is to avoid the EvmError if we can decode it as string. Going to need a review from team before merging.

@grandizzy grandizzy requested review from mattsse and zerosnacks March 27, 2025 17:27
@Hugoo
Copy link
Contributor Author

Hugoo commented Mar 27, 2025

yup nice thanks - yes i think this one is a little bit trickier than it looks like and def has breaking changes so... need to be handled with care 🫡

Copy link
Member

@yash-atreya yash-atreya left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-forge Command: forge T-bug Type: bug T-likely-breaking Type: requires changes that can be breaking
Projects
Status: Ready For Review
Development

Successfully merging this pull request may close these issues.

bug(forge): vm.expectRevert(bytes revertData...) + alloy Revert fmt::Display makes Error(string) unmatchable
7 participants