Skip to content

Commit

Permalink
yep yep yep yep
Browse files Browse the repository at this point in the history
  • Loading branch information
TateB committed Aug 22, 2024
1 parent 400229b commit a4740e3
Show file tree
Hide file tree
Showing 13 changed files with 260 additions and 252 deletions.
2 changes: 1 addition & 1 deletion arb-gateway/src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ const proofService = new ArbProofService({
l2RollupAddress,
cache: new InMemoryBlockCache(),
});

const gateway = new EVMGateway(proofService);

const router = CcipReadRouter({
port,
});
Expand Down
Binary file modified bun.lockb
Binary file not shown.
6 changes: 3 additions & 3 deletions evm-gateway/src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { type Request as CFWRequest } from '@cloudflare/workers-types';
import { type PropsDecoder } from '@ensdomains/server-analytics';
import type { Request as CFWRequest } from '@cloudflare/workers-types';
import type { PropsDecoder } from '@ensdomains/server-analytics';
import {
encodeAbiParameters,
parseAbiParameter,
Expand All @@ -10,7 +10,7 @@ import {
} from 'viem';

import type { AbiParametersToPrimitiveTypes } from 'abitype';
import { type StateProof } from './EVMProofHelper.js';
import type { StateProof } from './EVMProofHelper.js';

export interface Router {
handle: (request: CFWRequest) => Promise<Response>;
Expand Down
4 changes: 3 additions & 1 deletion l1-gateway/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"version": "0.1.0-beta.4",
"author": "Nick Johnson",
"license": "MIT",
"type": "module",
"repository": {
"type": "git",
"url": "https://github.com/ensdomains/evmgateway.git"
Expand Down Expand Up @@ -65,10 +66,11 @@
"dependencies": {
"@chainlink/ccip-read-server": "^0.2.1",
"@commander-js/extra-typings": "^11.0.0",
"@ensdomains/ccip-read-router": "^0.0.5",
"@ensdomains/evm-gateway": "0.1.0-beta.4",
"@ethereumjs/block": "^5.0.0",
"@nomicfoundation/ethereumjs-block": "^5.0.2",
"commander": "^11.0.0",
"ethers": "^6.7.1"
}
}
}
130 changes: 90 additions & 40 deletions l1-gateway/src/L1ProofService.ts
Original file line number Diff line number Diff line change
@@ -1,43 +1,48 @@
import {
AbiCoder,
encodeRlp as encodeRlp_,
type AddressLike,
type JsonRpcProvider,
} from 'ethers';

import {
EVMProofHelper,
convertIntoMerkleTrieProof,
type IProofService,
} from '@ensdomains/evm-gateway';
import { Block, type JsonRpcBlock } from '@ethereumjs/block';

type RlpObject = Uint8Array | Array<RlpObject>;
const encodeRlp = encodeRlp_ as (object: RlpObject) => string;
import {
encodeAbiParameters,
parseAbiParameters,
toRlp,
type Address,
type Client,
type Hex,
} from 'viem';
import { getBlock } from 'viem/actions';

export type L1ProvableBlock = number;

const toIdkHex = (val: bigint): Hex => {
if (val === 0n) return '0x';
const hexxed = val.toString(16);
return `0x${hexxed.length % 2 === 0 ? hexxed : `0${hexxed}`}`;
};

/**
* The proofService class can be used to calculate proofs for a given target and slot on the Optimism Bedrock network.
* It's also capable of proofing long types such as mappings or string by using all included slots in the proof.
*
*/
export class L1ProofService implements IProofService<L1ProvableBlock> {
private readonly provider: JsonRpcProvider;
private readonly client: Client;
private readonly helper: EVMProofHelper;

constructor(provider: JsonRpcProvider) {
this.provider = provider;
this.helper = new EVMProofHelper(provider);
constructor(client: Client) {
this.client = client;
this.helper = new EVMProofHelper(client);
}

/**
* @dev Returns an object representing a block whose state can be proven on L1.
*/
async getProvableBlock(): Promise<number> {
const block = await this.provider.getBlock('latest');
async getProvableBlock(): Promise<L1ProvableBlock> {
const block = await getBlock(this.client, { blockTag: 'latest' });
if (!block) throw new Error('No block found');
return block.number - 1;
return Number(block.number) - 1;
}

/**
Expand All @@ -47,12 +52,16 @@ export class L1ProofService implements IProofService<L1ProvableBlock> {
* @param slot The slot to fetch.
* @returns The value in `slot` of `address` at block `block`
*/
getStorageAt(
block: L1ProvableBlock,
address: AddressLike,
slot: bigint
): Promise<string> {
return this.helper.getStorageAt(block, address, slot);
getStorageAt({
block,
address,
slot,
}: {
block: L1ProvableBlock;
address: Address;
slot: bigint;
}): Promise<Hex> {
return this.helper.getStorageAt({ blockNumber: block, address, slot });
}

/**
Expand All @@ -63,24 +72,65 @@ export class L1ProofService implements IProofService<L1ProvableBlock> {
* @returns A proof of the given slots, encoded in a manner that this service's
* corresponding decoding library will understand.
*/
async getProofs(
blockNo: L1ProvableBlock,
address: AddressLike,
slots: bigint[]
): Promise<string> {
const proof = await this.helper.getProofs(blockNo, address, slots);
const rpcBlock: JsonRpcBlock = await this.provider.send(
'eth_getBlockByNumber',
['0x' + blockNo.toString(16), false]
);
const block = Block.fromRPC(rpcBlock);
const blockHeader = encodeRlp(block.header.raw());
return AbiCoder.defaultAbiCoder().encode(
async getProofs({
block,
address,
slots,
}: {
block: L1ProvableBlock;
address: Address;
slots: bigint[];
}): Promise<Hex> {
const proof = await this.helper.getProofs({
blockNumber: block,
address,
slots,
});
const comparisonBlock = await getBlock(this.client, {
blockNumber: BigInt(block),
includeTransactions: false,
});

if (!comparisonBlock) throw new Error('Block not found');

const headerArray = [
comparisonBlock.parentHash,
comparisonBlock.sha3Uncles,
comparisonBlock.miner,
comparisonBlock.stateRoot,
comparisonBlock.transactionsRoot,
comparisonBlock.receiptsRoot,
comparisonBlock.logsBloom!,
toIdkHex(comparisonBlock.difficulty),
toIdkHex(comparisonBlock.number!),
toIdkHex(comparisonBlock.gasLimit),
toIdkHex(comparisonBlock.gasUsed), // 10
toIdkHex(comparisonBlock.timestamp),
comparisonBlock.extraData,
comparisonBlock.mixHash,
comparisonBlock.nonce!,
toIdkHex(comparisonBlock.baseFeePerGas!), // 15
...(comparisonBlock.withdrawalsRoot
? [comparisonBlock.withdrawalsRoot]
: (['0x'] as const)), // anvil ???
...(typeof comparisonBlock.blobGasUsed === 'bigint'
? [
toIdkHex(comparisonBlock.blobGasUsed),
toIdkHex(comparisonBlock.excessBlobGas),
]
: []),
];

const blockHeader = toRlp(headerArray) as Hex;
return encodeAbiParameters(
parseAbiParameters([
'(uint256 blockNumber, bytes blockHeader)',
'(bytes stateTrieWitness, bytes[] storageProofs)',
]),
[
'tuple(uint256 blockNo, bytes blockHeader)',
'tuple(bytes stateTrieWitness, bytes[] storageProofs)',
],
[{ blockNo, blockHeader }, convertIntoMerkleTrieProof(proof)]
{ blockNumber: BigInt(block), blockHeader },
convertIntoMerkleTrieProof(proof),
]
);
}
}
10 changes: 7 additions & 3 deletions l1-gateway/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import { EVMGateway } from '@ensdomains/evm-gateway';
import { JsonRpcProvider } from 'ethers';
import { createClient, http } from 'viem';
import { L1ProofService, type L1ProvableBlock } from './L1ProofService.js';

export type L1Gateway = EVMGateway<L1ProvableBlock>;

export function makeL1Gateway(provider: JsonRpcProvider): L1Gateway {
return new EVMGateway(new L1ProofService(provider));
export function createL1Gateway(providerUrl: string): L1Gateway {
const client = createClient({ transport: http(providerUrl) });

const proofService = new L1ProofService(client);

return new EVMGateway(proofService);
}

export { L1ProofService, type L1ProvableBlock };
26 changes: 11 additions & 15 deletions l1-gateway/src/server.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { Server } from '@chainlink/ccip-read-server';
import { Command } from '@commander-js/extra-typings';
import { CcipReadRouter } from '@ensdomains/ccip-read-router';
import { EVMGateway } from '@ensdomains/evm-gateway';
import { ethers } from 'ethers';
import { createClient, http } from 'viem';

import { L1ProofService } from './L1ProofService.js';

const program = new Command()
Expand All @@ -10,18 +11,13 @@ const program = new Command()

program.parse();

const options = program.opts();
const provider = new ethers.JsonRpcProvider(options.providerUrl);
const gateway = new EVMGateway(new L1ProofService(provider));
const server = new Server();
gateway.add(server);
const app = server.makeApp('/');
const { port, providerUrl } = program.opts();

const client = createClient({ transport: http(providerUrl) });
const proofService = new L1ProofService(client);
const gateway = new EVMGateway(proofService);

const port = parseInt(options.port);
if (String(port) !== options.port) throw new Error('Invalid port');
const router = CcipReadRouter({ port });
gateway.add(router);

(async () => {
app.listen(port, function () {
console.log(`Listening on ${port}`);
});
})();
export default router;
35 changes: 17 additions & 18 deletions l1-gateway/src/worker.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,24 @@
import { Request as CFWRequest } from '@cloudflare/workers-types';
import { Server } from '@ensdomains/ccip-read-cf-worker';
import type { Router } from '@ensdomains/evm-gateway';
import type { Request as CFWRequest } from '@cloudflare/workers-types';
import { CcipReadRouter } from '@ensdomains/ccip-read-router';
import { EVMGateway } from '@ensdomains/evm-gateway';
import { createClient, http } from 'viem';
import { L1ProofService } from './L1ProofService.js';

interface Env {
WORKER_PROVIDER_URL: string;
}
let app: Router;

async function fetch(request: CFWRequest, env: Env) {
// Loading libraries dynamically as a temp work around.
// Otherwise, deployment thorws "Error: Script startup exceeded CPU time limit." error
if (!app) {
const ethers = await import('ethers');
const EVMGateway = (await import('@ensdomains/evm-gateway')).EVMGateway;
const L1ProofService = (await import('./L1ProofService.js')).L1ProofService;
const { WORKER_PROVIDER_URL } = env;
const provider = new ethers.JsonRpcProvider(WORKER_PROVIDER_URL);
const gateway = new EVMGateway(new L1ProofService(provider));
const server = new Server();
gateway.add(server);
app = server.makeApp('/');
}
return app.handle(request);
const { WORKER_PROVIDER_URL } = env;

const client = createClient({ transport: http(WORKER_PROVIDER_URL) });
const proofService = new L1ProofService(client);
const gateway = new EVMGateway(proofService);

const router = CcipReadRouter();
gateway.add(router);

return router.fetch(request);
}

export default {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import '@nomicfoundation/hardhat-toolbox';
import '@nomicfoundation/hardhat-toolbox-viem';
import { HardhatUserConfig } from 'hardhat/config';

const config: HardhatUserConfig = {
solidity: '0.8.19',
networks: {
ganache: {
anvil: {
url: `http://localhost:${parseInt(process.env['RPC_PORT'] || '8545')}`,
},
},
Expand Down
28 changes: 9 additions & 19 deletions l1-verifier/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"name": "@ensdomains/l1-verifier",
"license": "MIT",
"version": "0.1.0-beta.4",
"type": "module",
"repository": {
"type": "git",
"url": "https://github.com/ensdomains/evmgateway.git"
Expand All @@ -11,37 +12,26 @@
},
"homepage": "https://github.com/ensdomains/evmgateway/tree/main/l1-verifier",
"scripts": {
"build": "echo 'building l1-verifier...' && bun hardhat compile",
"hh": "NODE_OPTIONS='--experimental-loader ts-node/esm/transpile-only' hardhat",
"build": "echo 'building l1-verifier...' && bun hh compile",
"test": "node ./scripts/test.js",
"remote_test": "hardhat run scripts/remote.ts",
"remote_test": "hh run scripts/remote.ts",
"clean": "rm -fr artifacts cache node_modules typechain-types",
"lint": "exit 0"
},
"devDependencies": {
"@ensdomains/ccip-read-router": "^0.0.5",
"@ensdomains/l1-gateway": "0.1.0-beta.4",
"@nomicfoundation/hardhat-chai-matchers": "^2.0.0",
"@nomicfoundation/hardhat-ethers": "^3.0.0",
"@nomicfoundation/hardhat-network-helpers": "^1.0.0",
"@nomicfoundation/hardhat-toolbox": "^3.0.0",
"@nomicfoundation/hardhat-verify": "^1.0.0",
"@nomiclabs/hardhat-ganache": "^2.0.1",
"@typechain/ethers-v6": "^0.4.0",
"@typechain/hardhat": "^8.0.0",
"@nomicfoundation/hardhat-toolbox-viem": "^3.0.0",
"@types/chai": "^4.2.0",
"@types/express": "^4.17.18",
"@types/mocha": ">=9.1.0",
"@types/supertest": "^2.0.14",
"@viem/anvil": "^0.0.10",
"@whatwg-node/server": "^0.9.49",
"chai": "^4.2.0",
"ethers": "^6.8.0",
"express": "^4.18.2",
"ganache": "^7.9.1",
"hardhat": "^2.17.4",
"hardhat-gas-reporter": "^1.0.8",
"solidity-bytes-utils": "^0.8.0",
"solidity-coverage": "^0.8.1",
"supertest": "^6.3.3",
"hardhat": "^2.22.9",
"ts-node": "^10.9.1",
"typechain": "^8.2.0",
"typescript": "^5.2.2"
},
"dependencies": {
Expand Down
Loading

0 comments on commit a4740e3

Please sign in to comment.