1 /*
2 This file is part of solidity.
3
4 solidity is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
8
9 solidity is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with solidity. If not, see <http://www.gnu.org/licenses/>.
16 */
17 // SPDX-License-Identifier: GPL-3.0
18 /**
19 * @author Christian <c@ethdev.com>
20 * @author Gav Wood <g@ethdev.com>
21 * @date 2014
22 * Unit tests for the solidity expression compiler, testing the behaviour of the code.
23 */
24
25 #include <test/libsolidity/SolidityExecutionFramework.h>
26
27 #include <test/Common.h>
28 #include <test/EVMHost.h>
29
30 #include <liblangutil/Exceptions.h>
31 #include <liblangutil/EVMVersion.h>
32
33 #include <libevmasm/Assembly.h>
34
35 #include <libsolutil/Keccak256.h>
36 #include <libsolutil/ErrorCodes.h>
37
38 #include <boost/test/unit_test.hpp>
39
40 #include <range/v3/view/transform.hpp>
41
42 #include <functional>
43 #include <numeric>
44 #include <string>
45 #include <tuple>
46
47 using namespace std;
48 using namespace std::placeholders;
49 using namespace solidity;
50 using namespace solidity::util;
51 using namespace solidity::test;
52 using namespace solidity::langutil;
53
54 #define ALSO_VIA_YUL(CODE) \
55 { \
56 m_doEwasmTestrun = true; \
57 \
58 m_compileViaYul = false; \
59 m_compileToEwasm = false; \
60 { CODE } \
61 \
62 m_compileViaYul = true; \
63 reset(); \
64 { CODE } \
65 \
66 if (m_doEwasmTestrun) \
67 { \
68 m_compileToEwasm = true; \
69 reset(); \
70 { CODE } \
71 } \
72 }
73
74 #define DISABLE_EWASM_TESTRUN() \
75 { m_doEwasmTestrun = false; }
76
77 namespace solidity::frontend::test
78 {
79
80 struct SolidityEndToEndTestExecutionFramework: public SolidityExecutionFramework
81 {
82 bool m_doEwasmTestrun = false;
83 };
84
BOOST_FIXTURE_TEST_SUITE(SolidityEndToEndTest,SolidityEndToEndTestExecutionFramework)85 BOOST_FIXTURE_TEST_SUITE(SolidityEndToEndTest, SolidityEndToEndTestExecutionFramework)
86
87 unsigned constexpr roundTo32(unsigned _num)
88 {
89 return (_num + 31) / 32 * 32;
90 }
91
BOOST_AUTO_TEST_CASE(exp_operator)92 BOOST_AUTO_TEST_CASE(exp_operator)
93 {
94 char const* sourceCode = R"(
95 contract test {
96 function f(uint a) public returns(uint d) { return 2 ** a; }
97 }
98 )";
99 compileAndRun(sourceCode);
100 testContractAgainstCppOnRange("f(uint256)", [](u256 const& a) -> u256 { return u256(1 << a.convert_to<int>()); }, 0, 16);
101 }
102
BOOST_AUTO_TEST_CASE(exp_zero)103 BOOST_AUTO_TEST_CASE(exp_zero)
104 {
105 char const* sourceCode = R"(
106 contract test {
107 function f(uint a) public returns(uint d) { return a ** 0; }
108 }
109 )";
110 compileAndRun(sourceCode);
111 testContractAgainstCppOnRange("f(uint256)", [](u256 const&) -> u256 { return u256(1); }, 0, 16);
112 }
113
114 /* TODO let's add this back when I figure out the correct type conversion.
115 BOOST_AUTO_TEST_CASE(conditional_expression_string_literal)
116 {
117 char const* sourceCode = R"(
118 contract test {
119 function f(bool cond) public returns (bytes32) {
120 return cond ? "true" : "false";
121 }
122 }
123 )";
124 compileAndRun(sourceCode);
125 ABI_CHECK(callContractFunction("f(bool)", true), encodeArgs(string("true", 4)));
126 ABI_CHECK(callContractFunction("f(bool)", false), encodeArgs(string("false", 5)));
127 }
128 */
129
BOOST_AUTO_TEST_CASE(recursive_calls)130 BOOST_AUTO_TEST_CASE(recursive_calls)
131 {
132 char const* sourceCode = R"(
133 contract test {
134 function f(uint n) public returns(uint nfac) {
135 if (n <= 1) return 1;
136 else return n * f(n - 1);
137 }
138 }
139 )";
140 ALSO_VIA_YUL(
141 DISABLE_EWASM_TESTRUN()
142
143 compileAndRun(sourceCode);
144 function<u256(u256)> recursive_calls_cpp = [&recursive_calls_cpp](u256 const& n) -> u256
145 {
146 if (n <= 1)
147 return 1;
148 else
149 return n * recursive_calls_cpp(n - 1);
150 };
151
152 testContractAgainstCppOnRange("f(uint256)", recursive_calls_cpp, 0, 5);
153 )
154 }
155
BOOST_AUTO_TEST_CASE(while_loop)156 BOOST_AUTO_TEST_CASE(while_loop)
157 {
158 char const* sourceCode = R"(
159 contract test {
160 function f(uint n) public returns(uint nfac) {
161 nfac = 1;
162 uint i = 2;
163 while (i <= n) nfac *= i++;
164 }
165 }
166 )";
167 ALSO_VIA_YUL(
168 DISABLE_EWASM_TESTRUN()
169
170 compileAndRun(sourceCode);
171
172 auto while_loop_cpp = [](u256 const& n) -> u256
173 {
174 u256 nfac = 1;
175 u256 i = 2;
176 while (i <= n)
177 nfac *= i++;
178
179 return nfac;
180 };
181
182 testContractAgainstCppOnRange("f(uint256)", while_loop_cpp, 0, 5);
183 )
184 }
185
BOOST_AUTO_TEST_CASE(do_while_loop)186 BOOST_AUTO_TEST_CASE(do_while_loop)
187 {
188 char const* sourceCode = R"(
189 contract test {
190 function f(uint n) public returns(uint nfac) {
191 nfac = 1;
192 uint i = 2;
193 do { nfac *= i++; } while (i <= n);
194 }
195 }
196 )";
197 ALSO_VIA_YUL(
198 DISABLE_EWASM_TESTRUN()
199
200 compileAndRun(sourceCode);
201
202 auto do_while_loop_cpp = [](u256 const& n) -> u256
203 {
204 u256 nfac = 1;
205 u256 i = 2;
206 do
207 {
208 nfac *= i++;
209 }
210 while (i <= n);
211
212 return nfac;
213 };
214
215 testContractAgainstCppOnRange("f(uint256)", do_while_loop_cpp, 0, 5);
216 )
217 }
218
BOOST_AUTO_TEST_CASE(do_while_loop_multiple_local_vars)219 BOOST_AUTO_TEST_CASE(do_while_loop_multiple_local_vars)
220 {
221 char const* sourceCode = R"(
222 contract test {
223 function f(uint x) public pure returns(uint r) {
224 uint i = 0;
225 do
226 {
227 uint z = x * 2;
228 if (z < 4) break;
229 else {
230 uint k = z + 1;
231 if (k < 8) {
232 x++;
233 continue;
234 }
235 }
236 if (z > 12) return 0;
237 x++;
238 i++;
239 } while (true);
240 return 42;
241 }
242 }
243 )";
244 ALSO_VIA_YUL(
245 DISABLE_EWASM_TESTRUN()
246
247 compileAndRun(sourceCode);
248
249 auto do_while = [](u256 n) -> u256
250 {
251 u256 i = 0;
252 do
253 {
254 u256 z = n * 2;
255 if (z < 4) break;
256 else {
257 u256 k = z + 1;
258 if (k < 8) {
259 n++;
260 continue;
261 }
262 }
263 if (z > 12) return 0;
264 n++;
265 i++;
266 } while (true);
267 return 42;
268 };
269
270 testContractAgainstCppOnRange("f(uint256)", do_while, 0, 12);
271 )
272 }
273
BOOST_AUTO_TEST_CASE(nested_loops)274 BOOST_AUTO_TEST_CASE(nested_loops)
275 {
276 // tests that break and continue statements in nested loops jump to the correct place
277 char const* sourceCode = R"(
278 contract test {
279 function f(uint x) public returns(uint y) {
280 while (x > 1) {
281 if (x == 10) break;
282 while (x > 5) {
283 if (x == 8) break;
284 x--;
285 if (x == 6) continue;
286 return x;
287 }
288 x--;
289 if (x == 3) continue;
290 break;
291 }
292 return x;
293 }
294 }
295 )";
296 ALSO_VIA_YUL(
297 DISABLE_EWASM_TESTRUN()
298
299 compileAndRun(sourceCode);
300
301 auto nested_loops_cpp = [](u256 n) -> u256
302 {
303 while (n > 1)
304 {
305 if (n == 10)
306 break;
307 while (n > 5)
308 {
309 if (n == 8)
310 break;
311 n--;
312 if (n == 6)
313 continue;
314 return n;
315 }
316 n--;
317 if (n == 3)
318 continue;
319 break;
320 }
321
322 return n;
323 };
324
325 testContractAgainstCppOnRange("f(uint256)", nested_loops_cpp, 0, 12);
326 )
327 }
328
BOOST_AUTO_TEST_CASE(nested_loops_multiple_local_vars)329 BOOST_AUTO_TEST_CASE(nested_loops_multiple_local_vars)
330 {
331 // tests that break and continue statements in nested loops jump to the correct place
332 // and free local variables properly
333 char const* sourceCode = R"(
334 contract test {
335 function f(uint x) public returns(uint y) {
336 while (x > 0) {
337 uint z = x + 10;
338 uint k = z + 1;
339 if (k > 20) {
340 break;
341 uint p = 100;
342 k += p;
343 }
344 if (k > 15) {
345 x--;
346 continue;
347 uint t = 1000;
348 x += t;
349 }
350 while (k > 10) {
351 uint m = k - 1;
352 if (m == 10) return x;
353 return k;
354 uint h = 10000;
355 z += h;
356 }
357 x--;
358 break;
359 }
360 return x;
361 }
362 }
363 )";
364 ALSO_VIA_YUL(
365 DISABLE_EWASM_TESTRUN()
366
367 compileAndRun(sourceCode);
368
369 auto nested_loops_cpp = [](u256 n) -> u256
370 {
371 while (n > 0)
372 {
373 u256 z = n + 10;
374 u256 k = z + 1;
375 if (k > 20) break;
376 if (k > 15) {
377 n--;
378 continue;
379 }
380 while (k > 10)
381 {
382 u256 m = k - 1;
383 if (m == 10) return n;
384 return k;
385 }
386 n--;
387 break;
388 }
389
390 return n;
391 };
392
393 testContractAgainstCppOnRange("f(uint256)", nested_loops_cpp, 0, 12);
394 )
395 }
396
BOOST_AUTO_TEST_CASE(for_loop_multiple_local_vars)397 BOOST_AUTO_TEST_CASE(for_loop_multiple_local_vars)
398 {
399 char const* sourceCode = R"(
400 contract test {
401 function f(uint x) public pure returns(uint r) {
402 for (uint i = 0; i < 12; i++)
403 {
404 uint z = x + 1;
405 if (z < 4) break;
406 else {
407 uint k = z * 2;
408 if (i + k < 10) {
409 x++;
410 continue;
411 }
412 }
413 if (z > 8) return 0;
414 x++;
415 }
416 return 42;
417 }
418 }
419 )";
420 ALSO_VIA_YUL(
421 DISABLE_EWASM_TESTRUN()
422
423 compileAndRun(sourceCode);
424
425 auto for_loop = [](u256 n) -> u256
426 {
427 for (u256 i = 0; i < 12; i++)
428 {
429 u256 z = n + 1;
430 if (z < 4) break;
431 else {
432 u256 k = z * 2;
433 if (i + k < 10) {
434 n++;
435 continue;
436 }
437 }
438 if (z > 8) return 0;
439 n++;
440 }
441 return 42;
442 };
443
444 testContractAgainstCppOnRange("f(uint256)", for_loop, 0, 12);
445 )
446 }
447
BOOST_AUTO_TEST_CASE(nested_for_loop_multiple_local_vars)448 BOOST_AUTO_TEST_CASE(nested_for_loop_multiple_local_vars)
449 {
450 char const* sourceCode = R"(
451 contract test {
452 function f(uint x) public pure returns(uint r) {
453 for (uint i = 0; i < 5; i++)
454 {
455 uint z = x + 1;
456 if (z < 3) {
457 break;
458 uint p = z + 2;
459 }
460 for (uint j = 0; j < 5; j++)
461 {
462 uint k = z * 2;
463 if (j + k < 8) {
464 x++;
465 continue;
466 uint t = z * 3;
467 }
468 x++;
469 if (x > 20) {
470 return 84;
471 uint h = x + 42;
472 }
473 }
474 if (x > 30) {
475 return 42;
476 uint b = 0xcafe;
477 }
478 }
479 return 42;
480 }
481 }
482 )";
483 ALSO_VIA_YUL(
484 DISABLE_EWASM_TESTRUN()
485
486 compileAndRun(sourceCode);
487
488 auto for_loop = [](u256 n) -> u256
489 {
490 for (u256 i = 0; i < 5; i++)
491 {
492 u256 z = n + 1;
493 if (z < 3) break;
494 for (u256 j = 0; j < 5; j++)
495 {
496 u256 k = z * 2;
497 if (j + k < 8) {
498 n++;
499 continue;
500 }
501 n++;
502 if (n > 20) return 84;
503 }
504 if (n > 30) return 42;
505 }
506 return 42;
507 };
508
509 testContractAgainstCppOnRange("f(uint256)", for_loop, 0, 12);
510 )
511 }
512
BOOST_AUTO_TEST_CASE(for_loop)513 BOOST_AUTO_TEST_CASE(for_loop)
514 {
515 char const* sourceCode = R"(
516 contract test {
517 function f(uint n) public returns(uint nfac) {
518 nfac = 1;
519 uint i;
520 for (i = 2; i <= n; i++)
521 nfac *= i;
522 }
523 }
524 )";
525 ALSO_VIA_YUL(
526 DISABLE_EWASM_TESTRUN()
527
528 compileAndRun(sourceCode);
529
530 auto for_loop_cpp = [](u256 const& n) -> u256
531 {
532 u256 nfac = 1;
533 for (auto i = 2; i <= n; i++)
534 nfac *= i;
535 return nfac;
536 };
537
538 testContractAgainstCppOnRange("f(uint256)", for_loop_cpp, 0, 5);
539 )
540 }
541
BOOST_AUTO_TEST_CASE(for_loop_simple_init_expr)542 BOOST_AUTO_TEST_CASE(for_loop_simple_init_expr)
543 {
544 char const* sourceCode = R"(
545 contract test {
546 function f(uint n) public returns(uint nfac) {
547 nfac = 1;
548 uint256 i;
549 for (i = 2; i <= n; i++)
550 nfac *= i;
551 }
552 }
553 )";
554 ALSO_VIA_YUL(
555 DISABLE_EWASM_TESTRUN()
556
557 compileAndRun(sourceCode);
558
559 auto for_loop_simple_init_expr_cpp = [](u256 const& n) -> u256
560 {
561 u256 nfac = 1;
562 u256 i;
563 for (i = 2; i <= n; i++)
564 nfac *= i;
565 return nfac;
566 };
567
568 testContractAgainstCppOnRange("f(uint256)", for_loop_simple_init_expr_cpp, 0, 5);
569 )
570 }
571
BOOST_AUTO_TEST_CASE(for_loop_break_continue)572 BOOST_AUTO_TEST_CASE(for_loop_break_continue)
573 {
574 char const* sourceCode = R"(
575 contract test {
576 function f(uint n) public returns (uint r)
577 {
578 uint i = 1;
579 uint k = 0;
580 for (i *= 5; k < n; i *= 7)
581 {
582 k++;
583 i += 4;
584 if (n % 3 == 0)
585 break;
586 i += 9;
587 if (n % 2 == 0)
588 continue;
589 i += 19;
590 }
591 return i;
592 }
593 }
594 )";
595 ALSO_VIA_YUL(
596 DISABLE_EWASM_TESTRUN()
597 compileAndRun(sourceCode);
598
599 auto breakContinue = [](u256 const& n) -> u256
600 {
601 u256 i = 1;
602 u256 k = 0;
603 for (i *= 5; k < n; i *= 7)
604 {
605 k++;
606 i += 4;
607 if (n % 3 == 0)
608 break;
609 i += 9;
610 if (n % 2 == 0)
611 continue;
612 i += 19;
613 }
614 return i;
615 };
616
617 testContractAgainstCppOnRange("f(uint256)", breakContinue, 0, 10);
618 );
619 }
620
BOOST_AUTO_TEST_CASE(short_circuiting)621 BOOST_AUTO_TEST_CASE(short_circuiting)
622 {
623 char const* sourceCode = R"(
624 contract test {
625 function run(uint x) public returns(uint y) {
626 x == 0 || ((x = 8) > 0);
627 return x;
628 }
629 }
630 )";
631 ALSO_VIA_YUL(
632 DISABLE_EWASM_TESTRUN()
633
634 compileAndRun(sourceCode);
635
636 auto short_circuiting_cpp = [](u256 n) -> u256
637 {
638 (void)(n == 0 || (n = 8) > 0);
639 return n;
640 };
641
642 testContractAgainstCppOnRange("run(uint256)", short_circuiting_cpp, 0, 2);
643 )
644 }
645
BOOST_AUTO_TEST_CASE(high_bits_cleaning)646 BOOST_AUTO_TEST_CASE(high_bits_cleaning)
647 {
648 char const* sourceCode = R"(
649 contract test {
650 function run() public returns(uint256 y) {
651 unchecked {
652 uint32 t = uint32(0xffffffff);
653 uint32 x = t + 10;
654 if (x >= 0xffffffff) return 0;
655 return x;
656 }
657 }
658 }
659 )";
660 compileAndRun(sourceCode);
661 auto high_bits_cleaning_cpp = []() -> u256
662 {
663 uint32_t t = uint32_t(0xffffffff);
664 uint32_t x = t + 10;
665 if (x >= 0xffffffff)
666 return 0;
667 return x;
668 };
669 testContractAgainstCpp("run()", high_bits_cleaning_cpp);
670 }
671
BOOST_AUTO_TEST_CASE(sign_extension)672 BOOST_AUTO_TEST_CASE(sign_extension)
673 {
674 char const* sourceCode = R"(
675 contract test {
676 function run() public returns(uint256 y) {
677 unchecked {
678 int64 x = -int32(int64(0xff));
679 if (x >= 0xff) return 0;
680 return 0 - uint256(int256(x));
681 }
682 }
683 }
684 )";
685 compileAndRun(sourceCode);
686 auto sign_extension_cpp = []() -> u256
687 {
688 int64_t x = -int32_t(0xff);
689 if (x >= 0xff)
690 return 0;
691 return u256(x) * -1;
692 };
693 testContractAgainstCpp("run()", sign_extension_cpp);
694 }
695
BOOST_AUTO_TEST_CASE(small_unsigned_types)696 BOOST_AUTO_TEST_CASE(small_unsigned_types)
697 {
698 char const* sourceCode = R"(
699 contract test {
700 function run() public returns(uint256 y) {
701 unchecked {
702 uint32 t = uint32(0xffffff);
703 uint32 x = t * 0xffffff;
704 return x / 0x100;
705 }
706 }
707 }
708 )";
709 compileAndRun(sourceCode);
710 auto small_unsigned_types_cpp = []() -> u256
711 {
712 uint32_t t = uint32_t(0xffffff);
713 uint32_t x = t * 0xffffff;
714 return x / 0x100;
715 };
716 testContractAgainstCpp("run()", small_unsigned_types_cpp);
717 }
718
BOOST_AUTO_TEST_CASE(mapping_state_inc_dec)719 BOOST_AUTO_TEST_CASE(mapping_state_inc_dec)
720 {
721 char const* sourceCode = R"(
722 contract test {
723 uint value;
724 mapping(uint => uint) table;
725 function f(uint x) public returns (uint y) {
726 value = x;
727 if (x > 0) table[++value] = 8;
728 if (x > 1) value--;
729 if (x > 2) table[value]++;
730 table[value] += 10;
731 return --table[value++];
732 }
733 }
734 )";
735
736 u256 value;
737 map<u256, u256> table;
738 auto f = [&](u256 const& _x) -> u256
739 {
740 value = _x;
741 if (_x > 0)
742 table[++value] = 8;
743 if (_x > 1)
744 value --;
745 if (_x > 2)
746 table[value]++;
747 table[value] += 10;
748 return --table[value++];
749 };
750 ALSO_VIA_YUL(
751 DISABLE_EWASM_TESTRUN()
752
753 compileAndRun(sourceCode);
754 value = 0;
755 table.clear();
756
757 testContractAgainstCppOnRange("f(uint256)", f, 0, 5);
758 )
759 }
760
BOOST_AUTO_TEST_CASE(multi_level_mapping)761 BOOST_AUTO_TEST_CASE(multi_level_mapping)
762 {
763 char const* sourceCode = R"(
764 contract test {
765 mapping(uint => mapping(uint => uint)) table;
766 function f(uint x, uint y, uint z) public returns (uint w) {
767 if (z == 0) return table[x][y];
768 else return table[x][y] = z;
769 }
770 }
771 )";
772 map<u256, map<u256, u256>> table;
773 auto f = [&](u256 const& _x, u256 const& _y, u256 const& _z) -> u256
774 {
775 if (_z == 0) return table[_x][_y];
776 else return table[_x][_y] = _z;
777 };
778 ALSO_VIA_YUL(
779 DISABLE_EWASM_TESTRUN()
780
781 compileAndRun(sourceCode);
782 table.clear();
783
784 testContractAgainstCpp("f(uint256,uint256,uint256)", f, u256(4), u256(5), u256(0));
785 testContractAgainstCpp("f(uint256,uint256,uint256)", f, u256(5), u256(4), u256(0));
786 testContractAgainstCpp("f(uint256,uint256,uint256)", f, u256(4), u256(5), u256(9));
787 testContractAgainstCpp("f(uint256,uint256,uint256)", f, u256(4), u256(5), u256(0));
788 testContractAgainstCpp("f(uint256,uint256,uint256)", f, u256(5), u256(4), u256(0));
789 testContractAgainstCpp("f(uint256,uint256,uint256)", f, u256(5), u256(4), u256(7));
790 testContractAgainstCpp("f(uint256,uint256,uint256)", f, u256(4), u256(5), u256(0));
791 testContractAgainstCpp("f(uint256,uint256,uint256)", f, u256(5), u256(4), u256(0));
792 )
793 }
794
BOOST_AUTO_TEST_CASE(constructor)795 BOOST_AUTO_TEST_CASE(constructor)
796 {
797 char const* sourceCode = R"(
798 contract test {
799 mapping(uint => uint) data;
800 constructor() {
801 data[7] = 8;
802 }
803 function get(uint key) public returns (uint value) {
804 return data[key];
805 }
806 }
807 )";
808
809 map<u256, uint8_t> data;
810 data[7] = 8;
811 auto get = [&](u256 const& _x) -> u256
812 {
813 return data[_x];
814 };
815
816 ALSO_VIA_YUL(
817 DISABLE_EWASM_TESTRUN()
818
819 compileAndRun(sourceCode);
820 testContractAgainstCpp("get(uint256)", get, u256(6));
821 testContractAgainstCpp("get(uint256)", get, u256(7));
822 )
823 }
824
BOOST_AUTO_TEST_CASE(send_ether)825 BOOST_AUTO_TEST_CASE(send_ether)
826 {
827 char const* sourceCode = R"(
828 contract test {
829 constructor() payable {}
830 function a(address payable addr, uint amount) public returns (uint ret) {
831 addr.send(amount);
832 return address(this).balance;
833 }
834 }
835 )";
836 ALSO_VIA_YUL(
837 DISABLE_EWASM_TESTRUN()
838
839 u256 amount(250);
840 compileAndRun(sourceCode, amount + 1);
841 h160 address(23);
842 ABI_CHECK(callContractFunction("a(address,uint256)", address, amount), encodeArgs(1));
843 BOOST_CHECK_EQUAL(balanceAt(address), amount);
844 )
845 }
846
BOOST_AUTO_TEST_CASE(transfer_ether)847 BOOST_AUTO_TEST_CASE(transfer_ether)
848 {
849 char const* sourceCode = R"(
850 contract A {
851 constructor() payable {}
852 function a(address payable addr, uint amount) public returns (uint) {
853 addr.transfer(amount);
854 return address(this).balance;
855 }
856 function b(address payable addr, uint amount) public {
857 addr.transfer(amount);
858 }
859 }
860
861 contract B {
862 }
863
864 contract C {
865 receive () external payable {
866 revert();
867 }
868 }
869 )";
870 ALSO_VIA_YUL(
871 DISABLE_EWASM_TESTRUN()
872
873 compileAndRun(sourceCode, 0, "B");
874 h160 const nonPayableRecipient = m_contractAddress;
875 compileAndRun(sourceCode, 0, "C");
876 h160 const oogRecipient = m_contractAddress;
877 compileAndRun(sourceCode, 20, "A");
878 h160 payableRecipient(23);
879 ABI_CHECK(callContractFunction("a(address,uint256)", payableRecipient, 10), encodeArgs(10));
880 BOOST_CHECK_EQUAL(balanceAt(payableRecipient), 10);
881 BOOST_CHECK_EQUAL(balanceAt(m_contractAddress), 10);
882 ABI_CHECK(callContractFunction("b(address,uint256)", nonPayableRecipient, 10), encodeArgs());
883 ABI_CHECK(callContractFunction("b(address,uint256)", oogRecipient, 10), encodeArgs());
884 )
885 }
886
BOOST_AUTO_TEST_CASE(selfdestruct)887 BOOST_AUTO_TEST_CASE(selfdestruct)
888 {
889 char const* sourceCode = R"(
890 contract test {
891 constructor() payable {}
892 function a(address payable receiver) public returns (uint ret) {
893 selfdestruct(receiver);
894 return 10;
895 }
896 }
897 )";
898 u256 amount(130);
899 h160 address(23);
900 ALSO_VIA_YUL(
901 DISABLE_EWASM_TESTRUN()
902
903 compileAndRun(sourceCode, amount);
904 ABI_CHECK(callContractFunction("a(address)", address), bytes());
905 BOOST_CHECK(!addressHasCode(m_contractAddress));
906 BOOST_CHECK_EQUAL(balanceAt(address), amount);
907 )
908 }
909
BOOST_AUTO_TEST_CASE(keccak256)910 BOOST_AUTO_TEST_CASE(keccak256)
911 {
912 char const* sourceCode = R"(
913 contract test {
914 function a(bytes32 input) public returns (bytes32 hash) {
915 return keccak256(abi.encodePacked(input));
916 }
917 }
918 )";
919 ALSO_VIA_YUL(
920 DISABLE_EWASM_TESTRUN()
921 compileAndRun(sourceCode);
922 auto f = [&](u256 const& _x) -> u256
923 {
924 return util::keccak256(toBigEndian(_x));
925 };
926 testContractAgainstCpp("a(bytes32)", f, u256(4));
927 testContractAgainstCpp("a(bytes32)", f, u256(5));
928 testContractAgainstCpp("a(bytes32)", f, u256(-1));
929 );
930 }
931
BOOST_AUTO_TEST_CASE(sha256)932 BOOST_AUTO_TEST_CASE(sha256)
933 {
934 char const* sourceCode = R"(
935 contract test {
936 function a(bytes32 input) public returns (bytes32 sha256hash) {
937 return sha256(abi.encodePacked(input));
938 }
939 }
940 )";
941 auto f = [&](u256 const& _x) -> bytes
942 {
943 if (_x == u256(4))
944 return fromHex("e38990d0c7fc009880a9c07c23842e886c6bbdc964ce6bdd5817ad357335ee6f");
945 if (_x == u256(5))
946 return fromHex("96de8fc8c256fa1e1556d41af431cace7dca68707c78dd88c3acab8b17164c47");
947 if (_x == u256(-1))
948 return fromHex("af9613760f72635fbdb44a5a0a63c39f12af30f950a6ee5c971be188e89c4051");
949 return fromHex("");
950 };
951 ALSO_VIA_YUL(
952 DISABLE_EWASM_TESTRUN()
953 compileAndRun(sourceCode);
954 testContractAgainstCpp("a(bytes32)", f, u256(4));
955 testContractAgainstCpp("a(bytes32)", f, u256(5));
956 testContractAgainstCpp("a(bytes32)", f, u256(-1));
957 )
958 }
959
BOOST_AUTO_TEST_CASE(ripemd)960 BOOST_AUTO_TEST_CASE(ripemd)
961 {
962 char const* sourceCode = R"(
963 contract test {
964 function a(bytes32 input) public returns (bytes32 sha256hash) {
965 return ripemd160(abi.encodePacked(input));
966 }
967 }
968 )";
969 auto f = [&](u256 const& _x) -> bytes
970 {
971 if (_x == u256(4))
972 return fromHex("1b0f3c404d12075c68c938f9f60ebea4f74941a0000000000000000000000000");
973 if (_x == u256(5))
974 return fromHex("ee54aa84fc32d8fed5a5fe160442ae84626829d9000000000000000000000000");
975 if (_x == u256(-1))
976 return fromHex("1cf4e77f5966e13e109703cd8a0df7ceda7f3dc3000000000000000000000000");
977 return fromHex("");
978 };
979 ALSO_VIA_YUL(
980 DISABLE_EWASM_TESTRUN()
981 compileAndRun(sourceCode);
982 testContractAgainstCpp("a(bytes32)", f, u256(4));
983 testContractAgainstCpp("a(bytes32)", f, u256(5));
984 testContractAgainstCpp("a(bytes32)", f, u256(-1));
985 )
986 }
987
BOOST_AUTO_TEST_CASE(packed_keccak256)988 BOOST_AUTO_TEST_CASE(packed_keccak256)
989 {
990 char const* sourceCode = R"(
991 contract test {
992 function a(bytes32 input) public returns (bytes32 hash) {
993 uint24 b = 65536;
994 uint c = 256;
995 return keccak256(abi.encodePacked(uint8(8), input, b, input, c));
996 }
997 }
998 )";
999 auto f = [&](u256 const& _x) -> u256
1000 {
1001 return util::keccak256(
1002 toCompactBigEndian(unsigned(8)) +
1003 toBigEndian(_x) +
1004 toCompactBigEndian(unsigned(65536)) +
1005 toBigEndian(_x) +
1006 toBigEndian(u256(256))
1007 );
1008 };
1009 ALSO_VIA_YUL(
1010 DISABLE_EWASM_TESTRUN()
1011 compileAndRun(sourceCode);
1012 testContractAgainstCpp("a(bytes32)", f, u256(4));
1013 testContractAgainstCpp("a(bytes32)", f, u256(5));
1014 testContractAgainstCpp("a(bytes32)", f, u256(-1));
1015 )
1016 }
1017
BOOST_AUTO_TEST_CASE(packed_keccak256_complex_types)1018 BOOST_AUTO_TEST_CASE(packed_keccak256_complex_types)
1019 {
1020 char const* sourceCode = R"(
1021 contract test {
1022 uint120[3] x;
1023 function f() public returns (bytes32 hash1, bytes32 hash2, bytes32 hash3) {
1024 uint120[] memory y = new uint120[](3);
1025 x[0] = y[0] = uint120(type(uint).max - 1);
1026 x[1] = y[1] = uint120(type(uint).max - 2);
1027 x[2] = y[2] = uint120(type(uint).max - 3);
1028 hash1 = keccak256(abi.encodePacked(x));
1029 hash2 = keccak256(abi.encodePacked(y));
1030 hash3 = keccak256(abi.encodePacked(this.f));
1031 }
1032 }
1033 )";
1034 ALSO_VIA_YUL(
1035 DISABLE_EWASM_TESTRUN()
1036 compileAndRun(sourceCode);
1037 // Strangely, arrays are encoded with intra-element padding.
1038 ABI_CHECK(callContractFunction("f()"), encodeArgs(
1039 util::keccak256(encodeArgs(u256("0xfffffffffffffffffffffffffffffe"), u256("0xfffffffffffffffffffffffffffffd"), u256("0xfffffffffffffffffffffffffffffc"))),
1040 util::keccak256(encodeArgs(u256("0xfffffffffffffffffffffffffffffe"), u256("0xfffffffffffffffffffffffffffffd"), u256("0xfffffffffffffffffffffffffffffc"))),
1041 util::keccak256(fromHex(m_contractAddress.hex() + "26121ff0"))
1042 ));
1043 )
1044 }
1045
BOOST_AUTO_TEST_CASE(packed_sha256)1046 BOOST_AUTO_TEST_CASE(packed_sha256)
1047 {
1048 char const* sourceCode = R"(
1049 contract test {
1050 function a(bytes32 input) public returns (bytes32 hash) {
1051 uint24 b = 65536;
1052 uint c = 256;
1053 return sha256(abi.encodePacked(uint8(8), input, b, input, c));
1054 }
1055 }
1056 )";
1057 auto f = [&](u256 const& _x) -> bytes
1058 {
1059 if (_x == u256(4))
1060 return fromHex("804e0d7003cfd70fc925dc103174d9f898ebb142ecc2a286da1abd22ac2ce3ac");
1061 if (_x == u256(5))
1062 return fromHex("e94921945f9068726c529a290a954f412bcac53184bb41224208a31edbf63cf0");
1063 if (_x == u256(-1))
1064 return fromHex("f14def4d07cd185ddd8b10a81b2238326196a38867e6e6adbcc956dc913488c7");
1065 return fromHex("");
1066 };
1067 ALSO_VIA_YUL(
1068 DISABLE_EWASM_TESTRUN()
1069 compileAndRun(sourceCode);
1070 testContractAgainstCpp("a(bytes32)", f, u256(4));
1071 testContractAgainstCpp("a(bytes32)", f, u256(5));
1072 testContractAgainstCpp("a(bytes32)", f, u256(-1));
1073 )
1074 }
1075
BOOST_AUTO_TEST_CASE(packed_ripemd160)1076 BOOST_AUTO_TEST_CASE(packed_ripemd160)
1077 {
1078 char const* sourceCode = R"(
1079 contract test {
1080 function a(bytes32 input) public returns (bytes32 hash) {
1081 uint24 b = 65536;
1082 uint c = 256;
1083 return ripemd160(abi.encodePacked(uint8(8), input, b, input, c));
1084 }
1085 }
1086 )";
1087 auto f = [&](u256 const& _x) -> bytes
1088 {
1089 if (_x == u256(4))
1090 return fromHex("f93175303eba2a7b372174fc9330237f5ad202fc000000000000000000000000");
1091 if (_x == u256(5))
1092 return fromHex("04f4fc112e2bfbe0d38f896a46629e08e2fcfad5000000000000000000000000");
1093 if (_x == u256(-1))
1094 return fromHex("c0a2e4b1f3ff766a9a0089e7a410391730872495000000000000000000000000");
1095 return fromHex("");
1096 };
1097 ALSO_VIA_YUL(
1098 DISABLE_EWASM_TESTRUN()
1099 compileAndRun(sourceCode);
1100 testContractAgainstCpp("a(bytes32)", f, u256(4));
1101 testContractAgainstCpp("a(bytes32)", f, u256(5));
1102 testContractAgainstCpp("a(bytes32)", f, u256(-1));
1103 )
1104 }
1105
BOOST_AUTO_TEST_CASE(inter_contract_calls)1106 BOOST_AUTO_TEST_CASE(inter_contract_calls)
1107 {
1108 char const* sourceCode = R"(
1109 contract Helper {
1110 function multiply(uint a, uint b) public returns (uint c) {
1111 return a * b;
1112 }
1113 }
1114 contract Main {
1115 Helper h;
1116 function callHelper(uint a, uint b) public returns (uint c) {
1117 return h.multiply(a, b);
1118 }
1119 function getHelper() public returns (address haddress) {
1120 return address(h);
1121 }
1122 function setHelper(address haddress) public {
1123 h = Helper(haddress);
1124 }
1125 }
1126 )";
1127 compileAndRun(sourceCode, 0, "Helper");
1128 h160 const c_helperAddress = m_contractAddress;
1129 compileAndRun(sourceCode, 0, "Main");
1130 BOOST_REQUIRE(callContractFunction("setHelper(address)", c_helperAddress) == bytes());
1131 BOOST_REQUIRE(callContractFunction("getHelper()", c_helperAddress) == encodeArgs(c_helperAddress));
1132 u256 a(3456789);
1133 u256 b("0x282837623374623234aa74");
1134 BOOST_REQUIRE(callContractFunction("callHelper(uint256,uint256)", a, b) == encodeArgs(a * b));
1135 }
1136
BOOST_AUTO_TEST_CASE(inter_contract_calls_with_complex_parameters)1137 BOOST_AUTO_TEST_CASE(inter_contract_calls_with_complex_parameters)
1138 {
1139 char const* sourceCode = R"(
1140 contract Helper {
1141 function sel(uint a, bool select, uint b) public returns (uint c) {
1142 if (select) return a; else return b;
1143 }
1144 }
1145 contract Main {
1146 Helper h;
1147 function callHelper(uint a, bool select, uint b) public returns (uint c) {
1148 return h.sel(a, select, b) * 3;
1149 }
1150 function getHelper() public returns (address haddress) {
1151 return address(h);
1152 }
1153 function setHelper(address haddress) public {
1154 h = Helper(haddress);
1155 }
1156 }
1157 )";
1158 compileAndRun(sourceCode, 0, "Helper");
1159 h160 const c_helperAddress = m_contractAddress;
1160 compileAndRun(sourceCode, 0, "Main");
1161 BOOST_REQUIRE(callContractFunction("setHelper(address)", c_helperAddress) == bytes());
1162 BOOST_REQUIRE(callContractFunction("getHelper()", c_helperAddress) == encodeArgs(c_helperAddress));
1163 u256 a(3456789);
1164 u256 b("0x282837623374623234aa74");
1165 BOOST_REQUIRE(callContractFunction("callHelper(uint256,bool,uint256)", a, true, b) == encodeArgs(a * 3));
1166 BOOST_REQUIRE(callContractFunction("callHelper(uint256,bool,uint256)", a, false, b) == encodeArgs(b * 3));
1167 }
1168
BOOST_AUTO_TEST_CASE(inter_contract_calls_accessing_this)1169 BOOST_AUTO_TEST_CASE(inter_contract_calls_accessing_this)
1170 {
1171 char const* sourceCode = R"(
1172 contract Helper {
1173 function getAddress() public returns (address addr) {
1174 return address(this);
1175 }
1176 }
1177 contract Main {
1178 Helper h;
1179 function callHelper() public returns (address addr) {
1180 return h.getAddress();
1181 }
1182 function getHelper() public returns (address addr) {
1183 return address(h);
1184 }
1185 function setHelper(address addr) public {
1186 h = Helper(addr);
1187 }
1188 }
1189 )";
1190 compileAndRun(sourceCode, 0, "Helper");
1191 h160 const c_helperAddress = m_contractAddress;
1192 compileAndRun(sourceCode, 0, "Main");
1193 BOOST_REQUIRE(callContractFunction("setHelper(address)", c_helperAddress) == bytes());
1194 BOOST_REQUIRE(callContractFunction("getHelper()", c_helperAddress) == encodeArgs(c_helperAddress));
1195 BOOST_REQUIRE(callContractFunction("callHelper()") == encodeArgs(c_helperAddress));
1196 }
1197
BOOST_AUTO_TEST_CASE(calls_to_this)1198 BOOST_AUTO_TEST_CASE(calls_to_this)
1199 {
1200 char const* sourceCode = R"(
1201 contract Helper {
1202 function invoke(uint a, uint b) public returns (uint c) {
1203 return this.multiply(a, b, 10);
1204 }
1205 function multiply(uint a, uint b, uint8 c) public returns (uint ret) {
1206 return a * b + c;
1207 }
1208 }
1209 contract Main {
1210 Helper h;
1211 function callHelper(uint a, uint b) public returns (uint ret) {
1212 return h.invoke(a, b);
1213 }
1214 function getHelper() public returns (address addr) {
1215 return address(h);
1216 }
1217 function setHelper(address addr) public {
1218 h = Helper(addr);
1219 }
1220 }
1221 )";
1222 compileAndRun(sourceCode, 0, "Helper");
1223 h160 const c_helperAddress = m_contractAddress;
1224 compileAndRun(sourceCode, 0, "Main");
1225 BOOST_REQUIRE(callContractFunction("setHelper(address)", c_helperAddress) == bytes());
1226 BOOST_REQUIRE(callContractFunction("getHelper()", c_helperAddress) == encodeArgs(c_helperAddress));
1227 u256 a(3456789);
1228 u256 b("0x282837623374623234aa74");
1229 BOOST_REQUIRE(callContractFunction("callHelper(uint256,uint256)", a, b) == encodeArgs(a * b + 10));
1230 }
1231
BOOST_AUTO_TEST_CASE(inter_contract_calls_with_local_vars)1232 BOOST_AUTO_TEST_CASE(inter_contract_calls_with_local_vars)
1233 {
1234 // note that a reference to another contract's function occupies two stack slots,
1235 // so this tests correct stack slot allocation
1236 char const* sourceCode = R"(
1237 contract Helper {
1238 function multiply(uint a, uint b) public returns (uint c) {
1239 return a * b;
1240 }
1241 }
1242 contract Main {
1243 Helper h;
1244 function callHelper(uint a, uint b) public returns (uint c) {
1245 uint8 y = 9;
1246 uint256 ret = h.multiply(a, b);
1247 return ret + y;
1248 }
1249 function getHelper() public returns (address haddress) {
1250 return address(h);
1251 }
1252 function setHelper(address haddress) public {
1253 h = Helper(haddress);
1254 }
1255 }
1256 )";
1257 compileAndRun(sourceCode, 0, "Helper");
1258 h160 const c_helperAddress = m_contractAddress;
1259 compileAndRun(sourceCode, 0, "Main");
1260 BOOST_REQUIRE(callContractFunction("setHelper(address)", c_helperAddress) == bytes());
1261 BOOST_REQUIRE(callContractFunction("getHelper()", c_helperAddress) == encodeArgs(c_helperAddress));
1262 u256 a(3456789);
1263 u256 b("0x282837623374623234aa74");
1264 BOOST_REQUIRE(callContractFunction("callHelper(uint256,uint256)", a, b) == encodeArgs(a * b + 9));
1265 }
1266
BOOST_AUTO_TEST_CASE(fixed_bytes_in_calls)1267 BOOST_AUTO_TEST_CASE(fixed_bytes_in_calls)
1268 {
1269 char const* sourceCode = R"(
1270 contract Helper {
1271 function invoke(bytes3 x, bool stop) public returns (bytes4 ret) {
1272 return x;
1273 }
1274 }
1275 contract Main {
1276 Helper h;
1277 function callHelper(bytes2 x, bool stop) public returns (bytes5 ret) {
1278 return h.invoke(x, stop);
1279 }
1280 function getHelper() public returns (address addr) {
1281 return address(h);
1282 }
1283 function setHelper(address addr) public {
1284 h = Helper(addr);
1285 }
1286 }
1287 )";
1288 compileAndRun(sourceCode, 0, "Helper");
1289 h160 const c_helperAddress = m_contractAddress;
1290 compileAndRun(sourceCode, 0, "Main");
1291 BOOST_REQUIRE(callContractFunction("setHelper(address)", c_helperAddress) == bytes());
1292 BOOST_REQUIRE(callContractFunction("getHelper()", c_helperAddress) == encodeArgs(c_helperAddress));
1293 ABI_CHECK(callContractFunction("callHelper(bytes2,bool)", string("\0a", 2), true), encodeArgs(string("\0a\0\0\0", 5)));
1294 }
1295
BOOST_AUTO_TEST_CASE(constructor_with_long_arguments)1296 BOOST_AUTO_TEST_CASE(constructor_with_long_arguments)
1297 {
1298 char const* sourceCode = R"(
1299 contract Main {
1300 string public a;
1301 string public b;
1302
1303 constructor(string memory _a, string memory _b) {
1304 a = _a;
1305 b = _b;
1306 }
1307 }
1308 )";
1309 string a = "01234567890123gabddunaouhdaoneudapcgadi4567890789012oneudapcgadi4567890789012oneudapcgadi4567890789012oneudapcgadi4567890789012oneudapcgadi4567890789012oneudapcgadi4567890789012oneudapcgadi4567890789012oneudapcgadi45678907890123456789abcd123456787890123456789abcd90123456789012345678901234567890123456789aboneudapcgadi4567890789012oneudapcgadi4567890789012oneudapcgadi45678907890123456789abcd123456787890123456789abcd90123456789012345678901234567890123456789aboneudapcgadi4567890789012oneudapcgadi4567890789012oneudapcgadi45678907890123456789abcd123456787890123456789abcd90123456789012345678901234567890123456789aboneudapcgadi4567890789012cdef";
1310 string b = "AUTAHIACIANOTUHAOCUHAOEUNAOEHUNTHDYDHPYDRCPYDRSTITOEUBXHUDGO>PYAUTAHIACIANOTUHAOCUHAOEUNAOEHUNTHDYDHPYDRCPYDRSTITOEUBXHUDGO>PYAUTAHIACIANOTUHAOCUHAOEUNAOEHUNTHDYDHPYDRCPYDRSTITOEUBXHUDGO>PYAUTAHIACIANOTUHAOCUHAOEUNAOEHUNTHDYDHPYDRCPYDRSTITOEUBXHUDGO>PYAUTAHIACIANOTUHAOCUHAOEUNAOEHUNTHDYDHPYDRCPYDRSTITOEUBXHUDGO>PYAUTAHIACIANOTUHAOCUHAOEUNAOEHUNTHDYDHPYDRCPYDRSTITOEUBXHUDGO>PYAUTAHIACIANOTUHAOCUHAOEUNAOEHUNTHDYDHPYDRCPYDRSTITOEUBXHUDGO>PYAUTAHIACIANOTUHAOCUHAOEUNAOEHUNTHDYDHPYDRCPYDRSTITOEUBXHUDGO>PYAUTAHIACIANOTUHAOCUHAOEUNAOEHUNTHDYDHPYDRCPYDRSTITOEUBXHUDGO>PYAUTAHIACIANOTUHAOCUHAOEUNAOEHUNTHDYDHPYDRCPYDRSTITOEUBXHUDGO>PYAUTAHIACIANOTUHAOCUHAOEUNAOEHUNTHDYDHPYDRCPYDRSTITOEUBXHUDGO>PYAUTAHIACIANOTUHAOCUHAOEUNAOEHUNTHDYDHPYDRCPYDRSTITOEUBXHUDGO>PYAUTAHIACIANOTUHAOCUHAOEUNAOEHUNTHDYDHPYDRCPYDRSTITOEUBXHUDGO>PYAUTAHIACIANOTUHAOCUHAOEUNAOEHUNTHDYDHPYDRCPYDRSTITOEUBXHUDGO>PYAUTAHIACIANOTUHAOCUHAOEUNAOEHUNTHDYDHPYDRCPYDRSTITOEUBXHUDGO>PYAUTAHIACIANOTUHAOCUHAOEUNAOEHUNTHDYDHPYDRCPYDRSTITOEUBXHUDGO>PYAUTAHIACIANOTUHAOCUHAOEUNAOEHUNTHDYDHPYDRCPYDRSTITOEUBXHUDGO>PYAUTAHIACIANOTUHAOCUHAOEUNAOEHUNTHDYDHPYDRCPYDRSTITOEUBXHUDGO>PY";
1311
1312 compileAndRun(sourceCode, 0, "Main", encodeArgs(
1313 u256(0x40),
1314 u256(0x40 + 0x20 + ((a.length() + 31) / 32) * 32),
1315 u256(a.length()),
1316 a,
1317 u256(b.length()),
1318 b
1319 ));
1320 ABI_CHECK(callContractFunction("a()"), encodeDyn(a));
1321 ABI_CHECK(callContractFunction("b()"), encodeDyn(b));
1322 }
1323
BOOST_AUTO_TEST_CASE(contracts_as_addresses)1324 BOOST_AUTO_TEST_CASE(contracts_as_addresses)
1325 {
1326 char const* sourceCode = R"(
1327 contract helper {
1328 receive() external payable { } // can receive ether
1329 }
1330 contract test {
1331 helper h;
1332 constructor() payable { h = new helper(); payable(h).send(5); }
1333 function getBalance() public returns (uint256 myBalance, uint256 helperBalance) {
1334 myBalance = address(this).balance;
1335 helperBalance = address(h).balance;
1336 }
1337 }
1338 )";
1339 compileAndRun(sourceCode, 20);
1340 BOOST_CHECK_EQUAL(balanceAt(m_contractAddress), 20 - 5);
1341 BOOST_REQUIRE(callContractFunction("getBalance()") == encodeArgs(u256(20 - 5), u256(5)));
1342 }
1343
BOOST_AUTO_TEST_CASE(blockhash)1344 BOOST_AUTO_TEST_CASE(blockhash)
1345 {
1346 char const* sourceCode = R"(
1347 contract C {
1348 uint256 counter;
1349 function g() public returns (bool) { counter++; return true; }
1350 function f() public returns (bytes32[] memory r) {
1351 r = new bytes32[](259);
1352 for (uint i = 0; i < 259; i++) {
1353 unchecked {
1354 r[i] = blockhash(block.number - 257 + i);
1355 }
1356 }
1357 }
1358 }
1359 )";
1360 compileAndRun(sourceCode);
1361 // generate a sufficient amount of blocks
1362 while (blockNumber() < u256(255))
1363 ABI_CHECK(callContractFunction("g()"), encodeArgs(true));
1364
1365 vector<u256> hashes;
1366 // ``blockhash()`` is only valid for the last 256 blocks, otherwise zero
1367 hashes.emplace_back(0);
1368 for (u256 i = blockNumber() - u256(255); i <= blockNumber(); i++)
1369 hashes.emplace_back(blockHash(i));
1370 // the current block hash is not yet known at execution time and therefore zero
1371 hashes.emplace_back(0);
1372 // future block hashes are zero
1373 hashes.emplace_back(0);
1374
1375 ABI_CHECK(callContractFunction("f()"), encodeDyn(hashes));
1376 }
1377
BOOST_AUTO_TEST_CASE(internal_constructor)1378 BOOST_AUTO_TEST_CASE(internal_constructor)
1379 {
1380 char const* sourceCode = R"(
1381 abstract contract C {
1382 constructor() {}
1383 }
1384 )";
1385 // via yul disabled because it will throw an error instead of
1386 // returning empty bytecode.
1387 BOOST_CHECK(compileAndRunWithoutCheck({{"", sourceCode}}, 0, "C").empty());
1388 }
1389
BOOST_AUTO_TEST_CASE(default_fallback_throws)1390 BOOST_AUTO_TEST_CASE(default_fallback_throws)
1391 {
1392 char const* sourceCode = R"YY(
1393 contract A {
1394 function f() public returns (bool) {
1395 (bool success,) = address(this).call("");
1396 return success;
1397 }
1398 }
1399 )YY";
1400 compileAndRun(sourceCode);
1401 ABI_CHECK(callContractFunction("f()"), encodeArgs(0));
1402
1403 if (solidity::test::CommonOptions::get().evmVersion().hasStaticCall())
1404 {
1405 char const* sourceCode = R"YY(
1406 contract A {
1407 function f() public returns (bool) {
1408 (bool success, bytes memory data) = address(this).staticcall("");
1409 assert(data.length == 0);
1410 return success;
1411 }
1412 }
1413 )YY";
1414 compileAndRun(sourceCode);
1415 ABI_CHECK(callContractFunction("f()"), encodeArgs(0));
1416 }
1417 }
1418
BOOST_AUTO_TEST_CASE(empty_name_input_parameter_with_named_one)1419 BOOST_AUTO_TEST_CASE(empty_name_input_parameter_with_named_one)
1420 {
1421 char const* sourceCode = R"(
1422 contract test {
1423 function f(uint, uint k) public returns(uint ret_k, uint ret_g){
1424 uint g = 8;
1425 ret_k = k;
1426 ret_g = g;
1427 }
1428 }
1429 )";
1430 ALSO_VIA_YUL(
1431 DISABLE_EWASM_TESTRUN()
1432
1433 compileAndRun(sourceCode);
1434 BOOST_CHECK(callContractFunction("f(uint256,uint256)", 5, 9) != encodeArgs(5, 8));
1435 ABI_CHECK(callContractFunction("f(uint256,uint256)", 5, 9), encodeArgs(9, 8));
1436 )
1437 }
1438
BOOST_AUTO_TEST_CASE(generic_call)1439 BOOST_AUTO_TEST_CASE(generic_call)
1440 {
1441 char const* sourceCode = R"**(
1442 contract receiver {
1443 uint public received;
1444 function recv(uint256 x) public payable { received = x; }
1445 }
1446 contract sender {
1447 constructor() payable {}
1448 function doSend(address rec) public returns (uint d)
1449 {
1450 bytes4 signature = bytes4(bytes32(keccak256("recv(uint256)")));
1451 rec.call{value: 2}(abi.encodeWithSelector(signature, 23));
1452 return receiver(rec).received();
1453 }
1454 }
1455 )**";
1456 compileAndRun(sourceCode, 0, "receiver");
1457 h160 const c_receiverAddress = m_contractAddress;
1458 compileAndRun(sourceCode, 50, "sender");
1459 BOOST_REQUIRE(callContractFunction("doSend(address)", c_receiverAddress) == encodeArgs(23));
1460 BOOST_CHECK_EQUAL(balanceAt(m_contractAddress), 50 - 2);
1461 }
1462
BOOST_AUTO_TEST_CASE(generic_delegatecall)1463 BOOST_AUTO_TEST_CASE(generic_delegatecall)
1464 {
1465 char const* sourceCode = R"**(
1466 contract Receiver {
1467 uint public received;
1468 address public sender;
1469 uint public value;
1470 constructor() payable {}
1471 function recv(uint256 x) public payable { received = x; sender = msg.sender; value = msg.value; }
1472 }
1473 contract Sender {
1474 uint public received;
1475 address public sender;
1476 uint public value;
1477 constructor() payable {}
1478 function doSend(address rec) public payable
1479 {
1480 bytes4 signature = bytes4(bytes32(keccak256("recv(uint256)")));
1481 (bool success,) = rec.delegatecall(abi.encodeWithSelector(signature, 23));
1482 success;
1483 }
1484 }
1485 )**";
1486
1487 for (auto v2: {false, true})
1488 {
1489 string source = "pragma abicoder " + string(v2 ? "v2" : "v1") + ";\n" + string(sourceCode);
1490
1491 compileAndRun(source, 0, "Receiver");
1492 h160 const c_receiverAddress = m_contractAddress;
1493 compileAndRun(source, 50, "Sender");
1494 h160 const c_senderAddress = m_contractAddress;
1495 BOOST_CHECK(m_sender != c_senderAddress); // just for sanity
1496 ABI_CHECK(callContractFunctionWithValue("doSend(address)", 11, c_receiverAddress), encodeArgs());
1497 ABI_CHECK(callContractFunction("received()"), encodeArgs(u256(23)));
1498 ABI_CHECK(callContractFunction("sender()"), encodeArgs(m_sender));
1499 ABI_CHECK(callContractFunction("value()"), encodeArgs(u256(11)));
1500 m_contractAddress = c_receiverAddress;
1501 ABI_CHECK(callContractFunction("received()"), encodeArgs(u256(0)));
1502 ABI_CHECK(callContractFunction("sender()"), encodeArgs(u256(0)));
1503 ABI_CHECK(callContractFunction("value()"), encodeArgs(u256(0)));
1504 BOOST_CHECK(storageEmpty(c_receiverAddress));
1505 BOOST_CHECK(!storageEmpty(c_senderAddress));
1506 BOOST_CHECK_EQUAL(balanceAt(c_receiverAddress), 0);
1507 BOOST_CHECK_EQUAL(balanceAt(c_senderAddress), 50 + 11);
1508 }
1509 }
1510
BOOST_AUTO_TEST_CASE(generic_staticcall)1511 BOOST_AUTO_TEST_CASE(generic_staticcall)
1512 {
1513 if (solidity::test::CommonOptions::get().evmVersion().hasStaticCall())
1514 {
1515 char const* sourceCode = R"**(
1516 contract A {
1517 uint public x;
1518 constructor() { x = 42; }
1519 function pureFunction(uint256 p) public pure returns (uint256) { return p; }
1520 function viewFunction(uint256 p) public view returns (uint256) { return p + x; }
1521 function nonpayableFunction(uint256 p) public returns (uint256) { x = p; return x; }
1522 function assertFunction(uint256 p) public view returns (uint256) { assert(x == p); return x; }
1523 }
1524 contract C {
1525 function f(address a) public view returns (bool, bytes memory)
1526 {
1527 return a.staticcall(abi.encodeWithSignature("pureFunction(uint256)", 23));
1528 }
1529 function g(address a) public view returns (bool, bytes memory)
1530 {
1531 return a.staticcall(abi.encodeWithSignature("viewFunction(uint256)", 23));
1532 }
1533 function h(address a) public view returns (bool, bytes memory)
1534 {
1535 return a.staticcall(abi.encodeWithSignature("nonpayableFunction(uint256)", 23));
1536 }
1537 function i(address a, uint256 v) public view returns (bool, bytes memory)
1538 {
1539 return a.staticcall(abi.encodeWithSignature("assertFunction(uint256)", v));
1540 }
1541 }
1542 )**";
1543 compileAndRun(sourceCode, 0, "A");
1544 h160 const c_addressA = m_contractAddress;
1545 compileAndRun(sourceCode, 0, "C");
1546 ABI_CHECK(callContractFunction("f(address)", c_addressA), encodeArgs(true, 0x40, 0x20, 23));
1547 ABI_CHECK(callContractFunction("g(address)", c_addressA), encodeArgs(true, 0x40, 0x20, 23 + 42));
1548 ABI_CHECK(callContractFunction("h(address)", c_addressA), encodeArgs(false, 0x40, 0x00));
1549 ABI_CHECK(callContractFunction("i(address,uint256)", c_addressA, 42), encodeArgs(true, 0x40, 0x20, 42));
1550 ABI_CHECK(callContractFunction("i(address,uint256)", c_addressA, 23), encodeArgs(false, 0x40, 0x24) + panicData(PanicCode::Assert) + bytes(32 - 4, 0));
1551 }
1552 }
1553
BOOST_AUTO_TEST_CASE(library_call_protection)1554 BOOST_AUTO_TEST_CASE(library_call_protection)
1555 {
1556 // This tests code that reverts a call if it is a direct call to a library
1557 // as opposed to a delegatecall.
1558 char const* sourceCode = R"(
1559 library Lib {
1560 struct S { uint x; }
1561 // a direct call to this should revert
1562 function np(S storage s) public returns (address) { s.x = 3; return msg.sender; }
1563 // a direct call to this is fine
1564 function v(S storage) public view returns (address) { return msg.sender; }
1565 // a direct call to this is fine
1566 function pu() public pure returns (uint) { return 2; }
1567 }
1568 contract Test {
1569 Lib.S public s;
1570 function np() public returns (address) { return Lib.np(s); }
1571 function v() public view returns (address) { return Lib.v(s); }
1572 function pu() public pure returns (uint) { return Lib.pu(); }
1573 }
1574 )";
1575 ALSO_VIA_YUL(
1576 DISABLE_EWASM_TESTRUN()
1577 compileAndRun(sourceCode, 0, "Lib");
1578 ABI_CHECK(callContractFunction("np(Lib.S storage)", 0), encodeArgs());
1579 ABI_CHECK(callContractFunction("v(Lib.S storage)", 0), encodeArgs(m_sender));
1580 ABI_CHECK(callContractFunction("pu()"), encodeArgs(2));
1581 compileAndRun(sourceCode, 0, "Test", bytes(), map<string, h160>{{":Lib", m_contractAddress}});
1582 ABI_CHECK(callContractFunction("s()"), encodeArgs(0));
1583 ABI_CHECK(callContractFunction("np()"), encodeArgs(m_sender));
1584 ABI_CHECK(callContractFunction("s()"), encodeArgs(3));
1585 ABI_CHECK(callContractFunction("v()"), encodeArgs(m_sender));
1586 ABI_CHECK(callContractFunction("pu()"), encodeArgs(2));
1587 )
1588 }
1589
BOOST_AUTO_TEST_CASE(bytes_from_calldata_to_memory)1590 BOOST_AUTO_TEST_CASE(bytes_from_calldata_to_memory)
1591 {
1592 char const* sourceCode = R"(
1593 contract C {
1594 function f() public returns (bytes32) {
1595 return keccak256(abi.encodePacked("abc", msg.data));
1596 }
1597 }
1598 )";
1599 ALSO_VIA_YUL(
1600 DISABLE_EWASM_TESTRUN();
1601 compileAndRun(sourceCode);
1602 bytes calldata1 = FixedHash<4>(util::keccak256("f()")).asBytes() + bytes(61, 0x22) + bytes(12, 0x12);
1603 sendMessage(calldata1, false);
1604 BOOST_CHECK(m_transactionSuccessful);
1605 BOOST_CHECK(m_output == encodeArgs(util::keccak256(bytes{'a', 'b', 'c'} + calldata1)));
1606 );
1607 }
1608
BOOST_AUTO_TEST_CASE(call_forward_bytes_length)1609 BOOST_AUTO_TEST_CASE(call_forward_bytes_length)
1610 {
1611 char const* sourceCode = R"(
1612 contract receiver {
1613 uint public calledLength;
1614 fallback() external { calledLength = msg.data.length; }
1615 }
1616 contract sender {
1617 receiver rec;
1618 constructor() { rec = new receiver(); }
1619 function viaCalldata() public returns (uint) {
1620 (bool success,) = address(rec).call(msg.data);
1621 require(success);
1622 return rec.calledLength();
1623 }
1624 function viaMemory() public returns (uint) {
1625 bytes memory x = msg.data;
1626 (bool success,) = address(rec).call(x);
1627 require(success);
1628 return rec.calledLength();
1629 }
1630 bytes s;
1631 function viaStorage() public returns (uint) {
1632 s = msg.data;
1633 (bool success,) = address(rec).call(s);
1634 require(success);
1635 return rec.calledLength();
1636 }
1637 }
1638 )";
1639 ALSO_VIA_YUL(
1640 DISABLE_EWASM_TESTRUN();
1641 compileAndRun(sourceCode, 0, "sender");
1642
1643 // No additional data, just function selector
1644 ABI_CHECK(callContractFunction("viaCalldata()"), encodeArgs(4));
1645 ABI_CHECK(callContractFunction("viaMemory()"), encodeArgs(4));
1646 ABI_CHECK(callContractFunction("viaStorage()"), encodeArgs(4));
1647
1648 // Some additional unpadded data
1649 bytes unpadded = asBytes(string("abc"));
1650 ABI_CHECK(callContractFunctionNoEncoding("viaCalldata()", unpadded), encodeArgs(7));
1651 ABI_CHECK(callContractFunctionNoEncoding("viaMemory()", unpadded), encodeArgs(7));
1652 ABI_CHECK(callContractFunctionNoEncoding("viaStorage()", unpadded), encodeArgs(7));
1653 );
1654 }
1655
BOOST_AUTO_TEST_CASE(copying_bytes_multiassign)1656 BOOST_AUTO_TEST_CASE(copying_bytes_multiassign)
1657 {
1658 char const* sourceCode = R"(
1659 contract receiver {
1660 uint public received;
1661 function recv(uint x) public { received += x + 1; }
1662 fallback() external { received = 0x80; }
1663 }
1664 contract sender {
1665 constructor() { rec = new receiver(); }
1666 fallback() external { savedData1 = savedData2 = msg.data; }
1667 function forward(bool selector) public returns (bool) {
1668 if (selector) { address(rec).call(savedData1); delete savedData1; }
1669 else { address(rec).call(savedData2); delete savedData2; }
1670 return true;
1671 }
1672 function val() public returns (uint) { return rec.received(); }
1673 receiver rec;
1674 bytes savedData1;
1675 bytes savedData2;
1676 }
1677 )";
1678 ALSO_VIA_YUL(
1679 DISABLE_EWASM_TESTRUN()
1680 compileAndRun(sourceCode, 0, "sender");
1681 ABI_CHECK(callContractFunction("recv(uint256)", 7), bytes());
1682 ABI_CHECK(callContractFunction("val()"), encodeArgs(0));
1683 ABI_CHECK(callContractFunction("forward(bool)", true), encodeArgs(true));
1684 ABI_CHECK(callContractFunction("val()"), encodeArgs(8));
1685 ABI_CHECK(callContractFunction("forward(bool)", false), encodeArgs(true));
1686 ABI_CHECK(callContractFunction("val()"), encodeArgs(16));
1687 ABI_CHECK(callContractFunction("forward(bool)", true), encodeArgs(true));
1688 ABI_CHECK(callContractFunction("val()"), encodeArgs(0x80));
1689 );
1690 }
1691
BOOST_AUTO_TEST_CASE(copy_from_calldata_removes_bytes_data)1692 BOOST_AUTO_TEST_CASE(copy_from_calldata_removes_bytes_data)
1693 {
1694 char const* sourceCode = R"(
1695 contract c {
1696 function set() public returns (bool) { data = msg.data; return true; }
1697 fallback() external { data = msg.data; }
1698 bytes data;
1699 }
1700 )";
1701 ALSO_VIA_YUL(
1702 DISABLE_EWASM_TESTRUN()
1703 compileAndRun(sourceCode);
1704 ABI_CHECK(callContractFunction("set()", 1, 2, 3, 4, 5), encodeArgs(true));
1705 BOOST_CHECK(!storageEmpty(m_contractAddress));
1706 sendMessage(bytes(), false);
1707 BOOST_CHECK(m_transactionSuccessful);
1708 BOOST_CHECK(m_output.empty());
1709 BOOST_CHECK(storageEmpty(m_contractAddress));
1710 );
1711 }
1712
BOOST_AUTO_TEST_CASE(struct_referencing)1713 BOOST_AUTO_TEST_CASE(struct_referencing)
1714 {
1715 static char const* sourceCode = R"(
1716 pragma abicoder v2;
1717 interface I {
1718 struct S { uint a; }
1719 }
1720 library L {
1721 struct S { uint b; uint a; }
1722 function f() public pure returns (S memory) {
1723 S memory s;
1724 s.a = 3;
1725 return s;
1726 }
1727 function g() public pure returns (I.S memory) {
1728 I.S memory s;
1729 s.a = 4;
1730 return s;
1731 }
1732 // argument-dependant lookup tests
1733 function a(I.S memory) public pure returns (uint) { return 1; }
1734 function a(S memory) public pure returns (uint) { return 2; }
1735 }
1736 contract C is I {
1737 function f() public pure returns (S memory) {
1738 S memory s;
1739 s.a = 1;
1740 return s;
1741 }
1742 function g() public pure returns (I.S memory) {
1743 I.S memory s;
1744 s.a = 2;
1745 return s;
1746 }
1747 function h() public pure returns (L.S memory) {
1748 L.S memory s;
1749 s.a = 5;
1750 return s;
1751 }
1752 function x() public pure returns (L.S memory) {
1753 return L.f();
1754 }
1755 function y() public pure returns (I.S memory) {
1756 return L.g();
1757 }
1758 function a1() public pure returns (uint) { S memory s; return L.a(s); }
1759 function a2() public pure returns (uint) { L.S memory s; return L.a(s); }
1760 }
1761 )";
1762 ALSO_VIA_YUL(
1763 DISABLE_EWASM_TESTRUN()
1764 compileAndRun(sourceCode, 0, "L");
1765 ABI_CHECK(callContractFunction("f()"), encodeArgs(0, 3));
1766 ABI_CHECK(callContractFunction("g()"), encodeArgs(4));
1767 compileAndRun(sourceCode, 0, "C", bytes(), map<string, h160>{ {":L", m_contractAddress}});
1768 ABI_CHECK(callContractFunction("f()"), encodeArgs(1));
1769 ABI_CHECK(callContractFunction("g()"), encodeArgs(2));
1770 ABI_CHECK(callContractFunction("h()"), encodeArgs(0, 5));
1771 ABI_CHECK(callContractFunction("x()"), encodeArgs(0, 3));
1772 ABI_CHECK(callContractFunction("y()"), encodeArgs(4));
1773 ABI_CHECK(callContractFunction("a1()"), encodeArgs(1));
1774 ABI_CHECK(callContractFunction("a2()"), encodeArgs(2));
1775 )
1776 }
1777
BOOST_AUTO_TEST_CASE(enum_referencing)1778 BOOST_AUTO_TEST_CASE(enum_referencing)
1779 {
1780 char const* sourceCode = R"(
1781 interface I {
1782 enum Direction { A, B, Left, Right }
1783 }
1784 library L {
1785 enum Direction { Left, Right }
1786 function f() public pure returns (Direction) {
1787 return Direction.Right;
1788 }
1789 function g() public pure returns (I.Direction) {
1790 return I.Direction.Right;
1791 }
1792 }
1793 contract C is I {
1794 function f() public pure returns (Direction) {
1795 return Direction.Right;
1796 }
1797 function g() public pure returns (I.Direction) {
1798 return I.Direction.Right;
1799 }
1800 function h() public pure returns (L.Direction) {
1801 return L.Direction.Right;
1802 }
1803 function x() public pure returns (L.Direction) {
1804 return L.f();
1805 }
1806 function y() public pure returns (I.Direction) {
1807 return L.g();
1808 }
1809 }
1810 )";
1811 ALSO_VIA_YUL(
1812 DISABLE_EWASM_TESTRUN()
1813 compileAndRun(sourceCode, 0, "L");
1814 ABI_CHECK(callContractFunction("f()"), encodeArgs(1));
1815 ABI_CHECK(callContractFunction("g()"), encodeArgs(3));
1816 compileAndRun(sourceCode, 0, "C", bytes(), map<string, h160>{{":L", m_contractAddress}});
1817 ABI_CHECK(callContractFunction("f()"), encodeArgs(3));
1818 ABI_CHECK(callContractFunction("g()"), encodeArgs(3));
1819 ABI_CHECK(callContractFunction("h()"), encodeArgs(1));
1820 ABI_CHECK(callContractFunction("x()"), encodeArgs(1));
1821 ABI_CHECK(callContractFunction("y()"), encodeArgs(3));
1822 )
1823 }
1824
BOOST_AUTO_TEST_CASE(bytes_in_arguments)1825 BOOST_AUTO_TEST_CASE(bytes_in_arguments)
1826 {
1827 char const* sourceCode = R"(
1828 contract c {
1829 uint result;
1830 function f(uint a, uint b) public { result += a + b; }
1831 function g(uint a) public { result *= a; }
1832 function test(uint a, bytes calldata data1, bytes calldata data2, uint b) external returns (uint r_a, uint r, uint r_b, uint l) {
1833 r_a = a;
1834 address(this).call(data1);
1835 address(this).call(data2);
1836 r = result;
1837 r_b = b;
1838 l = data1.length;
1839 }
1840 }
1841 )";
1842 ALSO_VIA_YUL(
1843 DISABLE_EWASM_TESTRUN()
1844
1845 compileAndRun(sourceCode);
1846
1847 string innercalldata1 = asString(FixedHash<4>(util::keccak256("f(uint256,uint256)")).asBytes() + encodeArgs(8, 9));
1848 string innercalldata2 = asString(FixedHash<4>(util::keccak256("g(uint256)")).asBytes() + encodeArgs(3));
1849 bytes calldata = encodeArgs(
1850 12, 32 * 4, u256(32 * 4 + 32 + (innercalldata1.length() + 31) / 32 * 32), 13,
1851 u256(innercalldata1.length()), innercalldata1,
1852 u256(innercalldata2.length()), innercalldata2);
1853 ABI_CHECK(
1854 callContractFunction("test(uint256,bytes,bytes,uint256)", calldata),
1855 encodeArgs(12, (8 + 9) * 3, 13, u256(innercalldata1.length()))
1856 );
1857 );
1858 }
1859
BOOST_AUTO_TEST_CASE(array_copy_storage_abi)1860 BOOST_AUTO_TEST_CASE(array_copy_storage_abi)
1861 {
1862 // NOTE: This does not really test copying from storage to ABI directly,
1863 // because it will always copy to memory first.
1864 char const* sourceCode = R"(
1865 pragma abicoder v2;
1866 contract c {
1867 uint8[] x;
1868 uint16[] y;
1869 uint24[] z;
1870 uint24[][] w;
1871 function test1() public returns (uint8[] memory) {
1872 for (uint i = 0; i < 101; ++i)
1873 x.push(uint8(i));
1874 return x;
1875 }
1876 function test2() public returns (uint16[] memory) {
1877 for (uint i = 0; i < 101; ++i)
1878 y.push(uint16(i));
1879 return y;
1880 }
1881 function test3() public returns (uint24[] memory) {
1882 for (uint i = 0; i < 101; ++i)
1883 z.push(uint24(i));
1884 return z;
1885 }
1886 function test4() public returns (uint24[][] memory) {
1887 w = new uint24[][](5);
1888 for (uint i = 0; i < 5; ++i)
1889 for (uint j = 0; j < 101; ++j)
1890 w[i].push(uint24(j));
1891 return w;
1892 }
1893 }
1894 )";
1895 ALSO_VIA_YUL(
1896 DISABLE_EWASM_TESTRUN()
1897
1898 compileAndRun(sourceCode);
1899 bytes valueSequence;
1900 for (size_t i = 0; i < 101; ++i)
1901 valueSequence += toBigEndian(u256(i));
1902 ABI_CHECK(callContractFunction("test1()"), encodeArgs(0x20, 101) + valueSequence);
1903 ABI_CHECK(callContractFunction("test2()"), encodeArgs(0x20, 101) + valueSequence);
1904 ABI_CHECK(callContractFunction("test3()"), encodeArgs(0x20, 101) + valueSequence);
1905 ABI_CHECK(callContractFunction("test4()"),
1906 encodeArgs(0x20, 5, 0xa0, 0xa0 + 102 * 32 * 1, 0xa0 + 102 * 32 * 2, 0xa0 + 102 * 32 * 3, 0xa0 + 102 * 32 * 4) +
1907 encodeArgs(101) + valueSequence +
1908 encodeArgs(101) + valueSequence +
1909 encodeArgs(101) + valueSequence +
1910 encodeArgs(101) + valueSequence +
1911 encodeArgs(101) + valueSequence
1912 );
1913 );
1914 }
1915
1916 //BOOST_AUTO_TEST_CASE(assignment_to_const_array_vars)
1917 //{
1918 // char const* sourceCode = R"(
1919 // contract C {
1920 // uint[3] constant x = [uint(1), 2, 3];
1921 // uint constant y = x[0] + x[1] + x[2];
1922 // function f() public returns (uint) { return y; }
1923 // }
1924 // )";
1925 // compileAndRun(sourceCode);
1926 // ABI_CHECK(callContractFunction("f()"), encodeArgs(1 + 2 + 3));
1927 //}
1928
1929 // Disabled until https://github.com/ethereum/solidity/issues/715 is implemented
1930 //BOOST_AUTO_TEST_CASE(constant_struct)
1931 //{
1932 // char const* sourceCode = R"(
1933 // contract C {
1934 // struct S { uint x; uint[] y; }
1935 // S constant x = S(5, new uint[](4));
1936 // function f() public returns (uint) { return x.x; }
1937 // }
1938 // )";
1939 // compileAndRun(sourceCode);
1940 // ABI_CHECK(callContractFunction("f()"), encodeArgs(5));
1941 //}
1942
BOOST_AUTO_TEST_CASE(evm_exceptions_in_constructor_out_of_baund)1943 BOOST_AUTO_TEST_CASE(evm_exceptions_in_constructor_out_of_baund)
1944 {
1945 char const* sourceCode = R"(
1946 contract A {
1947 uint public test = 1;
1948 uint[3] arr;
1949 constructor()
1950 {
1951 uint index = 5;
1952 test = arr[index];
1953 ++test;
1954 }
1955 }
1956 )";
1957 ABI_CHECK(compileAndRunWithoutCheck({{"", sourceCode}}, 0, "A"), panicData(PanicCode::ArrayOutOfBounds));
1958 BOOST_CHECK(!m_transactionSuccessful);
1959 }
1960
BOOST_AUTO_TEST_CASE(failing_send)1961 BOOST_AUTO_TEST_CASE(failing_send)
1962 {
1963 char const* sourceCode = R"(
1964 contract Helper {
1965 uint[] data;
1966 fallback () external {
1967 data[9]; // trigger exception
1968 }
1969 }
1970 contract Main {
1971 constructor() payable {}
1972 function callHelper(address payable _a) public returns (bool r, uint bal) {
1973 r = !_a.send(5);
1974 bal = address(this).balance;
1975 }
1976 }
1977 )";
1978 compileAndRun(sourceCode, 0, "Helper");
1979 h160 const c_helperAddress = m_contractAddress;
1980 compileAndRun(sourceCode, 20, "Main");
1981 BOOST_REQUIRE(callContractFunction("callHelper(address)", c_helperAddress) == encodeArgs(true, 20));
1982 }
1983
BOOST_AUTO_TEST_CASE(return_multiple_strings_of_various_sizes)1984 BOOST_AUTO_TEST_CASE(return_multiple_strings_of_various_sizes)
1985 {
1986 char const* sourceCode = R"(
1987 contract Main {
1988 string public s1;
1989 string public s2;
1990 function set(string calldata _s1, uint x, string calldata _s2) external returns (uint) {
1991 s1 = _s1;
1992 s2 = _s2;
1993 return x;
1994 }
1995 function get() public returns (string memory r1, string memory r2) {
1996 r1 = s1;
1997 r2 = s2;
1998 }
1999 }
2000 )";
2001 compileAndRun(sourceCode, 0, "Main");
2002 string s1(
2003 "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"
2004 "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"
2005 "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"
2006 "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"
2007 );
2008 string s2(
2009 "ABCDEFGHIJKLMNOPQRSTUVXYZABCDEFGHIJKLMNOPQRSTUVXYZABCDEFGHIJKLMNOPQRSTUVXYZ"
2010 "ABCDEFGHIJKLMNOPQRSTUVXYZABCDEFGHIJKLMNOPQRSTUVXYZABCDEFGHIJKLMNOPQRSTUVXYZ"
2011 "ABCDEFGHIJKLMNOPQRSTUVXYZABCDEFGHIJKLMNOPQRSTUVXYZABCDEFGHIJKLMNOPQRSTUVXYZ"
2012 "ABCDEFGHIJKLMNOPQRSTUVXYZABCDEFGHIJKLMNOPQRSTUVXYZABCDEFGHIJKLMNOPQRSTUVXYZ"
2013 "ABCDEFGHIJKLMNOPQRSTUVXYZABCDEFGHIJKLMNOPQRSTUVXYZABCDEFGHIJKLMNOPQRSTUVXYZ"
2014 );
2015 vector<size_t> lengths{0, 30, 32, 63, 64, 65, 210, 300};
2016 for (auto l1: lengths)
2017 for (auto l2: lengths)
2018 {
2019 bytes dyn1 = encodeArgs(u256(l1), s1.substr(0, l1));
2020 bytes dyn2 = encodeArgs(u256(l2), s2.substr(0, l2));
2021 bytes args = encodeArgs(u256(0x60), u256(l1), u256(0x60 + dyn1.size())) + dyn1 + dyn2;
2022 BOOST_REQUIRE(
2023 callContractFunction("set(string,uint256,string)", asString(args)) ==
2024 encodeArgs(u256(l1))
2025 );
2026 bytes result = encodeArgs(u256(0x40), u256(0x40 + dyn1.size())) + dyn1 + dyn2;
2027 ABI_CHECK(callContractFunction("get()"), result);
2028 ABI_CHECK(callContractFunction("s1()"), encodeArgs(0x20) + dyn1);
2029 ABI_CHECK(callContractFunction("s2()"), encodeArgs(0x20) + dyn2);
2030 }
2031 }
2032
BOOST_AUTO_TEST_CASE(accessor_involving_strings)2033 BOOST_AUTO_TEST_CASE(accessor_involving_strings)
2034 {
2035 char const* sourceCode = R"(
2036 contract Main {
2037 struct stringData { string a; uint b; string c; }
2038 mapping(uint => stringData[]) public data;
2039 function set(uint x, uint y, string calldata a, uint b, string calldata c) external returns (bool) {
2040 while (data[x].length < y + 1)
2041 data[x].push();
2042 data[x][y].a = a;
2043 data[x][y].b = b;
2044 data[x][y].c = c;
2045 return true;
2046 }
2047 }
2048 )";
2049 compileAndRun(sourceCode, 0, "Main");
2050 string s1("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz");
2051 string s2("ABCDEFGHIJKLMNOPQRSTUVXYZABCDEFGHIJKLMNOPQRSTUVXYZABCDEFGHIJKLMNOPQRSTUVXYZ");
2052 bytes s1Data = encodeArgs(u256(s1.length()), s1);
2053 bytes s2Data = encodeArgs(u256(s2.length()), s2);
2054 u256 b = 765;
2055 u256 x = 7;
2056 u256 y = 123;
2057 bytes args = encodeArgs(x, y, u256(0xa0), b, u256(0xa0 + s1Data.size()), s1Data, s2Data);
2058 bytes result = encodeArgs(u256(0x60), b, u256(0x60 + s1Data.size()), s1Data, s2Data);
2059 BOOST_REQUIRE(callContractFunction("set(uint256,uint256,string,uint256,string)", asString(args)) == encodeArgs(true));
2060 BOOST_REQUIRE(callContractFunction("data(uint256,uint256)", x, y) == result);
2061 }
2062
BOOST_AUTO_TEST_CASE(bytes_in_function_calls)2063 BOOST_AUTO_TEST_CASE(bytes_in_function_calls)
2064 {
2065 char const* sourceCode = R"(
2066 contract Main {
2067 string public s1;
2068 string public s2;
2069 function set(string memory _s1, uint x, string memory _s2) public returns (uint) {
2070 s1 = _s1;
2071 s2 = _s2;
2072 return x;
2073 }
2074 function setIndirectFromMemory(string memory _s1, uint x, string memory _s2) public returns (uint) {
2075 return this.set(_s1, x, _s2);
2076 }
2077 function setIndirectFromCalldata(string calldata _s1, uint x, string calldata _s2) external returns (uint) {
2078 return this.set(_s1, x, _s2);
2079 }
2080 }
2081 )";
2082 compileAndRun(sourceCode, 0, "Main");
2083 string s1("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz");
2084 string s2("ABCDEFGHIJKLMNOPQRSTUVXYZABCDEFGHIJKLMNOPQRSTUVXYZABCDEFGHIJKLMNOPQRSTUVXYZ");
2085 vector<size_t> lengths{0, 31, 64, 65};
2086 for (auto l1: lengths)
2087 for (auto l2: lengths)
2088 {
2089 bytes dyn1 = encodeArgs(u256(l1), s1.substr(0, l1));
2090 bytes dyn2 = encodeArgs(u256(l2), s2.substr(0, l2));
2091 bytes args1 = encodeArgs(u256(0x60), u256(l1), u256(0x60 + dyn1.size())) + dyn1 + dyn2;
2092 BOOST_REQUIRE(
2093 callContractFunction("setIndirectFromMemory(string,uint256,string)", asString(args1)) ==
2094 encodeArgs(u256(l1))
2095 );
2096 ABI_CHECK(callContractFunction("s1()"), encodeArgs(0x20) + dyn1);
2097 ABI_CHECK(callContractFunction("s2()"), encodeArgs(0x20) + dyn2);
2098 // swapped
2099 bytes args2 = encodeArgs(u256(0x60), u256(l1), u256(0x60 + dyn2.size())) + dyn2 + dyn1;
2100 BOOST_REQUIRE(
2101 callContractFunction("setIndirectFromCalldata(string,uint256,string)", asString(args2)) ==
2102 encodeArgs(u256(l1))
2103 );
2104 ABI_CHECK(callContractFunction("s1()"), encodeArgs(0x20) + dyn2);
2105 ABI_CHECK(callContractFunction("s2()"), encodeArgs(0x20) + dyn1);
2106 }
2107 }
2108
BOOST_AUTO_TEST_CASE(return_bytes_internal)2109 BOOST_AUTO_TEST_CASE(return_bytes_internal)
2110 {
2111 char const* sourceCode = R"(
2112 contract Main {
2113 bytes s1;
2114 function doSet(bytes memory _s1) public returns (bytes memory _r1) {
2115 s1 = _s1;
2116 _r1 = s1;
2117 }
2118 function set(bytes calldata _s1) external returns (uint _r, bytes memory _r1) {
2119 _r1 = doSet(_s1);
2120 _r = _r1.length;
2121 }
2122 }
2123 )";
2124 compileAndRun(sourceCode, 0, "Main");
2125 string s1("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz");
2126 vector<size_t> lengths{0, 31, 64, 65};
2127 for (auto l1: lengths)
2128 {
2129 bytes dyn1 = encodeArgs(u256(l1), s1.substr(0, l1));
2130 bytes args1 = encodeArgs(u256(0x20)) + dyn1;
2131 BOOST_REQUIRE(
2132 callContractFunction("set(bytes)", asString(args1)) ==
2133 encodeArgs(u256(l1), u256(0x40)) + dyn1
2134 );
2135 }
2136 }
2137
BOOST_AUTO_TEST_CASE(calldata_struct_short)2138 BOOST_AUTO_TEST_CASE(calldata_struct_short)
2139 {
2140 char const* sourceCode = R"(
2141 pragma abicoder v2;
2142 contract C {
2143 struct S { uint256 a; uint256 b; }
2144 function f(S calldata) external pure returns (uint256) {
2145 return msg.data.length;
2146 }
2147 }
2148 )";
2149 compileAndRun(sourceCode, 0, "C");
2150
2151 // double check that the valid case goes through
2152 ABI_CHECK(callContractFunction("f((uint256,uint256))", u256(1), u256(2)), encodeArgs(0x44));
2153
2154 ABI_CHECK(callContractFunctionNoEncoding("f((uint256,uint256))", bytes(63,0)), encodeArgs());
2155 ABI_CHECK(callContractFunctionNoEncoding("f((uint256,uint256))", bytes(33,0)), encodeArgs());
2156 ABI_CHECK(callContractFunctionNoEncoding("f((uint256,uint256))", bytes(32,0)), encodeArgs());
2157 ABI_CHECK(callContractFunctionNoEncoding("f((uint256,uint256))", bytes(31,0)), encodeArgs());
2158 ABI_CHECK(callContractFunctionNoEncoding("f((uint256,uint256))", bytes()), encodeArgs());
2159 }
2160
BOOST_AUTO_TEST_CASE(calldata_struct_function_type)2161 BOOST_AUTO_TEST_CASE(calldata_struct_function_type)
2162 {
2163 char const* sourceCode = R"(
2164 pragma abicoder v2;
2165 contract C {
2166 struct S { function (uint) external returns (uint) fn; }
2167 function f(S calldata s) external returns (uint256) {
2168 return s.fn(42);
2169 }
2170 function g(uint256 a) external returns (uint256) {
2171 return a * 3;
2172 }
2173 function h(uint256 a) external returns (uint256) {
2174 return 23;
2175 }
2176 }
2177 )";
2178 compileAndRun(sourceCode, 0, "C");
2179
2180 bytes fn_C_g = m_contractAddress.asBytes() + FixedHash<4>(util::keccak256("g(uint256)")).asBytes() + bytes(8,0);
2181 bytes fn_C_h = m_contractAddress.asBytes() + FixedHash<4>(util::keccak256("h(uint256)")).asBytes() + bytes(8,0);
2182 ABI_CHECK(callContractFunctionNoEncoding("f((function))", fn_C_g), encodeArgs(42 * 3));
2183 ABI_CHECK(callContractFunctionNoEncoding("f((function))", fn_C_h), encodeArgs(23));
2184 }
2185
BOOST_AUTO_TEST_CASE(calldata_array_dynamic_three_dimensional)2186 BOOST_AUTO_TEST_CASE(calldata_array_dynamic_three_dimensional)
2187 {
2188 vector<vector<vector<u256>>> data {
2189 {
2190 { 0x010A01, 0x010A02, 0x010A03 },
2191 { 0x010B01, 0x010B02, 0x010B03 }
2192 },
2193 {
2194 { 0x020A01, 0x020A02, 0x020A03 },
2195 { 0x020B01, 0x020B02, 0x020B03 }
2196 }
2197 };
2198
2199 for (bool outerDynamicallySized: { true, false })
2200 for (bool middleDynamicallySized: { true, false })
2201 for (bool innerDynamicallySized: { true, false })
2202 {
2203 // only test dynamically encoded arrays
2204 if (!outerDynamicallySized && !middleDynamicallySized && !innerDynamicallySized)
2205 continue;
2206
2207 string arrayType = "uint256";
2208 arrayType += innerDynamicallySized ? "[]" : "[3]";
2209 arrayType += middleDynamicallySized ? "[]" : "[2]";
2210 arrayType += outerDynamicallySized ? "[]" : "[2]";
2211
2212 string sourceCode = R"(
2213 pragma abicoder v2;
2214 contract C {
2215 function test()" + arrayType + R"( calldata a) external returns (uint256) {
2216 return a.length;
2217 }
2218 function test()" + arrayType + R"( calldata a, uint256 i) external returns (uint256) {
2219 return a[i].length;
2220 }
2221 function test()" + arrayType + R"( calldata a, uint256 i, uint256 j) external returns (uint256) {
2222 return a[i][j].length;
2223 }
2224 function test()" + arrayType + R"( calldata a, uint256 i, uint256 j, uint256 k) external returns (uint256) {
2225 return a[i][j][k];
2226 }
2227 function reenc()" + arrayType + R"( calldata a, uint256 i, uint256 j, uint256 k) external returns (uint256) {
2228 return this.test(a, i, j, k);
2229 }
2230 }
2231 )";
2232 compileAndRun(sourceCode, 0, "C");
2233
2234 bytes encoding = encodeArray(
2235 outerDynamicallySized,
2236 middleDynamicallySized || innerDynamicallySized,
2237 data | ranges::views::transform([&](auto const& _middleData) {
2238 return encodeArray(
2239 middleDynamicallySized,
2240 innerDynamicallySized,
2241 _middleData | ranges::views::transform([&](auto const& _values) {
2242 return encodeArray(innerDynamicallySized, false, _values);
2243 })
2244 );
2245 })
2246 );
2247
2248 ABI_CHECK(callContractFunction("test(" + arrayType + ")", 0x20, encoding), encodeArgs(data.size()));
2249 for (size_t i = 0; i < data.size(); i++)
2250 {
2251 ABI_CHECK(callContractFunction("test(" + arrayType + ",uint256)", 0x40, i, encoding), encodeArgs(data[i].size()));
2252 for (size_t j = 0; j < data[i].size(); j++)
2253 {
2254 ABI_CHECK(callContractFunction("test(" + arrayType + ",uint256,uint256)", 0x60, i, j, encoding), encodeArgs(data[i][j].size()));
2255 for (size_t k = 0; k < data[i][j].size(); k++)
2256 {
2257 ABI_CHECK(callContractFunction("test(" + arrayType + ",uint256,uint256,uint256)", 0x80, i, j, k, encoding), encodeArgs(data[i][j][k]));
2258 ABI_CHECK(callContractFunction("reenc(" + arrayType + ",uint256,uint256,uint256)", 0x80, i, j, k, encoding), encodeArgs(data[i][j][k]));
2259 }
2260 ABI_CHECK(callContractFunction("test(" + arrayType + ",uint256,uint256,uint256)", 0x80, i, j, data[i][j].size(), encoding), panicData(PanicCode::ArrayOutOfBounds));
2261 }
2262 ABI_CHECK(callContractFunction("test(" + arrayType + ",uint256,uint256)", 0x60, i, data[i].size(), encoding), panicData(PanicCode::ArrayOutOfBounds));
2263 }
2264 ABI_CHECK(callContractFunction("test(" + arrayType + ",uint256)", 0x40, data.size(), encoding), panicData(PanicCode::ArrayOutOfBounds));
2265 }
2266 }
2267
BOOST_AUTO_TEST_CASE(literal_strings)2268 BOOST_AUTO_TEST_CASE(literal_strings)
2269 {
2270 char const* sourceCode = R"(
2271 contract Test {
2272 string public long;
2273 string public medium;
2274 string public short;
2275 string public empty;
2276 function f() public returns (string memory) {
2277 long = "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789001234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678900123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789001234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890";
2278 medium = "01234567890123456789012345678901234567890123456789012345678901234567890123456789";
2279 short = "123";
2280 empty = "";
2281 return "Hello, World!";
2282 }
2283 }
2284 )";
2285 compileAndRun(sourceCode, 0, "Test");
2286 string longStr = "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789001234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678900123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789001234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890";
2287 string medium = "01234567890123456789012345678901234567890123456789012345678901234567890123456789";
2288 string shortStr = "123";
2289 string hello = "Hello, World!";
2290
2291 ABI_CHECK(callContractFunction("f()"), encodeDyn(hello));
2292 ABI_CHECK(callContractFunction("long()"), encodeDyn(longStr));
2293 ABI_CHECK(callContractFunction("medium()"), encodeDyn(medium));
2294 ABI_CHECK(callContractFunction("short()"), encodeDyn(shortStr));
2295 ABI_CHECK(callContractFunction("empty()"), encodeDyn(string()));
2296 }
2297
BOOST_AUTO_TEST_CASE(initialise_string_constant)2298 BOOST_AUTO_TEST_CASE(initialise_string_constant)
2299 {
2300 char const* sourceCode = R"(
2301 contract Test {
2302 string public short = "abcdef";
2303 string public long = "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789001234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678900123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789001234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890";
2304 }
2305 )";
2306 compileAndRun(sourceCode, 0, "Test");
2307 string longStr = "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789001234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678900123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789001234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890";
2308 string shortStr = "abcdef";
2309
2310 ABI_CHECK(callContractFunction("long()"), encodeDyn(longStr));
2311 ABI_CHECK(callContractFunction("short()"), encodeDyn(shortStr));
2312 }
2313
BOOST_AUTO_TEST_CASE(string_as_mapping_key)2314 BOOST_AUTO_TEST_CASE(string_as_mapping_key)
2315 {
2316 char const* sourceCode = R"(
2317 contract Test {
2318 mapping(string => uint) data;
2319 function set(string memory _s, uint _v) public { data[_s] = _v; }
2320 function get(string memory _s) public returns (uint) { return data[_s]; }
2321 }
2322 )";
2323
2324 vector<string> strings{
2325 "Hello, World!",
2326 "Hello, World!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!1111",
2327 "",
2328 "1"
2329 };
2330
2331 ALSO_VIA_YUL(
2332 DISABLE_EWASM_TESTRUN()
2333
2334 compileAndRun(sourceCode, 0, "Test");
2335 for (unsigned i = 0; i < strings.size(); i++)
2336 ABI_CHECK(callContractFunction(
2337 "set(string,uint256)",
2338 u256(0x40),
2339 u256(7 + i),
2340 u256(strings[i].size()),
2341 strings[i]
2342 ), encodeArgs());
2343 for (unsigned i = 0; i < strings.size(); i++)
2344 ABI_CHECK(callContractFunction(
2345 "get(string)",
2346 u256(0x20),
2347 u256(strings[i].size()),
2348 strings[i]
2349 ), encodeArgs(u256(7 + i)));
2350 )
2351 }
2352
BOOST_AUTO_TEST_CASE(string_as_public_mapping_key)2353 BOOST_AUTO_TEST_CASE(string_as_public_mapping_key)
2354 {
2355 char const* sourceCode = R"(
2356 contract Test {
2357 mapping(string => uint) public data;
2358 function set(string memory _s, uint _v) public { data[_s] = _v; }
2359 }
2360 )";
2361 compileAndRun(sourceCode, 0, "Test");
2362 vector<string> strings{
2363 "Hello, World!",
2364 "Hello, World!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!1111",
2365 "",
2366 "1"
2367 };
2368 for (unsigned i = 0; i < strings.size(); i++)
2369 ABI_CHECK(callContractFunction(
2370 "set(string,uint256)",
2371 u256(0x40),
2372 u256(7 + i),
2373 u256(strings[i].size()),
2374 strings[i]
2375 ), encodeArgs());
2376 for (unsigned i = 0; i < strings.size(); i++)
2377 ABI_CHECK(callContractFunction(
2378 "data(string)",
2379 u256(0x20),
2380 u256(strings[i].size()),
2381 strings[i]
2382 ), encodeArgs(u256(7 + i)));
2383 }
2384
BOOST_AUTO_TEST_CASE(nested_string_as_public_mapping_key)2385 BOOST_AUTO_TEST_CASE(nested_string_as_public_mapping_key)
2386 {
2387 char const* sourceCode = R"(
2388 contract Test {
2389 mapping(string => mapping(string => uint)) public data;
2390 function set(string memory _s, string memory _s2, uint _v) public {
2391 data[_s][_s2] = _v; }
2392 }
2393 )";
2394 compileAndRun(sourceCode, 0, "Test");
2395 vector<string> strings{
2396 "Hello, World!",
2397 "Hello, World!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!1111",
2398 "",
2399 "1",
2400 "last one"
2401 };
2402 for (unsigned i = 0; i + 1 < strings.size(); i++)
2403 ABI_CHECK(callContractFunction(
2404 "set(string,string,uint256)",
2405 u256(0x60),
2406 u256(roundTo32(static_cast<unsigned>(0x80 + strings[i].size()))),
2407 u256(7 + i),
2408 u256(strings[i].size()),
2409 strings[i],
2410 u256(strings[i+1].size()),
2411 strings[i+1]
2412 ), encodeArgs());
2413 for (unsigned i = 0; i + 1 < strings.size(); i++)
2414 ABI_CHECK(callContractFunction(
2415 "data(string,string)",
2416 u256(0x40),
2417 u256(roundTo32(static_cast<unsigned>(0x60 + strings[i].size()))),
2418 u256(strings[i].size()),
2419 strings[i],
2420 u256(strings[i+1].size()),
2421 strings[i+1]
2422 ), encodeArgs(u256(7 + i)));
2423 }
2424
BOOST_AUTO_TEST_CASE(nested_mixed_string_as_public_mapping_key)2425 BOOST_AUTO_TEST_CASE(nested_mixed_string_as_public_mapping_key)
2426 {
2427 char const* sourceCode = R"(
2428 contract Test {
2429 mapping(string =>
2430 mapping(int =>
2431 mapping(address =>
2432 mapping(bytes => int)))) public data;
2433
2434 function set(
2435 string memory _s1,
2436 int _s2,
2437 address _s3,
2438 bytes memory _s4,
2439 int _value
2440 ) public
2441 {
2442 data[_s1][_s2][_s3][_s4] = _value;
2443 }
2444 }
2445 )";
2446 compileAndRun(sourceCode, 0, "Test");
2447
2448 struct Index
2449 {
2450 string s1;
2451 int s2;
2452 int s3;
2453 string s4;
2454 };
2455
2456 vector<Index> data{
2457 { "aabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcbc", 4, 23, "efg" },
2458 { "tiaron", 456, 63245, "908apzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapz" },
2459 { "", 2345, 12934, "665i65i65i65i65i65i65i65i65i65i65i65i65i65i65i65i65i65i5iart" },
2460 { "¡¿…", 9781, 8148, "" },
2461 { "ρν♀♀ω₂₃♀", 929608, 303030, "" }
2462 };
2463
2464 for (size_t i = 0; i + 1 < data.size(); i++)
2465 ABI_CHECK(callContractFunction(
2466 "set(string,int256,address,bytes,int256)",
2467 u256(0xA0),
2468 u256(data[i].s2),
2469 u256(data[i].s3),
2470 u256(roundTo32(static_cast<unsigned>(0xC0 + data[i].s1.size()))),
2471 u256(i - 3),
2472 u256(data[i].s1.size()),
2473 data[i].s1,
2474 u256(data[i].s4.size()),
2475 data[i].s4
2476 ), encodeArgs());
2477 for (size_t i = 0; i + 1 < data.size(); i++)
2478 ABI_CHECK(callContractFunction(
2479 "data(string,int256,address,bytes)",
2480 u256(0x80),
2481 u256(data[i].s2),
2482 u256(data[i].s3),
2483 u256(roundTo32(static_cast<unsigned>(0xA0 + data[i].s1.size()))),
2484 u256(data[i].s1.size()),
2485 data[i].s1,
2486 u256(data[i].s4.size()),
2487 data[i].s4
2488 ), encodeArgs(u256(i - 3)));
2489 }
2490
BOOST_AUTO_TEST_CASE(library_call)2491 BOOST_AUTO_TEST_CASE(library_call)
2492 {
2493 char const* sourceCode = R"(
2494 library Lib { function m(uint x, uint y) public returns (uint) { return x * y; } }
2495 contract Test {
2496 function f(uint x) public returns (uint) {
2497 return Lib.m(x, 9);
2498 }
2499 }
2500 )";
2501 ALSO_VIA_YUL(
2502 DISABLE_EWASM_TESTRUN()
2503 compileAndRun(sourceCode, 0, "Lib");
2504 compileAndRun(sourceCode, 0, "Test", bytes(), map<string, h160>{{":Lib", m_contractAddress}});
2505 ABI_CHECK(callContractFunction("f(uint256)", u256(33)), encodeArgs(u256(33) * 9));
2506 )
2507 }
2508
BOOST_AUTO_TEST_CASE(library_function_external)2509 BOOST_AUTO_TEST_CASE(library_function_external)
2510 {
2511 char const* sourceCode = R"(
2512 library Lib { function m(bytes calldata b) external pure returns (bytes1) { return b[2]; } }
2513 contract Test {
2514 function f(bytes memory b) public pure returns (bytes1) {
2515 return Lib.m(b);
2516 }
2517 }
2518 )";
2519 ALSO_VIA_YUL(
2520 DISABLE_EWASM_TESTRUN()
2521 compileAndRun(sourceCode, 0, "Lib");
2522 compileAndRun(sourceCode, 0, "Test", bytes(), map<string, h160>{{":Lib", m_contractAddress}});
2523 ABI_CHECK(callContractFunction("f(bytes)", u256(0x20), u256(5), "abcde"), encodeArgs("c"));
2524 )
2525 }
2526
BOOST_AUTO_TEST_CASE(using_library_mappings_external)2527 BOOST_AUTO_TEST_CASE(using_library_mappings_external)
2528 {
2529 char const* libSourceCode = R"(
2530 library Lib {
2531 function set(mapping(uint => uint) storage m, uint key, uint value) external
2532 {
2533 m[key] = value * 2;
2534 }
2535 }
2536 )";
2537 char const* sourceCode = R"(
2538 library Lib {
2539 function set(mapping(uint => uint) storage m, uint key, uint value) external {}
2540 }
2541 contract Test {
2542 mapping(uint => uint) m1;
2543 mapping(uint => uint) m2;
2544 function f() public returns (uint, uint, uint, uint, uint, uint)
2545 {
2546 Lib.set(m1, 0, 1);
2547 Lib.set(m1, 2, 42);
2548 Lib.set(m2, 0, 23);
2549 Lib.set(m2, 2, 99);
2550 return (m1[0], m1[1], m1[2], m2[0], m2[1], m2[2]);
2551 }
2552 }
2553 )";
2554 for (auto v2: {false, true})
2555 {
2556 string prefix = "pragma abicoder " + string(v2 ? "v2" : "v1") + ";\n";
2557 compileAndRun(prefix + libSourceCode, 0, "Lib");
2558 compileAndRun(prefix + sourceCode, 0, "Test", bytes(), map<string, h160>{{":Lib", m_contractAddress}});
2559 ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(2), u256(0), u256(84), u256(46), u256(0), u256(198)));
2560 }
2561 }
2562
BOOST_AUTO_TEST_CASE(short_strings)2563 BOOST_AUTO_TEST_CASE(short_strings)
2564 {
2565 // This test verifies that the byte array encoding that combines length and data works
2566 // correctly.
2567 char const* sourceCode = R"(
2568 contract A {
2569 bytes public data1 = "123";
2570 bytes data2;
2571 function lengthChange() public returns (uint)
2572 {
2573 // store constant in short and long string
2574 data1 = "123";
2575 if (!equal(data1, "123")) return 1;
2576 data2 = "12345678901234567890123456789012345678901234567890a";
2577 if (data2[17] != "8") return 3;
2578 if (data2.length != 51) return 4;
2579 if (data2[data2.length - 1] != "a") return 5;
2580 // change length: short -> short
2581 while (data1.length < 5)
2582 data1.push();
2583 if (data1.length != 5) return 6;
2584 data1[4] = "4";
2585 if (data1[0] != "1") return 7;
2586 if (data1[4] != "4") return 8;
2587 // change length: short -> long
2588 while (data1.length < 80)
2589 data1.push();
2590 if (data1.length != 80) return 9;
2591 while (data1.length > 70)
2592 data1.pop();
2593 if (data1.length != 70) return 9;
2594 if (data1[0] != "1") return 10;
2595 if (data1[4] != "4") return 11;
2596 for (uint i = 0; i < data1.length; i ++)
2597 data1[i] = bytes1(uint8(i * 3));
2598 if (uint8(data1[4]) != 4 * 3) return 12;
2599 if (uint8(data1[67]) != 67 * 3) return 13;
2600 // change length: long -> short
2601 while (data1.length > 22)
2602 data1.pop();
2603 if (data1.length != 22) return 14;
2604 if (uint8(data1[21]) != 21 * 3) return 15;
2605 if (uint8(data1[2]) != 2 * 3) return 16;
2606 // change length: short -> shorter
2607 while (data1.length > 19)
2608 data1.pop();
2609 if (data1.length != 19) return 17;
2610 if (uint8(data1[7]) != 7 * 3) return 18;
2611 // and now again to original size
2612 while (data1.length < 22)
2613 data1.push();
2614 if (data1.length != 22) return 19;
2615 if (data1[21] != 0) return 20;
2616 while (data1.length > 0)
2617 data1.pop();
2618 while (data2.length > 0)
2619 data2.pop();
2620 }
2621 function copy() public returns (uint) {
2622 bytes memory x = "123";
2623 bytes memory y = "012345678901234567890123456789012345678901234567890123456789";
2624 bytes memory z = "1234567";
2625 data1 = x;
2626 data2 = y;
2627 if (!equal(data1, x)) return 1;
2628 if (!equal(data2, y)) return 2;
2629 // lengthen
2630 data1 = y;
2631 if (!equal(data1, y)) return 3;
2632 // shorten
2633 data1 = x;
2634 if (!equal(data1, x)) return 4;
2635 // change while keeping short
2636 data1 = z;
2637 if (!equal(data1, z)) return 5;
2638 // copy storage -> storage
2639 data1 = x;
2640 data2 = y;
2641 // lengthen
2642 data1 = data2;
2643 if (!equal(data1, y)) return 6;
2644 // shorten
2645 data1 = x;
2646 data2 = data1;
2647 if (!equal(data2, x)) return 7;
2648 bytes memory c = data2;
2649 data1 = c;
2650 if (!equal(data1, x)) return 8;
2651 data1 = "";
2652 data2 = "";
2653 }
2654 function deleteElements() public returns (uint) {
2655 data1 = "01234";
2656 delete data1[2];
2657 if (data1[2] != 0) return 1;
2658 if (data1[0] != "0") return 2;
2659 if (data1[3] != "3") return 3;
2660 delete data1;
2661 if (data1.length != 0) return 4;
2662 }
2663
2664 function equal(bytes storage a, bytes memory b) internal returns (bool) {
2665 if (a.length != b.length) return false;
2666 for (uint i = 0; i < a.length; ++i) if (a[i] != b[i]) return false;
2667 return true;
2668 }
2669 }
2670 )";
2671 ALSO_VIA_YUL(
2672 DISABLE_EWASM_TESTRUN()
2673 compileAndRun(sourceCode, 0, "A");
2674 ABI_CHECK(callContractFunction("data1()"), encodeDyn(string("123")));
2675 ABI_CHECK(callContractFunction("lengthChange()"), encodeArgs(u256(0)));
2676 BOOST_CHECK(storageEmpty(m_contractAddress));
2677 ABI_CHECK(callContractFunction("deleteElements()"), encodeArgs(u256(0)));
2678 BOOST_CHECK(storageEmpty(m_contractAddress));
2679 ABI_CHECK(callContractFunction("copy()"), encodeArgs(u256(0)));
2680 BOOST_CHECK(storageEmpty(m_contractAddress));
2681 )
2682 }
2683
BOOST_AUTO_TEST_CASE(calldata_offset)2684 BOOST_AUTO_TEST_CASE(calldata_offset)
2685 {
2686 // This tests a specific bug that was caused by not using the correct memory offset in the
2687 // calldata unpacker.
2688 char const* sourceCode = R"(
2689 contract CB
2690 {
2691 address[] _arr;
2692 string public last = "nd";
2693 constructor(address[] memory guardians)
2694 {
2695 _arr = guardians;
2696 }
2697 }
2698 )";
2699 compileAndRun(sourceCode, 0, "CB", encodeArgs(u256(0x20), u256(0x00)));
2700 ABI_CHECK(callContractFunction("last()", encodeArgs()), encodeDyn(string("nd")));
2701 }
2702
BOOST_AUTO_TEST_CASE(reject_ether_sent_to_library)2703 BOOST_AUTO_TEST_CASE(reject_ether_sent_to_library)
2704 {
2705 char const* sourceCode = R"(
2706 library lib {}
2707 contract c {
2708 constructor() payable {}
2709 function f(address payable x) public returns (bool) {
2710 return x.send(1);
2711 }
2712 receive () external payable {}
2713 }
2714 )";
2715 ALSO_VIA_YUL(
2716 DISABLE_EWASM_TESTRUN()
2717 compileAndRun(sourceCode, 0, "lib");
2718 Address libraryAddress = m_contractAddress;
2719 compileAndRun(sourceCode, 10, "c");
2720 BOOST_CHECK_EQUAL(balanceAt(m_contractAddress), 10);
2721 BOOST_CHECK_EQUAL(balanceAt(libraryAddress), 0);
2722 ABI_CHECK(callContractFunction("f(address)", encodeArgs(libraryAddress)), encodeArgs(false));
2723 BOOST_CHECK_EQUAL(balanceAt(m_contractAddress), 10);
2724 BOOST_CHECK_EQUAL(balanceAt(libraryAddress), 0);
2725 ABI_CHECK(callContractFunction("f(address)", encodeArgs(m_contractAddress)), encodeArgs(true));
2726 BOOST_CHECK_EQUAL(balanceAt(m_contractAddress), 10);
2727 BOOST_CHECK_EQUAL(balanceAt(libraryAddress), 0);
2728 )
2729 }
2730
BOOST_AUTO_TEST_CASE(create_memory_array_allocation_size)2731 BOOST_AUTO_TEST_CASE(create_memory_array_allocation_size)
2732 {
2733 // Check allocation size of byte array. Should be 32 plus length rounded up to next
2734 // multiple of 32
2735 char const* sourceCode = R"(
2736 contract C {
2737 function f() public pure returns (uint d1, uint d2, uint d3, uint memsize) {
2738 bytes memory b1 = new bytes(31);
2739 bytes memory b2 = new bytes(32);
2740 bytes memory b3 = new bytes(256);
2741 bytes memory b4 = new bytes(31);
2742 assembly {
2743 d1 := sub(b2, b1)
2744 d2 := sub(b3, b2)
2745 d3 := sub(b4, b3)
2746 memsize := msize()
2747 }
2748 }
2749 }
2750 )";
2751 if (!m_optimiserSettings.runYulOptimiser)
2752 {
2753 compileAndRun(sourceCode);
2754 ABI_CHECK(callContractFunction("f()"), encodeArgs(0x40, 0x40, 0x20 + 256, 0x260));
2755 }
2756 }
2757
BOOST_AUTO_TEST_CASE(inline_long_string_return)2758 BOOST_AUTO_TEST_CASE(inline_long_string_return)
2759 {
2760 char const* sourceCode = R"(
2761 contract C {
2762 function f() public returns (string memory) {
2763 return (["somethingShort", "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789001234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678900123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789001234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"][1]);
2764 }
2765 }
2766 )";
2767
2768 string strLong = "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789001234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678900123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789001234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890";
2769 compileAndRun(sourceCode, 0, "C");
2770 ABI_CHECK(callContractFunction("f()"), encodeDyn(strLong));
2771 }
2772
BOOST_AUTO_TEST_CASE(index_access_with_type_conversion)2773 BOOST_AUTO_TEST_CASE(index_access_with_type_conversion)
2774 {
2775 // Test for a bug where higher order bits cleanup was not done for array index access.
2776 char const* sourceCode = R"(
2777 contract C {
2778 function f(uint x) public returns (uint[256] memory r){
2779 r[uint8(x)] = 2;
2780 }
2781 }
2782 )";
2783 compileAndRun(sourceCode, 0, "C");
2784 // neither of the two should throw due to out-of-bounds access
2785 BOOST_CHECK(callContractFunction("f(uint256)", u256(0x01)).size() == 256 * 32);
2786 BOOST_CHECK(callContractFunction("f(uint256)", u256(0x101)).size() == 256 * 32);
2787 }
2788
BOOST_AUTO_TEST_CASE(correctly_initialize_memory_array_in_constructor)2789 BOOST_AUTO_TEST_CASE(correctly_initialize_memory_array_in_constructor)
2790 {
2791 // Memory arrays are initialized using calldatacopy past the size of the calldata.
2792 // This test checks that it also works in the constructor context.
2793 char const* sourceCode = R"(
2794 contract C {
2795 bool public success;
2796 constructor() {
2797 // Make memory dirty.
2798 assembly {
2799 for { let i := 0 } lt(i, 64) { i := add(i, 1) } {
2800 mstore(msize(), not(0))
2801 }
2802 }
2803 uint16[3] memory c;
2804 require(c[0] == 0 && c[1] == 0 && c[2] == 0);
2805 uint16[] memory x = new uint16[](3);
2806 require(x[0] == 0 && x[1] == 0 && x[2] == 0);
2807 success = true;
2808 }
2809 }
2810 )";
2811 // Cannot run against yul optimizer because of msize
2812 if (!m_optimiserSettings.runYulOptimiser)
2813 {
2814 compileAndRun(sourceCode, 0, "C");
2815 ABI_CHECK(callContractFunction("success()"), encodeArgs(u256(1)));
2816 }
2817 }
2818
BOOST_AUTO_TEST_CASE(mutex)2819 BOOST_AUTO_TEST_CASE(mutex)
2820 {
2821 char const* sourceCode = R"(
2822 contract mutexed {
2823 bool locked;
2824 modifier protected {
2825 if (locked) revert();
2826 locked = true;
2827 _;
2828 locked = false;
2829 }
2830 }
2831 contract Fund is mutexed {
2832 uint shares;
2833 constructor() payable { shares = msg.value; }
2834 function withdraw(uint amount) public protected returns (uint) {
2835 // NOTE: It is very bad practice to write this function this way.
2836 // Please refer to the documentation of how to do this properly.
2837 if (amount > shares) revert();
2838 (bool success,) = msg.sender.call{value: amount}("");
2839 require(success);
2840 shares -= amount;
2841 return shares;
2842 }
2843 function withdrawUnprotected(uint amount) public returns (uint) {
2844 // NOTE: It is very bad practice to write this function this way.
2845 // Please refer to the documentation of how to do this properly.
2846 if (amount > shares) revert();
2847 (bool success,) = msg.sender.call{value: amount}("");
2848 require(success);
2849 shares -= amount;
2850 return shares;
2851 }
2852 }
2853 contract Attacker {
2854 Fund public fund;
2855 uint callDepth;
2856 bool protected;
2857 function setProtected(bool _protected) public { protected = _protected; }
2858 constructor(Fund _fund) { fund = _fund; }
2859 function attack() public returns (uint) {
2860 callDepth = 0;
2861 return attackInternal();
2862 }
2863 function attackInternal() internal returns (uint) {
2864 if (protected)
2865 return fund.withdraw(10);
2866 else
2867 return fund.withdrawUnprotected(10);
2868 }
2869 fallback() external payable {
2870 callDepth++;
2871 if (callDepth < 4)
2872 attackInternal();
2873 }
2874 }
2875 )";
2876 compileAndRun(sourceCode, 500, "Fund");
2877 h160 const fund = m_contractAddress;
2878 BOOST_CHECK_EQUAL(balanceAt(fund), 500);
2879 compileAndRun(sourceCode, 0, "Attacker", encodeArgs(fund));
2880 ABI_CHECK(callContractFunction("setProtected(bool)", true), encodeArgs());
2881 ABI_CHECK(callContractFunction("attack()"), encodeArgs());
2882 BOOST_CHECK_EQUAL(balanceAt(fund), 500);
2883 ABI_CHECK(callContractFunction("setProtected(bool)", false), encodeArgs());
2884 ABI_CHECK(callContractFunction("attack()"), encodeArgs(u256(460)));
2885 BOOST_CHECK_EQUAL(balanceAt(fund), 460);
2886 }
2887
BOOST_AUTO_TEST_CASE(payable_function)2888 BOOST_AUTO_TEST_CASE(payable_function)
2889 {
2890 char const* sourceCode = R"(
2891 contract C {
2892 uint public a;
2893 function f() payable public returns (uint) {
2894 return msg.value;
2895 }
2896 fallback() external payable {
2897 a = msg.value + 1;
2898 }
2899 }
2900 )";
2901 compileAndRun(sourceCode, 0, "C");
2902 ABI_CHECK(callContractFunctionWithValue("f()", 27), encodeArgs(u256(27)));
2903 BOOST_CHECK_EQUAL(balanceAt(m_contractAddress), 27);
2904 ABI_CHECK(callContractFunctionWithValue("", 27), encodeArgs());
2905 BOOST_CHECK_EQUAL(balanceAt(m_contractAddress), 27 + 27);
2906 ABI_CHECK(callContractFunction("a()"), encodeArgs(u256(28)));
2907 BOOST_CHECK_EQUAL(balanceAt(m_contractAddress), 27 + 27);
2908 }
2909
BOOST_AUTO_TEST_CASE(non_payable_throw)2910 BOOST_AUTO_TEST_CASE(non_payable_throw)
2911 {
2912 char const* sourceCode = R"(
2913 contract C {
2914 uint public a;
2915 function f() public returns (uint) {
2916 return msgvalue();
2917 }
2918 function msgvalue() internal returns (uint) {
2919 return msg.value;
2920 }
2921 fallback() external {
2922 update();
2923 }
2924 function update() internal {
2925 a = msg.value + 1;
2926 }
2927
2928 }
2929 )";
2930 ALSO_VIA_YUL(
2931 DISABLE_EWASM_TESTRUN()
2932 compileAndRun(sourceCode, 0, "C");
2933 ABI_CHECK(callContractFunctionWithValue("f()", 27), encodeArgs());
2934 BOOST_CHECK_EQUAL(balanceAt(m_contractAddress), 0);
2935 ABI_CHECK(callContractFunction(""), encodeArgs());
2936 ABI_CHECK(callContractFunction("a()"), encodeArgs(u256(1)));
2937 ABI_CHECK(callContractFunctionWithValue("", 27), encodeArgs());
2938 BOOST_CHECK_EQUAL(balanceAt(m_contractAddress), 0);
2939 ABI_CHECK(callContractFunction("a()"), encodeArgs(u256(1)));
2940 ABI_CHECK(callContractFunctionWithValue("a()", 27), encodeArgs());
2941 BOOST_CHECK_EQUAL(balanceAt(m_contractAddress), 0);
2942 )
2943 }
2944
BOOST_AUTO_TEST_CASE(mem_resize_is_not_paid_at_call)2945 BOOST_AUTO_TEST_CASE(mem_resize_is_not_paid_at_call)
2946 {
2947 // This tests that memory resize for return values is not paid during the call, which would
2948 // make the gas calculation overly complex. We access the end of the output area before
2949 // the call is made.
2950 // Tests that this also survives the optimizer.
2951 char const* sourceCode = R"(
2952 contract C {
2953 function f() public returns (uint[200] memory) {}
2954 }
2955 contract D {
2956 function f(C c) public returns (uint) { c.f(); return 7; }
2957 }
2958 )";
2959
2960 compileAndRun(sourceCode, 0, "C");
2961 h160 const cAddr = m_contractAddress;
2962 compileAndRun(sourceCode, 0, "D");
2963 ABI_CHECK(callContractFunction("f(address)", cAddr), encodeArgs(u256(7)));
2964 }
2965
BOOST_AUTO_TEST_CASE(receive_external_function_type)2966 BOOST_AUTO_TEST_CASE(receive_external_function_type)
2967 {
2968 char const* sourceCode = R"(
2969 contract C {
2970 function g() public returns (uint) { return 7; }
2971 function f(function() external returns (uint) g) public returns (uint) {
2972 return g();
2973 }
2974 }
2975 )";
2976
2977 ALSO_VIA_YUL(
2978 DISABLE_EWASM_TESTRUN()
2979 compileAndRun(sourceCode, 0, "C");
2980 ABI_CHECK(callContractFunction(
2981 "f(function)",
2982 m_contractAddress.asBytes() + FixedHash<4>(util::keccak256("g()")).asBytes() + bytes(32 - 4 - 20, 0)
2983 ), encodeArgs(u256(7)));
2984 )
2985 }
2986
BOOST_AUTO_TEST_CASE(return_external_function_type)2987 BOOST_AUTO_TEST_CASE(return_external_function_type)
2988 {
2989 char const* sourceCode = R"(
2990 contract C {
2991 function g() public {}
2992 function f() public returns (function() external) {
2993 return this.g;
2994 }
2995 }
2996 )";
2997
2998 compileAndRun(sourceCode, 0, "C");
2999 ABI_CHECK(
3000 callContractFunction("f()"),
3001 m_contractAddress.asBytes() + FixedHash<4>(util::keccak256("g()")).asBytes() + bytes(32 - 4 - 20, 0)
3002 );
3003 }
3004
3005 // TODO: store bound internal library functions
3006
BOOST_AUTO_TEST_CASE(shift_bytes)3007 BOOST_AUTO_TEST_CASE(shift_bytes)
3008 {
3009 char const* sourceCode = R"(
3010 contract C {
3011 function left(bytes20 x, uint8 y) public returns (bytes20) {
3012 return x << y;
3013 }
3014 function right(bytes20 x, uint8 y) public returns (bytes20) {
3015 return x >> y;
3016 }
3017 }
3018 )";
3019 compileAndRun(sourceCode, 0, "C");
3020 ABI_CHECK(callContractFunction("left(bytes20,uint8)", "12345678901234567890", 8 * 8), encodeArgs("901234567890" + string(8, 0)));
3021 ABI_CHECK(callContractFunction("right(bytes20,uint8)", "12345678901234567890", 8 * 8), encodeArgs(string(8, 0) + "123456789012"));
3022 }
3023
BOOST_AUTO_TEST_CASE(contracts_separated_with_comment)3024 BOOST_AUTO_TEST_CASE(contracts_separated_with_comment)
3025 {
3026 char const* sourceCode = R"(
3027 contract C1 {}
3028 /**
3029 **/
3030 contract C2 {}
3031 )";
3032 ALSO_VIA_YUL(
3033 DISABLE_EWASM_TESTRUN()
3034
3035 compileAndRun(sourceCode, 0, "C1");
3036 compileAndRun(sourceCode, 0, "C2");
3037 )
3038 }
3039
BOOST_AUTO_TEST_CASE(include_creation_bytecode_only_once)3040 BOOST_AUTO_TEST_CASE(include_creation_bytecode_only_once)
3041 {
3042 char const* sourceCode = R"(
3043 contract D {
3044 bytes a = hex"1237651237125387136581271652831736512837126583171583712358126123765123712538713658127165283173651283712658317158371235812612376512371253871365812716528317365128371265831715837123581261237651237125387136581271652831736512837126583171583712358126";
3045 bytes b = hex"1237651237125327136581271252831736512837126583171383712358126123765125712538713658127165253173651283712658357158371235812612376512371a5387136581271652a317365128371265a317158371235812612a765123712538a13658127165a83173651283712a58317158371235a126";
3046 constructor(uint) {}
3047 }
3048 contract Double {
3049 function f() public {
3050 new D(2);
3051 }
3052 function g() public {
3053 new D(3);
3054 }
3055 }
3056 contract Single {
3057 function f() public {
3058 new D(2);
3059 }
3060 }
3061 )";
3062 compileAndRun(sourceCode);
3063 BOOST_CHECK_LE(
3064 double(m_compiler.object("Double").bytecode.size()),
3065 1.2 * double(m_compiler.object("Single").bytecode.size())
3066 );
3067 }
3068
BOOST_AUTO_TEST_CASE(revert_with_cause)3069 BOOST_AUTO_TEST_CASE(revert_with_cause)
3070 {
3071 char const* sourceCode = R"(
3072 contract D {
3073 string constant msg1 = "test1234567890123456789012345678901234567890";
3074 string msg2 = "test1234567890123456789012345678901234567890";
3075 function f() public {
3076 revert("test123");
3077 }
3078 function g() public {
3079 revert("test1234567890123456789012345678901234567890");
3080 }
3081 function h() public {
3082 revert(msg1);
3083 }
3084 function i() public {
3085 revert(msg2);
3086 }
3087 function j() public {
3088 string memory msg3 = "test1234567890123456789012345678901234567890";
3089 revert(msg3);
3090 }
3091 }
3092 contract C {
3093 D d = new D();
3094 function forward(address target, bytes memory data) internal returns (bool success, bytes memory retval) {
3095 uint retsize;
3096 assembly {
3097 success := call(not(0), target, 0, add(data, 0x20), mload(data), 0, 0)
3098 retsize := returndatasize()
3099 }
3100 retval = new bytes(retsize);
3101 assembly {
3102 returndatacopy(add(retval, 0x20), 0, returndatasize())
3103 }
3104 }
3105 function f() public returns (bool, bytes memory) {
3106 return forward(address(d), msg.data);
3107 }
3108 function g() public returns (bool, bytes memory) {
3109 return forward(address(d), msg.data);
3110 }
3111 function h() public returns (bool, bytes memory) {
3112 return forward(address(d), msg.data);
3113 }
3114 function i() public returns (bool, bytes memory) {
3115 return forward(address(d), msg.data);
3116 }
3117 function j() public returns (bool, bytes memory) {
3118 return forward(address(d), msg.data);
3119 }
3120 }
3121 )";
3122 if (solidity::test::CommonOptions::get().evmVersion().supportsReturndata())
3123 {
3124 compileAndRun(sourceCode, 0, "C");
3125 bytes const errorSignature = bytes{0x08, 0xc3, 0x79, 0xa0};
3126 ABI_CHECK(callContractFunction("f()"), encodeArgs(0, 0x40, 0x64) + errorSignature + encodeArgs(0x20, 7, "test123") + bytes(28, 0));
3127 ABI_CHECK(callContractFunction("g()"), encodeArgs(0, 0x40, 0x84) + errorSignature + encodeArgs(0x20, 44, "test1234567890123456789012345678901234567890") + bytes(28, 0));
3128 ABI_CHECK(callContractFunction("h()"), encodeArgs(0, 0x40, 0x84) + errorSignature + encodeArgs(0x20, 44, "test1234567890123456789012345678901234567890") + bytes(28, 0));
3129 ABI_CHECK(callContractFunction("i()"), encodeArgs(0, 0x40, 0x84) + errorSignature + encodeArgs(0x20, 44, "test1234567890123456789012345678901234567890") + bytes(28, 0));
3130 ABI_CHECK(callContractFunction("j()"), encodeArgs(0, 0x40, 0x84) + errorSignature + encodeArgs(0x20, 44, "test1234567890123456789012345678901234567890") + bytes(28, 0));
3131 }
3132 }
3133
BOOST_AUTO_TEST_CASE(require_with_message)3134 BOOST_AUTO_TEST_CASE(require_with_message)
3135 {
3136 char const* sourceCode = R"(
3137 contract D {
3138 bool flag = false;
3139 string storageError = "abc";
3140 string constant constantError = "abc";
3141 function f(uint x) public {
3142 require(x > 7, "failed");
3143 }
3144 function g() public {
3145 // As a side-effect of internalFun, the flag will be set to true
3146 // (even if the condition is true),
3147 // but it will only throw in the next evaluation.
3148 bool flagCopy = flag;
3149 require(flagCopy == false, internalFun());
3150 }
3151 function internalFun() public returns (string memory) {
3152 flag = true;
3153 return "only on second run";
3154 }
3155 function h() public {
3156 require(false, storageError);
3157 }
3158 function i() public {
3159 require(false, constantError);
3160 }
3161 function j() public {
3162 string memory errMsg = "msg";
3163 require(false, errMsg);
3164 }
3165 }
3166 contract C {
3167 D d = new D();
3168 function forward(address target, bytes memory data) internal returns (bool success, bytes memory retval) {
3169 uint retsize;
3170 assembly {
3171 success := call(not(0), target, 0, add(data, 0x20), mload(data), 0, 0)
3172 retsize := returndatasize()
3173 }
3174 retval = new bytes(retsize);
3175 assembly {
3176 returndatacopy(add(retval, 0x20), 0, returndatasize())
3177 }
3178 }
3179 function f(uint x) public returns (bool, bytes memory) {
3180 return forward(address(d), msg.data);
3181 }
3182 function g() public returns (bool, bytes memory) {
3183 return forward(address(d), msg.data);
3184 }
3185 function h() public returns (bool, bytes memory) {
3186 return forward(address(d), msg.data);
3187 }
3188 function i() public returns (bool, bytes memory) {
3189 return forward(address(d), msg.data);
3190 }
3191 function j() public returns (bool, bytes memory) {
3192 return forward(address(d), msg.data);
3193 }
3194 }
3195 )";
3196 if (solidity::test::CommonOptions::get().evmVersion().supportsReturndata())
3197 {
3198 compileAndRun(sourceCode, 0, "C");
3199 bytes const errorSignature = bytes{0x08, 0xc3, 0x79, 0xa0};
3200 ABI_CHECK(callContractFunction("f(uint256)", 8), encodeArgs(1, 0x40, 0));
3201 ABI_CHECK(callContractFunction("f(uint256)", 5), encodeArgs(0, 0x40, 0x64) + errorSignature + encodeArgs(0x20, 6, "failed") + bytes(28, 0));
3202 ABI_CHECK(callContractFunction("g()"), encodeArgs(1, 0x40, 0));
3203 ABI_CHECK(callContractFunction("g()"), encodeArgs(0, 0x40, 0x64) + errorSignature + encodeArgs(0x20, 18, "only on second run") + bytes(28, 0));
3204 ABI_CHECK(callContractFunction("h()"), encodeArgs(0, 0x40, 0x64) + errorSignature + encodeArgs(0x20, 3, "abc") + bytes(28, 0));
3205 ABI_CHECK(callContractFunction("i()"), encodeArgs(0, 0x40, 0x64) + errorSignature + encodeArgs(0x20, 3, "abc") + bytes(28, 0));
3206 ABI_CHECK(callContractFunction("j()"), encodeArgs(0, 0x40, 0x64) + errorSignature + encodeArgs(0x20, 3, "msg") + bytes(28, 0));
3207 }
3208 }
3209
BOOST_AUTO_TEST_CASE(bubble_up_error_messages)3210 BOOST_AUTO_TEST_CASE(bubble_up_error_messages)
3211 {
3212 char const* sourceCode = R"(
3213 contract D {
3214 function f() public {
3215 revert("message");
3216 }
3217 function g() public {
3218 this.f();
3219 }
3220 }
3221 contract C {
3222 D d = new D();
3223 function forward(address target, bytes memory data) internal returns (bool success, bytes memory retval) {
3224 uint retsize;
3225 assembly {
3226 success := call(not(0), target, 0, add(data, 0x20), mload(data), 0, 0)
3227 retsize := returndatasize()
3228 }
3229 retval = new bytes(retsize);
3230 assembly {
3231 returndatacopy(add(retval, 0x20), 0, returndatasize())
3232 }
3233 }
3234 function f() public returns (bool, bytes memory) {
3235 return forward(address(d), msg.data);
3236 }
3237 function g() public returns (bool, bytes memory) {
3238 return forward(address(d), msg.data);
3239 }
3240 }
3241 )";
3242 if (solidity::test::CommonOptions::get().evmVersion().supportsReturndata())
3243 {
3244 compileAndRun(sourceCode, 0, "C");
3245 bytes const errorSignature = bytes{0x08, 0xc3, 0x79, 0xa0};
3246 ABI_CHECK(callContractFunction("f()"), encodeArgs(0, 0x40, 0x64) + errorSignature + encodeArgs(0x20, 7, "message") + bytes(28, 0));
3247 ABI_CHECK(callContractFunction("g()"), encodeArgs(0, 0x40, 0x64) + errorSignature + encodeArgs(0x20, 7, "message") + bytes(28, 0));
3248 }
3249 }
3250
BOOST_AUTO_TEST_CASE(bubble_up_error_messages_through_transfer)3251 BOOST_AUTO_TEST_CASE(bubble_up_error_messages_through_transfer)
3252 {
3253 char const* sourceCode = R"(
3254 contract D {
3255 receive() external payable {
3256 revert("message");
3257 }
3258 function f() public {
3259 payable(this).transfer(0);
3260 }
3261 }
3262 contract C {
3263 D d = new D();
3264 function forward(address target, bytes memory data) internal returns (bool success, bytes memory retval) {
3265 uint retsize;
3266 assembly {
3267 success := call(not(0), target, 0, add(data, 0x20), mload(data), 0, 0)
3268 retsize := returndatasize()
3269 }
3270 retval = new bytes(retsize);
3271 assembly {
3272 returndatacopy(add(retval, 0x20), 0, returndatasize())
3273 }
3274 }
3275 function f() public returns (bool, bytes memory) {
3276 return forward(address(d), msg.data);
3277 }
3278 }
3279 )";
3280 if (solidity::test::CommonOptions::get().evmVersion().supportsReturndata())
3281 {
3282 compileAndRun(sourceCode, 0, "C");
3283 bytes const errorSignature = bytes{0x08, 0xc3, 0x79, 0xa0};
3284 ABI_CHECK(callContractFunction("f()"), encodeArgs(0, 0x40, 0x64) + errorSignature + encodeArgs(0x20, 7, "message") + bytes(28, 0));
3285 }
3286 }
3287
BOOST_AUTO_TEST_CASE(bubble_up_error_messages_through_create)3288 BOOST_AUTO_TEST_CASE(bubble_up_error_messages_through_create)
3289 {
3290 char const* sourceCode = R"(
3291 contract E {
3292 constructor() {
3293 revert("message");
3294 }
3295 }
3296 contract D {
3297 function f() public {
3298 E x = new E();
3299 }
3300 }
3301 contract C {
3302 D d = new D();
3303 function forward(address target, bytes memory data) internal returns (bool success, bytes memory retval) {
3304 uint retsize;
3305 assembly {
3306 success := call(not(0), target, 0, add(data, 0x20), mload(data), 0, 0)
3307 retsize := returndatasize()
3308 }
3309 retval = new bytes(retsize);
3310 assembly {
3311 returndatacopy(add(retval, 0x20), 0, returndatasize())
3312 }
3313 }
3314 function f() public returns (bool, bytes memory) {
3315 return forward(address(d), msg.data);
3316 }
3317 }
3318 )";
3319 if (solidity::test::CommonOptions::get().evmVersion().supportsReturndata())
3320 {
3321 compileAndRun(sourceCode, 0, "C");
3322 bytes const errorSignature = bytes{0x08, 0xc3, 0x79, 0xa0};
3323 ABI_CHECK(callContractFunction("f()"), encodeArgs(0, 0x40, 0x64) + errorSignature + encodeArgs(0x20, 7, "message") + bytes(28, 0));
3324 }
3325 }
3326
BOOST_AUTO_TEST_CASE(interface_contract)3327 BOOST_AUTO_TEST_CASE(interface_contract)
3328 {
3329 char const* sourceCode = R"(
3330 interface I {
3331 event A();
3332 function f() external returns (bool);
3333 fallback() external payable;
3334 }
3335
3336 contract A is I {
3337 function f() public override returns (bool) {
3338 return g();
3339 }
3340
3341 function g() public returns (bool) {
3342 return true;
3343 }
3344
3345 fallback() override external payable {
3346 }
3347 }
3348
3349 contract C {
3350 function f(address payable _interfaceAddress) public returns (bool) {
3351 I i = I(_interfaceAddress);
3352 return i.f();
3353 }
3354 }
3355 )";
3356 compileAndRun(sourceCode, 0, "A");
3357 h160 const recipient = m_contractAddress;
3358 compileAndRun(sourceCode, 0, "C");
3359 ABI_CHECK(callContractFunction("f(address)", recipient), encodeArgs(true));
3360 }
3361
BOOST_AUTO_TEST_CASE(bare_call_invalid_address)3362 BOOST_AUTO_TEST_CASE(bare_call_invalid_address)
3363 {
3364 char const* sourceCode = R"YY(
3365 contract C {
3366 /// Calling into non-existent account is successful (creates the account)
3367 function f() external returns (bool) {
3368 (bool success,) = address(0x4242).call("");
3369 return success;
3370 }
3371 function h() external returns (bool) {
3372 (bool success,) = address(0x4242).delegatecall("");
3373 return success;
3374 }
3375 }
3376 )YY";
3377 compileAndRun(sourceCode, 0, "C");
3378 ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(1)));
3379 ABI_CHECK(callContractFunction("h()"), encodeArgs(u256(1)));
3380
3381 if (solidity::test::CommonOptions::get().evmVersion().hasStaticCall())
3382 {
3383 char const* sourceCode = R"YY(
3384 contract C {
3385 function f() external returns (bool, bytes memory) {
3386 return address(0x4242).staticcall("");
3387 }
3388 }
3389 )YY";
3390 compileAndRun(sourceCode, 0, "C");
3391 ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(1), 0x40, 0x00));
3392 }
3393 }
3394
BOOST_AUTO_TEST_CASE(bare_call_return_data)3395 BOOST_AUTO_TEST_CASE(bare_call_return_data)
3396 {
3397 if (solidity::test::CommonOptions::get().evmVersion().supportsReturndata())
3398 {
3399 vector<string> calltypes = {"call", "delegatecall"};
3400 if (solidity::test::CommonOptions::get().evmVersion().hasStaticCall())
3401 calltypes.emplace_back("staticcall");
3402 for (string const& calltype: calltypes)
3403 {
3404 string sourceCode = R"DELIMITER(
3405 contract A {
3406 constructor() {
3407 }
3408 function return_bool() public pure returns(bool) {
3409 return true;
3410 }
3411 function return_int32() public pure returns(int32) {
3412 return -32;
3413 }
3414 function return_uint32() public pure returns(uint32) {
3415 return 0x3232;
3416 }
3417 function return_int256() public pure returns(int256) {
3418 return -256;
3419 }
3420 function return_uint256() public pure returns(uint256) {
3421 return 0x256256;
3422 }
3423 function return_bytes4() public pure returns(bytes4) {
3424 return 0xabcd0012;
3425 }
3426 function return_multi() public pure returns(bool, uint32, bytes4) {
3427 return (false, 0x3232, 0xabcd0012);
3428 }
3429 function return_bytes() public pure returns(bytes memory b) {
3430 b = new bytes(2);
3431 b[0] = 0x42;
3432 b[1] = 0x21;
3433 }
3434 }
3435 contract C {
3436 A addr;
3437 constructor() {
3438 addr = new A();
3439 }
3440 function f(string memory signature) public returns (bool, bytes memory) {
3441 return address(addr).)DELIMITER" + calltype + R"DELIMITER((abi.encodeWithSignature(signature));
3442 }
3443 function check_bool() external returns (bool) {
3444 (bool success, bytes memory data) = f("return_bool()");
3445 assert(success);
3446 bool a = abi.decode(data, (bool));
3447 assert(a);
3448 return true;
3449 }
3450 function check_int32() external returns (bool) {
3451 (bool success, bytes memory data) = f("return_int32()");
3452 assert(success);
3453 int32 a = abi.decode(data, (int32));
3454 assert(a == -32);
3455 return true;
3456 }
3457 function check_uint32() external returns (bool) {
3458 (bool success, bytes memory data) = f("return_uint32()");
3459 assert(success);
3460 uint32 a = abi.decode(data, (uint32));
3461 assert(a == 0x3232);
3462 return true;
3463 }
3464 function check_int256() external returns (bool) {
3465 (bool success, bytes memory data) = f("return_int256()");
3466 assert(success);
3467 int256 a = abi.decode(data, (int256));
3468 assert(a == -256);
3469 return true;
3470 }
3471 function check_uint256() external returns (bool) {
3472 (bool success, bytes memory data) = f("return_uint256()");
3473 assert(success);
3474 uint256 a = abi.decode(data, (uint256));
3475 assert(a == 0x256256);
3476 return true;
3477 }
3478 function check_bytes4() external returns (bool) {
3479 (bool success, bytes memory data) = f("return_bytes4()");
3480 assert(success);
3481 bytes4 a = abi.decode(data, (bytes4));
3482 assert(a == 0xabcd0012);
3483 return true;
3484 }
3485 function check_multi() external returns (bool) {
3486 (bool success, bytes memory data) = f("return_multi()");
3487 assert(success);
3488 (bool a, uint32 b, bytes4 c) = abi.decode(data, (bool, uint32, bytes4));
3489 assert(a == false && b == 0x3232 && c == 0xabcd0012);
3490 return true;
3491 }
3492 function check_bytes() external returns (bool) {
3493 (bool success, bytes memory data) = f("return_bytes()");
3494 assert(success);
3495 (bytes memory d) = abi.decode(data, (bytes));
3496 assert(d.length == 2 && d[0] == 0x42 && d[1] == 0x21);
3497 return true;
3498 }
3499 }
3500 )DELIMITER";
3501 ALSO_VIA_YUL(
3502 DISABLE_EWASM_TESTRUN()
3503 compileAndRun(sourceCode, 0, "C");
3504 ABI_CHECK(callContractFunction("f(string)", encodeDyn(string("return_bool()"))), encodeArgs(true, 0x40, 0x20, true));
3505 ABI_CHECK(callContractFunction("f(string)", encodeDyn(string("return_int32()"))), encodeArgs(true, 0x40, 0x20, u256(-32)));
3506 ABI_CHECK(callContractFunction("f(string)", encodeDyn(string("return_uint32()"))), encodeArgs(true, 0x40, 0x20, u256(0x3232)));
3507 ABI_CHECK(callContractFunction("f(string)", encodeDyn(string("return_int256()"))), encodeArgs(true, 0x40, 0x20, u256(-256)));
3508 ABI_CHECK(callContractFunction("f(string)", encodeDyn(string("return_uint256()"))), encodeArgs(true, 0x40, 0x20, u256(0x256256)));
3509 ABI_CHECK(callContractFunction("f(string)", encodeDyn(string("return_bytes4()"))), encodeArgs(true, 0x40, 0x20, u256(0xabcd0012) << (28*8)));
3510 ABI_CHECK(callContractFunction("f(string)", encodeDyn(string("return_multi()"))), encodeArgs(true, 0x40, 0x60, false, u256(0x3232), u256(0xabcd0012) << (28*8)));
3511 ABI_CHECK(callContractFunction("f(string)", encodeDyn(string("return_bytes()"))), encodeArgs(true, 0x40, 0x60, 0x20, 0x02, encode(bytes{0x42,0x21}, false)));
3512 ABI_CHECK(callContractFunction("check_bool()"), encodeArgs(true));
3513 ABI_CHECK(callContractFunction("check_int32()"), encodeArgs(true));
3514 ABI_CHECK(callContractFunction("check_uint32()"), encodeArgs(true));
3515 ABI_CHECK(callContractFunction("check_int256()"), encodeArgs(true));
3516 ABI_CHECK(callContractFunction("check_uint256()"), encodeArgs(true));
3517 ABI_CHECK(callContractFunction("check_bytes4()"), encodeArgs(true));
3518 ABI_CHECK(callContractFunction("check_multi()"), encodeArgs(true));
3519 ABI_CHECK(callContractFunction("check_bytes()"), encodeArgs(true));
3520 )
3521 }
3522 }
3523 }
3524
BOOST_AUTO_TEST_CASE(abi_encodePacked)3525 BOOST_AUTO_TEST_CASE(abi_encodePacked)
3526 {
3527 char const* sourceCode = R"(
3528 contract C {
3529 function f0() public pure returns (bytes memory) {
3530 return abi.encodePacked();
3531 }
3532 function f1() public pure returns (bytes memory) {
3533 return abi.encodePacked(uint8(1), uint8(2));
3534 }
3535 function f2() public pure returns (bytes memory) {
3536 string memory x = "abc";
3537 return abi.encodePacked(uint8(1), x, uint8(2));
3538 }
3539 function f3() public pure returns (bytes memory r) {
3540 // test that memory is properly allocated
3541 string memory x = "abc";
3542 r = abi.encodePacked(uint8(1), x, uint8(2));
3543 bytes memory y = "def";
3544 require(y[0] == "d");
3545 y[0] = "e";
3546 require(y[0] == "e");
3547 }
3548 function f4() public pure returns (bytes memory) {
3549 string memory x = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz";
3550 return abi.encodePacked(uint16(0x0701), x, uint16(0x1201));
3551 }
3552 function f_literal() public pure returns (bytes memory) {
3553 return abi.encodePacked(uint8(0x01), "abc", uint8(0x02));
3554 }
3555 function f_calldata() public pure returns (bytes memory) {
3556 return abi.encodePacked(uint8(0x01), msg.data, uint8(0x02));
3557 }
3558 }
3559 )";
3560 for (auto v2: {false, true})
3561 {
3562 ALSO_VIA_YUL(
3563 DISABLE_EWASM_TESTRUN()
3564 string prefix = "pragma abicoder " + string(v2 ? "v2" : "v1") + ";\n";
3565 compileAndRun(prefix + sourceCode, 0, "C");
3566 ABI_CHECK(callContractFunction("f0()"), encodeArgs(0x20, 0));
3567 ABI_CHECK(callContractFunction("f1()"), encodeArgs(0x20, 2, "\x01\x02"));
3568 ABI_CHECK(callContractFunction("f2()"), encodeArgs(0x20, 5, "\x01" "abc" "\x02"));
3569 ABI_CHECK(callContractFunction("f3()"), encodeArgs(0x20, 5, "\x01" "abc" "\x02"));
3570 ABI_CHECK(callContractFunction("f4()"), encodeArgs(0x20, 2 + 26 + 26 + 2, "\x07\x01" "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz" "\x12\x01"));
3571 ABI_CHECK(callContractFunction("f_literal()"), encodeArgs(0x20, 5, "\x01" "abc" "\x02"));
3572 ABI_CHECK(callContractFunction("f_calldata()"), encodeArgs(0x20, 6, "\x01" "\xa5\xbf\xa1\xee" "\x02"));
3573 )
3574 }
3575 }
3576
BOOST_AUTO_TEST_CASE(abi_encodePacked_from_storage)3577 BOOST_AUTO_TEST_CASE(abi_encodePacked_from_storage)
3578 {
3579 char const* sourceCode = R"(
3580 contract C {
3581 uint24[9] small_fixed;
3582 int24[9] small_fixed_signed;
3583 uint24[] small_dyn;
3584 uint248[5] large_fixed;
3585 uint248[] large_dyn;
3586 bytes bytes_storage;
3587 function sf() public returns (bytes memory) {
3588 small_fixed[0] = 0xfffff1;
3589 small_fixed[2] = 0xfffff2;
3590 small_fixed[5] = 0xfffff3;
3591 small_fixed[8] = 0xfffff4;
3592 return abi.encodePacked(uint8(0x01), small_fixed, uint8(0x02));
3593 }
3594 function sd() public returns (bytes memory) {
3595 small_dyn.push(0xfffff1);
3596 small_dyn.push(0x00);
3597 small_dyn.push(0xfffff2);
3598 small_dyn.push(0x00);
3599 small_dyn.push(0x00);
3600 small_dyn.push(0xfffff3);
3601 small_dyn.push(0x00);
3602 small_dyn.push(0x00);
3603 small_dyn.push(0xfffff4);
3604 return abi.encodePacked(uint8(0x01), small_dyn, uint8(0x02));
3605 }
3606 function sfs() public returns (bytes memory) {
3607 small_fixed_signed[0] = -2;
3608 small_fixed_signed[2] = 0xffff2;
3609 small_fixed_signed[5] = -200;
3610 small_fixed_signed[8] = 0xffff4;
3611 return abi.encodePacked(uint8(0x01), small_fixed_signed, uint8(0x02));
3612 }
3613 function lf() public returns (bytes memory) {
3614 large_fixed[0] = 2**248-1;
3615 large_fixed[1] = 0xfffff2;
3616 large_fixed[2] = 2**248-2;
3617 large_fixed[4] = 0xfffff4;
3618 return abi.encodePacked(uint8(0x01), large_fixed, uint8(0x02));
3619 }
3620 function ld() public returns (bytes memory) {
3621 large_dyn.push(2**248-1);
3622 large_dyn.push(0xfffff2);
3623 large_dyn.push(2**248-2);
3624 large_dyn.push(0);
3625 large_dyn.push(0xfffff4);
3626 return abi.encodePacked(uint8(0x01), large_dyn, uint8(0x02));
3627 }
3628 function bytes_short() public returns (bytes memory) {
3629 bytes_storage = "abcd";
3630 return abi.encodePacked(uint8(0x01), bytes_storage, uint8(0x02));
3631 }
3632 function bytes_long() public returns (bytes memory) {
3633 bytes_storage = "0123456789012345678901234567890123456789";
3634 return abi.encodePacked(uint8(0x01), bytes_storage, uint8(0x02));
3635 }
3636 }
3637 )";
3638 for (auto v2: {false, true})
3639 {
3640 ALSO_VIA_YUL(
3641 DISABLE_EWASM_TESTRUN()
3642 string prefix = "pragma abicoder " + string(v2 ? "v2" : "v1") + ";\n";
3643 compileAndRun(prefix + sourceCode, 0, "C");
3644 bytes payload = encodeArgs(0xfffff1, 0, 0xfffff2, 0, 0, 0xfffff3, 0, 0, 0xfffff4);
3645 bytes encoded = encodeArgs(0x20, 0x122, "\x01" + asString(payload) + "\x02");
3646 ABI_CHECK(callContractFunction("sf()"), encoded);
3647 ABI_CHECK(callContractFunction("sd()"), encoded);
3648 ABI_CHECK(callContractFunction("sfs()"), encodeArgs(0x20, 0x122, "\x01" + asString(encodeArgs(
3649 u256(-2), 0, 0xffff2, 0, 0, u256(-200), 0, 0, 0xffff4
3650 )) + "\x02"));
3651 payload = encodeArgs(
3652 u256("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"),
3653 0xfffff2,
3654 u256("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe"),
3655 0,
3656 0xfffff4
3657 );
3658 ABI_CHECK(callContractFunction("lf()"), encodeArgs(0x20, 5 * 32 + 2, "\x01" + asString(encodeArgs(payload)) + "\x02"));
3659 ABI_CHECK(callContractFunction("ld()"), encodeArgs(0x20, 5 * 32 + 2, "\x01" + asString(encodeArgs(payload)) + "\x02"));
3660 ABI_CHECK(callContractFunction("bytes_short()"), encodeArgs(0x20, 6, "\x01" "abcd\x02"));
3661 ABI_CHECK(callContractFunction("bytes_long()"), encodeArgs(0x20, 42, "\x01" "0123456789012345678901234567890123456789\x02"));
3662 )
3663 }
3664 }
3665
BOOST_AUTO_TEST_CASE(abi_encodePacked_from_memory)3666 BOOST_AUTO_TEST_CASE(abi_encodePacked_from_memory)
3667 {
3668 char const* sourceCode = R"(
3669 contract C {
3670 function sf() public pure returns (bytes memory) {
3671 uint24[9] memory small_fixed;
3672 small_fixed[0] = 0xfffff1;
3673 small_fixed[2] = 0xfffff2;
3674 small_fixed[5] = 0xfffff3;
3675 small_fixed[8] = 0xfffff4;
3676 return abi.encodePacked(uint8(0x01), small_fixed, uint8(0x02));
3677 }
3678 function sd() public pure returns (bytes memory) {
3679 uint24[] memory small_dyn = new uint24[](9);
3680 small_dyn[0] = 0xfffff1;
3681 small_dyn[2] = 0xfffff2;
3682 small_dyn[5] = 0xfffff3;
3683 small_dyn[8] = 0xfffff4;
3684 return abi.encodePacked(uint8(0x01), small_dyn, uint8(0x02));
3685 }
3686 function sfs() public pure returns (bytes memory) {
3687 int24[9] memory small_fixed_signed;
3688 small_fixed_signed[0] = -2;
3689 small_fixed_signed[2] = 0xffff2;
3690 small_fixed_signed[5] = -200;
3691 small_fixed_signed[8] = 0xffff4;
3692 return abi.encodePacked(uint8(0x01), small_fixed_signed, uint8(0x02));
3693 }
3694 function lf() public pure returns (bytes memory) {
3695 uint248[5] memory large_fixed;
3696 large_fixed[0] = 2**248-1;
3697 large_fixed[1] = 0xfffff2;
3698 large_fixed[2] = 2**248-2;
3699 large_fixed[4] = 0xfffff4;
3700 return abi.encodePacked(uint8(0x01), large_fixed, uint8(0x02));
3701 }
3702 function ld() public pure returns (bytes memory) {
3703 uint248[] memory large_dyn = new uint248[](5);
3704 large_dyn[0] = 2**248-1;
3705 large_dyn[1] = 0xfffff2;
3706 large_dyn[2] = 2**248-2;
3707 large_dyn[4] = 0xfffff4;
3708 return abi.encodePacked(uint8(0x01), large_dyn, uint8(0x02));
3709 }
3710 }
3711 )";
3712 for (auto v2: {false, true})
3713 {
3714 ALSO_VIA_YUL(
3715 DISABLE_EWASM_TESTRUN()
3716 string prefix = "pragma abicoder " + string(v2 ? "v2" : "v1") + ";\n";
3717 compileAndRun(prefix + sourceCode, 0, "C");
3718 bytes payload = encodeArgs(0xfffff1, 0, 0xfffff2, 0, 0, 0xfffff3, 0, 0, 0xfffff4);
3719 bytes encoded = encodeArgs(0x20, 0x122, "\x01" + asString(payload) + "\x02");
3720 ABI_CHECK(callContractFunction("sf()"), encoded);
3721 ABI_CHECK(callContractFunction("sd()"), encoded);
3722 ABI_CHECK(callContractFunction("sfs()"), encodeArgs(0x20, 0x122, "\x01" + asString(encodeArgs(
3723 u256(-2), 0, 0xffff2, 0, 0, u256(-200), 0, 0, 0xffff4
3724 )) + "\x02"));
3725 payload = encodeArgs(
3726 u256("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"),
3727 0xfffff2,
3728 u256("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe"),
3729 0,
3730 0xfffff4
3731 );
3732 ABI_CHECK(callContractFunction("lf()"), encodeArgs(0x20, 5 * 32 + 2, "\x01" + asString(encodeArgs(payload)) + "\x02"));
3733 ABI_CHECK(callContractFunction("ld()"), encodeArgs(0x20, 5 * 32 + 2, "\x01" + asString(encodeArgs(payload)) + "\x02"));
3734 )
3735 }
3736 }
3737
BOOST_AUTO_TEST_CASE(abi_encodePacked_functionPtr)3738 BOOST_AUTO_TEST_CASE(abi_encodePacked_functionPtr)
3739 {
3740 char const* sourceCode = R"(
3741 contract C {
3742 C other = C(0x1112131400000000000011121314000000000087);
3743 function testDirect() public view returns (bytes memory) {
3744 return abi.encodePacked(uint8(8), other.f, uint8(2));
3745 }
3746 function testFixedArray() public view returns (bytes memory) {
3747 function () external pure returns (bytes memory)[1] memory x;
3748 x[0] = other.f;
3749 return abi.encodePacked(uint8(8), x, uint8(2));
3750 }
3751 function testDynamicArray() public view returns (bytes memory) {
3752 function () external pure returns (bytes memory)[] memory x = new function() external pure returns (bytes memory)[](1);
3753 x[0] = other.f;
3754 return abi.encodePacked(uint8(8), x, uint8(2));
3755 }
3756 function f() public pure returns (bytes memory) {}
3757 }
3758 )";
3759 for (auto v2: {false, true})
3760 {
3761 ALSO_VIA_YUL(
3762 DISABLE_EWASM_TESTRUN()
3763 string prefix = "pragma abicoder " + string(v2 ? "v2" : "v1") + ";\n";
3764 compileAndRun(prefix + sourceCode, 0, "C");
3765 string directEncoding = asString(fromHex("08" "1112131400000000000011121314000000000087" "26121ff0" "02"));
3766 ABI_CHECK(callContractFunction("testDirect()"), encodeArgs(0x20, directEncoding.size(), directEncoding));
3767 string arrayEncoding = asString(fromHex("08" "1112131400000000000011121314000000000087" "26121ff0" "0000000000000000" "02"));
3768 ABI_CHECK(callContractFunction("testFixedArray()"), encodeArgs(0x20, arrayEncoding.size(), arrayEncoding));
3769 ABI_CHECK(callContractFunction("testDynamicArray()"), encodeArgs(0x20, arrayEncoding.size(), arrayEncoding));
3770 )
3771 }
3772 }
3773
BOOST_AUTO_TEST_CASE(abi_encodePackedV2_structs)3774 BOOST_AUTO_TEST_CASE(abi_encodePackedV2_structs)
3775 {
3776 char const* sourceCode = R"(
3777 pragma abicoder v2;
3778 contract C {
3779 struct S {
3780 uint8 a;
3781 int16 b;
3782 uint8[2] c;
3783 int16[] d;
3784 }
3785 S s;
3786 event E(S indexed);
3787 constructor() {
3788 s.a = 0x12;
3789 s.b = -7;
3790 s.c[0] = 2;
3791 s.c[1] = 3;
3792 s.d.push(-7);
3793 s.d.push(-8);
3794 }
3795 function testStorage() public {
3796 emit E(s);
3797 }
3798 function testMemory() public {
3799 S memory m = s;
3800 emit E(m);
3801 }
3802 }
3803 )";
3804 ALSO_VIA_YUL(
3805 DISABLE_EWASM_TESTRUN()
3806 compileAndRun(sourceCode, 0, "C");
3807 bytes structEnc = encodeArgs(int(0x12), u256(-7), int(2), int(3), u256(-7), u256(-8));
3808 ABI_CHECK(callContractFunction("testStorage()"), encodeArgs());
3809 BOOST_REQUIRE_EQUAL(numLogTopics(0), 2);
3810 BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("E((uint8,int16,uint8[2],int16[]))")));
3811 BOOST_CHECK_EQUAL(logTopic(0, 1), util::keccak256(asString(structEnc)));
3812 ABI_CHECK(callContractFunction("testMemory()"), encodeArgs());
3813 BOOST_REQUIRE_EQUAL(numLogTopics(0), 2);
3814 BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("E((uint8,int16,uint8[2],int16[]))")));
3815 BOOST_CHECK_EQUAL(logTopic(0, 1), util::keccak256(asString(structEnc)));
3816 )
3817 }
3818
BOOST_AUTO_TEST_CASE(abi_encodePackedV2_nestedArray)3819 BOOST_AUTO_TEST_CASE(abi_encodePackedV2_nestedArray)
3820 {
3821 char const* sourceCode = R"(
3822 pragma abicoder v2;
3823 contract C {
3824 struct S {
3825 uint8 a;
3826 int16 b;
3827 }
3828 event E(S[2][][3] indexed);
3829 function testNestedArrays() public {
3830 S[2][][3] memory x;
3831 x[1] = new S[2][](2);
3832 x[1][0][0].a = 1;
3833 x[1][0][0].b = 2;
3834 x[1][0][1].a = 3;
3835 x[1][1][1].b = 4;
3836 emit E(x);
3837 }
3838 }
3839 )";
3840 ALSO_VIA_YUL(
3841 DISABLE_EWASM_TESTRUN()
3842 compileAndRun(sourceCode, 0, "C");
3843 bytes structEnc = encodeArgs(1, 2, 3, 0, 0, 0, 0, 4);
3844 ABI_CHECK(callContractFunction("testNestedArrays()"), encodeArgs());
3845 BOOST_REQUIRE_EQUAL(numLogTopics(0), 2);
3846 BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("E((uint8,int16)[2][][3])")));
3847 BOOST_CHECK_EQUAL(logTopic(0, 1), util::keccak256(asString(structEnc)));
3848 )
3849 }
3850
BOOST_AUTO_TEST_CASE(abi_encodePackedV2_arrayOfStrings)3851 BOOST_AUTO_TEST_CASE(abi_encodePackedV2_arrayOfStrings)
3852 {
3853 char const* sourceCode = R"(
3854 pragma abicoder v2;
3855 contract C {
3856 string[] x;
3857 event E(string[] indexed);
3858 constructor() {
3859 x.push("abc");
3860 x.push("0123456789012345678901234567890123456789");
3861 }
3862 function testStorage() public {
3863 emit E(x);
3864 }
3865 function testMemory() public {
3866 string[] memory y = x;
3867 emit E(y);
3868 }
3869 }
3870 )";
3871 ALSO_VIA_YUL(
3872 DISABLE_EWASM_TESTRUN()
3873 compileAndRun(sourceCode, 0, "C");
3874 bytes arrayEncoding = encodeArgs("abc", "0123456789012345678901234567890123456789");
3875 ABI_CHECK(callContractFunction("testStorage()"), encodeArgs());
3876 BOOST_REQUIRE_EQUAL(numLogTopics(0), 2);
3877 BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("E(string[])")));
3878 BOOST_CHECK_EQUAL(logTopic(0, 1), util::keccak256(asString(arrayEncoding)));
3879 ABI_CHECK(callContractFunction("testMemory()"), encodeArgs());
3880 BOOST_REQUIRE_EQUAL(numLogTopics(0), 2);
3881 BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("E(string[])")));
3882 BOOST_CHECK_EQUAL(logTopic(0, 1), util::keccak256(asString(arrayEncoding)));
3883 )
3884 }
3885
BOOST_AUTO_TEST_CASE(code_access)3886 BOOST_AUTO_TEST_CASE(code_access)
3887 {
3888 char const* sourceCode = R"(
3889 contract C {
3890 function lengths() public pure returns (bool) {
3891 uint crLen = type(D).creationCode.length;
3892 uint runLen = type(D).runtimeCode.length;
3893 require(runLen < crLen);
3894 require(crLen >= 0x20);
3895 require(runLen >= 0x20);
3896 return true;
3897 }
3898 function creation() public pure returns (bytes memory) {
3899 return type(D).creationCode;
3900 }
3901 function runtime() public pure returns (bytes memory) {
3902 return type(D).runtimeCode;
3903 }
3904 function runtimeAllocCheck() public pure returns (bytes memory) {
3905 uint[] memory a = new uint[](2);
3906 bytes memory c = type(D).runtimeCode;
3907 uint[] memory b = new uint[](2);
3908 a[0] = 0x1111;
3909 a[1] = 0x2222;
3910 b[0] = 0x3333;
3911 b[1] = 0x4444;
3912 return c;
3913 }
3914 }
3915 contract D {
3916 function f() public pure returns (uint) { return 7; }
3917 }
3918 )";
3919 compileAndRun(sourceCode, 0, "C");
3920 ABI_CHECK(callContractFunction("lengths()"), encodeArgs(true));
3921 bytes codeCreation = callContractFunction("creation()");
3922 bytes codeRuntime1 = callContractFunction("runtime()");
3923 bytes codeRuntime2 = callContractFunction("runtimeAllocCheck()");
3924 ABI_CHECK(codeRuntime1, codeRuntime2);
3925 }
3926
BOOST_AUTO_TEST_CASE(contract_name)3927 BOOST_AUTO_TEST_CASE(contract_name)
3928 {
3929 char const* sourceCode = R"(
3930 contract C {
3931 string public nameAccessor = type(C).name;
3932 string public constant constantNameAccessor = type(C).name;
3933
3934 function name() public virtual pure returns (string memory) {
3935 return type(C).name;
3936 }
3937 }
3938 contract D is C {
3939 function name() public override pure returns (string memory) {
3940 return type(D).name;
3941 }
3942 function name2() public pure returns (string memory) {
3943 return type(C).name;
3944 }
3945 }
3946 contract ThisIsAVeryLongContractNameExceeding256bits {
3947 string public nameAccessor = type(ThisIsAVeryLongContractNameExceeding256bits).name;
3948 string public constant constantNameAccessor = type(ThisIsAVeryLongContractNameExceeding256bits).name;
3949
3950 function name() public pure returns (string memory) {
3951 return type(ThisIsAVeryLongContractNameExceeding256bits).name;
3952 }
3953 }
3954 )";
3955
3956 compileAndRun(sourceCode, 0, "C");
3957 bytes argsC = encodeArgs(u256(0x20), u256(1), "C");
3958 ABI_CHECK(callContractFunction("name()"), argsC);
3959 ABI_CHECK(callContractFunction("nameAccessor()"), argsC);
3960 ABI_CHECK(callContractFunction("constantNameAccessor()"), argsC);
3961
3962 compileAndRun(sourceCode, 0, "D");
3963 bytes argsD = encodeArgs(u256(0x20), u256(1), "D");
3964 ABI_CHECK(callContractFunction("name()"), argsD);
3965 ABI_CHECK(callContractFunction("name2()"), argsC);
3966
3967 string longName = "ThisIsAVeryLongContractNameExceeding256bits";
3968 compileAndRun(sourceCode, 0, longName);
3969 bytes argsLong = encodeArgs(u256(0x20), u256(longName.length()), longName);
3970 ABI_CHECK(callContractFunction("name()"), argsLong);
3971 ABI_CHECK(callContractFunction("nameAccessor()"), argsLong);
3972 ABI_CHECK(callContractFunction("constantNameAccessor()"), argsLong);
3973 }
3974
BOOST_AUTO_TEST_CASE(event_wrong_abi_name)3975 BOOST_AUTO_TEST_CASE(event_wrong_abi_name)
3976 {
3977 char const* sourceCode = R"(
3978 library ClientReceipt {
3979 event Deposit(Test indexed _from, bytes32 indexed _id, uint _value);
3980 function deposit(bytes32 _id) public {
3981 Test a;
3982 emit Deposit(a, _id, msg.value);
3983 }
3984 }
3985 contract Test {
3986 function f() public {
3987 ClientReceipt.deposit("123");
3988 }
3989 }
3990 )";
3991 ALSO_VIA_YUL(
3992 DISABLE_EWASM_TESTRUN()
3993 compileAndRun(sourceCode, 0, "ClientReceipt", bytes());
3994 compileAndRun(sourceCode, 0, "Test", bytes(), map<string, h160>{{":ClientReceipt", m_contractAddress}});
3995
3996 callContractFunction("f()");
3997 BOOST_REQUIRE_EQUAL(numLogs(), 1);
3998 BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress);
3999 BOOST_REQUIRE_EQUAL(numLogTopics(0), 3);
4000 BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("Deposit(address,bytes32,uint256)")));
4001 )
4002 }
4003
BOOST_AUTO_TEST_CASE(dirty_scratch_space_prior_to_constant_optimiser)4004 BOOST_AUTO_TEST_CASE(dirty_scratch_space_prior_to_constant_optimiser)
4005 {
4006 char const* sourceCode = R"(
4007 contract C {
4008 event X(uint);
4009 constructor() {
4010 assembly {
4011 // make scratch space dirty
4012 mstore(0, 0x4242424242424242424242424242424242424242424242424242424242424242)
4013 }
4014 uint x = 0x0000000000001234123412431234123412412342112341234124312341234124;
4015 // This is just to create many instances of x
4016 unchecked { emit X(x + f() * g(tx.origin) ^ h(block.number)); }
4017 assembly {
4018 // make scratch space dirty
4019 mstore(0, 0x4242424242424242424242424242424242424242424242424242424242424242)
4020 }
4021 emit X(x);
4022 }
4023 function f() internal pure returns (uint) {
4024 return 0x0000000000001234123412431234123412412342112341234124312341234124;
4025 }
4026 function g(address a) internal pure returns (uint) {
4027 unchecked { return uint(uint160(a)) * 0x0000000000001234123412431234123412412342112341234124312341234124; }
4028 }
4029 function h(uint a) internal pure returns (uint) {
4030 unchecked { return a * 0x0000000000001234123412431234123412412342112341234124312341234124; }
4031 }
4032 }
4033 )";
4034 compileAndRun(sourceCode, 0, "C");
4035 BOOST_REQUIRE_EQUAL(numLogs(), 2);
4036 BOOST_CHECK_EQUAL(logAddress(1), m_contractAddress);
4037 ABI_CHECK(
4038 logData(1),
4039 encodeArgs(u256("0x0000000000001234123412431234123412412342112341234124312341234124"))
4040 );
4041 }
4042
BOOST_AUTO_TEST_CASE(strip_reason_strings)4043 BOOST_AUTO_TEST_CASE(strip_reason_strings)
4044 {
4045 char const* sourceCode = R"(
4046 contract C {
4047 function f(bool _x) public pure returns (uint) {
4048 require(_x, "some reason");
4049 return 7;
4050 }
4051 function g(bool _x) public pure returns (uint) {
4052 string memory x = "some indirect reason";
4053 require(_x, x);
4054 return 8;
4055 }
4056 function f1(bool _x) public pure returns (uint) {
4057 if (!_x) revert( /* */ "some reason" /* */ );
4058 return 9;
4059 }
4060 function g1(bool _x) public pure returns (uint) {
4061 string memory x = "some indirect reason";
4062 if (!_x) revert(x);
4063 return 10;
4064 }
4065 }
4066 )";
4067 ALSO_VIA_YUL(
4068 DISABLE_EWASM_TESTRUN()
4069 m_revertStrings = RevertStrings::Default;
4070 compileAndRun(sourceCode, 0, "C");
4071
4072 if (
4073 m_optimiserSettings == OptimiserSettings::minimal() ||
4074 m_optimiserSettings == OptimiserSettings::none()
4075 )
4076 // check that the reason string IS part of the binary.
4077 BOOST_CHECK(toHex(m_output).find("736f6d6520726561736f6e") != std::string::npos);
4078
4079 m_revertStrings = RevertStrings::Strip;
4080 compileAndRun(sourceCode, 0, "C");
4081 // check that the reason string is NOT part of the binary.
4082 BOOST_CHECK(toHex(m_output).find("736f6d6520726561736f6e") == std::string::npos);
4083
4084 ABI_CHECK(callContractFunction("f(bool)", true), encodeArgs(7));
4085 ABI_CHECK(callContractFunction("f(bool)", false), encodeArgs());
4086 ABI_CHECK(callContractFunction("g(bool)", true), encodeArgs(8));
4087 ABI_CHECK(callContractFunction("g(bool)", false), encodeArgs());
4088 ABI_CHECK(callContractFunction("f1(bool)", true), encodeArgs(9));
4089 ABI_CHECK(callContractFunction("f1(bool)", false), encodeArgs());
4090 ABI_CHECK(callContractFunction("g1(bool)", true), encodeArgs(10));
4091 ABI_CHECK(callContractFunction("g1(bool)", false), encodeArgs());
4092 )
4093 }
4094
4095 BOOST_AUTO_TEST_SUITE_END()
4096
4097 } // end namespaces
4098