mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
[Sol - Yul] Add support for ripemd160 & ecrecover.
This commit is contained in:
parent
b2122d479f
commit
91e9d54c71
@ -952,14 +952,6 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
|
||||
"))\n";
|
||||
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:
|
||||
{
|
||||
auto const& memberAccessExpression = dynamic_cast<MemberAccess const&>(_functionCall.expression()).expression();
|
||||
@ -1153,6 +1145,69 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
|
||||
|
||||
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:
|
||||
solUnimplemented("FunctionKind " + toString(static_cast<int>(functionType->kind())) + " not yet implemented");
|
||||
}
|
||||
|
@ -4,5 +4,7 @@ contract C {
|
||||
}
|
||||
}
|
||||
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// f() -> 0x9c1185a5c5e9fc54612808977ee8f548b2258d31000000000000000000000000
|
||||
|
@ -3,5 +3,7 @@ contract C {
|
||||
return sha256("");
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// f() -> 0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
|
||||
|
@ -3,6 +3,8 @@ contract test {
|
||||
return ecrecover(h, v, r, s);
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// a(bytes32,uint8,bytes32,bytes32):
|
||||
// 0x18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c,
|
||||
|
@ -4,6 +4,8 @@ contract test {
|
||||
return ecrecover(h, v, r, s);
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// a(bytes32,uint8,bytes32,bytes32):
|
||||
// 0x18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c,
|
||||
|
@ -6,5 +6,7 @@ contract C {
|
||||
return ecrecover(bytes32(uint(-1)), 1, bytes32(uint(2)), bytes32(uint(3)));
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// f() -> 0
|
||||
|
@ -11,5 +11,7 @@ contract C {
|
||||
);
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// f() -> 0
|
||||
|
@ -16,5 +16,7 @@ contract C {
|
||||
return ecrecover(hash, v, r, s);
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// f() -> 0
|
||||
|
Loading…
Reference in New Issue
Block a user