Skip to content

Commit

Permalink
Finalize last block retrieved from state sync
Browse files Browse the repository at this point in the history
  • Loading branch information
dimartiro committed Feb 7, 2025
1 parent 144f56b commit 0436421
Show file tree
Hide file tree
Showing 23 changed files with 106 additions and 96 deletions.
4 changes: 2 additions & 2 deletions dot/digest/digest_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}

Expand Down Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion dot/rpc/modules/chain_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand Down
2 changes: 1 addition & 1 deletion dot/state/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand Down
8 changes: 5 additions & 3 deletions dot/state/block_finalisation.go
Original file line number Diff line number Diff line change
Expand Up @@ -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()

Expand All @@ -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 {
Expand Down
4 changes: 2 additions & 2 deletions dot/state/block_finalisation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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)

Expand Down
4 changes: 2 additions & 2 deletions dot/state/block_notify_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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++ {
Expand Down Expand Up @@ -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 {
Expand Down
10 changes: 5 additions & 5 deletions dot/state/block_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
}

Expand Down Expand Up @@ -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())
Expand Down
2 changes: 1 addition & 1 deletion dot/state/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
6 changes: 3 additions & 3 deletions dot/state/service_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down Expand Up @@ -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)

Expand Down Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion dot/sync/block_importer.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down
8 changes: 4 additions & 4 deletions dot/sync/mocks_test.go

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

4 changes: 2 additions & 2 deletions dot/sync/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down
70 changes: 31 additions & 39 deletions dot/sync/state_sync.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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 {
Expand All @@ -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
Expand All @@ -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,
Expand Down Expand Up @@ -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)
Expand All @@ -276,25 +279,20 @@ 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 {
return fmt.Errorf("building retrieved state, err: %s", err)
}

// 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)
}
Expand Down Expand Up @@ -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
Expand Down
Loading

0 comments on commit 0436421

Please sign in to comment.