Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
24670c2
batch: use origin ethers.js 6.16.0
ericlee42 Dec 9, 2025
c4291ab
dtl: refactor and use axios v1
ericlee42 Dec 10, 2025
f7b0b81
refactor: simplify paramsSerializer function in L1BeaconClient
ericlee42 Dec 10, 2025
ae6937a
batch: refactor Blob class and L1BeaconClient for improved data handling
ericlee42 Dec 10, 2025
e104545
batch: enhance Blob class for hex string initialization and update L1…
ericlee42 Dec 10, 2025
67b9caf
batch: rename resolve method to toData in Blob class and update L1Bea…
ericlee42 Dec 10, 2025
57590d3
dtl: sort package.json
ericlee42 Dec 10, 2025
91cebda
fix: update MAX_BLOB_NUM_PER_TX to 6 for consistency in transaction l…
ericlee42 Dec 10, 2025
5d4bdb2
batch: refactor fetchBatches and L1BeaconClient integration for impro…
ericlee42 Dec 10, 2025
9bf2393
revert sort diff
ericlee42 Dec 10, 2025
3f2da0f
batch: improve proof validation in Blob class and remove unused import
ericlee42 Dec 10, 2025
44828ab
batch: update STEPS_FILE constant to use 'inbox_blob_txs.json' for co…
ericlee42 Dec 10, 2025
2015fb8
batch: change log level from info to debug for event storage
ericlee42 Dec 10, 2025
af0ca09
batch: streamline logging for Layer 1 synchronization by removing red…
ericlee42 Dec 10, 2025
e708b5c
batch: add logging for syncInboxBatch method to track block range
ericlee42 Dec 10, 2025
84c9398
batch: refactor timestamp handling in transaction-enqueued to use eve…
ericlee42 Dec 10, 2025
df4d373
batch: improve error handling in proposeMpcSign method by simplifying…
ericlee42 Dec 11, 2025
ea6ba75
batch: enhance error handling in fetchBatches for blob transactions
ericlee42 Dec 11, 2025
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
Expand Up @@ -48,7 +48,7 @@
"release": "yarn build && yarn changeset publish"
},
"dependencies": {
"ethersv6": "github:ericlee42/ethers#metis"
"ethersv6": "npm:ethers@^6.16.0"
},
"resolutions": {
"node-gyp": "^9.4.0"
Expand Down
2 changes: 1 addition & 1 deletion packages/batch-submitter/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
"bluebird": "^3.7.2",
"c-kzg": "^4.0.1",
"dotenv": "^10.0.0",
"ethersv6": "github:ericlee42/ethers#metis",
"ethersv6": "npm:ethers@^6.16.0",
"lodash": "^4.17.21",
"old-contracts": "npm:@eth-optimism/contracts@^0.0.2-alpha.7",
"prom-client": "^13.1.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,7 @@ export class StateBatchSubmitter extends BatchSubmitter {
if (!mpcInfo || !mpcInfo.mpc_address) {
throw new Error('MPC 1 info get failed')
}
const txUnsign: ethers.TransactionRequest = {
const txUnsign: ethers.TransactionLike = {
type: 2,
to: tx.to,
data: tx.data,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,13 @@ import {
zlibCompressHexString,
} from '@metis.io/core-utils'
import { Promise as bPromise } from 'bluebird'
import * as kzg from 'c-kzg'
import {
ethers,
Provider,
Signer,
toBeHex,
toBigInt,
TransactionReceipt,
TransactionRequest,
} from 'ethersv6'

/* Internal Imports */
Expand Down Expand Up @@ -146,7 +144,6 @@ export class TransactionBatchSubmitterInbox {
}
metrics.numTxPerBatch.observe(endBlock - startBlock)
this.logger.info('Submitting batch to inbox', {
meta: batchParams.inputMeta,
useBlob,
blobTxes: batchParams.blobTxData.length,
batchSizeInBytes,
Expand All @@ -157,7 +154,7 @@ export class TransactionBatchSubmitterInbox {
nextBatchIndex,
{
input: batchParams.inputData,
blobs: batchParams.blobTxData.map((tx) => tx.blobs.map((b) => b.data)),
blobs: batchParams.blobTxData.map((tx) => tx.blobs),
txHashes: [],
},
signer,
Expand Down Expand Up @@ -197,7 +194,7 @@ export class TransactionBatchSubmitterInbox {
) => Promise<TransactionReceipt>
): Promise<TransactionReceipt> {
const { chainId } = await signer.provider.getNetwork()
const inboxTx: TransactionRequest = {
const inboxTx: ethers.TransactionLike = {
type: 2,
chainId,
to: this.inboxAddress,
Expand Down Expand Up @@ -244,7 +241,7 @@ export class TransactionBatchSubmitterInbox {
continue
}

const blobTx: ethers.TransactionRequest = {
const blobTx: ethers.TransactionLike = {
type: 3, // 3 for blob tx type
to: this.inboxAddress,
// since we are using blob tx, call data will be empty,
Expand All @@ -253,7 +250,7 @@ export class TransactionBatchSubmitterInbox {
chainId,
nonce: await signer.provider.getTransactionCount(signerAddress),
blobs,
blobVersion: 1, // Osaka is enabled on all the chains
blobWrapperVersion: 1, // Osaka is enabled on all the chains
}

const replaced = await setTxEIP1559Fees(
Expand Down Expand Up @@ -285,9 +282,8 @@ export class TransactionBatchSubmitterInbox {

// need to append the blob sidecar to the signed tx
const signedTxUnmarshaled = ethers.Transaction.from(signedTx)
signedTxUnmarshaled.type = 3
signedTxUnmarshaled.kzg = kzg
signedTxUnmarshaled.blobVersion = blobTx.blobVersion
signedTxUnmarshaled.blobWrapperVersion =
blobTx.blobWrapperVersion
signedTxUnmarshaled.blobs = blobTx.blobs
// repack the tx
return signedTxUnmarshaled.serialized
Expand Down Expand Up @@ -661,13 +657,6 @@ export class TransactionBatchSubmitterInbox {

encoded = `${da}${compressType}${batchIndex}${l2Start}${totalElements}${compressedEncoded}`
return {
inputMeta: {
da,
compressType,
batchIndex,
l2Start,
totalElements,
},
inputData: encoded,
batch: blocks,
blobTxData,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -581,7 +581,7 @@ export class TransactionBatchSubmitter extends BatchSubmitter {
// this.encodeSequencerBatchOptions
// )
// unsigned tx
const tx: ethers.TransactionRequest = {
const tx: ethers.TransactionLike = {
to: this.useMinio
? await this.mvmCtcContract.getAddress()
: await this.chainContract.getAddress(),
Expand Down
34 changes: 16 additions & 18 deletions packages/batch-submitter/src/da/blob.ts
Original file line number Diff line number Diff line change
@@ -1,40 +1,32 @@
import {
blobToKzgCommitment,
Bytes48,
Blob as CBlob,
computeBlobKzgProof,
verifyBlobKzgProof,
computeCellsAndKzgProofs,
KZGCommitment,
KZGProof,
} from 'c-kzg'
import { createHash } from 'crypto'
import { Frame } from './types'

const BlobSize = 4096 * 32
const MaxBlobDataSize = (4 * 31 + 3) * 1024 - 4
const EncodingVersion = 0
const VersionOffset = 1
// const VersionOffset = 1
const Rounds = 1024

export class Blob {
public readonly data: Uint8Array = new Uint8Array(BlobSize)
public readonly commitment: Bytes48 = new Uint8Array(48)
public readonly proof: Bytes48 = new Uint8Array(48)
public readonly commitment: KZGCommitment = new Uint8Array(48)
// cell proofs
public readonly proof: KZGProof = new Uint8Array(48 * 128)
public versionedHash: string = ''

static kzgToVersionedHash(commitment: Bytes48): string {
static kzgToVersionedHash(commitment: KZGCommitment): string {
const hasher = createHash('sha256')
hasher.update(commitment)
// versioned hash = [1 byte version][31 byte hash]
return '0x01' + hasher.digest('hex').substring(2)
}

static verifyBlobProof(
blob: Blob,
commitment: Bytes48,
proof: Bytes48
): boolean {
return verifyBlobKzgProof(blob.data as CBlob, commitment, proof)
}

marshalFrame(frame: Frame): Uint8Array {
const buffer = new ArrayBuffer(16 + 2 + 4 + frame.data.length + 1)
const view = new DataView(buffer)
Expand Down Expand Up @@ -158,8 +150,14 @@ export class Blob {
)
}

this.commitment.set(blobToKzgCommitment(this.data as CBlob))
this.proof.set(computeBlobKzgProof(this.data as CBlob, this.commitment))
this.commitment.set(blobToKzgCommitment(this.data))
const proofs = Buffer.concat(computeCellsAndKzgProofs(this.data)[1])
if (proofs.length !== this.proof.length) {
throw new Error(
`Invalid proof length: expected ${this.proof.length}, got ${proofs.length}`
)
}
this.proof.set(proofs)
this.versionedHash = Blob.kzgToVersionedHash(this.commitment)

return this
Expand Down
16 changes: 12 additions & 4 deletions packages/batch-submitter/src/da/channel.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
// channel.ts
import { Logger } from '@eth-optimism/common-ts'
import { ethers } from 'ethersv6'
import { Blob } from './blob'
import { ChannelBuilder } from './channel-builder'
import {
BatchToInboxElement,
BlobLike,
ChannelConfig,
Frame,
RollupConfig,
TxData,
} from './types'
import { Blob } from './blob'
import { Logger } from '@eth-optimism/common-ts'

export class Channel {
private channelBuilder: ChannelBuilder
Expand Down Expand Up @@ -82,8 +83,15 @@ export class Channel {
return sb
},

get blobs(): Blob[] {
return this.frames.map((f: Frame) => new Blob().fromFrame(f))
get blobs(): BlobLike[] {
return this.frames.map((f: Frame) => {
const blob = new Blob().fromFrame(f)
return {
data: blob.data,
proof: blob.proof,
commitment: blob.commitment,
}
})
},
}
this.pendingTransactions.set(txData.id, txData)
Expand Down
2 changes: 1 addition & 1 deletion packages/batch-submitter/src/da/consts.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export const FRAME_OVERHEAD_SIZE = 200
export const MAX_RLP_BYTES_PER_CHANNEL = 100_000_000
export const MAX_BLOB_SIZE = (4 * 31 + 3) * 1024 - 4
export const MAX_BLOB_NUM_PER_TX = 7
export const MAX_BLOB_NUM_PER_TX = 6
export const TX_GAS = 21_000
export const CHANNEL_FULL_ERR = new Error('Channel is full')
19 changes: 8 additions & 11 deletions packages/batch-submitter/src/da/types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
// types.ts
import { BytesLike, ethers, getBytes } from 'ethersv6'
import { Blob } from './blob'

export interface RollupConfig {
l1ChainID: bigint
Expand Down Expand Up @@ -49,12 +48,18 @@ export interface Frame {
isLast: boolean
}

export type BlobLike = {
data: BytesLike
proof: BytesLike
commitment: BytesLike
}

export interface TxData {
frames: Frame[]
asBlob: boolean

get id(): string
get blobs(): Blob[]
get blobs(): BlobLike[]
}

export interface L1BlockInfo {
Expand Down Expand Up @@ -153,18 +158,10 @@ export interface BatchToInboxElement {
extraData: string
txs: BatchToInboxRawTx[]
}
export declare type BatchToInbox = BatchToInboxElement[]

export interface InboxInputMeta {
da: string
compressType: string
batchIndex: string
l2Start: string
totalElements: string
}
export declare type BatchToInbox = BatchToInboxElement[]

export interface InboxBatchParams {
inputMeta: InboxInputMeta
inputData: string
batch: BatchToInbox
blobTxData: TxData[]
Expand Down
36 changes: 27 additions & 9 deletions packages/batch-submitter/src/storage/inbox-storage.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
/* Imports: External */
import { Logger } from '@eth-optimism/common-ts'
import { BytesLike, toNumber } from 'ethersv6'
import { toNumber } from 'ethersv6'
import * as fs from 'fs/promises'
import * as path from 'path'
import { BlobLike } from '../da/types'

const INBOX_OK_FILE = 'inbox_ok.json'
const INBOX_FAIL_FILE = 'inbox_fail.json'
const STEPS_FILE = 'steps.json'
const STEPS_FILE = 'inbox_blobs.json'

export interface InboxRecordInfo {
batchIndex: number | bigint
Expand All @@ -16,7 +17,7 @@ export interface InboxRecordInfo {

export interface InboxSteps {
input: string // the inbox tx data input
blobs: Array<Array<BytesLike>> // array of blob tx data
blobs: Array<Array<BlobLike>> // array of blob tx data
txHashes: Array<string> // blob tx hashes + inbox tx hash
}

Expand Down Expand Up @@ -75,15 +76,25 @@ export class InboxStorage {
}

public async insertStep(jsonData: InboxSteps) {
const data = {
const data: InboxSteps = {
input: jsonData.input,
txHashes: jsonData.txHashes,
blobs: jsonData.blobs.map((blobArray) =>
blobArray.map((blob) => {
if (typeof blob === 'string') {
return blob
return {
data:
typeof blob.data === 'string'
? blob.data
: '0x' + Buffer.from(blob.data).toString('hex'),
proof:
typeof blob.proof === 'string'
? blob.proof
: '0x' + Buffer.from(blob.proof).toString('hex'),
commitment:
typeof blob.commitment === 'string'
? blob.commitment
: '0x' + Buffer.from(blob.commitment).toString('hex'),
}
return '0x' + Buffer.from(blob).toString('hex')
})
),
}
Expand All @@ -97,8 +108,15 @@ export class InboxStorage {
if (!(await this.fileExists(filePath))) {
return null
}
const data = await fs.readFile(filePath, 'utf-8')
return JSON.parse(data)
const raw = await fs.readFile(filePath, 'utf-8')
const parsed: InboxSteps = JSON.parse(raw)
if (!Array.isArray(parsed.blobs)) {
throw new Error('Invalid steps file format: blobs is not an array')
}
if (!Array.isArray(parsed.txHashes)) {
throw new Error('Invalid steps file format: txHashes is not an array')
}
return parsed
}

private async fileExists(filePath) {
Expand Down
Loading