Skip to content

Commit ea0dec6

Browse files
Support based rollups + centralized sequencer to based rollup integration test (cosmos#827)
Closes: cosmos#848, cosmos#849
1 parent 23cc81a commit ea0dec6

File tree

5 files changed

+132
-41
lines changed

5 files changed

+132
-41
lines changed

block/manager.go

+5-3
Original file line numberDiff line numberDiff line change
@@ -564,8 +564,10 @@ func (m *Manager) publishBlock(ctx context.Context) error {
564564
return err
565565
}
566566

567+
blockHeight := uint64(block.SignedHeader.Header.Height())
568+
567569
// Only update the stored height after successfully submitting to DA layer and committing to the DB
568-
m.store.SetHeight(uint64(block.SignedHeader.Header.Height()))
570+
m.store.SetHeight(blockHeight)
569571

570572
// Commit the new state and block which writes to disk on the proxy app
571573
_, _, err = m.executor.Commit(ctx, newState, block, responses)
@@ -574,13 +576,13 @@ func (m *Manager) publishBlock(ctx context.Context) error {
574576
}
575577

576578
// SaveBlockResponses commits the DB tx
577-
err = m.store.SaveBlockResponses(uint64(block.SignedHeader.Header.Height()), responses)
579+
err = m.store.SaveBlockResponses(blockHeight, responses)
578580
if err != nil {
579581
return err
580582
}
581583

582584
// SaveValidators commits the DB tx
583-
err = m.store.SaveValidators(uint64(block.SignedHeader.Header.Height()), m.lastState.Validators)
585+
err = m.store.SaveValidators(blockHeight, m.lastState.Validators)
584586
if err != nil {
585587
return err
586588
}

node/full_client_test.go

+105-36
Original file line numberDiff line numberDiff line change
@@ -650,21 +650,16 @@ func TestBlockchainInfo(t *testing.T) {
650650
}
651651
}
652652

