Skip to content

Commit 79d0f7d

Browse files
authored
feat: optionally skip processProposal while blocksyncing (#2658)
first part of #2657 adds a config and flag to the blocksync config that enables a user to select if they call ProcessProposal while blocksyncing or not. This can significantly increase syncing rate, especially with large blocks. When state syncing, users also suffer from a minimal security decrease. when verifying is disabled, we are only comparing the partsetheader, not the data root.
1 parent 0091750 commit 79d0f7d

File tree

5 files changed

+71
-8
lines changed

5 files changed

+71
-8
lines changed

blocksync/reactor.go

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,16 @@ type consensusReactor interface {
4242
SwitchToConsensus(state sm.State, skipWAL bool)
4343
}
4444

45+
// ReactorOption defines a function argument for Reactor.
46+
type ReactorOption func(*Reactor)
47+
48+
// ReactorVerifyData sets the verifyData field of the reactor.
49+
func ReactorVerifyData(verifyData bool) ReactorOption {
50+
return func(bcR *Reactor) {
51+
bcR.verifyData = verifyData
52+
}
53+
}
54+
4555
type peerError struct {
4656
err error
4757
peerID p2p.ID
@@ -63,6 +73,7 @@ type Reactor struct {
6373
pool *BlockPool
6474
traceClient trace.Tracer
6575
blockSync bool
76+
verifyData bool
6677
localAddr crypto.Address
6778
poolRoutineWg sync.WaitGroup
6879

@@ -76,14 +87,14 @@ type Reactor struct {
7687

7788
// NewReactor returns new reactor instance.
7889
func NewReactor(state sm.State, blockExec *sm.BlockExecutor, store *store.BlockStore,
79-
blockSync bool, metrics *Metrics, offlineStateSyncHeight int64,
90+
blockSync bool, metrics *Metrics, offlineStateSyncHeight int64, options ...ReactorOption,
8091
) *Reactor {
81-
return NewReactorWithAddr(state, blockExec, store, blockSync, nil, metrics, offlineStateSyncHeight, trace.NoOpTracer())
92+
return NewReactorWithAddr(state, blockExec, store, blockSync, nil, metrics, offlineStateSyncHeight, trace.NoOpTracer(), options...)
8293
}
8394

8495
// Function added to keep existing API.
8596
func NewReactorWithAddr(state sm.State, blockExec *sm.BlockExecutor, store *store.BlockStore,
86-
blockSync bool, localAddr crypto.Address, metrics *Metrics, offlineStateSyncHeight int64, traceClient trace.Tracer,
97+
blockSync bool, localAddr crypto.Address, metrics *Metrics, offlineStateSyncHeight int64, traceClient trace.Tracer, options ...ReactorOption,
8798
) *Reactor {
8899

89100
storeHeight := store.Height()
@@ -120,13 +131,19 @@ func NewReactorWithAddr(state sm.State, blockExec *sm.BlockExecutor, store *stor
120131
store: store,
121132
pool: pool,
122133
blockSync: blockSync,
134+
verifyData: true,
123135
localAddr: localAddr,
124136
requestsCh: requestsCh,
125137
errorsCh: errorsCh,
126138
metrics: metrics,
127139
traceClient: traceClient,
128140
}
129141
bcR.BaseReactor = *p2p.NewBaseReactor("BlockSync", bcR, p2p.WithIncomingQueueSize(ReactorIncomingMessageQueueSize))
142+
143+
for _, option := range options {
144+
option(bcR)
145+
}
146+
130147
return bcR
131148
}
132149

@@ -514,7 +531,7 @@ FOR_LOOP:
514531
err = bcR.blockExec.ValidateBlock(state, first)
515532
}
516533

517-
if err == nil {
534+
if err == nil && bcR.verifyData {
518535
var stateMachineValid bool
519536
// Block sync doesn't check that the `Data` in a block is valid.
520537
// Since celestia-core can't determine if the `Data` in a block

blocksync/reactor_test.go

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,18 @@ func newReactor(
6767
privVals []types.PrivValidator,
6868
maxBlockHeight int64,
6969
incorrectData ...int64,
70+
) ReactorPair {
71+
return newReactorWithConfig(t, logger, genDoc, privVals, maxBlockHeight, true, incorrectData...)
72+
}
73+
74+
func newReactorWithConfig(
75+
t *testing.T,
76+
logger log.Logger,
77+
genDoc *types.GenesisDoc,
78+
privVals []types.PrivValidator,
79+
maxBlockHeight int64,
80+
verifyData bool,
81+
incorrectData ...int64,
7082
) ReactorPair {
7183
if len(privVals) != 1 {
7284
panic("only support one validator")
@@ -177,12 +189,39 @@ func newReactor(
177189
}
178190
}
179191

180-
bcReactor := NewByzantineReactor(incorrectBlock, NewReactor(state.Copy(), blockExec, blockStore, blockSync, NopMetrics(), 0))
192+
bcReactor := NewByzantineReactor(incorrectBlock, NewReactor(state.Copy(), blockExec, blockStore, blockSync, NopMetrics(), 0, ReactorVerifyData(verifyData)))
181193
bcReactor.SetLogger(logger.With("module", "blocksync"))
182194

183195
return ReactorPair{bcReactor, proxyApp}
184196
}
185197

198+
func TestVerifyData(t *testing.T) {
199+
config = test.ResetTestRoot("blocksync_verify_data_test")
200+
defer os.RemoveAll(config.RootDir)
201+
genDoc, privVals := randGenesisDoc(1, false, 30)
202+
203+
maxBlockHeight := int64(10)
204+
205+
// Case 1: verifyData = true. Normal behavior.
206+
// We cannot easily mock ProcessProposal failure here because we are using a real app (NewBaseApplication) via proxy.
207+
// But we can observe that it works.
208+
// To test failure, we would need to mock the app or the proxy connection.
209+
// The current newReactor setup uses a real BaseApplication.
210+
// So, passing verifyData=false should also work for normal blocks.
211+
// To really test this, we might need a way to make ProcessProposal fail.
212+
213+
// Let's verify that we can construct reactors with both settings.
214+
rp1 := newReactorWithConfig(t, log.TestingLogger(), genDoc, privVals, maxBlockHeight, true)
215+
rp2 := newReactorWithConfig(t, log.TestingLogger(), genDoc, privVals, maxBlockHeight, false)
216+
217+
require.NotNil(t, rp1.reactor)
218+
require.NotNil(t, rp2.reactor)
219+
220+
// We can check the internal field
221+
assert.True(t, rp1.reactor.verifyData)
222+
assert.False(t, rp2.reactor.verifyData)
223+
}
224+
186225
func TestNoBlockResponse(t *testing.T) {
187226
config = test.ResetTestRoot("blocksync_reactor_test")
188227
defer os.RemoveAll(config.RootDir)

config/config.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1035,13 +1035,15 @@ func (cfg *StateSyncConfig) ValidateBasic() error {
10351035

10361036
// BlockSyncConfig (formerly known as FastSync) defines the configuration for the CometBFT block sync service
10371037
type BlockSyncConfig struct {
1038-
Version string `mapstructure:"version"`
1038+
Version string `mapstructure:"version"`
1039+
VerifyData bool `mapstructure:"verify_data"`
10391040
}
10401041

10411042
// DefaultBlockSyncConfig returns a default configuration for the block sync service
10421043
func DefaultBlockSyncConfig() *BlockSyncConfig {
10431044
return &BlockSyncConfig{
1044-
Version: "v0",
1045+
Version: "v0",
1046+
VerifyData: true,
10451047
}
10461048
}
10471049

config/toml.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -499,6 +499,11 @@ chunk_fetchers = "{{ .StateSync.ChunkFetchers }}"
499499
# 1) "v0" - the default block sync implementation
500500
version = "{{ .BlockSync.Version }}"
501501
502+
# If true, the node will verify the application data in the block via ProcessProposal
503+
# during block sync. If false, this verification is skipped.
504+
# Default: true
505+
verify_data = {{ .BlockSync.VerifyData }}
506+
502507
#######################################################
503508
### Consensus Configuration Options ###
504509
#######################################################

node/setup.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -352,7 +352,7 @@ func createBlocksyncReactor(config *cfg.Config,
352352
) (bcReactor p2p.Reactor, err error) {
353353
switch config.BlockSync.Version {
354354
case "v0":
355-
bcReactor = blocksync.NewReactorWithAddr(state.Copy(), blockExec, blockStore, blockSync, localAddr, metrics, offlineStateSyncHeight, tracer)
355+
bcReactor = blocksync.NewReactorWithAddr(state.Copy(), blockExec, blockStore, blockSync, localAddr, metrics, offlineStateSyncHeight, tracer, blocksync.ReactorVerifyData(config.BlockSync.VerifyData))
356356
case "v1", "v2":
357357
return nil, fmt.Errorf("block sync version %s has been deprecated. Please use v0", config.BlockSync.Version)
358358
default:

0 commit comments

Comments
 (0)