@@ -155,6 +155,7 @@ func (s *Service) ProcessProposal(
155155 ctx ,
156156 consensusBlk ,
157157 bytes .Equal (thisNodeAddress , req .NextProposerAddress ),
158+ req .NextProposerAddress ,
158159 )
159160 if err != nil {
160161 s .logger .Error ("failed to verify incoming block" , "error" , err )
@@ -259,6 +260,7 @@ func (s *Service) VerifyIncomingBlock(
259260 ctx context.Context ,
260261 blk * types.ConsensusBlock ,
261262 isNextBlockProposer bool ,
263+ nextProposerAddress []byte ,
262264) (transition.ValidatorUpdates , error ) {
263265 beaconBlk := blk .GetBeaconBlock ()
264266 state := s .storageBackend .StateFromContext (ctx )
@@ -302,7 +304,7 @@ func (s *Service) VerifyIncomingBlock(
302304 var (
303305 nextBlockData * builder.RequestPayloadData
304306 errFetch error
305- shouldBuildNextPayload = s .shouldBuildNextPayload (isNextBlockProposer )
307+ shouldBuildNextPayload = s .shouldBuildNextPayload (isNextBlockProposer , state , nextProposerAddress )
306308 )
307309
308310 if shouldBuildNextPayload {
@@ -398,8 +400,51 @@ func (s *Service) verifyStateRoot(
398400 return valUpdates , err
399401}
400402
401- // shouldBuildNextPayload returns true if optimistic
402- // payload builds are enabled.
403- func (s * Service ) shouldBuildNextPayload (isNextBlockProposer bool ) bool {
404- return isNextBlockProposer && s .localBuilder .Enabled ()
403+ // shouldBuildNextPayload returns true if optimistic payload builds should be triggered.
404+ // In normal mode, builds only when this node is the next proposer.
405+ // In sequencer mode, also builds when the next proposer is whitelisted.
406+ func (s * Service ) shouldBuildNextPayload (isNextBlockProposer bool , st * statedb.StateDB , nextProposerAddress []byte ) bool {
407+ if ! s .localBuilder .Enabled () {
408+ return false
409+ }
410+
411+ // Normal behavior: build if we are the proposer
412+ if isNextBlockProposer {
413+ return true
414+ }
415+
416+ // Sequencer mode: build if next proposer is whitelisted
417+ if s .preconfCfg != nil && s .preconfCfg .IsSequencer () {
418+ nextProposerPubkey , err := s .getNextProposerPubkey (st , nextProposerAddress )
419+ if err != nil {
420+ s .logger .Error ("Failed to get next proposer pubkey" , "error" , err )
421+ return false
422+ }
423+
424+ isWhitelisted := s .preconfWhitelist .IsWhitelisted (nextProposerPubkey )
425+ if isWhitelisted {
426+ s .logger .Info ("Sequencer mode: next proposer is whitelisted, triggering optimistic build" )
427+ }
428+
429+ return isWhitelisted
430+ }
431+
432+ return false
433+ }
434+
435+ // getNextProposerPubkey retrieves the BLS public key for the next proposer given their CometBFT address.
436+ func (s * Service ) getNextProposerPubkey (st * statedb.StateDB , nextProposerAddress []byte ) (crypto.BLSPubkey , error ) {
437+ // Convert CometBFT address to validator index
438+ proposerIndex , err := st .ValidatorIndexByCometBFTAddress (nextProposerAddress )
439+ if err != nil {
440+ return crypto.BLSPubkey {}, fmt .Errorf ("failed to get validator index: %w" , err )
441+ }
442+
443+ // Get validator record
444+ validator , err := st .ValidatorByIndex (proposerIndex )
445+ if err != nil {
446+ return crypto.BLSPubkey {}, fmt .Errorf ("failed to get validator: %w" , err )
447+ }
448+
449+ return validator .GetPubkey (), nil
405450}
0 commit comments