Commit 27f32ca0 authored by Mark Tyneway's avatar Mark Tyneway Committed by GitHub

dtl: add query param based querying for txs (#479)

* dtl: remove stopL2SyncAtHeight config

* dtl: implement query param based backend

* dtl: remove dead comment

* dtl: add changeset

* dtl: standardize on backend query param

* changeset: update comment
parent c75a0fc8
---
"@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.
......@@ -43,10 +43,6 @@ const optionSettings = {
default: false,
validate: validators.isBoolean,
},
stopL2SyncAtBlock: {
default: Infinity,
validate: validators.isInteger,
},
}
export class L2IngestionService extends BaseService<L2IngestionServiceOptions> {
......@@ -80,30 +76,7 @@ export class L2IngestionService extends BaseService<L2IngestionServiceOptions> {
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(
......
......@@ -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 = {
......
......@@ -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()
......
......@@ -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<L1TransportServerOptions> {
......@@ -66,7 +69,6 @@ export class L1TransportServer extends BaseService<L1TransportServerOptions> {
} = {} as any
protected async _init(): Promise<void> {
// 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<L1TransportServerOptions> {
* 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<SyncingResponse> => {
const highestL2BlockNumber = await this.state.db.getHighestL2BlockNumber()
const currentL2Block = await this.state.db.getLatestTransaction()
async (req): Promise<SyncingResponse> => {
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<L1TransportServerOptions> {
this._registerRoute(
'get',
'/transaction/latest',
async (): Promise<TransactionResponse> => {
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<TransactionResponse> => {
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<L1TransportServerOptions> {
'get',
'/transaction/index/:index',
async (req): Promise<TransactionResponse> => {
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<L1TransportServerOptions> {
this._registerRoute(
'get',
'/stateroot/latest',
async (): Promise<StateRootResponse> => {
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<StateRootResponse> => {
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<L1TransportServerOptions> {
'get',
'/stateroot/index/:index',
async (req): Promise<StateRootResponse> => {
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) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment