From 7294e7d97677ec6d5048c6d2b36a620232ea2244 Mon Sep 17 00:00:00 2001 From: Diego Date: Thu, 5 Dec 2024 18:38:45 +0900 Subject: [PATCH] Move types to warpsync package --- dot/network/messages/warp_sync.go | 36 ---- dot/network/messages/warp_sync_test.go | 43 ----- dot/network/mock_warp_sync_provider_test.go | 5 +- dot/network/warp_sync.go | 11 +- dot/services.go | 5 +- dot/sync/mocks_test.go | 5 +- dot/sync/warp_sync.go | 15 +- dot/sync/warp_sync_test.go | 3 +- lib/grandpa/warpsync/mocks_generate_test.go | 6 + lib/grandpa/warpsync/mocks_test.go | 169 ++++++++++++++++++ .../warpsync}/testdata/warp_sync_proofs.yaml | 0 lib/grandpa/{ => warpsync}/warp_sync.go | 50 +++++- lib/grandpa/{ => warpsync}/warp_sync_test.go | 33 +++- 13 files changed, 274 insertions(+), 107 deletions(-) delete mode 100644 dot/network/messages/warp_sync_test.go create mode 100644 lib/grandpa/warpsync/mocks_generate_test.go create mode 100644 lib/grandpa/warpsync/mocks_test.go rename {dot/network/messages => lib/grandpa/warpsync}/testdata/warp_sync_proofs.yaml (100%) rename lib/grandpa/{ => warpsync}/warp_sync.go (89%) rename lib/grandpa/{ => warpsync}/warp_sync_test.go (92%) diff --git a/dot/network/messages/warp_sync.go b/dot/network/messages/warp_sync.go index 294ef8f194..4307161fb0 100644 --- a/dot/network/messages/warp_sync.go +++ b/dot/network/messages/warp_sync.go @@ -6,9 +6,6 @@ package messages import ( "fmt" - "github.com/ChainSafe/gossamer/dot/types" - "github.com/ChainSafe/gossamer/internal/client/consensus/grandpa" - "github.com/ChainSafe/gossamer/internal/primitives/core/hash" "github.com/ChainSafe/gossamer/lib/common" "github.com/ChainSafe/gossamer/pkg/scale" ) @@ -46,37 +43,4 @@ func (wpr *WarpProofRequest) String() string { return fmt.Sprintf("WarpProofRequest begin=%v", wpr.Begin) } -type WarpSyncFragment struct { - Header types.Header - Justification grandpa.GrandpaJustification[hash.H256, uint32] -} - -type WarpSyncProof struct { - Proofs []WarpSyncFragment - // indicates whether the warp sync has been completed - IsFinished bool - proofsLength int -} - -func (wsp *WarpSyncProof) Decode(in []byte) error { - return scale.Unmarshal(in, wsp) -} - -func (wsp *WarpSyncProof) Encode() ([]byte, error) { - if wsp == nil { - return nil, fmt.Errorf("cannot encode nil WarpSyncProof") - } - return scale.Marshal(*wsp) -} - -func (wsp *WarpSyncProof) String() string { - if wsp == nil { - return "WarpSyncProof=nil" - } - - return fmt.Sprintf("WarpSyncProof proofs=%v isFinished=%v proofsLength=%v", - wsp.Proofs, wsp.IsFinished, wsp.proofsLength) -} - -var _ P2PMessage = (*WarpSyncProof)(nil) var _ P2PMessage = (*WarpProofRequest)(nil) diff --git a/dot/network/messages/warp_sync_test.go b/dot/network/messages/warp_sync_test.go deleted file mode 100644 index 744b8702f5..0000000000 --- a/dot/network/messages/warp_sync_test.go +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2024 ChainSafe Systems (ON) -// SPDX-License-Identifier: LGPL-3.0-only - -package messages - -import ( - "log" - "testing" - - _ "embed" - - "github.com/ChainSafe/gossamer/lib/common" - "github.com/stretchr/testify/require" - "gopkg.in/yaml.v3" -) - -//go:embed testdata/warp_sync_proofs.yaml -var rawWarpSyncProofs []byte - -type WarpSyncProofs struct { - SubstrateWarpSyncProof1 string `yaml:"substrate_warp_sync_proof_1"` -} - -func TestDecodeWarpSyncProof(t *testing.T) { - warpSyncProofs := &WarpSyncProofs{} - err := yaml.Unmarshal(rawWarpSyncProofs, warpSyncProofs) - require.NoError(t, err) - - // Generated using substrate - expected := common.MustHexToBytes(warpSyncProofs.SubstrateWarpSyncProof1) - if err != nil { - log.Fatal(err) - } - - var proof WarpSyncProof - - err = proof.Decode(expected) - require.NoError(t, err) - - encoded, err := proof.Encode() - require.NoError(t, err) - require.Equal(t, expected, encoded) -} diff --git a/dot/network/mock_warp_sync_provider_test.go b/dot/network/mock_warp_sync_provider_test.go index 04280930e7..4425377b94 100644 --- a/dot/network/mock_warp_sync_provider_test.go +++ b/dot/network/mock_warp_sync_provider_test.go @@ -14,6 +14,7 @@ import ( grandpa "github.com/ChainSafe/gossamer/internal/primitives/consensus/grandpa" common "github.com/ChainSafe/gossamer/lib/common" + warpsync "github.com/ChainSafe/gossamer/lib/grandpa/warpsync" gomock "go.uber.org/mock/gomock" ) @@ -56,10 +57,10 @@ func (mr *MockWarpSyncProviderMockRecorder) Generate(arg0 any) *gomock.Call { } // Verify mocks base method. -func (m *MockWarpSyncProvider) Verify(arg0 []byte, arg1 grandpa.SetID, arg2 grandpa.AuthorityList) (*WarpSyncVerificationResult, error) { +func (m *MockWarpSyncProvider) Verify(arg0 []byte, arg1 grandpa.SetID, arg2 grandpa.AuthorityList) (*warpsync.WarpSyncVerificationResult, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Verify", arg0, arg1, arg2) - ret0, _ := ret[0].(*WarpSyncVerificationResult) + ret0, _ := ret[0].(*warpsync.WarpSyncVerificationResult) ret1, _ := ret[1].(error) return ret0, ret1 } diff --git a/dot/network/warp_sync.go b/dot/network/warp_sync.go index 5e5e7b85b5..c72c8333ea 100644 --- a/dot/network/warp_sync.go +++ b/dot/network/warp_sync.go @@ -8,23 +8,16 @@ import ( "fmt" "github.com/ChainSafe/gossamer/dot/network/messages" - "github.com/ChainSafe/gossamer/dot/types" "github.com/ChainSafe/gossamer/internal/primitives/consensus/grandpa" primitives "github.com/ChainSafe/gossamer/internal/primitives/consensus/grandpa" "github.com/ChainSafe/gossamer/lib/common" + "github.com/ChainSafe/gossamer/lib/grandpa/warpsync" libp2pnetwork "github.com/libp2p/go-libp2p/core/network" "github.com/libp2p/go-libp2p/core/peer" ) const MaxAllowedSameRequestPerPeer = 5 -type WarpSyncVerificationResult struct { - SetId grandpa.SetID - AuthorityList primitives.AuthorityList - Header types.Header - Completed bool -} - // WarpSyncProvider is an interface for generating warp sync proofs type WarpSyncProvider interface { // Generate proof starting at given block hash. The proof is accumulated until maximum proof @@ -34,7 +27,7 @@ type WarpSyncProvider interface { encodedProof []byte, setId grandpa.SetID, authorities primitives.AuthorityList, - ) (*WarpSyncVerificationResult, error) + ) (*warpsync.WarpSyncVerificationResult, error) } func (s *Service) handleWarpSyncRequest(req messages.WarpProofRequest) ([]byte, error) { diff --git a/dot/services.go b/dot/services.go index a75f50b0f1..4ea2392f8e 100644 --- a/dot/services.go +++ b/dot/services.go @@ -31,6 +31,7 @@ import ( "github.com/ChainSafe/gossamer/lib/crypto/sr25519" "github.com/ChainSafe/gossamer/lib/genesis" "github.com/ChainSafe/gossamer/lib/grandpa" + "github.com/ChainSafe/gossamer/lib/grandpa/warpsync" "github.com/ChainSafe/gossamer/lib/keystore" "github.com/ChainSafe/gossamer/lib/runtime" rtstorage "github.com/ChainSafe/gossamer/lib/runtime/storage" @@ -349,7 +350,7 @@ func (nodeBuilder) createNetworkService(config *cfg.Config, stateSrvc *state.Ser return nil, fmt.Errorf("failed to parse network log level: %w", err) } - warpSyncProvider := grandpa.NewWarpSyncProofProvider( + warpSyncProvider := warpsync.NewWarpSyncProofProvider( stateSrvc.Block, stateSrvc.Grandpa, ) @@ -524,7 +525,7 @@ func (nodeBuilder) newSyncService(config *cfg.Config, st *state.Service, fg sync var warpSyncStrategy sync.Strategy if config.Core.Sync == "warp" { - warpSyncProvider := grandpa.NewWarpSyncProofProvider(st.Block, st.Grandpa) + warpSyncProvider := warpsync.NewWarpSyncProofProvider(st.Block, st.Grandpa) warpSyncCfg := &sync.WarpSyncConfig{ Telemetry: telemetryMailer, diff --git a/dot/sync/mocks_test.go b/dot/sync/mocks_test.go index 228f23533e..88b694a70d 100644 --- a/dot/sync/mocks_test.go +++ b/dot/sync/mocks_test.go @@ -19,6 +19,7 @@ import ( types "github.com/ChainSafe/gossamer/dot/types" grandpa "github.com/ChainSafe/gossamer/internal/primitives/consensus/grandpa" common "github.com/ChainSafe/gossamer/lib/common" + warpsync "github.com/ChainSafe/gossamer/lib/grandpa/warpsync" runtime "github.com/ChainSafe/gossamer/lib/runtime" storage "github.com/ChainSafe/gossamer/lib/runtime/storage" peer "github.com/libp2p/go-libp2p/core/peer" @@ -772,10 +773,10 @@ func (mr *MockWarpSyncProofProviderMockRecorder) CurrentAuthorities() *gomock.Ca } // Verify mocks base method. -func (m *MockWarpSyncProofProvider) Verify(arg0 []byte, arg1 grandpa.SetID, arg2 grandpa.AuthorityList) (*network.WarpSyncVerificationResult, error) { +func (m *MockWarpSyncProofProvider) Verify(arg0 []byte, arg1 grandpa.SetID, arg2 grandpa.AuthorityList) (*warpsync.WarpSyncVerificationResult, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Verify", arg0, arg1, arg2) - ret0, _ := ret[0].(*network.WarpSyncVerificationResult) + ret0, _ := ret[0].(*warpsync.WarpSyncVerificationResult) ret1, _ := ret[1].(error) return ret0, ret1 } diff --git a/dot/sync/warp_sync.go b/dot/sync/warp_sync.go index 30de7ddaf6..96a18e7667 100644 --- a/dot/sync/warp_sync.go +++ b/dot/sync/warp_sync.go @@ -13,6 +13,7 @@ import ( "github.com/ChainSafe/gossamer/dot/peerset" "github.com/ChainSafe/gossamer/dot/types" primitives "github.com/ChainSafe/gossamer/internal/primitives/consensus/grandpa" + "github.com/ChainSafe/gossamer/lib/grandpa/warpsync" "github.com/libp2p/go-libp2p/core/peer" ) @@ -27,7 +28,7 @@ const ( type WarpSyncProofProvider interface { CurrentAuthorities() (primitives.AuthorityList, error) Verify(encodedProof []byte, setId primitives.SetID, authorities primitives.AuthorityList) ( - *network.WarpSyncVerificationResult, error) + *warpsync.WarpSyncVerificationResult, error) } type WarpSyncStrategy struct { @@ -141,7 +142,7 @@ func (w *WarpSyncStrategy) NextActions() ([]*SyncTask, error) { case WarpProof: task = SyncTask{ request: messages.NewWarpProofRequest(lastBlock.Hash()), - response: &messages.WarpSyncProof{}, + response: &warpsync.WarpSyncProof{}, requestMaker: w.warpSyncReqMaker, } case TargetBlock: @@ -172,7 +173,7 @@ func (w *WarpSyncStrategy) Process(results []*SyncTaskResult) ( case WarpProof: logger.Debug("processing warp sync proof results") - var warpProofResult *network.WarpSyncVerificationResult + var warpProofResult *warpsync.WarpSyncVerificationResult repChanges, bans, warpProofResult = w.validateWarpSyncResults(results) @@ -208,16 +209,16 @@ func (w *WarpSyncStrategy) Process(results []*SyncTaskResult) ( } func (w *WarpSyncStrategy) validateWarpSyncResults(results []*SyncTaskResult) ( - repChanges []Change, peersToBlock []peer.ID, result *network.WarpSyncVerificationResult) { + repChanges []Change, peersToBlock []peer.ID, result *warpsync.WarpSyncVerificationResult) { repChanges = make([]Change, 0) peersToBlock = make([]peer.ID, 0) - bestProof := &messages.WarpSyncProof{} - var bestResult *network.WarpSyncVerificationResult + bestProof := &warpsync.WarpSyncProof{} + var bestResult *warpsync.WarpSyncVerificationResult for _, result := range results { switch response := result.response.(type) { - case *messages.WarpSyncProof: + case *warpsync.WarpSyncProof: if !result.completed { continue } diff --git a/dot/sync/warp_sync_test.go b/dot/sync/warp_sync_test.go index 1d55d34aac..e3d704a11b 100644 --- a/dot/sync/warp_sync_test.go +++ b/dot/sync/warp_sync_test.go @@ -11,6 +11,7 @@ import ( "github.com/ChainSafe/gossamer/dot/peerset" "github.com/ChainSafe/gossamer/dot/types" "github.com/ChainSafe/gossamer/lib/common" + "github.com/ChainSafe/gossamer/lib/grandpa/warpsync" "github.com/libp2p/go-libp2p/core/peer" "github.com/stretchr/testify/require" "go.uber.org/mock/gomock" @@ -143,7 +144,7 @@ func TestWarpSyncNextActions(t *testing.T) { "warp_sync_phase": { phase: WarpProof, expectedRequestType: &messages.WarpProofRequest{}, - expectedResponseType: &messages.WarpSyncProof{}, + expectedResponseType: &warpsync.WarpSyncProof{}, }, "target_block_phase": { phase: TargetBlock, diff --git a/lib/grandpa/warpsync/mocks_generate_test.go b/lib/grandpa/warpsync/mocks_generate_test.go new file mode 100644 index 0000000000..82185f8d08 --- /dev/null +++ b/lib/grandpa/warpsync/mocks_generate_test.go @@ -0,0 +1,6 @@ +// Copyright 2021 ChainSafe Systems (ON) +// SPDX-License-Identifier: LGPL-3.0-only + +package warpsync + +//go:generate mockgen -destination=mocks_test.go -package $GOPACKAGE . BlockState,GrandpaState diff --git a/lib/grandpa/warpsync/mocks_test.go b/lib/grandpa/warpsync/mocks_test.go new file mode 100644 index 0000000000..5d3ed95394 --- /dev/null +++ b/lib/grandpa/warpsync/mocks_test.go @@ -0,0 +1,169 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/ChainSafe/gossamer/lib/grandpa/warpsync (interfaces: BlockState,GrandpaState) +// +// Generated by this command: +// +// mockgen -destination=mocks_test.go -package warpsync . BlockState,GrandpaState +// + +// Package warpsync is a generated GoMock package. +package warpsync + +import ( + reflect "reflect" + + types "github.com/ChainSafe/gossamer/dot/types" + common "github.com/ChainSafe/gossamer/lib/common" + gomock "go.uber.org/mock/gomock" +) + +// MockBlockState is a mock of BlockState interface. +type MockBlockState struct { + ctrl *gomock.Controller + recorder *MockBlockStateMockRecorder +} + +// MockBlockStateMockRecorder is the mock recorder for MockBlockState. +type MockBlockStateMockRecorder struct { + mock *MockBlockState +} + +// NewMockBlockState creates a new mock instance. +func NewMockBlockState(ctrl *gomock.Controller) *MockBlockState { + mock := &MockBlockState{ctrl: ctrl} + mock.recorder = &MockBlockStateMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockBlockState) EXPECT() *MockBlockStateMockRecorder { + return m.recorder +} + +// GetHeader mocks base method. +func (m *MockBlockState) GetHeader(arg0 common.Hash) (*types.Header, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetHeader", arg0) + ret0, _ := ret[0].(*types.Header) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetHeader indicates an expected call of GetHeader. +func (mr *MockBlockStateMockRecorder) GetHeader(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetHeader", reflect.TypeOf((*MockBlockState)(nil).GetHeader), arg0) +} + +// GetHeaderByNumber mocks base method. +func (m *MockBlockState) GetHeaderByNumber(arg0 uint) (*types.Header, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetHeaderByNumber", arg0) + ret0, _ := ret[0].(*types.Header) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetHeaderByNumber indicates an expected call of GetHeaderByNumber. +func (mr *MockBlockStateMockRecorder) GetHeaderByNumber(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetHeaderByNumber", reflect.TypeOf((*MockBlockState)(nil).GetHeaderByNumber), arg0) +} + +// GetHighestFinalisedHeader mocks base method. +func (m *MockBlockState) GetHighestFinalisedHeader() (*types.Header, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetHighestFinalisedHeader") + ret0, _ := ret[0].(*types.Header) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetHighestFinalisedHeader indicates an expected call of GetHighestFinalisedHeader. +func (mr *MockBlockStateMockRecorder) GetHighestFinalisedHeader() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetHighestFinalisedHeader", reflect.TypeOf((*MockBlockState)(nil).GetHighestFinalisedHeader)) +} + +// GetJustification mocks base method. +func (m *MockBlockState) GetJustification(arg0 common.Hash) ([]byte, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetJustification", arg0) + ret0, _ := ret[0].([]byte) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetJustification indicates an expected call of GetJustification. +func (mr *MockBlockStateMockRecorder) GetJustification(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetJustification", reflect.TypeOf((*MockBlockState)(nil).GetJustification), arg0) +} + +// MockGrandpaState is a mock of GrandpaState interface. +type MockGrandpaState struct { + ctrl *gomock.Controller + recorder *MockGrandpaStateMockRecorder +} + +// MockGrandpaStateMockRecorder is the mock recorder for MockGrandpaState. +type MockGrandpaStateMockRecorder struct { + mock *MockGrandpaState +} + +// NewMockGrandpaState creates a new mock instance. +func NewMockGrandpaState(ctrl *gomock.Controller) *MockGrandpaState { + mock := &MockGrandpaState{ctrl: ctrl} + mock.recorder = &MockGrandpaStateMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockGrandpaState) EXPECT() *MockGrandpaStateMockRecorder { + return m.recorder +} + +// GetAuthorities mocks base method. +func (m *MockGrandpaState) GetAuthorities(arg0 uint64) ([]types.GrandpaVoter, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetAuthorities", arg0) + ret0, _ := ret[0].([]types.GrandpaVoter) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetAuthorities indicates an expected call of GetAuthorities. +func (mr *MockGrandpaStateMockRecorder) GetAuthorities(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAuthorities", reflect.TypeOf((*MockGrandpaState)(nil).GetAuthorities), arg0) +} + +// GetAuthoritiesChangesFromBlock mocks base method. +func (m *MockGrandpaState) GetAuthoritiesChangesFromBlock(arg0 uint) ([]uint, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetAuthoritiesChangesFromBlock", arg0) + ret0, _ := ret[0].([]uint) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetAuthoritiesChangesFromBlock indicates an expected call of GetAuthoritiesChangesFromBlock. +func (mr *MockGrandpaStateMockRecorder) GetAuthoritiesChangesFromBlock(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAuthoritiesChangesFromBlock", reflect.TypeOf((*MockGrandpaState)(nil).GetAuthoritiesChangesFromBlock), arg0) +} + +// GetCurrentSetID mocks base method. +func (m *MockGrandpaState) GetCurrentSetID() (uint64, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetCurrentSetID") + ret0, _ := ret[0].(uint64) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetCurrentSetID indicates an expected call of GetCurrentSetID. +func (mr *MockGrandpaStateMockRecorder) GetCurrentSetID() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCurrentSetID", reflect.TypeOf((*MockGrandpaState)(nil).GetCurrentSetID)) +} diff --git a/dot/network/messages/testdata/warp_sync_proofs.yaml b/lib/grandpa/warpsync/testdata/warp_sync_proofs.yaml similarity index 100% rename from dot/network/messages/testdata/warp_sync_proofs.yaml rename to lib/grandpa/warpsync/testdata/warp_sync_proofs.yaml diff --git a/lib/grandpa/warp_sync.go b/lib/grandpa/warpsync/warp_sync.go similarity index 89% rename from lib/grandpa/warp_sync.go rename to lib/grandpa/warpsync/warp_sync.go index 41c940b2a8..af1ae99739 100644 --- a/lib/grandpa/warp_sync.go +++ b/lib/grandpa/warpsync/warp_sync.go @@ -1,15 +1,15 @@ // Copyright 2024 ChainSafe Systems (ON) // SPDX-License-Identifier: LGPL-3.0-only -package grandpa +package warpsync import ( "bytes" "fmt" - "github.com/ChainSafe/gossamer/dot/network" "github.com/ChainSafe/gossamer/dot/types" consensus_grandpa "github.com/ChainSafe/gossamer/internal/client/consensus/grandpa" + "github.com/ChainSafe/gossamer/internal/log" "github.com/ChainSafe/gossamer/internal/primitives/consensus/grandpa" primitives "github.com/ChainSafe/gossamer/internal/primitives/consensus/grandpa" "github.com/ChainSafe/gossamer/internal/primitives/consensus/grandpa/app" @@ -23,10 +23,32 @@ import ( const MaxWarpSyncProofSize = 8 * 1024 * 1024 var ( + logger = log.NewFromGlobal(log.AddContext("pkg", "warpsync")) + errMissingStartBlock = fmt.Errorf("missing start block") errStartBlockNotFinalized = fmt.Errorf("start block is not finalized") ) +type BlockState interface { + GetHeader(common.Hash) (*types.Header, error) + GetHeaderByNumber(uint) (*types.Header, error) + GetJustification(common.Hash) ([]byte, error) + GetHighestFinalisedHeader() (*types.Header, error) +} + +type GrandpaState interface { + GetCurrentSetID() (uint64, error) + GetAuthorities(uint64) ([]types.GrandpaVoter, error) + GetAuthoritiesChangesFromBlock(uint) ([]uint, error) +} + +type WarpSyncVerificationResult struct { + SetId grandpa.SetID + AuthorityList primitives.AuthorityList + Header types.Header + Completed bool +} + type WarpSyncFragment struct { // The last block that the given authority set finalized. This block should contain a digest // signalling an authority set change from which we can fetch the next authority set. @@ -51,6 +73,26 @@ func NewWarpSyncProof() WarpSyncProof { } } +func (wsp *WarpSyncProof) Decode(in []byte) error { + return scale.Unmarshal(in, wsp) +} + +func (wsp *WarpSyncProof) Encode() ([]byte, error) { + if wsp == nil { + return nil, fmt.Errorf("cannot encode nil WarpSyncProof") + } + return scale.Marshal(*wsp) +} + +func (wsp *WarpSyncProof) String() string { + if wsp == nil { + return "WarpSyncProof=nil" + } + + return fmt.Sprintf("WarpSyncProof proofs=%v isFinished=%v proofsLength=%v", + wsp.Proofs, wsp.IsFinished, wsp.proofsLength) +} + func (w *WarpSyncProof) addFragment(fragment WarpSyncFragment) (limitReached bool, err error) { encodedFragment, err := scale.Marshal(fragment) if err != nil { @@ -285,7 +327,7 @@ func (p *WarpSyncProofProvider) Verify( encodedProof []byte, setId grandpa.SetID, authorities primitives.AuthorityList, -) (*network.WarpSyncVerificationResult, error) { +) (*WarpSyncVerificationResult, error) { var proof WarpSyncProof err := scale.Unmarshal(encodedProof, &proof) if err != nil { @@ -304,7 +346,7 @@ func (p *WarpSyncProofProvider) Verify( return nil, fmt.Errorf("verifying warp sync proof: %w", err) } - return &network.WarpSyncVerificationResult{ + return &WarpSyncVerificationResult{ SetId: nextSetAndAuthorities.SetID, AuthorityList: nextSetAndAuthorities.AuthorityList, Header: lastHeader, diff --git a/lib/grandpa/warp_sync_test.go b/lib/grandpa/warpsync/warp_sync_test.go similarity index 92% rename from lib/grandpa/warp_sync_test.go rename to lib/grandpa/warpsync/warp_sync_test.go index df22ff5c84..614fdf069d 100644 --- a/lib/grandpa/warp_sync_test.go +++ b/lib/grandpa/warpsync/warp_sync_test.go @@ -1,10 +1,11 @@ // Copyright 2024 ChainSafe Systems (ON) // SPDX-License-Identifier: LGPL-3.0-only -package grandpa +package warpsync import ( "errors" + "log" "math/rand" "slices" "testing" @@ -21,8 +22,38 @@ import ( "github.com/ChainSafe/gossamer/pkg/scale" "github.com/stretchr/testify/require" "go.uber.org/mock/gomock" + "gopkg.in/yaml.v3" + + _ "embed" ) +//go:embed testdata/warp_sync_proofs.yaml +var rawWarpSyncProofs []byte + +type WarpSyncProofs struct { + SubstrateWarpSyncProof1 string `yaml:"substrate_warp_sync_proof_1"` +} + +func TestDecodeWarpSyncProof(t *testing.T) { + warpSyncProofs := &WarpSyncProofs{} + err := yaml.Unmarshal(rawWarpSyncProofs, warpSyncProofs) + require.NoError(t, err) + + // Generated using substrate + expected := common.MustHexToBytes(warpSyncProofs.SubstrateWarpSyncProof1) + if err != nil { + log.Fatal(err) + } + + var proof WarpSyncProof + + err = proof.Decode(expected) + require.NoError(t, err) + + encoded, err := proof.Encode() + require.NoError(t, err) + require.Equal(t, expected, encoded) +} func TestGenerateWarpSyncProofBlockNotFound(t *testing.T) { t.Parallel()