| 190 | }); |
| 191 | } |
| 192 | std::string ABIFunctions::tupleDecoder(TypePointers const& _types, bool _fromMemory) |
| 193 | { |
| 194 | std::string functionName = std::string("abi_decode_tuple_"); |
| 195 | for (auto const& t: _types) |
| 196 | functionName += t->identifier(); |
| 197 | if (_fromMemory) |
| 198 | functionName += "_fromMemory"; |
| 199 | |
| 200 | return createFunction(functionName, [&]() { |
| 201 | TypePointers decodingTypes; |
| 202 | for (auto const& t: _types) |
| 203 | decodingTypes.emplace_back(t->decodingType()); |
| 204 | |
| 205 | Whiskers templ(R"( |
| 206 | function <functionName>(headStart, dataEnd) <arrow> <valueReturnParams> { |
| 207 | if slt(sub(dataEnd, headStart), <minimumSize>) { <revertString>() } |
| 208 | <decodeElements> |
| 209 | } |
| 210 | )"); |
| 211 | templ("functionName", functionName); |
| 212 | templ("revertString", revertReasonIfDebugFunction("ABI decoding: tuple data too short")); |
| 213 | templ("minimumSize", std::to_string(headSize(decodingTypes))); |
| 214 | |
| 215 | std::string decodeElements; |
| 216 | std::vector<std::string> valueReturnParams; |
| 217 | size_t headPos = 0; |
| 218 | size_t stackPos = 0; |
| 219 | for (size_t i = 0; i < _types.size(); ++i) |
| 220 | { |
| 221 | solAssert(_types[i], ""); |
| 222 | solAssert(decodingTypes[i], ""); |
| 223 | size_t sizeOnStack = _types[i]->sizeOnStack(); |
| 224 | solAssert(sizeOnStack == decodingTypes[i]->sizeOnStack(), ""); |
| 225 | solAssert(sizeOnStack > 0, ""); |
| 226 | std::vector<std::string> valueNamesLocal; |
| 227 | for (size_t j = 0; j < sizeOnStack; j++) |
| 228 | { |
| 229 | valueNamesLocal.emplace_back("value" + std::to_string(stackPos)); |
| 230 | valueReturnParams.emplace_back("value" + std::to_string(stackPos)); |
| 231 | stackPos++; |
| 232 | } |
| 233 | Whiskers elementTempl(R"( |
| 234 | { |
| 235 | <?dynamic> |
| 236 | let offset := <load>(add(headStart, <pos>)) |
| 237 | if gt(offset, 0xffffffffffffffff) { <revertString>() } |
| 238 | <!dynamic> |
| 239 | let offset := <pos> |
| 240 | </dynamic> |
| 241 | <values> := <abiDecode>(add(headStart, offset), dataEnd) |
| 242 | } |
| 243 | )"); |
| 244 | elementTempl("dynamic", decodingTypes[i]->isDynamicallyEncoded()); |
| 245 | // TODO add test |
| 246 | elementTempl("revertString", revertReasonIfDebugFunction("ABI decoding: invalid tuple offset")); |
| 247 | elementTempl("load", _fromMemory ? "mload" : "calldataload"); |
| 248 | elementTempl("values", boost::algorithm::join(valueNamesLocal, ", ")); |
| 249 | elementTempl("pos", std::to_string(headPos)); |
no test coverage detected