diff --git a/packages/linea-ens-resolver/contracts/L1Resolver.sol b/packages/linea-ens-resolver/contracts/L1Resolver.sol index 0b0a42b77..de9b92e45 100644 --- a/packages/linea-ens-resolver/contracts/L1Resolver.sol +++ b/packages/linea-ens-resolver/contracts/L1Resolver.sol @@ -39,7 +39,7 @@ contract L1Resolver is uint256 constant VERSIONABLE_HASHES_SLOT = 3; uint256 constant VERSIONABLE_TEXTS_SLOT = 10; // To check how old is the value/proof returned and is in the acceptable range - uint256 constant L2_BLOCK_RANGE_ACCEPTED = 86400; + uint256 constant ACCEPTED_L2_BLOCK_RANGE_LENGTH = 86400; string public graphqlUrl; event TargetSet(bytes name, address target); @@ -94,6 +94,18 @@ contract L1Resolver is l2ChainId = _l2ChainId; } + /** + * @dev inherits from EVMFetchTarget + */ + function getAcceptedL2BlockRangeLength() + public + pure + override + returns (uint256) + { + return ACCEPTED_L2_BLOCK_RANGE_LENGTH; + } + /** * Set target address to verify against * @param name The encoded name to query. @@ -209,10 +221,7 @@ contract L1Resolver is .ref(0) .element(node) .element(COIN_TYPE_ETH) - .fetch( - this.addrCallback.selector, - abi.encode(L2_BLOCK_RANGE_ACCEPTED) - ); // recordVersions + .fetch(this.addrCallback.selector, ""); // recordVersions } function addrCallback( @@ -235,10 +244,7 @@ contract L1Resolver is .ref(0) .element(node) .element(coinType) - .fetch( - this.addrCoinTypeCallback.selector, - abi.encode(L2_BLOCK_RANGE_ACCEPTED) - ); + .fetch(this.addrCoinTypeCallback.selector, ""); } function addrCoinTypeCallback( @@ -261,10 +267,7 @@ contract L1Resolver is .ref(0) .element(node) .element(key) - .fetch( - this.textCallback.selector, - abi.encode(L2_BLOCK_RANGE_ACCEPTED) - ); + .fetch(this.textCallback.selector, ""); } function textCallback( @@ -285,10 +288,7 @@ contract L1Resolver is .getDynamic(VERSIONABLE_HASHES_SLOT) .ref(0) .element(node) - .fetch( - this.contenthashCallback.selector, - abi.encode(L2_BLOCK_RANGE_ACCEPTED) - ); + .fetch(this.contenthashCallback.selector, ""); } function contenthashCallback( diff --git a/packages/linea-ens-resolver/test/testData.ts b/packages/linea-ens-resolver/test/testData.ts index 57e8bf6db..b5b9b5b82 100644 --- a/packages/linea-ens-resolver/test/testData.ts +++ b/packages/linea-ens-resolver/test/testData.ts @@ -167,10 +167,16 @@ export const proofTest = { }; export const extraDataTest = - "0x0000000000000000000000000b306bf915c4d645ff596e518faf3f9669b9701600000000000000000000000028f15b034f9744d43548ac64dce04ed77bdbd83200000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000120f470901a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003200000000000000000000000000000000000000000000000000000000000000002000001ff000000000000000000000000000000000000000000000000000000000102200304ff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020e312102006c30788eb679837a67baf80dc450ee6bb8ee493b14b16250d3e4922000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000020e312102006c30788eb679837a67baf80dc450ee6bb8ee493b14b16250d3e49220000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003c0000000000000000000000000000000000000000000000000000000000000000"; + "0x0000000000000000000000000b306bf915c4d645ff596e518faf3f9669b9701600000000000000000000000028f15b034f9744d43548ac64dce04ed77bdbd83200000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000120f470901a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003200000000000000000000000000000000000000000000000000000000000000002000001ff000000000000000000000000000000000000000000000000000000000102200304ff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020e312102006c30788eb679837a67baf80dc450ee6bb8ee493b14b16250d3e4922000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000020e312102006c30788eb679837a67baf80dc450ee6bb8ee493b14b16250d3e49220000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003c00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000015180"; export const wrongExtraData = - "0x0000000000000000000000000b306bf915c4d645ff596e518faf3f9669b9701600000000000000000000000028f15b034f9744d43548ac64dce04ed77bdbd83100000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000120f470901a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003200000000000000000000000000000000000000000000000000000000000000002000001ff000000000000000000000000000000000000000000000000000000000102200304ff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020e312102006c30788eb679837a67baf80dc450ee6bb8ee493b14b16250d3e4922000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000020e312102006c30788eb679837a67baf80dc450ee6bb8ee493b14b16250d3e49220000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003c0000000000000000000000000000000000000000000000000000000000000000"; + "0x0000000000000000000000000b306bf915c4d645ff596e518faf3f9669b9701600000000000000000000000028f15b034f9744d43548ac64dce04ed77bdbd83100000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000120f470901a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003200000000000000000000000000000000000000000000000000000000000000002000001ff000000000000000000000000000000000000000000000000000000000102200304ff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020e312102006c30788eb679837a67baf80dc450ee6bb8ee493b14b16250d3e4922000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000020e312102006c30788eb679837a67baf80dc450ee6bb8ee493b14b16250d3e49220000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003c00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000015180"; + +export const extraDataWithLongCallBackData = + "0x0000000000000000000000000b306bf915c4d645ff596e518faf3f9669b9701600000000000000000000000028f15b034f9744d43548ac64dce04ed77bdbd83200000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000120f470901a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003200000000000000000000000000000000000000000000000000000000000000002000001ff000000000000000000000000000000000000000000000000000000000102200304ff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020e312102006c30788eb679837a67baf80dc450ee6bb8ee493b14b16250d3e4922000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000020e312102006c30788eb679837a67baf80dc450ee6bb8ee493b14b16250d3e49220000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000151801231242aef3450"; + +export const extraDataWithShortCallBackData = + "0x0000000000000000000000000b306bf915c4d645ff596e518faf3f9669b9701600000000000000000000000028f15b034f9744d43548ac64dce04ed77bdbd83200000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000120f470901a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003200000000000000000000000000000000000000000000000000000000000000002000001ff000000000000000000000000000000000000000000000000000000000102200304ff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020e312102006c30788eb679837a67baf80dc450ee6bb8ee493b14b16250d3e4922000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000020e312102006c30788eb679837a67baf80dc450ee6bb8ee493b14b16250d3e49220000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000015180"; export const commandsTest = [ "0x000001ff00000000000000000000000000000000000000000000000000000000", @@ -190,3 +196,9 @@ export const constantsTest = [ "0xbebd415b7c88e97082bae6b4e3ba6bd83b660b8620cd7f90d99c8564f6e8da9b", "0x000000000000000000000000000000000000000000000000000000000000003c", ]; + +export const retValueTest = + "f470901a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003200000000000000000000000000000000000000000000000000000000000000002000001ff000000000000000000000000000000000000000000000000000000000102200304ff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020e312102006c30788eb679837a67baf80dc450ee6bb8ee493b14b16250d3e4922000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000020e312102006c30788eb679837a67baf80dc450ee6bb8ee493b14b16250d3e49220000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003c00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000015180"; + +export const retValueLongTest = + "f470901a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003200000000000000000000000000000000000000000000000000000000000000002000001ff000000000000000000000000000000000000000000000000000000000102200304ff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020e312102006c30788eb679837a67baf80dc450ee6bb8ee493b14b16250d3e4922000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000020e312102006c30788eb679837a67baf80dc450ee6bb8ee493b14b16250d3e49220000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000151801231242aef345000000000000000000000000000000000000000000000000000"; diff --git a/packages/linea-ens-resolver/test/testL1Resolver.spec.ts b/packages/linea-ens-resolver/test/testL1Resolver.spec.ts index 41c9f03f2..6cc19bb18 100644 --- a/packages/linea-ens-resolver/test/testL1Resolver.spec.ts +++ b/packages/linea-ens-resolver/test/testL1Resolver.spec.ts @@ -25,6 +25,10 @@ import { extraDataTest, stateRoot, wrongExtraData, + extraDataWithLongCallBackData, + extraDataWithShortCallBackData, + retValueTest, + retValueLongTest, } from "./testData"; const labelhash = (label) => ethers.keccak256(ethers.toUtf8Bytes(label)); const encodeName = (name) => "0x" + packet.name.encode(name).toString("hex"); @@ -45,6 +49,8 @@ const EMPTY_BYTES32 = const PROOF_ENCODING_PADDING = "0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000044e0"; +const ACCEPTED_L2_BLOCK_RANGE_LENGTH = 86400; + type ethersObj = typeof ethersT & Omit & { provider: Omit & { @@ -261,6 +267,7 @@ describe("Crosschain Resolver", () => { const incorrectname = encodeName("notowned.eth"); try { await target.setTarget(incorrectname, l2ResolverAddress); + throw "Should have reverted"; } catch (e) { expect(e.reason).equal("Not authorized to set target for this node"); } @@ -397,6 +404,7 @@ describe("Crosschain Resolver", () => { await target.resolve(encodedname, calldata, { enableCcipRead: true, }); + throw "Should have reverted"; } catch (error) { expect(error.reason).to.equal("invalid selector"); } @@ -414,14 +422,13 @@ describe("Crosschain Resolver", () => { await target.resolve(encodedname, calldata, { enableCcipRead: true, }); + throw "Should have reverted"; } catch (error) { expect(error.reason).to.equal("param data too short"); } }); it("should revert if the number of commands is bigger than the number of storage proofs returned by the gateway", async () => { - const currentBlockNo = await rollup.currentL2BlockNumber(); - const currentStateRoot = await rollup.stateRootHashes(currentBlockNo); await rollup.setCurrentStateRoot(blockNo, stateRoot); let proofsEncoded = AbiCoder.defaultAbiCoder().encode( [ @@ -437,22 +444,45 @@ describe("Crosschain Resolver", () => { commands2Test, constantsTest, proofsEncoded, - AbiCoder.defaultAbiCoder().encode(["uint256"], [blockNo]) + ACCEPTED_L2_BLOCK_RANGE_LENGTH ); + throw "Should have reverted"; } catch (error) { expect(error.reason).to.equal( "LineaProofHelper: commands number > storage proofs number" ); } - // Put back the right block number and state root - await rollup.setCurrentStateRoot(currentBlockNo, currentStateRoot); }); - it("should revert if the block number returned by the gateway is not the most recent one", async () => { - const currentBlockNo = await rollup.currentL2BlockNumber(); - const currentStateRoot = await rollup.stateRootHashes(currentBlockNo); - // Put a wrong block number - await rollup.setCurrentStateRoot(blockNo + 100_000, stateRoot); + it("should not revert if the block number returned by the gateway is in the accepted block range", async () => { + await rollup.setCurrentStateRoot(blockNo, stateRoot); + await rollup.setCurrentStateRoot( + blockNo + ACCEPTED_L2_BLOCK_RANGE_LENGTH - 10, + stateRoot + ); + let proofsEncoded = AbiCoder.defaultAbiCoder().encode( + [ + "uint256", + "tuple(bytes key, uint256 leafIndex, tuple(bytes value, bytes[] proofRelatedNodes) proof)", + "tuple(bytes32 key, uint256 leafIndex, tuple(bytes32 value, bytes[] proofRelatedNodes) proof, bool initialized)[]", + ], + [blockNo, proofTest.accountProof, proofTest.storageProofs] + ); + proofsEncoded = PROOF_ENCODING_PADDING + proofsEncoded.substring(2); + + const result = await target.getStorageSlotsCallback( + proofsEncoded, + extraDataTest + ); + expect(result.data.endsWith(retValueTest)).to.be.true; + }); + + it("should revert if the block number returned by the gateway is not in the accepted block range", async () => { + await rollup.setCurrentStateRoot(blockNo, stateRoot); + await rollup.setCurrentStateRoot( + blockNo + ACCEPTED_L2_BLOCK_RANGE_LENGTH + 10, + stateRoot + ); let proofsEncoded = AbiCoder.defaultAbiCoder().encode( [ "uint256", @@ -464,18 +494,116 @@ describe("Crosschain Resolver", () => { proofsEncoded = PROOF_ENCODING_PADDING + proofsEncoded.substring(2); try { await target.getStorageSlotsCallback(proofsEncoded, extraDataTest); + throw "Should have reverted"; } catch (error) { expect(error.reason).to.equal( "LineaSparseProofVerifier: block not in range accepted" ); } - // Put back the right block number and state root - await rollup.setCurrentStateRoot(currentBlockNo, currentStateRoot); + }); + + it("should not revert when callbackdata > 32 bytes", async () => { + await rollup.setCurrentStateRoot(blockNo, stateRoot); + await rollup.setCurrentStateRoot( + blockNo + ACCEPTED_L2_BLOCK_RANGE_LENGTH - 10, + stateRoot + ); + let proofsEncoded = AbiCoder.defaultAbiCoder().encode( + [ + "uint256", + "tuple(bytes key, uint256 leafIndex, tuple(bytes value, bytes[] proofRelatedNodes) proof)", + "tuple(bytes32 key, uint256 leafIndex, tuple(bytes32 value, bytes[] proofRelatedNodes) proof, bool initialized)[]", + ], + [blockNo, proofTest.accountProof, proofTest.storageProofs] + ); + proofsEncoded = PROOF_ENCODING_PADDING + proofsEncoded.substring(2); + + const result = await target.getStorageSlotsCallback( + proofsEncoded, + extraDataWithLongCallBackData + ); + + expect(result.data.endsWith(retValueLongTest)).to.be.true; + }); + + it("should revert when callbackdata < 32 bytes", async () => { + await rollup.setCurrentStateRoot(blockNo, stateRoot); + await rollup.setCurrentStateRoot( + blockNo + ACCEPTED_L2_BLOCK_RANGE_LENGTH - 10, + stateRoot + ); + let proofsEncoded = AbiCoder.defaultAbiCoder().encode( + [ + "uint256", + "tuple(bytes key, uint256 leafIndex, tuple(bytes value, bytes[] proofRelatedNodes) proof)", + "tuple(bytes32 key, uint256 leafIndex, tuple(bytes32 value, bytes[] proofRelatedNodes) proof, bool initialized)[]", + ], + [blockNo, proofTest.accountProof, proofTest.storageProofs] + ); + proofsEncoded = PROOF_ENCODING_PADDING + proofsEncoded.substring(2); + + try { + await target.getStorageSlotsCallback( + proofsEncoded, + extraDataWithShortCallBackData + ); + throw "Should have reverted"; + } catch (error) { + expect(error.reason).to.equal("require(false)"); + } + }); + + it("should not revert when block sent by the gateway <= currentL2BlockNumber and currentL2BlockNumber <= ACCEPTED_BLOCK_RANGE_LENGTH", async () => { + const veryOldBlockNb = 1; + await rollup.setCurrentStateRoot(veryOldBlockNb, stateRoot); + await rollup.setCurrentStateRoot(ACCEPTED_L2_BLOCK_RANGE_LENGTH, stateRoot); + let proofsEncoded = AbiCoder.defaultAbiCoder().encode( + [ + "uint256", + "tuple(bytes key, uint256 leafIndex, tuple(bytes value, bytes[] proofRelatedNodes) proof)", + "tuple(bytes32 key, uint256 leafIndex, tuple(bytes32 value, bytes[] proofRelatedNodes) proof, bool initialized)[]", + ], + [veryOldBlockNb, proofTest.accountProof, proofTest.storageProofs] + ); + proofsEncoded = PROOF_ENCODING_PADDING + proofsEncoded.substring(2); + + const result = await target.getStorageSlotsCallback( + proofsEncoded, + extraDataTest + ); + + expect(result.data.endsWith(retValueTest)).to.be.true; + }); + + it("should revert when block sent by the gateway > currentL2BlockNumber and currentL2BlockNumber <= ACCEPTED_BLOCK_RANGE_LENGTH", async () => { + const veryOldBlockNb = ACCEPTED_L2_BLOCK_RANGE_LENGTH + 1; + await rollup.setCurrentStateRoot(veryOldBlockNb, stateRoot); + await rollup.setCurrentStateRoot(ACCEPTED_L2_BLOCK_RANGE_LENGTH, stateRoot); + let proofsEncoded = AbiCoder.defaultAbiCoder().encode( + [ + "uint256", + "tuple(bytes key, uint256 leafIndex, tuple(bytes value, bytes[] proofRelatedNodes) proof)", + "tuple(bytes32 key, uint256 leafIndex, tuple(bytes32 value, bytes[] proofRelatedNodes) proof, bool initialized)[]", + ], + [ + veryOldBlockNb + ACCEPTED_L2_BLOCK_RANGE_LENGTH, + proofTest.accountProof, + proofTest.storageProofs, + ] + ); + proofsEncoded = PROOF_ENCODING_PADDING + proofsEncoded.substring(2); + + try { + await target.getStorageSlotsCallback(proofsEncoded, extraDataTest); + throw "Should have reverted"; + } catch (error) { + expect(error.reason).to.equal( + "LineaSparseProofVerifier: invalid state root" + ); + } }); it("should revert if the proof's target is not matching the one queried", async () => { - const currentBlockNo = await rollup.currentL2BlockNumber(); - const currentStateRoot = await rollup.stateRootHashes(currentBlockNo); // Set the block number and stateRoot to match the predefined proof in the proof test file await rollup.setCurrentStateRoot(blockNo, stateRoot); let proofsEncoded = AbiCoder.defaultAbiCoder().encode( @@ -489,10 +617,9 @@ describe("Crosschain Resolver", () => { proofsEncoded = PROOF_ENCODING_PADDING + proofsEncoded.substring(2); try { await target.getStorageSlotsCallback(proofsEncoded, wrongExtraData); + throw "Should have reverted"; } catch (error) { expect(error.reason).to.equal("LineaProofHelper: wrong target"); } - // Put back block number and state root - await rollup.setCurrentStateRoot(currentBlockNo, currentStateRoot); }); }); diff --git a/packages/linea-state-verifier/contracts/EVMFetchTarget.sol b/packages/linea-state-verifier/contracts/EVMFetchTarget.sol index 0f4102543..e04ab50ec 100644 --- a/packages/linea-state-verifier/contracts/EVMFetchTarget.sol +++ b/packages/linea-state-verifier/contracts/EVMFetchTarget.sol @@ -27,26 +27,37 @@ abstract contract EVMFetchTarget { bytes32[] memory commands, bytes[] memory constants, bytes4 callback, - uint256 l2BlockRangeAccepted + bytes memory callbackData ) = abi.decode( extradata, - (IEVMVerifier, address, bytes32[], bytes[], bytes4, uint256) + (IEVMVerifier, address, bytes32[], bytes[], bytes4, bytes) ); + bytes[] memory values = verifier.getStorageValues( addr, commands, constants, proof, - l2BlockRangeAccepted + getAcceptedL2BlockRangeLength() ); if (values.length != commands.length) { revert ResponseLengthMismatch(values.length, commands.length); } bytes memory ret = address(this).functionCall( - abi.encodeWithSelector(callback, values, "") + abi.encodeWithSelector(callback, values, callbackData) ); assembly { return(add(ret, 32), mload(ret)) } } + + /** + * @dev The child contract has to return an accepted L2 block range used by the verifier + * to verify that the block number verified is in the accepted block range. + */ + function getAcceptedL2BlockRangeLength() + public + view + virtual + returns (uint256); } diff --git a/packages/linea-state-verifier/contracts/IEVMVerifier.sol b/packages/linea-state-verifier/contracts/IEVMVerifier.sol index 77d7f1bca..1c0679c3b 100644 --- a/packages/linea-state-verifier/contracts/IEVMVerifier.sol +++ b/packages/linea-state-verifier/contracts/IEVMVerifier.sol @@ -9,6 +9,6 @@ interface IEVMVerifier { bytes32[] memory commands, bytes[] memory constants, bytes memory proof, - uint256 l2BlockRangeAccepted + uint256 acceptedL2BlockRangeLength ) external view returns (bytes[] memory values); } diff --git a/packages/linea-state-verifier/contracts/LineaSparseProofVerifier.sol b/packages/linea-state-verifier/contracts/LineaSparseProofVerifier.sol index 66473f4c2..2bf4c0bd2 100644 --- a/packages/linea-state-verifier/contracts/LineaSparseProofVerifier.sol +++ b/packages/linea-state-verifier/contracts/LineaSparseProofVerifier.sol @@ -26,7 +26,7 @@ contract LineaSparseProofVerifier is IEVMVerifier { bytes32[] memory commands, bytes[] memory constants, bytes memory proof, - uint256 l2BlockRangeAccepted + uint256 acceptedL2BlockRangeLength ) external view returns (bytes[] memory values) { ( uint256 blockNo, @@ -40,9 +40,9 @@ contract LineaSparseProofVerifier is IEVMVerifier { // Check that the L2 block number used is a recent one and is part of the range accepted uint256 currentL2BlockNumber = IRollup(_rollup).currentL2BlockNumber(); require( - (currentL2BlockNumber <= l2BlockRangeAccepted && + (currentL2BlockNumber <= acceptedL2BlockRangeLength && blockNo <= currentL2BlockNumber) || - blockNo >= currentL2BlockNumber - l2BlockRangeAccepted, + (blockNo >= currentL2BlockNumber - acceptedL2BlockRangeLength), "LineaSparseProofVerifier: block not in range accepted" );