Merge pull request #2982 from ethereum/encoderFixes

ABI encoder fixes and test.
This commit is contained in:
Alex Beregszaszi 2017-10-05 11:59:42 +01:00 committed by GitHub
commit 6ba0c2bba8
3 changed files with 104 additions and 30 deletions

View File

@ -87,7 +87,7 @@ string ABIFunctions::tupleEncoder(
);
elementTempl("values", valueNames);
elementTempl("pos", to_string(headPos));
elementTempl("abiEncode", abiEncodingFunction(*_givenTypes[i], *_targetTypes[i], _encodeAsLibraryTypes, false));
elementTempl("abiEncode", abiEncodingFunction(*_givenTypes[i], *_targetTypes[i], _encodeAsLibraryTypes, true));
encodeElements += elementTempl.render();
headPos += dynamic ? 0x20 : _targetTypes[i]->calldataEncodedSize();
}
@ -371,7 +371,7 @@ string ABIFunctions::abiEncodingFunction(
Type const& _from,
Type const& _to,
bool _encodeAsLibraryTypes,
bool _compacted
bool _fromStack
)
{
solUnimplementedAssert(
@ -415,7 +415,7 @@ string ABIFunctions::abiEncodingFunction(
dynamic_cast<FunctionType const&>(_from),
to,
_encodeAsLibraryTypes,
_compacted
_fromStack
);
solAssert(_from.sizeOnStack() == 1, "");
@ -542,7 +542,7 @@ string ABIFunctions::abiEncodingFunctionSimpleArray(
mstore(pos, sub(tail, headStart))
tail := <encodeToMemoryFun>(<arrayElementAccess>, tail)
srcPtr := <nextArrayElement>(srcPtr)
pos := add(pos, <elementEncodedSize>)
pos := add(pos, 0x20)
}
pos := tail
<assignEnd>
@ -580,7 +580,7 @@ string ABIFunctions::abiEncodingFunctionSimpleArray(
*_from.baseType(),
*_to.baseType(),
_encodeAsLibraryTypes,
true
false
));
templ("arrayElementAccess", inMemory ? "mload(srcPtr)" : _from.baseType()->isValueType() ? "sload(srcPtr)" : "srcPtr" );
templ("nextArrayElement", nextArrayElementFunction(_from));
@ -729,7 +729,7 @@ string ABIFunctions::abiEncodingFunctionCompactStorageArray(
*_from.baseType(),
*_to.baseType(),
_encodeAsLibraryTypes,
true
false
);
templ("encodeToMemoryFun", encodeToMemoryFun);
std::vector<std::map<std::string, std::string>> items(itemsPerSlot);
@ -925,7 +925,7 @@ string ABIFunctions::abiEncodingFunctionFunctionType(
FunctionType const& _from,
Type const& _to,
bool _encodeAsLibraryTypes,
bool _compacted
bool _fromStack
)
{
solAssert(_from.kind() == FunctionType::Kind::External, "");
@ -936,24 +936,10 @@ string ABIFunctions::abiEncodingFunctionFunctionType(
_from.identifier() +
"_to_" +
_to.identifier() +
(_compacted ? "_compacted" : "") +
(_fromStack ? "_fromStack" : "") +
(_encodeAsLibraryTypes ? "_library" : "");
if (_compacted)
{
return createFunction(functionName, [&]() {
return Whiskers(R"(
function <functionName>(addr_and_function_id, pos) {
mstore(pos, <cleanExtFun>(addr_and_function_id))
}
)")
("functionName", functionName)
("cleanExtFun", cleanupCombinedExternalFunctionIdFunction())
.render();
});
}
else
{
if (_fromStack)
return createFunction(functionName, [&]() {
return Whiskers(R"(
function <functionName>(addr, function_id, pos) {
@ -964,7 +950,17 @@ string ABIFunctions::abiEncodingFunctionFunctionType(
("combineExtFun", combineExternalFunctionIdFunction())
.render();
});
}
else
return createFunction(functionName, [&]() {
return Whiskers(R"(
function <functionName>(addr_and_function_id, pos) {
mstore(pos, <cleanExtFun>(addr_and_function_id))
}
)")
("functionName", functionName)
("cleanExtFun", cleanupCombinedExternalFunctionIdFunction())
.render();
});
}
string ABIFunctions::copyToMemoryFunction(bool _fromCalldata)
@ -1212,10 +1208,7 @@ size_t ABIFunctions::headSize(TypePointers const& _targetTypes)
if (t->isDynamicallyEncoded())
headSize += 0x20;
else
{
solAssert(t->calldataEncodedSize() > 0, "");
headSize += t->calldataEncodedSize();
}
}
return headSize;

View File

@ -89,13 +89,13 @@ private:
/// @returns the name of the ABI encoding function with the given type
/// and queues the generation of the function to the requested functions.
/// @param _compacted if true, the input value was just loaded from storage
/// @param _fromStack if false, the input value was just loaded from storage
/// or memory and thus might be compacted into a single slot (depending on the type).
std::string abiEncodingFunction(
Type const& _givenType,
Type const& _targetType,
bool _encodeAsLibraryTypes,
bool _compacted
bool _fromStack
);
/// Part of @a abiEncodingFunction for array target type and given calldata array.
std::string abiEncodingFunctionCalldataArray(
@ -143,7 +143,7 @@ private:
FunctionType const& _from,
Type const& _to,
bool _encodeAsLibraryTypes,
bool _compacted
bool _fromStack
);
/// @returns a function that copies raw bytes of dynamic length from calldata

View File

@ -462,6 +462,87 @@ BOOST_AUTO_TEST_CASE(structs)
)
}
BOOST_AUTO_TEST_CASE(empty_struct)
{
string sourceCode = R"(
contract C {
struct S { }
S s;
event e(uint16, S, uint16);
function f() returns (uint, S, uint) {
e(7, s, 8);
return (7, s, 8);
}
}
)";
NEW_ENCODER(
compileAndRun(sourceCode, 0, "C");
bytes encoded = encodeArgs(7, 8);
BOOST_CHECK(callContractFunction("f()") == encoded);
REQUIRE_LOG_DATA(encoded);
)
}
BOOST_AUTO_TEST_CASE(structs2)
{
string sourceCode = R"(
contract C {
enum E {A, B, C}
struct T { uint x; E e; uint8 y; }
struct S { C c; T[] t;}
function f() public returns (uint a, S[2] s1, S[] s2, uint b) {
a = 7;
b = 8;
s1[0].c = this;
s1[0].t = new T[](1);
s1[0].t[0].x = 0x11;
s1[0].t[0].e = E.B;
s1[0].t[0].y = 0x12;
s2 = new S[](2);
s2[1].c = C(0x1234);
s2[1].t = new T[](3);
s2[1].t[1].x = 0x21;
s2[1].t[1].e = E.C;
s2[1].t[1].y = 0x22;
}
}
)";
NEW_ENCODER(
compileAndRun(sourceCode, 0, "C");
ABI_CHECK(callContractFunction("f()"), encodeArgs(
7, 0x80, 0x1e0, 8,
// S[2] s1
0x40,
0x100,
// S s1[0]
u256(u160(m_contractAddress)),
0x40,
// T s1[0].t
1, // length
// s1[0].t[0]
0x11, 1, 0x12,
// S s1[1]
0, 0x40,
// T s1[1].t
0,
// S[] s2 (0x1e0)
2, // length
0x40, 0xa0,
// S s2[0]
0, 0x40, 0,
// S s2[1]
0x1234, 0x40,
// s2[1].t
3, // length
0, 0, 0,
0x21, 2, 0x22,
0, 0, 0
));
)
}
BOOST_AUTO_TEST_SUITE_END()
}