Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor requireOrAssert to use revertWithError #15058

Merged
merged 1 commit into from Apr 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
33 changes: 9 additions & 24 deletions libsolidity/codegen/YulUtilFunctions.cpp
Expand Up @@ -252,7 +252,7 @@ std::string YulUtilFunctions::revertWithError(
return templ.render();
}

std::string YulUtilFunctions::requireOrAssertFunction(bool _assert, Type const* _messageType)
std::string YulUtilFunctions::requireOrAssertFunction(bool _assert, Type const* _messageType, ASTPointer<Expression const> _stringArgumentExpression)
{
std::string functionName =
std::string(_assert ? "assert_helper" : "require_helper") +
Expand All @@ -271,34 +271,19 @@ std::string YulUtilFunctions::requireOrAssertFunction(bool _assert, Type const*
("functionName", functionName)
.render();

int const hashHeaderSize = 4;
u256 const errorHash = util::selectorFromSignatureU256("Error(string)");

std::string const encodeFunc = ABIFunctions(m_evmVersion, m_revertStrings, m_functionCollector)
.tupleEncoder(
{_messageType},
{TypeProvider::stringMemory()}
);
solAssert(_stringArgumentExpression, "Require with string must have a string argument");
solAssert(_stringArgumentExpression->annotation().type);
std::vector<std::string> functionParameterNames = IRVariable(*_stringArgumentExpression).stackSlots();

return Whiskers(R"(
function <functionName>(condition <messageVars>) {
if iszero(condition) {
let memPtr := <allocateUnbounded>()
mstore(memPtr, <errorHash>)
let end := <abiEncodeFunc>(add(memPtr, <hashHeaderSize>) <messageVars>)
revert(memPtr, sub(end, memPtr))
}
function <functionName>(condition <functionParameterNames>) {
if iszero(condition)
<revertWithError>
}
)")
("functionName", functionName)
("allocateUnbounded", allocateUnboundedFunction())
("errorHash", formatNumber(errorHash))
("abiEncodeFunc", encodeFunc)
("hashHeaderSize", std::to_string(hashHeaderSize))
("messageVars",
(_messageType->sizeOnStack() > 0 ? ", " : "") +
suffixedVariableNameList("message_", 1, 1 + _messageType->sizeOnStack())
)
("revertWithError", revertWithError("Error(string)", {_messageType}, {_stringArgumentExpression}))
("functionParameterNames", joinHumanReadablePrefixed(functionParameterNames))
.render();
});
}
Expand Down
6 changes: 5 additions & 1 deletion libsolidity/codegen/YulUtilFunctions.h
Expand Up @@ -104,7 +104,11 @@ class YulUtilFunctions

// @returns the name of a function that has the equivalent logic of an
// `assert` or `require` call.
std::string requireOrAssertFunction(bool _assert, Type const* _messageType = nullptr);
std::string requireOrAssertFunction(
bool _assert,
Type const* _messageType = nullptr,
ASTPointer<Expression const> _stringArgumentExpression = nullptr
);

// @returns function that has equivalent logic of a require function, but with a custom
// error constructor parameter.
Expand Down
4 changes: 3 additions & 1 deletion libsolidity/codegen/ir/IRGeneratorForStatements.cpp
Expand Up @@ -1166,9 +1166,11 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
}
else
{
ASTPointer<Expression const> stringArgumentExpression = messageArgumentType ? arguments[1] : nullptr;
std::string requireOrAssertFunction = m_utils.requireOrAssertFunction(
functionType->kind() == FunctionType::Kind::Assert,
messageArgumentType
messageArgumentType,
stringArgumentExpression
);
appendCode() << std::move(requireOrAssertFunction) << "(" << IRVariable(*arguments[0]).name();
if (messageArgumentType && messageArgumentType->sizeOnStack() > 0)
Expand Down
9 changes: 3 additions & 6 deletions test/cmdlineTests/require_with_error_ir/input.sol
Expand Up @@ -3,15 +3,12 @@ pragma solidity >=0.0;

error CustomError(uint256, string);

contract C
{
function f(bool condition) external pure
{
contract C {
function f(bool condition) external pure {
nikola-matic marked this conversation as resolved.
Show resolved Hide resolved
require(condition, CustomError(1, "two"));
}

function g(bool condition) external pure
{
function g(bool condition) external pure {
require(condition, CustomError(2, "three"));
}
}
1 change: 1 addition & 0 deletions test/cmdlineTests/require_with_string_ir/args
@@ -0,0 +1 @@
--ir --debug-info none
13 changes: 13 additions & 0 deletions test/cmdlineTests/require_with_string_ir/input.sol
@@ -0,0 +1,13 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.0;

contract C {
function f(bool condition) external pure {
string memory message = "Condition must be satisfied";
require(condition, message);
}

function g(bool condition) external pure {
require(condition, "Condition must be satisfied");
}
}