mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
b3230b0bdc
test: updat filereader test deprecate namespace std deprecate namespace std deprecate namespace std deprecate namespace std deprecate namespace std deprecate namespace std deprecate namespace std deprecate namespace std deprecated std namespace deprecated std namespace deprecated std namespace deprecated std namespace deprecated std namespace deprecated std namespace deprecated std namespace deprecated std namespace deprecated std namespace depecrate namespace std deprecated namespace std check ci clean line Co-authored-by: Nikola Matić <nikola.matic@ethereum.org> purge line pure line deprecate std deprecate std deprecate std deprecate std deprecate std deprecate deprecate std bye namespace
432 lines
14 KiB
C++
432 lines
14 KiB
C++
/*
|
|
This file is part of solidity.
|
|
|
|
solidity is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
solidity is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with solidity. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
// SPDX-License-Identifier: GPL-3.0
|
|
/**
|
|
* Unit tests for Solidity's ABI decoder.
|
|
*/
|
|
|
|
#include <functional>
|
|
#include <string>
|
|
#include <tuple>
|
|
#include <boost/test/unit_test.hpp>
|
|
#include <liblangutil/Exceptions.h>
|
|
#include <test/libsolidity/SolidityExecutionFramework.h>
|
|
|
|
#include <test/libsolidity/ABITestsCommon.h>
|
|
|
|
using namespace std::placeholders;
|
|
using namespace solidity::test;
|
|
|
|
namespace solidity::frontend::test
|
|
{
|
|
|
|
BOOST_FIXTURE_TEST_SUITE(ABIDecoderTest, SolidityExecutionFramework)
|
|
|
|
BOOST_AUTO_TEST_CASE(value_types)
|
|
{
|
|
std::string sourceCode = R"(
|
|
contract C {
|
|
function f(uint a, uint16 b, uint24 c, int24 d, bytes3 x, bool e, C g) public returns (uint) {
|
|
if (a != 1) return 1;
|
|
if (b != 2) return 2;
|
|
if (c != 3) return 3;
|
|
if (d != 4) return 4;
|
|
if (x != "abc") return 5;
|
|
if (e != true) return 6;
|
|
if (g != this) return 7;
|
|
return 20;
|
|
}
|
|
}
|
|
)";
|
|
BOTH_ENCODERS(
|
|
compileAndRun(sourceCode);
|
|
ABI_CHECK(callContractFunction(
|
|
"f(uint256,uint16,uint24,int24,bytes3,bool,address)",
|
|
1, 2, 3, 4, std::string("abc"), true, m_contractAddress
|
|
), encodeArgs(u256(20)));
|
|
)
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(decode_from_memory_simple)
|
|
{
|
|
std::string sourceCode = R"(
|
|
contract C {
|
|
uint public _a;
|
|
uint[] public _b;
|
|
constructor(uint a, uint[] memory b) {
|
|
_a = a;
|
|
_b = b;
|
|
}
|
|
}
|
|
)";
|
|
BOTH_ENCODERS(
|
|
compileAndRun(sourceCode, 0, "C", encodeArgs(
|
|
7, 0x40,
|
|
// b
|
|
3, 0x21, 0x22, 0x23
|
|
));
|
|
ABI_CHECK(callContractFunction("_a()"), encodeArgs(7));
|
|
ABI_CHECK(callContractFunction("_b(uint256)", 0), encodeArgs(0x21));
|
|
ABI_CHECK(callContractFunction("_b(uint256)", 1), encodeArgs(0x22));
|
|
ABI_CHECK(callContractFunction("_b(uint256)", 2), encodeArgs(0x23));
|
|
ABI_CHECK(callContractFunction("_b(uint256)", 3), encodeArgs());
|
|
)
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(decode_function_type)
|
|
{
|
|
std::string sourceCode = R"(
|
|
contract D {
|
|
function () external returns (uint) public _a;
|
|
constructor(function () external returns (uint) a) {
|
|
_a = a;
|
|
}
|
|
}
|
|
contract C {
|
|
function f() public returns (uint) {
|
|
return 3;
|
|
}
|
|
function g(function () external returns (uint) _f) public returns (uint) {
|
|
return _f();
|
|
}
|
|
// uses "decode from memory"
|
|
function test1() public returns (uint) {
|
|
D d = new D(this.f);
|
|
return d._a()();
|
|
}
|
|
// uses "decode from calldata"
|
|
function test2() public returns (uint) {
|
|
return this.g(this.f);
|
|
}
|
|
}
|
|
)";
|
|
BOTH_ENCODERS(
|
|
compileAndRun(sourceCode, 0, "C");
|
|
ABI_CHECK(callContractFunction("test1()"), encodeArgs(3));
|
|
ABI_CHECK(callContractFunction("test2()"), encodeArgs(3));
|
|
)
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(decode_function_type_array)
|
|
{
|
|
std::string sourceCode = R"(
|
|
contract D {
|
|
function () external returns (uint)[] public _a;
|
|
constructor(function () external returns (uint)[] memory a) {
|
|
_a = a;
|
|
}
|
|
}
|
|
contract E {
|
|
function () external returns (uint)[3] public _a;
|
|
constructor(function () external returns (uint)[3] memory a) {
|
|
_a = a;
|
|
}
|
|
}
|
|
contract C {
|
|
function f1() public returns (uint) {
|
|
return 1;
|
|
}
|
|
function f2() public returns (uint) {
|
|
return 2;
|
|
}
|
|
function f3() public returns (uint) {
|
|
return 3;
|
|
}
|
|
function g(function () external returns (uint)[] memory _f, uint i) public returns (uint) {
|
|
return _f[i]();
|
|
}
|
|
function h(function () external returns (uint)[3] memory _f, uint i) public returns (uint) {
|
|
return _f[i]();
|
|
}
|
|
// uses "decode from memory"
|
|
function test1_dynamic() public returns (uint) {
|
|
function () external returns (uint)[] memory x = new function() external returns (uint)[](4);
|
|
x[0] = this.f1;
|
|
x[1] = this.f2;
|
|
x[2] = this.f3;
|
|
D d = new D(x);
|
|
return d._a(2)();
|
|
}
|
|
function test1_static() public returns (uint) {
|
|
E e = new E([this.f1, this.f2, this.f3]);
|
|
return e._a(2)();
|
|
}
|
|
// uses "decode from calldata"
|
|
function test2_dynamic() public returns (uint) {
|
|
function () external returns (uint)[] memory x = new function() external returns (uint)[](3);
|
|
x[0] = this.f1;
|
|
x[1] = this.f2;
|
|
x[2] = this.f3;
|
|
return this.g(x, 0);
|
|
}
|
|
function test2_static() public returns (uint) {
|
|
return this.h([this.f1, this.f2, this.f3], 0);
|
|
}
|
|
}
|
|
)";
|
|
BOTH_ENCODERS(
|
|
compileAndRun(sourceCode, 0, "C");
|
|
ABI_CHECK(callContractFunction("test1_static()"), encodeArgs(3));
|
|
ABI_CHECK(callContractFunction("test1_dynamic()"), encodeArgs(3));
|
|
ABI_CHECK(callContractFunction("test2_static()"), encodeArgs(1));
|
|
ABI_CHECK(callContractFunction("test2_dynamic()"), encodeArgs(1));
|
|
)
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(decode_from_memory_complex)
|
|
{
|
|
std::string sourceCode = R"(
|
|
contract C {
|
|
uint public _a;
|
|
uint[] public _b;
|
|
bytes[2] public _c;
|
|
constructor(uint a, uint[] memory b, bytes[2] memory c) {
|
|
_a = a;
|
|
_b = b;
|
|
_c = c;
|
|
}
|
|
}
|
|
)";
|
|
NEW_ENCODER(
|
|
compileAndRun(sourceCode, 0, "C", encodeArgs(
|
|
7, 0x60, 7 * 0x20,
|
|
// b
|
|
3, 0x21, 0x22, 0x23,
|
|
// c
|
|
0x40, 0x80,
|
|
8, std::string("abcdefgh"),
|
|
52, std::string("ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ")
|
|
));
|
|
ABI_CHECK(callContractFunction("_a()"), encodeArgs(7));
|
|
ABI_CHECK(callContractFunction("_b(uint256)", 0), encodeArgs(0x21));
|
|
ABI_CHECK(callContractFunction("_b(uint256)", 1), encodeArgs(0x22));
|
|
ABI_CHECK(callContractFunction("_b(uint256)", 2), encodeArgs(0x23));
|
|
ABI_CHECK(callContractFunction("_b(uint256)", 3), encodeArgs());
|
|
ABI_CHECK(callContractFunction("_c(uint256)", 0), encodeArgs(0x20, 8, std::string("abcdefgh")));
|
|
ABI_CHECK(callContractFunction("_c(uint256)", 1), encodeArgs(0x20, 52, std::string("ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ")));
|
|
ABI_CHECK(callContractFunction("_c(uint256)", 2), encodeArgs());
|
|
)
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(short_input_value_type)
|
|
{
|
|
std::string sourceCode = R"(
|
|
contract C {
|
|
function f(uint a, uint b) public pure returns (uint) { return a; }
|
|
}
|
|
)";
|
|
BOTH_ENCODERS(
|
|
compileAndRun(sourceCode);
|
|
ABI_CHECK(callContractFunction("f(uint256,uint256)", 1, 2), encodeArgs(1));
|
|
ABI_CHECK(callContractFunctionNoEncoding("f(uint256,uint256)", bytes(64, 0)), encodeArgs(0));
|
|
ABI_CHECK(callContractFunctionNoEncoding("f(uint256,uint256)", bytes(63, 0)), encodeArgs());
|
|
)
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(short_input_array)
|
|
{
|
|
std::string sourceCode = R"(
|
|
contract C {
|
|
function f(uint[] memory a) public pure returns (uint) { return 7; }
|
|
}
|
|
)";
|
|
BOTH_ENCODERS(
|
|
compileAndRun(sourceCode);
|
|
ABI_CHECK(callContractFunctionNoEncoding("f(uint256[])", encodeArgs(0x20, 0)), encodeArgs(7));
|
|
ABI_CHECK(callContractFunctionNoEncoding("f(uint256[])", encodeArgs(0x20, 1)), encodeArgs());
|
|
ABI_CHECK(callContractFunctionNoEncoding("f(uint256[])", encodeArgs(0x20, 1) + bytes(31, 0)), encodeArgs());
|
|
ABI_CHECK(callContractFunctionNoEncoding("f(uint256[])", encodeArgs(0x20, 1) + bytes(32, 0)), encodeArgs(7));
|
|
ABI_CHECK(callContractFunctionNoEncoding("f(uint256[])", encodeArgs(0x20, 2, 5, 6)), encodeArgs(7));
|
|
)
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(short_dynamic_input_array)
|
|
{
|
|
std::string sourceCode = R"(
|
|
contract C {
|
|
function f(bytes[1] memory a) public pure returns (uint) { return 7; }
|
|
}
|
|
)";
|
|
NEW_ENCODER(
|
|
compileAndRun(sourceCode);
|
|
ABI_CHECK(callContractFunctionNoEncoding("f(bytes[1])", encodeArgs(0x20)), encodeArgs());
|
|
)
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(short_input_bytes)
|
|
{
|
|
std::string sourceCode = R"(
|
|
contract C {
|
|
function e(bytes memory a) public pure returns (uint) { return 7; }
|
|
function f(bytes[] memory a) public pure returns (uint) { return 7; }
|
|
}
|
|
)";
|
|
NEW_ENCODER(
|
|
compileAndRun(sourceCode);
|
|
ABI_CHECK(callContractFunctionNoEncoding("e(bytes)", encodeArgs(0x20, 7) + bytes(5, 0)), encodeArgs());
|
|
ABI_CHECK(callContractFunctionNoEncoding("e(bytes)", encodeArgs(0x20, 7) + bytes(6, 0)), encodeArgs());
|
|
ABI_CHECK(callContractFunctionNoEncoding("e(bytes)", encodeArgs(0x20, 7) + bytes(7, 0)), encodeArgs(7));
|
|
ABI_CHECK(callContractFunctionNoEncoding("e(bytes)", encodeArgs(0x20, 7) + bytes(8, 0)), encodeArgs(7));
|
|
ABI_CHECK(callContractFunctionNoEncoding("f(bytes[])", encodeArgs(0x20, 1, 0x20, 7) + bytes(5, 0)), encodeArgs());
|
|
ABI_CHECK(callContractFunctionNoEncoding("f(bytes[])", encodeArgs(0x20, 1, 0x20, 7) + bytes(6, 0)), encodeArgs());
|
|
ABI_CHECK(callContractFunctionNoEncoding("f(bytes[])", encodeArgs(0x20, 1, 0x20, 7) + bytes(7, 0)), encodeArgs(7));
|
|
ABI_CHECK(callContractFunctionNoEncoding("f(bytes[])", encodeArgs(0x20, 1, 0x20, 7) + bytes(8, 0)), encodeArgs(7));
|
|
)
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(validation_int_inside_arrays)
|
|
{
|
|
std::string sourceCode = R"(
|
|
contract C {
|
|
enum E { A, B }
|
|
function f(uint16[] memory a) public pure returns (uint r) { assembly { r := mload(add(a, 0x20)) } }
|
|
function g(int16[] memory a) public pure returns (uint r) { assembly { r := mload(add(a, 0x20)) } }
|
|
function h(E[] memory a) public pure returns (uint r) { assembly { r := mload(add(a, 0x20)) } }
|
|
}
|
|
)";
|
|
NEW_ENCODER(
|
|
compileAndRun(sourceCode);
|
|
ABI_CHECK(callContractFunction("f(uint16[])", 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("g(int16[])", 0x20, 1, u256("0xffff")), encodeArgs());
|
|
ABI_CHECK(callContractFunction("f(uint16[])", 0x20, 1, u256("0x1ffff")), encodeArgs());
|
|
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, 1), encodeArgs(u256(1)));
|
|
ABI_CHECK(callContractFunction("h(uint8[])", 0x20, 1, 2), encodeArgs());
|
|
)
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(validation_function_type)
|
|
{
|
|
std::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 = false;
|
|
std::string validFun{"01234567890123456789abcd"};
|
|
std::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(struct_short)
|
|
{
|
|
std::string sourceCode = R"(
|
|
contract C {
|
|
struct S { int a; uint b; bytes16 c; }
|
|
function f(S memory s) public pure returns (S memory q) {
|
|
q = s;
|
|
}
|
|
}
|
|
)";
|
|
NEW_ENCODER(
|
|
compileAndRun(sourceCode, 0, "C");
|
|
ABI_CHECK(
|
|
callContractFunction("f((int256,uint256,bytes16))", 0xff010, 0xff0002, "abcd"),
|
|
encodeArgs(0xff010, 0xff0002, "abcd")
|
|
);
|
|
ABI_CHECK(
|
|
callContractFunctionNoEncoding("f((int256,uint256,bytes16))", encodeArgs(0xff010, 0xff0002) + bytes(32, 0)),
|
|
encodeArgs(0xff010, 0xff0002, 0)
|
|
);
|
|
ABI_CHECK(
|
|
callContractFunctionNoEncoding("f((int256,uint256,bytes16))", encodeArgs(0xff010, 0xff0002) + bytes(31, 0)),
|
|
encodeArgs()
|
|
);
|
|
)
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(complex_struct)
|
|
{
|
|
std::string sourceCode = R"(
|
|
contract C {
|
|
enum E {A, B, C}
|
|
struct T { uint x; E e; uint8 y; }
|
|
struct S { C c; T[] t;}
|
|
function f(uint a, S[2] memory s1, S[] memory s2, uint b) public returns
|
|
(uint r1, C r2, uint r3, uint r4, C r5, uint r6, E r7, uint8 r8) {
|
|
r1 = a;
|
|
r2 = s1[0].c;
|
|
r3 = b;
|
|
r4 = s2.length;
|
|
r5 = s2[1].c;
|
|
r6 = s2[1].t.length;
|
|
r7 = s2[1].t[1].e;
|
|
r8 = s2[1].t[1].y;
|
|
}
|
|
}
|
|
)";
|
|
NEW_ENCODER(
|
|
compileAndRun(sourceCode, 0, "C");
|
|
std::string sig = "f(uint256,(address,(uint256,uint8,uint8)[])[2],(address,(uint256,uint8,uint8)[])[],uint256)";
|
|
bytes args = encodeArgs(
|
|
7, 0x80, 0x1e0, 8,
|
|
// S[2] s1
|
|
0x40,
|
|
0x100,
|
|
// S s1[0]
|
|
m_contractAddress,
|
|
0x40,
|
|
// T s1[0].t
|
|
1, // length
|
|
// s1[0].t[0]
|
|
0x11, 1, 0x12,
|
|
// S s1[1]
|
|
0, 0x40,
|
|
// T s1[1].t
|
|
0,
|
|
// S[] s2 (0x1e0)
|
|
2, // length
|
|
0x40, 0xa0,
|
|
// S s2[0]
|
|
0, 0x40, 0,
|
|
// S s2[1]
|
|
0x1234, 0x40,
|
|
// s2[1].t
|
|
3, // length
|
|
0, 0, 0,
|
|
0x21, 2, 0x22,
|
|
0, 0, 0
|
|
);
|
|
ABI_CHECK(callContractFunction(sig, args), encodeArgs(7, m_contractAddress, 8, 2, 0x1234, 3, 2, 0x22));
|
|
// invalid enum value
|
|
args.data()[0x20 * 28] = 3;
|
|
ABI_CHECK(callContractFunction(sig, args), encodeArgs());
|
|
)
|
|
}
|
|
|
|
BOOST_AUTO_TEST_SUITE_END()
|
|
|
|
} // end namespaces
|