Skip to content

Commit 0f3734a

Browse files
refactor(fabric): remove of fabric/protoutil
This commit moves protoutils imported from fabric into a local package, including tests. Signed-off-by: Marcus Brandenburger <bur@zurich.ibm.com>
1 parent cfd34c6 commit 0f3734a

File tree

10 files changed

+1595
-236
lines changed

10 files changed

+1595
-236
lines changed
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
/*
2+
Copyright IBM Corp. All Rights Reserved.
3+
4+
SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
package protoutil
8+
9+
import (
10+
"crypto/rand"
11+
12+
"github.com/hyperledger-labs/fabric-smart-client/pkg/utils/errors"
13+
"github.com/hyperledger-labs/fabric-smart-client/pkg/utils/proto"
14+
"github.com/hyperledger/fabric-protos-go-apiv2/common"
15+
"google.golang.org/protobuf/types/known/timestamppb"
16+
)
17+
18+
const (
19+
// NonceSize is the default NonceSize
20+
NonceSize = 24
21+
)
22+
23+
// MarshalOrPanic serializes a protobuf message and panics if this
24+
// operation fails
25+
func MarshalOrPanic(pb proto.Message) []byte {
26+
data, err := Marshal(pb)
27+
if err != nil {
28+
panic(err)
29+
}
30+
return data
31+
}
32+
33+
// Marshal serializes a protobuf message.
34+
func Marshal(pb proto.Message) ([]byte, error) {
35+
if !pb.ProtoReflect().IsValid() {
36+
return nil, errors.New("proto: Marshal called with nil")
37+
}
38+
return proto.Marshal(pb)
39+
}
40+
41+
// CreateNonce generates a nonce using the common/crypto package.
42+
func CreateNonce() ([]byte, error) {
43+
nonce, err := getRandomNonce()
44+
return nonce, errors.WithMessage(err, "error generating random nonce")
45+
}
46+
47+
func getRandomNonce() ([]byte, error) {
48+
key := make([]byte, NonceSize)
49+
50+
_, err := rand.Read(key)
51+
if err != nil {
52+
return nil, errors.Wrap(err, "error getting random bytes")
53+
}
54+
return key, nil
55+
}
56+
57+
// MakeChannelHeader creates a ChannelHeader.
58+
func MakeChannelHeader(headerType common.HeaderType, version int32, chainID string, epoch uint64) *common.ChannelHeader {
59+
tm := timestamppb.Now()
60+
tm.Nanos = 0
61+
return &common.ChannelHeader{
62+
Type: int32(headerType),
63+
Version: version,
64+
Timestamp: tm,
65+
ChannelId: chainID,
66+
Epoch: epoch,
67+
}
68+
}
69+
70+
// MakeSignatureHeader creates a SignatureHeader.
71+
func MakeSignatureHeader(serializedCreatorCertChain []byte, nonce []byte) *common.SignatureHeader {
72+
return &common.SignatureHeader{
73+
Creator: serializedCreatorCertChain,
74+
Nonce: nonce,
75+
}
76+
}
77+
78+
type Serializer interface {
79+
Serialize() ([]byte, error)
80+
}
81+
82+
// NewSignatureHeader returns a SignatureHeader with a valid nonce.
83+
func NewSignatureHeader(id Serializer) (*common.SignatureHeader, error) {
84+
creator, err := id.Serialize()
85+
if err != nil {
86+
return nil, err
87+
}
88+
nonce, err := CreateNonce()
89+
if err != nil {
90+
return nil, err
91+
}
92+
93+
return &common.SignatureHeader{
94+
Creator: creator,
95+
Nonce: nonce,
96+
}, nil
97+
}
98+
99+
// MakePayloadHeader creates a Payload Header.
100+
func MakePayloadHeader(ch *common.ChannelHeader, sh *common.SignatureHeader) *common.Header {
101+
return &common.Header{
102+
ChannelHeader: MarshalOrPanic(ch),
103+
SignatureHeader: MarshalOrPanic(sh),
104+
}
105+
}
106+
107+
// ExtractEnvelope retrieves the requested envelope from a given block and unmarshals it
108+
func ExtractEnvelope(block *common.Block, index int) (*common.Envelope, error) {
109+
if block.Data == nil {
110+
return nil, errors.New("block data is nil")
111+
}
112+
113+
envelopeCount := len(block.Data.Data)
114+
if index < 0 || index >= envelopeCount {
115+
return nil, errors.New("envelope index out of bounds")
116+
}
117+
marshaledEnvelope := block.Data.Data[index]
118+
envelope, err := GetEnvelopeFromBlock(marshaledEnvelope)
119+
err = errors.WithMessagef(err, "block data does not carry an envelope at index %d", index)
120+
return envelope, err
121+
}
Lines changed: 220 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,220 @@
1+
/*
2+
Copyright IBM Corp. All Rights Reserved.
3+
4+
SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
package protoutil
8+
9+
import (
10+
"bytes"
11+
"testing"
12+
13+
"github.com/hyperledger-labs/fabric-smart-client/pkg/utils/proto"
14+
cb "github.com/hyperledger/fabric-protos-go-apiv2/common"
15+
"github.com/stretchr/testify/require"
16+
)
17+
18+
func TestNonceRandomness(t *testing.T) {
19+
n1, err := CreateNonce()
20+
if err != nil {
21+
t.Fatal(err)
22+
}
23+
n2, err := CreateNonce()
24+
if err != nil {
25+
t.Fatal(err)
26+
}
27+
if bytes.Equal(n1, n2) {
28+
t.Fatalf("Expected nonces to be different, got %x and %x", n1, n2)
29+
}
30+
}
31+
32+
func TestNonceLength(t *testing.T) {
33+
n, err := CreateNonce()
34+
if err != nil {
35+
t.Fatal(err)
36+
}
37+
actual := len(n)
38+
expected := NonceSize
39+
if actual != expected {
40+
t.Fatalf("Expected nonce to be of size %d, got %d instead", expected, actual)
41+
}
42+
}
43+
44+
func TestUnmarshalPayload(t *testing.T) {
45+
var payload *cb.Payload
46+
good, _ := proto.Marshal(&cb.Payload{
47+
Data: []byte("payload"),
48+
})
49+
payload, err := UnmarshalPayload(good)
50+
require.NoError(t, err, "Unexpected error unmarshalling payload")
51+
require.NotNil(t, payload, "Payload should not be nil")
52+
}
53+
54+
func TestUnmarshalSignatureHeader(t *testing.T) {
55+
t.Run("invalid header", func(t *testing.T) {
56+
sighdrBytes := []byte("invalid signature header")
57+
_, err := UnmarshalSignatureHeader(sighdrBytes)
58+
require.Error(t, err, "Expected unmarshalling error")
59+
})
60+
61+
t.Run("valid empty header", func(t *testing.T) {
62+
sighdr := &cb.SignatureHeader{}
63+
sighdrBytes := MarshalOrPanic(sighdr)
64+
sighdr, err := UnmarshalSignatureHeader(sighdrBytes)
65+
require.NoError(t, err, "Unexpected error unmarshalling signature header")
66+
require.Nil(t, sighdr.Creator)
67+
require.Nil(t, sighdr.Nonce)
68+
})
69+
70+
t.Run("valid header", func(t *testing.T) {
71+
sighdr := &cb.SignatureHeader{
72+
Creator: []byte("creator"),
73+
Nonce: []byte("nonce"),
74+
}
75+
sighdrBytes := MarshalOrPanic(sighdr)
76+
sighdr, err := UnmarshalSignatureHeader(sighdrBytes)
77+
require.NoError(t, err, "Unexpected error unmarshalling signature header")
78+
require.Equal(t, []byte("creator"), sighdr.Creator)
79+
require.Equal(t, []byte("nonce"), sighdr.Nonce)
80+
})
81+
}
82+
83+
func TestUnmarshalEnvelope(t *testing.T) {
84+
var env *cb.Envelope
85+
good, _ := proto.Marshal(&cb.Envelope{})
86+
env, err := UnmarshalEnvelope(good)
87+
require.NoError(t, err, "Unexpected error unmarshalling envelope")
88+
require.NotNil(t, env, "Envelope should not be nil")
89+
}
90+
91+
func TestUnmarshalBlock(t *testing.T) {
92+
var env *cb.Block
93+
good, _ := proto.Marshal(&cb.Block{})
94+
env, err := UnmarshalBlock(good)
95+
require.NoError(t, err, "Unexpected error unmarshalling block")
96+
require.NotNil(t, env, "Block should not be nil")
97+
}
98+
99+
func TestUnmarshalEnvelopeOfType(t *testing.T) {
100+
env := &cb.Envelope{}
101+
102+
env.Payload = []byte("bad payload")
103+
_, err := UnmarshalEnvelopeOfType(env, cb.HeaderType_CONFIG, nil)
104+
require.Error(t, err, "Expected error unmarshalling malformed envelope")
105+
106+
payload, _ := proto.Marshal(&cb.Payload{
107+
Header: nil,
108+
})
109+
env.Payload = payload
110+
_, err = UnmarshalEnvelopeOfType(env, cb.HeaderType_CONFIG, nil)
111+
require.Error(t, err, "Expected error with missing payload header")
112+
113+
payload, _ = proto.Marshal(&cb.Payload{
114+
Header: &cb.Header{
115+
ChannelHeader: []byte("bad header"),
116+
},
117+
})
118+
env.Payload = payload
119+
_, err = UnmarshalEnvelopeOfType(env, cb.HeaderType_CONFIG, nil)
120+
require.Error(t, err, "Expected error for malformed channel header")
121+
122+
chdr, _ := proto.Marshal(&cb.ChannelHeader{
123+
Type: int32(cb.HeaderType_CHAINCODE_PACKAGE),
124+
})
125+
payload, _ = proto.Marshal(&cb.Payload{
126+
Header: &cb.Header{
127+
ChannelHeader: chdr,
128+
},
129+
})
130+
env.Payload = payload
131+
_, err = UnmarshalEnvelopeOfType(env, cb.HeaderType_CONFIG, nil)
132+
require.Error(t, err, "Expected error for wrong channel header type")
133+
134+
chdr, _ = proto.Marshal(&cb.ChannelHeader{
135+
Type: int32(cb.HeaderType_CONFIG),
136+
})
137+
payload, _ = proto.Marshal(&cb.Payload{
138+
Header: &cb.Header{
139+
ChannelHeader: chdr,
140+
},
141+
Data: []byte("bad data"),
142+
})
143+
env.Payload = payload
144+
_, err = UnmarshalEnvelopeOfType(env, cb.HeaderType_CONFIG, &cb.ConfigEnvelope{})
145+
require.Error(t, err, "Expected error for malformed payload data")
146+
147+
chdr, _ = proto.Marshal(&cb.ChannelHeader{
148+
Type: int32(cb.HeaderType_CONFIG),
149+
})
150+
configEnv, _ := proto.Marshal(&cb.ConfigEnvelope{})
151+
payload, _ = proto.Marshal(&cb.Payload{
152+
Header: &cb.Header{
153+
ChannelHeader: chdr,
154+
},
155+
Data: configEnv,
156+
})
157+
env.Payload = payload
158+
_, err = UnmarshalEnvelopeOfType(env, cb.HeaderType_CONFIG, &cb.ConfigEnvelope{})
159+
require.NoError(t, err, "Unexpected error unmarshalling envelope")
160+
}
161+
162+
func TestExtractEnvelopeNilData(t *testing.T) {
163+
block := &cb.Block{}
164+
_, err := ExtractEnvelope(block, 0)
165+
require.Error(t, err, "Nil data")
166+
}
167+
168+
func TestExtractEnvelopeWrongIndex(t *testing.T) {
169+
block := testBlock()
170+
if _, err := ExtractEnvelope(block, len(block.GetData().Data)); err == nil {
171+
t.Fatal("Expected envelope extraction to fail (wrong index)")
172+
}
173+
}
174+
175+
func TestExtractEnvelope(t *testing.T) {
176+
if envelope, err := ExtractEnvelope(testBlock(), 0); err != nil {
177+
t.Fatalf("Expected envelop extraction to succeed: %s", err)
178+
} else if !proto.Equal(envelope, testEnvelope()) {
179+
t.Fatal("Expected extracted envelope to match test envelope")
180+
}
181+
}
182+
183+
func TestExtractPayload(t *testing.T) {
184+
if payload, err := UnmarshalPayload(testEnvelope().Payload); err != nil {
185+
t.Fatalf("Expected payload extraction to succeed: %s", err)
186+
} else if !proto.Equal(payload, testPayload()) {
187+
t.Fatal("Expected extracted payload to match test payload")
188+
}
189+
}
190+
191+
// Helper functions
192+
193+
func testPayload() *cb.Payload {
194+
return &cb.Payload{
195+
Header: MakePayloadHeader(
196+
MakeChannelHeader(cb.HeaderType_MESSAGE, int32(1), "test", 0),
197+
MakeSignatureHeader([]byte("creator"), []byte("nonce"))),
198+
Data: []byte("test"),
199+
}
200+
}
201+
202+
func testEnvelope() *cb.Envelope {
203+
// No need to set the signature
204+
return &cb.Envelope{Payload: MarshalOrPanic(testPayload())}
205+
}
206+
207+
func testBlock() *cb.Block {
208+
// No need to set the block's Header, or Metadata
209+
return &cb.Block{
210+
Data: &cb.BlockData{
211+
Data: [][]byte{MarshalOrPanic(testEnvelope())},
212+
},
213+
}
214+
}
215+
216+
func TestGetRandomNonce(t *testing.T) {
217+
key1, err := getRandomNonce()
218+
require.NoErrorf(t, err, "error getting random bytes")
219+
require.Len(t, key1, NonceSize)
220+
}

0 commit comments

Comments
 (0)