Skip to content

Commit 4866c8c

Browse files
authored
Merge branch 'main' into dependabot/go_modules/main/patch-updates-540bcb214b
2 parents 5806146 + c43f273 commit 4866c8c

File tree

23 files changed

+253
-184
lines changed

23 files changed

+253
-184
lines changed

apps/evm/based/cmd/run.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010

1111
coreda "github.com/rollkit/rollkit/core/da"
1212
"github.com/rollkit/rollkit/execution/evm" // Import the evm flags package
13+
"github.com/rollkit/rollkit/node"
1314

1415
"github.com/rollkit/rollkit/da/jsonrpc"
1516
rollcmd "github.com/rollkit/rollkit/pkg/cmd"
@@ -172,7 +173,7 @@ func NewExtendedRunNodeCmd(ctx context.Context) *cobra.Command {
172173
// StartNode might need adjustment if it strictly requires coreda.Client methods.
173174
// For now, assume it can work with coreda.DA or will be adjusted later.
174175
// We also need to pass the namespace config for rollDA.
175-
return rollcmd.StartNode(logger, cmd, executor, sequencer, rollDA, p2pClient, datastore, nodeConfig, nil)
176+
return rollcmd.StartNode(logger, cmd, executor, sequencer, rollDA, p2pClient, datastore, nodeConfig, node.NodeOptions{})
176177
},
177178
}
178179

apps/evm/single/cmd/run.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"path/filepath"
77

88
"github.com/rollkit/rollkit/da/jsonrpc"
9+
"github.com/rollkit/rollkit/node"
910
"github.com/rollkit/rollkit/sequencers/single"
1011

1112
"github.com/ethereum/go-ethereum/common"
@@ -77,7 +78,7 @@ var RunCmd = &cobra.Command{
7778
return err
7879
}
7980

80-
return rollcmd.StartNode(logger, cmd, executor, sequencer, &daJrpc.DA, p2pClient, datastore, nodeConfig, nil)
81+
return rollcmd.StartNode(logger, cmd, executor, sequencer, &daJrpc.DA, p2pClient, datastore, nodeConfig, node.NodeOptions{})
8182
},
8283
}
8384

apps/testapp/cmd/run.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99

1010
kvexecutor "github.com/rollkit/rollkit/apps/testapp/kv"
1111
"github.com/rollkit/rollkit/da/jsonrpc"
12+
"github.com/rollkit/rollkit/node"
1213
rollcmd "github.com/rollkit/rollkit/pkg/cmd"
1314
"github.com/rollkit/rollkit/pkg/p2p"
1415
"github.com/rollkit/rollkit/pkg/p2p/key"
@@ -93,6 +94,6 @@ var RunCmd = &cobra.Command{
9394
return err
9495
}
9596

96-
return rollcmd.StartNode(logger, cmd, executor, sequencer, &daJrpc.DA, p2pClient, datastore, nodeConfig, nil)
97+
return rollcmd.StartNode(logger, cmd, executor, sequencer, &daJrpc.DA, p2pClient, datastore, nodeConfig, node.NodeOptions{})
9798
},
9899
}

block/manager.go

Lines changed: 73 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -70,10 +70,6 @@ type MetricsRecorder interface {
7070
RecordMetrics(gasPrice float64, blobSize uint64, statusCode coreda.StatusCode, numPendingBlocks uint64, includedBlockHeight uint64)
7171
}
7272

