mirror of
				https://github.com/ethereum/solidity
				synced 2023-10-03 13:03:40 +00:00 
			
		
		
		
	Provide ABI encoding options as single struct parameter.
This commit is contained in:
		
							parent
							
								
									8f694d5119
								
							
						
					
					
						commit
						7a69455c13
					
				| @ -39,14 +39,19 @@ string ABIFunctions::tupleEncoder( | ||||
| 	bool _encodeAsLibraryTypes | ||||
| ) | ||||
| { | ||||
| 	EncodingOptions options; | ||||
| 	options.encodeAsLibraryTypes = _encodeAsLibraryTypes; | ||||
| 	options.encodeFunctionFromStack = true; | ||||
| 	options.padded = true; | ||||
| 	options.dynamicInplace = false; | ||||
| 
 | ||||
| 	string functionName = string("abi_encode_tuple_"); | ||||
| 	for (auto const& t: _givenTypes) | ||||
| 		functionName += t->identifier() + "_"; | ||||
| 	functionName += "_to_"; | ||||
| 	for (auto const& t: _targetTypes) | ||||
| 		functionName += t->identifier() + "_"; | ||||
| 	if (_encodeAsLibraryTypes) | ||||
| 		functionName += "_library"; | ||||
| 	functionName += options.toFunctionNameSuffix(); | ||||
| 
 | ||||
| 	return createExternallyUsedFunction(functionName, [&]() { | ||||
| 		solAssert(!_givenTypes.empty(), ""); | ||||
| @ -90,7 +95,7 @@ string ABIFunctions::tupleEncoder( | ||||
| 			); | ||||
| 			elementTempl("values", valueNames); | ||||
| 			elementTempl("pos", to_string(headPos)); | ||||
| 			elementTempl("abiEncode", abiEncodingFunction(*_givenTypes[i], *_targetTypes[i], _encodeAsLibraryTypes, true)); | ||||
| 			elementTempl("abiEncode", abiEncodingFunction(*_givenTypes[i], *_targetTypes[i], options)); | ||||
| 			encodeElements += elementTempl.render(); | ||||
| 			headPos += dynamic ? 0x20 : _targetTypes[i]->calldataEncodedSize(); | ||||
| 		} | ||||
| @ -184,6 +189,20 @@ pair<string, set<string>> ABIFunctions::requestedFunctions() | ||||
| 	return make_pair(result, std::move(m_externallyUsedFunctions)); | ||||
| } | ||||
| 
 | ||||
| string ABIFunctions::EncodingOptions::toFunctionNameSuffix() const | ||||
| { | ||||
| 	string suffix; | ||||
| 	if (!padded) | ||||
| 		suffix += "_nonPadded"; | ||||
| 	if (dynamicInplace) | ||||
| 		suffix += "_inplace"; | ||||
| 	if (encodeFunctionFromStack) | ||||
| 		suffix += "_fromStack"; | ||||
| 	if (encodeAsLibraryTypes) | ||||
| 		suffix += "_library"; | ||||
| 	return suffix; | ||||
| } | ||||
| 
 | ||||
| string ABIFunctions::cleanupFunction(Type const& _type, bool _revertOnFailure) | ||||
| { | ||||
| 	string functionName = string("cleanup_") + (_revertOnFailure ? "revert_" : "assert_") + _type.identifier(); | ||||
| @ -490,32 +509,31 @@ string ABIFunctions::splitExternalFunctionIdFunction() | ||||
| string ABIFunctions::abiEncodingFunction( | ||||
| 	Type const& _from, | ||||
| 	Type const& _to, | ||||
| 	bool _encodeAsLibraryTypes, | ||||
| 	bool _fromStack | ||||
| 	EncodingOptions const& _options | ||||
| ) | ||||
| { | ||||
| 	TypePointer toInterface = _to.fullEncodingType(_encodeAsLibraryTypes, true, false); | ||||
| 	TypePointer toInterface = _to.fullEncodingType(_options.encodeAsLibraryTypes, true, false); | ||||
| 	solUnimplementedAssert(toInterface, "Encoding type \"" + _to.toString() + "\" not yet implemented."); | ||||
| 	Type const& to = *toInterface; | ||||
| 
 | ||||
| 	if (_from.category() == Type::Category::StringLiteral) | ||||
| 		return abiEncodingFunctionStringLiteral(_from, to, _encodeAsLibraryTypes); | ||||
| 		return abiEncodingFunctionStringLiteral(_from, to, _options); | ||||
| 	else if (auto toArray = dynamic_cast<ArrayType const*>(&to)) | ||||
| 	{ | ||||
| 		solAssert(_from.category() == Type::Category::Array, ""); | ||||
| 		solAssert(to.dataStoredIn(DataLocation::Memory), ""); | ||||
| 		ArrayType const& fromArray = dynamic_cast<ArrayType const&>(_from); | ||||
| 		if (fromArray.location() == DataLocation::CallData) | ||||
| 			return abiEncodingFunctionCalldataArray(fromArray, *toArray, _encodeAsLibraryTypes); | ||||
| 			return abiEncodingFunctionCalldataArray(fromArray, *toArray, _options); | ||||
| 		else if (!fromArray.isByteArray() && ( | ||||
| 				fromArray.location() == DataLocation::Memory || | ||||
| 				fromArray.baseType()->storageBytes() > 16 | ||||
| 		)) | ||||
| 			return abiEncodingFunctionSimpleArray(fromArray, *toArray, _encodeAsLibraryTypes); | ||||
| 			return abiEncodingFunctionSimpleArray(fromArray, *toArray, _options); | ||||
| 		else if (fromArray.location() == DataLocation::Memory) | ||||
| 			return abiEncodingFunctionMemoryByteArray(fromArray, *toArray, _encodeAsLibraryTypes); | ||||
| 			return abiEncodingFunctionMemoryByteArray(fromArray, *toArray, _options); | ||||
| 		else if (fromArray.location() == DataLocation::Storage) | ||||
| 			return abiEncodingFunctionCompactStorageArray(fromArray, *toArray, _encodeAsLibraryTypes); | ||||
| 			return abiEncodingFunctionCompactStorageArray(fromArray, *toArray, _options); | ||||
| 		else | ||||
| 			solAssert(false, ""); | ||||
| 	} | ||||
| @ -523,14 +541,13 @@ string ABIFunctions::abiEncodingFunction( | ||||
| 	{ | ||||
| 		StructType const* fromStruct = dynamic_cast<StructType const*>(&_from); | ||||
| 		solAssert(fromStruct, ""); | ||||
| 		return abiEncodingFunctionStruct(*fromStruct, *toStruct, _encodeAsLibraryTypes); | ||||
| 		return abiEncodingFunctionStruct(*fromStruct, *toStruct, _options); | ||||
| 	} | ||||
| 	else if (_from.category() == Type::Category::Function) | ||||
| 		return abiEncodingFunctionFunctionType( | ||||
| 			dynamic_cast<FunctionType const&>(_from), | ||||
| 			to, | ||||
| 			_encodeAsLibraryTypes, | ||||
| 			_fromStack | ||||
| 			_options | ||||
| 		); | ||||
| 
 | ||||
| 	solAssert(_from.sizeOnStack() == 1, ""); | ||||
| @ -541,7 +558,7 @@ string ABIFunctions::abiEncodingFunction( | ||||
| 		_from.identifier() + | ||||
| 		"_to_" + | ||||
| 		to.identifier() + | ||||
| 		(_encodeAsLibraryTypes ? "_library" : ""); | ||||
| 		_options.toFunctionNameSuffix(); | ||||
| 	return createFunction(functionName, [&]() { | ||||
| 		solAssert(!to.isDynamicallyEncoded(), ""); | ||||
| 
 | ||||
| @ -556,7 +573,7 @@ string ABIFunctions::abiEncodingFunction( | ||||
| 		{ | ||||
| 			// special case: convert storage reference type to value type - this is only
 | ||||
| 			// possible for library calls where we just forward the storage reference
 | ||||
| 			solAssert(_encodeAsLibraryTypes, ""); | ||||
| 			solAssert(_options.encodeAsLibraryTypes, ""); | ||||
| 			solAssert(to == IntegerType::uint256(), ""); | ||||
| 			templ("cleanupConvert", "value"); | ||||
| 		} | ||||
| @ -574,7 +591,7 @@ string ABIFunctions::abiEncodingFunction( | ||||
| string ABIFunctions::abiEncodingFunctionCalldataArray( | ||||
| 	Type const& _from, | ||||
| 	Type const& _to, | ||||
| 	bool _encodeAsLibraryTypes | ||||
| 	EncodingOptions const& _options | ||||
| ) | ||||
| { | ||||
| 	solAssert(_to.isDynamicallySized(), ""); | ||||
| @ -596,7 +613,7 @@ string ABIFunctions::abiEncodingFunctionCalldataArray( | ||||
| 		_from.identifier() + | ||||
| 		"_to_" + | ||||
| 		_to.identifier() + | ||||
| 		(_encodeAsLibraryTypes ? "_library" : ""); | ||||
| 		_options.toFunctionNameSuffix(); | ||||
| 	return createFunction(functionName, [&]() { | ||||
| 		solUnimplementedAssert(fromArrayType.isByteArray(), "Only byte arrays can be encoded from calldata currently."); | ||||
| 		// TODO if this is not a byte array, we might just copy byte-by-byte anyway,
 | ||||
| @ -622,7 +639,7 @@ string ABIFunctions::abiEncodingFunctionCalldataArray( | ||||
| string ABIFunctions::abiEncodingFunctionSimpleArray( | ||||
| 	ArrayType const& _from, | ||||
| 	ArrayType const& _to, | ||||
| 	bool _encodeAsLibraryTypes | ||||
| 	EncodingOptions const& _options | ||||
| ) | ||||
| { | ||||
| 	string functionName = | ||||
| @ -630,7 +647,7 @@ string ABIFunctions::abiEncodingFunctionSimpleArray( | ||||
| 		_from.identifier() + | ||||
| 		"_to_" + | ||||
| 		_to.identifier() + | ||||
| 		(_encodeAsLibraryTypes ? "_library" : ""); | ||||
| 		_options.toFunctionNameSuffix(); | ||||
| 
 | ||||
| 	solAssert(_from.isDynamicallySized() == _to.isDynamicallySized(), ""); | ||||
| 	solAssert(_from.length() == _to.length(), ""); | ||||
| @ -691,11 +708,13 @@ string ABIFunctions::abiEncodingFunctionSimpleArray( | ||||
| 			templ("storeLength", ""); | ||||
| 		templ("dataAreaFun", arrayDataAreaFunction(_from)); | ||||
| 		templ("elementEncodedSize", toCompactHexWithPrefix(_to.baseType()->calldataEncodedSize())); | ||||
| 
 | ||||
| 		EncodingOptions subOptions(_options); | ||||
| 		subOptions.encodeFunctionFromStack = false; | ||||
| 		templ("encodeToMemoryFun", abiEncodingFunction( | ||||
| 			*_from.baseType(), | ||||
| 			*_to.baseType(), | ||||
| 			_encodeAsLibraryTypes, | ||||
| 			false | ||||
| 			subOptions | ||||
| 		)); | ||||
| 		templ("arrayElementAccess", inMemory ? "mload(srcPtr)" : _from.baseType()->isValueType() ? "sload(srcPtr)" : "srcPtr" ); | ||||
| 		templ("nextArrayElement", nextArrayElementFunction(_from)); | ||||
| @ -706,7 +725,7 @@ string ABIFunctions::abiEncodingFunctionSimpleArray( | ||||
| string ABIFunctions::abiEncodingFunctionMemoryByteArray( | ||||
| 	ArrayType const& _from, | ||||
| 	ArrayType const& _to, | ||||
| 	bool _encodeAsLibraryTypes | ||||
| 	EncodingOptions const& _options | ||||
| ) | ||||
| { | ||||
| 	string functionName = | ||||
| @ -714,7 +733,7 @@ string ABIFunctions::abiEncodingFunctionMemoryByteArray( | ||||
| 		_from.identifier() + | ||||
| 		"_to_" + | ||||
| 		_to.identifier() + | ||||
| 		(_encodeAsLibraryTypes ? "_library" : ""); | ||||
| 		_options.toFunctionNameSuffix(); | ||||
| 
 | ||||
| 	solAssert(_from.isDynamicallySized() == _to.isDynamicallySized(), ""); | ||||
| 	solAssert(_from.length() == _to.length(), ""); | ||||
| @ -742,7 +761,7 @@ string ABIFunctions::abiEncodingFunctionMemoryByteArray( | ||||
| string ABIFunctions::abiEncodingFunctionCompactStorageArray( | ||||
| 	ArrayType const& _from, | ||||
| 	ArrayType const& _to, | ||||
| 	bool _encodeAsLibraryTypes | ||||
| 	EncodingOptions const& _options | ||||
| ) | ||||
| { | ||||
| 	string functionName = | ||||
| @ -750,7 +769,7 @@ string ABIFunctions::abiEncodingFunctionCompactStorageArray( | ||||
| 		_from.identifier() + | ||||
| 		"_to_" + | ||||
| 		_to.identifier() + | ||||
| 		(_encodeAsLibraryTypes ? "_library" : ""); | ||||
| 		_options.toFunctionNameSuffix(); | ||||
| 
 | ||||
| 	solAssert(_from.isDynamicallySized() == _to.isDynamicallySized(), ""); | ||||
| 	solAssert(_from.length() == _to.length(), ""); | ||||
| @ -840,11 +859,13 @@ string ABIFunctions::abiEncodingFunctionCompactStorageArray( | ||||
| 			templ("itemsPerSlot", to_string(itemsPerSlot)); | ||||
| 			string elementEncodedSize = toCompactHexWithPrefix(_to.baseType()->calldataEncodedSize()); | ||||
| 			templ("elementEncodedSize", elementEncodedSize); | ||||
| 
 | ||||
| 			EncodingOptions subOptions(_options); | ||||
| 			subOptions.encodeFunctionFromStack = false; | ||||
| 			string encodeToMemoryFun = abiEncodingFunction( | ||||
| 				*_from.baseType(), | ||||
| 				*_to.baseType(), | ||||
| 				_encodeAsLibraryTypes, | ||||
| 				false | ||||
| 				subOptions | ||||
| 			); | ||||
| 			templ("encodeToMemoryFun", encodeToMemoryFun); | ||||
| 			std::vector<std::map<std::string, std::string>> items(itemsPerSlot); | ||||
| @ -859,7 +880,7 @@ string ABIFunctions::abiEncodingFunctionCompactStorageArray( | ||||
| string ABIFunctions::abiEncodingFunctionStruct( | ||||
| 	StructType const& _from, | ||||
| 	StructType const& _to, | ||||
| 	bool _encodeAsLibraryTypes | ||||
| 	EncodingOptions const& _options | ||||
| ) | ||||
| { | ||||
| 	string functionName = | ||||
| @ -867,7 +888,7 @@ string ABIFunctions::abiEncodingFunctionStruct( | ||||
| 		_from.identifier() + | ||||
| 		"_to_" + | ||||
| 		_to.identifier() + | ||||
| 		(_encodeAsLibraryTypes ? "_library" : ""); | ||||
| 		_options.toFunctionNameSuffix(); | ||||
| 
 | ||||
| 	solUnimplementedAssert(!_from.dataStoredIn(DataLocation::CallData), "Encoding struct from calldata is not yet supported."); | ||||
| 	solAssert(&_from.structDefinition() == &_to.structDefinition(), ""); | ||||
| @ -904,7 +925,7 @@ string ABIFunctions::abiEncodingFunctionStruct( | ||||
| 			solAssert(member.type, ""); | ||||
| 			if (!member.type->canLiveOutsideStorage()) | ||||
| 				continue; | ||||
| 			TypePointer memberTypeTo = member.type->fullEncodingType(_encodeAsLibraryTypes, true, false); | ||||
| 			TypePointer memberTypeTo = member.type->fullEncodingType(_options.encodeAsLibraryTypes, true, false); | ||||
| 			solUnimplementedAssert(memberTypeTo, "Encoding type \"" + member.type->toString() + "\" not yet implemented."); | ||||
| 			auto memberTypeFrom = _from.memberType(member.name); | ||||
| 			solAssert(memberTypeFrom, ""); | ||||
| @ -958,7 +979,10 @@ string ABIFunctions::abiEncodingFunctionStruct( | ||||
| 			} | ||||
| 			memberTempl("encodingOffset", toCompactHexWithPrefix(encodingOffset)); | ||||
| 			encodingOffset += dynamicMember ? 0x20 : memberTypeTo->calldataEncodedSize(); | ||||
| 			memberTempl("abiEncode", abiEncodingFunction(*memberTypeFrom, *memberTypeTo, _encodeAsLibraryTypes, false)); | ||||
| 
 | ||||
| 			EncodingOptions subOptions(_options); | ||||
| 			subOptions.encodeFunctionFromStack = false; | ||||
| 			memberTempl("abiEncode", abiEncodingFunction(*memberTypeFrom, *memberTypeTo, subOptions)); | ||||
| 
 | ||||
| 			members.push_back({}); | ||||
| 			members.back()["encode"] = memberTempl.render(); | ||||
| @ -973,7 +997,7 @@ string ABIFunctions::abiEncodingFunctionStruct( | ||||
| string ABIFunctions::abiEncodingFunctionStringLiteral( | ||||
| 	Type const& _from, | ||||
| 	Type const& _to, | ||||
| 	bool _encodeAsLibraryTypes | ||||
| 	EncodingOptions const& _options | ||||
| ) | ||||
| { | ||||
| 	solAssert(_from.category() == Type::Category::StringLiteral, ""); | ||||
| @ -983,7 +1007,7 @@ string ABIFunctions::abiEncodingFunctionStringLiteral( | ||||
| 		_from.identifier() + | ||||
| 		"_to_" + | ||||
| 		_to.identifier() + | ||||
| 		(_encodeAsLibraryTypes ? "_library" : ""); | ||||
| 		_options.toFunctionNameSuffix(); | ||||
| 	return createFunction(functionName, [&]() { | ||||
| 		auto const& strType = dynamic_cast<StringLiteralType const&>(_from); | ||||
| 		string const& value = strType.value(); | ||||
| @ -1034,8 +1058,7 @@ string ABIFunctions::abiEncodingFunctionStringLiteral( | ||||
| string ABIFunctions::abiEncodingFunctionFunctionType( | ||||
| 	FunctionType const& _from, | ||||
| 	Type const& _to, | ||||
| 	bool _encodeAsLibraryTypes, | ||||
| 	bool _fromStack | ||||
| 	EncodingOptions const& _options | ||||
| ) | ||||
| { | ||||
| 	solAssert(_from.kind() == FunctionType::Kind::External, ""); | ||||
| @ -1046,10 +1069,9 @@ string ABIFunctions::abiEncodingFunctionFunctionType( | ||||
| 		_from.identifier() + | ||||
| 		"_to_" + | ||||
| 		_to.identifier() + | ||||
| 		(_fromStack ? "_fromStack" : "") + | ||||
| 		(_encodeAsLibraryTypes ? "_library" : ""); | ||||
| 		_options.toFunctionNameSuffix(); | ||||
| 
 | ||||
| 	if (_fromStack) | ||||
| 	if (_options.encodeFunctionFromStack) | ||||
| 		return createFunction(functionName, [&]() { | ||||
| 			return Whiskers(R"( | ||||
| 				function <functionName>(addr, function_id, pos) { | ||||
| @ -1716,3 +1738,4 @@ size_t ABIFunctions::headSize(TypePointers const& _targetTypes) | ||||
| 
 | ||||
| 	return headSize; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -87,6 +87,23 @@ public: | ||||
| 	std::pair<std::string, std::set<std::string>> requestedFunctions(); | ||||
| 
 | ||||
| private: | ||||
| 	struct EncodingOptions | ||||
| 	{ | ||||
| 		/// Pad/signextend value types and bytes/string to multiples of  32 bytes.
 | ||||
| 		bool padded = true; | ||||
| 		/// Store arrays and structs in place without "data pointer" and do not store the length.
 | ||||
| 		bool dynamicInplace = false; | ||||
| 		/// Only for external function types: The value is a pair of address / function id instead
 | ||||
| 		/// of a memory pointer to the compression representation.
 | ||||
| 		bool encodeFunctionFromStack = false; | ||||
| 		/// Encode storage pointers as storage pointers (we are targeting a library call).
 | ||||
| 		bool encodeAsLibraryTypes = false; | ||||
| 
 | ||||
| 		/// @returns a string to uniquely identify the encoding options for the encoding
 | ||||
| 		/// function name. Skips everything that has its default value.
 | ||||
| 		std::string toFunctionNameSuffix() const; | ||||
| 	}; | ||||
| 
 | ||||
| 	/// @returns the name of the cleanup function for the given type and
 | ||||
| 	/// adds its implementation to the requested functions.
 | ||||
| 	/// @param _revertOnFailure if true, causes revert on invalid data,
 | ||||
| @ -115,40 +132,39 @@ private: | ||||
| 	std::string abiEncodingFunction( | ||||
| 		Type const& _givenType, | ||||
| 		Type const& _targetType, | ||||
| 		bool _encodeAsLibraryTypes, | ||||
| 		bool _fromStack | ||||
| 		EncodingOptions const& _options | ||||
| 	); | ||||
| 	/// Part of @a abiEncodingFunction for array target type and given calldata array.
 | ||||
| 	std::string abiEncodingFunctionCalldataArray( | ||||
| 		Type const& _givenType, | ||||
| 		Type const& _targetType, | ||||
| 		bool _encodeAsLibraryTypes | ||||
| 		EncodingOptions const& _options | ||||
| 	); | ||||
| 	/// Part of @a abiEncodingFunction for array target type and given memory array or
 | ||||
| 	/// a given storage array with one item per slot.
 | ||||
| 	std::string abiEncodingFunctionSimpleArray( | ||||
| 		ArrayType const& _givenType, | ||||
| 		ArrayType const& _targetType, | ||||
| 		bool _encodeAsLibraryTypes | ||||
| 		EncodingOptions const& _options | ||||
| 	); | ||||
| 	std::string abiEncodingFunctionMemoryByteArray( | ||||
| 		ArrayType const& _givenType, | ||||
| 		ArrayType const& _targetType, | ||||
| 		bool _encodeAsLibraryTypes | ||||
| 		EncodingOptions const& _options | ||||
| 	); | ||||
| 	/// Part of @a abiEncodingFunction for array target type and given storage array
 | ||||
| 	/// where multiple items are packed into the same storage slot.
 | ||||
| 	std::string abiEncodingFunctionCompactStorageArray( | ||||
| 		ArrayType const& _givenType, | ||||
| 		ArrayType const& _targetType, | ||||
| 		bool _encodeAsLibraryTypes | ||||
| 		EncodingOptions const& _options | ||||
| 	); | ||||
| 
 | ||||
| 	/// Part of @a abiEncodingFunction for struct types.
 | ||||
| 	std::string abiEncodingFunctionStruct( | ||||
| 		StructType const& _givenType, | ||||
| 		StructType const& _targetType, | ||||
| 		bool _encodeAsLibraryTypes | ||||
| 		EncodingOptions const& _options | ||||
| 	); | ||||
| 
 | ||||
| 	// @returns the name of the ABI encoding function with the given type
 | ||||
| @ -157,14 +173,13 @@ private: | ||||
| 	std::string abiEncodingFunctionStringLiteral( | ||||
| 		Type const& _givenType, | ||||
| 		Type const& _targetType, | ||||
| 		bool _encodeAsLibraryTypes | ||||
| 		EncodingOptions const& _options | ||||
| 	); | ||||
| 
 | ||||
| 	std::string abiEncodingFunctionFunctionType( | ||||
| 		FunctionType const& _from, | ||||
| 		Type const& _to, | ||||
| 		bool _encodeAsLibraryTypes, | ||||
| 		bool _fromStack | ||||
| 		EncodingOptions const& _options | ||||
| 	); | ||||
| 
 | ||||
| 	/// @returns the name of the ABI decoding function for the given type
 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user