From 70863781777c7ba02469d61feee832e44f064ae2 Mon Sep 17 00:00:00 2001 From: heren-ke Date: Wed, 27 Nov 2024 17:42:43 +0800 Subject: [PATCH] docs: update docs for go files --- internal/configtxgen/encoder/encoder.go | 24 ++++++++++++++++ protoutil/blockutils.go | 37 ++++++++++++++++++++++++- protoutil/mocks/policy.go | 17 ++++++++++++ 3 files changed, 77 insertions(+), 1 deletion(-) diff --git a/internal/configtxgen/encoder/encoder.go b/internal/configtxgen/encoder/encoder.go index 03f9f134f26..dde64f7d305 100644 --- a/internal/configtxgen/encoder/encoder.go +++ b/internal/configtxgen/encoder/encoder.go @@ -83,7 +83,10 @@ func AddOrdererPolicies(cg *cb.ConfigGroup, policyMap map[string]*genesisconfig. return AddPolicies(cg, policyMap, modPolicy) } +// AddPolicies adds a set of policies to a ConfigGroup, validating required policies and +// handling different policy types (ImplicitMeta or Signature). func AddPolicies(cg *cb.ConfigGroup, policyMap map[string]*genesisconfig.Policy, modPolicy string) error { + // Validate that all necessary policies are present in the policyMap. switch { case policyMap == nil: return errors.Errorf("no policies defined") @@ -95,13 +98,19 @@ func AddPolicies(cg *cb.ConfigGroup, policyMap map[string]*genesisconfig.Policy, return errors.Errorf("no Writers policy defined") } + // Iterate over all policies in the map and add them to the ConfigGroup. for policyName, policy := range policyMap { switch policy.Type { case ImplicitMetaPolicyType: + + // Handle ImplicitMetaPolicy type. + // Parse the rule string into an ImplicitMetaPolicy object. imp, err := policies.ImplicitMetaFromString(policy.Rule) if err != nil { return errors.Wrapf(err, "invalid implicit meta policy rule '%s'", policy.Rule) } + + // Add the parsed policy to the ConfigGroup. cg.Policies[policyName] = &cb.ConfigPolicy{ ModPolicy: modPolicy, Policy: &cb.Policy{ @@ -110,10 +119,15 @@ func AddPolicies(cg *cb.ConfigGroup, policyMap map[string]*genesisconfig.Policy, }, } case SignaturePolicyType: + + // Handle SignaturePolicy type. + // Parse the rule string into a SignaturePolicy object. sp, err := policydsl.FromString(policy.Rule) if err != nil { return errors.Wrapf(err, "invalid signature policy rule '%s'", policy.Rule) } + + // Add the parsed policy to the ConfigGroup. cg.Policies[policyName] = &cb.ConfigPolicy{ ModPolicy: modPolicy, Policy: &cb.Policy{ @@ -183,6 +197,7 @@ func NewChannelGroup(conf *genesisconfig.Profile) (*cb.ConfigGroup, error) { // about how large blocks should be, how frequently they should be emitted, etc. as well as the organizations of the ordering network. // It sets the mod_policy of all elements to "Admins". This group is always present in any channel configuration. func NewOrdererGroup(conf *genesisconfig.Orderer, channelCapabilities map[string]bool) (*cb.ConfigGroup, error) { + // Validate compatibility of orderer type and channel capabilities. if conf.OrdererType == "BFT" && !channelCapabilities["V3_0"] { return nil, errors.Errorf("orderer type BFT must be used with V3_0 channel capability: %v", channelCapabilities) } @@ -190,10 +205,15 @@ func NewOrdererGroup(conf *genesisconfig.Orderer, channelCapabilities map[string return nil, errors.Errorf("global orderer endpoints exist, but can not be used with V3_0 capability: %v", conf.Addresses) } + // Create a new ConfigGroup for the orderer. ordererGroup := protoutil.NewConfigGroup() + + // Add policies to the orderer group. if err := AddOrdererPolicies(ordererGroup, conf.Policies, channelconfig.AdminsPolicyKey); err != nil { return nil, errors.Wrapf(err, "error adding policies to orderer group") } + + // Add configuration values for batch size, batch timeout, and channel restrictions. addValue(ordererGroup, channelconfig.BatchSizeValue( conf.BatchSize.MaxMessageCount, conf.BatchSize.AbsoluteMaxBytes, @@ -202,10 +222,12 @@ func NewOrdererGroup(conf *genesisconfig.Orderer, channelCapabilities map[string addValue(ordererGroup, channelconfig.BatchTimeoutValue(conf.BatchTimeout.String()), channelconfig.AdminsPolicyKey) addValue(ordererGroup, channelconfig.ChannelRestrictionsValue(conf.MaxChannels), channelconfig.AdminsPolicyKey) + // Add capabilities if they exist in the configuration. if len(conf.Capabilities) > 0 { addValue(ordererGroup, channelconfig.CapabilitiesValue(conf.Capabilities), channelconfig.AdminsPolicyKey) } + // Initialize consensus metadata and configure based on the orderer type. var consensusMetadata []byte var err error @@ -232,8 +254,10 @@ func NewOrdererGroup(conf *genesisconfig.Orderer, channelCapabilities map[string return nil, errors.Errorf("unknown orderer type: %s", conf.OrdererType) } + // Add the consensus type and metadata configuration to the orderer group. addValue(ordererGroup, channelconfig.ConsensusTypeValue(conf.OrdererType, consensusMetadata), channelconfig.AdminsPolicyKey) + // Configure organizations for the orderer. for _, org := range conf.Organizations { var err error ordererGroup.Groups[org.Name], err = NewOrdererOrgGroup(org, channelCapabilities) diff --git a/protoutil/blockutils.go b/protoutil/blockutils.go index 18962c4d2aa..723577a8cdd 100644 --- a/protoutil/blockutils.go +++ b/protoutil/blockutils.go @@ -89,24 +89,43 @@ func GetChannelIDFromBlockBytes(bytes []byte) (string, error) { return GetChannelIDFromBlock(block) } -// GetChannelIDFromBlock returns channel ID in the block + +// GetChannelIDFromBlock extracts the channel ID from the provided block. +// It parses the block data to retrieve the envelope, payload, and channel header, +// and finally retrieves the channel ID from the channel header. +// +// Parameters: +// - block: A pointer to a cb.Block object containing the blockchain block data. +// +// Returns: +// - (string): The channel ID extracted from the block. +// - (error): An error if the channel ID cannot be retrieved or the block is malformed. func GetChannelIDFromBlock(block *cb.Block) (string, error) { + + // Check if the block or its data is nil, or if it contains no data. if block == nil || block.Data == nil || block.Data.Data == nil || len(block.Data.Data) == 0 { return "", errors.New("failed to retrieve channel id - block is empty") } var err error + + // Retrieve the first envelope from the block. envelope, err := GetEnvelopeFromBlock(block.Data.Data[0]) if err != nil { return "", err } + + // Unmarshal the payload from the envelope. payload, err := UnmarshalPayload(envelope.Payload) if err != nil { return "", err } + // Verify that the payload header is not nil. if payload.Header == nil { return "", errors.New("failed to retrieve channel id - payload header is empty") } + + // Unmarshal the channel header from the payload header. chdr, err := UnmarshalChannelHeader(payload.Header.ChannelHeader) if err != nil { return "", err @@ -242,18 +261,31 @@ type policy interface { // copied from common.policies to avoid circular import. EvaluateSignedData(signatureSet []*SignedData) error } + +// BlockSignatureVerifier returns a BlockVerifierFunc that validates the signatures of a block based on the provided policy and consenter set. +// It checks the metadata of the block to retrieve and verify the signatures against the given policy. +// +// Parameters: +// - bftEnabled: A boolean flag indicating if BFT (Byzantine Fault Tolerant) consensus is enabled. +// - consenters: A list of consenter objects that may be used to look up consenter identities if required. +// - policy: A policy object that will be used to evaluate the validity of the signatures. +// +// Returns: +// - BlockVerifierFunc: A function that takes a block header and metadata, and returns an error if the signatures are invalid. func BlockSignatureVerifier(bftEnabled bool, consenters []*cb.Consenter, policy policy) BlockVerifierFunc { return func(header *cb.BlockHeader, metadata *cb.BlockMetadata) error { if len(metadata.GetMetadata()) < int(cb.BlockMetadataIndex_SIGNATURES)+1 { return errors.Errorf("no signatures in block metadata") } + // Unmarshal the signatures metadata from the block metadata. md := &cb.Metadata{} if err := proto.Unmarshal(metadata.Metadata[cb.BlockMetadataIndex_SIGNATURES], md); err != nil { return errors.Wrapf(err, "error unmarshalling signatures from metadata: %v", err) } var signatureSet []*SignedData + // Loop through each signature in the metadata. for _, metadataSignature := range md.Signatures { var signerIdentity []byte var signedPayload []byte @@ -269,6 +301,8 @@ func BlockSignatureVerifier(bftEnabled bool, consenters []*cb.Consenter, policy // The identifier is not within the consenter set continue } + + // Concatenate the necessary data for signature verification in BFT mode. signedPayload = util.ConcatenateBytes(md.Value, metadataSignature.IdentifierHeader, BlockHeaderBytes(header)) } else { signatureHeader, err := UnmarshalSignatureHeader(metadataSignature.GetSignatureHeader()) @@ -278,6 +312,7 @@ func BlockSignatureVerifier(bftEnabled bool, consenters []*cb.Consenter, policy signedPayload = util.ConcatenateBytes(md.Value, metadataSignature.SignatureHeader, BlockHeaderBytes(header)) + // Use the creator (identity) from the signature header. signerIdentity = signatureHeader.Creator } diff --git a/protoutil/mocks/policy.go b/protoutil/mocks/policy.go index 674fa0023d1..18dbe5028ab 100644 --- a/protoutil/mocks/policy.go +++ b/protoutil/mocks/policy.go @@ -23,20 +23,37 @@ type Policy struct { invocationsMutex sync.RWMutex } + +// EvaluateSignedData is a method of the fake Policy struct that evaluates signed data. +// It supports recording method invocations and managing predefined return values for testing purposes. func (fake *Policy) EvaluateSignedData(arg1 []*protoutil.SignedData) error { var arg1Copy []*protoutil.SignedData + + // If the input argument is not nil, create a copy of the slice. if arg1 != nil { arg1Copy = make([]*protoutil.SignedData, len(arg1)) copy(arg1Copy, arg1) } + + // Acquire a mutex lock to ensure thread safety when accessing shared data. fake.evaluateSignedDataMutex.Lock() + + // Retrieve specific return values for the current call based on the call count. ret, specificReturn := fake.evaluateSignedDataReturnsOnCall[len(fake.evaluateSignedDataArgsForCall)] + + // Append the arguments of the current call to a slice for tracking invocation history. fake.evaluateSignedDataArgsForCall = append(fake.evaluateSignedDataArgsForCall, struct { arg1 []*protoutil.SignedData }{arg1Copy}) + + // Retrieve the default return values. stub := fake.EvaluateSignedDataStub fakeReturns := fake.evaluateSignedDataReturns + + // Record the invocation of this method with its arguments. fake.recordInvocation("EvaluateSignedData", []interface{}{arg1Copy}) + + // Release the mutex lock after shared data manipulation is complete. fake.evaluateSignedDataMutex.Unlock() if stub != nil { return stub(arg1)