From 8f5c24c320a7ae2e50e2e1e9ab75ed2e99ec03e7 Mon Sep 17 00:00:00 2001 From: Alessandro Sorniotti Date: Fri, 1 Dec 2017 17:21:23 +0100 Subject: [PATCH] [FAB-6229] VSCC support for cfg tree cc lifecycle This change set introduces support at the VSCC side for the config-tree-based chaincode lifecycle management. Change-Id: Ib67927b7a535effcfa94387fbbcf00c4aa0a33f7 Signed-off-by: Alessandro Sorniotti --- common/mocks/scc/sccprovider.go | 45 ++++-- core/common/sysccprovider/sysccprovider.go | 10 ++ .../sysccprovider/sysccprovider_test.go | 10 ++ core/scc/sccproviderimpl.go | 15 ++ core/scc/vscc/validator_onevalidsignature.go | 47 ++++-- .../vscc/validator_onevalidsignature_test.go | 147 +++++++++++++++--- 6 files changed, 235 insertions(+), 39 deletions(-) diff --git a/common/mocks/scc/sccprovider.go b/common/mocks/scc/sccprovider.go index c984fe73492..6681796a151 100644 --- a/common/mocks/scc/sccprovider.go +++ b/common/mocks/scc/sccprovider.go @@ -17,37 +17,62 @@ limitations under the License. package scc import ( + "github.com/hyperledger/fabric/common/channelconfig" lm "github.com/hyperledger/fabric/common/mocks/ledger" + "github.com/hyperledger/fabric/common/policies" "github.com/hyperledger/fabric/core/common/sysccprovider" "github.com/hyperledger/fabric/core/ledger" ) type MocksccProviderFactory struct { - Qe *lm.MockQueryExecutor - QErr error + Qe *lm.MockQueryExecutor + QErr error + ApplicationConfigRv channelconfig.Application + ApplicationConfigBool bool + PolicyManagerRv policies.Manager + PolicyManagerBool bool } func (c *MocksccProviderFactory) NewSystemChaincodeProvider() sysccprovider.SystemChaincodeProvider { - return &mocksccProviderImpl{Qe: c.Qe, QErr: c.QErr} + return &MocksccProviderImpl{ + Qe: c.Qe, + QErr: c.QErr, + ApplicationConfigRv: c.ApplicationConfigRv, + ApplicationConfigBool: c.ApplicationConfigBool, + PolicyManagerBool: c.PolicyManagerBool, + PolicyManagerRv: c.PolicyManagerRv, + } } -type mocksccProviderImpl struct { - Qe *lm.MockQueryExecutor - QErr error +type MocksccProviderImpl struct { + Qe *lm.MockQueryExecutor + QErr error + ApplicationConfigRv channelconfig.Application + ApplicationConfigBool bool + PolicyManagerRv policies.Manager + PolicyManagerBool bool } -func (c *mocksccProviderImpl) IsSysCC(name string) bool { +func (c *MocksccProviderImpl) IsSysCC(name string) bool { return (name == "lscc") || (name == "escc") || (name == "vscc") || (name == "notext") } -func (c *mocksccProviderImpl) IsSysCCAndNotInvokableCC2CC(name string) bool { +func (c *MocksccProviderImpl) IsSysCCAndNotInvokableCC2CC(name string) bool { return (name == "escc") || (name == "vscc") } -func (c *mocksccProviderImpl) IsSysCCAndNotInvokableExternal(name string) bool { +func (c *MocksccProviderImpl) IsSysCCAndNotInvokableExternal(name string) bool { return (name == "escc") || (name == "vscc") || (name == "notext") } -func (c *mocksccProviderImpl) GetQueryExecutorForLedger(cid string) (ledger.QueryExecutor, error) { +func (c *MocksccProviderImpl) GetQueryExecutorForLedger(cid string) (ledger.QueryExecutor, error) { return c.Qe, c.QErr } + +func (c *MocksccProviderImpl) GetApplicationConfig(cid string) (channelconfig.Application, bool) { + return c.ApplicationConfigRv, c.ApplicationConfigBool +} + +func (c *MocksccProviderImpl) PolicyManager(channelID string) (policies.Manager, bool) { + return c.PolicyManagerRv, c.PolicyManagerBool +} diff --git a/core/common/sysccprovider/sysccprovider.go b/core/common/sysccprovider/sysccprovider.go index 3de927e04df..1613fdae165 100644 --- a/core/common/sysccprovider/sysccprovider.go +++ b/core/common/sysccprovider/sysccprovider.go @@ -17,6 +17,8 @@ limitations under the License. package sysccprovider import ( + "github.com/hyperledger/fabric/common/channelconfig" + "github.com/hyperledger/fabric/common/policies" "github.com/hyperledger/fabric/core/ledger" ) @@ -41,6 +43,14 @@ type SystemChaincodeProvider interface { // That's useful for system chaincodes that require unfettered // access to the ledger GetQueryExecutorForLedger(cid string) (ledger.QueryExecutor, error) + + // GetApplicationConfig returns the configtxapplication.SharedConfig for the channel + // and whether the Application config exists + GetApplicationConfig(cid string) (channelconfig.Application, bool) + + // Returns the policy manager associated to the passed channel + // and whether the policy manager exists + PolicyManager(channelID string) (policies.Manager, bool) } var sccFactory SystemChaincodeProviderFactory diff --git a/core/common/sysccprovider/sysccprovider_test.go b/core/common/sysccprovider/sysccprovider_test.go index 119fed0834a..10d4fee98d0 100644 --- a/core/common/sysccprovider/sysccprovider_test.go +++ b/core/common/sysccprovider/sysccprovider_test.go @@ -19,6 +19,8 @@ package sysccprovider import ( "testing" + "github.com/hyperledger/fabric/common/channelconfig" + "github.com/hyperledger/fabric/common/policies" "github.com/hyperledger/fabric/core/ledger" "github.com/stretchr/testify/assert" ) @@ -47,6 +49,14 @@ func (p MockChaincodeProvider) IsSysCCAndNotInvokableExternal(name string) bool return true } +func (p MockChaincodeProvider) GetApplicationConfig(cid string) (channelconfig.Application, bool) { + return nil, false +} + +func (p MockChaincodeProvider) PolicyManager(channelID string) (policies.Manager, bool) { + return nil, false +} + func (f MockFactory) NewSystemChaincodeProvider() SystemChaincodeProvider { return mockChaincodeProvider } diff --git a/core/scc/sccproviderimpl.go b/core/scc/sccproviderimpl.go index 6c97469a7d9..45bd4e5a91f 100644 --- a/core/scc/sccproviderimpl.go +++ b/core/scc/sccproviderimpl.go @@ -19,6 +19,8 @@ package scc import ( "fmt" + "github.com/hyperledger/fabric/common/channelconfig" + "github.com/hyperledger/fabric/common/policies" "github.com/hyperledger/fabric/core/common/sysccprovider" "github.com/hyperledger/fabric/core/ledger" "github.com/hyperledger/fabric/core/peer" @@ -71,3 +73,16 @@ func (c *sccProviderImpl) IsSysCCAndNotInvokableExternal(name string) bool { // call the static method of the same name return IsSysCCAndNotInvokableExternal(name) } + +// GetApplicationConfig returns the configtxapplication.SharedConfig for the channel +// and whether the Application config exists +func (c *sccProviderImpl) GetApplicationConfig(cid string) (channelconfig.Application, bool) { + return peer.GetSupport().GetApplicationConfig(cid) +} + +// Returns the policy manager associated to the passed channel +// and whether the policy manager exists +func (c *sccProviderImpl) PolicyManager(channelID string) (policies.Manager, bool) { + m := peer.GetPolicyManager(channelID) + return m, (m != nil) +} diff --git a/core/scc/vscc/validator_onevalidsignature.go b/core/scc/vscc/validator_onevalidsignature.go index 55306aecd0d..60f1d154d03 100644 --- a/core/scc/vscc/validator_onevalidsignature.go +++ b/core/scc/vscc/validator_onevalidsignature.go @@ -19,12 +19,10 @@ package vscc import ( "fmt" - "errors" - "github.com/golang/protobuf/proto" - "github.com/hyperledger/fabric/common/cauthdsl" "github.com/hyperledger/fabric/common/flogging" + "github.com/hyperledger/fabric/common/policies" "github.com/hyperledger/fabric/core/chaincode/shim" "github.com/hyperledger/fabric/core/common/ccprovider" "github.com/hyperledger/fabric/core/common/sysccprovider" @@ -36,6 +34,7 @@ import ( "github.com/hyperledger/fabric/protos/msp" pb "github.com/hyperledger/fabric/protos/peer" "github.com/hyperledger/fabric/protos/utils" + "github.com/pkg/errors" ) var logger = flogging.MustGetLogger("vscc") @@ -109,15 +108,45 @@ func (vscc *ValidatorOneValidSignature) Invoke(stub shim.ChaincodeStubInterface) return shim.Error(err.Error()) } - // get the policy - mgr := mspmgmt.GetManagerForChain(chdr.ChannelId) - pProvider := cauthdsl.NewPolicyProvider(mgr) - policy, _, err := pProvider.NewPolicy(args[2]) - if err != nil { - logger.Errorf("VSCC error: pProvider.NewPolicy failed, err %s", err) + ac, exists := vscc.sccprovider.GetApplicationConfig(chdr.ChannelId) + if !exists { + err = errors.Wrap(err, "failure while unmarshalling VSCCArgs") + logger.Errorf(err.Error()) return shim.Error(err.Error()) } + // get the policy + var policy policies.Policy + if ac.Capabilities().LifecycleViaConfig() { + vsccArgs := &pb.VSCCArgs{} + err = proto.Unmarshal(args[2], vsccArgs) + if err != nil { + err = errors.Wrap(err, "failure while unmarshalling VSCCArgs") + logger.Errorf(err.Error()) + return shim.Error(err.Error()) + } + + mgr, exists := vscc.sccprovider.PolicyManager(chdr.ChannelId) + if !exists { + logger.Errorf("Policy manager could not be found for channel %s", chdr.ChannelId) + return shim.Error(fmt.Sprintf("Policy manager could not be found for channel %s", chdr.ChannelId)) + } + + policy, exists = mgr.GetPolicy(vsccArgs.GetEndorsementPolicyRef()) + if !exists { + logger.Errorf("Policy '%s' could not be found for channel %s", vsccArgs.GetEndorsementPolicyRef(), chdr.ChannelId) + return shim.Error(fmt.Sprintf("Policy '%s' could not be found for channel %s", vsccArgs.GetEndorsementPolicyRef(), chdr.ChannelId)) + } + } else { + mgr := mspmgmt.GetManagerForChain(chdr.ChannelId) + pProvider := cauthdsl.NewPolicyProvider(mgr) + policy, _, err = pProvider.NewPolicy(args[2]) + if err != nil { + logger.Errorf("VSCC error: pProvider.NewPolicy failed, err %s", err) + return shim.Error(err.Error()) + } + } + // validate the payload type if common.HeaderType(chdr.Type) != common.HeaderType_ENDORSER_TRANSACTION { logger.Errorf("Only Endorser Transactions are supported, provided type %d", chdr.Type) diff --git a/core/scc/vscc/validator_onevalidsignature_test.go b/core/scc/vscc/validator_onevalidsignature_test.go index 2083e7f1c8a..ae0d4db95ab 100644 --- a/core/scc/vscc/validator_onevalidsignature_test.go +++ b/core/scc/vscc/validator_onevalidsignature_test.go @@ -16,19 +16,19 @@ limitations under the License. package vscc import ( - "testing" - - "fmt" - "os" - "archive/tar" - "compress/gzip" - "bytes" + "compress/gzip" + "fmt" + "os" + "testing" "github.com/golang/protobuf/proto" "github.com/hyperledger/fabric/common/cauthdsl" + mc "github.com/hyperledger/fabric/common/mocks/config" lm "github.com/hyperledger/fabric/common/mocks/ledger" + "github.com/hyperledger/fabric/common/mocks/policies" + mockpolicies "github.com/hyperledger/fabric/common/mocks/policies" "github.com/hyperledger/fabric/common/mocks/scc" "github.com/hyperledger/fabric/common/util" "github.com/hyperledger/fabric/core/chaincode/shim" @@ -257,6 +257,9 @@ func getSignedByMSPAdminPolicy(mspID string) ([]byte, error) { func TestInvoke(t *testing.T) { v := new(ValidatorOneValidSignature) stub := shim.NewMockStub("validatoronevalidsignature", v) + if res := stub.MockInit("1", nil); res.Status != shim.OK { + t.Fatalf("vscc init failed with %s", res.Message) + } // Failed path: Invalid arguments args := [][]byte{[]byte("dv")} @@ -374,6 +377,59 @@ func TestInvoke(t *testing.T) { } } +func TestInvokeNewLifecycle(t *testing.T) { + v := new(ValidatorOneValidSignature) + stub := shim.NewMockStub("validatoronevalidsignature", v) + + sysccprovider.RegisterSystemChaincodeProviderFactory(&scc.MocksccProviderFactory{ + ApplicationConfigBool: true, + ApplicationConfigRv: &mc.MockApplication{&mc.MockApplicationCapabilities{LifecycleViaConfigRv: true}}, + PolicyManagerBool: true, + PolicyManagerRv: &policies.Manager{Policy: &mockpolicies.Policy{}}, + }) + + if res := stub.MockInit("1", nil); res.Status != shim.OK { + t.Fatalf("vscc init failed with %s", res.Message) + } + + tx, err := createTx(false) + if err != nil { + t.Fatalf("createTx returned err %s", err) + } + + envBytes, err := utils.GetBytesEnvelope(tx) + if err != nil { + t.Fatalf("GetBytesEnvelope returned err %s", err) + } + + args := [][]byte{[]byte("dv"), envBytes, []byte("barf")} + if res := stub.MockInvoke("1", args); res.Status == shim.OK { + t.Fatalf("vscc invoke should have failed") + } + + v.sccprovider.(*scc.MocksccProviderImpl).PolicyManagerBool = false + + args = [][]byte{[]byte("dv"), envBytes, utils.MarshalOrPanic(&peer.VSCCArgs{EndorsementPolicyRef: "somePolicy"})} + if res := stub.MockInvoke("1", args); res.Status == shim.OK { + t.Fatalf("vscc invoke should have failed") + } + + v.sccprovider.(*scc.MocksccProviderImpl).PolicyManagerBool = true + v.sccprovider.(*scc.MocksccProviderImpl).PolicyManagerRv = &policies.Manager{} + + args = [][]byte{[]byte("dv"), envBytes, utils.MarshalOrPanic(&peer.VSCCArgs{EndorsementPolicyRef: "somePolicy"})} + if res := stub.MockInvoke("1", args); res.Status == shim.OK { + t.Fatalf("vscc invoke should have failed") + } + + v.sccprovider.(*scc.MocksccProviderImpl).PolicyManagerRv = &policies.Manager{Policy: &mockpolicies.Policy{}} + + args = [][]byte{[]byte("dv"), envBytes, utils.MarshalOrPanic(&peer.VSCCArgs{EndorsementPolicyRef: "somePolicy"})} + if res := stub.MockInvoke("1", args); res.Status != shim.OK { + t.Fatalf("vscc invoke should have succeeded but got error %s", res.Message) + } +} + func TestInvalidFunction(t *testing.T) { v := new(ValidatorOneValidSignature) stub := shim.NewMockStub("validatoronevalidsignature", v) @@ -383,7 +439,11 @@ func TestInvalidFunction(t *testing.T) { State := make(map[string]map[string][]byte) State["lscc"] = stublccc.State - sysccprovider.RegisterSystemChaincodeProviderFactory(&scc.MocksccProviderFactory{Qe: lm.NewMockQueryExecutor(State)}) + sysccprovider.RegisterSystemChaincodeProviderFactory(&scc.MocksccProviderFactory{ + Qe: lm.NewMockQueryExecutor(State), + ApplicationConfigBool: true, + ApplicationConfigRv: &mc.MockApplication{&mc.MockApplicationCapabilities{}}, + }) stub.MockPeerChaincode("lscc", stublccc) r1 := stub.MockInit("1", [][]byte{}) @@ -435,7 +495,11 @@ func TestRWSetTooBig(t *testing.T) { State := make(map[string]map[string][]byte) State["lscc"] = stublccc.State - sysccprovider.RegisterSystemChaincodeProviderFactory(&scc.MocksccProviderFactory{Qe: lm.NewMockQueryExecutor(State)}) + sysccprovider.RegisterSystemChaincodeProviderFactory(&scc.MocksccProviderFactory{ + Qe: lm.NewMockQueryExecutor(State), + ApplicationConfigBool: true, + ApplicationConfigRv: &mc.MockApplication{&mc.MockApplicationCapabilities{}}, + }) stub.MockPeerChaincode("lscc", stublccc) r1 := stub.MockInit("1", [][]byte{}) @@ -500,7 +564,11 @@ func TestValidateDeployFail(t *testing.T) { State := make(map[string]map[string][]byte) State["lscc"] = stublccc.State - sysccprovider.RegisterSystemChaincodeProviderFactory(&scc.MocksccProviderFactory{Qe: lm.NewMockQueryExecutor(State)}) + sysccprovider.RegisterSystemChaincodeProviderFactory(&scc.MocksccProviderFactory{ + Qe: lm.NewMockQueryExecutor(State), + ApplicationConfigBool: true, + ApplicationConfigRv: &mc.MockApplication{&mc.MockApplicationCapabilities{}}, + }) stub.MockPeerChaincode("lscc", stublccc) r1 := stub.MockInit("1", [][]byte{}) @@ -785,7 +853,11 @@ func TestAlreadyDeployed(t *testing.T) { State := make(map[string]map[string][]byte) State["lscc"] = stublccc.State - sysccprovider.RegisterSystemChaincodeProviderFactory(&scc.MocksccProviderFactory{Qe: lm.NewMockQueryExecutor(State)}) + sysccprovider.RegisterSystemChaincodeProviderFactory(&scc.MocksccProviderFactory{ + Qe: lm.NewMockQueryExecutor(State), + ApplicationConfigBool: true, + ApplicationConfigRv: &mc.MockApplication{&mc.MockApplicationCapabilities{}}, + }) stub.MockPeerChaincode("lscc", stublccc) r1 := stub.MockInit("1", [][]byte{}) @@ -860,7 +932,11 @@ func TestValidateDeployNoLedger(t *testing.T) { State := make(map[string]map[string][]byte) State["lscc"] = stublccc.State - sysccprovider.RegisterSystemChaincodeProviderFactory(&scc.MocksccProviderFactory{QErr: fmt.Errorf("Simulated error")}) + sysccprovider.RegisterSystemChaincodeProviderFactory(&scc.MocksccProviderFactory{ + QErr: fmt.Errorf("Simulated error"), + ApplicationConfigBool: true, + ApplicationConfigRv: &mc.MockApplication{&mc.MockApplicationCapabilities{}}, + }) stub.MockPeerChaincode("lscc", stublccc) r1 := stub.MockInit("1", [][]byte{}) @@ -914,7 +990,11 @@ func TestValidateDeployOK(t *testing.T) { State := make(map[string]map[string][]byte) State["lscc"] = stublccc.State - sysccprovider.RegisterSystemChaincodeProviderFactory(&scc.MocksccProviderFactory{Qe: lm.NewMockQueryExecutor(State)}) + sysccprovider.RegisterSystemChaincodeProviderFactory(&scc.MocksccProviderFactory{ + Qe: lm.NewMockQueryExecutor(State), + ApplicationConfigBool: true, + ApplicationConfigRv: &mc.MockApplication{&mc.MockApplicationCapabilities{}}, + }) stub.MockPeerChaincode("lscc", stublccc) r1 := stub.MockInit("1", [][]byte{}) @@ -968,7 +1048,11 @@ func TestValidateDeployWithPolicies(t *testing.T) { State := make(map[string]map[string][]byte) State["lscc"] = stublccc.State - sysccprovider.RegisterSystemChaincodeProviderFactory(&scc.MocksccProviderFactory{Qe: lm.NewMockQueryExecutor(State)}) + sysccprovider.RegisterSystemChaincodeProviderFactory(&scc.MocksccProviderFactory{ + Qe: lm.NewMockQueryExecutor(State), + ApplicationConfigBool: true, + ApplicationConfigRv: &mc.MockApplication{&mc.MockApplicationCapabilities{}}, + }) stub.MockPeerChaincode("lscc", stublccc) r1 := stub.MockInit("1", [][]byte{}) @@ -1052,7 +1136,11 @@ func TestInvalidUpgrade(t *testing.T) { State := make(map[string]map[string][]byte) State["lscc"] = stublccc.State - sysccprovider.RegisterSystemChaincodeProviderFactory(&scc.MocksccProviderFactory{Qe: lm.NewMockQueryExecutor(State)}) + sysccprovider.RegisterSystemChaincodeProviderFactory(&scc.MocksccProviderFactory{ + Qe: lm.NewMockQueryExecutor(State), + ApplicationConfigBool: true, + ApplicationConfigRv: &mc.MockApplication{&mc.MockApplicationCapabilities{}}, + }) stub.MockPeerChaincode("lscc", stublccc) r1 := stub.MockInit("1", [][]byte{}) @@ -1104,7 +1192,11 @@ func TestValidateUpgradeOK(t *testing.T) { State := make(map[string]map[string][]byte) State["lscc"] = stublccc.State - sysccprovider.RegisterSystemChaincodeProviderFactory(&scc.MocksccProviderFactory{Qe: lm.NewMockQueryExecutor(State)}) + sysccprovider.RegisterSystemChaincodeProviderFactory(&scc.MocksccProviderFactory{ + Qe: lm.NewMockQueryExecutor(State), + ApplicationConfigBool: true, + ApplicationConfigRv: &mc.MockApplication{&mc.MockApplicationCapabilities{}}, + }) stub.MockPeerChaincode("lscc", stublccc) r1 := stub.MockInit("1", [][]byte{}) @@ -1181,7 +1273,11 @@ func TestInvalidateUpgradeBadVersion(t *testing.T) { State := make(map[string]map[string][]byte) State["lscc"] = stublccc.State - sysccprovider.RegisterSystemChaincodeProviderFactory(&scc.MocksccProviderFactory{Qe: lm.NewMockQueryExecutor(State)}) + sysccprovider.RegisterSystemChaincodeProviderFactory(&scc.MocksccProviderFactory{ + Qe: lm.NewMockQueryExecutor(State), + ApplicationConfigBool: true, + ApplicationConfigRv: &mc.MockApplication{&mc.MockApplicationCapabilities{}}, + }) stub.MockPeerChaincode("lscc", stublccc) r1 := stub.MockInit("1", [][]byte{}) @@ -1256,7 +1352,11 @@ func TestValidateUpgradeWithPoliciesOK(t *testing.T) { State := make(map[string]map[string][]byte) State["lscc"] = stublccc.State - sysccprovider.RegisterSystemChaincodeProviderFactory(&scc.MocksccProviderFactory{Qe: lm.NewMockQueryExecutor(State)}) + sysccprovider.RegisterSystemChaincodeProviderFactory(&scc.MocksccProviderFactory{ + Qe: lm.NewMockQueryExecutor(State), + ApplicationConfigBool: true, + ApplicationConfigRv: &mc.MockApplication{&mc.MockApplicationCapabilities{}}, + }) stub.MockPeerChaincode("lscc", stublccc) r1 := stub.MockInit("1", [][]byte{}) @@ -1335,7 +1435,11 @@ func TestValidateUpgradeWithPoliciesFail(t *testing.T) { State := make(map[string]map[string][]byte) State["lscc"] = stublccc.State - sysccprovider.RegisterSystemChaincodeProviderFactory(&scc.MocksccProviderFactory{Qe: lm.NewMockQueryExecutor(State)}) + sysccprovider.RegisterSystemChaincodeProviderFactory(&scc.MocksccProviderFactory{ + Qe: lm.NewMockQueryExecutor(State), + ApplicationConfigBool: true, + ApplicationConfigRv: &mc.MockApplication{&mc.MockApplicationCapabilities{}}, + }) stub.MockPeerChaincode("lscc", stublccc) r1 := stub.MockInit("1", [][]byte{}) @@ -1436,7 +1540,10 @@ var lccctestpath = "/tmp/lscc-validation-test" func TestMain(m *testing.M) { ccprovider.SetChaincodesPath(lccctestpath) - sysccprovider.RegisterSystemChaincodeProviderFactory(&scc.MocksccProviderFactory{}) + sysccprovider.RegisterSystemChaincodeProviderFactory(&scc.MocksccProviderFactory{ + ApplicationConfigBool: true, + ApplicationConfigRv: &mc.MockApplication{&mc.MockApplicationCapabilities{}}, + }) policy.RegisterPolicyCheckerFactory(&mockPolicyCheckerFactory{}) mspGetter := func(cid string) []string {