{"record":{"id":"ec11c178d25bd041","repo":"hyperledger/fabric","slug":"mismatched-block-header","errorCode":null,"errorMessage":"mismatched block header","messagePattern":"mismatched block header","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"orderer/consensus/smartbft/verifier.go","lineNumber":388,"sourceCode":"\tfor indexInBlock := range blockData {\n\t\tres = append(res, indexToRequestInfo[indexInBlock])\n\t}\n\n\treturn res, nil\n}\n\nfunc (v *Verifier) verifySignatureIsBoundToProposal(sig *Signature, identityID uint64, prop types.Proposal) error {\n\t// We verify the following fields:\n\t// ConsenterMetadata    []byte\n\t// SignatureHeader      []byte\n\t// BlockHeader          []byte\n\t// OrdererBlockMetadata []byte\n\n\t// Ensure block header is equal\n\tif !bytes.Equal(prop.Header, sig.BlockHeader) {\n\t\tv.Logger.Errorf(\"Expected block header %s but got %s\", base64.StdEncoding.EncodeToString(prop.Header),\n\t\t\tbase64.StdEncoding.EncodeToString(sig.BlockHeader))\n\t\treturn errors.Errorf(\"mismatched block header\")\n\t}\n\n\t// Ensure signature header matches the identity\n\tsigHdr := &cb.IdentifierHeader{}\n\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}","sourceCodeStart":370,"sourceCodeEnd":406,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/orderer/consensus/smartbft/verifier.go#L370-L406","documentation":"In SmartBFT, each consenter signs over the proposal, and the signature records the block header it signed. VerifyConsenterSig -> verifySignatureIsBoundToProposal compares the proposal's header bytes with the header in the received signature (sig.BlockHeader). This error means the signature is not bound to the proposed block — a signature from another proposal/block is being applied to this one.","triggerScenarios":"VerifyConsenterSig -> verifySignatureIsBoundToProposal: bytes.Equal(prop.Header, sig.BlockHeader) is false. Triggered when a VerificationData/signature bundle references a different proposal — e.g. message mix-up in the BFT message layer, a replayed signature from a previous block, or the signature was persisted/loaded (Sign/VerificationData round trip in verifier_assembler) against a different proposal.","commonSituations":"Network reordering or bugs mixing quorum messages across proposals; an attacker or faulty node replaying old signatures; process restart where signature metadata was persisted but the proposal changed; a node assembling a commit certificate from mismatched parts.","solutions":["Discard/re-request the signature for the correct proposal; the bad signature bundle should be dropped, not retried as-is.","Force a view change so a fresh proposal and matching signatures are collected.","Check for replayed messages: ensure the node's clocks/sequence handling is correct and Fabric version is uniform across consenters.","If it follows a restart, verify the persisted signature metadata corresponds to the same block height/view as the current proposal."],"exampleFix":"// before: signature bound to a different block\nprop.Header = \"AAAA...\"; sig.BlockHeader = \"BBBB...\" -> error\n// after: collect a signature over the actual proposal\nprop.Header = \"AAAA...\"; sig.BlockHeader = \"AAAA...\"","handlingStrategy":"try-catch","validationCode":"if !bytes.Equal(sig.BlockHeader, prop.Header) {\n    return errors.New(\"signature does not bind to this proposal; request a fresh signature\")\n}","typeGuard":null,"tryCatchPattern":"err := verifier.VerifyConsenterSig(sig, identityID)\nif err != nil && strings.Contains(err.Error(), \"mismatched block header\") {\n    // drop the stale signature and re-request it from the consenter\n}","preventionTips":["Discard rather than retry mismatched signature bundles","Force a view change after any restart that restores old signature state","Keep BFT message sequencing strict to avoid cross-proposal message mix-ups"],"tags":["hyperledger-fabric","smartbft","signature-binding","consensus"],"backgroundTag":"signature-block-header-mismatch","analyzedSha":"2736b63f8fd5932511d56fe68b7039d15977f7f6","analyzedAt":"2026-09-04T08:52:36.465Z","contentChangedAt":"2026-09-04T08:52:36.465Z","schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}