@@ -15,6 +15,7 @@ import (
15
15
"github.com/hyperledger/fabric/common/flogging"
16
16
"github.com/hyperledger/fabric/core/comm"
17
17
"github.com/hyperledger/fabric/protos/common"
18
+ "github.com/hyperledger/fabric/protos/utils"
18
19
"github.com/pkg/errors"
19
20
)
20
21
@@ -84,3 +85,115 @@ type NoopBlockVerifier struct{}
84
85
func (* NoopBlockVerifier ) VerifyBlockSignature (sd []* common.SignedData , config * common.ConfigEnvelope ) error {
85
86
return nil
86
87
}
88
+
89
+ //go:generate mockery -dir . -name ChainPuller -case underscore -output mocks/
90
+
91
+ // ChainPuller pulls blocks from a chain
92
+ type ChainPuller interface {
93
+ // PullBlock pulls the given block from some orderer node
94
+ PullBlock (seq uint64 ) * common.Block
95
+ // Close closes the ChainPuller
96
+ Close ()
97
+ }
98
+
99
+ // ChainInspector walks over a chain
100
+ type ChainInspector struct {
101
+ Logger * flogging.FabricLogger
102
+ Puller ChainPuller
103
+ LastConfigBlock * common.Block
104
+ }
105
+
106
+ // Channels returns the list of channels
107
+ // that exist in the chain
108
+ func (cw * ChainInspector ) Channels () []string {
109
+ channels := make (map [string ]struct {})
110
+ lastConfigBlockNum := cw .LastConfigBlock .Header .Number
111
+ var block * common.Block
112
+ for seq := uint64 (1 ); seq < lastConfigBlockNum ; seq ++ {
113
+ block = cw .Puller .PullBlock (seq )
114
+ channel , err := IsNewChannelBlock (block )
115
+ if err != nil {
116
+ // If we failed to classify a block, something is wrong in the system chain
117
+ // we're trying to pull, so abort.
118
+ cw .Logger .Panic ("Failed classifying block" , seq , ":" , err )
119
+ continue
120
+ }
121
+ if channel == "" {
122
+ cw .Logger .Info ("Block" , seq , "doesn't contain a new channel" )
123
+ continue
124
+ }
125
+ cw .Logger .Info ("Block" , seq , "contains channel" , channel )
126
+ channels [channel ] = struct {}{}
127
+ }
128
+ // At this point, block holds reference to the last block pulled.
129
+ // We ensure that the hash of the last block pulled, is the previous hash
130
+ // of the LastConfigBlock we were initialized with.
131
+ // We don't need to verify the entire chain of all blocks we pulled,
132
+ // because the block puller calls VerifyBlockHash on all blocks it pulls.
133
+ last2Blocks := []* common.Block {block , cw .LastConfigBlock }
134
+ if err := VerifyBlockHash (1 , last2Blocks ); err != nil {
135
+ cw .Logger .Panic ("System channel pulled doesn't match the boot last config block:" , err )
136
+ }
137
+
138
+ return flattenChannelMap (channels )
139
+ }
140
+
141
+ func flattenChannelMap (m map [string ]struct {}) []string {
142
+ var res []string
143
+ for channel := range m {
144
+ res = append (res , channel )
145
+ }
146
+ return res
147
+ }
148
+
149
+ // IsNewChannelBlock returns a name of the channel in case
150
+ // it holds a channel create transaction, or empty string otherwise.
151
+ func IsNewChannelBlock (block * common.Block ) (string , error ) {
152
+ if block == nil {
153
+ return "" , errors .New ("nil block" )
154
+ }
155
+ env , err := utils .ExtractEnvelope (block , 0 )
156
+ if err != nil {
157
+ return "" , err
158
+ }
159
+ payload , err := utils .ExtractPayload (env )
160
+ if err != nil {
161
+ return "" , err
162
+ }
163
+ if payload .Header == nil {
164
+ return "" , errors .New ("nil header in payload" )
165
+ }
166
+ chdr , err := utils .UnmarshalChannelHeader (payload .Header .ChannelHeader )
167
+ if err != nil {
168
+ return "" , err
169
+ }
170
+ // The transaction is an orderer transaction
171
+ if common .HeaderType (chdr .Type ) != common .HeaderType_ORDERER_TRANSACTION {
172
+ return "" , nil
173
+ }
174
+ systemChannelName := chdr .ChannelId
175
+ innerEnvelope , err := utils .UnmarshalEnvelope (payload .Data )
176
+ if err != nil {
177
+ return "" , err
178
+ }
179
+ innerPayload , err := utils .UnmarshalPayload (innerEnvelope .Payload )
180
+ if err != nil {
181
+ return "" , err
182
+ }
183
+ if innerPayload .Header == nil {
184
+ return "" , errors .New ("inner payload's header is nil" )
185
+ }
186
+ chdr , err = utils .UnmarshalChannelHeader (innerPayload .Header .ChannelHeader )
187
+ if err != nil {
188
+ return "" , err
189
+ }
190
+ // The inner payload's header is a config transaction
191
+ if common .HeaderType (chdr .Type ) != common .HeaderType_CONFIG {
192
+ return "" , nil
193
+ }
194
+ // In any case, exclude all system channel transactions
195
+ if chdr .ChannelId == systemChannelName {
196
+ return "" , nil
197
+ }
198
+ return chdr .ChannelId , nil
199
+ }
0 commit comments