Skip to content

Commit

Permalink
fix: sdk - remove dependence on l2 eth_getLogs (#101)
Browse files Browse the repository at this point in the history
* remove dependence on eth_getLogs

* add nonce

* optimize l1 eth_getLogs

Co-authored-by: CAPtheorem <79423264+CAPtheorem@users.noreply.github.com>
  • Loading branch information
souradeep-das and CAPtheorem authored Apr 19, 2022
1 parent 024917b commit 7703599
Show file tree
Hide file tree
Showing 4 changed files with 126 additions and 16 deletions.
5 changes: 5 additions & 0 deletions packages/message-relayer/src/exec/run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,10 @@ const main = async () => {
'get-logs-interval',
parseInt(env.GET_LOGS_INTERVAL, 10) || 2000
)
const L1_START_OFFSET = config.uint(
'l1-start-offset',
parseInt(env.L1_BLOCK_OFFSET, 10) || 1
)
const FROM_L2_TRANSACTION_INDEX = config.uint(
'from-l2-transaction-index',
parseInt(env.FROM_L2_TRANSACTION_INDEX, 10) || 0
Expand Down Expand Up @@ -147,6 +151,7 @@ const main = async () => {
maxWaitTxTimeS: MAX_WAIT_TX_TIME_S,
fromL2TransactionIndex: FROM_L2_TRANSACTION_INDEX,
pollingInterval: POLLING_INTERVAL,
l1StartOffset: L1_START_OFFSET,
getLogsInterval: GET_LOGS_INTERVAL,
logger,
filterEndpoint: FILTER_ENDPOINT,
Expand Down
36 changes: 29 additions & 7 deletions packages/message-relayer/src/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@ interface MessageRelayerOptions {
*/
pollingInterval?: number

/**
* L1 block to start querying State commitments from. Recommended to set to the StateCommitmentChain deploy height
* not essential, only needed for optimization, event searches are already filtered by batchIndex
*/
l1StartOffset?: number

/**
* Size of the block range to query when looking for new SentMessage events.
*/
Expand Down Expand Up @@ -95,6 +101,9 @@ export class MessageRelayerService extends BaseService<MessageRelayerOptions> {
pollingInterval: {
default: 5000,
},
l1StartOffset: {
default: 0,
},
getLogsInterval: {
default: 2000,
},
Expand Down Expand Up @@ -239,7 +248,10 @@ export class MessageRelayerService extends BaseService<MessageRelayerOptions> {
// Filter out messages which have been processed
const newMB = []
for (const cur of this.state.messageBuffer) {
const status = await this.state.messenger.getMessageStatus(cur)
const status =
await this.state.messenger.getMessageStatusFromContracts(cur, {
fromBlock: this.options.l1StartOffset,
})
if (
// check failed message here too
status !== MessageStatus.RELAYED &&
Expand Down Expand Up @@ -271,10 +283,12 @@ export class MessageRelayerService extends BaseService<MessageRelayerOptions> {
_gasPrice: BigNumber
): Promise<any> => {
// Generate the transaction we will repeatedly submit
const nonce = await this.options.l1Wallet.getTransactionCount()
const txResponse =
await this.state.messenger.finalizeBatchMessage(subBuffer, {
overrides: {
gasPrice: _gasPrice,
nonce,
},
})
const txReceipt = await txResponse.wait(
Expand Down Expand Up @@ -398,9 +412,13 @@ export class MessageRelayerService extends BaseService<MessageRelayerOptions> {
// wait for a few seconds before we check again to see if this transaction is finalized.
let isFinalized = true
for (const message of messages) {
const status = await this.state.messenger.getMessageStatus(
message
)
const status =
await this.state.messenger.getMessageStatusFromContracts(
message,
{
fromBlock: this.options.l1StartOffset,
}
)
if (
status === MessageStatus.IN_CHALLENGE_PERIOD ||
status === MessageStatus.STATE_ROOT_NOT_PUBLISHED
Expand Down Expand Up @@ -442,9 +460,13 @@ export class MessageRelayerService extends BaseService<MessageRelayerOptions> {
}
}

const status = await this.state.messenger.getMessageStatus(
message
)
const status =
await this.state.messenger.getMessageStatusFromContracts(
message,
{
fromBlock: this.options.l1StartOffset,
}
)
if (status === MessageStatus.RELAYED) {
this.logger.info('Message has already been relayed, skipping.')
continue
Expand Down
93 changes: 84 additions & 9 deletions packages/sdk/src/cross-chain-messenger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,63 @@ export class CrossChainMessenger implements ICrossChainMessenger {
}
}

public async getMessageStatusFromContracts(
message: MessageLike,
opts: {
fromBlock?: BlockTag
} = {}
): Promise<MessageStatus> {
const resolved = await this.toCrossChainMessage(message)
const messageHash = hashCrossChainMessage(resolved)
if (resolved.direction === MessageDirection.L1_TO_L2) {
throw new Error(`can only determine for L2 to L1 messages`)
} else {
const stateRoot = await this.getMessageStateRoot(resolved, opts)
if (stateRoot === null) {
return MessageStatus.STATE_ROOT_NOT_PUBLISHED
} else {
// for the fast relayer this should be zero
const challengePeriod = await this.getChallengePeriodSeconds()
const targetBlock = await this.l1Provider.getBlock(
stateRoot.batch.blockNumber
)
const latestBlock = await this.l1Provider.getBlock('latest')
if (targetBlock.timestamp + challengePeriod > latestBlock.timestamp) {
return MessageStatus.IN_CHALLENGE_PERIOD
} else {
let successStatus: boolean
let failedStatus: boolean
if (this.fastRelayer) {
successStatus =
await this.contracts.l1.L1CrossDomainMessengerFast.successfulMessages(
messageHash
)
failedStatus =
await this.contracts.l1.L1CrossDomainMessengerFast.failedMessages(
messageHash
)
} else {
successStatus =
await this.contracts.l1.L1CrossDomainMessenger.successfulMessages(
messageHash
)
failedStatus =
await this.contracts.l1.L1CrossDomainMessenger.failedMessages(
messageHash
)
}
if (successStatus) {
return MessageStatus.RELAYED
} else if (failedStatus) {
return MessageStatus.RELAYED_FAILED
} else {
return MessageStatus.READY_FOR_RELAY
}
}
}
}
}

public async getMessageReceipt(
message: MessageLike,
opts?: {
Expand Down Expand Up @@ -680,7 +737,10 @@ export class CrossChainMessenger implements ICrossChainMessenger {
}

public async getMessageStateRoot(
message: MessageLike
message: MessageLike,
opts: {
fromBlock?: BlockTag
} = {}
): Promise<StateRoot | null> {
const resolved = await this.toCrossChainMessage(message)

Expand All @@ -702,7 +762,8 @@ export class CrossChainMessenger implements ICrossChainMessenger {
// Pull down the state root batch, we'll try to pick out the specific state root that
// corresponds to our message.
const stateRootBatch = await this.getStateRootBatchByTransactionIndex(
messageTxIndex
messageTxIndex,
opts
)

// No state root batch, no state root.
Expand Down Expand Up @@ -731,12 +792,16 @@ export class CrossChainMessenger implements ICrossChainMessenger {
}

public async getStateBatchAppendedEventByBatchIndex(
batchIndex: number
batchIndex: number,
opts?: {
fromBlock?: BlockTag
}
): Promise<ethers.Event | null> {
const events = await this.contracts.l1.StateCommitmentChain.queryFilter(
this.contracts.l1.StateCommitmentChain.filters.StateBatchAppended(
batchIndex
)
),
opts?.fromBlock
)

if (events.length === 0) {
Expand All @@ -750,7 +815,10 @@ export class CrossChainMessenger implements ICrossChainMessenger {
}

public async getStateBatchAppendedEventByTransactionIndex(
transactionIndex: number
transactionIndex: number,
opts: {
fromBlock?: BlockTag
} = {}
): Promise<ethers.Event | null> {
const isEventHi = (event: ethers.Event, index: number) => {
const prevTotalElements = event.args._prevTotalElements.toNumber()
Expand All @@ -772,7 +840,7 @@ export class CrossChainMessenger implements ICrossChainMessenger {
let lowerBound = 0
let upperBound = totalBatches.toNumber() - 1
let batchEvent: ethers.Event | null =
await this.getStateBatchAppendedEventByBatchIndex(upperBound)
await this.getStateBatchAppendedEventByBatchIndex(upperBound, opts)

// Only happens when no batches have been submitted yet.
if (batchEvent === null) {
Expand All @@ -793,7 +861,8 @@ export class CrossChainMessenger implements ICrossChainMessenger {
while (lowerBound < upperBound) {
const middleOfBounds = Math.floor((lowerBound + upperBound) / 2)
batchEvent = await this.getStateBatchAppendedEventByBatchIndex(
middleOfBounds
middleOfBounds,
opts
)

if (isEventHi(batchEvent, transactionIndex)) {
Expand All @@ -809,10 +878,16 @@ export class CrossChainMessenger implements ICrossChainMessenger {
}

public async getStateRootBatchByTransactionIndex(
transactionIndex: number
transactionIndex: number,
opts: {
fromBlock?: BlockTag
} = {}
): Promise<StateRootBatch | null> {
const stateBatchAppendedEvent =
await this.getStateBatchAppendedEventByTransactionIndex(transactionIndex)
await this.getStateBatchAppendedEventByTransactionIndex(
transactionIndex,
opts
)
if (stateBatchAppendedEvent === null) {
return null
}
Expand Down
8 changes: 8 additions & 0 deletions packages/sdk/src/interfaces/cross-chain-messenger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,14 @@ export interface ICrossChainMessenger {
*/
getMessageStatus(message: MessageLike): Promise<MessageStatus>

/**
* Retrieves the relay status of a message from the contracts
*
* @param message Cross chain message to check the status of.
* @returns Status of the message.
*/
getMessageStatusFromContracts(message: MessageLike): Promise<MessageStatus>

/**
* Finds the receipt of the transaction that executed a particular cross chain message.
*
Expand Down

0 comments on commit 7703599

Please sign in to comment.