Skip to content

Commit a364171

Browse files
manish-sethidenyeart
authored andcommitted
FAB-12987 Fix for statedb value format check
This CR fixes a bug that causes wrong decoding of channel config persisted by the binary of fabric versions lower than 1.3. In the presence of this bug, the older channel config stored by block-0 is interpreted as of new format. See Jira for more details Change-Id: I22e728e13ddf4c6838e68b022de2478666c31d22 Signed-off-by: manish <manish.sethi@gmail.com>
1 parent 3de7306 commit a364171

File tree

2 files changed

+22
-8
lines changed

2 files changed

+22
-8
lines changed

core/ledger/kvledger/txmgmt/statedb/stateleveldb/value_encoding.go

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ import (
1313
"github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/version"
1414
)
1515

16-
// encode value encodes the versioned value
16+
// encode value encodes the versioned value. starting in v1.3 the encoding begins with a nil
17+
// byte and includes metadata.
1718
func encodeValue(v *statedb.VersionedValue) ([]byte, error) {
1819
vvMsg := &msgs.VersionedValueProto{
1920
VersionBytes: v.Version.ToBytes(),
@@ -28,6 +29,8 @@ func encodeValue(v *statedb.VersionedValue) ([]byte, error) {
2829
return encodedValue, nil
2930
}
3031

32+
// decodeValue decodes the statedb value bytes using either the old (pre-v1.3) encoding
33+
// or the new (v1.3 and later) encoding that supports metadata.
3134
func decodeValue(encodedValue []byte) (*statedb.VersionedValue, error) {
3235
if oldFormatEncoding(encodedValue) {
3336
val, ver := decodeValueOldFormat(encodedValue)
@@ -49,7 +52,7 @@ func decodeValue(encodedValue []byte) (*statedb.VersionedValue, error) {
4952
}
5053

5154
// encodeValueOldFormat appends the value to the version, allows storage of version and value in binary form.
52-
// With the intorduction of metadata feature, we change the encoding (see function below). However, we retain
55+
// With the introduction of metadata feature in v1.3, we change the encoding (see function below). However, we retain
5356
// this funtion for test so as to make sure that we can decode old format and support mixed formats present
5457
// in a statedb. This function should be used only in tests to generate the encoding in old format
5558
func encodeValueOldFormat(value []byte, version *version.Height) []byte {
@@ -62,7 +65,7 @@ func encodeValueOldFormat(value []byte, version *version.Height) []byte {
6265

6366
// decodeValueOldFormat separates the version and value from a binary value
6467
// See comments in the function `encodeValueOldFormat`. We retain this function as is
65-
// to use this for decoding the old format data present in the statedb. This function
68+
// to use this for decoding the old format (pre-v1.3) data present in the statedb. This function
6669
// should not be used directly or in a tests. The function 'decodeValue' should be used
6770
// for all decodings - which is expected to detect the encoded format and direct the call
6871
// to this function for decoding the values encoded in the old format
@@ -72,6 +75,12 @@ func decodeValueOldFormat(encodedValue []byte) ([]byte, *version.Height) {
7275
return value, height
7376
}
7477

78+
// oldFormatEncoding checks whether the value is encoded using the old (pre-v1.3) format
79+
// or new format (v1.3 and later for encoding metadata).
7580
func oldFormatEncoding(encodedValue []byte) bool {
76-
return encodedValue[0] != byte(0)
81+
return encodedValue[0] != byte(0) ||
82+
(encodedValue[0]|encodedValue[1]) == byte(0) // this check covers a corner case
83+
// where the old formatted value happens to start with a nil byte. In this corner case,
84+
// the channel config happen to be persisted for the tuple <block 0, tran 0>. So, this
85+
// is assumed that block 0 contains a single transaction (i.e., tran 0)
7786
}

core/ledger/kvledger/txmgmt/statedb/stateleveldb/value_encoding_test.go

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ func TestEncodeDecodeJSONOldFormat(t *testing.T) {
3737

3838
func TestEncodeDecodeOldAndNewFormat(t *testing.T) {
3939
testdata := []*statedb.VersionedValue{
40+
{
41+
Value: []byte("value0"),
42+
Version: version.NewHeight(0, 0),
43+
},
4044
{
4145
Value: []byte("value1"),
4246
Version: version.NewHeight(1, 2),
@@ -61,7 +65,10 @@ func TestEncodeDecodeOldAndNewFormat(t *testing.T) {
6165

6266
for i, testdatum := range testdata {
6367
t.Run(fmt.Sprintf("testcase-oldfmt-%d", i),
64-
func(t *testing.T) { testEncodeDecodeOldFormat(t, testdatum) },
68+
func(t *testing.T) {
69+
testdatum.Metadata = nil
70+
testEncodeDecodeOldFormat(t, testdatum)
71+
},
6572
)
6673
}
6774

@@ -81,7 +88,5 @@ func testEncodeDecodeOldFormat(t *testing.T, v *statedb.VersionedValue) {
8188
// decodeValue should be able to handle the old format
8289
decodedFromOldFmt, err := decodeValue(encodedOldFmt)
8390
assert.NoError(t, err)
84-
assert.Equal(t, v.Value, decodedFromOldFmt.Value)
85-
assert.Equal(t, v.Version, decodedFromOldFmt.Version)
86-
assert.Nil(t, decodedFromOldFmt.Metadata)
91+
assert.Equal(t, v, decodedFromOldFmt)
8792
}

0 commit comments

Comments
 (0)