-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathproputils_test.go
419 lines (362 loc) · 12 KB
/
proputils_test.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
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
/*
Copyright IBM Corp. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/
package protoutil_test
import (
"bytes"
"crypto/sha256"
"encoding/hex"
"testing"
"github.com/davidkhala/protoutil"
"github.com/hyperledger/fabric-protos-go-apiv2/common"
pb "github.com/hyperledger/fabric-protos-go-apiv2/peer"
"github.com/stretchr/testify/require"
"google.golang.org/protobuf/proto"
)
func createCIS() *pb.ChaincodeInvocationSpec {
return &pb.ChaincodeInvocationSpec{
ChaincodeSpec: &pb.ChaincodeSpec{
Type: pb.ChaincodeSpec_GOLANG,
ChaincodeId: &pb.ChaincodeID{Name: "chaincode_name"},
Input: &pb.ChaincodeInput{Args: [][]byte{[]byte("arg1"), []byte("arg2")}},
},
}
}
func TestGetChaincodeDeploymentSpec(t *testing.T) {
_, err := protoutil.UnmarshalChaincodeDeploymentSpec([]byte("bad spec"))
require.Error(t, err, "Expected error with malformed spec")
cds, _ := proto.Marshal(&pb.ChaincodeDeploymentSpec{
ChaincodeSpec: &pb.ChaincodeSpec{
Type: pb.ChaincodeSpec_GOLANG,
},
})
_, err = protoutil.UnmarshalChaincodeDeploymentSpec(cds)
require.NoError(t, err, "Unexpected error getting deployment spec")
}
func TestCDSProposals(t *testing.T) {
var prop *pb.Proposal
var err error
var txid string
creator := []byte("creator")
cds := &pb.ChaincodeDeploymentSpec{
ChaincodeSpec: &pb.ChaincodeSpec{
Type: pb.ChaincodeSpec_GOLANG,
},
}
policy := []byte("policy")
escc := []byte("escc")
vscc := []byte("vscc")
chainID := "testchannelid"
// install
prop, txid, err = protoutil.CreateInstallProposalFromCDS(cds, creator)
require.NotNil(t, prop, "Install proposal should not be nil")
require.NoError(t, err, "Unexpected error creating install proposal")
require.NotEqual(t, "", txid, "txid should not be empty")
// deploy
prop, txid, err = protoutil.CreateDeployProposalFromCDS(chainID, cds, creator, policy, escc, vscc, nil)
require.NotNil(t, prop, "Deploy proposal should not be nil")
require.NoError(t, err, "Unexpected error creating deploy proposal")
require.NotEqual(t, "", txid, "txid should not be empty")
// upgrade
prop, txid, err = protoutil.CreateUpgradeProposalFromCDS(chainID, cds, creator, policy, escc, vscc, nil)
require.NotNil(t, prop, "Upgrade proposal should not be nil")
require.NoError(t, err, "Unexpected error creating upgrade proposal")
require.NotEqual(t, "", txid, "txid should not be empty")
}
func TestProposal(t *testing.T) {
// create a proposal from a ChaincodeInvocationSpec
prop, _, err := protoutil.CreateChaincodeProposalWithTransient(
common.HeaderType_ENDORSER_TRANSACTION,
testChannelID, createCIS(),
[]byte("creator"),
map[string][]byte{"certx": []byte("transient")})
if err != nil {
t.Fatalf("Could not create chaincode proposal, err %s\n", err)
return
}
// serialize the proposal
pBytes, err := proto.Marshal(prop)
if err != nil {
t.Fatalf("Could not serialize the chaincode proposal, err %s\n", err)
return
}
// deserialize it and expect it to be the same
propBack, err := protoutil.UnmarshalProposal(pBytes)
if err != nil {
t.Fatalf("Could not deserialize the chaincode proposal, err %s\n", err)
return
}
if !proto.Equal(prop, propBack) {
t.Fatalf("Proposal and deserialized proposals don't match\n")
return
}
// get back the header
hdr, err := protoutil.UnmarshalHeader(prop.Header)
if err != nil {
t.Fatalf("Could not extract the header from the proposal, err %s\n", err)
}
hdrBytes, err := protoutil.GetBytesHeader(hdr)
if err != nil {
t.Fatalf("Could not marshal the header, err %s\n", err)
}
hdr, err = protoutil.UnmarshalHeader(hdrBytes)
if err != nil {
t.Fatalf("Could not unmarshal the header, err %s\n", err)
}
chdr, err := protoutil.UnmarshalChannelHeader(hdr.ChannelHeader)
if err != nil {
t.Fatalf("Could not unmarshal channel header, err %s", err)
}
shdr, err := protoutil.UnmarshalSignatureHeader(hdr.SignatureHeader)
if err != nil {
t.Fatalf("Could not unmarshal signature header, err %s", err)
}
_, err = protoutil.GetBytesSignatureHeader(shdr)
if err != nil {
t.Fatalf("Could not marshal signature header, err %s", err)
}
// sanity check on header
if chdr.Type != int32(common.HeaderType_ENDORSER_TRANSACTION) ||
shdr.Nonce == nil ||
string(shdr.Creator) != "creator" {
t.Fatalf("Invalid header after unmarshalling\n")
return
}
// get back the header extension
hdrExt, err := protoutil.UnmarshalChaincodeHeaderExtension(chdr.Extension)
if err != nil {
t.Fatalf("Could not extract the header extensions from the proposal, err %s\n", err)
return
}
// sanity check on header extension
if string(hdrExt.ChaincodeId.Name) != "chaincode_name" {
t.Fatalf("Invalid header extension after unmarshalling\n")
return
}
cpp, err := protoutil.UnmarshalChaincodeProposalPayload(prop.Payload)
if err != nil {
t.Fatalf("could not unmarshal proposal payload")
}
cis, err := protoutil.UnmarshalChaincodeInvocationSpec(cpp.Input)
if err != nil {
t.Fatalf("could not unmarshal proposal chaincode invocation spec")
}
// sanity check on cis
if cis.ChaincodeSpec.Type != pb.ChaincodeSpec_GOLANG ||
cis.ChaincodeSpec.ChaincodeId.Name != "chaincode_name" ||
len(cis.ChaincodeSpec.Input.Args) != 2 ||
string(cis.ChaincodeSpec.Input.Args[0]) != "arg1" ||
string(cis.ChaincodeSpec.Input.Args[1]) != "arg2" {
t.Fatalf("Invalid chaincode invocation spec after unmarshalling\n")
return
}
if string(shdr.Creator) != "creator" {
t.Fatalf("Failed checking Creator field. Invalid value, expectext 'creator', got [%s]", string(shdr.Creator))
return
}
value, ok := cpp.TransientMap["certx"]
if !ok || string(value) != "transient" {
t.Fatalf("Failed checking Transient field. Invalid value, expectext 'transient', got [%s]", string(value))
return
}
}
func TestProposalWithTxID(t *testing.T) {
// create a proposal from a ChaincodeInvocationSpec
prop, txid, err := protoutil.CreateChaincodeProposalWithTxIDAndTransient(
common.HeaderType_ENDORSER_TRANSACTION,
testChannelID,
createCIS(),
[]byte("creator"),
"testtx",
map[string][]byte{"certx": []byte("transient")},
)
require.Nil(t, err)
require.NotNil(t, prop)
require.Equal(t, txid, "testtx")
prop, txid, err = protoutil.CreateChaincodeProposalWithTxIDAndTransient(
common.HeaderType_ENDORSER_TRANSACTION,
testChannelID,
createCIS(),
[]byte("creator"),
"",
map[string][]byte{"certx": []byte("transient")},
)
require.Nil(t, err)
require.NotNil(t, prop)
require.NotEmpty(t, txid)
}
func TestProposalResponse(t *testing.T) {
events := &pb.ChaincodeEvent{
ChaincodeId: "ccid",
EventName: "EventName",
Payload: []byte("EventPayload"),
TxId: "TxID",
}
ccid := &pb.ChaincodeID{
Name: "ccid",
Version: "v1",
}
pHashBytes := []byte("proposal_hash")
pResponse := &pb.Response{Status: 200}
results := []byte("results")
eventBytes, err := protoutil.GetBytesChaincodeEvent(events)
if err != nil {
t.Fatalf("Failure while marshalling the ProposalResponsePayload")
return
}
// get the bytes of the response
pResponseBytes, err := protoutil.GetBytesResponse(pResponse)
if err != nil {
t.Fatalf("Failure while marshalling the Response")
return
}
// get the response from bytes
_, err = protoutil.UnmarshalResponse(pResponseBytes)
if err != nil {
t.Fatalf("Failure while unmarshalling the Response")
return
}
// get the bytes of the ProposalResponsePayload
prpBytes, err := protoutil.GetBytesProposalResponsePayload(pHashBytes, pResponse, results, eventBytes, ccid)
if err != nil {
t.Fatalf("Failure while marshalling the ProposalResponsePayload")
return
}
// get the ProposalResponsePayload message
prp, err := protoutil.UnmarshalProposalResponsePayload(prpBytes)
if err != nil {
t.Fatalf("Failure while unmarshalling the ProposalResponsePayload")
return
}
// get the ChaincodeAction message
act, err := protoutil.UnmarshalChaincodeAction(prp.Extension)
if err != nil {
t.Fatalf("Failure while unmarshalling the ChaincodeAction")
return
}
// sanity check on the action
if string(act.Results) != "results" {
t.Fatalf("Invalid actions after unmarshalling")
return
}
event, err := protoutil.UnmarshalChaincodeEvents(act.Events)
if err != nil {
t.Fatalf("Failure while unmarshalling the ChainCodeEvents")
return
}
// sanity check on the event
if string(event.ChaincodeId) != "ccid" {
t.Fatalf("Invalid actions after unmarshalling")
return
}
pr := &pb.ProposalResponse{
Payload: prpBytes,
Endorsement: &pb.Endorsement{Endorser: []byte("endorser"), Signature: []byte("signature")},
Version: 1, // TODO: pick right version number
Response: &pb.Response{Status: 200, Message: "OK"},
}
// create a proposal response
prBytes, err := protoutil.GetBytesProposalResponse(pr)
if err != nil {
t.Fatalf("Failure while marshalling the ProposalResponse")
return
}
// get the proposal response message back
prBack, err := protoutil.UnmarshalProposalResponse(prBytes)
if err != nil {
t.Fatalf("Failure while unmarshalling the ProposalResponse")
return
}
// sanity check on pr
if prBack.Response.Status != 200 ||
string(prBack.Endorsement.Signature) != "signature" ||
string(prBack.Endorsement.Endorser) != "endorser" ||
!bytes.Equal(prBack.Payload, prpBytes) {
t.Fatalf("Invalid ProposalResponse after unmarshalling")
return
}
}
func TestProposalTxID(t *testing.T) {
nonce := []byte{1}
creator := []byte{2}
txid := protoutil.ComputeTxID(nonce, creator)
require.NotEmpty(t, txid, "TxID cannot be empty.")
require.Nil(t, protoutil.CheckTxID(txid, nonce, creator))
require.Error(t, protoutil.CheckTxID("", nonce, creator))
txid = protoutil.ComputeTxID(nil, nil)
require.NotEmpty(t, txid, "TxID cannot be empty.")
}
func TestComputeProposalTxID(t *testing.T) {
txid := protoutil.ComputeTxID([]byte{1}, []byte{1})
// Compute the function computed by ComputeTxID,
// namely, base64(sha256(nonce||creator))
hf := sha256.New()
hf.Write([]byte{1})
hf.Write([]byte{1})
hashOut := hf.Sum(nil)
txid2 := hex.EncodeToString(hashOut)
t.Logf("%x\n", hashOut)
t.Logf("%s\n", txid)
t.Logf("%s\n", txid2)
require.Equal(t, txid, txid2)
}
var (
signerSerialized []byte
)
func TestInvokedChaincodeName(t *testing.T) {
t.Run("Success", func(t *testing.T) {
name, err := protoutil.InvokedChaincodeName(protoutil.MarshalOrPanic(&pb.Proposal{
Payload: protoutil.MarshalOrPanic(&pb.ChaincodeProposalPayload{
Input: protoutil.MarshalOrPanic(&pb.ChaincodeInvocationSpec{
ChaincodeSpec: &pb.ChaincodeSpec{
ChaincodeId: &pb.ChaincodeID{
Name: "cscc",
},
},
}),
}),
}))
require.NoError(t, err)
require.Equal(t, "cscc", name)
})
t.Run("BadProposalBytes", func(t *testing.T) {
_, err := protoutil.InvokedChaincodeName([]byte("garbage"))
require.Error(t, err)
require.Contains(t, err.Error(), "could not unmarshal proposal")
})
t.Run("BadChaincodeProposalBytes", func(t *testing.T) {
_, err := protoutil.InvokedChaincodeName(protoutil.MarshalOrPanic(&pb.Proposal{
Payload: []byte("garbage"),
}))
require.Error(t, err)
require.Contains(t, err.Error(), "could not unmarshal chaincode proposal payload")
})
t.Run("BadChaincodeInvocationSpec", func(t *testing.T) {
_, err := protoutil.InvokedChaincodeName(protoutil.MarshalOrPanic(&pb.Proposal{
Payload: protoutil.MarshalOrPanic(&pb.ChaincodeProposalPayload{
Input: []byte("garbage"),
}),
}))
require.Error(t, err)
require.Contains(t, err.Error(), "could not unmarshal chaincode invocation spec")
})
t.Run("NilChaincodeSpec", func(t *testing.T) {
_, err := protoutil.InvokedChaincodeName(protoutil.MarshalOrPanic(&pb.Proposal{
Payload: protoutil.MarshalOrPanic(&pb.ChaincodeProposalPayload{
Input: protoutil.MarshalOrPanic(&pb.ChaincodeInvocationSpec{}),
}),
}))
require.EqualError(t, err, "chaincode spec is nil")
})
t.Run("NilChaincodeID", func(t *testing.T) {
_, err := protoutil.InvokedChaincodeName(protoutil.MarshalOrPanic(&pb.Proposal{
Payload: protoutil.MarshalOrPanic(&pb.ChaincodeProposalPayload{
Input: protoutil.MarshalOrPanic(&pb.ChaincodeInvocationSpec{
ChaincodeSpec: &pb.ChaincodeSpec{},
}),
}),
}))
require.EqualError(t, err, "chaincode id is nil")
})
}