From f9dd0d71d61d296b658ec15783efbb1da8ffd919 Mon Sep 17 00:00:00 2001 From: Raphael Panic Date: Wed, 5 Feb 2025 17:27:04 +0100 Subject: [PATCH] Implemented IncomingMessagesService for better stability of message fetching and inclusion --- .../services/prisma/PrismaMessageStorage.ts | 50 ++++++- .../prisma/PrismaSettlementStorage.ts | 26 ++++ .../src/protocol/baselayer/NoopBaseLayer.ts | 2 +- .../sequencing/BlockProducerModule.ts | 10 +- .../production/trigger/BlockTrigger.ts | 13 +- .../production/trigger/ManualBlockTrigger.ts | 8 +- .../production/trigger/TimedBlockTrigger.ts | 6 +- .../src/settlement/SettlementModule.ts | 45 ++---- .../messages/IncomingMessageAdapter.ts | 2 +- .../messages/IncomingMessagesService.ts | 131 ++++++++++++++++++ .../messages/MinaIncomingMessageAdapter.ts | 19 ++- .../inmemory/InMemoryMessageStorage.ts | 60 +++++++- .../inmemory/InMemorySettlementStorage.ts | 4 + .../storage/repositories/MessageStorage.ts | 21 ++- .../storage/repositories/SettlementStorage.ts | 2 + 15 files changed, 319 insertions(+), 80 deletions(-) create mode 100644 packages/sequencer/src/settlement/messages/IncomingMessagesService.ts diff --git a/packages/persistance/src/services/prisma/PrismaMessageStorage.ts b/packages/persistance/src/services/prisma/PrismaMessageStorage.ts index a844f1fd0..c1b113bb7 100644 --- a/packages/persistance/src/services/prisma/PrismaMessageStorage.ts +++ b/packages/persistance/src/services/prisma/PrismaMessageStorage.ts @@ -12,9 +12,41 @@ export class PrismaMessageStorage implements MessageStorage { private readonly transactionMapper: TransactionMapper ) {} - public async getMessages( - fromMessageHash: string - ): Promise { + public async getMessageBatches( + fromMessagesHash: string, + toMessagesHash: string + ) { + // TODO Make efficient + + const batches: { + fromMessagesHash: string; + toMessagesHash: string; + messages: PendingTransaction[]; + }[] = []; + let currentHash = fromMessagesHash; + + while (currentHash !== toMessagesHash) { + // eslint-disable-next-line no-await-in-loop + const batch = await this.getNextMessagesBatch(currentHash); + + if (batch === undefined) { + return batches; + } + + batches.push(batch); + currentHash = batch.toMessagesHash; + } + return batches; + } + + public async getNextMessagesBatch(fromMessageHash: string): Promise< + | { + fromMessagesHash: string; + toMessagesHash: string; + messages: PendingTransaction[]; + } + | undefined + > { const { prismaClient } = this.connection; const batch = await prismaClient.incomingMessageBatch.findFirst({ @@ -31,14 +63,22 @@ export class PrismaMessageStorage implements MessageStorage { }); if (batch === null) { - return []; + return undefined; } const dbTransactions = batch.messages.map((message) => { return message.transaction; }); - return dbTransactions.map((dbTx) => this.transactionMapper.mapIn(dbTx)); + const messages = dbTransactions.map((dbTx) => + this.transactionMapper.mapIn(dbTx) + ); + + return { + fromMessagesHash: fromMessageHash, + toMessagesHash: batch.toMessageHash, + messages, + }; } public async pushMessages( diff --git a/packages/persistance/src/services/prisma/PrismaSettlementStorage.ts b/packages/persistance/src/services/prisma/PrismaSettlementStorage.ts index 0748e932a..e6b5addcb 100644 --- a/packages/persistance/src/services/prisma/PrismaSettlementStorage.ts +++ b/packages/persistance/src/services/prisma/PrismaSettlementStorage.ts @@ -1,5 +1,6 @@ import { Settlement, SettlementStorage } from "@proto-kit/sequencer"; import { inject, injectable } from "tsyringe"; +import { Prisma } from "@prisma/client"; import type { PrismaConnection } from "../../PrismaDatabaseConnection"; @@ -12,6 +13,31 @@ export class PrismaSettlementStorage implements SettlementStorage { private readonly settlementMapper: SettlementMapper ) {} + public async getLatestSettlement(): Promise { + const { prismaClient } = this.connection; + + const batch = await prismaClient.batch.findFirst({ + where: { + settlementTransactionHash: { + not: null, + }, + }, + orderBy: [ + { + height: Prisma.SortOrder.desc, + }, + ], + include: { + settlement: true, + }, + }); + + if (batch !== null) { + return this.settlementMapper.mapIn([batch.settlement!, []]); + } + return undefined; + } + public async pushSettlement(settlement: Settlement): Promise { const { prismaClient } = this.connection; diff --git a/packages/sequencer/src/protocol/baselayer/NoopBaseLayer.ts b/packages/sequencer/src/protocol/baselayer/NoopBaseLayer.ts index 652fc5131..9d84abf7f 100644 --- a/packages/sequencer/src/protocol/baselayer/NoopBaseLayer.ts +++ b/packages/sequencer/src/protocol/baselayer/NoopBaseLayer.ts @@ -16,7 +16,7 @@ import { import { BaseLayer, BaseLayerDependencyRecord } from "./BaseLayer"; class NoopIncomingMessageAdapter implements IncomingMessageAdapter { - async getPendingMessages( + async fetchPendingMessages( address: PublicKey, params: { fromActionHash: string; diff --git a/packages/sequencer/src/protocol/production/sequencing/BlockProducerModule.ts b/packages/sequencer/src/protocol/production/sequencing/BlockProducerModule.ts index 592fab6b8..78e358955 100644 --- a/packages/sequencer/src/protocol/production/sequencing/BlockProducerModule.ts +++ b/packages/sequencer/src/protocol/production/sequencing/BlockProducerModule.ts @@ -1,6 +1,5 @@ import { inject } from "tsyringe"; import { log } from "@proto-kit/common"; -import { ACTIONS_EMPTY_HASH } from "@proto-kit/protocol"; import { MethodIdResolver, MethodParameterEncoder, @@ -23,8 +22,8 @@ import { BlockResult, BlockWithResult, } from "../../../storage/model/Block"; -import { MessageStorage } from "../../../storage/repositories/MessageStorage"; import { Database } from "../../../storage/Database"; +import { IncomingMessagesService } from "../../../settlement/messages/IncomingMessagesService"; import { BlockProductionService } from "./BlockProductionService"; import { BlockResultService } from "./BlockResultService"; @@ -40,7 +39,7 @@ export class BlockProducerModule extends SequencerModule { public constructor( @inject("Mempool") private readonly mempool: Mempool, - @inject("MessageStorage") private readonly messageStorage: MessageStorage, + private readonly messageService: IncomingMessagesService, @inject("UnprovenStateService") private readonly unprovenStateService: AsyncStateService, @inject("UnprovenMerkleStore") @@ -186,10 +185,7 @@ export class BlockProducerModule extends SequencerModule { }; } - const messages = await this.messageStorage.getMessages( - parentBlock?.block.toMessagesHash.toString() ?? - ACTIONS_EMPTY_HASH.toString() - ); + const messages = await this.messageService.getPendingMessages(); log.debug( `Block collected, ${txs.length} txs, ${messages.length} messages` diff --git a/packages/sequencer/src/protocol/production/trigger/BlockTrigger.ts b/packages/sequencer/src/protocol/production/trigger/BlockTrigger.ts index 348699065..09d47c997 100644 --- a/packages/sequencer/src/protocol/production/trigger/BlockTrigger.ts +++ b/packages/sequencer/src/protocol/production/trigger/BlockTrigger.ts @@ -13,7 +13,6 @@ import { BlockQueue } from "../../../storage/repositories/BlockStorage"; import { SequencerModule } from "../../../sequencer/builder/SequencerModule"; import { SettlementModule } from "../../../settlement/SettlementModule"; import { Block, BlockWithResult } from "../../../storage/model/Block"; -import { SettlementStorage } from "../../../storage/repositories/SettlementStorage"; /** * A BlockTrigger is the primary method to start the production of a block and @@ -44,8 +43,7 @@ export class BlockTriggerBase< protected readonly blockProducerModule: BlockProducerModule, protected readonly batchProducerModule: BatchProducerModule | undefined, protected readonly settlementModule: SettlementModule | undefined, - protected readonly blockQueue: BlockQueue, - protected readonly settlementStorage: SettlementStorage | undefined + protected readonly blockQueue: BlockQueue ) { super(); } @@ -96,14 +94,7 @@ export class BlockTriggerBase< ); return undefined; } - if (this.settlementStorage === undefined) { - throw new Error( - "SettlementStorage module not configured, check provided database moduel" - ); - } - const settlement = await this.settlementModule.settleBatch(batch); - await this.settlementStorage.pushSettlement(settlement); - return settlement; + return await this.settlementModule.settleBatch(batch); } public async start(): Promise { diff --git a/packages/sequencer/src/protocol/production/trigger/ManualBlockTrigger.ts b/packages/sequencer/src/protocol/production/trigger/ManualBlockTrigger.ts index d0bc9e312..ccef82b57 100644 --- a/packages/sequencer/src/protocol/production/trigger/ManualBlockTrigger.ts +++ b/packages/sequencer/src/protocol/production/trigger/ManualBlockTrigger.ts @@ -8,7 +8,6 @@ import { BlockProducerModule } from "../sequencing/BlockProducerModule"; import { Block, BlockWithResult } from "../../../storage/model/Block"; import { BlockQueue } from "../../../storage/repositories/BlockStorage"; import { SettlementModule } from "../../../settlement/SettlementModule"; -import { SettlementStorage } from "../../../storage/repositories/SettlementStorage"; import { BlockTrigger, BlockTriggerBase } from "./BlockTrigger"; @@ -25,17 +24,14 @@ export class ManualBlockTrigger @injectOptional("SettlementModule") settlementModule: SettlementModule | undefined, @inject("BlockQueue") - blockQueue: BlockQueue, - @injectOptional("SettlementStorage") - settlementStorage: SettlementStorage | undefined + blockQueue: BlockQueue ) { super( blockProducerModule, batchProducerModule, settlementModule, - blockQueue, - settlementStorage + blockQueue ); } diff --git a/packages/sequencer/src/protocol/production/trigger/TimedBlockTrigger.ts b/packages/sequencer/src/protocol/production/trigger/TimedBlockTrigger.ts index e36a80f60..03aefa5aa 100644 --- a/packages/sequencer/src/protocol/production/trigger/TimedBlockTrigger.ts +++ b/packages/sequencer/src/protocol/production/trigger/TimedBlockTrigger.ts @@ -8,7 +8,6 @@ import { Mempool } from "../../../mempool/Mempool"; import { BlockQueue } from "../../../storage/repositories/BlockStorage"; import { BlockProducerModule } from "../sequencing/BlockProducerModule"; import { SettlementModule } from "../../../settlement/SettlementModule"; -import { SettlementStorage } from "../../../storage/repositories/SettlementStorage"; import { BlockEvents, BlockTrigger, BlockTriggerBase } from "./BlockTrigger"; @@ -49,8 +48,6 @@ export class TimedBlockTrigger settlementModule: SettlementModule | undefined, @inject("BlockQueue") blockQueue: BlockQueue, - @injectOptional("SettlementStorage") - settlementStorage: SettlementStorage | undefined, @inject("Mempool") private readonly mempool: Mempool ) { @@ -58,8 +55,7 @@ export class TimedBlockTrigger blockProducerModule, batchProducerModule, settlementModule, - blockQueue, - settlementStorage + blockQueue ); } diff --git a/packages/sequencer/src/settlement/SettlementModule.ts b/packages/sequencer/src/settlement/SettlementModule.ts index 0f8f2b2a0..a80cfdb50 100644 --- a/packages/sequencer/src/settlement/SettlementModule.ts +++ b/packages/sequencer/src/settlement/SettlementModule.ts @@ -6,13 +6,11 @@ import { SettlementSmartContract, MandatorySettlementModulesRecord, MandatoryProtocolModulesRecord, - BlockProverPublicOutput, SettlementSmartContractBase, DynamicBlockProof, } from "@proto-kit/protocol"; import { AccountUpdate, - Field, Mina, PrivateKey, PublicKey, @@ -35,15 +33,14 @@ import { SequencerModule, sequencerModule, } from "../sequencer/builder/SequencerModule"; -import { MessageStorage } from "../storage/repositories/MessageStorage"; import type { MinaBaseLayer } from "../protocol/baselayer/MinaBaseLayer"; import { Batch, SettleableBatch } from "../storage/model/Batch"; import { BlockProofSerializer } from "../protocol/production/tasks/serializers/BlockProofSerializer"; import { Settlement } from "../storage/model/Settlement"; import { FeeStrategy } from "../protocol/baselayer/fees/FeeStrategy"; import { SettlementStartupModule } from "../sequencer/SettlementStartupModule"; +import { SettlementStorage } from "../storage/repositories/SettlementStorage"; -import { IncomingMessageAdapter } from "./messages/IncomingMessageAdapter"; import { MinaTransactionSender } from "./transactions/MinaTransactionSender"; import { ProvenSettlementPermissions } from "./permissions/ProvenSettlementPermissions"; import { SignedSettlementPermissions } from "./permissions/SignedSettlementPermissions"; @@ -88,10 +85,8 @@ export class SettlementModule @inject("BaseLayer") baseLayer: MinaBaseLayer, @inject("Protocol") private readonly protocol: Protocol, - @inject("IncomingMessageAdapter") - private readonly incomingMessagesAdapter: IncomingMessageAdapter, - @inject("MessageStorage") - private readonly messageStorage: MessageStorage, + @inject("SettlementStorage") + private readonly settlementStorage: SettlementStorage, private readonly blockProofSerializer: BlockProofSerializer, @inject("TransactionSender") private readonly transactionSender: MinaTransactionSender, @@ -169,38 +164,20 @@ export class SettlementModule } = {} ): Promise { await this.fetchContractAccounts(); - const { settlement, dispatch } = this.getContracts(); + const { settlement: settlementContract, dispatch } = this.getContracts(); const { feepayer } = this.config; log.debug("Preparing settlement"); const lastSettlementL1BlockHeight = - settlement.lastSettlementL1BlockHeight.get().value; + settlementContract.lastSettlementL1BlockHeight.get().value; const signature = Signature.create(feepayer, [ BATCH_SIGNATURE_PREFIX, lastSettlementL1BlockHeight, ]); - const fromSequenceStateHash = BlockProverPublicOutput.fromFields( - batch.proof.publicOutput.map((x) => Field(x)) - ).incomingMessagesHash; const latestSequenceStateHash = dispatch.account.actionState.get(); - // Fetch actions and store them into the messageStorage - const actions = await this.incomingMessagesAdapter.getPendingMessages( - dispatch.address, - { - fromActionHash: fromSequenceStateHash.toString(), - toActionHash: latestSequenceStateHash.toString(), - fromL1BlockHeight: Number(lastSettlementL1BlockHeight.toString()), - } - ); - await this.messageStorage.pushMessages( - actions.from, - actions.to, - actions.messages - ); - const blockProof = await this.blockProofSerializer .getBlockProofSerializer() .fromJSONProof(batch.proof); @@ -215,7 +192,7 @@ export class SettlementModule memo: "Protokit settle", }, async () => { - await settlement.settle( + await settlementContract.settle( dynamicBlockProof, signature, dispatch.address, @@ -233,12 +210,16 @@ export class SettlementModule log.info("Settlement transaction send queued"); - this.events.emit("settlement-submitted", batch); - - return { + const settlement = { batches: [batch.height], promisedMessagesHash: latestSequenceStateHash.toString(), }; + + await this.settlementStorage.pushSettlement(settlement); + + this.events.emit("settlement-submitted", batch); + + return settlement; } public async deploy( diff --git a/packages/sequencer/src/settlement/messages/IncomingMessageAdapter.ts b/packages/sequencer/src/settlement/messages/IncomingMessageAdapter.ts index 87ef582a5..dffae431b 100644 --- a/packages/sequencer/src/settlement/messages/IncomingMessageAdapter.ts +++ b/packages/sequencer/src/settlement/messages/IncomingMessageAdapter.ts @@ -9,7 +9,7 @@ import { PendingTransaction } from "../../mempool/PendingTransaction"; * (Dispatched Deposit Actions for example) */ export interface IncomingMessageAdapter { - getPendingMessages: ( + fetchPendingMessages: ( address: PublicKey, params: { fromActionHash: string; diff --git a/packages/sequencer/src/settlement/messages/IncomingMessagesService.ts b/packages/sequencer/src/settlement/messages/IncomingMessagesService.ts new file mode 100644 index 000000000..8e342d60e --- /dev/null +++ b/packages/sequencer/src/settlement/messages/IncomingMessagesService.ts @@ -0,0 +1,131 @@ +import { inject, injectable } from "tsyringe"; +import { ACTIONS_EMPTY_HASH } from "@proto-kit/protocol"; + +import { SettlementStorage } from "../../storage/repositories/SettlementStorage"; +import { MessageStorage } from "../../storage/repositories/MessageStorage"; +import { BlockStorage } from "../../storage/repositories/BlockStorage"; +import { PendingTransaction } from "../../mempool/PendingTransaction"; +import { SettlementModule } from "../SettlementModule"; + +import { IncomingMessageAdapter } from "./IncomingMessageAdapter"; + +@injectable() +export class IncomingMessagesService { + public constructor( + @inject("SettlementStorage") + private readonly settlementStorage: SettlementStorage, + @inject("MessageStorage") + private readonly messageStorage: MessageStorage, + @inject("IncomingMessageAdapter") + private readonly messagesAdapter: IncomingMessageAdapter, + @inject("BlockStorage") + private readonly blockStorage: BlockStorage, + @inject("SettlementModule") + private readonly settlementModule: SettlementModule + ) {} + + private async fetchRemaining( + fromMessagesHash: string, + toMessagesHash: string + ) { + const dispatchContractAddress = this.settlementModule.addresses?.dispatch; + + const fetched = await this.messagesAdapter.fetchPendingMessages( + dispatchContractAddress!, + { + fromActionHash: fromMessagesHash, + toActionHash: toMessagesHash, + // TODO For now, until we have access to the action's block height + fromL1BlockHeight: 0, + } + ); + await this.messageStorage.pushMessages( + fetched.from, + fetched.to, + fetched.messages + ); + return { + toMessagesHash: fetched.to, + messages: fetched.messages, + }; + } + + private isComplete( + messages: + | { toMessagesHash: string; messages: PendingTransaction[] } + | undefined, + targetMessagesHash: string + ) { + return ( + messages !== undefined && messages.toMessagesHash === targetMessagesHash + ); + } + + private async ensureMessageCompleteness( + messages: + | { toMessagesHash: string; messages: PendingTransaction[] } + | undefined, + fromMessagesHash: string, + targetMessagesHash: string + ) { + if (!this.isComplete(messages, targetMessagesHash)) { + const from = messages?.toMessagesHash ?? fromMessagesHash; + const newMessages = await this.fetchRemaining(from, targetMessagesHash); + + if (newMessages.toMessagesHash === targetMessagesHash) { + return { + toMessagesHash: newMessages.toMessagesHash, + messages: (messages?.messages ?? []).concat(newMessages.messages), + }; + } + throw new Error( + `Fetch of actions failed, wanted target ${targetMessagesHash} but got ${newMessages.toMessagesHash}` + ); + } + return messages!; + } + + private aggregateBatches( + batches: { + fromMessagesHash: string; + toMessagesHash: string; + messages: PendingTransaction[]; + }[] + ) { + return { + messages: batches.flatMap((batch) => batch.messages), + toMessagesHash: + batches.at(-1)?.toMessagesHash ?? ACTIONS_EMPTY_HASH.toString(), + }; + } + + public async getPendingMessages() { + const latestSettlement = await this.settlementStorage.getLatestSettlement(); + const latestBlock = await this.blockStorage.getLatestBlock(); + + const messagesHashCursor = + latestBlock?.block?.toMessagesHash?.toString() ?? + ACTIONS_EMPTY_HASH.toString(); + + const promisedMessages = + latestSettlement?.promisedMessagesHash ?? ACTIONS_EMPTY_HASH.toString(); + + // If there are any pending L1 messages that aren't yet included in the L2 + if (messagesHashCursor !== promisedMessages) { + // 1. Check that we have all the necessary messages in storage, if not, fetch + const storedMessages = await this.messageStorage.getMessageBatches( + messagesHashCursor, + promisedMessages + ); + + const completeMessages = await this.ensureMessageCompleteness( + this.aggregateBatches(storedMessages), + messagesHashCursor, + promisedMessages + ); + + return completeMessages.messages; + } + return []; + } +} diff --git a/packages/sequencer/src/settlement/messages/MinaIncomingMessageAdapter.ts b/packages/sequencer/src/settlement/messages/MinaIncomingMessageAdapter.ts index ce10a87e9..858911201 100644 --- a/packages/sequencer/src/settlement/messages/MinaIncomingMessageAdapter.ts +++ b/packages/sequencer/src/settlement/messages/MinaIncomingMessageAdapter.ts @@ -96,7 +96,7 @@ export class MinaIncomingMessageAdapter implements IncomingMessageAdapter { }); } - public async getPendingMessages( + public async fetchPendingMessages( address: PublicKey, params: { fromActionHash: string; @@ -116,12 +116,19 @@ export class MinaIncomingMessageAdapter implements IncomingMessageAdapter { throw new Error("L1 contract hasn't been deployed yet"); } + const toActionHashField = + params.toActionHash !== undefined + ? Field(params.toActionHash) + : undefined; + const actions = await network.fetchActions(address, { fromActionState: Field(params.fromActionHash), - // TODO Somehow that doesn't work on localBlockchain - // endActionState: params.toActionHash - // ? Field(params.toActionHash) - // : undefined, + // TODO Somehow endActionState doesn't work on localBlockchain + // For now, we can assume this function to be called synchronously so + // no further actions after the 'to' have been emitted + endActionState: this.baseLayer.isLocalBlockChain() + ? undefined + : toActionHashField, }); if ("error" in actions) { @@ -164,6 +171,8 @@ export class MinaIncomingMessageAdapter implements IncomingMessageAdapter { return await this.mapActionToTransactions(tx, args); }); + // TODO Add check that the endActionHash matches + return { messages, from: params.fromActionHash, diff --git a/packages/sequencer/src/storage/inmemory/InMemoryMessageStorage.ts b/packages/sequencer/src/storage/inmemory/InMemoryMessageStorage.ts index 7b486a100..1bf671315 100644 --- a/packages/sequencer/src/storage/inmemory/InMemoryMessageStorage.ts +++ b/packages/sequencer/src/storage/inmemory/InMemoryMessageStorage.ts @@ -5,12 +5,57 @@ import { MessageStorage } from "../repositories/MessageStorage"; @injectable() export class InMemoryMessageStorage implements MessageStorage { - private messages: { [key: string]: PendingTransaction[] } = {}; + private messages: { + [key: string]: { + toMessagesHash: string; + messages: PendingTransaction[]; + }; + } = {}; - public async getMessages( - fromMessagesHash: string - ): Promise { - return this.messages[fromMessagesHash] ?? []; + public async getNextMessagesBatch(fromMessagesHash: string): Promise< + | { + fromMessagesHash: string; + toMessagesHash: string; + messages: PendingTransaction[]; + } + | undefined + > { + const batch = this.messages[fromMessagesHash]; + if (batch !== undefined) { + return { + ...batch, + fromMessagesHash, + }; + } + return undefined; + } + + public async getMessageBatches( + fromMessagesHash: string, + toMessagesHash: string + ) { + const batches: { + fromMessagesHash: string; + toMessagesHash: string; + messages: PendingTransaction[]; + }[] = []; + let currentHash = fromMessagesHash; + + while (currentHash !== toMessagesHash) { + const batch = this.messages[currentHash]; + + if (batch === undefined) { + return batches; + } + + batches.push({ + ...batch, + fromMessagesHash: currentHash, + }); + currentHash = batch.toMessagesHash; + } + + return batches; } public async pushMessages( @@ -18,6 +63,9 @@ export class InMemoryMessageStorage implements MessageStorage { toMessagesHash: string, messages: PendingTransaction[] ): Promise { - this.messages[fromMessagesHash] = messages; + this.messages[fromMessagesHash] = { + messages, + toMessagesHash, + }; } } diff --git a/packages/sequencer/src/storage/inmemory/InMemorySettlementStorage.ts b/packages/sequencer/src/storage/inmemory/InMemorySettlementStorage.ts index 0f4c97116..38e4d3e90 100644 --- a/packages/sequencer/src/storage/inmemory/InMemorySettlementStorage.ts +++ b/packages/sequencer/src/storage/inmemory/InMemorySettlementStorage.ts @@ -10,4 +10,8 @@ export class InMemorySettlementStorage implements SettlementStorage { async pushSettlement(settlement: Settlement): Promise { this.settlements.push(settlement); } + + async getLatestSettlement(): Promise { + return this.settlements.at(-1); + } } diff --git a/packages/sequencer/src/storage/repositories/MessageStorage.ts b/packages/sequencer/src/storage/repositories/MessageStorage.ts index cf9b83008..343e831c8 100644 --- a/packages/sequencer/src/storage/repositories/MessageStorage.ts +++ b/packages/sequencer/src/storage/repositories/MessageStorage.ts @@ -9,5 +9,24 @@ export interface MessageStorage { toMessagesHash: string, messages: PendingTransaction[] ) => Promise; - getMessages: (fromMessagesHash: string) => Promise; + + getNextMessagesBatch: (fromMessagesHash: string) => Promise< + | { + fromMessagesHash: string; + toMessagesHash: string; + messages: PendingTransaction[]; + } + | undefined + >; + + getMessageBatches: ( + fromMessagesHash: string, + toMessagesHash: string + ) => Promise< + { + fromMessagesHash: string; + toMessagesHash: string; + messages: PendingTransaction[]; + }[] + >; } diff --git a/packages/sequencer/src/storage/repositories/SettlementStorage.ts b/packages/sequencer/src/storage/repositories/SettlementStorage.ts index 23db1e20e..5d71738cf 100644 --- a/packages/sequencer/src/storage/repositories/SettlementStorage.ts +++ b/packages/sequencer/src/storage/repositories/SettlementStorage.ts @@ -2,4 +2,6 @@ import { Settlement } from "../model/Settlement"; export interface SettlementStorage { pushSettlement: (settlement: Settlement) => Promise; + + getLatestSettlement: () => Promise; }