Skip to content

Commit

Permalink
[FAB-5871] VSCC to ensure no collection exists
Browse files Browse the repository at this point in the history
This change set completes the work for FAB-5871 by adding the check in VSCC
to ensure that no prior collection exists for the deployed chaincode.

Change-Id: I5046244ff9a8aa7a249fa79b0c8aafd263eabdb0
Signed-off-by: Alessandro Sorniotti <ale.linux@sopit.net>
  • Loading branch information
ale-linux authored and yacovm committed Dec 21, 2017
1 parent ebd1a52 commit 1a8be5a
Show file tree
Hide file tree
Showing 7 changed files with 92 additions and 13 deletions.
4 changes: 4 additions & 0 deletions core/common/privdata/collection.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,10 @@ type CollectionStore interface {

// GetCollectionAccessPolicy retrieves a collection's access policy
RetrieveCollectionAccessPolicy(common.CollectionCriteria) (CollectionAccessPolicy, error)

// RetrieveCollectionConfigPackage retrieves the configuration
// for the collection with the supplied criteria
RetrieveCollectionConfigPackage(common.CollectionCriteria) (*common.CollectionConfigPackage, error)
}

const (
Expand Down
18 changes: 17 additions & 1 deletion core/common/privdata/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ func NewSimpleCollectionStore(s Support) CollectionStore {
return &simpleCollectionStore{s}
}

func (c *simpleCollectionStore) retrieveSimpleCollection(cc common.CollectionCriteria) (*SimpleCollection, error) {
func (c *simpleCollectionStore) retrieveCollectionConfigPackage(cc common.CollectionCriteria) (*common.CollectionConfigPackage, error) {
qe, err := c.s.GetQueryExecutorForLedger(cc.Channel)
if err != nil {
return nil, errors.WithMessage(err, fmt.Sprintf("could not retrieve query executor for collection criteria %#v", cc))
Expand All @@ -69,6 +69,18 @@ func (c *simpleCollectionStore) retrieveSimpleCollection(cc common.CollectionCri
return nil, errors.Wrapf(err, "invalid configuration for collection criteria %#v", cc)
}

return collections, nil
}

func (c *simpleCollectionStore) retrieveSimpleCollection(cc common.CollectionCriteria) (*SimpleCollection, error) {
collections, err := c.retrieveCollectionConfigPackage(cc)
if err != nil {
return nil, err
}
if collections == nil {
return nil, nil
}

for _, cconf := range collections.Config {
switch cconf := cconf.Payload.(type) {
case *common.CollectionConfig_StaticCollectionConfig:
Expand Down Expand Up @@ -97,3 +109,7 @@ func (c *simpleCollectionStore) RetrieveCollection(cc common.CollectionCriteria)
func (c *simpleCollectionStore) RetrieveCollectionAccessPolicy(cc common.CollectionCriteria) (CollectionAccessPolicy, error) {
return c.retrieveSimpleCollection(cc)
}

func (c *simpleCollectionStore) RetrieveCollectionConfigPackage(cc common.CollectionCriteria) (*common.CollectionConfigPackage, error) {
return c.retrieveCollectionConfigPackage(cc)
}
4 changes: 4 additions & 0 deletions core/common/privdata/store_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,4 +93,8 @@ func TestCollectionStore(t *testing.T) {
c, err = cs.RetrieveCollection(common.CollectionCriteria{Channel: "ch", Namespace: "cc", Collection: "asd"})
assert.Error(t, err)
assert.Nil(t, c)

ccc, err := cs.RetrieveCollectionConfigPackage(ccr)
assert.NoError(t, err)
assert.NotNil(t, ccc)
}
38 changes: 34 additions & 4 deletions core/scc/vscc/validator_onevalidsignature.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (
"github.com/hyperledger/fabric/core/common/sysccprovider"
"github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/rwsetutil"
"github.com/hyperledger/fabric/core/scc/lscc"
m "github.com/hyperledger/fabric/msp"
mspmgmt "github.com/hyperledger/fabric/msp/mgmt"
"github.com/hyperledger/fabric/protos/common"
"github.com/hyperledger/fabric/protos/ledger/rwset/kvrwset"
Expand All @@ -54,11 +55,29 @@ type ValidatorOneValidSignature struct {
// methods of the system chaincode package without
// import cycles
sccprovider sysccprovider.SystemChaincodeProvider

// collectionStore provides support to retrieve
// collections from the ledger
collectionStore privdata.CollectionStore
}

// collectionStoreSupport implements privdata.Support
type collectionStoreSupport struct {
sysccprovider.SystemChaincodeProvider
}

func (c *collectionStoreSupport) GetCollectionKVSKey(cc common.CollectionCriteria) string {
return privdata.BuildCollectionKVSKey(cc.Namespace)
}

func (c *collectionStoreSupport) GetIdentityDeserializer(chainID string) m.IdentityDeserializer {
return mspmgmt.GetIdentityDeserializer(chainID)
}

// Init is called once when the chaincode started the first time
func (vscc *ValidatorOneValidSignature) Init(stub shim.ChaincodeStubInterface) pb.Response {
vscc.sccprovider = sysccprovider.GetSystemChaincodeProvider()
vscc.collectionStore = privdata.NewSimpleCollectionStore(&collectionStoreSupport{vscc.sccprovider})

return shim.Success(nil)
}
Expand Down Expand Up @@ -228,6 +247,7 @@ func (vscc *ValidatorOneValidSignature) validateDeployRWSetAndCollection(
lsccrwset *kvrwset.KVRWSet,
cdRWSet *ccprovider.ChaincodeData,
lsccArgs [][]byte,
chid, ccid string,
) error {
/********************************************/
/* security check 0.a - validation of rwset */
Expand Down Expand Up @@ -261,9 +281,19 @@ func (vscc *ValidatorOneValidSignature) validateDeployRWSetAndCollection(
cdRWSet.Name, cdRWSet.Version)
}

// TODO: make sure there isn't any existing collection on the ledger for this chaincode
// I'll take care of this as soon as we have implemented a collection store interface
// to retrieve collection configuration data from the ledger (https://jira.hyperledger.org/browse/FAB-5872)
ccp, err := vscc.collectionStore.RetrieveCollectionConfigPackage(common.CollectionCriteria{Channel: chid, Namespace: ccid})
if err != nil {
// fail if we get any error other than NoSuchCollectionError
// because it means something went wrong while looking up the
// older collection
if _, ok := err.(privdata.NoSuchCollectionError); !ok {
return errors.WithMessage(err, fmt.Sprintf("unable to check whether collection existed earlier for chaincode %s:%s",
cdRWSet.Name, cdRWSet.Version))
}
}
if ccp != nil {
return errors.Errorf("collection data should not exist for chaincode %s:%s", cdRWSet.Name, cdRWSet.Version)
}

if collectionsConfigArgs != nil {
collections := &common.CollectionConfigPackage{}
Expand Down Expand Up @@ -413,7 +443,7 @@ func (vscc *ValidatorOneValidSignature) ValidateLSCCInvocation(
/****************************************************************************/
if ac.PrivateChannelData() {
// do extra validation for collections
err = vscc.validateDeployRWSetAndCollection(lsccrwset, cdRWSet, lsccArgs)
err = vscc.validateDeployRWSetAndCollection(lsccrwset, cdRWSet, lsccArgs, chid, cdsArgs.ChaincodeSpec.ChaincodeId.Name)
if err != nil {
return err
}
Expand Down
33 changes: 25 additions & 8 deletions core/scc/vscc/validator_onevalidsignature_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1484,11 +1484,18 @@ func (c *mockPolicyChecker) CheckPolicyNoChannel(policyName string, signedProp *
}

func TestValidateDeployRWSetAndCollection(t *testing.T) {
chid := "ch"
ccid := "cc"

cd := &ccprovider.ChaincodeData{Name: "mycc"}

v := new(ValidatorOneValidSignature)
stub := shim.NewMockStub("validatoronevalidsignature", v)

State := make(map[string]map[string][]byte)
State["lscc"] = make(map[string][]byte)
sysccprovider.RegisterSystemChaincodeProviderFactory(&scc.MocksccProviderFactory{Qe: lm.NewMockQueryExecutor(State)})

r1 := stub.MockInit("1", [][]byte{})
if r1.Status != shim.OK {
fmt.Println("Init failed", string(r1.Message))
Expand All @@ -1497,38 +1504,38 @@ func TestValidateDeployRWSetAndCollection(t *testing.T) {

rwset := &kvrwset.KVRWSet{Writes: []*kvrwset.KVWrite{{Key: "a"}, {Key: "b"}, {Key: "c"}}}

err := v.validateDeployRWSetAndCollection(rwset, nil, nil)
err := v.validateDeployRWSetAndCollection(rwset, nil, nil, chid, ccid)
assert.Error(t, err)

rwset = &kvrwset.KVRWSet{Writes: []*kvrwset.KVWrite{{Key: "a"}, {Key: "b"}}}

err = v.validateDeployRWSetAndCollection(rwset, cd, nil)
err = v.validateDeployRWSetAndCollection(rwset, cd, nil, chid, ccid)
assert.Error(t, err)

rwset = &kvrwset.KVRWSet{Writes: []*kvrwset.KVWrite{{Key: "a"}}}

err = v.validateDeployRWSetAndCollection(rwset, cd, nil)
err = v.validateDeployRWSetAndCollection(rwset, cd, nil, chid, ccid)
assert.NoError(t, err)

lsccargs := [][]byte{nil, nil, nil, nil, nil, nil}

err = v.validateDeployRWSetAndCollection(rwset, cd, lsccargs)
err = v.validateDeployRWSetAndCollection(rwset, cd, lsccargs, chid, ccid)
assert.NoError(t, err)

rwset = &kvrwset.KVRWSet{Writes: []*kvrwset.KVWrite{{Key: "a"}, {Key: privdata.BuildCollectionKVSKey("mycc")}}}

err = v.validateDeployRWSetAndCollection(rwset, cd, lsccargs)
err = v.validateDeployRWSetAndCollection(rwset, cd, lsccargs, chid, ccid)
assert.NoError(t, err)

lsccargs = [][]byte{nil, nil, nil, nil, nil, []byte("barf")}

err = v.validateDeployRWSetAndCollection(rwset, cd, lsccargs)
err = v.validateDeployRWSetAndCollection(rwset, cd, lsccargs, chid, ccid)
assert.Error(t, err)

lsccargs = [][]byte{nil, nil, nil, nil, nil, []byte("barf")}
rwset = &kvrwset.KVRWSet{Writes: []*kvrwset.KVWrite{{Key: "a"}, {Key: privdata.BuildCollectionKVSKey("mycc"), Value: []byte("barf")}}}

err = v.validateDeployRWSetAndCollection(rwset, cd, lsccargs)
err = v.validateDeployRWSetAndCollection(rwset, cd, lsccargs, chid, ccid)
assert.Error(t, err)

cc := &common.CollectionConfig{Payload: &common.CollectionConfig_StaticCollectionConfig{&common.StaticCollectionConfig{Name: "mycollection"}}}
Expand All @@ -1540,8 +1547,18 @@ func TestValidateDeployRWSetAndCollection(t *testing.T) {
lsccargs = [][]byte{nil, nil, nil, nil, nil, ccpBytes}
rwset = &kvrwset.KVRWSet{Writes: []*kvrwset.KVWrite{{Key: "a"}, {Key: privdata.BuildCollectionKVSKey("mycc"), Value: ccpBytes}}}

err = v.validateDeployRWSetAndCollection(rwset, cd, lsccargs)
err = v.validateDeployRWSetAndCollection(rwset, cd, lsccargs, chid, ccid)
assert.NoError(t, err)

State["lscc"][(&collectionStoreSupport{v.sccprovider}).GetCollectionKVSKey(common.CollectionCriteria{Channel: chid, Namespace: ccid})] = []byte("barf")

err = v.validateDeployRWSetAndCollection(rwset, cd, lsccargs, chid, ccid)
assert.Error(t, err)

State["lscc"][(&collectionStoreSupport{v.sccprovider}).GetCollectionKVSKey(common.CollectionCriteria{Channel: chid, Namespace: ccid})] = ccpBytes

err = v.validateDeployRWSetAndCollection(rwset, cd, lsccargs, chid, ccid)
assert.Error(t, err)
}

var lccctestpath = "/tmp/lscc-validation-test"
Expand Down
4 changes: 4 additions & 0 deletions gossip/privdata/coordinator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,10 @@ func (cs *collectionStore) RetrieveCollection(common.CollectionCriteria) (privda
panic("implement me")
}

func (cs *collectionStore) RetrieveCollectionConfigPackage(common.CollectionCriteria) (*common.CollectionConfigPackage, error) {
panic("implement me")
}

type collectionAccessPolicy struct {
cs *collectionStore
n uint64
Expand Down
4 changes: 4 additions & 0 deletions gossip/privdata/pull_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ func (cs mockCollectionStore) RetrieveCollection(fcommon.CollectionCriteria) (pr
panic("implement me")
}

func (cs mockCollectionStore) RetrieveCollectionConfigPackage(fcommon.CollectionCriteria) (*fcommon.CollectionConfigPackage, error) {
panic("implement me")
}

type mockCollectionAccess struct {
cs *mockCollectionStore
}
Expand Down

0 comments on commit 1a8be5a

Please sign in to comment.