diff --git a/contracts/.solcover.js b/contracts/.solcover.js index 900f90f2a..5d9b2c141 100644 --- a/contracts/.solcover.js +++ b/contracts/.solcover.js @@ -1,7 +1,3 @@ module.exports = { - skipFiles: [ - "_testing", - "proxies", - "bridging/token/CustomBridgedToken.sol", - ], + skipFiles: ["_testing", "proxies", "bridging/token/CustomBridgedToken.sol"], }; diff --git a/contracts/local-deployments-artifacts/deployLineaScenarioDelegatingProxy.ts b/contracts/local-deployments-artifacts/deployLineaScenarioDelegatingProxy.ts new file mode 100644 index 000000000..17de4645b --- /dev/null +++ b/contracts/local-deployments-artifacts/deployLineaScenarioDelegatingProxy.ts @@ -0,0 +1,41 @@ +import { ethers } from "ethers"; +import { + contractName as lineaScenarioDelegatingProxyName, + abi as lineaScenarioDelegatingProxyAbi, + bytecode as lineaScenarioDelegatingProxyBytecode, +} from "./static-artifacts/LineaScenarioDelegatingProxy.json"; +import { deployContractFromArtifacts } from "../common/helpers/deployments"; + +async function main() { + const provider = new ethers.JsonRpcProvider(process.env.RPC_URL); + const wallet = new ethers.Wallet(process.env.PRIVATE_KEY!, provider); + + console.log(`Deploying LineaScenarioDelegatingProxy`); + const lineaScenarioDelegatingProxyAddress = await deploylineaScenarioDelegatingProxy(wallet); + console.log( + `LineaScenarioDelegatingProxy Deployed at lineaScenarioDelegatingProxyAddress=${lineaScenarioDelegatingProxyAddress}`, + ); +} + +async function deploylineaScenarioDelegatingProxy(wallet: ethers.Wallet): Promise { + const walletNonce = await wallet.getNonce(); + + const lineaScenarioDelegatingProxy = await deployContractFromArtifacts( + lineaScenarioDelegatingProxyName, + lineaScenarioDelegatingProxyAbi, + lineaScenarioDelegatingProxyBytecode, + wallet, + { + nonce: walletNonce, + }, + ); + + const lineaScenarioDelegatingProxyAddress = await lineaScenarioDelegatingProxy.getAddress(); + + return lineaScenarioDelegatingProxyAddress; +} + +main().catch((error) => { + console.error(error); + process.exit(1); +}); diff --git a/contracts/local-deployments-artifacts/executeLineaScenarioDelegatingProxyScenario.ts b/contracts/local-deployments-artifacts/executeLineaScenarioDelegatingProxyScenario.ts new file mode 100644 index 000000000..0ab79ca97 --- /dev/null +++ b/contracts/local-deployments-artifacts/executeLineaScenarioDelegatingProxyScenario.ts @@ -0,0 +1,49 @@ +/* + ******************************************************************************************* + 1. Set the RPC_URL + 2. Set the PRIVATE_KEY + 3. Set LINEA_SCENARIO_DELEGATING_PROXY_ADDRESS + 4. Set NUMBER_OF_LOOPS + 5. set LINEA_SCENARIO + 6. set GAS_LIMIT + ******************************************************************************************* + ******************************************************************************************* + LINEA_SCENARIO_DELEGATING_PROXY_ADDRESS=
\ + NUMBER_OF_LOOPS= \ + LINEA_SCENARIO= \ + GAS_LIMIT= \ + PRIVATE_KEY= \ + RPC_URL= \ + npx ts-node local-deployments-artifacts/executeLineaScenarioDelegatingProxyScenario.ts + ******************************************************************************************* +*/ + +import { getRequiredEnvVar } from "../common/helpers/environment"; +import { ethers } from "ethers"; +import { abi as testerAbi } from "./static-artifacts/LineaScenarioDelegatingProxy.json"; + +async function main() { + const provider = new ethers.JsonRpcProvider(process.env.RPC_URL); + const wallet = new ethers.Wallet(process.env.PRIVATE_KEY!, provider); + + const testContractAddress = getRequiredEnvVar("LINEA_SCENARIO_DELEGATING_PROXY_ADDRESS"); + const lineaScenario = 1; //getRequiredEnvVar("LINEA_SCENARIO"); + const numberOfLoops = getRequiredEnvVar("NUMBER_OF_LOOPS"); + const gasLimit = getRequiredEnvVar("GAS_LIMIT"); + + // Equivalent of getContractAt + const delegatingProxy = new ethers.Contract(testContractAddress, testerAbi, wallet); + const executeTx = await delegatingProxy.executeScenario(lineaScenario, numberOfLoops, { gasLimit: gasLimit }); + try { + const receipt = await executeTx.wait(); + console.log(`Executed transaction with gasUsed=${receipt?.gasUsed} status=${receipt?.status}`); + } catch (error) { + const receipt = await provider.getTransactionReceipt(executeTx.hash); + console.error("Transaction failed - tx receipt=", JSON.stringify(receipt)); + } +} + +main().catch((error) => { + console.error(error); + process.exit(1); +}); diff --git a/contracts/local-deployments-artifacts/static-artifacts/LineaScenarioDelegatingProxy.json b/contracts/local-deployments-artifacts/static-artifacts/LineaScenarioDelegatingProxy.json new file mode 100644 index 000000000..9e19c83c0 --- /dev/null +++ b/contracts/local-deployments-artifacts/static-artifacts/LineaScenarioDelegatingProxy.json @@ -0,0 +1,59 @@ +{ + "_format": "hh-sol-artifact-1", + "contractName": "LineaScenarioDelegatingProxy", + "sourceName": "src/_testing/mocks/base/LineaScenarioDelegatingProxy.sol", + "abi": [ + { + "inputs": [ + { + "internalType": "enum LineaScenarioTesting.Scenario", + "name": "_scenario", + "type": "uint8" + }, + { + "internalType": "uint256", + "name": "_loopIterations", + "type": "uint256" + } + ], + "name": "executeScenario", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "enum LineaScenarioTesting.Scenario", + "name": "", + "type": "uint8" + } + ], + "name": "executedScenarios", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + } + ], + "bytecode": "0x608060405234801561001057600080fd5b506105b1806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c8063632265341461003b578063bfc8045614610062575b600080fd5b61004e61004936600461025e565b61008d565b604051901515815260200160405180910390f35b61004e610070366004610288565b600060208181529281526040808220909352908152205460ff1681565b60008060405161009c9061023d565b604051809103906000f0801580156100b8573d6000803e3d6000fd5b50905060008173ffffffffffffffffffffffffffffffffffffffff1685856040516024016100e7929190610305565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f632265340000000000000000000000000000000000000000000000000000000017905251610168919061034a565b600060405180830381855af49150503d80600081146101a3576040519150601f19603f3d011682016040523d82523d6000602084013e6101a8565b606091505b505073ffffffffffffffffffffffffffffffffffffffff831660009081526020819052604081209192508291908760018111156101e7576101e76102d6565b60018111156101f8576101f86102d6565b8152602081019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055949350505050565b6102028061037a83390190565b80356002811061025957600080fd5b919050565b6000806040838503121561027157600080fd5b61027a8361024a565b946020939093013593505050565b6000806040838503121561029b57600080fd5b823573ffffffffffffffffffffffffffffffffffffffff811681146102bf57600080fd5b91506102cd6020840161024a565b90509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b6040810160028410610340577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b9281526020015290565b6000825160005b8181101561036b5760208186018101518583015201610351565b50600092019182525091905056fe608060405234801561001057600080fd5b506101e2806100206000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c80636322653414610030575b600080fd5b61004361003e3660046100ee565b610057565b604051901515815260200160405180910390f35b6000610063838361006a565b9392505050565b600060018360018111156100805761008061011e565b036100e55760005b828110156100a2578061009a8161014d565b915050610088565b600080548591907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600183818111156100de576100de61011e565b0217905550505b50600192915050565b6000806040838503121561010157600080fd5b82356002811061011057600080fd5b946020939093013593505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036101a5577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b506001019056fea264697066735822122008b0d6e2c41d2d38087305ac063c4bc5ee7b8c4802e25232107224956548426064736f6c63430008130033a264697066735822122045342910478fd755f4afea9b56e0fffb346af611864b922b89d2451664b941fb64736f6c63430008130033", + "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106100365760003560e01c8063632265341461003b578063bfc8045614610062575b600080fd5b61004e61004936600461025e565b61008d565b604051901515815260200160405180910390f35b61004e610070366004610288565b600060208181529281526040808220909352908152205460ff1681565b60008060405161009c9061023d565b604051809103906000f0801580156100b8573d6000803e3d6000fd5b50905060008173ffffffffffffffffffffffffffffffffffffffff1685856040516024016100e7929190610305565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f632265340000000000000000000000000000000000000000000000000000000017905251610168919061034a565b600060405180830381855af49150503d80600081146101a3576040519150601f19603f3d011682016040523d82523d6000602084013e6101a8565b606091505b505073ffffffffffffffffffffffffffffffffffffffff831660009081526020819052604081209192508291908760018111156101e7576101e76102d6565b60018111156101f8576101f86102d6565b8152602081019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055949350505050565b6102028061037a83390190565b80356002811061025957600080fd5b919050565b6000806040838503121561027157600080fd5b61027a8361024a565b946020939093013593505050565b6000806040838503121561029b57600080fd5b823573ffffffffffffffffffffffffffffffffffffffff811681146102bf57600080fd5b91506102cd6020840161024a565b90509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b6040810160028410610340577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b9281526020015290565b6000825160005b8181101561036b5760208186018101518583015201610351565b50600092019182525091905056fe608060405234801561001057600080fd5b506101e2806100206000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c80636322653414610030575b600080fd5b61004361003e3660046100ee565b610057565b604051901515815260200160405180910390f35b6000610063838361006a565b9392505050565b600060018360018111156100805761008061011e565b036100e55760005b828110156100a2578061009a8161014d565b915050610088565b600080548591907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600183818111156100de576100de61011e565b0217905550505b50600192915050565b6000806040838503121561010157600080fd5b82356002811061011057600080fd5b946020939093013593505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036101a5577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b506001019056fea264697066735822122008b0d6e2c41d2d38087305ac063c4bc5ee7b8c4802e25232107224956548426064736f6c63430008130033a264697066735822122045342910478fd755f4afea9b56e0fffb346af611864b922b89d2451664b941fb64736f6c63430008130033", + "linkReferences": {}, + "deployedLinkReferences": {} +} diff --git a/contracts/src/_testing/mocks/base/LineaScenarioDelegatingProxy.sol b/contracts/src/_testing/mocks/base/LineaScenarioDelegatingProxy.sol new file mode 100644 index 000000000..fc84e3cf2 --- /dev/null +++ b/contracts/src/_testing/mocks/base/LineaScenarioDelegatingProxy.sol @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: AGPL-3.0 +pragma solidity 0.8.19; + +import { LineaScenarioTesting } from "./LineaScenarioTesting.sol"; + +/// @dev Test ScenarioDelegatingProxy. +contract LineaScenarioDelegatingProxy { + mapping(address => mapping(LineaScenarioTesting.Scenario => bool)) public executedScenarios; + + function executeScenario(LineaScenarioTesting.Scenario _scenario, uint256 _loopIterations) external returns (bool) { + // Deploy new scenario contract to consume gas and delegate to. + LineaScenarioTesting lineaScenarioTesting = new LineaScenarioTesting(); + + // Delegate the call noting that only 63/64 of the gas will be sent into the scenario in order to handle the revert + (bool callSuccess, ) = address(lineaScenarioTesting).delegatecall( + abi.encodeCall(LineaScenarioTesting.executeScenario, (_scenario, _loopIterations)) + ); + + // If you are testing SSTORE out of gas here post delegatecall out of gas, this will never save. + executedScenarios[address(lineaScenarioTesting)][_scenario] = callSuccess; + + return callSuccess; + } +} diff --git a/contracts/src/_testing/mocks/base/LineaScenarioTesting.sol b/contracts/src/_testing/mocks/base/LineaScenarioTesting.sol new file mode 100644 index 000000000..7920b47a0 --- /dev/null +++ b/contracts/src/_testing/mocks/base/LineaScenarioTesting.sol @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: AGPL-3.0 +pragma solidity ^0.8.19; + +/// @dev Test scenarios on Linea. +contract LineaScenarioTesting { + enum Scenario { + RETURN_TRUE, + GAS_GUZZLE + } + + Scenario private scenario; + + function executeScenario(Scenario _scenario, uint256 _loopIterations) external returns (bool) { + return _executeScenario(_scenario, _loopIterations); + } + + function _executeScenario(Scenario _scenario, uint256 _loopIterations) internal returns (bool) { + if (_scenario == Scenario.GAS_GUZZLE) { + // guzzle the gas + uint256 counter; + while (counter < _loopIterations) { + counter++; + } + + // silencing the warning - this needs to be external to consume gas. + scenario = _scenario; + } + + return true; + } +} diff --git a/contracts/src/_testing/mocks/base/RevertingVerifier.sol b/contracts/src/_testing/mocks/base/RevertingVerifier.sol index 2347f007e..e83d7424d 100644 --- a/contracts/src/_testing/mocks/base/RevertingVerifier.sol +++ b/contracts/src/_testing/mocks/base/RevertingVerifier.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: AGPL-3.0 -pragma solidity 0.8.26; +pragma solidity ^0.8.26; import { IPlonkVerifier } from "../../../verifiers/interfaces/IPlonkVerifier.sol"; @@ -17,18 +17,28 @@ contract RevertingVerifier is IPlonkVerifier { } function Verify(bytes calldata, uint256[] calldata) external returns (bool) { - if (scenario == Scenario.GAS_GUZZLE) { + _executeScenario(scenario, type(uint256).max); + + // defaults to EMPTY_REVERT scenario + revert(); + } + + function ExecuteScenario(Scenario _scenario, uint256 _loopIterations) external returns (bool) { + return _executeScenario(_scenario, _loopIterations); + } + + function _executeScenario(Scenario _scenario, uint256 _loopIterations) internal returns (bool) { + if (_scenario == Scenario.GAS_GUZZLE) { // guzzle the gas - bool usingGas = true; - while (usingGas) { - usingGas = true; + uint256 counter; + while (counter < _loopIterations) { + counter++; } // silencing the warning - this needs to be external to consume gas. - scenario = Scenario.GAS_GUZZLE; + scenario = scenario; } - // defaults to EMPTY_REVERT scenario - revert(); + return true; } } diff --git a/makefile-contracts.mk b/makefile-contracts.mk index 1510137e3..bb15c1a93 100644 --- a/makefile-contracts.mk +++ b/makefile-contracts.mk @@ -122,3 +122,23 @@ evm-opcode-tester-execute-all-opcodes: RPC_URL=http:\\localhost:8545/ \ npx ts-node local-deployments-artifacts/executeAllOpcodes.ts +deploy-l2-scenario-testing-proxy: + # WARNING: FOR LOCAL DEV ONLY - DO NOT REUSE THESE KEYS ELSEWHERE + cd contracts/; \ + PRIVATE_KEY=0x1dd171cec7e2995408b5513004e8207fe88d6820aeff0d82463b3e41df251aae \ + RPC_URL=http:\\localhost:8545/ \ + npx ts-node local-deployments-artifacts/deployLineaScenarioDelegatingProxy.ts + +execute-scenario-testing-proxy-scenario: LINEA_SCENARIO_DELEGATING_PROXY_ADDRESS:=0x2f6dAaF8A81AB675fbD37Ca6Ed5b72cf86237453 +execute-scenario-testing-proxy-scenario: + # WARNING: FOR LOCAL DEV ONLY - DO NOT REUSE THESE KEYS ELSEWHERE + # GAS_LIMIT=452500 will cause it to fail + cd contracts/; \ + LINEA_SCENARIO_DELEGATING_PROXY_ADDRESS=$(LINEA_SCENARIO_DELEGATING_PROXY_ADDRESS) \ + NUMBER_OF_LOOPS=10000000 \ + LINEA_SCENARIO=1 \ + GAS_LIMIT=452500 \ + PRIVATE_KEY=0x1dd171cec7e2995408b5513004e8207fe88d6820aeff0d82463b3e41df251aae \ + RPC_URL=http:\\localhost:8545/ \ + npx ts-node local-deployments-artifacts/executeLineaScenarioDelegatingProxyScenario.ts +