Fabric 区块结构:

  • Header
    • Number:区块编号(等于区块高度减 1);
    • DataHash:区块中包含的所有交易合并成一个字节切片后计算摘要;
    • PreviousHash上一个区块的 Header 经过 asn1 编码后得到的字节切片的摘要。
      • PreviousHashMetadata 无关;创世块的 PreviousHash 是 nil(protoutil.NewBlock(0, nil))。
      • 正因为 PreviousHash 由上一个区块头计算得来,所以前后区块之间形成了关联性,这种关联性是链式结构的由来。
  • Data:区块中包含的交易组成的二维字节切片
  • Metadata
// 最终的区块结构,peer 和 orderer 共用这一结构
type Block struct {
	Header               *BlockHeader   `protobuf:"bytes,1,opt,name=header,proto3" json:"header,omitempty"`
	Data                 *BlockData     `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"`
	Metadata             *BlockMetadata `protobuf:"bytes,3,opt,name=metadata,proto3" json:"metadata,omitempty"`
}

type BlockHeader struct {
    Number               uint64   `protobuf:"varint,1,opt,name=number,proto3" json:"number,omitempty"`
    PreviousHash         []byte   `protobuf:"bytes,2,opt,name=previous_hash,json=previousHash,proto3" json:"previous_hash,omitempty"`
    DataHash             []byte   `protobuf:"bytes,3,opt,name=data_hash,json=dataHash,proto3" json:"data_hash,omitempty"`
}
type BlockData struct {
    Data                 [][]byte `protobuf:"bytes,1,rep,name=data,proto3" json:"data,omitempty"`
}
type BlockMetadata struct {
    Metadata             [][]byte `protobuf:"bytes,1,rep,name=metadata,proto3" json:"metadata,omitempty"`
}

// Metadata is a common structure to be used to encode block metadata
type Metadata struct {
    Value                []byte               `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty"`
    Signatures           []*MetadataSignature `protobuf:"bytes,2,rep,name=signatures,proto3" json:"signatures,omitempty"`
}
type MetadataSignature struct {
    SignatureHeader      []byte   `protobuf:"bytes,1,opt,name=signature_header,json=signatureHeader,proto3" json:"signature_header,omitempty"`
    Signature            []byte   `protobuf:"bytes,2,opt,name=signature,proto3" json:"signature,omitempty"`
}
type SignatureHeader struct {
    // Creator of the message, a marshaled msp.SerializedIdentity
    Creator []byte `protobuf:"bytes,1,opt,name=creator,proto3" json:"creator,omitempty"`
    // Arbitrary number that may only be used once. Can be used to detect replay attacks.
    Nonce                []byte   `protobuf:"bytes,2,opt,name=nonce,proto3" json:"nonce,omitempty"`
}

func (bw *BlockWriter) CreateNextBlock(messages []*cb.Envelope) *cb.Block {
	previousBlockHash := protoutil.BlockHeaderHash(bw.lastBlock.Header)
	data := &cb.BlockData{
		Data: make([][]byte, len(messages)),
	}
	var err error
	for i, msg := range messages {
		data.Data[i], err = proto.Marshal(msg)
		if err != nil {
			logger.Panicf("Could not marshal envelope: %s", err)
		}
	}
	block := protoutil.NewBlock(bw.lastBlock.Header.Number+1, previousBlockHash)
	block.Header.DataHash = protoutil.BlockDataHash(data)
	block.Data = data
	return block
}
// NewBlock constructs a block with no data and no metadata.
func NewBlock(seqNum uint64, previousHash []byte) *cb.Block {
    block := &cb.Block{}
    block.Header = &cb.BlockHeader{}
    block.Header.Number = seqNum
    block.Header.PreviousHash = previousHash
    block.Header.DataHash = []byte{}
    block.Data = &cb.BlockData{}
    var metadataContents [][]byte
    for i := 0; i < len(cb.BlockMetadataIndex_name); i++ {
        metadataContents = append(metadataContents, []byte{})
    }
    block.Metadata = &cb.BlockMetadata{Metadata: metadataContents}
    return block
}
var BlockMetadataIndex_name = map[int32]string{
    0: "SIGNATURES",
    1: "LAST_CONFIG",
    2: "TRANSACTIONS_FILTER",
    3: "ORDERER",
    4: "COMMIT_HASH",
}
const (
    // func (bw *BlockWriter) addBlockSignature(block *cb.Block, consenterMetadata []byte) {
    BlockMetadataIndex_SIGNATURES          BlockMetadataIndex = 0
    // 最新配置块的编号
    BlockMetadataIndex_LAST_CONFIG         BlockMetadataIndex = 1 // Deprecated: Do not use.
    // func (v *TxValidator) Validate(block *common.Block) error {
    BlockMetadataIndex_TRANSACTIONS_FILTER BlockMetadataIndex = 2
    BlockMetadataIndex_ORDERER             BlockMetadataIndex = 3 // Deprecated: Do not use.
    // func (l *kvLedger) addBlockCommitHash(block *common.Block, updateBatchBytes []byte) {
    BlockMetadataIndex_COMMIT_HASH         BlockMetadataIndex = 4
)
func BlockHeaderHash(b *cb.BlockHeader) []byte {
    sum := util.ComputeSHA256(BlockHeaderBytes(b))
    return sum[:]
}
func BlockDataHash(b *cb.BlockData) []byte {
    // ConcatenateBytes 将多个 []byte 合成一个 []byte
    sum := util.ComputeSHA256(util.ConcatenateBytes(b.Data...)) 
    return sum[:]
}
func ComputeSHA256(data []byte) (hash []byte) {
    hash, _ := factory.GetDefault().Hash(data, &bccsp.SHA256Opts{})
}
func BlockHeaderBytes(b *cb.BlockHeader) []byte {
    asn1Header := asn1Header{
        PreviousHash: b.PreviousHash,
        DataHash:     b.DataHash,
        Number:       new(big.Int).SetUint64(b.Number),
    }
    result, err := asn1.Marshal(asn1Header)
    return result
}

