{"record":{"id":"39f0e98f91247eb0","repo":"hyperledger/fabric","slug":"data-hash-is-s-but-expected-s","errorCode":null,"errorMessage":"data hash is %s but expected %s","messagePattern":"data hash is (.+?) but expected (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"orderer/consensus/smartbft/verifier.go","lineNumber":259,"sourceCode":"func (v *Verifier) VerificationSequence() uint64 {\n\treturn v.VerificationSequencer.Sequence()\n}\n\nfunc verifyHashChainAndDataHash(block *cb.Block, prevHeaderHash string) error {\n\tthisHdrHashOfPrevHdr := hex.EncodeToString(block.Header.PreviousHash)\n\tif prevHeaderHash != thisHdrHashOfPrevHdr {\n\t\treturn errors.Errorf(\"previous header hash is %s but expected %s\", thisHdrHashOfPrevHdr, prevHeaderHash)\n\t}\n\n\tdataHash, err := protoutil.BlockDataHash(block.Data)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdataHashString := hex.EncodeToString(block.Header.DataHash)\n\n\tactualHashOfData := hex.EncodeToString(dataHash)\n\tif dataHashString != actualHashOfData {\n\t\treturn errors.Errorf(\"data hash is %s but expected %s\", dataHashString, actualHashOfData)\n\t}\n\treturn nil\n}\n\nfunc (v *Verifier) verifyBlockDataAndMetadata(block *cb.Block, metadata []byte) ([]types.RequestInfo, error) {\n\tif block.Data == nil || len(block.Data.Data) == 0 {\n\t\treturn nil, errors.New(\"empty block data\")\n\t}\n\n\tif block.Metadata == nil || len(block.Metadata.Metadata) < len(cb.BlockMetadataIndex_name) {\n\t\treturn nil, errors.New(\"block metadata is either missing or contains too few entries\")\n\t}\n\n\tsignatureMetadata, err := protoutil.GetMetadataFromBlock(block, cb.BlockMetadataIndex_SIGNATURES)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tordererMetadataFromSignature := &cb.OrdererBlockMetadata{}","sourceCodeStart":241,"sourceCodeEnd":277,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/orderer/consensus/smartbft/verifier.go#L241-L277","documentation":"verifyHashChainAndDataHash recomputes the block data hash via protoutil.BlockDataHash and compares it to block.Header.DataHash. If the header's declared data hash does not match the actual data, the block content was altered or built incorrectly.","triggerScenarios":"A proposal whose block.Header.DataHash was computed over different data than block.Data contains — e.g. data mutated after hashing, or hash computed with a different algorithm/serialization.","commonSituations":"A buggy custom block assembler or middleware mutating block.Data after hashing; version mismatch in hashing utilities; corrupted proposal in-flight; adversarial/buggy leader proposing inconsistent blocks.","solutions":["Rebuild the proposal ensuring DataHash = protoutil.BlockDataHash(block.Data) as the final step after data assembly","Audit any code that mutates block.Data between hash computation and proposal","Verify all nodes run the same protoutil version for BlockDataHash","Discard and re-propose the block from the current leader"],"exampleFix":"// before: hash computed before adding a transaction\nhash := protoutil.BlockDataHash(data)\ndata.Data = append(data.Data, extraTx) // data changed after hashing\n// after: compute hash last\nblock.Data.Data = append(block.Data.Data, extraTx)\nblock.Header.DataHash = protoutil.BlockDataHash(block.Data)","handlingStrategy":"validation","validationCode":"dataHash, err := protoutil.BlockDataHash(block.Data)\nif err != nil { return err }\nif !bytes.Equal(dataHash, block.Header.DataHash) {\n    return errors.New(\"block.DataHash does not match block.Data; reject proposal\")\n}","typeGuard":"func dataHashMatches(b *cb.Block) bool {\n    h, err := protoutil.BlockDataHash(b.Data)\n    return err == nil && bytes.Equal(h, b.Header.DataHash)\n}","tryCatchPattern":"if err := verifyHashChainAndDataHash(block, prevHash); err != nil && strings.Contains(err.Error(), \"data hash\") {\n    logger.Warn(\"proposal data tampered or incorrectly assembled; discarding\")\n}","preventionTips":["Compute DataHash as the last step of block assembly, after all data is final","Never mutate block.Data after hashing","Use protoutil.BlockDataHash consistently, no custom hashing","Audit any middleware that touches block data"],"tags":["smartbft","fabric","data-hash","integrity"],"backgroundTag":"data-hash-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"}