diff --git a/Changelog.md b/Changelog.md index fbaddb36f988..4666c5a700a9 100644 --- a/Changelog.md +++ b/Changelog.md @@ -9,6 +9,7 @@ Compiler Features: Bugfixes: * ABIEncoderV2: Fix internal error related to bare delegatecall. + * ABIEncoderV2: Fix internal error related to ecrecover. * ABIEncoderV2: Fix internal error related to mappings as library parameters. * Yul: Properly detect name clashes with functions before their declaration. diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 23522a203f1a..c03cf2c1626d 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -1967,12 +1967,17 @@ void ExpressionCompiler::appendExternalFunctionCall( // If the function takes arbitrary parameters or is a bare call, copy dynamic length data in place. // Move arguments to memory, will not update the free memory pointer (but will update the memory // pointer on the stack). + bool encodeInPlace = _functionType.takesArbitraryParameters() || _functionType.isBareCall(); + if (_functionType.kind() == FunctionType::Kind::ECRecover) + // This would be the only combination of padding and in-place encoding, + // but all parameters of ecrecover are value types anyway. + encodeInPlace = false; bool encodeForLibraryCall = funKind == FunctionType::Kind::DelegateCall; utils().encodeToMemory( argumentTypes, parameterTypes, _functionType.padArguments(), - _functionType.takesArbitraryParameters() || _functionType.isBareCall(), + encodeInPlace, encodeForLibraryCall ); diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index 416990adf487..6c1e31f7f3e3 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -2633,6 +2633,25 @@ BOOST_AUTO_TEST_CASE(ecrecover) ABI_CHECK(callContractFunction("a(bytes32,uint8,bytes32,bytes32)", h, v, r, s), encodeArgs(addr)); } +BOOST_AUTO_TEST_CASE(ecrecover_abiV2) +{ + char const* sourceCode = R"( + pragma experimental ABIEncoderV2; + contract test { + function a(bytes32 h, uint8 v, bytes32 r, bytes32 s) public returns (address addr) { + return ecrecover(h, v, r, s); + } + } + )"; + compileAndRun(sourceCode); + u256 h("0x18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c"); + uint8_t v = 28; + u256 r("0x73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f"); + u256 s("0xeeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549"); + u160 addr("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b"); + ABI_CHECK(callContractFunction("a(bytes32,uint8,bytes32,bytes32)", h, v, r, s), encodeArgs(addr)); +} + BOOST_AUTO_TEST_CASE(inter_contract_calls) { char const* sourceCode = R"(