From ed96eb256f7519f350abc83b2eb7c712efe992ce Mon Sep 17 00:00:00 2001 From: Bhargava Shastry Date: Thu, 25 Jan 2024 06:36:50 +0100 Subject: [PATCH 01/57] Yul fuzzer: Support blobhash(uint) global function --- test/tools/ossfuzz/protoToYul.cpp | 9 +++++++++ test/tools/ossfuzz/yulProto.proto | 1 + 2 files changed, 10 insertions(+) diff --git a/test/tools/ossfuzz/protoToYul.cpp b/test/tools/ossfuzz/protoToYul.cpp index 1719dec46c..1ba0d599d4 100644 --- a/test/tools/ossfuzz/protoToYul.cpp +++ b/test/tools/ossfuzz/protoToYul.cpp @@ -599,6 +599,12 @@ void ProtoConverter::visit(UnaryOp const& _x) return; } + if (op == UnaryOp::BLOBHASH && !m_evmVersion.hasBlobHash()) + { + m_output << dictionaryToken(); + return; + } + // The following instructions may lead to change of EVM state and are hence // excluded to avoid false positives. if ( @@ -647,6 +653,9 @@ void ProtoConverter::visit(UnaryOp const& _x) case UnaryOp::BLOCKHASH: m_output << "blockhash"; break; + case UnaryOp::BLOBHASH: + m_output << "blobhash"; + break; } m_output << "("; if (op == UnaryOp::MLOAD) diff --git a/test/tools/ossfuzz/yulProto.proto b/test/tools/ossfuzz/yulProto.proto index 2c10329de6..cf14b887c1 100644 --- a/test/tools/ossfuzz/yulProto.proto +++ b/test/tools/ossfuzz/yulProto.proto @@ -156,6 +156,7 @@ message UnaryOp { EXTCODEHASH = 7; BALANCE = 8; BLOCKHASH = 9; + BLOBHASH = 10; } required UOp op = 1; required Expression operand = 2; From 44da00d3ff7be33c5dc87ad1a62b5aba320bec09 Mon Sep 17 00:00:00 2001 From: Nikola Matic Date: Tue, 6 Feb 2024 12:25:25 +0100 Subject: [PATCH 02/57] Use MCOPY when copying byte arrays --- Changelog.md | 1 + libsolidity/codegen/YulUtilFunctions.cpp | 32 ++++++------ .../debug_info_in_yul_snippet_escaping/output | 2 + .../args | 1 + .../input.sol | 10 ++++ .../output | 51 +++++++++++++++++++ .../args | 1 + .../input.sol | 9 ++++ .../output | 51 +++++++++++++++++++ .../yul_string_format_ascii/output.json | 2 + .../yul_string_format_ascii_long/output.json | 2 + .../semanticTests/various/address_code.sol | 2 +- .../sizeLimits/bytecode_too_large.sol | 4 +- 13 files changed, 150 insertions(+), 18 deletions(-) create mode 100644 test/cmdlineTests/mcopy_bytes_array_returned_from_function/args create mode 100644 test/cmdlineTests/mcopy_bytes_array_returned_from_function/input.sol create mode 100644 test/cmdlineTests/mcopy_bytes_array_returned_from_function/output create mode 100644 test/cmdlineTests/mcopy_string_literal_returned_from_function/args create mode 100644 test/cmdlineTests/mcopy_string_literal_returned_from_function/input.sol create mode 100644 test/cmdlineTests/mcopy_string_literal_returned_from_function/output diff --git a/Changelog.md b/Changelog.md index d20c266d83..3d64b1b80e 100644 --- a/Changelog.md +++ b/Changelog.md @@ -4,6 +4,7 @@ Language Features: Compiler Features: + * Code Generator: Use ``MCOPY`` instead of ``MLOAD``/``MSTORE`` loop when copying byte arrays. Bugfixes: diff --git a/libsolidity/codegen/YulUtilFunctions.cpp b/libsolidity/codegen/YulUtilFunctions.cpp index 35fea8ac4b..0dabc8a369 100644 --- a/libsolidity/codegen/YulUtilFunctions.cpp +++ b/libsolidity/codegen/YulUtilFunctions.cpp @@ -88,34 +88,36 @@ std::string YulUtilFunctions::copyToMemoryFunction(bool _fromCalldata, bool _cle "_to_memory"s + (_cleanup ? "_with_cleanup"s : ""s); - return m_functionCollector.createFunction(functionName, [&]() { + return m_functionCollector.createFunction(functionName, [&](std::vector& _args, std::vector&) { + _args = {"src", "dst", "length"}; + if (_fromCalldata) - { return Whiskers(R"( - function (src, dst, length) { - calldatacopy(dst, src, length) - mstore(add(dst, length), 0) - } + calldatacopy(dst, src, length) + mstore(add(dst, length), 0) )") - ("functionName", functionName) ("cleanup", _cleanup) .render(); - } else { - return Whiskers(R"( - function (src, dst, length) { + if (m_evmVersion.hasMcopy()) + return Whiskers(R"( + mcopy(dst, src, length) + mstore(add(dst, length), 0) + )") + ("cleanup", _cleanup) + .render(); + else + return Whiskers(R"( let i := 0 for { } lt(i, length) { i := add(i, 32) } { mstore(add(dst, i), mload(add(src, i))) } mstore(add(dst, length), 0) - } - )") - ("functionName", functionName) - ("cleanup", _cleanup) - .render(); + )") + ("cleanup", _cleanup) + .render(); } }); } diff --git a/test/cmdlineTests/debug_info_in_yul_snippet_escaping/output b/test/cmdlineTests/debug_info_in_yul_snippet_escaping/output index 94dfb86426..4c90d9054d 100644 --- a/test/cmdlineTests/debug_info_in_yul_snippet_escaping/output +++ b/test/cmdlineTests/debug_info_in_yul_snippet_escaping/output @@ -180,12 +180,14 @@ object "D_27" { } function copy_memory_to_memory_with_cleanup(src, dst, length) { + let i := 0 for { } lt(i, length) { i := add(i, 32) } { mstore(add(dst, i), mload(add(src, i))) } mstore(add(dst, length), 0) + } function round_up_to_mul_of_32(value) -> result { diff --git a/test/cmdlineTests/mcopy_bytes_array_returned_from_function/args b/test/cmdlineTests/mcopy_bytes_array_returned_from_function/args new file mode 100644 index 0000000000..c74711ba8a --- /dev/null +++ b/test/cmdlineTests/mcopy_bytes_array_returned_from_function/args @@ -0,0 +1 @@ +--evm-version cancun --no-cbor-metadata --via-ir --optimize --ir-optimized --debug-info none diff --git a/test/cmdlineTests/mcopy_bytes_array_returned_from_function/input.sol b/test/cmdlineTests/mcopy_bytes_array_returned_from_function/input.sol new file mode 100644 index 0000000000..05f24d64e7 --- /dev/null +++ b/test/cmdlineTests/mcopy_bytes_array_returned_from_function/input.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity >=0.0.0; + +contract C { + function foo() external pure returns (bytes memory) + { + bytes memory ret = "aaaaa"; + return ret; + } +} diff --git a/test/cmdlineTests/mcopy_bytes_array_returned_from_function/output b/test/cmdlineTests/mcopy_bytes_array_returned_from_function/output new file mode 100644 index 0000000000..2441357d97 --- /dev/null +++ b/test/cmdlineTests/mcopy_bytes_array_returned_from_function/output @@ -0,0 +1,51 @@ +Optimized IR: +/// @use-src 0:"mcopy_bytes_array_returned_from_function/input.sol" +object "C_14" { + code { + { + let _1 := memoryguard(0x80) + mstore(64, _1) + if callvalue() { revert(0, 0) } + let _2 := datasize("C_14_deployed") + codecopy(_1, dataoffset("C_14_deployed"), _2) + return(_1, _2) + } + } + /// @use-src 0:"mcopy_bytes_array_returned_from_function/input.sol" + object "C_14_deployed" { + code { + { + let _1 := memoryguard(0x80) + if iszero(lt(calldatasize(), 4)) + { + if eq(0xc2985578, shr(224, calldataload(0))) + { + if callvalue() { revert(0, 0) } + if slt(add(calldatasize(), not(3)), 0) { revert(0, 0) } + let _2 := 64 + let newFreePtr := add(_1, _2) + if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, _1)) + { + mstore(0, shl(224, 0x4e487b71)) + mstore(4, 0x41) + revert(0, 36) + } + mstore(_2, newFreePtr) + mstore(_1, 5) + let _3 := add(_1, 0x20) + mstore(_3, "aaaaa") + let memPos := mload(_2) + mstore(memPos, 0x20) + let length := mload(_1) + mstore(add(memPos, 0x20), length) + mcopy(add(memPos, _2), _3, length) + mstore(add(add(memPos, length), _2), 0) + return(memPos, add(sub(add(memPos, and(add(length, 31), not(31))), memPos), _2)) + } + } + revert(0, 0) + } + } + data ".metadata" hex"" + } +} diff --git a/test/cmdlineTests/mcopy_string_literal_returned_from_function/args b/test/cmdlineTests/mcopy_string_literal_returned_from_function/args new file mode 100644 index 0000000000..c74711ba8a --- /dev/null +++ b/test/cmdlineTests/mcopy_string_literal_returned_from_function/args @@ -0,0 +1 @@ +--evm-version cancun --no-cbor-metadata --via-ir --optimize --ir-optimized --debug-info none diff --git a/test/cmdlineTests/mcopy_string_literal_returned_from_function/input.sol b/test/cmdlineTests/mcopy_string_literal_returned_from_function/input.sol new file mode 100644 index 0000000000..0251c7cec9 --- /dev/null +++ b/test/cmdlineTests/mcopy_string_literal_returned_from_function/input.sol @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity >=0.0.0; + +contract C { + function foo() external pure returns (string memory) + { + return "MCOPY on Cancun vacation."; + } +} diff --git a/test/cmdlineTests/mcopy_string_literal_returned_from_function/output b/test/cmdlineTests/mcopy_string_literal_returned_from_function/output new file mode 100644 index 0000000000..02740ec0d6 --- /dev/null +++ b/test/cmdlineTests/mcopy_string_literal_returned_from_function/output @@ -0,0 +1,51 @@ +Optimized IR: +/// @use-src 0:"mcopy_string_literal_returned_from_function/input.sol" +object "C_10" { + code { + { + let _1 := memoryguard(0x80) + mstore(64, _1) + if callvalue() { revert(0, 0) } + let _2 := datasize("C_10_deployed") + codecopy(_1, dataoffset("C_10_deployed"), _2) + return(_1, _2) + } + } + /// @use-src 0:"mcopy_string_literal_returned_from_function/input.sol" + object "C_10_deployed" { + code { + { + let _1 := memoryguard(0x80) + if iszero(lt(calldatasize(), 4)) + { + if eq(0xc2985578, shr(224, calldataload(0))) + { + if callvalue() { revert(0, 0) } + if slt(add(calldatasize(), not(3)), 0) { revert(0, 0) } + let _2 := 64 + let newFreePtr := add(_1, _2) + if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, _1)) + { + mstore(0, shl(224, 0x4e487b71)) + mstore(4, 0x41) + revert(0, 0x24) + } + mstore(_2, newFreePtr) + mstore(_1, 25) + let _3 := add(_1, 0x20) + mstore(_3, "MCOPY on Cancun vacation.") + let memPos := mload(_2) + mstore(memPos, 0x20) + let length := mload(_1) + mstore(add(memPos, 0x20), length) + mcopy(add(memPos, _2), _3, length) + mstore(add(add(memPos, length), _2), 0) + return(memPos, add(sub(add(memPos, and(add(length, 31), not(31))), memPos), _2)) + } + } + revert(0, 0) + } + } + data ".metadata" hex"" + } +} diff --git a/test/cmdlineTests/yul_string_format_ascii/output.json b/test/cmdlineTests/yul_string_format_ascii/output.json index aa830d1abe..1a9612c777 100644 --- a/test/cmdlineTests/yul_string_format_ascii/output.json +++ b/test/cmdlineTests/yul_string_format_ascii/output.json @@ -96,12 +96,14 @@ object \"C_11\" { } function copy_memory_to_memory_with_cleanup(src, dst, length) { + let i := 0 for { } lt(i, length) { i := add(i, 32) } { mstore(add(dst, i), mload(add(src, i))) } mstore(add(dst, length), 0) + } function round_up_to_mul_of_32(value) -> result { diff --git a/test/cmdlineTests/yul_string_format_ascii_long/output.json b/test/cmdlineTests/yul_string_format_ascii_long/output.json index 348e5a0b57..5adeabfdff 100644 --- a/test/cmdlineTests/yul_string_format_ascii_long/output.json +++ b/test/cmdlineTests/yul_string_format_ascii_long/output.json @@ -96,12 +96,14 @@ object \"C_11\" { } function copy_memory_to_memory_with_cleanup(src, dst, length) { + let i := 0 for { } lt(i, length) { i := add(i, 32) } { mstore(add(dst, i), mload(add(src, i))) } mstore(add(dst, length), 0) + } function round_up_to_mul_of_32(value) -> result { diff --git a/test/libsolidity/semanticTests/various/address_code.sol b/test/libsolidity/semanticTests/various/address_code.sol index 80daf116cd..7e48b00ca8 100644 --- a/test/libsolidity/semanticTests/various/address_code.sol +++ b/test/libsolidity/semanticTests/various/address_code.sol @@ -8,7 +8,7 @@ contract C { } // To avoid dependency on exact length. - function f() public view returns (bool) { return address(this).code.length > 400; } + function f() public view returns (bool) { return address(this).code.length > 380; } function g() public view returns (uint) { return address(0).code.length; } function h() public view returns (uint) { return address(1).code.length; } } diff --git a/test/libsolidity/syntaxTests/sizeLimits/bytecode_too_large.sol b/test/libsolidity/syntaxTests/sizeLimits/bytecode_too_large.sol index 21c48cc433..f22b9755d6 100644 --- a/test/libsolidity/syntaxTests/sizeLimits/bytecode_too_large.sol +++ b/test/libsolidity/syntaxTests/sizeLimits/bytecode_too_large.sol @@ -7,6 +7,6 @@ contract test { } } // ==== -// EVMVersion: >=shanghai +// EVMVersion: >=cancun // ---- -// Warning 5574: (21-27154): Contract code size is 27187 bytes and exceeds 24576 bytes (a limit introduced in Spurious Dragon). This contract may not be deployable on Mainnet. Consider enabling the optimizer (with a low "runs" value!), turning off revert strings, or using libraries. +// Warning 5574: (21-27154): Contract code size is 27164 bytes and exceeds 24576 bytes (a limit introduced in Spurious Dragon). This contract may not be deployable on Mainnet. Consider enabling the optimizer (with a low "runs" value!), turning off revert strings, or using libraries. From 3122d35a4e8b0d49e20cb71833798d15d6e9ea73 Mon Sep 17 00:00:00 2001 From: Nikola Matic Date: Wed, 14 Feb 2024 14:41:26 +0100 Subject: [PATCH 03/57] ABI decode test case --- .../mcopy_bytes_array_abi_decode/args | 1 + .../mcopy_bytes_array_abi_decode/err | 5 + .../mcopy_bytes_array_abi_decode/input.sol | 9 + .../mcopy_bytes_array_abi_decode/output | 230 ++++++++++++++++++ 4 files changed, 245 insertions(+) create mode 100644 test/cmdlineTests/mcopy_bytes_array_abi_decode/args create mode 100644 test/cmdlineTests/mcopy_bytes_array_abi_decode/err create mode 100644 test/cmdlineTests/mcopy_bytes_array_abi_decode/input.sol create mode 100644 test/cmdlineTests/mcopy_bytes_array_abi_decode/output diff --git a/test/cmdlineTests/mcopy_bytes_array_abi_decode/args b/test/cmdlineTests/mcopy_bytes_array_abi_decode/args new file mode 100644 index 0000000000..4a03d8d932 --- /dev/null +++ b/test/cmdlineTests/mcopy_bytes_array_abi_decode/args @@ -0,0 +1 @@ +--evm-version cancun --no-cbor-metadata --via-ir --ir --debug-info none diff --git a/test/cmdlineTests/mcopy_bytes_array_abi_decode/err b/test/cmdlineTests/mcopy_bytes_array_abi_decode/err new file mode 100644 index 0000000000..de32e66295 --- /dev/null +++ b/test/cmdlineTests/mcopy_bytes_array_abi_decode/err @@ -0,0 +1,5 @@ +Warning: Statement has no effect. + --> mcopy_bytes_array_abi_decode/input.sol:7:9: + | +7 | abi.decode("abcd", (bytes)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/test/cmdlineTests/mcopy_bytes_array_abi_decode/input.sol b/test/cmdlineTests/mcopy_bytes_array_abi_decode/input.sol new file mode 100644 index 0000000000..07d66f800e --- /dev/null +++ b/test/cmdlineTests/mcopy_bytes_array_abi_decode/input.sol @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity >=0.0.0; + +contract C { + function foo() external pure + { + abi.decode("abcd", (bytes)); + } +} diff --git a/test/cmdlineTests/mcopy_bytes_array_abi_decode/output b/test/cmdlineTests/mcopy_bytes_array_abi_decode/output new file mode 100644 index 0000000000..2a24ec834f --- /dev/null +++ b/test/cmdlineTests/mcopy_bytes_array_abi_decode/output @@ -0,0 +1,230 @@ +IR: + +/// @use-src 0:"mcopy_bytes_array_abi_decode/input.sol" +object "C_15" { + code { + + mstore(64, memoryguard(128)) + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + + constructor_C_15() + + let _1 := allocate_unbounded() + codecopy(_1, dataoffset("C_15_deployed"), datasize("C_15_deployed")) + + return(_1, datasize("C_15_deployed")) + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + function constructor_C_15() { + + } + + } + /// @use-src 0:"mcopy_bytes_array_abi_decode/input.sol" + object "C_15_deployed" { + code { + + mstore(64, memoryguard(128)) + + if iszero(lt(calldatasize(), 4)) + { + let selector := shift_right_224_unsigned(calldataload(0)) + switch selector + + case 0xc2985578 + { + // foo() + + external_fun_foo_14() + } + + default {} + } + + revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() + + function shift_right_224_unsigned(value) -> newValue { + newValue := + + shr(224, value) + + } + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + function revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() { + revert(0, 0) + } + + function abi_decode_tuple_(headStart, dataEnd) { + if slt(sub(dataEnd, headStart), 0) { revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() } + + } + + function abi_encode_tuple__to__fromStack(headStart ) -> tail { + tail := add(headStart, 0) + + } + + function external_fun_foo_14() { + + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + abi_decode_tuple_(4, calldatasize()) + fun_foo_14() + let memPos := allocate_unbounded() + let memEnd := abi_encode_tuple__to__fromStack(memPos ) + return(memPos, sub(memEnd, memPos)) + + } + + function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { + revert(0, 0) + } + + function round_up_to_mul_of_32(value) -> result { + result := and(add(value, 31), not(31)) + } + + function panic_error_0x41() { + mstore(0, 35408467139433450592217433187231851964531694900788300625387963629091585785856) + mstore(4, 0x41) + revert(0, 0x24) + } + + function finalize_allocation(memPtr, size) { + let newFreePtr := add(memPtr, round_up_to_mul_of_32(size)) + // protect against overflow + if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { panic_error_0x41() } + mstore(64, newFreePtr) + } + + function allocate_memory(size) -> memPtr { + memPtr := allocate_unbounded() + finalize_allocation(memPtr, size) + } + + function array_allocation_size_t_string_memory_ptr(length) -> size { + // Make sure we can allocate memory without overflow + if gt(length, 0xffffffffffffffff) { panic_error_0x41() } + + size := round_up_to_mul_of_32(length) + + // add length slot + size := add(size, 0x20) + + } + + function allocate_memory_array_t_string_memory_ptr(length) -> memPtr { + let allocSize := array_allocation_size_t_string_memory_ptr(length) + memPtr := allocate_memory(allocSize) + + mstore(memPtr, length) + + } + + function store_literal_in_memory_48bed44d1bcd124a28c27f343a817e5f5243190d3c52bf347daf876de1dbbf77(memPtr) { + + mstore(add(memPtr, 0), "abcd") + + } + + function copy_literal_to_memory_48bed44d1bcd124a28c27f343a817e5f5243190d3c52bf347daf876de1dbbf77() -> memPtr { + memPtr := allocate_memory_array_t_string_memory_ptr(4) + store_literal_in_memory_48bed44d1bcd124a28c27f343a817e5f5243190d3c52bf347daf876de1dbbf77(add(memPtr, 32)) + } + + function convert_t_stringliteral_48bed44d1bcd124a28c27f343a817e5f5243190d3c52bf347daf876de1dbbf77_to_t_bytes_memory_ptr() -> converted { + converted := copy_literal_to_memory_48bed44d1bcd124a28c27f343a817e5f5243190d3c52bf347daf876de1dbbf77() + } + + function revert_error_c1322bf8034eace5e0b5c7295db60986aa89aae5e0ea0873e4689e076861a5db() { + revert(0, 0) + } + + function revert_error_1b9f4a0a5773e33b91aa01db23bf8c55fce1411167c872835e7fa00a4f17d46d() { + revert(0, 0) + } + + function revert_error_987264b3b1d58a9c7f8255e93e81c77d86d6299019c33110a076957a3e06e2ae() { + revert(0, 0) + } + + function array_allocation_size_t_bytes_memory_ptr(length) -> size { + // Make sure we can allocate memory without overflow + if gt(length, 0xffffffffffffffff) { panic_error_0x41() } + + size := round_up_to_mul_of_32(length) + + // add length slot + size := add(size, 0x20) + + } + + function copy_memory_to_memory_with_cleanup(src, dst, length) { + + mcopy(dst, src, length) + mstore(add(dst, length), 0) + + } + + function abi_decode_available_length_t_bytes_memory_ptr_fromMemory(src, length, end) -> array { + array := allocate_memory(array_allocation_size_t_bytes_memory_ptr(length)) + mstore(array, length) + let dst := add(array, 0x20) + if gt(add(src, length), end) { revert_error_987264b3b1d58a9c7f8255e93e81c77d86d6299019c33110a076957a3e06e2ae() } + copy_memory_to_memory_with_cleanup(src, dst, length) + } + + // bytes + function abi_decode_t_bytes_memory_ptr_fromMemory(offset, end) -> array { + if iszero(slt(add(offset, 0x1f), end)) { revert_error_1b9f4a0a5773e33b91aa01db23bf8c55fce1411167c872835e7fa00a4f17d46d() } + let length := mload(offset) + array := abi_decode_available_length_t_bytes_memory_ptr_fromMemory(add(offset, 0x20), length, end) + } + + function abi_decode_tuple_t_bytes_memory_ptr_fromMemory(headStart, dataEnd) -> value0 { + if slt(sub(dataEnd, headStart), 32) { revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() } + + { + + let offset := mload(add(headStart, 0)) + if gt(offset, 0xffffffffffffffff) { revert_error_c1322bf8034eace5e0b5c7295db60986aa89aae5e0ea0873e4689e076861a5db() } + + value0 := abi_decode_t_bytes_memory_ptr_fromMemory(add(headStart, offset), dataEnd) + } + + } + + function array_length_t_bytes_memory_ptr(value) -> length { + + length := mload(value) + + } + + function fun_foo_14() { + + let _1_mpos := convert_t_stringliteral_48bed44d1bcd124a28c27f343a817e5f5243190d3c52bf347daf876de1dbbf77_to_t_bytes_memory_ptr() + + let expr_11_mpos := abi_decode_tuple_t_bytes_memory_ptr_fromMemory(add(_1_mpos, 32), add(add(_1_mpos, 32), array_length_t_bytes_memory_ptr(_1_mpos))) + + } + + } + + data ".metadata" hex"" + } + +} From 4032b5946cc0ae48baf4a65dd35e9401a3d612eb Mon Sep 17 00:00:00 2001 From: Alexander Arlt Date: Sat, 10 Feb 2024 01:47:07 +0100 Subject: [PATCH 04/57] Add DebugData to AssemblyItem. --- libevmasm/Assembly.cpp | 2 +- libevmasm/AssemblyItem.h | 45 ++++++++--- libevmasm/CommonSubexpressionEliminator.cpp | 76 ++++++++++--------- libevmasm/CommonSubexpressionEliminator.h | 4 +- libevmasm/ControlFlowGraph.cpp | 2 +- libevmasm/ExpressionClasses.cpp | 7 +- libevmasm/ExpressionClasses.h | 2 +- libevmasm/KnownState.cpp | 62 +++++++-------- libevmasm/KnownState.h | 16 ++-- libevmasm/PeepholeOptimiser.cpp | 14 ++-- libevmasm/SimplificationRules.cpp | 12 +-- libevmasm/SimplificationRules.h | 4 +- liblangutil/CMakeLists.txt | 1 + liblangutil/DebugData.h | 70 +++++++++++++++++ libyul/AST.h | 72 +++++------------- libyul/ASTForward.h | 1 - libyul/AsmParser.cpp | 26 +++---- libyul/AsmParser.h | 8 +- libyul/AsmPrinter.cpp | 2 +- libyul/AsmPrinter.h | 4 +- libyul/backends/evm/ConstantOptimiser.h | 6 +- libyul/backends/evm/ControlFlowGraph.h | 22 +++--- .../backends/evm/ControlFlowGraphBuilder.cpp | 8 +- libyul/backends/evm/ControlFlowGraphBuilder.h | 4 +- .../evm/OptimizedEVMCodeTransform.cpp | 2 +- .../backends/evm/OptimizedEVMCodeTransform.h | 2 +- libyul/optimiser/ConditionalSimplifier.cpp | 2 +- libyul/optimiser/ControlFlowSimplifier.cpp | 4 +- libyul/optimiser/ExpressionSplitter.cpp | 2 +- libyul/optimiser/ForLoopConditionIntoBody.cpp | 2 +- .../optimiser/ForLoopConditionOutOfBody.cpp | 2 +- libyul/optimiser/SSATransform.cpp | 4 +- libyul/optimiser/SimplificationRules.cpp | 2 +- libyul/optimiser/SimplificationRules.h | 6 +- libyul/optimiser/StackToMemoryMover.cpp | 4 +- test/tools/yulInterpreter/Inspector.cpp | 4 +- test/tools/yulInterpreter/Inspector.h | 6 +- 37 files changed, 289 insertions(+), 223 deletions(-) create mode 100644 liblangutil/DebugData.h diff --git a/libevmasm/Assembly.cpp b/libevmasm/Assembly.cpp index b6e4d0006c..424d3229ca 100644 --- a/libevmasm/Assembly.cpp +++ b/libevmasm/Assembly.cpp @@ -180,7 +180,7 @@ AssemblyItem Assembly::createAssemblyItemFromJSON(Json::Value const& _json, std: if (c_instructions.count(name)) { - AssemblyItem item{c_instructions.at(name), location}; + AssemblyItem item{c_instructions.at(name), langutil::DebugData::create(location)}; if (!jumpType.empty()) { if (item.instruction() == Instruction::JUMP || item.instruction() == Instruction::JUMPI) diff --git a/libevmasm/AssemblyItem.h b/libevmasm/AssemblyItem.h index 93be394733..c2b3603c63 100644 --- a/libevmasm/AssemblyItem.h +++ b/libevmasm/AssemblyItem.h @@ -24,7 +24,8 @@ #include #include -#include +#include +#include #include #include #include @@ -64,16 +65,16 @@ class AssemblyItem public: enum class JumpType { Ordinary, IntoFunction, OutOfFunction }; - AssemblyItem(u256 _push, langutil::SourceLocation _location = langutil::SourceLocation()): - AssemblyItem(Push, std::move(_push), std::move(_location)) { } - AssemblyItem(Instruction _i, langutil::SourceLocation _location = langutil::SourceLocation()): + AssemblyItem(u256 _push, langutil::DebugData::ConstPtr _debugData = langutil::DebugData::create()): + AssemblyItem(Push, std::move(_push), std::move(_debugData)) { } + AssemblyItem(Instruction _i, langutil::DebugData::ConstPtr _debugData = langutil::DebugData::create()): m_type(Operation), m_instruction(_i), - m_location(std::move(_location)) + m_debugData(std::move(_debugData)) {} - AssemblyItem(AssemblyItemType _type, u256 _data = 0, langutil::SourceLocation _location = langutil::SourceLocation()): + AssemblyItem(AssemblyItemType _type, u256 _data = 0, langutil::DebugData::ConstPtr _debugData = langutil::DebugData::create()): m_type(_type), - m_location(std::move(_location)) + m_debugData(std::move(_debugData)) { if (m_type == Operation) m_instruction = Instruction(uint8_t(_data)); @@ -83,7 +84,8 @@ class AssemblyItem explicit AssemblyItem(bytes _verbatimData, size_t _arguments, size_t _returnVariables): m_type(VerbatimBytecode), m_instruction{}, - m_verbatimBytecode{{_arguments, _returnVariables, std::move(_verbatimData)}} + m_verbatimBytecode{{_arguments, _returnVariables, std::move(_verbatimData)}}, + m_debugData{langutil::DebugData::create()} {} AssemblyItem(AssemblyItem const&) = default; @@ -170,8 +172,29 @@ class AssemblyItem /// @returns true if the assembly item can be used in a functional context. bool canBeFunctional() const; - void setLocation(langutil::SourceLocation const& _location) { m_location = _location; } - langutil::SourceLocation const& location() const { return m_location; } + void setLocation(langutil::SourceLocation const& _location) + { + solAssert(m_debugData); + m_debugData = langutil::DebugData::create( + _location, + m_debugData->originLocation, + m_debugData->astID + ); + } + + langutil::SourceLocation const& location() const + { + solAssert(m_debugData); + return m_debugData->nativeLocation; + } + + void setDebugData(langutil::DebugData::ConstPtr _debugData) + { + solAssert(_debugData); + m_debugData = std::move(_debugData); + } + + langutil::DebugData::ConstPtr debugData() const { return m_debugData; } void setJumpType(JumpType _jumpType) { m_jumpType = _jumpType; } static std::optional parseJumpType(std::string const& _jumpType); @@ -196,7 +219,7 @@ class AssemblyItem /// If m_type == VerbatimBytecode, this holds number of arguments, number of /// return variables and verbatim bytecode. std::optional> m_verbatimBytecode; - langutil::SourceLocation m_location; + langutil::DebugData::ConstPtr m_debugData; JumpType m_jumpType = JumpType::Ordinary; /// Pushed value for operations with data to be determined during assembly stage, /// e.g. PushSubSize, PushTag, PushSub, etc. diff --git a/libevmasm/CommonSubexpressionEliminator.cpp b/libevmasm/CommonSubexpressionEliminator.cpp index de1e5a364a..cb4eaebff3 100644 --- a/libevmasm/CommonSubexpressionEliminator.cpp +++ b/libevmasm/CommonSubexpressionEliminator.cpp @@ -29,6 +29,7 @@ #include #include +#include using namespace solidity; using namespace solidity::evmasm; @@ -57,9 +58,9 @@ std::vector CommonSubexpressionEliminator::getOptimizedItems() if (!m_state.stackElements().empty()) minHeight = std::min(minHeight, m_state.stackElements().begin()->first); for (int height = minHeight; height <= m_initialState.stackHeight(); ++height) - initialStackContents[height] = m_initialState.stackElement(height, SourceLocation()); + initialStackContents[height] = m_initialState.stackElement(height, langutil::DebugData::create()); for (int height = minHeight; height <= m_state.stackHeight(); ++height) - targetStackContents[height] = m_state.stackElement(height, SourceLocation()); + targetStackContents[height] = m_state.stackElement(height, langutil::DebugData::create()); AssemblyItems items = CSECodeGenerator(m_state.expressionClasses(), m_storeOperations).generateCode( m_initialState.sequenceNumber(), @@ -87,23 +88,24 @@ void CommonSubexpressionEliminator::optimizeBreakingItem() ExpressionClasses& classes = m_state.expressionClasses(); SourceLocation const& itemLocation = m_breakingItem->location(); + langutil::DebugData::ConstPtr debugData{langutil::DebugData::create(itemLocation)}; if (*m_breakingItem == AssemblyItem(Instruction::JUMPI)) { AssemblyItem::JumpType jumpType = m_breakingItem->getJumpType(); - Id condition = m_state.stackElement(m_state.stackHeight() - 1, itemLocation); + Id condition = m_state.stackElement(m_state.stackHeight() - 1, debugData); if (classes.knownNonZero(condition)) { - feedItem(AssemblyItem(Instruction::SWAP1, itemLocation), true); - feedItem(AssemblyItem(Instruction::POP, itemLocation), true); + feedItem(AssemblyItem(Instruction::SWAP1, debugData), true); + feedItem(AssemblyItem(Instruction::POP, debugData), true); - AssemblyItem item(Instruction::JUMP, itemLocation); + AssemblyItem item(Instruction::JUMP, debugData); item.setJumpType(jumpType); m_breakingItem = classes.storeItem(item); } else if (classes.knownZero(condition)) { - AssemblyItem it(Instruction::POP, itemLocation); + AssemblyItem it(Instruction::POP, debugData); feedItem(it, true); feedItem(it, true); m_breakingItem = nullptr; @@ -111,12 +113,12 @@ void CommonSubexpressionEliminator::optimizeBreakingItem() } else if (*m_breakingItem == AssemblyItem(Instruction::RETURN)) { - Id size = m_state.stackElement(m_state.stackHeight() - 1, itemLocation); + Id size = m_state.stackElement(m_state.stackHeight() - 1, debugData); if (classes.knownZero(size)) { - feedItem(AssemblyItem(Instruction::POP, itemLocation), true); - feedItem(AssemblyItem(Instruction::POP, itemLocation), true); - AssemblyItem item(Instruction::STOP, itemLocation); + feedItem(AssemblyItem(Instruction::POP, debugData), true); + feedItem(AssemblyItem(Instruction::POP, debugData), true); + AssemblyItem item(Instruction::STOP, debugData); m_breakingItem = classes.storeItem(item); } } @@ -181,16 +183,16 @@ AssemblyItems CSECodeGenerator::generateCode( assertThrow(!m_classPositions[targetItem.second].empty(), OptimizerException, ""); if (m_classPositions[targetItem.second].count(targetItem.first)) continue; - SourceLocation sourceLocation; + langutil::DebugData::ConstPtr debugData; if (m_expressionClasses.representative(targetItem.second).item) - sourceLocation = m_expressionClasses.representative(targetItem.second).item->location(); + debugData = m_expressionClasses.representative(targetItem.second).item->debugData(); int position = classElementPosition(targetItem.second); if (position < targetItem.first) // it is already at its target, we need another copy - appendDup(position, sourceLocation); + appendDup(position, debugData); else - appendOrRemoveSwap(position, sourceLocation); - appendOrRemoveSwap(targetItem.first, sourceLocation); + appendOrRemoveSwap(position, debugData); + appendOrRemoveSwap(targetItem.first, debugData); } // remove surplus elements @@ -263,7 +265,7 @@ void CSECodeGenerator::addDependencies(Id _c) case Instruction::KECCAK256: { Id length = expr.arguments.at(1); - AssemblyItem offsetInstr(Instruction::SUB, expr.item->location()); + AssemblyItem offsetInstr(Instruction::SUB, expr.item->debugData()); Id offsetToStart = m_expressionClasses.find(offsetInstr, {slot, slotToLoadFrom}); u256 const* o = m_expressionClasses.knownConstant(offsetToStart); u256 const* l = m_expressionClasses.knownConstant(length); @@ -334,7 +336,7 @@ void CSECodeGenerator::generateClassElement(Id _c, bool _allowSequenced) for (Id arg: arguments | ranges::views::reverse) generateClassElement(arg); - SourceLocation const& itemLocation = expr.item->location(); + langutil::DebugData::ConstPtr itemDebugData = expr.item->debugData(); // The arguments are somewhere on the stack now, so it remains to move them at the correct place. // This is quite difficult as sometimes, the values also have to removed in this process // (if canBeRemoved() returns true) and the two arguments can be equal. For now, this is @@ -342,42 +344,42 @@ void CSECodeGenerator::generateClassElement(Id _c, bool _allowSequenced) if (arguments.size() == 1) { if (canBeRemoved(arguments[0], _c)) - appendOrRemoveSwap(classElementPosition(arguments[0]), itemLocation); + appendOrRemoveSwap(classElementPosition(arguments[0]), itemDebugData); else - appendDup(classElementPosition(arguments[0]), itemLocation); + appendDup(classElementPosition(arguments[0]), itemDebugData); } else if (arguments.size() == 2) { if (canBeRemoved(arguments[1], _c)) { - appendOrRemoveSwap(classElementPosition(arguments[1]), itemLocation); + appendOrRemoveSwap(classElementPosition(arguments[1]), itemDebugData); if (arguments[0] == arguments[1]) - appendDup(m_stackHeight, itemLocation); + appendDup(m_stackHeight, itemDebugData); else if (canBeRemoved(arguments[0], _c)) { - appendOrRemoveSwap(m_stackHeight - 1, itemLocation); - appendOrRemoveSwap(classElementPosition(arguments[0]), itemLocation); + appendOrRemoveSwap(m_stackHeight - 1, itemDebugData); + appendOrRemoveSwap(classElementPosition(arguments[0]), itemDebugData); } else - appendDup(classElementPosition(arguments[0]), itemLocation); + appendDup(classElementPosition(arguments[0]), itemDebugData); } else { if (arguments[0] == arguments[1]) { - appendDup(classElementPosition(arguments[0]), itemLocation); - appendDup(m_stackHeight, itemLocation); + appendDup(classElementPosition(arguments[0]), itemDebugData); + appendDup(m_stackHeight, itemDebugData); } else if (canBeRemoved(arguments[0], _c)) { - appendOrRemoveSwap(classElementPosition(arguments[0]), itemLocation); - appendDup(classElementPosition(arguments[1]), itemLocation); - appendOrRemoveSwap(m_stackHeight - 1, itemLocation); + appendOrRemoveSwap(classElementPosition(arguments[0]), itemDebugData); + appendDup(classElementPosition(arguments[1]), itemDebugData); + appendOrRemoveSwap(m_stackHeight - 1, itemDebugData); } else { - appendDup(classElementPosition(arguments[1]), itemLocation); - appendDup(classElementPosition(arguments[0]), itemLocation); + appendDup(classElementPosition(arguments[1]), itemDebugData); + appendDup(classElementPosition(arguments[0]), itemDebugData); } } } @@ -398,7 +400,7 @@ void CSECodeGenerator::generateClassElement(Id _c, bool _allowSequenced) !m_generatedItems.empty() && m_generatedItems.back() == AssemblyItem(Instruction::SWAP1)) // this will not append a swap but remove the one that is already there - appendOrRemoveSwap(m_stackHeight - 1, itemLocation); + appendOrRemoveSwap(m_stackHeight - 1, itemDebugData); for (size_t i = 0; i < arguments.size(); ++i) { m_classPositions[m_stack[m_stackHeight - static_cast(i)]].erase(m_stackHeight - static_cast(i)); @@ -467,18 +469,18 @@ bool CSECodeGenerator::removeStackTopIfPossible() return true; } -void CSECodeGenerator::appendDup(int _fromPosition, SourceLocation const& _location) +void CSECodeGenerator::appendDup(int _fromPosition, langutil::DebugData::ConstPtr _debugData) { assertThrow(_fromPosition != c_invalidPosition, OptimizerException, ""); int instructionNum = 1 + m_stackHeight - _fromPosition; assertThrow(instructionNum <= 16, StackTooDeepException, util::stackTooDeepString); assertThrow(1 <= instructionNum, OptimizerException, "Invalid stack access."); - appendItem(AssemblyItem(dupInstruction(static_cast(instructionNum)), _location)); + appendItem(AssemblyItem(dupInstruction(static_cast(instructionNum)), std::move(_debugData))); m_stack[m_stackHeight] = m_stack[_fromPosition]; m_classPositions[m_stack[m_stackHeight]].insert(m_stackHeight); } -void CSECodeGenerator::appendOrRemoveSwap(int _fromPosition, SourceLocation const& _location) +void CSECodeGenerator::appendOrRemoveSwap(int _fromPosition, langutil::DebugData::ConstPtr _debugData) { assertThrow(_fromPosition != c_invalidPosition, OptimizerException, ""); if (_fromPosition == m_stackHeight) @@ -486,7 +488,7 @@ void CSECodeGenerator::appendOrRemoveSwap(int _fromPosition, SourceLocation cons int instructionNum = m_stackHeight - _fromPosition; assertThrow(instructionNum <= 16, StackTooDeepException, util::stackTooDeepString); assertThrow(1 <= instructionNum, OptimizerException, "Invalid stack access."); - appendItem(AssemblyItem(swapInstruction(static_cast(instructionNum)), _location)); + appendItem(AssemblyItem(swapInstruction(static_cast(instructionNum)), std::move(_debugData))); if (m_stack[m_stackHeight] != m_stack[_fromPosition]) { diff --git a/libevmasm/CommonSubexpressionEliminator.h b/libevmasm/CommonSubexpressionEliminator.h index b0810a9a1d..3e963838a4 100644 --- a/libevmasm/CommonSubexpressionEliminator.h +++ b/libevmasm/CommonSubexpressionEliminator.h @@ -142,10 +142,10 @@ class CSECodeGenerator bool removeStackTopIfPossible(); /// Appends a dup instruction to m_generatedItems to retrieve the element at the given stack position. - void appendDup(int _fromPosition, langutil::SourceLocation const& _location); + void appendDup(int _fromPosition, langutil::DebugData::ConstPtr _debugData); /// Appends a swap instruction to m_generatedItems to retrieve the element at the given stack position. /// @note this might also remove the last item if it exactly the same swap instruction. - void appendOrRemoveSwap(int _fromPosition, langutil::SourceLocation const& _location); + void appendOrRemoveSwap(int _fromPosition, langutil::DebugData::ConstPtr _debugData); /// Appends the given assembly item. void appendItem(AssemblyItem const& _item); diff --git a/libevmasm/ControlFlowGraph.cpp b/libevmasm/ControlFlowGraph.cpp index 9d2927ed9c..5b73fb6d5b 100644 --- a/libevmasm/ControlFlowGraph.cpp +++ b/libevmasm/ControlFlowGraph.cpp @@ -275,7 +275,7 @@ void ControlFlowGraph::gatherKnowledge() //@todo in the case of JUMPI, add knowledge about the condition to the state // (for both values of the condition) std::set tags = state->tagsInExpression( - state->stackElement(state->stackHeight(), langutil::SourceLocation{}) + state->stackElement(state->stackHeight(), langutil::DebugData::create()) ); state->feedItem(m_items.at(pc++)); diff --git a/libevmasm/ExpressionClasses.cpp b/libevmasm/ExpressionClasses.cpp index dd66eea328..74de0ae3f4 100644 --- a/libevmasm/ExpressionClasses.cpp +++ b/libevmasm/ExpressionClasses.cpp @@ -33,6 +33,7 @@ #include #include #include +#include using namespace solidity; using namespace solidity::evmasm; @@ -134,11 +135,11 @@ void ExpressionClasses::forceEqual( m_expressions.insert(exp); } -ExpressionClasses::Id ExpressionClasses::newClass(SourceLocation const& _location) +ExpressionClasses::Id ExpressionClasses::newClass(langutil::DebugData::ConstPtr _debugData) { Expression exp; exp.id = static_cast(m_representatives.size()); - exp.item = storeItem(AssemblyItem(UndefinedItem, (u256(1) << 255) + exp.id, _location)); + exp.item = storeItem(AssemblyItem(UndefinedItem, (u256(1) << 255) + exp.id, std::move(_debugData))); m_representatives.push_back(exp); m_expressions.insert(exp); return exp.id; @@ -226,7 +227,7 @@ ExpressionClasses::Id ExpressionClasses::tryToSimplify(Expression const& _expr) std::cout << "to " << match->action().toString() << std::endl; } - return rebuildExpression(ExpressionTemplate(match->action(), _expr.item->location())); + return rebuildExpression(ExpressionTemplate(match->action(), _expr.item->debugData())); } return std::numeric_limits::max(); diff --git a/libevmasm/ExpressionClasses.h b/libevmasm/ExpressionClasses.h index 8d4159fc7b..510302e4c7 100644 --- a/libevmasm/ExpressionClasses.h +++ b/libevmasm/ExpressionClasses.h @@ -92,7 +92,7 @@ class ExpressionClasses void forceEqual(Id _id, AssemblyItem const& _item, Ids const& _arguments, bool _copyItem = true); /// @returns the id of a new class which is different to all other classes. - Id newClass(langutil::SourceLocation const& _location); + Id newClass(langutil::DebugData::ConstPtr _debugData); /// @returns true if the values of the given classes are known to be different (on every input). /// @note that this function might still return false for some different inputs. diff --git a/libevmasm/KnownState.cpp b/libevmasm/KnownState.cpp index 91f798bf38..3878ae0fdd 100644 --- a/libevmasm/KnownState.cpp +++ b/libevmasm/KnownState.cpp @@ -27,6 +27,7 @@ #include #include +#include using namespace solidity; using namespace solidity::evmasm; @@ -114,7 +115,7 @@ KnownState::StoreOperation KnownState::feedItem(AssemblyItem const& _item, bool for (size_t i = 0; i < _item.returnValues(); ++i) setStackElement( m_stackHeight - static_cast(i), - m_expressionClasses->newClass(_item.location()) + m_expressionClasses->newClass(_item.debugData()) ); } else if (_item.type() != Operation) @@ -137,44 +138,44 @@ KnownState::StoreOperation KnownState::feedItem(AssemblyItem const& _item, bool m_stackHeight + 1, stackElement( m_stackHeight - static_cast(instruction) + static_cast(Instruction::DUP1), - _item.location() + _item.debugData() ) ); else if (SemanticInformation::isSwapInstruction(_item)) swapStackElements( m_stackHeight, m_stackHeight - 1 - static_cast(instruction) + static_cast(Instruction::SWAP1), - _item.location() + _item.debugData() ); else if (instruction != Instruction::POP) { std::vector arguments(static_cast(info.args)); for (size_t i = 0; i < static_cast(info.args); ++i) - arguments[i] = stackElement(m_stackHeight - static_cast(i), _item.location()); + arguments[i] = stackElement(m_stackHeight - static_cast(i), _item.debugData()); switch (_item.instruction()) { case Instruction::SSTORE: - op = storeInStorage(arguments[0], arguments[1], _item.location()); + op = storeInStorage(arguments[0], arguments[1], _item.debugData()); break; case Instruction::SLOAD: setStackElement( m_stackHeight + static_cast(_item.deposit()), - loadFromStorage(arguments[0], _item.location()) + loadFromStorage(arguments[0], _item.debugData()) ); break; case Instruction::MSTORE: - op = storeInMemory(arguments[0], arguments[1], _item.location()); + op = storeInMemory(arguments[0], arguments[1], _item.debugData()); break; case Instruction::MLOAD: setStackElement( m_stackHeight + static_cast(_item.deposit()), - loadFromMemory(arguments[0], _item.location()) + loadFromMemory(arguments[0], _item.debugData()) ); break; case Instruction::KECCAK256: setStackElement( m_stackHeight + static_cast(_item.deposit()), - applyKeccak256(arguments.at(0), arguments.at(1), _item.location()) + applyKeccak256(arguments.at(0), arguments.at(1), _item.debugData()) ); break; default: @@ -276,18 +277,18 @@ bool KnownState::operator==(KnownState const& _other) const return (thisIt == m_stackElements.cend() && otherIt == _other.m_stackElements.cend()); } -ExpressionClasses::Id KnownState::stackElement(int _stackHeight, SourceLocation const& _location) +ExpressionClasses::Id KnownState::stackElement(int _stackHeight, langutil::DebugData::ConstPtr _debugData) { if (m_stackElements.count(_stackHeight)) return m_stackElements.at(_stackHeight); // Stack element not found (not assigned yet), create new unknown equivalence class. return m_stackElements[_stackHeight] = - m_expressionClasses->find(AssemblyItem(UndefinedItem, _stackHeight, _location)); + m_expressionClasses->find(AssemblyItem(UndefinedItem, _stackHeight, std::move(_debugData))); } -KnownState::Id KnownState::relativeStackElement(int _stackOffset, SourceLocation const& _location) +KnownState::Id KnownState::relativeStackElement(int _stackOffset, langutil::DebugData::ConstPtr _debugData) { - return stackElement(m_stackHeight + _stackOffset, _location); + return stackElement(m_stackHeight + _stackOffset, std::move(_debugData)); } void KnownState::clearTagUnions() @@ -307,13 +308,13 @@ void KnownState::setStackElement(int _stackHeight, Id _class) void KnownState::swapStackElements( int _stackHeightA, int _stackHeightB, - SourceLocation const& _location + langutil::DebugData::ConstPtr _debugData ) { assertThrow(_stackHeightA != _stackHeightB, OptimizerException, "Swap on same stack elements."); // ensure they are created - stackElement(_stackHeightA, _location); - stackElement(_stackHeightB, _location); + stackElement(_stackHeightA, _debugData); + stackElement(_stackHeightB, _debugData); std::swap(m_stackElements[_stackHeightA], m_stackElements[_stackHeightB]); } @@ -321,7 +322,8 @@ void KnownState::swapStackElements( KnownState::StoreOperation KnownState::storeInStorage( Id _slot, Id _value, - SourceLocation const& _location) + langutil::DebugData::ConstPtr _debugData +) { if (m_storageContent.count(_slot) && m_storageContent[_slot] == _value) // do not execute the storage if we know that the value is already there @@ -336,7 +338,7 @@ KnownState::StoreOperation KnownState::storeInStorage( storageContents.insert(storageItem); m_storageContent = std::move(storageContents); - AssemblyItem item(Instruction::SSTORE, _location); + AssemblyItem item(Instruction::SSTORE, std::move(_debugData)); Id id = m_expressionClasses->find(item, {_slot, _value}, true, m_sequenceNumber); StoreOperation operation{StoreOperation::Storage, _slot, m_sequenceNumber, id}; m_storageContent[_slot] = _value; @@ -346,16 +348,16 @@ KnownState::StoreOperation KnownState::storeInStorage( return operation; } -ExpressionClasses::Id KnownState::loadFromStorage(Id _slot, SourceLocation const& _location) +ExpressionClasses::Id KnownState::loadFromStorage(Id _slot, langutil::DebugData::ConstPtr _debugData) { if (m_storageContent.count(_slot)) return m_storageContent.at(_slot); - AssemblyItem item(Instruction::SLOAD, _location); + AssemblyItem item(Instruction::SLOAD, std::move(_debugData)); return m_storageContent[_slot] = m_expressionClasses->find(item, {_slot}, true, m_sequenceNumber); } -KnownState::StoreOperation KnownState::storeInMemory(Id _slot, Id _value, SourceLocation const& _location) +KnownState::StoreOperation KnownState::storeInMemory(Id _slot, Id _value, langutil::DebugData::ConstPtr _debugData) { if (m_memoryContent.count(_slot) && m_memoryContent[_slot] == _value) // do not execute the store if we know that the value is already there @@ -368,7 +370,7 @@ KnownState::StoreOperation KnownState::storeInMemory(Id _slot, Id _value, Source memoryContents.insert(memoryItem); m_memoryContent = std::move(memoryContents); - AssemblyItem item(Instruction::MSTORE, _location); + AssemblyItem item(Instruction::MSTORE, std::move(_debugData)); Id id = m_expressionClasses->find(item, {_slot, _value}, true, m_sequenceNumber); StoreOperation operation{StoreOperation::Memory, _slot, m_sequenceNumber, id}; m_memoryContent[_slot] = _value; @@ -377,22 +379,22 @@ KnownState::StoreOperation KnownState::storeInMemory(Id _slot, Id _value, Source return operation; } -ExpressionClasses::Id KnownState::loadFromMemory(Id _slot, SourceLocation const& _location) +ExpressionClasses::Id KnownState::loadFromMemory(Id _slot, langutil::DebugData::ConstPtr _debugData) { if (m_memoryContent.count(_slot)) return m_memoryContent.at(_slot); - AssemblyItem item(Instruction::MLOAD, _location); + AssemblyItem item(Instruction::MLOAD, std::move(_debugData)); return m_memoryContent[_slot] = m_expressionClasses->find(item, {_slot}, true, m_sequenceNumber); } KnownState::Id KnownState::applyKeccak256( Id _start, Id _length, - SourceLocation const& _location + langutil::DebugData::ConstPtr _debugData ) { - AssemblyItem keccak256Item(Instruction::KECCAK256, _location); + AssemblyItem keccak256Item(Instruction::KECCAK256, _debugData); // Special logic if length is a short constant, otherwise we cannot tell. u256 const* l = m_expressionClasses->knownConstant(_length); // unknown or too large length @@ -403,10 +405,10 @@ KnownState::Id KnownState::applyKeccak256( for (unsigned i = 0; i < length; i += 32) { Id slot = m_expressionClasses->find( - AssemblyItem(Instruction::ADD, _location), + AssemblyItem(Instruction::ADD, _debugData), {_start, m_expressionClasses->find(u256(i))} ); - arguments.push_back(loadFromMemory(slot, _location)); + arguments.push_back(loadFromMemory(slot, _debugData)); } if (m_knownKeccak256Hashes.count({arguments, length})) return m_knownKeccak256Hashes.at({arguments, length}); @@ -418,7 +420,7 @@ KnownState::Id KnownState::applyKeccak256( for (Id a: arguments) data += toBigEndian(*m_expressionClasses->knownConstant(a)); data.resize(length); - v = m_expressionClasses->find(AssemblyItem(u256(util::keccak256(data)), _location)); + v = m_expressionClasses->find(AssemblyItem(u256(util::keccak256(data)), _debugData)); } else v = m_expressionClasses->find(keccak256Item, {_start, _length}, true, m_sequenceNumber); @@ -443,7 +445,7 @@ KnownState::Id KnownState::tagUnion(std::set _tags) return m_tagUnions.right.at(_tags); else { - Id id = m_expressionClasses->newClass(SourceLocation()); + Id id = m_expressionClasses->newClass(langutil::DebugData::create()); m_tagUnions.right.insert(make_pair(_tags, id)); return id; } diff --git a/libevmasm/KnownState.h b/libevmasm/KnownState.h index 9cc22710fa..79426c36f4 100644 --- a/libevmasm/KnownState.h +++ b/libevmasm/KnownState.h @@ -134,9 +134,9 @@ class KnownState /// Retrieves the current equivalence class for the given stack element (or generates a new /// one if it does not exist yet). - Id stackElement(int _stackHeight, langutil::SourceLocation const& _location); + Id stackElement(int _stackHeight, langutil::DebugData::ConstPtr _debugData); /// @returns the stackElement relative to the current stack height. - Id relativeStackElement(int _stackOffset, langutil::SourceLocation const& _location = {}); + Id relativeStackElement(int _stackOffset, langutil::DebugData::ConstPtr _debugData = {}); /// @returns its set of tags if the given expression class is a known tag union; returns a set /// containing the tag if it is a PushTag expression and the empty set otherwise. @@ -155,22 +155,22 @@ class KnownState /// Assigns a new equivalence class to the next sequence number of the given stack element. void setStackElement(int _stackHeight, Id _class); /// Swaps the given stack elements in their next sequence number. - void swapStackElements(int _stackHeightA, int _stackHeightB, langutil::SourceLocation const& _location); + void swapStackElements(int _stackHeightA, int _stackHeightB, langutil::DebugData::ConstPtr _debugData); /// Increments the sequence number, deletes all storage information that might be overwritten /// and stores the new value at the given slot. /// @returns the store operation, which might be invalid if storage was not modified - StoreOperation storeInStorage(Id _slot, Id _value, langutil::SourceLocation const& _location); + StoreOperation storeInStorage(Id _slot, Id _value,langutil::DebugData::ConstPtr _debugData); /// Retrieves the current value at the given slot in storage or creates a new special sload class. - Id loadFromStorage(Id _slot, langutil::SourceLocation const& _location); + Id loadFromStorage(Id _slot, langutil::DebugData::ConstPtr _debugData); /// Increments the sequence number, deletes all memory information that might be overwritten /// and stores the new value at the given slot. /// @returns the store operation, which might be invalid if memory was not modified - StoreOperation storeInMemory(Id _slot, Id _value, langutil::SourceLocation const& _location); + StoreOperation storeInMemory(Id _slot, Id _value, langutil::DebugData::ConstPtr _debugData); /// Retrieves the current value at the given slot in memory or creates a new special mload class. - Id loadFromMemory(Id _slot, langutil::SourceLocation const& _location); + Id loadFromMemory(Id _slot, langutil::DebugData::ConstPtr _debugData); /// Finds or creates a new expression that applies the Keccak-256 hash function to the contents in memory. - Id applyKeccak256(Id _start, Id _length, langutil::SourceLocation const& _location); + Id applyKeccak256(Id _start, Id _length, langutil::DebugData::ConstPtr _debugData); /// @returns a new or already used Id representing the given set of tags. Id tagUnion(std::set _tags); diff --git a/libevmasm/PeepholeOptimiser.cpp b/libevmasm/PeepholeOptimiser.cpp index e9231c0a56..257a3727c0 100644 --- a/libevmasm/PeepholeOptimiser.cpp +++ b/libevmasm/PeepholeOptimiser.cpp @@ -119,7 +119,7 @@ struct OpPop: SimplePeepholeOptimizerMethod if (instructionInfo(instr, langutil::EVMVersion()).ret == 1 && !instructionInfo(instr, langutil::EVMVersion()).sideEffects) { for (int j = 0; j < instructionInfo(instr, langutil::EVMVersion()).args; j++) - *_out = {Instruction::POP, _op.location()}; + *_out = {Instruction::POP, _op.debugData()}; return true; } } @@ -142,13 +142,13 @@ struct OpStop: SimplePeepholeOptimizerMethod Instruction instr = _op.instruction(); if (!instructionInfo(instr, langutil::EVMVersion()).sideEffects) { - *_out = {Instruction::STOP, _op.location()}; + *_out = {Instruction::STOP, _op.debugData()}; return true; } } else if (_op.type() == Push) { - *_out = {Instruction::STOP, _op.location()}; + *_out = {Instruction::STOP, _op.debugData()}; return true; } } @@ -208,7 +208,7 @@ struct DoublePush: SimplePeepholeOptimizerMethod if (_push1.type() == Push && _push2.type() == Push && _push1.data() == _push2.data()) { *_out = _push1; - *_out = {Instruction::DUP1, _push2.location()}; + *_out = {Instruction::DUP1, _push2.debugData()}; return true; } else @@ -334,7 +334,7 @@ struct EqIsZeroJumpI: SimplePeepholeOptimizerMethod _jumpi == Instruction::JUMPI ) { - *_out = AssemblyItem(Instruction::SUB, _eq.location()); + *_out = AssemblyItem(Instruction::SUB, _eq.debugData()); *_out = _pushTag; *_out = _jumpi; return true; @@ -365,7 +365,7 @@ struct DoubleJump: SimplePeepholeOptimizerMethod _pushTag1.data() == _tag1.data() ) { - *_out = AssemblyItem(Instruction::ISZERO, _jumpi.location()); + *_out = AssemblyItem(Instruction::ISZERO, _jumpi.debugData()); *_out = _pushTag2; *_out = _jumpi; *_out = _tag1; @@ -393,7 +393,7 @@ struct JumpToNext: SimplePeepholeOptimizerMethod ) { if (_jump == Instruction::JUMPI) - *_out = AssemblyItem(Instruction::POP, _jump.location()); + *_out = AssemblyItem(Instruction::POP, _jump.debugData()); *_out = _tag; return true; } diff --git a/libevmasm/SimplificationRules.cpp b/libevmasm/SimplificationRules.cpp index ef2d68c7fd..5085b2c3c8 100644 --- a/libevmasm/SimplificationRules.cpp +++ b/libevmasm/SimplificationRules.cpp @@ -126,12 +126,12 @@ bool Pattern::matches(Expression const& _expr, ExpressionClasses const& _classes return true; } -AssemblyItem Pattern::toAssemblyItem(SourceLocation const& _location) const +AssemblyItem Pattern::toAssemblyItem(langutil::DebugData::ConstPtr _debugData) const { if (m_type == Operation) - return AssemblyItem(m_instruction, _location); + return AssemblyItem(m_instruction, std::move(_debugData)); else - return AssemblyItem(m_type, data(), _location); + return AssemblyItem(m_type, data(), std::move(_debugData)); } std::string Pattern::toString() const @@ -199,7 +199,7 @@ u256 const& Pattern::data() const return *m_data; } -ExpressionTemplate::ExpressionTemplate(Pattern const& _pattern, SourceLocation const& _location) +ExpressionTemplate::ExpressionTemplate(Pattern const& _pattern, langutil::DebugData::ConstPtr const& _debugData) { if (_pattern.matchGroup()) { @@ -209,10 +209,10 @@ ExpressionTemplate::ExpressionTemplate(Pattern const& _pattern, SourceLocation c else { hasId = false; - item = _pattern.toAssemblyItem(_location); + item = _pattern.toAssemblyItem(_debugData); } for (auto const& arg: _pattern.arguments()) - arguments.emplace_back(arg, _location); + arguments.emplace_back(arg, _debugData); } std::string ExpressionTemplate::toString() const diff --git a/libevmasm/SimplificationRules.h b/libevmasm/SimplificationRules.h index b3f8da3c7f..fadad36084 100644 --- a/libevmasm/SimplificationRules.h +++ b/libevmasm/SimplificationRules.h @@ -111,7 +111,7 @@ class Pattern unsigned matchGroup() const { return m_matchGroup; } bool matches(Expression const& _expr, ExpressionClasses const& _classes) const; - AssemblyItem toAssemblyItem(langutil::SourceLocation const& _location) const; + AssemblyItem toAssemblyItem(langutil::DebugData::ConstPtr _debugData) const; std::vector arguments() const { return m_arguments; } /// @returns the id of the matched expression if this pattern is part of a match group. @@ -149,7 +149,7 @@ struct ExpressionTemplate { using Expression = ExpressionClasses::Expression; using Id = ExpressionClasses::Id; - explicit ExpressionTemplate(Pattern const& _pattern, langutil::SourceLocation const& _location); + explicit ExpressionTemplate(Pattern const& _pattern, langutil::DebugData::ConstPtr const& _debugData); std::string toString() const; bool hasId = false; /// Id of the matched expression, if available. diff --git a/liblangutil/CMakeLists.txt b/liblangutil/CMakeLists.txt index 53be57e79d..054d01d918 100644 --- a/liblangutil/CMakeLists.txt +++ b/liblangutil/CMakeLists.txt @@ -3,6 +3,7 @@ set(sources Common.h CharStream.cpp CharStream.h + DebugData.h DebugInfoSelection.cpp DebugInfoSelection.h ErrorReporter.cpp diff --git a/liblangutil/DebugData.h b/liblangutil/DebugData.h new file mode 100644 index 0000000000..70259bd039 --- /dev/null +++ b/liblangutil/DebugData.h @@ -0,0 +1,70 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ +// SPDX-License-Identifier: GPL-3.0 + +#pragma once + +#include +#include +#include + +namespace solidity::langutil +{ + +struct DebugData +{ + typedef typename std::shared_ptr ConstPtr; + + explicit DebugData( + langutil::SourceLocation _nativeLocation = {}, + langutil::SourceLocation _originLocation = {}, + std::optional _astID = {} + ): + nativeLocation(std::move(_nativeLocation)), + originLocation(std::move(_originLocation)), + astID(_astID) + {} + + static DebugData::ConstPtr create( + langutil::SourceLocation _nativeLocation, + langutil::SourceLocation _originLocation = {}, + std::optional _astID = {} + ) + { + return std::make_shared( + std::move(_nativeLocation), + std::move(_originLocation), + _astID + ); + } + + static DebugData::ConstPtr create() + { + static DebugData::ConstPtr emptyDebugData = create({}); + return emptyDebugData; + } + + /// Location in the Yul code. + langutil::SourceLocation nativeLocation; + /// Location in the original source that the Yul code was produced from. + /// Optional. Only present if the Yul source contains location annotations. + langutil::SourceLocation originLocation; + /// ID in the (Solidity) source AST. + std::optional astID; +}; + +} // namespace solidity::langutil diff --git a/libyul/AST.h b/libyul/AST.h index 71419d807f..4e3e92de3d 100644 --- a/libyul/AST.h +++ b/libyul/AST.h @@ -26,7 +26,7 @@ #include #include -#include +#include #include #include @@ -36,77 +36,43 @@ namespace solidity::yul using Type = YulString; -struct DebugData -{ - explicit DebugData( - langutil::SourceLocation _nativeLocation, - langutil::SourceLocation _originLocation = {}, - std::optional _astID = {} - ): - nativeLocation(std::move(_nativeLocation)), - originLocation(std::move(_originLocation)), - astID(std::move(_astID)) - {} - - static std::shared_ptr create( - langutil::SourceLocation _nativeLocation = {}, - langutil::SourceLocation _originLocation = {}, - std::optional _astID = {} - ) - { - return std::make_shared( - std::move(_nativeLocation), - std::move(_originLocation), - std::move(_astID) - ); - } - - /// Location in the Yul code. - langutil::SourceLocation nativeLocation; - /// Location in the original source that the Yul code was produced from. - /// Optional. Only present if the Yul source contains location annotations. - langutil::SourceLocation originLocation; - /// ID in the (Solidity) source AST. - std::optional astID; -}; - -struct TypedName { std::shared_ptr debugData; YulString name; Type type; }; +struct TypedName { langutil::DebugData::ConstPtr debugData; YulString name; Type type; }; using TypedNameList = std::vector; /// Literal number or string (up to 32 bytes) enum class LiteralKind { Number, Boolean, String }; -struct Literal { std::shared_ptr debugData; LiteralKind kind; YulString value; Type type; }; +struct Literal { langutil::DebugData::ConstPtr debugData; LiteralKind kind; YulString value; Type type; }; /// External / internal identifier or label reference -struct Identifier { std::shared_ptr debugData; YulString name; }; +struct Identifier { langutil::DebugData::ConstPtr debugData; YulString name; }; /// Assignment ("x := mload(20:u256)", expects push-1-expression on the right hand /// side and requires x to occupy exactly one stack slot. /// /// Multiple assignment ("x, y := f()"), where the left hand side variables each occupy /// a single stack slot and expects a single expression on the right hand returning /// the same amount of items as the number of variables. -struct Assignment { std::shared_ptr debugData; std::vector variableNames; std::unique_ptr value; }; -struct FunctionCall { std::shared_ptr debugData; Identifier functionName; std::vector arguments; }; +struct Assignment { langutil::DebugData::ConstPtr debugData; std::vector variableNames; std::unique_ptr value; }; +struct FunctionCall { langutil::DebugData::ConstPtr debugData; Identifier functionName; std::vector arguments; }; /// Statement that contains only a single expression -struct ExpressionStatement { std::shared_ptr debugData; Expression expression; }; +struct ExpressionStatement { langutil::DebugData::ConstPtr debugData; Expression expression; }; /// Block-scope variable declaration ("let x:u256 := mload(20:u256)"), non-hoisted -struct VariableDeclaration { std::shared_ptr debugData; TypedNameList variables; std::unique_ptr value; }; +struct VariableDeclaration { langutil::DebugData::ConstPtr debugData; TypedNameList variables; std::unique_ptr value; }; /// Block that creates a scope (frees declared stack variables) -struct Block { std::shared_ptr debugData; std::vector statements; }; +struct Block { langutil::DebugData::ConstPtr debugData; std::vector statements; }; /// Function definition ("function f(a, b) -> (d, e) { ... }") -struct FunctionDefinition { std::shared_ptr debugData; YulString name; TypedNameList parameters; TypedNameList returnVariables; Block body; }; +struct FunctionDefinition { langutil::DebugData::ConstPtr debugData; YulString name; TypedNameList parameters; TypedNameList returnVariables; Block body; }; /// Conditional execution without "else" part. -struct If { std::shared_ptr debugData; std::unique_ptr condition; Block body; }; +struct If { langutil::DebugData::ConstPtr debugData; std::unique_ptr condition; Block body; }; /// Switch case or default case -struct Case { std::shared_ptr debugData; std::unique_ptr value; Block body; }; +struct Case { langutil::DebugData::ConstPtr debugData; std::unique_ptr value; Block body; }; /// Switch statement -struct Switch { std::shared_ptr debugData; std::unique_ptr expression; std::vector cases; }; -struct ForLoop { std::shared_ptr debugData; Block pre; std::unique_ptr condition; Block post; Block body; }; +struct Switch { langutil::DebugData::ConstPtr debugData; std::unique_ptr expression; std::vector cases; }; +struct ForLoop { langutil::DebugData::ConstPtr debugData; Block pre; std::unique_ptr condition; Block post; Block body; }; /// Break statement (valid within for loop) -struct Break { std::shared_ptr debugData; }; +struct Break { langutil::DebugData::ConstPtr debugData; }; /// Continue statement (valid within for loop) -struct Continue { std::shared_ptr debugData; }; +struct Continue { langutil::DebugData::ConstPtr debugData; }; /// Leave statement (valid within function) -struct Leave { std::shared_ptr debugData; }; +struct Leave { langutil::DebugData::ConstPtr debugData; }; /// Extracts the IR source location from a Yul node. template inline langutil::SourceLocation nativeLocationOf(T const& _node) @@ -133,13 +99,13 @@ template inline langutil::SourceLocation originLocationOf(std::v } /// Extracts the debug data from a Yul node. -template inline std::shared_ptr debugDataOf(T const& _node) +template inline langutil::DebugData::ConstPtr debugDataOf(T const& _node) { return _node.debugData; } /// Extracts the debug data from a Yul node. -template inline std::shared_ptr debugDataOf(std::variant const& _node) +template inline langutil::DebugData::ConstPtr debugDataOf(std::variant const& _node) { return std::visit([](auto const& _arg) { return debugDataOf(_arg); }, _node); } diff --git a/libyul/ASTForward.h b/libyul/ASTForward.h index 0e61c6ca12..a4dc5be3f8 100644 --- a/libyul/ASTForward.h +++ b/libyul/ASTForward.h @@ -28,7 +28,6 @@ namespace solidity::yul { -struct DebugData; enum class LiteralKind; struct Literal; struct Label; diff --git a/libyul/AsmParser.cpp b/libyul/AsmParser.cpp index 5d3ec84a4b..3635b096af 100644 --- a/libyul/AsmParser.cpp +++ b/libyul/AsmParser.cpp @@ -59,7 +59,7 @@ std::optional toInt(std::string const& _value) } -std::shared_ptr Parser::createDebugData() const +langutil::DebugData::ConstPtr Parser::createDebugData() const { switch (m_useSourceLocationFrom) { @@ -74,7 +74,7 @@ std::shared_ptr Parser::createDebugData() const } void Parser::updateLocationEndFrom( - std::shared_ptr& _debugData, + langutil::DebugData::ConstPtr& _debugData, SourceLocation const& _location ) const { @@ -286,7 +286,7 @@ std::optional>> Parser::parseASTI Block Parser::parseBlock() { RecursionGuard recursionGuard(*this); - Block block = createWithLocation(); + Block block = createWithDebugData(); expectToken(Token::LBrace); while (currentToken() != Token::RBrace) block.statements.emplace_back(parseStatement()); @@ -308,7 +308,7 @@ Statement Parser::parseStatement() return parseBlock(); case Token::If: { - If _if = createWithLocation(); + If _if = createWithDebugData(); advance(); _if.condition = std::make_unique(parseExpression()); _if.body = parseBlock(); @@ -317,7 +317,7 @@ Statement Parser::parseStatement() } case Token::Switch: { - Switch _switch = createWithLocation(); + Switch _switch = createWithDebugData(); advance(); _switch.expression = std::make_unique(parseExpression()); while (currentToken() == Token::Case) @@ -337,21 +337,21 @@ Statement Parser::parseStatement() return parseForLoop(); case Token::Break: { - Statement stmt{createWithLocation()}; + Statement stmt{createWithDebugData()}; checkBreakContinuePosition("break"); advance(); return stmt; } case Token::Continue: { - Statement stmt{createWithLocation()}; + Statement stmt{createWithDebugData()}; checkBreakContinuePosition("continue"); advance(); return stmt; } case Token::Leave: { - Statement stmt{createWithLocation()}; + Statement stmt{createWithDebugData()}; if (!m_insideFunction) m_errorReporter.syntaxError(8149_error, currentLocation(), "Keyword \"leave\" can only be used inside a function."); advance(); @@ -428,7 +428,7 @@ Statement Parser::parseStatement() Case Parser::parseCase() { RecursionGuard recursionGuard(*this); - Case _case = createWithLocation(); + Case _case = createWithDebugData(); if (currentToken() == Token::Default) advance(); else if (currentToken() == Token::Case) @@ -452,7 +452,7 @@ ForLoop Parser::parseForLoop() ForLoopComponent outerForLoopComponent = m_currentForLoopComponent; - ForLoop forLoop = createWithLocation(); + ForLoop forLoop = createWithDebugData(); expectToken(Token::For); m_currentForLoopComponent = ForLoopComponent::ForLoopPre; forLoop.pre = parseBlock(); @@ -559,7 +559,7 @@ std::variant Parser::parseLiteralOrIdentifier() VariableDeclaration Parser::parseVariableDeclaration() { RecursionGuard recursionGuard(*this); - VariableDeclaration varDecl = createWithLocation(); + VariableDeclaration varDecl = createWithDebugData(); expectToken(Token::Let); while (true) { @@ -595,7 +595,7 @@ FunctionDefinition Parser::parseFunctionDefinition() ForLoopComponent outerForLoopComponent = m_currentForLoopComponent; m_currentForLoopComponent = ForLoopComponent::None; - FunctionDefinition funDef = createWithLocation(); + FunctionDefinition funDef = createWithDebugData(); expectToken(Token::Function); funDef.name = expectAsmIdentifier(); expectToken(Token::LParen); @@ -657,7 +657,7 @@ FunctionCall Parser::parseCall(std::variant&& _initialOp) TypedName Parser::parseTypedName() { RecursionGuard recursionGuard(*this); - TypedName typedName = createWithLocation(); + TypedName typedName = createWithDebugData(); typedName.name = expectAsmIdentifier(); if (currentToken() == Token::Colon) { diff --git a/libyul/AsmParser.h b/libyul/AsmParser.h index da4f09ed22..3e0af66acc 100644 --- a/libyul/AsmParser.h +++ b/libyul/AsmParser.h @@ -118,15 +118,15 @@ class Parser: public langutil::ParserBase ); /// Creates a DebugData object with the correct source location set. - std::shared_ptr createDebugData() const; + langutil::DebugData::ConstPtr createDebugData() const; void updateLocationEndFrom( - std::shared_ptr& _debugData, + langutil::DebugData::ConstPtr& _debugData, langutil::SourceLocation const& _location ) const; - /// Creates an inline assembly node with the current source location. - template T createWithLocation() const + /// Creates an inline assembly node with the current debug data. + template T createWithDebugData() const { T r; r.debugData = createDebugData(); diff --git a/libyul/AsmPrinter.cpp b/libyul/AsmPrinter.cpp index bee213f8ca..b27af03713 100644 --- a/libyul/AsmPrinter.cpp +++ b/libyul/AsmPrinter.cpp @@ -305,7 +305,7 @@ std::string AsmPrinter::formatSourceLocation( return sourceLocation + (solidityCodeSnippet.empty() ? "" : " ") + solidityCodeSnippet; } -std::string AsmPrinter::formatDebugData(std::shared_ptr const& _debugData, bool _statement) +std::string AsmPrinter::formatDebugData(langutil::DebugData::ConstPtr const& _debugData, bool _statement) { if (!_debugData || m_debugInfoSelection.none()) return ""; diff --git a/libyul/AsmPrinter.h b/libyul/AsmPrinter.h index 7c67c14acf..d3f80b9a09 100644 --- a/libyul/AsmPrinter.h +++ b/libyul/AsmPrinter.h @@ -30,7 +30,7 @@ #include #include -#include +#include #include @@ -93,7 +93,7 @@ class AsmPrinter private: std::string formatTypedName(TypedName _variable); std::string appendTypeName(YulString _type, bool _isBoolLiteral = false) const; - std::string formatDebugData(std::shared_ptr const& _debugData, bool _statement); + std::string formatDebugData(langutil::DebugData::ConstPtr const& _debugData, bool _statement); template std::string formatDebugData(T const& _node) { diff --git a/libyul/backends/evm/ConstantOptimiser.h b/libyul/backends/evm/ConstantOptimiser.h index a60d2b2f56..280f50bf9b 100644 --- a/libyul/backends/evm/ConstantOptimiser.h +++ b/libyul/backends/evm/ConstantOptimiser.h @@ -27,7 +27,7 @@ #include #include -#include +#include #include @@ -74,7 +74,7 @@ class RepresentationFinder RepresentationFinder( EVMDialect const& _dialect, GasMeter const& _meter, - std::shared_ptr _debugData, + langutil::DebugData::ConstPtr _debugData, std::map& _cache ): m_dialect(_dialect), @@ -100,7 +100,7 @@ class RepresentationFinder EVMDialect const& m_dialect; GasMeter const& m_meter; - std::shared_ptr m_debugData; + langutil::DebugData::ConstPtr m_debugData; /// Counter for the complexity of optimization, will stop when it reaches zero. size_t m_maxSteps = 10000; std::map& m_cache; diff --git a/libyul/backends/evm/ControlFlowGraph.h b/libyul/backends/evm/ControlFlowGraph.h index 853a9e705d..980787c522 100644 --- a/libyul/backends/evm/ControlFlowGraph.h +++ b/libyul/backends/evm/ControlFlowGraph.h @@ -76,7 +76,7 @@ struct FunctionReturnLabelSlot struct VariableSlot { std::reference_wrapper variable; - std::shared_ptr debugData{}; + langutil::DebugData::ConstPtr debugData{}; bool operator==(VariableSlot const& _rhs) const { return &variable.get() == &_rhs.variable.get(); } bool operator<(VariableSlot const& _rhs) const { return &variable.get() < &_rhs.variable.get(); } static constexpr bool canBeFreelyGenerated = false; @@ -85,7 +85,7 @@ struct VariableSlot struct LiteralSlot { u256 value; - std::shared_ptr debugData{}; + langutil::DebugData::ConstPtr debugData{}; bool operator==(LiteralSlot const& _rhs) const { return value == _rhs.value; } bool operator<(LiteralSlot const& _rhs) const { return value < _rhs.value; } static constexpr bool canBeFreelyGenerated = true; @@ -132,7 +132,7 @@ struct CFG struct BuiltinCall { - std::shared_ptr debugData; + langutil::DebugData::ConstPtr debugData; std::reference_wrapper builtin; std::reference_wrapper functionCall; /// Number of proper arguments with a position on the stack, excluding literal arguments. @@ -142,7 +142,7 @@ struct CFG }; struct FunctionCall { - std::shared_ptr debugData; + langutil::DebugData::ConstPtr debugData; std::reference_wrapper function; std::reference_wrapper functionCall; /// True, if the call is recursive, i.e. entering the function involves a control flow path (potentially involving @@ -153,7 +153,7 @@ struct CFG }; struct Assignment { - std::shared_ptr debugData; + langutil::DebugData::ConstPtr debugData; /// The variables being assigned to also occur as ``output`` in the ``Operation`` containing /// the assignment, but are also stored here for convenience. std::vector variables; @@ -176,25 +176,25 @@ struct CFG struct MainExit {}; struct ConditionalJump { - std::shared_ptr debugData; + langutil::DebugData::ConstPtr debugData; StackSlot condition; BasicBlock* nonZero = nullptr; BasicBlock* zero = nullptr; }; struct Jump { - std::shared_ptr debugData; + langutil::DebugData::ConstPtr debugData; BasicBlock* target = nullptr; /// The only backwards jumps are jumps from loop post to loop condition. bool backwards = false; }; struct FunctionReturn { - std::shared_ptr debugData; + langutil::DebugData::ConstPtr debugData; CFG::FunctionInfo* info = nullptr; }; struct Terminated {}; - std::shared_ptr debugData; + langutil::DebugData::ConstPtr debugData; std::vector entries; std::vector operations; /// True, if the block is the beginning of a disconnected subgraph. That is, if no block that is reachable @@ -210,7 +210,7 @@ struct CFG struct FunctionInfo { - std::shared_ptr debugData; + langutil::DebugData::ConstPtr debugData; Scope::Function const& function; FunctionDefinition const& functionDefinition; BasicBlock* entry = nullptr; @@ -238,7 +238,7 @@ struct CFG /// the switch case literals when transforming the control flow of a switch to a sequence of conditional jumps. std::list ghostCalls; - BasicBlock& makeBlock(std::shared_ptr _debugData) + BasicBlock& makeBlock(langutil::DebugData::ConstPtr _debugData) { return blocks.emplace_back(BasicBlock{std::move(_debugData), {}, {}}); } diff --git a/libyul/backends/evm/ControlFlowGraphBuilder.cpp b/libyul/backends/evm/ControlFlowGraphBuilder.cpp index 9a0a73b35f..4b0da1e80d 100644 --- a/libyul/backends/evm/ControlFlowGraphBuilder.cpp +++ b/libyul/backends/evm/ControlFlowGraphBuilder.cpp @@ -333,7 +333,7 @@ void ControlFlowGraphBuilder::operator()(If const& _if) void ControlFlowGraphBuilder::operator()(Switch const& _switch) { yulAssert(m_currentBlock, ""); - std::shared_ptr preSwitchDebugData = debugDataOf(_switch); + langutil::DebugData::ConstPtr preSwitchDebugData = debugDataOf(_switch); auto ghostVariableId = m_graph.ghostVariables.size(); YulString ghostVariableName("GHOST[" + std::to_string(ghostVariableId) + "]"); @@ -393,7 +393,7 @@ void ControlFlowGraphBuilder::operator()(Switch const& _switch) void ControlFlowGraphBuilder::operator()(ForLoop const& _loop) { - std::shared_ptr preLoopDebugData = debugDataOf(_loop); + langutil::DebugData::ConstPtr preLoopDebugData = debugDataOf(_loop); ScopedSaveAndRestore scopeRestore(m_scope, m_info.scopes.at(&_loop.pre).get()); (*this)(_loop.pre); @@ -608,7 +608,7 @@ Scope::Variable const& ControlFlowGraphBuilder::lookupVariable(YulString _name) } void ControlFlowGraphBuilder::makeConditionalJump( - std::shared_ptr _debugData, + langutil::DebugData::ConstPtr _debugData, StackSlot _condition, CFG::BasicBlock& _nonZero, CFG::BasicBlock& _zero @@ -627,7 +627,7 @@ void ControlFlowGraphBuilder::makeConditionalJump( } void ControlFlowGraphBuilder::jump( - std::shared_ptr _debugData, + langutil::DebugData::ConstPtr _debugData, CFG::BasicBlock& _target, bool backwards ) diff --git a/libyul/backends/evm/ControlFlowGraphBuilder.h b/libyul/backends/evm/ControlFlowGraphBuilder.h index ffe935b0dd..5007d36108 100644 --- a/libyul/backends/evm/ControlFlowGraphBuilder.h +++ b/libyul/backends/evm/ControlFlowGraphBuilder.h @@ -67,13 +67,13 @@ class ControlFlowGraphBuilder Scope::Variable const& lookupVariable(YulString _name) const; /// Resets m_currentBlock to enforce a subsequent explicit reassignment. void makeConditionalJump( - std::shared_ptr _debugData, + langutil::DebugData::ConstPtr _debugData, StackSlot _condition, CFG::BasicBlock& _nonZero, CFG::BasicBlock& _zero ); void jump( - std::shared_ptr _debugData, + langutil::DebugData::ConstPtr _debugData, CFG::BasicBlock& _target, bool _backwards = false ); diff --git a/libyul/backends/evm/OptimizedEVMCodeTransform.cpp b/libyul/backends/evm/OptimizedEVMCodeTransform.cpp index 3df75bb88f..a3052a542f 100644 --- a/libyul/backends/evm/OptimizedEVMCodeTransform.cpp +++ b/libyul/backends/evm/OptimizedEVMCodeTransform.cpp @@ -237,7 +237,7 @@ void OptimizedEVMCodeTransform::validateSlot(StackSlot const& _slot, Expression }, _expression); } -void OptimizedEVMCodeTransform::createStackLayout(std::shared_ptr _debugData, Stack _targetStack) +void OptimizedEVMCodeTransform::createStackLayout(langutil::DebugData::ConstPtr _debugData, Stack _targetStack) { static constexpr auto slotVariableName = [](StackSlot const& _slot) { return std::visit(util::GenericVisitor{ diff --git a/libyul/backends/evm/OptimizedEVMCodeTransform.h b/libyul/backends/evm/OptimizedEVMCodeTransform.h index ed03c14530..7e648ca964 100644 --- a/libyul/backends/evm/OptimizedEVMCodeTransform.h +++ b/libyul/backends/evm/OptimizedEVMCodeTransform.h @@ -83,7 +83,7 @@ class OptimizedEVMCodeTransform /// Shuffles m_stack to the desired @a _targetStack while emitting the shuffling code to m_assembly. /// Sets the source locations to the one in @a _debugData. - void createStackLayout(std::shared_ptr _debugData, Stack _targetStack); + void createStackLayout(langutil::DebugData::ConstPtr _debugData, Stack _targetStack); /// Generate code for the given block @a _block. /// Expects the current stack layout m_stack to be a stack layout that is compatible with the diff --git a/libyul/optimiser/ConditionalSimplifier.cpp b/libyul/optimiser/ConditionalSimplifier.cpp index b08b113de0..7119091257 100644 --- a/libyul/optimiser/ConditionalSimplifier.cpp +++ b/libyul/optimiser/ConditionalSimplifier.cpp @@ -78,7 +78,7 @@ void ConditionalSimplifier::operator()(Block& _block) ) { YulString condition = std::get(*_if.condition).name; - std::shared_ptr debugData = _if.debugData; + langutil::DebugData::ConstPtr debugData = _if.debugData; return make_vector( std::move(_s), Assignment{ diff --git a/libyul/optimiser/ControlFlowSimplifier.cpp b/libyul/optimiser/ControlFlowSimplifier.cpp index 771b4e86bf..10f479a421 100644 --- a/libyul/optimiser/ControlFlowSimplifier.cpp +++ b/libyul/optimiser/ControlFlowSimplifier.cpp @@ -37,7 +37,7 @@ namespace { ExpressionStatement makeDiscardCall( - std::shared_ptr const& _debugData, + langutil::DebugData::ConstPtr const& _debugData, BuiltinFunction const& _discardFunction, Expression&& _expression ) @@ -196,7 +196,7 @@ OptionalStatements ControlFlowSimplifier::reduceSingleCaseSwitch(Switch& _switch yulAssert(_switchStmt.cases.size() == 1, "Expected only one case!"); auto& switchCase = _switchStmt.cases.front(); - std::shared_ptr debugData = debugDataOf(*_switchStmt.expression); + langutil::DebugData::ConstPtr debugData = debugDataOf(*_switchStmt.expression); YulString type = m_typeInfo.typeOf(*_switchStmt.expression); if (switchCase.value) { diff --git a/libyul/optimiser/ExpressionSplitter.cpp b/libyul/optimiser/ExpressionSplitter.cpp index 986bcb097f..6f0834d776 100644 --- a/libyul/optimiser/ExpressionSplitter.cpp +++ b/libyul/optimiser/ExpressionSplitter.cpp @@ -98,7 +98,7 @@ void ExpressionSplitter::outlineExpression(Expression& _expr) visit(_expr); - std::shared_ptr debugData = debugDataOf(_expr); + langutil::DebugData::ConstPtr debugData = debugDataOf(_expr); YulString var = m_nameDispenser.newName({}); YulString type = m_typeInfo.typeOf(_expr); m_statementsToPrefix.emplace_back(VariableDeclaration{ diff --git a/libyul/optimiser/ForLoopConditionIntoBody.cpp b/libyul/optimiser/ForLoopConditionIntoBody.cpp index 2dd0832c42..33d8496f08 100644 --- a/libyul/optimiser/ForLoopConditionIntoBody.cpp +++ b/libyul/optimiser/ForLoopConditionIntoBody.cpp @@ -38,7 +38,7 @@ void ForLoopConditionIntoBody::operator()(ForLoop& _forLoop) !std::holds_alternative(*_forLoop.condition) ) { - std::shared_ptr debugData = debugDataOf(*_forLoop.condition); + langutil::DebugData::ConstPtr debugData = debugDataOf(*_forLoop.condition); _forLoop.body.statements.emplace( begin(_forLoop.body.statements), diff --git a/libyul/optimiser/ForLoopConditionOutOfBody.cpp b/libyul/optimiser/ForLoopConditionOutOfBody.cpp index 363ecdf0c0..e2451bc6c6 100644 --- a/libyul/optimiser/ForLoopConditionOutOfBody.cpp +++ b/libyul/optimiser/ForLoopConditionOutOfBody.cpp @@ -54,7 +54,7 @@ void ForLoopConditionOutOfBody::operator()(ForLoop& _forLoop) return; YulString iszero = m_dialect.booleanNegationFunction()->name; - std::shared_ptr debugData = debugDataOf(*firstStatement.condition); + langutil::DebugData::ConstPtr debugData = debugDataOf(*firstStatement.condition); if ( std::holds_alternative(*firstStatement.condition) && diff --git a/libyul/optimiser/SSATransform.cpp b/libyul/optimiser/SSATransform.cpp index 74a7701494..675d21acc3 100644 --- a/libyul/optimiser/SSATransform.cpp +++ b/libyul/optimiser/SSATransform.cpp @@ -84,7 +84,7 @@ void IntroduceSSA::operator()(Block& _block) // Replace "let a := v" by "let a_1 := v let a := a_1" // Replace "let a, b := v" by "let a_1, b_1 := v let a := a_1 let b := b_2" - std::shared_ptr debugData = varDecl.debugData; + langutil::DebugData::ConstPtr debugData = varDecl.debugData; std::vector statements; statements.emplace_back(VariableDeclaration{debugData, {}, std::move(varDecl.value)}); TypedNameList newVariables; @@ -111,7 +111,7 @@ void IntroduceSSA::operator()(Block& _block) // Replace "a := v" by "let a_1 := v a := v" // Replace "a, b := v" by "let a_1, b_1 := v a := a_1 b := b_2" - std::shared_ptr debugData = assignment.debugData; + langutil::DebugData::ConstPtr debugData = assignment.debugData; std::vector statements; statements.emplace_back(VariableDeclaration{debugData, {}, std::move(assignment.value)}); TypedNameList newVariables; diff --git a/libyul/optimiser/SimplificationRules.cpp b/libyul/optimiser/SimplificationRules.cpp index f8bbcf678a..7fe56026ac 100644 --- a/libyul/optimiser/SimplificationRules.cpp +++ b/libyul/optimiser/SimplificationRules.cpp @@ -234,7 +234,7 @@ evmasm::Instruction Pattern::instruction() const return m_instruction; } -Expression Pattern::toExpression(std::shared_ptr const& _debugData, langutil::EVMVersion _evmVersion) const +Expression Pattern::toExpression(langutil::DebugData::ConstPtr const& _debugData, langutil::EVMVersion _evmVersion) const { if (matchGroup()) return ASTCopier().translate(matchGroupValue()); diff --git a/libyul/optimiser/SimplificationRules.h b/libyul/optimiser/SimplificationRules.h index e36730f054..5e498bd5c9 100644 --- a/libyul/optimiser/SimplificationRules.h +++ b/libyul/optimiser/SimplificationRules.h @@ -30,7 +30,7 @@ #include #include -#include +#include #include #include @@ -42,6 +42,8 @@ struct Dialect; struct AssignedValue; class Pattern; +using DebugData = langutil::DebugData; + /** * Container for all simplification rules. */ @@ -131,7 +133,7 @@ class Pattern /// Turns this pattern into an actual expression. Should only be called /// for patterns resulting from an action, i.e. with match groups assigned. - Expression toExpression(std::shared_ptr const& _debugData, langutil::EVMVersion _evmVersion) const; + Expression toExpression(langutil::DebugData::ConstPtr const& _debugData, langutil::EVMVersion _evmVersion) const; private: Expression const& matchGroupValue() const; diff --git a/libyul/optimiser/StackToMemoryMover.cpp b/libyul/optimiser/StackToMemoryMover.cpp index ab39669b2d..dedb5cd382 100644 --- a/libyul/optimiser/StackToMemoryMover.cpp +++ b/libyul/optimiser/StackToMemoryMover.cpp @@ -36,7 +36,7 @@ namespace { std::vector generateMemoryStore( Dialect const& _dialect, - std::shared_ptr const& _debugData, + langutil::DebugData::ConstPtr const& _debugData, YulString _mpos, Expression _value ) @@ -55,7 +55,7 @@ std::vector generateMemoryStore( return result; } -FunctionCall generateMemoryLoad(Dialect const& _dialect, std::shared_ptr const& _debugData, YulString _mpos) +FunctionCall generateMemoryLoad(Dialect const& _dialect, langutil::DebugData::ConstPtr const& _debugData, YulString _mpos) { BuiltinFunction const* memoryLoadFunction = _dialect.memoryLoadFunction(_dialect.defaultType); yulAssert(memoryLoadFunction, ""); diff --git a/test/tools/yulInterpreter/Inspector.cpp b/test/tools/yulInterpreter/Inspector.cpp index 9c4701d00a..7746483a36 100644 --- a/test/tools/yulInterpreter/Inspector.cpp +++ b/test/tools/yulInterpreter/Inspector.cpp @@ -56,7 +56,7 @@ void InspectedInterpreter::run( InspectedInterpreter{_inspector, _state, _dialect, scope, _disableExternalCalls, _disableMemoryTrace}(_ast); } -Inspector::NodeAction Inspector::queryUser(DebugData const& _data, std::map const& _variables) +Inspector::NodeAction Inspector::queryUser(langutil::DebugData const& _data, std::map const& _variables) { if (m_stepMode == NodeAction::RunNode) { @@ -131,7 +131,7 @@ Inspector::NodeAction Inspector::queryUser(DebugData const& _data, std::map(_data.nativeLocation.start), diff --git a/test/tools/yulInterpreter/Inspector.h b/test/tools/yulInterpreter/Inspector.h index 611279c6fe..f4518c7087 100644 --- a/test/tools/yulInterpreter/Inspector.h +++ b/test/tools/yulInterpreter/Inspector.h @@ -53,13 +53,13 @@ class Inspector * @returns NodeAction::RunNode if the current AST node (and all children nodes!) should be * processed without stopping, else NodeAction::StepThroughNode. */ - NodeAction queryUser(DebugData const& _data, std::map const& _variables); + NodeAction queryUser(langutil::DebugData const& _data, std::map const& _variables); void stepMode(NodeAction _action) { m_stepMode = _action; } std::string const& source() const { return m_source; } - void interactiveVisit(DebugData const& _debugData, std::map const& _variables, std::function _visitNode) + void interactiveVisit(langutil::DebugData const& _debugData, std::map const& _variables, std::function _visitNode) { Inspector::NodeAction action = queryUser(_debugData, _variables); @@ -78,7 +78,7 @@ class Inspector } private: - std::string currentSource(DebugData const& _data) const; + std::string currentSource(langutil::DebugData const& _data) const; /// Source of the file std::string const& m_source; From c7b8dcc52f28d68862ef298a94c7ce44f8080346 Mon Sep 17 00:00:00 2001 From: Alexander Arlt Date: Fri, 16 Feb 2024 20:40:05 +0100 Subject: [PATCH 05/57] [test] Add /usr/local/lib to search paths for macOS. --- test/Common.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/Common.cpp b/test/Common.cpp index 14d90d837e..bb4d2db7eb 100644 --- a/test/Common.cpp +++ b/test/Common.cpp @@ -78,7 +78,10 @@ std::optional findInDefaultPath(std::string const& lib_name) fs::current_path() / ".." / "deps" / "lib", fs::current_path() / ".." / ".." / "deps", fs::current_path() / ".." / ".." / "deps" / "lib", - fs::current_path() + fs::current_path(), +#ifdef __APPLE__ + fs::current_path().root_path() / fs::path("usr") / "local" / "lib", +#endif }; for (auto const& basePath: searchPath) { From 9b8ed03823569a48005f0826175a08d5e1281f80 Mon Sep 17 00:00:00 2001 From: Alexander Arlt Date: Sun, 18 Feb 2024 20:53:03 +0100 Subject: [PATCH 06/57] Fix typo in Assembly::fromJSON(..). --- libevmasm/Assembly.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libevmasm/Assembly.cpp b/libevmasm/Assembly.cpp index b6e4d0006c..ab6ac2c63f 100644 --- a/libevmasm/Assembly.cpp +++ b/libevmasm/Assembly.cpp @@ -555,7 +555,7 @@ std::pair, std::vector> Assembly::fromJSO result->importAssemblyItemsFromJSON(_json[".code"], _level == 0 ? parsedSourceList : _sourceList); - if (_json[".auxdata"]) + if (_json.isMember(".auxdata")) { solRequire(_json[".auxdata"].isString(), AssemblyImportException, "Optional member '.auxdata' is not a string."); result->m_auxiliaryData = fromHex(_json[".auxdata"].asString()); From 5aed7515efd427b8f13f0abf3313539166292a3c Mon Sep 17 00:00:00 2001 From: r0qs Date: Mon, 19 Feb 2024 10:22:12 +0100 Subject: [PATCH 07/57] Use ethers version 6.11.0 on openzeppelin external tests --- test/externalTests/zeppelin.sh | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/externalTests/zeppelin.sh b/test/externalTests/zeppelin.sh index 64e6f5f0ec..9f72aa4ec9 100755 --- a/test/externalTests/zeppelin.sh +++ b/test/externalTests/zeppelin.sh @@ -110,6 +110,13 @@ function zeppelin_test # Maybe related to the use of dynamic imports here: https://github.com/NomicFoundation/hardhat/commit/16ae15642951ac324ef7093a3342f7cf3a2a49a4 npm install @nomicfoundation/hardhat-chai-matchers@2.0.3 + # TODO: Remove when OpenZeppelin update to ethers 6.11.1+ + # Prior versions of ethers accepts an object instead of a string as an argument to the toUtf8Bytes function. + # However, starting from Ethers version 6.11.1, string arguments are enforced, + # which causes the introduced assertion to fail in some OpenZeppelin tests. + # See: https://github.com/ethers-io/ethers.js/issues/4583 + npm install ethers@6.11.0 + replace_version_pragmas for preset in $SELECTED_PRESETS; do From c21490f3c2e5c66e224029fc7f9cb482168bd7fe Mon Sep 17 00:00:00 2001 From: Alexander Arlt Date: Mon, 19 Feb 2024 13:34:15 +0100 Subject: [PATCH 08/57] [ci] Remove usage of ETH_EVMONE environment variable. --- .circleci/config.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index b29c46bf8b..f3843a6898 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -498,7 +498,6 @@ defaults: TERM: xterm MAKEFLAGS: -j5 CPUs: 5 - ETH_EVMONE: /usr/local/lib/libevmone.dylib - base_python_small: &base_python_small docker: From 18cabee1e4f60aae045ee9a0a0f2aba6d0d2c279 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Tue, 9 Jan 2024 14:08:38 +0100 Subject: [PATCH 09/57] CompilerStack: Don't swallow details include in OptimizerException - By catching and asserting it we hide the line number and message. - OptimizerException inherits from util::Exception so just letting it through will have the same effect as asserting. --- libsolidity/interface/CompilerStack.cpp | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp index 9b5c87818b..6939441758 100644 --- a/libsolidity/interface/CompilerStack.cpp +++ b/libsolidity/interface/CompilerStack.cpp @@ -1480,15 +1480,8 @@ void CompilerStack::compileContract( solAssert(!m_viaIR, ""); bytes cborEncodedMetadata = createCBORMetadata(compiledContract, /* _forIR */ false); - try - { - // Run optimiser and compile the contract. - compiler->compileContract(_contract, _otherCompilers, cborEncodedMetadata); - } - catch(evmasm::OptimizerException const&) - { - solAssert(false, "Optimizer exception during compilation"); - } + // Run optimiser and compile the contract. + compiler->compileContract(_contract, _otherCompilers, cborEncodedMetadata); _otherCompilers[compiledContract.contract] = compiler; From f5188158f7edbc672cfc2b5b9125730bbf1886b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Tue, 9 Jan 2024 16:44:27 +0100 Subject: [PATCH 10/57] Remove obsolete gas cost tiers - They're no longer used because the cost depends on the EVM version. --- libevmasm/Assembly.cpp | 1 - libevmasm/GasMeter.cpp | 24 +++++++++++++----------- libevmasm/Instruction.cpp | 12 ++++++------ libevmasm/Instruction.h | 2 -- solc/CommandLineInterface.cpp | 2 -- 5 files changed, 19 insertions(+), 22 deletions(-) diff --git a/libevmasm/Assembly.cpp b/libevmasm/Assembly.cpp index ab6ac2c63f..3f067ff6bc 100644 --- a/libevmasm/Assembly.cpp +++ b/libevmasm/Assembly.cpp @@ -29,7 +29,6 @@ #include #include #include -#include #include #include diff --git a/libevmasm/GasMeter.cpp b/libevmasm/GasMeter.cpp index 5982b8a080..e237e32a26 100644 --- a/libevmasm/GasMeter.cpp +++ b/libevmasm/GasMeter.cpp @@ -274,18 +274,20 @@ unsigned GasMeter::runGas(Instruction _instruction, langutil::EVMVersion _evmVer switch (instructionInfo(_instruction, _evmVersion).gasPriceTier) { - case Tier::Zero: return GasCosts::tier0Gas; - case Tier::Base: return GasCosts::tier1Gas; - case Tier::VeryLow: return GasCosts::tier2Gas; - case Tier::Low: return GasCosts::tier3Gas; - case Tier::Mid: return GasCosts::tier4Gas; - case Tier::High: return GasCosts::tier5Gas; - case Tier::Ext: return GasCosts::tier6Gas; - case Tier::WarmAccess: return GasCosts::warmStorageReadCost; - default: break; + case Tier::Zero: return GasCosts::tier0Gas; + case Tier::Base: return GasCosts::tier1Gas; + case Tier::VeryLow: return GasCosts::tier2Gas; + case Tier::Low: return GasCosts::tier3Gas; + case Tier::Mid: return GasCosts::tier4Gas; + case Tier::High: return GasCosts::tier5Gas; + case Tier::Ext: return GasCosts::tier6Gas; + case Tier::WarmAccess: return GasCosts::warmStorageReadCost; + + case Tier::Special: + case Tier::Invalid: + assertThrow(false, OptimizerException, "Invalid gas tier for instruction " + instructionInfo(_instruction, _evmVersion).name); } - assertThrow(false, OptimizerException, "Invalid gas tier for instruction " + instructionInfo(_instruction, _evmVersion).name); - return 0; + util::unreachable(); } u256 GasMeter::dataGas(bytes const& _data, bool _inCreation, langutil::EVMVersion _evmVersion) diff --git a/libevmasm/Instruction.cpp b/libevmasm/Instruction.cpp index a21f33e183..4e0684b6b4 100644 --- a/libevmasm/Instruction.cpp +++ b/libevmasm/Instruction.cpp @@ -211,7 +211,7 @@ static std::map const c_instructionInfo = { Instruction::SIGNEXTEND, { "SIGNEXTEND", 0, 2, 1, false, Tier::Low } }, { Instruction::KECCAK256, { "KECCAK256", 0, 2, 1, true, Tier::Special } }, { Instruction::ADDRESS, { "ADDRESS", 0, 0, 1, false, Tier::Base } }, - { Instruction::BALANCE, { "BALANCE", 0, 1, 1, false, Tier::Balance } }, + { Instruction::BALANCE, { "BALANCE", 0, 1, 1, false, Tier::Special } }, { Instruction::ORIGIN, { "ORIGIN", 0, 0, 1, false, Tier::Base } }, { Instruction::CALLER, { "CALLER", 0, 0, 1, false, Tier::Base } }, { Instruction::CALLVALUE, { "CALLVALUE", 0, 0, 1, false, Tier::Base } }, @@ -221,12 +221,12 @@ static std::map const c_instructionInfo = { Instruction::CODESIZE, { "CODESIZE", 0, 0, 1, false, Tier::Base } }, { Instruction::CODECOPY, { "CODECOPY", 0, 3, 0, true, Tier::VeryLow } }, { Instruction::GASPRICE, { "GASPRICE", 0, 0, 1, false, Tier::Base } }, - { Instruction::EXTCODESIZE, { "EXTCODESIZE", 0, 1, 1, false, Tier::ExtCode } }, - { Instruction::EXTCODECOPY, { "EXTCODECOPY", 0, 4, 0, true, Tier::ExtCode } }, - { Instruction::RETURNDATASIZE, {"RETURNDATASIZE", 0, 0, 1, false, Tier::Base } }, - { Instruction::RETURNDATACOPY, {"RETURNDATACOPY", 0, 3, 0, true, Tier::VeryLow } }, + { Instruction::EXTCODESIZE, { "EXTCODESIZE", 0, 1, 1, false, Tier::Special } }, + { Instruction::EXTCODECOPY, { "EXTCODECOPY", 0, 4, 0, true, Tier::Special } }, + { Instruction::RETURNDATASIZE, {"RETURNDATASIZE", 0, 0, 1, false, Tier::Base } }, + { Instruction::RETURNDATACOPY, {"RETURNDATACOPY", 0, 3, 0, true, Tier::VeryLow } }, { Instruction::MCOPY, { "MCOPY", 0, 3, 0, true, Tier::VeryLow } }, - { Instruction::EXTCODEHASH, { "EXTCODEHASH", 0, 1, 1, false, Tier::Balance } }, + { Instruction::EXTCODEHASH, { "EXTCODEHASH", 0, 1, 1, false, Tier::Special } }, { Instruction::BLOCKHASH, { "BLOCKHASH", 0, 1, 1, false, Tier::Ext } }, { Instruction::BLOBHASH, { "BLOBHASH", 0, 1, 1, false, Tier::VeryLow } }, { Instruction::COINBASE, { "COINBASE", 0, 0, 1, false, Tier::Base } }, diff --git a/libevmasm/Instruction.h b/libevmasm/Instruction.h index 1733863aa5..d29a6feca7 100644 --- a/libevmasm/Instruction.h +++ b/libevmasm/Instruction.h @@ -297,8 +297,6 @@ enum class Tier High, // 10, Slow Ext, // 20, Ext WarmAccess, // 100, Warm Access - ExtCode, // 700, Extcode - Balance, // 400, Balance Special, // multiparam or otherwise special Invalid // Invalid. }; diff --git a/solc/CommandLineInterface.cpp b/solc/CommandLineInterface.cpp index 7181bfd4cc..4c08efb51a 100644 --- a/solc/CommandLineInterface.cpp +++ b/solc/CommandLineInterface.cpp @@ -43,9 +43,7 @@ #include -#include #include -#include #include #include From 686f5cd455c837d6a54f819c8cff66733e2ecc8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Tue, 9 Jan 2024 15:54:03 +0100 Subject: [PATCH 11/57] Document the Tier enum and constants that come from Execution Specs --- libevmasm/GasMeter.h | 56 +++++++++++++++++++++-------------------- libevmasm/Instruction.h | 25 ++++++++++-------- 2 files changed, 44 insertions(+), 37 deletions(-) diff --git a/libevmasm/GasMeter.h b/libevmasm/GasMeter.h index ec19466447..e4bb199257 100644 --- a/libevmasm/GasMeter.h +++ b/libevmasm/GasMeter.h @@ -43,32 +43,34 @@ class KnownState; namespace GasCosts { + /// NOTE: The GAS_... constants referenced by comments are defined for each EVM version in the Execution Specs: + /// https://ethereum.github.io/execution-specs/autoapi/ethereum//vm/gas/index.html + static unsigned const stackLimit = 1024; - static unsigned const tier0Gas = 0; - static unsigned const tier1Gas = 2; - static unsigned const tier2Gas = 3; - static unsigned const tier3Gas = 5; - static unsigned const tier4Gas = 8; - static unsigned const tier5Gas = 10; - static unsigned const tier6Gas = 20; - static unsigned const tier7Gas = 0; - static unsigned const expGas = 10; + static unsigned const tier0Gas = 0; // GAS_ZERO (in Execution Specs) + static unsigned const tier1Gas = 2; // GAS_BASE + static unsigned const tier2Gas = 3; // GAS_VERY_LOW + static unsigned const tier3Gas = 5; // GAS_LOW / GAS_FAST_STEP + static unsigned const tier4Gas = 8; // GAS_MID + static unsigned const tier5Gas = 10; // GAS_HIGH + static unsigned const tier6Gas = 20; // GAS_BLOCK_HASH + static unsigned const expGas = 10; // GAS_EXPONENTIATION inline unsigned expByteGas(langutil::EVMVersion _evmVersion) { - return _evmVersion >= langutil::EVMVersion::spuriousDragon() ? 50 : 10; + return _evmVersion >= langutil::EVMVersion::spuriousDragon() ? 50 : 10; // GAS_EXPONENTIATION_PER_BYTE } - static unsigned const keccak256Gas = 30; - static unsigned const keccak256WordGas = 6; + static unsigned const keccak256Gas = 30; // GAS_KECCAK256 + static unsigned const keccak256WordGas = 6; // GAS_KECCAK256_WORD /// Corresponds to ACCESS_LIST_ADDRESS_COST from EIP-2930 static unsigned const accessListAddressCost = 2400; /// Corresponds to ACCESS_LIST_STORAGE_COST from EIP-2930 static unsigned const accessListStorageKeyCost = 1900; /// Corresponds to COLD_SLOAD_COST from EIP-2929 - static unsigned const coldSloadCost = 2100; + static unsigned const coldSloadCost = 2100; // GAS_COLD_SLOAD /// Corresponds to COLD_ACCOUNT_ACCESS_COST from EIP-2929 - static unsigned const coldAccountAccessCost = 2600; + static unsigned const coldAccountAccessCost = 2600; // GAS_COLD_ACCOUNT_ACCESS /// Corresponds to WARM_STORAGE_READ_COST from EIP-2929 - static unsigned const warmStorageReadCost = 100; + static unsigned const warmStorageReadCost = 100; // GAS_WARM_ACCESS inline unsigned sloadGas(langutil::EVMVersion _evmVersion) { if (_evmVersion >= langutil::EVMVersion::berlin()) @@ -81,7 +83,7 @@ namespace GasCosts return 50; } /// Corresponds to SSTORE_SET_GAS - static unsigned const sstoreSetGas = 20000; + static unsigned const sstoreSetGas = 20000; // GAS_STORAGE_SET /// Corresponds to SSTORE_RESET_GAS from EIP-2929 static unsigned const sstoreResetGas = 5000 - coldSloadCost; /// Corresponds to SSTORE_CLEARS_SCHEDULE from EIP-2200 @@ -130,11 +132,11 @@ namespace GasCosts else return 20; } - static unsigned const jumpdestGas = 1; - static unsigned const logGas = 375; - static unsigned const logDataGas = 8; - static unsigned const logTopicGas = 375; - static unsigned const createGas = 32000; + static unsigned const jumpdestGas = 1; // GAS_JUMPDEST + static unsigned const logGas = 375; // GAS_LOG + static unsigned const logDataGas = 8; // GAS_LOG_DATA + static unsigned const logTopicGas = 375; // GAS_LOG_TOPIC + static unsigned const createGas = 32000; // GAS_CREATE inline unsigned callGas(langutil::EVMVersion _evmVersion) { if (_evmVersion >= langutil::EVMVersion::berlin()) @@ -144,10 +146,10 @@ namespace GasCosts else return 40; } - static unsigned const callStipend = 2300; - static unsigned const callValueTransferGas = 9000; - static unsigned const callNewAccountGas = 25000; - inline unsigned selfdestructGas(langutil::EVMVersion _evmVersion) + static unsigned const callStipend = 2300; // GAS_CALL_STIPEND + static unsigned const callValueTransferGas = 9000; // GAS_CALL_VALUE + static unsigned const callNewAccountGas = 25000; // GAS_NEW_ACCOUNT / GAS_SELF_DESTRUCT_NEW_ACCOUNT + inline unsigned selfdestructGas(langutil::EVMVersion _evmVersion) // GAS_SELF_DESTRUCT { if (_evmVersion >= langutil::EVMVersion::berlin()) return coldAccountAccessCost; @@ -164,9 +166,9 @@ namespace GasCosts else return 24000; } - static unsigned const memoryGas = 3; + static unsigned const memoryGas = 3; // GAS_MEMORY / GAS_COPY / GAS_RETURN_DATA_COPY static unsigned const quadCoeffDiv = 512; - static unsigned const createDataGas = 200; + static unsigned const createDataGas = 200; // GAS_CODE_DEPOSIT static unsigned const txGas = 21000; static unsigned const txCreateGas = 53000; static unsigned const txDataZeroGas = 4; diff --git a/libevmasm/Instruction.h b/libevmasm/Instruction.h index d29a6feca7..7d551f71d7 100644 --- a/libevmasm/Instruction.h +++ b/libevmasm/Instruction.h @@ -287,18 +287,23 @@ inline Instruction logInstruction(unsigned _number) return Instruction(unsigned(Instruction::LOG0) + _number); } +/// Gas price tiers representing static cost of an instruction. +/// Opcodes whose cost is dynamic or depends on EVM version should use the `Special` tier and need +/// dedicated logic in GasMeter (especially in estimateMax()). +/// The tiers loosely follow opcode groups originally defined in the Yellow Paper. enum class Tier { - Zero = 0, // 0, Zero - Base, // 2, Quick - VeryLow, // 3, Fastest - Low, // 5, Fast - Mid, // 8, Mid - High, // 10, Slow - Ext, // 20, Ext - WarmAccess, // 100, Warm Access - Special, // multiparam or otherwise special - Invalid // Invalid. + // NOTE: Tiers should be ordered by cost, since we sometimes perform comparisons between them. + Zero = 0, // 0, Zero + Base, // 2, Quick + VeryLow, // 3, Fastest + Low, // 5, Fast + Mid, // 8, Mid + High, // 10, Slow + Ext, // 20, Ext + WarmAccess, // 100, Warm Access + Special, // multiparam or otherwise special + Invalid, // Invalid. }; /// Information structure for a particular instruction. From a973b4c6bffbd25497fb6b06fa1935ce4b63cbcd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Tue, 9 Jan 2024 17:13:42 +0100 Subject: [PATCH 12/57] Rename Ext gas cost tier to BlockHash --- libevmasm/GasMeter.cpp | 2 +- libevmasm/Instruction.cpp | 2 +- libevmasm/Instruction.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libevmasm/GasMeter.cpp b/libevmasm/GasMeter.cpp index e237e32a26..b3d160585e 100644 --- a/libevmasm/GasMeter.cpp +++ b/libevmasm/GasMeter.cpp @@ -280,7 +280,7 @@ unsigned GasMeter::runGas(Instruction _instruction, langutil::EVMVersion _evmVer case Tier::Low: return GasCosts::tier3Gas; case Tier::Mid: return GasCosts::tier4Gas; case Tier::High: return GasCosts::tier5Gas; - case Tier::Ext: return GasCosts::tier6Gas; + case Tier::BlockHash: return GasCosts::tier6Gas; case Tier::WarmAccess: return GasCosts::warmStorageReadCost; case Tier::Special: diff --git a/libevmasm/Instruction.cpp b/libevmasm/Instruction.cpp index 4e0684b6b4..ca0dff185a 100644 --- a/libevmasm/Instruction.cpp +++ b/libevmasm/Instruction.cpp @@ -227,7 +227,7 @@ static std::map const c_instructionInfo = { Instruction::RETURNDATACOPY, {"RETURNDATACOPY", 0, 3, 0, true, Tier::VeryLow } }, { Instruction::MCOPY, { "MCOPY", 0, 3, 0, true, Tier::VeryLow } }, { Instruction::EXTCODEHASH, { "EXTCODEHASH", 0, 1, 1, false, Tier::Special } }, - { Instruction::BLOCKHASH, { "BLOCKHASH", 0, 1, 1, false, Tier::Ext } }, + { Instruction::BLOCKHASH, { "BLOCKHASH", 0, 1, 1, false, Tier::BlockHash } }, { Instruction::BLOBHASH, { "BLOBHASH", 0, 1, 1, false, Tier::VeryLow } }, { Instruction::COINBASE, { "COINBASE", 0, 0, 1, false, Tier::Base } }, { Instruction::TIMESTAMP, { "TIMESTAMP", 0, 0, 1, false, Tier::Base } }, diff --git a/libevmasm/Instruction.h b/libevmasm/Instruction.h index 7d551f71d7..289469b5ef 100644 --- a/libevmasm/Instruction.h +++ b/libevmasm/Instruction.h @@ -300,7 +300,7 @@ enum class Tier Low, // 5, Fast Mid, // 8, Mid High, // 10, Slow - Ext, // 20, Ext + BlockHash, // 20 WarmAccess, // 100, Warm Access Special, // multiparam or otherwise special Invalid, // Invalid. From 88ee7d8bb57075c94df3d70fce115357f1290b0c Mon Sep 17 00:00:00 2001 From: Alexander Arlt Date: Mon, 19 Feb 2024 16:28:08 +0100 Subject: [PATCH 13/57] [ci] Remove code signature from universal binary. --- .circleci/config.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index b29c46bf8b..672b77c96d 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -242,6 +242,13 @@ commands: # -------------------------------------------------------------------------- # Artifact Commands + remove_signature_from_universal_binary: + description: Remove signature from universal binary + steps: + - run: + name: Remove signature from universal binary + command: codesign --remove-signature build/solc/solc + store_artifacts_solc: description: Store compiled solc executable as artifact steps: @@ -1156,6 +1163,7 @@ jobs: - checkout - install_dependencies_osx - run_build + - remove_signature_from_universal_binary - store_artifacts_solc - store_artifacts_yul_phaser - persist_executables_to_workspace_osx From ac54fe1972f25227f9932c8b224ef119360b0e2d Mon Sep 17 00:00:00 2001 From: Nikola Matic Date: Thu, 11 Jan 2024 13:58:23 +0100 Subject: [PATCH 14/57] Purge using namespace std from test --- scripts/check_style.sh | 1 + test/Common.cpp | 34 +++++++------- test/CommonSyntaxTest.cpp | 69 ++++++++++++++-------------- test/EVMHost.cpp | 55 +++++++++++------------ test/ExecutionFramework.cpp | 45 +++++++++---------- test/FilesystemUtils.cpp | 17 ++++--- test/Metadata.cpp | 24 +++++----- test/TestCase.cpp | 35 +++++++-------- test/TestCaseReader.cpp | 89 ++++++++++++++++++------------------- test/soltest.cpp | 21 +++++---- 10 files changed, 192 insertions(+), 198 deletions(-) diff --git a/scripts/check_style.sh b/scripts/check_style.sh index fe4d19734f..3c9acf86ca 100755 --- a/scripts/check_style.sh +++ b/scripts/check_style.sh @@ -39,6 +39,7 @@ NAMESPACE_STD_FREE_FILES=( libyul/backends/evm/* libyul/optimiser/* solc/* + test/* test/contracts/* test/libevmasm/* test/liblangutil/* diff --git a/test/Common.cpp b/test/Common.cpp index bb4d2db7eb..ae725774c4 100644 --- a/test/Common.cpp +++ b/test/Common.cpp @@ -32,8 +32,6 @@ namespace fs = boost::filesystem; namespace po = boost::program_options; -using namespace std; - namespace solidity::test { @@ -147,15 +145,15 @@ void CommonOptions::validate() const ); if (!enforceGasTest) - cout << endl << "WARNING :: Gas cost expectations are not being enforced" << endl << endl; + std::cout << std::endl << "WARNING :: Gas cost expectations are not being enforced" << std::endl << std::endl; else if (evmVersion() != langutil::EVMVersion{} || useABIEncoderV1) { - cout << endl << "WARNING :: Enforcing gas cost expectations with non-standard settings:" << endl; + std::cout << std::endl << "WARNING :: Enforcing gas cost expectations with non-standard settings:" << std::endl; if (evmVersion() != langutil::EVMVersion{}) - cout << "- EVM version: " << evmVersion().name() << " (default: " << langutil::EVMVersion{}.name() << ")" << endl; + std::cout << "- EVM version: " << evmVersion().name() << " (default: " << langutil::EVMVersion{}.name() << ")" << std::endl; if (useABIEncoderV1) - cout << "- ABI coder: v1 (default: v2)" << endl; - cout << endl << "DO NOT COMMIT THE UPDATED EXPECTATIONS." << endl << endl; + std::cout << "- ABI coder: v1 (default: v2)" << std::endl; + std::cout << std::endl << "DO NOT COMMIT THE UPDATED EXPECTATIONS." << std::endl << std::endl; } } @@ -176,7 +174,7 @@ bool CommonOptions::parse(int argc, char const* const* argv) // Request as uint64_t, since uint8_t will be parsed as character by boost. uint64_t eofVersion = arguments["eof-version"].as(); if (eofVersion != 1) - BOOST_THROW_EXCEPTION(std::runtime_error("Invalid EOF version: " + to_string(eofVersion))); + BOOST_THROW_EXCEPTION(std::runtime_error("Invalid EOF version: " + std::to_string(eofVersion))); m_eofVersion = 1; } @@ -213,18 +211,18 @@ bool CommonOptions::parse(int argc, char const* const* argv) return true; } -string CommonOptions::toString(vector const& _selectedOptions) const +std::string CommonOptions::toString(std::vector const& _selectedOptions) const { if (_selectedOptions.empty()) return ""; - auto boolToString = [](bool _value) -> string { return _value ? "true" : "false"; }; + auto boolToString = [](bool _value) -> std::string { return _value ? "true" : "false"; }; // Using std::map to avoid if-else/switch-case block - map optionValueMap = { + std::map optionValueMap = { {"evmVersion", evmVersion().name()}, {"optimize", boolToString(optimize)}, {"useABIEncoderV1", boolToString(useABIEncoderV1)}, - {"batch", to_string(selectedBatch + 1) + "/" + to_string(batches)}, + {"batch", std::to_string(selectedBatch + 1) + "/" + std::to_string(batches)}, {"enforceGasTest", boolToString(enforceGasTest)}, {"enforceGasTestMinValue", enforceGasTestMinValue.str()}, {"disableSemanticTests", boolToString(disableSemanticTests)}, @@ -233,18 +231,18 @@ string CommonOptions::toString(vector const& _selectedOptions) const {"showMetadata", boolToString(showMetadata)} }; - soltestAssert(ranges::all_of(_selectedOptions, [&optionValueMap](string const& _option) { return optionValueMap.count(_option) > 0; })); + soltestAssert(ranges::all_of(_selectedOptions, [&optionValueMap](std::string const& _option) { return optionValueMap.count(_option) > 0; })); - vector optionsWithValues = _selectedOptions | - ranges::views::transform([&optionValueMap](string const& _option) { return _option + "=" + optionValueMap.at(_option); }) | - ranges::to(); + std::vector optionsWithValues = _selectedOptions | + ranges::views::transform([&optionValueMap](std::string const& _option) { return _option + "=" + optionValueMap.at(_option); }) | + ranges::to(); return solidity::util::joinHumanReadable(optionsWithValues); } -void CommonOptions::printSelectedOptions(ostream& _stream, string const& _linePrefix, vector const& _selectedOptions) const +void CommonOptions::printSelectedOptions(std::ostream& _stream, std::string const& _linePrefix, std::vector const& _selectedOptions) const { - _stream << _linePrefix << "Run Settings: " << toString(_selectedOptions) << endl; + _stream << _linePrefix << "Run Settings: " << toString(_selectedOptions) << std::endl; } langutil::EVMVersion CommonOptions::evmVersion() const diff --git a/test/CommonSyntaxTest.cpp b/test/CommonSyntaxTest.cpp index 0dedd1fb04..3cb908118e 100644 --- a/test/CommonSyntaxTest.cpp +++ b/test/CommonSyntaxTest.cpp @@ -34,7 +34,6 @@ #include #include -using namespace std; using namespace solidity; using namespace solidity::util; using namespace solidity::util::formatting; @@ -48,10 +47,10 @@ namespace fs = boost::filesystem; namespace { -int parseUnsignedInteger(string::iterator& _it, string::iterator _end) +int parseUnsignedInteger(std::string::iterator& _it, std::string::iterator _end) { if (_it == _end || !util::isDigit(*_it)) - BOOST_THROW_EXCEPTION(runtime_error("Invalid test expectation. Source location expected.")); + BOOST_THROW_EXCEPTION(std::runtime_error("Invalid test expectation. Source location expected.")); int result = 0; while (_it != _end && util::isDigit(*_it)) { @@ -64,7 +63,7 @@ int parseUnsignedInteger(string::iterator& _it, string::iterator _end) } -CommonSyntaxTest::CommonSyntaxTest(string const& _filename, langutil::EVMVersion _evmVersion): +CommonSyntaxTest::CommonSyntaxTest(std::string const& _filename, langutil::EVMVersion _evmVersion): EVMVersionRestrictedTestCase(_filename), m_sources(m_reader.sources()), m_expectations(parseExpectations(m_reader.stream())), @@ -72,7 +71,7 @@ CommonSyntaxTest::CommonSyntaxTest(string const& _filename, langutil::EVMVersion { } -TestCase::TestResult CommonSyntaxTest::run(ostream& _stream, string const& _linePrefix, bool _formatted) +TestCase::TestResult CommonSyntaxTest::run(std::ostream& _stream, std::string const& _linePrefix, bool _formatted) { parseCustomExpectations(m_reader.stream()); parseAndAnalyze(); @@ -80,7 +79,7 @@ TestCase::TestResult CommonSyntaxTest::run(ostream& _stream, string const& _line return conclude(_stream, _linePrefix, _formatted); } -TestCase::TestResult CommonSyntaxTest::conclude(ostream& _stream, string const& _linePrefix, bool _formatted) +TestCase::TestResult CommonSyntaxTest::conclude(std::ostream& _stream, std::string const& _linePrefix, bool _formatted) { if (expectationsMatch()) return TestResult::Success; @@ -89,16 +88,16 @@ TestCase::TestResult CommonSyntaxTest::conclude(ostream& _stream, string const& return TestResult::Failure; } -void CommonSyntaxTest::printExpectationAndError(ostream& _stream, string const& _linePrefix, bool _formatted) +void CommonSyntaxTest::printExpectationAndError(std::ostream& _stream, std::string const& _linePrefix, bool _formatted) { - string nextIndentLevel = _linePrefix + " "; - util::AnsiColorized(_stream, _formatted, {BOLD, CYAN}) << _linePrefix << "Expected result:" << endl; + std::string nextIndentLevel = _linePrefix + " "; + util::AnsiColorized(_stream, _formatted, {BOLD, CYAN}) << _linePrefix << "Expected result:" << std::endl; printExpectedResult(_stream, nextIndentLevel, _formatted); - util::AnsiColorized(_stream, _formatted, {BOLD, CYAN}) << _linePrefix << "Obtained result:" << endl; + util::AnsiColorized(_stream, _formatted, {BOLD, CYAN}) << _linePrefix << "Obtained result:" << std::endl; printObtainedResult(_stream, nextIndentLevel, _formatted); } -void CommonSyntaxTest::printSource(ostream& _stream, string const& _linePrefix, bool _formatted) const +void CommonSyntaxTest::printSource(std::ostream& _stream, std::string const& _linePrefix, bool _formatted) const { if (m_sources.sources.empty()) return; @@ -113,8 +112,8 @@ void CommonSyntaxTest::printSource(ostream& _stream, string const& _linePrefix, continue; if (outputSourceNames) - _stream << _linePrefix << util::formatting::CYAN << "==== Source: " << name << " ====" << util::formatting::RESET << endl; - vector sourceFormatting(source.length(), util::formatting::RESET); + _stream << _linePrefix << util::formatting::CYAN << "==== Source: " << name << " ====" << util::formatting::RESET << std::endl; + std::vector sourceFormatting(source.length(), util::formatting::RESET); for (auto const& error: m_errorList) if (error.sourceName == name && error.locationStart >= 0 && error.locationEnd >= 0) { @@ -143,7 +142,7 @@ void CommonSyntaxTest::printSource(ostream& _stream, string const& _linePrefix, _stream << source[i]; else { - _stream << util::formatting::RESET << endl; + _stream << util::formatting::RESET << std::endl; if (i + 1 < source.length()) _stream << _linePrefix << sourceFormatting[i]; } @@ -158,9 +157,9 @@ void CommonSyntaxTest::printSource(ostream& _stream, string const& _linePrefix, } } -void CommonSyntaxTest::parseCustomExpectations(istream& _stream) +void CommonSyntaxTest::parseCustomExpectations(std::istream& _stream) { - string remainingExpectations = boost::trim_copy(readUntilEnd(_stream)); + std::string remainingExpectations = boost::trim_copy(readUntilEnd(_stream)); soltestAssert( remainingExpectations.empty(), "Found custom expectations not supported by the test case:\n" + remainingExpectations @@ -172,27 +171,27 @@ bool CommonSyntaxTest::expectationsMatch() return m_expectations == m_errorList; } -void CommonSyntaxTest::printExpectedResult(ostream& _stream, string const& _linePrefix, bool _formatted) const +void CommonSyntaxTest::printExpectedResult(std::ostream& _stream, std::string const& _linePrefix, bool _formatted) const { printErrorList(_stream, m_expectations, _linePrefix, _formatted); } -void CommonSyntaxTest::printObtainedResult(ostream& _stream, string const& _linePrefix, bool _formatted) const +void CommonSyntaxTest::printObtainedResult(std::ostream& _stream, std::string const& _linePrefix, bool _formatted) const { printErrorList(_stream, m_errorList, _linePrefix, _formatted); } void CommonSyntaxTest::printErrorList( - ostream& _stream, - vector const& _errorList, - string const& _linePrefix, + std::ostream& _stream, + std::vector const& _errorList, + std::string const& _linePrefix, bool _formatted ) { if (_errorList.empty()) { if (_formatted) - util::AnsiColorized(_stream, _formatted, {BOLD, GREEN}) << _linePrefix << "Success" << endl; + util::AnsiColorized(_stream, _formatted, {BOLD, GREEN}) << _linePrefix << "Success" << std::endl; } else for (auto const& error: _errorList) @@ -220,11 +219,11 @@ void CommonSyntaxTest::printErrorList( _stream << error.locationEnd; _stream << "): "; } - _stream << error.message << endl; + _stream << error.message << std::endl; } } -string CommonSyntaxTest::errorMessage(util::Exception const& _e) +std::string CommonSyntaxTest::errorMessage(util::Exception const& _e) { if (_e.comment() && !_e.comment()->empty()) return boost::replace_all_copy(*_e.comment(), "\n", "\\n"); @@ -232,13 +231,13 @@ string CommonSyntaxTest::errorMessage(util::Exception const& _e) return "NONE"; } -vector CommonSyntaxTest::parseExpectations(istream& _stream) +std::vector CommonSyntaxTest::parseExpectations(std::istream& _stream) { - static string const customExpectationsDelimiter("// ----"); + static std::string const customExpectationsDelimiter("// ----"); - vector expectations; - string line; - while (getline(_stream, line)) + std::vector expectations; + std::string line; + while (std::getline(_stream, line)) { auto it = line.begin(); @@ -254,17 +253,17 @@ vector CommonSyntaxTest::parseExpectations(istream& _stream) if (it == line.end()) continue; auto typeBegin = it; - while (it != line.end() && isalpha(*it, locale::classic())) + while (it != line.end() && isalpha(*it, std::locale::classic())) ++it; - string errorTypeStr(typeBegin, it); - optional errorType = Error::parseErrorType(errorTypeStr); + std::string errorTypeStr(typeBegin, it); + std::optional errorType = Error::parseErrorType(errorTypeStr); if (!errorType.has_value()) - BOOST_THROW_EXCEPTION(runtime_error("Invalid error type: " + errorTypeStr)); + BOOST_THROW_EXCEPTION(std::runtime_error("Invalid error type: " + errorTypeStr)); skipWhitespace(it, line.end()); - optional errorId; + std::optional errorId; if (it != line.end() && util::isDigit(*it)) errorId = ErrorId{static_cast(parseUnsignedInteger(it, line.end()))}; @@ -295,7 +294,7 @@ vector CommonSyntaxTest::parseExpectations(istream& _stream) skipWhitespace(it, line.end()); - string errorMessage(it, line.end()); + std::string errorMessage(it, line.end()); expectations.emplace_back(SyntaxTestError{ errorType.value(), std::move(errorId), diff --git a/test/EVMHost.cpp b/test/EVMHost.cpp index 7e05ceec3e..9af4d7099d 100644 --- a/test/EVMHost.cpp +++ b/test/EVMHost.cpp @@ -31,16 +31,15 @@ #include #include -using namespace std; using namespace solidity; using namespace solidity::util; using namespace solidity::test; using namespace evmc::literals; -evmc::VM& EVMHost::getVM(string const& _path) +evmc::VM& EVMHost::getVM(std::string const& _path) { static evmc::VM NullVM{nullptr}; - static map> vms; + static std::map> vms; if (vms.count(_path) == 0) { evmc_loader_error_code errorCode = {}; @@ -48,16 +47,16 @@ evmc::VM& EVMHost::getVM(string const& _path) if (vm && errorCode == EVMC_LOADER_SUCCESS) { if (vm.get_capabilities() & (EVMC_CAPABILITY_EVM1)) - vms[_path] = make_unique(evmc::VM(std::move(vm))); + vms[_path] = std::make_unique(evmc::VM(std::move(vm))); else - cerr << "VM loaded does not support EVM1" << endl; + std::cerr << "VM loaded does not support EVM1" << std::endl; } else { - cerr << "Error loading VM from " << _path; + std::cerr << "Error loading VM from " << _path; if (char const* errorMsg = evmc_last_error_msg()) - cerr << ":" << endl << errorMsg; - cerr << endl; + std::cerr << ":" << std::endl << errorMsg; + std::cerr << std::endl; } } @@ -67,7 +66,7 @@ evmc::VM& EVMHost::getVM(string const& _path) return NullVM; } -bool EVMHost::checkVmPaths(vector const& _vmPaths) +bool EVMHost::checkVmPaths(std::vector const& _vmPaths) { bool evmVmFound = false; for (auto const& path: _vmPaths) @@ -79,7 +78,7 @@ bool EVMHost::checkVmPaths(vector const& _vmPaths) if (vm.has_capability(EVMC_CAPABILITY_EVM1)) { if (evmVmFound) - BOOST_THROW_EXCEPTION(runtime_error("Multiple evm1 evmc vms defined. Please only define one evm1 evmc vm.")); + BOOST_THROW_EXCEPTION(std::runtime_error("Multiple evm1 evmc vms defined. Please only define one evm1 evmc vm.")); evmVmFound = true; } } @@ -92,7 +91,7 @@ EVMHost::EVMHost(langutil::EVMVersion _evmVersion, evmc::VM& _vm): { if (!m_vm) { - cerr << "Unable to find evmone library" << endl; + std::cerr << "Unable to find evmone library" << std::endl; assertThrow(false, Exception, ""); } @@ -319,7 +318,7 @@ evmc::Result EVMHost::call(evmc_message const& _message) noexcept h160 createAddress(keccak256( bytes{static_cast(0xc0 + 21 + encodedNonce.size())} + bytes{0x94} + - bytes(begin(message.sender.bytes), end(message.sender.bytes)) + + bytes(std::begin(message.sender.bytes), std::end(message.sender.bytes)) + encodedNonce ), h160::AlignRight); @@ -332,8 +331,8 @@ evmc::Result EVMHost::call(evmc_message const& _message) noexcept { h160 createAddress(keccak256( bytes{0xff} + - bytes(begin(message.sender.bytes), end(message.sender.bytes)) + - bytes(begin(message.create2_salt.bytes), end(message.create2_salt.bytes)) + + bytes(std::begin(message.sender.bytes), std::end(message.sender.bytes)) + + bytes(std::begin(message.create2_salt.bytes), std::end(message.create2_salt.bytes)) + keccak256(bytes(message.input_data, message.input_data + message.input_size)).asBytes() ), h160::AlignRight); @@ -421,7 +420,7 @@ evmc::bytes32 EVMHost::get_block_hash(int64_t _number) const noexcept h160 EVMHost::convertFromEVMC(evmc::address const& _addr) { - return h160(bytes(begin(_addr.bytes), end(_addr.bytes))); + return h160(bytes(std::begin(_addr.bytes), std::end(_addr.bytes))); } evmc::address EVMHost::convertToEVMC(h160 const& _addr) @@ -434,7 +433,7 @@ evmc::address EVMHost::convertToEVMC(h160 const& _addr) h256 EVMHost::convertFromEVMC(evmc::bytes32 const& _data) { - return h256(bytes(begin(_data.bytes), end(_data.bytes))); + return h256(bytes(std::begin(_data.bytes), std::end(_data.bytes))); } evmc::bytes32 EVMHost::convertToEVMC(h256 const& _data) @@ -452,7 +451,7 @@ evmc::Result EVMHost::precompileECRecover(evmc_message const& _message) noexcept // Fixed cost of 3000 gas. constexpr int64_t gas_cost = 3000; - static map const inputOutput{ + static std::map const inputOutput{ { fromHex( "18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c" @@ -509,7 +508,7 @@ evmc::Result EVMHost::precompileRipeMD160(evmc_message const& _message) noexcept return 600 + 120 * ((size + 31) / 32); }; - static map const inputOutput{ + static std::map const inputOutput{ { bytes{}, { @@ -628,7 +627,7 @@ evmc::Result EVMHost::precompileALTBN128G1Add(evmc_message const& _message) noex // Fixed 500 or 150 gas. int64_t gas_cost = (Revision < EVMC_ISTANBUL) ? 500 : 150; - static map const inputOutput{ + static std::map const inputOutput{ { fromHex( "0000000000000000000000000000000000000000000000000000000000000000" @@ -896,7 +895,7 @@ evmc::Result EVMHost::precompileALTBN128G1Mul(evmc_message const& _message) noex // Fixed 40000 or 6000 gas. int64_t gas_cost = (Revision < EVMC_ISTANBUL) ? 40000 : 6000; - static map const inputOutput{ + static std::map const inputOutput{ { fromHex("0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000"), { @@ -990,7 +989,7 @@ evmc::Result EVMHost::precompileALTBN128PairingProduct(evmc_message const& _mess }; // NOTE this is a partial implementation for some inputs. - static map const inputOutput{ + static std::map const inputOutput{ { fromHex( "17c139df0efee0f766bc0204762b774362e4ded88953a39ce849a8a7fa163fa9" @@ -1155,7 +1154,7 @@ evmc::Result EVMHost::precompileBlake2f(evmc_message const&) noexcept evmc::Result EVMHost::precompileGeneric( evmc_message const& _message, - map const& _inOut) noexcept + std::map const& _inOut) noexcept { bytes input(_message.input_data, _message.input_data + _message.input_size); if (_inOut.count(input)) @@ -1202,7 +1201,7 @@ StorageMap const& EVMHost::get_address_storage(evmc::address const& _addr) return accounts[_addr].storage; } -string EVMHostPrinter::state() +std::string EVMHostPrinter::state() { // Print state and execution trace. if (m_host.account_exists(m_account)) @@ -1225,14 +1224,14 @@ void EVMHostPrinter::storage() << m_host.convertFromEVMC(slot) << ": " << m_host.convertFromEVMC(value.current) - << endl; + << std::endl; } void EVMHostPrinter::balance() { m_stateStream << "BALANCE " << m_host.convertFromEVMC(m_host.get_balance(m_account)) - << endl; + << std::endl; } void EVMHostPrinter::selfdestructRecords() @@ -1242,12 +1241,12 @@ void EVMHostPrinter::selfdestructRecords() m_stateStream << "SELFDESTRUCT" << " BENEFICIARY " << m_host.convertFromEVMC(beneficiary) - << endl; + << std::endl; } void EVMHostPrinter::callRecords() { - static auto constexpr callKind = [](evmc_call_kind _kind) -> string + static auto constexpr callKind = [](evmc_call_kind _kind) -> std::string { switch (_kind) { @@ -1270,5 +1269,5 @@ void EVMHostPrinter::callRecords() m_stateStream << callKind(record.kind) << " VALUE " << m_host.convertFromEVMC(record.value) - << endl; + << std::endl; } diff --git a/test/ExecutionFramework.cpp b/test/ExecutionFramework.cpp index a18a73de06..9fc36440b3 100644 --- a/test/ExecutionFramework.cpp +++ b/test/ExecutionFramework.cpp @@ -41,7 +41,6 @@ #include #include -using namespace std; using namespace solidity; using namespace solidity::util; using namespace solidity::test; @@ -52,7 +51,7 @@ ExecutionFramework::ExecutionFramework(): { } -ExecutionFramework::ExecutionFramework(langutil::EVMVersion _evmVersion, vector const& _vmPaths): +ExecutionFramework::ExecutionFramework(langutil::EVMVersion _evmVersion, std::vector const& _vmPaths): m_evmVersion(_evmVersion), m_optimiserSettings(solidity::frontend::OptimiserSettings::minimal()), m_showMessages(solidity::test::CommonOptions::get().showMessages), @@ -71,7 +70,7 @@ void ExecutionFramework::selectVM(evmc_capabilities _cap) evmc::VM& vm = EVMHost::getVM(path.string()); if (vm.has_capability(_cap)) { - m_evmcHost = make_unique(m_evmVersion, vm); + m_evmcHost = std::make_unique(m_evmVersion, vm); break; } } @@ -87,7 +86,7 @@ void ExecutionFramework::reset() EVMHost::convertToEVMC(u256(1) << 100); } -std::pair ExecutionFramework::compareAndCreateMessage( +std::pair ExecutionFramework::compareAndCreateMessage( bytes const& _result, bytes const& _expectation ) @@ -101,8 +100,8 @@ std::pair ExecutionFramework::compareAndCreateMessage( auto expectedHex = boost::replace_all_copy(util::toHex(_expectation), "0", "."); for (size_t i = 0; i < std::max(resultHex.size(), expectedHex.size()); i += 0x40) { - std::string result{i >= resultHex.size() ? string{} : resultHex.substr(i, 0x40)}; - std::string expected{i > expectedHex.size() ? string{} : expectedHex.substr(i, 0x40)}; + std::string result{i >= resultHex.size() ? std::string{} : resultHex.substr(i, 0x40)}; + std::string expected{i > expectedHex.size() ? std::string{} : expectedHex.substr(i, 0x40)}; message += (result == expected ? " " : " X ") + result + @@ -137,7 +136,7 @@ u256 ExecutionFramework::gasPrice() const u256 ExecutionFramework::blockHash(u256 const& _number) const { return u256{EVMHost::convertFromEVMC( - m_evmcHost->get_block_hash(static_cast(_number & numeric_limits::max())) + m_evmcHost->get_block_hash(static_cast(_number & std::numeric_limits::max())) )}; } @@ -153,12 +152,12 @@ void ExecutionFramework::sendMessage(bytes const& _data, bool _isCreation, u256 if (m_showMessages) { if (_isCreation) - cout << "CREATE " << m_sender.hex() << ":" << endl; + std::cout << "CREATE " << m_sender.hex() << ":" << std::endl; else - cout << "CALL " << m_sender.hex() << " -> " << m_contractAddress.hex() << ":" << endl; + std::cout << "CALL " << m_sender.hex() << " -> " << m_contractAddress.hex() << ":" << std::endl; if (_value > 0) - cout << " value: " << _value << endl; - cout << " in: " << util::toHex(_data) << endl; + std::cout << " value: " << _value << std::endl; + std::cout << " in: " << util::toHex(_data) << std::endl; } evmc_message message{}; message.input_data = _data.data(); @@ -189,19 +188,19 @@ void ExecutionFramework::sendMessage(bytes const& _data, bool _isCreation, u256 unsigned const refundRatio = (m_evmVersion >= langutil::EVMVersion::london() ? 5 : 2); auto const totalGasUsed = InitialGas - result.gas_left; - auto const gasRefund = min(u256(result.gas_refund), totalGasUsed / refundRatio); + auto const gasRefund = std::min(u256(result.gas_refund), totalGasUsed / refundRatio); m_gasUsed = totalGasUsed - gasRefund; m_transactionSuccessful = (result.status_code == EVMC_SUCCESS); if (m_showMessages) { - cout << " out: " << util::toHex(m_output) << endl; - cout << " result: " << static_cast(result.status_code) << endl; - cout << " gas used: " << m_gasUsed.str() << endl; - cout << " gas used (without refund): " << totalGasUsed.str() << endl; - cout << " gas refund (total): " << result.gas_refund << endl; - cout << " gas refund (bound): " << gasRefund.str() << endl; + std::cout << " out: " << util::toHex(m_output) << std::endl; + std::cout << " result: " << static_cast(result.status_code) << std::endl; + std::cout << " gas used: " << m_gasUsed.str() << std::endl; + std::cout << " gas used (without refund): " << totalGasUsed.str() << std::endl; + std::cout << " gas refund (total): " << result.gas_refund << std::endl; + std::cout << " gas refund (bound): " << gasRefund.str() << std::endl; } } @@ -211,9 +210,9 @@ void ExecutionFramework::sendEther(h160 const& _addr, u256 const& _amount) if (m_showMessages) { - cout << "SEND_ETHER " << m_sender.hex() << " -> " << _addr.hex() << ":" << endl; + std::cout << "SEND_ETHER " << m_sender.hex() << " -> " << _addr.hex() << ":" << std::endl; if (_amount > 0) - cout << " value: " << _amount << endl; + std::cout << " value: " << _amount << std::endl; } evmc_message message{}; message.sender = EVMHost::convertToEVMC(m_sender); @@ -294,14 +293,14 @@ bool ExecutionFramework::storageEmpty(h160 const& _addr) const return true; } -vector ExecutionFramework::recordedLogs() const +std::vector ExecutionFramework::recordedLogs() const { - vector logs; + std::vector logs; for (evmc::MockedHost::log_record const& logRecord: m_evmcHost->recorded_logs) logs.emplace_back( EVMHost::convertFromEVMC(logRecord.creator), bytes{logRecord.data.begin(), logRecord.data.end()}, - logRecord.topics | ranges::views::transform([](evmc::bytes32 _bytes) { return EVMHost::convertFromEVMC(_bytes); }) | ranges::to + logRecord.topics | ranges::views::transform([](evmc::bytes32 _bytes) { return EVMHost::convertFromEVMC(_bytes); }) | ranges::to ); return logs; } diff --git a/test/FilesystemUtils.cpp b/test/FilesystemUtils.cpp index 7506d677ec..2d917485d6 100644 --- a/test/FilesystemUtils.cpp +++ b/test/FilesystemUtils.cpp @@ -22,11 +22,10 @@ #include -using namespace std; using namespace solidity; using namespace solidity::test; -void solidity::test::createFilesWithParentDirs(set const& _paths, string const& _content) +void solidity::test::createFilesWithParentDirs(std::set const& _paths, std::string const& _content) { for (boost::filesystem::path const& path: _paths) { @@ -34,23 +33,23 @@ void solidity::test::createFilesWithParentDirs(set cons boost::filesystem::create_directories(path.parent_path()); // Use binary mode to avoid line ending conversion on Windows. - ofstream newFile(path.string(), std::ofstream::binary); + std::ofstream newFile(path.string(), std::ofstream::binary); newFile << _content; if (newFile.fail() || !boost::filesystem::exists(path)) - BOOST_THROW_EXCEPTION(runtime_error("Failed to create an empty file: \"" + path.string() + "\".")); + BOOST_THROW_EXCEPTION(std::runtime_error("Failed to create an empty file: \"" + path.string() + "\".")); } } -void solidity::test::createFileWithContent(boost::filesystem::path const& _path, string const& _content) +void solidity::test::createFileWithContent(boost::filesystem::path const& _path, std::string const& _content) { if (boost::filesystem::is_regular_file(_path)) - BOOST_THROW_EXCEPTION(runtime_error("File already exists: \"" + _path.string() + "\".")); \ + BOOST_THROW_EXCEPTION(std::runtime_error("File already exists: \"" + _path.string() + "\".")); \ // Use binary mode to avoid line ending conversion on Windows. - ofstream newFile(_path.string(), std::ofstream::binary); + std::ofstream newFile(_path.string(), std::ofstream::binary); if (newFile.fail() || !boost::filesystem::is_regular_file(_path)) - BOOST_THROW_EXCEPTION(runtime_error("Failed to create a file: \"" + _path.string() + "\".")); \ + BOOST_THROW_EXCEPTION(std::runtime_error("Failed to create a file: \"" + _path.string() + "\".")); \ newFile << _content; } @@ -80,7 +79,7 @@ bool solidity::test::createSymlinkIfSupportedByFilesystem( ) return false; else - BOOST_THROW_EXCEPTION(runtime_error( + BOOST_THROW_EXCEPTION(std::runtime_error( "Failed to create a symbolic link: \"" + _linkName.string() + "\"" " -> " + _targetPath.string() + "\"." " " + symlinkCreationError.message() + "." diff --git a/test/Metadata.cpp b/test/Metadata.cpp index 88a1f7b42f..2fea65c65b 100644 --- a/test/Metadata.cpp +++ b/test/Metadata.cpp @@ -26,8 +26,6 @@ #include #include -using namespace std; - namespace solidity::test { @@ -54,7 +52,7 @@ bytes bytecodeSansMetadata(bytes const& _bytecode) return bytes(_bytecode.begin(), _bytecode.end() - static_cast(metadataSize) - 2); } -string bytecodeSansMetadata(string const& _bytecode) +std::string bytecodeSansMetadata(std::string const& _bytecode) { return util::toHex(bytecodeSansMetadata(fromHex(_bytecode, util::WhenError::Throw))); } @@ -73,11 +71,11 @@ class TinyCBORParser assertThrow(nextType() == MajorType::Map, CBORException, "Fixed-length map expected."); return readLength(); } - string readKey() + std::string readKey() { return readString(); } - string readValue() + std::string readValue() { switch(nextType()) { @@ -132,7 +130,7 @@ class TinyCBORParser if (length == 24) return m_metadata.at(m_pos++); // Unsupported length kind. (Only by this parser.) - assertThrow(false, CBORException, string("Unsupported length ") + to_string(length)); + assertThrow(false, CBORException, std::string("Unsupported length ") + std::to_string(length)); } bytes readBytes(unsigned length) { @@ -140,28 +138,28 @@ class TinyCBORParser m_pos += length; return ret; } - string readString() + std::string readString() { // Expect a text string. assertThrow(nextType() == MajorType::TextString, CBORException, "String expected."); bytes tmp{readBytes(readLength())}; - return string{tmp.begin(), tmp.end()}; + return std::string{tmp.begin(), tmp.end()}; } unsigned m_pos; bytes const& m_metadata; }; -std::optional> parseCBORMetadata(bytes const& _metadata) +std::optional> parseCBORMetadata(bytes const& _metadata) { try { TinyCBORParser parser(_metadata); - map ret; + std::map ret; unsigned count = parser.mapItemCount(); for (unsigned i = 0; i < count; i++) { - string key = parser.readKey(); - string value = parser.readValue(); + std::string key = parser.readKey(); + std::string value = parser.readValue(); ret[std::move(key)] = std::move(value); } return ret; @@ -172,7 +170,7 @@ std::optional> parseCBORMetadata(bytes const& _metadata) } } -bool isValidMetadata(string const& _serialisedMetadata) +bool isValidMetadata(std::string const& _serialisedMetadata) { Json::Value metadata; if (!util::jsonParseStrict(_serialisedMetadata, metadata)) diff --git a/test/TestCase.cpp b/test/TestCase.cpp index 51608bd4a3..ae89bb56f3 100644 --- a/test/TestCase.cpp +++ b/test/TestCase.cpp @@ -27,21 +27,20 @@ #include #include -using namespace std; using namespace solidity; using namespace solidity::frontend; using namespace solidity::frontend::test; using namespace solidity::util; -void TestCase::printSettings(ostream& _stream, const string& _linePrefix, const bool) +void TestCase::printSettings(std::ostream& _stream, const std::string& _linePrefix, const bool) { auto& settings = m_reader.settings(); if (settings.empty()) return; - _stream << _linePrefix << "// ====" << endl; + _stream << _linePrefix << "// ====" << std::endl; for (auto const& setting: settings) - _stream << _linePrefix << "// " << setting.first << ": " << setting.second << endl; + _stream << _linePrefix << "// " << setting.first << ": " << setting.second << std::endl; } void TestCase::printUpdatedSettings(std::ostream& _stream, std::string const& _linePrefix) @@ -51,7 +50,7 @@ void TestCase::printUpdatedSettings(std::ostream& _stream, std::string const& _l bool TestCase::isTestFilename(boost::filesystem::path const& _filename) { - string extension = _filename.extension().string(); + std::string extension = _filename.extension().string(); return (extension == ".sol" || extension == ".yul" || extension == ".stack") && !boost::starts_with(_filename.string(), "~") && !boost::starts_with(_filename.string(), "."); @@ -63,19 +62,19 @@ bool TestCase::shouldRun() return m_shouldRun; } -void TestCase::expect(string::iterator& _it, string::iterator _end, string::value_type _c) +void TestCase::expect(std::string::iterator& _it, std::string::iterator _end, std::string::value_type _c) { if (_it == _end || *_it != _c) - BOOST_THROW_EXCEPTION(runtime_error(string("Invalid test expectation. Expected: \"") + _c + "\".")); + BOOST_THROW_EXCEPTION(std::runtime_error(std::string("Invalid test expectation. Expected: \"") + _c + "\".")); ++_it; } -void TestCase::printSource(ostream& _stream, string const& _linePrefix, bool const) const +void TestCase::printSource(std::ostream& _stream, std::string const& _linePrefix, bool const) const { printPrefixed(_stream, m_source, _linePrefix); } -void TestCase::printUpdatedExpectations(ostream& _stream, string const& _linePrefix) const +void TestCase::printUpdatedExpectations(std::ostream& _stream, std::string const& _linePrefix) const { printPrefixed(_stream, m_obtainedResult, _linePrefix); } @@ -84,30 +83,30 @@ TestCase::TestResult TestCase::checkResult(std::ostream& _stream, const std::str { if (m_expectation != m_obtainedResult) { - string nextIndentLevel = _linePrefix + " "; + std::string nextIndentLevel = _linePrefix + " "; util::AnsiColorized(_stream, _formatted, {util::formatting::BOLD, util::formatting::CYAN}) - << _linePrefix << "Expected result:" << endl; + << _linePrefix << "Expected result:" << std::endl; // TODO could compute a simple diff with highlighted lines printPrefixed(_stream, m_expectation, nextIndentLevel); util::AnsiColorized(_stream, _formatted, {util::formatting::BOLD, util::formatting::CYAN}) - << _linePrefix << "Obtained result:" << endl; + << _linePrefix << "Obtained result:" << std::endl; printPrefixed(_stream, m_obtainedResult, nextIndentLevel); return TestResult::Failure; } return TestResult::Success; } -EVMVersionRestrictedTestCase::EVMVersionRestrictedTestCase(string const& _filename): +EVMVersionRestrictedTestCase::EVMVersionRestrictedTestCase(std::string const& _filename): TestCase(_filename) { - string versionString = m_reader.stringSetting("EVMVersion", "any"); + std::string versionString = m_reader.stringSetting("EVMVersion", "any"); if (versionString == "any") return; - string comparator; + std::string comparator; size_t versionBegin = 0; for (auto character: versionString) - if (!isalpha(character, locale::classic())) + if (!isalpha(character, std::locale::classic())) { comparator += character; versionBegin++; @@ -118,7 +117,7 @@ EVMVersionRestrictedTestCase::EVMVersionRestrictedTestCase(string const& _filena versionString = versionString.substr(versionBegin); std::optional version = langutil::EVMVersion::fromString(versionString); if (!version) - BOOST_THROW_EXCEPTION(runtime_error{"Invalid EVM version: \"" + versionString + "\""}); + BOOST_THROW_EXCEPTION(std::runtime_error{"Invalid EVM version: \"" + versionString + "\""}); langutil::EVMVersion evmVersion = solidity::test::CommonOptions::get().evmVersion(); bool comparisonResult; @@ -135,7 +134,7 @@ EVMVersionRestrictedTestCase::EVMVersionRestrictedTestCase(string const& _filena else if (comparator == "!") comparisonResult = !(evmVersion == version); else - BOOST_THROW_EXCEPTION(runtime_error{"Invalid EVM comparator: \"" + comparator + "\""}); + BOOST_THROW_EXCEPTION(std::runtime_error{"Invalid EVM comparator: \"" + comparator + "\""}); if (!comparisonResult) m_shouldRun = false; diff --git a/test/TestCaseReader.cpp b/test/TestCaseReader.cpp index 7ad752ef81..da6174cbe9 100644 --- a/test/TestCaseReader.cpp +++ b/test/TestCaseReader.cpp @@ -23,36 +23,35 @@ #include #include -using namespace std; using namespace solidity::frontend::test; namespace fs = boost::filesystem; -TestCaseReader::TestCaseReader(string const& _filename): m_fileStream(_filename), m_fileName(_filename) +TestCaseReader::TestCaseReader(std::string const& _filename): m_fileStream(_filename), m_fileName(_filename) { if (!m_fileStream) - BOOST_THROW_EXCEPTION(runtime_error("Cannot open file: \"" + _filename + "\".")); - m_fileStream.exceptions(ios::badbit); + BOOST_THROW_EXCEPTION(std::runtime_error("Cannot open file: \"" + _filename + "\".")); + m_fileStream.exceptions(std::ios::badbit); - tie(m_sources, m_lineNumber) = parseSourcesAndSettingsWithLineNumber(m_fileStream); + std::tie(m_sources, m_lineNumber) = parseSourcesAndSettingsWithLineNumber(m_fileStream); m_unreadSettings = m_settings; } -TestCaseReader::TestCaseReader(istringstream const& _str) +TestCaseReader::TestCaseReader(std::istringstream const& _str) { - tie(m_sources, m_lineNumber) = parseSourcesAndSettingsWithLineNumber( - static_cast(const_cast(_str)) + std::tie(m_sources, m_lineNumber) = parseSourcesAndSettingsWithLineNumber( + static_cast(const_cast(_str)) ); } -string const& TestCaseReader::source() const +std::string const& TestCaseReader::source() const { if (m_sources.sources.size() != 1) - BOOST_THROW_EXCEPTION(runtime_error("Expected single source definition, but got multiple sources.")); + BOOST_THROW_EXCEPTION(std::runtime_error("Expected single source definition, but got multiple sources.")); return m_sources.sources.at(m_sources.mainSourceFile); } -string TestCaseReader::simpleExpectations() +std::string TestCaseReader::simpleExpectations() { return parseSimpleExpectations(m_fileStream); } @@ -63,13 +62,13 @@ bool TestCaseReader::boolSetting(std::string const& _name, bool _defaultValue) return _defaultValue; m_unreadSettings.erase(_name); - string value = m_settings.at(_name); + std::string value = m_settings.at(_name); if (value == "false") return false; if (value == "true") return true; - BOOST_THROW_EXCEPTION(runtime_error("Invalid Boolean value: " + value + ".")); + BOOST_THROW_EXCEPTION(std::runtime_error("Invalid Boolean value: " + value + ".")); } size_t TestCaseReader::sizetSetting(std::string const& _name, size_t _defaultValue) @@ -83,7 +82,7 @@ size_t TestCaseReader::sizetSetting(std::string const& _name, size_t _defaultVal return stoul(m_settings.at(_name)); } -string TestCaseReader::stringSetting(string const& _name, string const& _defaultValue) +std::string TestCaseReader::stringSetting(std::string const& _name, std::string const& _defaultValue) { if (m_settings.count(_name) == 0) return _defaultValue; @@ -95,26 +94,26 @@ string TestCaseReader::stringSetting(string const& _name, string const& _default void TestCaseReader::ensureAllSettingsRead() const { if (!m_unreadSettings.empty()) - BOOST_THROW_EXCEPTION(runtime_error( + BOOST_THROW_EXCEPTION(std::runtime_error( "Unknown setting(s): " + util::joinHumanReadable(m_unreadSettings | ranges::views::keys) )); } -pair TestCaseReader::parseSourcesAndSettingsWithLineNumber(istream& _stream) +std::pair TestCaseReader::parseSourcesAndSettingsWithLineNumber(std::istream& _stream) { - map sources; - map externalSources; - string currentSourceName; - string currentSource; - string line; + std::map sources; + std::map externalSources; + std::string currentSourceName; + std::string currentSource; + std::string line; size_t lineNumber = 1; - static string const externalSourceDelimiterStart("==== ExternalSource:"); - static string const sourceDelimiterStart("==== Source:"); - static string const sourceDelimiterEnd("===="); - static string const comment("// "); - static string const settingsDelimiter("// ===="); - static string const expectationsDelimiter("// ----"); + static std::string const externalSourceDelimiterStart("==== ExternalSource:"); + static std::string const sourceDelimiterStart("==== Source:"); + static std::string const sourceDelimiterEnd("===="); + static std::string const comment("// "); + static std::string const settingsDelimiter("// ===="); + static std::string const expectationsDelimiter("// ----"); bool sourcePart = true; while (getline(_stream, line)) { @@ -138,19 +137,19 @@ pair TestCaseReader::parseSourcesAndSettingsWithLineNumber(is line.size() - sourceDelimiterEnd.size() - sourceDelimiterStart.size() )); if (sources.count(currentSourceName)) - BOOST_THROW_EXCEPTION(runtime_error("Multiple definitions of test source \"" + currentSourceName + "\".")); + BOOST_THROW_EXCEPTION(std::runtime_error("Multiple definitions of test source \"" + currentSourceName + "\".")); } else if (boost::algorithm::starts_with(line, externalSourceDelimiterStart) && boost::algorithm::ends_with(line, sourceDelimiterEnd)) { - string externalSourceString = boost::trim_copy(line.substr( + std::string externalSourceString = boost::trim_copy(line.substr( externalSourceDelimiterStart.size(), line.size() - sourceDelimiterEnd.size() - externalSourceDelimiterStart.size() )); - string externalSourceName; + std::string externalSourceName; size_t remappingPos = externalSourceString.find('='); // Does the external source define a remapping? - if (remappingPos != string::npos) + if (remappingPos != std::string::npos) { externalSourceName = boost::trim_copy(externalSourceString.substr(0, remappingPos)); externalSourceString = boost::trim_copy(externalSourceString.substr(remappingPos + 1)); @@ -164,16 +163,16 @@ pair TestCaseReader::parseSourcesAndSettingsWithLineNumber(is if (!externalSourceTarget.is_relative() || !externalSourceTarget.root_path().empty()) // NOTE: UNC paths (ones starting with // or \\) are considered relative by Boost // since they have an empty root directory (but non-empty root name). - BOOST_THROW_EXCEPTION(runtime_error("External Source paths need to be relative to the location of the test case.")); + BOOST_THROW_EXCEPTION(std::runtime_error("External Source paths need to be relative to the location of the test case.")); fs::path externalSourceFullPath = testCaseParentDir / externalSourceTarget; - string externalSourceContent; + std::string externalSourceContent; if (!fs::exists(externalSourceFullPath)) - BOOST_THROW_EXCEPTION(runtime_error("External Source '" + externalSourceTarget.string() + "' not found.")); + BOOST_THROW_EXCEPTION(std::runtime_error("External Source '" + externalSourceTarget.string() + "' not found.")); else externalSourceContent = util::readFileAsString(externalSourceFullPath); if (sources.count(externalSourceName)) - BOOST_THROW_EXCEPTION(runtime_error("Multiple definitions of test source \"" + externalSourceName + "\".")); + BOOST_THROW_EXCEPTION(std::runtime_error("Multiple definitions of test source \"" + externalSourceName + "\".")); sources[externalSourceName] = externalSourceContent; externalSources[externalSourceName] = externalSourceTarget; } @@ -183,32 +182,32 @@ pair TestCaseReader::parseSourcesAndSettingsWithLineNumber(is else if (boost::algorithm::starts_with(line, comment)) { size_t colon = line.find(':'); - if (colon == string::npos) - BOOST_THROW_EXCEPTION(runtime_error(string("Expected \":\" inside setting."))); - string key = line.substr(comment.size(), colon - comment.size()); - string value = line.substr(colon + 1); + if (colon == std::string::npos) + BOOST_THROW_EXCEPTION(std::runtime_error(std::string("Expected \":\" inside setting."))); + std::string key = line.substr(comment.size(), colon - comment.size()); + std::string value = line.substr(colon + 1); boost::algorithm::trim(key); boost::algorithm::trim(value); m_settings[key] = value; } else - BOOST_THROW_EXCEPTION(runtime_error(string("Expected \"//\" or \"// ---\" to terminate settings and source."))); + BOOST_THROW_EXCEPTION(std::runtime_error(std::string("Expected \"//\" or \"// ---\" to terminate settings and source."))); } // Register the last source as the main one sources[currentSourceName] = currentSource; return {{std::move(sources), std::move(externalSources), std::move(currentSourceName)}, lineNumber}; } -string TestCaseReader::parseSimpleExpectations(istream& _file) +std::string TestCaseReader::parseSimpleExpectations(std::istream& _file) { - string result; - string line; - while (getline(_file, line)) + std::string result; + std::string line; + while (std::getline(_file, line)) if (boost::algorithm::starts_with(line, "// ")) result += line.substr(3) + "\n"; else if (line == "//") result += "\n"; else - BOOST_THROW_EXCEPTION(runtime_error("Test expectations must start with \"// \".")); + BOOST_THROW_EXCEPTION(std::runtime_error("Test expectations must start with \"// \".")); return result; } diff --git a/test/soltest.cpp b/test/soltest.cpp index 443c4c5de3..5fde4bda56 100644 --- a/test/soltest.cpp +++ b/test/soltest.cpp @@ -35,6 +35,7 @@ #pragma warning(pop) #endif +#pragma GCC diagnostic pop #pragma GCC diagnostic pop #include @@ -49,7 +50,6 @@ using namespace boost::unit_test; using namespace solidity::frontend::test; namespace fs = boost::filesystem; -using namespace std; namespace { @@ -100,7 +100,7 @@ void runTestCase(TestCase::Config const& _config, TestCase::TestCaseCreator cons { try { - stringstream errorStream; + std::stringstream errorStream; auto testCase = _testCaseCreator(_config); if (testCase->shouldRun()) switch (testCase->run(errorStream)) @@ -133,7 +133,7 @@ int registerTests( boost::unit_test::test_suite& _suite, boost::filesystem::path const& _basepath, boost::filesystem::path const& _path, - vector const& _labels, + std::vector const& _labels, TestCase::TestCaseCreator _testCaseCreator, solidity::test::Batcher& _batcher ) @@ -176,9 +176,9 @@ int registerTests( // This must be a vector of unique_ptrs because Boost.Test keeps the equivalent of a string_view to the filename // that is passed in. If the strings were stored directly in the vector, pointers/references to them would be // invalidated on reallocation. - static vector> filenames; + static std::vector> filenames; - filenames.emplace_back(make_unique(_path.string())); + filenames.emplace_back(std::make_unique(_path.string())); auto test_case = make_test_case( [config, _testCaseCreator] { @@ -236,11 +236,14 @@ test_suite* init_unit_test_suite(int /*argc*/, char* /*argv*/[]) exit(EXIT_FAILURE); if (solidity::test::CommonOptions::get().disableSemanticTests) - cout << endl << "--- SKIPPING ALL SEMANTICS TESTS ---" << endl << endl; + std::cout << std::endl << "--- SKIPPING ALL SEMANTICS TESTS ---" << std::endl << std::endl; + + if (!solidity::test::CommonOptions::get().enforceGasTest) + std::cout << std::endl << "WARNING :: Gas Cost Expectations are not being enforced" << std::endl << std::endl; Batcher batcher(CommonOptions::get().selectedBatch, CommonOptions::get().batches); if (CommonOptions::get().batches > 1) - cout << "Batch " << CommonOptions::get().selectedBatch << " out of " << CommonOptions::get().batches << endl; + std::cout << "Batch " << CommonOptions::get().selectedBatch << " out of " << CommonOptions::get().batches << std::endl; // Batch the boost tests BoostBatcher boostBatcher(batcher); @@ -287,12 +290,12 @@ test_suite* init_unit_test_suite(int /*argc*/, char* /*argv*/[]) } catch (solidity::test::ConfigException const& exception) { - cerr << exception.what() << endl; + std::cerr << exception.what() << std::endl; exit(EXIT_FAILURE); } catch (std::runtime_error const& exception) { - cerr << exception.what() << endl; + std::cerr << exception.what() << std::endl; exit(EXIT_FAILURE); } From ac398869ad8ab1191f5c52fc58703877e3766ebc Mon Sep 17 00:00:00 2001 From: Martin Blicha Date: Wed, 7 Feb 2024 12:38:41 +0100 Subject: [PATCH 15/57] SMTChecker: Respect signedness of integer type When creating zero-value expression, we need to respect the signedness of the passed type. --- libsolidity/formal/SymbolicTypes.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsolidity/formal/SymbolicTypes.cpp b/libsolidity/formal/SymbolicTypes.cpp index 45b872b3d0..350e18bdcf 100644 --- a/libsolidity/formal/SymbolicTypes.cpp +++ b/libsolidity/formal/SymbolicTypes.cpp @@ -476,7 +476,7 @@ smtutil::Expression zeroValue(frontend::Type const* _type) if (isSupportedType(*_type)) { if (isNumber(*_type)) - return 0; + return isSigned(_type) ? smtutil::Expression(s256(0)) : smtutil::Expression(static_cast(0)); if (isBool(*_type)) return smtutil::Expression(false); if (isArray(*_type) || isMapping(*_type)) From 8770952466d9c7c16cabe534c843e29ef27f7a78 Mon Sep 17 00:00:00 2001 From: Martin Blicha Date: Wed, 7 Feb 2024 12:39:04 +0100 Subject: [PATCH 16/57] SMTChecker: Unsigned number expressions should have unsigned type --- libsmtutil/SolverInterface.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsmtutil/SolverInterface.h b/libsmtutil/SolverInterface.h index 4a21f18410..82f8111335 100644 --- a/libsmtutil/SolverInterface.h +++ b/libsmtutil/SolverInterface.h @@ -124,7 +124,7 @@ class Expression explicit Expression(std::string _name, std::vector _arguments, SortPointer _sort): name(std::move(_name)), arguments(std::move(_arguments)), sort(std::move(_sort)) {} Expression(size_t _number): Expression(std::to_string(_number), {}, SortProvider::uintSort) {} - Expression(u256 const& _number): Expression(_number.str(), {}, SortProvider::sintSort) {} + Expression(u256 const& _number): Expression(_number.str(), {}, SortProvider::uintSort) {} Expression(s256 const& _number): Expression( _number >= 0 ? _number.str() : "-", _number >= 0 ? From a1ad970aa10cb9dcf55af859a0de57ed41893722 Mon Sep 17 00:00:00 2001 From: Martin Blicha Date: Fri, 9 Feb 2024 16:07:52 +0100 Subject: [PATCH 17/57] SMTChecker: Add test case --- test/libsolidity/smtCheckerTests/types/mapping_6.sol | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 test/libsolidity/smtCheckerTests/types/mapping_6.sol diff --git a/test/libsolidity/smtCheckerTests/types/mapping_6.sol b/test/libsolidity/smtCheckerTests/types/mapping_6.sol new file mode 100644 index 0000000000..f2b6d74d7a --- /dev/null +++ b/test/libsolidity/smtCheckerTests/types/mapping_6.sol @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: GPL-3.0 + + +// Regression for handling signedness, see issues #14791 and #14792 +contract C { + mapping(bool => int240) internal v1; + mapping(bytes14 => bytes15) internal v; + + function f() public payable { + delete v["A"]; + } +} From 22da46c91ceaa4e1a8061b16b69123b5b4ca2457 Mon Sep 17 00:00:00 2001 From: Martin Blicha Date: Fri, 9 Feb 2024 16:25:56 +0100 Subject: [PATCH 18/57] Update changelog --- Changelog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/Changelog.md b/Changelog.md index 3d64b1b80e..a33421f1cc 100644 --- a/Changelog.md +++ b/Changelog.md @@ -8,6 +8,7 @@ Compiler Features: Bugfixes: + * SMTChecker: Fix internal error caused by not respecting the sign of an integer type when constructing zero-value SMT expressions. ### 0.8.24 (2024-01-25) From 4d163ff4bb6b84afff0dfd5817ad52b03e5aa521 Mon Sep 17 00:00:00 2001 From: Simon Perriard Date: Sun, 18 Feb 2024 20:13:37 +0100 Subject: [PATCH 19/57] Convert tagPos to a size for address size computation --- libevmasm/Assembly.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libevmasm/Assembly.cpp b/libevmasm/Assembly.cpp index 203db8613d..acf6067697 100644 --- a/libevmasm/Assembly.cpp +++ b/libevmasm/Assembly.cpp @@ -861,8 +861,8 @@ LinkerObject const& Assembly::assemble() const immutableReferencesBySub = linkerObject.immutableReferences; } for (size_t tagPos: sub->m_tagPositionsInBytecode) - if (tagPos != std::numeric_limits::max() && tagPos > subTagSize) - subTagSize = tagPos; + if (tagPos != std::numeric_limits::max() && numberEncodingSize(tagPos) > subTagSize) + subTagSize = numberEncodingSize(tagPos); } bool setsImmutables = false; From 8e212553d6f96031d000914cd19550cfbc06eca6 Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Mon, 19 Feb 2024 21:10:34 +0100 Subject: [PATCH 20/57] Account for subassemblies in tag size calculation, test adjustments and changelog entry. --- Changelog.md | 1 + libevmasm/Assembly.cpp | 12 ++++++++++++ test/cmdlineTests/function_debug_info/output | 2 +- .../output.json | 4 ++-- test/libsolidity/GasCosts.cpp | 16 ++++++++-------- .../semanticTests/arithmetics/check_var_init.sol | 2 +- .../array/constant_var_as_array_length.sol | 2 +- ...leanup_during_multi_element_per_slot_copy.sol | 6 +++--- .../array/fixed_arrays_in_constructors.sol | 2 +- .../semanticTests/array/reusing_memory.sol | 2 +- .../byte_array_to_storage_cleanup.sol | 6 +++--- .../constructor/arrays_in_constructors.sol | 2 +- .../constructor/bytes_in_constructors_packer.sol | 2 +- .../bytes_in_constructors_unpacker.sol | 2 +- .../constructor_arguments_external.sol | 4 ++-- .../constructor_static_array_argument.sol | 2 +- .../constructor_inheritance_init_order.sol | 2 +- .../constructor_inheritance_init_order_2.sol | 6 +++--- .../semanticTests/constructor_with_params.sol | 4 ++-- ...nstructor_with_params_diamond_inheritance.sol | 4 ++-- .../constructor_with_params_inheritance.sol | 4 ++-- .../events/event_emit_from_other_contract.sol | 6 +++--- .../externalContracts/FixedFeeRegistrar.sol | 6 +++--- .../semanticTests/externalContracts/base64.sol | 6 +++--- .../externalContracts/deposit_contract.sol | 4 ++-- .../externalContracts/prbmath_signed.sol | 6 +++--- .../externalContracts/prbmath_unsigned.sol | 6 +++--- .../externalContracts/ramanujan_pi.sol | 6 +++--- .../semanticTests/externalContracts/strings.sol | 6 +++--- .../creation_function_call_with_args.sol | 6 +++--- .../creation_function_call_with_salt.sol | 6 +++--- .../functionCall/gas_and_value_basic.sol | 6 +++--- .../functionCall/gas_and_value_brace_syntax.sol | 6 +++--- .../functionCall/send_zero_ether.sol | 2 +- .../semanticTests/immutable/use_scratch.sol | 4 ++-- .../inheritance/member_notation_ctor.sol | 4 ++-- .../inheritance/value_for_constructor.sol | 4 ++-- .../isoltestTesting/balance_other_contract.sol | 6 +++--- .../salted_create/prediction_example.sol | 2 +- .../salted_create/salted_create_with_value.sol | 2 +- .../semanticTests/smoke/constructor.sol | 6 +++--- .../semanticTests/state/blockhash_basic.sol | 6 +++--- .../semanticTests/userDefinedValueType/erc20.sol | 4 ++-- .../semanticTests/various/code_length.sol | 2 +- test/libsolidity/semanticTests/various/erc20.sol | 4 ++-- .../various/negative_stack_height.sol | 4 ++-- ...estruct_pre_cancun_multiple_beneficiaries.sol | 2 +- .../various/selfdestruct_pre_cancun_redeploy.sol | 6 +++--- .../semanticTests/various/senders_balance.sol | 6 +++--- .../semanticTests/various/value_complex.sol | 6 +++--- .../semanticTests/various/value_insane.sol | 6 +++--- .../sizeLimits/combined_too_large_shanghai.sol | 2 +- .../sizeLimits/initcode_too_large_shanghai.sol | 2 +- 53 files changed, 125 insertions(+), 112 deletions(-) diff --git a/Changelog.md b/Changelog.md index a33421f1cc..b2ac59c65a 100644 --- a/Changelog.md +++ b/Changelog.md @@ -8,6 +8,7 @@ Compiler Features: Bugfixes: + * Assembler: Prevent incorrect calculation of tag sizes. * SMTChecker: Fix internal error caused by not respecting the sign of an integer type when constructing zero-value SMT expressions. diff --git a/libevmasm/Assembly.cpp b/libevmasm/Assembly.cpp index acf6067697..569ecda26a 100644 --- a/libevmasm/Assembly.cpp +++ b/libevmasm/Assembly.cpp @@ -890,6 +890,18 @@ LinkerObject const& Assembly::assemble() const std::multimap subRef; std::vector sizeRef; ///< Pointers to code locations where the size of the program is inserted unsigned bytesPerTag = numberEncodingSize(bytesRequiredForCode); + // Adjust bytesPerTag for references to sub assemblies. + for (AssemblyItem const& i: m_items) + if (i.type() == PushTag) + { + auto [subId, tagId] = i.splitForeignPushTag(); + if (subId == std::numeric_limits::max()) + continue; + assertThrow(subId < m_subs.size(), AssemblyException, "Invalid sub id"); + auto subTagPosition = m_subs[subId]->m_tagPositionsInBytecode.at(tagId); + assertThrow(subTagPosition != std::numeric_limits::max(), AssemblyException, "Reference to tag without position."); + bytesPerTag = std::max(bytesPerTag, numberEncodingSize(subTagPosition)); + } uint8_t tagPush = static_cast(pushInstruction(bytesPerTag)); unsigned bytesRequiredIncludingData = bytesRequiredForCode + 1 + static_cast(m_auxiliaryData.size()); diff --git a/test/cmdlineTests/function_debug_info/output b/test/cmdlineTests/function_debug_info/output index b9ca3f3c40..c359d4e1c1 100644 --- a/test/cmdlineTests/function_debug_info/output +++ b/test/cmdlineTests/function_debug_info/output @@ -13,7 +13,7 @@ }, "abi_decode_tuple_t_uint256_fromMemory": { - "entryPoint": 92, + "entryPoint": 88, "parameterSlots": 2, "returnSlots": 1 } diff --git a/test/cmdlineTests/linking_standard_solidity_unresolved_references/output.json b/test/cmdlineTests/linking_standard_solidity_unresolved_references/output.json index 169e99961e..3a69e3e2d7 100644 --- a/test/cmdlineTests/linking_standard_solidity_unresolved_references/output.json +++ b/test/cmdlineTests/linking_standard_solidity_unresolved_references/output.json @@ -17,11 +17,11 @@ [ { "length": 20, - "start": 174 + "start": 173 }, { "length": 20, - "start": 350 + "start": 349 } ] } diff --git a/test/libsolidity/GasCosts.cpp b/test/libsolidity/GasCosts.cpp index 5207328101..d8dad9e027 100644 --- a/test/libsolidity/GasCosts.cpp +++ b/test/libsolidity/GasCosts.cpp @@ -101,7 +101,7 @@ BOOST_AUTO_TEST_CASE(string_storage) if (CommonOptions::get().useABIEncoderV1) CHECK_DEPLOY_GAS(133045, 129731, evmVersion); else - CHECK_DEPLOY_GAS(144999, 121229, evmVersion); + CHECK_DEPLOY_GAS(144995, 121229, evmVersion); } // This is only correct on >=Constantinople. else if (!CommonOptions::get().useABIEncoderV1) @@ -110,22 +110,22 @@ BOOST_AUTO_TEST_CASE(string_storage) { // Costs with 0 are cases which cannot be triggered in tests. if (evmVersion < EVMVersion::istanbul()) - CHECK_DEPLOY_GAS(0, 109241, evmVersion); + CHECK_DEPLOY_GAS(0, 109237, evmVersion); else if (evmVersion < EVMVersion::shanghai()) - CHECK_DEPLOY_GAS(0, 97697, evmVersion); + CHECK_DEPLOY_GAS(0, 97693, evmVersion); // Shanghai is cheaper due to `push0` else - CHECK_DEPLOY_GAS(0, 97071, evmVersion); + CHECK_DEPLOY_GAS(0, 97067, evmVersion); } else { if (evmVersion < EVMVersion::istanbul()) - CHECK_DEPLOY_GAS(139013, 123969, evmVersion); + CHECK_DEPLOY_GAS(139009, 123969, evmVersion); else if (evmVersion < EVMVersion::shanghai()) - CHECK_DEPLOY_GAS(123361, 110969, evmVersion); + CHECK_DEPLOY_GAS(123357, 110969, evmVersion); // Shanghai is cheaper due to `push0` else - CHECK_DEPLOY_GAS(121493, 110969, evmVersion); + CHECK_DEPLOY_GAS(121489, 110969, evmVersion); } } else if (evmVersion < EVMVersion::istanbul()) @@ -133,7 +133,7 @@ BOOST_AUTO_TEST_CASE(string_storage) else if (evmVersion < EVMVersion::shanghai()) CHECK_DEPLOY_GAS(114077, 96461, evmVersion); else - CHECK_DEPLOY_GAS(114077, 95835, evmVersion); + CHECK_DEPLOY_GAS(114077, 95831, evmVersion); if (evmVersion >= EVMVersion::byzantium()) { diff --git a/test/libsolidity/semanticTests/arithmetics/check_var_init.sol b/test/libsolidity/semanticTests/arithmetics/check_var_init.sol index 6cc02bd975..fc5418cb0e 100644 --- a/test/libsolidity/semanticTests/arithmetics/check_var_init.sol +++ b/test/libsolidity/semanticTests/arithmetics/check_var_init.sol @@ -16,4 +16,4 @@ contract D { // ---- // f() -> FAILURE, hex"4e487b71", 0x11 // g(), 100 wei -> 1 -// gas legacy: 100388 +// gas legacy: 100380 diff --git a/test/libsolidity/semanticTests/array/constant_var_as_array_length.sol b/test/libsolidity/semanticTests/array/constant_var_as_array_length.sol index ca65f07065..45861babaa 100644 --- a/test/libsolidity/semanticTests/array/constant_var_as_array_length.sol +++ b/test/libsolidity/semanticTests/array/constant_var_as_array_length.sol @@ -8,7 +8,7 @@ contract C { } // ---- // constructor(): 1, 2, 3 -> -// gas irOptimized: 139656 +// gas irOptimized: 139616 // gas legacy: 180517 // gas legacyOptimized: 150462 // a(uint256): 0 -> 1 diff --git a/test/libsolidity/semanticTests/array/copying/cleanup_during_multi_element_per_slot_copy.sol b/test/libsolidity/semanticTests/array/copying/cleanup_during_multi_element_per_slot_copy.sol index d2361dac54..8be8328926 100644 --- a/test/libsolidity/semanticTests/array/copying/cleanup_during_multi_element_per_slot_copy.sol +++ b/test/libsolidity/semanticTests/array/copying/cleanup_during_multi_element_per_slot_copy.sol @@ -16,7 +16,7 @@ contract C { } // ---- // constructor() -// gas irOptimized: 226349 -// gas legacy: 215757 -// gas legacyOptimized: 181760 +// gas irOptimized: 226321 +// gas legacy: 215753 +// gas legacyOptimized: 181756 // f() -> 0 diff --git a/test/libsolidity/semanticTests/array/fixed_arrays_in_constructors.sol b/test/libsolidity/semanticTests/array/fixed_arrays_in_constructors.sol index ac11d779a5..c7b2dc77a3 100644 --- a/test/libsolidity/semanticTests/array/fixed_arrays_in_constructors.sol +++ b/test/libsolidity/semanticTests/array/fixed_arrays_in_constructors.sol @@ -9,7 +9,7 @@ contract Creator { } // ---- // constructor(): 1, 2, 3, 4 -> -// gas irOptimized: 126363 +// gas irOptimized: 126327 // gas legacy: 174186 // gas legacyOptimized: 128709 // r() -> 4 diff --git a/test/libsolidity/semanticTests/array/reusing_memory.sol b/test/libsolidity/semanticTests/array/reusing_memory.sol index 92b0c06bfb..8f6afe30ba 100644 --- a/test/libsolidity/semanticTests/array/reusing_memory.sol +++ b/test/libsolidity/semanticTests/array/reusing_memory.sol @@ -25,5 +25,5 @@ contract Main { // ---- // f(uint256): 0x34 -> 0x46bddb1178e94d7f2892ff5f366840eb658911794f2c3a44c450aa2c505186c1 // gas irOptimized: 111924 -// gas legacy: 125162 +// gas legacy: 125154 // gas legacyOptimized: 113012 diff --git a/test/libsolidity/semanticTests/byte_array_to_storage_cleanup.sol b/test/libsolidity/semanticTests/byte_array_to_storage_cleanup.sol index dc77f0dff8..877e2a1bce 100644 --- a/test/libsolidity/semanticTests/byte_array_to_storage_cleanup.sol +++ b/test/libsolidity/semanticTests/byte_array_to_storage_cleanup.sol @@ -28,9 +28,9 @@ contract C { // compileViaYul: also // ---- // constructor() -> -// gas irOptimized: 443406 -// gas legacy: 711299 -// gas legacyOptimized: 482382 +// gas irOptimized: 443402 +// gas legacy: 711295 +// gas legacyOptimized: 482378 // h() -> 0x20, 0x40, 0x00, 0 // ~ emit ev(uint256[],uint256): 0x40, 0x21, 0x02, 0x00, 0x00 // g() -> 0x20, 0x40, 0, 0x00 diff --git a/test/libsolidity/semanticTests/constructor/arrays_in_constructors.sol b/test/libsolidity/semanticTests/constructor/arrays_in_constructors.sol index 3d9c1ffece..19d79b6c4f 100644 --- a/test/libsolidity/semanticTests/constructor/arrays_in_constructors.sol +++ b/test/libsolidity/semanticTests/constructor/arrays_in_constructors.sol @@ -25,5 +25,5 @@ contract Creator { // ---- // f(uint256,address[]): 7, 0x40, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 -> 7, 8 // gas irOptimized: 424526 -// gas legacy: 581443 +// gas legacy: 581426 // gas legacyOptimized: 444599 diff --git a/test/libsolidity/semanticTests/constructor/bytes_in_constructors_packer.sol b/test/libsolidity/semanticTests/constructor/bytes_in_constructors_packer.sol index 067a64e0e5..cfa74f016f 100644 --- a/test/libsolidity/semanticTests/constructor/bytes_in_constructors_packer.sol +++ b/test/libsolidity/semanticTests/constructor/bytes_in_constructors_packer.sol @@ -25,5 +25,5 @@ contract Creator { // ---- // f(uint256,bytes): 7, 0x40, 78, "abcdefghijklmnopqrstuvwxyzabcdef", "ghijklmnopqrstuvwxyzabcdefghijkl", "mnopqrstuvwxyz" -> 7, "h" // gas irOptimized: 275102 -// gas legacy: 418462 +// gas legacy: 418433 // gas legacyOptimized: 291960 diff --git a/test/libsolidity/semanticTests/constructor/bytes_in_constructors_unpacker.sol b/test/libsolidity/semanticTests/constructor/bytes_in_constructors_unpacker.sol index 0665cb807a..39da45e8a5 100644 --- a/test/libsolidity/semanticTests/constructor/bytes_in_constructors_unpacker.sol +++ b/test/libsolidity/semanticTests/constructor/bytes_in_constructors_unpacker.sol @@ -9,7 +9,7 @@ contract Test { // ---- // constructor(): 7, 0x40, 78, "abcdefghijklmnopqrstuvwxyzabcdef", "ghijklmnopqrstuvwxyzabcdefghijkl", "mnopqrstuvwxyz" -> // gas irOptimized: 269225 -// gas legacy: 311324 +// gas legacy: 310820 // gas legacyOptimized: 258604 // m_x() -> 7 // m_s() -> 0x20, 78, "abcdefghijklmnopqrstuvwxyzabcdef", "ghijklmnopqrstuvwxyzabcdefghijkl", "mnopqrstuvwxyz" diff --git a/test/libsolidity/semanticTests/constructor/constructor_arguments_external.sol b/test/libsolidity/semanticTests/constructor/constructor_arguments_external.sol index 3037aaa317..714ae3e554 100644 --- a/test/libsolidity/semanticTests/constructor/constructor_arguments_external.sol +++ b/test/libsolidity/semanticTests/constructor/constructor_arguments_external.sol @@ -17,8 +17,8 @@ contract Main { } // ---- // constructor(): "abc", true -// gas irOptimized: 104394 +// gas irOptimized: 104374 // gas legacy: 143300 -// gas legacyOptimized: 102961 +// gas legacyOptimized: 102933 // getFlag() -> true // getName() -> "abc" diff --git a/test/libsolidity/semanticTests/constructor/constructor_static_array_argument.sol b/test/libsolidity/semanticTests/constructor/constructor_static_array_argument.sol index 22acd1cc3f..a61192742d 100644 --- a/test/libsolidity/semanticTests/constructor/constructor_static_array_argument.sol +++ b/test/libsolidity/semanticTests/constructor/constructor_static_array_argument.sol @@ -9,7 +9,7 @@ contract C { } // ---- // constructor(): 1, 2, 3, 4 -> -// gas irOptimized: 171015 +// gas irOptimized: 170975 // gas legacy: 218378 // gas legacyOptimized: 176211 // a() -> 1 diff --git a/test/libsolidity/semanticTests/constructor_inheritance_init_order.sol b/test/libsolidity/semanticTests/constructor_inheritance_init_order.sol index 20cd8760b9..ece0cc31a6 100644 --- a/test/libsolidity/semanticTests/constructor_inheritance_init_order.sol +++ b/test/libsolidity/semanticTests/constructor_inheritance_init_order.sol @@ -14,5 +14,5 @@ contract B is A { // compileViaYul: true // ---- // constructor() -> -// gas irOptimized: 119640 +// gas irOptimized: 119636 // y() -> 42 diff --git a/test/libsolidity/semanticTests/constructor_inheritance_init_order_2.sol b/test/libsolidity/semanticTests/constructor_inheritance_init_order_2.sol index 820c56a4ee..654c9af56d 100644 --- a/test/libsolidity/semanticTests/constructor_inheritance_init_order_2.sol +++ b/test/libsolidity/semanticTests/constructor_inheritance_init_order_2.sol @@ -9,7 +9,7 @@ contract B is A { } // ---- // constructor() -> -// gas irOptimized: 119640 -// gas legacy: 133594 -// gas legacyOptimized: 115341 +// gas irOptimized: 119636 +// gas legacy: 133574 +// gas legacyOptimized: 115337 // y() -> 42 diff --git a/test/libsolidity/semanticTests/constructor_with_params.sol b/test/libsolidity/semanticTests/constructor_with_params.sol index 1916f692fd..e427f6d9ab 100644 --- a/test/libsolidity/semanticTests/constructor_with_params.sol +++ b/test/libsolidity/semanticTests/constructor_with_params.sol @@ -9,7 +9,7 @@ contract C { } // ---- // constructor(): 2, 0 -> -// gas irOptimized: 101390 -// gas legacy: 115678 +// gas irOptimized: 101370 +// gas legacy: 115614 // i() -> 2 // k() -> 0 diff --git a/test/libsolidity/semanticTests/constructor_with_params_diamond_inheritance.sol b/test/libsolidity/semanticTests/constructor_with_params_diamond_inheritance.sol index b2f66e4500..6507081447 100644 --- a/test/libsolidity/semanticTests/constructor_with_params_diamond_inheritance.sol +++ b/test/libsolidity/semanticTests/constructor_with_params_diamond_inheritance.sol @@ -21,9 +21,9 @@ contract D is B, C { } // ---- // constructor(): 2, 0 -> -// gas irOptimized: 151966 +// gas irOptimized: 151950 // gas legacy: 168623 -// gas legacyOptimized: 144577 +// gas legacyOptimized: 144521 // i() -> 2 // j() -> 2 // k() -> 1 diff --git a/test/libsolidity/semanticTests/constructor_with_params_inheritance.sol b/test/libsolidity/semanticTests/constructor_with_params_inheritance.sol index f5b20d9816..8cc7c69f68 100644 --- a/test/libsolidity/semanticTests/constructor_with_params_inheritance.sol +++ b/test/libsolidity/semanticTests/constructor_with_params_inheritance.sol @@ -12,8 +12,8 @@ contract D is C { } // ---- // constructor(): 2, 0 -> -// gas irOptimized: 121805 +// gas irOptimized: 121781 // gas legacy: 137193 -// gas legacyOptimized: 118548 +// gas legacyOptimized: 118504 // i() -> 2 // k() -> 1 diff --git a/test/libsolidity/semanticTests/events/event_emit_from_other_contract.sol b/test/libsolidity/semanticTests/events/event_emit_from_other_contract.sol index f8b5141b97..0c56cbb671 100644 --- a/test/libsolidity/semanticTests/events/event_emit_from_other_contract.sol +++ b/test/libsolidity/semanticTests/events/event_emit_from_other_contract.sol @@ -15,8 +15,8 @@ contract C { } // ---- // constructor() -> -// gas irOptimized: 165386 -// gas legacy: 244800 -// gas legacyOptimized: 171615 +// gas irOptimized: 165370 +// gas legacy: 244776 +// gas legacyOptimized: 171587 // deposit(bytes32), 18 wei: 0x1234 -> // ~ emit Deposit(address,bytes32,uint256) from 0x137aa4dfc0911524504fcd4d98501f179bc13b4a: #0xc06afe3a8444fc0004668591e8306bfb9968e79e, #0x1234, 0x00 diff --git a/test/libsolidity/semanticTests/externalContracts/FixedFeeRegistrar.sol b/test/libsolidity/semanticTests/externalContracts/FixedFeeRegistrar.sol index f9f53275bb..011fecbd34 100644 --- a/test/libsolidity/semanticTests/externalContracts/FixedFeeRegistrar.sol +++ b/test/libsolidity/semanticTests/externalContracts/FixedFeeRegistrar.sol @@ -74,9 +74,9 @@ contract FixedFeeRegistrar is Registrar { } // ---- // constructor() -// gas irOptimized: 384610 -// gas legacy: 913421 -// gas legacyOptimized: 476928 +// gas irOptimized: 384606 +// gas legacy: 913417 +// gas legacyOptimized: 476924 // reserve(string), 69 ether: 0x20, 3, "abc" -> // ~ emit Changed(string): #0x4e03657aea45a94fc7d47ba826c8d667c0d1e6e33a64a036ec44f58fa12d6c45 // gas irOptimized: 45967 diff --git a/test/libsolidity/semanticTests/externalContracts/base64.sol b/test/libsolidity/semanticTests/externalContracts/base64.sol index 646601e6fb..ee2745d1ac 100644 --- a/test/libsolidity/semanticTests/externalContracts/base64.sol +++ b/test/libsolidity/semanticTests/externalContracts/base64.sol @@ -33,9 +33,9 @@ contract test { // EVMVersion: >=constantinople // ---- // constructor() -// gas irOptimized: 405832 -// gas legacy: 735054 -// gas legacyOptimized: 522722 +// gas irOptimized: 405828 +// gas legacy: 735050 +// gas legacyOptimized: 522718 // encode_inline_asm(bytes): 0x20, 0 -> 0x20, 0 // encode_inline_asm(bytes): 0x20, 1, "f" -> 0x20, 4, "Zg==" // encode_inline_asm(bytes): 0x20, 2, "fo" -> 0x20, 4, "Zm8=" diff --git a/test/libsolidity/semanticTests/externalContracts/deposit_contract.sol b/test/libsolidity/semanticTests/externalContracts/deposit_contract.sol index 4f3342dea7..caa7fc39c8 100644 --- a/test/libsolidity/semanticTests/externalContracts/deposit_contract.sol +++ b/test/libsolidity/semanticTests/externalContracts/deposit_contract.sol @@ -177,8 +177,8 @@ contract DepositContract is IDepositContract, ERC165 { // ---- // constructor() // gas irOptimized: 1386886 -// gas legacy: 2369061 -// gas legacyOptimized: 1740144 +// gas legacy: 2368733 +// gas legacyOptimized: 1740004 // supportsInterface(bytes4): 0x0 -> 0 // supportsInterface(bytes4): 0xffffffff00000000000000000000000000000000000000000000000000000000 -> false # defined to be false by ERC-165 # // supportsInterface(bytes4): 0x01ffc9a700000000000000000000000000000000000000000000000000000000 -> true # ERC-165 id # diff --git a/test/libsolidity/semanticTests/externalContracts/prbmath_signed.sol b/test/libsolidity/semanticTests/externalContracts/prbmath_signed.sol index 3311a8dcf4..ba7a208fd7 100644 --- a/test/libsolidity/semanticTests/externalContracts/prbmath_signed.sol +++ b/test/libsolidity/semanticTests/externalContracts/prbmath_signed.sol @@ -48,9 +48,9 @@ contract test { } // ---- // constructor() -// gas irOptimized: 1841740 -// gas legacy: 2414091 -// gas legacyOptimized: 1847616 +// gas irOptimized: 1841736 +// gas legacy: 2414087 +// gas legacyOptimized: 1847612 // div(int256,int256): 3141592653589793238, 88714123 -> 35412542528203691288251815328 // gas irOptimized: 22137 // gas legacy: 22767 diff --git a/test/libsolidity/semanticTests/externalContracts/prbmath_unsigned.sol b/test/libsolidity/semanticTests/externalContracts/prbmath_unsigned.sol index fb1d1a4352..90b283db46 100644 --- a/test/libsolidity/semanticTests/externalContracts/prbmath_unsigned.sol +++ b/test/libsolidity/semanticTests/externalContracts/prbmath_unsigned.sol @@ -48,9 +48,9 @@ contract test { } // ---- // constructor() -// gas irOptimized: 1716327 -// gas legacy: 2193550 -// gas legacyOptimized: 1725061 +// gas irOptimized: 1716323 +// gas legacy: 2193546 +// gas legacyOptimized: 1725057 // div(uint256,uint256): 3141592653589793238, 88714123 -> 35412542528203691288251815328 // gas irOptimized: 22004 // gas legacy: 22497 diff --git a/test/libsolidity/semanticTests/externalContracts/ramanujan_pi.sol b/test/libsolidity/semanticTests/externalContracts/ramanujan_pi.sol index 3f555405dd..4442b6d479 100644 --- a/test/libsolidity/semanticTests/externalContracts/ramanujan_pi.sol +++ b/test/libsolidity/semanticTests/externalContracts/ramanujan_pi.sol @@ -33,9 +33,9 @@ contract test { } // ---- // constructor() -// gas irOptimized: 407507 -// gas legacy: 615090 -// gas legacyOptimized: 451871 +// gas irOptimized: 407503 +// gas legacy: 615086 +// gas legacyOptimized: 451867 // prb_pi() -> 3141592656369545286 // gas irOptimized: 57478 // gas legacy: 100947 diff --git a/test/libsolidity/semanticTests/externalContracts/strings.sol b/test/libsolidity/semanticTests/externalContracts/strings.sol index 18d6db37df..3f88fc39c6 100644 --- a/test/libsolidity/semanticTests/externalContracts/strings.sol +++ b/test/libsolidity/semanticTests/externalContracts/strings.sol @@ -49,9 +49,9 @@ contract test { } // ---- // constructor() -// gas irOptimized: 630224 -// gas legacy: 1061957 -// gas legacyOptimized: 718937 +// gas irOptimized: 630220 +// gas legacy: 1061953 +// gas legacyOptimized: 718933 // toSlice(string): 0x20, 11, "hello world" -> 11, 0xa0 // gas irOptimized: 22660 // gas legacy: 23190 diff --git a/test/libsolidity/semanticTests/functionCall/creation_function_call_with_args.sol b/test/libsolidity/semanticTests/functionCall/creation_function_call_with_args.sol index 39592f4a48..34aac74efa 100644 --- a/test/libsolidity/semanticTests/functionCall/creation_function_call_with_args.sol +++ b/test/libsolidity/semanticTests/functionCall/creation_function_call_with_args.sol @@ -15,7 +15,7 @@ contract D { } // ---- // constructor(): 2 -> -// gas irOptimized: 192703 -// gas legacy: 241234 -// gas legacyOptimized: 192961 +// gas irOptimized: 192663 +// gas legacy: 241170 +// gas legacyOptimized: 192897 // f() -> 2 diff --git a/test/libsolidity/semanticTests/functionCall/creation_function_call_with_salt.sol b/test/libsolidity/semanticTests/functionCall/creation_function_call_with_salt.sol index 3850a0be7f..cb26a6e26a 100644 --- a/test/libsolidity/semanticTests/functionCall/creation_function_call_with_salt.sol +++ b/test/libsolidity/semanticTests/functionCall/creation_function_call_with_salt.sol @@ -17,7 +17,7 @@ contract D { // EVMVersion: >=constantinople // ---- // constructor(): 2 -> -// gas irOptimized: 192866 -// gas legacy: 241606 -// gas legacyOptimized: 193193 +// gas irOptimized: 192826 +// gas legacy: 241536 +// gas legacyOptimized: 193129 // f() -> 2 diff --git a/test/libsolidity/semanticTests/functionCall/gas_and_value_basic.sol b/test/libsolidity/semanticTests/functionCall/gas_and_value_basic.sol index 79a829aa77..8396cb12db 100644 --- a/test/libsolidity/semanticTests/functionCall/gas_and_value_basic.sol +++ b/test/libsolidity/semanticTests/functionCall/gas_and_value_basic.sol @@ -38,9 +38,9 @@ contract test { } // ---- // constructor(), 20 wei -> -// gas irOptimized: 252642 -// gas legacy: 391588 -// gas legacyOptimized: 268089 +// gas irOptimized: 252626 +// gas legacy: 391568 +// gas legacyOptimized: 268069 // sendAmount(uint256): 5 -> 5 // outOfGas() -> FAILURE # call to helper should not succeed but amount should be transferred anyway # // checkState() -> false, 15 diff --git a/test/libsolidity/semanticTests/functionCall/gas_and_value_brace_syntax.sol b/test/libsolidity/semanticTests/functionCall/gas_and_value_brace_syntax.sol index 71b6ebb2c7..9d9c3f603f 100644 --- a/test/libsolidity/semanticTests/functionCall/gas_and_value_brace_syntax.sol +++ b/test/libsolidity/semanticTests/functionCall/gas_and_value_brace_syntax.sol @@ -37,9 +37,9 @@ contract test { } // ---- // constructor(), 20 wei -> -// gas irOptimized: 252642 -// gas legacy: 391588 -// gas legacyOptimized: 268089 +// gas irOptimized: 252626 +// gas legacy: 391568 +// gas legacyOptimized: 268069 // sendAmount(uint256): 5 -> 5 // outOfGas() -> FAILURE # call to helper should not succeed but amount should be transferred anyway # // checkState() -> false, 15 diff --git a/test/libsolidity/semanticTests/functionCall/send_zero_ether.sol b/test/libsolidity/semanticTests/functionCall/send_zero_ether.sol index 18a1997929..a737de5cd4 100644 --- a/test/libsolidity/semanticTests/functionCall/send_zero_ether.sol +++ b/test/libsolidity/semanticTests/functionCall/send_zero_ether.sol @@ -16,6 +16,6 @@ contract Main { // ---- // constructor(), 20 wei -> // gas irOptimized: 100264 -// gas legacy: 113411 +// gas legacy: 110555 // gas legacyOptimized: 100361 // s() -> true diff --git a/test/libsolidity/semanticTests/immutable/use_scratch.sol b/test/libsolidity/semanticTests/immutable/use_scratch.sol index 0a5ccf729f..a7c8ea6a50 100644 --- a/test/libsolidity/semanticTests/immutable/use_scratch.sol +++ b/test/libsolidity/semanticTests/immutable/use_scratch.sol @@ -15,8 +15,8 @@ contract C { } // ---- // constructor(): 3 -> -// gas irOptimized: 123542 +// gas irOptimized: 123526 // gas legacy: 197645 -// gas legacyOptimized: 137678 +// gas legacyOptimized: 137658 // f() -> 84, 23 // m(uint256): 3 -> 7 diff --git a/test/libsolidity/semanticTests/inheritance/member_notation_ctor.sol b/test/libsolidity/semanticTests/inheritance/member_notation_ctor.sol index 33392e8d48..263588abab 100644 --- a/test/libsolidity/semanticTests/inheritance/member_notation_ctor.sol +++ b/test/libsolidity/semanticTests/inheritance/member_notation_ctor.sol @@ -19,6 +19,6 @@ contract A { } // ---- // g(int256): -1 -> -1 -// gas legacy: 102086 +// gas legacy: 102078 // g(int256): 10 -> 10 -// gas legacy: 101714 +// gas legacy: 101706 diff --git a/test/libsolidity/semanticTests/inheritance/value_for_constructor.sol b/test/libsolidity/semanticTests/inheritance/value_for_constructor.sol index d8fd8766fe..9627ad025d 100644 --- a/test/libsolidity/semanticTests/inheritance/value_for_constructor.sol +++ b/test/libsolidity/semanticTests/inheritance/value_for_constructor.sol @@ -39,9 +39,9 @@ contract Main { } // ---- // constructor(), 22 wei -> -// gas irOptimized: 261888 +// gas irOptimized: 261864 // gas legacy: 392786 -// gas legacyOptimized: 261633 +// gas legacyOptimized: 261593 // getFlag() -> true // getName() -> "abc" // getBalances() -> 12, 10 diff --git a/test/libsolidity/semanticTests/isoltestTesting/balance_other_contract.sol b/test/libsolidity/semanticTests/isoltestTesting/balance_other_contract.sol index 306bc35670..1a5c9b19b4 100644 --- a/test/libsolidity/semanticTests/isoltestTesting/balance_other_contract.sol +++ b/test/libsolidity/semanticTests/isoltestTesting/balance_other_contract.sol @@ -16,9 +16,9 @@ contract ClientReceipt { } // ---- // constructor(), 2000 wei -> -// gas irOptimized: 169915 -// gas legacy: 230038 -// gas legacyOptimized: 173883 +// gas irOptimized: 169907 +// gas legacy: 230018 +// gas legacyOptimized: 173867 // balance -> 1500 // gas irOptimized: 191881 // gas legacy: 235167 diff --git a/test/libsolidity/semanticTests/salted_create/prediction_example.sol b/test/libsolidity/semanticTests/salted_create/prediction_example.sol index 1c5ce63ad4..e7171536d6 100644 --- a/test/libsolidity/semanticTests/salted_create/prediction_example.sol +++ b/test/libsolidity/semanticTests/salted_create/prediction_example.sol @@ -26,4 +26,4 @@ contract C { // compileViaYul: also // ---- // createDSalted(bytes32,uint256): 42, 64 -> -// gas legacy: 102943 +// gas legacy: 102841 diff --git a/test/libsolidity/semanticTests/salted_create/salted_create_with_value.sol b/test/libsolidity/semanticTests/salted_create/salted_create_with_value.sol index c4db174742..58b3f07603 100644 --- a/test/libsolidity/semanticTests/salted_create/salted_create_with_value.sol +++ b/test/libsolidity/semanticTests/salted_create/salted_create_with_value.sol @@ -23,4 +23,4 @@ contract A { // f(), 10 ether -> 3007, 3008, 3009 // gas irOptimized: 253005 // gas legacy: 381063 -// gas legacyOptimized: 279694 +// gas legacyOptimized: 279658 diff --git a/test/libsolidity/semanticTests/smoke/constructor.sol b/test/libsolidity/semanticTests/smoke/constructor.sol index 79b92867bc..55789b2f4b 100644 --- a/test/libsolidity/semanticTests/smoke/constructor.sol +++ b/test/libsolidity/semanticTests/smoke/constructor.sol @@ -12,9 +12,9 @@ contract C { } // ---- // constructor(), 2 wei: 3 -> -// gas irOptimized: 104412 -// gas legacy: 148308 -// gas legacyOptimized: 106727 +// gas irOptimized: 104396 +// gas legacy: 148256 +// gas legacyOptimized: 106699 // state() -> 3 // balance() -> 2 // balance -> 2 diff --git a/test/libsolidity/semanticTests/state/blockhash_basic.sol b/test/libsolidity/semanticTests/state/blockhash_basic.sol index 01069aa0c6..03d6f9fe76 100644 --- a/test/libsolidity/semanticTests/state/blockhash_basic.sol +++ b/test/libsolidity/semanticTests/state/blockhash_basic.sol @@ -12,9 +12,9 @@ contract C { } // ---- // constructor() -// gas irOptimized: 108150 -// gas legacy: 152179 -// gas legacyOptimized: 106750 +// gas irOptimized: 108138 +// gas legacy: 152171 +// gas legacyOptimized: 106738 // genesisHash() -> 0x3737373737373737373737373737373737373737373737373737373737373737 // currentHash() -> 0 // f(uint256): 0 -> 0x3737373737373737373737373737373737373737373737373737373737373737 diff --git a/test/libsolidity/semanticTests/userDefinedValueType/erc20.sol b/test/libsolidity/semanticTests/userDefinedValueType/erc20.sol index 27ab530cd7..ac8609d713 100644 --- a/test/libsolidity/semanticTests/userDefinedValueType/erc20.sol +++ b/test/libsolidity/semanticTests/userDefinedValueType/erc20.sol @@ -113,8 +113,8 @@ contract ERC20 { // ---- // constructor() // ~ emit Transfer(address,address,uint256): #0x00, #0x1212121212121212121212121212120000000012, 0x14 -// gas irOptimized: 352698 -// gas legacy: 834932 +// gas irOptimized: 352682 +// gas legacy: 834752 // gas legacyOptimized: 412648 // totalSupply() -> 20 // gas irOptimized: 23415 diff --git a/test/libsolidity/semanticTests/various/code_length.sol b/test/libsolidity/semanticTests/various/code_length.sol index 97a7637976..a8aac5306f 100644 --- a/test/libsolidity/semanticTests/various/code_length.sol +++ b/test/libsolidity/semanticTests/various/code_length.sol @@ -59,5 +59,5 @@ contract C { } // ---- // constructor() -// gas legacy: 124168 +// gas legacy: 124136 // f(): true, true -> true, true diff --git a/test/libsolidity/semanticTests/various/erc20.sol b/test/libsolidity/semanticTests/various/erc20.sol index b752a52101..00c12fb18a 100644 --- a/test/libsolidity/semanticTests/various/erc20.sol +++ b/test/libsolidity/semanticTests/various/erc20.sol @@ -96,8 +96,8 @@ contract ERC20 { // ---- // constructor() // ~ emit Transfer(address,address,uint256): #0x00, #0x1212121212121212121212121212120000000012, 0x14 -// gas irOptimized: 353276 -// gas legacy: 807683 +// gas irOptimized: 353248 +// gas legacy: 807559 // gas legacyOptimized: 408718 // totalSupply() -> 20 // gas irOptimized: 23415 diff --git a/test/libsolidity/semanticTests/various/negative_stack_height.sol b/test/libsolidity/semanticTests/various/negative_stack_height.sol index 3c9130e9fd..7289d2bbd9 100644 --- a/test/libsolidity/semanticTests/various/negative_stack_height.sol +++ b/test/libsolidity/semanticTests/various/negative_stack_height.sol @@ -65,5 +65,5 @@ contract C { // compileViaYul: false // ---- // constructor() -> -// gas legacy: 575272 -// gas legacyOptimized: 345026 +// gas legacy: 575268 +// gas legacyOptimized: 345022 diff --git a/test/libsolidity/semanticTests/various/selfdestruct_pre_cancun_multiple_beneficiaries.sol b/test/libsolidity/semanticTests/various/selfdestruct_pre_cancun_multiple_beneficiaries.sol index 57b2d5c66a..87e81a2902 100644 --- a/test/libsolidity/semanticTests/various/selfdestruct_pre_cancun_multiple_beneficiaries.sol +++ b/test/libsolidity/semanticTests/various/selfdestruct_pre_cancun_multiple_beneficiaries.sol @@ -36,7 +36,7 @@ contract D { // ---- // constructor(), 2 ether -> // gas irOptimized: 223918 -// gas legacy: 374228 +// gas legacy: 374024 // gas legacyOptimized: 239815 // balance: 0x1111111111111111111111111111111111111111 -> 0 // balance: 0x2222222222222222222222222222222222222222 -> 0 diff --git a/test/libsolidity/semanticTests/various/selfdestruct_pre_cancun_redeploy.sol b/test/libsolidity/semanticTests/various/selfdestruct_pre_cancun_redeploy.sol index 9c9949854a..e0885782c2 100644 --- a/test/libsolidity/semanticTests/various/selfdestruct_pre_cancun_redeploy.sol +++ b/test/libsolidity/semanticTests/various/selfdestruct_pre_cancun_redeploy.sol @@ -79,9 +79,9 @@ contract D { // EVMVersion: =shanghai // ---- // constructor(), 1 ether -> -// gas irOptimized: 430265 -// gas legacy: 690264 -// gas legacyOptimized: 412819 +// gas irOptimized: 430253 +// gas legacy: 690244 +// gas legacyOptimized: 412799 // exists() -> false // test_deploy_and_terminate() -> // ~ emit Deployed(address,bytes32) from 0x137aa4dfc0911524504fcd4d98501f179bc13b4a: 0x7e6580007e709ac52945fae182c61131d42634e8, 0x1234000000000000000000000000000000000000000000000000000000000000 diff --git a/test/libsolidity/semanticTests/various/senders_balance.sol b/test/libsolidity/semanticTests/various/senders_balance.sol index 6628454db9..a1c7d4147f 100644 --- a/test/libsolidity/semanticTests/various/senders_balance.sol +++ b/test/libsolidity/semanticTests/various/senders_balance.sol @@ -16,7 +16,7 @@ contract D { } // ---- // constructor(), 27 wei -> -// gas irOptimized: 167865 -// gas legacy: 218459 -// gas legacyOptimized: 167292 +// gas irOptimized: 167857 +// gas legacy: 218435 +// gas legacyOptimized: 167276 // f() -> 27 diff --git a/test/libsolidity/semanticTests/various/value_complex.sol b/test/libsolidity/semanticTests/various/value_complex.sol index 9f262fbdeb..2adac6bf4c 100644 --- a/test/libsolidity/semanticTests/various/value_complex.sol +++ b/test/libsolidity/semanticTests/various/value_complex.sol @@ -19,7 +19,7 @@ contract test { } // ---- // constructor(), 20 wei -> -// gas irOptimized: 172407 -// gas legacy: 252296 -// gas legacyOptimized: 180352 +// gas irOptimized: 172399 +// gas legacy: 252276 +// gas legacyOptimized: 180336 // sendAmount(uint256): 5 -> 8 diff --git a/test/libsolidity/semanticTests/various/value_insane.sol b/test/libsolidity/semanticTests/various/value_insane.sol index 1e591050c3..87fa01485d 100644 --- a/test/libsolidity/semanticTests/various/value_insane.sol +++ b/test/libsolidity/semanticTests/various/value_insane.sol @@ -18,7 +18,7 @@ contract test { } // ---- // constructor(), 20 wei -> -// gas irOptimized: 173271 -// gas legacy: 253820 -// gas legacyOptimized: 180784 +// gas irOptimized: 173263 +// gas legacy: 253800 +// gas legacyOptimized: 180768 // sendAmount(uint256): 5 -> 8 diff --git a/test/libsolidity/syntaxTests/sizeLimits/combined_too_large_shanghai.sol b/test/libsolidity/syntaxTests/sizeLimits/combined_too_large_shanghai.sol index 3fc466db39..32e8d9133b 100644 --- a/test/libsolidity/syntaxTests/sizeLimits/combined_too_large_shanghai.sol +++ b/test/libsolidity/syntaxTests/sizeLimits/combined_too_large_shanghai.sol @@ -29,4 +29,4 @@ contract test { // Warning 5574: (0-27130): Contract code size is 27187 bytes and exceeds 24576 bytes (a limit introduced in Spurious Dragon). This contract may not be deployable on Mainnet. Consider enabling the optimizer (with a low "runs" value!), turning off revert strings, or using libraries. // Warning 5574: (27132-27224): Contract code size is 27213 bytes and exceeds 24576 bytes (a limit introduced in Spurious Dragon). This contract may not be deployable on Mainnet. Consider enabling the optimizer (with a low "runs" value!), turning off revert strings, or using libraries. // Warning 5574: (27226-27319): Contract code size is 27212 bytes and exceeds 24576 bytes (a limit introduced in Spurious Dragon). This contract may not be deployable on Mainnet. Consider enabling the optimizer (with a low "runs" value!), turning off revert strings, or using libraries. -// Warning 3860: (27321-27398): Contract initcode size is 54628 bytes and exceeds 49152 bytes (a limit introduced in Shanghai). This contract may not be deployable on Mainnet. Consider enabling the optimizer (with a low "runs" value!), turning off revert strings, or using libraries. +// Warning 3860: (27321-27398): Contract initcode size is 54618 bytes and exceeds 49152 bytes (a limit introduced in Shanghai). This contract may not be deployable on Mainnet. Consider enabling the optimizer (with a low "runs" value!), turning off revert strings, or using libraries. diff --git a/test/libsolidity/syntaxTests/sizeLimits/initcode_too_large_shanghai.sol b/test/libsolidity/syntaxTests/sizeLimits/initcode_too_large_shanghai.sol index f82434d5d6..d48693db05 100644 --- a/test/libsolidity/syntaxTests/sizeLimits/initcode_too_large_shanghai.sol +++ b/test/libsolidity/syntaxTests/sizeLimits/initcode_too_large_shanghai.sol @@ -27,4 +27,4 @@ contract test { // ==== // EVMVersion: =shanghai // ---- -// Warning 3860: (20321-20415): Contract initcode size is 60896 bytes and exceeds 49152 bytes (a limit introduced in Shanghai). This contract may not be deployable on Mainnet. Consider enabling the optimizer (with a low "runs" value!), turning off revert strings, or using libraries. +// Warning 3860: (20321-20415): Contract initcode size is 60882 bytes and exceeds 49152 bytes (a limit introduced in Shanghai). This contract may not be deployable on Mainnet. Consider enabling the optimizer (with a low "runs" value!), turning off revert strings, or using libraries. From c49d84784e62082756b671bd1ed85c076185fe31 Mon Sep 17 00:00:00 2001 From: Nikola Matic Date: Tue, 20 Feb 2024 07:27:58 +0100 Subject: [PATCH 21/57] Force install python3.12 for Window bytecode compare job --- .circleci/config.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 5ab0b056a2..72d96fe4f8 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1697,8 +1697,12 @@ jobs: # platforms so line ending conversions must absolutely be disabled. - run: git config --global core.autocrlf false - checkout - # Ensure windows has python3 alias required by prepare_bytecode_report - - run: ln -s /c/Python312/python /c/Python312/python3 + - run: + name: Force install python3.12.2 + command: choco install python3 --pre --force --version=3.12.2 + - run: + name: Create a symlink for python3 + command: ln -s /c/ProgramData/chocolatey/bin/python3.12 /c/ProgramData/chocolatey/bin/python3 - attach_workspace: at: build - prepare_bytecode_report: From 1185ad0400223a54777904d1521102eec599d666 Mon Sep 17 00:00:00 2001 From: r0qs Date: Tue, 20 Feb 2024 14:49:28 +0100 Subject: [PATCH 22/57] Build hardhat from latest release in t_ems_ext_hardhat --- .circleci/config.yml | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 5ab0b056a2..5b13a79456 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1386,7 +1386,31 @@ jobs: - checkout - attach_workspace: at: /tmp/workspace - - run: git clone --depth 1 https://github.com/nomiclabs/hardhat.git + - run: + name: Ensure pnpm is installed if npm is present + command: | + if command -v npm &> /dev/null; then + sudo npm install -g pnpm + fi + - run: + name: Retrieve Hardhat latest release tag + command: | + # Make authenticated requests when the Github token is available + if [[ -n "$GITHUB_ACCESS_TOKEN" ]]; then + EXTRA_HEADERS=(--header 'Authorization: Bearer '"${GITHUB_ACCESS_TOKEN}") + fi + HARDHAT_RELEASE_TAG=$( + curl \ + --silent \ + --location \ + --fail \ + --show-error \ + "${EXTRA_HEADERS[@]}" \ + https://api.github.com/repos/nomiclabs/hardhat/releases/latest \ + | jq --raw-output .tag_name \ + ) + echo "export HARDHAT_RELEASE_TAG='${HARDHAT_RELEASE_TAG}'" >> "$BASH_ENV" + - run: git clone --depth 1 https://github.com/nomiclabs/hardhat.git --branch $HARDHAT_RELEASE_TAG - run: name: Install dependencies command: | From d703b829b2f13d6a6d7b7bdd6271ec3fecdae4dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Sun, 11 Feb 2024 16:04:27 +0100 Subject: [PATCH 23/57] gas_diff_stats.py: Add basic unit tests --- .circleci/config.yml | 6 +- test/scripts/test_gas_diff_stats.py | 87 +++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+), 1 deletion(-) create mode 100644 test/scripts/test_gas_diff_stats.py diff --git a/.circleci/config.yml b/.circleci/config.yml index 72d96fe4f8..e14a4ec78c 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -973,6 +973,10 @@ jobs: <<: *base_ubuntu2204_small steps: - checkout + - run: + # TODO: Add these to the base image + name: Install gas_diff_stats.py dependencies + command: python3 -m pip install --user parsec tabulate - run: name: Python unit tests command: python3 test/pyscriptTests.py @@ -985,7 +989,7 @@ jobs: - checkout - run: name: Install dependencies - command: python -m pip install --user requests + command: python -m pip install --user requests parsec tabulate - run: name: Python unit tests command: python.exe test/pyscriptTests.py diff --git a/test/scripts/test_gas_diff_stats.py b/test/scripts/test_gas_diff_stats.py new file mode 100644 index 0000000000..4980293aea --- /dev/null +++ b/test/scripts/test_gas_diff_stats.py @@ -0,0 +1,87 @@ +#!/usr/bin/env python + +import unittest +from textwrap import dedent + +# NOTE: This test file file only works with scripts/ added to PYTHONPATH so pylint can't find the imports +# pragma pylint: disable=import-error +from gas_diff_stats import collect_statistics +# pragma pylint: enable=import-error + +class TestGasDiffStats(unittest.TestCase): + def test_collect_statistics_should_fail_on_empty_diff(self): + with self.assertRaises(RuntimeError): + self.assertEqual(collect_statistics(""), (0, 0, 0, 0, 0, 0)) + + def test_collect_statistics_should_accept_whitespace_only_diff(self): + # TODO: Should it really work this way? + # If we're rejecting empty diff, not sure why whitespace is accepted. + self.assertEqual(collect_statistics("\n"), (0, 0, 0, 0, 0, 0)) + self.assertEqual(collect_statistics("\n \n\t\n\n"), (0, 0, 0, 0, 0, 0)) + + def test_collect_statistics_should_report_sum_of_gas_costs(self): + diff_output = dedent(""" + diff --git a/test/libsolidity/semanticTests/various/staticcall_for_view_and_pure.sol b/test/libsolidity/semanticTests/various/staticcall_for_view_and_pure.sol + index 1306529d4..77a330f3c 100644 + --- a/test/libsolidity/semanticTests/various/staticcall_for_view_and_pure.sol + +++ b/test/libsolidity/semanticTests/various/staticcall_for_view_and_pure.sol + @@ -38 +38,2 @@ contract D { + -// gas legacy: 102095 + +// gas legacy: 76495 + @@ -40,3 +41,6 @@ contract D { + -// gas irOptimized: 98438588 + -// gas legacy: 98438774 + -// gas legacyOptimized: 98438580 + +// gas irOptimized: 25388 + +// gas legacy: 98413174 + +// gas legacyOptimized: 25380 + @@ -44,3 +48,6 @@ contract D { + -// gas irOptimized: 98438589 + -// gas legacy: 98438774 + -// gas legacyOptimized: 98438580 + +// gas irOptimized: 25389 + +// gas legacy: 98413174 + +// gas legacyOptimized: 25380 + """).splitlines() + + self.assertEqual(collect_statistics(diff_output), ( + 98438588 + 98438589, # -irOptimized + 98438580 + 98438580, # -legacyOptimized + 102095 + 98438774 + 98438774, # -legacy + 25388 + 25389, # +irOptimized + 25380 + 25380, # +legacyOptimized + 76495 + 98413174 + 98413174, # +legacy + )) + + def test_collect_statistics_should_ignore_ir_costs(self): + diff_output = dedent(""" + -// gas legacy: 1 + -// gas ir: 2 + +// gas legacy: 3 + +// gas ir: 4 + """).splitlines() + + self.assertEqual(collect_statistics(diff_output), ( + 0, # -irOptimized + 0, # -legacyOptimized + 1, # -legacy + 0, # +irOptimized + 0, # +legacyOptimized + 3, # +legacy + )) + + def test_collect_statistics_should_ignore_unchanged_costs(self): + diff_output = dedent(""" + -// gas legacy: 1 + // gas legacyOptimized: 2 + +// gas legacy: 3 + """).splitlines() + + self.assertEqual(collect_statistics(diff_output), ( + 0, # -irOptimized + 0, # -legacyOptimized + 1, # -legacy + 0, # +irOptimized + 0, # +legacyOptimized + 3, # +legacy + )) From c6e23311cca599f25d1df87dcae8d2ce1f758793 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Sun, 11 Feb 2024 13:29:28 +0100 Subject: [PATCH 24/57] gas_diff_stats.py: Add a Python shebang - The script is executable but executes as a Bash script and fails. --- scripts/gas_diff_stats.py | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/gas_diff_stats.py b/scripts/gas_diff_stats.py index 234d42df0c..90a153cd31 100755 --- a/scripts/gas_diff_stats.py +++ b/scripts/gas_diff_stats.py @@ -1,3 +1,4 @@ +#!/usr/bin/env python3 """A script to collect gas statistics and print it. Useful to summarize gas differences to semantic tests for a PR / branch. From e28a1d436a15e698b933f2a6cc5b160f2bcb3616 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Sun, 11 Feb 2024 13:31:42 +0100 Subject: [PATCH 25/57] gas_diff_stats.py: Print errors to stderr, not stdout --- scripts/gas_diff_stats.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/scripts/gas_diff_stats.py b/scripts/gas_diff_stats.py index 90a153cd31..b220485c00 100755 --- a/scripts/gas_diff_stats.py +++ b/scripts/gas_diff_stats.py @@ -18,7 +18,9 @@ repository. The changes are compared against ``origin/develop``. """ + import subprocess +import sys from pathlib import Path from enum import Enum from parsec import generate, ParseError, regex, string @@ -110,8 +112,8 @@ def try_parse_git_diff(fname): if diff_output: return collect_statistics(diff_output) except subprocess.CalledProcessError as e: - print("Error in the git diff:") - print(e.output) + print("Error in the git diff:", file=sys.stderr) + print(e.output, file=sys.stderr) return None def stat(old, new): return ((new - old) / old) * 100 if old else 0 From 5518a3074f0804e7d075122d27733b71812549c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Sun, 11 Feb 2024 13:35:50 +0100 Subject: [PATCH 26/57] gas_diff_stats.py: Don't let shell evaluate file names and support names with spaces --- scripts/gas_diff_stats.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/scripts/gas_diff_stats.py b/scripts/gas_diff_stats.py index b220485c00..6f8087d481 100755 --- a/scripts/gas_diff_stats.py +++ b/scripts/gas_diff_stats.py @@ -105,8 +105,7 @@ def semantictest_statistics(): def try_parse_git_diff(fname): try: diff_output = subprocess.check_output( - "git diff --unified=0 origin/develop HEAD " + fname, - shell=True, + ["git", "diff", "--unified=0", "origin/develop", "HEAD", fname], universal_newlines=True ).splitlines() if diff_output: From 39f3e7673f84f874a33515f383efca029b2abc49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Sun, 11 Feb 2024 13:36:26 +0100 Subject: [PATCH 27/57] gas_diff_stats.py: Fail when the semantic test dir does not exist --- scripts/gas_diff_stats.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/scripts/gas_diff_stats.py b/scripts/gas_diff_stats.py index 6f8087d481..922aa7de45 100755 --- a/scripts/gas_diff_stats.py +++ b/scripts/gas_diff_stats.py @@ -35,6 +35,8 @@ class Diff(Enum): Minus = 1 Plus = 2 +SEMANTIC_TEST_DIR = Path("test/libsolidity/semanticTests/") + minus = string("-").result(Diff.Minus) plus = string("+").result(Diff.Plus) @@ -119,7 +121,10 @@ def stat(old, new): table = [] - for path in Path("test/libsolidity/semanticTests").rglob("*.sol"): + if not SEMANTIC_TEST_DIR.is_dir(): + sys.exit(f"Semantic tests not found. '{SEMANTIC_TEST_DIR.absolute()}' is missing or not a directory.") + + for path in SEMANTIC_TEST_DIR.rglob("*.sol"): fname = path.as_posix() parsed = try_parse_git_diff(fname) if parsed is None: From 855096b84b71aa5f5dd949f83e2dc90831f1e3f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Sun, 11 Feb 2024 15:17:41 +0100 Subject: [PATCH 28/57] gas_diff_stats.py: Skip non-gas lines to avoid having to silence parsing errors --- scripts/gas_diff_stats.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/scripts/gas_diff_stats.py b/scripts/gas_diff_stats.py index 922aa7de45..5d95d5a193 100755 --- a/scripts/gas_diff_stats.py +++ b/scripts/gas_diff_stats.py @@ -89,7 +89,12 @@ def try_parse(line): pass return None - out = [parsed for line in lines if (parsed := try_parse(line)) is not None] + out = [ + parsed + for line in lines + if line.startswith('+// gas ') or line.startswith('-// gas ') + if (parsed := try_parse(line)) is not None + ] diff_kinds = [Diff.Minus, Diff.Plus] codegen_kinds = [Kind.IrOptimized, Kind.LegacyOptimized, Kind.Legacy] return tuple( From b9c7b69c76ed73c57aef3681d6f29dd155d1607e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Sun, 11 Feb 2024 15:57:36 +0100 Subject: [PATCH 29/57] gas_diff_stats.py: Explicitly ignore ir gas instead of failing to parse it --- scripts/gas_diff_stats.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/scripts/gas_diff_stats.py b/scripts/gas_diff_stats.py index 5d95d5a193..518d8c2c75 100755 --- a/scripts/gas_diff_stats.py +++ b/scripts/gas_diff_stats.py @@ -27,9 +27,10 @@ from tabulate import tabulate class Kind(Enum): - IrOptimized = 1 - Legacy = 2 - LegacyOptimized = 3 + Ir = 1 + IrOptimized = 2 + Legacy = 3 + LegacyOptimized = 4 class Diff(Enum): Minus = 1 @@ -44,6 +45,7 @@ class Diff(Enum): comment = string("//") colon = string(":") +gas_ir = string("gas ir").result(Kind.Ir) gas_ir_optimized = string("gas irOptimized").result(Kind.IrOptimized) gas_legacy_optimized = string("gas legacyOptimized").result(Kind.LegacyOptimized) gas_legacy = string("gas legacy").result(Kind.Legacy) @@ -64,7 +66,7 @@ def diff_string() -> (Kind, Diff, int): diff_kind = yield minus | plus yield comment yield space - codegen_kind = yield gas_ir_optimized ^ gas_legacy_optimized ^ gas_legacy + codegen_kind = yield gas_ir_optimized ^ gas_ir ^ gas_legacy_optimized ^ gas_legacy yield colon yield space val = yield number() From 65031d3b3e128cd30283afcec254d2326030069d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Sun, 11 Feb 2024 15:22:17 +0100 Subject: [PATCH 30/57] gas_diff_stats.py: Handle errors instead of ignoring them - It's possible now that errors are something really exceptional and don't happen on every run. --- scripts/gas_diff_stats.py | 46 ++++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/scripts/gas_diff_stats.py b/scripts/gas_diff_stats.py index 518d8c2c75..3527002524 100755 --- a/scripts/gas_diff_stats.py +++ b/scripts/gas_diff_stats.py @@ -84,18 +84,11 @@ def collect_statistics(lines) -> (int, int, int, int, int, int): if not lines: raise RuntimeError("Empty list") - def try_parse(line): - try: - return diff_string.parse(line) - except ParseError: - pass - return None - out = [ parsed for line in lines if line.startswith('+// gas ') or line.startswith('-// gas ') - if (parsed := try_parse(line)) is not None + if (parsed := diff_string.parse(line)) is not None ] diff_kinds = [Diff.Minus, Diff.Plus] codegen_kinds = [Kind.IrOptimized, Kind.LegacyOptimized, Kind.Legacy] @@ -111,18 +104,15 @@ def try_parse(line): def semantictest_statistics(): """Prints the tabulated statistics that can be pasted in github.""" - def try_parse_git_diff(fname): - try: - diff_output = subprocess.check_output( - ["git", "diff", "--unified=0", "origin/develop", "HEAD", fname], - universal_newlines=True - ).splitlines() - if diff_output: - return collect_statistics(diff_output) - except subprocess.CalledProcessError as e: - print("Error in the git diff:", file=sys.stderr) - print(e.output, file=sys.stderr) - return None + def parse_git_diff(fname): + diff_output = subprocess.check_output( + ["git", "diff", "--unified=0", "origin/develop", "HEAD", fname], + universal_newlines=True + ).splitlines() + if len(diff_output) == 0: + return None + return collect_statistics(diff_output) + def stat(old, new): return ((new - old) / old) * 100 if old else 0 @@ -133,7 +123,7 @@ def stat(old, new): for path in SEMANTIC_TEST_DIR.rglob("*.sol"): fname = path.as_posix() - parsed = try_parse_git_diff(fname) + parsed = parse_git_diff(fname) if parsed is None: continue ir_optimized = stat(parsed[0], parsed[3]) @@ -150,5 +140,17 @@ def stat(old, new): else: print("No differences found.") +def main(): + try: + semantictest_statistics() + except subprocess.CalledProcessError as exception: + sys.exit(f"Error in the git diff:\n{exception.output}") + except ParseError as exception: + sys.exit( + f"ParseError: {exception}\n\n" + f"{exception.text}\n" + f"{' ' * exception.index}^\n" + ) + if __name__ == "__main__": - semantictest_statistics() + main() From 43274fddef0ecc55f4026d089fef3928b0617680 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Sun, 11 Feb 2024 14:14:17 +0100 Subject: [PATCH 31/57] gas_diff_stats.py: Improve table and number formatting - Use blanks if percentage is infinite instead of misleadingly showing zero. - Round percentages to nearest integer (but indicate when numbers are only close to zero rather than exactly zero). Differences below one percent are rarely relevant, if ever. - Include % after the numbers. - Put file names in backticks to get them displayed using fixed-width font on github. --- scripts/gas_diff_stats.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/scripts/gas_diff_stats.py b/scripts/gas_diff_stats.py index 3527002524..0707b9857b 100755 --- a/scripts/gas_diff_stats.py +++ b/scripts/gas_diff_stats.py @@ -114,7 +114,16 @@ def parse_git_diff(fname): return collect_statistics(diff_output) def stat(old, new): - return ((new - old) / old) * 100 if old else 0 + if old == 0: + return '' + percentage = (new - old) / old * 100 + prefix = ( + # Distinguish actual zero from very small differences + '+' if round(percentage) == 0 and percentage > 0 else + '-' if round(percentage) == 0 and percentage < 0 else + '' + ) + return f'{prefix}{round(percentage)}%' table = [] @@ -129,12 +138,12 @@ def stat(old, new): ir_optimized = stat(parsed[0], parsed[3]) legacy_optimized = stat(parsed[1], parsed[4]) legacy = stat(parsed[2], parsed[5]) - fname = fname.split('/', 3)[-1] - table += [map(str, [fname, ir_optimized, legacy_optimized, legacy])] + fname = f"`{fname.split('/', 3)[-1]}`" + table += [[fname, ir_optimized, legacy_optimized, legacy]] if table: print("
Click for a table of gas differences\n") - table_header = ["File name", "IR-optimized (%)", "Legacy-Optimized (%)", "Legacy (%)"] + table_header = ["File name", "IR optimized", "Legacy optimized", "Legacy"] print(tabulate(table, headers=table_header, tablefmt="github")) print("
") else: From b88d690c66b963282a77e214001b160873434ddd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Sun, 11 Feb 2024 14:16:33 +0100 Subject: [PATCH 32/57] gas_diff_stats.py: Order rows in a deterministic way (by file path) --- scripts/gas_diff_stats.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/gas_diff_stats.py b/scripts/gas_diff_stats.py index 0707b9857b..7403b39172 100755 --- a/scripts/gas_diff_stats.py +++ b/scripts/gas_diff_stats.py @@ -144,7 +144,7 @@ def stat(old, new): if table: print("
Click for a table of gas differences\n") table_header = ["File name", "IR optimized", "Legacy optimized", "Legacy"] - print(tabulate(table, headers=table_header, tablefmt="github")) + print(tabulate(sorted(table), headers=table_header, tablefmt="github")) print("
") else: print("No differences found.") From 36f2d39282a9f951b0f4780193398f5084073874 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Sun, 11 Feb 2024 16:15:52 +0100 Subject: [PATCH 33/57] CI: Add a smoke test run for gas_diff_stats.py --- .circleci/config.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index e14a4ec78c..8a16effd0f 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -980,6 +980,9 @@ jobs: - run: name: Python unit tests command: python3 test/pyscriptTests.py + - run: + name: Smoke test for gas_diff_stats.py + command: scripts/gas_diff_stats.py - matrix_notify_failure_unless_pr t_win_pyscripts: From a851c59bb9c6f226cfb483767a73ebf8b79e8329 Mon Sep 17 00:00:00 2001 From: r0qs Date: Wed, 21 Feb 2024 20:52:11 +0100 Subject: [PATCH 34/57] Fix ENS external test ensuring it applies memory-safe-assembly filter on files and not directories --- test/externalTests/ens.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/externalTests/ens.sh b/test/externalTests/ens.sh index aee291a1a4..178f468549 100755 --- a/test/externalTests/ens.sh +++ b/test/externalTests/ens.sh @@ -81,7 +81,7 @@ function ens_test sed -i "s|it\(('Cannot be called if CANNOT_CREATE_SUBDOMAIN is burned and is a new subdomain',\)|it.skip\1|g" test/wrapper/NameWrapper.js sed -i "s|it\(('Cannot be called if PARENT_CANNOT_CONTROL is burned and is an existing subdomain',\)|it.skip\1|g" test/wrapper/NameWrapper.js - find . -name "*.sol" -exec sed -i -e 's/^\(\s*\)\(assembly\)/\1\/\/\/ @solidity memory-safe-assembly\n\1\2/' '{}' \; + find . -name "*.sol" -type f -exec sed -i -e 's/^\(\s*\)\(assembly\)/\1\/\/\/ @solidity memory-safe-assembly\n\1\2/' '{}' \; for preset in $SELECTED_PRESETS; do hardhat_run_test "$config_file" "$preset" "${compile_only_presets[*]}" compile_fn test_fn From d7aa37de2eaa20e5463d2a266d8804c5fa2c80e4 Mon Sep 17 00:00:00 2001 From: r0qs Date: Tue, 20 Feb 2024 18:35:07 +0100 Subject: [PATCH 35/57] Use latest release instead of main branch on external tests --- scripts/externalTests/common.sh | 39 +++++++++++++------------ scripts/externalTests/runners/base.py | 3 +- scripts/externalTests/test_helpers.py | 40 +++++++++++++++----------- test/externalTests/bleeps.sh | 3 +- test/externalTests/brink.sh | 12 ++------ test/externalTests/chainlink.sh | 3 +- test/externalTests/colony.sh | 3 +- test/externalTests/elementfi.sh | 5 ++-- test/externalTests/ens.sh | 3 +- test/externalTests/euler.sh | 3 +- test/externalTests/gnosis.sh | 6 ++-- test/externalTests/gp2.sh | 15 ++-------- test/externalTests/perpetual-pools.sh | 3 +- test/externalTests/pool-together.sh | 8 ++---- test/externalTests/prb-math.py | 3 +- test/externalTests/trident.sh | 3 +- test/externalTests/uniswap.sh | 3 +- test/externalTests/yield-liquidator.sh | 3 +- test/externalTests/zeppelin.sh | 18 ++---------- 19 files changed, 68 insertions(+), 108 deletions(-) diff --git a/scripts/externalTests/common.sh b/scripts/externalTests/common.sh index 3bca968a5a..e49be6c8a0 100644 --- a/scripts/externalTests/common.sh +++ b/scripts/externalTests/common.sh @@ -106,25 +106,28 @@ function setup_solc function download_project { - local repo="$1" - local ref_type="$2" - local solcjs_ref="$3" - local test_dir="$4" - - [[ $ref_type == commit || $ref_type == branch || $ref_type == tag ]] || assertFail - - printLog "Cloning ${ref_type} ${solcjs_ref} of ${repo}..." - if [[ $ref_type == commit ]]; then - mkdir ext - cd ext - git init - git remote add origin "$repo" - git fetch --depth 1 origin "$solcjs_ref" - git reset --hard FETCH_HEAD - else - git clone --depth 1 "$repo" -b "$solcjs_ref" "$test_dir/ext" - cd ext + local repo_url="$1" + local ref="$2" + local test_dir="$3" + + printLog "Cloning ${repo_url}..." + # Clone the repo ignoring all blobs until needed by git. + # This allows access to commit history but with a fast initial clone + git clone --filter=blob:none "$repo_url" "$test_dir/ext" + cd "$test_dir/ext" + + # If the ref is '' try to use the latest tag as ref + # NOTE: Sadly this will not work with monorepos and may not always + # return the latest tag. + if [[ "$ref" == "" ]]; then + ref=$(git tag --sort=-v:refname | head --lines=1) fi + + [[ $ref != "" ]] || assertFail + + printLog "Using ref: ${ref}" + git checkout "$ref" + echo "Current commit hash: $(git rev-parse HEAD)" } diff --git a/scripts/externalTests/runners/base.py b/scripts/externalTests/runners/base.py index a79ed53442..c3807c528c 100644 --- a/scripts/externalTests/runners/base.py +++ b/scripts/externalTests/runners/base.py @@ -47,7 +47,6 @@ class TestConfig: name: str repo_url: str - ref_type: str ref: str compile_only_presets: List[SettingsPreset] = field(default_factory=list) settings_presets: List[SettingsPreset] = field(default_factory=lambda: list(SettingsPreset)) @@ -134,7 +133,7 @@ def run_test(runner: BaseRunner): print(f"Using compiler version {solc_version}") # Download project - download_project(runner.test_dir, runner.config.repo_url, runner.config.ref_type, runner.config.ref) + download_project(runner.test_dir, runner.config.repo_url, runner.config.ref) # Configure run environment runner.setup_environment() diff --git a/scripts/externalTests/test_helpers.py b/scripts/externalTests/test_helpers.py index 9a573d50ad..576db4429b 100644 --- a/scripts/externalTests/test_helpers.py +++ b/scripts/externalTests/test_helpers.py @@ -96,23 +96,29 @@ def parse_command_line(description: str, args: List[str]): return arg_parser.parse_args(args) -def download_project(test_dir: Path, repo_url: str, ref_type: str = "branch", ref: str = "master"): - assert ref_type in ("commit", "branch", "tag") - - print(f"Cloning {ref_type} {ref} of {repo_url}...") - if ref_type == "commit": - os.mkdir(test_dir) - os.chdir(test_dir) - subprocess.run(["git", "init"], check=True) - subprocess.run(["git", "remote", "add", "origin", repo_url], check=True) - subprocess.run(["git", "fetch", "--depth", "1", "origin", ref], check=True) - subprocess.run(["git", "reset", "--hard", "FETCH_HEAD"], check=True) - else: - os.chdir(test_dir.parent) - subprocess.run(["git", "clone", "--no-progress", "--depth", "1", repo_url, "-b", ref, test_dir.resolve()], check=True) - if not test_dir.exists(): - raise RuntimeError("Failed to clone the project.") - os.chdir(test_dir) +def download_project(test_dir: Path, repo_url: str, ref: str = ""): + print(f"Cloning {repo_url}...") + # Clone the repo ignoring all blobs until needed by git. + # This allows access to commit history but with a fast initial clone + subprocess.run(["git", "clone", "--filter", "blob:none", repo_url, test_dir.resolve()], check=True) + if not test_dir.exists(): + raise RuntimeError("Failed to clone the project.") + os.chdir(test_dir) + + # If the ref is '' try to use the latest tag as ref + # NOTE: Sadly this will not work with monorepos and may not always + # return the latest tag. + if ref == "": + tags = subprocess.check_output( + ["git", "tag", "--sort", "-v:refname"], + encoding="ascii" + ).strip().split('\n') + if len(tags) == 0: + raise RuntimeError("Failed to retrieve latest release tag.") + ref = tags[0] + + print(f"Using ref: {ref}") + subprocess.run(["git", "checkout", ref], check=True) if (test_dir / ".gitmodules").exists(): subprocess.run(["git", "submodule", "update", "--init"], check=True) diff --git a/test/externalTests/bleeps.sh b/test/externalTests/bleeps.sh index 30f0ec9240..5090e6c12e 100755 --- a/test/externalTests/bleeps.sh +++ b/test/externalTests/bleeps.sh @@ -38,7 +38,6 @@ function test_fn { HARDHAT_DEPLOY_FIXTURE=true npx --no hardhat --no-compile tes function bleeps_test { local repo="https://github.com/wighawag/bleeps" - local ref_type=branch local ref=main local config_file="hardhat.config.ts" local config_var=config @@ -58,7 +57,7 @@ function bleeps_test print_presets_or_exit "$SELECTED_PRESETS" setup_solc "$DIR" "$BINARY_TYPE" "$BINARY_PATH" - download_project "$repo" "$ref_type" "$ref" "$DIR" + download_project "$repo" "$ref" "$DIR" pushd "common-lib/" neutralize_package_json_hooks diff --git a/test/externalTests/brink.sh b/test/externalTests/brink.sh index 1c3ad2e19a..48cc4028f3 100755 --- a/test/externalTests/brink.sh +++ b/test/externalTests/brink.sh @@ -37,8 +37,7 @@ function test_fn { SNAPSHOT_UPDATE=1 npx --no hardhat test; } function brink_test { local repo="https://github.com/brinktrade/brink-core" - local ref_type=branch - local ref=master + local ref="" local config_file="hardhat.config.js" local config_var="" local extra_settings="metadata: {bytecodeHash: 'none'}" @@ -60,25 +59,18 @@ function brink_test print_presets_or_exit "$SELECTED_PRESETS" setup_solc "$DIR" "$BINARY_TYPE" "$BINARY_PATH" - download_project "$repo" "$ref_type" "$ref" "$DIR" + download_project "$repo" "$ref" "$DIR" # TODO: Remove this when Brink merges https://github.com/brinktrade/brink-core/pull/52 sed -i "s|\(function isValidSignature(bytes \)calldata\( _data, bytes \)calldata\( _signature)\)|\1memory\2memory\3|g" src/Test/MockEIP1271Validator.sol - neutralize_package_lock neutralize_package_json_hooks force_hardhat_compiler_binary "$config_file" "$BINARY_TYPE" "$BINARY_PATH" force_hardhat_compiler_settings "$config_file" "$(first_word "$SELECTED_PRESETS")" "$config_var" "$CURRENT_EVM_VERSION" "$extra_settings" "$extra_optimizer_settings" yarn install yarn add hardhat-gas-reporter - # TODO: Remove when https://github.com/brinktrade/brink-core/issues/48 is fixed. - # TODO: Chai is ESM-only since version 5.x (see: https://github.com/chaijs/chai/issues/1561#issuecomment-1871134261), - # thus, we should stick to version 4.x until Brink and other dependencies also migrate to ESM. - yarn add chai@4.4.0 - replace_version_pragmas - for preset in $SELECTED_PRESETS; do hardhat_run_test "$config_file" "$preset" "${compile_only_presets[*]}" compile_fn test_fn "$config_var" "$extra_settings" "$extra_optimizer_settings" store_benchmark_report hardhat brink "$repo" "$preset" diff --git a/test/externalTests/chainlink.sh b/test/externalTests/chainlink.sh index 4d5080730f..f11156713c 100755 --- a/test/externalTests/chainlink.sh +++ b/test/externalTests/chainlink.sh @@ -37,7 +37,6 @@ function test_fn { yarn test; } function chainlink_test { local repo="https://github.com/solidity-external-tests/chainlink" - local ref_type=branch local ref=develop_080 local config_file="hardhat.config.ts" local config_var=config @@ -58,7 +57,7 @@ function chainlink_test print_presets_or_exit "$SELECTED_PRESETS" setup_solc "$DIR" "$BINARY_TYPE" "$BINARY_PATH" - download_project "$repo" "$ref_type" "$ref" "$DIR" + download_project "$repo" "$ref" "$DIR" cd "contracts/" diff --git a/test/externalTests/colony.sh b/test/externalTests/colony.sh index 402865107a..1dcd7deaa3 100755 --- a/test/externalTests/colony.sh +++ b/test/externalTests/colony.sh @@ -37,7 +37,6 @@ function test_fn { yarn run test:contracts; } function colony_test { local repo="https://github.com/solidity-external-tests/colonyNetwork.git" - local ref_type=branch local ref="develop_080" local config_file="truffle.js" @@ -57,7 +56,7 @@ function colony_test print_presets_or_exit "$SELECTED_PRESETS" setup_solc "$DIR" "$BINARY_TYPE" "$BINARY_PATH" - download_project "$repo" "$ref_type" "$ref" "$DIR" + download_project "$repo" "$ref" "$DIR" [[ $BINARY_TYPE == native ]] && replace_global_solc "$BINARY_PATH" neutralize_package_json_hooks diff --git a/test/externalTests/elementfi.sh b/test/externalTests/elementfi.sh index 94e622d10c..f3ecbb1417 100755 --- a/test/externalTests/elementfi.sh +++ b/test/externalTests/elementfi.sh @@ -37,8 +37,7 @@ function test_fn { npm run test; } function elementfi_test { local repo="https://github.com/element-fi/elf-contracts" - local ref_type=branch - local ref=main + local ref="" local config_file="hardhat.config.ts" local config_var=config @@ -60,7 +59,7 @@ function elementfi_test print_presets_or_exit "$SELECTED_PRESETS" setup_solc "$DIR" "$BINARY_TYPE" "$BINARY_PATH" - download_project "$repo" "$ref_type" "$ref" "$DIR" + download_project "$repo" "$ref" "$DIR" chmod +x scripts/load-balancer-contracts.sh scripts/load-balancer-contracts.sh diff --git a/test/externalTests/ens.sh b/test/externalTests/ens.sh index aee291a1a4..a79d26c4ef 100755 --- a/test/externalTests/ens.sh +++ b/test/externalTests/ens.sh @@ -37,7 +37,6 @@ function test_fn { yarn test; } function ens_test { local repo="https://github.com/ensdomains/ens-contracts.git" - local ref_type=commit local ref="083d29a2c50cd0a8307386abf8fadc217b256256" local config_file="hardhat.config.js" @@ -57,7 +56,7 @@ function ens_test print_presets_or_exit "$SELECTED_PRESETS" setup_solc "$DIR" "$BINARY_TYPE" "$BINARY_PATH" - download_project "$repo" "$ref_type" "$ref" "$DIR" + download_project "$repo" "$ref" "$DIR" neutralize_package_lock neutralize_package_json_hooks diff --git a/test/externalTests/euler.sh b/test/externalTests/euler.sh index 80f18e702d..9ede1a3406 100755 --- a/test/externalTests/euler.sh +++ b/test/externalTests/euler.sh @@ -40,7 +40,6 @@ function test_fn { function euler_test { local repo="https://github.com/euler-xyz/euler-contracts" - local ref_type=branch local ref="master" local config_file="hardhat.config.js" @@ -59,7 +58,7 @@ function euler_test print_presets_or_exit "$SELECTED_PRESETS" setup_solc "$DIR" "$BINARY_TYPE" "$BINARY_PATH" - download_project "$repo" "$ref_type" "$ref" "$DIR" + download_project "$repo" "$ref" "$DIR" # Disable tests that won't pass on the ir presets due to Hardhat heuristics. Note that this also disables # them for other presets but that's fine - we want same code run for benchmarks to be comparable. diff --git a/test/externalTests/gnosis.sh b/test/externalTests/gnosis.sh index 5f7ea48765..218a5a7504 100755 --- a/test/externalTests/gnosis.sh +++ b/test/externalTests/gnosis.sh @@ -37,8 +37,7 @@ function test_fn { npm test; } function gnosis_safe_test { local repo="https://github.com/safe-global/safe-contracts.git" - local ref_type=branch - local ref=main + local ref="" local config_file="hardhat.config.ts" local config_var=userConfig @@ -58,7 +57,7 @@ function gnosis_safe_test print_presets_or_exit "$SELECTED_PRESETS" setup_solc "$DIR" "$BINARY_TYPE" "$BINARY_PATH" - download_project "$repo" "$ref_type" "$ref" "$DIR" + download_project "$repo" "$ref" "$DIR" [[ $BINARY_TYPE == native ]] && replace_global_solc "$BINARY_PATH" # NOTE: The patterns below intentionally have hard-coded versions. @@ -77,7 +76,6 @@ function gnosis_safe_test sed -i "s|\(it\)\((\"can be used only via DELEGATECALL opcode\"\)|\1.skip\2|g" test/libraries/SignMessageLib.spec.ts sed -i "s|it\((\"can only be called from Safe itself\"\)|it.skip\1|g" test/libraries/Migration.spec.ts - neutralize_package_lock neutralize_package_json_hooks force_hardhat_compiler_binary "$config_file" "$BINARY_TYPE" "$BINARY_PATH" force_hardhat_compiler_settings "$config_file" "$(first_word "$SELECTED_PRESETS")" "$config_var" diff --git a/test/externalTests/gp2.sh b/test/externalTests/gp2.sh index bbb442226f..1e52134a43 100755 --- a/test/externalTests/gp2.sh +++ b/test/externalTests/gp2.sh @@ -37,8 +37,7 @@ function test_fn { yarn test; } function gp2_test { local repo="https://github.com/cowprotocol/contracts.git" - local ref_type=branch - local ref=main + local ref="" local config_file="hardhat.config.ts" local config_var="config" @@ -58,10 +57,9 @@ function gp2_test print_presets_or_exit "$SELECTED_PRESETS" setup_solc "$DIR" "$BINARY_TYPE" "$BINARY_PATH" - download_project "$repo" "$ref_type" "$ref" "$DIR" + download_project "$repo" "$ref" "$DIR" [[ $BINARY_TYPE == native ]] && replace_global_solc "$BINARY_PATH" - neutralize_package_lock neutralize_package_json_hooks name_hardhat_default_export "$config_file" "$config_var" force_hardhat_compiler_binary "$config_file" "$BINARY_TYPE" "$BINARY_PATH" @@ -69,14 +67,6 @@ function gp2_test force_hardhat_unlimited_contract_size "$config_file" "$config_var" yarn - # Workaround for error caused by the last release of hardhat-waffle@2.0.6 that bumps ethereum-waffle - # to version 4.0.10 and breaks gp2 build with the following error: - # - # Cannot find module 'ethereum-waffle/dist/cjs/src/deployContract' - # - # See: https://github.com/NomicFoundation/hardhat-waffle/commit/83ee9cb36ee59d0bedacbbd00043f030af104ad0 - yarn add '@nomiclabs/hardhat-waffle@2.0.5' - # Some dependencies come with pre-built artifacts. We want to build from scratch. rm -r node_modules/@gnosis.pm/safe-contracts/build/ @@ -104,7 +94,6 @@ function gp2_test sed -i 's|it\(("should revert when encoding invalid flags"\)|it.skip\1|g' test/GPv2Trade.test.ts replace_version_pragmas - for preset in $SELECTED_PRESETS; do hardhat_run_test "$config_file" "$preset" "${compile_only_presets[*]}" compile_fn test_fn "$config_var" store_benchmark_report hardhat gp2 "$repo" "$preset" diff --git a/test/externalTests/perpetual-pools.sh b/test/externalTests/perpetual-pools.sh index 8d8dc34e21..31748a40ca 100755 --- a/test/externalTests/perpetual-pools.sh +++ b/test/externalTests/perpetual-pools.sh @@ -37,7 +37,6 @@ function test_fn { yarn test; } function perpetual_pools_test { local repo="https://github.com/solidity-external-tests/perpetual-pools-contracts" - local ref_type=branch local ref=pools-v2 local config_file="hardhat.config.ts" local config_var="config" @@ -57,7 +56,7 @@ function perpetual_pools_test print_presets_or_exit "$SELECTED_PRESETS" setup_solc "$DIR" "$BINARY_TYPE" "$BINARY_PATH" - download_project "$repo" "$ref_type" "$ref" "$DIR" + download_project "$repo" "$ref" "$DIR" # Disable tests that won't pass on the ir presets due to Hardhat heuristics. Note that this also disables # them for other presets but that's fine - we want same code run for benchmarks to be comparable. diff --git a/test/externalTests/pool-together.sh b/test/externalTests/pool-together.sh index 3f7141d9ba..f841206ef2 100755 --- a/test/externalTests/pool-together.sh +++ b/test/externalTests/pool-together.sh @@ -36,9 +36,8 @@ function test_fn { yarn test; } function pool_together_test { - local repo="https://github.com/pooltogether/v4-core" - local ref_type=branch - local ref=master + local repo="https://github.com/pooltogether/v4-core.git" + local ref="" local config_file="hardhat.config.ts" local config_var="config" @@ -57,13 +56,12 @@ function pool_together_test print_presets_or_exit "$SELECTED_PRESETS" setup_solc "$DIR" "$BINARY_TYPE" "$BINARY_PATH" - download_project "$repo" "$ref_type" "$ref" "$DIR" + download_project "$repo" "$ref" "$DIR" # TODO: Remove this when https://github.com/NomicFoundation/hardhat/issues/3365 gets fixed. sed -i "s|it\(('should fail to return value if value passed does not fit in [0-9]\+ bits'\)|it.skip\1|g" test/libraries/ExtendedSafeCast.test.ts sed -i "s|it\(('should require an rng to be requested'\)|it.skip\1|g" test/DrawBeacon.test.ts - neutralize_package_lock neutralize_package_json_hooks force_hardhat_compiler_binary "$config_file" "$BINARY_TYPE" "$BINARY_PATH" force_hardhat_compiler_settings "$config_file" "$(first_word "$SELECTED_PRESETS")" "$config_var" diff --git a/test/externalTests/prb-math.py b/test/externalTests/prb-math.py index e57688ec2e..2d1469fc90 100755 --- a/test/externalTests/prb-math.py +++ b/test/externalTests/prb-math.py @@ -51,8 +51,7 @@ def configure(self): test_config = TestConfig( name="PRBMath", repo_url="https://github.com/PaulRBerg/prb-math.git", - ref_type="branch", - ref="main", + ref="", compile_only_presets=[ # pylint: disable=line-too-long # SettingsPreset.IR_NO_OPTIMIZE, # Error: Yul exception:Variable expr_15699_address is 2 slot(s) too deep inside the stack. Stack too deep. diff --git a/test/externalTests/trident.sh b/test/externalTests/trident.sh index d8d94eb3c1..e5fa914e9c 100755 --- a/test/externalTests/trident.sh +++ b/test/externalTests/trident.sh @@ -45,7 +45,6 @@ function test_fn { function trident_test { local repo="https://github.com/sushiswap/trident" - local ref_type=commit # FIXME: Switch back to master branch when https://github.com/sushiswap/trident/issues/303 gets fixed. local ref="0cab5ae884cc9a41223d52791be775c3a053cb26" # master as of 2021-12-16 local config_file="hardhat.config.ts" @@ -66,7 +65,7 @@ function trident_test print_presets_or_exit "$SELECTED_PRESETS" setup_solc "$DIR" "$BINARY_TYPE" "$BINARY_PATH" - download_project "$repo" "$ref_type" "$ref" "$DIR" + download_project "$repo" "$ref" "$DIR" # TODO: Currently tests work only with the exact versions from yarn.lock. # Re-enable this when https://github.com/sushiswap/trident/issues/284 is fixed. diff --git a/test/externalTests/uniswap.sh b/test/externalTests/uniswap.sh index 8d2551b619..bf5f828987 100755 --- a/test/externalTests/uniswap.sh +++ b/test/externalTests/uniswap.sh @@ -37,7 +37,6 @@ function test_fn { UPDATE_SNAPSHOT=1 npx hardhat test; } function uniswap_test { local repo="https://github.com/solidity-external-tests/uniswap-v3-core.git" - local ref_type=branch local ref=main_080 local config_file="hardhat.config.ts" local config_var=config @@ -57,7 +56,7 @@ function uniswap_test print_presets_or_exit "$SELECTED_PRESETS" setup_solc "$DIR" "$BINARY_TYPE" "$BINARY_PATH" - download_project "$repo" "$ref_type" "$ref" "$DIR" + download_project "$repo" "$ref" "$DIR" # Disable tests that won't pass on the ir presets due to Hardhat heuristics. Note that this also disables # them for other presets but that's fine - we want same code run for benchmarks to be comparable. diff --git a/test/externalTests/yield-liquidator.sh b/test/externalTests/yield-liquidator.sh index 7a4353af57..16a6287e53 100755 --- a/test/externalTests/yield-liquidator.sh +++ b/test/externalTests/yield-liquidator.sh @@ -37,7 +37,6 @@ function test_fn { npm run test; } function yield_liquidator_test { local repo="https://github.com/yieldprotocol/yield-liquidator-v2" - local ref_type=branch local ref="master" local config_file="hardhat.config.ts" local config_var="module.exports" @@ -57,7 +56,7 @@ function yield_liquidator_test print_presets_or_exit "$SELECTED_PRESETS" setup_solc "$DIR" "$BINARY_TYPE" "$BINARY_PATH" - download_project "$repo" "$ref_type" "$ref" "$DIR" + download_project "$repo" "$ref" "$DIR" neutralize_package_lock neutralize_package_json_hooks diff --git a/test/externalTests/zeppelin.sh b/test/externalTests/zeppelin.sh index 9f72aa4ec9..655e4814f7 100755 --- a/test/externalTests/zeppelin.sh +++ b/test/externalTests/zeppelin.sh @@ -42,8 +42,7 @@ function test_fn { npm test; } function zeppelin_test { local repo="https://github.com/OpenZeppelin/openzeppelin-contracts.git" - local ref_type=branch - local ref="master" + local ref="" local config_file="hardhat.config.js" local compile_only_presets=( @@ -62,7 +61,7 @@ function zeppelin_test print_presets_or_exit "$SELECTED_PRESETS" setup_solc "$DIR" "$BINARY_TYPE" "$BINARY_PATH" - download_project "$repo" "$ref_type" "$ref" "$DIR" + download_project "$repo" "$ref" "$DIR" # Disable tests that won't pass on the ir presets due to Hardhat heuristics. Note that this also disables # them for other presets but that's fine - we want same code run for benchmarks to be comparable. @@ -100,25 +99,12 @@ function zeppelin_test # Here only the testToInt(248) and testToInt(256) cases fail so change the loop range to skip them sed -i "s|range(8, 256, 8)\(.forEach(bits => testToInt(bits));\)|range(8, 240, 8)\1|" test/utils/math/SafeCast.test.js - neutralize_package_lock neutralize_package_json_hooks force_hardhat_compiler_binary "$config_file" "$BINARY_TYPE" "$BINARY_PATH" force_hardhat_compiler_settings "$config_file" "$(first_word "$SELECTED_PRESETS")" npm install - # TODO: We fix the version to 2.0.3 instead of 2.0.4 since the latter does not work with ethers.js 6.10.0 - # Maybe related to the use of dynamic imports here: https://github.com/NomicFoundation/hardhat/commit/16ae15642951ac324ef7093a3342f7cf3a2a49a4 - npm install @nomicfoundation/hardhat-chai-matchers@2.0.3 - - # TODO: Remove when OpenZeppelin update to ethers 6.11.1+ - # Prior versions of ethers accepts an object instead of a string as an argument to the toUtf8Bytes function. - # However, starting from Ethers version 6.11.1, string arguments are enforced, - # which causes the introduced assertion to fail in some OpenZeppelin tests. - # See: https://github.com/ethers-io/ethers.js/issues/4583 - npm install ethers@6.11.0 - replace_version_pragmas - for preset in $SELECTED_PRESETS; do hardhat_run_test "$config_file" "$preset" "${compile_only_presets[*]}" compile_fn test_fn store_benchmark_report hardhat zeppelin "$repo" "$preset" From a9a870d8fc87e43e89467cabfe9c6b84217c715b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Wed, 7 Feb 2024 14:53:31 +0100 Subject: [PATCH 36/57] Test coverage for existing parsing and formatting functionality of gas expectations --- test/libsolidity/util/TestFileParserTests.cpp | 70 +++++++++++++++---- .../util/TestFunctionCallTests.cpp | 28 ++++++++ 2 files changed, 86 insertions(+), 12 deletions(-) diff --git a/test/libsolidity/util/TestFileParserTests.cpp b/test/libsolidity/util/TestFileParserTests.cpp index 59934fdb25..46499c1475 100644 --- a/test/libsolidity/util/TestFileParserTests.cpp +++ b/test/libsolidity/util/TestFileParserTests.cpp @@ -49,18 +49,18 @@ std::vector parse(std::string const& _source, std::map _rawArguments = std::vector{}, - bool _isConstructor = false, - bool _isLibrary = false + FunctionCall const& _call, + FunctionCall::DisplayMode _mode, + std::string _signature = "", + bool _failure = true, + bytes _arguments = bytes{}, + bytes _expectations = bytes{}, + FunctionValue _value = { 0 }, + std::string _argumentComment = "", + std::string _expectationComment = "", + std::vector _rawArguments = std::vector{}, + bool _isConstructor = false, + bool _isLibrary = false ) { BOOST_REQUIRE_EQUAL(_call.expectations.failure, _failure); @@ -1063,6 +1063,52 @@ BOOST_AUTO_TEST_CASE(call_effects) BOOST_CHECK_THROW(parse(source, builtins), std::exception); } +BOOST_AUTO_TEST_CASE(gas) +{ + char const* source = R"( + // f() -> + // gas ir: 3245 + // gas legacy: 5000 + // gas legacyOptimized: 0 + )"; + auto const calls = parse(source); + BOOST_REQUIRE_EQUAL(calls.size(), 1); + BOOST_REQUIRE_EQUAL(calls[0].expectations.failure, false); + BOOST_TEST(calls[0].expectations.gasUsed == (std::map{ + {"ir", 3245}, + {"legacy", 5000}, + {"legacyOptimized", 0}, + })); +} + +BOOST_AUTO_TEST_CASE(gas_before_call) +{ + char const* source = R"( + // gas ir: 3245 + // f() -> + )"; + BOOST_REQUIRE_THROW(parse(source), TestParserError); +} + +BOOST_AUTO_TEST_CASE(gas_invalid_run_type) +{ + char const* source = R"( + // f() -> + // gas ir: 3245 + // gas experimental: 5000 + )"; + BOOST_REQUIRE_THROW(parse(source), TestParserError); +} + +BOOST_AUTO_TEST_CASE(gas_duplicate_run_type) +{ + char const* source = R"( + // f() -> + // gas ir: 3245 + // gas ir: 3245 + )"; + BOOST_REQUIRE_THROW(parse(source), TestParserError); +} BOOST_AUTO_TEST_SUITE_END() } diff --git a/test/libsolidity/util/TestFunctionCallTests.cpp b/test/libsolidity/util/TestFunctionCallTests.cpp index fa3fe995ca..74a45c3268 100644 --- a/test/libsolidity/util/TestFunctionCallTests.cpp +++ b/test/libsolidity/util/TestFunctionCallTests.cpp @@ -250,6 +250,34 @@ BOOST_AUTO_TEST_CASE(format_failure_singleline) BOOST_REQUIRE_EQUAL(test.format(), "// f(uint8): 1 -> FAILURE"); } +BOOST_AUTO_TEST_CASE(format_gas) +{ + FunctionCall call{ + "f()", + FunctionValue{0}, + FunctionCallArgs{}, + FunctionCallExpectations{ + std::vector{}, + false, // failure + "some comment", + { + {"ir", 3245}, + {"legacy", 5000}, + {"legacy optimized", 0}, + }, + } + }; + call.omitsArrow = false; + + BOOST_REQUIRE_EQUAL( + TestFunctionCall(call).format(), + "// f() -> #some comment#\n" + "// gas ir: 3245\n" + "// gas legacy: 5000\n" + "// gas legacy optimized: 0" + ); +} + BOOST_AUTO_TEST_SUITE_END() } From e47e948ff6d1319660b98d1502eff44356c303aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Sun, 11 Feb 2024 13:07:13 +0100 Subject: [PATCH 37/57] SoltesTypes: Fix outdated comment about allowed keys in gasUsed --- test/libsolidity/util/SoltestTypes.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/libsolidity/util/SoltestTypes.h b/test/libsolidity/util/SoltestTypes.h index b5b746e325..672e705534 100644 --- a/test/libsolidity/util/SoltestTypes.h +++ b/test/libsolidity/util/SoltestTypes.h @@ -216,7 +216,9 @@ struct FunctionCallExpectations return raw; } /// Gas used by function call - /// Should have values for Yul, YulOptimized, Legacy and LegacyOptimized + /// Keys represent all distinct combinations of compilation settings that affect produced + /// bytecode (and therefore the cost), except for EVM version. E.g. IR codegen without + /// optimization legacy codegen with optimization. std::map gasUsed; }; From d98c9438b2779ad554a179ca2d537d3da2dda33b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Wed, 7 Feb 2024 18:39:44 +0100 Subject: [PATCH 38/57] TestFunctionCall::formatGasExpectations(): runType can't be empty in practice --- test/libsolidity/util/TestFunctionCall.cpp | 43 +++++++++++----------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/test/libsolidity/util/TestFunctionCall.cpp b/test/libsolidity/util/TestFunctionCall.cpp index 64dfbd9825..716dbff13b 100644 --- a/test/libsolidity/util/TestFunctionCall.cpp +++ b/test/libsolidity/util/TestFunctionCall.cpp @@ -339,27 +339,28 @@ std::string TestFunctionCall::formatGasExpectations( { std::stringstream os; for (auto const& [runType, gasUsed]: (_useActualCost ? m_gasCosts : m_call.expectations.gasUsed)) - if (!runType.empty()) - { - bool differentResults = - m_gasCosts.count(runType) > 0 && - m_call.expectations.gasUsed.count(runType) > 0 && - m_gasCosts.at(runType) != m_call.expectations.gasUsed.at(runType); - - s256 difference = 0; - if (differentResults) - difference = - static_cast(m_gasCosts.at(runType)) - - static_cast(m_call.expectations.gasUsed.at(runType)); - int percent = 0; - if (differentResults) - percent = static_cast( - 100.0 * (static_cast(difference) / static_cast(m_call.expectations.gasUsed.at(runType))) - ); - os << std::endl << _linePrefix << "// gas " << runType << ": " << (gasUsed.str()); - if (_showDifference && differentResults && _useActualCost) - os << " [" << std::showpos << difference << " (" << percent << "%)]"; - } + { + soltestAssert(runType != ""); + + bool differentResults = + m_gasCosts.count(runType) > 0 && + m_call.expectations.gasUsed.count(runType) > 0 && + m_gasCosts.at(runType) != m_call.expectations.gasUsed.at(runType); + + s256 difference = 0; + if (differentResults) + difference = + static_cast(m_gasCosts.at(runType)) - + static_cast(m_call.expectations.gasUsed.at(runType)); + int percent = 0; + if (differentResults) + percent = static_cast( + 100.0 * (static_cast(difference) / static_cast(m_call.expectations.gasUsed.at(runType))) + ); + os << std::endl << _linePrefix << "// gas " << runType << ": " << (gasUsed.str()); + if (_showDifference && differentResults && _useActualCost) + os << " [" << std::showpos << difference << " (" << percent << "%)]"; + } return os.str(); } From c55c8b5504fdb8789741883e5af6f890be2b5cb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Wed, 7 Feb 2024 19:42:41 +0100 Subject: [PATCH 39/57] TestFunctionCall::formatGasExpectations(): Move diffing into a helper --- test/libsolidity/util/TestFunctionCall.cpp | 43 +++++++++++++--------- 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/test/libsolidity/util/TestFunctionCall.cpp b/test/libsolidity/util/TestFunctionCall.cpp index 716dbff13b..1d8c721919 100644 --- a/test/libsolidity/util/TestFunctionCall.cpp +++ b/test/libsolidity/util/TestFunctionCall.cpp @@ -21,6 +21,7 @@ #include +#include #include #include #include @@ -331,6 +332,23 @@ std::string TestFunctionCall::formatRawParameters( return os.str(); } +namespace +{ + +std::string formatGasDiff(std::optional const& _gasUsed, std::optional const& _reference) +{ + if (!_reference.has_value() || !_gasUsed.has_value() || _gasUsed == _reference) + return ""; + + s256 difference = static_cast(*_gasUsed) - static_cast(*_reference); + int percent = static_cast( + 100.0 * (static_cast(difference) / static_cast(*_reference)) + ); + return fmt::format("{} ({:+}%)", difference.str(), percent); +} + +} + std::string TestFunctionCall::formatGasExpectations( std::string const& _linePrefix, bool _useActualCost, @@ -342,24 +360,13 @@ std::string TestFunctionCall::formatGasExpectations( { soltestAssert(runType != ""); - bool differentResults = - m_gasCosts.count(runType) > 0 && - m_call.expectations.gasUsed.count(runType) > 0 && - m_gasCosts.at(runType) != m_call.expectations.gasUsed.at(runType); - - s256 difference = 0; - if (differentResults) - difference = - static_cast(m_gasCosts.at(runType)) - - static_cast(m_call.expectations.gasUsed.at(runType)); - int percent = 0; - if (differentResults) - percent = static_cast( - 100.0 * (static_cast(difference) / static_cast(m_call.expectations.gasUsed.at(runType))) - ); - os << std::endl << _linePrefix << "// gas " << runType << ": " << (gasUsed.str()); - if (_showDifference && differentResults && _useActualCost) - os << " [" << std::showpos << difference << " (" << percent << "%)]"; + os << std::endl << _linePrefix << "// gas " << runType << ": " << gasUsed.str(); + std::string gasDiff = formatGasDiff( + m_gasCosts.count(runType) > 0 ? std::make_optional(m_gasCosts.at(runType)) : std::nullopt, + m_call.expectations.gasUsed.count(runType) > 0 ? std::make_optional(m_call.expectations.gasUsed.at(runType)) : std::nullopt + ); + if (_showDifference && !gasDiff.empty() && _useActualCost) + os << " [" << gasDiff << "]"; } return os.str(); } From cd94139f3f666ea3087122a46ab8b461722bd4fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Wed, 7 Feb 2024 19:51:57 +0100 Subject: [PATCH 40/57] TestFunctionCall::formatGasExpectations(): Handle corner cases properly --- test/libsolidity/util/TestFunctionCall.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/libsolidity/util/TestFunctionCall.cpp b/test/libsolidity/util/TestFunctionCall.cpp index 1d8c721919..7a77f72879 100644 --- a/test/libsolidity/util/TestFunctionCall.cpp +++ b/test/libsolidity/util/TestFunctionCall.cpp @@ -340,7 +340,13 @@ std::string formatGasDiff(std::optional const& _gasUsed, std::optional(*_gasUsed) - static_cast(*_reference); + + if (*_reference == 0) + return fmt::format("{}", difference.str()); + int percent = static_cast( 100.0 * (static_cast(difference) / static_cast(*_reference)) ); From d5bae3f5973c54395e450762ce8df25ba1dd3285 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Wed, 7 Feb 2024 20:00:19 +0100 Subject: [PATCH 41/57] TestFunctionCall::formatGasExpectations(): Helper for getting optional values from a map --- test/libsolidity/util/TestFunctionCall.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/test/libsolidity/util/TestFunctionCall.cpp b/test/libsolidity/util/TestFunctionCall.cpp index 7a77f72879..54dd769d61 100644 --- a/test/libsolidity/util/TestFunctionCall.cpp +++ b/test/libsolidity/util/TestFunctionCall.cpp @@ -353,6 +353,16 @@ std::string formatGasDiff(std::optional const& _gasUsed, std::optional gasOrNullopt(std::map const& _map, std::string const& _key) +{ + auto it = _map.find(_key); + if (it == _map.end()) + return std::nullopt; + + return it->second; +} + } std::string TestFunctionCall::formatGasExpectations( @@ -368,8 +378,8 @@ std::string TestFunctionCall::formatGasExpectations( os << std::endl << _linePrefix << "// gas " << runType << ": " << gasUsed.str(); std::string gasDiff = formatGasDiff( - m_gasCosts.count(runType) > 0 ? std::make_optional(m_gasCosts.at(runType)) : std::nullopt, - m_call.expectations.gasUsed.count(runType) > 0 ? std::make_optional(m_call.expectations.gasUsed.at(runType)) : std::nullopt + gasOrNullopt(m_gasCosts, runType), + gasOrNullopt(m_call.expectations.gasUsed, runType) ); if (_showDifference && !gasDiff.empty() && _useActualCost) os << " [" << gasDiff << "]"; From 2ee4d6b1eeaee104007a64ce0b23faa57862800d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 9 Feb 2024 19:24:34 +0100 Subject: [PATCH 42/57] Keep track of code deposit gas when executing contract code --- test/EVMHost.cpp | 7 ++++++- test/EVMHost.h | 7 +++++++ test/ExecutionFramework.cpp | 2 ++ test/ExecutionFramework.h | 6 ++++++ 4 files changed, 21 insertions(+), 1 deletion(-) diff --git a/test/EVMHost.cpp b/test/EVMHost.cpp index 9af4d7099d..c43d53d6bc 100644 --- a/test/EVMHost.cpp +++ b/test/EVMHost.cpp @@ -161,6 +161,7 @@ void EVMHost::reset() recorded_calls.clear(); // Clear EIP-2929 account access indicator recorded_account_accesses.clear(); + m_totalCodeDepositGas = 0; // Mark all precompiled contracts as existing. Existing here means to have a balance (as per EIP-161). // NOTE: keep this in sync with `EVMHost::call` below. @@ -203,6 +204,7 @@ void EVMHost::newTransactionFrame() // Otherwise, the previous behavior (pre-Cancun) is maintained. accounts.erase(address); newlyCreatedAccounts.clear(); + m_totalCodeDepositGas = 0; recorded_selfdestructs.clear(); } @@ -392,15 +394,18 @@ evmc::Result EVMHost::call(evmc_message const& _message) noexcept if (message.kind == EVMC_CREATE || message.kind == EVMC_CREATE2) { - result.gas_left -= static_cast(evmasm::GasCosts::createDataGas * result.output_size); + int64_t codeDepositGas = static_cast(evmasm::GasCosts::createDataGas * result.output_size); + result.gas_left -= codeDepositGas; if (result.gas_left < 0) { + m_totalCodeDepositGas += -result.gas_left; result.gas_left = 0; result.status_code = EVMC_OUT_OF_GAS; // TODO clear some fields? } else { + m_totalCodeDepositGas += codeDepositGas; result.create_address = message.recipient; destination.code = evmc::bytes(result.output_data, result.output_data + result.output_size); destination.codehash = convertToEVMC(keccak256({result.output_data, result.output_size})); diff --git a/test/EVMHost.h b/test/EVMHost.h index 144596e05e..848314c879 100644 --- a/test/EVMHost.h +++ b/test/EVMHost.h @@ -94,6 +94,8 @@ class EVMHost: public evmc::MockedHost /// @returns contents of storage at @param _addr. StorageMap const& get_address_storage(evmc::address const& _addr); + u256 totalCodeDepositGas() const { return m_totalCodeDepositGas; } + static Address convertFromEVMC(evmc::address const& _addr); static evmc::address convertToEVMC(Address const& _addr); static util::h256 convertFromEVMC(evmc::bytes32 const& _data); @@ -137,6 +139,11 @@ class EVMHost: public evmc::MockedHost langutil::EVMVersion m_evmVersion; /// EVM version requested from EVMC (matches the above) evmc_revision m_evmRevision; + + /// The part of the total cost of the current transaction that paid for the code deposits. + /// I.e. GAS_CODE_DEPOSIT times the total size of deployed code of all newly created contracts, + /// including the current contract itself if it was a creation transaction. + u256 m_totalCodeDepositGas; }; class EVMHostPrinter diff --git a/test/ExecutionFramework.cpp b/test/ExecutionFramework.cpp index 9fc36440b3..0081ba4a9d 100644 --- a/test/ExecutionFramework.cpp +++ b/test/ExecutionFramework.cpp @@ -191,6 +191,7 @@ void ExecutionFramework::sendMessage(bytes const& _data, bool _isCreation, u256 auto const gasRefund = std::min(u256(result.gas_refund), totalGasUsed / refundRatio); m_gasUsed = totalGasUsed - gasRefund; + m_gasUsedForCodeDeposit = m_evmcHost->totalCodeDepositGas(); m_transactionSuccessful = (result.status_code == EVMC_SUCCESS); if (m_showMessages) @@ -199,6 +200,7 @@ void ExecutionFramework::sendMessage(bytes const& _data, bool _isCreation, u256 std::cout << " result: " << static_cast(result.status_code) << std::endl; std::cout << " gas used: " << m_gasUsed.str() << std::endl; std::cout << " gas used (without refund): " << totalGasUsed.str() << std::endl; + std::cout << " code deposits only: " << m_gasUsedForCodeDeposit.str() << std::endl; std::cout << " gas refund (total): " << result.gas_refund << std::endl; std::cout << " gas refund (bound): " << gasRefund.str() << std::endl; } diff --git a/test/ExecutionFramework.h b/test/ExecutionFramework.h index 27ceb4f280..5d66ea10d0 100644 --- a/test/ExecutionFramework.h +++ b/test/ExecutionFramework.h @@ -303,7 +303,13 @@ class ExecutionFramework util::h160 m_sender = account(0); util::h160 m_contractAddress; bytes m_output; + + /// Total gas used by the transaction, after refund. u256 m_gasUsed; + + /// The portion of @a m_gasUsed spent on code deposits of newly created contracts. + /// May exceed @a m_gasUsed in rare corner cases due to refunds. + u256 m_gasUsedForCodeDeposit; }; #define ABI_CHECK(result, expectation) do { \ From 96233864437e304b6c02c867b29ffe428a72c630 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 9 Feb 2024 19:27:07 +0100 Subject: [PATCH 43/57] Separate 'code' gas settings in semantic tests --- test/libsolidity/SemanticTest.cpp | 10 +- test/libsolidity/util/SoltestTypes.h | 5 + test/libsolidity/util/TestFileParser.cpp | 42 ++++++-- test/libsolidity/util/TestFileParserTests.cpp | 102 ++++++++++++++++++ test/libsolidity/util/TestFunctionCall.cpp | 22 ++++ test/libsolidity/util/TestFunctionCall.h | 9 +- .../util/TestFunctionCallTests.cpp | 65 ++++++++--- 7 files changed, 231 insertions(+), 24 deletions(-) diff --git a/test/libsolidity/SemanticTest.cpp b/test/libsolidity/SemanticTest.cpp index 25113b689d..676c39eaf9 100644 --- a/test/libsolidity/SemanticTest.cpp +++ b/test/libsolidity/SemanticTest.cpp @@ -569,6 +569,11 @@ bool SemanticTest::checkGasCostExpectation(TestFunctionCall& io_test, bool _comp (_compileViaYul ? "ir"s : "legacy"s) + (m_optimiserSettings == OptimiserSettings::full() ? "Optimized" : ""); + soltestAssert( + io_test.call().expectations.gasUsed.count(setting) == + io_test.call().expectations.gasUsedForCodeDeposit.count(setting) + ); + // We don't check gas if enforce gas cost is not active // or test is run with abi encoder v1 only // or gas used less than threshold for enforcing feature @@ -587,9 +592,12 @@ bool SemanticTest::checkGasCostExpectation(TestFunctionCall& io_test, bool _comp solAssert(!m_runWithABIEncoderV1Only, ""); io_test.setGasCost(setting, m_gasUsed); + io_test.setCodeDepositGasCost(setting, m_gasUsedForCodeDeposit); + return io_test.call().expectations.gasUsed.count(setting) > 0 && - m_gasUsed == io_test.call().expectations.gasUsed.at(setting); + m_gasUsed == io_test.call().expectations.gasUsed.at(setting) && + m_gasUsedForCodeDeposit == io_test.call().expectations.gasUsedForCodeDeposit.at(setting); } void SemanticTest::printSource(std::ostream& _stream, std::string const& _linePrefix, bool _formatted) const diff --git a/test/libsolidity/util/SoltestTypes.h b/test/libsolidity/util/SoltestTypes.h index 672e705534..a2d593fd3c 100644 --- a/test/libsolidity/util/SoltestTypes.h +++ b/test/libsolidity/util/SoltestTypes.h @@ -220,6 +220,11 @@ struct FunctionCallExpectations /// bytecode (and therefore the cost), except for EVM version. E.g. IR codegen without /// optimization legacy codegen with optimization. std::map gasUsed; + + /// The portion of @a gasUsed spent on code deposits of newly created contracts. + /// May exceed @a gasUsed in rare corner cases due to refunds. + /// Keys must always match @a gasUsedExcludingCode. + std::map gasUsedForCodeDeposit; }; /** diff --git a/test/libsolidity/util/TestFileParser.cpp b/test/libsolidity/util/TestFileParser.cpp index 3fba998a07..e7e20f7c5c 100644 --- a/test/libsolidity/util/TestFileParser.cpp +++ b/test/libsolidity/util/TestFileParser.cpp @@ -84,18 +84,31 @@ std::vector TestFileParser::parseFunctio BOOST_THROW_EXCEPTION(TestParserError("Expected function call before gas usage filter.")); std::string runType = m_scanner.currentLiteral(); - if (std::set{"ir", "irOptimized", "legacy", "legacyOptimized"}.count(runType) > 0) - { - m_scanner.scanNextToken(); - expect(Token::Colon); - if (calls.back().expectations.gasUsed.count(runType) > 0) - throw TestParserError("Gas usage expectation set multiple times."); - calls.back().expectations.gasUsed[runType] = u256(parseDecimalNumber()); - } - else + if (std::set{"ir", "irOptimized", "legacy", "legacyOptimized"}.count(runType) == 0) BOOST_THROW_EXCEPTION(TestParserError( "Expected \"ir\", \"irOptimized\", \"legacy\", or \"legacyOptimized\"." )); + m_scanner.scanNextToken(); + + bool isCodeDepositCost = false; + if (accept(Token::Identifier)) + { + if (m_scanner.currentLiteral() != "code") + BOOST_THROW_EXCEPTION(TestParserError("Expected \"code\" or \":\".")); + isCodeDepositCost = true; + m_scanner.scanNextToken(); + } + + expect(Token::Colon); + + std::map& gasExpectationMap = (isCodeDepositCost ? + calls.back().expectations.gasUsedForCodeDeposit : + calls.back().expectations.gasUsed + ); + if (gasExpectationMap.count(runType) > 0) + throw TestParserError("Gas usage expectation set multiple times."); + + gasExpectationMap[runType] = u256(parseDecimalNumber()); } else { @@ -189,6 +202,17 @@ std::vector TestFileParser::parseFunctio } } } + + for (FunctionCall& call: calls) + { + // Ensure that each specified gas expectation has both components to simplify working with them. + for (auto const& [runType, gas]: call.expectations.gasUsedForCodeDeposit) + call.expectations.gasUsed.try_emplace({runType, 0}); + + for (auto const& [runType, gas]: call.expectations.gasUsed) + call.expectations.gasUsedForCodeDeposit.try_emplace({runType, 0}); + } + return calls; } diff --git a/test/libsolidity/util/TestFileParserTests.cpp b/test/libsolidity/util/TestFileParserTests.cpp index 46499c1475..7a794f9152 100644 --- a/test/libsolidity/util/TestFileParserTests.cpp +++ b/test/libsolidity/util/TestFileParserTests.cpp @@ -1079,6 +1079,11 @@ BOOST_AUTO_TEST_CASE(gas) {"legacy", 5000}, {"legacyOptimized", 0}, })); + BOOST_TEST(calls[0].expectations.gasUsedForCodeDeposit == (std::map{ + {"ir", 0}, + {"legacy", 0}, + {"legacyOptimized", 0}, + })); } BOOST_AUTO_TEST_CASE(gas_before_call) @@ -1109,6 +1114,103 @@ BOOST_AUTO_TEST_CASE(gas_duplicate_run_type) )"; BOOST_REQUIRE_THROW(parse(source), TestParserError); } + +BOOST_AUTO_TEST_CASE(gas_with_code_deposit_cost) +{ + char const* source = R"( + // f() -> + // gas legacyOptimized code: 1 + // gas ir: 13000 + // gas irOptimized: 6666 + // gas irOptimized code: 666 + // gas legacy code: 0 + // gas legacyOptimized: 2 + )"; + auto const calls = parse(source); + BOOST_REQUIRE_EQUAL(calls.size(), 1); + BOOST_REQUIRE_EQUAL(calls[0].expectations.failure, false); + BOOST_TEST(calls[0].expectations.gasUsed == (std::map{ + {"ir", 13000}, + {"irOptimized", 6666}, + {"legacy", 0}, + {"legacyOptimized", 2}, + })); + BOOST_TEST(calls[0].expectations.gasUsedForCodeDeposit == (std::map{ + {"ir", 0}, + {"irOptimized", 666}, + {"legacy", 0}, + {"legacyOptimized", 1}, + })); +} + +BOOST_AUTO_TEST_CASE(gas_with_code_deposit_cost_invalid_suffix) +{ + char const* source = R"( + // f() -> + // gas ir data: 3245 + )"; + BOOST_REQUIRE_THROW(parse(source), TestParserError); +} + +BOOST_AUTO_TEST_CASE(gas_with_code_deposit_cost_tokens_after_suffix) +{ + char const* source = R"( + // f() -> + // gas ir code code: 3245 + )"; + BOOST_REQUIRE_THROW(parse(source), TestParserError); +} + +BOOST_AUTO_TEST_CASE(gas_with_code_deposit_cost_double_code_gas) +{ + char const* source = R"( + // f() -> + // gas ir: 3245 + // gas ir code: 1 + // gas ir code: 1 + )"; + BOOST_REQUIRE_THROW(parse(source), TestParserError); +} + +BOOST_AUTO_TEST_CASE(gas_with_code_deposit_cost_negative_non_code_cost) +{ + // NOTE: This arrangement is unlikely but may still be possible due to refunds. + char const* source = R"( + // f() -> + // gas ir: 10 + // gas ir code: 20 + )"; + auto const calls = parse(source); + BOOST_REQUIRE_EQUAL(calls.size(), 1); + BOOST_REQUIRE_EQUAL(calls[0].expectations.failure, false); + BOOST_TEST(calls[0].expectations.gasUsed == (std::map{ + {"ir", 10}, + })); + BOOST_TEST(calls[0].expectations.gasUsedForCodeDeposit == (std::map{ + {"ir", 20}, + })); +} + +BOOST_AUTO_TEST_CASE(gas_with_code_deposit_cost_negative_total_cost) +{ + char const* source = R"( + // f() -> + // gas ir: -10 + // gas ir code: 20 + )"; + BOOST_REQUIRE_THROW(parse(source), TestParserError); +} + +BOOST_AUTO_TEST_CASE(gas_with_code_deposit_cost_negative_code_cost) +{ + char const* source = R"( + // f() -> + // gas ir: 20 + // gas ir code: -10 + )"; + BOOST_REQUIRE_THROW(parse(source), TestParserError); +} + BOOST_AUTO_TEST_SUITE_END() } diff --git a/test/libsolidity/util/TestFunctionCall.cpp b/test/libsolidity/util/TestFunctionCall.cpp index 54dd769d61..b22ac3716a 100644 --- a/test/libsolidity/util/TestFunctionCall.cpp +++ b/test/libsolidity/util/TestFunctionCall.cpp @@ -22,6 +22,9 @@ #include #include +#include +#include + #include #include #include @@ -371,11 +374,19 @@ std::string TestFunctionCall::formatGasExpectations( bool _showDifference ) const { + using ranges::views::keys; + using ranges::views::set_symmetric_difference; + + soltestAssert(set_symmetric_difference(m_codeDepositGasCosts | keys, m_gasCosts | keys).empty()); + soltestAssert(set_symmetric_difference(m_call.expectations.gasUsedForCodeDeposit | keys, m_call.expectations.gasUsed | keys).empty()); + std::stringstream os; for (auto const& [runType, gasUsed]: (_useActualCost ? m_gasCosts : m_call.expectations.gasUsed)) { soltestAssert(runType != ""); + u256 gasUsedForCodeDeposit = (_useActualCost ? m_codeDepositGasCosts : m_call.expectations.gasUsedForCodeDeposit).at(runType); + os << std::endl << _linePrefix << "// gas " << runType << ": " << gasUsed.str(); std::string gasDiff = formatGasDiff( gasOrNullopt(m_gasCosts, runType), @@ -383,6 +394,17 @@ std::string TestFunctionCall::formatGasExpectations( ); if (_showDifference && !gasDiff.empty() && _useActualCost) os << " [" << gasDiff << "]"; + + if (gasUsedForCodeDeposit != 0) + { + os << std::endl << _linePrefix << "// gas " << runType << " code: " << gasUsedForCodeDeposit.str(); + std::string codeGasDiff = formatGasDiff( + gasOrNullopt(m_codeDepositGasCosts, runType), + gasOrNullopt(m_call.expectations.gasUsedForCodeDeposit, runType) + ); + if (_showDifference && !codeGasDiff.empty() && _useActualCost) + os << " [" << codeGasDiff << "]"; + } } return os.str(); } diff --git a/test/libsolidity/util/TestFunctionCall.h b/test/libsolidity/util/TestFunctionCall.h index 8b4ed5019d..cf05b6a216 100644 --- a/test/libsolidity/util/TestFunctionCall.h +++ b/test/libsolidity/util/TestFunctionCall.h @@ -51,7 +51,11 @@ class TestFunctionCall ExpectedValuesActualGas }; - TestFunctionCall(FunctionCall _call): m_call(std::move(_call)), m_gasCosts(m_call.expectations.gasUsed) {} + TestFunctionCall(FunctionCall _call): + m_call(std::move(_call)), + m_gasCosts(m_call.expectations.gasUsed), + m_codeDepositGasCosts(m_call.expectations.gasUsedForCodeDeposit) + {} /// Formats this function call test and applies the format that was detected during parsing. /// _renderMode determines the source of values to be inserted into the updated test expectations. @@ -94,6 +98,7 @@ class TestFunctionCall void setFailure(const bool _failure) { m_failure = _failure; } void setRawBytes(const bytes _rawBytes) { m_rawBytes = _rawBytes; } void setGasCost(std::string const& _runType, u256 const& _gasCost) { m_gasCosts[_runType] = _gasCost; } + void setCodeDepositGasCost(std::string const& _runType, u256 const& _gasCost) { m_codeDepositGasCosts[_runType] = _gasCost; } void setContractABI(Json::Value _contractABI) { m_contractABI = std::move(_contractABI); } void setSideEffects(std::vector _sideEffects) { m_call.actualSideEffects = _sideEffects; } @@ -143,6 +148,8 @@ class TestFunctionCall bytes m_rawBytes = bytes{}; /// Actual gas costs std::map m_gasCosts; + /// Actual code deposit gas costs + std::map m_codeDepositGasCosts; /// Transaction status of the actual call. False in case of a REVERT or any other failure. bool m_failure = true; /// JSON object which holds the contract ABI and that is used to set the output formatting diff --git a/test/libsolidity/util/TestFunctionCallTests.cpp b/test/libsolidity/util/TestFunctionCallTests.cpp index 74a45c3268..b78b7e5f29 100644 --- a/test/libsolidity/util/TestFunctionCallTests.cpp +++ b/test/libsolidity/util/TestFunctionCallTests.cpp @@ -38,7 +38,7 @@ BOOST_AUTO_TEST_CASE(format_unsigned_singleline) bytes expectedBytes = toBigEndian(u256{1}); ABIType abiType{ABIType::UnsignedDec, ABIType::AlignRight, 32}; Parameter param{expectedBytes, "1", abiType, FormatInfo{}}; - FunctionCallExpectations expectations{std::vector{param}, false, std::string{}, {}}; + FunctionCallExpectations expectations{std::vector{param}, false, std::string{}, {}, {}}; FunctionCallArgs arguments{std::vector{param}, std::string{}}; FunctionCall call{"f(uint8)", {0}, arguments, expectations}; call.omitsArrow = false; @@ -58,7 +58,7 @@ BOOST_AUTO_TEST_CASE(format_unsigned_singleline_signed_encoding) bytes expectedBytes = toBigEndian(u256{1}); ABIType abiType{ABIType::UnsignedDec, ABIType::AlignRight, 32}; Parameter param{expectedBytes, "1", abiType, FormatInfo{}}; - FunctionCallExpectations expectations{std::vector{param}, false, std::string{}, {}}; + FunctionCallExpectations expectations{std::vector{param}, false, std::string{}, {}, {}}; FunctionCallArgs arguments{std::vector{param}, std::string{}}; FunctionCall call{"f(uint8)", {0}, arguments, expectations}; call.omitsArrow = false; @@ -78,7 +78,7 @@ BOOST_AUTO_TEST_CASE(format_unsigned_multiline) bytes expectedBytes = toBigEndian(u256{1}); ABIType abiType{ABIType::UnsignedDec, ABIType::AlignRight, 32}; Parameter result{expectedBytes, "1", abiType, FormatInfo{}}; - FunctionCallExpectations expectations{std::vector{result}, false, std::string{}, {}}; + FunctionCallExpectations expectations{std::vector{result}, false, std::string{}, {}, {}}; FunctionCallArgs arguments{std::vector{}, std::string{}}; FunctionCall call{"f(uint8)", {0}, arguments, expectations}; call.omitsArrow = false; @@ -93,7 +93,7 @@ BOOST_AUTO_TEST_CASE(format_multiple_unsigned_singleline) bytes expectedBytes = toBigEndian(u256{1}); ABIType abiType{ABIType::UnsignedDec, ABIType::AlignRight, 32}; Parameter param{expectedBytes, "1", abiType, FormatInfo{}}; - FunctionCallExpectations expectations{std::vector{param, param}, false, std::string{}, {}}; + FunctionCallExpectations expectations{std::vector{param, param}, false, std::string{}, {}, {}}; FunctionCallArgs arguments{std::vector{param, param}, std::string{}}; FunctionCall call{"f(uint8, uint8)", {0}, arguments, expectations}; call.omitsArrow = false; @@ -107,7 +107,7 @@ BOOST_AUTO_TEST_CASE(format_signed_singleline) bytes expectedBytes = toBigEndian(u256{-1}); ABIType abiType{ABIType::UnsignedDec, ABIType::AlignRight, 32}; Parameter param{expectedBytes, "-1", abiType, FormatInfo{}}; - FunctionCallExpectations expectations{std::vector{param}, false, std::string{}, {}}; + FunctionCallExpectations expectations{std::vector{param}, false, std::string{}, {}, {}}; FunctionCallArgs arguments{std::vector{param}, std::string{}}; FunctionCall call{"f(int8)", {0}, arguments, expectations}; call.omitsArrow = false; @@ -127,7 +127,7 @@ BOOST_AUTO_TEST_CASE(format_hex_singleline) bytes expectedBytes = result + bytes(32 - result.size(), 0); ABIType abiType{ABIType::Hex, ABIType::AlignRight, 32}; Parameter param{expectedBytes, "0x31", abiType, FormatInfo{}}; - FunctionCallExpectations expectations{std::vector{param}, false, std::string{}, {}}; + FunctionCallExpectations expectations{std::vector{param}, false, std::string{}, {}, {}}; FunctionCallArgs arguments{std::vector{param}, std::string{}}; FunctionCall call{"f(bytes32)", {0}, arguments, expectations}; call.omitsArrow = false; @@ -149,7 +149,7 @@ BOOST_AUTO_TEST_CASE(format_hex_string_singleline) bytes expectedBytes = fromHex("4200ef"); ABIType abiType{ABIType::HexString, ABIType::AlignLeft, 3}; Parameter param{expectedBytes, "hex\"4200ef\"", abiType, FormatInfo{}}; - FunctionCallExpectations expectations{std::vector{param}, false, std::string{}, {}}; + FunctionCallExpectations expectations{std::vector{param}, false, std::string{}, {}, {}}; FunctionCallArgs arguments{std::vector{param}, std::string{}}; FunctionCall call{"f(string)", {0}, arguments, expectations}; call.omitsArrow = false; @@ -163,7 +163,7 @@ BOOST_AUTO_TEST_CASE(format_bool_true_singleline) bytes expectedBytes = toBigEndian(u256{true}); ABIType abiType{ABIType::Boolean, ABIType::AlignRight, 32}; Parameter param{expectedBytes, "true", abiType, FormatInfo{}}; - FunctionCallExpectations expectations{std::vector{param}, false, std::string{}, {}}; + FunctionCallExpectations expectations{std::vector{param}, false, std::string{}, {}, {}}; FunctionCallArgs arguments{std::vector{param}, std::string{}}; FunctionCall call{"f(bool)", {0}, arguments, expectations}; call.omitsArrow = false; @@ -184,7 +184,7 @@ BOOST_AUTO_TEST_CASE(format_bool_false_singleline) bytes expectedBytes = toBigEndian(u256{false}); ABIType abiType{ABIType::Boolean, ABIType::AlignRight, 32}; Parameter param{expectedBytes, "false", abiType, FormatInfo{}}; - FunctionCallExpectations expectations{std::vector{param}, false, std::string{}, {}}; + FunctionCallExpectations expectations{std::vector{param}, false, std::string{}, {}, {}}; FunctionCallArgs arguments{std::vector{param}, std::string{}}; FunctionCall call{"f(bool)", {0}, arguments, expectations}; call.omitsArrow = false; @@ -198,7 +198,7 @@ BOOST_AUTO_TEST_CASE(format_bool_left_singleline) bytes expectedBytes = toBigEndian(u256{false}); ABIType abiType{ABIType::Boolean, ABIType::AlignLeft, 32}; Parameter param{expectedBytes, "left(false)", abiType, FormatInfo{}}; - FunctionCallExpectations expectations{std::vector{param}, false, std::string{}, {}}; + FunctionCallExpectations expectations{std::vector{param}, false, std::string{}, {}, {}}; FunctionCallArgs arguments{std::vector{param}, std::string{}}; FunctionCall call{"f(bool)", {0}, arguments, expectations}; call.omitsArrow = false; @@ -213,7 +213,7 @@ BOOST_AUTO_TEST_CASE(format_hex_number_right_singleline) bytes expectedBytes = result + bytes(32 - result.size(), 0); ABIType abiType{ABIType::Hex, ABIType::AlignRight, 32}; Parameter param{expectedBytes, "right(0x42)", abiType, FormatInfo{}}; - FunctionCallExpectations expectations{std::vector{param}, false, std::string{}, {}}; + FunctionCallExpectations expectations{std::vector{param}, false, std::string{}, {}, {}}; FunctionCallArgs arguments{std::vector{param}, std::string{}}; FunctionCall call{"f(bool)", {0}, arguments, expectations}; call.omitsArrow = false; @@ -227,7 +227,7 @@ BOOST_AUTO_TEST_CASE(format_empty_byte_range) bytes expectedBytes; ABIType abiType{ABIType::None, ABIType::AlignNone, 0}; Parameter param{expectedBytes, "1", abiType, FormatInfo{}}; - FunctionCallExpectations expectations{std::vector{param}, false, std::string{}, {}}; + FunctionCallExpectations expectations{std::vector{param}, false, std::string{}, {}, {}}; FunctionCallArgs arguments{std::vector{}, std::string{}}; FunctionCall call{"f()", {0}, arguments, expectations}; call.omitsArrow = false; @@ -241,7 +241,7 @@ BOOST_AUTO_TEST_CASE(format_failure_singleline) bytes expectedBytes = toBigEndian(u256{1}); ABIType abiType{ABIType::UnsignedDec, ABIType::AlignRight, 32}; Parameter param{expectedBytes, "1", abiType, FormatInfo{}}; - FunctionCallExpectations expectations{std::vector{}, true, std::string{}, {}}; + FunctionCallExpectations expectations{std::vector{}, true, std::string{}, {}, {}}; FunctionCallArgs arguments{std::vector{param}, std::string{}}; FunctionCall call{"f(uint8)", {0}, arguments, expectations}; call.omitsArrow = false; @@ -265,6 +265,11 @@ BOOST_AUTO_TEST_CASE(format_gas) {"legacy", 5000}, {"legacy optimized", 0}, }, + { + {"ir", 0}, + {"legacy", 0}, + {"legacy optimized", 0}, + }, } }; call.omitsArrow = false; @@ -278,6 +283,40 @@ BOOST_AUTO_TEST_CASE(format_gas) ); } +BOOST_AUTO_TEST_CASE(format_gas_with_code_deposit) +{ + FunctionCall call{ + "f()", + FunctionValue{0}, + FunctionCallArgs{}, + FunctionCallExpectations{ + std::vector{}, + false, // failure + "some comment", + { + {"ir", 0}, // Zero costs are shown + {"legacy", 5000}, + {"legacy optimized", 300}, + }, + { + {"ir", 0}, // Zero code deposit costs are omitted + {"legacy", 125}, + {"legacy optimized", 0}, + }, + } + }; + call.omitsArrow = false; + + BOOST_REQUIRE_EQUAL( + TestFunctionCall(call).format(), + "// f() -> #some comment#\n" + "// gas ir: 0\n" + "// gas legacy: 5000\n" + "// gas legacy code: 125\n" + "// gas legacy optimized: 300" + ); +} + BOOST_AUTO_TEST_SUITE_END() } From 96ce95aa3a21f285ee32d30d8b2eed8017a2bdd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 9 Feb 2024 21:30:46 +0100 Subject: [PATCH 44/57] Do not include code deposit gas in the total visible in test expectations --- test/libsolidity/SemanticTest.cpp | 13 +++++---- ...2_in_function_inherited_in_v1_contract.sol | 9 ++++-- ...ode_v2_in_modifier_used_in_v1_contract.sol | 3 +- .../arithmetics/check_var_init.sol | 3 +- .../array/constant_var_as_array_length.sol | 9 ++++-- ...nup_during_multi_element_per_slot_copy.sol | 9 ++++-- .../array/fixed_arrays_as_return_type.sol | 9 ++++-- .../array/fixed_arrays_in_constructors.sol | 9 ++++-- .../array/function_array_cross_calls.sol | 9 ++++-- .../semanticTests/array/reusing_memory.sol | 9 ++++-- .../byte_array_to_storage_cleanup.sol | 9 ++++-- .../constructor/arrays_in_constructors.sol | 9 ++++-- .../bytes_in_constructors_packer.sol | 9 ++++-- .../bytes_in_constructors_unpacker.sol | 9 ++++-- .../constructor_arguments_external.sol | 9 ++++-- .../constructor_function_complex.sol | 3 +- .../constructor_static_array_argument.sol | 9 ++++-- .../constructor/no_callvalue_check.sol | 9 ++++-- .../constructor_inheritance_init_order.sol | 3 +- .../constructor_inheritance_init_order_2.sol | 9 ++++-- .../semanticTests/constructor_with_params.sol | 6 ++-- ...ructor_with_params_diamond_inheritance.sol | 9 ++++-- .../constructor_with_params_inheritance.sol | 9 ++++-- .../events/event_emit_from_other_contract.sol | 9 ++++-- .../externalContracts/FixedFeeRegistrar.sol | 9 ++++-- .../externalContracts/base64.sol | 9 ++++-- .../externalContracts/deposit_contract.sol | 9 ++++-- .../externalContracts/prbmath_signed.sol | 9 ++++-- .../externalContracts/prbmath_unsigned.sol | 9 ++++-- .../externalContracts/ramanujan_pi.sol | 9 ++++-- .../externalContracts/strings.sol | 9 ++++-- .../freeFunctions/new_operator.sol | 3 +- .../creation_function_call_no_args.sol | 3 +- .../creation_function_call_with_args.sol | 9 ++++-- .../creation_function_call_with_salt.sol | 9 ++++-- .../external_call_to_nonexisting.sol | 9 ++++-- ...ernal_call_to_nonexisting_debugstrings.sol | 9 ++++-- .../functionCall/failed_create.sol | 9 ++++-- .../functionCall/gas_and_value_basic.sol | 9 ++++-- .../gas_and_value_brace_syntax.sol | 9 ++++-- .../functionCall/send_zero_ether.sol | 3 +- .../functionTypes/store_function.sol | 6 ++-- .../immutable/multi_creation.sol | 9 ++++-- .../semanticTests/immutable/use_scratch.sol | 9 ++++-- .../address_overload_resolution.sol | 6 ++-- ...d_function_calldata_calldata_interface.sol | 3 +- ...ted_function_calldata_memory_interface.sol | 6 ++-- .../inheritance/member_notation_ctor.sol | 6 ++-- .../inheritance/value_for_constructor.sol | 9 ++++-- .../balance_other_contract.sol | 9 ++++-- .../operator_making_pure_external_call.sol | 12 +++++--- .../operator_making_view_external_call.sol | 12 +++++--- .../salted_create/prediction_example.sol | 3 +- .../salted_create/salted_create.sol | 9 ++++-- .../salted_create_with_value.sol | 9 ++++-- .../semanticTests/smoke/alignment.sol | 3 +- .../semanticTests/smoke/constructor.sol | 9 ++++-- .../semanticTests/state/blockhash_basic.sol | 9 ++++-- .../userDefinedValueType/erc20.sol | 9 ++++-- .../using/using_global_invisible.sol | 3 +- .../semanticTests/various/address_code.sol | 9 ++++-- .../various/code_access_content.sol | 6 ++-- .../various/code_access_create.sol | 3 +- .../various/code_access_runtime.sol | 3 +- .../semanticTests/various/code_length.sol | 3 +- .../semanticTests/various/create_calldata.sol | 9 ++++-- .../semanticTests/various/erc20.sol | 9 ++++-- .../various/external_types_in_calls.sol | 3 +- .../various/many_subassemblies.sol | 9 ++++-- .../various/negative_stack_height.sol | 6 ++-- .../various/selfdestruct_pre_cancun.sol | 9 ++++-- ...ruct_pre_cancun_multiple_beneficiaries.sol | 21 +++++++++----- .../selfdestruct_pre_cancun_redeploy.sol | 18 ++++++++---- .../semanticTests/various/senders_balance.sol | 9 ++++-- .../various/staticcall_for_view_and_pure.sol | 21 +++++++++----- .../semanticTests/various/value_complex.sol | 9 ++++-- .../semanticTests/various/value_insane.sol | 9 ++++-- test/libsolidity/util/SoltestTypes.h | 6 ++-- test/libsolidity/util/TestFileParser.cpp | 6 ++-- test/libsolidity/util/TestFileParserTests.cpp | 29 +++++++------------ test/libsolidity/util/TestFunctionCall.cpp | 12 ++++---- test/libsolidity/util/TestFunctionCall.h | 6 ++-- .../util/TestFunctionCallTests.cpp | 4 +-- 83 files changed, 444 insertions(+), 244 deletions(-) diff --git a/test/libsolidity/SemanticTest.cpp b/test/libsolidity/SemanticTest.cpp index 676c39eaf9..381ec5bda5 100644 --- a/test/libsolidity/SemanticTest.cpp +++ b/test/libsolidity/SemanticTest.cpp @@ -570,7 +570,7 @@ bool SemanticTest::checkGasCostExpectation(TestFunctionCall& io_test, bool _comp (m_optimiserSettings == OptimiserSettings::full() ? "Optimized" : ""); soltestAssert( - io_test.call().expectations.gasUsed.count(setting) == + io_test.call().expectations.gasUsedExcludingCode.count(setting) == io_test.call().expectations.gasUsedForCodeDeposit.count(setting) ); @@ -584,19 +584,22 @@ bool SemanticTest::checkGasCostExpectation(TestFunctionCall& io_test, bool _comp !m_enforceGasCost || m_gasUsed < m_enforceGasCostMinValue || m_gasUsed >= InitialGas || - (setting == "ir" && io_test.call().expectations.gasUsed.count(setting) == 0) || + (setting == "ir" && io_test.call().expectations.gasUsedExcludingCode.count(setting) == 0) || io_test.call().kind == FunctionCall::Kind::Builtin ) return true; solAssert(!m_runWithABIEncoderV1Only, ""); - io_test.setGasCost(setting, m_gasUsed); + // NOTE: Cost excluding code is unlikely to be negative but it may still be possible due to refunds. + // We'll deal with it when we actually have a test case like that. + solUnimplementedAssert(m_gasUsed >= m_gasUsedForCodeDeposit); + io_test.setGasCostExcludingCode(setting, m_gasUsed - m_gasUsedForCodeDeposit); io_test.setCodeDepositGasCost(setting, m_gasUsedForCodeDeposit); return - io_test.call().expectations.gasUsed.count(setting) > 0 && - m_gasUsed == io_test.call().expectations.gasUsed.at(setting) && + io_test.call().expectations.gasUsedExcludingCode.count(setting) > 0 && + m_gasUsed - m_gasUsedForCodeDeposit == io_test.call().expectations.gasUsedExcludingCode.at(setting) && m_gasUsedForCodeDeposit == io_test.call().expectations.gasUsedForCodeDeposit.at(setting); } diff --git a/test/libsolidity/semanticTests/abiEncoderV2/abi_encode_v2_in_function_inherited_in_v1_contract.sol b/test/libsolidity/semanticTests/abiEncoderV2/abi_encode_v2_in_function_inherited_in_v1_contract.sol index 55f7991def..c41905e2a4 100644 --- a/test/libsolidity/semanticTests/abiEncoderV2/abi_encode_v2_in_function_inherited_in_v1_contract.sol +++ b/test/libsolidity/semanticTests/abiEncoderV2/abi_encode_v2_in_function_inherited_in_v1_contract.sol @@ -30,6 +30,9 @@ contract C is B { } // ---- // test() -> 77 -// gas irOptimized: 110348 -// gas legacy: 151866 -// gas legacyOptimized: 110373 +// gas irOptimized: 55148 +// gas irOptimized code: 55200 +// gas legacy: 57266 +// gas legacy code: 94600 +// gas legacyOptimized: 55173 +// gas legacyOptimized code: 55200 diff --git a/test/libsolidity/semanticTests/abiEncoderV2/abi_encode_v2_in_modifier_used_in_v1_contract.sol b/test/libsolidity/semanticTests/abiEncoderV2/abi_encode_v2_in_modifier_used_in_v1_contract.sol index 7de2630120..7a2395549b 100644 --- a/test/libsolidity/semanticTests/abiEncoderV2/abi_encode_v2_in_modifier_used_in_v1_contract.sol +++ b/test/libsolidity/semanticTests/abiEncoderV2/abi_encode_v2_in_modifier_used_in_v1_contract.sol @@ -39,4 +39,5 @@ contract C is B { // ---- // test() -> 5, 10 // gas irOptimized: 87337 -// gas legacy: 102651 +// gas legacy: 66251 +// gas legacy code: 36400 diff --git a/test/libsolidity/semanticTests/arithmetics/check_var_init.sol b/test/libsolidity/semanticTests/arithmetics/check_var_init.sol index fc5418cb0e..9061cd284d 100644 --- a/test/libsolidity/semanticTests/arithmetics/check_var_init.sol +++ b/test/libsolidity/semanticTests/arithmetics/check_var_init.sol @@ -16,4 +16,5 @@ contract D { // ---- // f() -> FAILURE, hex"4e487b71", 0x11 // g(), 100 wei -> 1 -// gas legacy: 100380 +// gas legacy: 76780 +// gas legacy code: 23600 diff --git a/test/libsolidity/semanticTests/array/constant_var_as_array_length.sol b/test/libsolidity/semanticTests/array/constant_var_as_array_length.sol index 45861babaa..19acb7cba1 100644 --- a/test/libsolidity/semanticTests/array/constant_var_as_array_length.sol +++ b/test/libsolidity/semanticTests/array/constant_var_as_array_length.sol @@ -8,9 +8,12 @@ contract C { } // ---- // constructor(): 1, 2, 3 -> -// gas irOptimized: 139616 -// gas legacy: 180517 -// gas legacyOptimized: 150462 +// gas irOptimized: 124816 +// gas irOptimized code: 14800 +// gas legacy: 134317 +// gas legacy code: 46200 +// gas legacyOptimized: 127062 +// gas legacyOptimized code: 23400 // a(uint256): 0 -> 1 // a(uint256): 1 -> 2 // a(uint256): 2 -> 3 diff --git a/test/libsolidity/semanticTests/array/copying/cleanup_during_multi_element_per_slot_copy.sol b/test/libsolidity/semanticTests/array/copying/cleanup_during_multi_element_per_slot_copy.sol index 8be8328926..36b94d7c39 100644 --- a/test/libsolidity/semanticTests/array/copying/cleanup_during_multi_element_per_slot_copy.sol +++ b/test/libsolidity/semanticTests/array/copying/cleanup_during_multi_element_per_slot_copy.sol @@ -16,7 +16,10 @@ contract C { } // ---- // constructor() -// gas irOptimized: 226321 -// gas legacy: 215753 -// gas legacyOptimized: 181756 +// gas irOptimized: 89121 +// gas irOptimized code: 137200 +// gas legacy: 89553 +// gas legacy code: 126200 +// gas legacyOptimized: 83556 +// gas legacyOptimized code: 98200 // f() -> 0 diff --git a/test/libsolidity/semanticTests/array/fixed_arrays_as_return_type.sol b/test/libsolidity/semanticTests/array/fixed_arrays_as_return_type.sol index dd90985735..0fb513543b 100644 --- a/test/libsolidity/semanticTests/array/fixed_arrays_as_return_type.sol +++ b/test/libsolidity/semanticTests/array/fixed_arrays_as_return_type.sol @@ -18,6 +18,9 @@ contract B { } // ---- // f() -> 2, 3, 4, 5, 6, 1000, 1001, 1002, 1003, 1004 -// gas irOptimized: 114404 -// gas legacy: 230001 -// gas legacyOptimized: 130637 +// gas irOptimized: 59204 +// gas irOptimized code: 55200 +// gas legacy: 68001 +// gas legacy code: 162000 +// gas legacyOptimized: 60037 +// gas legacyOptimized code: 70600 diff --git a/test/libsolidity/semanticTests/array/fixed_arrays_in_constructors.sol b/test/libsolidity/semanticTests/array/fixed_arrays_in_constructors.sol index c7b2dc77a3..0eb0f1e90e 100644 --- a/test/libsolidity/semanticTests/array/fixed_arrays_in_constructors.sol +++ b/test/libsolidity/semanticTests/array/fixed_arrays_in_constructors.sol @@ -9,8 +9,11 @@ contract Creator { } // ---- // constructor(): 1, 2, 3, 4 -> -// gas irOptimized: 126327 -// gas legacy: 174186 -// gas legacyOptimized: 128709 +// gas irOptimized: 103927 +// gas irOptimized code: 22400 +// gas legacy: 115186 +// gas legacy code: 59000 +// gas legacyOptimized: 104909 +// gas legacyOptimized code: 23800 // r() -> 4 // ch() -> 3 diff --git a/test/libsolidity/semanticTests/array/function_array_cross_calls.sol b/test/libsolidity/semanticTests/array/function_array_cross_calls.sol index 773e904cc0..e35e24bbf1 100644 --- a/test/libsolidity/semanticTests/array/function_array_cross_calls.sol +++ b/test/libsolidity/semanticTests/array/function_array_cross_calls.sol @@ -42,6 +42,9 @@ contract C { } // ---- // test() -> 5, 6, 7 -// gas irOptimized: 255728 -// gas legacy: 440376 -// gas legacyOptimized: 278651 +// gas irOptimized: 86128 +// gas irOptimized code: 169600 +// gas legacy: 97576 +// gas legacy code: 342800 +// gas legacyOptimized: 87851 +// gas legacyOptimized code: 190800 diff --git a/test/libsolidity/semanticTests/array/reusing_memory.sol b/test/libsolidity/semanticTests/array/reusing_memory.sol index 8f6afe30ba..a7608f6e0c 100644 --- a/test/libsolidity/semanticTests/array/reusing_memory.sol +++ b/test/libsolidity/semanticTests/array/reusing_memory.sol @@ -24,6 +24,9 @@ contract Main { } // ---- // f(uint256): 0x34 -> 0x46bddb1178e94d7f2892ff5f366840eb658911794f2c3a44c450aa2c505186c1 -// gas irOptimized: 111924 -// gas legacy: 125154 -// gas legacyOptimized: 113012 +// gas irOptimized: 99524 +// gas irOptimized code: 12400 +// gas legacy: 101554 +// gas legacy code: 23600 +// gas legacyOptimized: 99612 +// gas legacyOptimized code: 13400 diff --git a/test/libsolidity/semanticTests/byte_array_to_storage_cleanup.sol b/test/libsolidity/semanticTests/byte_array_to_storage_cleanup.sol index 877e2a1bce..14130926e7 100644 --- a/test/libsolidity/semanticTests/byte_array_to_storage_cleanup.sol +++ b/test/libsolidity/semanticTests/byte_array_to_storage_cleanup.sol @@ -28,9 +28,12 @@ contract C { // compileViaYul: also // ---- // constructor() -> -// gas irOptimized: 443402 -// gas legacy: 711295 -// gas legacyOptimized: 482378 +// gas irOptimized: 82402 +// gas irOptimized code: 361000 +// gas legacy: 101895 +// gas legacy code: 609400 +// gas legacyOptimized: 85378 +// gas legacyOptimized code: 397000 // h() -> 0x20, 0x40, 0x00, 0 // ~ emit ev(uint256[],uint256): 0x40, 0x21, 0x02, 0x00, 0x00 // g() -> 0x20, 0x40, 0, 0x00 diff --git a/test/libsolidity/semanticTests/constructor/arrays_in_constructors.sol b/test/libsolidity/semanticTests/constructor/arrays_in_constructors.sol index 19d79b6c4f..3e60ba451c 100644 --- a/test/libsolidity/semanticTests/constructor/arrays_in_constructors.sol +++ b/test/libsolidity/semanticTests/constructor/arrays_in_constructors.sol @@ -24,6 +24,9 @@ contract Creator { } // ---- // f(uint256,address[]): 7, 0x40, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 -> 7, 8 -// gas irOptimized: 424526 -// gas legacy: 581426 -// gas legacyOptimized: 444599 +// gas irOptimized: 328126 +// gas irOptimized code: 96400 +// gas legacy: 336626 +// gas legacy code: 244800 +// gas legacyOptimized: 329599 +// gas legacyOptimized code: 115000 diff --git a/test/libsolidity/semanticTests/constructor/bytes_in_constructors_packer.sol b/test/libsolidity/semanticTests/constructor/bytes_in_constructors_packer.sol index cfa74f016f..7885d3ceec 100644 --- a/test/libsolidity/semanticTests/constructor/bytes_in_constructors_packer.sol +++ b/test/libsolidity/semanticTests/constructor/bytes_in_constructors_packer.sol @@ -24,6 +24,9 @@ contract Creator { } // ---- // f(uint256,bytes): 7, 0x40, 78, "abcdefghijklmnopqrstuvwxyzabcdef", "ghijklmnopqrstuvwxyzabcdefghijkl", "mnopqrstuvwxyz" -> 7, "h" -// gas irOptimized: 275102 -// gas legacy: 418433 -// gas legacyOptimized: 291960 +// gas irOptimized: 169902 +// gas irOptimized code: 105200 +// gas legacy: 173433 +// gas legacy code: 245000 +// gas legacyOptimized: 170360 +// gas legacyOptimized code: 121600 diff --git a/test/libsolidity/semanticTests/constructor/bytes_in_constructors_unpacker.sol b/test/libsolidity/semanticTests/constructor/bytes_in_constructors_unpacker.sol index 39da45e8a5..1d6b01127c 100644 --- a/test/libsolidity/semanticTests/constructor/bytes_in_constructors_unpacker.sol +++ b/test/libsolidity/semanticTests/constructor/bytes_in_constructors_unpacker.sol @@ -8,8 +8,11 @@ contract Test { } // ---- // constructor(): 7, 0x40, 78, "abcdefghijklmnopqrstuvwxyzabcdef", "ghijklmnopqrstuvwxyzabcdefghijkl", "mnopqrstuvwxyz" -> -// gas irOptimized: 269225 -// gas legacy: 310820 -// gas legacyOptimized: 258604 +// gas irOptimized: 182025 +// gas irOptimized code: 87200 +// gas legacy: 196220 +// gas legacy code: 114600 +// gas legacyOptimized: 182604 +// gas legacyOptimized code: 76000 // m_x() -> 7 // m_s() -> 0x20, 78, "abcdefghijklmnopqrstuvwxyzabcdef", "ghijklmnopqrstuvwxyzabcdefghijkl", "mnopqrstuvwxyz" diff --git a/test/libsolidity/semanticTests/constructor/constructor_arguments_external.sol b/test/libsolidity/semanticTests/constructor/constructor_arguments_external.sol index 714ae3e554..8fa725dad5 100644 --- a/test/libsolidity/semanticTests/constructor/constructor_arguments_external.sol +++ b/test/libsolidity/semanticTests/constructor/constructor_arguments_external.sol @@ -17,8 +17,11 @@ contract Main { } // ---- // constructor(): "abc", true -// gas irOptimized: 104374 -// gas legacy: 143300 -// gas legacyOptimized: 102933 +// gas irOptimized: 80174 +// gas irOptimized code: 24200 +// gas legacy: 85100 +// gas legacy code: 58200 +// gas legacyOptimized: 80133 +// gas legacyOptimized code: 22800 // getFlag() -> true // getName() -> "abc" diff --git a/test/libsolidity/semanticTests/constructor/constructor_function_complex.sol b/test/libsolidity/semanticTests/constructor/constructor_function_complex.sol index 4117b84b64..33650aff6f 100644 --- a/test/libsolidity/semanticTests/constructor/constructor_function_complex.sol +++ b/test/libsolidity/semanticTests/constructor/constructor_function_complex.sol @@ -17,4 +17,5 @@ contract C { } // ---- // f() -> 16 -// gas legacy: 102082 +// gas legacy: 78482 +// gas legacy code: 23600 diff --git a/test/libsolidity/semanticTests/constructor/constructor_static_array_argument.sol b/test/libsolidity/semanticTests/constructor/constructor_static_array_argument.sol index a61192742d..e6ce445ada 100644 --- a/test/libsolidity/semanticTests/constructor/constructor_static_array_argument.sol +++ b/test/libsolidity/semanticTests/constructor/constructor_static_array_argument.sol @@ -9,9 +9,12 @@ contract C { } // ---- // constructor(): 1, 2, 3, 4 -> -// gas irOptimized: 170975 -// gas legacy: 218378 -// gas legacyOptimized: 176211 +// gas irOptimized: 147975 +// gas irOptimized code: 23000 +// gas legacy: 157978 +// gas legacy code: 60400 +// gas legacyOptimized: 150011 +// gas legacyOptimized code: 26200 // a() -> 1 // b(uint256): 0 -> 2 // b(uint256): 1 -> 3 diff --git a/test/libsolidity/semanticTests/constructor/no_callvalue_check.sol b/test/libsolidity/semanticTests/constructor/no_callvalue_check.sol index eec01005eb..b1dc80a408 100644 --- a/test/libsolidity/semanticTests/constructor/no_callvalue_check.sol +++ b/test/libsolidity/semanticTests/constructor/no_callvalue_check.sol @@ -17,6 +17,9 @@ contract C { } // ---- // f(), 2000 ether -> true -// gas irOptimized: 119441 -// gas legacy: 122621 -// gas legacyOptimized: 122490 +// gas irOptimized: 117641 +// gas irOptimized code: 1800 +// gas legacy: 117821 +// gas legacy code: 4800 +// gas legacyOptimized: 117690 +// gas legacyOptimized code: 4800 diff --git a/test/libsolidity/semanticTests/constructor_inheritance_init_order.sol b/test/libsolidity/semanticTests/constructor_inheritance_init_order.sol index ece0cc31a6..ef53142d45 100644 --- a/test/libsolidity/semanticTests/constructor_inheritance_init_order.sol +++ b/test/libsolidity/semanticTests/constructor_inheritance_init_order.sol @@ -14,5 +14,6 @@ contract B is A { // compileViaYul: true // ---- // constructor() -> -// gas irOptimized: 119636 +// gas irOptimized: 99436 +// gas irOptimized code: 20200 // y() -> 42 diff --git a/test/libsolidity/semanticTests/constructor_inheritance_init_order_2.sol b/test/libsolidity/semanticTests/constructor_inheritance_init_order_2.sol index 654c9af56d..e19ad39cfa 100644 --- a/test/libsolidity/semanticTests/constructor_inheritance_init_order_2.sol +++ b/test/libsolidity/semanticTests/constructor_inheritance_init_order_2.sol @@ -9,7 +9,10 @@ contract B is A { } // ---- // constructor() -> -// gas irOptimized: 119636 -// gas legacy: 133574 -// gas legacyOptimized: 115337 +// gas irOptimized: 99436 +// gas irOptimized code: 20200 +// gas legacy: 100974 +// gas legacy code: 32600 +// gas legacyOptimized: 99137 +// gas legacyOptimized code: 16200 // y() -> 42 diff --git a/test/libsolidity/semanticTests/constructor_with_params.sol b/test/libsolidity/semanticTests/constructor_with_params.sol index e427f6d9ab..1c5a170202 100644 --- a/test/libsolidity/semanticTests/constructor_with_params.sol +++ b/test/libsolidity/semanticTests/constructor_with_params.sol @@ -9,7 +9,9 @@ contract C { } // ---- // constructor(): 2, 0 -> -// gas irOptimized: 101370 -// gas legacy: 115614 +// gas irOptimized: 81170 +// gas irOptimized code: 20200 +// gas legacy: 83614 +// gas legacy code: 32000 // i() -> 2 // k() -> 0 diff --git a/test/libsolidity/semanticTests/constructor_with_params_diamond_inheritance.sol b/test/libsolidity/semanticTests/constructor_with_params_diamond_inheritance.sol index 6507081447..29f401a773 100644 --- a/test/libsolidity/semanticTests/constructor_with_params_diamond_inheritance.sol +++ b/test/libsolidity/semanticTests/constructor_with_params_diamond_inheritance.sol @@ -21,9 +21,12 @@ contract D is B, C { } // ---- // constructor(): 2, 0 -> -// gas irOptimized: 151950 -// gas legacy: 168623 -// gas legacyOptimized: 144521 +// gas irOptimized: 124350 +// gas irOptimized code: 27600 +// gas legacy: 128223 +// gas legacy code: 40400 +// gas legacyOptimized: 123921 +// gas legacyOptimized code: 20600 // i() -> 2 // j() -> 2 // k() -> 1 diff --git a/test/libsolidity/semanticTests/constructor_with_params_inheritance.sol b/test/libsolidity/semanticTests/constructor_with_params_inheritance.sol index 8cc7c69f68..b0373b74f1 100644 --- a/test/libsolidity/semanticTests/constructor_with_params_inheritance.sol +++ b/test/libsolidity/semanticTests/constructor_with_params_inheritance.sol @@ -12,8 +12,11 @@ contract D is C { } // ---- // constructor(): 2, 0 -> -// gas irOptimized: 121781 -// gas legacy: 137193 -// gas legacyOptimized: 118504 +// gas irOptimized: 101581 +// gas irOptimized code: 20200 +// gas legacy: 105193 +// gas legacy code: 32000 +// gas legacyOptimized: 101504 +// gas legacyOptimized code: 17000 // i() -> 2 // k() -> 1 diff --git a/test/libsolidity/semanticTests/events/event_emit_from_other_contract.sol b/test/libsolidity/semanticTests/events/event_emit_from_other_contract.sol index 0c56cbb671..6a01d00192 100644 --- a/test/libsolidity/semanticTests/events/event_emit_from_other_contract.sol +++ b/test/libsolidity/semanticTests/events/event_emit_from_other_contract.sol @@ -15,8 +15,11 @@ contract C { } // ---- // constructor() -> -// gas irOptimized: 165370 -// gas legacy: 244776 -// gas legacyOptimized: 171587 +// gas irOptimized: 113970 +// gas irOptimized code: 51400 +// gas legacy: 119776 +// gas legacy code: 125000 +// gas legacyOptimized: 114187 +// gas legacyOptimized code: 57400 // deposit(bytes32), 18 wei: 0x1234 -> // ~ emit Deposit(address,bytes32,uint256) from 0x137aa4dfc0911524504fcd4d98501f179bc13b4a: #0xc06afe3a8444fc0004668591e8306bfb9968e79e, #0x1234, 0x00 diff --git a/test/libsolidity/semanticTests/externalContracts/FixedFeeRegistrar.sol b/test/libsolidity/semanticTests/externalContracts/FixedFeeRegistrar.sol index 011fecbd34..d308d4597e 100644 --- a/test/libsolidity/semanticTests/externalContracts/FixedFeeRegistrar.sol +++ b/test/libsolidity/semanticTests/externalContracts/FixedFeeRegistrar.sol @@ -74,9 +74,12 @@ contract FixedFeeRegistrar is Registrar { } // ---- // constructor() -// gas irOptimized: 384606 -// gas legacy: 913417 -// gas legacyOptimized: 476924 +// gas irOptimized: 78006 +// gas irOptimized code: 306600 +// gas legacy: 115817 +// gas legacy code: 797600 +// gas legacyOptimized: 84924 +// gas legacyOptimized code: 392000 // reserve(string), 69 ether: 0x20, 3, "abc" -> // ~ emit Changed(string): #0x4e03657aea45a94fc7d47ba826c8d667c0d1e6e33a64a036ec44f58fa12d6c45 // gas irOptimized: 45967 diff --git a/test/libsolidity/semanticTests/externalContracts/base64.sol b/test/libsolidity/semanticTests/externalContracts/base64.sol index ee2745d1ac..b712092ed0 100644 --- a/test/libsolidity/semanticTests/externalContracts/base64.sol +++ b/test/libsolidity/semanticTests/externalContracts/base64.sol @@ -33,9 +33,12 @@ contract test { // EVMVersion: >=constantinople // ---- // constructor() -// gas irOptimized: 405828 -// gas legacy: 735050 -// gas legacyOptimized: 522718 +// gas irOptimized: 79428 +// gas irOptimized code: 326400 +// gas legacy: 102450 +// gas legacy code: 632600 +// gas legacyOptimized: 88318 +// gas legacyOptimized code: 434400 // encode_inline_asm(bytes): 0x20, 0 -> 0x20, 0 // encode_inline_asm(bytes): 0x20, 1, "f" -> 0x20, 4, "Zg==" // encode_inline_asm(bytes): 0x20, 2, "fo" -> 0x20, 4, "Zm8=" diff --git a/test/libsolidity/semanticTests/externalContracts/deposit_contract.sol b/test/libsolidity/semanticTests/externalContracts/deposit_contract.sol index caa7fc39c8..0ef87edd4f 100644 --- a/test/libsolidity/semanticTests/externalContracts/deposit_contract.sol +++ b/test/libsolidity/semanticTests/externalContracts/deposit_contract.sol @@ -176,9 +176,12 @@ contract DepositContract is IDepositContract, ERC165 { } // ---- // constructor() -// gas irOptimized: 1386886 -// gas legacy: 2368733 -// gas legacyOptimized: 1740004 +// gas irOptimized: 815686 +// gas irOptimized code: 571200 +// gas legacy: 925933 +// gas legacy code: 1442800 +// gas legacyOptimized: 854404 +// gas legacyOptimized code: 885600 // supportsInterface(bytes4): 0x0 -> 0 // supportsInterface(bytes4): 0xffffffff00000000000000000000000000000000000000000000000000000000 -> false # defined to be false by ERC-165 # // supportsInterface(bytes4): 0x01ffc9a700000000000000000000000000000000000000000000000000000000 -> true # ERC-165 id # diff --git a/test/libsolidity/semanticTests/externalContracts/prbmath_signed.sol b/test/libsolidity/semanticTests/externalContracts/prbmath_signed.sol index ba7a208fd7..ddd6397183 100644 --- a/test/libsolidity/semanticTests/externalContracts/prbmath_signed.sol +++ b/test/libsolidity/semanticTests/externalContracts/prbmath_signed.sol @@ -48,9 +48,12 @@ contract test { } // ---- // constructor() -// gas irOptimized: 1841736 -// gas legacy: 2414087 -// gas legacyOptimized: 1847612 +// gas irOptimized: 177336 +// gas irOptimized code: 1664400 +// gas legacy: 209687 +// gas legacy code: 2204400 +// gas legacyOptimized: 178012 +// gas legacyOptimized code: 1669600 // div(int256,int256): 3141592653589793238, 88714123 -> 35412542528203691288251815328 // gas irOptimized: 22137 // gas legacy: 22767 diff --git a/test/libsolidity/semanticTests/externalContracts/prbmath_unsigned.sol b/test/libsolidity/semanticTests/externalContracts/prbmath_unsigned.sol index 90b283db46..deacfd0564 100644 --- a/test/libsolidity/semanticTests/externalContracts/prbmath_unsigned.sol +++ b/test/libsolidity/semanticTests/externalContracts/prbmath_unsigned.sol @@ -48,9 +48,12 @@ contract test { } // ---- // constructor() -// gas irOptimized: 1716323 -// gas legacy: 2193546 -// gas legacyOptimized: 1725057 +// gas irOptimized: 168523 +// gas irOptimized code: 1547800 +// gas legacy: 195146 +// gas legacy code: 1998400 +// gas legacyOptimized: 168857 +// gas legacyOptimized code: 1556200 // div(uint256,uint256): 3141592653589793238, 88714123 -> 35412542528203691288251815328 // gas irOptimized: 22004 // gas legacy: 22497 diff --git a/test/libsolidity/semanticTests/externalContracts/ramanujan_pi.sol b/test/libsolidity/semanticTests/externalContracts/ramanujan_pi.sol index 4442b6d479..cdaec8797e 100644 --- a/test/libsolidity/semanticTests/externalContracts/ramanujan_pi.sol +++ b/test/libsolidity/semanticTests/externalContracts/ramanujan_pi.sol @@ -33,9 +33,12 @@ contract test { } // ---- // constructor() -// gas irOptimized: 407503 -// gas legacy: 615086 -// gas legacyOptimized: 451867 +// gas irOptimized: 79503 +// gas irOptimized code: 328000 +// gas legacy: 92086 +// gas legacy code: 523000 +// gas legacyOptimized: 82667 +// gas legacyOptimized code: 369200 // prb_pi() -> 3141592656369545286 // gas irOptimized: 57478 // gas legacy: 100947 diff --git a/test/libsolidity/semanticTests/externalContracts/strings.sol b/test/libsolidity/semanticTests/externalContracts/strings.sol index 3f88fc39c6..a4b0f9fd35 100644 --- a/test/libsolidity/semanticTests/externalContracts/strings.sol +++ b/test/libsolidity/semanticTests/externalContracts/strings.sol @@ -49,9 +49,12 @@ contract test { } // ---- // constructor() -// gas irOptimized: 630220 -// gas legacy: 1061953 -// gas legacyOptimized: 718933 +// gas irOptimized: 96420 +// gas irOptimized code: 533800 +// gas legacy: 126553 +// gas legacy code: 935400 +// gas legacyOptimized: 102933 +// gas legacyOptimized code: 616000 // toSlice(string): 0x20, 11, "hello world" -> 11, 0xa0 // gas irOptimized: 22660 // gas legacy: 23190 diff --git a/test/libsolidity/semanticTests/freeFunctions/new_operator.sol b/test/libsolidity/semanticTests/freeFunctions/new_operator.sol index dd44a1b595..d621629c3b 100644 --- a/test/libsolidity/semanticTests/freeFunctions/new_operator.sol +++ b/test/libsolidity/semanticTests/freeFunctions/new_operator.sol @@ -13,4 +13,5 @@ contract D { } // ---- // f() -> 2 -// gas legacy: 100211 +// gas legacy: 76611 +// gas legacy code: 23600 diff --git a/test/libsolidity/semanticTests/functionCall/creation_function_call_no_args.sol b/test/libsolidity/semanticTests/functionCall/creation_function_call_no_args.sol index b6a33fb7e8..6044065958 100644 --- a/test/libsolidity/semanticTests/functionCall/creation_function_call_no_args.sol +++ b/test/libsolidity/semanticTests/functionCall/creation_function_call_no_args.sol @@ -11,4 +11,5 @@ contract D { } // ---- // f() -> 2 -// gas legacy: 100185 +// gas legacy: 76585 +// gas legacy code: 23600 diff --git a/test/libsolidity/semanticTests/functionCall/creation_function_call_with_args.sol b/test/libsolidity/semanticTests/functionCall/creation_function_call_with_args.sol index 34aac74efa..1133dc2be3 100644 --- a/test/libsolidity/semanticTests/functionCall/creation_function_call_with_args.sol +++ b/test/libsolidity/semanticTests/functionCall/creation_function_call_with_args.sol @@ -15,7 +15,10 @@ contract D { } // ---- // constructor(): 2 -> -// gas irOptimized: 192663 -// gas legacy: 241170 -// gas legacyOptimized: 192897 +// gas irOptimized: 138863 +// gas irOptimized code: 53800 +// gas legacy: 145570 +// gas legacy code: 95600 +// gas legacyOptimized: 138297 +// gas legacyOptimized code: 54600 // f() -> 2 diff --git a/test/libsolidity/semanticTests/functionCall/creation_function_call_with_salt.sol b/test/libsolidity/semanticTests/functionCall/creation_function_call_with_salt.sol index cb26a6e26a..ba90a8ecd5 100644 --- a/test/libsolidity/semanticTests/functionCall/creation_function_call_with_salt.sol +++ b/test/libsolidity/semanticTests/functionCall/creation_function_call_with_salt.sol @@ -17,7 +17,10 @@ contract D { // EVMVersion: >=constantinople // ---- // constructor(): 2 -> -// gas irOptimized: 192826 -// gas legacy: 241536 -// gas legacyOptimized: 193129 +// gas irOptimized: 139026 +// gas irOptimized code: 53800 +// gas legacy: 145936 +// gas legacy code: 95600 +// gas legacyOptimized: 138529 +// gas legacyOptimized code: 54600 // f() -> 2 diff --git a/test/libsolidity/semanticTests/functionCall/external_call_to_nonexisting.sol b/test/libsolidity/semanticTests/functionCall/external_call_to_nonexisting.sol index a1c74cf898..9d521f7777 100644 --- a/test/libsolidity/semanticTests/functionCall/external_call_to_nonexisting.sol +++ b/test/libsolidity/semanticTests/functionCall/external_call_to_nonexisting.sol @@ -22,9 +22,12 @@ contract C { } // ---- // constructor(), 1 ether -> -// gas irOptimized: 262355 -// gas legacy: 441442 -// gas legacyOptimized: 292862 +// gas irOptimized: 89555 +// gas irOptimized code: 172800 +// gas legacy: 103042 +// gas legacy code: 338400 +// gas legacyOptimized: 91862 +// gas legacyOptimized code: 201000 // f(uint256): 0 -> FAILURE // f(uint256): 1 -> FAILURE // f(uint256): 2 -> FAILURE diff --git a/test/libsolidity/semanticTests/functionCall/external_call_to_nonexisting_debugstrings.sol b/test/libsolidity/semanticTests/functionCall/external_call_to_nonexisting_debugstrings.sol index 96f097ce7f..9baacd8127 100644 --- a/test/libsolidity/semanticTests/functionCall/external_call_to_nonexisting_debugstrings.sol +++ b/test/libsolidity/semanticTests/functionCall/external_call_to_nonexisting_debugstrings.sol @@ -25,9 +25,12 @@ contract C { // revertStrings: debug // ---- // constructor(), 1 ether -> -// gas irOptimized: 390464 -// gas legacy: 809985 -// gas legacyOptimized: 498331 +// gas irOptimized: 99264 +// gas irOptimized code: 291200 +// gas legacy: 123585 +// gas legacy code: 686400 +// gas legacyOptimized: 107331 +// gas legacyOptimized code: 391000 // f(uint256): 0 -> FAILURE, hex"08c379a0", 0x20, 37, "Target contract does not contain", " code" // f(uint256): 1 -> FAILURE, hex"08c379a0", 0x20, 37, "Target contract does not contain", " code" // f(uint256): 2 -> FAILURE, hex"08c379a0", 0x20, 37, "Target contract does not contain", " code" diff --git a/test/libsolidity/semanticTests/functionCall/failed_create.sol b/test/libsolidity/semanticTests/functionCall/failed_create.sol index 091e5a77a6..b6c077753a 100644 --- a/test/libsolidity/semanticTests/functionCall/failed_create.sol +++ b/test/libsolidity/semanticTests/functionCall/failed_create.sol @@ -17,9 +17,12 @@ contract C { // EVMVersion: >=byzantium // ---- // constructor(), 20 wei -// gas irOptimized: 166148 -// gas legacy: 285547 -// gas legacyOptimized: 168515 +// gas irOptimized: 61548 +// gas irOptimized code: 104600 +// gas legacy: 70147 +// gas legacy code: 215400 +// gas legacyOptimized: 61715 +// gas legacyOptimized code: 106800 // f(uint256): 20 -> 0x137aa4dfc0911524504fcd4d98501f179bc13b4a // x() -> 1 // f(uint256): 20 -> FAILURE diff --git a/test/libsolidity/semanticTests/functionCall/gas_and_value_basic.sol b/test/libsolidity/semanticTests/functionCall/gas_and_value_basic.sol index 8396cb12db..806c8eb41b 100644 --- a/test/libsolidity/semanticTests/functionCall/gas_and_value_basic.sol +++ b/test/libsolidity/semanticTests/functionCall/gas_and_value_basic.sol @@ -38,9 +38,12 @@ contract test { } // ---- // constructor(), 20 wei -> -// gas irOptimized: 252626 -// gas legacy: 391568 -// gas legacyOptimized: 268069 +// gas irOptimized: 120226 +// gas irOptimized code: 132400 +// gas legacy: 130568 +// gas legacy code: 261000 +// gas legacyOptimized: 121069 +// gas legacyOptimized code: 147000 // sendAmount(uint256): 5 -> 5 // outOfGas() -> FAILURE # call to helper should not succeed but amount should be transferred anyway # // checkState() -> false, 15 diff --git a/test/libsolidity/semanticTests/functionCall/gas_and_value_brace_syntax.sol b/test/libsolidity/semanticTests/functionCall/gas_and_value_brace_syntax.sol index 9d9c3f603f..c186fc40b2 100644 --- a/test/libsolidity/semanticTests/functionCall/gas_and_value_brace_syntax.sol +++ b/test/libsolidity/semanticTests/functionCall/gas_and_value_brace_syntax.sol @@ -37,9 +37,12 @@ contract test { } // ---- // constructor(), 20 wei -> -// gas irOptimized: 252626 -// gas legacy: 391568 -// gas legacyOptimized: 268069 +// gas irOptimized: 120226 +// gas irOptimized code: 132400 +// gas legacy: 130568 +// gas legacy code: 261000 +// gas legacyOptimized: 121069 +// gas legacyOptimized code: 147000 // sendAmount(uint256): 5 -> 5 // outOfGas() -> FAILURE # call to helper should not succeed but amount should be transferred anyway # // checkState() -> false, 15 diff --git a/test/libsolidity/semanticTests/functionCall/send_zero_ether.sol b/test/libsolidity/semanticTests/functionCall/send_zero_ether.sol index a737de5cd4..94a7213232 100644 --- a/test/libsolidity/semanticTests/functionCall/send_zero_ether.sol +++ b/test/libsolidity/semanticTests/functionCall/send_zero_ether.sol @@ -16,6 +16,7 @@ contract Main { // ---- // constructor(), 20 wei -> // gas irOptimized: 100264 -// gas legacy: 110555 +// gas legacy: 57555 +// gas legacy code: 53000 // gas legacyOptimized: 100361 // s() -> true diff --git a/test/libsolidity/semanticTests/functionTypes/store_function.sol b/test/libsolidity/semanticTests/functionTypes/store_function.sol index 132a6c9565..5397d0b701 100644 --- a/test/libsolidity/semanticTests/functionTypes/store_function.sol +++ b/test/libsolidity/semanticTests/functionTypes/store_function.sol @@ -26,5 +26,7 @@ contract C { // ---- // t() -> 9 // gas irOptimized: 99064 -// gas legacy: 149095 -// gas legacyOptimized: 106188 +// gas legacy: 79495 +// gas legacy code: 69600 +// gas legacyOptimized: 77588 +// gas legacyOptimized code: 28600 diff --git a/test/libsolidity/semanticTests/immutable/multi_creation.sol b/test/libsolidity/semanticTests/immutable/multi_creation.sol index 145c32add6..c8806c50d0 100644 --- a/test/libsolidity/semanticTests/immutable/multi_creation.sol +++ b/test/libsolidity/semanticTests/immutable/multi_creation.sol @@ -27,8 +27,11 @@ contract C { } // ---- // f() -> 3, 7, 5 -// gas irOptimized: 124021 -// gas legacy: 148528 -// gas legacyOptimized: 123971 +// gas irOptimized: 86821 +// gas irOptimized code: 37200 +// gas legacy: 87728 +// gas legacy code: 60800 +// gas legacyOptimized: 86771 +// gas legacyOptimized code: 37200 // x() -> 7 // y() -> 5 diff --git a/test/libsolidity/semanticTests/immutable/use_scratch.sol b/test/libsolidity/semanticTests/immutable/use_scratch.sol index a7c8ea6a50..dc07086c29 100644 --- a/test/libsolidity/semanticTests/immutable/use_scratch.sol +++ b/test/libsolidity/semanticTests/immutable/use_scratch.sol @@ -15,8 +15,11 @@ contract C { } // ---- // constructor(): 3 -> -// gas irOptimized: 123526 -// gas legacy: 197645 -// gas legacyOptimized: 137658 +// gas irOptimized: 81126 +// gas irOptimized code: 42400 +// gas legacy: 88245 +// gas legacy code: 109400 +// gas legacyOptimized: 81858 +// gas legacyOptimized code: 55800 // f() -> 84, 23 // m(uint256): 3 -> 7 diff --git a/test/libsolidity/semanticTests/inheritance/address_overload_resolution.sol b/test/libsolidity/semanticTests/inheritance/address_overload_resolution.sol index c65d1abec5..0865ed2876 100644 --- a/test/libsolidity/semanticTests/inheritance/address_overload_resolution.sol +++ b/test/libsolidity/semanticTests/inheritance/address_overload_resolution.sol @@ -21,7 +21,9 @@ contract D { // ---- // f() -> 1 // gas irOptimized: 77051 -// gas legacy: 112280 +// gas legacy: 54480 +// gas legacy code: 57800 // g() -> 5 // gas irOptimized: 77106 -// gas legacy: 112816 +// gas legacy: 55016 +// gas legacy code: 57800 diff --git a/test/libsolidity/semanticTests/inheritance/inherited_function_calldata_calldata_interface.sol b/test/libsolidity/semanticTests/inheritance/inherited_function_calldata_calldata_interface.sol index 3114c80f19..0567c2ab14 100644 --- a/test/libsolidity/semanticTests/inheritance/inherited_function_calldata_calldata_interface.sol +++ b/test/libsolidity/semanticTests/inheritance/inherited_function_calldata_calldata_interface.sol @@ -23,4 +23,5 @@ contract B { // ---- // g() -> 42 // gas irOptimized: 80813 -// gas legacy: 122471 +// gas legacy: 55871 +// gas legacy code: 66600 diff --git a/test/libsolidity/semanticTests/inheritance/inherited_function_calldata_memory_interface.sol b/test/libsolidity/semanticTests/inheritance/inherited_function_calldata_memory_interface.sol index 74bf42ec7e..d5ff54b68a 100644 --- a/test/libsolidity/semanticTests/inheritance/inherited_function_calldata_memory_interface.sol +++ b/test/libsolidity/semanticTests/inheritance/inherited_function_calldata_memory_interface.sol @@ -23,5 +23,7 @@ contract B { // ---- // g() -> 42 // gas irOptimized: 100282 -// gas legacy: 180440 -// gas legacyOptimized: 112596 +// gas legacy: 56840 +// gas legacy code: 123600 +// gas legacyOptimized: 54996 +// gas legacyOptimized code: 57600 diff --git a/test/libsolidity/semanticTests/inheritance/member_notation_ctor.sol b/test/libsolidity/semanticTests/inheritance/member_notation_ctor.sol index 263588abab..e704a297bb 100644 --- a/test/libsolidity/semanticTests/inheritance/member_notation_ctor.sol +++ b/test/libsolidity/semanticTests/inheritance/member_notation_ctor.sol @@ -19,6 +19,8 @@ contract A { } // ---- // g(int256): -1 -> -1 -// gas legacy: 102078 +// gas legacy: 77878 +// gas legacy code: 24200 // g(int256): 10 -> 10 -// gas legacy: 101706 +// gas legacy: 77506 +// gas legacy code: 24200 diff --git a/test/libsolidity/semanticTests/inheritance/value_for_constructor.sol b/test/libsolidity/semanticTests/inheritance/value_for_constructor.sol index 9627ad025d..fdd0bafaad 100644 --- a/test/libsolidity/semanticTests/inheritance/value_for_constructor.sol +++ b/test/libsolidity/semanticTests/inheritance/value_for_constructor.sol @@ -39,9 +39,12 @@ contract Main { } // ---- // constructor(), 22 wei -> -// gas irOptimized: 261864 -// gas legacy: 392786 -// gas legacyOptimized: 261593 +// gas irOptimized: 143864 +// gas irOptimized code: 118000 +// gas legacy: 156586 +// gas legacy code: 236200 +// gas legacyOptimized: 143593 +// gas legacyOptimized code: 118000 // getFlag() -> true // getName() -> "abc" // getBalances() -> 12, 10 diff --git a/test/libsolidity/semanticTests/isoltestTesting/balance_other_contract.sol b/test/libsolidity/semanticTests/isoltestTesting/balance_other_contract.sol index 1a5c9b19b4..0ad55b5ddf 100644 --- a/test/libsolidity/semanticTests/isoltestTesting/balance_other_contract.sol +++ b/test/libsolidity/semanticTests/isoltestTesting/balance_other_contract.sol @@ -16,9 +16,12 @@ contract ClientReceipt { } // ---- // constructor(), 2000 wei -> -// gas irOptimized: 169907 -// gas legacy: 230018 -// gas legacyOptimized: 173867 +// gas irOptimized: 114107 +// gas irOptimized code: 55800 +// gas legacy: 118618 +// gas legacy code: 111400 +// gas legacyOptimized: 114067 +// gas legacyOptimized code: 59800 // balance -> 1500 // gas irOptimized: 191881 // gas legacy: 235167 diff --git a/test/libsolidity/semanticTests/operators/userDefined/operator_making_pure_external_call.sol b/test/libsolidity/semanticTests/operators/userDefined/operator_making_pure_external_call.sol index ce6a0f48db..a621b4c12a 100644 --- a/test/libsolidity/semanticTests/operators/userDefined/operator_making_pure_external_call.sol +++ b/test/libsolidity/semanticTests/operators/userDefined/operator_making_pure_external_call.sol @@ -53,9 +53,13 @@ contract C { // ---- // testMul(int32,int32): 42, 10 -> 420 // gas irOptimized: 102563 -// gas legacy: 183981 -// gas legacyOptimized: 123563 +// gas legacy: 56981 +// gas legacy code: 127000 +// gas legacyOptimized: 55163 +// gas legacyOptimized code: 68400 // testInc(int32): 42 -> 43 // gas irOptimized: 102386 -// gas legacy: 183239 -// gas legacyOptimized: 123251 +// gas legacy: 56239 +// gas legacy code: 127000 +// gas legacyOptimized: 54851 +// gas legacyOptimized code: 68400 diff --git a/test/libsolidity/semanticTests/operators/userDefined/operator_making_view_external_call.sol b/test/libsolidity/semanticTests/operators/userDefined/operator_making_view_external_call.sol index f3f8ebdc63..84f6bf08e7 100644 --- a/test/libsolidity/semanticTests/operators/userDefined/operator_making_view_external_call.sol +++ b/test/libsolidity/semanticTests/operators/userDefined/operator_making_view_external_call.sol @@ -59,9 +59,13 @@ contract C { // ---- // testMul(int32,int32): 42, 10 -> 420 // gas irOptimized: 102563 -// gas legacy: 183981 -// gas legacyOptimized: 123563 +// gas legacy: 56981 +// gas legacy code: 127000 +// gas legacyOptimized: 55163 +// gas legacyOptimized code: 68400 // testInc(int32): 42 -> 43 // gas irOptimized: 102386 -// gas legacy: 183239 -// gas legacyOptimized: 123251 +// gas legacy: 56239 +// gas legacy code: 127000 +// gas legacyOptimized: 54851 +// gas legacyOptimized code: 68400 diff --git a/test/libsolidity/semanticTests/salted_create/prediction_example.sol b/test/libsolidity/semanticTests/salted_create/prediction_example.sol index e7171536d6..6fa865440b 100644 --- a/test/libsolidity/semanticTests/salted_create/prediction_example.sol +++ b/test/libsolidity/semanticTests/salted_create/prediction_example.sol @@ -26,4 +26,5 @@ contract C { // compileViaYul: also // ---- // createDSalted(bytes32,uint256): 42, 64 -> -// gas legacy: 102841 +// gas legacy: 79241 +// gas legacy code: 23600 diff --git a/test/libsolidity/semanticTests/salted_create/salted_create.sol b/test/libsolidity/semanticTests/salted_create/salted_create.sol index 743ff5fd2a..535a2813c1 100644 --- a/test/libsolidity/semanticTests/salted_create/salted_create.sol +++ b/test/libsolidity/semanticTests/salted_create/salted_create.sol @@ -21,6 +21,9 @@ contract A { // ---- // different_salt() -> true // same_salt() -> true -// gas irOptimized: 98438895 -// gas legacy: 98439109 -// gas legacyOptimized: 98438967 +// gas irOptimized: 98438295 +// gas irOptimized code: 600 +// gas legacy: 98437509 +// gas legacy code: 1600 +// gas legacyOptimized: 98437367 +// gas legacyOptimized code: 1600 diff --git a/test/libsolidity/semanticTests/salted_create/salted_create_with_value.sol b/test/libsolidity/semanticTests/salted_create/salted_create_with_value.sol index 58b3f07603..735731c8ab 100644 --- a/test/libsolidity/semanticTests/salted_create/salted_create_with_value.sol +++ b/test/libsolidity/semanticTests/salted_create/salted_create_with_value.sol @@ -21,6 +21,9 @@ contract A { // EVMVersion: >=constantinople // ---- // f(), 10 ether -> 3007, 3008, 3009 -// gas irOptimized: 253005 -// gas legacy: 381063 -// gas legacyOptimized: 279658 +// gas irOptimized: 187005 +// gas irOptimized code: 66000 +// gas legacy: 190863 +// gas legacy code: 190200 +// gas legacyOptimized: 187258 +// gas legacyOptimized code: 92400 diff --git a/test/libsolidity/semanticTests/smoke/alignment.sol b/test/libsolidity/semanticTests/smoke/alignment.sol index 3e8016f988..296ae01617 100644 --- a/test/libsolidity/semanticTests/smoke/alignment.sol +++ b/test/libsolidity/semanticTests/smoke/alignment.sol @@ -25,5 +25,6 @@ contract D { // stateDecimal() -> right(42) // stateBytes() -> left(0x4200ef) // internalStateDecimal() -> 0x20 -// gas legacy: 100265 +// gas legacy: 76665 +// gas legacy code: 23600 // update(bool,uint256,bytes32): false, -23, left(0x2300ef) -> false, -23, left(0x2300ef) diff --git a/test/libsolidity/semanticTests/smoke/constructor.sol b/test/libsolidity/semanticTests/smoke/constructor.sol index 55789b2f4b..2783fe4a8c 100644 --- a/test/libsolidity/semanticTests/smoke/constructor.sol +++ b/test/libsolidity/semanticTests/smoke/constructor.sol @@ -12,9 +12,12 @@ contract C { } // ---- // constructor(), 2 wei: 3 -> -// gas irOptimized: 104396 -// gas legacy: 148256 -// gas legacyOptimized: 106699 +// gas irOptimized: 78996 +// gas irOptimized code: 25400 +// gas legacy: 83056 +// gas legacy code: 65200 +// gas legacyOptimized: 78899 +// gas legacyOptimized code: 27800 // state() -> 3 // balance() -> 2 // balance -> 2 diff --git a/test/libsolidity/semanticTests/state/blockhash_basic.sol b/test/libsolidity/semanticTests/state/blockhash_basic.sol index 03d6f9fe76..64b8d55a26 100644 --- a/test/libsolidity/semanticTests/state/blockhash_basic.sol +++ b/test/libsolidity/semanticTests/state/blockhash_basic.sol @@ -12,9 +12,12 @@ contract C { } // ---- // constructor() -// gas irOptimized: 108138 -// gas legacy: 152171 -// gas legacyOptimized: 106738 +// gas irOptimized: 80338 +// gas irOptimized code: 27800 +// gas legacy: 83571 +// gas legacy code: 68600 +// gas legacyOptimized: 80338 +// gas legacyOptimized code: 26400 // genesisHash() -> 0x3737373737373737373737373737373737373737373737373737373737373737 // currentHash() -> 0 // f(uint256): 0 -> 0x3737373737373737373737373737373737373737373737373737373737373737 diff --git a/test/libsolidity/semanticTests/userDefinedValueType/erc20.sol b/test/libsolidity/semanticTests/userDefinedValueType/erc20.sol index ac8609d713..8976cf3c52 100644 --- a/test/libsolidity/semanticTests/userDefinedValueType/erc20.sol +++ b/test/libsolidity/semanticTests/userDefinedValueType/erc20.sol @@ -113,9 +113,12 @@ contract ERC20 { // ---- // constructor() // ~ emit Transfer(address,address,uint256): #0x00, #0x1212121212121212121212121212120000000012, 0x14 -// gas irOptimized: 352682 -// gas legacy: 834752 -// gas legacyOptimized: 412648 +// gas irOptimized: 121082 +// gas irOptimized code: 231600 +// gas legacy: 163352 +// gas legacy code: 671400 +// gas legacyOptimized: 127448 +// gas legacyOptimized code: 285200 // totalSupply() -> 20 // gas irOptimized: 23415 // gas legacy: 23653 diff --git a/test/libsolidity/semanticTests/using/using_global_invisible.sol b/test/libsolidity/semanticTests/using/using_global_invisible.sol index 3e767a185d..818707f6fe 100644 --- a/test/libsolidity/semanticTests/using/using_global_invisible.sol +++ b/test/libsolidity/semanticTests/using/using_global_invisible.sol @@ -40,4 +40,5 @@ contract D { // ---- // library: "A":L // test() -> 3 -// gas legacy: 120881 +// gas legacy: 59681 +// gas legacy code: 61200 diff --git a/test/libsolidity/semanticTests/various/address_code.sol b/test/libsolidity/semanticTests/various/address_code.sol index 7e48b00ca8..6a97c0bf7e 100644 --- a/test/libsolidity/semanticTests/various/address_code.sol +++ b/test/libsolidity/semanticTests/various/address_code.sol @@ -14,9 +14,12 @@ contract C { } // ---- // constructor() -> -// gas irOptimized: 173273 -// gas legacy: 241796 -// gas legacyOptimized: 153670 +// gas irOptimized: 70873 +// gas irOptimized code: 102400 +// gas legacy: 82796 +// gas legacy code: 159000 +// gas legacyOptimized: 69870 +// gas legacyOptimized code: 83800 // initCode() -> 0x20, 0 // f() -> true // g() -> 0 diff --git a/test/libsolidity/semanticTests/various/code_access_content.sol b/test/libsolidity/semanticTests/various/code_access_content.sol index 92d31d6214..dc4e49b2da 100644 --- a/test/libsolidity/semanticTests/various/code_access_content.sol +++ b/test/libsolidity/semanticTests/various/code_access_content.sol @@ -38,6 +38,8 @@ contract C { } // ---- // testRuntime() -> true -// gas legacy: 100177 +// gas legacy: 76577 +// gas legacy code: 23600 // testCreation() -> true -// gas legacy: 100600 +// gas legacy: 77000 +// gas legacy code: 23600 diff --git a/test/libsolidity/semanticTests/various/code_access_create.sol b/test/libsolidity/semanticTests/various/code_access_create.sol index 075682129c..d2b7f92f4e 100644 --- a/test/libsolidity/semanticTests/various/code_access_create.sol +++ b/test/libsolidity/semanticTests/various/code_access_create.sol @@ -23,4 +23,5 @@ contract C { } // ---- // test() -> 7 -// gas legacy: 100849 +// gas legacy: 76649 +// gas legacy code: 24200 diff --git a/test/libsolidity/semanticTests/various/code_access_runtime.sol b/test/libsolidity/semanticTests/various/code_access_runtime.sol index 9a9e7a80bf..b62eb0b853 100644 --- a/test/libsolidity/semanticTests/various/code_access_runtime.sol +++ b/test/libsolidity/semanticTests/various/code_access_runtime.sol @@ -23,4 +23,5 @@ contract C { // EVMVersion: >=constantinople // ---- // test() -> 42 -// gas legacy: 100235 +// gas legacy: 76035 +// gas legacy code: 24200 diff --git a/test/libsolidity/semanticTests/various/code_length.sol b/test/libsolidity/semanticTests/various/code_length.sol index a8aac5306f..c30ac838fe 100644 --- a/test/libsolidity/semanticTests/various/code_length.sol +++ b/test/libsolidity/semanticTests/various/code_length.sol @@ -59,5 +59,6 @@ contract C { } // ---- // constructor() -// gas legacy: 124136 +// gas legacy: 66936 +// gas legacy code: 57200 // f(): true, true -> true, true diff --git a/test/libsolidity/semanticTests/various/create_calldata.sol b/test/libsolidity/semanticTests/various/create_calldata.sol index c3d038136f..2db42adebb 100644 --- a/test/libsolidity/semanticTests/various/create_calldata.sol +++ b/test/libsolidity/semanticTests/various/create_calldata.sol @@ -8,7 +8,10 @@ contract C { } // ---- // constructor(): 42 -> -// gas irOptimized: 145578 -// gas legacy: 173845 -// gas legacyOptimized: 137877 +// gas irOptimized: 68378 +// gas irOptimized code: 77200 +// gas legacy: 78445 +// gas legacy code: 95400 +// gas legacyOptimized: 68677 +// gas legacyOptimized code: 69200 // s() -> 0x20, 0 diff --git a/test/libsolidity/semanticTests/various/erc20.sol b/test/libsolidity/semanticTests/various/erc20.sol index 00c12fb18a..f7956c4c50 100644 --- a/test/libsolidity/semanticTests/various/erc20.sol +++ b/test/libsolidity/semanticTests/various/erc20.sol @@ -96,9 +96,12 @@ contract ERC20 { // ---- // constructor() // ~ emit Transfer(address,address,uint256): #0x00, #0x1212121212121212121212121212120000000012, 0x14 -// gas irOptimized: 353248 -// gas legacy: 807559 -// gas legacyOptimized: 408718 +// gas irOptimized: 121248 +// gas irOptimized code: 232000 +// gas legacy: 159959 +// gas legacy code: 647600 +// gas legacyOptimized: 126918 +// gas legacyOptimized code: 281800 // totalSupply() -> 20 // gas irOptimized: 23415 // gas legacy: 23524 diff --git a/test/libsolidity/semanticTests/various/external_types_in_calls.sol b/test/libsolidity/semanticTests/various/external_types_in_calls.sol index e8742c2346..aff302d26e 100644 --- a/test/libsolidity/semanticTests/various/external_types_in_calls.sol +++ b/test/libsolidity/semanticTests/various/external_types_in_calls.sol @@ -24,5 +24,6 @@ contract C { } // ---- // test() -> 9, 7 -// gas legacy: 127514 +// gas legacy: 80314 +// gas legacy code: 47200 // t2() -> 9 diff --git a/test/libsolidity/semanticTests/various/many_subassemblies.sol b/test/libsolidity/semanticTests/various/many_subassemblies.sol index 26c3a1bbff..67a576da78 100644 --- a/test/libsolidity/semanticTests/various/many_subassemblies.sol +++ b/test/libsolidity/semanticTests/various/many_subassemblies.sol @@ -30,6 +30,9 @@ contract D { } // ---- // run() -> -// gas irOptimized: 381615 -// gas legacy: 392719 -// gas legacyOptimized: 392719 +// gas irOptimized: 375015 +// gas irOptimized code: 6600 +// gas legacy: 375119 +// gas legacy code: 17600 +// gas legacyOptimized: 375119 +// gas legacyOptimized code: 17600 diff --git a/test/libsolidity/semanticTests/various/negative_stack_height.sol b/test/libsolidity/semanticTests/various/negative_stack_height.sol index 7289d2bbd9..44fd0089cf 100644 --- a/test/libsolidity/semanticTests/various/negative_stack_height.sol +++ b/test/libsolidity/semanticTests/various/negative_stack_height.sol @@ -65,5 +65,7 @@ contract C { // compileViaYul: false // ---- // constructor() -> -// gas legacy: 575268 -// gas legacyOptimized: 345022 +// gas legacy: 92268 +// gas legacy code: 483000 +// gas legacyOptimized: 75022 +// gas legacyOptimized code: 270000 diff --git a/test/libsolidity/semanticTests/various/selfdestruct_pre_cancun.sol b/test/libsolidity/semanticTests/various/selfdestruct_pre_cancun.sol index 4142eb25cf..a39b6c4235 100644 --- a/test/libsolidity/semanticTests/various/selfdestruct_pre_cancun.sol +++ b/test/libsolidity/semanticTests/various/selfdestruct_pre_cancun.sol @@ -62,9 +62,12 @@ contract D { // EVMVersion: =shanghai // ---- // constructor(), 1 ether -> -// gas irOptimized: 242428 -// gas legacy: 373563 -// gas legacyOptimized: 234516 +// gas irOptimized: 67028 +// gas irOptimized code: 175400 +// gas legacy: 76163 +// gas legacy code: 297400 +// gas legacyOptimized: 66516 +// gas legacyOptimized code: 168000 // exists() -> false // test_create_and_terminate() -> // exists() -> false diff --git a/test/libsolidity/semanticTests/various/selfdestruct_pre_cancun_multiple_beneficiaries.sol b/test/libsolidity/semanticTests/various/selfdestruct_pre_cancun_multiple_beneficiaries.sol index 87e81a2902..a09a7cac68 100644 --- a/test/libsolidity/semanticTests/various/selfdestruct_pre_cancun_multiple_beneficiaries.sol +++ b/test/libsolidity/semanticTests/various/selfdestruct_pre_cancun_multiple_beneficiaries.sol @@ -35,23 +35,30 @@ contract D { // EVMVersion: <=shanghai // ---- // constructor(), 2 ether -> -// gas irOptimized: 223918 -// gas legacy: 374024 -// gas legacyOptimized: 239815 +// gas irOptimized: 107718 +// gas irOptimized code: 116200 +// gas legacy: 120424 +// gas legacy code: 253600 +// gas legacyOptimized: 109015 +// gas legacyOptimized code: 130800 // balance: 0x1111111111111111111111111111111111111111 -> 0 // balance: 0x2222222222222222222222222222222222222222 -> 0 // balance -> 2000000000000000000 // exists() -> false // test_deploy_and_terminate_twice() -> -// gas irOptimized: 135350 -// gas legacy: 165584 -// gas legacyOptimized: 144396 +// gas irOptimized: 121350 +// gas irOptimized code: 14000 +// gas legacy: 122384 +// gas legacy code: 43200 +// gas legacyOptimized: 121596 +// gas legacyOptimized code: 22800 // exists() -> false // balance: 0x1111111111111111111111111111111111111111 -> 1000000000000000000 // balance: 0x2222222222222222222222222222222222222222 -> 0 // balance -> 1000000000000000000 // deploy() -> -// gas legacy: 101691 +// gas legacy: 58491 +// gas legacy code: 43200 // exists() -> true // balance: 0x1111111111111111111111111111111111111111 -> 1000000000000000000 // balance: 0x2222222222222222222222222222222222222222 -> 0 diff --git a/test/libsolidity/semanticTests/various/selfdestruct_pre_cancun_redeploy.sol b/test/libsolidity/semanticTests/various/selfdestruct_pre_cancun_redeploy.sol index e0885782c2..fc650ebba7 100644 --- a/test/libsolidity/semanticTests/various/selfdestruct_pre_cancun_redeploy.sol +++ b/test/libsolidity/semanticTests/various/selfdestruct_pre_cancun_redeploy.sol @@ -79,15 +79,21 @@ contract D { // EVMVersion: =shanghai // ---- // constructor(), 1 ether -> -// gas irOptimized: 430253 -// gas legacy: 690244 -// gas legacyOptimized: 412799 +// gas irOptimized: 133253 +// gas irOptimized code: 297000 +// gas legacy: 151644 +// gas legacy code: 538600 +// gas legacyOptimized: 131799 +// gas legacyOptimized code: 281000 // exists() -> false // test_deploy_and_terminate() -> // ~ emit Deployed(address,bytes32) from 0x137aa4dfc0911524504fcd4d98501f179bc13b4a: 0x7e6580007e709ac52945fae182c61131d42634e8, 0x1234000000000000000000000000000000000000000000000000000000000000 -// gas irOptimized: 117489 -// gas legacy: 118895 -// gas legacyOptimized: 117137 +// gas irOptimized: 96689 +// gas irOptimized code: 20800 +// gas legacy: 98095 +// gas legacy code: 20800 +// gas legacyOptimized: 96337 +// gas legacyOptimized code: 20800 // exists() -> false // deploy_create2() -> // ~ emit Deployed(address,bytes32) from 0x137aa4dfc0911524504fcd4d98501f179bc13b4a: 0x7e6580007e709ac52945fae182c61131d42634e8, 0x1234000000000000000000000000000000000000000000000000000000000000 diff --git a/test/libsolidity/semanticTests/various/senders_balance.sol b/test/libsolidity/semanticTests/various/senders_balance.sol index a1c7d4147f..5b4371149f 100644 --- a/test/libsolidity/semanticTests/various/senders_balance.sol +++ b/test/libsolidity/semanticTests/various/senders_balance.sol @@ -16,7 +16,10 @@ contract D { } // ---- // constructor(), 27 wei -> -// gas irOptimized: 167857 -// gas legacy: 218435 -// gas legacyOptimized: 167276 +// gas irOptimized: 114057 +// gas irOptimized code: 53800 +// gas legacy: 117835 +// gas legacy code: 100600 +// gas legacyOptimized: 113676 +// gas legacyOptimized code: 53600 // f() -> 27 diff --git a/test/libsolidity/semanticTests/various/staticcall_for_view_and_pure.sol b/test/libsolidity/semanticTests/various/staticcall_for_view_and_pure.sol index 1306529d41..77a330f3cd 100644 --- a/test/libsolidity/semanticTests/various/staticcall_for_view_and_pure.sol +++ b/test/libsolidity/semanticTests/various/staticcall_for_view_and_pure.sol @@ -35,12 +35,19 @@ contract D { // EVMVersion: >=byzantium // ---- // f() -> 0x1 # This should work, next should throw # -// gas legacy: 102095 +// gas legacy: 76495 +// gas legacy code: 25600 // fview() -> FAILURE -// gas irOptimized: 98438588 -// gas legacy: 98438774 -// gas legacyOptimized: 98438580 +// gas irOptimized: 98425388 +// gas irOptimized code: 13200 +// gas legacy: 98413174 +// gas legacy code: 25600 +// gas legacyOptimized: 98425380 +// gas legacyOptimized code: 13200 // fpure() -> FAILURE -// gas irOptimized: 98438589 -// gas legacy: 98438774 -// gas legacyOptimized: 98438580 +// gas irOptimized: 98425389 +// gas irOptimized code: 13200 +// gas legacy: 98413174 +// gas legacy code: 25600 +// gas legacyOptimized: 98425380 +// gas legacyOptimized code: 13200 diff --git a/test/libsolidity/semanticTests/various/value_complex.sol b/test/libsolidity/semanticTests/various/value_complex.sol index 2adac6bf4c..427a006dc1 100644 --- a/test/libsolidity/semanticTests/various/value_complex.sol +++ b/test/libsolidity/semanticTests/various/value_complex.sol @@ -19,7 +19,10 @@ contract test { } // ---- // constructor(), 20 wei -> -// gas irOptimized: 172399 -// gas legacy: 252276 -// gas legacyOptimized: 180336 +// gas irOptimized: 114399 +// gas irOptimized code: 58000 +// gas legacy: 120076 +// gas legacy code: 132200 +// gas legacyOptimized: 114536 +// gas legacyOptimized code: 65800 // sendAmount(uint256): 5 -> 8 diff --git a/test/libsolidity/semanticTests/various/value_insane.sol b/test/libsolidity/semanticTests/various/value_insane.sol index 87fa01485d..97fbbab1e6 100644 --- a/test/libsolidity/semanticTests/various/value_insane.sol +++ b/test/libsolidity/semanticTests/various/value_insane.sol @@ -18,7 +18,10 @@ contract test { } // ---- // constructor(), 20 wei -> -// gas irOptimized: 173263 -// gas legacy: 253800 -// gas legacyOptimized: 180768 +// gas irOptimized: 114463 +// gas irOptimized code: 58800 +// gas legacy: 120200 +// gas legacy code: 133600 +// gas legacyOptimized: 114568 +// gas legacyOptimized code: 66200 // sendAmount(uint256): 5 -> 8 diff --git a/test/libsolidity/util/SoltestTypes.h b/test/libsolidity/util/SoltestTypes.h index a2d593fd3c..791cea0116 100644 --- a/test/libsolidity/util/SoltestTypes.h +++ b/test/libsolidity/util/SoltestTypes.h @@ -215,11 +215,11 @@ struct FunctionCallExpectations raw += param.rawBytes; return raw; } - /// Gas used by function call - /// Keys represent all distinct combinations of compilation settings that affect produced + /// Gas used by function call minus the portion spent on code deposits (which is tracked + /// separately, in @a gasUsedForCodeDeposit). /// bytecode (and therefore the cost), except for EVM version. E.g. IR codegen without /// optimization legacy codegen with optimization. - std::map gasUsed; + std::map gasUsedExcludingCode; /// The portion of @a gasUsed spent on code deposits of newly created contracts. /// May exceed @a gasUsed in rare corner cases due to refunds. diff --git a/test/libsolidity/util/TestFileParser.cpp b/test/libsolidity/util/TestFileParser.cpp index e7e20f7c5c..5a32a1591a 100644 --- a/test/libsolidity/util/TestFileParser.cpp +++ b/test/libsolidity/util/TestFileParser.cpp @@ -103,7 +103,7 @@ std::vector TestFileParser::parseFunctio std::map& gasExpectationMap = (isCodeDepositCost ? calls.back().expectations.gasUsedForCodeDeposit : - calls.back().expectations.gasUsed + calls.back().expectations.gasUsedExcludingCode ); if (gasExpectationMap.count(runType) > 0) throw TestParserError("Gas usage expectation set multiple times."); @@ -207,9 +207,9 @@ std::vector TestFileParser::parseFunctio { // Ensure that each specified gas expectation has both components to simplify working with them. for (auto const& [runType, gas]: call.expectations.gasUsedForCodeDeposit) - call.expectations.gasUsed.try_emplace({runType, 0}); + call.expectations.gasUsedExcludingCode.try_emplace({runType, 0}); - for (auto const& [runType, gas]: call.expectations.gasUsed) + for (auto const& [runType, gas]: call.expectations.gasUsedExcludingCode) call.expectations.gasUsedForCodeDeposit.try_emplace({runType, 0}); } diff --git a/test/libsolidity/util/TestFileParserTests.cpp b/test/libsolidity/util/TestFileParserTests.cpp index 7a794f9152..4bb4aed3ac 100644 --- a/test/libsolidity/util/TestFileParserTests.cpp +++ b/test/libsolidity/util/TestFileParserTests.cpp @@ -1074,7 +1074,7 @@ BOOST_AUTO_TEST_CASE(gas) auto const calls = parse(source); BOOST_REQUIRE_EQUAL(calls.size(), 1); BOOST_REQUIRE_EQUAL(calls[0].expectations.failure, false); - BOOST_TEST(calls[0].expectations.gasUsed == (std::map{ + BOOST_TEST(calls[0].expectations.gasUsedExcludingCode == (std::map{ {"ir", 3245}, {"legacy", 5000}, {"legacyOptimized", 0}, @@ -1121,19 +1121,19 @@ BOOST_AUTO_TEST_CASE(gas_with_code_deposit_cost) // f() -> // gas legacyOptimized code: 1 // gas ir: 13000 - // gas irOptimized: 6666 + // gas irOptimized: 6000 // gas irOptimized code: 666 // gas legacy code: 0 - // gas legacyOptimized: 2 + // gas legacyOptimized: 1 )"; auto const calls = parse(source); BOOST_REQUIRE_EQUAL(calls.size(), 1); BOOST_REQUIRE_EQUAL(calls[0].expectations.failure, false); - BOOST_TEST(calls[0].expectations.gasUsed == (std::map{ + BOOST_TEST(calls[0].expectations.gasUsedExcludingCode == (std::map{ {"ir", 13000}, - {"irOptimized", 6666}, + {"irOptimized", 6000}, {"legacy", 0}, - {"legacyOptimized", 2}, + {"legacyOptimized", 1}, })); BOOST_TEST(calls[0].expectations.gasUsedForCodeDeposit == (std::map{ {"ir", 0}, @@ -1175,27 +1175,20 @@ BOOST_AUTO_TEST_CASE(gas_with_code_deposit_cost_double_code_gas) BOOST_AUTO_TEST_CASE(gas_with_code_deposit_cost_negative_non_code_cost) { // NOTE: This arrangement is unlikely but may still be possible due to refunds. + // We'll deal with it when we actually have a test case like that. char const* source = R"( // f() -> - // gas ir: 10 + // gas ir: -10 // gas ir code: 20 )"; - auto const calls = parse(source); - BOOST_REQUIRE_EQUAL(calls.size(), 1); - BOOST_REQUIRE_EQUAL(calls[0].expectations.failure, false); - BOOST_TEST(calls[0].expectations.gasUsed == (std::map{ - {"ir", 10}, - })); - BOOST_TEST(calls[0].expectations.gasUsedForCodeDeposit == (std::map{ - {"ir", 20}, - })); + BOOST_REQUIRE_THROW(parse(source), TestParserError); } BOOST_AUTO_TEST_CASE(gas_with_code_deposit_cost_negative_total_cost) { char const* source = R"( // f() -> - // gas ir: -10 + // gas ir: -30 // gas ir code: 20 )"; BOOST_REQUIRE_THROW(parse(source), TestParserError); @@ -1205,7 +1198,7 @@ BOOST_AUTO_TEST_CASE(gas_with_code_deposit_cost_negative_code_cost) { char const* source = R"( // f() -> - // gas ir: 20 + // gas ir: 10 // gas ir code: -10 )"; BOOST_REQUIRE_THROW(parse(source), TestParserError); diff --git a/test/libsolidity/util/TestFunctionCall.cpp b/test/libsolidity/util/TestFunctionCall.cpp index b22ac3716a..dd74d4035c 100644 --- a/test/libsolidity/util/TestFunctionCall.cpp +++ b/test/libsolidity/util/TestFunctionCall.cpp @@ -377,20 +377,20 @@ std::string TestFunctionCall::formatGasExpectations( using ranges::views::keys; using ranges::views::set_symmetric_difference; - soltestAssert(set_symmetric_difference(m_codeDepositGasCosts | keys, m_gasCosts | keys).empty()); - soltestAssert(set_symmetric_difference(m_call.expectations.gasUsedForCodeDeposit | keys, m_call.expectations.gasUsed | keys).empty()); + soltestAssert(set_symmetric_difference(m_codeDepositGasCosts | keys, m_gasCostsExcludingCode | keys).empty()); + soltestAssert(set_symmetric_difference(m_call.expectations.gasUsedForCodeDeposit | keys, m_call.expectations.gasUsedExcludingCode | keys).empty()); std::stringstream os; - for (auto const& [runType, gasUsed]: (_useActualCost ? m_gasCosts : m_call.expectations.gasUsed)) + for (auto const& [runType, gasUsedExcludingCode]: (_useActualCost ? m_gasCostsExcludingCode : m_call.expectations.gasUsedExcludingCode)) { soltestAssert(runType != ""); u256 gasUsedForCodeDeposit = (_useActualCost ? m_codeDepositGasCosts : m_call.expectations.gasUsedForCodeDeposit).at(runType); - os << std::endl << _linePrefix << "// gas " << runType << ": " << gasUsed.str(); + os << std::endl << _linePrefix << "// gas " << runType << ": " << gasUsedExcludingCode.str(); std::string gasDiff = formatGasDiff( - gasOrNullopt(m_gasCosts, runType), - gasOrNullopt(m_call.expectations.gasUsed, runType) + gasOrNullopt(m_gasCostsExcludingCode, runType), + gasOrNullopt(m_call.expectations.gasUsedExcludingCode, runType) ); if (_showDifference && !gasDiff.empty() && _useActualCost) os << " [" << gasDiff << "]"; diff --git a/test/libsolidity/util/TestFunctionCall.h b/test/libsolidity/util/TestFunctionCall.h index cf05b6a216..724cb8286c 100644 --- a/test/libsolidity/util/TestFunctionCall.h +++ b/test/libsolidity/util/TestFunctionCall.h @@ -53,7 +53,7 @@ class TestFunctionCall TestFunctionCall(FunctionCall _call): m_call(std::move(_call)), - m_gasCosts(m_call.expectations.gasUsed), + m_gasCostsExcludingCode(m_call.expectations.gasUsedExcludingCode), m_codeDepositGasCosts(m_call.expectations.gasUsedForCodeDeposit) {} @@ -97,7 +97,7 @@ class TestFunctionCall void calledNonExistingFunction() { m_calledNonExistingFunction = true; } void setFailure(const bool _failure) { m_failure = _failure; } void setRawBytes(const bytes _rawBytes) { m_rawBytes = _rawBytes; } - void setGasCost(std::string const& _runType, u256 const& _gasCost) { m_gasCosts[_runType] = _gasCost; } + void setGasCostExcludingCode(std::string const& _runType, u256 const& _gasCost) { m_gasCostsExcludingCode[_runType] = _gasCost; } void setCodeDepositGasCost(std::string const& _runType, u256 const& _gasCost) { m_codeDepositGasCosts[_runType] = _gasCost; } void setContractABI(Json::Value _contractABI) { m_contractABI = std::move(_contractABI); } void setSideEffects(std::vector _sideEffects) { m_call.actualSideEffects = _sideEffects; } @@ -147,7 +147,7 @@ class TestFunctionCall /// Result of the actual call been made. bytes m_rawBytes = bytes{}; /// Actual gas costs - std::map m_gasCosts; + std::map m_gasCostsExcludingCode; /// Actual code deposit gas costs std::map m_codeDepositGasCosts; /// Transaction status of the actual call. False in case of a REVERT or any other failure. diff --git a/test/libsolidity/util/TestFunctionCallTests.cpp b/test/libsolidity/util/TestFunctionCallTests.cpp index b78b7e5f29..5741ccd0de 100644 --- a/test/libsolidity/util/TestFunctionCallTests.cpp +++ b/test/libsolidity/util/TestFunctionCallTests.cpp @@ -295,7 +295,7 @@ BOOST_AUTO_TEST_CASE(format_gas_with_code_deposit) "some comment", { {"ir", 0}, // Zero costs are shown - {"legacy", 5000}, + {"legacy", 4875}, {"legacy optimized", 300}, }, { @@ -311,7 +311,7 @@ BOOST_AUTO_TEST_CASE(format_gas_with_code_deposit) TestFunctionCall(call).format(), "// f() -> #some comment#\n" "// gas ir: 0\n" - "// gas legacy: 5000\n" + "// gas legacy: 4875\n" "// gas legacy code: 125\n" "// gas legacy optimized: 300" ); From 381b149b8dd3fe87ae9d1af49514788adaa3e997 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Sun, 11 Feb 2024 16:03:50 +0100 Subject: [PATCH 45/57] gas_diff_stats.py: Include code deposit costs in total cost --- scripts/gas_diff_stats.py | 5 ++++- test/scripts/test_gas_diff_stats.py | 22 ++++++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/scripts/gas_diff_stats.py b/scripts/gas_diff_stats.py index 7403b39172..13d8a59e8d 100755 --- a/scripts/gas_diff_stats.py +++ b/scripts/gas_diff_stats.py @@ -23,7 +23,7 @@ import sys from pathlib import Path from enum import Enum -from parsec import generate, ParseError, regex, string +from parsec import generate, ParseError, regex, string, optional from tabulate import tabulate class Kind(Enum): @@ -49,6 +49,7 @@ class Diff(Enum): gas_ir_optimized = string("gas irOptimized").result(Kind.IrOptimized) gas_legacy_optimized = string("gas legacyOptimized").result(Kind.LegacyOptimized) gas_legacy = string("gas legacy").result(Kind.Legacy) +code_suffix = string("code") def number() -> int: """Parse number.""" @@ -67,6 +68,8 @@ def diff_string() -> (Kind, Diff, int): yield comment yield space codegen_kind = yield gas_ir_optimized ^ gas_ir ^ gas_legacy_optimized ^ gas_legacy + yield optional(space) + yield optional(code_suffix) yield colon yield space val = yield number() diff --git a/test/scripts/test_gas_diff_stats.py b/test/scripts/test_gas_diff_stats.py index 4980293aea..e67bd0be89 100644 --- a/test/scripts/test_gas_diff_stats.py +++ b/test/scripts/test_gas_diff_stats.py @@ -85,3 +85,25 @@ def test_collect_statistics_should_ignore_unchanged_costs(self): 0, # +legacyOptimized 3, # +legacy )) + + def test_collect_statistics_should_include_code_deposit_in_total_cost(self): + diff_output = dedent(""" + -// gas irOptimized: 1 + -// gas legacy: 20 + -// gas legacyOptimized: 300 + +// gas irOptimized: 4000 + +// gas irOptimized code: 50000 + +// gas legacy: 600000 + +// gas legacyOptimized: 7000000 + +// gas legacyOptimized code: 80000000 + -// gas legacy code: 900000000 + """).splitlines() + + self.assertEqual(collect_statistics(diff_output), ( + 1, # -irOptimized + 300, # -legacyOptimized + 900000020, # -legacy + 54000, # +irOptimized + 87000000, # +legacyOptimized + 600000, # +legacy + )) From e7312a501086e1b0751bc3abbc7e7f08de8b8acd Mon Sep 17 00:00:00 2001 From: r0qs Date: Wed, 21 Feb 2024 21:09:09 +0100 Subject: [PATCH 46/57] Use CircleCI rust+node convenience image for t_ems_ext_hardhat job --- .circleci/config.yml | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 663c64520e..30c0229642 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1385,7 +1385,7 @@ jobs: t_ems_ext_hardhat: <<: *base_node_small docker: - - image: cimg/node:18.16 + - image: cimg/rust:1.74.0-node environment: <<: *base_node_small_env HARDHAT_TESTS_SOLC_PATH: /tmp/workspace/soljson.js @@ -1395,18 +1395,15 @@ jobs: at: /tmp/workspace - run: name: Ensure pnpm is installed if npm is present - command: | - if command -v npm &> /dev/null; then - sudo npm install -g pnpm - fi + command: sudo npm install -g pnpm - run: name: Retrieve Hardhat latest release tag command: | # Make authenticated requests when the Github token is available if [[ -n "$GITHUB_ACCESS_TOKEN" ]]; then - EXTRA_HEADERS=(--header 'Authorization: Bearer '"${GITHUB_ACCESS_TOKEN}") + EXTRA_HEADERS=(--header "Authorization: Bearer ${GITHUB_ACCESS_TOKEN}") fi - HARDHAT_RELEASE_TAG=$( + HARDHAT_LATEST_RELEASE_TAG=$( curl \ --silent \ --location \ @@ -1416,8 +1413,8 @@ jobs: https://api.github.com/repos/nomiclabs/hardhat/releases/latest \ | jq --raw-output .tag_name \ ) - echo "export HARDHAT_RELEASE_TAG='${HARDHAT_RELEASE_TAG}'" >> "$BASH_ENV" - - run: git clone --depth 1 https://github.com/nomiclabs/hardhat.git --branch $HARDHAT_RELEASE_TAG + echo "export HARDHAT_LATEST_RELEASE_TAG='${HARDHAT_LATEST_RELEASE_TAG}'" >> "$BASH_ENV" + - run: git clone --depth 1 https://github.com/nomiclabs/hardhat.git --branch "$HARDHAT_LATEST_RELEASE_TAG" - run: name: Install dependencies command: | From c8358f5677a786847fb4783866f995d0e140389c Mon Sep 17 00:00:00 2001 From: r0qs Date: Wed, 21 Feb 2024 21:01:28 +0100 Subject: [PATCH 47/57] Fix detect_hardhat_artifact_dir in externalTests scripts --- scripts/externalTests/common.sh | 41 ++++++++++++++++----------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/scripts/externalTests/common.sh b/scripts/externalTests/common.sh index 3bca968a5a..082a25c4c5 100644 --- a/scripts/externalTests/common.sh +++ b/scripts/externalTests/common.sh @@ -570,17 +570,15 @@ function gas_report_to_json cat - | "${REPO_ROOT}/scripts/externalTests/parse_eth_gas_report.py" | jq '{gas: .}' } -function detect_hardhat_artifact_dir -{ - if [[ -e build/ && -e artifacts/ ]]; then - fail "Cannot determine Hardhat artifact location. Both build/ and artifacts/ exist" - elif [[ -e build/ ]]; then - echo -n build/artifacts - elif [[ -e artifacts/ ]]; then - echo -n artifacts - else - fail "Hardhat build artifacts not found." - fi +function detect_hardhat_artifact_dirs +{ + # NOTE: The artifacts path is a configured parameter in Hardhat, so the below may fail for new external tests + # See: https://hardhat.org/hardhat-runner/docs/config#path-configuration + local artifact_dir=() + [[ -e build/artifacts ]] && artifact_dir+=("build/artifacts") + [[ -e artifacts/ ]] && artifact_dir+=("artifacts") + (( ${#artifact_dir[@]} != 0 )) || assertFail + echo -n "${artifact_dir[@]}" } function bytecode_size_json_from_truffle_artifacts @@ -605,16 +603,17 @@ function bytecode_size_json_from_truffle_artifacts function bytecode_size_json_from_hardhat_artifacts { # NOTE: The output of this function is a series of concatenated JSON dicts rather than a list. - - for artifact in "$(detect_hardhat_artifact_dir)"/build-info/*.json; do - # Each artifact contains Standard JSON output under the `output` key. - # Process it into a dict of the form `{"": {"": }}`, - # Note that one Hardhat artifact often represents multiple input files. - jq '.output.contracts | to_entries[] | { - "\(.key)": .value | to_entries[] | { - "\(.key)": (.value.evm.bytecode.object | length / 2) - } - }' "$artifact" + for artifact_dir in $(detect_hardhat_artifact_dirs); do + for artifact in "$artifact_dir"/build-info/*.json; do + # Each artifact contains Standard JSON output under the `output` key. + # Process it into a dict of the form `{"": {"": }}`, + # Note that one Hardhat artifact often represents multiple input files. + jq '.output.contracts | to_entries[] | { + "\(.key)": .value | to_entries[] | { + "\(.key)": (.value.evm.bytecode.object | length / 2) + } + }' "$artifact" + done done } From e095590330dfbd3022db12eb5f106606f818dd21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Thu, 2 Nov 2023 18:59:14 +0100 Subject: [PATCH 48/57] Parser::parseFunctionDefinition(): Return FunctionDefinition, not ASTNode --- libsolidity/parsing/Parser.cpp | 2 +- libsolidity/parsing/Parser.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libsolidity/parsing/Parser.cpp b/libsolidity/parsing/Parser.cpp index 42be1ab9ee..c7f0c313fd 100644 --- a/libsolidity/parsing/Parser.cpp +++ b/libsolidity/parsing/Parser.cpp @@ -627,7 +627,7 @@ Parser::FunctionHeaderParserResult Parser::parseFunctionHeader(bool _isStateVari return result; } -ASTPointer Parser::parseFunctionDefinition(bool _freeFunction, bool _allowBody) +ASTPointer Parser::parseFunctionDefinition(bool _freeFunction, bool _allowBody) { RecursionGuard recursionGuard(*this); ASTNodeFactory nodeFactory(*this); diff --git a/libsolidity/parsing/Parser.h b/libsolidity/parsing/Parser.h index d4c48c7a63..86dd2843fd 100644 --- a/libsolidity/parsing/Parser.h +++ b/libsolidity/parsing/Parser.h @@ -102,7 +102,7 @@ class Parser: public langutil::ParserBase ASTPointer parseOverrideSpecifier(); StateMutability parseStateMutability(); FunctionHeaderParserResult parseFunctionHeader(bool _isStateVariable); - ASTPointer parseFunctionDefinition(bool _freeFunction = false, bool _allowBody = true); + ASTPointer parseFunctionDefinition(bool _freeFunction = false, bool _allowBody = true); ASTPointer parseStructDefinition(); ASTPointer parseEnumDefinition(); ASTPointer parseUserDefinedValueTypeDefinition(); From fa35ed5b98baa56e6e03abe61f3e6b9b42643e5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Thu, 2 Nov 2023 18:37:14 +0100 Subject: [PATCH 49/57] Add ForAllQuantifier AST node --- libsolidity/ast/AST.h | 32 ++++++++++++++++++++++++++++++++ libsolidity/ast/ASTAnnotations.h | 4 ++++ libsolidity/ast/ASTForward.h | 1 + libsolidity/ast/ASTVisitor.h | 4 ++++ libsolidity/ast/AST_accept.h | 20 ++++++++++++++++++++ 5 files changed, 61 insertions(+) diff --git a/libsolidity/ast/AST.h b/libsolidity/ast/AST.h index b9cc2118ef..27926721aa 100644 --- a/libsolidity/ast/AST.h +++ b/libsolidity/ast/AST.h @@ -2625,6 +2625,38 @@ class Builtin: public Expression SourceLocation m_nameParameterLocation; }; +// TODO: NatSpec used on the quantifier should be recognized as applying to the function. +class ForAllQuantifier: public ASTNode, public Scopable, public ScopeOpener +{ +public: + ForAllQuantifier( + int64_t _id, + SourceLocation _location, + ASTPointer _typeVariableDeclarations, + ASTPointer _quantifiedDeclaration + ): + ASTNode(_id, std::move(_location)), + m_typeVariableDeclarations(std::move(_typeVariableDeclarations)), + m_quantifiedDeclaration(std::move(_quantifiedDeclaration)) + { + solAssert(m_typeVariableDeclarations); + solAssert(m_quantifiedDeclaration); + } + + void accept(ASTVisitor& _visitor) override; + void accept(ASTConstVisitor& _visitor) const override; + ForAllQuantifierAnnotation& annotation() const override { return initAnnotation(); } + + bool experimentalSolidityOnly() const override { return true; } + + ParameterList const& typeVariableDeclarations() const { return *m_typeVariableDeclarations; } + FunctionDefinition const& quantifiedDeclaration() const { return *m_quantifiedDeclaration; } + +private: + ASTPointer m_typeVariableDeclarations; + ASTPointer m_quantifiedDeclaration; +}; + /// @} } diff --git a/libsolidity/ast/ASTAnnotations.h b/libsolidity/ast/ASTAnnotations.h index e68614f464..f7519250a3 100644 --- a/libsolidity/ast/ASTAnnotations.h +++ b/libsolidity/ast/ASTAnnotations.h @@ -350,6 +350,10 @@ struct FunctionCallAnnotation: ExpressionAnnotation struct TypeClassDefinitionAnnotation: TypeDeclarationAnnotation, StructurallyDocumentedAnnotation { }; + +struct ForAllQuantifierAnnotation: StatementAnnotation, ScopableAnnotation +{ +}; /// @} } diff --git a/libsolidity/ast/ASTForward.h b/libsolidity/ast/ASTForward.h index f7c3d60237..b8a3a4ae00 100644 --- a/libsolidity/ast/ASTForward.h +++ b/libsolidity/ast/ASTForward.h @@ -106,6 +106,7 @@ class TypeClassInstantiation; class TypeClassName; class TypeDefinition; class Builtin; +class ForAllQuantifier; /// @} class VariableScope; diff --git a/libsolidity/ast/ASTVisitor.h b/libsolidity/ast/ASTVisitor.h index f9196d6b95..f985a44901 100644 --- a/libsolidity/ast/ASTVisitor.h +++ b/libsolidity/ast/ASTVisitor.h @@ -116,6 +116,7 @@ class ASTVisitor virtual bool visit(TypeDefinition& _node) { return visitNode(_node); } virtual bool visit(TypeClassName& _node) { return visitNode(_node); } virtual bool visit(Builtin& _node) { return visitNode(_node); } + virtual bool visit(ForAllQuantifier& _node) { return visitNode(_node); } /// @} virtual void endVisit(SourceUnit& _node) { endVisitNode(_node); } @@ -180,6 +181,7 @@ class ASTVisitor virtual void endVisit(TypeDefinition& _node) { endVisitNode(_node); } virtual void endVisit(TypeClassName& _node) { endVisitNode(_node); } virtual void endVisit(Builtin& _node) { endVisitNode(_node); } + virtual void endVisit(ForAllQuantifier& _node) { endVisitNode(_node); } /// @} protected: @@ -266,6 +268,7 @@ class ASTConstVisitor virtual bool visit(TypeDefinition const& _node) { return visitNode(_node); } virtual bool visit(TypeClassName const& _node) { return visitNode(_node); } virtual bool visit(Builtin const& _node) { return visitNode(_node); } + virtual bool visit(ForAllQuantifier const& _node) { return visitNode(_node); } /// @} virtual void endVisit(SourceUnit const& _node) { endVisitNode(_node); } @@ -330,6 +333,7 @@ class ASTConstVisitor virtual void endVisit(TypeDefinition const& _node) { endVisitNode(_node); } virtual void endVisit(TypeClassName const& _node) { endVisitNode(_node); } virtual void endVisit(Builtin const& _node) { endVisitNode(_node); } + virtual void endVisit(ForAllQuantifier const& _node) { endVisitNode(_node); } /// @} protected: diff --git a/libsolidity/ast/AST_accept.h b/libsolidity/ast/AST_accept.h index be9de64db7..55ebe2a78c 100644 --- a/libsolidity/ast/AST_accept.h +++ b/libsolidity/ast/AST_accept.h @@ -1140,6 +1140,26 @@ void Builtin::accept(ASTConstVisitor& _visitor) const _visitor.visit(*this); _visitor.endVisit(*this); } + +void ForAllQuantifier::accept(ASTVisitor& _visitor) +{ + if (_visitor.visit(*this)) + { + m_typeVariableDeclarations->accept(_visitor); + m_quantifiedDeclaration->accept(_visitor); + } + _visitor.endVisit(*this); +} + +void ForAllQuantifier::accept(ASTConstVisitor& _visitor) const +{ + if (_visitor.visit(*this)) + { + m_typeVariableDeclarations->accept(_visitor); + m_quantifiedDeclaration->accept(_visitor); + } + _visitor.endVisit(*this); +} /// @} } From 4d051c1fcefa9c8766f7083139e294703503d88a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Thu, 2 Nov 2023 19:07:44 +0100 Subject: [PATCH 50/57] Add parser support for quantified function definitions --- liblangutil/Token.h | 1 + .../experimental/analysis/TypeInference.cpp | 13 ++++++ .../experimental/analysis/TypeInference.h | 1 + libsolidity/parsing/Parser.cpp | 24 +++++++++++ libsolidity/parsing/Parser.h | 1 + .../parsing/forall_free_function.sol | 27 ++++++++++++ .../forall_free_function_no_type_var.sol | 14 ++++++ .../forall_free_function_with_sorts.sol | 43 +++++++++++++++++++ .../parsing/forall_type_class.sol | 8 ++++ .../forall_type_class_instantiation.sol | 12 ++++++ 10 files changed, 144 insertions(+) create mode 100644 test/libsolidity/syntaxTests/experimental/parsing/forall_free_function.sol create mode 100644 test/libsolidity/syntaxTests/experimental/parsing/forall_free_function_no_type_var.sol create mode 100644 test/libsolidity/syntaxTests/experimental/parsing/forall_free_function_with_sorts.sol create mode 100644 test/libsolidity/syntaxTests/experimental/parsing/forall_type_class.sol create mode 100644 test/libsolidity/syntaxTests/experimental/parsing/forall_type_class_instantiation.sol diff --git a/liblangutil/Token.h b/liblangutil/Token.h index 98de0b228d..0f7c2df080 100644 --- a/liblangutil/Token.h +++ b/liblangutil/Token.h @@ -276,6 +276,7 @@ namespace solidity::langutil K(Itself, "itself", 0) \ K(StaticAssert, "static_assert", 0) \ K(Builtin, "__builtin", 0) \ + K(ForAll, "forall", 0) \ T(ExperimentalEnd, nullptr, 0) /* used as experimental enum end marker */ \ \ /* Illegal token - not able to scan. */ \ diff --git a/libsolidity/experimental/analysis/TypeInference.cpp b/libsolidity/experimental/analysis/TypeInference.cpp index 63a377f90d..8625937a35 100644 --- a/libsolidity/experimental/analysis/TypeInference.cpp +++ b/libsolidity/experimental/analysis/TypeInference.cpp @@ -129,6 +129,19 @@ bool TypeInference::analyze(SourceUnit const& _sourceUnit) return !m_errorReporter.hasErrors(); } +bool TypeInference::visit(ForAllQuantifier const& _quantifier) +{ + solAssert(m_expressionContext == ExpressionContext::Term); + + { + ScopedSaveAndRestore expressionContext{m_expressionContext, ExpressionContext::Type}; + _quantifier.typeVariableDeclarations().accept(*this); + } + + _quantifier.quantifiedDeclaration().accept(*this); + return false; +} + bool TypeInference::visit(FunctionDefinition const& _functionDefinition) { solAssert(m_expressionContext == ExpressionContext::Term); diff --git a/libsolidity/experimental/analysis/TypeInference.h b/libsolidity/experimental/analysis/TypeInference.h index 3eb2ad94cf..0932367995 100644 --- a/libsolidity/experimental/analysis/TypeInference.h +++ b/libsolidity/experimental/analysis/TypeInference.h @@ -56,6 +56,7 @@ class TypeInference: public ASTConstVisitor void endVisit(VariableDeclarationStatement const& _variableDeclarationStatement) override; bool visit(VariableDeclaration const& _variableDeclaration) override; + bool visit(ForAllQuantifier const& _forAllQuantifier) override; bool visit(FunctionDefinition const& _functionDefinition) override; void endVisit(FunctionDefinition const& _functionDefinition) override; bool visit(ParameterList const&) override { return true; } diff --git a/libsolidity/parsing/Parser.cpp b/libsolidity/parsing/Parser.cpp index c7f0c313fd..f650e0dbf1 100644 --- a/libsolidity/parsing/Parser.cpp +++ b/libsolidity/parsing/Parser.cpp @@ -137,6 +137,9 @@ ASTPointer Parser::parse(CharStream& _charStream) case Token::Function: nodes.push_back(parseFunctionDefinition(true)); break; + case Token::ForAll: + nodes.push_back(parseQuantifiedFunctionDefinition()); + break; case Token::Event: nodes.push_back(parseEventDefinition()); break; @@ -627,6 +630,27 @@ Parser::FunctionHeaderParserResult Parser::parseFunctionHeader(bool _isStateVari return result; } +ASTPointer Parser::parseQuantifiedFunctionDefinition() +{ + solAssert(m_experimentalSolidityEnabledInCurrentSourceUnit); + RecursionGuard recursionGuard(*this); + ASTNodeFactory nodeFactory(*this); + + expectToken(Token::ForAll); + ASTPointer typeVariableDeclarations = parseParameterList(); + nodeFactory.markEndPosition(); + + if (m_scanner->currentToken() != Token::Function) + fatalParserError(5709_error, "Expected a function definition."); + + ASTPointer quantifiedFunction = parseFunctionDefinition(true /* _freeFunction */, true /* _allowBody */); + + return nodeFactory.createNode( + std::move(typeVariableDeclarations), + std::move(quantifiedFunction) + ); +} + ASTPointer Parser::parseFunctionDefinition(bool _freeFunction, bool _allowBody) { RecursionGuard recursionGuard(*this); diff --git a/libsolidity/parsing/Parser.h b/libsolidity/parsing/Parser.h index 86dd2843fd..aedfdb7ddd 100644 --- a/libsolidity/parsing/Parser.h +++ b/libsolidity/parsing/Parser.h @@ -102,6 +102,7 @@ class Parser: public langutil::ParserBase ASTPointer parseOverrideSpecifier(); StateMutability parseStateMutability(); FunctionHeaderParserResult parseFunctionHeader(bool _isStateVariable); + ASTPointer parseQuantifiedFunctionDefinition(); ASTPointer parseFunctionDefinition(bool _freeFunction = false, bool _allowBody = true); ASTPointer parseStructDefinition(); ASTPointer parseEnumDefinition(); diff --git a/test/libsolidity/syntaxTests/experimental/parsing/forall_free_function.sol b/test/libsolidity/syntaxTests/experimental/parsing/forall_free_function.sol new file mode 100644 index 0000000000..ba22a9fae4 --- /dev/null +++ b/test/libsolidity/syntaxTests/experimental/parsing/forall_free_function.sol @@ -0,0 +1,27 @@ +pragma experimental solidity; + +forall (A) +function f(a: A) {} + +forall (A, B) +function g(a: A, b: B) {} +// ==== +// EVMVersion: >=constantinople +// compileViaYul: true +// ---- +// Warning 2264: (0-29): Experimental features are turned on. Do not use experimental features on live deployments. +// Info 4164: (38-41): Inferred type: 's:type +// Info 4164: (39-40): Inferred type: 's:type +// Info 4164: (42-61): Inferred type: 's:type -> () +// Info 4164: (52-58): Inferred type: 's:type +// Info 4164: (53-57): Inferred type: 's:type +// Info 4164: (56-57): Inferred type: 's:type +// Info 4164: (70-76): Inferred type: ('v:type, 'w:type) +// Info 4164: (71-72): Inferred type: 'v:type +// Info 4164: (74-75): Inferred type: 'w:type +// Info 4164: (77-102): Inferred type: ('v:type, 'w:type) -> () +// Info 4164: (87-99): Inferred type: ('v:type, 'w:type) +// Info 4164: (88-92): Inferred type: 'v:type +// Info 4164: (91-92): Inferred type: 'v:type +// Info 4164: (94-98): Inferred type: 'w:type +// Info 4164: (97-98): Inferred type: 'w:type diff --git a/test/libsolidity/syntaxTests/experimental/parsing/forall_free_function_no_type_var.sol b/test/libsolidity/syntaxTests/experimental/parsing/forall_free_function_no_type_var.sol new file mode 100644 index 0000000000..66753fdd0f --- /dev/null +++ b/test/libsolidity/syntaxTests/experimental/parsing/forall_free_function_no_type_var.sol @@ -0,0 +1,14 @@ +pragma experimental solidity; + +forall () +function f(x: ()) {} +// ==== +// EVMVersion: >=constantinople +// compileViaYul: true +// ---- +// Warning 2264: (0-29): Experimental features are turned on. Do not use experimental features on live deployments. +// Info 4164: (38-40): Inferred type: () +// Info 4164: (41-61): Inferred type: () -> () +// Info 4164: (51-58): Inferred type: () +// Info 4164: (52-57): Inferred type: () +// Info 4164: (55-57): Inferred type: () diff --git a/test/libsolidity/syntaxTests/experimental/parsing/forall_free_function_with_sorts.sol b/test/libsolidity/syntaxTests/experimental/parsing/forall_free_function_with_sorts.sol new file mode 100644 index 0000000000..1ab09fd2bd --- /dev/null +++ b/test/libsolidity/syntaxTests/experimental/parsing/forall_free_function_with_sorts.sol @@ -0,0 +1,43 @@ +pragma experimental solidity; + +class Self: Class1 {} +class Self: Class2 {} + +forall (A: (Class1, Class2), B: Class1) +function f(a: A: Class1, b: B: Class1) {} + +forall A: Class1 +function g(a: A) {} +// ==== +// EVMVersion: >=constantinople +// compileViaYul: true +// ---- +// Warning 2264: (0-29): Experimental features are turned on. Do not use experimental features on live deployments. +// Info 4164: (31-52): Inferred type: Class1 +// Info 4164: (37-41): Inferred type: 'k:(type, Class1) +// Info 4164: (53-74): Inferred type: Class2 +// Info 4164: (59-63): Inferred type: 'l:(type, Class2) +// Info 4164: (83-115): Inferred type: ('ba:(type, Class1, Class2), 'bg:(type, Class1)) +// Info 4164: (84-103): Inferred type: 'ba:(type, Class1, Class2) +// Info 4164: (87-103): Inferred type: 'ba:(type, Class1, Class2) +// Info 4164: (88-94): Inferred type: 'ba:(type, Class1, Class2) +// Info 4164: (96-102): Inferred type: 'ba:(type, Class1, Class2) +// Info 4164: (105-114): Inferred type: 'bg:(type, Class1) +// Info 4164: (108-114): Inferred type: 'bg:(type, Class1) +// Info 4164: (116-157): Inferred type: ('ba:(type, Class1, Class2), 'bg:(type, Class1)) -> () +// Info 4164: (126-154): Inferred type: ('ba:(type, Class1, Class2), 'bg:(type, Class1)) +// Info 4164: (127-139): Inferred type: 'ba:(type, Class1, Class2) +// Info 4164: (130-139): Inferred type: 'ba:(type, Class1, Class2) +// Info 4164: (130-131): Inferred type: 'ba:(type, Class1, Class2) +// Info 4164: (133-139): Inferred type: 'ba:(type, Class1, Class2) +// Info 4164: (141-153): Inferred type: 'bg:(type, Class1) +// Info 4164: (144-153): Inferred type: 'bg:(type, Class1) +// Info 4164: (144-145): Inferred type: 'bg:(type, Class1) +// Info 4164: (147-153): Inferred type: 'bg:(type, Class1) +// Info 4164: (166-175): Inferred type: 'bi:(type, Class1) +// Info 4164: (166-175): Inferred type: 'bi:(type, Class1) +// Info 4164: (169-175): Inferred type: 'bi:(type, Class1) +// Info 4164: (176-195): Inferred type: 'bi:(type, Class1) -> () +// Info 4164: (186-192): Inferred type: 'bi:(type, Class1) +// Info 4164: (187-191): Inferred type: 'bi:(type, Class1) +// Info 4164: (190-191): Inferred type: 'bi:(type, Class1) diff --git a/test/libsolidity/syntaxTests/experimental/parsing/forall_type_class.sol b/test/libsolidity/syntaxTests/experimental/parsing/forall_type_class.sol new file mode 100644 index 0000000000..aa0012eac1 --- /dev/null +++ b/test/libsolidity/syntaxTests/experimental/parsing/forall_type_class.sol @@ -0,0 +1,8 @@ +pragma experimental solidity; + +forall (A, B) +class Self: C {} +// ==== +// EVMVersion: >=constantinople +// ---- +// ParserError 5709: (45-50): Expected a function definition. diff --git a/test/libsolidity/syntaxTests/experimental/parsing/forall_type_class_instantiation.sol b/test/libsolidity/syntaxTests/experimental/parsing/forall_type_class_instantiation.sol new file mode 100644 index 0000000000..31573447a3 --- /dev/null +++ b/test/libsolidity/syntaxTests/experimental/parsing/forall_type_class_instantiation.sol @@ -0,0 +1,12 @@ +pragma experimental solidity; + +type T; + +class Self: C {} + +forall (A, B) +instantiation T: C {} +// ==== +// EVMVersion: >=constantinople +// ---- +// ParserError 5709: (72-85): Expected a function definition. From cd52e5aa9c282e75654709cd2890638e52561521 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Mon, 6 Nov 2023 12:01:25 +0100 Subject: [PATCH 51/57] TypeInference: Require declarations for type variables --- libsolidity/analysis/NameAndTypeResolver.cpp | 31 ++++++-- .../experimental/analysis/TypeInference.cpp | 6 +- .../undeclared_type_variable_in_function.sol | 17 +++++ ...d_type_variable_in_quantified_function.sol | 12 ++++ ...undeclared_type_variable_in_type_class.sol | 17 +++++ .../inference/polymorphic_function_call.sol | 70 ++++++++++--------- .../inference/polymorphic_type.sol | 41 ++++++----- ...ulti_use_function_parameter_and_return.sol | 16 +++++ ...variable_multi_use_function_parameters.sol | 16 +++++ 9 files changed, 169 insertions(+), 57 deletions(-) create mode 100644 test/libsolidity/syntaxTests/experimental/forall/undeclared_type_variable_in_function.sol create mode 100644 test/libsolidity/syntaxTests/experimental/forall/undeclared_type_variable_in_quantified_function.sol create mode 100644 test/libsolidity/syntaxTests/experimental/forall/undeclared_type_variable_in_type_class.sol create mode 100644 test/libsolidity/syntaxTests/experimental/inference/type_variable_multi_use_function_parameter_and_return.sol create mode 100644 test/libsolidity/syntaxTests/experimental/inference/type_variable_multi_use_function_parameters.sol diff --git a/libsolidity/analysis/NameAndTypeResolver.cpp b/libsolidity/analysis/NameAndTypeResolver.cpp index 94d0568118..642e87a53b 100644 --- a/libsolidity/analysis/NameAndTypeResolver.cpp +++ b/libsolidity/analysis/NameAndTypeResolver.cpp @@ -703,11 +703,34 @@ void DeclarationRegistrationHelper::registerDeclaration(Declaration& _declaratio solAssert(m_currentScope && m_scopes.count(m_currentScope), "No current scope."); solAssert(m_currentScope == _declaration.scope(), "Unexpected current scope."); - // Register declaration as inactive if we are in block scope. - bool inactive = - (dynamic_cast(m_currentScope) || dynamic_cast(m_currentScope)); + // Functions defined inside quantifiers should be visible in the scope containing the quantifier + // TODO: Turn it into a more generic mechanism in the same vein as Scopable and ScopeOpener if + // it turns out we need more special-casing here. + auto const* quantifier = dynamic_cast(m_currentScope); + auto const* functionDefinition = dynamic_cast(&_declaration); + if (quantifier && functionDefinition) + { + solAssert(quantifier->scope()); + solAssert( + // forall quantifiers cannot be used in block scope so the declaration is always active. + !dynamic_cast(quantifier->scope()) && + !dynamic_cast(quantifier->scope()) + ); - registerDeclaration(*m_scopes[m_currentScope], _declaration, nullptr, nullptr, inactive, m_errorReporter); + // NOTE: We're registering the function outside of its scope(). This will only affect + // name lookups. An more general alternative would be to modify Scoper to simply assign it + // that scope in the first place, but this would complicate the AST traversal here, which + // currently assumes that scopes follow ScopeOpener nesting. + registerDeclaration(*m_scopes.at(quantifier->scope()), _declaration, nullptr, nullptr, false /* inactive */, m_errorReporter); + } + else + { + // Register declaration as inactive if we are in block scope. + bool inactive = + (dynamic_cast(m_currentScope) || dynamic_cast(m_currentScope)); + + registerDeclaration(*m_scopes[m_currentScope], _declaration, nullptr, nullptr, inactive, m_errorReporter); + } solAssert(_declaration.annotation().scope == m_currentScope, ""); solAssert(_declaration.annotation().contract == m_currentContract, ""); diff --git a/libsolidity/experimental/analysis/TypeInference.cpp b/libsolidity/experimental/analysis/TypeInference.cpp index 8625937a35..6913dc0bf7 100644 --- a/libsolidity/experimental/analysis/TypeInference.cpp +++ b/libsolidity/experimental/analysis/TypeInference.cpp @@ -580,9 +580,11 @@ bool TypeInference::visit(Identifier const& _identifier) solAssert(false); break; case ExpressionContext::Type: - // TODO: register free type variable name! + m_errorReporter.typeError(5934_error, _identifier.location(), "Undeclared type variable."); + + // Assign it a fresh variable anyway just so that we can continue analysis. identifierAnnotation.type = m_typeSystem.freshTypeVariable({}); - return false; + break; case ExpressionContext::Sort: // TODO: error handling solAssert(false); diff --git a/test/libsolidity/syntaxTests/experimental/forall/undeclared_type_variable_in_function.sol b/test/libsolidity/syntaxTests/experimental/forall/undeclared_type_variable_in_function.sol new file mode 100644 index 0000000000..da11699691 --- /dev/null +++ b/test/libsolidity/syntaxTests/experimental/forall/undeclared_type_variable_in_function.sol @@ -0,0 +1,17 @@ +pragma experimental solidity; + +type T(X); + +function f(p: P, q: T(Q)) { + let r: (R, S); + let s: S; +} +// ==== +// EVMVersion: >=constantinople +// ---- +// Warning 2264: (0-29): Experimental features are turned on. Do not use experimental features on live deployments. +// TypeError 5934: (57-58): Undeclared type variable. +// TypeError 5934: (65-66): Undeclared type variable. +// TypeError 5934: (83-84): Undeclared type variable. +// TypeError 5934: (86-87): Undeclared type variable. +// TypeError 5934: (101-102): Undeclared type variable. diff --git a/test/libsolidity/syntaxTests/experimental/forall/undeclared_type_variable_in_quantified_function.sol b/test/libsolidity/syntaxTests/experimental/forall/undeclared_type_variable_in_quantified_function.sol new file mode 100644 index 0000000000..91b7345693 --- /dev/null +++ b/test/libsolidity/syntaxTests/experimental/forall/undeclared_type_variable_in_quantified_function.sol @@ -0,0 +1,12 @@ +pragma experimental solidity; + +forall A +function f(b: B) { + let c: C; +} +// ==== +// EVMVersion: >=constantinople +// ---- +// Warning 2264: (0-29): Experimental features are turned on. Do not use experimental features on live deployments. +// TypeError 5934: (54-55): Undeclared type variable. +// TypeError 5934: (70-71): Undeclared type variable. diff --git a/test/libsolidity/syntaxTests/experimental/forall/undeclared_type_variable_in_type_class.sol b/test/libsolidity/syntaxTests/experimental/forall/undeclared_type_variable_in_type_class.sol new file mode 100644 index 0000000000..8af0cce826 --- /dev/null +++ b/test/libsolidity/syntaxTests/experimental/forall/undeclared_type_variable_in_type_class.sol @@ -0,0 +1,17 @@ +pragma experimental solidity; + +type T(X); + +class Self: C { + function f(self: Self); +} + +instantiation T(Y): C { + function f(self: T(Z)) {} +} +// ==== +// EVMVersion: >=constantinople +// ---- +// Warning 2264: (0-29): Experimental features are turned on. Do not use experimental features on live deployments. +// TypeError 5934: (137-138): Undeclared type variable. +// TypeError 7428: (90-145): Instantiation function 'f' does not match the declaration in the type class (T('bc:type) -> () != T('y:type) -> ()). diff --git a/test/libsolidity/syntaxTests/experimental/inference/polymorphic_function_call.sol b/test/libsolidity/syntaxTests/experimental/inference/polymorphic_function_call.sol index c73a857a2f..c9c7e01109 100644 --- a/test/libsolidity/syntaxTests/experimental/inference/polymorphic_function_call.sol +++ b/test/libsolidity/syntaxTests/experimental/inference/polymorphic_function_call.sol @@ -3,6 +3,7 @@ pragma experimental solidity; type T; type U(A); +forall (X, Y) function f(x, y: X, z: U(Y)) {} function run(a: T, b: U(T), c: U(U(T))) { @@ -18,36 +19,39 @@ function run(a: T, b: U(T), c: U(U(T))) { // Info 4164: (39-49): Inferred type: tfun('t:type, U('t:type)) // Info 4164: (45-48): Inferred type: 't:type // Info 4164: (46-47): Inferred type: 't:type -// Info 4164: (51-82): Inferred type: ('w:type, 'x:type, U('z:type)) -> () -// Info 4164: (61-79): Inferred type: ('w:type, 'x:type, U('z:type)) -// Info 4164: (62-63): Inferred type: 'w:type -// Info 4164: (65-69): Inferred type: 'x:type -// Info 4164: (68-69): Inferred type: 'x:type -// Info 4164: (71-78): Inferred type: U('z:type) -// Info 4164: (74-78): Inferred type: U('z:type) -// Info 4164: (74-75): Inferred type: tfun('z:type, U('z:type)) -// Info 4164: (76-77): Inferred type: 'z:type -// Info 4164: (84-159): Inferred type: (T, U(T), U(U(T))) -> () -// Info 4164: (96-123): Inferred type: (T, U(T), U(U(T))) -// Info 4164: (97-101): Inferred type: T -// Info 4164: (100-101): Inferred type: T -// Info 4164: (103-110): Inferred type: U(T) -// Info 4164: (106-110): Inferred type: U(T) -// Info 4164: (106-107): Inferred type: tfun(T, U(T)) -// Info 4164: (108-109): Inferred type: T -// Info 4164: (112-122): Inferred type: U(U(T)) -// Info 4164: (115-122): Inferred type: U(U(T)) -// Info 4164: (115-116): Inferred type: tfun(U(T), U(U(T))) -// Info 4164: (117-121): Inferred type: U(T) -// Info 4164: (117-118): Inferred type: tfun(T, U(T)) -// Info 4164: (119-120): Inferred type: T -// Info 4164: (130-140): Inferred type: () -// Info 4164: (130-131): Inferred type: (T, T, U(T)) -> () -// Info 4164: (132-133): Inferred type: T -// Info 4164: (135-136): Inferred type: T -// Info 4164: (138-139): Inferred type: U(T) -// Info 4164: (146-156): Inferred type: () -// Info 4164: (146-147): Inferred type: (U(T), U(T), U(U(T))) -> () -// Info 4164: (148-149): Inferred type: U(T) -// Info 4164: (151-152): Inferred type: U(T) -// Info 4164: (154-155): Inferred type: U(U(T)) +// Info 4164: (58-64): Inferred type: ('u:type, 'v:type) +// Info 4164: (59-60): Inferred type: 'u:type +// Info 4164: (62-63): Inferred type: 'v:type +// Info 4164: (65-96): Inferred type: ('y:type, 'u:type, U('v:type)) -> () +// Info 4164: (75-93): Inferred type: ('y:type, 'u:type, U('v:type)) +// Info 4164: (76-77): Inferred type: 'y:type +// Info 4164: (79-83): Inferred type: 'u:type +// Info 4164: (82-83): Inferred type: 'u:type +// Info 4164: (85-92): Inferred type: U('v:type) +// Info 4164: (88-92): Inferred type: U('v:type) +// Info 4164: (88-89): Inferred type: tfun('v:type, U('v:type)) +// Info 4164: (90-91): Inferred type: 'v:type +// Info 4164: (98-173): Inferred type: (T, U(T), U(U(T))) -> () +// Info 4164: (110-137): Inferred type: (T, U(T), U(U(T))) +// Info 4164: (111-115): Inferred type: T +// Info 4164: (114-115): Inferred type: T +// Info 4164: (117-124): Inferred type: U(T) +// Info 4164: (120-124): Inferred type: U(T) +// Info 4164: (120-121): Inferred type: tfun(T, U(T)) +// Info 4164: (122-123): Inferred type: T +// Info 4164: (126-136): Inferred type: U(U(T)) +// Info 4164: (129-136): Inferred type: U(U(T)) +// Info 4164: (129-130): Inferred type: tfun(U(T), U(U(T))) +// Info 4164: (131-135): Inferred type: U(T) +// Info 4164: (131-132): Inferred type: tfun(T, U(T)) +// Info 4164: (133-134): Inferred type: T +// Info 4164: (144-154): Inferred type: () +// Info 4164: (144-145): Inferred type: (T, T, U(T)) -> () +// Info 4164: (146-147): Inferred type: T +// Info 4164: (149-150): Inferred type: T +// Info 4164: (152-153): Inferred type: U(T) +// Info 4164: (160-170): Inferred type: () +// Info 4164: (160-161): Inferred type: (U(T), U(T), U(U(T))) -> () +// Info 4164: (162-163): Inferred type: U(T) +// Info 4164: (165-166): Inferred type: U(T) +// Info 4164: (168-169): Inferred type: U(U(T)) diff --git a/test/libsolidity/syntaxTests/experimental/inference/polymorphic_type.sol b/test/libsolidity/syntaxTests/experimental/inference/polymorphic_type.sol index ca83ca2ec7..85f810a9dc 100644 --- a/test/libsolidity/syntaxTests/experimental/inference/polymorphic_type.sol +++ b/test/libsolidity/syntaxTests/experimental/inference/polymorphic_type.sol @@ -7,6 +7,7 @@ type V; class Self: C {} class Self: D {} +forall (X, Y, Z) function run() { let x: T(U, X, Z: C); let y: T(V, Y, Z: D); @@ -27,21 +28,25 @@ function run() { // Info 4164: (71-75): Inferred type: 'k:(type, C) // Info 4164: (82-98): Inferred type: D // Info 4164: (88-92): Inferred type: 'l:(type, D) -// Info 4164: (100-170): Inferred type: () -> () -// Info 4164: (112-114): Inferred type: () -// Info 4164: (125-141): Inferred type: T(U, ?bh:type, ?bj:(type, C)) -// Info 4164: (128-141): Inferred type: T(U, ?bh:type, ?bj:(type, C)) -// Info 4164: (128-129): Inferred type: tfun((U, ?bh:type, ?bj:(type, C)), T(U, ?bh:type, ?bj:(type, C))) -// Info 4164: (130-131): Inferred type: U -// Info 4164: (133-134): Inferred type: ?bh:type -// Info 4164: (136-140): Inferred type: ?bj:(type, C) -// Info 4164: (136-137): Inferred type: ?bj:(type, C) -// Info 4164: (139-140): Inferred type: ?bj:(type, C) -// Info 4164: (151-167): Inferred type: T(V, ?bo:type, ?bq:(type, D)) -// Info 4164: (154-167): Inferred type: T(V, ?bo:type, ?bq:(type, D)) -// Info 4164: (154-155): Inferred type: tfun((V, ?bo:type, ?bq:(type, D)), T(V, ?bo:type, ?bq:(type, D))) -// Info 4164: (156-157): Inferred type: V -// Info 4164: (159-160): Inferred type: ?bo:type -// Info 4164: (162-166): Inferred type: ?bq:(type, D) -// Info 4164: (162-163): Inferred type: ?bq:(type, D) -// Info 4164: (165-166): Inferred type: ?bq:(type, D) +// Info 4164: (107-116): Inferred type: (?bc:type, ?bd:type, ?bq:(type, C, D)) +// Info 4164: (108-109): Inferred type: ?bc:type +// Info 4164: (111-112): Inferred type: ?bd:type +// Info 4164: (114-115): Inferred type: ?bq:(type, C, D) +// Info 4164: (117-187): Inferred type: () -> () +// Info 4164: (129-131): Inferred type: () +// Info 4164: (142-158): Inferred type: T(U, ?bc:type, ?bq:(type, C, D)) +// Info 4164: (145-158): Inferred type: T(U, ?bc:type, ?bq:(type, C, D)) +// Info 4164: (145-146): Inferred type: tfun((U, ?bc:type, ?bq:(type, C, D)), T(U, ?bc:type, ?bq:(type, C, D))) +// Info 4164: (147-148): Inferred type: U +// Info 4164: (150-151): Inferred type: ?bc:type +// Info 4164: (153-157): Inferred type: ?bq:(type, C, D) +// Info 4164: (153-154): Inferred type: ?bq:(type, C, D) +// Info 4164: (156-157): Inferred type: ?bq:(type, C, D) +// Info 4164: (168-184): Inferred type: T(V, ?bd:type, ?bq:(type, C, D)) +// Info 4164: (171-184): Inferred type: T(V, ?bd:type, ?bq:(type, C, D)) +// Info 4164: (171-172): Inferred type: tfun((V, ?bd:type, ?bq:(type, C, D)), T(V, ?bd:type, ?bq:(type, C, D))) +// Info 4164: (173-174): Inferred type: V +// Info 4164: (176-177): Inferred type: ?bd:type +// Info 4164: (179-183): Inferred type: ?bq:(type, C, D) +// Info 4164: (179-180): Inferred type: ?bq:(type, C, D) +// Info 4164: (182-183): Inferred type: ?bq:(type, C, D) diff --git a/test/libsolidity/syntaxTests/experimental/inference/type_variable_multi_use_function_parameter_and_return.sol b/test/libsolidity/syntaxTests/experimental/inference/type_variable_multi_use_function_parameter_and_return.sol new file mode 100644 index 0000000000..00cd7b1207 --- /dev/null +++ b/test/libsolidity/syntaxTests/experimental/inference/type_variable_multi_use_function_parameter_and_return.sol @@ -0,0 +1,16 @@ +pragma experimental solidity; + +type T; +type U; + +forall X +function f(x: X) -> X {} + +function test(t: T, u: U) { + t = f(u); +} +// ==== +// EVMVersion: >=constantinople +// ---- +// Warning 2264: (0-29): Experimental features are turned on. Do not use experimental features on live deployments. +// TypeError 8456: (115-123): Cannot unify T and U. diff --git a/test/libsolidity/syntaxTests/experimental/inference/type_variable_multi_use_function_parameters.sol b/test/libsolidity/syntaxTests/experimental/inference/type_variable_multi_use_function_parameters.sol new file mode 100644 index 0000000000..7122cdd9ef --- /dev/null +++ b/test/libsolidity/syntaxTests/experimental/inference/type_variable_multi_use_function_parameters.sol @@ -0,0 +1,16 @@ +pragma experimental solidity; + +type T; +type U; + +forall X +function f(x: X, y: X) {} + +function test(t: T, u: U) { + f(t, u); +} +// ==== +// EVMVersion: >=constantinople +// ---- +// Warning 2264: (0-29): Experimental features are turned on. Do not use experimental features on live deployments. +// TypeError 8456: (116-123): Cannot unify T and U. From 180f744c434dc6a5fbeb09715e194ab05a30bd88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Mon, 26 Feb 2024 19:44:15 +0100 Subject: [PATCH 52/57] gas_diff_stats.py: Sort the table by average change --- scripts/gas_diff_stats.py | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/scripts/gas_diff_stats.py b/scripts/gas_diff_stats.py index 13d8a59e8d..e593bb9a97 100755 --- a/scripts/gas_diff_stats.py +++ b/scripts/gas_diff_stats.py @@ -116,10 +116,16 @@ def parse_git_diff(fname): return None return collect_statistics(diff_output) - def stat(old, new): - if old == 0: + def percent(old, new): + return (int(new) - int(old)) / int(old) * 100 if int(old) != 0 else None + + def percent_or_zero(old, new): + result = percent(old, new) + return result if result is not None else 0 + + def format_percent(percentage): + if percentage is None: return '' - percentage = (new - old) / old * 100 prefix = ( # Distinguish actual zero from very small differences '+' if round(percentage) == 0 and percentage > 0 else @@ -128,6 +134,9 @@ def stat(old, new): ) return f'{prefix}{round(percentage)}%' + def stat(old, new): + return format_percent(percent(old, new)) + table = [] if not SEMANTIC_TEST_DIR.is_dir(): @@ -138,16 +147,24 @@ def stat(old, new): parsed = parse_git_diff(fname) if parsed is None: continue + assert len(parsed) == 6 ir_optimized = stat(parsed[0], parsed[3]) legacy_optimized = stat(parsed[1], parsed[4]) legacy = stat(parsed[2], parsed[5]) fname = f"`{fname.split('/', 3)[-1]}`" - table += [[fname, ir_optimized, legacy_optimized, legacy]] + average = (( + percent_or_zero(parsed[0], parsed[3]) + + percent_or_zero(parsed[1], parsed[4]) + + percent_or_zero(parsed[2], parsed[5]) + ) / 3) + table += [[average, fname, ir_optimized, legacy_optimized, legacy]] + + sorted_table = [row[1:] for row in sorted(table, reverse=True)] if table: print("
Click for a table of gas differences\n") table_header = ["File name", "IR optimized", "Legacy optimized", "Legacy"] - print(tabulate(sorted(table), headers=table_header, tablefmt="github")) + print(tabulate(sorted_table, headers=table_header, tablefmt="github")) print("
") else: print("No differences found.") From 125767ed17b9a6ab517aaf6ef910b7eaabe82fe0 Mon Sep 17 00:00:00 2001 From: Martin Blicha Date: Tue, 27 Feb 2024 17:21:34 +0100 Subject: [PATCH 53/57] SMTCommand: Remember to flush query before calling solver On MacOS I often experienced a problem that the solver reported SMT-LIB file as malformed. It appears that the whole query was not written to the file and using std::flush fixed the problem. --- Changelog.md | 1 + libsolidity/interface/SMTSolverCommand.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Changelog.md b/Changelog.md index b2ac59c65a..33e2793d5c 100644 --- a/Changelog.md +++ b/Changelog.md @@ -10,6 +10,7 @@ Compiler Features: Bugfixes: * Assembler: Prevent incorrect calculation of tag sizes. * SMTChecker: Fix internal error caused by not respecting the sign of an integer type when constructing zero-value SMT expressions. + * SMTChecker: Ensure query is properly flushed to a file before calling solver when using SMT-LIB interface. ### 0.8.24 (2024-01-25) diff --git a/libsolidity/interface/SMTSolverCommand.cpp b/libsolidity/interface/SMTSolverCommand.cpp index 92e0485b84..d1c58c0c0a 100644 --- a/libsolidity/interface/SMTSolverCommand.cpp +++ b/libsolidity/interface/SMTSolverCommand.cpp @@ -51,7 +51,7 @@ ReadCallback::Result SMTSolverCommand::solve(std::string const& _kind, std::stri auto queryFileName = tempDir.path() / ("query_" + queryHash.hex() + ".smt2"); auto queryFile = boost::filesystem::ofstream(queryFileName); - queryFile << _query; + queryFile << _query << std::flush; auto eldBin = boost::process::search_path(m_solverCmd); From 51eff63222ae7866ebbda2cc280c3291e74ac719 Mon Sep 17 00:00:00 2001 From: ByeongSu Go <107296751+eclipse1228@users.noreply.github.com> Date: Thu, 29 Feb 2024 18:45:48 +0900 Subject: [PATCH 54/57] Update introduction-to-smart-contracts.rst (#14884) --- docs/introduction-to-smart-contracts.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/introduction-to-smart-contracts.rst b/docs/introduction-to-smart-contracts.rst index c4cc1201b0..614cb275d4 100644 --- a/docs/introduction-to-smart-contracts.rst +++ b/docs/introduction-to-smart-contracts.rst @@ -156,7 +156,7 @@ creates a public state variable, but it is a more complex datatype. The :ref:`mapping ` type maps addresses to :ref:`unsigned integers `. Mappings can be seen as `hash tables `_ which are -virtually initialised such that every possible key exists from the start and is mapped to a +virtually initialized such that every possible key exists from the start and is mapped to a value whose byte-representation is all zeros. However, it is neither possible to obtain a list of all keys of a mapping, nor a list of all values. Record what you added to the mapping, or use it in a context where this is not needed. Or From e7aaf03d57e560d29a6c3e7ae631aba7c3fbccf7 Mon Sep 17 00:00:00 2001 From: Vojtch Date: Thu, 29 Feb 2024 10:58:53 +0100 Subject: [PATCH 55/57] docs: Replace references to "mining" with "attestation" (#14147) * docs: fix old wording Updated mining to attestation, but maybe it doesn't even make sense to put it like this. This is for the maintainers to decide but maybe it'd make sense to remove "(which is called "attestation")" altogether and just add a link to more information about LMD-GHOST. * Update docs/introduction-to-smart-contracts.rst --------- Co-authored-by: Vishwa Mehta --- docs/introduction-to-smart-contracts.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/introduction-to-smart-contracts.rst b/docs/introduction-to-smart-contracts.rst index 614cb275d4..3c43e5f193 100644 --- a/docs/introduction-to-smart-contracts.rst +++ b/docs/introduction-to-smart-contracts.rst @@ -304,7 +304,7 @@ These blocks form a linear sequence in time, and that is where the word "blockch Blocks are added to the chain at regular intervals, although these intervals may be subject to change in the future. For the most up-to-date information, it is recommended to monitor the network, for example, on `Etherscan `_. -As part of the "order selection mechanism" (which is called "mining") it may happen that +As part of the "order selection mechanism", which is called `attestation `_, it may happen that blocks are reverted from time to time, but only at the "tip" of the chain. The more blocks are added on top of a particular block, the less likely this block will be reverted. So it might be that your transactions are reverted and even removed from the blockchain, but the longer you wait, the less From 9bd2424cffbd7b21ee37b736c7c339f606bd6667 Mon Sep 17 00:00:00 2001 From: Chomtana Date: Thu, 29 Feb 2024 17:02:31 +0700 Subject: [PATCH 56/57] Fix typos in variable names and comment (#14876) * Fix word determinsm -> determinism * Fix word Optimzation -> Optimization * Fix word affilate -> affiliate * fix: import_base assertion --- libyul/optimiser/StackCompressor.cpp | 6 ++--- test/compilationTests/corion/ico.sol | 22 +++++++++---------- .../smtCheckerTests/imports/import_base.sol | 4 ++-- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/libyul/optimiser/StackCompressor.cpp b/libyul/optimiser/StackCompressor.cpp index 87a5e411c5..58552147a6 100644 --- a/libyul/optimiser/StackCompressor.cpp +++ b/libyul/optimiser/StackCompressor.cpp @@ -253,7 +253,7 @@ bool StackCompressor::run( _optimizeStackAllocation && evmDialect->evmVersion().canOverchargeGasForCall() && evmDialect->providesObjectAccess(); - bool allowMSizeOptimzation = !MSizeFinder::containsMSize(_dialect, *_object.code); + bool allowMSizeOptimization = !MSizeFinder::containsMSize(_dialect, *_object.code); if (usesOptimizedCodeGenerator) { yul::AsmAnalysisInfo analysisInfo = yul::AsmAnalyzer::analyzeStrictAssertCorrect(_dialect, _object); @@ -262,7 +262,7 @@ bool StackCompressor::run( _dialect, *_object.code, StackLayoutGenerator::reportStackTooDeep(*cfg), - allowMSizeOptimzation + allowMSizeOptimization ); } else @@ -275,7 +275,7 @@ bool StackCompressor::run( _dialect, *_object.code, stackSurplus, - allowMSizeOptimzation + allowMSizeOptimization ); } return false; diff --git a/test/compilationTests/corion/ico.sol b/test/compilationTests/corion/ico.sol index 36510ea658..35960fe43a 100644 --- a/test/compilationTests/corion/ico.sol +++ b/test/compilationTests/corion/ico.sol @@ -284,7 +284,7 @@ contract ico is safeMath { require( buy(payable(msg.sender), address(0x00)) ); } - function buy(address payable beneficiaryAddress, address affilateAddress) public payable returns (bool success) { + function buy(address payable beneficiaryAddress, address affiliateAddress) public payable returns (bool success) { /* Buying a token @@ -297,12 +297,12 @@ contract ico is safeMath { More than 1e10 token: 3% More than 1e9 token: 2% below 1% @beneficiaryAddress The address of the accredited where the token will be sent. - @affilateAddress The address of the person who offered who will get the referral reward. It can not be equal with the beneficiaryAddress. + @affiliateAddress The address of the person who offered who will get the referral reward. It can not be equal with the beneficiaryAddress. */ require( isICO() ); if ( beneficiaryAddress == address(0x00)) { beneficiaryAddress = payable(msg.sender); } - if ( beneficiaryAddress == affilateAddress ) { - affilateAddress = address(0x00); + if ( beneficiaryAddress == affiliateAddress ) { + affiliateAddress = address(0x00); } uint256 _value = msg.value; if ( beneficiaryAddress.balance < 0.2 ether ) { @@ -317,9 +317,9 @@ contract ico is safeMath { totalMint = safeAdd(totalMint, _reward); require( foundationAddress.send(_value * 10 / 100) ); uint256 extra; - if ( affilateAddress != address(0x00) && ( brought[affilateAddress].eth > 0 || interestDB[affilateAddress][0].amount > 0 ) ) { - affiliate[affilateAddress].weight = safeAdd(affiliate[affilateAddress].weight, _reward); - extra = affiliate[affilateAddress].weight; + if ( affiliateAddress != address(0x00) && ( brought[affiliateAddress].eth > 0 || interestDB[affiliateAddress][0].amount > 0 ) ) { + affiliate[affiliateAddress].weight = safeAdd(affiliate[affiliateAddress].weight, _reward); + extra = affiliate[affiliateAddress].weight; uint256 rate; if (extra >= 1e12) { rate = 5; @@ -332,12 +332,12 @@ contract ico is safeMath { } else { rate = 1; } - extra = safeSub(extra * rate / 100, affiliate[affilateAddress].paid); - affiliate[affilateAddress].paid = safeAdd(affiliate[affilateAddress].paid, extra); - token(tokenAddr).mint(affilateAddress, extra); + extra = safeSub(extra * rate / 100, affiliate[affiliateAddress].paid); + affiliate[affiliateAddress].paid = safeAdd(affiliate[affiliateAddress].paid, extra); + token(tokenAddr).mint(affiliateAddress, extra); } checkPremium(beneficiaryAddress); - emit EICO(beneficiaryAddress, _reward, affilateAddress, extra); + emit EICO(beneficiaryAddress, _reward, affiliateAddress, extra); return true; } diff --git a/test/libsolidity/smtCheckerTests/imports/import_base.sol b/test/libsolidity/smtCheckerTests/imports/import_base.sol index 3e8aeefe48..fb6ed2ee48 100644 --- a/test/libsolidity/smtCheckerTests/imports/import_base.sol +++ b/test/libsolidity/smtCheckerTests/imports/import_base.sol @@ -12,7 +12,7 @@ contract Base { import "base"; contract Der is Base { function g(uint y) public { - require(x < 10); // added to restrict the search space and avoid non-determinsm in Spacer + require(x < 10); // added to restrict the search space and avoid non-determinism in Spacer x += f(); assert(y > x); } @@ -20,5 +20,5 @@ contract Der is Base { // ==== // SMTEngine: all // ---- -// Warning 6328: (der:173-186): CHC: Assertion violation happens here. +// Warning 6328: (der:174-187): CHC: Assertion violation happens here. // Info 1391: CHC: 2 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them. From 7676ab1014b9fe6bd4314cb648ef790933992e7f Mon Sep 17 00:00:00 2001 From: Aditya Kode <105551807+adityakode@users.noreply.github.com> Date: Thu, 29 Feb 2024 15:38:54 +0530 Subject: [PATCH 57/57] Update natspec-format.rst : Added structs and enums to Tags (#14267) * Update natspec-format.rst * Update docs/natspec-format.rst --------- Co-authored-by: Vishwa Mehta --- docs/natspec-format.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/natspec-format.rst b/docs/natspec-format.rst index 0265fef3e6..f92958b90c 100644 --- a/docs/natspec-format.rst +++ b/docs/natspec-format.rst @@ -115,10 +115,10 @@ in the same way as if it were tagged with ``@notice``. =============== ====================================================================================== ============================= Tag Context =============== ====================================================================================== ============================= -``@title`` A title that should describe the contract/interface contract, library, interface -``@author`` The name of the author contract, library, interface -``@notice`` Explain to an end user what this does contract, library, interface, function, public state variable, event -``@dev`` Explain to a developer any extra details contract, library, interface, function, state variable, event +``@title`` A title that should describe the contract/interface contract, library, interface, struct, enum +``@author`` The name of the author contract, library, interface, struct, enum +``@notice`` Explain to an end user what this does contract, library, interface, function, public state variable, event, struct, enum +``@dev`` Explain to a developer any extra details contract, library, interface, function, state variable, event, struct, enum ``@param`` Documents a parameter just like in Doxygen (must be followed by parameter name) function, event ``@return`` Documents the return variables of a contract's function function, public state variable ``@inheritdoc`` Copies all missing tags from the base function (must be followed by the contract name) function, public state variable