73-
func defaultSignaturePayloadProvider(header *types.Header) ([]byte, error) {
74-
return header.MarshalBinary()
75-
}
76-
7773
// NewHeaderEvent is used to pass header and DA height to headerInCh
7874
type NewHeaderEvent struct {
7975
Header *types.SignedHeader
@@ -168,14 +164,14 @@ type Manager struct {
168164
// signaturePayloadProvider is used to provide a signature payload for the header.
169165
// It is used to sign the header with the provided signer.
170166
signaturePayloadProvider types.SignaturePayloadProvider
167+
168+
// validatorHasherProvider is used to provide the validator hash for the header.
169+
// It is used to set the validator hash in the header.
170+
validatorHasherProvider types.ValidatorHasherProvider
171171
}
172172

173173
// getInitialState tries to load lastState from Store, and if it's not available it reads genesis.
174-
func getInitialState(ctx context.Context, genesis genesis.Genesis, signer signer.Signer, store storepkg.Store, exec coreexecutor.Executor, logger logging.EventLogger, signaturePayloadProvider types.SignaturePayloadProvider) (types.State, error) {
175-
if signaturePayloadProvider == nil {
176-
signaturePayloadProvider = defaultSignaturePayloadProvider
177-
}
178-
174+
func getInitialState(ctx context.Context, genesis genesis.Genesis, signer signer.Signer, store storepkg.Store, exec coreexecutor.Executor, logger logging.EventLogger, managerOpts ManagerOptions) (types.State, error) {
179175
// Load the state from store.
180176
s, err := store.GetState(ctx)
181177

@@ -201,9 +197,12 @@ func getInitialState(ctx context.Context, genesis genesis.Genesis, signer signer
201197
},
202198
}
203199

204-
var signature types.Signature
200+
var (
201+
data = &types.Data{}
202+
signature types.Signature
203+
pubKey crypto.PubKey
204+
)
205205

206-
var pubKey crypto.PubKey
207206
// The signer is only provided in aggregator nodes. This enables the creation of a signed genesis header,
208207
// which includes a public key and a cryptographic signature for the header.
209208
// In a full node (non-aggregator), the signer will be nil, and only an unsigned genesis header will be initialized locally.
@@ -213,11 +212,12 @@ func getInitialState(ctx context.Context, genesis genesis.Genesis, signer signer
213212
return types.State{}, fmt.Errorf("failed to get public key: %w", err)
214213
}
215214

216-
b, err := signaturePayloadProvider(&header)
215+
bz, err := managerOpts.SignaturePayloadProvider(&header)
217216
if err != nil {
218217
return types.State{}, fmt.Errorf("failed to get signature payload: %w", err)
219218
}
220-
signature, err = signer.Sign(b)
219+
220+
signature, err = signer.Sign(bz)
221221
if err != nil {
222222
return types.State{}, fmt.Errorf("failed to get header signature: %w", err)
223223
}
@@ -232,14 +232,7 @@ func getInitialState(ctx context.Context, genesis genesis.Genesis, signer signer
232232
Signature: signature,
233233
}
234234

235-
// Set the same custom verifier used during normal block validation
236-
if err := genesisHeader.SetCustomVerifier(func(h *types.Header) ([]byte, error) {
237-
return signaturePayloadProvider(h)
238-
}); err != nil {
239-
return types.State{}, fmt.Errorf("failed to set custom verifier for genesis header: %w", err)
240-
}
241-
242-
err = store.SaveBlockData(ctx, genesisHeader, &types.Data{}, &signature)
235+
err = store.SaveBlockData(ctx, genesisHeader, data, &signature)
243236
if err != nil {
244237
return types.State{}, fmt.Errorf("failed to save genesis block: %w", err)
245238
}
@@ -269,6 +262,31 @@ func getInitialState(ctx context.Context, genesis genesis.Genesis, signer signer
269262
return s, nil
270263
}
271264

265+
// ManagerOptions defines the options for creating a new block Manager.
266+
type ManagerOptions struct {
267+
SignaturePayloadProvider types.SignaturePayloadProvider
268+
ValidatorHasherProvider types.ValidatorHasherProvider
269+
}
270+
271+
func (opts *ManagerOptions) Validate() error {
272+
if opts.SignaturePayloadProvider == nil {
273+
return fmt.Errorf("signature payload provider cannot be nil")
274+
}
275+
if opts.ValidatorHasherProvider == nil {
276+
return fmt.Errorf("validator hasher provider cannot be nil")
277+
}
278+
279+
return nil
280+
}
281+
282+
// DefaultManagerOptions returns the default options for creating a new block Manager.
283+
func DefaultManagerOptions() ManagerOptions {
284+
return ManagerOptions{
285+
SignaturePayloadProvider: types.DefaultSignaturePayloadProvider,
286+
ValidatorHasherProvider: types.DefaultValidatorHasherProvider,
287+
}
288+
}
289+
272290
// NewManager creates new block Manager.
273291
func NewManager(
274292
ctx context.Context,
@@ -287,13 +305,9 @@ func NewManager(
287305
seqMetrics *Metrics,
288306
gasPrice float64,
289307
gasMultiplier float64,
290-
signaturePayloadProvider types.SignaturePayloadProvider,
308+
managerOpts ManagerOptions,
291309
) (*Manager, error) {
292-
if signaturePayloadProvider == nil {
293-
signaturePayloadProvider = defaultSignaturePayloadProvider
294-
}
295-
296-
s, err := getInitialState(ctx, genesis, signer, store, exec, logger, signaturePayloadProvider)
310+
s, err := getInitialState(ctx, genesis, signer, store, exec, logger, managerOpts)
297311
if err != nil {
298312
return nil, fmt.Errorf("failed to get initial state: %w", err)
299313
}
@@ -384,7 +398,8 @@ func NewManager(
384398
gasPrice: gasPrice,
385399
gasMultiplier: gasMultiplier,
386400
txNotifyCh: make(chan struct{}, 1), // Non-blocking channel
387-
signaturePayloadProvider: signaturePayloadProvider,
401+
signaturePayloadProvider: managerOpts.SignaturePayloadProvider,
402+
validatorHasherProvider: managerOpts.ValidatorHasherProvider,
388403
}
389404

390405
// initialize da included height
@@ -659,33 +674,12 @@ func (m *Manager) publishBlockInternal(ctx context.Context) error {
659674
return err
660675
}
661676

662-
if err = m.store.SaveBlockData(ctx, header, data, &signature); err != nil {
677+
if err = m.store.SaveBlockData(ctx, header, data, &signature); err != nil { // saved early for crash recovery, will be overwritten later with the final signature
663678
return fmt.Errorf("failed to save block: %w", err)
664679
}
665680
}
666681

667-
signature, err = m.getHeaderSignature(header.Header)
668-
if err != nil {
669-
return err
670-
}
671-
672-
// set the signature to current block's signed header
673-
header.Signature = signature
674-
675-
// Set the custom verifier to ensure proper signature validation (if not already set by executor)
676-
// Note: The executor may have already set a custom verifier during transaction execution
677-
if err := header.SetCustomVerifier(func(h *types.Header) ([]byte, error) {
678-
return m.signaturePayloadProvider(h)
679-
}); err != nil {
680-
return fmt.Errorf("failed to set custom verifier: %w", err)
681-
}
682-
683-
if err := header.ValidateBasic(); err != nil {
684-
// If this ever happens, for recovery, check for a mismatch between the configured signing key and the proposer address in the genesis file
685-
return fmt.Errorf("header validation error: %w", err)
686-
}
687-
688-
newState, err := m.applyBlock(ctx, header, data)
682+
newState, err := m.applyBlock(ctx, header.Header, data)
689683
if err != nil {
690684
return fmt.Errorf("error applying block: %w", err)
691685
}
@@ -697,13 +691,24 @@ func (m *Manager) publishBlockInternal(ctx context.Context) error {
697691
Time: header.BaseHeader.Time,
698692
LastDataHash: lastDataHash,
699693
}
694+
695+
// we sign the header after executing the block, as a signature payload provider could depend on the block's data
696+
signature, err = m.getHeaderSignature(header.Header)
697+
if err != nil {
698+
return err
699+
}
700+
701+
// set the signature to current block's signed header
702+
header.Signature = signature
703+
704+
// set the custom verifier to ensure proper signature validation
705+
header.SetCustomVerifier(m.signaturePayloadProvider)
706+
700707
// Validate the created block before storing
701708
if err := m.Validate(ctx, header, data); err != nil {
702709
return fmt.Errorf("failed to validate block: %w", err)
703710
}
704711

705-
headerHeight := header.Height()
706-
707712
headerHash := header.Hash().String()
708713
m.headerCache.SetSeen(headerHash)
709714

@@ -714,6 +719,7 @@ func (m *Manager) publishBlockInternal(ctx context.Context) error {
714719
}
715720

716721
// Update the store height before submitting to the DA layer but after committing to the DB
722+
headerHeight := header.Height()
717723
if err = m.store.SetHeight(ctx, headerHeight); err != nil {
718724
return err
719725
}
@@ -773,7 +779,7 @@ func (m *Manager) createBlock(ctx context.Context, height uint64, lastSignature
773779
return m.execCreateBlock(ctx, height, lastSignature, lastHeaderHash, m.lastState, batchData)
774780
}
775781

776-
func (m *Manager) applyBlock(ctx context.Context, header *types.SignedHeader, data *types.Data) (types.State, error) {
782+
func (m *Manager) applyBlock(ctx context.Context, header types.Header, data *types.Data) (types.State, error) {
777783
m.lastStateMtx.RLock()
778784
defer m.lastStateMtx.RUnlock()
779785
return m.execApplyBlock(ctx, m.lastState, header, data)
@@ -845,9 +851,15 @@ func (m *Manager) execCreateBlock(_ context.Context, height uint64, lastSignatur
845851
return nil, nil, fmt.Errorf("proposer address is not the same as the genesis proposer address %x != %x", address, m.genesis.ProposerAddress)
846852
}
847853

848-
// Determine if this is an empty block
854+
// determine if this is an empty block
849855
isEmpty := batchData.Batch == nil || len(batchData.Transactions) == 0
850856

857+
// build validator hash
858+
validatorHash, err := m.validatorHasherProvider(m.genesis.ProposerAddress, key)
859+
if err != nil {
860+
return nil, nil, fmt.Errorf("failed to get validator hash: %w", err)
861+
}
862+
851863
header := &types.SignedHeader{
852864
Header: types.Header{
853865
Version: types.Version{
@@ -857,13 +869,14 @@ func (m *Manager) execCreateBlock(_ context.Context, height uint64, lastSignatur
857869
BaseHeader: types.BaseHeader{
858870
ChainID: m.lastState.ChainID,
859871
Height: height,
860-
Time: uint64(batchData.UnixNano()), //nolint:gosec // why is time unix? (tac0turtle)
872+
Time: uint64(batchData.UnixNano()),
861873
},
862874
LastHeaderHash: lastHeaderHash,
863875
// DataHash is set at the end of the function
864876
ConsensusHash: make(types.Hash, 32),
865877
AppHash: m.lastState.AppHash,
866878
ProposerAddress: m.genesis.ProposerAddress,
879+
ValidatorHash: validatorHash,
867880
},
868881
Signature: *lastSignature,
869882
Signer: types.Signer{
@@ -891,13 +904,13 @@ func (m *Manager) execCreateBlock(_ context.Context, height uint64, lastSignatur
891904
return header, blockData, nil
892905
}
893906

894-
func (m *Manager) execApplyBlock(ctx context.Context, lastState types.State, header *types.SignedHeader, data *types.Data) (types.State, error) {
907+
func (m *Manager) execApplyBlock(ctx context.Context, lastState types.State, header types.Header, data *types.Data) (types.State, error) {
895908
rawTxs := make([][]byte, len(data.Txs))
896909
for i := range data.Txs {
897910
rawTxs[i] = data.Txs[i]
898911
}
899912

900-
ctx = context.WithValue(ctx, types.SignedHeaderContextKey, header)
913+
ctx = context.WithValue(ctx, types.HeaderContextKey, header)
901914
newStateRoot, _, err := m.exec.ExecuteTxs(ctx, rawTxs, header.Height(), header.Time(), lastState.AppHash)
902915
if err != nil {
903916
return types.State{}, fmt.Errorf("failed to execute transactions: %w", err)
@@ -985,9 +998,11 @@ func (m *Manager) getHeaderSignature(header types.Header) (types.Signature, erro
985998
if err != nil {
986999
return nil, err
9871000
}
1001+
9881002
if m.signer == nil {
9891003
return nil, fmt.Errorf("signer is nil; cannot sign header")
9901004
}
1005+
9911006
return m.signer.Sign(b)
9921007
}
9931008

block/manager_test.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,8 @@ func getManager(t *testing.T, da da.DA, gasPrice float64, gasMultiplier float64)
5353
metrics: NopMetrics(),
5454
store: mockStore,
5555
txNotifyCh: make(chan struct{}, 1),
56-
signaturePayloadProvider: defaultSignaturePayloadProvider,
56+
signaturePayloadProvider: types.DefaultSignaturePayloadProvider,
57+
validatorHasherProvider: types.DefaultValidatorHasherProvider,
5758
}
5859

5960
m.publishBlock = m.publishBlockInternal
@@ -77,7 +78,7 @@ func TestInitialStateClean(t *testing.T) {
7778
mockExecutor.On("InitChain", ctx, genesisData.GenesisDAStartTime, genesisData.InitialHeight, genesisData.ChainID).
7879
Return([]byte("mockAppHash"), uint64(1000), nil).Once()
7980

80-
s, err := getInitialState(ctx, genesisData, nil, emptyStore, mockExecutor, logger, nil /* uses default signature verification */)
81+
s, err := getInitialState(ctx, genesisData, nil, emptyStore, mockExecutor, logger, DefaultManagerOptions())
8182
require.NoError(err)
8283
initialHeight := genesisData.InitialHeight
8384
require.Equal(initialHeight-1, s.LastBlockHeight)
@@ -108,7 +109,7 @@ func TestInitialStateStored(t *testing.T) {
108109
mockExecutor := mocks.NewMockExecutor(t)
109110

110111
// getInitialState should not call InitChain if state exists
111-
s, err := getInitialState(ctx, genesisData, nil, store, mockExecutor, logger, nil /* uses default signature verification */)
112+
s, err := getInitialState(ctx, genesisData, nil, store, mockExecutor, logger, DefaultManagerOptions())
112113
require.NoError(err)
113114
require.Equal(s.LastBlockHeight, uint64(100))
114115
require.Equal(s.InitialHeight, uint64(1))
@@ -143,7 +144,7 @@ func TestInitialStateUnexpectedHigherGenesis(t *testing.T) {
143144
require.NoError(err)
144145
mockExecutor := mocks.NewMockExecutor(t)
145146

146-
_, err = getInitialState(ctx, genesis, nil, store, mockExecutor, logger, nil /* uses default signature verification */)
147+
_, err = getInitialState(ctx, genesis, nil, store, mockExecutor, logger, DefaultManagerOptions())
147148
require.EqualError(err, "genesis.InitialHeight (2) is greater than last stored state's LastBlockHeight (0)")
148149

149150
// Assert mock expectations (InitChain should not have been called)

block/publish_block_p2p_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@ func setupBlockManager(t *testing.T, ctx context.Context, workDir string, mainKV
217217
NopMetrics(),
218218
1.,
219219
1.,
220-
nil, // using default signature verification
220+
DefaultManagerOptions(),
221221
)
222222
require.NoError(t, err)
223223
return result, headerSyncService, dataSyncService

0 commit comments

Comments
 (0)