diff --git a/dot/digest/block_import.go b/dot/digest/block_import.go index 4084c345d1..2382a754c4 100644 --- a/dot/digest/block_import.go +++ b/dot/digest/block_import.go @@ -24,8 +24,7 @@ func NewBlockImportHandler(epochState EpochState, grandpaState GrandpaState) *Bl // HandleDigests handles consensus digests for an imported block func (h *BlockImportHandler) HandleDigests(header *types.Header) error { - consensusDigests := toConsensusDigests(header.Digest) - consensusDigests, err := checkForGRANDPAForcedChanges(consensusDigests) + consensusDigests, err := types.FilterGRANDPAForcedChanges(header.Digest.ToConsensusDigests()) if err != nil { return fmt.Errorf("failed while checking GRANDPA digests: %w", err) } @@ -74,65 +73,3 @@ func (h *BlockImportHandler) handleConsensusDigest(d *types.ConsensusDigest, hea return nil } - -// toConsensusDigests converts a slice of scale.VaryingDataType to a slice of types.ConsensusDigest. -func toConsensusDigests(scaleVaryingTypes types.Digest) []types.ConsensusDigest { - consensusDigests := make([]types.ConsensusDigest, 0, len(scaleVaryingTypes)) - - for _, d := range scaleVaryingTypes { - digestValue, err := d.Value() - if err != nil { - logger.Error(err.Error()) - continue - } - digest, ok := digestValue.(types.ConsensusDigest) - if !ok { - continue - } - - switch digest.ConsensusEngineID { - case types.GrandpaEngineID, types.BabeEngineID: - consensusDigests = append(consensusDigests, digest) - } - } - - return consensusDigests -} - -// checkForGRANDPAForcedChanges removes any GrandpaScheduledChange in the presence of a -// GrandpaForcedChange in the same block digest, returning a new slice of types.ConsensusDigest -func checkForGRANDPAForcedChanges(digests []types.ConsensusDigest) ([]types.ConsensusDigest, error) { - var hasForcedChange bool - digestsWithoutScheduled := make([]types.ConsensusDigest, 0, len(digests)) - for i, digest := range digests { - if digest.ConsensusEngineID != types.GrandpaEngineID { - digestsWithoutScheduled = append(digestsWithoutScheduled, digest) - continue - } - - data := types.NewGrandpaConsensusDigest() - err := scale.Unmarshal(digest.Data, &data) - if err != nil { - return nil, fmt.Errorf("cannot unmarshal GRANDPA consensus digest: %w", err) - } - - dataValue, err := data.Value() - if err != nil { - return nil, fmt.Errorf("getting value of digest type at index %d: %w", i, err) - } - switch dataValue.(type) { - case types.GrandpaScheduledChange: - case types.GrandpaForcedChange: - hasForcedChange = true - digestsWithoutScheduled = append(digestsWithoutScheduled, digest) - default: - digestsWithoutScheduled = append(digestsWithoutScheduled, digest) - } - } - - if hasForcedChange { - return digestsWithoutScheduled, nil - } - - return digests, nil -} diff --git a/dot/sync/block_importer.go b/dot/sync/block_importer.go index c5ae40b8e0..f00b9316d5 100644 --- a/dot/sync/block_importer.go +++ b/dot/sync/block_importer.go @@ -15,6 +15,7 @@ import ( "github.com/ChainSafe/gossamer/internal/database" "github.com/ChainSafe/gossamer/lib/common" rtstorage "github.com/ChainSafe/gossamer/lib/runtime/storage" + "github.com/ChainSafe/gossamer/pkg/scale" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" ) @@ -54,6 +55,7 @@ type ( // GrandpaState is the interface for the state.GrandpaState GrandpaState interface { + HandleGRANDPADigest(header *types.Header, digest types.GrandpaConsensusDigest) error ApplyForcedChanges(importedHeader *types.Header) error } @@ -106,6 +108,36 @@ func (b *blockImporter) importBlock(bd *types.BlockData, origin BlockOrigin) (im return true, nil } +func (b *blockImporter) checkAndApplyForcedAuthChanges(blockData types.BlockData) error { + header := blockData.Header + consensusDigests, err := types.FilterGRANDPAForcedChanges(header.Digest.ToConsensusDigests()) + if err != nil { + return fmt.Errorf("failed while checking GRANDPA digests: %w", err) + } + + for i := range consensusDigests { + digest := consensusDigests[i] + switch digest.ConsensusEngineID { + case types.GrandpaEngineID: + data := types.NewGrandpaConsensusDigest() + err := scale.Unmarshal(digest.Data, &data) + if err != nil { + return fmt.Errorf("unmarshaling grandpa consensus digest: %w", err) + } + + err = b.grandpaState.HandleGRANDPADigest(header, data) + if err != nil { + return fmt.Errorf("handling grandpa digest: %w", err) + } + default: + // Will be handle by the block importer + continue + } + } + + return b.grandpaState.ApplyForcedChanges(header) +} + // processBlockData processes the BlockData from a BlockResponse and // returns the index of the last BlockData it handled on success, // or the index of the block data that errored on failure. @@ -117,7 +149,7 @@ func (b *blockImporter) processBlockData(blockData types.BlockData, origin Block setID uint64 ) - err := b.grandpaState.ApplyForcedChanges(blockData.Header) + err := b.checkAndApplyForcedAuthChanges(blockData) if err != nil { return fmt.Errorf("applying forced changes: %w", err) } diff --git a/dot/types/digest.go b/dot/types/digest.go index 06931011bb..6e1c172e46 100644 --- a/dot/types/digest.go +++ b/dot/types/digest.go @@ -111,6 +111,28 @@ func (d *Digest) Add(values ...any) (err error) { return nil } +func (d *Digest) ToConsensusDigests() []ConsensusDigest { + consensusDigests := make([]ConsensusDigest, 0, len(*d)) + + for _, d := range *d { + digestValue, err := d.Value() + if err != nil { + continue + } + digest, ok := digestValue.(ConsensusDigest) + if !ok { + continue + } + + switch digest.ConsensusEngineID { + case GrandpaEngineID, BabeEngineID: + consensusDigests = append(consensusDigests, digest) + } + } + + return consensusDigests +} + func (d *Digest) String() string { stringTypes := make([]string, len(*d)) for i, vdt := range *d { @@ -182,3 +204,41 @@ type RuntimeEnvironmentUpdated struct{} func (RuntimeEnvironmentUpdated) String() string { return "RuntimeEnvironmentUpdated" } + +// FilterGRANDPAForcedChanges removes any GrandpaScheduledChange in the presence of a +// GrandpaForcedChange in the same block digest, returning a new slice of ConsensusDigest +func FilterGRANDPAForcedChanges(digests []ConsensusDigest) ([]ConsensusDigest, error) { + var hasForcedChange bool + digestsWithoutScheduled := make([]ConsensusDigest, 0, len(digests)) + for i, digest := range digests { + if digest.ConsensusEngineID != GrandpaEngineID { + digestsWithoutScheduled = append(digestsWithoutScheduled, digest) + continue + } + + data := NewGrandpaConsensusDigest() + err := scale.Unmarshal(digest.Data, &data) + if err != nil { + return nil, fmt.Errorf("cannot unmarshal GRANDPA consensus digest: %w", err) + } + + dataValue, err := data.Value() + if err != nil { + return nil, fmt.Errorf("getting value of digest type at index %d: %w", i, err) + } + switch dataValue.(type) { + case GrandpaScheduledChange: + case GrandpaForcedChange: + hasForcedChange = true + digestsWithoutScheduled = append(digestsWithoutScheduled, digest) + default: + digestsWithoutScheduled = append(digestsWithoutScheduled, digest) + } + } + + if hasForcedChange { + return digestsWithoutScheduled, nil + } + + return digests, nil +}