diff --git a/yarn-project/sequencer-client/src/sequencer/sequencer.test.ts b/yarn-project/sequencer-client/src/sequencer/sequencer.test.ts index cd3debc369ef..f3c0a67cfcb4 100644 --- a/yarn-project/sequencer-client/src/sequencer/sequencer.test.ts +++ b/yarn-project/sequencer-client/src/sequencer/sequencer.test.ts @@ -491,6 +491,18 @@ describe('sequencer', () => { expect(publisher.proposeL2Block).not.toHaveBeenCalled(); }); + it('does not publish a block if the block proposal failed', async () => { + const tx = makeTx(); + mockPendingTxs([tx]); + block = await makeBlock([tx]); + + validatorClient.createBlockProposal.mockResolvedValue(undefined); + + await sequencer.doRealWork(); + + expect(publisher.proposeL2Block).not.toHaveBeenCalled(); + }); + describe('proof quotes', () => { let tx: Tx; let txHash: TxHash; @@ -587,6 +599,25 @@ describe('sequencer', () => { expect(publisher.proposeL2Block).not.toHaveBeenCalled(); }); + it('submits a valid proof quote if building a block proposal fails', async () => { + const blockNumber = epochDuration + 1; + await setupForBlockNumber(blockNumber); + + const proofQuote = mockEpochProofQuote(); + + p2p.getEpochProofQuotes.mockResolvedValue([proofQuote]); + publisher.validateProofQuote.mockImplementation((x: EpochProofQuote) => Promise.resolve(x)); + + // The previous epoch can be claimed + publisher.getClaimableEpoch.mockImplementation(() => Promise.resolve(currentEpoch - 1n)); + + validatorClient.createBlockProposal.mockResolvedValue(undefined); + + await sequencer.doRealWork(); + expect(publisher.claimEpochProofRight).toHaveBeenCalledWith(proofQuote); + expect(publisher.proposeL2Block).not.toHaveBeenCalled(); + }); + it('does not claim the epoch previous to the first', async () => { const blockNumber = 1; await setupForBlockNumber(blockNumber); diff --git a/yarn-project/sequencer-client/src/sequencer/sequencer.ts b/yarn-project/sequencer-client/src/sequencer/sequencer.ts index 6388bf22086e..d1300a73f44a 100644 --- a/yarn-project/sequencer-client/src/sequencer/sequencer.ts +++ b/yarn-project/sequencer-client/src/sequencer/sequencer.ts @@ -300,6 +300,9 @@ export class Sequencer { await this.buildBlockAndAttemptToPublish(pendingTxs, proposalHeader); } catch (err) { this.log.error(`Error assembling block`, err, { blockNumber: newBlockNumber, slot }); + + // If the block failed to build, we might still want to claim the proving rights + await this.claimEpochProofRightIfAvailable(slot); } this.setState(SequencerState.IDLE, 0n); } @@ -627,8 +630,8 @@ export class Sequencer { this.log.debug('Creating block proposal for validators'); const proposal = await this.validatorClient.createBlockProposal(block.header, block.archive.root, txHashes); if (!proposal) { - this.log.warn(`Failed to create block proposal, skipping collecting attestations`); - return undefined; + const msg = `Failed to create block proposal`; + throw new Error(msg); } this.log.debug('Broadcasting block proposal to validators'); diff --git a/yarn-project/simulator/src/public/public_processor.ts b/yarn-project/simulator/src/public/public_processor.ts index b3c1194c27ba..f95595699ac8 100644 --- a/yarn-project/simulator/src/public/public_processor.ts +++ b/yarn-project/simulator/src/public/public_processor.ts @@ -280,7 +280,7 @@ export class PublicProcessor implements Traceable { const rate = duration > 0 ? totalPublicGas.l2Gas / duration : 0; this.metrics.recordAllTxs(totalPublicGas, rate); - this.log.info(`Processed ${result.length} succesful txs and ${failed.length} txs in ${duration}ms`, { + this.log.info(`Processed ${result.length} successful txs and ${failed.length} txs in ${duration}s`, { duration, rate, totalPublicGas,