diff --git a/block/sequencers.go b/block/sequencers.go index 6c72d4d2..b6df0384 100644 --- a/block/sequencers.go +++ b/block/sequencers.go @@ -117,7 +117,7 @@ func (m *Manager) CompleteRotation(ctx context.Context, nextSeqAddr string) erro if seq == nil { return types.ErrMissingProposerPubKey } - copy(nextSeqHash[:], seq.Hash()) + copy(nextSeqHash[:], seq.MustHash()) } err := m.CreateAndPostLastBatch(ctx, nextSeqHash) diff --git a/block/state.go b/block/state.go index f003f525..e13d8c3b 100644 --- a/block/state.go +++ b/block/state.go @@ -161,7 +161,7 @@ func (e *Executor) UpdateProposerFromBlock(s *types.State, block *types.Block) b } localSeq := s.Sequencers.GetByConsAddress(e.localAddress) - if localSeq != nil && bytes.Equal(localSeq.Hash(), block.Header.NextSequencersHash[:]) { + if localSeq != nil && bytes.Equal(localSeq.MustHash(), block.Header.NextSequencersHash[:]) { return true } diff --git a/rpc/client/client.go b/rpc/client/client.go index a589c84d..3ff25a3f 100644 --- a/rpc/client/client.go +++ b/rpc/client/client.go @@ -514,7 +514,7 @@ func (c *Client) Validators(ctx context.Context, heightPtr *int64, pagePtr, perP } return &ctypes.ResultValidators{ BlockHeight: int64(height), - Validators: []*tmtypes.Validator{sequencers.Proposer.TMValidator()}, + Validators: sequencers.Proposer.TMValidators(), Count: 1, Total: 1, }, nil diff --git a/rpc/client/client_test.go b/rpc/client/client_test.go index aebc0957..a0d664bb 100644 --- a/rpc/client/client_test.go +++ b/rpc/client/client_test.go @@ -1,6 +1,7 @@ package client_test import ( + stdbytes "bytes" "context" crand "crypto/rand" "encoding/hex" @@ -335,6 +336,40 @@ func TestGetCommit(t *testing.T) { require.NoError(err) } +// Ensures the results of the commit and validators queries are consistent wrt. val set hash +func TestValidatorSetHashConsistency(t *testing.T) { + require := require.New(t) + assert := assert.New(t) + mockApp, rpc, node := getRPCAndNodeSequencer(t) + + mockApp.On("BeginBlock", mock.Anything).Return(abci.ResponseBeginBlock{}) + mockApp.On("Commit", mock.Anything).Return(abci.ResponseCommit{}) + mockApp.On("InitChain", mock.Anything).Return(abci.ResponseInitChain{}) + + b := getRandomBlock(1, 10) + + err := node.Start() + require.NoError(err) + + _, err = node.Store.SaveBlock(b, &types.Commit{Height: b.Header.Height}, nil) + node.BlockManager.State.SetHeight(b.Header.Height) + require.NoError(err) + + h := int64(b.Header.Height) + commit, err := rpc.Commit(context.Background(), &h) + require.NoError(err) + require.NotNil(commit) + + vals, err := rpc.Validators(context.Background(), &h, nil, nil) + require.NoError(err) + + commitValHash := commit.ValidatorsHash + valsValHash, err := tmtypes.ValidatorSetFromExistingValidators(vals.Validators) + require.NoError(err) + ok := stdbytes.Equal(commitValHash, valsValHash.Hash()) + require.True(ok) +} + func TestBlockSearch(t *testing.T) { require := require.New(t) assert := assert.New(t) diff --git a/testutil/types.go b/testutil/types.go index e019fc0b..519eee3f 100644 --- a/testutil/types.go +++ b/testutil/types.go @@ -89,7 +89,7 @@ func generateBlock(height uint64, proposerHash []byte) *types.Block { func GenerateBlocksWithTxs(startHeight uint64, num uint64, proposerKey crypto.PrivKey, nTxs int) ([]*types.Block, error) { r, _ := proposerKey.Raw() seq := types.NewSequencerFromValidator(*tmtypes.NewValidator(ed25519.PrivKey(r).PubKey(), 1)) - proposerHash := seq.Hash() + proposerHash := seq.MustHash() blocks := make([]*types.Block, num) for i := uint64(0); i < num; i++ { @@ -122,7 +122,7 @@ func GenerateBlocksWithTxs(startHeight uint64, num uint64, proposerKey crypto.Pr func GenerateBlocks(startHeight uint64, num uint64, proposerKey crypto.PrivKey) ([]*types.Block, error) { r, _ := proposerKey.Raw() seq := types.NewSequencerFromValidator(*tmtypes.NewValidator(ed25519.PrivKey(r).PubKey(), 1)) - proposerHash := seq.Hash() + proposerHash := seq.MustHash() blocks := make([]*types.Block, num) for i := uint64(0); i < num; i++ { diff --git a/types/sequencer_set.go b/types/sequencer_set.go index 5d33796b..d6bb06e2 100644 --- a/types/sequencer_set.go +++ b/types/sequencer_set.go @@ -34,10 +34,6 @@ func (s Sequencer) IsEmpty() bool { return s.val.PubKey == nil } -func (s Sequencer) TMValidator() *types.Validator { - return &s.val -} - func (s Sequencer) ConsAddress() string { return s.val.Address.String() } @@ -46,10 +42,34 @@ func (s Sequencer) PubKey() tmcrypto.PubKey { return s.val.PubKey } +func (s Sequencer) TMValidator() *types.Validator { + return &s.val +} + +func (s Sequencer) TMValidators() []*types.Validator { + return []*types.Validator{s.TMValidator()} +} + +func (s Sequencer) TMValset() (*types.ValidatorSet, error) { + return types.ValidatorSetFromExistingValidators(s.TMValidators()) +} + // Hash returns tendermint compatible hash of the sequencer -func (s Sequencer) Hash() []byte { - tempProposerSet := types.NewValidatorSet([]*types.Validator{&s.val}) - return tempProposerSet.Hash() +func (s Sequencer) Hash() ([]byte, error) { + vs, err := s.TMValset() + if err != nil { + return nil, fmt.Errorf("tm valset: %w", err) + } + return vs.Hash(), nil +} + +// MustHash returns tendermint compatible hash of the sequencer +func (s Sequencer) MustHash() []byte { + h, err := s.Hash() + if err != nil { + panic(fmt.Errorf("hash: %w", err)) + } + return h } // SequencerSet is a set of rollapp sequencers and a proposer. @@ -63,8 +83,6 @@ type SequencerSet struct { Proposer *Sequencer `json:"proposer"` } -func (s *SequencerSet) TMProposer() - func (s *SequencerSet) GetProposerPubKey() tmcrypto.PubKey { if s.Proposer == nil { return nil @@ -77,7 +95,7 @@ func (s *SequencerSet) ProposerHash() []byte { if s.Proposer == nil { return make([]byte, 0, 32) } - return s.Proposer.Hash() + return s.Proposer.MustHash() } // SetProposerByHash sets the proposer by hash. @@ -85,7 +103,7 @@ func (s *SequencerSet) ProposerHash() []byte { // Used when updating proposer from the L2 blocks (nextSequencerHash header field) func (s *SequencerSet) SetProposerByHash(hash []byte) error { for _, seq := range s.Sequencers { - if bytes.Equal(seq.Hash(), hash) { + if bytes.Equal(seq.MustHash(), hash) { s.SetProposer(&seq) return nil }