Skip to content

Commit 42403c0

Browse files
committed
[FAB-9546] allow collection updates - vscc side
This CR allows changes to existing collection configuration as well as adding new collections via chaincode upgrade transaction. Only the VSCC side changes has been made. During chaincode upgrade, if no collection is modified, either all existing collection config must be sent as argument or none. If any collection is being modified, it is necessary to send all existing collection configs as well. This design is chosen over sending only the delta because existing collection config can be fetched from peer (requires peer chaincode command to support fetching of existing collection) and necessary modifications can be made. Only if the peer is in V1_2Validation mode, chaincode upgrade can modify the collection. Change-Id: Icf092df222c052a48568615ab5b5edeaabfc7592 Signed-off-by: senthil <cendhu@gmail.com>
1 parent ad66c6f commit 42403c0

File tree

2 files changed

+374
-21
lines changed

2 files changed

+374
-21
lines changed

core/scc/vscc/validator_onevalidsignature.go

Lines changed: 86 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,48 @@ func validateNewCollectionConfigs(newCollectionConfigs []*common.CollectionConfi
275275
return nil
276276
}
277277

278+
func validateNewCollectionConfigsAgainstOld(newCollectionConfigs []*common.CollectionConfig, oldCollectionConfigs []*common.CollectionConfig,
279+
) error {
280+
// All old collections must exist in the new collection config package
281+
if len(newCollectionConfigs) < len(oldCollectionConfigs) {
282+
return fmt.Errorf("Some existing collection configurations are missing in the new collection configuration package")
283+
}
284+
newCollectionsMap := make(map[string]*common.StaticCollectionConfig, len(newCollectionConfigs))
285+
286+
for _, newCollectionConfig := range newCollectionConfigs {
287+
newCollection := newCollectionConfig.GetStaticCollectionConfig()
288+
// Collection object itself is stored as value so that we can
289+
// check whether the block to live is changed -- FAB-7810
290+
newCollectionsMap[newCollection.GetName()] = newCollection
291+
}
292+
293+
// In the new collection config package, ensure that there is one entry per old collection. Any
294+
// number of new collections are allowed.
295+
for _, oldCollectionConfig := range oldCollectionConfigs {
296+
297+
oldCollection := oldCollectionConfig.GetStaticCollectionConfig()
298+
// It cannot be nil
299+
if oldCollection == nil {
300+
return fmt.Errorf("unknown collection configuration type")
301+
}
302+
303+
// All old collection must exist in the new collection config package
304+
oldCollectionName := oldCollection.GetName()
305+
newCollection, ok := newCollectionsMap[oldCollectionName]
306+
if !ok {
307+
return fmt.Errorf("existing collection named %s is missing in the new collection configuration package",
308+
oldCollectionName)
309+
}
310+
// BlockToLive cannot be changed
311+
if newCollection.GetBlockToLive() != oldCollection.GetBlockToLive() {
312+
return fmt.Errorf("BlockToLive in the existing collection named %s cannot be changed",
313+
oldCollectionName)
314+
}
315+
}
316+
317+
return nil
318+
}
319+
278320
// validateRWSetAndCollection performs validation of the rwset
279321
// of an LSCC deploy operation and then it validates any collection
280322
// configuration
@@ -355,6 +397,31 @@ func (vscc *ValidatorOneValidSignature) validateRWSetAndCollection(
355397
if err := validateNewCollectionConfigs(newCollectionConfigs); err != nil {
356398
return err
357399
}
400+
401+
if lsccFunc == lscc.UPGRADE {
402+
403+
collectionCriteria := common.CollectionCriteria{Channel: channelName, Namespace: cdRWSet.Name}
404+
// oldCollectionConfigPackage denotes the existing collection config package in the ledger
405+
oldCollectionConfigPackage, err := vscc.collectionStore.RetrieveCollectionConfigPackage(collectionCriteria)
406+
if err != nil {
407+
// fail if we get any error other than NoSuchCollectionError
408+
// because it means something went wrong while looking up the
409+
// older collection
410+
if _, ok := err.(privdata.NoSuchCollectionError); !ok {
411+
return errors.WithMessage(err, fmt.Sprintf("unable to check whether collection existed earlier for chaincode %s:%s",
412+
cdRWSet.Name, cdRWSet.Version))
413+
}
414+
}
415+
416+
// oldCollectionConfigPackage denotes the existing collection config package in the ledger
417+
if oldCollectionConfigPackage != nil {
418+
oldCollectionConfigs := oldCollectionConfigPackage.GetConfig()
419+
if err := validateNewCollectionConfigsAgainstOld(newCollectionConfigs, oldCollectionConfigs); err != nil {
420+
return err
421+
}
422+
423+
}
424+
}
358425
}
359426

360427
// TODO: FAB-6526 - to add validation of the collections object
@@ -533,14 +600,6 @@ func (vscc *ValidatorOneValidSignature) ValidateLSCCInvocation(
533600
}
534601

535602
case lscc.UPGRADE:
536-
/********************************************/
537-
/* security check 0.a - validation of rwset */
538-
/********************************************/
539-
// there can only be a single ledger write
540-
if len(lsccrwset.Writes) != 1 {
541-
return errors.New("LSCC can only issue one putState upon upgrade")
542-
}
543-
544603
/**************************************************************/
545604
/* security check 1 - cc in the LCCC table of instantiated cc */
546605
/**************************************************************/
@@ -555,8 +614,25 @@ func (vscc *ValidatorOneValidSignature) ValidateLSCCInvocation(
555614
return fmt.Errorf("Existing version of the cc on the ledger (%s) should be different from the upgraded one", cdsArgs.ChaincodeSpec.ChaincodeId.Version)
556615
}
557616

617+
/****************************************************************************/
618+
/* security check 3 validation of rwset (and of collections if enabled) */
619+
/****************************************************************************/
620+
// Only in v1.2, a collection can be updated during a chaincode upgrade
621+
if ac.V1_2Validation() {
622+
// do extra validation for collections
623+
err = vscc.validateRWSetAndCollection(lsccrwset, cdRWSet, lsccArgs, lsccFunc, ac, chid)
624+
if err != nil {
625+
return err
626+
}
627+
} else {
628+
// there can only be a single ledger write
629+
if len(lsccrwset.Writes) != 1 {
630+
return errors.New("LSCC can only issue a single putState upon deploy/upgrade")
631+
}
632+
}
633+
558634
/*****************************************************/
559-
/* security check 3 - check the instantiation policy */
635+
/* security check 4 - check the instantiation policy */
560636
/*****************************************************/
561637
pol := cdLedger.InstantiationPolicy
562638
if pol == nil {
@@ -573,7 +649,7 @@ func (vscc *ValidatorOneValidSignature) ValidateLSCCInvocation(
573649
}
574650

575651
/******************************************************************/
576-
/* security check 4 - check the instantiation policy in the rwset */
652+
/* security check 5 - check the instantiation policy in the rwset */
577653
/******************************************************************/
578654
if ac.V1_1Validation() {
579655
polNew := cdRWSet.InstantiationPolicy

0 commit comments

Comments
 (0)