mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Allow encoding calldata arrays for base types that do not require cleanup.
This commit is contained in:
parent
ee2f566207
commit
b0cb330397
@ -607,20 +607,32 @@ string ABIFunctions::abiEncodingFunction(
|
|||||||
solAssert(_from.category() == Type::Category::Array, "");
|
solAssert(_from.category() == Type::Category::Array, "");
|
||||||
solAssert(to.dataStoredIn(DataLocation::Memory), "");
|
solAssert(to.dataStoredIn(DataLocation::Memory), "");
|
||||||
ArrayType const& fromArray = dynamic_cast<ArrayType const&>(_from);
|
ArrayType const& fromArray = dynamic_cast<ArrayType const&>(_from);
|
||||||
if (fromArray.location() == DataLocation::CallData)
|
|
||||||
return abiEncodingFunctionCalldataArray(fromArray, *toArray, _options);
|
switch (fromArray.location())
|
||||||
else if (!fromArray.isByteArray() && (
|
{
|
||||||
fromArray.location() == DataLocation::Memory ||
|
case DataLocation::CallData:
|
||||||
fromArray.baseType()->storageBytes() > 16
|
if (
|
||||||
))
|
fromArray.isByteArray() ||
|
||||||
|
*fromArray.baseType() == IntegerType::uint256() ||
|
||||||
|
*fromArray.baseType() == FixedBytesType(32)
|
||||||
|
)
|
||||||
|
return abiEncodingFunctionCalldataArrayWithoutCleanup(fromArray, *toArray, _options);
|
||||||
|
else
|
||||||
return abiEncodingFunctionSimpleArray(fromArray, *toArray, _options);
|
return abiEncodingFunctionSimpleArray(fromArray, *toArray, _options);
|
||||||
else if (fromArray.location() == DataLocation::Memory)
|
case DataLocation::Memory:
|
||||||
|
if (fromArray.isByteArray())
|
||||||
return abiEncodingFunctionMemoryByteArray(fromArray, *toArray, _options);
|
return abiEncodingFunctionMemoryByteArray(fromArray, *toArray, _options);
|
||||||
else if (fromArray.location() == DataLocation::Storage)
|
else
|
||||||
|
return abiEncodingFunctionSimpleArray(fromArray, *toArray, _options);
|
||||||
|
case DataLocation::Storage:
|
||||||
|
if (fromArray.baseType()->storageBytes() <= 16)
|
||||||
return abiEncodingFunctionCompactStorageArray(fromArray, *toArray, _options);
|
return abiEncodingFunctionCompactStorageArray(fromArray, *toArray, _options);
|
||||||
else
|
else
|
||||||
|
return abiEncodingFunctionSimpleArray(fromArray, *toArray, _options);
|
||||||
|
default:
|
||||||
solAssert(false, "");
|
solAssert(false, "");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else if (auto const* toStruct = dynamic_cast<StructType const*>(&to))
|
else if (auto const* toStruct = dynamic_cast<StructType const*>(&to))
|
||||||
{
|
{
|
||||||
StructType const* fromStruct = dynamic_cast<StructType const*>(&_from);
|
StructType const* fromStruct = dynamic_cast<StructType const*>(&_from);
|
||||||
@ -721,19 +733,24 @@ string ABIFunctions::abiEncodeAndReturnUpdatedPosFunction(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
string ABIFunctions::abiEncodingFunctionCalldataArray(
|
string ABIFunctions::abiEncodingFunctionCalldataArrayWithoutCleanup(
|
||||||
Type const& _from,
|
Type const& _from,
|
||||||
Type const& _to,
|
Type const& _to,
|
||||||
EncodingOptions const& _options
|
EncodingOptions const& _options
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
solAssert(_to.isDynamicallySized(), "");
|
|
||||||
solAssert(_from.category() == Type::Category::Array, "Unknown dynamic type.");
|
solAssert(_from.category() == Type::Category::Array, "Unknown dynamic type.");
|
||||||
solAssert(_to.category() == Type::Category::Array, "Unknown dynamic type.");
|
solAssert(_to.category() == Type::Category::Array, "Unknown dynamic type.");
|
||||||
auto const& fromArrayType = dynamic_cast<ArrayType const&>(_from);
|
auto const& fromArrayType = dynamic_cast<ArrayType const&>(_from);
|
||||||
auto const& toArrayType = dynamic_cast<ArrayType const&>(_to);
|
auto const& toArrayType = dynamic_cast<ArrayType const&>(_to);
|
||||||
|
|
||||||
solAssert(fromArrayType.location() == DataLocation::CallData, "");
|
solAssert(fromArrayType.location() == DataLocation::CallData, "");
|
||||||
|
solAssert(
|
||||||
|
fromArrayType.isByteArray() ||
|
||||||
|
*fromArrayType.baseType() == IntegerType::uint256() ||
|
||||||
|
*fromArrayType.baseType() == FixedBytesType(32),
|
||||||
|
"");
|
||||||
|
solAssert(fromArrayType.calldataStride() == toArrayType.memoryStride(), "");
|
||||||
|
|
||||||
solAssert(
|
solAssert(
|
||||||
*fromArrayType.copyForLocation(DataLocation::Memory, true) ==
|
*fromArrayType.copyForLocation(DataLocation::Memory, true) ==
|
||||||
@ -748,24 +765,54 @@ string ABIFunctions::abiEncodingFunctionCalldataArray(
|
|||||||
_to.identifier() +
|
_to.identifier() +
|
||||||
_options.toFunctionNameSuffix();
|
_options.toFunctionNameSuffix();
|
||||||
return createFunction(functionName, [&]() {
|
return createFunction(functionName, [&]() {
|
||||||
solUnimplementedAssert(fromArrayType.isByteArray(), "Only byte arrays can be encoded from calldata currently.");
|
bool needsPadding = _options.padded && fromArrayType.isByteArray();
|
||||||
// TODO if this is not a byte array, we might just copy byte-by-byte anyway,
|
if (fromArrayType.isDynamicallySized())
|
||||||
// because the encoding is position-independent, but we have to check that.
|
{
|
||||||
Whiskers templ(R"(
|
Whiskers templ(R"(
|
||||||
// <readableTypeNameFrom> -> <readableTypeNameTo>
|
// <readableTypeNameFrom> -> <readableTypeNameTo>
|
||||||
function <functionName>(start, length, pos) -> end {
|
function <functionName>(start, length, pos) -> end {
|
||||||
pos := <storeLength>(pos, length)
|
pos := <storeLength>(pos, length)
|
||||||
|
<scaleLengthByStride>
|
||||||
<copyFun>(start, pos, length)
|
<copyFun>(start, pos, length)
|
||||||
end := add(pos, <lengthPadded>)
|
end := add(pos, <lengthPadded>)
|
||||||
}
|
}
|
||||||
)");
|
)");
|
||||||
templ("storeLength", arrayStoreLengthForEncodingFunction(toArrayType, _options));
|
templ("storeLength", arrayStoreLengthForEncodingFunction(toArrayType, _options));
|
||||||
templ("functionName", functionName);
|
templ("functionName", functionName);
|
||||||
|
if (fromArrayType.isByteArray() || fromArrayType.calldataStride() == 1)
|
||||||
|
templ("scaleLengthByStride", "");
|
||||||
|
else
|
||||||
|
templ("scaleLengthByStride",
|
||||||
|
Whiskers(R"(
|
||||||
|
if gt(length, <maxLength>) { revert(0, 0) }
|
||||||
|
length := mul(length, <stride>)
|
||||||
|
)")
|
||||||
|
("stride", toCompactHexWithPrefix(fromArrayType.calldataStride()))
|
||||||
|
("maxLength", toCompactHexWithPrefix(u256(-1) / fromArrayType.calldataStride()))
|
||||||
|
.render()
|
||||||
|
);
|
||||||
templ("readableTypeNameFrom", _from.toString(true));
|
templ("readableTypeNameFrom", _from.toString(true));
|
||||||
templ("readableTypeNameTo", _to.toString(true));
|
templ("readableTypeNameTo", _to.toString(true));
|
||||||
templ("copyFun", m_utils.copyToMemoryFunction(true));
|
templ("copyFun", m_utils.copyToMemoryFunction(true));
|
||||||
templ("lengthPadded", _options.padded ? m_utils.roundUpFunction() + "(length)" : "length");
|
templ("lengthPadded", needsPadding ? m_utils.roundUpFunction() + "(length)" : "length");
|
||||||
return templ.render();
|
return templ.render();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
solAssert(fromArrayType.calldataStride() == 32, "");
|
||||||
|
Whiskers templ(R"(
|
||||||
|
// <readableTypeNameFrom> -> <readableTypeNameTo>
|
||||||
|
function <functionName>(start, pos) {
|
||||||
|
<copyFun>(start, pos, <byteLength>)
|
||||||
|
}
|
||||||
|
)");
|
||||||
|
templ("functionName", functionName);
|
||||||
|
templ("readableTypeNameFrom", _from.toString(true));
|
||||||
|
templ("readableTypeNameTo", _to.toString(true));
|
||||||
|
templ("copyFun", m_utils.copyToMemoryFunction(true));
|
||||||
|
templ("byteLength", toCompactHexWithPrefix(fromArrayType.length() * fromArrayType.calldataStride()));
|
||||||
|
return templ.render();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -176,7 +176,9 @@ private:
|
|||||||
EncodingOptions const& _options
|
EncodingOptions const& _options
|
||||||
);
|
);
|
||||||
/// Part of @a abiEncodingFunction for array target type and given calldata array.
|
/// Part of @a abiEncodingFunction for array target type and given calldata array.
|
||||||
std::string abiEncodingFunctionCalldataArray(
|
/// Uses calldatacopy and does not perform cleanup or validation and can therefore only
|
||||||
|
/// be used for byte arrays and arrays with the base type uint256 or bytes32.
|
||||||
|
std::string abiEncodingFunctionCalldataArrayWithoutCleanup(
|
||||||
Type const& _givenType,
|
Type const& _givenType,
|
||||||
Type const& _targetType,
|
Type const& _targetType,
|
||||||
EncodingOptions const& _options
|
EncodingOptions const& _options
|
||||||
|
Loading…
Reference in New Issue
Block a user