Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix/handle tx underpriced #360

Merged
merged 4 commits into from
Nov 19, 2024
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
4 changes: 4 additions & 0 deletions src/cli/setupServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ const getCompressionHandler = async (
}

const getExecutor = ({
mempool,
config,
senderManager,
reputationManager,
Expand All @@ -124,6 +125,7 @@ const getExecutor = ({
gasPriceManager,
eventManager
}: {
mempool: MemoryMempool
config: AltoConfig
senderManager: SenderManager
reputationManager: InterfaceReputationManager
Expand All @@ -133,6 +135,7 @@ const getExecutor = ({
eventManager: EventManager
}): Executor => {
return new Executor({
mempool,
config,
senderManager,
reputationManager,
Expand Down Expand Up @@ -299,6 +302,7 @@ export const setupServer = async ({
})

const executor = getExecutor({
mempool,
config,
senderManager,
reputationManager,
Expand Down
44 changes: 43 additions & 1 deletion src/executor/executor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import type {
EventManager,
GasPriceManager
} from "@alto/handlers"
import type { InterfaceReputationManager } from "@alto/mempool"
import type { InterfaceReputationManager, MemoryMempool } from "@alto/mempool"
import {
type Address,
type BundleResult,
Expand Down Expand Up @@ -87,10 +87,12 @@ export class Executor {
compressionHandler: CompressionHandler | null
gasPriceManager: GasPriceManager
mutex: Mutex
mempool: MemoryMempool
eventManager: EventManager

constructor({
config,
mempool,
senderManager,
reputationManager,
metrics,
Expand All @@ -99,6 +101,7 @@ export class Executor {
eventManager
}: {
config: AltoConfig
mempool: MemoryMempool
senderManager: SenderManager
reputationManager: InterfaceReputationManager
metrics: Metrics
Expand All @@ -107,6 +110,7 @@ export class Executor {
eventManager: EventManager
}) {
this.config = config
this.mempool = mempool
this.senderManager = senderManager
this.reputationManager = reputationManager
this.logger = config.getLogger(
Expand Down Expand Up @@ -540,6 +544,7 @@ export class Executor {
...opts
})

let isTransactionUnderPriced = false
let attempts = 0
let transactionHash: Hex | undefined
const maxAttempts = 3
Expand All @@ -552,11 +557,13 @@ export class Executor {

break
} catch (e: unknown) {
isTransactionUnderPriced = false
let isErrorHandled = false

if (e instanceof BaseError) {
if (isTransactionUnderpricedError(e)) {
this.logger.warn("Transaction underpriced, retrying")

request.maxFeePerGas = scaleBigIntByPercent(
request.maxFeePerGas,
150
Expand All @@ -566,6 +573,7 @@ export class Executor {
150
)
isErrorHandled = true
isTransactionUnderPriced = true
}
}

Expand Down Expand Up @@ -612,6 +620,13 @@ export class Executor {
}
}

if (isTransactionUnderPriced) {
await this.handleTransactionUnderPriced({
nonce: request.nonce,
executor: request.from
})
}

// needed for TS
if (!transactionHash) {
throw new Error("Transaction hash not assigned")
Expand All @@ -620,6 +635,33 @@ export class Executor {
return transactionHash as Hex
}

// Occurs when tx was sent with conflicting nonce, we want to resubmit all conflicting ops
async handleTransactionUnderPriced({
nonce,
executor
}: { nonce: number; executor: Address }) {
const submitted = this.mempool.dumpSubmittedOps()

const conflictingOps = submitted
.filter((submitted) => {
const tx = submitted.transactionInfo

return (
tx.executor.address === executor &&
tx.transactionRequest.nonce === nonce
)
})
.map(({ userOperation }) => userOperation)

conflictingOps.map((op) => {
this.logger.info(
`Resubmitting ${op.userOperationHash} due to transaction underpriced`
)
this.mempool.removeSubmitted(op.userOperationHash)
this.mempool.add(op.mempoolUserOperation, op.entryPoint)
})
}

async bundle(
entryPoint: Address,
ops: UserOperation[]
Expand Down
Loading