github.com/onflow/flow-go@v0.33.17/consensus/hotstuff/signature/block_signer_decoder.go (about) 1 package signature 2 3 import ( 4 "errors" 5 "fmt" 6 7 "github.com/onflow/flow-go/consensus/hotstuff" 8 "github.com/onflow/flow-go/consensus/hotstuff/model" 9 "github.com/onflow/flow-go/model/flow" 10 "github.com/onflow/flow-go/module/signature" 11 ) 12 13 // BlockSignerDecoder is a wrapper around the `hotstuff.DynamicCommittee`, which implements 14 // the auxiliary logic for de-coding signer indices of a block (header) to full node IDs 15 type BlockSignerDecoder struct { 16 hotstuff.DynamicCommittee 17 } 18 19 func NewBlockSignerDecoder(committee hotstuff.DynamicCommittee) *BlockSignerDecoder { 20 return &BlockSignerDecoder{committee} 21 } 22 23 var _ hotstuff.BlockSignerDecoder = (*BlockSignerDecoder)(nil) 24 25 // DecodeSignerIDs decodes the signer indices from the given block header into full node IDs. 26 // Note: A block header contains a quorum certificate for its parent, which proves that the 27 // consensus committee has reached agreement on validity of parent block. Consequently, the 28 // returned IdentifierList contains the consensus participants that signed the parent block. 29 // Expected Error returns during normal operations: 30 // - signature.InvalidSignerIndicesError if signer indices included in the header do 31 // not encode a valid subset of the consensus committee 32 // - state.ErrUnknownSnapshotReference if the input header is not a known incorporated block. 33 func (b *BlockSignerDecoder) DecodeSignerIDs(header *flow.Header) (flow.IdentifierList, error) { 34 // root block does not have signer indices 35 if header.ParentVoterIndices == nil && header.View == 0 { 36 return []flow.Identifier{}, nil 37 } 38 39 // we will use IdentitiesByEpoch since it's a faster call and avoids DB lookup 40 members, err := b.IdentitiesByEpoch(header.ParentView) 41 if err != nil { 42 if errors.Is(err, model.ErrViewForUnknownEpoch) { 43 // possibly, we request epoch which is far behind in the past, in this case we won't have it in cache. 44 // try asking by parent ID 45 // TODO: this assumes no identity table changes within epochs, must be changed for Dynamic Protocol State 46 // See https://github.com/onflow/flow-go/issues/4085 47 members, err = b.IdentitiesByBlock(header.ParentID) 48 if err != nil { 49 return nil, fmt.Errorf("could not retrieve identities for block %x with QC view %d for parent %x: %w", 50 header.ID(), header.ParentView, header.ParentID, err) // state.ErrUnknownSnapshotReference or exception 51 } 52 } else { 53 return nil, fmt.Errorf("unexpected error retrieving identities for block %v: %w", header.ID(), err) 54 } 55 } 56 signerIDs, err := signature.DecodeSignerIndicesToIdentifiers(members.NodeIDs(), header.ParentVoterIndices) 57 if err != nil { 58 return nil, fmt.Errorf("could not decode signer indices for block %v: %w", header.ID(), err) 59 } 60 61 return signerIDs, nil 62 } 63 64 // NoopBlockSignerDecoder does not decode any signer indices and consistently returns 65 // nil for the signing node IDs (auxiliary data) 66 type NoopBlockSignerDecoder struct{} 67 68 func NewNoopBlockSignerDecoder() *NoopBlockSignerDecoder { 69 return &NoopBlockSignerDecoder{} 70 } 71 72 func (b *NoopBlockSignerDecoder) DecodeSignerIDs(_ *flow.Header) (flow.IdentifierList, error) { 73 return nil, nil 74 }