Currently the call() with a method signature and parameters returns a boolean stating the success of execution (true if successful).
I think it would make more sense to return (or to have a version of call which does) the raw ABI bytes.
The reason call does not return the raw ABI bytes is because there is no way in the EVM to find out how much the called contract actually returned - in fact the caller has to "guess" or "know" that number and reserve the memory in advance.
With inline assembly, you can implement a version of call that returns a given number of bytes.
Well actually there's a way you have proposed https://github.com/ethereum/EIPs/blob/master/EIPS/eip-5.md - would it make sense having this open until that is implemented?
Question: should we re-throw on failure or somehow report the failure condition (e.g. by returning (bytes, bool))?
This is now possible with returndatasize/returndatacopy.
I am not entirely sure what would be the best method, but perhaps a tuple (bool, bytes) would be the best for the next breaking release and once multiple return values are supported by CALL (in order to distinguish between revert) I'd consider introducing either (uint, bytes) or (enum, bytes).
I had opened #3368. But let's move the discussion there as it seems quite related.
I think we must make this change non-breaking by creating a new function making a raw call.
The way I see it working would be
var (x, y) = callReturn[uint, string](bytes4(keccak256("fun(uint256)")), 5778));
We could also reserve the first return to indicate if the call succeeded, so it could be used like
var (succ, x, y) = callReturn[uint, string](bytes4(keccak256("fun(uint256)")), 5778));
Where succ is a boolean being true in case of success.
@axic do we want to have this for 0.5.0?
I'd be happy but it may be too many changes (from the users' perspective).
Also it will be more useful once the abi.decode helper is introduced, which we haven't even started yet, so realistically I'd say to postpone it to 0.6.0 assuming it will come strictly <= 6 months after 0.5.0 :)
I agree. In addition to that, we wanted to deprecate the use of low-level features that do not go all the way down the rabbit hole. So I think a generic abi.decode in connection with the call via inline assembly should be the way to go.
Given abi.decode and abi.encode availability, what would be very useful is something like
callReturn(bytes) returns (bool, bytes)
input bytes would be encoded with abi.encode
output bool is to signal failure
output bytes are returned abi encoded bytes ready to be decoded with abi.decode
I think we must make this change non-breaking by creating a new function making a raw call.
The original issue statement should be extended that this should apply to all low-level calls: call, delegatecall and staticcall.
In that case we'd need to come up with 3 new names, which seems a bit too much namespace pollution.
Since staticall is close to useless without access to the return value, and since we now have abi.decode and the change in semantics of call, we might also take this in for 0.5.0.
I vote for including it in 0.5.0.
Most helpful comment
This is now possible with
returndatasize/returndatacopy.I am not entirely sure what would be the best method, but perhaps a tuple
(bool, bytes)would be the best for the next breaking release and once multiple return values are supported byCALL(in order to distinguish betweenrevert) I'd consider introducing either(uint, bytes)or(enum, bytes).