Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(ccip-gateway): Improve Reliability of the CCIP Gateway #281

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion packages/linea-ccip-gateway/.env.example
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
PORT=8081

L1_PROVIDER_URL=http://127.0.0.1:8545
L1_PROVIDER_URL=https://sepolia.gateway.tenderly.co
L1_PROVIDER_URL_FALLBACK=https://ethereum-sepolia-rpc.publicnode.com
L2_PROVIDER_URL=https://rpc.sepolia.linea.build/
L2_PROVIDER_URL_FALLBACK=https://linea-sepolia-rpc.publicnode.com
L1_ROLLUP_ADDRESS=0xB218f8A4Bc926cF1cA7b3423c154a0D627Bdb7E5
L2_CHAIN_ID=59141
9 changes: 4 additions & 5 deletions packages/linea-ccip-gateway/src/L2ProofService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {
AddressLike,
Contract,
ethers,
JsonRpcProvider,
FallbackProvider,
} from 'ethers';
import { EVMProofHelper, IProofService, StateProof } from './evm-gateway';
import { logDebug, logError } from './utils';
Expand All @@ -23,12 +23,11 @@ export class L2ProofService implements IProofService<L2ProvableBlock> {
private readonly helper: EVMProofHelper;

constructor(
providerL1: JsonRpcProvider,
providerL2: JsonRpcProvider,
providerL1: FallbackProvider,
providerL2: FallbackProvider,
rollupAddress: string,
shomeiNode?: JsonRpcProvider,
) {
this.helper = new EVMProofHelper(providerL2, shomeiNode);
this.helper = new EVMProofHelper(providerL2);
const currentL2BlockNumberIface = new ethers.Interface([
currentL2BlockNumberSig,
]);
Expand Down
54 changes: 32 additions & 22 deletions packages/linea-ccip-gateway/src/evm-gateway/EVMProofHelper.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { AddressLike, ethers, JsonRpcProvider, toBeHex } from 'ethers';
import { AddressLike, FallbackProvider, JsonRpcProvider, toBeHex } from 'ethers';
import { logDebug, logInfo } from '../utils';

interface ProofStruct {
Expand Down Expand Up @@ -26,13 +26,10 @@ export interface StateProof {
*
*/
export class EVMProofHelper {
private readonly providerL2: JsonRpcProvider;
private readonly shomeiNode: JsonRpcProvider;
private readonly providerL2: FallbackProvider;

constructor(providerL2: JsonRpcProvider, shomeiNode?: JsonRpcProvider) {
constructor(providerL2: FallbackProvider) {
this.providerL2 = providerL2;
// shomeiNode optional since an rpc infura nodes can support both eth_getStorageAt and linea_getProof
this.shomeiNode = shomeiNode ? shomeiNode : providerL2;
}

/**
Expand Down Expand Up @@ -63,29 +60,42 @@ export class EVMProofHelper {
address: AddressLike,
slots: bigint[],
): Promise<StateProof> {
const args = [
const args: (AddressLike | string[])[] = [
address,
slots.map(slot => toBeHex(slot, 32)),
'0x' + blockNo.toString(16),
];

logInfo('Calling linea_getProof with args', args);

// We have to reinitilize the provider L2 because of an issue when multiple
// requests are sent at the same time, the provider becomes not aware of
// We have to reinitialize the provider L2 because of an issue when multiple
// requests are sent at the same time, the provider becomes unaware of
// the linea_getProof method
const providerUrl = this.shomeiNode._getConnection().url;
const providerChainId = this.shomeiNode._network.chainId;
const providerL2 = new ethers.JsonRpcProvider(
providerUrl,
providerChainId,
{
staticNetwork: true,
},
);
logDebug('Calling linea_getProof with L2 provider', providerUrl);
const proofs: StateProof = await providerL2.send('linea_getProof', args);
logDebug('Proof result', proofs);
return proofs;

const providerConfigs = this.providerL2.providerConfigs;

for (const config of providerConfigs) {
// @ts-ignore - We know this is a JsonRpcProvider
const provider: JsonRpcProvider = config.provider;

try {
logDebug(
`Trying provider with URL: ${provider._getConnection().url}`,
);

const proofs: StateProof = await provider.send(
'linea_getProof',
args,
);

logDebug('Proof result from provider:', proofs);

return proofs;
} catch (error) {
logInfo(`Provider failed: ${provider._getConnection().url}`, error);
}
}

throw new Error('All providers failed to fetch linea_getProof');
}
}
9 changes: 4 additions & 5 deletions packages/linea-ccip-gateway/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
import { EVMGateway } from './evm-gateway';
import { JsonRpcProvider } from 'ethers';
import { FallbackProvider } from 'ethers';
import { L2ProofService, L2ProvableBlock } from './L2ProofService';

export type L1Gateway = EVMGateway<L2ProvableBlock>;

export function makeL2Gateway(
providerL1: JsonRpcProvider,
providerL2: JsonRpcProvider,
providerL1: FallbackProvider,
providerL2: FallbackProvider,
rollupAddress: string,
shomeiNode?: JsonRpcProvider,
): L1Gateway {
return new EVMGateway(
new L2ProofService(providerL1, providerL2, rollupAddress, shomeiNode),
new L2ProofService(providerL1, providerL2, rollupAddress),
);
}

Expand Down
19 changes: 14 additions & 5 deletions packages/linea-ccip-gateway/src/server.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,33 @@
import { Request, Response } from 'express';
import { EVMGateway } from './evm-gateway';
import { ethers } from 'ethers';
import { FallbackProvider, JsonRpcProvider } from 'ethers';
import { L2ProofService } from './L2ProofService';
import 'dotenv/config';
import { Server } from '@chainlink/ccip-read-server';
import { logError } from './utils';

const l1ProviderUrl = process.env.L1_PROVIDER_URL;
const l1ProviderUrlFallback = process.env.L1_PROVIDER_URL_FALLBACK;
const l2ProviderUrl = process.env.L2_PROVIDER_URL;
const l2ProviderUrlFallback = process.env.L2_PROVIDER_URL_FALLBACK;
const l2ChainId = parseInt(process.env.L2_CHAIN_ID ?? '59141');
const rollupAddress =
process.env.L1_ROLLUP_ADDRESS ?? '0xB218f8A4Bc926cF1cA7b3423c154a0D627Bdb7E5';
const port = process.env.PORT || 3000;
const nodeEnv = process.env.NODE_ENV || 'test';

try {
const providerL1 = new ethers.JsonRpcProvider(l1ProviderUrl);
const providerL2 = new ethers.JsonRpcProvider(l2ProviderUrl, l2ChainId, {
staticNetwork: true,
});
const providerL1 = new FallbackProvider([
new JsonRpcProvider(l1ProviderUrl),
new JsonRpcProvider(l1ProviderUrlFallback),
]);
const providerL2 = new FallbackProvider(
[
new JsonRpcProvider(l2ProviderUrl),
new JsonRpcProvider(l2ProviderUrlFallback),
],
l2ChainId,
);

const gateway = new EVMGateway(
new L2ProofService(providerL1, providerL2, rollupAddress),
Expand Down
4 changes: 2 additions & 2 deletions packages/linea-ccip-gateway/test/constants.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export const L1_RPC_URL = 'https://gateway.tenderly.co/public/sepolia';
export const L2_RPC_URL = 'https://rpc.sepolia.linea.build/';
export const L1_RPC_URL = 'https://sepolia.gateway.tenderly.co';
export const L2_RPC_URL = 'https://rpc.sepolia.linea.build';
export const L2_TEST_CONTRACT_ADDRESS =
'0x09a434561f4b40067F71444d7042fd110013F879';
export const ROLLUP_SEPOLIA_ADDRESS =
Expand Down
5 changes: 3 additions & 2 deletions packages/linea-ccip-gateway/test/testVerifier.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
BrowserProvider,
Contract,
ethers,
FallbackProvider,
FetchRequest,
JsonRpcProvider,
Signer,
Expand Down Expand Up @@ -75,8 +76,8 @@ describe('L1Verifier', () => {
const rollup = await Rollup.deploy(currentL2BlockNumber, stateRootHash);

const gateway = makeL2Gateway(
(l1Provider as unknown) as JsonRpcProvider,
l2Provider,
new FallbackProvider([(l1Provider as unknown) as JsonRpcProvider]),
new FallbackProvider([l2Provider]),
await rollup.getAddress(),
);
const server = new Server();
Expand Down
Loading