block.Metadata.Metadata[cb.BlockMetadataIndex_LAST_CONFIG] = protoutil.MarshalOrPanic(&cb.Metadata{
    Value: protoutil.MarshalOrPanic(&cb.LastConfig{Index: 0}),
    // This is a genesis block, peer never verify this signature because we can't bootstrap
    // trust from an earlier block, hence there are no signatures here.
})
block.Metadata.Metadata[cb.BlockMetadataIndex_SIGNATURES] = protoutil.MarshalOrPanic(&cb.Metadata{
    Value: protoutil.MarshalOrPanic(&cb.OrdererBlockMetadata{
        LastConfig: &cb.LastConfig{Index: 0},
        // This is a genesis block, peer never verify this signature because we can't bootstrap
		// trust from an earlier block, hence there are no signatures here.
    }),
})


// Envelope wraps a Payload with a signature so that the message may be authenticated
type Envelope struct {
	// A marshaled Payload
	Payload []byte `protobuf:"bytes,1,opt,name=payload,proto3" json:"payload,omitempty"`
	// A signature by the creator specified in the Payload header
	Signature            []byte   `protobuf:"bytes,2,opt,name=signature,proto3" json:"signature,omitempty"`
}
// Payload is the message contents (and header to allow for signing)
type Payload struct {
    // Header is included to provide identity and prevent replay
    Header *Header `protobuf:"bytes,1,opt,name=header,proto3" json:"header,omitempty"`
    // Data, the encoding of which is defined by the type in the header
    Data                 []byte   `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"`
}
type Header struct {
    ChannelHeader        []byte   `protobuf:"bytes,1,opt,name=channel_header,json=channelHeader,proto3" json:"channel_header,omitempty"`
    SignatureHeader      []byte   `protobuf:"bytes,2,opt,name=signature_header,json=signatureHeader,proto3" json:"signature_header,omitempty"`
}

// Header is a generic replay prevention and identity message to include in a signed payload
type ChannelHeader struct {
	Type int32 `protobuf:"varint,1,opt,name=type,proto3" json:"type,omitempty"`
	// Version indicates message protocol version
	Version int32 `protobuf:"varint,2,opt,name=version,proto3" json:"version,omitempty"`
	// Timestamp is the local time when the message was created
	// by the sender
	Timestamp *timestamp.Timestamp `protobuf:"bytes,3,opt,name=timestamp,proto3" json:"timestamp,omitempty"`
	// Identifier of the channel this message is bound for
	ChannelId string `protobuf:"bytes,4,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty"`
	// An unique identifier that is used end-to-end.
	//  -  set by higher layers such as end user or SDK
	//  -  passed to the endorser (which will check for uniqueness)
	//  -  as the header is passed along unchanged, it will be
	//     be retrieved by the committer (uniqueness check here as well)
	//  -  to be stored in the ledger
	TxId string `protobuf:"bytes,5,opt,name=tx_id,json=txId,proto3" json:"tx_id,omitempty"`
	// The epoch in which this header was generated, where epoch is defined based on block height
	// Epoch in which the response has been generated. This field identifies a
	// logical window of time. A proposal response is accepted by a peer only if
	// two conditions hold:
	// 1. the epoch specified in the message is the current epoch
	// 2. this message has been only seen once during this epoch (i.e. it hasn't
	//    been replayed)
	Epoch uint64 `protobuf:"varint,6,opt,name=epoch,proto3" json:"epoch,omitempty"`
	// Extension that may be attached based on the header type
	Extension []byte `protobuf:"bytes,7,opt,name=extension,proto3" json:"extension,omitempty"`
	// If mutual TLS is employed, this represents
	// the hash of the client's TLS certificate
	TlsCertHash          []byte   `protobuf:"bytes,8,opt,name=tls_cert_hash,json=tlsCertHash,proto3" json:"tls_cert_hash,omitempty"`
}