Skip to content

Commit

Permalink
header: verify NextValidatorsHash for light nodes (cosmos#844)
Browse files Browse the repository at this point in the history
Fixes: cosmos#835

---------

Co-authored-by: Ganesha Upadhyaya <[email protected]>
  • Loading branch information
tuxcanfly and Ganesha Upadhyaya authored Sep 29, 2023
1 parent 497c015 commit d9eb2da
Show file tree
Hide file tree
Showing 11 changed files with 187 additions and 94 deletions.
15 changes: 14 additions & 1 deletion block/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,11 @@ func (m *Manager) trySyncNextBlock(ctx context.Context, daHeight uint64) error {
if b != nil && commit != nil {
bHeight := uint64(b.Height())
m.logger.Info("Syncing block", "height", bHeight)
newState, responses, err := m.applyBlock(ctx, b)
// Validate the received block before applying
if err := m.executor.Validate(m.lastState, b); err != nil {
return fmt.Errorf("failed to validate block: %w", err)
}
newState, responses, err := m.executor.ApplyBlock(ctx, m.lastState, b)
if err != nil {
return fmt.Errorf("failed to ApplyBlock: %w", err)
}
Expand Down Expand Up @@ -607,6 +611,7 @@ func (m *Manager) publishBlock(ctx context.Context) error {
if err != nil {
return nil
}
block.SignedHeader.Header.NextAggregatorsHash = m.getNextAggregatorsHash()
commit, err = m.getCommit(block.SignedHeader.Header)
if err != nil {
return err
Expand Down Expand Up @@ -636,6 +641,8 @@ func (m *Manager) publishBlock(ctx context.Context) error {
return err
}

block.SignedHeader.Header.NextAggregatorsHash = newState.NextValidators.Hash()

commit, err = m.getCommit(block.SignedHeader.Header)
if err != nil {
return err
Expand Down Expand Up @@ -758,6 +765,12 @@ func (m *Manager) getLastStateValidators() *cmtypes.ValidatorSet {
return m.lastState.Validators
}

func (m *Manager) getNextAggregatorsHash() types.Hash {
m.lastStateMtx.RLock()
defer m.lastStateMtx.RUnlock()
return m.lastState.NextValidators.Hash()
}

func (m *Manager) getLastBlockTime() time.Time {
m.lastStateMtx.RLock()
defer m.lastStateMtx.RUnlock()
Expand Down
4 changes: 2 additions & 2 deletions conv/abci/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ func ToABCIHeaderPB(header *types.Header) (cmproto.Header, error) {
LastCommitHash: header.LastHeaderHash[:],
DataHash: header.DataHash[:],
ValidatorsHash: header.AggregatorsHash[:],
NextValidatorsHash: nil,
NextValidatorsHash: header.NextAggregatorsHash[:],
ConsensusHash: header.ConsensusHash[:],
AppHash: header.AppHash[:],
LastResultsHash: header.LastResultsHash[:],
Expand Down Expand Up @@ -59,7 +59,7 @@ func ToABCIHeader(header *types.Header) (cmtypes.Header, error) {
LastCommitHash: cmbytes.HexBytes(header.LastCommitHash),
DataHash: cmbytes.HexBytes(header.DataHash),
ValidatorsHash: cmbytes.HexBytes(header.AggregatorsHash),
NextValidatorsHash: nil,
NextValidatorsHash: cmbytes.HexBytes(header.NextAggregatorsHash),
ConsensusHash: cmbytes.HexBytes(header.ConsensusHash),
AppHash: cmbytes.HexBytes(header.AppHash),
LastResultsHash: cmbytes.HexBytes(header.LastResultsHash),
Expand Down
11 changes: 11 additions & 0 deletions node/full_client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -832,6 +832,15 @@ func checkValSet(rpc *FullClient, assert *assert.Assertions, h int64, expectedVa
assert.EqualValues(expectedValCount, vals.Total)
assert.Len(vals.Validators, expectedValCount)
assert.EqualValues(vals.BlockHeight, h)

commit, err := rpc.Commit(context.Background(), &h)
assert.NoError(err)
assert.NotNil(vals)

h1 := h + 1
vals, err = rpc.Validators(context.Background(), &h1, nil, nil)
assert.NoError(err)
assert.Equal(commit.NextValidatorsHash.Bytes(), cmtypes.NewValidatorSet(vals.Validators).Hash())
}

func checkValSetLatest(rpc *FullClient, assert *assert.Assertions, lastBlockHeight int64, expectedValCount int) {
Expand Down Expand Up @@ -885,6 +894,8 @@ func TestValidatorSetHandling(t *testing.T) {
checkValSet(rpc, assert, h, numNodes-1)
}

// test next val set hash in block 4, 5

// 5th EndBlock adds validator back
for h := int64(6); h <= 9; h++ {
checkValSet(rpc, assert, h, numNodes)
Expand Down
5 changes: 4 additions & 1 deletion proto/rollkit/rollkit.proto
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,11 @@ message Header {
// Hash of block aggregator set, at a time of block creation
bytes aggregators_hash = 11;

// Hash of next block aggregator set, at a time of block creation
bytes next_aggregators_hash = 12;

// Chain ID the block belongs to
string chain_id = 12;
string chain_id = 13;
}

message Commit {
Expand Down
1 change: 1 addition & 0 deletions state/executor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ func doTestCreateBlock(t *testing.T) {
},
}
state.Validators = cmtypes.NewValidatorSet(validators)
state.NextValidators = cmtypes.NewValidatorSet(validators)

// empty block
block := executor.CreateBlock(1, &types.Commit{}, []byte{}, state)
Expand Down
2 changes: 1 addition & 1 deletion types/hashing.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ func (h *Header) Hash() Hash {
LastCommitHash: cmbytes.HexBytes(h.LastCommitHash),
DataHash: cmbytes.HexBytes(h.DataHash),
ValidatorsHash: cmbytes.HexBytes(h.AggregatorsHash),
NextValidatorsHash: nil,
NextValidatorsHash: cmbytes.HexBytes(h.NextAggregatorsHash),
ConsensusHash: cmbytes.HexBytes(h.ConsensusHash),
AppHash: cmbytes.HexBytes(h.AppHash),
LastResultsHash: cmbytes.HexBytes(h.LastResultsHash),
Expand Down
32 changes: 18 additions & 14 deletions types/header.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package types

import (
"bytes"
"encoding"
"fmt"
"time"

"github.com/celestiaorg/go-header"
Expand Down Expand Up @@ -47,6 +49,9 @@ type Header struct {

// Hash of block aggregator set, at a time of block creation
AggregatorsHash Hash

// Hash of next block aggregator set, at a time of block creation
NextAggregatorsHash Hash
}

func (h *Header) New() *Header {
Expand Down Expand Up @@ -74,20 +79,19 @@ func (h *Header) Time() time.Time {
return time.Unix(0, int64(h.BaseHeader.Time))
}

func (h *Header) Verify(_ *Header) error {

// Check the validator hashes are the same in the case headers are adjacent
// TODO: next validator set is not available, disable this check until NextValidatorHash is enabled
// if untrstH.Height() == h.Height()+1 {
// if !bytes.Equal(untrstH.AggregatorsHash[:], h.AggregatorsHash[:]) {
// return &header.VerifyError{
// Reason: fmt.Errorf("expected old header next validators (%X) to match those from new header (%X)",
// h.AggregatorsHash,
// untrstH.AggregatorsHash,
// ),
// }
// }
// }
func (h *Header) Verify(untrstH *Header) error {
// perform actual verification
if untrstH.Height() == h.Height()+1 {
// Check the validator hashes are the same in the case headers are adjacent
if !bytes.Equal(untrstH.AggregatorsHash[:], h.NextAggregatorsHash[:]) {
return &header.VerifyError{
Reason: fmt.Errorf("expected old header validators (%X) to match those from new header (%X)",
h.NextAggregatorsHash,
untrstH.AggregatorsHash,
),
}
}
}

// TODO: There must be a way to verify non-adjacent headers
// Ensure that untrusted commit has enough of trusted commit's power.
Expand Down
138 changes: 97 additions & 41 deletions types/pb/rollkit/rollkit.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

24 changes: 13 additions & 11 deletions types/serialization.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,17 +139,18 @@ func (h *Header) ToProto() *pb.Header {
Block: h.Version.Block,
App: h.Version.App,
},
Height: h.BaseHeader.Height,
Time: h.BaseHeader.Time,
LastHeaderHash: h.LastHeaderHash[:],
LastCommitHash: h.LastCommitHash[:],
DataHash: h.DataHash[:],
ConsensusHash: h.ConsensusHash[:],
AppHash: h.AppHash[:],
LastResultsHash: h.LastResultsHash[:],
ProposerAddress: h.ProposerAddress[:],
AggregatorsHash: h.AggregatorsHash[:],
ChainId: h.BaseHeader.ChainID,
Height: h.BaseHeader.Height,
Time: h.BaseHeader.Time,
LastHeaderHash: h.LastHeaderHash[:],
LastCommitHash: h.LastCommitHash[:],
DataHash: h.DataHash[:],
ConsensusHash: h.ConsensusHash[:],
AppHash: h.AppHash[:],
LastResultsHash: h.LastResultsHash[:],
ProposerAddress: h.ProposerAddress[:],
AggregatorsHash: h.AggregatorsHash[:],
NextAggregatorsHash: h.NextAggregatorsHash[:],
ChainId: h.BaseHeader.ChainID,
}
}

Expand All @@ -167,6 +168,7 @@ func (h *Header) FromProto(other *pb.Header) error {
h.AppHash = other.AppHash
h.LastResultsHash = other.LastResultsHash
h.AggregatorsHash = other.AggregatorsHash
h.NextAggregatorsHash = other.NextAggregatorsHash
if len(other.ProposerAddress) > 0 {
h.ProposerAddress = make([]byte, len(other.ProposerAddress))
copy(h.ProposerAddress, other.ProposerAddress)
Expand Down
Loading

0 comments on commit d9eb2da

Please sign in to comment.