From 04364215838ed249c9ef4b939905468fd99f550b Mon Sep 17 00:00:00 2001 From: Diego Date: Thu, 6 Feb 2025 23:51:29 -0300 Subject: [PATCH] Finalize last block retrieved from state sync --- dot/digest/digest_integration_test.go | 4 +- dot/rpc/modules/chain_integration_test.go | 2 +- dot/state/block.go | 2 +- dot/state/block_finalisation.go | 8 ++- dot/state/block_finalisation_test.go | 4 +- dot/state/block_notify_test.go | 4 +- dot/state/block_test.go | 10 +-- dot/state/service.go | 2 +- dot/state/service_integration_test.go | 6 +- dot/sync/block_importer.go | 2 +- dot/sync/mocks_test.go | 8 +-- dot/sync/service.go | 4 +- dot/sync/state_sync.go | 70 ++++++++----------- dot/sync/warp_sync.go | 14 ++-- lib/babe/verify_integration_test.go | 2 +- lib/grandpa/grandpa.go | 4 +- .../message_handler_integration_test.go | 2 +- lib/grandpa/message_integration_test.go | 2 +- lib/grandpa/message_tracker_test.go | 2 +- lib/grandpa/mocks_test.go | 8 +-- lib/grandpa/round_integration_test.go | 2 +- lib/grandpa/state.go | 2 +- lib/grandpa/warpsync/warp_sync.go | 38 ++++++---- 23 files changed, 106 insertions(+), 96 deletions(-) diff --git a/dot/digest/digest_integration_test.go b/dot/digest/digest_integration_test.go index a2a9c99a27..32458e2250 100644 --- a/dot/digest/digest_integration_test.go +++ b/dot/digest/digest_integration_test.go @@ -67,7 +67,7 @@ func TestHandler_GrandpaScheduledChange(t *testing.T) { // create 4 blocks and finalize only blocks 0, 1, 2 headers, _ := state.AddBlocksToState(t, handler.blockState.(*state.BlockState), 4, false) for i, h := range headers[:3] { - err := handler.blockState.(*state.BlockState).SetFinalisedHash(h.Hash(), uint64(i), 0) + err := handler.blockState.(*state.BlockState).SetFinalisedHash(h.Hash(), uint64(i), 0, true) require.NoError(t, err) } @@ -98,7 +98,7 @@ func TestHandler_GrandpaScheduledChange(t *testing.T) { require.NoError(t, err) // finalize block of number 3 - err = handler.blockState.(*state.BlockState).SetFinalisedHash(headers[3].Hash(), 3, 0) + err = handler.blockState.(*state.BlockState).SetFinalisedHash(headers[3].Hash(), 3, 0, true) require.NoError(t, err) time.Sleep(time.Millisecond * 500) diff --git a/dot/rpc/modules/chain_integration_test.go b/dot/rpc/modules/chain_integration_test.go index 6bbbf741d8..82a0f9350d 100644 --- a/dot/rpc/modules/chain_integration_test.go +++ b/dot/rpc/modules/chain_integration_test.go @@ -328,7 +328,7 @@ func TestChainGetFinalizedHeadByRound(t *testing.T) { require.NoError(t, err) testhash := header.Hash() - err = state.Block.SetFinalisedHash(testhash, 77, 1) + err = state.Block.SetFinalisedHash(testhash, 77, 1, true) require.NoError(t, err) req = ChainFinalizedHeadRequest{77, 1} diff --git a/dot/state/block.go b/dot/state/block.go index 1558eba4e2..dfdd41e00d 100644 --- a/dot/state/block.go +++ b/dot/state/block.go @@ -153,7 +153,7 @@ func NewBlockStateFromGenesis(db database.Database, trs *Tries, header *types.He } // set the latest finalised head to the genesis header - if err := bs.SetFinalisedHash(bs.genesisHash, 0, 0); err != nil { + if err := bs.SetFinalisedHash(bs.genesisHash, 0, 0, true); err != nil { return nil, err } diff --git a/dot/state/block_finalisation.go b/dot/state/block_finalisation.go index 781ff5aeda..ade7a137fc 100644 --- a/dot/state/block_finalisation.go +++ b/dot/state/block_finalisation.go @@ -123,7 +123,7 @@ func (bs *BlockState) GetHighestFinalisedHeader() (*types.Header, error) { } // SetFinalisedHash sets the latest finalised block hash -func (bs *BlockState) SetFinalisedHash(hash common.Hash, round, setID uint64) error { +func (bs *BlockState) SetFinalisedHash(hash common.Hash, round, setID uint64, finalizeAncestors bool) error { bs.lock.Lock() defer bs.lock.Unlock() @@ -139,8 +139,10 @@ func (bs *BlockState) SetFinalisedHash(hash common.Hash, round, setID uint64) er return fmt.Errorf("cannot finalise unknown block %s", hash) } - if err := bs.handleFinalisedBlock(hash); err != nil { - return fmt.Errorf("failed to set finalised subchain in db on finalisation: %w", err) + if finalizeAncestors { + if err := bs.handleFinalisedBlock(hash); err != nil { + return fmt.Errorf("failed to set finalised subchain in db on finalisation: %w", err) + } } if err := bs.db.Put(finalisedHashKey(round, setID), hash[:]); err != nil { diff --git a/dot/state/block_finalisation_test.go b/dot/state/block_finalisation_test.go index f08b3d718c..d9f56d3714 100644 --- a/dot/state/block_finalisation_test.go +++ b/dot/state/block_finalisation_test.go @@ -99,7 +99,7 @@ func TestBlockState_SetFinalisedHash(t *testing.T) { // set tries with some state root bs.tries.softSet(someStateRoot, inmemory_trie.NewEmptyTrie()) - err = bs.SetFinalisedHash(testhash, 1, 1) + err = bs.SetFinalisedHash(testhash, 1, 1, true) require.NoError(t, err) h, err = bs.GetFinalisedHash(1, 1) @@ -148,7 +148,7 @@ func TestSetFinalisedHash_retrieveBlockNumber1SlotNumber(t *testing.T) { }) require.NoError(t, err) - err = bs.SetFinalisedHash(header2.Hash(), 1, 1) + err = bs.SetFinalisedHash(header2.Hash(), 1, 1, true) require.NoError(t, err) require.Equal(t, header2.Hash(), bs.lastFinalised) diff --git a/dot/state/block_notify_test.go b/dot/state/block_notify_test.go index a8bf3c639c..6a346a9084 100644 --- a/dot/state/block_notify_test.go +++ b/dot/state/block_notify_test.go @@ -51,7 +51,7 @@ func TestFinalizedChannel(t *testing.T) { chain, _ := AddBlocksToState(t, bs, 3, false) for _, b := range chain { - bs.SetFinalisedHash(b.Hash(), 1, 0) + bs.SetFinalisedHash(b.Hash(), 1, 0, true) } for i := 0; i < 1; i++ { @@ -124,7 +124,7 @@ func TestFinalizedChannel_Multi(t *testing.T) { } time.Sleep(time.Millisecond * 10) - bs.SetFinalisedHash(chain[0].Hash(), 1, 0) + bs.SetFinalisedHash(chain[0].Hash(), 1, 0, true) wg.Wait() for _, ch := range chs { diff --git a/dot/state/block_test.go b/dot/state/block_test.go index 38f8c9f969..c4e5eae7ea 100644 --- a/dot/state/block_test.go +++ b/dot/state/block_test.go @@ -304,7 +304,7 @@ func TestGetAllDescendants(t *testing.T) { err = bs.AddBlockWithArrivalTime(block2, time.Now()) require.NoError(t, err) - err = bs.SetFinalisedHash(block2.Header.Hash(), 1, 1) + err = bs.SetFinalisedHash(block2.Header.Hash(), 1, 1, true) require.NoError(t, err) // can't fetch given block's descendants since the given block get removed from memory after @@ -455,7 +455,7 @@ func TestFinalization_DeleteBlock(t *testing.T) { // pick block to finalise fin := leaves[len(leaves)-1] - err := bs.SetFinalisedHash(fin, 1, 1) + err := bs.SetFinalisedHash(fin, 1, 1, true) require.NoError(t, err) after := bs.bt.GetAllBlocks() @@ -683,7 +683,7 @@ func TestNumberIsFinalised(t *testing.T) { Body: types.Body{}, }) require.NoError(t, err) - err = bs.SetFinalisedHash(header2.Hash(), 1, 1) + err = bs.SetFinalisedHash(header2.Hash(), 1, 1, true) require.NoError(t, err) fin, err = bs.NumberIsFinalised(0) @@ -1023,7 +1023,7 @@ func TestRange(t *testing.T) { hashIndexToSetAsFinalized := tt.blocksToPersistAtDisk - 1 selectedHash := hashesCreated[hashIndexToSetAsFinalized] - err := blockState.SetFinalisedHash(selectedHash, 0, 0) + err := blockState.SetFinalisedHash(selectedHash, 0, 0, true) require.NoError(t, err) } @@ -1093,7 +1093,7 @@ func Test_GetRuntime_StoreRuntime(t *testing.T) { } lastElementOnChain := chain[len(chain)-1] - err = blockState.SetFinalisedHash(lastElementOnChain.Hash(), 1, 0) + err = blockState.SetFinalisedHash(lastElementOnChain.Hash(), 1, 0, true) require.NoError(t, err) sameRuntimeOnDiffHash, err := blockState.GetRuntime(lastElementOnChain.Hash()) diff --git a/dot/state/service.go b/dot/state/service.go index 6f85c9c438..190a2ad304 100644 --- a/dot/state/service.go +++ b/dot/state/service.go @@ -214,7 +214,7 @@ func (s *Service) Rewind(toBlock uint) error { // TODO: this is broken, it needs to set the latest finalised header after // rewinding to some block number, but there is no reverse lookup function // for block -> (round, setID) where it was finalised (#1859) - err = s.Block.SetFinalisedHash(header.Hash(), 0, 0) + err = s.Block.SetFinalisedHash(header.Hash(), 0, 0, true) if err != nil { return err } diff --git a/dot/state/service_integration_test.go b/dot/state/service_integration_test.go index f3246ed23c..4226ac106c 100644 --- a/dot/state/service_integration_test.go +++ b/dot/state/service_integration_test.go @@ -154,7 +154,7 @@ func TestService_BlockTree(t *testing.T) { AddBlocksToState(t, stateA.Block, 10, false) head := stateA.Block.BestBlockHash() - err = stateA.Block.SetFinalisedHash(head, 1, 1) + err = stateA.Block.SetFinalisedHash(head, 1, 1, true) require.NoError(t, err) err = stateA.Stop() @@ -302,7 +302,7 @@ func TestService_PruneStorage(t *testing.T) { } // finalise a block - serv.Block.SetFinalisedHash(toFinalize, 0, 0) + serv.Block.SetFinalisedHash(toFinalize, 0, 0, true) time.Sleep(1 * time.Second) @@ -347,7 +347,7 @@ func TestService_Rewind(t *testing.T) { AddBlocksToState(t, serv.Block, 12, false) head := serv.Block.BestBlockHash() - err = serv.Block.SetFinalisedHash(head, 0, 0) + err = serv.Block.SetFinalisedHash(head, 0, 0, true) require.NoError(t, err) err = serv.Rewind(6) diff --git a/dot/sync/block_importer.go b/dot/sync/block_importer.go index f34f8aa038..4a8febf34e 100644 --- a/dot/sync/block_importer.go +++ b/dot/sync/block_importer.go @@ -132,7 +132,7 @@ func (b *blockImporter) processBlockData(blockData types.BlockData, origin Block return fmt.Errorf("verifying justification for block %s: %w", header.Hash().String(), err) } - err = b.blockState.SetFinalisedHash(header.Hash(), round, setID) + err = b.blockState.SetFinalisedHash(header.Hash(), round, setID, true) if err != nil { return fmt.Errorf("setting finalised hash: %w", err) } diff --git a/dot/sync/mocks_test.go b/dot/sync/mocks_test.go index fca3f75a2d..b118ffa176 100644 --- a/dot/sync/mocks_test.go +++ b/dot/sync/mocks_test.go @@ -409,17 +409,17 @@ func (mr *MockBlockStateMockRecorder) SetBlockTree(arg0 any) *gomock.Call { } // SetFinalisedHash mocks base method. -func (m *MockBlockState) SetFinalisedHash(arg0 common.Hash, arg1, arg2 uint64) error { +func (m *MockBlockState) SetFinalisedHash(arg0 common.Hash, arg1, arg2 uint64, arg3 bool) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "SetFinalisedHash", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "SetFinalisedHash", arg0, arg1, arg2, arg3) ret0, _ := ret[0].(error) return ret0 } // SetFinalisedHash indicates an expected call of SetFinalisedHash. -func (mr *MockBlockStateMockRecorder) SetFinalisedHash(arg0, arg1, arg2 any) *gomock.Call { +func (mr *MockBlockStateMockRecorder) SetFinalisedHash(arg0, arg1, arg2, arg3 any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetFinalisedHash", reflect.TypeOf((*MockBlockState)(nil).SetFinalisedHash), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetFinalisedHash", reflect.TypeOf((*MockBlockState)(nil).SetFinalisedHash), arg0, arg1, arg2, arg3) } // SetFirstNonOriginSlotNumber mocks base method. diff --git a/dot/sync/service.go b/dot/sync/service.go index 40491dcdfe..5b1227fa65 100644 --- a/dot/sync/service.go +++ b/dot/sync/service.go @@ -74,7 +74,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 + SetFinalisedHash(hash common.Hash, round uint64, setID uint64, finalizeAncestors bool) error SetJustification(hash common.Hash, data []byte) error GetHashByNumber(blockNumber uint) (common.Hash, error) GetBlockByHash(common.Hash) (*types.Block, error) @@ -367,7 +367,7 @@ func (s *SyncService) runStrategy() { FinalityGadget: s.finalityGadget, TransactionState: s.transactionState, BlockImportHandler: s.blockImportHandler, - TargetBlock: s.currentStrategy.Result().(types.BlockData), + WarpSyncResult: s.currentStrategy.Result().(warpsync.WarpSyncVerificationResult), } s.currentStrategy = NewStateSyncStrategy(stateSyncCfg) diff --git a/dot/sync/state_sync.go b/dot/sync/state_sync.go index 2af3e72a74..97a458772d 100644 --- a/dot/sync/state_sync.go +++ b/dot/sync/state_sync.go @@ -13,6 +13,7 @@ import ( "github.com/ChainSafe/gossamer/dot/peerset" "github.com/ChainSafe/gossamer/dot/types" "github.com/ChainSafe/gossamer/lib/blocktree" + "github.com/ChainSafe/gossamer/lib/grandpa/warpsync" "github.com/ChainSafe/gossamer/lib/runtime/storage" wazero_runtime "github.com/ChainSafe/gossamer/lib/runtime/wazero" "github.com/ChainSafe/gossamer/pkg/trie" @@ -40,10 +41,11 @@ type StateSyncStrategy struct { blockImporter importer // State sync state - phase WarpSyncPhase - startedAt time.Time - targetBlock types.BlockData - firstBlock types.BlockData + phase WarpSyncPhase + startedAt time.Time + warpSyncResult warpsync.WarpSyncVerificationResult + targetHeader types.Header + firstBlock types.BlockData } type StateSyncStrategyConfig struct { @@ -53,7 +55,7 @@ type StateSyncStrategyConfig struct { Peers *peerViewSet ReqMaker network.RequestMaker BlockReqMaker network.RequestMaker - TargetBlock types.BlockData + WarpSyncResult warpsync.WarpSyncVerificationResult StateStorage StorageState FinalityGadget FinalityGadget TransactionState TransactionState @@ -64,17 +66,20 @@ type StateSyncStrategyConfig struct { func NewStateSyncStrategy( cfg *StateSyncStrategyConfig, ) *StateSyncStrategy { + targetHeader := cfg.WarpSyncResult.Header + return &StateSyncStrategy{ peers: cfg.Peers, badBlocks: cfg.BadBlocks, blockState: cfg.BlockState, - targetBlock: cfg.TargetBlock, + targetHeader: targetHeader, + warpSyncResult: cfg.WarpSyncResult, reqMaker: cfg.ReqMaker, blockReqMaker: cfg.BlockReqMaker, storage: cfg.StateStorage, finalityGadget: cfg.FinalityGadget, // TODO: we can assume that v1 is right for every chain but we need to find a way to set the right state version - stateRequestProvider: NewStateRequestProvider(cfg.TargetBlock.Header.Hash(), trie.V1), + stateRequestProvider: NewStateRequestProvider(targetHeader.Hash(), trie.V1), phase: DownloadState, blockImporter: newBlockImporter(&BlockImporterConfig{ BlockState: cfg.BlockState, @@ -264,8 +269,6 @@ func (s *StateSyncStrategy) IsSynced() bool { // with some extra logic to skip validations func (s *StateSyncStrategy) setBlockAsFullSyncStartingBlock() error { // Importing first block to set epochs - logger.Infof("First block data: %+v", s.firstBlock) - slotNumber, err := s.firstBlock.Header.SlotNumber() if err != nil { return fmt.Errorf("getting slot number, err: %s", err) @@ -276,11 +279,6 @@ func (s *StateSyncStrategy) setBlockAsFullSyncStartingBlock() error { return fmt.Errorf("setting non origin slot number, err: %s", err) } - logger.Infof("First block imported successfully") - - blockHeader := s.targetBlock.Header - justification := s.targetBlock.Justification - // Get download trie state trieState, err := s.stateRequestProvider.BuildTrie() if err != nil { @@ -288,13 +286,13 @@ func (s *StateSyncStrategy) setBlockAsFullSyncStartingBlock() error { } // Check state is the expected - if trieState.MustHash() != s.targetBlock.Header.StateRoot { - return fmt.Errorf("state root mismatch: got %s expected %s", trieState.MustHash(), s.targetBlock.Header.StateRoot) + if trieState.MustHash() != s.targetHeader.StateRoot { + return fmt.Errorf("state root mismatch: got %s expected %s", trieState.MustHash(), s.targetHeader.StateRoot) } // Store downloaded trie state storageTrie := storage.NewTrieState(trieState) - err = s.storage.StoreTrie(storageTrie, blockHeader) + err = s.storage.StoreTrie(storageTrie, &s.targetHeader) if err != nil { return fmt.Errorf("storing new state trie, err: %s", err) } @@ -330,39 +328,33 @@ func (s *StateSyncStrategy) setBlockAsFullSyncStartingBlock() error { return fmt.Errorf("creating new runtime, err: %s", err) } - // Set block header in block state - err = s.blockState.SetHeader(blockHeader) - if err != nil { - return fmt.Errorf("setting new block header, err: %s", err) - } - // Initialize runtime and set it in the new blocktree - blockTree := blocktree.NewBlockTreeFromRoot(blockHeader) + blockTree := blocktree.NewBlockTreeFromRoot(&s.targetHeader) - blockTree.StoreRuntime(s.targetBlock.Header.Hash(), instance) + blockTree.StoreRuntime(s.targetHeader.Hash(), instance) s.blockState.SetBlockTree(blockTree) + // Set block header in block state + err = s.blockState.SetHeader(&s.targetHeader) if err != nil { - return fmt.Errorf("setting new block tree, err: %s", err) + return fmt.Errorf("setting new block header, err: %s", err) } - if justification != nil && len(*justification) > 0 { - round, setID, err := s.finalityGadget.VerifyBlockJustification( - blockHeader.Hash(), blockHeader.Number, *justification) - if err != nil { - return fmt.Errorf("verifying justification for block %s: %w", blockHeader.Hash().String(), err) - } - - err = s.blockState.SetFinalisedHash(blockHeader.Hash(), round, setID) - if err != nil { - return fmt.Errorf("setting finalised hash: %w", err) - } + justification := s.warpSyncResult.Justification + err = s.blockState.SetFinalisedHash(s.targetHeader.Hash(), + justification.Justification.Round, uint64(s.warpSyncResult.SetId), false) + if err != nil { + return fmt.Errorf("setting finalised hash: %w", err) + } + /* + TODO: solve this later err = s.blockState.SetJustification(blockHeader.Hash(), *justification) if err != nil { return fmt.Errorf("setting justification for block number %d: %w", blockHeader.Number, err) - } - } + }*/ + + logger.Infof("block finalized successfully %s", s.targetHeader.Hash()) // TODO: // update authorities set return nil diff --git a/dot/sync/warp_sync.go b/dot/sync/warp_sync.go index 95dfa4612e..92833bc740 100644 --- a/dot/sync/warp_sync.go +++ b/dot/sync/warp_sync.go @@ -47,7 +47,7 @@ type WarpSyncStrategy struct { setId primitives.SetID authorities primitives.AuthorityList lastBlock *types.Header - result types.BlockData + result warpsync.WarpSyncVerificationResult } type WarpSyncConfig struct { @@ -188,12 +188,13 @@ func (w *WarpSyncStrategy) Process(results []*SyncTaskResult) ( } else { logger.Debugf("⏩ Warping, finish processing proofs, downloading target block #%d (%s)", w.lastBlock.Number, w.lastBlock.Hash().String()) - w.phase = TargetBlock + w.result = *warpProofResult + w.phase = WarpSyncCompleted } } case TargetBlock: - logger.Debug("processing warp sync target block results") + /*logger.Debug("processing warp sync target block results") var validRes []RequestResponseData @@ -201,9 +202,12 @@ func (w *WarpSyncStrategy) Process(results []*SyncTaskResult) ( repChanges, bans, validRes = validateResults(results, w.badBlocks) if len(validRes) > 0 && validRes[0].responseData != nil && len(validRes[0].responseData) > 0 { - w.result = *validRes[0].responseData[0] + w.result = WarpSyncResult{ + Block: *validRes[0].responseData[0], + Justification: w.bestJustification, + } w.phase = WarpSyncCompleted - } + }*/ } return w.IsSynced(), repChanges, bans, nil diff --git a/lib/babe/verify_integration_test.go b/lib/babe/verify_integration_test.go index c309d6b9ba..5ab210976c 100644 --- a/lib/babe/verify_integration_test.go +++ b/lib/babe/verify_integration_test.go @@ -750,7 +750,7 @@ func TestVerifyForkBlocksWithRespectiveEpochData(t *testing.T) { fmt.Sprint(forkBobLastHeader.Number), ), ) - err = stateService.Block.SetFinalisedHash(forkBobLastHeader.Hash(), 1, 1) + err = stateService.Block.SetFinalisedHash(forkBobLastHeader.Hash(), 1, 1, true) require.NoError(t, err) // wait for digest handleBlockFinalize goroutine gets the finalized diff --git a/lib/grandpa/grandpa.go b/lib/grandpa/grandpa.go index 4a3f50d25c..24d1e0d880 100644 --- a/lib/grandpa/grandpa.go +++ b/lib/grandpa/grandpa.go @@ -682,7 +682,7 @@ func (s *Service) finalise() error { } // set finalised head for round in db - if err = s.blockState.SetFinalisedHash(bfc.Hash, s.state.round, s.state.setID); err != nil { + if err = s.blockState.SetFinalisedHash(bfc.Hash, s.state.round, s.state.setID, true); err != nil { return err } @@ -1199,7 +1199,7 @@ func (s *Service) handleCommitMessage(commitMessage *CommitMessage) error { return fmt.Errorf("verifying commit message justification: %w", err) } - err = s.blockState.SetFinalisedHash(commitMessage.Vote.Hash, commitMessage.Round, s.state.setID) + err = s.blockState.SetFinalisedHash(commitMessage.Vote.Hash, commitMessage.Round, s.state.setID, true) if err != nil { return fmt.Errorf("setting finalised hash: %w", err) } diff --git a/lib/grandpa/message_handler_integration_test.go b/lib/grandpa/message_handler_integration_test.go index f1713dd504..98580d85e3 100644 --- a/lib/grandpa/message_handler_integration_test.go +++ b/lib/grandpa/message_handler_integration_test.go @@ -468,7 +468,7 @@ func TestMessageHandler_CatchUpRequest_WithResponse(t *testing.T) { err = st.Block.AddBlock(block) require.NoError(t, err) - err = gs.blockState.SetFinalisedHash(testGenesisHeader.Hash(), round, setID) + err = gs.blockState.SetFinalisedHash(testGenesisHeader.Hash(), round, setID, true) require.NoError(t, err) err = gs.blockState.(*state.BlockState).SetHeader(&block.Header) require.NoError(t, err) diff --git a/lib/grandpa/message_integration_test.go b/lib/grandpa/message_integration_test.go index e638f1aedf..2562bdc91e 100644 --- a/lib/grandpa/message_integration_test.go +++ b/lib/grandpa/message_integration_test.go @@ -180,7 +180,7 @@ func TestNewCatchUpResponse(t *testing.T) { err = st.Block.AddBlock(block) require.NoError(t, err) - err = gs.blockState.SetFinalisedHash(hash, round, setID) + err = gs.blockState.SetFinalisedHash(hash, round, setID, true) require.NoError(t, err) err = gs.blockState.(*state.BlockState).SetHeader(testHeader) require.NoError(t, err) diff --git a/lib/grandpa/message_tracker_test.go b/lib/grandpa/message_tracker_test.go index 6bccda47b1..8525dcf338 100644 --- a/lib/grandpa/message_tracker_test.go +++ b/lib/grandpa/message_tracker_test.go @@ -118,7 +118,7 @@ func TestMessageTracker_handleTick_commitMessage(t *testing.T) { Return(false, nil) blockStateMock.EXPECT(). - SetFinalisedHash(testHash, commitMessageRound, serviceStateSetID). + SetFinalisedHash(testHash, commitMessageRound, serviceStateSetID, true). Return(nil) grandpaStateMock := NewMockGrandpaState(ctrl) diff --git a/lib/grandpa/mocks_test.go b/lib/grandpa/mocks_test.go index 250315b781..a97b55ef00 100644 --- a/lib/grandpa/mocks_test.go +++ b/lib/grandpa/mocks_test.go @@ -351,17 +351,17 @@ func (mr *MockBlockStateMockRecorder) LowestCommonAncestor(arg0, arg1 any) *gomo } // SetFinalisedHash mocks base method. -func (m *MockBlockState) SetFinalisedHash(arg0 common.Hash, arg1, arg2 uint64) error { +func (m *MockBlockState) SetFinalisedHash(arg0 common.Hash, arg1, arg2 uint64, arg3 bool) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "SetFinalisedHash", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "SetFinalisedHash", arg0, arg1, arg2, arg3) ret0, _ := ret[0].(error) return ret0 } // SetFinalisedHash indicates an expected call of SetFinalisedHash. -func (mr *MockBlockStateMockRecorder) SetFinalisedHash(arg0, arg1, arg2 any) *gomock.Call { +func (mr *MockBlockStateMockRecorder) SetFinalisedHash(arg0, arg1, arg2, arg3 any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetFinalisedHash", reflect.TypeOf((*MockBlockState)(nil).SetFinalisedHash), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetFinalisedHash", reflect.TypeOf((*MockBlockState)(nil).SetFinalisedHash), arg0, arg1, arg2, arg3) } // SetJustification mocks base method. diff --git a/lib/grandpa/round_integration_test.go b/lib/grandpa/round_integration_test.go index 28dc481ba3..d73ce85d39 100644 --- a/lib/grandpa/round_integration_test.go +++ b/lib/grandpa/round_integration_test.go @@ -617,7 +617,7 @@ func TestSendingVotesInRightStage(t *testing.T) { GetHeader(testGenesisHeader.Hash()). Return(testGenesisHeader, nil) mockedState.EXPECT(). - SetFinalisedHash(testGenesisHeader.Hash(), uint64(1), uint64(0)). + SetFinalisedHash(testGenesisHeader.Hash(), uint64(1), uint64(0), true). Return(nil) expectedFinalizedTelemetryMessage := telemetry.NewAfgFinalizedBlocksUpTo( diff --git a/lib/grandpa/state.go b/lib/grandpa/state.go index f072118f97..c0ceae591f 100644 --- a/lib/grandpa/state.go +++ b/lib/grandpa/state.go @@ -25,7 +25,7 @@ type BlockState interface { GetFinalisedHeader(round, setID uint64) (*types.Header, error) GetRoundAndSetID() (uint64, uint64) GetFinalisedHash(round, setID uint64) (common.Hash, error) - SetFinalisedHash(common.Hash, uint64, uint64) error + SetFinalisedHash(common.Hash, uint64, uint64, bool) error BestBlockHeader() (*types.Header, error) GetHighestFinalisedHeader() (*types.Header, error) GetImportedBlockNotifierChannel() chan *types.Block diff --git a/lib/grandpa/warpsync/warp_sync.go b/lib/grandpa/warpsync/warp_sync.go index 9759556b8e..98f764133d 100644 --- a/lib/grandpa/warpsync/warp_sync.go +++ b/lib/grandpa/warpsync/warp_sync.go @@ -45,6 +45,7 @@ type WarpSyncVerificationResult struct { SetId grandpa.SetID AuthorityList grandpa.AuthorityList Header types.Header + Justification consensus_grandpa.GrandpaJustification[hash.H256, uint32] Completed bool } @@ -123,10 +124,13 @@ func (w *WarpSyncProof) verify( setId grandpa.SetID, authorities grandpa.AuthorityList, hardForks map[string]SetIdAuthorityList, -) (*SetIdAuthorityList, error) { - setIdAuth := &SetIdAuthorityList{ - SetID: setId, - AuthorityList: authorities, +) (*VerifyResult, error) { + result := &VerifyResult{ + SetIdAuthorityList{ + SetID: setId, + AuthorityList: authorities, + }, + consensus_grandpa.GrandpaJustification[hash.H256, uint32]{}, } for fragmentNumber, proof := range w.Proofs { @@ -135,15 +139,17 @@ func (w *WarpSyncProof) verify( hardForkKey := fmt.Sprintf("%v-%v", headerHash, number) if fork, ok := hardForks[hardForkKey]; ok { - setIdAuth.SetID = fork.SetID - setIdAuth.AuthorityList = fork.AuthorityList + result.SetID = fork.SetID + result.AuthorityList = fork.AuthorityList } else { - err := proof.Justification.Verify(uint64(setIdAuth.SetID), setIdAuth.AuthorityList) + err := proof.Justification.Verify(uint64(result.SetID), result.AuthorityList) if err != nil { logger.Debugf("failed to verify justification %s", err) return nil, err } + result.Justification = proof.Justification + if !bytes.Equal(proof.Justification.Target().Hash.Bytes(), headerHash.ToBytes()) { return nil, fmt.Errorf("mismatch between header and justification") } @@ -159,15 +165,15 @@ func (w *WarpSyncProof) verify( return nil, fmt.Errorf("cannot parse GRANPDA raw authorities: %w", err) } - setIdAuth.SetID += 1 - setIdAuth.AuthorityList = auths + result.SetID += 1 + result.AuthorityList = auths } else if fragmentNumber != len(w.Proofs)-1 || !w.IsFinished { return nil, fmt.Errorf("header is missing authority set change digest") } } } - return setIdAuth, nil + return result, nil } type WarpSyncProofProvider struct { @@ -188,6 +194,11 @@ type SetIdAuthorityList struct { grandpa.AuthorityList } +type VerifyResult struct { + SetIdAuthorityList + Justification consensus_grandpa.GrandpaJustification[hash.H256, uint32] +} + func (p *WarpSyncProofProvider) CurrentAuthorities() (grandpa.AuthorityList, error) { currentSetid, err := p.grandpaState.GetCurrentSetID() if err != nil { @@ -340,15 +351,16 @@ func (p *WarpSyncProofProvider) Verify( lastProof := proof.Proofs[len(proof.Proofs)-1] lastHeader := lastProof.Header - nextSetAndAuthorities, err := proof.verify(setId, authorities, p.hardForks) + verifyResult, err := proof.verify(setId, authorities, p.hardForks) if err != nil { return nil, fmt.Errorf("verifying warp sync proof: %w", err) } return &WarpSyncVerificationResult{ - SetId: nextSetAndAuthorities.SetID, - AuthorityList: nextSetAndAuthorities.AuthorityList, Header: lastHeader, + SetId: verifyResult.SetID, + AuthorityList: verifyResult.AuthorityList, + Justification: verifyResult.Justification, Completed: proof.IsFinished, }, nil }