Skip to content

Conversation

@msooseth
Copy link
Collaborator

This partially addresses #917 The issue is that bytes bytes1[36] is packed as per ABI spec. From the ABI documentation: https://docs.soliditylang.org/en/latest/abi-spec.html#formal-specification-of-the-encoding

bytes, of length k (which is assumed to be of type uint256):

enc(X) = enc(k) pad_right(X), i.e. the number of bytes is encoded as a uint256 followed by the actual value of X as a byte 
sequence, followed by the minimum number of zero-bytes such that len(enc(X)) is a multiple of 32.

However, we treated it as a regular Array, which is padded to 32B for each element.

Description

Checklist

  • tested locally
  • added automated tests
  • updated the docs
  • updated the changelog

Update comment

Fix

Update changelog
@msooseth msooseth marked this pull request as ready for review October 29, 2025 11:55
@gustavo-grieco
Copy link
Collaborator

Why this is a partial fix?

@msooseth
Copy link
Collaborator Author

@gustavo-grieco only because it doesn't remove the trailing zeros... not sure they must be removed, but they probably could be removed. Either way, it definitely fixes the bigger issue, and the printing of the output will allow a user to just send in the counterexample that is short.

mstore(0x40, add(dataPtr, dataLen))

// Perform the low-level call
success := call(gas(), target, 0, dataPtr, dataLen, 0, 0)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can you explain what is this going to call?

Copy link
Collaborator Author

@msooseth msooseth Oct 29, 2025

Choose a reason for hiding this comment

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

@gustavo-grieco came up with this example, I just copied it :)
@gustavo-grieco can you maybe give some context?

Copy link
Collaborator Author

@msooseth msooseth Oct 29, 2025

Choose a reason for hiding this comment

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

I think the idea is to call inc()

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yes, it calls inc in order to violate

assert(state == 0);

because:

cast keccak "inc()" 
0x371303c051bff726100ad13871cababf50c20dd920fca137e519f98f089a74b4

And indeed the correct CEX, is:

0x37, 0x13, 0x03, 0xc0

Which are the first 4 bytes of that keccak, i.e. the function selector.

So the idea is for the system to calculate the function it needs to call that increments the state so that the state == 0 no longer holds.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

OK, I now added this to the code, can you check again?

Copy link
Collaborator

@gustavo-grieco gustavo-grieco Oct 29, 2025

Choose a reason for hiding this comment

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

Yes, this is correct. This was an experiment to make hevm/echidna run a symbolic transaction and perform some checks after that (e.g. calling a functions with no parameters). It can be generalized to more transactions.

Fixing indentation
@msooseth msooseth force-pushed the Fixing-RPC branch 2 times, most recently from e022669 to 980d0a1 Compare October 29, 2025 16:21
Update

Update
Comment on lines +25 to +35
// Perform the low-level call
// this should call the inc() function, which has selector:
//```
//cast keccak "inc()"
//0x371303c051bff726100ad13871cababf50c20dd920fca137e519f98f089a74b4
//```
// which happens to have the first 4 bytes as
// 0x37, 0x13 0x03, 0xc0
// This will increment `state` by 1, thereby violating the property

success := call(gas(), target, 0, dataPtr, dataLen, 0, 0)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Oh, I see, this basically just calls this contract again, with the calldata passed in as argument to this function.
So the number 36 is rather arbitrary here, no?
4 would be sufficient, since we only need the selector (which has 4 bytes) to be able to call inc, no?

Why was 36 chosen as the magic number?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Yes, sorry, the 36 was selected to allow at least one parameter, but here it can be reduced.

@msooseth
Copy link
Collaborator Author

msooseth commented Oct 30, 2025

Ooops:

2025-10-29T16:28:45.2063660Z hevm>     symbolic-abi encoding-vs-solidity-2-args:                     FAIL (1.06s)
2025-10-29T16:28:45.2064412Z hevm>       *** Failed! (after 95 tests):
2025-10-29T16:28:45.2064837Z hevm>       Exception:
2025-10-29T16:28:45.2065433Z hevm>         Internal Error: Left (Revert (ConcreteBuf "")) -- CallStack (from HasCallStack):
2025-10-29T16:28:45.2066214Z hevm>           internalError, called at test/test.hs:5620:13 in main:Main
2025-10-29T16:28:45.2066601Z hevm>         CallStack (from HasCallStack):
2025-10-29T16:28:45.2067037Z hevm>           error, called at src/EVM/Types.hs:1547:19 in hevm-0.56.0-7NJEoXrfiAACDJcfgNGfWY:EVM.Types
2025-10-29T16:28:45.2067532Z hevm>           internalError, called at test/test.hs:5620:13 in main:Main
2025-10-29T16:28:45.2068110Z hevm>       (SymbolicAbiVal 0x6454be4953aaaf542dbf21db8d4244833ebdda80,SymbolicAbiVal [0x7d, 0xf9, 0xf6, 0x0f, 0x0b])
2025-10-29T16:28:45.2068749Z hevm>       Use --quickcheck-replay="(SMGen 3482784650225922177 7199675813539884525,94)" to reproduce.
2025-10-29T16:28:45.2069481Z hevm>       Use -p '/symbolic-abi encoding-vs-solidity-2-args/' to rerun this test only.

and:

2025-10-29T16:40:42.3228998Z     abi-encoding-vs-solidity-2-args:                              FAIL (1.31s)
2025-10-29T16:40:42.3230776Z       *** Failed! (after 39 tests):
2025-10-29T16:40:42.3231304Z       Exception:
2025-10-29T16:40:42.3231956Z         Internal Error: Left (Revert (ConcreteBuf "")) -- CallStack (from HasCallStack):
2025-10-29T16:40:42.3232951Z           internalError, called at test\test.hs:5620:13 in hevm-0.56.0-inplace-test:Main
2025-10-29T16:40:42.3233731Z         CallStack (from HasCallStack):
2025-10-29T16:40:42.3234386Z           error, called at src\EVM\Types.hs:1547:19 in hevm-0.56.0-inplace:EVM.Types
2025-10-29T16:40:42.3235315Z           internalError, called at test\test.hs:5620:13 in hevm-0.56.0-inplace-test:Main
2025-10-29T16:40:42.3236082Z       ([0x19, 0x34, 0x1d, 0x0e, 0x3c, 0x0d, 0x01, 0x21, 0x12, 0x1f, 0x0e, 0x15, 0x30, 0x1a, 0x3b, 0x35, 0x06, 0x29, 0x32, 0x3a, 0x21, 0x14, 0x2b, 0x23, 0x00, 0x30, 0x10, 0x1e, 0x38],0x0000000000000000000000000000000000006866)
2025-10-29T16:40:42.3237134Z       Use --quickcheck-replay="(SMGen 9011992352728319783 16502856406791791583,38)" to reproduce.
2025-10-29T16:40:42.3237723Z       Use -p '/abi-encoding-vs-solidity-2-args/' to rerun this test only.

@blishko
Copy link
Collaborator

blishko commented Oct 30, 2025

I confirm this problem is not reproducible on main, so it must be introduced here.

@msooseth
Copy link
Collaborator Author

Yes, I know. I am working on it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants