mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #5815 from ethereum/strict-abi-decoder
Strict abi decoder (validate incoming data instead of cleaning it)
This commit is contained in:
commit
ee2f566207
@ -5,6 +5,7 @@ Language Features:
|
|||||||
|
|
||||||
|
|
||||||
Compiler Features:
|
Compiler Features:
|
||||||
|
* ABI Decoder: Raise a runtime error on dirty inputs when using the experimental decoder.
|
||||||
* SMTChecker: Support arithmetic compound assignment operators.
|
* SMTChecker: Support arithmetic compound assignment operators.
|
||||||
* Optimizer: Add rule for shifts by constants larger than 255 for Constantinople.
|
* Optimizer: Add rule for shifts by constants larger than 255 for Constantinople.
|
||||||
* Optimizer: Add rule to simplify certain ANDs and SHL combinations
|
* Optimizer: Add rule to simplify certain ANDs and SHL combinations
|
||||||
|
@ -255,10 +255,9 @@ string ABIFunctions::EncodingOptions::toFunctionNameSuffix() const
|
|||||||
return suffix;
|
return suffix;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string ABIFunctions::cleanupFunction(Type const& _type)
|
||||||
string ABIFunctions::cleanupFunction(Type const& _type, bool _revertOnFailure)
|
|
||||||
{
|
{
|
||||||
string functionName = string("cleanup_") + (_revertOnFailure ? "revert_" : "assert_") + _type.identifier();
|
string functionName = string("cleanup_") + _type.identifier();
|
||||||
return createFunction(functionName, [&]() {
|
return createFunction(functionName, [&]() {
|
||||||
Whiskers templ(R"(
|
Whiskers templ(R"(
|
||||||
function <functionName>(value) -> cleaned {
|
function <functionName>(value) -> cleaned {
|
||||||
@ -269,7 +268,7 @@ string ABIFunctions::cleanupFunction(Type const& _type, bool _revertOnFailure)
|
|||||||
switch (_type.category())
|
switch (_type.category())
|
||||||
{
|
{
|
||||||
case Type::Category::Address:
|
case Type::Category::Address:
|
||||||
templ("body", "cleaned := " + cleanupFunction(IntegerType(160), _revertOnFailure) + "(value)");
|
templ("body", "cleaned := " + cleanupFunction(IntegerType(160)) + "(value)");
|
||||||
break;
|
break;
|
||||||
case Type::Category::Integer:
|
case Type::Category::Integer:
|
||||||
{
|
{
|
||||||
@ -291,6 +290,10 @@ string ABIFunctions::cleanupFunction(Type const& _type, bool _revertOnFailure)
|
|||||||
case Type::Category::FixedPoint:
|
case Type::Category::FixedPoint:
|
||||||
solUnimplemented("Fixed point types not implemented.");
|
solUnimplemented("Fixed point types not implemented.");
|
||||||
break;
|
break;
|
||||||
|
case Type::Category::Function:
|
||||||
|
solAssert(dynamic_cast<FunctionType const&>(_type).kind() == FunctionType::Kind::External, "");
|
||||||
|
templ("body", "cleaned := " + cleanupFunction(FixedBytesType(24)) + "(value)");
|
||||||
|
break;
|
||||||
case Type::Category::Array:
|
case Type::Category::Array:
|
||||||
case Type::Category::Struct:
|
case Type::Category::Struct:
|
||||||
case Type::Category::Mapping:
|
case Type::Category::Mapping:
|
||||||
@ -319,20 +322,13 @@ string ABIFunctions::cleanupFunction(Type const& _type, bool _revertOnFailure)
|
|||||||
StateMutability::Payable :
|
StateMutability::Payable :
|
||||||
StateMutability::NonPayable
|
StateMutability::NonPayable
|
||||||
);
|
);
|
||||||
templ("body", "cleaned := " + cleanupFunction(addressType, _revertOnFailure) + "(value)");
|
templ("body", "cleaned := " + cleanupFunction(addressType) + "(value)");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Type::Category::Enum:
|
case Type::Category::Enum:
|
||||||
{
|
{
|
||||||
size_t members = dynamic_cast<EnumType const&>(_type).numberOfMembers();
|
// Out of range enums cannot be truncated unambigiously and therefore it should be an error.
|
||||||
solAssert(members > 0, "empty enum should have caused a parser error.");
|
templ("body", "cleaned := value " + validatorFunction(_type) + "(value)");
|
||||||
Whiskers w("if iszero(lt(value, <members>)) { <failure> } cleaned := value");
|
|
||||||
w("members", to_string(members));
|
|
||||||
if (_revertOnFailure)
|
|
||||||
w("failure", "revert(0, 0)");
|
|
||||||
else
|
|
||||||
w("failure", "invalid()");
|
|
||||||
templ("body", w.render());
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Type::Category::InaccessibleDynamic:
|
case Type::Category::InaccessibleDynamic:
|
||||||
@ -346,6 +342,56 @@ string ABIFunctions::cleanupFunction(Type const& _type, bool _revertOnFailure)
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string ABIFunctions::validatorFunction(Type const& _type, bool _revertOnFailure)
|
||||||
|
{
|
||||||
|
string functionName = string("validator_") + (_revertOnFailure ? "revert_" : "assert_") + _type.identifier();
|
||||||
|
return createFunction(functionName, [&]() {
|
||||||
|
Whiskers templ(R"(
|
||||||
|
function <functionName>(value) {
|
||||||
|
if iszero(<condition>) { <failure> }
|
||||||
|
}
|
||||||
|
)");
|
||||||
|
templ("functionName", functionName);
|
||||||
|
if (_revertOnFailure)
|
||||||
|
templ("failure", "revert(0, 0)");
|
||||||
|
else
|
||||||
|
templ("failure", "invalid()");
|
||||||
|
|
||||||
|
switch (_type.category())
|
||||||
|
{
|
||||||
|
case Type::Category::Address:
|
||||||
|
case Type::Category::Integer:
|
||||||
|
case Type::Category::RationalNumber:
|
||||||
|
case Type::Category::Bool:
|
||||||
|
case Type::Category::FixedPoint:
|
||||||
|
case Type::Category::Function:
|
||||||
|
case Type::Category::Array:
|
||||||
|
case Type::Category::Struct:
|
||||||
|
case Type::Category::Mapping:
|
||||||
|
case Type::Category::FixedBytes:
|
||||||
|
case Type::Category::Contract:
|
||||||
|
{
|
||||||
|
templ("condition", "eq(value, " + cleanupFunction(_type) + "(value))");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Type::Category::Enum:
|
||||||
|
{
|
||||||
|
size_t members = dynamic_cast<EnumType const&>(_type).numberOfMembers();
|
||||||
|
solAssert(members > 0, "empty enum should have caused a parser error.");
|
||||||
|
templ("condition", "lt(value, " + to_string(members) + ")");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Type::Category::InaccessibleDynamic:
|
||||||
|
templ("condition", "1");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
solAssert(false, "Validation of type " + _type.identifier() + " requested.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return templ.render();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
string ABIFunctions::cleanupFromStorageFunction(Type const& _type, bool _splitFunctionTypes)
|
string ABIFunctions::cleanupFromStorageFunction(Type const& _type, bool _splitFunctionTypes)
|
||||||
{
|
{
|
||||||
solAssert(_type.isValueType(), "");
|
solAssert(_type.isValueType(), "");
|
||||||
@ -544,21 +590,6 @@ string ABIFunctions::conversionFunction(Type const& _from, Type const& _to)
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
string ABIFunctions::cleanupCombinedExternalFunctionIdFunction()
|
|
||||||
{
|
|
||||||
string functionName = "cleanup_combined_external_function_id";
|
|
||||||
return createFunction(functionName, [&]() {
|
|
||||||
return Whiskers(R"(
|
|
||||||
function <functionName>(addr_and_selector) -> cleaned {
|
|
||||||
cleaned := <clean>(addr_and_selector)
|
|
||||||
}
|
|
||||||
)")
|
|
||||||
("functionName", functionName)
|
|
||||||
("clean", cleanupFunction(FixedBytesType(24)))
|
|
||||||
.render();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
string ABIFunctions::abiEncodingFunction(
|
string ABIFunctions::abiEncodingFunction(
|
||||||
Type const& _from,
|
Type const& _from,
|
||||||
Type const& _to,
|
Type const& _to,
|
||||||
@ -1248,7 +1279,7 @@ string ABIFunctions::abiEncodingFunctionFunctionType(
|
|||||||
}
|
}
|
||||||
)")
|
)")
|
||||||
("functionName", functionName)
|
("functionName", functionName)
|
||||||
("cleanExtFun", cleanupCombinedExternalFunctionIdFunction())
|
("cleanExtFun", cleanupFunction(_to))
|
||||||
.render();
|
.render();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -1306,14 +1337,15 @@ string ABIFunctions::abiDecodingFunctionValueType(Type const& _type, bool _fromM
|
|||||||
return createFunction(functionName, [&]() {
|
return createFunction(functionName, [&]() {
|
||||||
Whiskers templ(R"(
|
Whiskers templ(R"(
|
||||||
function <functionName>(offset, end) -> value {
|
function <functionName>(offset, end) -> value {
|
||||||
value := <cleanup>(<load>(offset))
|
value := <load>(offset)
|
||||||
|
<validator>(value)
|
||||||
}
|
}
|
||||||
)");
|
)");
|
||||||
templ("functionName", functionName);
|
templ("functionName", functionName);
|
||||||
templ("load", _fromMemory ? "mload" : "calldataload");
|
templ("load", _fromMemory ? "mload" : "calldataload");
|
||||||
// Cleanup itself should use the type and not decodingType, because e.g.
|
// Validation should use the type and not decodingType, because e.g.
|
||||||
// the decoding type of an enum is a plain int.
|
// the decoding type of an enum is a plain int.
|
||||||
templ("cleanup", cleanupFunction(_type, true));
|
templ("validator", validatorFunction(_type, true));
|
||||||
return templ.render();
|
return templ.render();
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -1560,11 +1592,11 @@ string ABIFunctions::abiDecodingFunctionFunctionType(FunctionType const& _type,
|
|||||||
{
|
{
|
||||||
return Whiskers(R"(
|
return Whiskers(R"(
|
||||||
function <functionName>(offset, end) -> addr, function_selector {
|
function <functionName>(offset, end) -> addr, function_selector {
|
||||||
addr, function_selector := <splitExtFun>(<load>(offset))
|
addr, function_selector := <splitExtFun>(<decodeFun>(offset, end))
|
||||||
}
|
}
|
||||||
)")
|
)")
|
||||||
("functionName", functionName)
|
("functionName", functionName)
|
||||||
("load", _fromMemory ? "mload" : "calldataload")
|
("decodeFun", abiDecodingFunctionFunctionType(_type, _fromMemory, false))
|
||||||
("splitExtFun", m_utils.splitExternalFunctionIdFunction())
|
("splitExtFun", m_utils.splitExternalFunctionIdFunction())
|
||||||
.render();
|
.render();
|
||||||
}
|
}
|
||||||
@ -1572,12 +1604,13 @@ string ABIFunctions::abiDecodingFunctionFunctionType(FunctionType const& _type,
|
|||||||
{
|
{
|
||||||
return Whiskers(R"(
|
return Whiskers(R"(
|
||||||
function <functionName>(offset, end) -> fun {
|
function <functionName>(offset, end) -> fun {
|
||||||
fun := <cleanExtFun>(<load>(offset))
|
fun := <load>(offset)
|
||||||
|
<validateExtFun>(fun)
|
||||||
}
|
}
|
||||||
)")
|
)")
|
||||||
("functionName", functionName)
|
("functionName", functionName)
|
||||||
("load", _fromMemory ? "mload" : "calldataload")
|
("load", _fromMemory ? "mload" : "calldataload")
|
||||||
("cleanExtFun", cleanupCombinedExternalFunctionIdFunction())
|
("validateExtFun", validatorFunction(_type, true))
|
||||||
.render();
|
.render();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -130,9 +130,17 @@ private:
|
|||||||
|
|
||||||
/// @returns the name of the cleanup function for the given type and
|
/// @returns the name of the cleanup function for the given type and
|
||||||
/// adds its implementation to the requested functions.
|
/// adds its implementation to the requested functions.
|
||||||
|
/// The cleanup function defers to the validator function with "assert"
|
||||||
|
/// if there is no reasonable way to clean a value.
|
||||||
|
std::string cleanupFunction(Type const& _type);
|
||||||
|
|
||||||
|
/// @returns the name of the validator function for the given type and
|
||||||
|
/// adds its implementation to the requested functions.
|
||||||
/// @param _revertOnFailure if true, causes revert on invalid data,
|
/// @param _revertOnFailure if true, causes revert on invalid data,
|
||||||
/// otherwise an assertion failure.
|
/// otherwise an assertion failure.
|
||||||
std::string cleanupFunction(Type const& _type, bool _revertOnFailure = false);
|
///
|
||||||
|
/// This is used for data decoded from external sources.
|
||||||
|
std::string validatorFunction(Type const& _type, bool _revertOnFailure = false);
|
||||||
|
|
||||||
/// Performs cleanup after reading from a potentially compressed storage slot.
|
/// Performs cleanup after reading from a potentially compressed storage slot.
|
||||||
/// The function does not perform any validation, it just masks or sign-extends
|
/// The function does not perform any validation, it just masks or sign-extends
|
||||||
@ -146,10 +154,10 @@ private:
|
|||||||
/// @returns the name of the function that converts a value of type @a _from
|
/// @returns the name of the function that converts a value of type @a _from
|
||||||
/// to a value of type @a _to. The resulting vale is guaranteed to be in range
|
/// to a value of type @a _to. The resulting vale is guaranteed to be in range
|
||||||
/// (i.e. "clean"). Asserts on failure.
|
/// (i.e. "clean"). Asserts on failure.
|
||||||
|
///
|
||||||
|
/// This is used for data being encoded or general type conversions in the code.
|
||||||
std::string conversionFunction(Type const& _from, Type const& _to);
|
std::string conversionFunction(Type const& _from, Type const& _to);
|
||||||
|
|
||||||
std::string cleanupCombinedExternalFunctionIdFunction();
|
|
||||||
|
|
||||||
/// @returns the name of the ABI encoding function with the given type
|
/// @returns the name of the ABI encoding function with the given type
|
||||||
/// and queues the generation of the function to the requested functions.
|
/// and queues the generation of the function to the requested functions.
|
||||||
/// @param _fromStack if false, the input value was just loaded from storage
|
/// @param _fromStack if false, the input value was just loaded from storage
|
||||||
|
@ -1406,6 +1406,7 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
|
|||||||
case Type::Category::Struct:
|
case Type::Category::Struct:
|
||||||
{
|
{
|
||||||
StructType const& type = dynamic_cast<StructType const&>(*_memberAccess.expression().annotation().type);
|
StructType const& type = dynamic_cast<StructType const&>(*_memberAccess.expression().annotation().type);
|
||||||
|
TypePointer const& memberType = _memberAccess.annotation().type;
|
||||||
switch (type.location())
|
switch (type.location())
|
||||||
{
|
{
|
||||||
case DataLocation::Storage:
|
case DataLocation::Storage:
|
||||||
@ -1418,7 +1419,7 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
|
|||||||
case DataLocation::Memory:
|
case DataLocation::Memory:
|
||||||
{
|
{
|
||||||
m_context << type.memoryOffsetOfMember(member) << Instruction::ADD;
|
m_context << type.memoryOffsetOfMember(member) << Instruction::ADD;
|
||||||
setLValue<MemoryItem>(_memberAccess, *_memberAccess.annotation().type);
|
setLValue<MemoryItem>(_memberAccess, *memberType);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DataLocation::CallData:
|
case DataLocation::CallData:
|
||||||
@ -1427,21 +1428,28 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
|
|||||||
{
|
{
|
||||||
m_context << Instruction::DUP1;
|
m_context << Instruction::DUP1;
|
||||||
m_context << type.calldataOffsetOfMember(member) << Instruction::ADD;
|
m_context << type.calldataOffsetOfMember(member) << Instruction::ADD;
|
||||||
CompilerUtils(m_context).accessCalldataTail(*_memberAccess.annotation().type);
|
CompilerUtils(m_context).accessCalldataTail(*memberType);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_context << type.calldataOffsetOfMember(member) << Instruction::ADD;
|
m_context << type.calldataOffsetOfMember(member) << Instruction::ADD;
|
||||||
// For non-value types the calldata offset is returned directly.
|
// For non-value types the calldata offset is returned directly.
|
||||||
if (_memberAccess.annotation().type->isValueType())
|
if (memberType->isValueType())
|
||||||
{
|
{
|
||||||
solAssert(_memberAccess.annotation().type->calldataEncodedSize() > 0, "");
|
solAssert(memberType->calldataEncodedSize() > 0, "");
|
||||||
CompilerUtils(m_context).loadFromMemoryDynamic(*_memberAccess.annotation().type, true, true, false);
|
solAssert(memberType->storageBytes() <= 32, "");
|
||||||
|
if (memberType->storageBytes() < 32 && m_context.experimentalFeatureActive(ExperimentalFeature::ABIEncoderV2))
|
||||||
|
{
|
||||||
|
m_context << u256(32);
|
||||||
|
CompilerUtils(m_context).abiDecodeV2({memberType}, false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
CompilerUtils(m_context).loadFromMemoryDynamic(*memberType, true, true, false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
solAssert(
|
solAssert(
|
||||||
_memberAccess.annotation().type->category() == Type::Category::Array ||
|
memberType->category() == Type::Category::Array ||
|
||||||
_memberAccess.annotation().type->category() == Type::Category::Struct,
|
memberType->category() == Type::Category::Struct,
|
||||||
""
|
""
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -1588,12 +1596,25 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess)
|
|||||||
{
|
{
|
||||||
ArrayUtils(m_context).accessIndex(arrayType, true);
|
ArrayUtils(m_context).accessIndex(arrayType, true);
|
||||||
if (arrayType.baseType()->isValueType())
|
if (arrayType.baseType()->isValueType())
|
||||||
|
{
|
||||||
|
solAssert(arrayType.baseType()->storageBytes() <= 32, "");
|
||||||
|
if (
|
||||||
|
!arrayType.isByteArray() &&
|
||||||
|
arrayType.baseType()->storageBytes() < 32 &&
|
||||||
|
m_context.experimentalFeatureActive(ExperimentalFeature::ABIEncoderV2)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
m_context << u256(32);
|
||||||
|
CompilerUtils(m_context).abiDecodeV2({arrayType.baseType()}, false);
|
||||||
|
}
|
||||||
|
else
|
||||||
CompilerUtils(m_context).loadFromMemoryDynamic(
|
CompilerUtils(m_context).loadFromMemoryDynamic(
|
||||||
*arrayType.baseType(),
|
*arrayType.baseType(),
|
||||||
true,
|
true,
|
||||||
!arrayType.isByteArray(),
|
!arrayType.isByteArray(),
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
solAssert(
|
solAssert(
|
||||||
arrayType.baseType()->category() == Type::Category::Struct ||
|
arrayType.baseType()->category() == Type::Category::Struct ||
|
||||||
|
@ -2,11 +2,11 @@
|
|||||||
======= gas_test_abiv2/input.sol:C =======
|
======= gas_test_abiv2/input.sol:C =======
|
||||||
Gas estimation:
|
Gas estimation:
|
||||||
construction:
|
construction:
|
||||||
1140 + 1096600 = 1097740
|
1160 + 1115800 = 1116960
|
||||||
external:
|
external:
|
||||||
a(): 530
|
a(): 530
|
||||||
b(uint256): 1118
|
b(uint256): infinite
|
||||||
f1(uint256): 586
|
f1(uint256): infinite
|
||||||
f2(uint256[],string[],uint16,address): infinite
|
f2(uint256[],string[],uint16,address): infinite
|
||||||
f3(uint16[],string[],uint16,address): infinite
|
f3(uint16[],string[],uint16,address): infinite
|
||||||
f4(uint32[],string[12],bytes[2][],address): infinite
|
f4(uint32[],string[12],bytes[2][],address): infinite
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
======= gas_test_abiv2_optimize_yul/input.sol:C =======
|
======= gas_test_abiv2_optimize_yul/input.sol:C =======
|
||||||
Gas estimation:
|
Gas estimation:
|
||||||
construction:
|
construction:
|
||||||
651 + 617200 = 617851
|
651 + 616600 = 617251
|
||||||
external:
|
external:
|
||||||
a(): 429
|
a(): 429
|
||||||
b(uint256): 884
|
b(uint256): 884
|
||||||
|
@ -464,7 +464,8 @@ BOOST_AUTO_TEST_CASE(creation)
|
|||||||
{
|
{
|
||||||
deployWallet(200);
|
deployWallet(200);
|
||||||
BOOST_REQUIRE(callContractFunction("isOwner(address)", h256(m_sender, h256::AlignRight)) == encodeArgs(true));
|
BOOST_REQUIRE(callContractFunction("isOwner(address)", h256(m_sender, h256::AlignRight)) == encodeArgs(true));
|
||||||
BOOST_REQUIRE(callContractFunction("isOwner(address)", ~h256(m_sender, h256::AlignRight)) == encodeArgs(false));
|
bool v2 = dev::test::Options::get().useABIEncoderV2;
|
||||||
|
BOOST_REQUIRE(callContractFunction("isOwner(address)", ~h256(m_sender, h256::AlignRight)) == (v2 ? encodeArgs() : encodeArgs(false)));
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(add_owners)
|
BOOST_AUTO_TEST_CASE(add_owners)
|
||||||
|
@ -108,6 +108,7 @@ BOOST_AUTO_TEST_CASE(cleanup)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
|
bool newDecoder = dev::test::Options::get().useABIEncoderV2;
|
||||||
BOTH_ENCODERS(
|
BOTH_ENCODERS(
|
||||||
compileAndRun(sourceCode);
|
compileAndRun(sourceCode);
|
||||||
ABI_CHECK(
|
ABI_CHECK(
|
||||||
@ -117,10 +118,46 @@ BOOST_AUTO_TEST_CASE(cleanup)
|
|||||||
ABI_CHECK(
|
ABI_CHECK(
|
||||||
callContractFunction(
|
callContractFunction(
|
||||||
"f(uint16,int16,address,bytes3,bool)",
|
"f(uint16,int16,address,bytes3,bool)",
|
||||||
u256(0xffffff), u256(0x1ffff), u256(-1), string("abcd"), u256(4)
|
u256(0xffffff), u256(0x1ffff), u256(-1), string("abcd"), u256(1)
|
||||||
),
|
),
|
||||||
encodeArgs(u256(0xffff), u256(-1), (u256(1) << 160) - 1, string("abc"), true)
|
newDecoder ? bytes{} : encodeArgs(u256(0xffff), u256(-1), (u256(1) << 160) - 1, string("abc"), true)
|
||||||
);
|
);
|
||||||
|
ABI_CHECK(
|
||||||
|
callContractFunction(
|
||||||
|
"f(uint16,int16,address,bytes3,bool)",
|
||||||
|
u256(0xffffff), u256(0), u256(0), string("bcd"), u256(1)
|
||||||
|
),
|
||||||
|
newDecoder ? bytes{} : encodeArgs(u256(0xffff), u256(0), 0, string("bcd"), true)
|
||||||
|
);
|
||||||
|
ABI_CHECK(
|
||||||
|
callContractFunction(
|
||||||
|
"f(uint16,int16,address,bytes3,bool)",
|
||||||
|
u256(0), u256(0x1ffff), u256(0), string("ab"), u256(1)
|
||||||
|
),
|
||||||
|
newDecoder ? bytes{} : encodeArgs(u256(0), u256(-1), 0, string("ab"), true)
|
||||||
|
);
|
||||||
|
ABI_CHECK(
|
||||||
|
callContractFunction(
|
||||||
|
"f(uint16,int16,address,bytes3,bool)",
|
||||||
|
u256(0), u256(0), u256(-1), string("ad"), u256(1)
|
||||||
|
),
|
||||||
|
newDecoder ? bytes{} : encodeArgs(u256(0), u256(0), (u256(1) << 160) - 1, string("ad"), true)
|
||||||
|
);
|
||||||
|
ABI_CHECK(
|
||||||
|
callContractFunction(
|
||||||
|
"f(uint16,int16,address,bytes3,bool)",
|
||||||
|
u256(0), u256(0), u256(0), string("abcd"), u256(1)
|
||||||
|
),
|
||||||
|
newDecoder ? bytes{} : encodeArgs(u256(0), u256(0), 0, string("abc"), true)
|
||||||
|
);
|
||||||
|
ABI_CHECK(
|
||||||
|
callContractFunction(
|
||||||
|
"f(uint16,int16,address,bytes3,bool)",
|
||||||
|
u256(0), u256(0), u256(0), string("abc"), u256(2)
|
||||||
|
),
|
||||||
|
newDecoder ? bytes{} : encodeArgs(u256(0), u256(0), 0, string("abc"), true)
|
||||||
|
);
|
||||||
|
newDecoder = true;
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -506,7 +543,7 @@ BOOST_AUTO_TEST_CASE(short_input_bytes)
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(cleanup_int_inside_arrays)
|
BOOST_AUTO_TEST_CASE(validation_int_inside_arrays)
|
||||||
{
|
{
|
||||||
string sourceCode = R"(
|
string sourceCode = R"(
|
||||||
contract C {
|
contract C {
|
||||||
@ -521,15 +558,69 @@ BOOST_AUTO_TEST_CASE(cleanup_int_inside_arrays)
|
|||||||
ABI_CHECK(callContractFunction("f(uint16[])", 0x20, 1, 7), encodeArgs(7));
|
ABI_CHECK(callContractFunction("f(uint16[])", 0x20, 1, 7), encodeArgs(7));
|
||||||
ABI_CHECK(callContractFunction("g(int16[])", 0x20, 1, 7), encodeArgs(7));
|
ABI_CHECK(callContractFunction("g(int16[])", 0x20, 1, 7), encodeArgs(7));
|
||||||
ABI_CHECK(callContractFunction("f(uint16[])", 0x20, 1, u256("0xffff")), encodeArgs(u256("0xffff")));
|
ABI_CHECK(callContractFunction("f(uint16[])", 0x20, 1, u256("0xffff")), encodeArgs(u256("0xffff")));
|
||||||
ABI_CHECK(callContractFunction("g(int16[])", 0x20, 1, u256("0xffff")), encodeArgs(u256(-1)));
|
ABI_CHECK(callContractFunction("g(int16[])", 0x20, 1, u256("0xffff")), encodeArgs());
|
||||||
ABI_CHECK(callContractFunction("f(uint16[])", 0x20, 1, u256("0x1ffff")), encodeArgs(u256("0xffff")));
|
ABI_CHECK(callContractFunction("f(uint16[])", 0x20, 1, u256("0x1ffff")), encodeArgs());
|
||||||
ABI_CHECK(callContractFunction("g(int16[])", 0x20, 1, u256("0x10fff")), encodeArgs(u256("0x0fff")));
|
ABI_CHECK(callContractFunction("g(int16[])", 0x20, 1, u256("0x10fff")), encodeArgs());
|
||||||
ABI_CHECK(callContractFunction("h(uint8[])", 0x20, 1, 0), encodeArgs(u256(0)));
|
ABI_CHECK(callContractFunction("h(uint8[])", 0x20, 1, 0), encodeArgs(u256(0)));
|
||||||
ABI_CHECK(callContractFunction("h(uint8[])", 0x20, 1, 1), encodeArgs(u256(1)));
|
ABI_CHECK(callContractFunction("h(uint8[])", 0x20, 1, 1), encodeArgs(u256(1)));
|
||||||
ABI_CHECK(callContractFunction("h(uint8[])", 0x20, 1, 2), encodeArgs());
|
ABI_CHECK(callContractFunction("h(uint8[])", 0x20, 1, 2), encodeArgs());
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(validation_function_type)
|
||||||
|
{
|
||||||
|
string sourceCode = R"(
|
||||||
|
contract C {
|
||||||
|
function f(function () external) public pure returns (uint r) { r = 1; }
|
||||||
|
function g(function () external[] memory) public pure returns (uint r) { r = 2; }
|
||||||
|
function h(function () external[] calldata) external pure returns (uint r) { r = 3; }
|
||||||
|
function i(function () external[] calldata a) external pure returns (uint r) { a[0]; r = 4; }
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
bool newDecoder = dev::test::Options::get().useABIEncoderV2;
|
||||||
|
string validFun{"01234567890123456789abcd"};
|
||||||
|
string invalidFun{"01234567890123456789abcdX"};
|
||||||
|
BOTH_ENCODERS(
|
||||||
|
compileAndRun(sourceCode);
|
||||||
|
ABI_CHECK(callContractFunction("f(function)", validFun), encodeArgs(1));
|
||||||
|
ABI_CHECK(callContractFunction("f(function)", invalidFun), newDecoder ? bytes{} : encodeArgs(1));
|
||||||
|
ABI_CHECK(callContractFunction("g(function[])", 0x20, 1, validFun), encodeArgs(2));
|
||||||
|
ABI_CHECK(callContractFunction("g(function[])", 0x20, 1, invalidFun), newDecoder ? bytes{} : encodeArgs(2));
|
||||||
|
ABI_CHECK(callContractFunction("h(function[])", 0x20, 1, validFun), encodeArgs(3));
|
||||||
|
// No failure because the data is not accessed.
|
||||||
|
ABI_CHECK(callContractFunction("h(function[])", 0x20, 1, invalidFun), encodeArgs(3));
|
||||||
|
ABI_CHECK(callContractFunction("i(function[])", 0x20, 1, validFun), encodeArgs(4));
|
||||||
|
ABI_CHECK(callContractFunction("i(function[])", 0x20, 1, invalidFun), newDecoder ? bytes{} : encodeArgs(4));
|
||||||
|
newDecoder = true;
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(validation_function_type_inside_struct)
|
||||||
|
{
|
||||||
|
string sourceCode = R"(
|
||||||
|
contract C {
|
||||||
|
struct S { function () external x; }
|
||||||
|
function f(S memory) public pure returns (uint r) { r = 1; }
|
||||||
|
function g(S calldata) external pure returns (uint r) { r = 2; }
|
||||||
|
function h(S calldata s) external pure returns (uint r) { s.x; r = 3; }
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
string validFun{"01234567890123456789abcd"};
|
||||||
|
string invalidFun{"01234567890123456789abcdX"};
|
||||||
|
NEW_ENCODER(
|
||||||
|
compileAndRun(sourceCode);
|
||||||
|
ABI_CHECK(callContractFunction("f((function))", validFun), encodeArgs(1));
|
||||||
|
// Error because we copy to memory
|
||||||
|
ABI_CHECK(callContractFunction("f((function))", invalidFun), encodeArgs());
|
||||||
|
ABI_CHECK(callContractFunction("g((function))", validFun), encodeArgs(2));
|
||||||
|
// No error because x is not accessed.
|
||||||
|
ABI_CHECK(callContractFunction("g((function))", invalidFun), encodeArgs(2));
|
||||||
|
ABI_CHECK(callContractFunction("h((function))", validFun), encodeArgs(3));
|
||||||
|
// Error on access.
|
||||||
|
ABI_CHECK(callContractFunction("h((function))", invalidFun), encodeArgs());
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(storage_ptr)
|
BOOST_AUTO_TEST_CASE(storage_ptr)
|
||||||
{
|
{
|
||||||
string sourceCode = R"(
|
string sourceCode = R"(
|
||||||
@ -583,7 +674,7 @@ BOOST_AUTO_TEST_CASE(struct_simple)
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(struct_cleanup)
|
BOOST_AUTO_TEST_CASE(struct_validation)
|
||||||
{
|
{
|
||||||
string sourceCode = R"(
|
string sourceCode = R"(
|
||||||
contract C {
|
contract C {
|
||||||
@ -597,11 +688,24 @@ BOOST_AUTO_TEST_CASE(struct_cleanup)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
|
u256 largeNeg("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01");
|
||||||
NEW_ENCODER(
|
NEW_ENCODER(
|
||||||
compileAndRun(sourceCode, 0, "C");
|
compileAndRun(sourceCode, 0, "C");
|
||||||
ABI_CHECK(
|
ABI_CHECK(
|
||||||
callContractFunction("f((int16,uint8,bytes2))", 0xff010, 0xff0002, "abcd"),
|
callContractFunction("f((int16,uint8,bytes2))", largeNeg, 0xff, "ab"),
|
||||||
encodeArgs(u256("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff010"), 2, "ab")
|
encodeArgs(largeNeg, 0xff, "ab")
|
||||||
|
);
|
||||||
|
ABI_CHECK(
|
||||||
|
callContractFunction("f((int16,uint8,bytes2))", 0xff010, 0xff, "ab"),
|
||||||
|
encodeArgs()
|
||||||
|
);
|
||||||
|
ABI_CHECK(
|
||||||
|
callContractFunction("f((int16,uint8,bytes2))", largeNeg, 0xff0002, "ab"),
|
||||||
|
encodeArgs()
|
||||||
|
);
|
||||||
|
ABI_CHECK(
|
||||||
|
callContractFunction("f((int16,uint8,bytes2))", largeNeg, 0xff, "abcd"),
|
||||||
|
encodeArgs()
|
||||||
);
|
);
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -759,7 +863,6 @@ BOOST_AUTO_TEST_CASE(complex_struct)
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(return_dynamic_types_cross_call_simple)
|
BOOST_AUTO_TEST_CASE(return_dynamic_types_cross_call_simple)
|
||||||
{
|
{
|
||||||
if (m_evmVersion == langutil::EVMVersion::homestead())
|
if (m_evmVersion == langutil::EVMVersion::homestead())
|
||||||
@ -844,6 +947,24 @@ BOOST_AUTO_TEST_CASE(return_dynamic_types_cross_call_out_of_range)
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(out_of_bounds_bool_value)
|
||||||
|
{
|
||||||
|
string sourceCode = R"(
|
||||||
|
contract C {
|
||||||
|
function f(bool b) public pure returns (bool) { return b; }
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
bool newDecoder = dev::test::Options::get().useABIEncoderV2;
|
||||||
|
BOTH_ENCODERS(
|
||||||
|
compileAndRun(sourceCode);
|
||||||
|
ABI_CHECK(callContractFunction("f(bool)", true), encodeArgs(true));
|
||||||
|
ABI_CHECK(callContractFunction("f(bool)", false), encodeArgs(false));
|
||||||
|
ABI_CHECK(callContractFunctionNoEncoding("f(bool)", bytes(32, 0)), encodeArgs(0));
|
||||||
|
ABI_CHECK(callContractFunctionNoEncoding("f(bool)", bytes(32, 0xff)), newDecoder ? encodeArgs() : encodeArgs(1));
|
||||||
|
newDecoder = true;
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE_END()
|
BOOST_AUTO_TEST_SUITE_END()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -6773,16 +6773,17 @@ BOOST_AUTO_TEST_CASE(bool_conversion)
|
|||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
compileAndRun(sourceCode, 0, "C");
|
compileAndRun(sourceCode, 0, "C");
|
||||||
|
bool v2 = dev::test::Options::get().useABIEncoderV2;
|
||||||
ABI_CHECK(callContractFunction("f(bool)", 0), encodeArgs(0));
|
ABI_CHECK(callContractFunction("f(bool)", 0), encodeArgs(0));
|
||||||
ABI_CHECK(callContractFunction("f(bool)", 1), encodeArgs(1));
|
ABI_CHECK(callContractFunction("f(bool)", 1), encodeArgs(1));
|
||||||
ABI_CHECK(callContractFunction("f(bool)", 2), encodeArgs(1));
|
ABI_CHECK(callContractFunction("f(bool)", 2), v2 ? encodeArgs() : encodeArgs(1));
|
||||||
ABI_CHECK(callContractFunction("f(bool)", 3), encodeArgs(1));
|
ABI_CHECK(callContractFunction("f(bool)", 3), v2 ? encodeArgs() : encodeArgs(1));
|
||||||
ABI_CHECK(callContractFunction("f(bool)", 255), encodeArgs(1));
|
ABI_CHECK(callContractFunction("f(bool)", 255), v2 ? encodeArgs() : encodeArgs(1));
|
||||||
ABI_CHECK(callContractFunction("g(bool)", 0), encodeArgs(0));
|
ABI_CHECK(callContractFunction("g(bool)", 0), encodeArgs(0));
|
||||||
ABI_CHECK(callContractFunction("g(bool)", 1), encodeArgs(1));
|
ABI_CHECK(callContractFunction("g(bool)", 1), encodeArgs(1));
|
||||||
ABI_CHECK(callContractFunction("g(bool)", 2), encodeArgs(1));
|
ABI_CHECK(callContractFunction("g(bool)", 2), v2 ? encodeArgs() : encodeArgs(1));
|
||||||
ABI_CHECK(callContractFunction("g(bool)", 3), encodeArgs(1));
|
ABI_CHECK(callContractFunction("g(bool)", 3), v2 ? encodeArgs() : encodeArgs(1));
|
||||||
ABI_CHECK(callContractFunction("g(bool)", 255), encodeArgs(1));
|
ABI_CHECK(callContractFunction("g(bool)", 255), v2 ? encodeArgs() : encodeArgs(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(packed_storage_signed)
|
BOOST_AUTO_TEST_CASE(packed_storage_signed)
|
||||||
@ -8244,8 +8245,8 @@ BOOST_AUTO_TEST_CASE(calldata_struct_cleaning)
|
|||||||
|
|
||||||
// double check that the valid case goes through
|
// double check that the valid case goes through
|
||||||
ABI_CHECK(callContractFunction("f((uint8,bytes1))", u256(0x12), bytes{0x34} + bytes(31,0)), encodeArgs(0x12, bytes{0x34} + bytes(31,0)));
|
ABI_CHECK(callContractFunction("f((uint8,bytes1))", u256(0x12), bytes{0x34} + bytes(31,0)), encodeArgs(0x12, bytes{0x34} + bytes(31,0)));
|
||||||
ABI_CHECK(callContractFunction("f((uint8,bytes1))", u256(0x1234), bytes{0x56, 0x78} + bytes(30,0)), encodeArgs(0x34, bytes{0x56} + bytes(31,0)));
|
ABI_CHECK(callContractFunction("f((uint8,bytes1))", u256(0x1234), bytes{0x56, 0x78} + bytes(30,0)), encodeArgs());
|
||||||
ABI_CHECK(callContractFunction("f((uint8,bytes1))", u256(-1), u256(-1)), encodeArgs(0xFF, bytes{0xFF} + bytes(31,0)));
|
ABI_CHECK(callContractFunction("f((uint8,bytes1))", u256(-1), u256(-1)), encodeArgs());
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(calldata_struct_function_type)
|
BOOST_AUTO_TEST_CASE(calldata_struct_function_type)
|
||||||
@ -11031,7 +11032,8 @@ BOOST_AUTO_TEST_CASE(cleanup_bytes_types)
|
|||||||
)";
|
)";
|
||||||
compileAndRun(sourceCode, 0, "C");
|
compileAndRun(sourceCode, 0, "C");
|
||||||
// We input longer data on purpose.
|
// We input longer data on purpose.
|
||||||
ABI_CHECK(callContractFunction("f(bytes2,uint16)", string("abc"), u256(0x040102)), encodeArgs(0));
|
bool v2 = dev::test::Options::get().useABIEncoderV2;
|
||||||
|
ABI_CHECK(callContractFunction("f(bytes2,uint16)", string("abc"), u256(0x040102)), v2 ? encodeArgs() : encodeArgs(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(cleanup_bytes_types_shortening)
|
BOOST_AUTO_TEST_CASE(cleanup_bytes_types_shortening)
|
||||||
@ -11068,9 +11070,11 @@ BOOST_AUTO_TEST_CASE(cleanup_address_types)
|
|||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
compileAndRun(sourceCode, 0, "C");
|
compileAndRun(sourceCode, 0, "C");
|
||||||
|
|
||||||
|
bool v2 = dev::test::Options::get().useABIEncoderV2;
|
||||||
// We input longer data on purpose.
|
// We input longer data on purpose.
|
||||||
ABI_CHECK(callContractFunction("f(address)", u256("0xFFFF1234567890123456789012345678901234567890")), encodeArgs(0));
|
ABI_CHECK(callContractFunction("f(address)", u256("0xFFFF1234567890123456789012345678901234567890")), v2 ? encodeArgs() : encodeArgs(0));
|
||||||
ABI_CHECK(callContractFunction("g(address)", u256("0xFFFF1234567890123456789012345678901234567890")), encodeArgs(0));
|
ABI_CHECK(callContractFunction("g(address)", u256("0xFFFF1234567890123456789012345678901234567890")), v2 ? encodeArgs() : encodeArgs(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(cleanup_address_types_shortening)
|
BOOST_AUTO_TEST_CASE(cleanup_address_types_shortening)
|
||||||
@ -12325,8 +12329,9 @@ BOOST_AUTO_TEST_CASE(shift_right_garbled)
|
|||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
compileAndRun(sourceCode, 0, "C");
|
compileAndRun(sourceCode, 0, "C");
|
||||||
|
bool v2 = dev::test::Options::get().useABIEncoderV2;
|
||||||
ABI_CHECK(callContractFunction("f(uint8,uint8)", u256(0x0), u256(4)), encodeArgs(u256(0xf)));
|
ABI_CHECK(callContractFunction("f(uint8,uint8)", u256(0x0), u256(4)), encodeArgs(u256(0xf)));
|
||||||
ABI_CHECK(callContractFunction("f(uint8,uint8)", u256(0x0), u256(0x1004)), encodeArgs(u256(0xf)));
|
ABI_CHECK(callContractFunction("f(uint8,uint8)", u256(0x0), u256(0x1004)), v2 ? encodeArgs() : encodeArgs(u256(0xf)));
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(shift_right_garbled_signed)
|
BOOST_AUTO_TEST_CASE(shift_right_garbled_signed)
|
||||||
@ -12350,16 +12355,17 @@ BOOST_AUTO_TEST_CASE(shift_right_garbled_signed)
|
|||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
compileAndRun(sourceCode, 0, "C");
|
compileAndRun(sourceCode, 0, "C");
|
||||||
|
bool v2 = dev::test::Options::get().useABIEncoderV2;
|
||||||
ABI_CHECK(callContractFunction("f(int8,uint8)", u256(0x0), u256(3)), encodeArgs(u256(-2)));
|
ABI_CHECK(callContractFunction("f(int8,uint8)", u256(0x0), u256(3)), encodeArgs(u256(-2)));
|
||||||
ABI_CHECK(callContractFunction("f(int8,uint8)", u256(0x0), u256(4)), encodeArgs(u256(-1)));
|
ABI_CHECK(callContractFunction("f(int8,uint8)", u256(0x0), u256(4)), encodeArgs(u256(-1)));
|
||||||
ABI_CHECK(callContractFunction("f(int8,uint8)", u256(0x0), u256(0xFF)), encodeArgs(u256(-1)));
|
ABI_CHECK(callContractFunction("f(int8,uint8)", u256(0x0), u256(0xFF)), encodeArgs(u256(-1)));
|
||||||
ABI_CHECK(callContractFunction("f(int8,uint8)", u256(0x0), u256(0x1003)), encodeArgs(u256(-2)));
|
ABI_CHECK(callContractFunction("f(int8,uint8)", u256(0x0), u256(0x1003)), v2 ? encodeArgs() : encodeArgs(u256(-2)));
|
||||||
ABI_CHECK(callContractFunction("f(int8,uint8)", u256(0x0), u256(0x1004)), encodeArgs(u256(-1)));
|
ABI_CHECK(callContractFunction("f(int8,uint8)", u256(0x0), u256(0x1004)), v2 ? encodeArgs() : encodeArgs(u256(-1)));
|
||||||
ABI_CHECK(callContractFunction("g(int8,uint8)", u256(0x0), u256(3)), encodeArgs(u256(-2)));
|
ABI_CHECK(callContractFunction("g(int8,uint8)", u256(0x0), u256(3)), encodeArgs(u256(-2)));
|
||||||
ABI_CHECK(callContractFunction("g(int8,uint8)", u256(0x0), u256(4)), encodeArgs(u256(-1)));
|
ABI_CHECK(callContractFunction("g(int8,uint8)", u256(0x0), u256(4)), encodeArgs(u256(-1)));
|
||||||
ABI_CHECK(callContractFunction("g(int8,uint8)", u256(0x0), u256(0xFF)), encodeArgs(u256(-1)));
|
ABI_CHECK(callContractFunction("g(int8,uint8)", u256(0x0), u256(0xFF)), encodeArgs(u256(-1)));
|
||||||
ABI_CHECK(callContractFunction("g(int8,uint8)", u256(0x0), u256(0x1003)), encodeArgs(u256(-2)));
|
ABI_CHECK(callContractFunction("g(int8,uint8)", u256(0x0), u256(0x1003)), v2 ? encodeArgs() : encodeArgs(u256(-2)));
|
||||||
ABI_CHECK(callContractFunction("g(int8,uint8)", u256(0x0), u256(0x1004)), encodeArgs(u256(-1)));
|
ABI_CHECK(callContractFunction("g(int8,uint8)", u256(0x0), u256(0x1004)), v2 ? encodeArgs() : encodeArgs(u256(-1)));
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(shift_right_uint32)
|
BOOST_AUTO_TEST_CASE(shift_right_uint32)
|
||||||
@ -12541,11 +12547,12 @@ BOOST_AUTO_TEST_CASE(shift_right_negative_lvalue_signextend_int8)
|
|||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
compileAndRun(sourceCode, 0, "C");
|
compileAndRun(sourceCode, 0, "C");
|
||||||
ABI_CHECK(callContractFunction("f(int8,int8)", u256(0x99u), u256(0)), encodeArgs(u256(-103)));
|
bool v2 = dev::test::Options::get().useABIEncoderV2;
|
||||||
ABI_CHECK(callContractFunction("f(int8,int8)", u256(0x99u), u256(1)), encodeArgs(u256(-52)));
|
ABI_CHECK(callContractFunction("f(int8,int8)", u256(0x99u), u256(0)), v2 ? encodeArgs() : encodeArgs(u256(-103)));
|
||||||
ABI_CHECK(callContractFunction("f(int8,int8)", u256(0x99u), u256(2)), encodeArgs(u256(-26)));
|
ABI_CHECK(callContractFunction("f(int8,int8)", u256(0x99u), u256(1)), v2 ? encodeArgs() : encodeArgs(u256(-52)));
|
||||||
ABI_CHECK(callContractFunction("f(int8,int8)", u256(0x99u), u256(4)), encodeArgs(u256(-7)));
|
ABI_CHECK(callContractFunction("f(int8,int8)", u256(0x99u), u256(2)), v2 ? encodeArgs() : encodeArgs(u256(-26)));
|
||||||
ABI_CHECK(callContractFunction("f(int8,int8)", u256(0x99u), u256(8)), encodeArgs(u256(-1)));
|
ABI_CHECK(callContractFunction("f(int8,int8)", u256(0x99u), u256(4)), v2 ? encodeArgs() : encodeArgs(u256(-7)));
|
||||||
|
ABI_CHECK(callContractFunction("f(int8,int8)", u256(0x99u), u256(8)), v2 ? encodeArgs() : encodeArgs(u256(-1)));
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(shift_right_negative_lvalue_signextend_int16)
|
BOOST_AUTO_TEST_CASE(shift_right_negative_lvalue_signextend_int16)
|
||||||
@ -12558,11 +12565,12 @@ BOOST_AUTO_TEST_CASE(shift_right_negative_lvalue_signextend_int16)
|
|||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
compileAndRun(sourceCode, 0, "C");
|
compileAndRun(sourceCode, 0, "C");
|
||||||
ABI_CHECK(callContractFunction("f(int16,int16)", u256(0xFF99u), u256(0)), encodeArgs(u256(-103)));
|
bool v2 = dev::test::Options::get().useABIEncoderV2;
|
||||||
ABI_CHECK(callContractFunction("f(int16,int16)", u256(0xFF99u), u256(1)), encodeArgs(u256(-52)));
|
ABI_CHECK(callContractFunction("f(int16,int16)", u256(0xFF99u), u256(0)), v2 ? encodeArgs() : encodeArgs(u256(-103)));
|
||||||
ABI_CHECK(callContractFunction("f(int16,int16)", u256(0xFF99u), u256(2)), encodeArgs(u256(-26)));
|
ABI_CHECK(callContractFunction("f(int16,int16)", u256(0xFF99u), u256(1)), v2 ? encodeArgs() : encodeArgs(u256(-52)));
|
||||||
ABI_CHECK(callContractFunction("f(int16,int16)", u256(0xFF99u), u256(4)), encodeArgs(u256(-7)));
|
ABI_CHECK(callContractFunction("f(int16,int16)", u256(0xFF99u), u256(2)), v2 ? encodeArgs() : encodeArgs(u256(-26)));
|
||||||
ABI_CHECK(callContractFunction("f(int16,int16)", u256(0xFF99u), u256(8)), encodeArgs(u256(-1)));
|
ABI_CHECK(callContractFunction("f(int16,int16)", u256(0xFF99u), u256(4)), v2 ? encodeArgs() : encodeArgs(u256(-7)));
|
||||||
|
ABI_CHECK(callContractFunction("f(int16,int16)", u256(0xFF99u), u256(8)), v2 ? encodeArgs() : encodeArgs(u256(-1)));
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(shift_right_negative_lvalue_signextend_int32)
|
BOOST_AUTO_TEST_CASE(shift_right_negative_lvalue_signextend_int32)
|
||||||
@ -12575,11 +12583,12 @@ BOOST_AUTO_TEST_CASE(shift_right_negative_lvalue_signextend_int32)
|
|||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
compileAndRun(sourceCode, 0, "C");
|
compileAndRun(sourceCode, 0, "C");
|
||||||
ABI_CHECK(callContractFunction("f(int32,int32)", u256(0xFFFFFF99u), u256(0)), encodeArgs(u256(-103)));
|
bool v2 = dev::test::Options::get().useABIEncoderV2;
|
||||||
ABI_CHECK(callContractFunction("f(int32,int32)", u256(0xFFFFFF99u), u256(1)), encodeArgs(u256(-52)));
|
ABI_CHECK(callContractFunction("f(int32,int32)", u256(0xFFFFFF99u), u256(0)), v2 ? encodeArgs() : encodeArgs(u256(-103)));
|
||||||
ABI_CHECK(callContractFunction("f(int32,int32)", u256(0xFFFFFF99u), u256(2)), encodeArgs(u256(-26)));
|
ABI_CHECK(callContractFunction("f(int32,int32)", u256(0xFFFFFF99u), u256(1)), v2 ? encodeArgs() : encodeArgs(u256(-52)));
|
||||||
ABI_CHECK(callContractFunction("f(int32,int32)", u256(0xFFFFFF99u), u256(4)), encodeArgs(u256(-7)));
|
ABI_CHECK(callContractFunction("f(int32,int32)", u256(0xFFFFFF99u), u256(2)), v2 ? encodeArgs() : encodeArgs(u256(-26)));
|
||||||
ABI_CHECK(callContractFunction("f(int32,int32)", u256(0xFFFFFF99u), u256(8)), encodeArgs(u256(-1)));
|
ABI_CHECK(callContractFunction("f(int32,int32)", u256(0xFFFFFF99u), u256(4)), v2 ? encodeArgs() : encodeArgs(u256(-7)));
|
||||||
|
ABI_CHECK(callContractFunction("f(int32,int32)", u256(0xFFFFFF99u), u256(8)), v2 ? encodeArgs() : encodeArgs(u256(-1)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user