-
Notifications
You must be signed in to change notification settings - Fork 0
/
blockutils.go
179 lines (156 loc) · 5.03 KB
/
blockutils.go
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
172
173
174
175
176
177
178
179
/*
Copyright IBM Corp. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/
package protoutil
import (
"encoding/asn1"
"fmt"
"math"
"github.com/golang/protobuf/proto"
"github.com/hyperledger/fabric/common/util"
cb "github.com/hyperledger/fabric/protos/common"
"github.com/pkg/errors"
)
// 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.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
}
type asn1Header struct {
Number int64
PreviousHash []byte
DataHash []byte
}
func BlockHeaderBytes(b *cb.BlockHeader) []byte {
if b.Number > uint64(math.MaxInt64) {
panic(fmt.Errorf("Golang does not currently support encoding uint64 to asn1"))
}
asn1Header := asn1Header{
PreviousHash: b.PreviousHash,
DataHash: b.DataHash,
Number: int64(b.Number),
}
result, err := asn1.Marshal(asn1Header)
if err != nil {
// Errors should only arise for types which cannot be encoded, since the
// BlockHeader type is known a-priori to contain only encodable types, an
// error here is fatal and should not be propogated
panic(err)
}
return result
}
func BlockHeaderHash(b *cb.BlockHeader) []byte {
return util.ComputeSHA256(BlockHeaderBytes(b))
}
func BlockDataHash(b *cb.BlockData) []byte {
return util.ComputeSHA256(util.ConcatenateBytes(b.Data...))
}
// GetChainIDFromBlockBytes returns chain ID given byte array which represents
// the block
func GetChainIDFromBlockBytes(bytes []byte) (string, error) {
block, err := GetBlockFromBlockBytes(bytes)
if err != nil {
return "", err
}
return GetChainIDFromBlock(block)
}
// GetChainIDFromBlock returns chain ID in the block
func GetChainIDFromBlock(block *cb.Block) (string, error) {
if block == nil || block.Data == nil || block.Data.Data == nil || len(block.Data.Data) == 0 {
return "", errors.Errorf("failed to retrieve channel id - block is empty")
}
var err error
envelope, err := GetEnvelopeFromBlock(block.Data.Data[0])
if err != nil {
return "", err
}
payload, err := GetPayload(envelope)
if err != nil {
return "", err
}
if payload.Header == nil {
return "", errors.Errorf("failed to retrieve channel id - payload header is empty")
}
chdr, err := UnmarshalChannelHeader(payload.Header.ChannelHeader)
if err != nil {
return "", err
}
return chdr.ChannelId, nil
}
// GetMetadataFromBlock retrieves metadata at the specified index.
func GetMetadataFromBlock(block *cb.Block, index cb.BlockMetadataIndex) (*cb.Metadata, error) {
md := &cb.Metadata{}
err := proto.Unmarshal(block.Metadata.Metadata[index], md)
if err != nil {
return nil, errors.Wrapf(err, "error unmarshaling metadata from block at index [%s]", index)
}
return md, nil
}
// GetMetadataFromBlockOrPanic retrieves metadata at the specified index, or
// panics on error
func GetMetadataFromBlockOrPanic(block *cb.Block, index cb.BlockMetadataIndex) *cb.Metadata {
md, err := GetMetadataFromBlock(block, index)
if err != nil {
panic(err)
}
return md
}
// GetLastConfigIndexFromBlock retrieves the index of the last config block as
// encoded in the block metadata
func GetLastConfigIndexFromBlock(block *cb.Block) (uint64, error) {
md, err := GetMetadataFromBlock(block, cb.BlockMetadataIndex_LAST_CONFIG)
if err != nil {
return 0, err
}
lc := &cb.LastConfig{}
err = proto.Unmarshal(md.Value, lc)
if err != nil {
return 0, errors.Wrap(err, "error unmarshaling LastConfig")
}
return lc.Index, nil
}
// GetLastConfigIndexFromBlockOrPanic retrieves the index of the last config
// block as encoded in the block metadata, or panics on error
func GetLastConfigIndexFromBlockOrPanic(block *cb.Block) uint64 {
index, err := GetLastConfigIndexFromBlock(block)
if err != nil {
panic(err)
}
return index
}
// GetBlockFromBlockBytes marshals the bytes into Block
func GetBlockFromBlockBytes(blockBytes []byte) (*cb.Block, error) {
block := &cb.Block{}
err := proto.Unmarshal(blockBytes, block)
if err != nil {
return block, errors.Wrap(err, "error unmarshaling block")
}
return block, nil
}
// CopyBlockMetadata copies metadata from one block into another
func CopyBlockMetadata(src *cb.Block, dst *cb.Block) {
dst.Metadata = src.Metadata
// Once copied initialize with rest of the
// required metadata positions.
InitBlockMetadata(dst)
}
// InitBlockMetadata initializes metadata structure
func InitBlockMetadata(block *cb.Block) {
if block.Metadata == nil {
block.Metadata = &cb.BlockMetadata{Metadata: [][]byte{{}, {}, {}}}
} else if len(block.Metadata.Metadata) < int(cb.BlockMetadataIndex_TRANSACTIONS_FILTER+1) {
for i := int(len(block.Metadata.Metadata)); i <= int(cb.BlockMetadataIndex_TRANSACTIONS_FILTER); i++ {
block.Metadata.Metadata = append(block.Metadata.Metadata, []byte{})
}
}
}