mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #7077 from ethereum/sol-yul-delete-fixed-storage
[Sol->Yul] Implement delete for fixed-sized storage arrays
This commit is contained in:
commit
9955c51769
@ -557,7 +557,6 @@ std::string YulUtilFunctions::resizeDynamicArrayFunction(ArrayType const& _type)
|
||||
solAssert(_type.location() == DataLocation::Storage, "");
|
||||
solAssert(_type.isDynamicallySized(), "");
|
||||
solUnimplementedAssert(!_type.isByteArray(), "Byte Arrays not yet implemented!");
|
||||
solUnimplementedAssert(_type.baseType()->isValueType(), "...");
|
||||
solUnimplementedAssert(_type.baseType()->storageBytes() <= 32, "...");
|
||||
solUnimplementedAssert(_type.baseType()->storageSize() == 1, "");
|
||||
|
||||
@ -598,18 +597,62 @@ string YulUtilFunctions::clearStorageRangeFunction(Type const& _type)
|
||||
{
|
||||
string functionName = "clear_storage_range_" + _type.identifier();
|
||||
|
||||
solUnimplementedAssert(_type.isValueType(), "...");
|
||||
solAssert(_type.storageBytes() >= 32, "Expected smaller value for storage bytes");
|
||||
|
||||
return m_functionCollector->createFunction(functionName, [&]() {
|
||||
return Whiskers(R"(
|
||||
function <functionName>(start, end) {
|
||||
for {} lt(start, end) { start := add(start, 1) }
|
||||
for {} lt(start, end) { start := add(start, <increment>) }
|
||||
{
|
||||
sstore(start, 0)
|
||||
<setToZero>(start, 0)
|
||||
}
|
||||
}
|
||||
)")
|
||||
("functionName", functionName)
|
||||
("setToZero", storageSetToZeroFunction(_type))
|
||||
("increment", _type.storageSize().str())
|
||||
.render();
|
||||
});
|
||||
}
|
||||
|
||||
string YulUtilFunctions::clearStorageArrayFunction(ArrayType const& _type)
|
||||
{
|
||||
solAssert(_type.location() == DataLocation::Storage, "");
|
||||
|
||||
if (_type.baseType()->storageBytes() < 32)
|
||||
{
|
||||
solAssert(_type.baseType()->isValueType(), "Invalid storage size for non-value type.");
|
||||
solAssert(_type.baseType()->storageSize() <= 1, "Invalid storage size for type.");
|
||||
}
|
||||
|
||||
if (_type.baseType()->isValueType())
|
||||
solAssert(_type.baseType()->storageSize() <= 1, "Invalid size for value type.");
|
||||
|
||||
string functionName = "clear_storage_array_" + _type.identifier();
|
||||
|
||||
return m_functionCollector->createFunction(functionName, [&]() {
|
||||
return Whiskers(R"(
|
||||
function <functionName>(slot) {
|
||||
<?dynamic>
|
||||
<resizeArray>(slot, 0)
|
||||
<!dynamic>
|
||||
<clearRange>(slot, add(slot, <lenToSize>(<len>)))
|
||||
</dynamic>
|
||||
}
|
||||
)")
|
||||
("functionName", functionName)
|
||||
("dynamic", _type.isDynamicallySized())
|
||||
("resizeArray", _type.isDynamicallySized() ? resizeDynamicArrayFunction(_type) : "")
|
||||
(
|
||||
"clearRange",
|
||||
clearStorageRangeFunction(
|
||||
(_type.baseType()->storageBytes() < 32) ?
|
||||
*TypeProvider::uint256() :
|
||||
*_type.baseType()
|
||||
)
|
||||
)
|
||||
("lenToSize", arrayConvertLengthToSize(_type))
|
||||
("len", _type.length().str())
|
||||
.render();
|
||||
});
|
||||
}
|
||||
@ -1631,6 +1674,35 @@ string YulUtilFunctions::zeroValueFunction(Type const& _type)
|
||||
});
|
||||
}
|
||||
|
||||
string YulUtilFunctions::storageSetToZeroFunction(Type const& _type)
|
||||
{
|
||||
string const functionName = "storage_set_to_zero_" + _type.identifier();
|
||||
|
||||
return m_functionCollector->createFunction(functionName, [&]() {
|
||||
if (_type.isValueType())
|
||||
return Whiskers(R"(
|
||||
function <functionName>(slot, offset) {
|
||||
<store>(slot, offset, <zeroValue>())
|
||||
}
|
||||
)")
|
||||
("functionName", functionName)
|
||||
("store", updateStorageValueFunction(_type))
|
||||
("zeroValue", zeroValueFunction(_type))
|
||||
.render();
|
||||
else if (_type.category() == Type::Category::Array)
|
||||
return Whiskers(R"(
|
||||
function <functionName>(slot, offset) {
|
||||
<clearArray>(slot)
|
||||
}
|
||||
)")
|
||||
("functionName", functionName)
|
||||
("clearArray", clearStorageArrayFunction(dynamic_cast<ArrayType const&>(_type)))
|
||||
.render();
|
||||
else
|
||||
solUnimplemented("setToZero for type " + _type.identifier() + " not yet implemented!");
|
||||
});
|
||||
}
|
||||
|
||||
string YulUtilFunctions::conversionFunctionSpecial(Type const& _from, Type const& _to)
|
||||
{
|
||||
string functionName =
|
||||
|
@ -122,10 +122,14 @@ public:
|
||||
std::string resizeDynamicArrayFunction(ArrayType const& _type);
|
||||
|
||||
/// @returns the name of a function that will clear the storage area given
|
||||
/// by the start and end (exclusive) parameters (slots). Only works for value types.
|
||||
/// by the start and end (exclusive) parameters (slots).
|
||||
/// signature: (start, end)
|
||||
std::string clearStorageRangeFunction(Type const& _type);
|
||||
|
||||
/// @returns the name of a function that will clear the given storage array
|
||||
/// signature: (slot) ->
|
||||
std::string clearStorageArrayFunction(ArrayType const& _type);
|
||||
|
||||
/// Returns the name of a function that will convert a given length to the
|
||||
/// size in memory (number of storage slots or calldata/memory bytes) it
|
||||
/// will require.
|
||||
@ -262,6 +266,11 @@ public:
|
||||
/// @returns the name of a function that returns the zero value for the
|
||||
/// provided type
|
||||
std::string zeroValueFunction(Type const& _type);
|
||||
|
||||
/// @returns the name of a function that will set the given storage item to
|
||||
/// zero
|
||||
/// signature: (slot, offset) ->
|
||||
std::string storageSetToZeroFunction(Type const& _type);
|
||||
private:
|
||||
/// Special case of conversionFunction - handles everything that does not
|
||||
/// use exactly one variable to hold the value.
|
||||
|
@ -135,8 +135,17 @@ string IRStorageItem::storeValue(string const& _value, Type const& _sourceType)
|
||||
|
||||
string IRStorageItem::setToZero() const
|
||||
{
|
||||
solUnimplementedAssert(m_type->isValueType(), "");
|
||||
return storeValue(m_context.utils().zeroValueFunction(*m_type) + "()", *m_type);
|
||||
return
|
||||
m_context.utils().storageSetToZeroFunction(*m_type) +
|
||||
"(" +
|
||||
m_slot +
|
||||
", " +
|
||||
(
|
||||
m_offset.type() == typeid(unsigned) ?
|
||||
to_string(get<unsigned>(m_offset)) :
|
||||
get<string>(m_offset)
|
||||
) +
|
||||
")\n";
|
||||
}
|
||||
|
||||
IRStorageArrayLength::IRStorageArrayLength(IRGenerationContext& _context, string _slot, Type const& _type, ArrayType const& _arrayType):
|
||||
|
@ -3139,14 +3139,16 @@ BOOST_AUTO_TEST_CASE(event_dynamic_nested_array_storage_v2)
|
||||
}
|
||||
}
|
||||
)";
|
||||
compileAndRun(sourceCode);
|
||||
u256 x(42);
|
||||
callContractFunction("createEvent(uint256)", x);
|
||||
BOOST_REQUIRE_EQUAL(m_logs.size(), 1);
|
||||
BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress);
|
||||
BOOST_CHECK(m_logs[0].data == encodeArgs(0x20, 2, 0x40, 0xa0, 2, x, x + 1, 2, x + 2, x + 3));
|
||||
BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 1);
|
||||
BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::keccak256(string("E(uint256[][])")));
|
||||
ALSO_VIA_YUL(
|
||||
compileAndRun(sourceCode);
|
||||
u256 x(42);
|
||||
callContractFunction("createEvent(uint256)", x);
|
||||
BOOST_REQUIRE_EQUAL(m_logs.size(), 1);
|
||||
BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress);
|
||||
BOOST_CHECK(m_logs[0].data == encodeArgs(0x20, 2, 0x40, 0xa0, 2, x, x + 1, 2, x + 2, x + 3));
|
||||
BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 1);
|
||||
BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::keccak256(string("E(uint256[][])")));
|
||||
);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(event_indexed_string)
|
||||
@ -4384,12 +4386,14 @@ BOOST_AUTO_TEST_CASE(fixed_array_cleanup)
|
||||
function clear() public { delete data; }
|
||||
}
|
||||
)";
|
||||
compileAndRun(sourceCode);
|
||||
BOOST_CHECK(storageEmpty(m_contractAddress));
|
||||
ABI_CHECK(callContractFunction("fill()"), bytes());
|
||||
BOOST_CHECK(!storageEmpty(m_contractAddress));
|
||||
ABI_CHECK(callContractFunction("clear()"), bytes());
|
||||
BOOST_CHECK(storageEmpty(m_contractAddress));
|
||||
ALSO_VIA_YUL(
|
||||
compileAndRun(sourceCode);
|
||||
BOOST_CHECK(storageEmpty(m_contractAddress));
|
||||
ABI_CHECK(callContractFunction("fill()"), bytes());
|
||||
BOOST_CHECK(!storageEmpty(m_contractAddress));
|
||||
ABI_CHECK(callContractFunction("clear()"), bytes());
|
||||
BOOST_CHECK(storageEmpty(m_contractAddress));
|
||||
);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(short_fixed_array_cleanup)
|
||||
@ -4405,12 +4409,14 @@ BOOST_AUTO_TEST_CASE(short_fixed_array_cleanup)
|
||||
function clear() public { delete data; }
|
||||
}
|
||||
)";
|
||||
compileAndRun(sourceCode);
|
||||
BOOST_CHECK(storageEmpty(m_contractAddress));
|
||||
ABI_CHECK(callContractFunction("fill()"), bytes());
|
||||
BOOST_CHECK(!storageEmpty(m_contractAddress));
|
||||
ABI_CHECK(callContractFunction("clear()"), bytes());
|
||||
BOOST_CHECK(storageEmpty(m_contractAddress));
|
||||
ALSO_VIA_YUL(
|
||||
compileAndRun(sourceCode);
|
||||
BOOST_CHECK(storageEmpty(m_contractAddress));
|
||||
ABI_CHECK(callContractFunction("fill()"), bytes());
|
||||
BOOST_CHECK(!storageEmpty(m_contractAddress));
|
||||
ABI_CHECK(callContractFunction("clear()"), bytes());
|
||||
BOOST_CHECK(storageEmpty(m_contractAddress));
|
||||
);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(dynamic_array_cleanup)
|
||||
@ -4427,14 +4433,16 @@ BOOST_AUTO_TEST_CASE(dynamic_array_cleanup)
|
||||
function fullClear() public { delete dynamic; }
|
||||
}
|
||||
)";
|
||||
compileAndRun(sourceCode);
|
||||
BOOST_CHECK(storageEmpty(m_contractAddress));
|
||||
ABI_CHECK(callContractFunction("fill()"), bytes());
|
||||
BOOST_CHECK(!storageEmpty(m_contractAddress));
|
||||
ABI_CHECK(callContractFunction("halfClear()"), bytes());
|
||||
BOOST_CHECK(!storageEmpty(m_contractAddress));
|
||||
ABI_CHECK(callContractFunction("fullClear()"), bytes());
|
||||
BOOST_CHECK(storageEmpty(m_contractAddress));
|
||||
ALSO_VIA_YUL(
|
||||
compileAndRun(sourceCode);
|
||||
BOOST_CHECK(storageEmpty(m_contractAddress));
|
||||
ABI_CHECK(callContractFunction("fill()"), bytes());
|
||||
BOOST_CHECK(!storageEmpty(m_contractAddress));
|
||||
ABI_CHECK(callContractFunction("halfClear()"), bytes());
|
||||
BOOST_CHECK(!storageEmpty(m_contractAddress));
|
||||
ABI_CHECK(callContractFunction("fullClear()"), bytes());
|
||||
BOOST_CHECK(storageEmpty(m_contractAddress));
|
||||
);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(dynamic_multi_array_cleanup)
|
||||
@ -6651,17 +6659,19 @@ BOOST_AUTO_TEST_CASE(arrays_complex_memory_index_access)
|
||||
}
|
||||
}
|
||||
)";
|
||||
compileAndRun(sourceCode, 0, "Test");
|
||||
|
||||
vector<u256> data{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18};
|
||||
BOOST_REQUIRE(callContractFunction(
|
||||
"set(uint24[3][],uint256,uint256)",
|
||||
u256(0x60),
|
||||
u256(3),
|
||||
u256(2),
|
||||
u256(data.size() / 3),
|
||||
data
|
||||
) == encodeArgs(u256(data.size() / 3), u256(data[3 * 3 + 2])));
|
||||
ALSO_VIA_YUL(
|
||||
compileAndRun(sourceCode, 0, "Test");
|
||||
|
||||
BOOST_REQUIRE(callContractFunction(
|
||||
"set(uint24[3][],uint256,uint256)",
|
||||
u256(0x60),
|
||||
u256(3),
|
||||
u256(2),
|
||||
u256(data.size() / 3),
|
||||
data
|
||||
) == encodeArgs(u256(data.size() / 3), u256(data[3 * 3 + 2])));
|
||||
);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(bytes_memory_index_access)
|
||||
@ -6674,16 +6684,19 @@ BOOST_AUTO_TEST_CASE(bytes_memory_index_access)
|
||||
}
|
||||
}
|
||||
)";
|
||||
compileAndRun(sourceCode, 0, "Test");
|
||||
|
||||
string data("abcdefgh");
|
||||
BOOST_REQUIRE(callContractFunction(
|
||||
"set(bytes,uint256)",
|
||||
u256(0x40),
|
||||
u256(3),
|
||||
u256(data.size()),
|
||||
data
|
||||
) == encodeArgs(u256(data.size()), string("d")));
|
||||
|
||||
ALSO_VIA_YUL(
|
||||
compileAndRun(sourceCode, 0, "Test");
|
||||
|
||||
BOOST_REQUIRE(callContractFunction(
|
||||
"set(bytes,uint256)",
|
||||
u256(0x40),
|
||||
u256(3),
|
||||
u256(data.size()),
|
||||
data
|
||||
) == encodeArgs(u256(data.size()), string("d")));
|
||||
);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(storage_array_ref)
|
||||
@ -6720,23 +6733,25 @@ BOOST_AUTO_TEST_CASE(storage_array_ref)
|
||||
}
|
||||
}
|
||||
)";
|
||||
compileAndRun(sourceCode, 0, "Store");
|
||||
BOOST_REQUIRE(callContractFunction("find(uint256)", u256(7)) == encodeArgs(u256(-1)));
|
||||
BOOST_REQUIRE(callContractFunction("add(uint256)", u256(7)) == encodeArgs());
|
||||
BOOST_REQUIRE(callContractFunction("find(uint256)", u256(7)) == encodeArgs(u256(0)));
|
||||
ABI_CHECK(callContractFunction("add(uint256)", u256(11)), encodeArgs());
|
||||
ABI_CHECK(callContractFunction("add(uint256)", u256(17)), encodeArgs());
|
||||
ABI_CHECK(callContractFunction("add(uint256)", u256(27)), encodeArgs());
|
||||
ABI_CHECK(callContractFunction("add(uint256)", u256(31)), encodeArgs());
|
||||
ABI_CHECK(callContractFunction("add(uint256)", u256(32)), encodeArgs());
|
||||
ABI_CHECK(callContractFunction("add(uint256)", u256(66)), encodeArgs());
|
||||
ABI_CHECK(callContractFunction("add(uint256)", u256(177)), encodeArgs());
|
||||
ABI_CHECK(callContractFunction("find(uint256)", u256(7)), encodeArgs(u256(0)));
|
||||
ABI_CHECK(callContractFunction("find(uint256)", u256(27)), encodeArgs(u256(3)));
|
||||
ABI_CHECK(callContractFunction("find(uint256)", u256(32)), encodeArgs(u256(5)));
|
||||
ABI_CHECK(callContractFunction("find(uint256)", u256(176)), encodeArgs(u256(-1)));
|
||||
ABI_CHECK(callContractFunction("find(uint256)", u256(0)), encodeArgs(u256(-1)));
|
||||
ABI_CHECK(callContractFunction("find(uint256)", u256(400)), encodeArgs(u256(-1)));
|
||||
ALSO_VIA_YUL(
|
||||
compileAndRun(sourceCode, 0, "Store");
|
||||
BOOST_REQUIRE(callContractFunction("find(uint256)", u256(7)) == encodeArgs(u256(-1)));
|
||||
BOOST_REQUIRE(callContractFunction("add(uint256)", u256(7)) == encodeArgs());
|
||||
BOOST_REQUIRE(callContractFunction("find(uint256)", u256(7)) == encodeArgs(u256(0)));
|
||||
ABI_CHECK(callContractFunction("add(uint256)", u256(11)), encodeArgs());
|
||||
ABI_CHECK(callContractFunction("add(uint256)", u256(17)), encodeArgs());
|
||||
ABI_CHECK(callContractFunction("add(uint256)", u256(27)), encodeArgs());
|
||||
ABI_CHECK(callContractFunction("add(uint256)", u256(31)), encodeArgs());
|
||||
ABI_CHECK(callContractFunction("add(uint256)", u256(32)), encodeArgs());
|
||||
ABI_CHECK(callContractFunction("add(uint256)", u256(66)), encodeArgs());
|
||||
ABI_CHECK(callContractFunction("add(uint256)", u256(177)), encodeArgs());
|
||||
ABI_CHECK(callContractFunction("find(uint256)", u256(7)), encodeArgs(u256(0)));
|
||||
ABI_CHECK(callContractFunction("find(uint256)", u256(27)), encodeArgs(u256(3)));
|
||||
ABI_CHECK(callContractFunction("find(uint256)", u256(32)), encodeArgs(u256(5)));
|
||||
ABI_CHECK(callContractFunction("find(uint256)", u256(176)), encodeArgs(u256(-1)));
|
||||
ABI_CHECK(callContractFunction("find(uint256)", u256(0)), encodeArgs(u256(-1)));
|
||||
ABI_CHECK(callContractFunction("find(uint256)", u256(400)), encodeArgs(u256(-1)));
|
||||
);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(memory_types_initialisation)
|
||||
|
Loading…
Reference in New Issue
Block a user