github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/consensus/hotstuff/signature/packer.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  // ConsensusSigDataPacker implements the hotstuff.Packer interface.
    14  // The encoding method is RLP.
    15  type ConsensusSigDataPacker struct {
    16  	model.SigDataPacker
    17  	committees hotstuff.Replicas
    18  }
    19  
    20  var _ hotstuff.Packer = &ConsensusSigDataPacker{}
    21  
    22  // NewConsensusSigDataPacker creates a new ConsensusSigDataPacker instance
    23  func NewConsensusSigDataPacker(committees hotstuff.Replicas) *ConsensusSigDataPacker {
    24  	return &ConsensusSigDataPacker{
    25  		committees: committees,
    26  	}
    27  }
    28  
    29  // Pack serializes the block signature data into raw bytes, suitable to create a QC.
    30  // To pack the block signature data, we first build a compact data type, and then encode it into bytes.
    31  // Expected error returns during normal operations:
    32  //   - none; all errors are symptoms of inconsistent input data or corrupted internal state.
    33  func (p *ConsensusSigDataPacker) Pack(view uint64, sig *hotstuff.BlockSignatureData) ([]byte, []byte, error) {
    34  	// retrieve all authorized consensus participants at the given block
    35  	fullMembers, err := p.committees.IdentitiesByEpoch(view)
    36  	if err != nil {
    37  		return nil, nil, fmt.Errorf("could not find consensus committee for view %d: %w", view, err)
    38  	}
    39  
    40  	// breaking staking and random beacon signers into signerIDs and sig type for compaction
    41  	// each signer must have its signerID and sig type stored at the same index in the two slices
    42  	// For v2, RandomBeaconSigners is nil, as we don't track individually which nodes contributed to the random beacon
    43  	// For v3, RandomBeaconSigners is not nil, each RandomBeaconSigner also signed staking sig, so the returned signerIDs, should
    44  	// include both StakingSigners and RandomBeaconSigners
    45  	signerIndices, sigType, err := signature.EncodeSignerToIndicesAndSigType(fullMembers.NodeIDs(), sig.StakingSigners, sig.RandomBeaconSigners)
    46  	if err != nil {
    47  		return nil, nil, fmt.Errorf("unexpected internal error while encoding signer indices and sig types: %w", err)
    48  	}
    49  
    50  	data := model.SignatureData{
    51  		SigType:                      sigType,
    52  		AggregatedStakingSig:         sig.AggregatedStakingSig,
    53  		AggregatedRandomBeaconSig:    sig.AggregatedRandomBeaconSig,
    54  		ReconstructedRandomBeaconSig: sig.ReconstructedRandomBeaconSig,
    55  	}
    56  
    57  	// encode the structured data into raw bytes
    58  	encoded, err := p.Encode(&data)
    59  	if err != nil {
    60  		return nil, nil, fmt.Errorf("could not encode data %v, %w", data, err)
    61  	}
    62  
    63  	return signerIndices, encoded, nil
    64  }
    65  
    66  // Unpack de-serializes the provided signature data.
    67  // view is the view of the block that the aggregated sig is signed for
    68  // sig is the aggregated signature data
    69  // It returns:
    70  //   - (sigData, nil) if successfully unpacked the signature data
    71  //   - (nil, model.InvalidFormatError) if failed to unpack the signature data
    72  func (p *ConsensusSigDataPacker) Unpack(signerIdentities flow.IdentitySkeletonList, sigData []byte) (*hotstuff.BlockSignatureData, error) {
    73  	// decode into typed data
    74  	data, err := p.Decode(sigData) // all potential error are of type `model.InvalidFormatError`
    75  	if err != nil {
    76  		return nil, fmt.Errorf("could not decode sig data %w", err)
    77  	}
    78  
    79  	stakingSigners, randomBeaconSigners, err := signature.DecodeSigTypeToStakingAndBeaconSigners(signerIdentities, data.SigType)
    80  	if err != nil {
    81  		if errors.Is(err, signature.ErrIllegallyPaddedBitVector) || errors.Is(err, signature.ErrIncompatibleBitVectorLength) {
    82  			return nil, model.NewInvalidFormatErrorf("invalid SigType vector: %w", err)
    83  		}
    84  		return nil, fmt.Errorf("could not decode signer indices and sig type: %w", err)
    85  	}
    86  
    87  	return &hotstuff.BlockSignatureData{
    88  		StakingSigners:               stakingSigners.NodeIDs(),
    89  		RandomBeaconSigners:          randomBeaconSigners.NodeIDs(),
    90  		AggregatedStakingSig:         data.AggregatedStakingSig,
    91  		AggregatedRandomBeaconSig:    data.AggregatedRandomBeaconSig,
    92  		ReconstructedRandomBeaconSig: data.ReconstructedRandomBeaconSig,
    93  	}, nil
    94  }