{"record":{"id":"2e4c988e4f8efbb0","repo":"hyperledger/fabric","slug":"no-signatures-in-block-metadata","errorCode":null,"errorMessage":"no signatures in block metadata","messagePattern":"no signatures in block metadata","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"protoutil/blockutils.go","lineNumber":254,"sourceCode":"\t}\n}\n\ntype VerifierBuilder func(block *cb.Block) BlockVerifierFunc\n\ntype BlockVerifierFunc func(header *cb.BlockHeader, metadata *cb.BlockMetadata) error\n\n//go:generate counterfeiter -o mocks/policy.go --fake-name Policy . policy\ntype policy interface { // copied from common.policies to avoid circular import.\n\t// EvaluateSignedData takes a set of SignedData and evaluates whether\n\t// 1) the signatures are valid over the related message\n\t// 2) the signing identities satisfy the policy\n\tEvaluateSignedData(signatureSet []*SignedData) error\n}\n\nfunc BlockSignatureVerifier(bftEnabled bool, consenters []*cb.Consenter, policy policy) BlockVerifierFunc {\n\treturn func(header *cb.BlockHeader, metadata *cb.BlockMetadata) error {\n\t\tif len(metadata.GetMetadata()) < int(cb.BlockMetadataIndex_SIGNATURES)+1 {\n\t\t\treturn errors.Errorf(\"no signatures in block metadata\")\n\t\t}\n\n\t\tmd := &cb.Metadata{}\n\t\tif err := proto.Unmarshal(metadata.Metadata[cb.BlockMetadataIndex_SIGNATURES], md); err != nil {\n\t\t\treturn errors.Wrapf(err, \"error unmarshalling signatures from metadata: %v\", err)\n\t\t}\n\n\t\tvar signatureSet []*SignedData\n\t\tfor _, metadataSignature := range md.Signatures {\n\t\t\tvar signerIdentity []byte\n\t\t\tvar signedPayload []byte\n\t\t\t// if the SignatureHeader is empty and the IdentifierHeader is present, then  the consenter expects us to fetch its identity by its numeric identifier\n\t\t\tif bftEnabled && len(metadataSignature.GetSignatureHeader()) == 0 && len(metadataSignature.GetIdentifierHeader()) > 0 {\n\t\t\t\tidentifierHeader, err := UnmarshalIdentifierHeader(metadataSignature.IdentifierHeader)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"failed unmarshalling identifier header for block %d: %v\", header.GetNumber(), err)\n\t\t\t\t}\n\t\t\t\tidentifier := identifierHeader.GetIdentifier()","sourceCodeStart":236,"sourceCodeEnd":272,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/protoutil/blockutils.go#L236-L272","documentation":"BlockSignatureVerifier validates a block's signature metadata. If the block metadata slice does not contain an entry at BlockMetadataIndex_SIGNATURES (metadata too short), there are no signatures to verify, so it fails with this error. It guards against accepting unsigned or structurally invalid blocks.","triggerScenarios":"Calling the returned BlockVerifierFunc with a cb.BlockMetadata whose Metadata array has fewer entries than BlockMetadataIndex_SIGNATURES+1 — e.g. a genesis-like block, a hand-crafted block, or truncated metadata.","commonSituations":"Delivering blocks from an untrusted/misbehaving ordering node, testing with manually constructed blocks lacking signatures, or version mismatch where signature metadata is stored at a different index.","solutions":["Ensure blocks come from a legitimate ordering service that always writes the SIGNATURES metadata entry","Check block.Metadata length before invoking the verifier and reject early with a clearer message","If building test blocks, populate Metadata[BlockMetadataIndex_SIGNATURES] with a signed cb.Metadata","Confirm BFT/standard ordering metadata index layout matches the verifier configuration (bftEnabled flag)"],"exampleFix":"// before\nerr := verifier(header, metadata)\n// after\nif len(metadata.GetMetadata()) < int(cb.BlockMetadataIndex_SIGNATURES)+1 {\n    return errors.Errorf(\"block %d: metadata has no SIGNATURES entry\", header.GetNumber())\n}\nerr := verifier(header, metadata)","handlingStrategy":"validation","validationCode":"func hasSignatureEntry(metadata *cb.BlockMetadata) bool {\n    return len(metadata.GetMetadata()) >= int(cb.BlockMetadataIndex_SIGNATURES)+1\n}\nif !hasSignatureEntry(md) {\n    return errors.New(\"block lacks signature metadata; reject\")\n}","typeGuard":"func isSignedBlock(block *cb.Block) bool {\n    return len(block.GetMetadata().GetMetadata()) >= int(cb.BlockMetadataIndex_SIGNATURES)+1\n}","tryCatchPattern":"if err := verifier(header, metadata); err != nil {\n    return fmt.Errorf(\"rejecting block %d: %w\", header.GetNumber(), err)\n}","preventionTips":["Only accept blocks from authorized ordering nodes","Never bypass block verification even for genesis-like blocks in tests — build signed metadata instead","Check metadata array length before verification","Ensure bftEnabled matches the channel's actual consensus type"],"tags":["signatures","block-verification","block-metadata","security"],"backgroundTag":"missing-block-signatures","analyzedSha":"2736b63f8fd5932511d56fe68b7039d15977f7f6","analyzedAt":"2026-09-04T08:52:36.465Z","contentChangedAt":"2026-09-04T08:52:36.465Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}