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  }