diff --git a/.changeset/calm-books-hope.md b/.changeset/calm-books-hope.md new file mode 100644 index 00000000000..beaec01e286 --- /dev/null +++ b/.changeset/calm-books-hope.md @@ -0,0 +1,8 @@ +--- +"@eth-optimism/data-transport-layer": patch +--- + +Allow the DTL to provide data from either L1 or L2, configurable via a query param sent by the client. +The config option `default-backend` can be used to specify the backend to be +used if the query param is not specified. This allows it to be backwards +compatible with how the DTL was previously used. diff --git a/packages/data-transport-layer/src/services/l2-ingestion/service.ts b/packages/data-transport-layer/src/services/l2-ingestion/service.ts index 61c6536b081..1d7f6848ddb 100644 --- a/packages/data-transport-layer/src/services/l2-ingestion/service.ts +++ b/packages/data-transport-layer/src/services/l2-ingestion/service.ts @@ -43,10 +43,6 @@ const optionSettings = { default: false, validate: validators.isBoolean, }, - stopL2SyncAtBlock: { - default: Infinity, - validate: validators.isInteger, - }, } export class L2IngestionService extends BaseService { @@ -80,30 +76,7 @@ export class L2IngestionService extends BaseService { const highestSyncedL2BlockNumber = (await this.state.db.getHighestSyncedUnconfirmedBlock()) || 1 - // Shut down if we're at the stop block. - if ( - this.options.stopL2SyncAtBlock !== undefined && - this.options.stopL2SyncAtBlock !== null && - highestSyncedL2BlockNumber >= this.options.stopL2SyncAtBlock - ) { - this.logger.info( - "L2 sync is shutting down because we've reached your target block. Goodbye!" - ) - return - } - - let currentL2Block = await this.state.l2RpcProvider.getBlockNumber() - - // Make sure we can't exceed the stop block. - if ( - this.options.stopL2SyncAtBlock !== undefined && - this.options.stopL2SyncAtBlock !== null - ) { - currentL2Block = Math.min( - currentL2Block, - this.options.stopL2SyncAtBlock - ) - } + const currentL2Block = await this.state.l2RpcProvider.getBlockNumber() // Make sure we don't exceed the tip. const targetL2Block = Math.min( diff --git a/packages/data-transport-layer/src/services/main/service.ts b/packages/data-transport-layer/src/services/main/service.ts index 703d9ff2f41..dde1f33ec70 100644 --- a/packages/data-transport-layer/src/services/main/service.ts +++ b/packages/data-transport-layer/src/services/main/service.ts @@ -21,13 +21,12 @@ export interface L1DataTransportServiceOptions { logsPerPollingInterval: number pollingInterval: number port: number - showUnconfirmedTransactions: boolean syncFromL1?: boolean syncFromL2?: boolean transactionsPerPollingInterval: number legacySequencerCompatibility: boolean - stopL2SyncAtBlock?: number sentryDsn?: string + defaultBackend: string } const optionSettings = { diff --git a/packages/data-transport-layer/src/services/run.ts b/packages/data-transport-layer/src/services/run.ts index 181ca7bd00e..fd6e568e8af 100644 --- a/packages/data-transport-layer/src/services/run.ts +++ b/packages/data-transport-layer/src/services/run.ts @@ -39,7 +39,6 @@ interface Bcfg { l2ChainId: config.uint('l2ChainId'), syncFromL1: config.bool('syncFromL1', true), syncFromL2: config.bool('syncFromL2', false), - showUnconfirmedTransactions: config.bool('syncFromL2', false), transactionsPerPollingInterval: config.uint( 'transactionsPerPollingInterval', 1000 @@ -48,8 +47,8 @@ interface Bcfg { 'legacySequencerCompatibility', false ), - stopL2SyncAtBlock: config.uint('stopL2SyncAtBlock'), sentryDsn: config.str('sentryDsn'), + defaultBackend: config.str('defaultBackend', 'l1'), }) await service.start() diff --git a/packages/data-transport-layer/src/services/server/service.ts b/packages/data-transport-layer/src/services/server/service.ts index 32a1f7c04a2..ae9940d3ed9 100644 --- a/packages/data-transport-layer/src/services/server/service.ts +++ b/packages/data-transport-layer/src/services/server/service.ts @@ -48,9 +48,12 @@ const optionSettings = { return validators.isUrl(val) || validators.isJsonRpcProvider(val) }, }, - showUnconfirmedTransactions: { - validate: validators.isBoolean, - }, + defaultBackend: { + default: 'l1', + validate: (val: string) => { + return val === 'l1' || val === 'l2' + } + } } export class L1TransportServer extends BaseService { @@ -66,7 +69,6 @@ export class L1TransportServer extends BaseService { } = {} as any protected async _init(): Promise { - // TODO: I don't know if this is strictly necessary, but it's probably a good thing to do. if (!this.options.db.isOpen()) { await this.options.db.open() } @@ -171,14 +173,26 @@ export class L1TransportServer extends BaseService { * TODO: Link to our API spec. */ private _registerAllRoutes(): void { - // TODO: Maybe add doc-like comments to each of these routes? - this._registerRoute( 'get', '/eth/syncing', - async (): Promise => { - const highestL2BlockNumber = await this.state.db.getHighestL2BlockNumber() - const currentL2Block = await this.state.db.getLatestTransaction() + async (req): Promise => { + const backend = req.query.backend || this.options.defaultBackend + + let currentL2Block + let highestL2BlockNumber + switch (backend) { + case 'l1': + currentL2Block = await this.state.db.getLatestTransaction() + highestL2BlockNumber = await this.state.db.getHighestL2BlockNumber() + break + case 'l2': + currentL2Block = await this.state.db.getLatestUnconfirmedTransaction() + highestL2BlockNumber = await this.state.db.getHighestSyncedUnconfirmedBlock() + break + default: + throw new Error(`Unknown transaction backend ${backend}`) + } if (currentL2Block === null) { if (highestL2BlockNumber === null) { @@ -329,21 +343,19 @@ export class L1TransportServer extends BaseService { this._registerRoute( 'get', '/transaction/latest', - async (): Promise => { - let transaction = await this.state.db.getLatestFullTransaction() - if (this.options.showUnconfirmedTransactions) { - const latestUnconfirmedTx = await this.state.db.getLatestUnconfirmedTransaction() - if ( - transaction === null || - transaction === undefined || - latestUnconfirmedTx.index >= transaction.index - ) { - transaction = latestUnconfirmedTx - } - } + async (req): Promise => { + const backend = req.query.backend || this.options.defaultBackend + let transaction = null - if (transaction === null) { - transaction = await this.state.db.getLatestFullTransaction() + switch (backend) { + case 'l1': + transaction = await this.state.db.getLatestFullTransaction() + break + case 'l2': + transaction = await this.state.db.getLatestUnconfirmedTransaction() + break + default: + throw new Error(`Unknown transaction backend ${backend}`) } if (transaction === null) { @@ -368,17 +380,22 @@ export class L1TransportServer extends BaseService { 'get', '/transaction/index/:index', async (req): Promise => { + const backend = req.query.backend || this.options.defaultBackend let transaction = null - if (this.options.showUnconfirmedTransactions) { - transaction = await this.state.db.getUnconfirmedTransactionByIndex( - BigNumber.from(req.params.index).toNumber() - ) - } - if (transaction === null) { - transaction = await this.state.db.getFullTransactionByIndex( - BigNumber.from(req.params.index).toNumber() - ) + switch (backend ) { + case 'l1': + transaction = await this.state.db.getFullTransactionByIndex( + BigNumber.from(req.params.index).toNumber() + ) + break + case 'l2': + transaction = await this.state.db.getUnconfirmedTransactionByIndex( + BigNumber.from(req.params.index).toNumber() + ) + break + default: + throw new Error(`Unknown transaction backend ${backend}`) } if (transaction === null) { @@ -456,21 +473,19 @@ export class L1TransportServer extends BaseService { this._registerRoute( 'get', '/stateroot/latest', - async (): Promise => { - let stateRoot = await this.state.db.getLatestStateRoot() - if (this.options.showUnconfirmedTransactions) { - const latestUnconfirmedStateRoot = await this.state.db.getLatestUnconfirmedStateRoot() - if ( - stateRoot === null || - stateRoot === undefined || - latestUnconfirmedStateRoot.index >= stateRoot.index - ) { - stateRoot = latestUnconfirmedStateRoot - } - } + async (req): Promise => { + const backend = req.query.backend || this.options.defaultBackend + let stateRoot = null - if (stateRoot === null) { - stateRoot = await this.state.db.getLatestStateRoot() + switch (backend) { + case 'l1': + stateRoot = await this.state.db.getLatestStateRoot() + break + case 'l2': + stateRoot = await this.state.db.getLatestUnconfirmedStateRoot() + break + default: + throw new Error(`Unknown transaction backend ${backend}`) } if (stateRoot === null) { @@ -495,17 +510,22 @@ export class L1TransportServer extends BaseService { 'get', '/stateroot/index/:index', async (req): Promise => { + const backend = req.query.backend || this.options.defaultBackend let stateRoot = null - if (this.options.showUnconfirmedTransactions) { - stateRoot = await this.state.db.getUnconfirmedStateRootByIndex( - BigNumber.from(req.params.index).toNumber() - ) - } - if (stateRoot === null) { - stateRoot = await this.state.db.getStateRootByIndex( - BigNumber.from(req.params.index).toNumber() - ) + switch (backend) { + case 'l1': + stateRoot = await this.state.db.getStateRootByIndex( + BigNumber.from(req.params.index).toNumber() + ) + break + case 'l2': + stateRoot = await this.state.db.getUnconfirmedStateRootByIndex( + BigNumber.from(req.params.index).toNumber() + ) + break + default: + throw new Error(`Unknown transaction backend ${backend}`) } if (stateRoot === null) {