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

Change BASE to OPFaultRollup / Fix TrustedRollup Types #13

Merged
merged 4 commits into from
Nov 1, 2024
Merged
Show file tree
Hide file tree
Changes from 2 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
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@unruggable/gateways",
"version": "0.1.4",
"version": "0.1.5",
"description": "Trustless Ethereum Multichain CCIP-Read Gateway",
"publishConfig": {
"access": "public"
Expand Down
46 changes: 19 additions & 27 deletions scripts/serve.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,10 @@ import { EthSelfRollup } from '../src/eth/EthSelfRollup.js';
import { Contract } from 'ethers/contract';
import { SigningKey } from 'ethers/crypto';
import { toUnpaddedHex } from '../src/utils.js';
import { TrustedRollup } from '../src/eth/TrustedRollup.js';
import { TrustedRollup } from '../src/TrustedRollup.js';
import { EthProver } from '../src/eth/EthProver.js';
//import { LineaProver } from '../src/linea/LineaProver.js';
import { ZKSyncProver } from '../src/zksync/ZKSyncProver.js';
import { AbstractProver, type LatestProverFactory } from '../src/vm.js';

// NOTE: you can use CCIPRewriter to test an existing setup against a local gateway!
// [raffy] https://adraffy.github.io/ens-normalize.js/test/resolver.html#raffy.linea.eth.nb2hi4dthixs62dpnvss4ylooruxg5dvobuwiltdn5ws62duoryc6.ccipr.eth
Expand Down Expand Up @@ -180,13 +179,22 @@ async function createGateway(name: string) {
const slug = match[1].toUpperCase().replaceAll('-', '_');
if (slug in CHAINS) {
const chain = CHAINS[slug as keyof typeof CHAINS];
return new Gateway(
new TrustedRollup(
createProvider(chain),
getProverFactory(chain),
new SigningKey(signingKey)
)
);
const provider = createProvider(chain);
const key = new SigningKey(signingKey);
switch (chain) {
case CHAINS.ZKSYNC:
case CHAINS.ZKSYNC_SEPOLIA:
return new Gateway(new TrustedRollup(provider, ZKSyncProver, key));
// NOTE: linea should use eth_getProof instead of linea_getProof
// NOTE: this probably needs "--latest" cli option too
// rollup => SMT w/Mimc root using linea_getProof
// chain => PMT w/Keccak root using eth_getProof
// case CHAINS.LINEA:
// case CHAINS.LINEA_SEPOLIA:
// return LineaProver;
Comment on lines +192 to +194
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These lines should be removed.

Copy link
Collaborator Author

@adraffy adraffy Nov 1, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think these need to stay for the explanatory value. Otherwise, it might seem logical to add them back but the reasoning is pretty nuanced.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree. It's more that the block doesn't return a Prover directly now, and the former 4 lines still provide the explanatory value.

default:
return new Gateway(new TrustedRollup(provider, EthProver, key));
}
}
}
switch (name) {
Expand Down Expand Up @@ -287,7 +295,8 @@ async function createGateway(name: string) {
return new Gateway(new ZKSyncRollup(createProviderPair(config), config));
}
case 'base':
return createOPGateway(OPRollup.baseMainnetConfig);
// return createOPGateway(OPRollup.baseMainnetConfig);
clowestab marked this conversation as resolved.
Show resolved Hide resolved
return createOPFaultGateway(OPFaultRollup.baseMainnetConfig);
case 'base-sepolia':
return createOPFaultGateway(OPFaultRollup.baseSepoliaConfig);
case 'unfinalized-base-sepolia':
Expand Down Expand Up @@ -337,23 +346,6 @@ async function createGateway(name: string) {
}
}

function getProverFactory(chain: Chain): LatestProverFactory<AbstractProver> {
switch (chain) {
case CHAINS.ZKSYNC:
case CHAINS.ZKSYNC_SEPOLIA:
return ZKSyncProver;
// NOTE: linea should use eth_getProof instead of linea_getProof
// NOTE: this probably needs "--latest" cli option too
// rollup => SMT w/Mimc root using linea_getProof
// chain => PMT w/Keccak root using eth_getProof
// case CHAINS.LINEA:
// case CHAINS.LINEA_SEPOLIA:
// return LineaProver;
default:
return EthProver;
}
}

function createSelfGateway(chain: Chain) {
return new Gateway(new EthSelfRollup(createProvider(chain)));
}
Expand Down
25 changes: 16 additions & 9 deletions src/eth/TrustedRollup.ts → src/TrustedRollup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ import type {
HexString32,
ProofSequence,
Provider,
} from '../types.js';
import { AbstractProver, type LatestProverFactory } from '../vm.js';
import { AbstractRollup, type RollupCommit } from '../rollup.js';
import { ABI_CODER } from '../utils.js';
import { CachedValue } from '../cached.js';
import { VOID_PROVIDER } from '../VoidProvider.js';
} from './types.js';
import type { AbstractProver, LatestProverFactory } from './vm.js';
import { AbstractRollup, type RollupCommit } from './rollup.js';
import { ABI_CODER } from './utils.js';
import { CachedValue } from './cached.js';
import { VOID_PROVIDER } from './VoidProvider.js';
import { ZeroAddress } from 'ethers/constants';
import { SigningKey } from 'ethers/crypto';
import { computeAddress } from 'ethers/transaction';
Expand All @@ -24,13 +24,14 @@ export class TrustedRollup<P extends AbstractProver> extends AbstractRollup<
TrustedCommit<P>
> {
readonly latest: CachedValue<TrustedCommit<P>>;
private _signed = 0n;
constructor(
provider2: Provider,
readonly factory: LatestProverFactory<P>,
readonly signingKey: SigningKey
) {
super({ provider1: VOID_PROVIDER, provider2 });
this.latest = new CachedValue<TrustedCommit<P>>(async () => {
this.latest = new CachedValue(async () => {
const prover = await factory.latest(this.provider2, this.latestBlockTag);
const stateRoot = await prover.fetchStateRoot();
const signedAt = Math.ceil(Date.now() / 1000);
Expand All @@ -39,7 +40,13 @@ export class TrustedRollup<P extends AbstractProver> extends AbstractRollup<
['0x1900', ZeroAddress, signedAt, stateRoot]
);
const signature = this.signingKey.sign(hash).serialized;
return { index: 0n, prover, stateRoot, signature, signedAt };
return {
index: this._signed++,
prover,
stateRoot,
signature,
signedAt,
};
}, 60000);
}
get signerAddress() {
Expand All @@ -49,7 +56,7 @@ export class TrustedRollup<P extends AbstractProver> extends AbstractRollup<
return true;
}
override async fetchLatestCommitIndex(): Promise<bigint> {
return 0n;
return (await this.latest.get()).index;
}
protected override async _fetchParentCommitIndex(
_commit: RollupCommit<P>
Expand Down
3 changes: 2 additions & 1 deletion src/eth/EthProver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ import { withResolvers, toPaddedHex } from '../utils.js';
export class EthProver extends BlockProver {
static readonly encodeProof = encodeProof;
static readonly isContract = isContract;
override async isContract(target: HexAddress) {
static readonly latest = this._createLatest();
clowestab marked this conversation as resolved.
Show resolved Hide resolved
override async isContract(target: HexAddress): Promise<boolean> {
target = target.toLowerCase();
if (this.fast) {
return this.cache.get(target, async () => {
Expand Down
7 changes: 4 additions & 3 deletions src/eth/EthSelfRollup.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { HexString, ProofSequence, Provider } from '../types.js';
import { AbstractRollup, type RollupCommit } from '../rollup.js';
import { ABI_CODER, fetchBlock, MAINNET_BLOCK_SEC } from '../utils.js';
import { fetchBlockNumber, ABI_CODER, MAINNET_BLOCK_SEC } from '../utils.js';
import { EthProver } from './EthProver.js';
import { encodeRlpBlock } from '../rlp.js';

Expand All @@ -23,8 +23,9 @@ export class EthSelfRollup extends AbstractRollup<EthSelfCommit> {
return index - (index % this.commitStep);
}
override async fetchLatestCommitIndex(): Promise<bigint> {
const blockInfo = await fetchBlock(this.provider1, this.latestBlockTag);
return this.align(BigInt(blockInfo.number));
return this.align(
await fetchBlockNumber(this.provider1, this.latestBlockTag)
);
}
protected override async _fetchParentCommitIndex(
commit: EthSelfCommit
Expand Down
3 changes: 2 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export * from './utils.js';
export * from './rlp.js';
export * from './chains.js';
export * from './VoidProvider.js';
export * from './GatewayProvider.js';

//export * from './ops.js'; use GatewayRequest.Opcodes instead
export * from './reader.js';
Expand Down Expand Up @@ -34,7 +35,7 @@ export * from './taiko/TaikoRollup.js';
export * from './scroll/ScrollRollup.js';
export * from './zksync/ZKSyncRollup.js';
export * from './eth/EthSelfRollup.js';
export * from './eth/TrustedRollup.js';
export * from './TrustedRollup.js';

export * from './gateway.js';
export * from './linea/LineaGatewayV1.js';
21 changes: 11 additions & 10 deletions src/linea/LineaProver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,22 @@ export class LineaProver extends BlockProver {
static readonly isInclusionProof = isInclusionProof;
static readonly isContract = isContract;
static readonly encodeProof = encodeProof;
static readonly latest = this._createLatest();
stateRoot?: HexString32;
override async fetchStateRoot() {
if (!this.stateRoot) throw new Error(`unknown stateRoot`);
return this.stateRoot;
}
override async isContract(target: HexString): Promise<boolean> {
if (this.fast) {
return this.cache.get(target, async () => {
const code = await this.provider.getCode(target, this.block);
return code.length > 2;
});
}
const { accountProof } = await this.getProofs(target);
return isContract(accountProof);
}
override async getStorage(
target: HexString,
slot: bigint,
Expand Down Expand Up @@ -52,16 +63,6 @@ export class LineaProver extends BlockProver {
? proof.storageProofs[0].proof.value
: ZeroHash;
}
override async isContract(target: HexString) {
if (this.fast) {
return this.cache.get(target, async () => {
const code = await this.provider.getCode(target, this.block);
return code.length > 2;
});
}
const { accountProof } = await this.getProofs(target);
return isContract(accountProof);
}
protected override async _proveNeed(
need: TargetNeed,
accountRef: ProofRef,
Expand Down
8 changes: 7 additions & 1 deletion src/op/OPFaultRollup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,20 @@ export class OPFaultRollup extends AbstractOPRollup {
OptimismPortal: '0xbEb5Fc579115071764c7423A4f12eDde41f106Ed',
GameFinder: GAME_FINDER_MAINNET,
};

static readonly sepoliaConfig: RollupDeployment<OPFaultConfig> = {
chain1: CHAINS.SEPOLIA,
chain2: CHAINS.OP_SEPOLIA,
OptimismPortal: '0x16Fc5058F25648194471939df75CF27A2fdC48BC',
GameFinder: GAME_FINDER_SEPOLIA,
};

// https://docs.base.org/docs/base-contracts#l1-contract-addresses
static readonly baseMainnetConfig: RollupDeployment<OPFaultConfig> = {
chain1: CHAINS.MAINNET,
chain2: CHAINS.BASE,
OptimismPortal: '0x49048044D57e1C92A77f79988d21Fa8fAF74E97e',
GameFinder: GAME_FINDER_MAINNET,
};
// https://docs.base.org/docs/base-contracts/#ethereum-testnet-sepolia
static readonly baseSepoliaConfig: RollupDeployment<OPFaultConfig> = {
chain1: CHAINS.SEPOLIA,
Expand Down
12 changes: 6 additions & 6 deletions src/op/OPRollup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ export type OPConfig = {
};

export class OPRollup extends AbstractOPRollup {
// https://docs.base.org/docs/base-contracts#base-mainnet
static readonly baseMainnetConfig: RollupDeployment<OPConfig> = {
chain1: CHAINS.MAINNET,
chain2: CHAINS.BASE,
L2OutputOracle: '0x56315b90c40730925ec5485cf004d835058518A0',
};
// 20241030: base changed to fault proofs
// static readonly baseMainnetConfig: RollupDeployment<OPConfig> = {
// chain1: CHAINS.MAINNET,
// chain2: CHAINS.BASE,
// L2OutputOracle: '0x56315b90c40730925ec5485cf004d835058518A0',
// };

// https://docs.blast.io/building/contracts#mainnet
static readonly blastMainnnetConfig: RollupDeployment<OPConfig> = {
Expand Down
1 change: 1 addition & 0 deletions src/polygon/ZKEVMProver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
export class ZKEVMProver extends BlockProver {
static readonly isContract = isContract;
static readonly encodeProof = encodeProof;
static readonly latest = this._createLatest();
override async isContract(target: HexAddress): Promise<boolean> {
target = target.toLowerCase();
if (this.fast) {
Expand Down
19 changes: 9 additions & 10 deletions src/vm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -485,10 +485,6 @@ export function makeStorageKey(target: HexAddress, slot: bigint) {
return `${target}${slot.toString(16)}`;
}

export interface LatestProverFactory<P extends AbstractProver> {
latest(provider: Provider, relative: BigNumberish): Promise<P>;
}

// TODO: totalAssembledBytes
export abstract class AbstractProver {
// general proof cache
Expand Down Expand Up @@ -966,14 +962,17 @@ export abstract class AbstractProver {
}
}

export interface LatestProverFactory<P extends AbstractProver> {
latest(provider: Provider, relative?: BigNumberish): Promise<P>;
}

export abstract class BlockProver extends AbstractProver {
// absolutely disgusting typescript
static async latest<T extends InstanceType<typeof BlockProver>>(
this: new (...a: ConstructorParameters<typeof BlockProver>) => T,
provider: Provider,
relBlockTag: BigNumberish = 0
protected static _createLatest<P extends BlockProver>(
this: new (...a: ConstructorParameters<typeof BlockProver>) => P
) {
return new this(provider, await fetchBlockNumber(provider, relBlockTag));
return async (provider: Provider, relative: BigNumberish = 0) => {
return new this(provider, await fetchBlockNumber(provider, relative));
};
}
readonly block: HexString;
constructor(provider: Provider, block: BigNumberish) {
Expand Down
3 changes: 2 additions & 1 deletion src/zksync/ZKSyncProver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ export class ZKSyncProver extends AbstractProver {
return batchIndex + Number(relative); //(typeof relative === 'string' ? 0 : Number(relative));
}
static async latest(provider: Provider, relative: BigNumberish = 0) {
return new this(provider, await this.latestBatchIndex(provider, relative));
const batchIndex = await this.latestBatchIndex(provider, relative);
return new this(provider, batchIndex);
}
constructor(
provider: Provider,
Expand Down
17 changes: 14 additions & 3 deletions test/debug/play.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,21 @@
import { GatewayRequestV1, GatewayRequest, EthProver, CHAINS, NitroRollup, OPRollup, TaikoRollup, ZKSyncRollup, fetchBlockNumber } from '../../src/index.js';
import { randomBytes, SigningKey, ZeroHash } from 'ethers';
import { GatewayRequestV1, GatewayRequest, EthProver, CHAINS, NitroRollup, OPRollup, TaikoRollup, ZKSyncRollup, fetchBlockNumber, TrustedRollup, ZKEVMProver, ZKSyncProver, LineaProver, OPFaultRollup } from '../../src/index.js';
import { createProvider, createProviderPair } from '../providers.js';

// this is just a worksheet

//console.log(createProvider(1n)._getConnection())

if (1) {
const provider = createProvider(CHAINS.MAINNET);
const key = new SigningKey(randomBytes(32));
const rollup1 = new TrustedRollup(provider, EthProver, key);
const rollup2 = new TrustedRollup(provider, ZKSyncProver, key);
const rollup3 = new TrustedRollup(provider, LineaProver, key);
const rollup4 = new TrustedRollup(provider, ZKEVMProver, key);
throw 1;
}

if (1) {
const provider = createProvider(CHAINS.OP_SEPOLIA);
console.log(await fetchBlockNumber(provider, 'finalized'));
Expand All @@ -31,8 +42,8 @@ if (0) {


if (0) {
const config = OPRollup.baseMainnetConfig;
const rollup = new OPRollup(createProviderPair(config), config);
const config = OPFaultRollup.baseMainnetConfig;
const rollup = new OPFaultRollup(createProviderPair(config), config);
//const commit = await rollup.fetchLatestCommit();
const commit = await rollup.fetchCommit(0n);
console.log(commit);
Expand Down
9 changes: 6 additions & 3 deletions test/gateway/base.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { OPRollup } from '../../src/op/OPRollup.js';
import { testOP } from './common.js';
import { OPFaultRollup } from '../../src/op/OPFaultRollup.js';
import { testOPFault } from './common.js';

testOP(OPRollup.baseMainnetConfig, {
// 20241030: base changed to fault proofs
// https://base.mirror.xyz/eOsedW4tm8MU5OhdGK107A9wsn-aU7MAb8f3edgX5Tk
// https://twitter.com/base/status/1851672364439814529
testOPFault(OPFaultRollup.baseMainnetConfig, {
// https://basescan.org/address/0x0C49361E151BC79899A9DD31B8B0CCdE4F6fd2f6
slotDataContract: '0x0C49361E151BC79899A9DD31B8B0CCdE4F6fd2f6',
});
2 changes: 1 addition & 1 deletion test/gateway/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import {
ScrollRollup,
} from '../../src/scroll/ScrollRollup.js';
import { EthSelfRollup } from '../../src/eth/EthSelfRollup.js';
import { TrustedRollup } from '../../src/eth/TrustedRollup.js';
import { TrustedRollup } from '../../src/TrustedRollup.js';
import { EthProver } from '../../src/eth/EthProver.js';
import { randomBytes, SigningKey } from 'ethers/crypto';
import { afterAll } from 'bun:test';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { OPRollup } from '../../src/op/OPRollup.js';
import { testOP } from './common.js';

testOP(OPRollup.baseMainnetConfig, {
// https://basescan.org/address/0x0C49361E151BC79899A9DD31B8B0CCdE4F6fd2f6
slotDataContract: '0x0C49361E151BC79899A9DD31B8B0CCdE4F6fd2f6',
testOP(OPRollup.zoraMainnetConfig, {
// https://explorer.zora.energy/address/0x73404681064a8e16c22C1411A02D47e6395f6582
slotDataContract: '0x73404681064a8e16c22C1411A02D47e6395f6582',
// delay by 1 hour
// NOTE: to delay longer, Gateway.commitDepth needs to be bigger
minAgeSec: 3600,
Expand Down
Loading