Commit 3b132974 authored by Karl Floersch's avatar Karl Floersch

fix: estimate gas when pending tx in mempool

style: address pr feedback
parent 6702ce41
---
'@eth-optimism/batch-submitter': patch
---
Fix tx resubmission estimateGas bug in batch submitter
...@@ -159,14 +159,14 @@ export class StateBatchSubmitter extends BatchSubmitter { ...@@ -159,14 +159,14 @@ export class StateBatchSubmitter extends BatchSubmitter {
endBlock: number endBlock: number
): Promise<TransactionReceipt> { ): Promise<TransactionReceipt> {
const batch = await this._generateStateCommitmentBatch(startBlock, endBlock) const batch = await this._generateStateCommitmentBatch(startBlock, endBlock)
const tx = this.chainContract.interface.encodeFunctionData( const calldata = this.chainContract.interface.encodeFunctionData(
'appendStateBatch', 'appendStateBatch',
[batch, startBlock] [batch, startBlock]
) )
const batchSizeInBytes = remove0x(tx).length / 2 const batchSizeInBytes = remove0x(calldata).length / 2
this.logger.debug('State batch generated', { this.logger.debug('State batch generated', {
batchSizeInBytes, batchSizeInBytes,
tx, calldata,
}) })
if (!this._shouldSubmitBatch(batchSizeInBytes)) { if (!this._shouldSubmitBatch(batchSizeInBytes)) {
...@@ -174,29 +174,31 @@ export class StateBatchSubmitter extends BatchSubmitter { ...@@ -174,29 +174,31 @@ export class StateBatchSubmitter extends BatchSubmitter {
} }
const offsetStartsAtIndex = startBlock - this.blockOffset const offsetStartsAtIndex = startBlock - this.blockOffset
this.logger.debug('Submitting batch.', { tx }) this.logger.debug('Submitting batch.', { calldata })
const nonce = await this.signer.getTransactionCount() // Generate the transaction we will repeatedly submit
const tx = await this.chainContract.populateTransaction.appendStateBatch(
batch,
offsetStartsAtIndex
)
const contractFunction = async (gasPrice): Promise<TransactionReceipt> => { const contractFunction = async (gasPrice): Promise<TransactionReceipt> => {
this.logger.info('Submitting appendStateBatch transaction', { this.logger.info('Submitting appendStateBatch transaction', {
gasPrice, gasPrice,
nonce,
contractAddr: this.chainContract.address, contractAddr: this.chainContract.address,
}) })
const contractTx = await this.chainContract.appendStateBatch( const txResponse = await this.signer.sendTransaction({
batch, ...tx,
offsetStartsAtIndex, gasPrice,
{ nonce, gasPrice } })
)
this.logger.info('Submitted appendStateBatch transaction', { this.logger.info('Submitted appendStateBatch transaction', {
txHash: contractTx.hash, txHash: txResponse.hash,
from: contractTx.from, from: txResponse.from,
}) })
this.logger.debug('appendStateBatch transaction data', { this.logger.debug('appendStateBatch transaction data', {
data: contractTx.data, data: txResponse.data,
}) })
return this.signer.provider.waitForTransaction( return this.signer.provider.waitForTransaction(
contractTx.hash, txResponse.hash,
this.numConfirmations this.numConfirmations
) )
} }
......
...@@ -140,28 +140,32 @@ export class TransactionBatchSubmitter extends BatchSubmitter { ...@@ -140,28 +140,32 @@ export class TransactionBatchSubmitter extends BatchSubmitter {
) )
if (!this.disableQueueBatchAppend) { if (!this.disableQueueBatchAppend) {
const nonce = await this.signer.getTransactionCount() // Generate the transaction we will repeatedly submit
const tx = await this.chainContract.populateTransaction.appendQueueBatch(
ethers.constants.MaxUint256 // Completely empty the queue by appending (up to) an enormous number of queue elements.
)
const contractFunction = async ( const contractFunction = async (
gasPrice gasPrice
): Promise<TransactionReceipt> => { ): Promise<TransactionReceipt> => {
this.logger.info('Submitting appendQueueBatch transaction', { this.logger.info('Submitting appendQueueBatch transaction', {
gasPrice, gasPrice,
nonce,
contractAddr: this.chainContract.address, contractAddr: this.chainContract.address,
}) })
const tx = await this.chainContract.appendQueueBatch(99999999, { const txResponse = await this.chainContract.appendQueueBatch(
nonce, ethers.constants.MaxUint256, // Completely empty the queue by appending (up to) an enormous number of queue elements.
gasPrice, {
}) gasPrice,
}
)
this.logger.info('Submitted appendQueueBatch transaction', { this.logger.info('Submitted appendQueueBatch transaction', {
txHash: tx.hash, txHash: txResponse.hash,
from: tx.from, from: txResponse.from,
}) })
this.logger.debug('appendQueueBatch transaction data', { this.logger.debug('appendQueueBatch transaction data', {
data: tx.data, data: txResponse.data,
}) })
return this.signer.provider.waitForTransaction( return this.signer.provider.waitForTransaction(
tx.hash, txResponse.hash,
this.numConfirmations this.numConfirmations
) )
} }
...@@ -250,26 +254,28 @@ export class TransactionBatchSubmitter extends BatchSubmitter { ...@@ -250,26 +254,28 @@ export class TransactionBatchSubmitter extends BatchSubmitter {
l1tipHeight, l1tipHeight,
}) })
const nonce = await this.signer.getTransactionCount() // Generate the transaction we will repeatedly submit
const tx = await this.chainContract.customPopulateTransaction.appendSequencerBatch(
batchParams
)
const contractFunction = async (gasPrice): Promise<TransactionReceipt> => { const contractFunction = async (gasPrice): Promise<TransactionReceipt> => {
this.logger.info('Submitting appendSequencerBatch transaction', { this.logger.info('Submitting appendSequencerBatch transaction', {
gasPrice, gasPrice,
nonce,
contractAddr: this.chainContract.address, contractAddr: this.chainContract.address,
}) })
const tx = await this.chainContract.appendSequencerBatch(batchParams, { const txResponse = await this.signer.sendTransaction({
nonce, ...tx,
gasPrice, gasPrice,
}) })
this.logger.info('Submitted appendSequencerBatch transaction', { this.logger.info('Submitted appendSequencerBatch transaction', {
txHash: tx.hash, txHash: txResponse.hash,
from: tx.from, from: txResponse.from,
}) })
this.logger.debug('appendSequencerBatch transaction data', { this.logger.debug('appendSequencerBatch transaction data', {
data: tx.data, data: txResponse.data,
}) })
return this.signer.provider.waitForTransaction( return this.signer.provider.waitForTransaction(
tx.hash, txResponse.hash,
this.numConfirmations this.numConfirmations
) )
} }
......
/* External Imports */ /* External Imports */
import { Contract, BigNumber } from 'ethers' import { Contract, BigNumber, ethers } from 'ethers'
import { import {
TransactionResponse, TransactionResponse,
TransactionRequest, TransactionRequest,
} from '@ethersproject/abstract-provider' } from '@ethersproject/abstract-provider'
import { JsonRpcProvider } from '@ethersproject/providers'
import { keccak256 } from 'ethers/lib/utils' import { keccak256 } from 'ethers/lib/utils'
import { import {
AppendSequencerBatchParams, AppendSequencerBatchParams,
BatchContext, BatchContext,
encodeAppendSequencerBatch, encodeAppendSequencerBatch,
encodeHex, encodeHex,
remove0x,
} from '@eth-optimism/core-utils' } from '@eth-optimism/core-utils'
export { encodeAppendSequencerBatch, BatchContext, AppendSequencerBatchParams } export { encodeAppendSequencerBatch, BatchContext, AppendSequencerBatchParams }
...@@ -19,6 +21,28 @@ export { encodeAppendSequencerBatch, BatchContext, AppendSequencerBatchParams } ...@@ -19,6 +21,28 @@ export { encodeAppendSequencerBatch, BatchContext, AppendSequencerBatchParams }
* where the `appendSequencerBatch(...)` function uses a specialized encoding for improved efficiency. * where the `appendSequencerBatch(...)` function uses a specialized encoding for improved efficiency.
*/ */
export class CanonicalTransactionChainContract extends Contract { export class CanonicalTransactionChainContract extends Contract {
public customPopulateTransaction = {
appendSequencerBatch: async (
batch: AppendSequencerBatchParams
): Promise<ethers.PopulatedTransaction> => {
const nonce = await this.signer.getTransactionCount()
const to = this.address
const data = getEncodedCalldata(batch)
const gasLimit = await this.signer.provider.estimateGas({
to,
from: await this.signer.getAddress(),
data,
})
const value = 0
return {
nonce,
to,
data,
gasLimit,
}
},
}
public async appendSequencerBatch( public async appendSequencerBatch(
batch: AppendSequencerBatchParams, batch: AppendSequencerBatchParams,
options?: TransactionRequest options?: TransactionRequest
...@@ -38,17 +62,21 @@ const appendSequencerBatch = async ( ...@@ -38,17 +62,21 @@ const appendSequencerBatch = async (
batch: AppendSequencerBatchParams, batch: AppendSequencerBatchParams,
options?: TransactionRequest options?: TransactionRequest
): Promise<TransactionResponse> => { ): Promise<TransactionResponse> => {
const methodId = keccak256(
Buffer.from(APPEND_SEQUENCER_BATCH_METHOD_ID)
).slice(2, 10)
const calldata = encodeAppendSequencerBatch(batch)
return OVM_CanonicalTransactionChain.signer.sendTransaction({ return OVM_CanonicalTransactionChain.signer.sendTransaction({
to: OVM_CanonicalTransactionChain.address, to: OVM_CanonicalTransactionChain.address,
data: '0x' + methodId + calldata, data: getEncodedCalldata(batch),
...options, ...options,
}) })
} }
const getEncodedCalldata = (batch: AppendSequencerBatchParams): string => {
const methodId = keccak256(
Buffer.from(APPEND_SEQUENCER_BATCH_METHOD_ID)
).slice(2, 10)
const calldata = encodeAppendSequencerBatch(batch)
return '0x' + remove0x(methodId) + remove0x(calldata)
}
const encodeBatchContext = (context: BatchContext): string => { const encodeBatchContext = (context: BatchContext): string => {
return ( return (
encodeHex(context.numSequencedTransactions, 6) + encodeHex(context.numSequencedTransactions, 6) +
......
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