{"record":{"id":"afdc1e3b8982c653","repo":"hyperledger/fabric","slug":"consenter-metadata-in-ordererblockmetadata-doesn-t","errorCode":null,"errorMessage":"consenter metadata in OrdererBlockMetadata doesn't match proposal","messagePattern":"consenter metadata in OrdererBlockMetadata doesn't match proposal","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"orderer/consensus/smartbft/verifier.go","lineNumber":411,"sourceCode":"\tif err := proto.Unmarshal(sig.IdentifierHeader, sigHdr); err != nil {\n\t\treturn errors.Wrap(err, \"malformed signature header\")\n\t}\n\tif identityID != uint64(sigHdr.Identifier) {\n\t\tv.Logger.Warnf(\"Expected identity %d but got %d\", identityID,\n\t\t\tsigHdr.Identifier)\n\t\treturn errors.Errorf(\"identity in signature header does not match expected identity\")\n\t}\n\n\t// Ensure orderer block metadata's consenter MD matches the proposal\n\tordererMD := &cb.OrdererBlockMetadata{}\n\tif err := proto.Unmarshal(sig.OrdererBlockMetadata, ordererMD); err != nil {\n\t\treturn errors.Wrap(err, \"malformed orderer metadata in signature\")\n\t}\n\n\tif !bytes.Equal(ordererMD.ConsenterMetadata, prop.Metadata) {\n\t\tv.Logger.Warnf(\"Expected consenter metadata %s but got %s in proposal\",\n\t\t\tbase64.StdEncoding.EncodeToString(ordererMD.ConsenterMetadata), base64.StdEncoding.EncodeToString(prop.Metadata))\n\t\treturn errors.Errorf(\"consenter metadata in OrdererBlockMetadata doesn't match proposal\")\n\t}\n\n\tblock, err := ProposalToBlock(prop)\n\tif err != nil {\n\t\tv.Logger.Warnf(\"got malformed proposal: %v\", err)\n\t\treturn err\n\t}\n\n\t// Ensure Metadata slice is of the right size\n\tif len(block.Metadata.Metadata) != len(cb.BlockMetadataIndex_name) {\n\t\treturn errors.Errorf(\"block metadata is of size %d but should be of size %d\",\n\t\t\tlen(block.Metadata.Metadata), len(cb.BlockMetadataIndex_name))\n\t}\n\n\tsignatureMetadata := &cb.Metadata{}\n\tif err := proto.Unmarshal(block.Metadata.Metadata[cb.BlockMetadataIndex_SIGNATURES], signatureMetadata); err != nil {\n\t\treturn errors.Wrap(err, \"malformed signature metadata\")\n\t}","sourceCodeStart":393,"sourceCodeEnd":429,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/orderer/consensus/smartbft/verifier.go#L393-L429","documentation":"VerifyConsenterSig converts the proposal back into a block via ProposalToBlock and then validates the block's structure. This error means the proposal bytes could not be converted into a well-formed block — the proposal is malformed at the structural level (bad header, data, or metadata encoding), so no signature over it can be trusted.","triggerScenarios":"VerifyConsenterSig -> verifySignatureIsBoundToProposal: ProposalToBlock(prop) returns an error (e.g. the proposal's Header/Data/Metadata fields are missing, wrong length, or fail internal unmarshalling). Triggered by a corrupted or hand-crafted proposal arriving in a BFT message, or a proposal produced by incompatible code.","commonSituations":"Corrupted network payloads between orderers; version skew where one node encodes proposals differently; tampered or fuzzed messages; storage corruption of persisted proposals after restart.","solutions":["Reject the proposal and let the BFT layer force a view change / new proposal from a healthy leader.","Ensure all ordering nodes run the same Fabric version so ProposalToBlock encoding is uniform.","Inspect network/TLS integrity between orderers if corruption recurs (packet-level issues, proxies).","If it follows a crash-recovery, rebuild the node's consensus state from the ledger or re-provision it."],"exampleFix":"// before: proposal with missing header bytes\nprop.Header = nil // ProposalToBlock fails -> error\n// after: proposer always fills complete block fields\nprop.Header = protoutil.MarshalOrPanic(&cb.Header{Number: blockNum, PreviousHash: prevHash, DataHash: dataHash})","handlingStrategy":"try-catch","validationCode":"if _, err := ProposalToBlock(prop); err != nil {\n    return fmt.Errorf(\"proposal is structurally invalid: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"err := verifier.VerifyConsenterSig(sig, id)\nif err != nil {\n    // malformed proposal: reject and force a new proposal from the leader\n    if errors.Is(err, ErrMalformedProposal) || strings.Contains(err.Error(), \"malformed\") {\n        triggerViewChange()\n    }\n    return err\n}","preventionTips":["Reject malformed BFT messages at ingestion and log the sender","Keep Fabric versions identical across the ordering service","Protect inter-orderer links with TLS and integrity checks"],"tags":["hyperledger-fabric","smartbft","malformed-proposal","consensus"],"backgroundTag":"malformed-block-proposal","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"}