@@ -8,10 +8,14 @@ package cluster
8
8
9
9
import (
10
10
"bytes"
11
+ "encoding/hex"
11
12
"encoding/pem"
12
13
"sync/atomic"
13
14
15
+ "github.com/hyperledger/fabric/common/util"
14
16
"github.com/hyperledger/fabric/core/comm"
17
+ "github.com/hyperledger/fabric/protos/common"
18
+ "github.com/hyperledger/fabric/protos/utils"
15
19
"github.com/pkg/errors"
16
20
"google.golang.org/grpc"
17
21
)
@@ -141,3 +145,120 @@ func DERtoPEM(der []byte) string {
141
145
Bytes : der ,
142
146
}))
143
147
}
148
+
149
+ // StandardDialerDialer wraps a PredicateDialer
150
+ // to a standard cluster.Dialer that passes in a nil verify function
151
+ type StandardDialerDialer struct {
152
+ Dialer * PredicateDialer
153
+ }
154
+
155
+ func (bdp * StandardDialerDialer ) Dial (address string ) (* grpc.ClientConn , error ) {
156
+ return bdp .Dialer .Dial (address , nil )
157
+ }
158
+
159
+ //go:generate mockery -dir . -name BlockVerifier -case underscore -output ./mocks/
160
+
161
+ // BlockVerifier verifies block signatures.
162
+ type BlockVerifier interface {
163
+ // VerifyBlockSignature verifies a signature of a block
164
+ VerifyBlockSignature (sd []* common.SignedData ) error
165
+ }
166
+
167
+ // BlockSequenceVerifier verifies that the given consecutive sequence
168
+ // of blocks is valid.
169
+ type BlockSequenceVerifier func ([]* common.Block ) error
170
+
171
+ // Dialer creates a gRPC connection to a remote address
172
+ type Dialer interface {
173
+ Dial (address string ) (* grpc.ClientConn , error )
174
+ }
175
+
176
+ // VerifyBlocks verifies the given consecutive sequence of blocks is valid,
177
+ // and returns nil if it's valid, else an error.
178
+ func VerifyBlocks (blockBuff []* common.Block , signatureVerifier BlockVerifier ) error {
179
+ if len (blockBuff ) == 0 {
180
+ return errors .New ("buffer is empty" )
181
+ }
182
+ // First, we verify that the block hash in every block is:
183
+ // Equal to the hash in the header
184
+ // Equal to the previous hash in the succeeding block
185
+ for i := range blockBuff {
186
+ if err := VerifyBlockHash (i , blockBuff ); err != nil {
187
+ return err
188
+ }
189
+ }
190
+
191
+ // Verify the last block's signature
192
+ lastBlock := blockBuff [len (blockBuff )- 1 ]
193
+ return VerifyBlockSignature (lastBlock , signatureVerifier )
194
+ }
195
+
196
+ // VerifyBlockHash verifies the hash chain of the block with the given index
197
+ // among the blocks of the given block buffer.
198
+ func VerifyBlockHash (indexInBuffer int , blockBuff []* common.Block ) error {
199
+ if len (blockBuff ) <= indexInBuffer {
200
+ return errors .Errorf ("index %d out of bounds (total %d blocks)" , indexInBuffer , len (blockBuff ))
201
+ }
202
+ block := blockBuff [indexInBuffer ]
203
+ if block .Header == nil {
204
+ return errors .New ("missing block header" )
205
+ }
206
+ seq := block .Header .Number
207
+ dataHash := block .Data .Hash ()
208
+ // Verify data hash matches the hash in the header
209
+ if ! bytes .Equal (dataHash , block .Header .DataHash ) {
210
+ computedHash := hex .EncodeToString (dataHash )
211
+ claimedHash := hex .EncodeToString (block .Header .DataHash )
212
+ return errors .Errorf ("computed hash of block (%d) (%s) doesn't match claimed hash (%s)" ,
213
+ seq , computedHash , claimedHash )
214
+ }
215
+ // We have a previous block in the buffer, ensure current block's previous hash matches the previous one.
216
+ if indexInBuffer > 0 {
217
+ prevBlock := blockBuff [indexInBuffer - 1 ]
218
+ currSeq := block .Header .Number
219
+ if prevBlock .Header == nil {
220
+ return errors .New ("previous block header is nil" )
221
+ }
222
+ prevSeq := prevBlock .Header .Number
223
+ if prevSeq + 1 != currSeq {
224
+ return errors .Errorf ("sequences %d and %d were received consecutively" , prevSeq , currSeq )
225
+ }
226
+ if ! bytes .Equal (block .Header .PreviousHash , prevBlock .Header .Hash ()) {
227
+ claimedPrevHash := hex .EncodeToString (block .Header .PreviousHash )
228
+ actualPrevHash := hex .EncodeToString (prevBlock .Header .Hash ())
229
+ return errors .Errorf ("block %d's hash (%s) mismatches %d's prev block hash (%s)" ,
230
+ currSeq , actualPrevHash , prevSeq , claimedPrevHash )
231
+ }
232
+ }
233
+ return nil
234
+ }
235
+
236
+ // VerifyBlockSignature verifies the signature on the block with the given BlockVerifier
237
+ func VerifyBlockSignature (block * common.Block , verifier BlockVerifier ) error {
238
+ if block .Metadata == nil || len (block .Metadata .Metadata ) <= int (common .BlockMetadataIndex_SIGNATURES ) {
239
+ return errors .New ("no metadata in block" )
240
+ }
241
+ metadata , err := utils .GetMetadataFromBlock (block , common .BlockMetadataIndex_SIGNATURES )
242
+ if err != nil {
243
+ return errors .Errorf ("failed unmarshaling medatata for signatures: %v" , err )
244
+ }
245
+
246
+ var signatureSet []* common.SignedData
247
+ for _ , metadataSignature := range metadata .Signatures {
248
+ sigHdr , err := utils .GetSignatureHeader (metadataSignature .SignatureHeader )
249
+ if err != nil {
250
+ return errors .Errorf ("failed unmarshaling signature header for block with id %d: %v" ,
251
+ block .Header .Number , err )
252
+ }
253
+ signatureSet = append (signatureSet ,
254
+ & common.SignedData {
255
+ Identity : sigHdr .Creator ,
256
+ Data : util .ConcatenateBytes (metadata .Value ,
257
+ metadataSignature .SignatureHeader , block .Header .Bytes ()),
258
+ Signature : metadataSignature .Signature ,
259
+ },
260
+ )
261
+ }
262
+
263
+ return verifier .VerifyBlockSignature (signatureSet )
264
+ }
0 commit comments