Commit 7e38638b authored by Annie Ke's avatar Annie Ke Committed by GitHub

feat: add node_env to batch submitter (#678)

* add node_env to batch submitter

* rename log to logger for service consistency

* address review comments

* make ETH_NETWORK_NAME to disambiguate

* move tx data to debug
parent 7e6f3933
# Environment
NODE_ENV=development
# Leave blank during local development
ETH_NETWORK_NAME=
# Logging & monitoring # Logging & monitoring
DEBUG=info*,error*,warn*,debug* DEBUG=info*,error*,warn*,debug*
# Leave the SENTRY_DSN variable unset during local development # Leave the SENTRY_DSN variable unset during local development
SENTRY_DSN= SENTRY_DSN=
SENTRY_TRACE_RATE=
L1_NODE_WEB3_URL=http://localhost:9545 L1_NODE_WEB3_URL=http://localhost:9545
L2_NODE_WEB3_URL=http://localhost:8545 L2_NODE_WEB3_URL=http://localhost:8545
......
...@@ -40,7 +40,7 @@ export abstract class BatchSubmitter { ...@@ -40,7 +40,7 @@ export abstract class BatchSubmitter {
readonly maxGasPriceInGwei: number, readonly maxGasPriceInGwei: number,
readonly gasRetryIncrement: number, readonly gasRetryIncrement: number,
readonly gasThresholdInGwei: number, readonly gasThresholdInGwei: number,
readonly log: Logger, readonly logger: Logger,
readonly metrics: Metrics readonly metrics: Metrics
) {} ) {}
...@@ -58,13 +58,13 @@ export abstract class BatchSubmitter { ...@@ -58,13 +58,13 @@ export abstract class BatchSubmitter {
} }
await this._updateChainInfo() await this._updateChainInfo()
await this._checkBalance() await this._checkBalance()
this.log.info('Readying to submit next batch...', { this.logger.info('Readying to submit next batch...', {
l2ChainId: this.l2ChainId, l2ChainId: this.l2ChainId,
batchSubmitterAddress: await this.signer.getAddress(), batchSubmitterAddress: await this.signer.getAddress(),
}) })
if (this.syncing === true) { if (this.syncing === true) {
this.log.info( this.logger.info(
'Syncing mode enabled! Skipping batch submission and clearing queue...' 'Syncing mode enabled! Skipping batch submission and clearing queue...'
) )
return this._onSync() return this._onSync()
...@@ -83,13 +83,13 @@ export abstract class BatchSubmitter { ...@@ -83,13 +83,13 @@ export abstract class BatchSubmitter {
const ether = utils.formatEther(balance) const ether = utils.formatEther(balance)
const num = parseFloat(ether) const num = parseFloat(ether)
this.log.info('Checked balance', { this.logger.info('Checked balance', {
address, address,
ether, ether,
}) })
if (num < this.minBalanceEther) { if (num < this.minBalanceEther) {
this.log.fatal('Current balance lower than min safe balance', { this.logger.fatal('Current balance lower than min safe balance', {
current: num, current: num,
safeBalance: this.minBalanceEther, safeBalance: this.minBalanceEther,
}) })
...@@ -130,7 +130,7 @@ export abstract class BatchSubmitter { ...@@ -130,7 +130,7 @@ export abstract class BatchSubmitter {
currentTimestamp currentTimestamp
if (batchSizeInBytes < this.minTxSize) { if (batchSizeInBytes < this.minTxSize) {
if (!isTimeoutReached) { if (!isTimeoutReached) {
this.log.info( this.logger.info(
'Skipping batch submission. Batch too small & max submission timeout not reached.', 'Skipping batch submission. Batch too small & max submission timeout not reached.',
{ {
batchSizeInBytes, batchSizeInBytes,
...@@ -141,25 +141,28 @@ export abstract class BatchSubmitter { ...@@ -141,25 +141,28 @@ export abstract class BatchSubmitter {
) )
return false return false
} }
this.log.info('Timeout reached, proceeding with batch submission.', { this.logger.info('Timeout reached, proceeding with batch submission.', {
batchSizeInBytes, batchSizeInBytes,
lastBatchSubmissionTimestamp: this.lastBatchSubmissionTimestamp, lastBatchSubmissionTimestamp: this.lastBatchSubmissionTimestamp,
currentTimestamp, currentTimestamp,
}) })
return true return true
} }
this.log.info('Sufficient batch size, proceeding with batch submission.', { this.logger.info(
batchSizeInBytes, 'Sufficient batch size, proceeding with batch submission.',
lastBatchSubmissionTimestamp: this.lastBatchSubmissionTimestamp, {
currentTimestamp, batchSizeInBytes,
}) lastBatchSubmissionTimestamp: this.lastBatchSubmissionTimestamp,
currentTimestamp,
}
)
return true return true
} }
public static async getReceiptWithResubmission( public static async getReceiptWithResubmission(
txFunc: (gasPrice) => Promise<TransactionReceipt>, txFunc: (gasPrice) => Promise<TransactionReceipt>,
resubmissionConfig: ResubmissionConfig, resubmissionConfig: ResubmissionConfig,
log: Logger logger: Logger
): Promise<TransactionReceipt> { ): Promise<TransactionReceipt> {
const { const {
resubmissionTimeout, resubmissionTimeout,
...@@ -176,7 +179,7 @@ export abstract class BatchSubmitter { ...@@ -176,7 +179,7 @@ export abstract class BatchSubmitter {
delay: resubmissionTimeout, delay: resubmissionTimeout,
}) })
log.debug('Resubmission tx receipt', { receipt }) logger.debug('Resubmission tx receipt', { receipt })
return receipt return receipt
} }
...@@ -190,7 +193,7 @@ export abstract class BatchSubmitter { ...@@ -190,7 +193,7 @@ export abstract class BatchSubmitter {
10 10
) )
if (minGasPriceInGwei > this.maxGasPriceInGwei) { if (minGasPriceInGwei > this.maxGasPriceInGwei) {
this.log.warn( this.logger.warn(
'Minimum gas price is higher than max! Ethereum must be congested...' 'Minimum gas price is higher than max! Ethereum must be congested...'
) )
minGasPriceInGwei = this.maxGasPriceInGwei minGasPriceInGwei = this.maxGasPriceInGwei
...@@ -203,7 +206,7 @@ export abstract class BatchSubmitter { ...@@ -203,7 +206,7 @@ export abstract class BatchSubmitter {
successMessage: string successMessage: string
): Promise<TransactionReceipt> { ): Promise<TransactionReceipt> {
this.lastBatchSubmissionTimestamp = Date.now() this.lastBatchSubmissionTimestamp = Date.now()
this.log.debug('Waiting for receipt...') this.logger.debug('Waiting for receipt...')
const resubmissionConfig: ResubmissionConfig = { const resubmissionConfig: ResubmissionConfig = {
resubmissionTimeout: this.resubmissionTimeout, resubmissionTimeout: this.resubmissionTimeout,
...@@ -215,11 +218,11 @@ export abstract class BatchSubmitter { ...@@ -215,11 +218,11 @@ export abstract class BatchSubmitter {
const receipt = await BatchSubmitter.getReceiptWithResubmission( const receipt = await BatchSubmitter.getReceiptWithResubmission(
txFunc, txFunc,
resubmissionConfig, resubmissionConfig,
this.log this.logger
) )
this.log.info('Received transaction receipt', { receipt }) this.logger.info('Received transaction receipt', { receipt })
this.log.info(successMessage) this.logger.info(successMessage)
return receipt return receipt
} }
} }
...@@ -40,7 +40,7 @@ export class StateBatchSubmitter extends BatchSubmitter { ...@@ -40,7 +40,7 @@ export class StateBatchSubmitter extends BatchSubmitter {
maxGasPriceInGwei: number, maxGasPriceInGwei: number,
gasRetryIncrement: number, gasRetryIncrement: number,
gasThresholdInGwei: number, gasThresholdInGwei: number,
log: Logger, logger: Logger,
metrics: Metrics, metrics: Metrics,
fraudSubmissionAddress: string fraudSubmissionAddress: string
) { ) {
...@@ -60,7 +60,7 @@ export class StateBatchSubmitter extends BatchSubmitter { ...@@ -60,7 +60,7 @@ export class StateBatchSubmitter extends BatchSubmitter {
maxGasPriceInGwei, maxGasPriceInGwei,
gasRetryIncrement, gasRetryIncrement,
gasThresholdInGwei, gasThresholdInGwei,
log, logger,
metrics metrics
) )
this.fraudSubmissionAddress = fraudSubmissionAddress this.fraudSubmissionAddress = fraudSubmissionAddress
...@@ -73,7 +73,7 @@ export class StateBatchSubmitter extends BatchSubmitter { ...@@ -73,7 +73,7 @@ export class StateBatchSubmitter extends BatchSubmitter {
public async _updateChainInfo(): Promise<void> { public async _updateChainInfo(): Promise<void> {
const info: RollupInfo = await this._getRollupInfo() const info: RollupInfo = await this._getRollupInfo()
if (info.mode === 'verifier') { if (info.mode === 'verifier') {
this.log.error( this.logger.error(
'Verifier mode enabled! Batch submitter only compatible with sequencer mode' 'Verifier mode enabled! Batch submitter only compatible with sequencer mode'
) )
process.exit(1) process.exit(1)
...@@ -88,7 +88,7 @@ export class StateBatchSubmitter extends BatchSubmitter { ...@@ -88,7 +88,7 @@ export class StateBatchSubmitter extends BatchSubmitter {
sccAddress === this.chainContract.address && sccAddress === this.chainContract.address &&
ctcAddress === this.ctcContract.address ctcAddress === this.ctcContract.address
) { ) {
this.log.debug('Chain contract already initialized', { this.logger.debug('Chain contract already initialized', {
sccAddress, sccAddress,
ctcAddress, ctcAddress,
}) })
...@@ -102,7 +102,7 @@ export class StateBatchSubmitter extends BatchSubmitter { ...@@ -102,7 +102,7 @@ export class StateBatchSubmitter extends BatchSubmitter {
await getContractFactory('OVM_CanonicalTransactionChain', this.signer) await getContractFactory('OVM_CanonicalTransactionChain', this.signer)
).attach(ctcAddress) ).attach(ctcAddress)
this.log.info('Connected Optimism contracts', { this.logger.info('Connected Optimism contracts', {
stateCommitmentChain: this.chainContract.address, stateCommitmentChain: this.chainContract.address,
canonicalTransactionChain: this.ctcContract.address, canonicalTransactionChain: this.ctcContract.address,
}) })
...@@ -110,23 +110,23 @@ export class StateBatchSubmitter extends BatchSubmitter { ...@@ -110,23 +110,23 @@ export class StateBatchSubmitter extends BatchSubmitter {
} }
public async _onSync(): Promise<TransactionReceipt> { public async _onSync(): Promise<TransactionReceipt> {
this.log.info('Syncing mode enabled! Skipping state batch submission...') this.logger.info('Syncing mode enabled! Skipping state batch submission...')
return return
} }
public async _getBatchStartAndEnd(): Promise<Range> { public async _getBatchStartAndEnd(): Promise<Range> {
this.log.info('Getting batch start and end for state batch submitter...') this.logger.info('Getting batch start and end for state batch submitter...')
// TODO: Remove BLOCK_OFFSET by adding a tx to Geth's genesis // TODO: Remove BLOCK_OFFSET by adding a tx to Geth's genesis
const startBlock: number = const startBlock: number =
(await this.chainContract.getTotalElements()).toNumber() + BLOCK_OFFSET (await this.chainContract.getTotalElements()).toNumber() + BLOCK_OFFSET
this.log.info('Retrieved start block number from SCC', { this.logger.info('Retrieved start block number from SCC', {
startBlock, startBlock,
}) })
// We will submit state roots for txs which have been in the tx chain for a while. // We will submit state roots for txs which have been in the tx chain for a while.
const totalElements: number = const totalElements: number =
(await this.ctcContract.getTotalElements()).toNumber() + BLOCK_OFFSET (await this.ctcContract.getTotalElements()).toNumber() + BLOCK_OFFSET
this.log.info('Retrieved total elements from CTC', { this.logger.info('Retrieved total elements from CTC', {
totalElements, totalElements,
}) })
...@@ -137,11 +137,11 @@ export class StateBatchSubmitter extends BatchSubmitter { ...@@ -137,11 +137,11 @@ export class StateBatchSubmitter extends BatchSubmitter {
if (startBlock >= endBlock) { if (startBlock >= endBlock) {
if (startBlock > endBlock) { if (startBlock > endBlock) {
this.log.error( this.logger.error(
'State commitment chain is larger than transaction chain. This should never happen!' 'State commitment chain is larger than transaction chain. This should never happen!'
) )
} }
this.log.info( this.logger.info(
'No state commitments to submit. Skipping batch submission...' 'No state commitments to submit. Skipping batch submission...'
) )
return return
...@@ -162,7 +162,7 @@ export class StateBatchSubmitter extends BatchSubmitter { ...@@ -162,7 +162,7 @@ export class StateBatchSubmitter extends BatchSubmitter {
[batch, startBlock] [batch, startBlock]
) )
const batchSizeInBytes = remove0x(tx).length / 2 const batchSizeInBytes = remove0x(tx).length / 2
this.log.debug('State batch generated', { this.logger.debug('State batch generated', {
batchSizeInBytes, batchSizeInBytes,
tx, tx,
}) })
...@@ -172,7 +172,7 @@ export class StateBatchSubmitter extends BatchSubmitter { ...@@ -172,7 +172,7 @@ export class StateBatchSubmitter extends BatchSubmitter {
} }
const offsetStartsAtIndex = startBlock - BLOCK_OFFSET // TODO: Remove BLOCK_OFFSET by adding a tx to Geth's genesis const offsetStartsAtIndex = startBlock - BLOCK_OFFSET // TODO: Remove BLOCK_OFFSET by adding a tx to Geth's genesis
this.log.debug('Submitting batch.', { tx }) this.logger.debug('Submitting batch.', { tx })
const nonce = await this.signer.getTransactionCount() const nonce = await this.signer.getTransactionCount()
const contractFunction = async (gasPrice): Promise<TransactionReceipt> => { const contractFunction = async (gasPrice): Promise<TransactionReceipt> => {
...@@ -181,11 +181,13 @@ export class StateBatchSubmitter extends BatchSubmitter { ...@@ -181,11 +181,13 @@ export class StateBatchSubmitter extends BatchSubmitter {
offsetStartsAtIndex, offsetStartsAtIndex,
{ nonce, gasPrice } { nonce, gasPrice }
) )
this.log.info('Submitted appendStateBatch transaction', { this.logger.info('Submitted appendStateBatch transaction', {
nonce, nonce,
txHash: contractTx.hash, txHash: contractTx.hash,
contractAddr: this.chainContract.address, contractAddr: this.chainContract.address,
from: contractTx.from, from: contractTx.from,
})
this.logger.debug('appendStateBatch transaction data', {
data: contractTx.data, data: contractTx.data,
}) })
return this.signer.provider.waitForTransaction( return this.signer.provider.waitForTransaction(
...@@ -208,13 +210,15 @@ export class StateBatchSubmitter extends BatchSubmitter { ...@@ -208,13 +210,15 @@ export class StateBatchSubmitter extends BatchSubmitter {
const batch: Bytes32[] = await bPromise.map( const batch: Bytes32[] = await bPromise.map(
[...Array(blockRange).keys()], [...Array(blockRange).keys()],
async (i: number) => { async (i: number) => {
this.log.debug('Fetching L2BatchElement', { blockNo: startBlock + i }) this.logger.debug('Fetching L2BatchElement', {
blockNo: startBlock + i,
})
const block = (await this.l2Provider.getBlockWithTransactions( const block = (await this.l2Provider.getBlockWithTransactions(
startBlock + i startBlock + i
)) as L2Block )) as L2Block
const blockTx = block.transactions[0] const blockTx = block.transactions[0]
if (blockTx.from === this.fraudSubmissionAddress) { if (blockTx.from === this.fraudSubmissionAddress) {
this.log.warn('Found transaction from fraud submission address', { this.logger.warn('Found transaction from fraud submission address', {
txHash: blockTx.hash, txHash: blockTx.hash,
fraudSubmissionAddress: this.fraudSubmissionAddress, fraudSubmissionAddress: this.fraudSubmissionAddress,
}) })
...@@ -232,7 +236,7 @@ export class StateBatchSubmitter extends BatchSubmitter { ...@@ -232,7 +236,7 @@ export class StateBatchSubmitter extends BatchSubmitter {
) )
while (remove0x(tx).length / 2 > this.maxTxSize) { while (remove0x(tx).length / 2 > this.maxTxSize) {
batch.splice(Math.ceil((batch.length * 2) / 3)) // Delete 1/3rd of all of the batch elements batch.splice(Math.ceil((batch.length * 2) / 3)) // Delete 1/3rd of all of the batch elements
this.log.debug('Splicing batch...', { this.logger.debug('Splicing batch...', {
batchSizeInBytes: tx.length / 2, batchSizeInBytes: tx.length / 2,
}) })
tx = this.chainContract.interface.encodeFunctionData('appendStateBatch', [ tx = this.chainContract.interface.encodeFunctionData('appendStateBatch', [
...@@ -241,7 +245,7 @@ export class StateBatchSubmitter extends BatchSubmitter { ...@@ -241,7 +245,7 @@ export class StateBatchSubmitter extends BatchSubmitter {
]) ])
} }
this.log.info('Generated state commitment batch', { this.logger.info('Generated state commitment batch', {
batch, // list of stateRoots batch, // list of stateRoots
}) })
return batch return batch
......
...@@ -16,19 +16,34 @@ import { ...@@ -16,19 +16,34 @@ import {
TX_BATCH_SUBMITTER_LOG_TAG, TX_BATCH_SUBMITTER_LOG_TAG,
} from '..' } from '..'
const environment = process.env.NODE_ENV
const network = process.env.ETH_NETWORK_NAME
const release = `batch-submitter@${process.env.npm_package_version}`
/* Logger */ /* Logger */
const name = 'oe:batch_submitter:init' const name = 'oe:batch_submitter:init'
const log = new Logger({ let logger
name,
sentryOptions: { if (network) {
release: `batch-submitter@${process.env.npm_package_version}`, // Initialize Sentry for Batch Submitter deployed to a network
dsn: process.env.SENTRY_DSN, logger = new Logger({
tracesSampleRate: 0.05, name,
}, sentryOptions: {
}) release,
dsn: process.env.SENTRY_DSN,
tracesSampleRate: parseInt(process.env.SENTRY_TRACE_RATE, 10) || 0.05,
environment: network, // separate our Sentry errors by network instead of node environment
},
})
} else {
// Skip initializing Sentry
logger = new Logger({ name })
}
/* Metrics */ /* Metrics */
const metrics = new Metrics({ const metrics = new Metrics({
prefix: name, prefix: name,
labels: { environment, release, network },
}) })
interface RequiredEnvVars { interface RequiredEnvVars {
...@@ -115,11 +130,11 @@ const autoFixBatchOptions: AutoFixBatchOptions = { ...@@ -115,11 +130,11 @@ const autoFixBatchOptions: AutoFixBatchOptions = {
} }
export const run = async () => { export const run = async () => {
log.info('Starting batch submitter...') logger.info('Starting batch submitter...')
for (const [i, val] of Object.entries(requiredEnvVars)) { for (const [i, val] of Object.entries(requiredEnvVars)) {
if (!process.env[val]) { if (!process.env[val]) {
log.warn('Missing environment variable', { logger.warn('Missing environment variable', {
varName: val, varName: val,
}) })
exit(1) exit(1)
...@@ -144,7 +159,7 @@ export const run = async () => { ...@@ -144,7 +159,7 @@ export const run = async () => {
} }
const address = await sequencerSigner.getAddress() const address = await sequencerSigner.getAddress()
log.info('Configured batch submitter addresses', { logger.info('Configured batch submitter addresses', {
batchSubmitterAddress: address, batchSubmitterAddress: address,
addressManagerAddress: requiredEnvVars.ADDRESS_MANAGER_ADDRESS, addressManagerAddress: requiredEnvVars.ADDRESS_MANAGER_ADDRESS,
}) })
...@@ -164,8 +179,11 @@ export const run = async () => { ...@@ -164,8 +179,11 @@ export const run = async () => {
MAX_GAS_PRICE_IN_GWEI, MAX_GAS_PRICE_IN_GWEI,
GAS_RETRY_INCREMENT, GAS_RETRY_INCREMENT,
GAS_THRESHOLD_IN_GWEI, GAS_THRESHOLD_IN_GWEI,
log.child({ name: TX_BATCH_SUBMITTER_LOG_TAG }), logger.child({ name: TX_BATCH_SUBMITTER_LOG_TAG }),
new Metrics({ prefix: TX_BATCH_SUBMITTER_LOG_TAG }), new Metrics({
prefix: TX_BATCH_SUBMITTER_LOG_TAG,
labels: { environment, release, network },
}),
DISABLE_QUEUE_BATCH_APPEND, DISABLE_QUEUE_BATCH_APPEND,
autoFixBatchOptions autoFixBatchOptions
) )
...@@ -186,8 +204,11 @@ export const run = async () => { ...@@ -186,8 +204,11 @@ export const run = async () => {
MAX_GAS_PRICE_IN_GWEI, MAX_GAS_PRICE_IN_GWEI,
GAS_RETRY_INCREMENT, GAS_RETRY_INCREMENT,
GAS_THRESHOLD_IN_GWEI, GAS_THRESHOLD_IN_GWEI,
log.child({ name: STATE_BATCH_SUBMITTER_LOG_TAG }), logger.child({ name: STATE_BATCH_SUBMITTER_LOG_TAG }),
new Metrics({ prefix: STATE_BATCH_SUBMITTER_LOG_TAG }), new Metrics({
prefix: STATE_BATCH_SUBMITTER_LOG_TAG,
labels: { environment, release, network },
}),
FRAUD_SUBMISSION_ADDRESS FRAUD_SUBMISSION_ADDRESS
) )
...@@ -201,18 +222,22 @@ export const run = async () => { ...@@ -201,18 +222,22 @@ export const run = async () => {
const pendingTxs = await sequencerSigner.getTransactionCount('pending') const pendingTxs = await sequencerSigner.getTransactionCount('pending')
const latestTxs = await sequencerSigner.getTransactionCount('latest') const latestTxs = await sequencerSigner.getTransactionCount('latest')
if (pendingTxs > latestTxs) { if (pendingTxs > latestTxs) {
log.info('Detected pending transactions. Clearing all transactions!') logger.info(
'Detected pending transactions. Clearing all transactions!'
)
for (let i = latestTxs; i < pendingTxs; i++) { for (let i = latestTxs; i < pendingTxs; i++) {
const response = await sequencerSigner.sendTransaction({ const response = await sequencerSigner.sendTransaction({
to: await sequencerSigner.getAddress(), to: await sequencerSigner.getAddress(),
value: 0, value: 0,
nonce: i, nonce: i,
}) })
log.info('Submitted empty transaction', { logger.info('Submitted empty transaction', {
nonce: i, nonce: i,
txHash: response.hash, txHash: response.hash,
to: response.to, to: response.to,
from: response.from, from: response.from,
})
logger.debug('empty transaction data', {
data: response.data, data: response.data,
}) })
await sequencerSigner.provider.waitForTransaction( await sequencerSigner.provider.waitForTransaction(
...@@ -222,7 +247,7 @@ export const run = async () => { ...@@ -222,7 +247,7 @@ export const run = async () => {
} }
} }
} catch (err) { } catch (err) {
log.error('Cannot clear transactions', { err }) logger.error('Cannot clear transactions', { err })
process.exit(1) process.exit(1)
} }
} }
...@@ -231,8 +256,8 @@ export const run = async () => { ...@@ -231,8 +256,8 @@ export const run = async () => {
try { try {
await func() await func()
} catch (err) { } catch (err) {
log.error('Error submitting batch', { err }) logger.error('Error submitting batch', { err })
log.info('Retrying...') logger.info('Retrying...')
} }
// Sleep // Sleep
await new Promise((r) => await new Promise((r) =>
......
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