653-
func TestValidatorSetHandling(t *testing.T) {
654-
assert := assert.New(t)
655-
require := require.New(t)
656-
657-
waitCh := make(chan interface{})
658-
659-
vKeys := make([]tmcrypto.PrivKey, 2)
660-
apps := make([]*mocks.Application, 2)
661-
nodes := make([]*FullNode, 2)
653+
func createGenesisValidators(numNodes int, appCreator func(vKeyToRemove tmcrypto.PrivKey) *mocks.Application, require *require.Assertions) *FullClient {
654+
vKeys := make([]tmcrypto.PrivKey, numNodes)
655+
apps := make([]*mocks.Application, numNodes)
656+
nodes := make([]*FullNode, numNodes)
662657

663658
genesisValidators := make([]tmtypes.GenesisValidator, len(vKeys))
664659
for i := 0; i < len(vKeys); i++ {
665660
vKeys[i] = ed25519.GenPrivKey()
666661
genesisValidators[i] = tmtypes.GenesisValidator{Address: vKeys[i].PubKey().Address(), PubKey: vKeys[i].PubKey(), Power: int64(i + 100), Name: fmt.Sprintf("gen #%d", i)}
667-
apps[i] = createApp(vKeys[0], waitCh, require)
662+
apps[i] = appCreator(vKeys[0])
668663
}
669664

670665
dalc := &mockda.DataAvailabilityLayerClient{}
@@ -712,6 +707,39 @@ func TestValidatorSetHandling(t *testing.T) {
712707
err := nodes[i].Start()
713708
require.NoError(err)
714709
}
710+
return rpc
711+
}
712+
713+
// Tests moving from two validators to one validator and then back to two validators
714+
func TestValidatorSetHandling(t *testing.T) {
715+
assert := assert.New(t)
716+
require := require.New(t)
717+
718+
waitCh := make(chan interface{})
719+
720+
numNodes := 2
721+
createApp := func(vKeyToRemove tmcrypto.PrivKey) *mocks.Application {
722+
app := &mocks.Application{}
723+
app.On("InitChain", mock.Anything).Return(abci.ResponseInitChain{})
724+
app.On("CheckTx", mock.Anything).Return(abci.ResponseCheckTx{})
725+
app.On("BeginBlock", mock.Anything).Return(abci.ResponseBeginBlock{})
726+
app.On("Commit", mock.Anything).Return(abci.ResponseCommit{})
727+
app.On("GetAppHash", mock.Anything).Return(abci.ResponseGetAppHash{})
728+
app.On("GenerateFraudProof", mock.Anything).Return(abci.ResponseGenerateFraudProof{})
729+
730+
pbValKey, err := encoding.PubKeyToProto(vKeyToRemove.PubKey())
731+
require.NoError(err)
732+
733+
app.On("EndBlock", mock.Anything).Return(abci.ResponseEndBlock{}).Times(2)
734+
app.On("EndBlock", mock.Anything).Return(abci.ResponseEndBlock{ValidatorUpdates: []abci.ValidatorUpdate{{PubKey: pbValKey, Power: 0}}}).Once()
735+
app.On("EndBlock", mock.Anything).Return(abci.ResponseEndBlock{}).Once()
736+
app.On("EndBlock", mock.Anything).Return(abci.ResponseEndBlock{ValidatorUpdates: []abci.ValidatorUpdate{{PubKey: pbValKey, Power: 100}}}).Once()
737+
app.On("EndBlock", mock.Anything).Return(abci.ResponseEndBlock{}).Run(func(args mock.Arguments) {
738+
waitCh <- nil
739+
})
740+
return app
741+
}
742+
rpc := createGenesisValidators(numNodes, createApp, require)
715743

716744
<-waitCh
717745
<-waitCh
@@ -721,8 +749,8 @@ func TestValidatorSetHandling(t *testing.T) {
721749
vals, err := rpc.Validators(context.Background(), &h, nil, nil)
722750
assert.NoError(err)
723751
assert.NotNil(vals)
724-
assert.EqualValues(len(genesisValidators), vals.Total)
725-
assert.Len(vals.Validators, len(genesisValidators))
752+
assert.EqualValues(numNodes, vals.Total)
753+
assert.Len(vals.Validators, numNodes)
726754
assert.EqualValues(vals.BlockHeight, h)
727755
}
728756

@@ -731,8 +759,8 @@ func TestValidatorSetHandling(t *testing.T) {
731759
vals, err := rpc.Validators(context.Background(), &h, nil, nil)
732760
assert.NoError(err)
733761
assert.NotNil(vals)
734-
assert.EqualValues(len(genesisValidators)-1, vals.Total)
735-
assert.Len(vals.Validators, len(genesisValidators)-1)
762+
assert.EqualValues(numNodes-1, vals.Total)
763+
assert.Len(vals.Validators, numNodes-1)
736764
assert.EqualValues(vals.BlockHeight, h)
737765
}
738766

@@ -743,40 +771,81 @@ func TestValidatorSetHandling(t *testing.T) {
743771
vals, err := rpc.Validators(context.Background(), &h, nil, nil)
744772
assert.NoError(err)
745773
assert.NotNil(vals)
746-
assert.EqualValues(len(genesisValidators), vals.Total)
747-
assert.Len(vals.Validators, len(genesisValidators))
774+
assert.EqualValues(numNodes, vals.Total)
775+
assert.Len(vals.Validators, numNodes)
748776
assert.EqualValues(vals.BlockHeight, h)
749777
}
750778

751779
// check for "latest block"
752780
vals, err := rpc.Validators(context.Background(), nil, nil, nil)
753781
assert.NoError(err)
754782
assert.NotNil(vals)
755-
assert.EqualValues(len(genesisValidators), vals.Total)
756-
assert.Len(vals.Validators, len(genesisValidators))
783+
assert.EqualValues(numNodes, vals.Total)
784+
assert.Len(vals.Validators, numNodes)
757785
assert.GreaterOrEqual(vals.BlockHeight, int64(9))
758786
}
759787

760-
func createApp(keyToRemove tmcrypto.PrivKey, waitCh chan interface{}, require *require.Assertions) *mocks.Application {
761-
app := &mocks.Application{}
762-
app.On("InitChain", mock.Anything).Return(abci.ResponseInitChain{})
763-
app.On("CheckTx", mock.Anything).Return(abci.ResponseCheckTx{})
764-
app.On("BeginBlock", mock.Anything).Return(abci.ResponseBeginBlock{})
765-
app.On("Commit", mock.Anything).Return(abci.ResponseCommit{})
766-
app.On("GetAppHash", mock.Anything).Return(abci.ResponseGetAppHash{})
767-
app.On("GenerateFraudProof", mock.Anything).Return(abci.ResponseGenerateFraudProof{})
788+
// Tests moving from a centralized validator to empty validator set
789+
func TestValidatorSetHandlingBased(t *testing.T) {
790+
assert := assert.New(t)
791+
require := require.New(t)
768792

769-
pbValKey, err := encoding.PubKeyToProto(keyToRemove.PubKey())
770-
require.NoError(err)
793+
waitCh := make(chan interface{})
771794

772-
app.On("EndBlock", mock.Anything).Return(abci.ResponseEndBlock{}).Times(2)
773-
app.On("EndBlock", mock.Anything).Return(abci.ResponseEndBlock{ValidatorUpdates: []abci.ValidatorUpdate{{PubKey: pbValKey, Power: 0}}}).Once()
774-
app.On("EndBlock", mock.Anything).Return(abci.ResponseEndBlock{}).Once()
775-
app.On("EndBlock", mock.Anything).Return(abci.ResponseEndBlock{ValidatorUpdates: []abci.ValidatorUpdate{{PubKey: pbValKey, Power: 100}}}).Once()
776-
app.On("EndBlock", mock.Anything).Return(abci.ResponseEndBlock{}).Run(func(args mock.Arguments) {
777-
waitCh <- nil
778-
})
779-
return app
795+
numNodes := 1
796+
createApp := func(vKeyToRemove tmcrypto.PrivKey) *mocks.Application {
797+
app := &mocks.Application{}
798+
app.On("InitChain", mock.Anything).Return(abci.ResponseInitChain{})
799+
app.On("CheckTx", mock.Anything).Return(abci.ResponseCheckTx{})
800+
app.On("BeginBlock", mock.Anything).Return(abci.ResponseBeginBlock{})
801+
app.On("Commit", mock.Anything).Return(abci.ResponseCommit{})
802+
app.On("GetAppHash", mock.Anything).Return(abci.ResponseGetAppHash{})
803+
app.On("GenerateFraudProof", mock.Anything).Return(abci.ResponseGenerateFraudProof{})
804+
805+
pbValKey, err := encoding.PubKeyToProto(vKeyToRemove.PubKey())
806+
require.NoError(err)
807+
808+
app.On("EndBlock", mock.Anything).Return(abci.ResponseEndBlock{}).Times(2)
809+
app.On("EndBlock", mock.Anything).Return(abci.ResponseEndBlock{ValidatorUpdates: []abci.ValidatorUpdate{{PubKey: pbValKey, Power: 0}}}).Once()
810+
app.On("EndBlock", mock.Anything).Return(abci.ResponseEndBlock{}).Run(func(args mock.Arguments) {
811+
waitCh <- nil
812+
})
813+
return app
814+
}
815+
816+
rpc := createGenesisValidators(numNodes, createApp, require)
817+
818+
<-waitCh
819+
820+
// test first blocks
821+
for h := int64(1); h <= 3; h++ {
822+
vals, err := rpc.Validators(context.Background(), &h, nil, nil)
823+
assert.NoError(err)
824+
assert.NotNil(vals)
825+
assert.EqualValues(numNodes, vals.Total)
826+
assert.Len(vals.Validators, numNodes)
827+
assert.EqualValues(vals.BlockHeight, h)
828+
}
829+
830+
// 3rd EndBlock removes the first validator and makes the rollup based
831+
for h := int64(4); h <= 9; h++ {
832+
<-waitCh
833+
vals, err := rpc.Validators(context.Background(), &h, nil, nil)
834+
assert.NoError(err)
835+
assert.NotNil(vals)
836+
assert.EqualValues(numNodes-1, vals.Total)
837+
assert.Len(vals.Validators, numNodes-1)
838+
assert.EqualValues(vals.BlockHeight, h)
839+
}
840+
841+
// check for "latest block"
842+
<-waitCh
843+
vals, err := rpc.Validators(context.Background(), nil, nil, nil)
844+
assert.NoError(err)
845+
assert.NotNil(vals)
846+
assert.EqualValues(numNodes-1, vals.Total)
847+
assert.Len(vals.Validators, numNodes-1)
848+
assert.GreaterOrEqual(vals.BlockHeight, int64(9))
780849
}
781850

782851
// copy-pasted from store/store_test.go

state/executor.go

+11-2
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
)
2424

2525
var ErrFraudProofGenerated = errors.New("failed to ApplyBlock: halting node due to fraud")
26+
var ErrEmptyValSetGenerated = errors.New("applying the validator changes would result in empty set")
2627

2728
// BlockExecutor creates and applies blocks and maintains state.
2829
type BlockExecutor struct {
@@ -210,14 +211,22 @@ func (e *BlockExecutor) updateState(state types.State, block *types.Block, abciR
210211
if len(validatorUpdates) > 0 {
211212
err := nValSet.UpdateWithChangeSet(validatorUpdates)
212213
if err != nil {
213-
return state, nil
214+
if err.Error() != ErrEmptyValSetGenerated.Error() {
215+
return state, err
216+
}
217+
nValSet = &tmtypes.ValidatorSet{
218+
Validators: make([]*tmtypes.Validator, 0),
219+
Proposer: nil,
220+
}
214221
}
215222
// Change results from this height but only applies to the next next height.
216223
lastHeightValSetChanged = block.SignedHeader.Header.Height() + 1 + 1
217224
}
218225

226+
if len(nValSet.Validators) > 0 {
227+
nValSet.IncrementProposerPriority(1)
228+
}
219229
// TODO(tzdybal): right now, it's for backward compatibility, may need to change this
220-
nValSet.IncrementProposerPriority(1)
221230
}
222231

223232
s := types.State{

store/store.go

+6
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,12 @@ func (s *DefaultStore) LoadValidators(height uint64) (*tmtypes.ValidatorSet, err
224224
if err != nil {
225225
return nil, fmt.Errorf("failed to unmarshal to protobuf: %w", err)
226226
}
227+
if len(pbValSet.Validators) == 0 {
228+
return &tmtypes.ValidatorSet{
229+
Validators: make([]*tmtypes.Validator, 0),
230+
Proposer: nil,
231+
}, nil
232+
}
227233

228234
return tmtypes.ValidatorSetFromProto(&pbValSet)
229235
}

types/validation.go

+5
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,11 @@ func (h *SignedHeader) ValidateBasic() error {
5757
return err
5858
}
5959

60+
// Handle Based Rollup case
61+
if len(h.Validators.Validators) == 0 {
62+
return nil
63+
}
64+
6065
err = h.Validators.ValidateBasic()
6166
if err != nil {
6267
return err

0 commit comments

Comments
 (0)