Skip to content

Commit 8b172f5

Browse files
committed
[FAB-2498] Fix Panic upon Recover (CouchdB)
If peers starts up and there is no CouchDB state database, there is a nil pointer panic due to nil savepoint. This changeset fixes it by returning nil height when there is nil savepont. Nil height for savepoint will trigger full state db recovery upon peer startup. Added test to ensure nil height is returned in these cases. Ensured that leveldb and couchdb behave consistently now. Tested recovery on both leveldb and couchdb. Change-Id: I0f2f2f89d7d3176fcf4a560d20665bd59c4d8a5d Signed-off-by: denyeart <[email protected]>
1 parent 7134f9f commit 8b172f5

File tree

5 files changed

+19
-13
lines changed

5 files changed

+19
-13
lines changed

core/ledger/kvledger/txmgmt/statedb/commontests/test_common.go

+6-1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,11 @@ func TestBasicRW(t *testing.T, dbProvider statedb.VersionedDBProvider) {
3030
db, err := dbProvider.GetDBHandle("testbasicrw")
3131
testutil.AssertNoError(t, err, "")
3232

33+
// Test that savepoint is nil for a new state db
34+
sp, err := db.GetLatestSavePoint()
35+
testutil.AssertNoError(t, err, "Error upon GetLatestSavePoint()")
36+
testutil.AssertNil(t, sp)
37+
3338
// Test retrieval of non-existent key - returns nil rather than error
3439
// For more details see https://github.com/hyperledger-archives/fabric/issues/936.
3540
val, err := db.GetState("ns", "key1")
@@ -54,7 +59,7 @@ func TestBasicRW(t *testing.T, dbProvider statedb.VersionedDBProvider) {
5459
vv, _ = db.GetState("ns2", "key4")
5560
testutil.AssertEquals(t, vv, &vv4)
5661

57-
sp, err := db.GetLatestSavePoint()
62+
sp, err = db.GetLatestSavePoint()
5863
testutil.AssertNoError(t, err, "")
5964
testutil.AssertEquals(t, sp, savePoint)
6065
}

core/ledger/kvledger/txmgmt/statedb/statecouchdb/statecouchdb.go

+5-8
Original file line numberDiff line numberDiff line change
@@ -277,9 +277,6 @@ func (vdb *VersionedDB) ApplyUpdates(batch *statedb.UpdateBatch, height *version
277277
attachment.AttachmentBytes = vv.Value
278278
attachment.ContentType = "application/octet-stream"
279279
attachment.Name = binaryWrapper
280-
281-
attachments := []couchdb.Attachment{}
282-
attachments = append(attachments, *attachment)
283280
couchDoc.Attachments = append(couchDoc.Attachments, *attachment)
284281
couchDoc.JSONValue = addVersionAndChainCodeID(nil, ns, vv.Version)
285282
}
@@ -398,19 +395,19 @@ func (vdb *VersionedDB) GetLatestSavePoint() (*version.Height, error) {
398395
couchDoc, _, err := vdb.db.ReadDoc(savepointDocID)
399396
if err != nil {
400397
logger.Errorf("Failed to read savepoint data %s\n", err.Error())
401-
return &version.Height{BlockNum: 0, TxNum: 0}, err
398+
return nil, err
402399
}
403400

404-
// ReadDoc() not found (404) will result in nil response, in these cases return height 0
405-
if couchDoc.JSONValue == nil {
406-
return &version.Height{BlockNum: 0, TxNum: 0}, nil
401+
// ReadDoc() not found (404) will result in nil response, in these cases return height nil
402+
if couchDoc == nil || couchDoc.JSONValue == nil {
403+
return nil, nil
407404
}
408405

409406
savepointDoc := &couchSavepointData{}
410407
err = json.Unmarshal(couchDoc.JSONValue, &savepointDoc)
411408
if err != nil {
412409
logger.Errorf("Failed to unmarshal savepoint data %s\n", err.Error())
413-
return &version.Height{BlockNum: 0, TxNum: 0}, err
410+
return nil, err
414411
}
415412

416413
return &version.Height{BlockNum: savepointDoc.BlockNum, TxNum: savepointDoc.TxNum}, nil

core/ledger/kvledger/txmgmt/statedb/statecouchdb/statecouchdb_test.go

+4-1
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,12 @@ func TestMain(m *testing.M) {
3333

3434
//call a helper method to load the core.yaml, will be used to detect if CouchDB is enabled
3535
ledgertestutil.SetupCoreYAMLConfig("./../../../../../../peer")
36+
viper.Set("peer.fileSystemPath", "/tmp/fabric/ledgertests/kvledger/txmgmt/statedb/statecouchdb")
3637
viper.Set("ledger.state.stateDatabase", "CouchDB")
38+
39+
// both vagrant and CI have couchdb configured at host "couchdb"
3740
viper.Set("ledger.state.couchDBConfig.couchDBAddress", "couchdb:5984")
38-
viper.Set("peer.fileSystemPath", "/tmp/fabric/ledgertests/kvledger/txmgmt/statedb/statecouchdb")
41+
3942
result := m.Run()
4043
viper.Set("ledger.state.stateDatabase", "goleveldb")
4144
os.Exit(result)

core/ledger/kvledger/txmgmt/txmgr/commontests/pkg_test.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,8 @@ func (env *couchDBLockBasedEnv) getName() string {
113113

114114
func (env *couchDBLockBasedEnv) init(t *testing.T) {
115115
viper.Set("peer.fileSystemPath", testFilesystemPath)
116-
viper.Set("ledger.state.couchDBConfig.couchDBAddress", "127.0.0.1:5984")
116+
// both vagrant and CI have couchdb configured at host "couchdb"
117+
viper.Set("ledger.state.couchDBConfig.couchDBAddress", "couchdb:5984")
117118
testDBEnv := statecouchdb.NewTestVDBEnv(t)
118119
testDB, err := testDBEnv.DBProvider.GetDBHandle(couchTestChainID)
119120
testutil.AssertNoError(t, err, "")

peer/core.yaml

+2-2
Original file line numberDiff line numberDiff line change
@@ -211,9 +211,9 @@ peer:
211211
Hash: SHA2
212212
Security: 256
213213
# Location of Key Store, can be subdirectory of SbftLocal.DataDir
214-
FileKeyStore:
214+
FileKeyStore:
215215
# If "", defaults to 'mspConfigPath'/keystore
216-
KeyStore:
216+
KeyStore:
217217

218218
# Path on the file system where peer will find MSP local configurations
219219
mspConfigPath: msp/sampleconfig

0 commit comments

Comments
 (0)