diff --git a/.github/assets/revive-dev-node-polkavm-resolc.json b/.github/assets/revive-dev-node-polkavm-resolc.json index 7cd6184286b8f..39df8f87df177 100644 --- a/.github/assets/revive-dev-node-polkavm-resolc.json +++ b/.github/assets/revive-dev-node-polkavm-resolc.json @@ -27,12 +27,6 @@ "fixtures/solidity/simple/modular/mulmod.sol::4::Y M0 S-": "Failed", "fixtures/solidity/simple/modular/mulmod.sol::5::Y M0 S+": "Failed", "fixtures/solidity/simple/modular/mulmod.sol::5::Y M0 S-": "Failed", - "fixtures/solidity/simple/try_catch/revert_long_data.sol::0::Y M0 S+": "Failed", - "fixtures/solidity/simple/try_catch/revert_long_data.sol::0::Y M0 S-": "Failed", - "fixtures/solidity/simple/try_catch/revert_long_data.sol::0::Y M3 S+": "Failed", - "fixtures/solidity/simple/try_catch/revert_long_data.sol::0::Y M3 S-": "Failed", - "fixtures/solidity/simple/try_catch/revert_long_data.sol::0::Y Mz S+": "Failed", - "fixtures/solidity/simple/try_catch/revert_long_data.sol::0::Y Mz S-": "Failed", "fixtures/solidity/simple/yul_instructions/mulmod.sol::0::Y M0 S+": "Failed", "fixtures/solidity/simple/yul_instructions/mulmod.sol::0::Y M0 S-": "Failed", "fixtures/solidity/simple/yul_instructions/mulmod.sol::1::Y M0 S+": "Failed", @@ -198,455 +192,5 @@ "fixtures/solidity/simple/yul_instructions/mulmod.sol::81::Y M0 S+": "Failed", "fixtures/solidity/simple/yul_instructions/mulmod.sol::81::Y M0 S-": "Failed", "fixtures/solidity/simple/yul_instructions/mulmod.sol::82::Y M0 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/mulmod.sol::82::Y M0 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::11::Y M0 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::11::Y M0 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::11::Y M3 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::11::Y M3 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::11::Y Mz S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::11::Y Mz S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::12::Y M0 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::12::Y M0 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::12::Y M3 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::12::Y M3 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::12::Y Mz S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::12::Y Mz S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::13::Y M0 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::13::Y M0 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::13::Y M3 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::13::Y M3 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::13::Y Mz S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::13::Y Mz S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::25::Y M0 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::25::Y M0 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::25::Y M3 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::25::Y M3 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::25::Y Mz S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::25::Y Mz S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::26::Y M0 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::26::Y M0 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::26::Y M3 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::26::Y M3 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::26::Y Mz S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::26::Y Mz S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::27::Y M0 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::27::Y M0 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::27::Y M3 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::27::Y M3 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::27::Y Mz S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::27::Y Mz S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::39::Y M0 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::39::Y M0 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::39::Y M3 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::39::Y M3 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::39::Y Mz S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::39::Y Mz S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::40::Y M0 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::40::Y M0 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::40::Y M3 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::40::Y M3 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::40::Y Mz S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::40::Y Mz S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::41::Y M0 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::41::Y M0 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::41::Y M3 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::41::Y M3 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::41::Y Mz S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::41::Y Mz S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::53::Y M0 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::53::Y M0 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::53::Y M3 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::53::Y M3 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::53::Y Mz S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::53::Y Mz S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::54::Y M0 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::54::Y M0 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::54::Y M3 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::54::Y M3 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::54::Y Mz S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::54::Y Mz S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::55::Y M0 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::55::Y M0 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::55::Y M3 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::55::Y M3 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::55::Y Mz S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::55::Y Mz S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::67::Y M0 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::67::Y M0 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::67::Y M3 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::67::Y M3 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::67::Y Mz S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::67::Y Mz S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::68::Y M0 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::68::Y M0 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::68::Y M3 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::68::Y M3 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::68::Y Mz S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::68::Y Mz S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::69::Y M0 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::69::Y M0 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::69::Y M3 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::69::Y M3 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::69::Y Mz S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::69::Y Mz S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::81::Y M0 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::81::Y M0 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::81::Y M3 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::81::Y M3 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::81::Y Mz S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::81::Y Mz S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::82::Y M0 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::82::Y M0 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::82::Y M3 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::82::Y M3 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::82::Y Mz S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::82::Y Mz S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::83::Y M0 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::83::Y M0 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::83::Y M3 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::83::Y M3 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::83::Y Mz S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::83::Y Mz S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::95::Y M0 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::95::Y M0 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::95::Y M3 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::95::Y M3 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::95::Y Mz S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::95::Y Mz S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::96::Y M0 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::96::Y M0 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::96::Y M3 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::96::Y M3 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::96::Y Mz S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::96::Y Mz S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::97::Y M0 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::97::Y M0 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::97::Y M3 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::97::Y M3 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::97::Y Mz S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::97::Y Mz S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::109::Y M0 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::109::Y M0 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::109::Y M3 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::109::Y M3 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::109::Y Mz S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::109::Y Mz S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::110::Y M0 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::110::Y M0 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::110::Y M3 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::110::Y M3 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::110::Y Mz S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::110::Y Mz S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::111::Y M0 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::111::Y M0 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::111::Y M3 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::111::Y M3 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::111::Y Mz S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::111::Y Mz S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::123::Y M0 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::123::Y M0 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::123::Y M3 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::123::Y M3 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::123::Y Mz S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::123::Y Mz S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::124::Y M0 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::124::Y M0 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::124::Y M3 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::124::Y M3 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::124::Y Mz S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::124::Y Mz S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::125::Y M0 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::125::Y M0 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::125::Y M3 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::125::Y M3 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::125::Y Mz S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::125::Y Mz S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::137::Y M0 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::137::Y M0 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::137::Y M3 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::137::Y M3 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::137::Y Mz S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::137::Y Mz S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::138::Y M0 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::138::Y M0 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::138::Y M3 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::138::Y M3 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::138::Y Mz S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::138::Y Mz S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::139::Y M0 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::139::Y M0 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::139::Y M3 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::139::Y M3 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::139::Y Mz S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::139::Y Mz S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::151::Y M0 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::151::Y M0 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::151::Y M3 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::151::Y M3 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::151::Y Mz S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::151::Y Mz S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::152::Y M0 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::152::Y M0 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::152::Y M3 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::152::Y M3 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::152::Y Mz S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::152::Y Mz S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::153::Y M0 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::153::Y M0 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::153::Y M3 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::153::Y M3 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::153::Y Mz S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::153::Y Mz S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::154::Y M0 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::154::Y M0 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::154::Y M3 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::154::Y M3 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::154::Y Mz S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::154::Y Mz S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::155::Y M0 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::155::Y M0 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::155::Y M3 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::155::Y M3 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::155::Y Mz S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::155::Y Mz S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::156::Y M0 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::156::Y M0 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::156::Y M3 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::156::Y M3 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::156::Y Mz S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::156::Y Mz S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::157::Y M0 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::157::Y M0 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::157::Y M3 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::157::Y M3 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::157::Y Mz S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::157::Y Mz S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::158::Y M0 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::158::Y M0 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::158::Y M3 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::158::Y M3 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::158::Y Mz S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::158::Y Mz S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::159::Y M0 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::159::Y M0 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::159::Y M3 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::159::Y M3 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::159::Y Mz S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::159::Y Mz S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::160::Y M0 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::160::Y M0 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::160::Y M3 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::160::Y M3 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::160::Y Mz S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::160::Y Mz S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::161::Y M0 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::161::Y M0 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::161::Y M3 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::161::Y M3 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::161::Y Mz S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::161::Y Mz S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::162::Y M0 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::162::Y M0 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::162::Y M3 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::162::Y M3 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::162::Y Mz S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::162::Y Mz S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::163::Y M0 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::163::Y M0 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::163::Y M3 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::163::Y M3 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::163::Y Mz S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::163::Y Mz S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::164::Y M0 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::164::Y M0 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::164::Y M3 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::164::Y M3 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::164::Y Mz S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::164::Y Mz S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::165::Y M0 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::165::Y M0 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::165::Y M3 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::165::Y M3 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::165::Y Mz S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::165::Y Mz S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::166::Y M0 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::166::Y M0 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::166::Y M3 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::166::Y M3 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::166::Y Mz S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::166::Y Mz S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::167::Y M0 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::167::Y M0 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::167::Y M3 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::167::Y M3 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::167::Y Mz S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::167::Y Mz S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::168::Y M0 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::168::Y M0 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::168::Y M3 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::168::Y M3 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::168::Y Mz S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::168::Y Mz S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::169::Y M0 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::169::Y M0 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::169::Y M3 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::169::Y M3 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::169::Y Mz S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::169::Y Mz S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::170::Y M0 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::170::Y M0 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::170::Y M3 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::170::Y M3 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::170::Y Mz S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::170::Y Mz S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::171::Y M0 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::171::Y M0 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::171::Y M3 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::171::Y M3 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::171::Y Mz S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::171::Y Mz S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::172::Y M0 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::172::Y M0 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::172::Y M3 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::172::Y M3 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::172::Y Mz S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::172::Y Mz S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::173::Y M0 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::173::Y M0 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::173::Y M3 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::173::Y M3 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::173::Y Mz S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::173::Y Mz S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::174::Y M0 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::174::Y M0 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::174::Y M3 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::174::Y M3 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::174::Y Mz S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::174::Y Mz S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::175::Y M0 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::175::Y M0 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::175::Y M3 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::175::Y M3 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::175::Y Mz S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::175::Y Mz S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::176::Y M0 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::176::Y M0 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::176::Y M3 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::176::Y M3 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::176::Y Mz S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::176::Y Mz S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::177::Y M0 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::177::Y M0 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::177::Y M3 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::177::Y M3 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::177::Y Mz S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::177::Y Mz S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::178::Y M0 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::178::Y M0 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::178::Y M3 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::178::Y M3 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::178::Y Mz S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::178::Y Mz S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::179::Y M0 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::179::Y M0 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::179::Y M3 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::179::Y M3 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::179::Y Mz S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::179::Y Mz S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::180::Y M0 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::180::Y M0 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::180::Y M3 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::180::Y M3 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::180::Y Mz S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::180::Y Mz S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::181::Y M0 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::181::Y M0 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::181::Y M3 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::181::Y M3 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::181::Y Mz S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::181::Y Mz S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::182::Y M0 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::182::Y M0 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::182::Y M3 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::182::Y M3 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::182::Y Mz S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::182::Y Mz S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::183::Y M0 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::183::Y M0 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::183::Y M3 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::183::Y M3 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::183::Y Mz S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::183::Y Mz S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::184::Y M0 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::184::Y M0 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::184::Y M3 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::184::Y M3 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::184::Y Mz S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::184::Y Mz S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::185::Y M0 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::185::Y M0 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::185::Y M3 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::185::Y M3 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::185::Y Mz S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::185::Y Mz S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::186::Y M0 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::186::Y M0 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::186::Y M3 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::186::Y M3 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::186::Y Mz S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::186::Y Mz S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::187::Y M0 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::187::Y M0 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::187::Y M3 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::187::Y M3 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::187::Y Mz S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::187::Y Mz S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::188::Y M0 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::188::Y M0 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::188::Y M3 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::188::Y M3 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::188::Y Mz S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::188::Y Mz S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::189::Y M0 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::189::Y M0 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::189::Y M3 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::189::Y M3 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::189::Y Mz S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::189::Y Mz S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::190::Y M0 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::190::Y M0 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::190::Y M3 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::190::Y M3 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::190::Y Mz S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::190::Y Mz S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::191::Y M0 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::191::Y M0 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::191::Y M3 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::191::Y M3 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::191::Y Mz S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::191::Y Mz S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::192::Y M0 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::192::Y M0 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::192::Y M3 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::192::Y M3 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::192::Y Mz S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::192::Y Mz S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::193::Y M0 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::193::Y M0 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::193::Y M3 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::193::Y M3 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::193::Y Mz S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::193::Y Mz S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::194::Y M0 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::194::Y M0 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::194::Y M3 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::194::Y M3 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::194::Y Mz S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::194::Y Mz S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::195::Y M0 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::195::Y M0 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::195::Y M3 S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::195::Y M3 S-": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::195::Y Mz S+": "Failed", - "fixtures/solidity/simple/yul_instructions/revert.sol::195::Y Mz S-": "Failed" -} + "fixtures/solidity/simple/yul_instructions/mulmod.sol::82::Y M0 S-": "Failed" +} \ No newline at end of file diff --git a/.gitignore b/.gitignore index bab68c65eb107..59a747f2fef17 100644 --- a/.gitignore +++ b/.gitignore @@ -40,7 +40,8 @@ rls*.log runtime/wasm/target/ substrate.code-workspace target/ +target.noindex/ *.scale rustc-ice-* /.claude/settings.local.json -*.local.md +*.local.md \ No newline at end of file diff --git a/prdoc/pr_11000.prdoc b/prdoc/pr_11000.prdoc new file mode 100644 index 0000000000000..2261433b7872e --- /dev/null +++ b/prdoc/pr_11000.prdoc @@ -0,0 +1,16 @@ +title: Revive, Estimate Gas with Binary Search +doc: +- audience: Runtime Dev + description: |- + # Description + + This PR implements binary search for the gas estimation logic in the eth-rpc which means that gas estimations are no longer just simple dry runs but that binary search is now used to find the smallest gas limit at which the transaction would run. + + This PR closes https://github.com/paritytech/contract-issues/issues/217 and also _kind of_ fixes https://github.com/paritytech/contract-issues/issues/259 or at least makes it harder to trigger the case in which we observe it, but the underlying issue still exists. + + The binary search algorithm implemented in this PR is as close as possible to that used in Geth +crates: +- name: pallet-revive + bump: minor +- name: pallet-revive-eth-rpc + bump: minor diff --git a/substrate/frame/revive/fixtures/contracts/ContractRequiringBinarySearchForGasEstimation.sol b/substrate/frame/revive/fixtures/contracts/ContractRequiringBinarySearchForGasEstimation.sol new file mode 100644 index 0000000000000..65b92fa1df9f6 --- /dev/null +++ b/substrate/frame/revive/fixtures/contracts/ContractRequiringBinarySearchForGasEstimation.sol @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: MIT + +pragma solidity >=0.8.4; + +contract ContractRequiringBinarySearchForGasEstimation { + function main() public view { + this.expensive_operation{gas: gasleft() / 2}(); + } + + function expensive_operation() external pure returns (uint256 sum) { + for (uint256 i = 0; i < 500; i++) { + sum += i * i; + } + } +} diff --git a/substrate/frame/revive/fixtures/contracts/ContractWithConsumeAllGas.sol b/substrate/frame/revive/fixtures/contracts/ContractWithConsumeAllGas.sol new file mode 100644 index 0000000000000..d6244f64af75f --- /dev/null +++ b/substrate/frame/revive/fixtures/contracts/ContractWithConsumeAllGas.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: MIT + +pragma solidity >=0.4.21; + +contract ContractWithConsumeAllGas { + function test() external { + assembly { + mstore(0, 0xcc572cf9) // main selector + mstore(32, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF) + mstore(64, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF) + let gas_value := div(mul(gas(), 1), 100) + let success := call(gas_value, address(), 0, 28, 68, 0, 0) + + mstore(0, success) + return(0, 32) + } + } + + function main(uint256 offset, uint256 len) external pure { + assembly { + // nullify memory ptr slot + mstore(0x40, 0) + revert(offset, len) + } + } +} diff --git a/substrate/frame/revive/rpc/src/client.rs b/substrate/frame/revive/rpc/src/client.rs index a6ee7f7fddc66..05e84d7daae02 100644 --- a/substrate/frame/revive/rpc/src/client.rs +++ b/substrate/frame/revive/rpc/src/client.rs @@ -179,6 +179,10 @@ pub enum ClientError { /// Transaction submission timeout. #[error("Transaction submission timeout")] Timeout, + /// All of the estimation methods `eth_estimate`, `eth_transact_with_config`, and + /// `eth_transact` were not found and therefore none of the estimation methods succeeded. + #[error("None of the estimation methods were found")] + NoEstimationMethodSucceeded, /// Chain identity mismatch between stored genesis and connected node. #[error("Genesis hash mismatch")] ChainMismatch, diff --git a/substrate/frame/revive/rpc/src/client/runtime_api.rs b/substrate/frame/revive/rpc/src/client/runtime_api.rs index 78548f374480f..9a727661d91ee 100644 --- a/substrate/frame/revive/rpc/src/client/runtime_api.rs +++ b/substrate/frame/revive/rpc/src/client/runtime_api.rs @@ -20,7 +20,7 @@ use crate::{ client::Balance, subxt_client::{self, SrcChainConfig}, }; -use futures::TryFutureExt; +use futures::{StreamExt, TryFutureExt, stream}; use pallet_revive::{ DryRunConfig, EthTransactInfo, evm::{ @@ -66,6 +66,68 @@ impl RuntimeApi { Ok(result) } + /// Estimates the minimum gas limit required for the transaction execution. Returns a [`U256`] + /// of the gas limit. + pub async fn estimate_gas( + &self, + tx: GenericTransaction, + block: BlockNumberOrTagOrHash, + ) -> Result { + let timestamp_override = match block { + BlockNumberOrTagOrHash::BlockTag(BlockTag::Pending) => { + Some(Timestamp::current().as_millis()) + }, + _ => None, + }; + + // Not all versions of pallet-revive have all of the runtime functions that we require. Thus + // we need to be able to perform the gas estimation through any of the runtime functions + // that the pallet may have available which is why we make use of this stream. The functions + // with higher priority are put at the start while the functions with lower priority are at + // the end. + let mut stream = + // Estimate through the `estimate_gas` function + stream::once(Box::pin(async { + let payload = subxt_client::apis().revive_api().eth_estimate_gas( + tx.clone().into(), + DryRunConfig::new(timestamp_override).into(), + ); + self.0.call(payload).await.map(|value| value.map(|value| value.0)) + })) + // Otherwise, estimate through `eth_transact_with_config` + .chain(stream::once(Box::pin(async { + let payload = subxt_client::apis().revive_api().eth_transact_with_config( + tx.clone().into(), + DryRunConfig::new(timestamp_override).into(), + ); + self.0.call(payload).await.map(|value| value.map(|value| value.eth_gas)) + }))) + // Otherwise, estimate through `eth_transact` + .chain(stream::once(Box::pin(async { + let payload = subxt_client::apis().revive_api().eth_transact(tx.clone().into()); + self.0.call(payload).await.map(|value| value.map(|value| value.eth_gas)) + }))); + + while let Some(result) = stream.next().await { + match result { + Ok(estimation) => { + return estimation.map_err(|err| ClientError::TransactError(err.0)); + }, + Err(Metadata(MetadataError::RuntimeMethodNotFound(name))) => { + log::debug!(target: LOG_TARGET, "Method {name:?} not found falling back"); + }, + Err(subxt::Error::Rpc(subxt::error::RpcError::ClientError( + subxt::ext::subxt_rpcs::Error::User(UserError { message, .. }), + ))) if message.contains("is not found") => { + log::debug!(target: LOG_TARGET, "{message:?} not found falling back") + }, + Err(err) => return Err(err.into()), + } + } + + Err(ClientError::NoEstimationMethodSucceeded.into()) + } + /// Dry run a transaction and returns the [`EthTransactInfo`] for the transaction. pub async fn dry_run( &self, diff --git a/substrate/frame/revive/rpc/src/lib.rs b/substrate/frame/revive/rpc/src/lib.rs index 3b755b88790cb..0e87fa0d739c5 100644 --- a/substrate/frame/revive/rpc/src/lib.rs +++ b/substrate/frame/revive/rpc/src/lib.rs @@ -164,12 +164,17 @@ impl EthRpcServer for EthRpcServerImpl { Ok(receipt) } + /// Performs gas estimations to find the lowest gas limit required to run the transaction. + /// + /// This method implements the same gas estimation logic found in Geth which performs binary + /// search with some simple heuristics to find the smallest gas limit for the transaction. async fn estimate_gas( &self, transaction: GenericTransaction, block: Option, ) -> RpcResult { log::trace!(target: LOG_TARGET, "estimate_gas transaction={transaction:?} block={block:?}"); + let block = block.unwrap_or_else(|| { if self.use_pending_for_estimate_gas { BlockTag::Pending.into() @@ -177,11 +182,15 @@ impl EthRpcServer for EthRpcServerImpl { Default::default() } }); - let hash = self.client.block_hash_for_tag(block.clone().into()).await?; - let runtime_api = self.client.runtime_api(hash); - let dry_run = runtime_api.dry_run(transaction, block.into()).await?; - log::trace!(target: LOG_TARGET, "estimate_gas result={dry_run:?}"); - Ok(dry_run.eth_gas) + let hash = self.client.block_hash_for_tag(block.into()).await?; + let gas_estimate = + self.client.runtime_api(hash).estimate_gas(transaction, block.into()).await?; + + log::trace!( + target: LOG_TARGET, + "estimate_gas result={gas_estimate:?}", + ); + Ok(gas_estimate) } async fn call( diff --git a/substrate/frame/revive/rpc/src/tests.rs b/substrate/frame/revive/rpc/src/tests.rs index 594f0480797c2..a53af72df3b31 100644 --- a/substrate/frame/revive/rpc/src/tests.rs +++ b/substrate/frame/revive/rpc/src/tests.rs @@ -30,12 +30,15 @@ use crate::{ }; use anyhow::anyhow; use clap::Parser; -use jsonrpsee::ws_client::{WsClient, WsClientBuilder}; +use jsonrpsee::{ + core::ClientError, + ws_client::{WsClient, WsClientBuilder}, +}; use pallet_revive::{ create1, evm::{ - Account, Block, BlockNumberOrTag, BlockNumberOrTagOrHash, BlockTag, H256, - HashesOrTransactionInfos, TransactionInfo, TransactionUnsigned, U256, + Account, Block, BlockNumberOrTag, BlockNumberOrTagOrHash, BlockTag, GenericTransaction, + H256, HashesOrTransactionInfos, TransactionInfo, TransactionUnsigned, U256, }, }; use sqlx::sqlite::{SqliteConnectOptions, SqlitePoolOptions}; @@ -46,6 +49,7 @@ use subxt::{ ext::subxt_rpcs::rpc_params, tx::{SubmittableTransaction, TxStatus}, }; +use subxt_signer::eth::Keypair; const LOG_TARGET: &str = "eth-rpc-tests"; @@ -321,6 +325,10 @@ async fn run_all_eth_rpc_tests_inner() -> anyhow::Result<()> { test_multiple_transactions_in_block, test_mixed_evm_substrate_transactions, test_runtime_pallets_address_upload_code, + test_estimate_gas_of_contract_with_consume_all_gas, + test_gas_estimation_for_contract_requiring_binary_search, + test_gas_estimation_with_no_funds_no_gas_specified, + test_gas_estimation_with_no_funds_and_with_gas_specified, test_block_sync_fresh, test_block_sync_resume_interrupted, test_block_sync_detects_corruption, @@ -707,7 +715,7 @@ async fn test_block_hash_for_tag_with_block_tags_works() -> anyhow::Result<()> { ]; for tag in tags { - let balance = client.get_balance(account.address(), tag.clone().into()).await?; + let balance = client.get_balance(account.address(), tag.into()).await?; assert!(balance >= U256::zero(), "Balance should be retrievable with tag {tag:?}"); } @@ -845,6 +853,82 @@ async fn test_runtime_pallets_address_upload_code() -> anyhow::Result<()> { Ok(()) } +async fn test_estimate_gas_of_contract_with_consume_all_gas() -> anyhow::Result<()> { + // Arrange + let code = pallet_revive_fixtures::compile_module_with_type( + "ContractWithConsumeAllGas", + pallet_revive_fixtures::FixtureType::Resolc, + )? + .0; + let client = Arc::new(SharedResources::client().await); + let account = Account::default(); + + let receipt = TransactionBuilder::new(client.clone()) + .input(code) + .send() + .await? + .wait_for_receipt() + .await?; + let contract_address = receipt + .contract_address + .expect("Expected the transaction to publish a contract"); + + // Act + let test_function_selector = [0xf8, 0xa8, 0xfd, 0x6d].to_vec(); + let transaction = GenericTransaction { + from: Some(account.address()), + input: test_function_selector.into(), + to: Some(contract_address), + chain_id: Some(client.chain_id().await?), + nonce: Some( + client.get_transaction_count(account.address(), BlockTag::Latest.into()).await?, + ), + r#type: Some(0u8.into()), + ..Default::default() + }; + let dry_run_result = client.estimate_gas(transaction, None).await; + + // Assert + dry_run_result.expect("Dry run of this transaction must succeed"); + + Ok(()) +} + +async fn test_gas_estimation_for_contract_requiring_binary_search() -> anyhow::Result<()> { + // Arrange + let code = pallet_revive_fixtures::compile_module_with_type( + "ContractRequiringBinarySearchForGasEstimation", + pallet_revive_fixtures::FixtureType::Resolc, + )? + .0; + let client = Arc::new(SharedResources::client().await); + + let receipt = TransactionBuilder::new(client.clone()) + .input(code) + .send() + .await? + .wait_for_receipt() + .await?; + let contract_address = receipt + .contract_address + .expect("Expected the transaction to publish a contract"); + + // Act + let main_function_selector = [0xdf, 0xfe, 0xad, 0xd0]; + let receipt = TransactionBuilder::new(client.clone()) + .to(contract_address) + .input(main_function_selector.to_vec()) + .send() + .await? + .wait_for_receipt() + .await?; + + // Assert + assert!(receipt.is_success()); + + Ok(()) +} + /// Test that deploys and calls the Fibonacci contract via Substrate APIs works async fn test_fibonacci_call_via_runtime_api() -> anyhow::Result<()> { use pallet_revive::precompiles::alloy::sol_types::SolCall; @@ -963,6 +1047,47 @@ async fn test_fibonacci_call_via_runtime_api() -> anyhow::Result<()> { Ok(()) } +async fn test_gas_estimation_with_no_funds_no_gas_specified() -> anyhow::Result<()> { + // Arrange + let code = pallet_revive_fixtures::compile_module_with_type( + "ContractWithConsumeAllGas", + pallet_revive_fixtures::FixtureType::Resolc, + )? + .0; + let client = Arc::new(SharedResources::client().await); + let account = Account::from(Keypair::from_seed([0xFF; 16].as_slice()).unwrap()); + + let receipt = TransactionBuilder::new(client.clone()) + .input(code) + .send() + .await? + .wait_for_receipt() + .await?; + let contract_address = receipt + .contract_address + .expect("Expected the transaction to publish a contract"); + + // Act + let test_function_selector = [0xf8, 0xa8, 0xfd, 0x6d].to_vec(); + let transaction = GenericTransaction { + from: Some(account.address()), + input: test_function_selector.into(), + to: Some(contract_address), + chain_id: Some(client.chain_id().await?), + nonce: Some( + client.get_transaction_count(account.address(), BlockTag::Latest.into()).await?, + ), + r#type: Some(0u8.into()), + ..Default::default() + }; + let dry_run_result = client.estimate_gas(transaction, None).await; + + // Assert + dry_run_result.expect("Expected this dry run to succeed"); + + Ok(()) +} + /// Submit `count` EVM transfer transactions and wait for inclusion. async fn submit_evm_transfers(count: usize) -> anyhow::Result<()> { let ws_client = Arc::new(SharedResources::client().await); @@ -1104,6 +1229,51 @@ async fn test_block_sync_fresh() -> anyhow::Result<()> { Ok(()) } +async fn test_gas_estimation_with_no_funds_and_with_gas_specified() -> anyhow::Result<()> { + // Arrange + let code = pallet_revive_fixtures::compile_module_with_type( + "ContractWithConsumeAllGas", + pallet_revive_fixtures::FixtureType::Resolc, + )? + .0; + let client = Arc::new(SharedResources::client().await); + let account = Account::from(Keypair::from_seed([0xFF; 16].as_slice()).unwrap()); + + let receipt = TransactionBuilder::new(client.clone()) + .input(code) + .send() + .await? + .wait_for_receipt() + .await?; + let contract_address = receipt + .contract_address + .expect("Expected the transaction to publish a contract"); + + // Act + let test_function_selector = [0xf8, 0xa8, 0xfd, 0x6d].to_vec(); + let transaction = GenericTransaction { + from: Some(account.address()), + input: test_function_selector.into(), + to: Some(contract_address), + chain_id: Some(client.chain_id().await?), + nonce: Some( + client.get_transaction_count(account.address(), BlockTag::Latest.into()).await?, + ), + r#type: Some(0u8.into()), + gas: Some(U256::from(100_000_000u64)), + ..Default::default() + }; + let dry_run_result = client.estimate_gas(transaction, None).await; + + // Assert + assert!(matches!( + dry_run_result, Err(ClientError::Call(error_object)) + if error_object.message().contains("insufficient funds for gas") + )); + + Ok(()) +} + /// Simulate an interrupted sync by manually setting both Head and Tail /// to create a top gap and a bottom gap, then verify that `resume_sync` fills both. async fn test_block_sync_resume_interrupted() -> anyhow::Result<()> { diff --git a/substrate/frame/revive/src/evm/api/rpc_types.rs b/substrate/frame/revive/src/evm/api/rpc_types.rs index 589fdba78200b..b7710795e3b5d 100644 --- a/substrate/frame/revive/src/evm/api/rpc_types.rs +++ b/substrate/frame/revive/src/evm/api/rpc_types.rs @@ -23,21 +23,39 @@ use scale_info::TypeInfo; use sp_core::{H160, U256}; /// Configuration specific to a dry-run execution. -#[derive(Debug, Encode, Decode, TypeInfo, Clone, DefaultNoBound)] +#[derive(Debug, Encode, Decode, TypeInfo, Clone, Copy, DefaultNoBound)] pub struct DryRunConfig { /// Optional timestamp override for dry-run in pending block. pub timestamp_override: Option, - /// Used for future extensions without breaking encoding. - pub reserved: Option<()>, + /// Used to control if the dry run logic should perform the balance checks or not. + pub perform_balance_checks: Option, } impl DryRunConfig { /// Create a new `DryRunConfig` with an optional timestamp override. pub fn new(timestamp_override: Option) -> Self { Self { timestamp_override, - reserved: None, // default value + perform_balance_checks: Some(true), // default value } } + + /// A builder method which consumes the object and modifies the `timestamp_override` field. + pub fn with_timestamp_override( + mut self, + timestamp_override: impl Into>, + ) -> Self { + self.timestamp_override = timestamp_override.into(); + self + } + + /// A builder method which consumes the object and modifies the `perform_balance_checks` field. + pub fn with_perform_balance_checks( + mut self, + perform_balance_checks: impl Into>, + ) -> Self { + self.perform_balance_checks = perform_balance_checks.into(); + self + } } impl From for BlockNumberOrTagOrHash { diff --git a/substrate/frame/revive/src/evm/api/rpc_types_gen.rs b/substrate/frame/revive/src/evm/api/rpc_types_gen.rs index fcd1be75c8930..3c1298b67d258 100644 --- a/substrate/frame/revive/src/evm/api/rpc_types_gen.rs +++ b/substrate/frame/revive/src/evm/api/rpc_types_gen.rs @@ -141,7 +141,7 @@ pub struct Block { } /// Block number or tag -#[derive(Debug, Clone, Serialize, Deserialize, From, TryInto, Eq, PartialEq)] +#[derive(Debug, Copy, Clone, Serialize, Deserialize, From, TryInto, Eq, PartialEq)] #[serde(untagged)] pub enum BlockNumberOrTag { /// Block number @@ -498,7 +498,7 @@ pub type Addresses = Vec
; /// and containing the set of transactions usually taken from local mempool. Before the merge /// transition is finalized, any call querying for `finalized` or `safe` block MUST be responded to /// with `-39001: Unknown block` error -#[derive(Debug, Default, Clone, Serialize, Deserialize, Eq, PartialEq)] +#[derive(Debug, Copy, Default, Clone, Serialize, Deserialize, Eq, PartialEq)] #[serde(rename_all = "lowercase")] pub enum BlockTag { Earliest, diff --git a/substrate/frame/revive/src/evm/runtime.rs b/substrate/frame/revive/src/evm/runtime.rs index 630cc492df727..ce38c255dd344 100644 --- a/substrate/frame/revive/src/evm/runtime.rs +++ b/substrate/frame/revive/src/evm/runtime.rs @@ -319,6 +319,7 @@ pub trait EthExtra { })?; log::debug!(target: LOG_TARGET, "Decoded Ethereum transaction with signer: {signer_addr:?} nonce: {nonce:?}"); + log::trace!(target: LOG_TARGET, "Decoded Ethereum transaction was: {tx:?}"); let call_info = tx.into_call::(CreateCallMode::ExtrinsicExecution( encoded_len as u32, payload.to_vec(), diff --git a/substrate/frame/revive/src/lib.rs b/substrate/frame/revive/src/lib.rs index c66500b74b577..906e8a67fd51e 100644 --- a/substrate/frame/revive/src/lib.rs +++ b/substrate/frame/revive/src/lib.rs @@ -54,6 +54,7 @@ use crate::{ fees::InfoT as FeeInfo, runtime::SetWeightLimit, }, exec::{AccountIdOf, ExecError, ReentrancyProtection, Stack as ExecStack}, + sp_runtime::TransactionOutcome, storage::{AccountType, DeletionQueueManager}, tracing::if_tracing, vm::{CodeInfo, RuntimeCosts, pvm::extract_code_and_data}, @@ -70,6 +71,7 @@ use frame_support::{ }, ensure, pallet_prelude::DispatchClass, + storage::with_transaction, traits::{ ConstU32, ConstU64, EnsureOrigin, Get, IsSubType, IsType, OnUnbalanced, OriginTrait, fungible::{Balanced, Credit, Inspect, Mutate, MutateHold}, @@ -827,13 +829,15 @@ pub mod pallet { }, Some(genesis::ContractData { code, storage }) => { let blob = if code.0.starts_with(&polkavm_common::program::BLOB_MAGIC) { - ContractBlob::::from_pvm_code( code.0.clone(), owner.clone()).inspect_err(|err| { - log::error!(target: LOG_TARGET, "Failed to create PVM ContractBlob for {address:?}: {err:?}"); - }) + ContractBlob::::from_pvm_code(code.0.clone(), owner.clone()) + .inspect_err(|err| { + log::error!(target: LOG_TARGET, "Failed to create PVM ContractBlob for {address:?}: {err:?}"); + }) } else { - ContractBlob::::from_evm_runtime_code(code.0.clone(), account_id).inspect_err(|err| { - log::error!(target: LOG_TARGET, "Failed to create EVM ContractBlob for {address:?}: {err:?}"); - }) + ContractBlob::::from_evm_runtime_code(code.0.clone(), account_id) + .inspect_err(|err| { + log::error!(target: LOG_TARGET, "Failed to create EVM ContractBlob for {address:?}: {err:?}"); + }) }; let Ok(blob) = blob else { @@ -1766,6 +1770,162 @@ impl Pallet { } } + /// Estimates the amount of gas that a transactions requires. + /// + /// This function estimates the gas of the transaction according to the same binary search + /// algorithm that's implemented in Geth. It stops when with an acceptable error ratio of + /// 1.5% so that the algorithm terminates early. + /// + /// # Note + /// + /// All calls to [`Self::dry_run_eth_transact`] need to happen inside of a [`with_transaction`] + /// with state rollback to ensure that dry runs subsequent to the first one preserve the correct + /// amount of storage deposits needed without any kind of caching from the previous dry runs. + pub fn eth_estimate_gas( + tx: GenericTransaction, + config: DryRunConfig<<::Time as Time>::Moment>, + ) -> Result + where + T::Nonce: Into, + CallOf: SetWeightLimit, + { + log::debug!(target: LOG_TARGET, "eth_estimate_gas: {tx:?}"); + + let mut low = U256::zero(); + let mut high = Self::evm_block_gas_limit(); + + log::trace!(target: LOG_TARGET, "eth_estimate_gas starting with low={low}, high={high}"); + + // If the user has specified a gas limit then this is the limit we use as the high bound for + // the binary search. Also, if the user didn't specify a gas limit then we need to skip the + // balance checks. + let perform_balance_checks = if let Some(gas_limit) = tx.gas { + high = gas_limit; + log::trace!(target: LOG_TARGET, "eth_estimate_gas high limited by the gas limit high={high}"); + true + } else { + false + }; + + // Cap the high bound of the binary search based on the account's balance if it can be done. + let fee_cap = tx.max_fee_per_gas.or(tx.gas_price); + if let (Some(fee_cap), Some(from), true) = (fee_cap, tx.from, perform_balance_checks) { + let mut available_balance = Self::evm_balance(&from); + if let Some(value) = tx.value { + available_balance = available_balance.checked_sub(value).ok_or_else(|| { + EthTransactError::Message("insufficient funds for value transfer".into()) + })?; + } + if let Some(allowance) = available_balance.checked_div(fee_cap) { + if high > allowance && allowance != U256::zero() { + log::trace!(target: LOG_TARGET, "eth_estimate_gas high limited by the user's allowance high={high} allowance={allowance}"); + high = allowance + } + } + } + + // TODO: Implement a short circuit for simple transfers. We just need to determine the gas + // needed for it. + + // Perform the first dry run with the gas limit of the binary search's high bound. If it + // fails then we attempt again with the max extrinsic weight in gas which we do since some + // transactions fail the dry run with the highest gas limit. If both of these fail then we + // return early as it means that the transaction simply can't succeed. + let dry_run_results = [high, Self::evm_max_extrinsic_weight_in_gas()].map(|gas_limit| { + let mut transaction = tx.clone(); + transaction.gas = Some(gas_limit); + let eth_transact_result = with_transaction(|| { + TransactionOutcome::Rollback(Ok::<_, DispatchError>(Self::dry_run_eth_transact( + transaction, + config.with_perform_balance_checks(perform_balance_checks), + ))) + }) + .expect("Rollback shouldn't error out"); + (gas_limit, eth_transact_result) + }); + let (gas_limit, first_dry_run_result) = match dry_run_results { + [(gas_limit1, Ok(dry_run_result1)), (gas_limit2, Ok(dry_run_result2))] => { + if dry_run_result2.eth_gas >= gas_limit2 { + (gas_limit1, dry_run_result1) + } else { + (gas_limit2, dry_run_result2) + } + }, + [(gas_limit, Ok(dry_run_result)), (_, Err(_))] | + [(_, Err(_)), (gas_limit, Ok(dry_run_result))] => (gas_limit, dry_run_result), + [(_, Err(err)), (_, Err(..))] => return Err(err), + }; + log::trace!( + target: LOG_TARGET, + "eth_estimate_gas first dry run succeeded with gas_limit={} consumed={}", + gas_limit, + first_dry_run_result.eth_gas + ); + low = first_dry_run_result.eth_gas; + high = gas_limit; + + while low + U256::one() < high { + log::trace!(target: LOG_TARGET, "eth_estimate_gas estimation iteration with low={low} high={high}"); + let error_ratio = high + .checked_sub(low) + .and_then(|value| value.checked_mul(U256::from(1000))) + .and_then(|value| value.checked_div(high)) + .ok_or_else(|| { + EthTransactError::Message( + "failed to calculate error ratio in gas estimation".into(), + ) + })?; + if error_ratio <= U256::from(15) { + log::trace!( + target: LOG_TARGET, + "eth_estimate_gas finished due to error ratio being less than 1.5% high={}", + high + ); + break; + } + + let mut midpoint = high + .checked_sub(low) + .and_then(|value| value.checked_div(U256::from(2))) + .and_then(|value| value.checked_add(low)) + .ok_or_else(|| { + EthTransactError::Message( + "failed to calculate midpoint in gas estimation".into(), + ) + })?; + + if let Some(other_midpoint) = low.checked_mul(U256::from(2)) { + if other_midpoint != U256::zero() { + midpoint = midpoint.min(other_midpoint) + } + }; + + let mut transaction = tx.clone(); + transaction.gas = Some(midpoint); + let dry_run_result = with_transaction(|| { + TransactionOutcome::Rollback(Ok::<_, DispatchError>(Self::dry_run_eth_transact( + transaction, + config.with_perform_balance_checks(perform_balance_checks), + ))) + }) + .expect("Rollback shouldn't error out"); + log::trace!(target: LOG_TARGET, "eth_estimate_gas dry run result with midpoint={midpoint} is dry_run_result={dry_run_result:?}"); + match dry_run_result { + Ok(..) => { + log::trace!(target: LOG_TARGET, "eth_estimate_gas dry run succeeded, new high={midpoint}"); + high = midpoint + }, + Err(..) => { + log::trace!(target: LOG_TARGET, "eth_estimate_gas dry run failed, new low={midpoint}"); + low = midpoint + }, + } + } + + log::trace!(target: LOG_TARGET, "eth_estimate_gas completed. high={high}"); + Ok(high) + } + /// Dry-run Ethereum calls. /// /// # Parameters @@ -1841,7 +2001,12 @@ impl Pallet { // emulate transaction behavior let fees = call_info.tx_fee.saturating_add(call_info.storage_deposit); if let Some(from) = &from { - let fees = if gas.is_some() { fees } else { Zero::zero() }; + let fees = + if gas.is_some() && matches!(dry_run_config.perform_balance_checks, Some(true)) { + fees + } else { + Zero::zero() + }; let balance = Self::evm_balance(from); if balance < Pallet::::convert_native_to_evm(fees).saturating_add(value) { return Err(EthTransactError::Message(format!( @@ -2112,6 +2277,13 @@ impl Pallet { u64::MAX.into() } + /// Returns the maximum value of gas that can be represented in weights. + pub fn evm_max_extrinsic_weight_in_gas() -> U256 { + let max_extrinsic_fee = T::FeeInfo::weight_to_fee(&Self::evm_max_extrinsic_weight()); + let gas_scale: BalanceOf = T::GasScale::get().into(); + (max_extrinsic_fee / gas_scale).into() + } + /// The maximum weight an `eth_transact` is allowed to consume. pub fn evm_max_extrinsic_weight() -> Weight { let factor = ::MaxEthExtrinsicWeight::get(); @@ -2576,6 +2748,9 @@ sp_api::decl_runtime_apis! { /// Returns the block gas limit. fn block_gas_limit() -> U256; + /// Returns the block gas limit as calculated from the weights. + fn max_extrinsic_weight_in_gas() -> U256; + /// Returns the free balance of the given `[H160]` address, using EVM decimals. fn balance(address: H160) -> U256; @@ -2625,6 +2800,16 @@ sp_api::decl_runtime_apis! { config: DryRunConfig, ) -> Result, EthTransactError>; + /// Estimates the amount of gas that a transactions requires. + /// + /// This function estimates the gas of the transaction according to the same binary search + /// algorithm that's implemented in Geth. It stops when with an acceptable error ratio of + /// 1.5% so that the algorithm terminates early. + fn eth_estimate_gas( + tx: GenericTransaction, + config: DryRunConfig + ) -> Result; + /// Upload new code without instantiating a contract from it. /// /// See [`crate::Pallet::bare_upload_code`]. @@ -2768,6 +2953,10 @@ macro_rules! impl_runtime_apis_plus_revive_traits { $crate::Pallet::::evm_block_gas_limit() } + fn max_extrinsic_weight_in_gas() -> $crate::U256 { + $crate::Pallet::::evm_max_extrinsic_weight_in_gas() + } + fn gas_price() -> $crate::U256 { $crate::Pallet::::evm_base_fee() } @@ -2806,6 +2995,18 @@ macro_rules! impl_runtime_apis_plus_revive_traits { $crate::Pallet::::dry_run_eth_transact(tx, config) } + fn eth_estimate_gas( + tx: $crate::evm::GenericTransaction, + config: $crate::DryRunConfig<__ReviveMacroMoment>, + ) -> Result<$crate::U256, $crate::EthTransactError> { + use $crate::{ + codec::Encode, evm::runtime::EthExtra, frame_support::traits::Get, + sp_runtime::traits::TransactionExtension, + sp_runtime::traits::Block as BlockT + }; + $crate::Pallet::::eth_estimate_gas(tx, config) + } + fn call( origin: AccountId, dest: $crate::H160, diff --git a/substrate/frame/revive/src/primitives.rs b/substrate/frame/revive/src/primitives.rs index b6450b280aa95..c130151cc4247 100644 --- a/substrate/frame/revive/src/primitives.rs +++ b/substrate/frame/revive/src/primitives.rs @@ -450,7 +450,7 @@ impl ExecConfig { bump_nonce: self.bump_nonce, collect_deposit_from_hold: self.collect_deposit_from_hold, effective_gas_price: self.effective_gas_price, - is_dry_run: self.is_dry_run.clone(), + is_dry_run: self.is_dry_run, mock_handler: None, test_env_transient_storage: None, }