msg.data or calldata store the data of the called function means calling function id, and its parameters in the form of bytes.
here is an method:
function getMsgData(address _address, bytes _bytes, uint _int, uint[] _array, string _string ) external returns (bytes) { return msg.data; }
Now assume we pass call above method like this:
contract.getMsgData( someAddress, web3.toHex('my bytes'), 12, [1, 4, 412], 'thisislargerthanthirtytwobytesstring' );
This calldata or msg.data something like this.
0x d1621754 // (1) methodId 000000000000000000000000c6e012db5298275a4c11b3e07d2caba88473fce1 // (2) "_address" 00000000000000000000000000000000000000000000000000000000000000a0 // (3) location of start of "_bytes" data (item 7) = 160 bytes 000000000000000000000000000000000000000000000000000000000000000c // (4) "_val" = 12 00000000000000000000000000000000000000000000000000000000000000e0 // (5) location of start of "_array" data (item 9) = 224 bytes 0000000000000000000000000000000000000000000000000000000000000160 // (6) location of start of "_string" data (item 13) = 352 bytes 0000000000000000000000000000000000000000000000000000000000000008 // (7) size of "_bytes" data in bytes (32 bytes) 6d79206279746573000000000000000000000000000000000000000000000000 // (8) "_bytes" data padded to 32 bytes 0000000000000000000000000000000000000000000000000000000000000003 // (9) length of "_array" data = 3 0000000000000000000000000000000000000000000000000000000000000001 // (10) _array[0] value = 1 0000000000000000000000000000000000000000000000000000000000000004 // (11) _array[2] value = 4 000000000000000000000000000000000000000000000000000000000000019c // (12) _array[3] value = 412 0000000000000000000000000000000000000000000000000000000000000024 // (13) size of "_string" data in bytes (64 bytes) 7468697369736c61726765727468616e74686972747974776f6279746573737472696e670..0 // (14) "_string" data padded to 64 bytes
another example of calldata
contract Calldata { function add(uint256 _a, uint256 _b) public view returns(uint256 result) { assembly { let a: = mload(0x40) let b: = add(a, 32) calldatacopy(a, 4, 32) calldatacopy(b, add(4, 32), 32) result: = add(mload(a), mload(b)) } } }
The idea here is to return the addition of two numbers passed by arguments. As you can see, once again we are loading a memory pointer reading from <code0x40, but please ignore that for now; we will explain it right after this example. We are storing that memory pointer in the variable a
and storing in b
the following position which is 32-bytes right after a
. Then we use calldatacopy
to store the first parameter in a
. You may have noticed we are copying it from the 4th position of the calldata instead of its beginning. This is because the first 4 bytes of the calldata hold the signature of the function being called, in this case bytes4(keccak256("add(uint256,uint256)"))
; this is what the EVM uses to identify which function has to be executed on a call. Then, we store the second parameter in b copying the following 32 bytes of the calldata. Finally, we just need to calculate the addition of both values loading them from memory.