Skip to content

Commit

Permalink
Add sequencer orderings (FIFO, LIFO, HighestValue, Random) (#62)
Browse files Browse the repository at this point in the history
* Add sequencer orderings (FIFO, LIFO, HighestValue, Random)

* Add sequencer order in config

* Add configurable sequencer orderings

* Format code
  • Loading branch information
fewwwww authored Oct 15, 2023
1 parent 38d3b39 commit 6dd75d8
Show file tree
Hide file tree
Showing 8 changed files with 408 additions and 3 deletions.
1 change: 1 addition & 0 deletions packages/node/src/Application.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ export class Application {
logger,
calculateTransactionLimit(config.batchPoster.gasLimit),
config.batchPoster.intervalMs,
config.batchPoster.sequencerOrder,
)

const routers: AppRouters = {
Expand Down
1 change: 1 addition & 0 deletions packages/node/src/config/Config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export interface Config {
readonly batchPoster: {
readonly intervalMs: number
readonly gasLimit: number
readonly sequencerOrder: string
}
readonly privateKey: Hex
readonly genesisState: Record<string, number>
Expand Down
1 change: 1 addition & 0 deletions packages/node/src/config/config.local.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export function getLocalConfig(): Config {
batchPoster: {
intervalMs: 10_000,
gasLimit: 3_000_000,
sequencerOrder: env.string('SEQUENCER_ORDER', 'FEE'),
},
privateKey: Hex(
'0x47e179ec197488593b187f80a00eb0da91f1b9d0b13f8733639f19c30a34926a',
Expand Down
1 change: 1 addition & 0 deletions packages/node/src/config/config.production.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export function getProductionConfig(): Config {
batchPoster: {
intervalMs: 10_000,
gasLimit: 3_000_000,
sequencerOrder: env.string('SEQUENCER_ORDER', 'FEE'),
},
privateKey: Hex(env.string('PRIVATE_KEY')),
genesisState: GENESIS_STATE,
Expand Down
68 changes: 68 additions & 0 deletions packages/node/src/core/BatchPoster.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ describe(BatchPoster.name, () => {

const FLUSH_PERIOD_MS = 1_000
const TRANSACTION_LIMIT = 100
const SEQUENCER_ORDER = 'FEE'

describe(BatchPoster.prototype.start.name, () => {
it('submits transactions where every one applies every flush period seconds', async () => {
Expand Down Expand Up @@ -103,6 +104,7 @@ describe(BatchPoster.name, () => {
Logger.SILENT,
TRANSACTION_LIMIT,
FLUSH_PERIOD_MS,
SEQUENCER_ORDER,
)
batchPoster.start()
await time.tickAsync(FLUSH_PERIOD_MS * 3)
Expand Down Expand Up @@ -160,6 +162,7 @@ describe(BatchPoster.name, () => {
Logger.SILENT,
TRANSACTION_LIMIT,
FLUSH_PERIOD_MS,
SEQUENCER_ORDER,
)
batchPoster.start()
await time.tickAsync(FLUSH_PERIOD_MS * 3)
Expand Down Expand Up @@ -213,6 +216,7 @@ describe(BatchPoster.name, () => {
Logger.SILENT,
TRANSACTION_LIMIT,
FLUSH_PERIOD_MS,
SEQUENCER_ORDER,
)
batchPoster.start()
await time.tickAsync(FLUSH_PERIOD_MS * 3)
Expand Down Expand Up @@ -263,6 +267,7 @@ describe(BatchPoster.name, () => {
Logger.SILENT,
TRANSACTION_LIMIT,
FLUSH_PERIOD_MS,
SEQUENCER_ORDER,
)
batchPoster.start()
await time.tickAsync(FLUSH_PERIOD_MS * 3)
Expand Down Expand Up @@ -320,6 +325,7 @@ describe(BatchPoster.name, () => {
Logger.SILENT,
TRANSACTION_LIMIT,
FLUSH_PERIOD_MS,
SEQUENCER_ORDER,
)
batchPoster.start()
await time.tickAsync(FLUSH_PERIOD_MS * 3)
Expand Down Expand Up @@ -369,6 +375,7 @@ describe(BatchPoster.name, () => {
Logger.SILENT,
TRANSACTION_LIMIT,
FLUSH_PERIOD_MS,
SEQUENCER_ORDER,
)
batchPoster.start()
await time.tickAsync(FLUSH_PERIOD_MS * 3)
Expand Down Expand Up @@ -420,6 +427,7 @@ describe(BatchPoster.name, () => {
Logger.SILENT,
TRANSACTION_LIMIT,
FLUSH_PERIOD_MS,
SEQUENCER_ORDER,
)
batchPoster.start()
await time.tickAsync(FLUSH_PERIOD_MS * 3)
Expand All @@ -436,5 +444,65 @@ describe(BatchPoster.name, () => {
modelTx2SerializedHex,
)
})

it('submits transactions every flush period seconds with different sequencer ordering', async () => {
const stateUpdater = mockObject<StateUpdater>({
getState: mockFn()
.returnsOnce({
'0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266': {
balance: 100n,
nonce: 0n,
},
'0x70997970C51812dc3A010C7d01b50e0d17dc79C8': {
balance: 500n,
nonce: 0n,
},
})
.returnsOnce({
'0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266': {
balance: 88n,
nonce: 1n,
},
'0x70997970C51812dc3A010C7d01b50e0d17dc79C8': {
balance: 0n,
nonce: 1n,
},
}),
})
const client = mockObject<EthereumPrivateClient>({
writeToInputsContract: mockFn()
.throwsOnce(new Error('failed'))
.returns(null),
})
const mempool = mockObject<Mempool>({
popNFIFO: mockFn()
.returnsOnce([modelSignedTx1])
.returnsOnce([modelSignedTx2]),
empty: mockFn().returns(null),
})
const batchPoster = new BatchPoster(
stateUpdater,
client,
mempool,
Logger.SILENT,
TRANSACTION_LIMIT,
FLUSH_PERIOD_MS,
'FIFO',
)
batchPoster.start()
await time.tickAsync(FLUSH_PERIOD_MS * 3)

expect(mempool.empty).toHaveBeenCalledTimes(0)
expect(mempool.popNFIFO).toHaveBeenCalledTimes(2)
expect(client.writeToInputsContract).toHaveBeenCalledTimes(2)
expect(client.writeToInputsContract).toHaveBeenNthCalledWith(
1,
modelTx1SerializedHex,
)
expect(client.writeToInputsContract).toHaveBeenNthCalledWith(
2,
modelTx2SerializedHex,
)
})
})
})
37 changes: 34 additions & 3 deletions packages/node/src/core/BatchPoster.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export class BatchPoster {
private readonly logger: Logger,
private readonly transactionLimit: number,
private readonly intervalMs: number,
private readonly sequencerOrder: string,
) {
this.logger = logger.for(this)
}
Expand All @@ -29,9 +30,39 @@ export class BatchPoster {
}

private async postBatch(): Promise<void> {
const candidateTransactions = this.mempool.popNHighestFee(
this.transactionLimit,
)
let candidateTransactions
switch (this.sequencerOrder) {
case 'FEE': {
candidateTransactions = this.mempool.popNHighestFee(
this.transactionLimit,
)
break
}
case 'FIFO': {
candidateTransactions = this.mempool.popNFIFO(this.transactionLimit)
break
}
case 'LIFO': {
candidateTransactions = this.mempool.popNLIFO(this.transactionLimit)
break
}
case 'RANDOM': {
candidateTransactions = this.mempool.popNRandom(this.transactionLimit)
break
}
case 'VALUE': {
candidateTransactions = this.mempool.popNHighestValue(
this.transactionLimit,
)
break
}
default: {
candidateTransactions = this.mempool.popNHighestFee(
this.transactionLimit,
)
}
}

if (candidateTransactions.length === 0) {
return
}
Expand Down
Loading

0 comments on commit 6dd75d8

Please sign in to comment.