From b2dee71600a50001dac68a9ec4230fc33cdf2131 Mon Sep 17 00:00:00 2001 From: Raphael Panic Date: Tue, 24 Mar 2026 20:32:49 +0100 Subject: [PATCH 1/3] Made missing block result be handled more gracefully --- .../sdk/src/query/BlockStorageNetworkStateModule.ts | 4 +++- .../production/sequencing/BlockProducerModule.ts | 11 +++++++++-- .../settlement/messages/IncomingMessagesService.ts | 8 ++++---- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/packages/sdk/src/query/BlockStorageNetworkStateModule.ts b/packages/sdk/src/query/BlockStorageNetworkStateModule.ts index 274037c14..23cc3598b 100644 --- a/packages/sdk/src/query/BlockStorageNetworkStateModule.ts +++ b/packages/sdk/src/query/BlockStorageNetworkStateModule.ts @@ -38,7 +38,7 @@ export class BlockStorageNetworkStateModule } public async getUnprovenNetworkState(): Promise { - const latestBlock = await this.unprovenStorage.getLatestBlock(); + const latestBlock = await this.unprovenQueue.getLatestBlockAndResult(); return latestBlock?.block.networkState.during; } @@ -47,6 +47,8 @@ export class BlockStorageNetworkStateModule * with afterBundle() hooks executed */ public async getStagedNetworkState(): Promise { + // TODO Result could be null here, add method that specifically looks for the + // last block with a result const result = await this.unprovenStorage.getLatestBlock(); return result?.result.afterNetworkState; } diff --git a/packages/sequencer/src/protocol/production/sequencing/BlockProducerModule.ts b/packages/sequencer/src/protocol/production/sequencing/BlockProducerModule.ts index 278de217a..9d0ed507c 100644 --- a/packages/sequencer/src/protocol/production/sequencing/BlockProducerModule.ts +++ b/packages/sequencer/src/protocol/production/sequencing/BlockProducerModule.ts @@ -140,6 +140,9 @@ export class BlockProducerModule extends SequencerModule { @ensureNotBusy() public async tryProduceBlock(): Promise { + // Check if previous result has been computed, and if not, compute it + await this.blockResultCompleteCheck(); + const block = await this.produceBlock(); if (block === undefined) { @@ -239,19 +242,23 @@ export class BlockProducerModule extends SequencerModule { return blockResult?.block; } - public async blockResultCompleteCheck() { + public async blockResultCompleteCheck(): Promise< + "genesis" | "existent" | "generated" + > { // Check if metadata height is behind block production. // This can happen when the sequencer crashes after a block has been produced // but before the metadata generation has finished const latestBlock = await this.blockQueue.getLatestBlockAndResult(); - // eslint-disable-next-line sonarjs/no-collapsible-if if (latestBlock !== undefined) { if (latestBlock.result === undefined) { await this.generateMetadata(latestBlock.block); + return "generated"; } // Here, the metadata has been computed already + return "existent"; } // If we reach here, its a genesis startup, no blocks exist yet + return "genesis"; } public async start() { diff --git a/packages/sequencer/src/settlement/messages/IncomingMessagesService.ts b/packages/sequencer/src/settlement/messages/IncomingMessagesService.ts index 6311cb30a..52e266679 100644 --- a/packages/sequencer/src/settlement/messages/IncomingMessagesService.ts +++ b/packages/sequencer/src/settlement/messages/IncomingMessagesService.ts @@ -3,7 +3,7 @@ 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 { BlockQueue } from "../../storage/repositories/BlockStorage"; import { PendingTransaction } from "../../mempool/PendingTransaction"; import type { BridgingModule } from "../BridgingModule"; @@ -18,8 +18,8 @@ export class IncomingMessagesService { private readonly messageStorage: MessageStorage, @inject("IncomingMessageAdapter") private readonly messagesAdapter: IncomingMessageAdapter, - @inject("BlockStorage") - private readonly blockStorage: BlockStorage, + @inject("BlockQueue") + private readonly blockStorage: BlockQueue, @inject("BridgingModule") private readonly bridgingModule: BridgingModule ) {} @@ -102,7 +102,7 @@ export class IncomingMessagesService { public async getPendingMessages() { const latestSettlement = await this.settlementStorage.getLatestSettlement(); - const latestBlock = await this.blockStorage.getLatestBlock(); + const latestBlock = await this.blockStorage.getLatestBlockAndResult(); const messagesHashCursor = latestBlock?.block?.toMessagesHash?.toString() ?? From c25556e4b3deea1af987f07931c5eceb876076cc Mon Sep 17 00:00:00 2001 From: Raphael Panic Date: Tue, 24 Mar 2026 20:33:05 +0100 Subject: [PATCH 2/3] Default console tracer interval increase --- packages/sequencer/src/logging/ConsoleTracer.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/sequencer/src/logging/ConsoleTracer.ts b/packages/sequencer/src/logging/ConsoleTracer.ts index 96fc4b5cb..3e419938d 100644 --- a/packages/sequencer/src/logging/ConsoleTracer.ts +++ b/packages/sequencer/src/logging/ConsoleTracer.ts @@ -14,7 +14,7 @@ type StoreType = Record; @closeable() export class ConsoleTracer implements Tracer { // Hard-code this for the moment. Needs to be configured. - timeInterval: number = 60000; + timeInterval: number = 180000; store: StoreType = {}; From dc8c6baed622a35d4928973836daae358fcde2b8 Mon Sep 17 00:00:00 2001 From: Raphael Panic Date: Wed, 25 Mar 2026 12:45:37 +0100 Subject: [PATCH 3/3] Fixed test --- .../production/sequencing/atomic-block-production.test.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/sequencer/test/protocol/production/sequencing/atomic-block-production.test.ts b/packages/sequencer/test/protocol/production/sequencing/atomic-block-production.test.ts index 79dccbcd4..dde755d41 100644 --- a/packages/sequencer/test/protocol/production/sequencing/atomic-block-production.test.ts +++ b/packages/sequencer/test/protocol/production/sequencing/atomic-block-production.test.ts @@ -89,7 +89,7 @@ describe("atomic block production", () => { * the second block production can succeed */ it("should recover from non-generated metadata", async () => { - expect.assertions(6); + expect.assertions(5); const module = appchain.sequencer.dependencyContainer.resolve(BlockResultService); @@ -102,9 +102,6 @@ describe("atomic block production", () => { await expect(() => trigger.produceBlock()).rejects.toThrow(); - // This checks that it correctly throws when producing a block with no previous result existing - await expect(() => trigger.produceBlock()).rejects.toThrow(); - await appchain.sequencer .resolve("BlockProducerModule") .blockResultCompleteCheck();