Merge pull request #8841 from ethereum/sol_yul_ripemd160_ecrecover

[Sol - Yul] Add support for ripemd160 & ecrecover.
This commit is contained in:
chriseth 2020-05-14 18:43:55 +02:00 committed by GitHub
commit 7ef114db9a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 77 additions and 8 deletions

View File

@ -952,14 +952,6 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
"))\n"; "))\n";
break; break;
} }
case FunctionType::Kind::ECRecover:
case FunctionType::Kind::SHA256:
case FunctionType::Kind::RIPEMD160:
{
solAssert(!_functionCall.annotation().tryCall, "");
appendExternalFunctionCall(_functionCall, arguments);
break;
}
case FunctionType::Kind::ArrayPop: case FunctionType::Kind::ArrayPop:
{ {
auto const& memberAccessExpression = dynamic_cast<MemberAccess const&>(_functionCall.expression()).expression(); auto const& memberAccessExpression = dynamic_cast<MemberAccess const&>(_functionCall.expression()).expression();
@ -1153,6 +1145,69 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
break; break;
} }
case FunctionType::Kind::ECRecover:
case FunctionType::Kind::RIPEMD160:
case FunctionType::Kind::SHA256:
{
solAssert(!_functionCall.annotation().tryCall, "");
solAssert(!functionType->valueSet(), "");
solAssert(!functionType->gasSet(), "");
solAssert(!functionType->bound(), "");
static map<FunctionType::Kind, std::tuple<u160, size_t>> precompiles = {
{FunctionType::Kind::ECRecover, std::make_tuple(1, 0)},
{FunctionType::Kind::SHA256, std::make_tuple(2, 0)},
{FunctionType::Kind::RIPEMD160, std::make_tuple(3, 12)},
};
auto [ address, offset ] = precompiles[functionType->kind()];
TypePointers argumentTypes;
vector<string> argumentStrings;
for (auto const& arg: arguments)
{
argumentTypes.emplace_back(&type(*arg));
argumentStrings += IRVariable(*arg).stackSlots();
}
Whiskers templ(R"(
let <pos> := <allocateTemporary>()
let <end> := <encodeArgs>(<pos> <argumentString>)
<?isECRecover>
mstore(0, 0)
</isECRecover>
let <success> := <call>(<gas>, <address> <?isCall>, 0</isCall>, <pos>, sub(<end>, <pos>), 0, 32)
if iszero(<success>) { <forwardingRevert>() }
let <retVars> := <shl>(mload(0))
)");
templ("call", m_context.evmVersion().hasStaticCall() ? "staticcall" : "call");
templ("isCall", !m_context.evmVersion().hasStaticCall());
templ("shl", m_utils.shiftLeftFunction(offset * 8));
templ("allocateTemporary", m_utils.allocationTemporaryMemoryFunction());
templ("pos", m_context.newYulVariable());
templ("end", m_context.newYulVariable());
templ("isECRecover", FunctionType::Kind::ECRecover == functionType->kind());
if (FunctionType::Kind::ECRecover == functionType->kind())
templ("encodeArgs", m_context.abiFunctions().tupleEncoder(argumentTypes, parameterTypes));
else
templ("encodeArgs", m_context.abiFunctions().tupleEncoderPacked(argumentTypes, parameterTypes));
templ("argumentString", joinHumanReadablePrefixed(argumentStrings));
templ("address", toString(address));
templ("success", m_context.newYulVariable());
templ("retVars", IRVariable(_functionCall).commaSeparatedList());
templ("forwardingRevert", m_utils.forwardingRevertFunction());
if (m_context.evmVersion().canOverchargeGasForCall())
// Send all gas (requires tangerine whistle EVM)
templ("gas", "gas()");
else
{
// @todo The value 10 is not exact and this could be fine-tuned,
// but this has worked for years in the old code generator.
u256 gasNeededByCaller = evmasm::GasCosts::callGas(m_context.evmVersion()) + 10 + evmasm::GasCosts::callNewAccountGas;
templ("gas", "sub(gas(), " + formatNumber(gasNeededByCaller) + ")");
}
m_code << templ.render();
break;
}
default: default:
solUnimplemented("FunctionKind " + toString(static_cast<int>(functionType->kind())) + " not yet implemented"); solUnimplemented("FunctionKind " + toString(static_cast<int>(functionType->kind())) + " not yet implemented");
} }

View File

@ -4,5 +4,7 @@ contract C {
} }
} }
// ====
// compileViaYul: also
// ---- // ----
// f() -> 0x9c1185a5c5e9fc54612808977ee8f548b2258d31000000000000000000000000 // f() -> 0x9c1185a5c5e9fc54612808977ee8f548b2258d31000000000000000000000000

View File

@ -3,5 +3,7 @@ contract C {
return sha256(""); return sha256("");
} }
} }
// ====
// compileViaYul: also
// ---- // ----
// f() -> 0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 // f() -> 0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855

View File

@ -3,6 +3,8 @@ contract test {
return ecrecover(h, v, r, s); return ecrecover(h, v, r, s);
} }
} }
// ====
// compileViaYul: also
// ---- // ----
// a(bytes32,uint8,bytes32,bytes32): // a(bytes32,uint8,bytes32,bytes32):
// 0x18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c, // 0x18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c,

View File

@ -4,6 +4,8 @@ contract test {
return ecrecover(h, v, r, s); return ecrecover(h, v, r, s);
} }
} }
// ====
// compileViaYul: also
// ---- // ----
// a(bytes32,uint8,bytes32,bytes32): // a(bytes32,uint8,bytes32,bytes32):
// 0x18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c, // 0x18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c,

View File

@ -6,5 +6,7 @@ contract C {
return ecrecover(bytes32(uint(-1)), 1, bytes32(uint(2)), bytes32(uint(3))); return ecrecover(bytes32(uint(-1)), 1, bytes32(uint(2)), bytes32(uint(3)));
} }
} }
// ====
// compileViaYul: also
// ---- // ----
// f() -> 0 // f() -> 0

View File

@ -11,5 +11,7 @@ contract C {
); );
} }
} }
// ====
// compileViaYul: also
// ---- // ----
// f() -> 0 // f() -> 0

View File

@ -16,5 +16,7 @@ contract C {
return ecrecover(hash, v, r, s); return ecrecover(hash, v, r, s);
} }
} }
// ====
// compileViaYul: also
// ---- // ----
// f() -> 0 // f() -> 0