mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Bare functions take single bytes argument.
This commit is contained in:
parent
0e66a1ddde
commit
23c4142005
@ -42,7 +42,7 @@ m_magicVariables(vector<shared_ptr<MagicVariableDeclaration const>>{
|
|||||||
make_shared<MagicVariableDeclaration>("blockhash", make_shared<FunctionType>(strings{"uint256"}, strings{"bytes32"}, FunctionType::Kind::BlockHash, false, StateMutability::View)),
|
make_shared<MagicVariableDeclaration>("blockhash", make_shared<FunctionType>(strings{"uint256"}, strings{"bytes32"}, FunctionType::Kind::BlockHash, false, StateMutability::View)),
|
||||||
make_shared<MagicVariableDeclaration>("ecrecover", make_shared<FunctionType>(strings{"bytes32", "uint8", "bytes32", "bytes32"}, strings{"address"}, FunctionType::Kind::ECRecover, false, StateMutability::Pure)),
|
make_shared<MagicVariableDeclaration>("ecrecover", make_shared<FunctionType>(strings{"bytes32", "uint8", "bytes32", "bytes32"}, strings{"address"}, FunctionType::Kind::ECRecover, false, StateMutability::Pure)),
|
||||||
make_shared<MagicVariableDeclaration>("gasleft", make_shared<FunctionType>(strings(), strings{"uint256"}, FunctionType::Kind::GasLeft, false, StateMutability::View)),
|
make_shared<MagicVariableDeclaration>("gasleft", make_shared<FunctionType>(strings(), strings{"uint256"}, FunctionType::Kind::GasLeft, false, StateMutability::View)),
|
||||||
make_shared<MagicVariableDeclaration>("keccak256", make_shared<FunctionType>(strings(), strings{"bytes32"}, FunctionType::Kind::SHA3, true, StateMutability::Pure)),
|
make_shared<MagicVariableDeclaration>("keccak256", make_shared<FunctionType>(strings{"bytes memory"}, strings{"bytes32"}, FunctionType::Kind::SHA3, false, StateMutability::Pure)),
|
||||||
make_shared<MagicVariableDeclaration>("log0", make_shared<FunctionType>(strings{"bytes32"}, strings{}, FunctionType::Kind::Log0)),
|
make_shared<MagicVariableDeclaration>("log0", make_shared<FunctionType>(strings{"bytes32"}, strings{}, FunctionType::Kind::Log0)),
|
||||||
make_shared<MagicVariableDeclaration>("log1", make_shared<FunctionType>(strings{"bytes32", "bytes32"}, strings{}, FunctionType::Kind::Log1)),
|
make_shared<MagicVariableDeclaration>("log1", make_shared<FunctionType>(strings{"bytes32", "bytes32"}, strings{}, FunctionType::Kind::Log1)),
|
||||||
make_shared<MagicVariableDeclaration>("log2", make_shared<FunctionType>(strings{"bytes32", "bytes32", "bytes32"}, strings{}, FunctionType::Kind::Log2)),
|
make_shared<MagicVariableDeclaration>("log2", make_shared<FunctionType>(strings{"bytes32", "bytes32", "bytes32"}, strings{}, FunctionType::Kind::Log2)),
|
||||||
@ -55,10 +55,10 @@ m_magicVariables(vector<shared_ptr<MagicVariableDeclaration const>>{
|
|||||||
make_shared<MagicVariableDeclaration>("require", make_shared<FunctionType>(strings{"bool", "string memory"}, strings{}, FunctionType::Kind::Require, false, StateMutability::Pure)),
|
make_shared<MagicVariableDeclaration>("require", make_shared<FunctionType>(strings{"bool", "string memory"}, strings{}, FunctionType::Kind::Require, false, StateMutability::Pure)),
|
||||||
make_shared<MagicVariableDeclaration>("revert", make_shared<FunctionType>(strings(), strings(), FunctionType::Kind::Revert, false, StateMutability::Pure)),
|
make_shared<MagicVariableDeclaration>("revert", make_shared<FunctionType>(strings(), strings(), FunctionType::Kind::Revert, false, StateMutability::Pure)),
|
||||||
make_shared<MagicVariableDeclaration>("revert", make_shared<FunctionType>(strings{"string memory"}, strings(), FunctionType::Kind::Revert, false, StateMutability::Pure)),
|
make_shared<MagicVariableDeclaration>("revert", make_shared<FunctionType>(strings{"string memory"}, strings(), FunctionType::Kind::Revert, false, StateMutability::Pure)),
|
||||||
make_shared<MagicVariableDeclaration>("ripemd160", make_shared<FunctionType>(strings(), strings{"bytes20"}, FunctionType::Kind::RIPEMD160, true, StateMutability::Pure)),
|
make_shared<MagicVariableDeclaration>("ripemd160", make_shared<FunctionType>(strings{"bytes memory"}, strings{"bytes20"}, FunctionType::Kind::RIPEMD160, false, StateMutability::Pure)),
|
||||||
make_shared<MagicVariableDeclaration>("selfdestruct", make_shared<FunctionType>(strings{"address"}, strings{}, FunctionType::Kind::Selfdestruct)),
|
make_shared<MagicVariableDeclaration>("selfdestruct", make_shared<FunctionType>(strings{"address"}, strings{}, FunctionType::Kind::Selfdestruct)),
|
||||||
make_shared<MagicVariableDeclaration>("sha256", make_shared<FunctionType>(strings(), strings{"bytes32"}, FunctionType::Kind::SHA256, true, StateMutability::Pure)),
|
make_shared<MagicVariableDeclaration>("sha256", make_shared<FunctionType>(strings{"bytes memory"}, strings{"bytes32"}, FunctionType::Kind::SHA256, false, StateMutability::Pure)),
|
||||||
make_shared<MagicVariableDeclaration>("sha3", make_shared<FunctionType>(strings(), strings{"bytes32"}, FunctionType::Kind::SHA3, true, StateMutability::Pure)),
|
make_shared<MagicVariableDeclaration>("sha3", make_shared<FunctionType>(strings{"bytes memory"}, strings{"bytes32"}, FunctionType::Kind::SHA3, false, StateMutability::Pure)),
|
||||||
make_shared<MagicVariableDeclaration>("suicide", make_shared<FunctionType>(strings{"address"}, strings{}, FunctionType::Kind::Selfdestruct)),
|
make_shared<MagicVariableDeclaration>("suicide", make_shared<FunctionType>(strings{"address"}, strings{}, FunctionType::Kind::Selfdestruct)),
|
||||||
make_shared<MagicVariableDeclaration>("tx", make_shared<MagicType>(MagicType::Kind::Transaction))
|
make_shared<MagicVariableDeclaration>("tx", make_shared<MagicType>(MagicType::Kind::Transaction))
|
||||||
})
|
})
|
||||||
|
@ -1750,35 +1750,6 @@ bool TypeChecker::visit(FunctionCall const& _functionCall)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (functionType->takesSinglePackedBytesParameter())
|
|
||||||
{
|
|
||||||
if (
|
|
||||||
(arguments.size() > 1) ||
|
|
||||||
(arguments.size() == 1 && !type(*arguments.front())->isImplicitlyConvertibleTo(ArrayType(DataLocation::Memory)))
|
|
||||||
)
|
|
||||||
{
|
|
||||||
string msg =
|
|
||||||
"This function only accepts a single \"bytes\" argument. Please use "
|
|
||||||
"\"abi.encodePacked(...)\" or a similar function to encode the data.";
|
|
||||||
if (v050)
|
|
||||||
m_errorReporter.typeError(_functionCall.location(), msg);
|
|
||||||
else
|
|
||||||
m_errorReporter.warning(_functionCall.location(), msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (arguments.size() == 1 && !type(*arguments.front())->isImplicitlyConvertibleTo(ArrayType(DataLocation::Memory)))
|
|
||||||
{
|
|
||||||
string msg =
|
|
||||||
"The provided argument of type " +
|
|
||||||
type(*arguments.front())->toString() +
|
|
||||||
" is not implicitly convertible to expected type bytes memory.";
|
|
||||||
if (v050)
|
|
||||||
m_errorReporter.typeError(_functionCall.location(), msg);
|
|
||||||
else
|
|
||||||
m_errorReporter.warning(_functionCall.location(), msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (functionType->takesArbitraryParameters() && arguments.size() < parameterTypes.size())
|
if (functionType->takesArbitraryParameters() && arguments.size() < parameterTypes.size())
|
||||||
{
|
{
|
||||||
solAssert(_functionCall.annotation().kind == FunctionCallKind::FunctionCall, "");
|
solAssert(_functionCall.annotation().kind == FunctionCallKind::FunctionCall, "");
|
||||||
|
@ -599,9 +599,9 @@ MemberList::MemberMap IntegerType::nativeMembers(ContractDefinition const*) cons
|
|||||||
if (isAddress())
|
if (isAddress())
|
||||||
return {
|
return {
|
||||||
{"balance", make_shared<IntegerType>(256)},
|
{"balance", make_shared<IntegerType>(256)},
|
||||||
{"call", make_shared<FunctionType>(strings(), strings{"bool"}, FunctionType::Kind::BareCall, true, StateMutability::Payable)},
|
{"call", make_shared<FunctionType>(strings{"bytes memory"}, strings{"bool"}, FunctionType::Kind::BareCall, true, StateMutability::Payable)},
|
||||||
{"callcode", make_shared<FunctionType>(strings(), strings{"bool"}, FunctionType::Kind::BareCallCode, true, StateMutability::Payable)},
|
{"callcode", make_shared<FunctionType>(strings{"bytes memory"}, strings{"bool"}, FunctionType::Kind::BareCallCode, true, StateMutability::Payable)},
|
||||||
{"delegatecall", make_shared<FunctionType>(strings(), strings{"bool"}, FunctionType::Kind::BareDelegateCall, true)},
|
{"delegatecall", make_shared<FunctionType>(strings{"bytes memory"}, strings{"bool"}, FunctionType::Kind::BareDelegateCall, true)},
|
||||||
{"send", make_shared<FunctionType>(strings{"uint"}, strings{"bool"}, FunctionType::Kind::Send)},
|
{"send", make_shared<FunctionType>(strings{"uint"}, strings{"bool"}, FunctionType::Kind::Send)},
|
||||||
{"transfer", make_shared<FunctionType>(strings{"uint"}, strings(), FunctionType::Kind::Transfer)}
|
{"transfer", make_shared<FunctionType>(strings{"uint"}, strings(), FunctionType::Kind::Transfer)}
|
||||||
};
|
};
|
||||||
@ -3001,6 +3001,25 @@ ASTPointer<ASTString> FunctionType::documentation() const
|
|||||||
return ASTPointer<ASTString>();
|
return ASTPointer<ASTString>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool FunctionType::padArguments() const
|
||||||
|
{
|
||||||
|
// No padding only for hash functions, low-level calls and the packed encoding function.
|
||||||
|
switch (m_kind)
|
||||||
|
{
|
||||||
|
case Kind::BareCall:
|
||||||
|
case Kind::BareCallCode:
|
||||||
|
case Kind::BareDelegateCall:
|
||||||
|
case Kind::SHA256:
|
||||||
|
case Kind::RIPEMD160:
|
||||||
|
case Kind::SHA3:
|
||||||
|
case Kind::ABIEncodePacked:
|
||||||
|
return false;
|
||||||
|
default:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
string MappingType::richIdentifier() const
|
string MappingType::richIdentifier() const
|
||||||
{
|
{
|
||||||
return "t_mapping" + identifierList(m_keyType, m_valueType);
|
return "t_mapping" + identifierList(m_keyType, m_valueType);
|
||||||
|
@ -1058,8 +1058,9 @@ public:
|
|||||||
ASTPointer<ASTString> documentation() const;
|
ASTPointer<ASTString> documentation() const;
|
||||||
|
|
||||||
/// true iff arguments are to be padded to multiples of 32 bytes for external calls
|
/// true iff arguments are to be padded to multiples of 32 bytes for external calls
|
||||||
/// TODO should this be true in general for bareCall*?
|
/// The only functions that do not pad are hash functions, the low-level call functions
|
||||||
bool padArguments() const { return !(m_kind == Kind::SHA3 || m_kind == Kind::SHA256 || m_kind == Kind::RIPEMD160 || m_kind == Kind::ABIEncodePacked); }
|
/// and abi.encodePacked.
|
||||||
|
bool padArguments() const;
|
||||||
bool takesArbitraryParameters() const { return m_arbitraryParameters; }
|
bool takesArbitraryParameters() const { return m_arbitraryParameters; }
|
||||||
/// true iff the function takes a single bytes parameter and it is passed on without padding.
|
/// true iff the function takes a single bytes parameter and it is passed on without padding.
|
||||||
bool takesSinglePackedBytesParameter() const
|
bool takesSinglePackedBytesParameter() const
|
||||||
|
@ -1837,39 +1837,12 @@ void ExpressionCompiler::appendExternalFunctionCall(
|
|||||||
// Evaluate arguments.
|
// Evaluate arguments.
|
||||||
TypePointers argumentTypes;
|
TypePointers argumentTypes;
|
||||||
TypePointers parameterTypes = _functionType.parameterTypes();
|
TypePointers parameterTypes = _functionType.parameterTypes();
|
||||||
// This can be removed (will always be false) with 0.5.0
|
|
||||||
bool manualFunctionId = false;
|
|
||||||
if (
|
|
||||||
(funKind == FunctionType::Kind::BareCall || funKind == FunctionType::Kind::BareCallCode || funKind == FunctionType::Kind::BareDelegateCall) &&
|
|
||||||
!_arguments.empty()
|
|
||||||
)
|
|
||||||
{
|
|
||||||
solAssert(_arguments.front()->annotation().type->mobileType(), "");
|
|
||||||
manualFunctionId =
|
|
||||||
_arguments.front()->annotation().type->mobileType()->calldataEncodedSize(false) ==
|
|
||||||
CompilerUtils::dataStartOffset;
|
|
||||||
}
|
|
||||||
if (manualFunctionId)
|
|
||||||
{
|
|
||||||
// If we have a Bare* and the first type has exactly 4 bytes, use it as
|
|
||||||
// function identifier.
|
|
||||||
_arguments.front()->accept(*this);
|
|
||||||
utils().convertType(
|
|
||||||
*_arguments.front()->annotation().type,
|
|
||||||
IntegerType(8 * CompilerUtils::dataStartOffset),
|
|
||||||
true
|
|
||||||
);
|
|
||||||
for (unsigned i = 0; i < gasValueSize; ++i)
|
|
||||||
m_context << swapInstruction(gasValueSize - i);
|
|
||||||
gasStackPos++;
|
|
||||||
valueStackPos++;
|
|
||||||
}
|
|
||||||
if (_functionType.bound())
|
if (_functionType.bound())
|
||||||
{
|
{
|
||||||
argumentTypes.push_back(_functionType.selfType());
|
argumentTypes.push_back(_functionType.selfType());
|
||||||
parameterTypes.insert(parameterTypes.begin(), _functionType.selfType());
|
parameterTypes.insert(parameterTypes.begin(), _functionType.selfType());
|
||||||
}
|
}
|
||||||
for (size_t i = manualFunctionId ? 1 : 0; i < _arguments.size(); ++i)
|
for (size_t i = 0; i < _arguments.size(); ++i)
|
||||||
{
|
{
|
||||||
_arguments[i]->accept(*this);
|
_arguments[i]->accept(*this);
|
||||||
argumentTypes.push_back(_arguments[i]->annotation().type);
|
argumentTypes.push_back(_arguments[i]->annotation().type);
|
||||||
@ -1905,36 +1878,22 @@ void ExpressionCompiler::appendExternalFunctionCall(
|
|||||||
|
|
||||||
// Copy function identifier to memory.
|
// Copy function identifier to memory.
|
||||||
utils().fetchFreeMemoryPointer();
|
utils().fetchFreeMemoryPointer();
|
||||||
if (!_functionType.isBareCall() || manualFunctionId)
|
if (!_functionType.isBareCall())
|
||||||
{
|
{
|
||||||
m_context << dupInstruction(2 + gasValueSize + CompilerUtils::sizeOnStack(argumentTypes));
|
m_context << dupInstruction(2 + gasValueSize + CompilerUtils::sizeOnStack(argumentTypes));
|
||||||
utils().storeInMemoryDynamic(IntegerType(8 * CompilerUtils::dataStartOffset), false);
|
utils().storeInMemoryDynamic(IntegerType(8 * CompilerUtils::dataStartOffset), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is a function that takes a single bytes parameter which is supposed to be passed
|
// If the function takes arbitrary parameters or is a bare call, copy dynamic length data in place.
|
||||||
// on inline and without padding.
|
// Move arguments to memory, will not update the free memory pointer (but will update the memory
|
||||||
if (_functionType.takesSinglePackedBytesParameter() && v050 && argumentTypes.size() == 1)
|
// pointer on the stack).
|
||||||
{
|
utils().encodeToMemory(
|
||||||
utils().encodeToMemory(
|
argumentTypes,
|
||||||
argumentTypes,
|
parameterTypes,
|
||||||
TypePointers{make_shared<ArrayType>(DataLocation::Memory)},
|
_functionType.padArguments(),
|
||||||
false,
|
_functionType.takesArbitraryParameters() || _functionType.isBareCall(),
|
||||||
true
|
isCallCode || isDelegateCall
|
||||||
);
|
);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// If the function takes arbitrary parameters, copy dynamic length data in place.
|
|
||||||
// Move arguments to memory, will not update the free memory pointer (but will update the memory
|
|
||||||
// pointer on the stack).
|
|
||||||
utils().encodeToMemory(
|
|
||||||
argumentTypes,
|
|
||||||
parameterTypes,
|
|
||||||
_functionType.padArguments(),
|
|
||||||
_functionType.takesArbitraryParameters(),
|
|
||||||
isCallCode || isDelegateCall
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stack now:
|
// Stack now:
|
||||||
// <stack top>
|
// <stack top>
|
||||||
@ -2013,9 +1972,9 @@ void ExpressionCompiler::appendExternalFunctionCall(
|
|||||||
|
|
||||||
unsigned remainsSize =
|
unsigned remainsSize =
|
||||||
2 + // contract address, input_memory_end
|
2 + // contract address, input_memory_end
|
||||||
_functionType.valueSet() +
|
(_functionType.valueSet() ? 1 : 0) +
|
||||||
_functionType.gasSet() +
|
(_functionType.gasSet() ? 1 : 0) +
|
||||||
(!_functionType.isBareCall() || manualFunctionId);
|
(!_functionType.isBareCall() ? 1 : 0);
|
||||||
|
|
||||||
if (returnSuccessCondition)
|
if (returnSuccessCondition)
|
||||||
m_context << swapInstruction(remainsSize);
|
m_context << swapInstruction(remainsSize);
|
||||||
|
Loading…
Reference in New Issue
Block a user