Fabric 区块结构:

  • Header
    • Number:区块编号(等于区块高度减 1);
    • DataHash:区块中包含的所有交易合并成一个字节切片后计算摘要;
    • PreviousHash上一个区块的 Header 经过 asn1 编码后得到的字节切片的摘要。
      • PreviousHashMetadata 无关;创世块的 PreviousHash 是 nil(protoutil.NewBlock(0, nil))。
      • 正因为 PreviousHash 由上一个区块头计算得来,所以前后区块之间形成了关联性,这种关联性是链式结构的由来。
  • Data:区块中包含的交易组成的二维字节切片
  • Metadata
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
// 最终的区块结构,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"`
}