Commit c79dc8b2 authored by Karl Floersch's avatar Karl Floersch Committed by GitHub

feat: add config for impersonating accounts to BS (#864)

* feat: add config for impersonating accounts to BS

Useful for testing against hardhat forks.

* Make block offset configurable (#865)

* feat: make block offset configurable

* Add a USE_HARDHAT config

* batch-submitter: must pass both impersonate options (#866)
Co-authored-by: default avatarMark Tyneway <mark.tyneway@gmail.com>

* batch-submitter: update example env

* batch-submitter: lint fix

* batch-submitter: clean up old comments

* batch-submitter: USE_HARDHAT

* batch-submitter: add error messages
Co-authored-by: default avatarMark Tyneway <mark.tyneway@gmail.com>
parent e1cc9898
---
'@eth-optimism/batch-submitter': patch
---
Add impersonate account debug config.
---
'@eth-optimism/batch-submitter': patch
---
Make BLOCK_OFFSET configurable.
...@@ -28,6 +28,10 @@ SAFE_MINIMUM_ETHER_BALANCE=0 ...@@ -28,6 +28,10 @@ SAFE_MINIMUM_ETHER_BALANCE=0
CLEAR_PENDING_TXS=false CLEAR_PENDING_TXS=false
ADDRESS_MANAGER_ADDRESS= ADDRESS_MANAGER_ADDRESS=
USE_HARDHAT=
DEBUG_IMPERSONATE_SEQUENCER_ADDRESS=
DEBUG_IMPERSONATE_PROPOSER_ADDRESS=
# Optional gas settings # Optional gas settings
MAX_GAS_PRICE_IN_GWEI=200 MAX_GAS_PRICE_IN_GWEI=200
GAS_RETRY_INCREMENT=5 GAS_RETRY_INCREMENT=5
......
...@@ -6,6 +6,8 @@ import { ...@@ -6,6 +6,8 @@ import {
RUN_OVM_TEST_GAS, RUN_OVM_TEST_GAS,
} from './test/helpers/constants' } from './test/helpers/constants'
import '@nomiclabs/hardhat-ethers'
const config: HardhatUserConfig = { const config: HardhatUserConfig = {
networks: { networks: {
hardhat: { hardhat: {
......
...@@ -50,6 +50,7 @@ export abstract class BatchSubmitter { ...@@ -50,6 +50,7 @@ export abstract class BatchSubmitter {
readonly maxGasPriceInGwei: number, readonly maxGasPriceInGwei: number,
readonly gasRetryIncrement: number, readonly gasRetryIncrement: number,
readonly gasThresholdInGwei: number, readonly gasThresholdInGwei: number,
readonly blockOffset: number,
readonly logger: Logger, readonly logger: Logger,
readonly defaultMetrics: Metrics readonly defaultMetrics: Metrics
) { ) {
......
...@@ -4,7 +4,3 @@ export * from './state-batch-submitter' ...@@ -4,7 +4,3 @@ export * from './state-batch-submitter'
export const TX_BATCH_SUBMITTER_LOG_TAG = 'oe:batch_submitter:tx_chain' export const TX_BATCH_SUBMITTER_LOG_TAG = 'oe:batch_submitter:tx_chain'
export const STATE_BATCH_SUBMITTER_LOG_TAG = 'oe:batch_submitter:state_chain' export const STATE_BATCH_SUBMITTER_LOG_TAG = 'oe:batch_submitter:state_chain'
// BLOCK_OFFSET is the number of L2 blocks we need to skip for the
// batch submitter.
export const BLOCK_OFFSET = 1 // TODO: Update testnet / mainnet to make this zero.
...@@ -12,7 +12,7 @@ import { ...@@ -12,7 +12,7 @@ import {
import { Logger, Metrics } from '@eth-optimism/common-ts' import { Logger, Metrics } from '@eth-optimism/common-ts'
/* Internal Imports */ /* Internal Imports */
import { Range, BatchSubmitter, BLOCK_OFFSET } from '.' import { Range, BatchSubmitter } from '.'
export class StateBatchSubmitter extends BatchSubmitter { export class StateBatchSubmitter extends BatchSubmitter {
// TODO: Change this so that we calculate start = scc.totalElements() and end = ctc.totalElements()! // TODO: Change this so that we calculate start = scc.totalElements() and end = ctc.totalElements()!
...@@ -40,6 +40,7 @@ export class StateBatchSubmitter extends BatchSubmitter { ...@@ -40,6 +40,7 @@ export class StateBatchSubmitter extends BatchSubmitter {
maxGasPriceInGwei: number, maxGasPriceInGwei: number,
gasRetryIncrement: number, gasRetryIncrement: number,
gasThresholdInGwei: number, gasThresholdInGwei: number,
blockOffset: number,
logger: Logger, logger: Logger,
metrics: Metrics, metrics: Metrics,
fraudSubmissionAddress: string fraudSubmissionAddress: string
...@@ -60,6 +61,7 @@ export class StateBatchSubmitter extends BatchSubmitter { ...@@ -60,6 +61,7 @@ export class StateBatchSubmitter extends BatchSubmitter {
maxGasPriceInGwei, maxGasPriceInGwei,
gasRetryIncrement, gasRetryIncrement,
gasThresholdInGwei, gasThresholdInGwei,
blockOffset,
logger, logger,
metrics metrics
) )
...@@ -116,16 +118,16 @@ export class StateBatchSubmitter extends BatchSubmitter { ...@@ -116,16 +118,16 @@ export class StateBatchSubmitter extends BatchSubmitter {
public async _getBatchStartAndEnd(): Promise<Range> { public async _getBatchStartAndEnd(): Promise<Range> {
this.logger.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
const startBlock: number = const startBlock: number =
(await this.chainContract.getTotalElements()).toNumber() + BLOCK_OFFSET (await this.chainContract.getTotalElements()).toNumber() +
this.blockOffset
this.logger.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() + this.blockOffset
this.logger.info('Retrieved total elements from CTC', { this.logger.info('Retrieved total elements from CTC', {
totalElements, totalElements,
}) })
...@@ -171,7 +173,7 @@ export class StateBatchSubmitter extends BatchSubmitter { ...@@ -171,7 +173,7 @@ export class StateBatchSubmitter extends BatchSubmitter {
return return
} }
const offsetStartsAtIndex = startBlock - BLOCK_OFFSET // TODO: Remove BLOCK_OFFSET by adding a tx to Geth's genesis const offsetStartsAtIndex = startBlock - this.blockOffset
this.logger.debug('Submitting batch.', { tx }) this.logger.debug('Submitting batch.', { tx })
const nonce = await this.signer.getTransactionCount() const nonce = await this.signer.getTransactionCount()
......
...@@ -21,7 +21,7 @@ import { ...@@ -21,7 +21,7 @@ import {
AppendSequencerBatchParams, AppendSequencerBatchParams,
} from '../transaction-chain-contract' } from '../transaction-chain-contract'
import { Range, BatchSubmitter, BLOCK_OFFSET } from '.' import { Range, BatchSubmitter } from '.'
export interface AutoFixBatchOptions { export interface AutoFixBatchOptions {
fixDoublePlayedDeposits: boolean fixDoublePlayedDeposits: boolean
...@@ -51,6 +51,7 @@ export class TransactionBatchSubmitter extends BatchSubmitter { ...@@ -51,6 +51,7 @@ export class TransactionBatchSubmitter extends BatchSubmitter {
maxGasPriceInGwei: number, maxGasPriceInGwei: number,
gasRetryIncrement: number, gasRetryIncrement: number,
gasThresholdInGwei: number, gasThresholdInGwei: number,
blockOffset: number,
logger: Logger, logger: Logger,
metrics: Metrics, metrics: Metrics,
disableQueueBatchAppend: boolean, disableQueueBatchAppend: boolean,
...@@ -76,6 +77,7 @@ export class TransactionBatchSubmitter extends BatchSubmitter { ...@@ -76,6 +77,7 @@ export class TransactionBatchSubmitter extends BatchSubmitter {
maxGasPriceInGwei, maxGasPriceInGwei,
gasRetryIncrement, gasRetryIncrement,
gasThresholdInGwei, gasThresholdInGwei,
blockOffset,
logger, logger,
metrics metrics
) )
...@@ -172,9 +174,9 @@ export class TransactionBatchSubmitter extends BatchSubmitter { ...@@ -172,9 +174,9 @@ export class TransactionBatchSubmitter extends BatchSubmitter {
this.logger.info( this.logger.info(
'Getting batch start and end for transaction batch submitter...' 'Getting batch start and end for transaction batch submitter...'
) )
// TODO: Remove BLOCK_OFFSET by adding a tx to Geth's genesis
const startBlock = const startBlock =
(await this.chainContract.getTotalElements()).toNumber() + BLOCK_OFFSET (await this.chainContract.getTotalElements()).toNumber() +
this.blockOffset
this.logger.info('Retrieved start block number from CTC', { this.logger.info('Retrieved start block number from CTC', {
startBlock, startBlock,
}) })
...@@ -753,8 +755,7 @@ export class TransactionBatchSubmitter extends BatchSubmitter { ...@@ -753,8 +755,7 @@ export class TransactionBatchSubmitter extends BatchSubmitter {
} }
return { return {
// TODO: Remove BLOCK_OFFSET by adding a tx to Geth's genesis shouldStartAtElement: shouldStartAtIndex - this.blockOffset,
shouldStartAtElement: shouldStartAtIndex - BLOCK_OFFSET,
totalElementsToAppend, totalElementsToAppend,
contexts, contexts,
transactions, transactions,
......
...@@ -63,6 +63,10 @@ interface RequiredEnvVars { ...@@ -63,6 +63,10 @@ interface RequiredEnvVars {
* PROPOSER_MNEMONIC * PROPOSER_MNEMONIC
* SEQUENCER_HD_PATH * SEQUENCER_HD_PATH
* PROPOSER_HD_PATH * PROPOSER_HD_PATH
* BLOCK_OFFSET
* USE_HARDHAT
* DEBUG_IMPERSONATE_SEQUENCER_ADDRESS
* DEBUG_IMPERSONATE_PROPOSER_ADDRESS
*/ */
export const run = async () => { export const run = async () => {
...@@ -85,6 +89,12 @@ export const run = async () => { ...@@ -85,6 +89,12 @@ export const run = async () => {
parseFloat(env.SENTRY_TRACE_RATE) || 0.05 parseFloat(env.SENTRY_TRACE_RATE) || 0.05
) )
// Default is 1 because Geth normally has 1 more block than L1
const BLOCK_OFFSET = config.uint(
'block-offset',
parseInt(env.BLOCK_OFFSET, 10) || 1
)
/* Logger */ /* Logger */
const name = 'oe:batch_submitter:init' const name = 'oe:batch_submitter:init'
let logger let logger
...@@ -105,6 +115,66 @@ export const run = async () => { ...@@ -105,6 +115,66 @@ export const run = async () => {
logger = new Logger({ name }) logger = new Logger({ name })
} }
const useHardhat = config.bool('use-hardhat', !!env.USE_HARDAT)
const DEBUG_IMPERSONATE_SEQUENCER_ADDRESS = config.str(
'debug-impersonate-sequencer-address',
env.DEBUG_IMPERSONATE_SEQUENCER_ADDRESS
)
const DEBUG_IMPERSONATE_PROPOSER_ADDRESS = config.str(
'debug-impersonate-proposer-address',
env.DEBUG_IMPERSONATE_PROPOSER_ADDRESS
)
const getSequencerSigner = async (): Promise<Signer> => {
const l1Provider = new JsonRpcProvider(requiredEnvVars.L1_NODE_WEB3_URL)
if (useHardhat) {
if (!DEBUG_IMPERSONATE_SEQUENCER_ADDRESS) {
throw new Error('Must pass DEBUG_IMPERSONATE_SEQUENCER_ADDRESS')
}
await l1Provider.send('hardhat_impersonateAccount', [
DEBUG_IMPERSONATE_SEQUENCER_ADDRESS,
])
return l1Provider.getSigner(DEBUG_IMPERSONATE_SEQUENCER_ADDRESS)
}
if (SEQUENCER_PRIVATE_KEY) {
return new Wallet(SEQUENCER_PRIVATE_KEY, l1Provider)
} else if (SEQUENCER_MNEMONIC) {
return Wallet.fromMnemonic(SEQUENCER_MNEMONIC, SEQUENCER_HD_PATH).connect(
l1Provider
)
}
throw new Error(
'Must pass one of SEQUENCER_PRIVATE_KEY, MNEMONIC, or SEQUENCER_MNEMONIC'
)
}
const getProposerSigner = async (): Promise<Signer> => {
const l1Provider = new JsonRpcProvider(requiredEnvVars.L1_NODE_WEB3_URL)
if (useHardhat) {
if (!DEBUG_IMPERSONATE_PROPOSER_ADDRESS) {
throw new Error('Must pass DEBUG_IMPERSONATE_PROPOSER_ADDRESS')
}
await l1Provider.send('hardhat_impersonateAccount', [
DEBUG_IMPERSONATE_PROPOSER_ADDRESS,
])
return l1Provider.getSigner(DEBUG_IMPERSONATE_PROPOSER_ADDRESS)
}
if (PROPOSER_PRIVATE_KEY) {
return new Wallet(PROPOSER_PRIVATE_KEY, l1Provider)
} else if (PROPOSER_MNEMONIC) {
return Wallet.fromMnemonic(PROPOSER_MNEMONIC, PROPOSER_HD_PATH).connect(
l1Provider
)
}
throw new Error(
'Must pass one of PROPOSER_PRIVATE_KEY, MNEMONIC, or PROPOSER_MNEMONIC'
)
}
/* Metrics */ /* Metrics */
const metrics = new Metrics({ const metrics = new Metrics({
prefix: name, prefix: name,
...@@ -255,52 +325,26 @@ export const run = async () => { ...@@ -255,52 +325,26 @@ export const run = async () => {
const clearPendingTxs = requiredEnvVars.CLEAR_PENDING_TXS const clearPendingTxs = requiredEnvVars.CLEAR_PENDING_TXS
const l1Provider = new JsonRpcProvider(requiredEnvVars.L1_NODE_WEB3_URL)
const l2Provider = injectL2Context( const l2Provider = injectL2Context(
new JsonRpcProvider(requiredEnvVars.L2_NODE_WEB3_URL) new JsonRpcProvider(requiredEnvVars.L2_NODE_WEB3_URL)
) )
let sequencerSigner: Signer const sequencerSigner: Signer = await getSequencerSigner()
let proposerSigner: Signer let proposerSigner: Signer = await getProposerSigner()
if (SEQUENCER_PRIVATE_KEY) {
sequencerSigner = new Wallet(SEQUENCER_PRIVATE_KEY, l1Provider)
} else if (SEQUENCER_MNEMONIC) {
sequencerSigner = Wallet.fromMnemonic(
SEQUENCER_MNEMONIC,
SEQUENCER_HD_PATH
).connect(l1Provider)
} else {
throw new Error(
'Must pass one of SEQUENCER_PRIVATE_KEY, MNEMONIC, or SEQUENCER_MNEMONIC'
)
}
if (PROPOSER_PRIVATE_KEY) {
proposerSigner = new Wallet(PROPOSER_PRIVATE_KEY, l1Provider)
} else if (PROPOSER_MNEMONIC) {
proposerSigner = Wallet.fromMnemonic(
PROPOSER_MNEMONIC,
PROPOSER_HD_PATH
).connect(l1Provider)
} else {
throw new Error(
'Must pass one of PROPOSER_PRIVATE_KEY, MNEMONIC, or PROPOSER_MNEMONIC'
)
}
const sequencerAddress = await sequencerSigner.getAddress() const sequencerAddress = await sequencerSigner.getAddress()
const proposerAddress = await proposerSigner.getAddress() const proposerAddress = await proposerSigner.getAddress()
const address = await sequencerSigner.getAddress() // If the sequencer & proposer are the same, use a single wallet
if (sequencerAddress === proposerAddress) {
proposerSigner = sequencerSigner
}
logger.info('Configured batch submitter addresses', { logger.info('Configured batch submitter addresses', {
sequencerAddress, sequencerAddress,
proposerAddress, proposerAddress,
addressManagerAddress: requiredEnvVars.ADDRESS_MANAGER_ADDRESS, addressManagerAddress: requiredEnvVars.ADDRESS_MANAGER_ADDRESS,
}) })
// If the sequencer & proposer are the same, use a single wallet
if (sequencerAddress === proposerAddress) {
proposerSigner = sequencerSigner
}
const txBatchSubmitter = new TransactionBatchSubmitter( const txBatchSubmitter = new TransactionBatchSubmitter(
sequencerSigner, sequencerSigner,
l2Provider, l2Provider,
...@@ -316,6 +360,7 @@ export const run = async () => { ...@@ -316,6 +360,7 @@ 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,
BLOCK_OFFSET,
logger.child({ name: TX_BATCH_SUBMITTER_LOG_TAG }), logger.child({ name: TX_BATCH_SUBMITTER_LOG_TAG }),
new Metrics({ new Metrics({
prefix: TX_BATCH_SUBMITTER_LOG_TAG, prefix: TX_BATCH_SUBMITTER_LOG_TAG,
...@@ -341,6 +386,7 @@ export const run = async () => { ...@@ -341,6 +386,7 @@ 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,
BLOCK_OFFSET,
logger.child({ name: STATE_BATCH_SUBMITTER_LOG_TAG }), logger.child({ name: STATE_BATCH_SUBMITTER_LOG_TAG }),
new Metrics({ new Metrics({
prefix: STATE_BATCH_SUBMITTER_LOG_TAG, prefix: STATE_BATCH_SUBMITTER_LOG_TAG,
......
...@@ -216,6 +216,7 @@ describe('BatchSubmitter', () => { ...@@ -216,6 +216,7 @@ describe('BatchSubmitter', () => {
MAX_GAS_PRICE_IN_GWEI, MAX_GAS_PRICE_IN_GWEI,
GAS_RETRY_INCREMENT, GAS_RETRY_INCREMENT,
GAS_THRESHOLD_IN_GWEI, GAS_THRESHOLD_IN_GWEI,
1,
new Logger({ name: TX_BATCH_SUBMITTER_LOG_TAG }), new Logger({ name: TX_BATCH_SUBMITTER_LOG_TAG }),
testMetrics, testMetrics,
false false
...@@ -432,6 +433,7 @@ describe('BatchSubmitter', () => { ...@@ -432,6 +433,7 @@ describe('BatchSubmitter', () => {
MAX_GAS_PRICE_IN_GWEI, MAX_GAS_PRICE_IN_GWEI,
GAS_RETRY_INCREMENT, GAS_RETRY_INCREMENT,
GAS_THRESHOLD_IN_GWEI, GAS_THRESHOLD_IN_GWEI,
1,
new Logger({ name: STATE_BATCH_SUBMITTER_LOG_TAG }), new Logger({ name: STATE_BATCH_SUBMITTER_LOG_TAG }),
testMetrics, testMetrics,
'0x' + '01'.repeat(20) // placeholder for fraudSubmissionAddress '0x' + '01'.repeat(20) // placeholder for fraudSubmissionAddress
......
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