From a19c474d88df5dbb17890c190eba141c08f93517 Mon Sep 17 00:00:00 2001 From: Luis Mastrangelo Date: Tue, 16 Jan 2024 05:03:54 -0300 Subject: [PATCH] Improve Markdown snapshot output and add selfdestruct --- test/__snapshots__/contracts.snap.md | 368 -------------- .../control/bounded-for-loop.snap.md | 471 ++++++++++++++++++ .../contracts/dispatch/pure-functions.snap.md | 339 +++++++++++++ .../contracts/empty/with-no-functions.snap.md | 91 ++++ .../locals/no-dedup-local-var.snap.md | 116 +++++ .../contracts/mappings/public-mapping.snap.md | 418 ++++++++++++++++ .../contracts/system/selfdestruct.snap.md | 89 ++++ test/contracts.test.ts | 203 +++++--- test/contracts/selfdestruct.test.ts | 33 -- 9 files changed, 1657 insertions(+), 471 deletions(-) delete mode 100644 test/__snapshots__/contracts.snap.md create mode 100644 test/__snapshots__/contracts/control/bounded-for-loop.snap.md create mode 100644 test/__snapshots__/contracts/dispatch/pure-functions.snap.md create mode 100644 test/__snapshots__/contracts/empty/with-no-functions.snap.md create mode 100644 test/__snapshots__/contracts/locals/no-dedup-local-var.snap.md create mode 100644 test/__snapshots__/contracts/mappings/public-mapping.snap.md create mode 100644 test/__snapshots__/contracts/system/selfdestruct.snap.md delete mode 100644 test/contracts/selfdestruct.test.ts diff --git a/test/__snapshots__/contracts.snap.md b/test/__snapshots__/contracts.snap.md deleted file mode 100644 index a0e7f5e..0000000 --- a/test/__snapshots__/contracts.snap.md +++ /dev/null @@ -1,368 +0,0 @@ -# ::contracts - -```solidity empty/with-no-functions/match-Solidity-snapshot -// SPDX-License-Identifier: UNLICENSED -// Metadata ipfs://Qmc7NUcdp12QQzhVAMQGPVCLb19V1ifakkLWL7SgvUoYkM -pragma solidity 0.7.6; - -contract Contract { - - fallback() external payable { - revert(); - } - -} - -``` - -```yul empty/with-no-functions/match-Yul-snapshot -object "runtime" { - code { - mstore(0x40, 0x80) - let local0 = 0x0 // #refs 0 - revert(local0, local0) - - } -} - -``` - -```solidity locals/no-dedup-local-variable-with-emit/match-Solidity-snapshot -// SPDX-License-Identifier: UNLICENSED -// Metadata ipfs://QmR3j8ecZd9cGBspFUPWFJMuocmpCatPtfUxyqiCS8K1kB -pragma solidity 0.7.6; - -contract Contract { - - event Deposit(uint256 _arg0); - - fallback() external payable { - uint local0 = block.number; // #refs 1 - emit Deposit(local0); - emit Deposit(local0); - return; - } - -} - -``` - -```yul locals/no-dedup-local-variable-with-emit/match-Yul-snapshot -object "runtime" { - code { - mstore(0x40, 0x80) - let local0 = number() // #refs 1 - let local1 = mload(0x40) // #refs 0 - mstore(local1, local0) - let local2 = mload(0x40) // #refs 0 - log1(local2, sub(add(0x20, local1), local2), 0x4d6ce1e535dbade1c23defba91e23b8f791ce5edc0cc320257a2b364e4e38426) - let local3 = mload(0x40) // #refs 0 - mstore(local3, local0) - let local4 = mload(0x40) // #refs 0 - log1(local4, sub(add(0x20, local3), local4), 0x4d6ce1e535dbade1c23defba91e23b8f791ce5edc0cc320257a2b364e4e38426) - stop() - - } -} - -``` - -```solidity locals/no-dedup-local-variable-with-emit-optimized/match-Solidity-snapshot -// SPDX-License-Identifier: UNLICENSED -// Metadata ipfs://QmSeJbVEgSPm1gJ7wnPsmsSShhZuBgfsjM7qkTsS1SPe1x -pragma solidity 0.7.6; - -contract Contract { - - event Deposit(uint256 _arg0); - - fallback() external payable { - emit Deposit(block.number); - emit Deposit(block.number); - return; - } - -} - -``` - -```yul locals/no-dedup-local-variable-with-emit-optimized/match-Yul-snapshot -object "runtime" { - code { - let local0 = 0x80 // #refs -1 - mstore(0x40, local0) - let local1 = number() // #refs -1 - mstore(local0, local1) - log1(local0, 0x20, 0x4d6ce1e535dbade1c23defba91e23b8f791ce5edc0cc320257a2b364e4e38426) - let local2 = 0x40 // #refs 0 - let local3 = mload(local2) // #refs -1 - mstore(local3, local1) - let local4 = mload(local2) // #refs 0 - log1(local4, add(0x20, sub(local3, local4)), 0x4d6ce1e535dbade1c23defba91e23b8f791ce5edc0cc320257a2b364e4e38426) - stop() - - } -} - -``` - -```solidity dispatch/pure-payable-and-non-payable-functions/match-Solidity-snapshot -// SPDX-License-Identifier: UNLICENSED -// Metadata ipfs://Qmbq3oLNpZcm17Gb7pxnFJnka9fmjwtwMTg5xCnt3E7Xix -pragma solidity 0.7.6; - -contract Contract { - - fallback() external payable { - if (~(msg.data.length < 0x4)) { - undefined local0 = msg.data >>> 0xe0; // #refs 1 - if (msg.sig == 5d2c7ee6) { - $5d2c7ee6(); - } else { - if (msg.sig == 6d4ce63c) { - $6d4ce63c(); - } else { - revert(); - } - } - } - revert(); - } - - function 5d2c7ee6() public payable returns (uint256) { - return 0x1; - } - - function get() public returns (uint256) { - require(msg.value == 0); - return 0x1; - } - -} - -``` - -```yul dispatch/pure-payable-and-non-payable-functions/match-Yul-snapshot -object "runtime" { - code { - mstore(0x40, 0x80) - if (not(lt(calldatasize(), 0x4))) { - let local0 = shr(calldataload(0x0), 0xe0) // #refs 1 - if (eq(msg.sig, 5d2c7ee6)) { - $5d2c7ee6(); - } else { - if (eq(msg.sig, 6d4ce63c)) { - $6d4ce63c(); - } else { - let local1 = 0x0 // #refs 0 - revert(local1, local1) - } - } - } - let local0 = 0x0 // #refs 0 - revert(local0, local0) - - function __$5d2c7ee6(/*unknown*/) { // public payable - let local1 = mload(0x40) // #refs 0 - let local2 = 0x1 // #refs -1 - mstore(local1, local2) - let local3 = mload(0x40) // #refs 0 - return(local3, sub(add(0x20, local1), local3)) // 0x1 - } - - function get() { // public - let local1 = callvalue() // #refs 0 - require(iszero(local1)); - let local2 = mload(0x40) // #refs 0 - let local3 = 0x1 // #refs -1 - mstore(local2, local3) - let local4 = mload(0x40) // #refs 0 - return(local4, sub(add(0x20, local2), local4)) // 0x1 - } - - } -} - -``` - -```solidity dispatch/pure-payable-and-non-payable-functions-optimized/match-Solidity-snapshot -// SPDX-License-Identifier: UNLICENSED -// Metadata ipfs://QmXbZWxxMqei9Rfz17KsZ9b9ei3AtyTbqePnX7jzrQzSPC -pragma solidity 0.7.6; - -contract Contract { - - fallback() external payable { - if (~(msg.data.length < 0x4)) { - undefined local0 = msg.data >>> 0xe0; // #refs 1 - if (msg.sig == 5d2c7ee6) { - $5d2c7ee6(); - } else { - if (msg.sig == 6d4ce63c) { - $6d4ce63c(); - } else { - revert(); - } - } - } - revert(); - } - - function 5d2c7ee6() public payable returns (uint256) { - return 0x1; - } - - function get() public returns (uint256) { - require(msg.value == 0); - return 0x1; - } - -} - -``` - -```yul dispatch/pure-payable-and-non-payable-functions-optimized/match-Yul-snapshot -object "runtime" { - code { - mstore(0x40, 0x80) - if (not(lt(calldatasize(), 0x4))) { - let local0 = shr(calldataload(0x0), 0xe0) // #refs 1 - if (eq(msg.sig, 5d2c7ee6)) { - $5d2c7ee6(); - } else { - if (eq(msg.sig, 6d4ce63c)) { - $6d4ce63c(); - } else { - let local1 = 0x0 // #refs 0 - revert(local1, local1) - } - } - } - let local0 = 0x0 // #refs 0 - revert(local0, local0) - - function __$5d2c7ee6(/*unknown*/) { // public payable - let local1 = 0x40 // #refs 0 - let local2 = mload(local1) // #refs -1 - mstore(local2, 0x1) - let local3 = mload(local1) // #refs 0 - return(local3, add(0x20, sub(local2, local3))) // 0x1 - } - - function get() { // public - let local1 = callvalue() // #refs 0 - require(iszero(local1)); - let local2 = 0x40 // #refs 0 - let local3 = mload(local2) // #refs -1 - mstore(local3, 0x1) - let local4 = mload(local2) // #refs 0 - return(local4, add(0x20, sub(local3, local4))) // 0x1 - } - - } -} - -``` - -```solidity mappings/pure-payable-and-mappings/match-Solidity-snapshot -// SPDX-License-Identifier: UNLICENSED -// Metadata ipfs://QmUE6kHz7hCV1hx6JPpoqaNPVBtTHdG5SdX3erkBwnJc8B -pragma solidity 0.7.6; - -contract Contract { - -mapping (address => mapping (address => unknown)) public allowance; - - fallback() external payable { - require(msg.value == 0); - if (~(msg.data.length < 0x4)) { - undefined local1 = msg.data >>> 0xe0; // #refs 1 - if (msg.sig == 20965255) { - $20965255(); - } else { - if (msg.sig == dd62ed3e) { - $dd62ed3e(); - } else { - revert(); - } - } - } - revert(); - } - - function getValue() public returns (unknown) { - return allowance[msg.sender][msg.sender]; - } - - function allowance(address _arg0, address _arg1) public returns (unknown) { - undefined local2 = 0x4; // #refs 3 - require((msg.data.length - local2 < 0x40) == 0); - return allowance[_arg0][_arg1]; - } - -} - -``` - -```yul mappings/pure-payable-and-mappings/match-Yul-snapshot -object "runtime" { - code { - mstore(0x40, 0x80) - let local0 = callvalue() // #refs 0 - require(iszero(local0)); - if (not(lt(calldatasize(), 0x4))) { - let local1 = shr(calldataload(0x0), 0xe0) // #refs 1 - if (eq(msg.sig, 20965255)) { - $20965255(); - } else { - if (eq(msg.sig, dd62ed3e)) { - $dd62ed3e(); - } else { - let local2 = 0x0 // #refs 0 - revert(local2, local2) - } - } - } - let local1 = 0x0 // #refs 0 - revert(local1, local1) - - function getValue() { // public - let local2 = 0x0 // #refs -1 - let local3 = 0x0 // #refs -1 - mstore(local3, and(0xffffffffffffffffffffffffffffffffffffffff, and(0xffffffffffffffffffffffffffffffffffffffff, caller()))) - let local4 = add(0x20, local3) // #refs -1 - mstore(local4, local2) - let local5 = 0x0 // #refs -1 - mstore(local5, and(0xffffffffffffffffffffffffffffffffffffffff, and(0xffffffffffffffffffffffffffffffffffffffff, caller()))) - let local6 = add(0x20, local5) // #refs -1 - mstore(local6, keccak256(0x0, add(0x20, local4) /*caller().0x0*/)) - let local7 = mload(0x40) // #refs 0 - let local8 = sload(keccak256(0x0, add(0x20, local6) /*caller().keccak256(0x0, add(0x20, local4) /*caller().0x0*/)*/)/*base0[caller()][caller()]*/) // #refs -1 - mstore(local7, local8) - let local9 = mload(0x40) // #refs 0 - return(local9, sub(add(0x20, local7), local9)) // sload(keccak256(0x0, add(0x20, local6) /*caller().keccak256(0x0, add(0x20, local4) /*caller().0x0*/)*/)/*base0[caller()][caller()]*/) - } - - function allowance(address,address) { // public - let local2 = 0x4 // #refs 3 - let local3 = sub(calldatasize(), local2) // #refs 0 - require(iszero(lt(local3, 0x40))); - let local4 = add(0x20, local2) // #refs 0 - mstore(0x20, 0x0) - let local5 = and(0xffffffffffffffffffffffffffffffffffffffff, calldataload(local2)) // #refs -1 - mstore(0x0, local5) - mstore(0x20, keccak256(0x0, 0x40 /*calldataload(0x4).0x0*/)) - let local6 = and(0xffffffffffffffffffffffffffffffffffffffff, calldataload(local4)) // #refs -1 - mstore(0x0, local6) - let local7 = [J]0xbb // #refs 0 - let local8 = mload(0x40) // #refs 0 - let local9 = sload(keccak256(0x0, 0x40 /*calldataload(0x24).keccak256(0x0, 0x40 /*calldataload(0x4).0x0*/)*/)/*base0[calldataload(0x4)][calldataload(0x24)]*/) // #refs -1 - mstore(local8, local9) - let local10 = mload(0x40) // #refs 0 - return(local10, sub(add(0x20, local8), local10)) // sload(keccak256(0x0, 0x40 /*calldataload(0x24).keccak256(0x0, 0x40 /*calldataload(0x4).0x0*/)*/)/*base0[calldataload(0x4)][calldataload(0x24)]*/) - } - - } -} - -``` diff --git a/test/__snapshots__/contracts/control/bounded-for-loop.snap.md b/test/__snapshots__/contracts/control/bounded-for-loop.snap.md new file mode 100644 index 0000000..3a47d4b --- /dev/null +++ b/test/__snapshots__/contracts/control/bounded-for-loop.snap.md @@ -0,0 +1,471 @@ +# contracts/control/bounded for-loop + +```sol -no-opt +// SPDX-License-Identifier: UNLICENSED +// Metadata ipfs://QmYPjcvsjL1MSEMDtdGswmUaxVMuxyeHsfaQgTgbUtUoKo +pragma solidity 0.7.6; + +contract Contract { + +unknown var1__1; // Slot #0 + fallback() external payable { + undefined local0 = 0x0; // #refs 4 + if (~(local0 < block.number) == 0) { + var_1 = local0; + undefined local1 = 0x1 + local0; // #refs 4 + if (~(local1 < block.number) == 0) { + var_1 = local1; + undefined local2 = 0x1 + local1; // #refs 4 + if (~(local2 < block.number) == 0) { + var_1 = local2; + undefined local3 = 0x1 + local2; // #refs 4 + if (~(local3 < block.number) == 0) { + var_1 = local3; + undefined local4 = 0x1 + local3; // #refs 4 + if (~(local4 < block.number) == 0) { + var_1 = local4; + undefined local5 = 0x1 + local4; // #refs 4 + if (~(local5 < block.number) == 0) { + var_1 = local5; + undefined local6 = 0x1 + local5; // #refs 4 + if (~(local6 < block.number) == 0) { + var_1 = local6; + undefined local7 = 0x1 + local6; // #refs 4 + if (~(local7 < block.number) == 0) { + var_1 = local7; + undefined local8 = 0x1 + local7; // #refs 4 + if (~(local8 < block.number) == 0) { + var_1 = local8; + undefined local9 = 0x1 + local8; // #refs 4 + if (~(local9 < block.number) == 0) { + var_1 = local9; + undefined local10 = 0x1 + local9; // #refs 4 + if (~(local10 < block.number) == 0) { + var_1 = local10; + } + return; + } + return; + } + return; + } + return; + } + return; + } + return; + } + return; + } + return; + } + return; + } + return; + } + return; + } + +} + +``` + +```yul -no-opt +object "runtime" { + code { + mstore(0x40, 0x80) + let local0 = 0x0 // #refs 4 + if (not(iszero(lt(local0, number())))) { + sstore(0x0, local0) + let local1 = add(0x1, local0) // #refs 4 + if (not(iszero(lt(local1, number())))) { + sstore(0x0, local1) + let local2 = add(0x1, local1) // #refs 4 + if (not(iszero(lt(local2, number())))) { + sstore(0x0, local2) + let local3 = add(0x1, local2) // #refs 4 + if (not(iszero(lt(local3, number())))) { + sstore(0x0, local3) + let local4 = add(0x1, local3) // #refs 4 + if (not(iszero(lt(local4, number())))) { + sstore(0x0, local4) + let local5 = add(0x1, local4) // #refs 4 + if (not(iszero(lt(local5, number())))) { + sstore(0x0, local5) + let local6 = add(0x1, local5) // #refs 4 + if (not(iszero(lt(local6, number())))) { + sstore(0x0, local6) + let local7 = add(0x1, local6) // #refs 4 + if (not(iszero(lt(local7, number())))) { + sstore(0x0, local7) + let local8 = add(0x1, local7) // #refs 4 + if (not(iszero(lt(local8, number())))) { + sstore(0x0, local8) + let local9 = add(0x1, local8) // #refs 4 + if (not(iszero(lt(local9, number())))) { + sstore(0x0, local9) + let local10 = add(0x1, local9) // #refs 4 + if (not(iszero(lt(local10, number())))) { + sstore(0x0, local10) + } + stop() + } + stop() + } + stop() + } + stop() + } + stop() + } + stop() + } + stop() + } + stop() + } + stop() + } + stop() + } + stop() + + } +} + +``` + +```graphviz -no-opt +digraph G { + color="#efefef"; + graph[fontsize=8]; + + node[shape=box style="rounded,filled" fontsize=9 fontname="Arial" fillcolor="#efefef"]; + + subgraph cluster_0 { + style="filled,rounded"; + label = "pc @0"; + "id-0" [label="pc @0 (id-0)\l=| 0x0\lmemory[0x40] = 0x80;\lfall: 7:\l" fillcolor="#cf91f7"]; + } + + subgraph cluster_7 { + style="filled,rounded"; + label = "pc @7"; + "id-1" [label="pc @7 (id-1)\l=| local0\lundefined local0 = 0x0; // #refs 4\lwhen (local0 < block.number) == 0 goto 33 or fall 15\l" fillcolor="#cf91f7"]; + "id-2" [label="pc @7 (id-2)\l=| local1\lundefined local1 = 0x1 + local0; // #refs 4\lwhen (local1 < block.number) == 0 goto 33 or fall 15\l" fillcolor="#cf91f7"]; + "id-3" [label="pc @7 (id-3)\l=| local2\lundefined local2 = 0x1 + local1; // #refs 4\lwhen (local2 < block.number) == 0 goto 33 or fall 15\l" fillcolor="#cf91f7"]; + "id-4" [label="pc @7 (id-4)\l=| local3\lundefined local3 = 0x1 + local2; // #refs 4\lwhen (local3 < block.number) == 0 goto 33 or fall 15\l" fillcolor="#cf91f7"]; + "id-5" [label="pc @7 (id-5)\l=| local4\lundefined local4 = 0x1 + local3; // #refs 4\lwhen (local4 < block.number) == 0 goto 33 or fall 15\l" fillcolor="#cf91f7"]; + "id-6" [label="pc @7 (id-6)\l=| local5\lundefined local5 = 0x1 + local4; // #refs 4\lwhen (local5 < block.number) == 0 goto 33 or fall 15\l" fillcolor="#cf91f7"]; + "id-7" [label="pc @7 (id-7)\l=| local6\lundefined local6 = 0x1 + local5; // #refs 4\lwhen (local6 < block.number) == 0 goto 33 or fall 15\l" fillcolor="#cf91f7"]; + "id-8" [label="pc @7 (id-8)\l=| local7\lundefined local7 = 0x1 + local6; // #refs 4\lwhen (local7 < block.number) == 0 goto 33 or fall 15\l" fillcolor="#cf91f7"]; + "id-9" [label="pc @7 (id-9)\l=| local8\lundefined local8 = 0x1 + local7; // #refs 4\lwhen (local8 < block.number) == 0 goto 33 or fall 15\l" fillcolor="#cf91f7"]; + "id-10" [label="pc @7 (id-10)\l=| local9\lundefined local9 = 0x1 + local8; // #refs 4\lwhen (local9 < block.number) == 0 goto 33 or fall 15\l" fillcolor="#cf91f7"]; + "id-11" [label="pc @7 (id-11)\l=| local10\lundefined local10 = 0x1 + local9; // #refs 4\lwhen (local10 < block.number) == 0 goto 33 or fall 15\l" fillcolor="#cf91f7"]; + } + + subgraph cluster_15 { + style="filled,rounded"; + label = "pc @15"; + "id-12" [label="pc @15 (id-12)\l=| add(0x1, local0)\lvar_1 = local0;\lgoto :[J]0x7 branch:7\l" fillcolor="#cf91f7"]; + "id-13" [label="pc @15 (id-13)\l=| add(0x1, local1)\lvar_1 = local1;\lgoto :[J]0x7 branch:7\l" fillcolor="#cf91f7"]; + "id-14" [label="pc @15 (id-14)\l=| add(0x1, local2)\lvar_1 = local2;\lgoto :[J]0x7 branch:7\l" fillcolor="#cf91f7"]; + "id-15" [label="pc @15 (id-15)\l=| add(0x1, local3)\lvar_1 = local3;\lgoto :[J]0x7 branch:7\l" fillcolor="#cf91f7"]; + "id-16" [label="pc @15 (id-16)\l=| add(0x1, local4)\lvar_1 = local4;\lgoto :[J]0x7 branch:7\l" fillcolor="#cf91f7"]; + "id-17" [label="pc @15 (id-17)\l=| add(0x1, local5)\lvar_1 = local5;\lgoto :[J]0x7 branch:7\l" fillcolor="#cf91f7"]; + "id-18" [label="pc @15 (id-18)\l=| add(0x1, local6)\lvar_1 = local6;\lgoto :[J]0x7 branch:7\l" fillcolor="#cf91f7"]; + "id-19" [label="pc @15 (id-19)\l=| add(0x1, local7)\lvar_1 = local7;\lgoto :[J]0x7 branch:7\l" fillcolor="#cf91f7"]; + "id-20" [label="pc @15 (id-20)\l=| add(0x1, local8)\lvar_1 = local8;\lgoto :[J]0x7 branch:7\l" fillcolor="#cf91f7"]; + "id-21" [label="pc @15 (id-21)\l=| add(0x1, local9)\lvar_1 = local9;\lgoto :[J]0x7 branch:7\l" fillcolor="#cf91f7"]; + "id-22" [label="pc @15 (id-22)\l=| add(0x1, local10)\lvar_1 = local10;\lgoto :[J]0x7 branch:7\l" fillcolor="#cf91f7"]; + } + + subgraph cluster_33 { + style="filled,rounded"; + label = "pc @33"; + "id-23" [label="pc @33 (id-23)\l=| \lreturn;\l" fillcolor="#cf91f7"]; + "id-24" [label="pc @33 (id-24)\l=| \lreturn;\l" fillcolor="#cf91f7"]; + "id-25" [label="pc @33 (id-25)\l=| \lreturn;\l" fillcolor="#cf91f7"]; + "id-26" [label="pc @33 (id-26)\l=| \lreturn;\l" fillcolor="#cf91f7"]; + "id-27" [label="pc @33 (id-27)\l=| \lreturn;\l" fillcolor="#cf91f7"]; + "id-28" [label="pc @33 (id-28)\l=| \lreturn;\l" fillcolor="#cf91f7"]; + "id-29" [label="pc @33 (id-29)\l=| \lreturn;\l" fillcolor="#cf91f7"]; + "id-30" [label="pc @33 (id-30)\l=| \lreturn;\l" fillcolor="#cf91f7"]; + "id-31" [label="pc @33 (id-31)\l=| \lreturn;\l" fillcolor="#cf91f7"]; + "id-32" [label="pc @33 (id-32)\l=| \lreturn;\l" fillcolor="#cf91f7"]; + "id-33" [label="pc @33 (id-33)\l=| \lreturn;\l" fillcolor="#cf91f7"]; + } + + "id-0" -> "id-1"; + "id-1" -> "id-33"; + "id-1" -> "id-12"; + "id-2" -> "id-32"; + "id-2" -> "id-13"; + "id-3" -> "id-31"; + "id-3" -> "id-14"; + "id-4" -> "id-30"; + "id-4" -> "id-15"; + "id-5" -> "id-29"; + "id-5" -> "id-16"; + "id-6" -> "id-28"; + "id-6" -> "id-17"; + "id-7" -> "id-27"; + "id-7" -> "id-18"; + "id-8" -> "id-26"; + "id-8" -> "id-19"; + "id-9" -> "id-25"; + "id-9" -> "id-20"; + "id-10" -> "id-24"; + "id-10" -> "id-21"; + "id-11" -> "id-23"; + "id-11" -> "id-22"; + "id-12" -> "id-2"; + "id-13" -> "id-3"; + "id-14" -> "id-4"; + "id-15" -> "id-5"; + "id-16" -> "id-6"; + "id-17" -> "id-7"; + "id-18" -> "id-8"; + "id-19" -> "id-9"; + "id-20" -> "id-10"; + "id-21" -> "id-11"; + "id-22" -> "undefined"; + +} + +``` + +```sol -opt +// SPDX-License-Identifier: UNLICENSED +// Metadata ipfs://QmNeUP433KicpZd6iGR1rFCCUNQkYqaFR684J4LNiJSuaL +pragma solidity 0.7.6; + +contract Contract { + +unknown var1__1; // Slot #0 + fallback() external payable { + undefined local0 = 0x0; // #refs 1 + if (~(local0 < block.number) == 0) { + var_1 = local0; + undefined local1 = 0x1 + local0; // #refs 1 + if (~(local1 < block.number) == 0) { + var_1 = local1; + undefined local2 = 0x1 + local1; // #refs 1 + if (~(local2 < block.number) == 0) { + var_1 = local2; + undefined local3 = 0x1 + local2; // #refs 1 + if (~(local3 < block.number) == 0) { + var_1 = local3; + undefined local4 = 0x1 + local3; // #refs 1 + if (~(local4 < block.number) == 0) { + var_1 = local4; + undefined local5 = 0x1 + local4; // #refs 1 + if (~(local5 < block.number) == 0) { + var_1 = local5; + undefined local6 = 0x1 + local5; // #refs 1 + if (~(local6 < block.number) == 0) { + var_1 = local6; + undefined local7 = 0x1 + local6; // #refs 1 + if (~(local7 < block.number) == 0) { + var_1 = local7; + undefined local8 = 0x1 + local7; // #refs 1 + if (~(local8 < block.number) == 0) { + var_1 = local8; + undefined local9 = 0x1 + local8; // #refs 1 + if (~(local9 < block.number) == 0) { + var_1 = local9; + undefined local10 = 0x1 + local9; // #refs 1 + if (~(local10 < block.number) == 0) { + var_1 = local10; + } + return; + } + return; + } + return; + } + return; + } + return; + } + return; + } + return; + } + return; + } + return; + } + return; + } + return; + } + +} + +``` + +```yul -opt +object "runtime" { + code { + mstore(0x40, 0x80) + let local0 = 0x0 // #refs 1 + if (not(iszero(lt(local0, number())))) { + sstore(0x0, local0) + let local1 = add(0x1, local0) // #refs 1 + if (not(iszero(lt(local1, number())))) { + sstore(0x0, local1) + let local2 = add(0x1, local1) // #refs 1 + if (not(iszero(lt(local2, number())))) { + sstore(0x0, local2) + let local3 = add(0x1, local2) // #refs 1 + if (not(iszero(lt(local3, number())))) { + sstore(0x0, local3) + let local4 = add(0x1, local3) // #refs 1 + if (not(iszero(lt(local4, number())))) { + sstore(0x0, local4) + let local5 = add(0x1, local4) // #refs 1 + if (not(iszero(lt(local5, number())))) { + sstore(0x0, local5) + let local6 = add(0x1, local5) // #refs 1 + if (not(iszero(lt(local6, number())))) { + sstore(0x0, local6) + let local7 = add(0x1, local6) // #refs 1 + if (not(iszero(lt(local7, number())))) { + sstore(0x0, local7) + let local8 = add(0x1, local7) // #refs 1 + if (not(iszero(lt(local8, number())))) { + sstore(0x0, local8) + let local9 = add(0x1, local8) // #refs 1 + if (not(iszero(lt(local9, number())))) { + sstore(0x0, local9) + let local10 = add(0x1, local9) // #refs 1 + if (not(iszero(lt(local10, number())))) { + sstore(0x0, local10) + } + stop() + } + stop() + } + stop() + } + stop() + } + stop() + } + stop() + } + stop() + } + stop() + } + stop() + } + stop() + } + stop() + + } +} + +``` + +```graphviz -opt +digraph G { + color="#efefef"; + graph[fontsize=8]; + + node[shape=box style="rounded,filled" fontsize=9 fontname="Arial" fillcolor="#efefef"]; + + subgraph cluster_0 { + style="filled,rounded"; + label = "pc @0"; + "id-0" [label="pc @0 (id-0)\l=| 0x0\lmemory[0x40] = 0x80;\lfall: 7:\l" fillcolor="#cf91f7"]; + } + + subgraph cluster_7 { + style="filled,rounded"; + label = "pc @7"; + "id-1" [label="pc @7 (id-1)\l=| local0\lundefined local0 = 0x0; // #refs 1\lwhen (local0 < block.number) == 0 goto 26 or fall 15\l" fillcolor="#cf91f7"]; + "id-2" [label="pc @7 (id-2)\l=| local1\lundefined local1 = 0x1 + local0; // #refs 1\lwhen (local1 < block.number) == 0 goto 26 or fall 15\l" fillcolor="#cf91f7"]; + "id-3" [label="pc @7 (id-3)\l=| local2\lundefined local2 = 0x1 + local1; // #refs 1\lwhen (local2 < block.number) == 0 goto 26 or fall 15\l" fillcolor="#cf91f7"]; + "id-4" [label="pc @7 (id-4)\l=| local3\lundefined local3 = 0x1 + local2; // #refs 1\lwhen (local3 < block.number) == 0 goto 26 or fall 15\l" fillcolor="#cf91f7"]; + "id-5" [label="pc @7 (id-5)\l=| local4\lundefined local4 = 0x1 + local3; // #refs 1\lwhen (local4 < block.number) == 0 goto 26 or fall 15\l" fillcolor="#cf91f7"]; + "id-6" [label="pc @7 (id-6)\l=| local5\lundefined local5 = 0x1 + local4; // #refs 1\lwhen (local5 < block.number) == 0 goto 26 or fall 15\l" fillcolor="#cf91f7"]; + "id-7" [label="pc @7 (id-7)\l=| local6\lundefined local6 = 0x1 + local5; // #refs 1\lwhen (local6 < block.number) == 0 goto 26 or fall 15\l" fillcolor="#cf91f7"]; + "id-8" [label="pc @7 (id-8)\l=| local7\lundefined local7 = 0x1 + local6; // #refs 1\lwhen (local7 < block.number) == 0 goto 26 or fall 15\l" fillcolor="#cf91f7"]; + "id-9" [label="pc @7 (id-9)\l=| local8\lundefined local8 = 0x1 + local7; // #refs 1\lwhen (local8 < block.number) == 0 goto 26 or fall 15\l" fillcolor="#cf91f7"]; + "id-10" [label="pc @7 (id-10)\l=| local9\lundefined local9 = 0x1 + local8; // #refs 1\lwhen (local9 < block.number) == 0 goto 26 or fall 15\l" fillcolor="#cf91f7"]; + "id-11" [label="pc @7 (id-11)\l=| local10\lundefined local10 = 0x1 + local9; // #refs 1\lwhen (local10 < block.number) == 0 goto 26 or fall 15\l" fillcolor="#cf91f7"]; + } + + subgraph cluster_15 { + style="filled,rounded"; + label = "pc @15"; + "id-12" [label="pc @15 (id-12)\l=| add(0x1, local0)\lvar_1 = local0;\lgoto :[J]0x7 branch:7\l" fillcolor="#cf91f7"]; + "id-13" [label="pc @15 (id-13)\l=| add(0x1, local1)\lvar_1 = local1;\lgoto :[J]0x7 branch:7\l" fillcolor="#cf91f7"]; + "id-14" [label="pc @15 (id-14)\l=| add(0x1, local2)\lvar_1 = local2;\lgoto :[J]0x7 branch:7\l" fillcolor="#cf91f7"]; + "id-15" [label="pc @15 (id-15)\l=| add(0x1, local3)\lvar_1 = local3;\lgoto :[J]0x7 branch:7\l" fillcolor="#cf91f7"]; + "id-16" [label="pc @15 (id-16)\l=| add(0x1, local4)\lvar_1 = local4;\lgoto :[J]0x7 branch:7\l" fillcolor="#cf91f7"]; + "id-17" [label="pc @15 (id-17)\l=| add(0x1, local5)\lvar_1 = local5;\lgoto :[J]0x7 branch:7\l" fillcolor="#cf91f7"]; + "id-18" [label="pc @15 (id-18)\l=| add(0x1, local6)\lvar_1 = local6;\lgoto :[J]0x7 branch:7\l" fillcolor="#cf91f7"]; + "id-19" [label="pc @15 (id-19)\l=| add(0x1, local7)\lvar_1 = local7;\lgoto :[J]0x7 branch:7\l" fillcolor="#cf91f7"]; + "id-20" [label="pc @15 (id-20)\l=| add(0x1, local8)\lvar_1 = local8;\lgoto :[J]0x7 branch:7\l" fillcolor="#cf91f7"]; + "id-21" [label="pc @15 (id-21)\l=| add(0x1, local9)\lvar_1 = local9;\lgoto :[J]0x7 branch:7\l" fillcolor="#cf91f7"]; + "id-22" [label="pc @15 (id-22)\l=| add(0x1, local10)\lvar_1 = local10;\lgoto :[J]0x7 branch:7\l" fillcolor="#cf91f7"]; + } + + subgraph cluster_26 { + style="filled,rounded"; + label = "pc @26"; + "id-23" [label="pc @26 (id-23)\l=| \lreturn;\l" fillcolor="#cf91f7"]; + "id-24" [label="pc @26 (id-24)\l=| \lreturn;\l" fillcolor="#cf91f7"]; + "id-25" [label="pc @26 (id-25)\l=| \lreturn;\l" fillcolor="#cf91f7"]; + "id-26" [label="pc @26 (id-26)\l=| \lreturn;\l" fillcolor="#cf91f7"]; + "id-27" [label="pc @26 (id-27)\l=| \lreturn;\l" fillcolor="#cf91f7"]; + "id-28" [label="pc @26 (id-28)\l=| \lreturn;\l" fillcolor="#cf91f7"]; + "id-29" [label="pc @26 (id-29)\l=| \lreturn;\l" fillcolor="#cf91f7"]; + "id-30" [label="pc @26 (id-30)\l=| \lreturn;\l" fillcolor="#cf91f7"]; + "id-31" [label="pc @26 (id-31)\l=| \lreturn;\l" fillcolor="#cf91f7"]; + "id-32" [label="pc @26 (id-32)\l=| \lreturn;\l" fillcolor="#cf91f7"]; + "id-33" [label="pc @26 (id-33)\l=| \lreturn;\l" fillcolor="#cf91f7"]; + } + + "id-0" -> "id-1"; + "id-1" -> "id-33"; + "id-1" -> "id-12"; + "id-2" -> "id-32"; + "id-2" -> "id-13"; + "id-3" -> "id-31"; + "id-3" -> "id-14"; + "id-4" -> "id-30"; + "id-4" -> "id-15"; + "id-5" -> "id-29"; + "id-5" -> "id-16"; + "id-6" -> "id-28"; + "id-6" -> "id-17"; + "id-7" -> "id-27"; + "id-7" -> "id-18"; + "id-8" -> "id-26"; + "id-8" -> "id-19"; + "id-9" -> "id-25"; + "id-9" -> "id-20"; + "id-10" -> "id-24"; + "id-10" -> "id-21"; + "id-11" -> "id-23"; + "id-11" -> "id-22"; + "id-12" -> "id-2"; + "id-13" -> "id-3"; + "id-14" -> "id-4"; + "id-15" -> "id-5"; + "id-16" -> "id-6"; + "id-17" -> "id-7"; + "id-18" -> "id-8"; + "id-19" -> "id-9"; + "id-20" -> "id-10"; + "id-21" -> "id-11"; + "id-22" -> "undefined"; + +} + +``` diff --git a/test/__snapshots__/contracts/dispatch/pure-functions.snap.md b/test/__snapshots__/contracts/dispatch/pure-functions.snap.md new file mode 100644 index 0000000..d406b8e --- /dev/null +++ b/test/__snapshots__/contracts/dispatch/pure-functions.snap.md @@ -0,0 +1,339 @@ +# contracts/dispatch/pure functions + +```sol -no-opt +// SPDX-License-Identifier: UNLICENSED +// Metadata ipfs://QmRHsusWvnMjnuZciCkG6nDhuk1MKuqDGqGjTaJKWZu36c +pragma solidity 0.7.6; + +contract Contract { + + fallback() external payable { + if (~(msg.data.length < 0x4)) { + undefined local0 = msg.data >>> 0xe0; // #refs 1 + if (msg.sig == 5d2c7ee6) { + $5d2c7ee6(); + } else { + if (msg.sig == 6d4ce63c) { + $6d4ce63c(); + } else { + revert(); + } + } + } + revert(); + } + + function 5d2c7ee6() public payable returns (uint256) { + return 0x1; + } + + function get() public returns (uint256) { + require(msg.value == 0); + return 0x1; + } + +} + +``` + +```yul -no-opt +object "runtime" { + code { + mstore(0x40, 0x80) + if (not(lt(calldatasize(), 0x4))) { + let local0 = shr(calldataload(0x0), 0xe0) // #refs 1 + if (eq(msg.sig, 5d2c7ee6)) { + $5d2c7ee6(); + } else { + if (eq(msg.sig, 6d4ce63c)) { + $6d4ce63c(); + } else { + let local1 = 0x0 // #refs 0 + revert(local1, local1) + } + } + } + let local0 = 0x0 // #refs 0 + revert(local0, local0) + + function __$5d2c7ee6(/*unknown*/) { // public payable + let local1 = mload(0x40) // #refs 0 + let local2 = 0x1 // #refs -1 + mstore(local1, local2) + let local3 = mload(0x40) // #refs 0 + return(local3, sub(add(0x20, local1), local3)) // 0x1 + } + + function get() { // public + let local1 = callvalue() // #refs 0 + require(iszero(local1)); + let local2 = mload(0x40) // #refs 0 + let local3 = 0x1 // #refs -1 + mstore(local2, local3) + let local4 = mload(0x40) // #refs 0 + return(local4, sub(add(0x20, local2), local4)) // 0x1 + } + + } +} + +``` + +```graphviz -no-opt +digraph G { + color="#efefef"; + graph[fontsize=8]; + + node[shape=box style="rounded,filled" fontsize=9 fontname="Arial" fillcolor="#efefef"]; + + subgraph cluster_0 { + style="filled,rounded"; + label = "pc @0"; + "id-0" [label="pc @0 (id-0)\l=| \lmemory[0x40] = 0x80;\lwhen msg.data.length < 0x4 goto 38 or fall 12\l" fillcolor="#cf91f7"]; + } + + subgraph cluster_12 { + style="filled,rounded"; + label = "pc @12"; + "id-1" [label="pc @12 (id-1)\l=| local0\lundefined local0 = msg.data >>> 0xe0; // #refs 1\lcase when msg.sig == 5d2c7ee6 goto [J]0x2b or fall 28\l" fillcolor="#cf91f7"]; + } + + subgraph cluster_28 { + style="filled,rounded"; + label = "pc @28"; + "id-2" [label="pc @28 (id-2)\l=| local0\lcase when msg.sig == 6d4ce63c goto [J]0x47 or fall 38\l" fillcolor="#cf91f7"]; + } + + subgraph cluster_38 { + style="filled,rounded"; + label = "pc @38"; + "id-3" [label="pc @38 (id-3)\l=| local0\lundefined local1 = 0x0; // #refs 0\lrevert();\l" fillcolor="#cf91f7"]; + "id-4" [label="pc @38 (id-4)\l=| \lundefined local0 = 0x0; // #refs 0\lrevert();\l" fillcolor="#cf91f7"]; + } + + subgraph cluster_43 { + style="filled,rounded"; + label = "pc @43"; + "id-5" [label="pc @43 (id-5)\l=| [J]0x31|local0\lgoto :[J]0x6f branch:111\l" fillcolor="#cf91f7"]; + } + + subgraph cluster_111 { + style="filled,rounded"; + label = "pc @111"; + "id-6" [label="pc @111 (id-6)\l=| 0x1|local0\lgoto :[J]0x31 branch:49\l" fillcolor="#cf91f7"]; + } + + subgraph cluster_49 { + style="filled,rounded"; + label = "pc @49"; + "id-7" [label="pc @49 (id-7)\l=| local0\lundefined local1 = memory[0x40]; // #refs 0\lundefined local2 = 0x1; // #refs -1\lmemory[memory[0x40]] = 0x1;\lundefined local3 = memory[0x40]; // #refs 0\lreturn 0x1;\l" fillcolor="#cf91f7"]; + } + + subgraph cluster_71 { + style="filled,rounded"; + label = "pc @71"; + "id-8" [label="pc @71 (id-8)\l=| local1|local0\lundefined local1 = msg.value; // #refs 0\lwhen msg.value == 0 goto 82 or fall 78\l" fillcolor="#cf91f7"]; + } + + subgraph cluster_78 { + style="filled,rounded"; + label = "pc @78"; + "id-9" [label="pc @78 (id-9)\l=| local1|local0\lundefined local2 = 0x0; // #refs 0\lrevert();\l" fillcolor="#cf91f7"]; + } + + subgraph cluster_82 { + style="filled,rounded"; + label = "pc @82"; + "id-10" [label="pc @82 (id-10)\l=| [J]0x59|local0\lgoto :[J]0x78 branch:120\l" fillcolor="#cf91f7"]; + } + + subgraph cluster_120 { + style="filled,rounded"; + label = "pc @120"; + "id-11" [label="pc @120 (id-11)\l=| 0x1|local0\lgoto :[J]0x59 branch:89\l" fillcolor="#cf91f7"]; + } + + subgraph cluster_89 { + style="filled,rounded"; + label = "pc @89"; + "id-12" [label="pc @89 (id-12)\l=| local0\lundefined local2 = memory[0x40]; // #refs 0\lundefined local3 = 0x1; // #refs -1\lmemory[memory[0x40]] = 0x1;\lundefined local4 = memory[0x40]; // #refs 0\lreturn 0x1;\l" fillcolor="#cf91f7"]; + } + + "id-0" -> "id-4"; + "id-0" -> "id-1"; + "id-1" -> "id-2"; + "id-2" -> "id-3"; + "id-5" -> "id-6"; + "id-6" -> "id-7"; + "id-8" -> "id-10"; + "id-8" -> "id-9"; + "id-10" -> "id-11"; + "id-11" -> "id-12"; + +} + +``` + +```sol -opt +// SPDX-License-Identifier: UNLICENSED +// Metadata ipfs://QmageuWBk2AFaFebYDj6s8YjF6CWqQrsJ3FVvzXcJwQwsN +pragma solidity 0.7.6; + +contract Contract { + + fallback() external payable { + if (~(msg.data.length < 0x4)) { + undefined local0 = msg.data >>> 0xe0; // #refs 1 + if (msg.sig == 5d2c7ee6) { + $5d2c7ee6(); + } else { + if (msg.sig == 6d4ce63c) { + $6d4ce63c(); + } else { + revert(); + } + } + } + revert(); + } + + function 5d2c7ee6() public payable returns (uint256) { + return 0x1; + } + + function get() public returns (uint256) { + require(msg.value == 0); + return 0x1; + } + +} + +``` + +```yul -opt +object "runtime" { + code { + mstore(0x40, 0x80) + if (not(lt(calldatasize(), 0x4))) { + let local0 = shr(calldataload(0x0), 0xe0) // #refs 1 + if (eq(msg.sig, 5d2c7ee6)) { + $5d2c7ee6(); + } else { + if (eq(msg.sig, 6d4ce63c)) { + $6d4ce63c(); + } else { + let local1 = 0x0 // #refs 0 + revert(local1, local1) + } + } + } + let local0 = 0x0 // #refs 0 + revert(local0, local0) + + function __$5d2c7ee6(/*unknown*/) { // public payable + let local1 = 0x40 // #refs 0 + let local2 = mload(local1) // #refs -1 + mstore(local2, 0x1) + let local3 = mload(local1) // #refs 0 + return(local3, add(0x20, sub(local2, local3))) // 0x1 + } + + function get() { // public + let local1 = callvalue() // #refs 0 + require(iszero(local1)); + let local2 = 0x40 // #refs 0 + let local3 = mload(local2) // #refs -1 + mstore(local3, 0x1) + let local4 = mload(local2) // #refs 0 + return(local4, add(0x20, sub(local3, local4))) // 0x1 + } + + } +} + +``` + +```graphviz -opt +digraph G { + color="#efefef"; + graph[fontsize=8]; + + node[shape=box style="rounded,filled" fontsize=9 fontname="Arial" fillcolor="#efefef"]; + + subgraph cluster_0 { + style="filled,rounded"; + label = "pc @0"; + "id-0" [label="pc @0 (id-0)\l=| \lmemory[0x40] = 0x80;\lwhen msg.data.length < 0x4 goto 38 or fall 12\l" fillcolor="#cf91f7"]; + } + + subgraph cluster_12 { + style="filled,rounded"; + label = "pc @12"; + "id-1" [label="pc @12 (id-1)\l=| local0\lundefined local0 = msg.data >>> 0xe0; // #refs 1\lcase when msg.sig == 5d2c7ee6 goto [J]0x2b or fall 28\l" fillcolor="#cf91f7"]; + } + + subgraph cluster_28 { + style="filled,rounded"; + label = "pc @28"; + "id-2" [label="pc @28 (id-2)\l=| local0\lcase when msg.sig == 6d4ce63c goto [J]0x43 or fall 38\l" fillcolor="#cf91f7"]; + } + + subgraph cluster_38 { + style="filled,rounded"; + label = "pc @38"; + "id-3" [label="pc @38 (id-3)\l=| local0\lundefined local1 = 0x0; // #refs 0\lrevert();\l" fillcolor="#cf91f7"]; + "id-4" [label="pc @38 (id-4)\l=| \lundefined local0 = 0x0; // #refs 0\lrevert();\l" fillcolor="#cf91f7"]; + } + + subgraph cluster_43 { + style="filled,rounded"; + label = "pc @43"; + "id-5" [label="pc @43 (id-5)\l=| [J]0x31|local0\lgoto :[J]0x52 branch:82\l" fillcolor="#cf91f7"]; + } + + subgraph cluster_82 { + style="filled,rounded"; + label = "pc @82"; + "id-6" [label="pc @82 (id-6)\l=| 0x1|local0\lgoto :[J]0x31 branch:49\l" fillcolor="#cf91f7"]; + "id-7" [label="pc @82 (id-7)\l=| 0x1|local0\lgoto :[J]0x31 branch:49\l" fillcolor="#cf91f7"]; + } + + subgraph cluster_49 { + style="filled,rounded"; + label = "pc @49"; + "id-8" [label="pc @49 (id-8)\l=| local0\lundefined local1 = 0x40; // #refs 0\lundefined local2 = memory[0x40]; // #refs -1\lmemory[memory[0x40]] = 0x1;\lundefined local3 = memory[0x40]; // #refs 0\lreturn 0x1;\l" fillcolor="#cf91f7"]; + "id-9" [label="pc @49 (id-9)\l=| local0\lundefined local2 = 0x40; // #refs 0\lundefined local3 = memory[0x40]; // #refs -1\lmemory[memory[0x40]] = 0x1;\lundefined local4 = memory[0x40]; // #refs 0\lreturn 0x1;\l" fillcolor="#cf91f7"]; + } + + subgraph cluster_67 { + style="filled,rounded"; + label = "pc @67"; + "id-10" [label="pc @67 (id-10)\l=| local1|local0\lundefined local1 = msg.value; // #refs 0\lwhen msg.value == 0 goto 78 or fall 74\l" fillcolor="#cf91f7"]; + } + + subgraph cluster_74 { + style="filled,rounded"; + label = "pc @74"; + "id-11" [label="pc @74 (id-11)\l=| local1|local0\lundefined local2 = 0x0; // #refs 0\lrevert();\l" fillcolor="#cf91f7"]; + } + + subgraph cluster_78 { + style="filled,rounded"; + label = "pc @78"; + "id-12" [label="pc @78 (id-12)\l=| [J]0x31|local0\lfall: 82:\l" fillcolor="#cf91f7"]; + } + + "id-0" -> "id-4"; + "id-0" -> "id-1"; + "id-1" -> "id-2"; + "id-2" -> "id-3"; + "id-5" -> "id-6"; + "id-6" -> "id-8"; + "id-7" -> "id-9"; + "id-10" -> "id-12"; + "id-10" -> "id-11"; + "id-12" -> "id-7"; + +} + +``` diff --git a/test/__snapshots__/contracts/empty/with-no-functions.snap.md b/test/__snapshots__/contracts/empty/with-no-functions.snap.md new file mode 100644 index 0000000..a7bf48f --- /dev/null +++ b/test/__snapshots__/contracts/empty/with-no-functions.snap.md @@ -0,0 +1,91 @@ +# contracts/empty/with no functions + +```sol -no-opt +// SPDX-License-Identifier: UNLICENSED +// Metadata ipfs://Qmc7NUcdp12QQzhVAMQGPVCLb19V1ifakkLWL7SgvUoYkM +pragma solidity 0.7.6; + +contract Contract { + + fallback() external payable { + revert(); + } + +} + +``` + +```yul -no-opt +object "runtime" { + code { + mstore(0x40, 0x80) + let local0 = 0x0 // #refs 0 + revert(local0, local0) + + } +} + +``` + +```graphviz -no-opt +digraph G { + color="#efefef"; + graph[fontsize=8]; + + node[shape=box style="rounded,filled" fontsize=9 fontname="Arial" fillcolor="#efefef"]; + + subgraph cluster_0 { + style="filled,rounded"; + label = "pc @0"; + "id-0" [label="pc @0 (id-0)\l=| \lmemory[0x40] = 0x80;\lundefined local0 = 0x0; // #refs 0\lrevert();\l" fillcolor="#cf91f7"]; + } + + +} + +``` + +```sol -opt +// SPDX-License-Identifier: UNLICENSED +// Metadata ipfs://QmbfibgUvdfkZYGTTwQsEqWF8srkJCoMFMsMyAjFSmGw4S +pragma solidity 0.7.6; + +contract Contract { + + fallback() external payable { + revert(); + } + +} + +``` + +```yul -opt +object "runtime" { + code { + mstore(0x40, 0x80) + let local0 = 0x0 // #refs 0 + revert(local0, local0) + + } +} + +``` + +```graphviz -opt +digraph G { + color="#efefef"; + graph[fontsize=8]; + + node[shape=box style="rounded,filled" fontsize=9 fontname="Arial" fillcolor="#efefef"]; + + subgraph cluster_0 { + style="filled,rounded"; + label = "pc @0"; + "id-0" [label="pc @0 (id-0)\l=| \lmemory[0x40] = 0x80;\lundefined local0 = 0x0; // #refs 0\lrevert();\l" fillcolor="#cf91f7"]; + } + + +} + +``` diff --git a/test/__snapshots__/contracts/locals/no-dedup-local-var.snap.md b/test/__snapshots__/contracts/locals/no-dedup-local-var.snap.md new file mode 100644 index 0000000..53ebae7 --- /dev/null +++ b/test/__snapshots__/contracts/locals/no-dedup-local-var.snap.md @@ -0,0 +1,116 @@ +# contracts/locals/no dedup local var + +```sol -no-opt +// SPDX-License-Identifier: UNLICENSED +// Metadata ipfs://QmdxVs9n72jjdRhjvXStBXyiNMuCfWRoVywqnGpYnKhWJk +pragma solidity 0.7.6; + +contract Contract { + + event Deposit(uint256 _arg0); + + fallback() external payable { + uint local0 = block.number; // #refs 1 + emit Deposit(local0); + emit Deposit(local0); + return; + } + +} + +``` + +```yul -no-opt +object "runtime" { + code { + mstore(0x40, 0x80) + let local0 = number() // #refs 1 + let local1 = mload(0x40) // #refs 0 + mstore(local1, local0) + let local2 = mload(0x40) // #refs 0 + log1(local2, sub(add(0x20, local1), local2), 0x4d6ce1e535dbade1c23defba91e23b8f791ce5edc0cc320257a2b364e4e38426) + let local3 = mload(0x40) // #refs 0 + mstore(local3, local0) + let local4 = mload(0x40) // #refs 0 + log1(local4, sub(add(0x20, local3), local4), 0x4d6ce1e535dbade1c23defba91e23b8f791ce5edc0cc320257a2b364e4e38426) + stop() + + } +} + +``` + +```graphviz -no-opt +digraph G { + color="#efefef"; + graph[fontsize=8]; + + node[shape=box style="rounded,filled" fontsize=9 fontname="Arial" fillcolor="#efefef"]; + + subgraph cluster_0 { + style="filled,rounded"; + label = "pc @0"; + "id-0" [label="pc @0 (id-0)\l=| \lmemory[0x40] = 0x80;\luint local0 = block.number; // #refs 1\lundefined local1 = memory[0x40]; // #refs 0\lmemory[memory[0x40]] = local0;\lundefined local2 = memory[0x40]; // #refs 0\lemit Deposit(local0);\lundefined local3 = memory[0x40]; // #refs 0\lmemory[memory[0x40]] = local0;\lundefined local4 = memory[0x40]; // #refs 0\lemit Deposit(local0);\lreturn;\l" fillcolor="#cf91f7"]; + } + + +} + +``` + +```sol -opt +// SPDX-License-Identifier: UNLICENSED +// Metadata ipfs://QmQpUm3Zy5qLKhkS9KA8Sad6yUjZTvVB1adauVq2p1qxac +pragma solidity 0.7.6; + +contract Contract { + + event Deposit(uint256 _arg0); + + fallback() external payable { + emit Deposit(block.number); + emit Deposit(block.number); + return; + } + +} + +``` + +```yul -opt +object "runtime" { + code { + let local0 = 0x80 // #refs -1 + mstore(0x40, local0) + let local1 = number() // #refs -1 + mstore(local0, local1) + log1(local0, 0x20, 0x4d6ce1e535dbade1c23defba91e23b8f791ce5edc0cc320257a2b364e4e38426) + let local2 = 0x40 // #refs 0 + let local3 = mload(local2) // #refs -1 + mstore(local3, local1) + let local4 = mload(local2) // #refs 0 + log1(local4, add(0x20, sub(local3, local4)), 0x4d6ce1e535dbade1c23defba91e23b8f791ce5edc0cc320257a2b364e4e38426) + stop() + + } +} + +``` + +```graphviz -opt +digraph G { + color="#efefef"; + graph[fontsize=8]; + + node[shape=box style="rounded,filled" fontsize=9 fontname="Arial" fillcolor="#efefef"]; + + subgraph cluster_0 { + style="filled,rounded"; + label = "pc @0"; + "id-0" [label="pc @0 (id-0)\l=| \lundefined local0 = 0x80; // #refs -1\lmemory[0x40] = 0x80;\luint local1 = block.number; // #refs -1\lmemory[0x80] = block.number;\lemit Deposit(block.number);\lundefined local2 = 0x40; // #refs 0\lundefined local3 = memory[0x40]; // #refs -1\lmemory[memory[0x40]] = block.number;\lundefined local4 = memory[0x40]; // #refs 0\lemit Deposit(block.number);\lreturn;\l" fillcolor="#cf91f7"]; + } + + +} + +``` diff --git a/test/__snapshots__/contracts/mappings/public-mapping.snap.md b/test/__snapshots__/contracts/mappings/public-mapping.snap.md new file mode 100644 index 0000000..8ece345 --- /dev/null +++ b/test/__snapshots__/contracts/mappings/public-mapping.snap.md @@ -0,0 +1,418 @@ +# contracts/mappings/public mapping + +```sol -no-opt +// SPDX-License-Identifier: UNLICENSED +// Metadata ipfs://QmXUabbCeD7Lv8du5q45dZYekx8Qw9ACfgCuRRaMifyEU8 +pragma solidity 0.7.6; + +contract Contract { + +mapping (address => mapping (address => unknown)) public allowance; + + fallback() external payable { + require(msg.value == 0); + if (~(msg.data.length < 0x4)) { + undefined local1 = msg.data >>> 0xe0; // #refs 1 + if (msg.sig == 20965255) { + $20965255(); + } else { + if (msg.sig == dd62ed3e) { + $dd62ed3e(); + } else { + revert(); + } + } + } + revert(); + } + + function getValue() public returns (unknown) { + return allowance[msg.sender][msg.sender]; + } + + function allowance(address _arg0, address _arg1) public returns (unknown) { + undefined local2 = 0x4; // #refs 3 + require((msg.data.length - local2 < 0x40) == 0); + return allowance[_arg0][_arg1]; + } + +} + +``` + +```yul -no-opt +object "runtime" { + code { + mstore(0x40, 0x80) + let local0 = callvalue() // #refs 0 + require(iszero(local0)); + if (not(lt(calldatasize(), 0x4))) { + let local1 = shr(calldataload(0x0), 0xe0) // #refs 1 + if (eq(msg.sig, 20965255)) { + $20965255(); + } else { + if (eq(msg.sig, dd62ed3e)) { + $dd62ed3e(); + } else { + let local2 = 0x0 // #refs 0 + revert(local2, local2) + } + } + } + let local1 = 0x0 // #refs 0 + revert(local1, local1) + + function getValue() { // public + let local2 = 0x0 // #refs -1 + let local3 = 0x0 // #refs -1 + mstore(local3, and(0xffffffffffffffffffffffffffffffffffffffff, and(0xffffffffffffffffffffffffffffffffffffffff, caller()))) + let local4 = add(0x20, local3) // #refs -1 + mstore(local4, local2) + let local5 = 0x0 // #refs -1 + mstore(local5, and(0xffffffffffffffffffffffffffffffffffffffff, and(0xffffffffffffffffffffffffffffffffffffffff, caller()))) + let local6 = add(0x20, local5) // #refs -1 + mstore(local6, keccak256(0x0, add(0x20, local4) /*caller().0x0*/)) + let local7 = mload(0x40) // #refs 0 + let local8 = sload(keccak256(0x0, add(0x20, local6) /*caller().keccak256(0x0, add(0x20, local4) /*caller().0x0*/)*/)/*base0[caller()][caller()]*/) // #refs -1 + mstore(local7, local8) + let local9 = mload(0x40) // #refs 0 + return(local9, sub(add(0x20, local7), local9)) // sload(keccak256(0x0, add(0x20, local6) /*caller().keccak256(0x0, add(0x20, local4) /*caller().0x0*/)*/)/*base0[caller()][caller()]*/) + } + + function allowance(address,address) { // public + let local2 = 0x4 // #refs 3 + let local3 = sub(calldatasize(), local2) // #refs 0 + require(iszero(lt(local3, 0x40))); + let local4 = add(0x20, local2) // #refs 0 + mstore(0x20, 0x0) + let local5 = and(0xffffffffffffffffffffffffffffffffffffffff, calldataload(local2)) // #refs -1 + mstore(0x0, local5) + mstore(0x20, keccak256(0x0, 0x40 /*calldataload(0x4).0x0*/)) + let local6 = and(0xffffffffffffffffffffffffffffffffffffffff, calldataload(local4)) // #refs -1 + mstore(0x0, local6) + let local7 = [J]0xbb // #refs 0 + let local8 = mload(0x40) // #refs 0 + let local9 = sload(keccak256(0x0, 0x40 /*calldataload(0x24).keccak256(0x0, 0x40 /*calldataload(0x4).0x0*/)*/)/*base0[calldataload(0x4)][calldataload(0x24)]*/) // #refs -1 + mstore(local8, local9) + let local10 = mload(0x40) // #refs 0 + return(local10, sub(add(0x20, local8), local10)) // sload(keccak256(0x0, 0x40 /*calldataload(0x24).keccak256(0x0, 0x40 /*calldataload(0x4).0x0*/)*/)/*base0[calldataload(0x4)][calldataload(0x24)]*/) + } + + } +} + +``` + +```graphviz -no-opt +digraph G { + color="#efefef"; + graph[fontsize=8]; + + node[shape=box style="rounded,filled" fontsize=9 fontname="Arial" fillcolor="#efefef"]; + + subgraph cluster_0 { + style="filled,rounded"; + label = "pc @0"; + "id-0" [label="pc @0 (id-0)\l=| local0\lmemory[0x40] = 0x80;\lundefined local0 = msg.value; // #refs 0\lwhen msg.value == 0 goto 16 or fall 12\l" fillcolor="#cf91f7"]; + } + + subgraph cluster_12 { + style="filled,rounded"; + label = "pc @12"; + "id-1" [label="pc @12 (id-1)\l=| local0\lundefined local1 = 0x0; // #refs 0\lrevert();\l" fillcolor="#cf91f7"]; + } + + subgraph cluster_16 { + style="filled,rounded"; + label = "pc @16"; + "id-2" [label="pc @16 (id-2)\l=| \lwhen msg.data.length < 0x4 goto 54 or fall 26\l" fillcolor="#cf91f7"]; + } + + subgraph cluster_26 { + style="filled,rounded"; + label = "pc @26"; + "id-3" [label="pc @26 (id-3)\l=| local1\lundefined local1 = msg.data >>> 0xe0; // #refs 1\lcase when msg.sig == 20965255 goto [J]0x3b or fall 43\l" fillcolor="#cf91f7"]; + } + + subgraph cluster_43 { + style="filled,rounded"; + label = "pc @43"; + "id-4" [label="pc @43 (id-4)\l=| local1\lcase when msg.sig == dd62ed3e goto [J]0x59 or fall 54\l" fillcolor="#cf91f7"]; + } + + subgraph cluster_54 { + style="filled,rounded"; + label = "pc @54"; + "id-5" [label="pc @54 (id-5)\l=| local1\lundefined local2 = 0x0; // #refs 0\lrevert();\l" fillcolor="#cf91f7"]; + "id-6" [label="pc @54 (id-6)\l=| \lundefined local1 = 0x0; // #refs 0\lrevert();\l" fillcolor="#cf91f7"]; + } + + subgraph cluster_59 { + style="filled,rounded"; + label = "pc @59"; + "id-7" [label="pc @59 (id-7)\l=| [J]0x43|local1\lgoto :[J]0xd1 branch:209\l" fillcolor="#cf91f7"]; + } + + subgraph cluster_209 { + style="filled,rounded"; + label = "pc @209"; + "id-8" [label="pc @209 (id-8)\l=| sload(keccak256(0x0, add(0x20, local6) /*caller().keccak256(0x0, add(0x20, local4) /*caller().0x0*/)*/)/*base0[caller()][caller()]*/)|local1\lundefined local2 = 0x0; // #refs -1\lundefined local3 = 0x0; // #refs -1\lmemory[0x0] = 0xffffffffffffffffffffffffffffffffffffffff & 0xffffffffffffffffffffffffffffffffffffffff & msg.sender;\lundefined local4 = 0x20 + 0x0; // #refs -1\lmemory[0x20 + 0x0] = 0x0;\lundefined local5 = 0x0; // #refs -1\lmemory[0x0] = 0xffffffffffffffffffffffffffffffffffffffff & 0xffffffffffffffffffffffffffffffffffffffff & msg.sender;\lundefined local6 = 0x20 + 0x0; // #refs -1\lmemory[0x20 + 0x0] = keccak256(msg.sender, 0x0);\lgoto :[J]0x43 branch:67\l" fillcolor="#cf91f7"]; + } + + subgraph cluster_67 { + style="filled,rounded"; + label = "pc @67"; + "id-9" [label="pc @67 (id-9)\l=| local1\lundefined local7 = memory[0x40]; // #refs 0\lundefined local8 = allowance[msg.sender][msg.sender]; // #refs -1\lmemory[memory[0x40]] = allowance[msg.sender][msg.sender];\lundefined local9 = memory[0x40]; // #refs 0\lreturn allowance[msg.sender][msg.sender];\l" fillcolor="#cf91f7"]; + } + + subgraph cluster_89 { + style="filled,rounded"; + label = "pc @89"; + "id-10" [label="pc @89 (id-10)\l=| local3|local2|[J]0xbb|local1\lundefined local2 = 0x4; // #refs 3\lundefined local3 = msg.data.length - local2; // #refs 0\lwhen (msg.data.length - local2 < 0x40) == 0 goto 111 or fall 107\l" fillcolor="#cf91f7"]; + } + + subgraph cluster_107 { + style="filled,rounded"; + label = "pc @107"; + "id-11" [label="pc @107 (id-11)\l=| local3|local2|[J]0xbb|local1\lundefined local4 = 0x0; // #refs 0\lrevert();\l" fillcolor="#cf91f7"]; + } + + subgraph cluster_111 { + style="filled,rounded"; + label = "pc @111"; + "id-12" [label="pc @111 (id-12)\l=| and(0xffffffffffffffffffffffffffffffffffffffff, calldataload(local4))|and(0xffffffffffffffffffffffffffffffffffffffff, calldataload(local2))|[J]0xbb|local1\lundefined local4 = 0x20 + local2; // #refs 0\lgoto :[J]0x154 branch:340\l" fillcolor="#cf91f7"]; + } + + subgraph cluster_340 { + style="filled,rounded"; + label = "pc @340"; + "id-13" [label="pc @340 (id-13)\l=| sload(keccak256(0x0, 0x40 /*calldataload(0x24).keccak256(0x0, 0x40 /*calldataload(0x4).0x0*/)*/)/*base0[calldataload(0x4)][calldataload(0x24)]*/)|local7|local1\lmemory[0x20] = 0x0;\lundefined local5 = 0xffffffffffffffffffffffffffffffffffffffff & msg.data[local2]; // #refs -1\lmemory[0x0] = 0xffffffffffffffffffffffffffffffffffffffff & msg.data[local2];\lmemory[0x20] = keccak256(_arg0, 0x0);\lundefined local6 = 0xffffffffffffffffffffffffffffffffffffffff & msg.data[0x20 + local2]; // #refs -1\lmemory[0x0] = 0xffffffffffffffffffffffffffffffffffffffff & msg.data[0x20 + local2];\lundefined local7 = [J]0xbb; // #refs 0\lgoto :[J]0xbb branch:187\l" fillcolor="#cf91f7"]; + } + + subgraph cluster_187 { + style="filled,rounded"; + label = "pc @187"; + "id-14" [label="pc @187 (id-14)\l=| local7|local1\lundefined local8 = memory[0x40]; // #refs 0\lundefined local9 = allowance[_arg0][_arg1]; // #refs -1\lmemory[memory[0x40]] = allowance[_arg0][_arg1];\lundefined local10 = memory[0x40]; // #refs 0\lreturn allowance[_arg0][_arg1];\l" fillcolor="#cf91f7"]; + } + + "id-0" -> "id-2"; + "id-0" -> "id-1"; + "id-2" -> "id-6"; + "id-2" -> "id-3"; + "id-3" -> "id-4"; + "id-4" -> "id-5"; + "id-7" -> "id-8"; + "id-8" -> "id-9"; + "id-10" -> "id-12"; + "id-10" -> "id-11"; + "id-12" -> "id-13"; + "id-13" -> "id-14"; + +} + +``` + +```sol -opt +// SPDX-License-Identifier: UNLICENSED +// Metadata ipfs://QmSrjZkbwKtEg7uMhwXX3nW2nesTsmJYYH2ns4jkXWmEqs +pragma solidity 0.7.6; + +contract Contract { + +mapping (address => mapping (address => unknown)) public allowance; + + fallback() external payable { + require(msg.value == 0); + if (~(msg.data.length < 0x4)) { + undefined local1 = msg.data >>> 0xe0; // #refs 1 + if (msg.sig == 20965255) { + $20965255(); + } else { + if (msg.sig == dd62ed3e) { + $dd62ed3e(); + } else { + revert(); + } + } + } + revert(); + } + + function getValue() public returns (unknown) { + return allowance[msg.sender][msg.sender]; + } + + function allowance(address _arg0, address _arg1) public returns (unknown) { + undefined local2 = 0x4; // #refs 1 + require((msg.data.length - local2 < 0x40) == 0); + return allowance[_arg0][_arg1]; + } + +} + +``` + +```yul -opt +object "runtime" { + code { + mstore(0x40, 0x80) + let local0 = callvalue() // #refs 0 + require(iszero(local0)); + if (not(lt(calldatasize(), 0x4))) { + let local1 = shr(calldataload(0x0), 0xe0) // #refs 1 + if (eq(msg.sig, 20965255)) { + $20965255(); + } else { + if (eq(msg.sig, dd62ed3e)) { + $dd62ed3e(); + } else { + let local2 = 0x0 // #refs 0 + revert(local2, local2) + } + } + } + let local1 = 0x0 // #refs 0 + revert(local1, local1) + + function getValue() { // public + let local2 = 0x0 // #refs 0 + mstore(local2, caller()) + let local3 = 0x20 // #refs -2 + mstore(local3, local2) + let local4 = 0x40 // #refs 0 + mstore(local3, keccak256(local2, local4 /*caller().0x0*/)) + let local5 = 0x40 // #refs 0 + let local6 = mload(local5) // #refs -1 + mstore(local6, sload(keccak256(local2, local4 /*caller().keccak256(local2, local4 /*caller().0x0*/)*/)/*base0[caller()][caller()]*/)) + let local7 = mload(local5) // #refs 0 + return(local7, add(0x20, sub(local6, local7))) // sload(keccak256(local2, local4 /*caller().keccak256(local2, local4 /*caller().0x0*/)*/)/*base0[caller()][caller()]*/) + } + + function allowance(address,address) { // public + let local2 = 0x4 // #refs 1 + let local3 = sub(calldatasize(), local2) // #refs 0 + require(iszero(lt(local3, 0x40))); + let local4 = sub(shl(0x1, 0xa0), 0x1) // #refs 0 + let local5 = 0x0 // #refs 0 + let local6 = 0x20 // #refs -2 + mstore(local6, local5) + mstore(local5, and(local4, calldataload(local2))) + let local7 = 0x40 // #refs 0 + mstore(local6, keccak256(local5, local7 /*calldataload(0x4).0x0*/)) + mstore(local5, and(calldataload(add(0x20, local2)), local4)) + let local8 = [J]0x3d // #refs 0 + let local9 = 0x40 // #refs 0 + let local10 = mload(local9) // #refs -1 + mstore(local10, sload(keccak256(local5, local7 /*calldataload(0x24).keccak256(local5, local7 /*calldataload(0x4).0x0*/)*/)/*base0[calldataload(0x4)][calldataload(0x24)]*/)) + let local11 = mload(local9) // #refs 0 + return(local11, add(0x20, sub(local10, local11))) // sload(keccak256(local5, local7 /*calldataload(0x24).keccak256(local5, local7 /*calldataload(0x4).0x0*/)*/)/*base0[calldataload(0x4)][calldataload(0x24)]*/) + } + + } +} + +``` + +```graphviz -opt +digraph G { + color="#efefef"; + graph[fontsize=8]; + + node[shape=box style="rounded,filled" fontsize=9 fontname="Arial" fillcolor="#efefef"]; + + subgraph cluster_0 { + style="filled,rounded"; + label = "pc @0"; + "id-0" [label="pc @0 (id-0)\l=| local0\lmemory[0x40] = 0x80;\lundefined local0 = msg.value; // #refs 0\lwhen msg.value == 0 goto 15 or fall 11\l" fillcolor="#cf91f7"]; + } + + subgraph cluster_11 { + style="filled,rounded"; + label = "pc @11"; + "id-1" [label="pc @11 (id-1)\l=| local0\lundefined local1 = 0x0; // #refs 0\lrevert();\l" fillcolor="#cf91f7"]; + } + + subgraph cluster_15 { + style="filled,rounded"; + label = "pc @15"; + "id-2" [label="pc @15 (id-2)\l=| \lwhen msg.data.length < 0x4 goto 50 or fall 24\l" fillcolor="#cf91f7"]; + } + + subgraph cluster_24 { + style="filled,rounded"; + label = "pc @24"; + "id-3" [label="pc @24 (id-3)\l=| local1\lundefined local1 = msg.data >>> 0xe0; // #refs 1\lcase when msg.sig == 20965255 goto [J]0x37 or fall 40\l" fillcolor="#cf91f7"]; + } + + subgraph cluster_40 { + style="filled,rounded"; + label = "pc @40"; + "id-4" [label="pc @40 (id-4)\l=| local1\lcase when msg.sig == dd62ed3e goto [J]0x4f or fall 50\l" fillcolor="#cf91f7"]; + } + + subgraph cluster_50 { + style="filled,rounded"; + label = "pc @50"; + "id-5" [label="pc @50 (id-5)\l=| local1\lundefined local2 = 0x0; // #refs 0\lrevert();\l" fillcolor="#cf91f7"]; + "id-6" [label="pc @50 (id-6)\l=| \lundefined local1 = 0x0; // #refs 0\lrevert();\l" fillcolor="#cf91f7"]; + } + + subgraph cluster_55 { + style="filled,rounded"; + label = "pc @55"; + "id-7" [label="pc @55 (id-7)\l=| [J]0x3d|local1\lgoto :[J]0x7a branch:122\l" fillcolor="#cf91f7"]; + } + + subgraph cluster_122 { + style="filled,rounded"; + label = "pc @122"; + "id-8" [label="pc @122 (id-8)\l=| sload(keccak256(local2, local4 /*caller().keccak256(local2, local4 /*caller().0x0*/)*/)/*base0[caller()][caller()]*/)|local1\lundefined local2 = 0x0; // #refs 0\lmemory[0x0] = msg.sender;\lundefined local3 = 0x20; // #refs -2\lmemory[0x20] = 0x0;\lundefined local4 = 0x40; // #refs 0\lmemory[0x20] = keccak256(msg.sender, 0x0);\lgoto :[J]0x3d branch:61\l" fillcolor="#cf91f7"]; + } + + subgraph cluster_61 { + style="filled,rounded"; + label = "pc @61"; + "id-9" [label="pc @61 (id-9)\l=| local1\lundefined local5 = 0x40; // #refs 0\lundefined local6 = memory[0x40]; // #refs -1\lmemory[memory[0x40]] = allowance[msg.sender][msg.sender];\lundefined local7 = memory[0x40]; // #refs 0\lreturn allowance[msg.sender][msg.sender];\l" fillcolor="#cf91f7"]; + "id-10" [label="pc @61 (id-10)\l=| local8|local1\lundefined local9 = 0x40; // #refs 0\lundefined local10 = memory[0x40]; // #refs -1\lmemory[memory[0x40]] = allowance[_arg0][_arg1];\lundefined local11 = memory[0x40]; // #refs 0\lreturn allowance[_arg0][_arg1];\l" fillcolor="#cf91f7"]; + } + + subgraph cluster_79 { + style="filled,rounded"; + label = "pc @79"; + "id-11" [label="pc @79 (id-11)\l=| local3|local2|[J]0x3d|local1\lundefined local2 = 0x4; // #refs 1\lundefined local3 = msg.data.length - local2; // #refs 0\lwhen (msg.data.length - local2 < 0x40) == 0 goto 99 or fall 95\l" fillcolor="#cf91f7"]; + } + + subgraph cluster_95 { + style="filled,rounded"; + label = "pc @95"; + "id-12" [label="pc @95 (id-12)\l=| local3|local2|[J]0x3d|local1\lundefined local4 = 0x0; // #refs 0\lrevert();\l" fillcolor="#cf91f7"]; + } + + subgraph cluster_99 { + style="filled,rounded"; + label = "pc @99"; + "id-13" [label="pc @99 (id-13)\l=| and(calldataload(add(0x20, local2)), local4)|and(local4, calldataload(local2))|[J]0x3d|local1\lundefined local4 = (0x1 << 0xa0) - 0x1; // #refs 0\lgoto :[J]0x93 branch:147\l" fillcolor="#cf91f7"]; + } + + subgraph cluster_147 { + style="filled,rounded"; + label = "pc @147"; + "id-14" [label="pc @147 (id-14)\l=| sload(keccak256(local5, local7 /*calldataload(0x24).keccak256(local5, local7 /*calldataload(0x4).0x0*/)*/)/*base0[calldataload(0x4)][calldataload(0x24)]*/)|local8|local1\lundefined local5 = 0x0; // #refs 0\lundefined local6 = 0x20; // #refs -2\lmemory[0x20] = 0x0;\lmemory[0x0] = (0x1 << 0xa0) - 0x1 & msg.data[local2];\lundefined local7 = 0x40; // #refs 0\lmemory[0x20] = keccak256(_arg0, 0x0);\lmemory[0x0] = msg.data[0x20 + local2] & (0x1 << 0xa0) - 0x1;\lundefined local8 = [J]0x3d; // #refs 0\lgoto :[J]0x3d branch:61\l" fillcolor="#cf91f7"]; + } + + "id-0" -> "id-2"; + "id-0" -> "id-1"; + "id-2" -> "id-6"; + "id-2" -> "id-3"; + "id-3" -> "id-4"; + "id-4" -> "id-5"; + "id-7" -> "id-8"; + "id-8" -> "id-9"; + "id-11" -> "id-13"; + "id-11" -> "id-12"; + "id-13" -> "id-14"; + "id-14" -> "id-10"; + +} + +``` diff --git a/test/__snapshots__/contracts/system/selfdestruct.snap.md b/test/__snapshots__/contracts/system/selfdestruct.snap.md new file mode 100644 index 0000000..c6faed0 --- /dev/null +++ b/test/__snapshots__/contracts/system/selfdestruct.snap.md @@ -0,0 +1,89 @@ +# contracts/system/selfdestruct + +```sol -no-opt +// SPDX-License-Identifier: UNLICENSED +// Metadata ipfs://QmVxFdWfLZNK7URjamqvyzq2oL29wiXKHQ9VVPnLgu5xoG +pragma solidity 0.7.6; + +contract Contract { + + fallback() external payable { + selfdestruct(0xffffffffffffffffffffffffffffffffffffffff & msg.sender); + } + +} + +``` + +```yul -no-opt +object "runtime" { + code { + mstore(0x40, 0x80) + selfdestruct(and(0xffffffffffffffffffffffffffffffffffffffff, caller())) + + } +} + +``` + +```graphviz -no-opt +digraph G { + color="#efefef"; + graph[fontsize=8]; + + node[shape=box style="rounded,filled" fontsize=9 fontname="Arial" fillcolor="#efefef"]; + + subgraph cluster_0 { + style="filled,rounded"; + label = "pc @0"; + "id-0" [label="pc @0 (id-0)\l=| \lmemory[0x40] = 0x80;\lselfdestruct(0xffffffffffffffffffffffffffffffffffffffff & msg.sender);\l" fillcolor="#cf91f7"]; + } + + +} + +``` + +```sol -opt +// SPDX-License-Identifier: UNLICENSED +// Metadata ipfs://QmTYoyy7D6orDPjDivuJFhPvSFdRUnpJnq7jYhSE61Nsot +pragma solidity 0.7.6; + +contract Contract { + + fallback() external payable { + selfdestruct(msg.sender); + } + +} + +``` + +```yul -opt +object "runtime" { + code { + mstore(0x40, 0x80) + selfdestruct(caller()) + + } +} + +``` + +```graphviz -opt +digraph G { + color="#efefef"; + graph[fontsize=8]; + + node[shape=box style="rounded,filled" fontsize=9 fontname="Arial" fillcolor="#efefef"]; + + subgraph cluster_0 { + style="filled,rounded"; + label = "pc @0"; + "id-0" [label="pc @0 (id-0)\l=| \lmemory[0x40] = 0x80;\lselfdestruct(msg.sender);\l" fillcolor="#cf91f7"]; + } + + +} + +``` diff --git a/test/contracts.test.ts b/test/contracts.test.ts index f819896..171100a 100644 --- a/test/contracts.test.ts +++ b/test/contracts.test.ts @@ -1,97 +1,160 @@ +import { strict as assert } from 'assert'; import { expect } from 'chai'; -import { Contract } from 'sevm'; +import { Contract, sol, yul, type State } from 'sevm'; +import type { Branch, Expr, Inst } from 'sevm/ast'; import { compile } from './utils/solc'; describe('::contracts', function () { + const t = (title: string, src: string, options?: Parameters[3]) => + ({ title, src, options }); - Object.entries<{ - title: string, - src: string, - options?: Parameters[3], - }[] - >({ + Object.entries<{ title: string, src: string }[]>({ empty: [ - { - title: 'with no functions', - src: `contract Test { }`, - }, + t('with no functions', `contract Test { }`), ], locals: [ - { - title: 'no dedup local variable with emit', - src: `contract Test { - event Deposit(uint256); - fallback () external payable { - uint256 n = block.number; - emit Deposit(n); - emit Deposit(n); - } - }` - }, - { - title: 'no dedup local variable with emit optimized', - src: `contract Test { - event Deposit(uint256); - fallback () external payable { - uint256 n = block.number; - emit Deposit(n); - emit Deposit(n); - } - }`, - options: { optimizer: { enabled: true } }, - } + t('no dedup local var', `contract Test { + event Deposit(uint256); + fallback () external payable { + uint256 n = block.number; + emit Deposit(n); + emit Deposit(n); + } + }`), ], dispatch: [ - { - title: 'pure payable and non-payable functions', - src: `contract Test { - function get() external pure returns (uint256) { return 1; } - function getPayable() external payable returns (uint256) { return 1; } - }`, - }, - { - title: 'pure payable and non-payable functions optimized', - src: `contract Test { - function get() external pure returns (uint256) { return 1; } - function getPayable() external payable returns (uint256) { return 1; } - }`, - options: { optimizer: { enabled: true } }, - }, + t('pure functions', `contract Test { + function get() external pure returns (uint256) { return 1; } + function getPayable() external payable returns (uint256) { return 1; } + }`), ], mappings: [ - { - title: 'pure payable and mappings', - src: `contract Test { - mapping (address => mapping (address => uint256)) public allowance; - function getValue() external view returns (uint256) { - return allowance[msg.sender][msg.sender]; - } - }`, - }, + t('public mapping', `contract Test { + mapping (address => mapping (address => uint256)) public allowance; + function getValue() external view returns (uint256) { + return allowance[msg.sender][msg.sender]; + } + }`), + ], + control: [ + t('bounded for-loop', `contract Test { + uint256 value; + fallback() external payable { + for (uint256 i = 0; i < block.number; i++) value = i; + } + }`), + ], + system: [ + t('selfdestruct', `contract Test { + fallback() external payable { + selfdestruct(payable(msg.sender)); + } + }`), ], }).forEach(([name, contracts]) => { describe(name, function () { - contracts.forEach(({ title, src, options }) => { + contracts.forEach(({ title, src }) => { + [undefined, { optimizer: { enabled: true } }].forEach(options => { + const root = `contracts/${name}/${title}`; + const suffix = options === undefined ? '-no-opt' : '-opt'; - describe(title, function () { - let contract: Contract; + describe(title + suffix, function () { + let contract: Contract; - before(function () { - contract = new Contract(compile(src, '0.7.6', this, options).bytecode).patch(); - }); + before(function () { + contract = new Contract(compile(src, '0.7.6', this, options).bytecode).patch(); + }); - it(`should match Solidity snapshot`, function () { - expect(contract.solidify()).to.matchSnapshot('solidity', this); - }); + it(`should match Solidity snapshot`, function () { + expect(contract.solidify()).to.matchSnapshot('sol', this, [root, suffix]); + }); - it(`should match Yul snapshot`, function () { - expect(contract.yul()).to.matchSnapshot('yul', this); + it(`should match Yul snapshot`, function () { + expect(contract.yul()).to.matchSnapshot('yul', this, [root, suffix]); + }); + + it(`should match CFG snapshot`, function () { + expect(cfgdot(contract)).to.matchSnapshot('graphviz', this, [root, suffix]); + }); }); }); }); }); }); - }); + +function cfgdot(evm: Contract) { + const ids = new WeakMap, string>(); + let id = 0; + for (const block of evm.blocks.values()) { + for (const state of block.states) { + assert(!ids.has(state)); + + if (!ids.has(state)) { + ids.set(state, `id-${id}`); + id++; + } + } + } + + let output = ''; + const write = (content: string) => output += content + '\n'; + + write(`digraph G { + color="#efefef"; + graph[fontsize=8]; + + node[shape=box style="rounded,filled" fontsize=9 fontname="Arial" fillcolor="#efefef"]; +`); + + let edges = ''; + for (const [pc, block] of evm.blocks) { + write(` subgraph cluster_${pc} {`); + write(` style="filled,rounded";`); + write(` label = "pc @${pc}";`); + + for (const state of block.states) { + writeNode(pc, state); + switch (state.last?.name) { + case 'Jumpi': + writeEdge(state, state.last.destBranch); + writeEdge(state, state.last.fallBranch); + break; + case 'SigCase': + // writeEdge(pc, state.last.condition.hash); + writeEdge(state, state.last.fallBranch); + break; + case 'Jump': + writeEdge(state, state.last.destBranch); + break; + case 'JumpDest': + writeEdge(state, state.last.fallBranch); + break; + default: + } + } + write(' }\n'); + } + write(edges); + write('}'); + return output; + + function writeNode(pc: number, state: State) { + const id = ids.get(state); + let label = `pc @${pc} (${id})`; + label += '\\l'; + label += '=| ' + state.stack.values.map(elem => yul`${elem}`).join('|'); + label += '\\l'; + label += state.stmts.map(stmt => sol`${stmt}`).join('\\l'); + label += '\\l'; + + write(` "${id}" [label="${label}" fillcolor="${'#cf91f7'}"];`); + } + + function writeEdge(src: State, branch: Branch) { + const id = ids.get(src); + edges += ` "${id}" -> "${ids.get(branch.state)}";\n`; + } +} \ No newline at end of file diff --git a/test/contracts/selfdestruct.test.ts b/test/contracts/selfdestruct.test.ts deleted file mode 100644 index 75aac68..0000000 --- a/test/contracts/selfdestruct.test.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { expect } from 'chai'; - -import { Contract } from 'sevm'; - -import { contracts } from '../utils/solc'; - -contracts('selfdestruct', (compile, fallback, version) => { - if (version === '0.8.16' || version === '0.5.5' || version === '0.5.17') return; - - it('should detect `SELFDESTRUCT` and `decompile` bytecode', function () { - const src = `contract Test { - ${fallback}() external payable { - selfdestruct(payable(msg.sender)); - } - }`; - const contract = new Contract(compile(src, this, { - optimizer: { enabled: true }, - ignoreWarnings: true, - }).bytecode); - - const text = contract.solidify({ license: null, pragma: false }); - expect(text).to.be.equal( - `contract Contract { - - ${fallback}() external payable { - selfdestruct(msg.sender); - } - -} -` - ); - }); -});