Skip to content

Commit

Permalink
FAB-23 user given name instead of fabric generated hash
Browse files Browse the repository at this point in the history
FAB-23 is implemented by this changeset.

Deployment usage change : name has to be specified in addition to
path. For example in the sample below, "-n mycc" will serve as the
name of the chaincode.
  peer chaincode deploy -n mycc -p github.com/hyperledger/fabric/
examples/chaincode/go/chaincode_example02 -c '{"Args":["init","a",
"100","b","200"]}'

The name should be unique.

The Life Cycle System Chaincode (LCCC) maps unique chaincode names
to other chaincode properies such as Version and deployment spec
using chaincode state variables.  With these we no longer need
to depend upon generated hash to provide uniqueness. We may still
use hash to restrict duplicate deployments of the same code but using
different names in a separate story.

Also we will disallow some characters in chaincode name for use in
future support for namespaces. Currently these characters are "/[]{}$:".

Unit tests have been modified to use name. In particular, example04
no longer needs to depend on generated hash and uses user provided
name.

Change-Id: I6b81f75e54cb13aa19b9c9d982b3756c5dca7440
Signed-off-by: Srinivasan Muralidharan <muralisr@us.ibm.com>
  • Loading branch information
Srinivasan Muralidharan committed Nov 4, 2016
1 parent 351423d commit c3a3e2f
Show file tree
Hide file tree
Showing 17 changed files with 120 additions and 76 deletions.
41 changes: 21 additions & 20 deletions core/chaincode/exectransaction_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,7 @@ func closeListenerAndSleep(l net.Listener) {
}
}

