Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(lib/grandpa): verify GRANDPA justification before applying the block #4144

Merged
merged 6 commits into from
Sep 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion dot/mock_node_builder_test.go

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

2 changes: 1 addition & 1 deletion dot/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ type nodeBuilderIface interface {
) (*core.Service, error)
createGRANDPAService(config *cfg.Config, st *state.Service, ks KeyStore,
net *network.Service, telemetryMailer Telemetry) (*grandpa.Service, error)
newSyncService(config *cfg.Config, st *state.Service, finalityGadget BlockJustificationVerifier,
newSyncService(config *cfg.Config, st *state.Service, finalityGadget dotsync.FinalityGadget,
verifier *babe.VerificationManager, cs *core.Service, net *network.Service,
telemetryMailer Telemetry) (*dotsync.Service, error)
createBABEService(config *cfg.Config, st *state.Service, ks KeyStore, cs *core.Service,
Expand Down
2 changes: 1 addition & 1 deletion dot/services.go
Original file line number Diff line number Diff line change
Expand Up @@ -497,7 +497,7 @@ func (nodeBuilder) createBlockVerifier(st *state.Service) *babe.VerificationMana
return babe.NewVerificationManager(st.Block, st.Slot, st.Epoch)
}

func (nodeBuilder) newSyncService(config *cfg.Config, st *state.Service, fg BlockJustificationVerifier,
func (nodeBuilder) newSyncService(config *cfg.Config, st *state.Service, fg sync.FinalityGadget,
verifier *babe.VerificationManager, cs *core.Service, net *network.Service, telemetryMailer Telemetry) (
*sync.Service, error) {
slotDuration, err := st.Epoch.GetSlotDuration()
Expand Down
3 changes: 2 additions & 1 deletion dot/services_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"github.com/ChainSafe/gossamer/dot/network"
rpc "github.com/ChainSafe/gossamer/dot/rpc"
"github.com/ChainSafe/gossamer/dot/state"
"github.com/ChainSafe/gossamer/dot/sync"
"github.com/ChainSafe/gossamer/dot/telemetry"
"github.com/ChainSafe/gossamer/dot/types"
"github.com/ChainSafe/gossamer/internal/log"
Expand Down Expand Up @@ -373,7 +374,7 @@ func Test_nodeBuilder_newSyncService(t *testing.T) {
require.NoError(t, err)

type args struct {
fg BlockJustificationVerifier
fg sync.FinalityGadget
verifier *babe.VerificationManager
cs *core.Service
net *network.Service
Expand Down
43 changes: 25 additions & 18 deletions dot/sync/chain_sync.go
Original file line number Diff line number Diff line change
Expand Up @@ -843,18 +843,40 @@ func (cs *chainSync) processBlockData(blockData types.BlockData, origin blockOri
announceImportedBlock := cs.getSyncMode() == tip

if blockData.Header != nil {
var (
hasJustification = blockData.Justification != nil && len(*blockData.Justification) > 0
round uint64
setID uint64
)

if hasJustification {
var err error
round, setID, err = cs.finalityGadget.VerifyBlockJustification(
blockData.Header.Hash(), blockData.Header.Number, *blockData.Justification)
if err != nil {
return fmt.Errorf("verifying justification: %w", err)
}
}

if blockData.Body != nil {
err := cs.processBlockDataWithHeaderAndBody(blockData, origin, announceImportedBlock)
if err != nil {
return fmt.Errorf("processing block data with header and body: %w", err)
}
}

if blockData.Justification != nil && len(*blockData.Justification) > 0 {
err := cs.handleJustification(blockData.Header, *blockData.Justification)
if hasJustification {
header := blockData.Header
err := cs.blockState.SetFinalisedHash(header.Hash(), round, setID)
if err != nil {
return fmt.Errorf("handling justification: %w", err)
return fmt.Errorf("setting finalised hash: %w", err)
}
err = cs.blockState.SetJustification(header.Hash(), *blockData.Justification)
if err != nil {
return fmt.Errorf("setting justification for block number %d: %w", header.Number, err)
}

return nil
}
}

Expand Down Expand Up @@ -902,21 +924,6 @@ func (cs *chainSync) handleBody(body *types.Body) {
blockSizeGauge.Set(float64(acc))
}

func (cs *chainSync) handleJustification(header *types.Header, justification []byte) (err error) {
headerHash := header.Hash()
err = cs.finalityGadget.VerifyBlockJustification(headerHash, justification)
if err != nil {
return fmt.Errorf("verifying block number %d justification: %w", header.Number, err)
}

err = cs.blockState.SetJustification(headerHash, justification)
if err != nil {
return fmt.Errorf("setting justification for block number %d: %w", header.Number, err)
}

return nil
}

// handleHeader handles blocks (header+body) included in BlockResponses
func (cs *chainSync) handleBlock(block *types.Block, announceImportedBlock bool) error {
parent, err := cs.blockState.GetHeader(block.Header.ParentHash)
Expand Down
1 change: 1 addition & 0 deletions dot/sync/chain_sync_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1851,6 +1851,7 @@ func TestChainSync_BootstrapSync_SuccessfulSync_WithInvalidJusticationBlock(t *t
mockFinalityGadget.EXPECT().
VerifyBlockJustification(
invalidJustificationBlock.Header.Hash(),
invalidJustificationBlock.Header.Number,
*invalidJustification).
Return(uint64(0), uint64(0), errVerifyBlockJustification)

Expand Down
4 changes: 3 additions & 1 deletion dot/sync/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ type BlockState interface {
GetReceipt(common.Hash) ([]byte, error)
GetMessageQueue(common.Hash) ([]byte, error)
GetJustification(common.Hash) ([]byte, error)
SetFinalisedHash(hash common.Hash, round uint64, setID uint64) error
SetJustification(hash common.Hash, data []byte) error
GetHashByNumber(blockNumber uint) (common.Hash, error)
GetBlockByHash(common.Hash) (*types.Block, error)
Expand Down Expand Up @@ -61,7 +62,8 @@ type BabeVerifier interface {

// FinalityGadget implements justification verification functionality
type FinalityGadget interface {
VerifyBlockJustification(common.Hash, []byte) error
VerifyBlockJustification(finalizedHash common.Hash, finalizedNumber uint, encoded []byte) (
round uint64, setID uint64, err error)
}

// BlockImportHandler is the interface for the handler of newly imported blocks
Expand Down
28 changes: 22 additions & 6 deletions dot/sync/mocks_test.go

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

7 changes: 4 additions & 3 deletions dot/sync/syncer_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,9 +113,10 @@ func newTestSyncer(t *testing.T) *Service {
cfg.LogLvl = log.Trace
mockFinalityGadget := NewMockFinalityGadget(ctrl)
mockFinalityGadget.EXPECT().VerifyBlockJustification(gomock.AssignableToTypeOf(common.Hash{}),
gomock.AssignableToTypeOf([]byte{})).DoAndReturn(func(hash common.Hash, justification []byte) error {
return nil
}).AnyTimes()
gomock.AssignableToTypeOf(uint(0)), gomock.AssignableToTypeOf([]byte{})).
DoAndReturn(func(hash common.Hash, justification []byte) error {
return nil
}).AnyTimes()

cfg.FinalityGadget = mockFinalityGadget
cfg.Network = NewMockNetwork(ctrl)
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ require (
github.com/stretchr/testify v1.9.0
github.com/tetratelabs/wazero v1.1.0
github.com/tidwall/btree v1.7.0
github.com/tyler-smith/go-bip39 v1.1.0
go.uber.org/mock v0.4.0
golang.org/x/crypto v0.26.0
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -665,6 +665,8 @@ github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+F
github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY=
github.com/tomasen/realip v0.0.0-20180522021738-f0c99a92ddce h1:fb190+cK2Xz/dvi9Hv8eCYJYvIGUTN2/KLq1pT6CjEc=
github.com/tomasen/realip v0.0.0-20180522021738-f0c99a92ddce/go.mod h1:o8v6yHRoik09Xen7gje4m9ERNah1d1PPsVq1VEx9vE4=
github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8=
github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U=
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/urfave/cli v1.22.10/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
Expand Down
10 changes: 10 additions & 0 deletions internal/client/consensus/grandpa/authorities.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Copyright 2023 ChainSafe Systems (ON)
// SPDX-License-Identifier: LGPL-3.0-only

package grandpa

// generic representation of hash and number tuple
type HashNumber[H, N any] struct {
Hash H
Number N
}
Loading
Loading