hyperledger/fabric · error
signature's OrdererBlockMetadata and OrdererBlockMetadata ex
Error message
signature's OrdererBlockMetadata and OrdererBlockMetadata extracted from block do not match
What it means
The OrdererBlockMetadata decoded from the block's SIGNATURES metadata is not identical (proto.Equal) to the OrdererBlockMetadata carried in the signature being verified. This means the signature is not bound to this block's metadata, so the block fails verification. It is an integrity/consistency check in the SmartBFT verifier.
Source
Thrown at orderer/consensus/smartbft/verifier.go:438
// Ensure Metadata slice is of the right size
if len(block.Metadata.Metadata) != len(cb.BlockMetadataIndex_name) {
return errors.Errorf("block metadata is of size %d but should be of size %d",
len(block.Metadata.Metadata), len(cb.BlockMetadataIndex_name))
}
signatureMetadata := &cb.Metadata{}
if err := proto.Unmarshal(block.Metadata.Metadata[cb.BlockMetadataIndex_SIGNATURES], signatureMetadata); err != nil {
return errors.Wrap(err, "malformed signature metadata")
}
ordererMDFromBlock := &cb.OrdererBlockMetadata{}
if err := proto.Unmarshal(signatureMetadata.Value, ordererMDFromBlock); err != nil {
return errors.Wrap(err, "malformed orderer metadata in block")
}
// Ensure the block's OrdererBlockMetadata matches the signature.
if !proto.Equal(ordererMDFromBlock, ordererMD) {
return errors.Errorf("signature's OrdererBlockMetadata and OrdererBlockMetadata extracted from block do not match")
}
return nil
}
type consenterVerifier struct {
logger *flogging.FabricLogger
channel string
policyManager policies.Manager
}
// Evaluate evaluates signed data and returns no error if signature is valid and satisfies the policy
func (cv *consenterVerifier) Evaluate(signatureSet []*protoutil.SignedData) error {
policy, ok := cv.policyManager.GetPolicy(policies.ChannelOrdererWriters)
if !ok {
cv.logger.Errorf("[%s] Error: could not find policy %s in policy manager %v", cv.channel, policies.ChannelOrdererWriters, cv.policyManager)
return errors.Errorf("could not find policy %s", policies.ChannelOrdererWriters)
}View on GitHub (pinned to 2736b63f8f)
Solutions
- Use the signature produced for exactly this block (same seqNo and metadata); do not copy signatures across blocks
- Re-fetch the block and its signature bundle from the consensus/ledger source
- Check that no middleware or tooling rewrites block metadata after signing
- If seen repeatedly from one consenter, investigate that node for buggy or malicious behavior
Example fix
// before: signature taken from a cached map keyed only by height sig := sigCache[block.Header.Number] // after: key by block header hash / proposal digest sig := sigCache[hex.EncodeToString(protoutil.BlockHeaderHash(block.Header))]
Defensive patterns
Strategy: try-catch
Validate before calling
// verify binding yourself before calling the API
sigMD, _ := protoutil.GetMetadataFromBlock(blk, cb.BlockMetadataIndex_SIGNATURES)
obm := &cb.OrdererBlockMetadata{}
if err := proto.Unmarshal(sigMD.Value, obm); err != nil { return err }
if !proto.Equal(obm, expectedOrdererMD) {
return errors.New("signature not bound to this block's metadata")
} Type guard
func signatureBoundToBlock(sigOrdererMD, blkOrdererMD *cb.OrdererBlockMetadata) bool {
return proto.Equal(sigOrdererMD, blkOrdererMD)
} Try / catch
if err := verifier.VerifyConsenterSig(blk, sig); err != nil {
if strings.Contains(err.Error(), "do not match") {
log.Warnf("signature/block binding failed for block %d; re-fetching block", blk.Header.Number)
return reFetchBlockAndSignature(blk.Header.Number)
}
return err
} Prevention
- Never reuse signatures across blocks; key signature caches by block hash/proposal digest
- Treat repeated mismatches from one consenter as a security signal and investigate
- Avoid post-signing mutations of block metadata in tooling
- Re-fetch blocks/signatures from consensus rather than repairing locally
When it happens
Trigger: VerifyConsenterSig is given a signature whose attached OrdererBlockMetadata differs from the one embedded in the block — e.g. signature copied from a different block, or block metadata was altered after signing.
Common situations: Replay of signatures across blocks during Byzantine/malicious activity or buggy custom code; blocks assembled by hand in tests; mixing blocks from different channels/heights.
Related errors
- failed to submit request
- pending config does not match calculated expected config
- failed creating a new BFTChain
- cannot get HeightsByEndpoints
- no cluster members to synchronize with
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/b26eac574773a20e.
Report an issue: GitHub.