diff --git a/arb-gateway/src/ArbProofService.ts b/arb-gateway/src/ArbProofService.ts index fc4cac9b..f31aad03 100644 --- a/arb-gateway/src/ArbProofService.ts +++ b/arb-gateway/src/ArbProofService.ts @@ -1,5 +1,5 @@ /* eslint-disable prettier/prettier */ -import { EVMProofHelper, type IProofService } from '@ensdomains/evm-gateway'; +import { EVMProofHelper, convertIntoMerkleTrieProof, type IProofService } from '@ensdomains/evm-gateway'; import { AbiCoder, Contract, EventLog, ethers, toBeHex, type AddressLike, toNumber } from 'ethers'; import rollupAbi from "./abi/rollupABI.js"; import type { IBlockCache } from './blockCache/IBlockCache.js'; @@ -63,7 +63,7 @@ export class ArbProofService implements IProofService { return AbiCoder.defaultAbiCoder().encode( [ 'tuple(bytes32 version, bytes32 sendRoot, uint64 nodeIndex,bytes rlpEncodedBlock)', - 'tuple(bytes[] stateTrieWitness, bytes[][] storageProofs)', + 'tuple(bytes stateTrieWitness, bytes[] storageProofs)', ], [ { @@ -73,7 +73,7 @@ export class ArbProofService implements IProofService { nodeIndex: block.nodeIndex, rlpEncodedBlock: block.rlpEncodedBlock }, - proof, + convertIntoMerkleTrieProof(proof) ] ); } diff --git a/evm-gateway/src/EVMProofHelper.ts b/evm-gateway/src/EVMProofHelper.ts index e18ee0a2..d4395163 100644 --- a/evm-gateway/src/EVMProofHelper.ts +++ b/evm-gateway/src/EVMProofHelper.ts @@ -4,7 +4,7 @@ import { toBeHex, type AddressLike, type JsonRpcProvider } from 'ethers'; * Response of the eth_getProof RPC method. */ interface EthGetProofResponse { - accountProof: string[]; + accountProof: string; balance: string; codeHash: string; nonce: string; @@ -12,13 +12,13 @@ interface EthGetProofResponse { storageProof: { key: string; value: string; - proof: string[]; + proof: string; }[]; } export interface StateProof { - stateTrieWitness: string[]; - storageProofs: string[][]; + stateTrieWitness: string; + storageProofs: string[]; stateRoot: string; } diff --git a/evm-gateway/src/index.ts b/evm-gateway/src/index.ts index b582ddbc..8a7c5a24 100644 --- a/evm-gateway/src/index.ts +++ b/evm-gateway/src/index.ts @@ -1,4 +1,4 @@ export { EVMGateway, StorageLayout } from './EVMGateway.js'; export { EVMProofHelper, type StateProof } from './EVMProofHelper.js'; export type { IProofService, ProvableBlock } from './IProofService.js'; -export { propsDecoder, type Router } from './utils.js'; +export { propsDecoder, convertIntoMerkleTrieProof,type Router } from './utils.js'; diff --git a/evm-gateway/src/utils.ts b/evm-gateway/src/utils.ts index e3975480..440a5b39 100644 --- a/evm-gateway/src/utils.ts +++ b/evm-gateway/src/utils.ts @@ -1,5 +1,7 @@ import { type Request as CFWRequest } from '@cloudflare/workers-types'; import { type PropsDecoder } from '@ensdomains/server-analytics'; +import { AbiCoder } from 'ethers'; +import { type StateProof } from './EVMProofHelper.js'; export interface Router { handle: (request: CFWRequest) => Promise; } @@ -22,3 +24,18 @@ export const propsDecoder: PropsDecoder = ( return {}; } }; + +export const convertIntoMerkleTrieProof = ( + proof: StateProof +) => { + const storageProofs:any = [] + const stateTrieWitness = AbiCoder.defaultAbiCoder().encode(["bytes[]"], [proof.stateTrieWitness]) + for (let index = 0; index < proof.storageProofs.length; index++) { + const storageProof = AbiCoder.defaultAbiCoder().encode(["bytes[]"], [proof.storageProofs[index]]) + storageProofs[index] = storageProof + } + return({ + stateTrieWitness, + storageProofs + }) +} diff --git a/evm-verifier/contracts/EVMProofHelper.sol b/evm-verifier/contracts/EVMProofHelper.sol index c691862a..bc8621fc 100644 --- a/evm-verifier/contracts/EVMProofHelper.sol +++ b/evm-verifier/contracts/EVMProofHelper.sol @@ -6,8 +6,8 @@ import {Bytes} from "@eth-optimism/contracts-bedrock/src/libraries/Bytes.sol"; import {SecureMerkleTrie} from "./SecureMerkleTrie.sol"; struct StateProof { - bytes[] stateTrieWitness; // Witness proving the `storageRoot` against a state root. - bytes[][] storageProofs; // An array of proofs of individual storage elements + bytes stateTrieWitness; // Witness proving the `storageRoot` against a state root. + bytes[] storageProofs; // An array of proofs of individual storage elements } uint8 constant OP_CONSTANT = 0x00; @@ -31,10 +31,10 @@ library EVMProofHelper { */ function getSingleStorageProof( address target, - function(address,uint256,bytes[] memory, bytes32) internal view returns(bytes memory) getter, + function(address,uint256,bytes memory, bytes32) internal view returns(bytes memory) getter, bytes32 storageRoot, uint256 slot, - bytes[] memory witness + bytes memory witness ) private view returns (bytes memory) { return getter( target, @@ -46,8 +46,8 @@ library EVMProofHelper { function getFixedValue( address target, - function(address,uint256,bytes[] memory, bytes32) internal view returns(bytes memory) getter, - bytes32 storageRoot, uint256 slot, bytes[] memory witness + function(address,uint256,bytes memory, bytes32) internal view returns(bytes memory) getter, + bytes32 storageRoot, uint256 slot, bytes memory witness ) private view returns(bytes32) { bytes memory value = getSingleStorageProof(target, getter, storageRoot, slot, witness); // RLP encoded storage slots are stored without leading 0 bytes. @@ -85,8 +85,8 @@ library EVMProofHelper { function getDynamicValue( address target, - function(address,uint256,bytes[] memory, bytes32) internal view returns(bytes memory) getter, - bytes32 storageRoot, uint256 slot, bytes[][] memory proof, uint256 proofIdx) private view returns(bytes memory value, uint256 newProofIdx + function(address,uint256,bytes memory, bytes32) internal view returns(bytes memory) getter, + bytes32 storageRoot, uint256 slot, bytes[] memory proof, uint256 proofIdx) private view returns(bytes memory value, uint256 newProofIdx ) { uint256 firstValue = uint256(getFixedValue(target, getter,storageRoot, slot, proof[proofIdx++])); if(firstValue & 0x01 == 0x01) { @@ -115,8 +115,8 @@ library EVMProofHelper { function getStorageValues( address target, - function(address,uint256,bytes[] memory, bytes32) internal view returns(bytes memory) getter, - bytes32[] memory commands, bytes[] memory constants, bytes32 storageRoot, bytes[][] memory proof) internal view returns(bytes[] memory values + function(address,uint256,bytes memory, bytes32) internal view returns(bytes memory) getter, + bytes32[] memory commands, bytes[] memory constants, bytes32 storageRoot, bytes[] memory proof) internal view returns(bytes[] memory values ) { uint256 proofIdx = 0; values = new bytes[](commands.length); diff --git a/evm-verifier/contracts/MerkleTrieProofHelper.sol b/evm-verifier/contracts/MerkleTrieProofHelper.sol index 367f9fe5..87f44f46 100644 --- a/evm-verifier/contracts/MerkleTrieProofHelper.sol +++ b/evm-verifier/contracts/MerkleTrieProofHelper.sol @@ -25,12 +25,12 @@ library MerkleTrieProofHelper { * @return The storage value */ - // function getTrieProof(address, uint256 slot, bytes[] memory witness, bytes32 root) internal pure returns(bytes memory){ - function getTrieProof(address, uint256 slot, bytes[] memory witness, bytes32 root) internal pure returns(bytes memory){ - + function getTrieProof(address, uint256 slot, bytes memory witness, bytes32 root) internal pure returns(bytes memory){ + (bytes[] memory _witness) = abi.decode(witness, (bytes[])); + (bool exists, bytes memory retrievedValue) = SecureMerkleTrie.get( abi.encodePacked(slot), - witness, + _witness, root ); if(!exists) { @@ -47,10 +47,11 @@ library MerkleTrieProofHelper { * @param witness A witness proving the value of the storage root for `target`. * @return The storage root retrieved from the provided state root */ - function getStorageRoot(bytes32 stateRoot, address target, bytes[] memory witness) internal view returns (bytes32) { + function getStorageRoot(bytes32 stateRoot, address target, bytes memory witness) internal view returns (bytes32) { + (bytes[] memory _witness) = abi.decode(witness, (bytes[])); (bool exists, bytes memory encodedResolverAccount) = SecureMerkleTrie.get( abi.encodePacked(target), - witness, + _witness, stateRoot ); if(!exists) { diff --git a/l1-gateway/src/L1ProofService.ts b/l1-gateway/src/L1ProofService.ts index 15d5880e..d246bba8 100644 --- a/l1-gateway/src/L1ProofService.ts +++ b/l1-gateway/src/L1ProofService.ts @@ -5,7 +5,7 @@ import { type JsonRpcProvider, } from 'ethers'; -import { EVMProofHelper, type IProofService } from '@ensdomains/evm-gateway'; +import { EVMProofHelper, convertIntoMerkleTrieProof, type IProofService } from '@ensdomains/evm-gateway'; import { Block, type JsonRpcBlock } from '@ethereumjs/block'; type RlpObject = Uint8Array | Array; @@ -74,9 +74,9 @@ export class L1ProofService implements IProofService { return AbiCoder.defaultAbiCoder().encode( [ 'tuple(uint256 blockNo, bytes blockHeader)', - 'tuple(bytes[] stateTrieWitness, bytes[][] storageProofs)', + 'tuple(bytes stateTrieWitness, bytes[] storageProofs)', ], - [{ blockNo, blockHeader }, proof] + [{ blockNo, blockHeader }, convertIntoMerkleTrieProof(proof)] ); } } diff --git a/l1-verifier/contracts/L1Verifier.sol b/l1-verifier/contracts/L1Verifier.sol index dd72ac17..9f1b9317 100644 --- a/l1-verifier/contracts/L1Verifier.sol +++ b/l1-verifier/contracts/L1Verifier.sol @@ -4,6 +4,7 @@ pragma solidity ^0.8.17; import { IEVMVerifier } from "@ensdomains/evm-verifier/contracts/IEVMVerifier.sol"; import { RLPReader } from "@eth-optimism/contracts-bedrock/src/libraries/rlp/RLPReader.sol"; import { StateProof, EVMProofHelper } from "@ensdomains/evm-verifier/contracts/EVMProofHelper.sol"; +import {MerkleTrieProofHelper} from '@ensdomains/evm-verifier/contracts/MerkleTrieProofHelper.sol'; struct L1WitnessData { uint256 blockNo; @@ -30,6 +31,7 @@ contract L1Verifier is IEVMVerifier { } RLPReader.RLPItem[] memory headerFields = RLPReader.readList(l1Data.blockHeader); bytes32 stateRoot = bytes32(RLPReader.readBytes(headerFields[3])); - return EVMProofHelper.getStorageValues(target, commands, constants, stateRoot, stateProof); + bytes32 storageRoot = MerkleTrieProofHelper.getStorageRoot(stateRoot, target, stateProof.stateTrieWitness); + return EVMProofHelper.getStorageValues(target, MerkleTrieProofHelper.getTrieProof, commands, constants, storageRoot, stateProof.storageProofs); } } diff --git a/op-gateway/src/OPProofService.ts b/op-gateway/src/OPProofService.ts index 7346fcfd..685d8ba7 100644 --- a/op-gateway/src/OPProofService.ts +++ b/op-gateway/src/OPProofService.ts @@ -1,4 +1,4 @@ -import { EVMProofHelper, type IProofService } from '@ensdomains/evm-gateway'; +import { EVMProofHelper, convertIntoMerkleTrieProof, type IProofService } from '@ensdomains/evm-gateway'; import { type JsonRpcBlock } from '@ethereumjs/block'; import { AbiCoder, Contract, JsonRpcProvider, type AddressLike } from 'ethers'; @@ -109,7 +109,7 @@ export class OPProofService implements IProofService { return AbiCoder.defaultAbiCoder().encode( [ 'tuple(uint256 l2OutputIndex, tuple(bytes32 version, bytes32 stateRoot, bytes32 messagePasserStorageRoot, bytes32 latestBlockhash) outputRootProof)', - 'tuple(bytes[] stateTrieWitness, bytes[][] storageProofs)', + 'tuple(bytes stateTrieWitness, bytes[] storageProofs)', ], [ { @@ -123,7 +123,7 @@ export class OPProofService implements IProofService { latestBlockhash: rpcBlock.hash, }, }, - proof, + convertIntoMerkleTrieProof(proof), ] ); } diff --git a/scroll-gateway/src/ScrollProofService.ts b/scroll-gateway/src/ScrollProofService.ts index c66d43f5..b7902b09 100644 --- a/scroll-gateway/src/ScrollProofService.ts +++ b/scroll-gateway/src/ScrollProofService.ts @@ -62,11 +62,10 @@ export class ScrollProofService implements IProofService { const batchIndex = obj.batch_index const proof = await this.helper.getProofs(Number(block.number), address, slots) const compressedProofs:any = [] - const accountProof: Array = proof.stateTrieWitness; + const accountProof: string = proof.stateTrieWitness; for (let index = 0; index < proof.storageProofs.length; index++) { - const storageProof: Array = proof.storageProofs[index]; - compressedProofs[index] = [] - compressedProofs[index][0] = concat([ + const storageProof: string = proof.storageProofs[index]; + compressedProofs[index] = concat([ `0x${accountProof.length.toString(16).padStart(2, "0")}`, ...accountProof, `0x${storageProof.length.toString(16).padStart(2, "0")}`, @@ -77,16 +76,13 @@ export class ScrollProofService implements IProofService { const res:any = AbiCoder.defaultAbiCoder().encode( [ 'tuple(uint256 batchIndex)', - 'tuple(bytes[] stateTrieWitness, bytes[][] storageProofs)', - // Refactoring TODO - // 'tuple(bytes stateTrieWitness, bytes[] storageProofs)', + 'tuple(bytes[] storageProofs)', ], [ { batchIndex }, { - stateTrieWitness:[], storageProofs:compressedProofs }, ] diff --git a/scroll-verifier/contracts/ScrollVerifier.sol b/scroll-verifier/contracts/ScrollVerifier.sol index 5d927055..2d35c4b2 100644 --- a/scroll-verifier/contracts/ScrollVerifier.sol +++ b/scroll-verifier/contracts/ScrollVerifier.sol @@ -1,6 +1,6 @@ //SPDX-License-Identifier: MIT pragma solidity ^0.8.17; -import {StateProof, EVMProofHelper} from '@ensdomains/evm-verifier/contracts/EVMProofHelper.sol'; +import {EVMProofHelper} from '@ensdomains/evm-verifier/contracts/EVMProofHelper.sol'; import {IEVMVerifier} from '@ensdomains/evm-verifier/contracts/IEVMVerifier.sol'; import {RLPReader} from "@eth-optimism/contracts-bedrock/src/libraries/rlp/RLPReader.sol"; @@ -32,6 +32,10 @@ struct ScrollWitnessData { uint256 batchIndex; } +struct StateProof { + bytes[] storageProofs; // An array of proofs of individual storage elements +} + contract ScrollVerifier is IEVMVerifier { error InvalidSlotSize(uint256 size); IScrollChainCommitmentVerifier public immutable verifier; @@ -50,24 +54,9 @@ contract ScrollVerifier is IEVMVerifier { return _gatewayURLs; } - function compressProof( - bytes[] memory stateTrieWitness, - bytes[][] memory storageProofs, - uint256 storageIndex - ) public pure returns (bytes memory output) { - output = abi.encodePacked(uint8(stateTrieWitness.length)); - for (uint256 i = 0; i < stateTrieWitness.length; i++) { - output = abi.encodePacked(output, stateTrieWitness[i]); - } - output = abi.encodePacked(output, uint8(storageProofs[storageIndex].length)); - for (uint256 i = 0; i < storageProofs[storageIndex].length; i++) { - output = abi.encodePacked(output, storageProofs[storageIndex][i]); - } - return output; - } - function getTrieProof(address target, uint256 slot, bytes[] memory compressedProof, bytes32 root) internal view returns(bytes memory){ - (bytes32 stateRoot, bytes32 storageValue) = verifier.verifyZkTrieProof(target, bytes32(slot), compressedProof[0]); + function getTrieProof(address target, uint256 slot, bytes memory compressedProof, bytes32 root) internal view returns(bytes memory){ + (bytes32 stateRoot, bytes32 storageValue) = verifier.verifyZkTrieProof(target, bytes32(slot), compressedProof); require(stateRoot == root, "stateRoot not matched"); return abi.encodePacked(storageValue); }