1

basically we have this function

function FlaggedMethods(
        bytes memory data
    ) public returns (address) {
        bytes4 funcSig;
        assembly {

            // Shift right by 224 bits to retain only the first 4 bytes
            funcSig := mload(add(data, 0x20)) //this saves the first 4 bytes and emits them in events

            let shiftedFuncSig := shr(224, funcSig) // Shift right by 4 bytes to get the function signature

            //this is done so that the funcSig is checked against each switch cases
            switch shiftedFuncSig
            case 0x095ea7b3 {}

and even though the bytes4 funcSig gives us the correct result every time, even on event emission, it doesn't step into the switch cases at all, only after we shift it by 224 bytes that the switch cases start working, but this time emitting an event with shiftedFuncSig returns us a 0x000000000, so we reused the original bytes4 funcSig for event emission.

so I am just curious as to why the shiftedFuncSig works for switch cases, not event emissions, and vice versa for the funcSig which emits the correct funcSig but does not work when checking against each individual switch statement

1 Answer 1

0

Short answer: because the data format are different between bytes4 (used by your event) and uint256 (used by the switch case implementation).

Long explaination:

The byte code below is to compare in the switch case:

PUSH4 095ea7b3 # top of stack = 0x0000....000095ea7b3
DUP2  # or dup somewhere else, where your value shiftedFuncSig is at
SUB # UINT256 SUB, check if 2 values equal
PUSH2 00b9 # JUMP Destination
JUMPI # Here if they are not equal, jump, else go to switch case

Your bytes4 funcSig will look like this in the stack before going to the SUB opcode: 0x095ea7b30000000..... (32 bytes) while the value on the stack for SUB is 0x00000000000000000000000000000000000000000000000000000000095ea7b3, which are clearly different. When you use SUB to compare them, they are not equal and can't go to the switch case .

Your uint256 shiftedFuncSig will look exactly like the value solidity used to compare for the switch case, it is right-aligned and big-endian: 0x00000000000000000000000000000000000000000000000000000000095ea7b3. This explains why you can reach the switch case.

When you use shiftedFuncSig in event emit, it will then be treated as an array of bytes, which is left-aligned, hence you get the 0x00000000 result

In summary: fixed length bytes arrays are left aligned (when reading by our eyes) while uint256 is right aligned (again, when reading by our eyes, it's actually big-endian). Read more about that in solidity specification here or my answer for another question

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.