0

my solidity code is below:

pragma solidity ^0.4.24;

contract Test {

    event Event(address);
    event TestEvent(uint256);
    event Data(bytes);
    event Data1(bytes);
    function show() public returns(uint256){
        emit Event(msg.sender);
        return 100;
    }

    function test(uint256 a)external returns(bytes){

        emit Data(msg.data);
        emit TestEvent(a);
        return msg.data;

    }
    function caller1(address _addr) {
        emit Data1(abi.encodeWithSelector(bytes4(keccak256("test(uint256)")),100));
        _addr.call(abi.encodeWithSelector(bytes4(keccak256("test(uint256)")),100));
    }
}

contract Call {

    function caller1(address _addr) {
        _addr.call(abi.encodeWithSelector(bytes4(keccak256("test(uint256)")),100));
    }
}

I have been deployed contract Test and Call。when I call function test(100) directly, this event Data show the msg.data is "0x29e99f070000000000000000000000000000000000000000000000000000000000000064",ok.

But, when I call the contract Test's function caller1 or contract Call's function caller1 to call the function test by solidity lib function .call,the event Data show the msg.data is "0x29e99f07000000000000000000000000000000000000000000000000000000000000006400000000000000000000000000000000000000000000000000000000".

yes,you can see this msg.data is longer than that one ,this msg.data is much more an hexString "00000000000000000000000000000000000000000000000000000000".the length of the hexString is 56,of course,the length is 26 byte. Why,somebody could you help me .

My English is poorly,understand what I say ?

  • Something is wrong with how you are calling the function. When you say you are calling caller1, you should have a different value at the front of the function call. 29e99f07 should be specific to the function you are calling, so it has to represent either test or caller1, but not both – Shawn Tabrizi Oct 31 '18 at 4:48
1

This has been fixed and works properly starting with the first 0.4.26 nightly build ( 0.4.26-nightly.2018.9.13+commit.8b089cc8 )

Trying to use it in a version prior to this will most likely result in issues:

I can reproduce the issue you found and it seems to be an oversight in the abi.encodeWithSelector method that adds an extra 28 bytes to the result.

These typically get ignored when read by the called method.

BUT can cause issues if ignored and used in this form in checks like ( some token transfer payload size checks )

modifier onlyPayloadSize(uint numwords) {
    assert(msg.data.length == numwords * 32 + 4);
_;

How the ABI works:

The solidity v1 ABI uses 32byte words to pad / store variables.

msg.data starts with 4 bytes that represent the first 4 bytes of the hash of the method you're calling

add 32 bytes for each of the arguments you're passing, which depending on the type are as follow:

  • a) 32 bytes value if simple type like uint / byte / bytes[1-32] / bool / etc
  • b) 32 bytes containing the pointer to the address where the variable content starts in the msg.data in case of dynamic size variables ( strings / arrays )
    • Pointer then leads to a 32 byte space where we find the number of words / 32 byte blocks used by our variable then based on said number we know how many blocks to read to get the full contents

Fallback:

If you do want to call it "properly" you can use the good old tested way

_address.call(bytes4(bytes32(keccak256("_method(type1,typeN)"))), _param, _paramN));
  • You're very welcome :) – Micky Socaci Oct 31 '18 at 5:31
  • Feel free to accept the question if it does the job for you, thanks. – Micky Socaci Oct 31 '18 at 15:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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