|
69 | 69 | // This allows for overriding the behavior in tests. |
70 | 70 | type publishBlockFunc func(ctx context.Context) error |
71 | 71 |
|
| 72 | +func defaultSignaturePayloadProvider(header *types.Header) ([]byte, error) { |
| 73 | + return header.MarshalBinary() |
| 74 | +} |
| 75 | + |
72 | 76 | // NewHeaderEvent is used to pass header and DA height to headerInCh |
73 | 77 | type NewHeaderEvent struct { |
74 | 78 | Header *types.SignedHeader |
@@ -165,10 +169,18 @@ type Manager struct { |
165 | 169 | // dataCommitmentToHeight tracks the height a data commitment (data hash) has been seen on. |
166 | 170 | // Key: data commitment (string), Value: uint64 (height) |
167 | 171 | dataCommitmentToHeight sync.Map |
| 172 | + |
| 173 | + // signaturePayloadProvider is used to provide a signature payload for the header. |
| 174 | + // It is used to sign the header with the provided signer. |
| 175 | + signaturePayloadProvider types.SignaturePayloadProvider |
168 | 176 | } |
169 | 177 |
|
170 | 178 | // getInitialState tries to load lastState from Store, and if it's not available it reads genesis. |
171 | | -func getInitialState(ctx context.Context, genesis genesis.Genesis, signer signer.Signer, store store.Store, exec coreexecutor.Executor, logger log.Logger) (types.State, error) { |
| 179 | +func getInitialState(ctx context.Context, genesis genesis.Genesis, signer signer.Signer, store store.Store, exec coreexecutor.Executor, logger log.Logger, signaturePayloadProvider types.SignaturePayloadProvider) (types.State, error) { |
| 180 | + if signaturePayloadProvider == nil { |
| 181 | + signaturePayloadProvider = defaultSignaturePayloadProvider |
| 182 | + } |
| 183 | + |
172 | 184 | // Load the state from store. |
173 | 185 | s, err := store.GetState(ctx) |
174 | 186 |
|
@@ -206,28 +218,33 @@ func getInitialState(ctx context.Context, genesis genesis.Genesis, signer signer |
206 | 218 | return types.State{}, fmt.Errorf("failed to get public key: %w", err) |
207 | 219 | } |
208 | 220 |
|
209 | | - b, err := header.MarshalBinary() |
| 221 | + b, err := signaturePayloadProvider(&header) |
210 | 222 | if err != nil { |
211 | | - return types.State{}, err |
| 223 | + return types.State{}, fmt.Errorf("failed to get signature payload: %w", err) |
212 | 224 | } |
213 | 225 | signature, err = signer.Sign(b) |
214 | 226 | if err != nil { |
215 | 227 | return types.State{}, fmt.Errorf("failed to get header signature: %w", err) |
216 | 228 | } |
217 | 229 | } |
218 | 230 |
|
219 | | - err = store.SaveBlockData(ctx, |
220 | | - &types.SignedHeader{ |
221 | | - Header: header, |
222 | | - Signer: types.Signer{ |
223 | | - PubKey: pubKey, |
224 | | - Address: genesis.ProposerAddress, |
225 | | - }, |
226 | | - Signature: signature, |
| 231 | + genesisHeader := &types.SignedHeader{ |
| 232 | + Header: header, |
| 233 | + Signer: types.Signer{ |
| 234 | + PubKey: pubKey, |
| 235 | + Address: genesis.ProposerAddress, |
227 | 236 | }, |
228 | | - &types.Data{}, |
229 | | - &signature, |
230 | | - ) |
| 237 | + Signature: signature, |
| 238 | + } |
| 239 | + |
| 240 | + // Set the same custom verifier used during normal block validation |
| 241 | + if err := genesisHeader.SetCustomVerifier(func(h *types.Header) ([]byte, error) { |
| 242 | + return signaturePayloadProvider(h) |
| 243 | + }); err != nil { |
| 244 | + return types.State{}, fmt.Errorf("failed to set custom verifier for genesis header: %w", err) |
| 245 | + } |
| 246 | + |
| 247 | + err = store.SaveBlockData(ctx, genesisHeader, &types.Data{}, &signature) |
231 | 248 | if err != nil { |
232 | 249 | return types.State{}, fmt.Errorf("failed to save genesis block: %w", err) |
233 | 250 | } |
@@ -275,8 +292,13 @@ func NewManager( |
275 | 292 | seqMetrics *Metrics, |
276 | 293 | gasPrice float64, |
277 | 294 | gasMultiplier float64, |
| 295 | + signaturePayloadProvider types.SignaturePayloadProvider, |
278 | 296 | ) (*Manager, error) { |
279 | | - s, err := getInitialState(ctx, genesis, signer, store, exec, logger) |
| 297 | + if signaturePayloadProvider == nil { |
| 298 | + signaturePayloadProvider = defaultSignaturePayloadProvider |
| 299 | + } |
| 300 | + |
| 301 | + s, err := getInitialState(ctx, genesis, signer, store, exec, logger, signaturePayloadProvider) |
280 | 302 | if err != nil { |
281 | 303 | return nil, fmt.Errorf("failed to get initial state: %w", err) |
282 | 304 | } |
@@ -339,29 +361,30 @@ func NewManager( |
339 | 361 | headerBroadcaster: headerBroadcaster, |
340 | 362 | dataBroadcaster: dataBroadcaster, |
341 | 363 | // channels are buffered to avoid blocking on input/output operations, buffer sizes are arbitrary |
342 | | - headerInCh: make(chan NewHeaderEvent, eventInChLength), |
343 | | - dataInCh: make(chan NewDataEvent, eventInChLength), |
344 | | - headerStoreCh: make(chan struct{}, 1), |
345 | | - dataStoreCh: make(chan struct{}, 1), |
346 | | - headerStore: headerStore, |
347 | | - dataStore: dataStore, |
348 | | - lastStateMtx: new(sync.RWMutex), |
349 | | - lastBatchData: lastBatchData, |
350 | | - headerCache: cache.NewCache[types.SignedHeader](), |
351 | | - dataCache: cache.NewCache[types.Data](), |
352 | | - retrieveCh: make(chan struct{}, 1), |
353 | | - daIncluderCh: make(chan struct{}, 1), |
354 | | - logger: logger, |
355 | | - txsAvailable: false, |
356 | | - pendingHeaders: pendingHeaders, |
357 | | - metrics: seqMetrics, |
358 | | - sequencer: sequencer, |
359 | | - exec: exec, |
360 | | - da: da, |
361 | | - gasPrice: gasPrice, |
362 | | - gasMultiplier: gasMultiplier, |
363 | | - txNotifyCh: make(chan struct{}, 1), // Non-blocking channel |
364 | | - batchSubmissionChan: make(chan coresequencer.Batch, eventInChLength), |
| 364 | + headerInCh: make(chan NewHeaderEvent, eventInChLength), |
| 365 | + dataInCh: make(chan NewDataEvent, eventInChLength), |
| 366 | + headerStoreCh: make(chan struct{}, 1), |
| 367 | + dataStoreCh: make(chan struct{}, 1), |
| 368 | + headerStore: headerStore, |
| 369 | + dataStore: dataStore, |
| 370 | + lastStateMtx: new(sync.RWMutex), |
| 371 | + lastBatchData: lastBatchData, |
| 372 | + headerCache: cache.NewCache[types.SignedHeader](), |
| 373 | + dataCache: cache.NewCache[types.Data](), |
| 374 | + retrieveCh: make(chan struct{}, 1), |
| 375 | + daIncluderCh: make(chan struct{}, 1), |
| 376 | + logger: logger, |
| 377 | + txsAvailable: false, |
| 378 | + pendingHeaders: pendingHeaders, |
| 379 | + metrics: seqMetrics, |
| 380 | + sequencer: sequencer, |
| 381 | + exec: exec, |
| 382 | + da: da, |
| 383 | + gasPrice: gasPrice, |
| 384 | + gasMultiplier: gasMultiplier, |
| 385 | + txNotifyCh: make(chan struct{}, 1), // Non-blocking channel |
| 386 | + batchSubmissionChan: make(chan coresequencer.Batch, eventInChLength), |
| 387 | + signaturePayloadProvider: signaturePayloadProvider, |
365 | 388 | } |
366 | 389 |
|
367 | 390 | // initialize da included height |
@@ -611,6 +634,14 @@ func (m *Manager) publishBlockInternal(ctx context.Context) error { |
611 | 634 | // set the signature to current block's signed header |
612 | 635 | header.Signature = signature |
613 | 636 |
|
| 637 | + // Set the custom verifier to ensure proper signature validation (if not already set by executor) |
| 638 | + // Note: The executor may have already set a custom verifier during transaction execution |
| 639 | + if err := header.SetCustomVerifier(func(h *types.Header) ([]byte, error) { |
| 640 | + return m.signaturePayloadProvider(h) |
| 641 | + }); err != nil { |
| 642 | + return fmt.Errorf("failed to set custom verifier: %w", err) |
| 643 | + } |
| 644 | + |
614 | 645 | if err := header.ValidateBasic(); err != nil { |
615 | 646 | // If this ever happens, for recovery, check for a mismatch between the configured signing key and the proposer address in the genesis file |
616 | 647 | return fmt.Errorf("header validation error: %w", err) |
@@ -914,7 +945,7 @@ func bytesToBatchData(data []byte) ([][]byte, error) { |
914 | 945 | } |
915 | 946 |
|
916 | 947 | func (m *Manager) getHeaderSignature(header types.Header) (types.Signature, error) { |
917 | | - b, err := header.MarshalBinary() |
| 948 | + b, err := m.signaturePayloadProvider(&header) |
918 | 949 | if err != nil { |
919 | 950 | return nil, err |
920 | 951 | } |
|
0 commit comments