From 57bc89e2f665bfe9ecf5885e7e7c9ffd57c88972 Mon Sep 17 00:00:00 2001 From: Daniel T <30197399+danwt@users.noreply.github.com> Date: Tue, 22 Oct 2024 10:52:44 +0100 Subject: [PATCH] fix(validator set): use comet compatible API for validators set wrt hash (#1159) --- block/initchain.go | 5 +---- block/sequencers.go | 2 +- block/state.go | 2 +- rpc/client/client.go | 26 +++------------------- rpc/client/client_test.go | 45 +++++++++++++++++++++++++++++++++++++++ testutil/types.go | 4 ++-- types/sequencer_set.go | 38 +++++++++++++++++++++++++-------- 7 files changed, 82 insertions(+), 40 deletions(-) diff --git a/block/initchain.go b/block/initchain.go index 224ae8cf1..db65485df 100644 --- a/block/initchain.go +++ b/block/initchain.go @@ -13,10 +13,7 @@ func (m *Manager) RunInitChain(ctx context.Context) error { if proposer == nil { return errors.New("failed to get proposer") } - tmProposer, err := proposer.TMValidator() - if err != nil { - return err - } + tmProposer := proposer.TMValidator() res, err := m.Executor.InitChain(m.Genesis, []*tmtypes.Validator{tmProposer}) if err != nil { return err diff --git a/block/sequencers.go b/block/sequencers.go index 6c72d4d22..b6df0384f 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 f003f525c..e13d8c3bc 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 6fa48a6bb..3ff25a3f4 100644 --- a/rpc/client/client.go +++ b/rpc/client/client.go @@ -512,31 +512,11 @@ func (c *Client) Validators(ctx context.Context, heightPtr *int64, pagePtr, perP if err != nil { return nil, fmt.Errorf("load validators for height %d: %w", height, err) } - - totalCount := len(sequencers.Sequencers) - perPage := validatePerPage(perPagePtr) - page, err := validatePage(pagePtr, perPage, totalCount) - if err != nil { - return nil, err - } - - skipCount := validateSkipCount(page, perPage) - - var vals []*tmtypes.Validator - for _, s := range sequencers.Sequencers { - val, err := s.TMValidator() - if err != nil { - return nil, fmt.Errorf("convert sequencer to validator: %s :%w", s.SettlementAddress, err) - } - vals = append(vals, val) - } - - v := vals[skipCount : skipCount+tmmath.MinInt(perPage, totalCount-skipCount)] return &ctypes.ResultValidators{ BlockHeight: int64(height), - Validators: v, - Count: len(v), - Total: totalCount, + Validators: sequencers.Proposer.TMValidators(), + Count: 1, + Total: 1, }, nil } diff --git a/rpc/client/client_test.go b/rpc/client/client_test.go index aebc0957d..c8ad73372 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,50 @@ 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) + mockApp, rpc, node := getRPCAndNode(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{}) + + v := tmtypes.NewValidator(ed25519.GenPrivKey().PubKey(), 1) + s := types.NewSequencerFromValidator(*v) + node.BlockManager.State.Sequencers.SetProposer(s) + + b := getRandomBlock(1, 10) + copy(b.Header.SequencerHash[:], node.BlockManager.State.Sequencers.ProposerHash()) + + 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) + + batch := node.Store.NewBatch() + batch, err = node.Store.SaveSequencers(b.Header.Height, &node.BlockManager.State.Sequencers, batch) + require.NoError(err) + err = batch.Commit() + 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) + + valsRes, err := tmtypes.ValidatorSetFromExistingValidators(vals.Validators) + require.NoError(err) + hash := valsRes.Hash() + ok := stdbytes.Equal(commit.ValidatorsHash, 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 e019fc0bc..519eee3f7 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 45ab8447b..d6bb06e26 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, error) { - return &s.val, nil -} - 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. @@ -75,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. @@ -83,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 }