Hyperledger Fabric 区块结构
Fabric 区块结构:
Header
Number
:区块编号(等于区块高度减 1);DataHash
:区块中包含的所有交易合并成一个字节切片后计算摘要;PreviousHash
:上一个区块的Header
经过 asn1 编码后得到的字节切片的摘要。PreviousHash
和Metadata
无关;创世块的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"`
}