Skip to content

Commit 66aef3c

Browse files
committed
[FAB-7816] Fix cc event handling and debug
Chaincode event handling was intended to pick up LSCC chaincode updates, but was also picking up LSCC chaincode collection updates. This change ignores chaincode collection updates. Additionally, related chaincode event debug is improved. Note that two copies of Collecion-specific constants were found. The unused duplicate is removed from lscc. Change-Id: I8d7c4320d757a7d3327bd2bb22bba0b653febc23 Signed-off-by: David Enyeart <enyeart@us.ibm.com>
1 parent 6921a19 commit 66aef3c

File tree

7 files changed

+106
-34
lines changed

7 files changed

+106
-34
lines changed

core/common/privdata/collection.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ SPDX-License-Identifier: Apache-2.0
77
package privdata
88

99
import (
10+
"strings"
11+
1012
"github.com/hyperledger/fabric/protos/common"
1113
)
1214

@@ -77,7 +79,7 @@ type CollectionStore interface {
7779
const (
7880
// Collecion-specific constants
7981

80-
// collectionSeparator is the separator used to build the KVS
82+
// CollectionSeparator is the separator used to build the KVS
8183
// key storing the collections of a chaincode; note that we are
8284
// using as separator a character which is illegal for either the
8385
// name or the version of a chaincode so there cannot be any
@@ -92,3 +94,8 @@ const (
9294
func BuildCollectionKVSKey(ccname string) string {
9395
return ccname + collectionSeparator + collectionSuffix
9496
}
97+
98+
// IsCollectionConfigKey detects if a key is a collection key
99+
func IsCollectionConfigKey(key string) bool {
100+
return strings.Contains(key, collectionSeparator)
101+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*
2+
Copyright IBM Corp. All Rights Reserved.
3+
4+
SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
package privdata
8+
9+
import (
10+
"testing"
11+
12+
"github.com/stretchr/testify/assert"
13+
)
14+
15+
func TestBuildCollectionKVSKey(t *testing.T) {
16+
17+
chaincodeCollectionKey := BuildCollectionKVSKey("chaincodeKey")
18+
assert.Equal(t, "chaincodeKey~collection", chaincodeCollectionKey, "collection keys should end in ~collection")
19+
}
20+
21+
func TestIsCollectionConfigKey(t *testing.T) {
22+
23+
isCollection := IsCollectionConfigKey("chaincodeKey")
24+
assert.False(t, isCollection, "key without tilda is not a collection key and should have returned false")
25+
26+
isCollection = IsCollectionConfigKey("chaincodeKey~collection")
27+
assert.True(t, isCollection, "key with tilda is a collection key and should have returned true")
28+
}

core/ledger/cceventmgmt/lsccstate_listener.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111

1212
"github.com/golang/protobuf/proto"
1313
"github.com/hyperledger/fabric/core/common/ccprovider"
14+
"github.com/hyperledger/fabric/core/common/privdata"
1415
"github.com/hyperledger/fabric/core/ledger"
1516
"github.com/hyperledger/fabric/protos/ledger/rwset/kvrwset"
1617
)
@@ -24,12 +25,21 @@ type KVLedgerLSCCStateListener struct {
2425
// artifacts for the chaincode statedata)
2526
func (listener *KVLedgerLSCCStateListener) HandleStateUpdates(channelName string, stateUpdates ledger.StateUpdates) error {
2627
kvWrites := stateUpdates.([]*kvrwset.KVWrite)
27-
logger.Debugf("HandleStateUpdates() - channelName=%s, stateUpdates=%#v", channelName, kvWrites)
28+
logger.Debugf("Channel [%s]: Handling state updates in LSCC namespace - stateUpdates=%#v", channelName, kvWrites)
2829
chaincodeDefs := []*ChaincodeDefinition{}
2930
for _, kvWrite := range kvWrites {
31+
// There are LSCC entries for the chaincode and for the chaincode collections.
32+
// We need to ignore changes to chaincode collections, and handle changes to chaincode
33+
// We can detect collections based on the presence of a CollectionSeparator, which never exists in chaincode names
34+
if privdata.IsCollectionConfigKey(kvWrite.Key) {
35+
continue
36+
}
37+
// Ignore delete events
3038
if kvWrite.IsDelete {
3139
continue
3240
}
41+
// Chaincode instantiate/upgrade is not logged on committing peer anywhere else. This is a good place to log it.
42+
logger.Infof("Channel [%s]: Handling LSCC state update for chaincode [%s]", channelName, kvWrite.Key)
3343
chaincodeData := &ccprovider.ChaincodeData{}
3444
if err := proto.Unmarshal(kvWrite.Value, chaincodeData); err != nil {
3545
return fmt.Errorf("Unmarshalling ChaincodeQueryResponse failed, error %s", err)

core/ledger/cceventmgmt/mgmt_test.go

Lines changed: 43 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -66,24 +66,57 @@ func TestCCEventMgmt(t *testing.T) {
6666

6767
func TestLSCCListener(t *testing.T) {
6868
channelName := "testChannel"
69-
cc1Def := &ChaincodeDefinition{Name: "testChaincode", Version: "v1", Hash: []byte("hash_testChaincode")}
70-
cc1DBArtifactsTar := []byte("cc1DBArtifacts")
71-
// cc1 is installed but not deployed
69+
70+
cc1Def := &ChaincodeDefinition{Name: "testChaincode1", Version: "v1", Hash: []byte("hash_testChaincode")}
71+
cc2Def := &ChaincodeDefinition{Name: "testChaincode2", Version: "v1", Hash: []byte("hash_testChaincode")}
72+
cc3Def := &ChaincodeDefinition{Name: "testChaincode~collection", Version: "v1", Hash: []byte("hash_testChaincode")}
73+
74+
ccDBArtifactsTar := []byte("ccDBArtifacts")
75+
76+
// cc1, cc2, cc3 installed but not deployed
7277
mockProvider := newMockProvider()
73-
mockProvider.setChaincodeInstalled(cc1Def, cc1DBArtifactsTar)
78+
mockProvider.setChaincodeInstalled(cc1Def, ccDBArtifactsTar)
79+
mockProvider.setChaincodeInstalled(cc2Def, ccDBArtifactsTar)
80+
mockProvider.setChaincodeInstalled(cc3Def, ccDBArtifactsTar)
81+
7482
setEventMgrForTest(newMgr(mockProvider))
7583
defer clearEventMgrForTest()
7684
handler1 := &mockHandler{}
7785
GetMgr().Register(channelName, handler1)
7886
lsccStateListener := &KVLedgerLSCCStateListener{}
7987

80-
sampleChaincodeData := &ccprovider.ChaincodeData{Name: cc1Def.Name, Version: cc1Def.Version, Id: cc1Def.Hash}
81-
sampleChaincodeDataBytes, err := proto.Marshal(sampleChaincodeData)
82-
assert.NoError(t, err, "")
83-
lsccStateListener.HandleStateUpdates(channelName, []*kvrwset.KVWrite{
84-
{Key: cc1Def.Name, Value: sampleChaincodeDataBytes},
88+
// test1 regular deploy lscc event gets sent to handler
89+
t.Run("DeployEvent", func(t *testing.T) {
90+
sampleChaincodeData1 := &ccprovider.ChaincodeData{Name: cc1Def.Name, Version: cc1Def.Version, Id: cc1Def.Hash}
91+
sampleChaincodeDataBytes1, err := proto.Marshal(sampleChaincodeData1)
92+
assert.NoError(t, err, "")
93+
lsccStateListener.HandleStateUpdates(channelName, []*kvrwset.KVWrite{
94+
{Key: cc1Def.Name, Value: sampleChaincodeDataBytes1},
95+
})
96+
assert.Contains(t, handler1.eventsRecieved, &mockEvent{cc1Def, ccDBArtifactsTar})
97+
})
98+
99+
// test2 delete lscc event NOT sent to handler
100+
t.Run("DeleteEvent", func(t *testing.T) {
101+
sampleChaincodeData2 := &ccprovider.ChaincodeData{Name: cc2Def.Name, Version: cc2Def.Version, Id: cc2Def.Hash}
102+
sampleChaincodeDataBytes2, err := proto.Marshal(sampleChaincodeData2)
103+
assert.NoError(t, err, "")
104+
lsccStateListener.HandleStateUpdates(channelName, []*kvrwset.KVWrite{
105+
{Key: cc2Def.Name, Value: sampleChaincodeDataBytes2, IsDelete: true},
106+
})
107+
assert.NotContains(t, handler1.eventsRecieved, &mockEvent{cc2Def, ccDBArtifactsTar})
108+
})
109+
110+
// test3 collection lscc event (with tilda separator in chaincode key) NOT sent to handler
111+
t.Run("CollectionEvent", func(t *testing.T) {
112+
sampleChaincodeData3 := &ccprovider.ChaincodeData{Name: cc3Def.Name, Version: cc3Def.Version, Id: cc3Def.Hash}
113+
sampleChaincodeDataBytes3, err := proto.Marshal(sampleChaincodeData3)
114+
assert.NoError(t, err, "")
115+
lsccStateListener.HandleStateUpdates(channelName, []*kvrwset.KVWrite{
116+
{Key: cc3Def.Name, Value: sampleChaincodeDataBytes3},
117+
})
118+
assert.NotContains(t, handler1.eventsRecieved, &mockEvent{cc3Def, ccDBArtifactsTar})
85119
})
86-
assert.Contains(t, handler1.eventsRecieved, &mockEvent{cc1Def, cc1DBArtifactsTar})
87120
}
88121

89122
type mockProvider struct {

core/ledger/cceventmgmt/mgr.go

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ func (m *Mgr) Register(ledgerid string, l ChaincodeLifecycleEventListener) {
7272
// the deployed chaincode. So, in function `HandleChaincodeInstall`, we explicitly check for chaincode deployed
7373
// in this stored `chaincodeDefinitions`
7474
func (m *Mgr) HandleChaincodeDeploy(chainid string, chaincodeDefinitions []*ChaincodeDefinition) error {
75-
logger.Debugf("HandleChaincodeDeploy() - chainid=%s, chaincodeDefinition=%s", chainid, chaincodeDefinitions)
75+
logger.Debugf("Channel [%s]: Handling chaincode deploy event for chaincode [%s]", chainid, chaincodeDefinitions)
7676
// Read lock to allow concurrent deploy on multiple channels but to synchronize concurrent `chaincode insall` operation
7777
m.rwlock.RLock()
7878
defer m.rwlock.RUnlock()
@@ -84,14 +84,15 @@ func (m *Mgr) HandleChaincodeDeploy(chainid string, chaincodeDefinitions []*Chai
8484
return err
8585
}
8686
if !installed {
87-
logger.Infof("Chaincode [%s] is not installed hence not creating statedb indexes", chaincodeDefinition)
87+
logger.Infof("Channel [%s]: Chaincode [%s] is not installed hence no need to create chaincode artifacts for endorsement",
88+
chainid, chaincodeDefinition)
8889
continue
8990
}
9091
if err := m.invokeHandler(chainid, chaincodeDefinition, dbArtifacts); err != nil {
91-
logger.Warningf("Error while invoking a listener for handling chaincode install event: %s", err)
92+
logger.Warningf("Channel [%s]: Error while invoking a listener for handling chaincode install event: %s", chainid, err)
9293
return err
9394
}
94-
logger.Infof("Created statedb indexes successfully for Chaincode [%s] on channel [%s]", chaincodeDefinition, chainid)
95+
logger.Debugf("Channel [%s]: Handled chaincode deploy event for chaincode [%s]", chainid, chaincodeDefinitions)
9596
}
9697
return nil
9798
}
@@ -103,25 +104,26 @@ func (m *Mgr) HandleChaincodeInstall(chaincodeDefinition *ChaincodeDefinition, d
103104
m.rwlock.Lock()
104105
defer m.rwlock.Unlock()
105106
for chainid := range m.ccLifecycleListeners {
106-
logger.Infof("Handling chaincode install event for chain = %s", chainid)
107+
logger.Debugf("Channel [%s]: Handling chaincode install event for chaincode [%s]", chainid, chaincodeDefinition)
107108
var deployed bool
108109
var err error
109110
deployed = m.isChaincodePresentInLatestDeploys(chainid, chaincodeDefinition)
110111
if !deployed {
111112
if deployed, err = m.infoProvider.IsChaincodeDeployed(chainid, chaincodeDefinition); err != nil {
112-
logger.Warningf("Error while getting the deployment status of chaincode: %s", err)
113+
logger.Warningf("Channel [%s]: Error while getting the deployment status of chaincode: %s", chainid, err)
113114
return err
114115
}
115116
}
116117
if !deployed {
117-
logger.Info("chaincode [%s] is not deployed hence ignoring the install event", chaincodeDefinition)
118+
logger.Debugf("Channel [%s]: Chaincode [%s] is not deployed on channel hence not creating chaincode artifacts.",
119+
chainid, chaincodeDefinition)
118120
continue
119121
}
120122
if err := m.invokeHandler(chainid, chaincodeDefinition, dbArtifacts); err != nil {
121-
logger.Warningf("Error while invoking a listener for handling chaincode install event: %s", err)
123+
logger.Warningf("Channel [%s]: Error while invoking a listener for handling chaincode install event: %s", chainid, err)
122124
return err
123125
}
124-
logger.Infof("Created statedb indexes successfully for Chaincode [%s] on channel [%s]", chaincodeDefinition, chainid)
126+
logger.Debugf("Channel [%s]: Handled chaincode install event for chaincode [%s]", chainid, chaincodeDefinition)
125127
}
126128
return nil
127129
}

core/ledger/util/couchdb/couchdb.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,7 @@ func (dbclient *CouchDatabase) CreateDatabaseIfNotExist() (*DBOperationResponse,
296296
json.NewDecoder(resp.Body).Decode(&dbResponse)
297297

298298
if dbResponse.Ok == true {
299-
logger.Debugf("Created database %s ", dbclient.DBName)
299+
logger.Infof("Created state database %s", dbclient.DBName)
300300
}
301301

302302
logger.Debugf("Exiting CreateDatabaseIfNotExist()")
@@ -1120,6 +1120,8 @@ func (dbclient *CouchDatabase) CreateIndex(indexdefinition string) error {
11201120
}
11211121
defer closeResponseBody(resp)
11221122

1123+
logger.Infof("Created CouchDB index in state database %s", dbclient.DBName)
1124+
11231125
return nil
11241126

11251127
}

core/scc/lscc/lscc.go

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -78,18 +78,6 @@ const (
7878

7979
allowedCharsChaincodeName = "[A-Za-z0-9_-]+"
8080
allowedCharsVersion = "[A-Za-z0-9_.+-]+"
81-
82-
// Collecion-specific constants
83-
84-
// collectionSeparator is the separator used to build the KVS
85-
// key storing the collections of a chaincode; note that we are
86-
// using as separator a character which is illegal for either the
87-
// name or the version of a chaincode so there cannot be any
88-
// collisions when chosing the name
89-
collectionSeparator = "~"
90-
// collectionSuffix is the suffix of the KVS key storing the
91-
// collections of a chaincode
92-
collectionSuffix = "collection"
9381
)
9482

9583
// Support contains functions that LSCC requires to execute its tasks
@@ -421,6 +409,8 @@ func (lscc *lifeCycleSysCC) executeInstall(stub shim.ChaincodeStubInterface, ccb
421409
return err
422410
}
423411

412+
logger.Infof("Installed Chaincode [%s] Version [%s] to peer", ccpack.GetChaincodeData().Name, ccpack.GetChaincodeData().Version)
413+
424414
return nil
425415
}
426416

0 commit comments

Comments
 (0)