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 }