Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 63 additions & 6 deletions packages/rollup-full-node/src/app/account-rate-limiter.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
/* External imports */
import { getLogger, TimeBucketedCounter } from '@eth-optimism/core-utils'
import {
getLogger,
logError,
TimeBucketedCounter,
} from '@eth-optimism/core-utils'

/* Internal imports */
import {
AccountRateLimiter,
RateLimitError,
TransactionLimitError,
} from '../types'
import { Environment } from './util'

const log = getLogger('routing-handler')

Expand All @@ -30,10 +35,11 @@ export class DefaultAccountRateLimiter implements AccountRateLimiter {
private readonly requestingAddressesSinceLastPurge: Set<string>

constructor(
private readonly maxRequestsPerTimeUnit,
private readonly maxTransactionsPerTimeUnit,
private readonly requestLimitPeriodInMillis,
private purgeIntervalMultiplier: number = 1_000
private maxRequestsPerTimeUnit,
private maxTransactionsPerTimeUnit,
private requestLimitPeriodInMillis,
purgeIntervalMultiplier: number = 1_000,
variableRefreshRateMillis = 300_000
) {
this.requestingIpsSinceLastPurge = new Set<string>()
this.requestingAddressesSinceLastPurge = new Set<string>()
Expand All @@ -48,6 +54,10 @@ export class DefaultAccountRateLimiter implements AccountRateLimiter {
setInterval(() => {
this.purgeStale(true)
}, this.requestLimitPeriodInMillis * (purgeIntervalMultiplier + 5))

setInterval(() => {
this.refreshVariables()
}, variableRefreshRateMillis)
}

/**
Expand Down Expand Up @@ -94,7 +104,7 @@ export class DefaultAccountRateLimiter implements AccountRateLimiter {
this.requestingAddressesSinceLastPurge.add(address)

const numRequests = this.addressToRequestCounter.get(address).increment()
if (numRequests > this.maxRequestsPerTimeUnit) {
if (numRequests > this.maxTransactionsPerTimeUnit) {
throw new TransactionLimitError(
address,
numRequests,
Expand Down Expand Up @@ -127,4 +137,51 @@ export class DefaultAccountRateLimiter implements AccountRateLimiter {
})
set.clear()
}

/**
* Refreshes configured member variables from updated Environment Variables.
*/
private refreshVariables(): void {
try {
const envPeriod = Environment.requestLimitPeriodMillis()
if (!!envPeriod && this.requestLimitPeriodInMillis !== envPeriod) {
const prevVal = this.requestLimitPeriodInMillis
this.requestLimitPeriodInMillis = envPeriod
this.ipToRequestCounter.clear()
this.addressToRequestCounter.clear()
this.requestingIpsSinceLastPurge.clear()
this.requestingAddressesSinceLastPurge.clear()
log.info(
`Updated Rate Limit time period from ${prevVal} to ${this.requestLimitPeriodInMillis} millis`
)
}

const envRequestLimit = Environment.maxNonTransactionRequestsPerUnitTime()
if (
!!envRequestLimit &&
this.maxRequestsPerTimeUnit !== envRequestLimit
) {
const prevVal = this.maxRequestsPerTimeUnit
this.maxRequestsPerTimeUnit = envRequestLimit
log.info(
`Updated Max Requests Per unit time value from ${prevVal} to ${this.maxRequestsPerTimeUnit}`
)
}

const envTxLimit = Environment.maxTransactionsPerUnitTime()
if (!!envTxLimit && this.maxTransactionsPerTimeUnit !== envTxLimit) {
const prevVal = this.maxTransactionsPerTimeUnit
this.maxTransactionsPerTimeUnit = envTxLimit
log.info(
`Updated Max Transactions Per unit time value from ${prevVal} to ${this.maxTransactionsPerTimeUnit}`
)
}
} catch (e) {
logError(
log,
`Error updating rate limiter variables from environment variables`,
e
)
}
}
}
71 changes: 65 additions & 6 deletions packages/rollup-full-node/src/app/routing-handler.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/* External Imports */
import { Address } from '@eth-optimism/rollup-core'
import {
areEqual,
getLogger,
isJsonRpcErrorResponse,
JsonRpcErrorResponse,
Expand All @@ -22,6 +23,7 @@ import {
Web3RpcMethods,
web3RpcMethodsExcludingTest,
} from '../types'
import { Environment } from './util'

const log = getLogger('routing-handler')

Expand All @@ -47,14 +49,19 @@ export class RoutingHandler implements FullnodeHandler {
constructor(
private readonly transactionClient: SimpleClient,
private readonly readOnlyClient: SimpleClient,
private readonly deployAddress: Address,
private deployAddress: Address,
private readonly accountRateLimiter: AccountRateLimiter,
private readonly rateLimiterWhitelistedIps: string[] = [],
private readonly toAddressWhitelist: Address[] = [],
private rateLimiterWhitelistedIps: string[] = [],
private toAddressWhitelist: Address[] = [],
private readonly whitelistedMethods: Set<string> = new Set<string>(
web3RpcMethodsExcludingTest
)
) {}
),
variableRefreshRateMillis = 300_000
) {
setInterval(() => {
this.refreshVariables()
}, variableRefreshRateMillis)
}

/**
* Handles the provided request by
Expand Down Expand Up @@ -155,7 +162,59 @@ export class RoutingHandler implements FullnodeHandler {
) {
throw new InvalidTransactionDesinationError(
tx.to,
this.toAddressWhitelist
Array.from(this.toAddressWhitelist)
)
}
}

/**
* Refreshes configured member variables from updated Environment Variables.
*/
private refreshVariables(): void {
try {
const envToWhitelist = Environment.transactionToAddressWhitelist()
if (
!!envToWhitelist &&
envToWhitelist.length &&
!areEqual(envToWhitelist.sort(), this.toAddressWhitelist.sort())
) {
const prevValue = this.toAddressWhitelist
this.toAddressWhitelist = envToWhitelist
log.info(
`Transaction 'to' address whitelist updated from ${JSON.stringify(
prevValue
)} to ${JSON.stringify(this.toAddressWhitelist)}`
)
}

const envIpWhitelist = Environment.rateLimitWhitelistIpAddresses()
if (
!!envIpWhitelist &&
!!envIpWhitelist.length &&
!areEqual(envIpWhitelist.sort(), this.rateLimiterWhitelistedIps.sort())
) {
const prevValue = this.rateLimiterWhitelistedIps
this.rateLimiterWhitelistedIps = envIpWhitelist
log.info(
`IP whitelist updated from ${JSON.stringify(
prevValue
)} to ${JSON.stringify(this.rateLimiterWhitelistedIps)}`
)
}

const deployerAddress = Environment.contractDeployerAddress()
if (!!deployerAddress && deployerAddress !== this.deployAddress) {
const prevValue = this.deployAddress
this.deployAddress = deployerAddress
log.info(
`Deployer address updated from ${prevValue} to ${this.deployAddress}`
)
}
} catch (e) {
logError(
log,
`Error updating router variables from environment variables`,
e
)
}
}
Expand Down
Loading