Skip to content

Commit

Permalink
FAB-10998 GetChaincodeData to use LSCC directly
Browse files Browse the repository at this point in the history
Now that LSCC can be queried directly for chaincode definitions instead
of having to go the roundabout way of invoking chaincode, the assorted
internal users of 'getccdata' can be converted to use the new interface.

Change-Id: Ic435742817643d2dc08d83afe2f66980c649b56a
Signed-off-by: Jason Yellick <jyellick@us.ibm.com>
  • Loading branch information
Jason Yellick committed Jul 16, 2018
1 parent 8ec2ffa commit d861bbf
Show file tree
Hide file tree
Showing 16 changed files with 153 additions and 242 deletions.
20 changes: 5 additions & 15 deletions core/chaincode/chaincode_support.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"github.com/hyperledger/fabric/core/common/ccprovider"
"github.com/hyperledger/fabric/core/common/sysccprovider"
"github.com/hyperledger/fabric/core/container/ccintf"
"github.com/hyperledger/fabric/core/ledger"
"github.com/hyperledger/fabric/core/peer"
pb "github.com/hyperledger/fabric/protos/peer"
"github.com/pkg/errors"
Expand All @@ -37,14 +38,7 @@ type Launcher interface {
// Lifecycle provides a way to retrieve chaincode definitions and the packages necessary to run them
type Lifecycle interface {
// GetChaincodeDefinition returns the details for a chaincode by name
GetChaincodeDefinition(
ctx context.Context,
txid string,
signedProp *pb.SignedProposal,
prop *pb.Proposal,
chainID string,
chaincodeID string,
) (ccprovider.ChaincodeDefinition, error)
GetChaincodeDefinition(chaincodeName string, txSim ledger.QueryExecutor) (ccprovider.ChaincodeDefinition, error)

// ChaincodeContainerInfo returns the package necessary to launch a chaincode
ChaincodeContainerInfo(chainID string, chaincodeID string) (*lifecycle.ChaincodeContainerInfo, error)
Expand All @@ -71,7 +65,7 @@ func NewChaincodeSupport(
caCert []byte,
certGenerator CertGenerator,
packageProvider PackageProvider,
chaincodeStore lifecycle.InstantiatedChaincodeStore,
lifecycle Lifecycle,
aclProvider ACLProvider,
processor Processor,
sccp sysccprovider.SystemChaincodeProvider,
Expand All @@ -84,18 +78,14 @@ func NewChaincodeSupport(
HandlerRegistry: NewHandlerRegistry(userRunsCC),
ACLProvider: aclProvider,
sccp: sccp,
Lifecycle: lifecycle,
}

// Keep TestQueries working
if !config.TLSEnabled {
certGenerator = nil
}

cs.Lifecycle = &lifecycle.Lifecycle{
Executor: cs,
InstantiatedChaincodeStore: chaincodeStore,
}

cs.Runtime = &ContainerRuntime{
CertGenerator: certGenerator,
Processor: processor,
Expand Down Expand Up @@ -188,7 +178,7 @@ func (cs *ChaincodeSupport) HandleChaincodeStream(ctxt context.Context, stream c

handler := &Handler{
Invoker: cs,
DefinitionGetter: &lifecycle.Lifecycle{Executor: cs},
DefinitionGetter: cs.Lifecycle,
Keepalive: cs.Keepalive,
Registry: cs.HandlerRegistry,
ACLProvider: cs.ACLProvider,
Expand Down
4 changes: 3 additions & 1 deletion core/chaincode/chaincode_support_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,9 @@ func initMockPeer(chainIDs ...string) (*ChaincodeSupport, error) {
ca.CertBytes(),
certGenerator,
&ccprovider.CCInfoFSImpl{},
lsccImpl,
&lifecycle.Lifecycle{
InstantiatedChaincodeStore: lsccImpl,
},
mockAclProvider,
container.NewVMController(
map[string]container.VMProvider{
Expand Down
5 changes: 4 additions & 1 deletion core/chaincode/exectransaction_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import (
"github.com/hyperledger/fabric/core/aclmgmt"
aclmocks "github.com/hyperledger/fabric/core/aclmgmt/mocks"
"github.com/hyperledger/fabric/core/chaincode/accesscontrol"
"github.com/hyperledger/fabric/core/chaincode/lifecycle"
"github.com/hyperledger/fabric/core/chaincode/platforms"
"github.com/hyperledger/fabric/core/chaincode/platforms/golang"
"github.com/hyperledger/fabric/core/chaincode/shim"
Expand Down Expand Up @@ -137,7 +138,9 @@ func initPeer(chainIDs ...string) (net.Listener, *ChaincodeSupport, func(), erro
ca.CertBytes(),
certGenerator,
&ccprovider.CCInfoFSImpl{},
lsccImpl,
&lifecycle.Lifecycle{
InstantiatedChaincodeStore: lsccImpl,
},
aclmgmt.NewACLProvider(func(string) channelconfig.Resources { return nil }),
container.NewVMController(
map[string]container.VMProvider{
Expand Down
4 changes: 2 additions & 2 deletions core/chaincode/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ type QueryResponseBuilder interface {
// ChaincodeDefinitionGetter is responsible for retrieving a chaincode definition
// from the system. The definition is used by the InstantiationPolicyChecker.
type ChaincodeDefinitionGetter interface {
GetChaincodeDefinition(ctxt context.Context, txid string, signedProp *pb.SignedProposal, prop *pb.Proposal, chainID string, chaincodeID string) (ccprovider.ChaincodeDefinition, error)
GetChaincodeDefinition(chaincodeName string, txSim ledger.QueryExecutor) (ccprovider.ChaincodeDefinition, error)
}

// LedgerGetter is used to get ledgers for chaincode.
Expand Down Expand Up @@ -858,7 +858,7 @@ func (h *Handler) HandleInvokeChaincode(msg *pb.ChaincodeMessage, txContext *Tra
version := h.SystemCCVersion
if !h.SystemCCProvider.IsSysCC(targetInstance.ChaincodeName) {
// if its a user chaincode, get the details
cd, err := h.DefinitionGetter.GetChaincodeDefinition(ctxt, msg.Txid, txContext.SignedProp, txContext.Proposal, targetInstance.ChainID, targetInstance.ChaincodeName)
cd, err := h.DefinitionGetter.GetChaincodeDefinition(targetInstance.ChaincodeName, txsim)
if err != nil {
return nil, errors.WithStack(err)
}
Expand Down
7 changes: 2 additions & 5 deletions core/chaincode/handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1583,12 +1583,9 @@ var _ = Describe("Handler", func() {
Expect(err).NotTo(HaveOccurred())

Expect(fakeDefinitionGetter.GetChaincodeDefinitionCallCount()).To(Equal(1))
_, txid, signedProp, prop, chainID, ccname := fakeDefinitionGetter.GetChaincodeDefinitionArgsForCall(0)
Expect(txid).To(Equal("tx-id"))
Expect(signedProp).To(Equal(expectedSignedProp))
Expect(prop).To(Equal(expectedProposal))
Expect(chainID).To(Equal("channel-id"))
ccname, txSim := fakeDefinitionGetter.GetChaincodeDefinitionArgsForCall(0)
Expect(ccname).To(Equal("target-chaincode-name"))
Expect(txSim).To(Equal(newTxSimulator))
})

It("checks the instantiation policy on the target", func() {
Expand Down
51 changes: 5 additions & 46 deletions core/chaincode/lifecycle/lifecycle.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,28 +7,20 @@ SPDX-License-Identifier: Apache-2.0
package lifecycle

import (
"github.com/golang/protobuf/proto"
"github.com/hyperledger/fabric/common/util"
"github.com/hyperledger/fabric/core/chaincode/shim"
"github.com/hyperledger/fabric/core/common/ccprovider"
"github.com/hyperledger/fabric/core/ledger"
pb "github.com/hyperledger/fabric/protos/peer"
"github.com/pkg/errors"
"golang.org/x/net/context"
)

// Executor is used to invoke chaincode.
type Executor interface {
Execute(ctxt context.Context, cccid *ccprovider.CCContext, cis *pb.ChaincodeInvocationSpec) (*pb.Response, *pb.ChaincodeEvent, error)
}

// InstantiatedChaincodeStore returns information on chaincodes which are instantiated
type InstantiatedChaincodeStore interface {
ChaincodeDeploymentSpec(channelID, chaincodeName string) (*pb.ChaincodeDeploymentSpec, error)
ChaincodeDefinition(chaincodeName string, txSim ledger.QueryExecutor) (ccprovider.ChaincodeDefinition, error)
}

// Lifecycle provides methods to invoke the lifecycle system chaincode.
type Lifecycle struct {
Executor Executor
InstantiatedChaincodeStore InstantiatedChaincodeStore
}

Expand All @@ -54,42 +46,9 @@ func (l *Lifecycle) ChaincodeContainerInfo(channelID, chaincodeName string) (*Ch
}

// GetChaincodeDefinition returns a ccprovider.ChaincodeDefinition for the chaincode
// associated with the provided channel and name.
func (l *Lifecycle) GetChaincodeDefinition(
ctx context.Context,
txid string,
signedProp *pb.SignedProposal,
prop *pb.Proposal,
chainID string,
chaincodeID string,
) (ccprovider.ChaincodeDefinition, error) {
version := util.GetSysCCVersion()
cccid := ccprovider.NewCCContext(chainID, "lscc", version, txid, true, signedProp, prop)

invocationSpec := &pb.ChaincodeInvocationSpec{
ChaincodeSpec: &pb.ChaincodeSpec{
Type: pb.ChaincodeSpec_GOLANG,
ChaincodeId: &pb.ChaincodeID{Name: cccid.Name},
Input: &pb.ChaincodeInput{
Args: util.ToChaincodeArgs("getccdata", chainID, chaincodeID),
},
},
}
res, _, err := l.Executor.Execute(ctx, cccid, invocationSpec)
if err != nil {
return nil, errors.Wrapf(err, "getccdata %s/%s failed", chainID, chaincodeID)
}
if res.Status != shim.OK {
return nil, errors.Errorf("getccdata %s/%s responded with error: %s", chainID, chaincodeID, res.Message)
}

cd := &ccprovider.ChaincodeData{}
err = proto.Unmarshal(res.Payload, cd)
if err != nil {
return nil, errors.Wrap(err, "failed to unmarshal chaincode definition")
}

return cd, nil
// associated with the provided txsim and name.
func (l *Lifecycle) GetChaincodeDefinition(chaincodeName string, txSim ledger.QueryExecutor) (ccprovider.ChaincodeDefinition, error) {
return l.InstantiatedChaincodeStore.ChaincodeDefinition(chaincodeName, txSim)
}

func DeploymentSpecToChaincodeContainerInfo(cds *pb.ChaincodeDeploymentSpec) *ChaincodeContainerInfo {
Expand Down
5 changes: 0 additions & 5 deletions core/chaincode/lifecycle/lifecycle_suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,6 @@ import (
"testing"
)

//go:generate counterfeiter -o mock/executor.go --fake-name Executor . executor
type executor interface {
lifecycle.Executor
}

//go:generate counterfeiter -o mock/instantiated_cc_store.go --fake-name InstantiatedChaincodeStore . instantiatedChaincodeStore
type instantiatedChaincodeStore interface {
lifecycle.InstantiatedChaincodeStore
Expand Down
110 changes: 18 additions & 92 deletions core/chaincode/lifecycle/lifecycle_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,31 +7,32 @@ SPDX-License-Identifier: Apache-2.0
package lifecycle_test

import (
"github.com/golang/protobuf/proto"
"github.com/hyperledger/fabric/common/util"
lc "github.com/hyperledger/fabric/core/chaincode/lifecycle"
"github.com/hyperledger/fabric/core/chaincode/lifecycle/mock"
"github.com/hyperledger/fabric/core/chaincode/shim"
"github.com/hyperledger/fabric/core/common/ccprovider"
pb "github.com/hyperledger/fabric/protos/peer"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/pkg/errors"
"golang.org/x/net/context"
)

var _ = Describe("Lifecycle", func() {
var (
lifecycle *lc.Lifecycle
lifecycle *lc.Lifecycle
fakeInstantiatedCCStore *mock.InstantiatedChaincodeStore
)

BeforeEach(func() {
fakeInstantiatedCCStore = &mock.InstantiatedChaincodeStore{}

lifecycle = &lc.Lifecycle{
InstantiatedChaincodeStore: fakeInstantiatedCCStore,
}
})

Describe("ChaincodeContainerInfo", func() {
var (
fakeInstantiatedCCStore *mock.InstantiatedChaincodeStore
deploymentSpec *pb.ChaincodeDeploymentSpec
deploymentSpec *pb.ChaincodeDeploymentSpec
)

BeforeEach(func() {
Expand All @@ -47,12 +48,7 @@ var _ = Describe("Lifecycle", func() {
ExecEnv: pb.ChaincodeDeploymentSpec_SYSTEM,
}

fakeInstantiatedCCStore = &mock.InstantiatedChaincodeStore{}
fakeInstantiatedCCStore.ChaincodeDeploymentSpecReturns(deploymentSpec, nil)

lifecycle = &lc.Lifecycle{
InstantiatedChaincodeStore: fakeInstantiatedCCStore,
}
})

It("invokes lscc getdepspec with the correct args", func() {
Expand Down Expand Up @@ -85,94 +81,24 @@ var _ = Describe("Lifecycle", func() {
Describe("GetChaincodeDefinition", func() {
var (
chaincodeData *ccprovider.ChaincodeData

fakeExecutor *mock.Executor
signedProp *pb.SignedProposal
proposal *pb.Proposal
)

BeforeEach(func() {
fakeExecutor = &mock.Executor{}
signedProp = &pb.SignedProposal{ProposalBytes: []byte("some-proposal-bytes")}
proposal = &pb.Proposal{Payload: []byte("some-payload-bytes")}

lifecycle = &lc.Lifecycle{
Executor: fakeExecutor,
}

chaincodeData = &ccprovider.ChaincodeData{
Name: "george",
Version: "old",
}
payload, err := proto.Marshal(chaincodeData)
Expect(err).NotTo(HaveOccurred())

response := &pb.Response{
Status: shim.OK,
Payload: payload,
Name: "chaincode-data-name",
}
fakeExecutor.ExecuteReturns(response, nil, nil)
})

It("invokes lscc getccdata with the correct args", func() {
cd, err := lifecycle.GetChaincodeDefinition(context.Background(), "tx-id", signedProp, proposal, "chain-id", "chaincode-id")
Expect(err).NotTo(HaveOccurred())
Expect(cd).To(Equal(chaincodeData))

Expect(fakeExecutor.ExecuteCallCount()).To(Equal(1))
ctx, cccid, cis := fakeExecutor.ExecuteArgsForCall(0)
Expect(ctx).To(Equal(context.Background()))
Expect(cccid).To(Equal(ccprovider.NewCCContext("chain-id", "lscc", "latest", "tx-id", true, signedProp, proposal)))
Expect(cis).To(Equal(&pb.ChaincodeInvocationSpec{
ChaincodeSpec: &pb.ChaincodeSpec{
Type: pb.ChaincodeSpec_GOLANG,
ChaincodeId: &pb.ChaincodeID{Name: "lscc"},
Input: &pb.ChaincodeInput{
Args: util.ToChaincodeArgs("getccdata", "chain-id", "chaincode-id"),
},
},
}))
fakeInstantiatedCCStore.ChaincodeDefinitionReturns(chaincodeData, errors.New("fake-error"))
})

Context("when the executor fails", func() {
BeforeEach(func() {
fakeExecutor.ExecuteReturns(nil, nil, errors.New("mango-tango"))
})

It("returns a wrapped error", func() {
_, err := lifecycle.GetChaincodeDefinition(context.Background(), "tx-id", signedProp, proposal, "chain-id", "chaincode-id")
Expect(err).To(MatchError("getccdata chain-id/chaincode-id failed: mango-tango"))
})
})

Context("when the executor returns an error response", func() {
BeforeEach(func() {
response := &pb.Response{
Status: shim.ERROR,
Message: "danger-danger",
}
fakeExecutor.ExecuteReturns(response, nil, nil)
})

It("returns a wrapped error", func() {
_, err := lifecycle.GetChaincodeDefinition(context.Background(), "tx-id", signedProp, proposal, "chain-id", "chaincode-id")
Expect(err).To(MatchError("getccdata chain-id/chaincode-id responded with error: danger-danger"))
})
})

Context("when unmarshaling the response fails", func() {
BeforeEach(func() {
response := &pb.Response{
Status: shim.OK,
Payload: []byte("totally-bogus-payload"),
}
fakeExecutor.ExecuteReturns(response, nil, nil)
})

It("returns a wrapped error", func() {
_, err := lifecycle.GetChaincodeDefinition(context.Background(), "tx-id", signedProp, proposal, "chain-id", "chaincode-id")
Expect(err).To(MatchError(HavePrefix("failed to unmarshal chaincode definition: proto: ")))
})
It("passes through to the underlying implementation", func() {
chaincodeDefinition, err := lifecycle.GetChaincodeDefinition("foo", nil)
Expect(chaincodeDefinition.(*ccprovider.ChaincodeData)).To(Equal(chaincodeData))
Expect(err).To(MatchError("fake-error"))
Expect(fakeInstantiatedCCStore.ChaincodeDefinitionCallCount()).To(Equal(1))
ccNameArg, txSimArg := fakeInstantiatedCCStore.ChaincodeDefinitionArgsForCall(0)
Expect(ccNameArg).To(Equal("foo"))
Expect(txSimArg).To(BeNil())
})
})
})
Loading

0 comments on commit d861bbf

Please sign in to comment.