func executeDeployTransaction(t *testing.T, url string) {
func executeDeployTransaction(t *testing.T, name string, url string) {
lis, err := initPeer()
if err != nil {
t.Fail()
Expand All @@ -400,7 +400,7 @@ func executeDeployTransaction(t *testing.T, url string) {

f := "init"
args := util.ToChaincodeArgs(f, "a", "100", "b", "200")
spec := &pb.ChaincodeSpec{Type: 1, ChaincodeID: &pb.ChaincodeID{Path: url}, CtorMsg: &pb.ChaincodeInput{Args: args}}
spec := &pb.ChaincodeSpec{Type: 1, ChaincodeID: &pb.ChaincodeID{Name: name, Path: url}, CtorMsg: &pb.ChaincodeInput{Args: args}}
_, err = deploy(ctxt, spec)
chaincodeID := spec.ChaincodeID.Name
if err != nil {
Expand All @@ -415,23 +415,23 @@ func executeDeployTransaction(t *testing.T, url string) {

// Test deploy of a transaction
func TestExecuteDeployTransaction(t *testing.T) {
executeDeployTransaction(t, "github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example01")
executeDeployTransaction(t, "example01", "github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example01")
}

// Test deploy of a transaction with a GOPATH with multiple elements
func TestGopathExecuteDeployTransaction(t *testing.T) {
// add a trailing slash to GOPATH
// and a couple of elements - it doesn't matter what they are
os.Setenv("GOPATH", os.Getenv("GOPATH")+string(os.PathSeparator)+string(os.PathListSeparator)+"/tmp/foo"+string(os.PathListSeparator)+"/tmp/bar")
executeDeployTransaction(t, "github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example01")
executeDeployTransaction(t, "example01", "github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example01")
}

// Test deploy of a transaction with a chaincode over HTTP.
func TestHTTPExecuteDeployTransaction(t *testing.T) {
// The chaincode used here cannot be from the fabric repo
// itself or it won't be downloaded because it will be found
// in GOPATH, which would defeat the test
executeDeployTransaction(t, "http://gopkg.in/mastersingh24/fabric-test-resources.v1")
executeDeployTransaction(t, "example01", "http://gopkg.in/mastersingh24/fabric-test-resources.v1")
}

// Check the correctness of the final state after transaction execution.
Expand Down Expand Up @@ -537,7 +537,7 @@ func TestExecuteInvokeTransaction(t *testing.T) {
var ctxt = context.Background()

url := "github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02"
chaincodeID := &pb.ChaincodeID{Path: url}
chaincodeID := &pb.ChaincodeID{Name: "example02", Path: url}

args := []string{"a", "b", "10"}
err = invokeExample02Transaction(ctxt, chaincodeID, args, true)
Expand Down Expand Up @@ -601,7 +601,7 @@ func TestExecuteQuery(t *testing.T) {

url := "github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02"

cID := &pb.ChaincodeID{Path: url}
cID := &pb.ChaincodeID{Name: "example02", Path: url}
f := "init"
args := util.ToChaincodeArgs(f, "a", "100", "b", "200")

Expand Down Expand Up @@ -658,7 +658,7 @@ func TestExecuteInvokeInvalidTransaction(t *testing.T) {
var ctxt = context.Background()

url := "github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02"
chaincodeID := &pb.ChaincodeID{Path: url}
chaincodeID := &pb.ChaincodeID{Name: "example02", Path: url}

//FAIL, FAIL!
args := []string{"x", "-1"}
Expand Down Expand Up @@ -707,7 +707,7 @@ func chaincodeInvokeChaincode(t *testing.T, user string) (err error) {
// Deploy first chaincode
url1 := "github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02"

cID1 := &pb.ChaincodeID{Path: url1}
cID1 := &pb.ChaincodeID{Name: "example02", Path: url1}
f := "init"
args := util.ToChaincodeArgs(f, "a", "100", "b", "200")

Expand All @@ -729,7 +729,7 @@ func chaincodeInvokeChaincode(t *testing.T, user string) (err error) {
// Deploy second chaincode
url2 := "github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example04"

cID2 := &pb.ChaincodeID{Path: url2}
cID2 := &pb.ChaincodeID{Name: "example04", Path: url2}
f = "init"
args = util.ToChaincodeArgs(f, "e", "0")

Expand All @@ -747,8 +747,9 @@ func chaincodeInvokeChaincode(t *testing.T, user string) (err error) {

time.Sleep(time.Second)

// Invoke second chaincode, which will inturn invoke the first chaincode
f = "invoke"
// Invoke second chaincode passing the first chaincode's name as first param,
// which will inturn invoke the first chaincode
f = spec1.ChaincodeID.Name
args = util.ToChaincodeArgs(f, "e", "1")

spec2 = &pb.ChaincodeSpec{Type: 1, ChaincodeID: cID2, CtorMsg: &pb.ChaincodeInput{Args: args}, SecureContext: user}
Expand Down Expand Up @@ -796,7 +797,7 @@ func TestChaincodeInvokeChaincodeErrorCase(t *testing.T) {
// Deploy first chaincode
url1 := "github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02"

cID1 := &pb.ChaincodeID{Path: url1}
cID1 := &pb.ChaincodeID{Name: "example02", Path: url1}
f := "init"
args := util.ToChaincodeArgs(f, "a", "100", "b", "200")

Expand All @@ -816,7 +817,7 @@ func TestChaincodeInvokeChaincodeErrorCase(t *testing.T) {
// Deploy second chaincode
url2 := "github.com/hyperledger/fabric/examples/chaincode/go/passthru"

cID2 := &pb.ChaincodeID{Path: url2}
cID2 := &pb.ChaincodeID{Name: "pthru", Path: url2}
f = "init"
args = util.ToChaincodeArgs(f)

Expand Down Expand Up @@ -868,7 +869,7 @@ func chaincodeQueryChaincode(user string) error {
// Deploy first chaincode
url1 := "github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02"

cID1 := &pb.ChaincodeID{Path: url1}
cID1 := &pb.ChaincodeID{Name: "example02", Path: url1}
f := "init"
args := util.ToChaincodeArgs(f, "a", "100", "b", "200")

Expand All @@ -886,7 +887,7 @@ func chaincodeQueryChaincode(user string) error {
// Deploy second chaincode
url2 := "github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example05"

cID2 := &pb.ChaincodeID{Path: url2}
cID2 := &pb.ChaincodeID{Name: "example05", Path: url2}
f = "init"
args = util.ToChaincodeArgs(f, "sum", "0")

Expand Down Expand Up @@ -994,7 +995,7 @@ func TestChaincodeQueryChaincodeErrorCase(t *testing.T) {
// Deploy first chaincode
url1 := "github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02"

cID1 := &pb.ChaincodeID{Path: url1}
cID1 := &pb.ChaincodeID{Name: "example02", Path: url1}
f := "init"
args := util.ToChaincodeArgs(f, "a", "100", "b", "200")

Expand All @@ -1014,7 +1015,7 @@ func TestChaincodeQueryChaincodeErrorCase(t *testing.T) {
// Deploy second chaincode
url2 := "github.com/hyperledger/fabric/examples/chaincode/go/passthru"

cID2 := &pb.ChaincodeID{Path: url2}
cID2 := &pb.ChaincodeID{Name: "pthru", Path: url2}
f = "init"
args = util.ToChaincodeArgs(f)

Expand Down Expand Up @@ -1128,7 +1129,7 @@ func TestRangeQuery(t *testing.T) {
var ctxt = context.Background()

url := "github.com/hyperledger/fabric/examples/chaincode/go/map"
cID := &pb.ChaincodeID{Path: url}
cID := &pb.ChaincodeID{Name: "tmap", Path: url}

f := "init"
args := util.ToChaincodeArgs(f)
Expand Down Expand Up @@ -1173,7 +1174,7 @@ func TestGetEvent(t *testing.T) {

url := "github.com/hyperledger/fabric/examples/chaincode/go/eventsender"

cID := &pb.ChaincodeID{Path: url}
cID := &pb.ChaincodeID{Name: "esender", Path: url}
f := "init"
spec := &pb.ChaincodeSpec{Type: 1, ChaincodeID: cID, CtorMsg: &pb.ChaincodeInput{Args: util.ToChaincodeArgs(f)}}

Expand Down
14 changes: 12 additions & 2 deletions core/chaincode/lccc.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package chaincode

import (
"fmt"
"strings"

"github.com/golang/protobuf/proto"
"github.com/hyperledger/fabric/core/chaincode/shim"
Expand Down Expand Up @@ -53,6 +54,9 @@ const (

//GETDEPSPEC get ChaincodeDeploymentSpec
GETDEPSPEC = "getdepspec"

//characters used in chaincodenamespace
specialChars = "/:[]${}"
)

//---------- the LCCC -----------------
Expand Down Expand Up @@ -227,7 +231,7 @@ func (lccc *LifeCycleSysCC) acl(stub shim.ChaincodeStubInterface, chainname Chai

//check validity of chain name
func (lccc *LifeCycleSysCC) isValidChainName(chainname string) bool {
//TODO we probably need more checks and have
//TODO we probably need more checks
if chainname == "" {
return false
}
Expand All @@ -236,10 +240,16 @@ func (lccc *LifeCycleSysCC) isValidChainName(chainname string) bool {

//check validity of chaincode name
func (lccc *LifeCycleSysCC) isValidChaincodeName(chaincodename string) bool {
//TODO we probably need more checks and have
//TODO we probably need more checks
if chaincodename == "" {
return false
}

//do not allow special characters in chaincode name
if strings.ContainsAny(chaincodename, specialChars) {
return false
}

return true
}

Expand Down
40 changes: 32 additions & 8 deletions core/chaincode/lccc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ func register(stub *shim.MockStub, ccname string) error {
return nil
}

func constructDeploymentSpec(path string, initArgs [][]byte) (*pb.ChaincodeDeploymentSpec, error) {
spec := &pb.ChaincodeSpec{Type: 1, ChaincodeID: &pb.ChaincodeID{Path: path}, CtorMsg: &pb.ChaincodeInput{Args: initArgs}}
func constructDeploymentSpec(name string, path string, initArgs [][]byte) (*pb.ChaincodeDeploymentSpec, error) {
spec := &pb.ChaincodeSpec{Type: 1, ChaincodeID: &pb.ChaincodeID{Name: name, Path: path}, CtorMsg: &pb.ChaincodeInput{Args: initArgs}}
codePackageBytes, err := container.GetChaincodePackageBytes(spec)
if err != nil {
return nil, err
Expand Down Expand Up @@ -67,7 +67,7 @@ func TestDeploy(t *testing.T) {
scc := new(LifeCycleSysCC)
stub := shim.NewMockStub("lccc", scc)

cds, err := constructDeploymentSpec("github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02", [][]byte{[]byte("init"), []byte("a"), []byte("100"), []byte("b"), []byte("200")})
cds, err := constructDeploymentSpec("example02", "github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02", [][]byte{[]byte("init"), []byte("a"), []byte("100"), []byte("b"), []byte("200")})
var b []byte
if b, err = proto.Marshal(cds); err != nil || b == nil {
t.FailNow()
Expand All @@ -94,14 +94,38 @@ func TestInvalidCodeDeploy(t *testing.T) {
}
}

//TestInvalidChaincodeName tests the deploy function with invalid chaincode name
func TestInvalidChaincodeName(t *testing.T) {
initialize()

scc := new(LifeCycleSysCC)
stub := shim.NewMockStub("lccc", scc)

cds, err := constructDeploymentSpec("example02", "github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02", [][]byte{[]byte("init"), []byte("a"), []byte("100"), []byte("b"), []byte("200")})

//change name to empty
cds.ChaincodeSpec.ChaincodeID.Name = ""

var b []byte
if b, err = proto.Marshal(cds); err != nil || b == nil {
t.FailNow()
}

args := [][]byte{[]byte(DEPLOY), []byte("test"), b}
_, err = stub.MockInvoke("1", args)
if _, ok := err.(InvalidChaincodeNameErr); !ok {
t.FailNow()
}
}

//TestRedeploy tests the redeploying will fail function(and fail with "exists" error)
func TestRedeploy(t *testing.T) {
initialize()

scc := new(LifeCycleSysCC)
stub := shim.NewMockStub("lccc", scc)

cds, err := constructDeploymentSpec("github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02", [][]byte{[]byte("init"), []byte("a"), []byte("100"), []byte("b"), []byte("200")})
cds, err := constructDeploymentSpec("example02", "github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02", [][]byte{[]byte("init"), []byte("a"), []byte("100"), []byte("b"), []byte("200")})
var b []byte
if b, err = proto.Marshal(cds); err != nil || b == nil {
t.FailNow()
Expand All @@ -127,7 +151,7 @@ func TestCheckCC(t *testing.T) {
scc := new(LifeCycleSysCC)
stub := shim.NewMockStub("lccc", scc)

cds, err := constructDeploymentSpec("github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02", [][]byte{[]byte("init"), []byte("a"), []byte("100"), []byte("b"), []byte("200")})
cds, err := constructDeploymentSpec("example02", "github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02", [][]byte{[]byte("init"), []byte("a"), []byte("100"), []byte("b"), []byte("200")})
var b []byte
if b, err = proto.Marshal(cds); err != nil || b == nil {
t.FailNow()
Expand All @@ -152,7 +176,7 @@ func TestMultipleDeploy(t *testing.T) {
stub := shim.NewMockStub("lccc", scc)

//deploy 02
cds, err := constructDeploymentSpec("github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02", [][]byte{[]byte("init"), []byte("a"), []byte("100"), []byte("b"), []byte("200")})
cds, err := constructDeploymentSpec("example02", "github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02", [][]byte{[]byte("init"), []byte("a"), []byte("100"), []byte("b"), []byte("200")})
var b []byte
if b, err = proto.Marshal(cds); err != nil || b == nil {
t.FailNow()
Expand All @@ -169,7 +193,7 @@ func TestMultipleDeploy(t *testing.T) {
}

//deploy 01
cds, err = constructDeploymentSpec("github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example01", [][]byte{[]byte("init"), []byte("a"), []byte("100"), []byte("b"), []byte("200")})
cds, err = constructDeploymentSpec("example01", "github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example01", [][]byte{[]byte("init"), []byte("a"), []byte("100"), []byte("b"), []byte("200")})
if b, err = proto.Marshal(cds); err != nil || b == nil {
t.FailNow()
}
Expand All @@ -193,7 +217,7 @@ func TestRetryFailedDeploy(t *testing.T) {
stub := shim.NewMockStub("lccc", scc)

//deploy 02
cds, err := constructDeploymentSpec("github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02", [][]byte{[]byte("init"), []byte("a"), []byte("100"), []byte("b"), []byte("200")})
cds, err := constructDeploymentSpec("example02", "github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02", [][]byte{[]byte("init"), []byte("a"), []byte("100"), []byte("b"), []byte("200")})
var b []byte
if b, err = proto.Marshal(cds); err != nil || b == nil {
t.FailNow()
Expand Down
5 changes: 0 additions & 5 deletions core/chaincode/platforms/car/package.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,6 @@ func (carPlatform *Platform) WritePackage(spec *pb.ChaincodeSpec, tw *tar.Writer
return err
}

spec.ChaincodeID.Name, err = generateHashcode(spec, path)
if err != nil {
return fmt.Errorf("Error generating hashcode: %s", err)
}

var buf []string

//let the executable's name be chaincode ID's name
Expand Down
2 changes: 1 addition & 1 deletion core/chaincode/platforms/car/test/car_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ func TestCar_BuildImage(t *testing.T) {
}

chaincodePath := cwd + "/org.hyperledger.chaincode.example02-0.1-SNAPSHOT.car"
spec := &pb.ChaincodeSpec{Type: pb.ChaincodeSpec_CAR, ChaincodeID: &pb.ChaincodeID{Path: chaincodePath}, CtorMsg: &pb.ChaincodeInput{Args: util.ToChaincodeArgs("f")}}
spec := &pb.ChaincodeSpec{Type: pb.ChaincodeSpec_CAR, ChaincodeID: &pb.ChaincodeID{Name: "cartest", Path: chaincodePath}, CtorMsg: &pb.ChaincodeInput{Args: util.ToChaincodeArgs("f")}}
if _, err := vm.BuildChaincodeContainer(spec); err != nil {
t.Fail()
t.Log(err)
Expand Down
12 changes: 6 additions & 6 deletions core/chaincode/platforms/golang/hash.go
Original file line number Diff line number Diff line change
Expand Up @@ -210,25 +210,25 @@ func getCodeFromFS(path string) (codegopath string, err error) {
return
}

//generateHashcode gets hashcode of the code under path. If path is a HTTP(s) url
//it downloads the code first to compute the hash.
//collectChaincodeFiles collects chaincode files and generates hashcode for the
//package. If path is a HTTP(s) url it downloads the code first.
//NOTE: for dev mode, user builds and runs chaincode manually. The name provided
//by the user is equivalent to the path. This method will treat the name
//as codebytes and compute the hash from it. ie, user cannot run the chaincode
//with the same (name, ctor, args)
func generateHashcode(spec *pb.ChaincodeSpec, tw *tar.Writer) (string, error) {
func collectChaincodeFiles(spec *pb.ChaincodeSpec, tw *tar.Writer) (string, error) {
if spec == nil {
return "", fmt.Errorf("Cannot generate hashcode from nil spec")
return "", fmt.Errorf("Cannot collect files from nil spec")
}

chaincodeID := spec.ChaincodeID
if chaincodeID == nil || chaincodeID.Path == "" {
return "", fmt.Errorf("Cannot generate hashcode from empty chaincode path")
return "", fmt.Errorf("Cannot collect files from empty chaincode path")
}

ctor := spec.CtorMsg
if ctor == nil || len(ctor.Args) == 0 {
return "", fmt.Errorf("Cannot generate hashcode from empty ctor")
return "", fmt.Errorf("Cannot collect files from empty ctor")
}

//code root will point to the directory where the code exists
Expand Down
6 changes: 5 additions & 1 deletion core/chaincode/platforms/golang/platform.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,11 @@ func (goPlatform *Platform) ValidateSpec(spec *pb.ChaincodeSpec) error {
func (goPlatform *Platform) WritePackage(spec *pb.ChaincodeSpec, tw *tar.Writer) error {

var err error
spec.ChaincodeID.Name, err = generateHashcode(spec, tw)

//ignore the generated hash. Just use the tw
//The hash could be used in a future enhancement
//to check, warn of duplicate installs etc.
_, err = collectChaincodeFiles(spec, tw)
if err != nil {
return err
}
Expand Down
Loading

0 comments on commit c3a3e2f

Please sign in to comment.