diff --git a/contracts/test/helpers/JSONDecoder.sol b/contracts/test/helpers/JSONDecoder.sol index 4736974b..cbca9a03 100644 --- a/contracts/test/helpers/JSONDecoder.sol +++ b/contracts/test/helpers/JSONDecoder.sol @@ -7,6 +7,7 @@ contract JSONDecoder { address challenger; uint256 finalizationPeriod; uint256 l2BlockTime; + string l2GethNode; address l2OutputOracleProxy; string l2RollupNode; address owner; diff --git a/contracts/test/helpers/Utils.sol b/contracts/test/helpers/Utils.sol index 96b81cc1..137a112c 100644 --- a/contracts/test/helpers/Utils.sol +++ b/contracts/test/helpers/Utils.sol @@ -8,16 +8,23 @@ import {Proxy} from "@optimism/src/universal/Proxy.sol"; import {ZKL2OutputOracle} from "src/ZKL2OutputOracle.sol"; contract Utils is Test, JSONDecoder { - function deployWithConfig(Config memory cfg, bytes32 startingOutputRoot, uint256 startingTimestamp) - public - returns (address) - { + function deployWithConfig( + Config memory cfg, + bytes32 startingOutputRoot, + uint256 startingTimestamp + ) public returns (address) { address zkL2OutputOracleImpl = address(new ZKL2OutputOracle()); cfg.l2OutputOracleProxy = address(new Proxy(address(this))); // Upgrade the proxy to point to the implementation and call initialize(). // Override the starting output root and timestmp with the passed values. - upgradeAndInitialize(zkL2OutputOracleImpl, cfg, address(0), startingOutputRoot, startingTimestamp); + upgradeAndInitialize( + zkL2OutputOracleImpl, + cfg, + address(0), + startingOutputRoot, + startingTimestamp + ); // Transfer ownership of proxy to owner specified in the config. Proxy(payable(cfg.l2OutputOracleProxy)).changeAdmin(cfg.owner); @@ -25,6 +32,7 @@ contract Utils is Test, JSONDecoder { return cfg.l2OutputOracleProxy; } + // TODO: Modify this to get the l2Starting block number. function upgradeAndInitialize( address impl, Config memory cfg, @@ -33,23 +41,35 @@ contract Utils is Test, JSONDecoder { uint256 startingTimestamp ) public { // require that the verifier gateway is deployed - require(address(cfg.verifierGateway).code.length > 0, "ZKUpgrader: verifier gateway not deployed"); + require( + address(cfg.verifierGateway).code.length > 0, + "ZKUpgrader: verifier gateway not deployed" + ); + + // When initializing the contract, use the latest block number from the L2 Geth node. + cfg.startingBlockNumber = fetchL2StartingBlockNumber(cfg); // If we passed a starting output root or starting timestamp, use it. // Otherwise, use the L2 Rollup Node to fetch the values based on the starting block number in the config. if (startingOutputRoot == bytes32(0) || startingTimestamp == 0) { - (bytes32 returnedStartingOutputRoot, uint256 returnedStartingTimestamp) = fetchOutputRoot(cfg); - if (startingOutputRoot == bytes32(0)) startingOutputRoot = returnedStartingOutputRoot; - if (startingTimestamp == 0) startingTimestamp = returnedStartingTimestamp; + ( + bytes32 returnedStartingOutputRoot, + uint256 returnedStartingTimestamp + ) = fetchOutputRoot(cfg); + if (startingOutputRoot == bytes32(0)) + startingOutputRoot = returnedStartingOutputRoot; + if (startingTimestamp == 0) + startingTimestamp = returnedStartingTimestamp; } - ZKL2OutputOracle.ZKInitParams memory zkInitParams = ZKL2OutputOracle.ZKInitParams({ - chainId: cfg.chainId, - verifierGateway: cfg.verifierGateway, - vkey: cfg.vkey, - owner: cfg.owner, - startingOutputRoot: startingOutputRoot - }); + ZKL2OutputOracle.ZKInitParams memory zkInitParams = ZKL2OutputOracle + .ZKInitParams({ + chainId: cfg.chainId, + verifierGateway: cfg.verifierGateway, + vkey: cfg.vkey, + owner: cfg.owner, + startingOutputRoot: startingOutputRoot + }); // If we are spoofing the admin (used in testing), start prank. if (_spoofedAdmin != address(0)) vm.startPrank(_spoofedAdmin); @@ -72,7 +92,9 @@ contract Utils is Test, JSONDecoder { ); } - function readJson(string memory filepath) public view returns (Config memory) { + function readJson( + string memory filepath + ) public view returns (Config memory) { string memory root = vm.projectRoot(); string memory path = string.concat(root, "/", filepath); string memory json = vm.readFile(path); @@ -80,17 +102,46 @@ contract Utils is Test, JSONDecoder { return abi.decode(data, (Config)); } - function readJsonWithRPCFromEnv(string memory filepath) public view returns (Config memory) { + function readJsonWithRPCFromEnv( + string memory filepath + ) public view returns (Config memory) { Config memory config = readJson(filepath); config.l2RollupNode = vm.envString("L2_NODE_RPC"); + config.l2GethNode = vm.envString("L2_RPC"); return config; } - function fetchOutputRoot(Config memory config) - public - returns (bytes32 startingOutputRoot, uint256 startingTimestamp) - { - string memory hexStartingBlockNumber = createHexString(config.startingBlockNumber); + function fetchL2StartingBlockNumber( + Config memory config + ) public returns (uint256) { + string[] memory inputs = new string[](4); + inputs[0] = "cast"; + inputs[1] = "bn"; + inputs[2] = "--rpc-url"; + inputs[3] = config.l2GethNode; + + bytes memory result = vm.ffi(inputs); + console.logBytes(result); + + // The result is being misinterpreted as a bytes32 value, when it's actually a number! Convert it to a string, then to a uint256. + // console.log("Result string:", resultString); + uint256 startingBlockNumber = uint256(bytes32(bytes(jsonRes))); + + // // Convert the result to a bytes32 value and then to a uint256. + // console.logBytes32(bytes32(result)); + // console.logBytes(result); + // // The result is a hex string, so we need to convert it to a uint256. + // uint256 startingBlockNumber = uint256(bytes32(result)) >> (256 - result.length * 8); + console.log("Starting block number:", startingBlockNumber); + return startingBlockNumber - 10; + } + + function fetchOutputRoot( + Config memory config + ) public returns (bytes32 startingOutputRoot, uint256 startingTimestamp) { + string memory hexStartingBlockNumber = createHexString( + config.startingBlockNumber + ); string[] memory inputs = new string[](6); inputs[0] = "cast"; @@ -101,19 +152,26 @@ contract Utils is Test, JSONDecoder { inputs[5] = hexStartingBlockNumber; string memory jsonRes = string(vm.ffi(inputs)); + console.log("JSON result:", jsonRes); bytes memory outputRootBytes = vm.parseJson(jsonRes, ".outputRoot"); - bytes memory startingTimestampBytes = vm.parseJson(jsonRes, ".blockRef.timestamp"); + bytes memory startingTimestampBytes = vm.parseJson( + jsonRes, + ".blockRef.timestamp" + ); startingOutputRoot = abi.decode(outputRootBytes, (bytes32)); startingTimestamp = abi.decode(startingTimestampBytes, (uint256)); } - function createHexString(uint256 value) public pure returns (string memory) { + function createHexString( + uint256 value + ) public pure returns (string memory) { string memory hexStartingBlockNum = Strings.toHexString(value); bytes memory startingBlockNumAsBytes = bytes(hexStartingBlockNum); require( - startingBlockNumAsBytes.length >= 4 && startingBlockNumAsBytes[0] == "0" - && startingBlockNumAsBytes[1] == "x", + startingBlockNumAsBytes.length >= 4 && + startingBlockNumAsBytes[0] == "0" && + startingBlockNumAsBytes[1] == "x", "Invalid input" ); diff --git a/contracts/zkconfig.json b/contracts/zkconfig.json index 61d3f45d..6c50bc6e 100644 --- a/contracts/zkconfig.json +++ b/contracts/zkconfig.json @@ -1,6 +1,7 @@ { "startingBlockNumber": 16837928, "l2RollupNode": "", + "l2GethNode": "", "submissionInterval": 150, "l2BlockTime": 2, "proposer": "0x0000000000000000000000000000000000000000", @@ -11,4 +12,4 @@ "vkey": "0x0050443c17829b5a1db8fdcf2cd7458d9a2e9ea6b93bd968183101d0801b796b", "verifierGateway": "0x3B6041173B80E77f038f3F2C0f9744f04837185e", "l2OutputOracleProxy": "0x863508f057c09f7b94e582d74404859ecd36a306" -} +} \ No newline at end of file