Merge pull request #2980 from ethereum/abi-api

Add abi.encode and abi.encodePacked
This commit is contained in:
chriseth
2018-04-12 20:55:03 +02:00
committed by GitHub
17 changed files with 700 additions and 66 deletions
+1
View File
@@ -35,6 +35,7 @@ namespace solidity
GlobalContext::GlobalContext():
m_magicVariables(vector<shared_ptr<MagicVariableDeclaration const>>{
make_shared<MagicVariableDeclaration>("abi", make_shared<MagicType>(MagicType::Kind::ABI)),
make_shared<MagicVariableDeclaration>("addmod", make_shared<FunctionType>(strings{"uint256", "uint256", "uint256"}, strings{"uint256"}, FunctionType::Kind::AddMod, false, StateMutability::Pure)),
make_shared<MagicVariableDeclaration>("assert", make_shared<FunctionType>(strings{"bool"}, strings{}, FunctionType::Kind::Assert, false, StateMutability::Pure)),
make_shared<MagicVariableDeclaration>("block", make_shared<MagicType>(MagicType::Kind::Block)),
+32 -10
View File
@@ -1688,7 +1688,19 @@ bool TypeChecker::visit(FunctionCall const& _functionCall)
}
}
if (!functionType->takesArbitraryParameters() && parameterTypes.size() != arguments.size())
if (functionType->takesArbitraryParameters() && arguments.size() < parameterTypes.size())
{
solAssert(_functionCall.annotation().kind == FunctionCallKind::FunctionCall, "");
m_errorReporter.typeError(
_functionCall.location(),
"Need at least " +
toString(parameterTypes.size()) +
" arguments for function call, but provided only " +
toString(arguments.size()) +
"."
);
}
else if (!functionType->takesArbitraryParameters() && parameterTypes.size() != arguments.size())
{
bool isStructConstructorCall = _functionCall.annotation().kind == FunctionCallKind::StructConstructorCall;
@@ -1711,11 +1723,12 @@ bool TypeChecker::visit(FunctionCall const& _functionCall)
}
else if (isPositionalCall)
{
// call by positional arguments
bool const abiEncodeV2 = m_scope->sourceUnit().annotation().experimentalFeatures.count(ExperimentalFeature::ABIEncoderV2);
for (size_t i = 0; i < arguments.size(); ++i)
{
auto const& argType = type(*arguments[i]);
if (functionType->takesArbitraryParameters())
if (functionType->takesArbitraryParameters() && i >= parameterTypes.size())
{
bool errored = false;
if (auto t = dynamic_cast<RationalNumberType const*>(argType.get()))
@@ -1724,13 +1737,22 @@ bool TypeChecker::visit(FunctionCall const& _functionCall)
m_errorReporter.typeError(arguments[i]->location(), "Invalid rational number (too large or division by zero).");
errored = true;
}
if (!errored && !(
argType->mobileType() &&
argType->mobileType()->interfaceType(false) &&
argType->mobileType()->interfaceType(false)->encodingType() &&
!(dynamic_cast<StructType const*>(argType->mobileType()->interfaceType(false)->encodingType().get()))
))
m_errorReporter.typeError(arguments[i]->location(), "This type cannot be encoded.");
if (!errored)
{
TypePointer encodingType;
if (
argType->mobileType() &&
argType->mobileType()->interfaceType(false) &&
argType->mobileType()->interfaceType(false)->encodingType()
)
encodingType = argType->mobileType()->interfaceType(false)->encodingType();
// Structs are fine as long as ABIV2 is activated and we do not do packed encoding.
if (!encodingType || (
dynamic_cast<StructType const*>(encodingType.get()) &&
!(abiEncodeV2 && functionType->padArguments())
))
m_errorReporter.typeError(arguments[i]->location(), "This type cannot be encoded.");
}
}
else if (!type(*arguments[i])->isImplicitlyConvertibleTo(*parameterTypes[i]))
m_errorReporter.typeError(
+6 -1
View File
@@ -305,10 +305,15 @@ void ViewPureChecker::endVisit(MemberAccess const& _memberAccess)
mutability = StateMutability::View;
break;
case Type::Category::Magic:
{
// we can ignore the kind of magic and only look at the name of the member
if (member != "data" && member != "sig" && member != "blockhash")
set<string> static const pureMembers{
"encode", "encodePacked", "encodeWithSelector", "encodeWithSignature", "data", "sig", "blockhash"
};
if (!pureMembers.count(member))
mutability = StateMutability::View;
break;
}
case Type::Category::Struct:
{
if (_memberAccess.expression().annotation().type->dataStoredIn(DataLocation::Storage))