github.com/leonlxy/hyperledger@v1.0.0-alpha.0.20170427033203-34922035d248/core/chaincode/upgrade_test.go (about) 1 /* 2 Copyright IBM Corp. 2016 All Rights Reserved. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package chaincode 18 19 import ( 20 "fmt" 21 "strings" 22 "testing" 23 24 "github.com/hyperledger/fabric/common/util" 25 "github.com/hyperledger/fabric/core/common/ccprovider" 26 pb "github.com/hyperledger/fabric/protos/peer" 27 28 "github.com/golang/protobuf/proto" 29 "golang.org/x/net/context" 30 ) 31 32 //getUpgradeLSCCSpec gets the spec for the chaincode upgrade to be sent to LSCC 33 func getUpgradeLSCCSpec(chainID string, cds *pb.ChaincodeDeploymentSpec) (*pb.ChaincodeInvocationSpec, error) { 34 b, err := proto.Marshal(cds) 35 if err != nil { 36 return nil, err 37 } 38 39 //wrap the deployment in an invocation spec to lscc... 40 lsccSpec := &pb.ChaincodeInvocationSpec{ChaincodeSpec: &pb.ChaincodeSpec{Type: pb.ChaincodeSpec_GOLANG, ChaincodeId: &pb.ChaincodeID{Name: "lscc"}, Input: &pb.ChaincodeInput{Args: [][]byte{[]byte("upgrade"), []byte(chainID), b}}}} 41 42 return lsccSpec, nil 43 } 44 45 // upgrade a chaincode - i.e., build and initialize. 46 func upgrade(ctx context.Context, cccid *ccprovider.CCContext, spec *pb.ChaincodeSpec, blockNumber uint64) (*ccprovider.CCContext, error) { 47 // First build and get the deployment spec 48 chaincodeDeploymentSpec, err := getDeploymentSpec(ctx, spec) 49 if err != nil { 50 return nil, err 51 } 52 53 return upgrade2(ctx, cccid, chaincodeDeploymentSpec, blockNumber) 54 } 55 56 func upgrade2(ctx context.Context, cccid *ccprovider.CCContext, 57 chaincodeDeploymentSpec *pb.ChaincodeDeploymentSpec, blockNumber uint64) (newcccid *ccprovider.CCContext, err error) { 58 cis, err := getUpgradeLSCCSpec(cccid.ChainID, chaincodeDeploymentSpec) 59 if err != nil { 60 return nil, fmt.Errorf("Error creating lscc spec : %s\n", err) 61 } 62 63 ctx, txsim, err := startTxSimulation(ctx, cccid.ChainID) 64 if err != nil { 65 return nil, fmt.Errorf("Failed to get handle to simulator: %s ", err) 66 } 67 68 uuid := util.GenerateUUID() 69 70 cccid.TxID = uuid 71 72 defer func() { 73 //no error, lets try commit 74 if err == nil { 75 //capture returned error from commit 76 err = endTxSimulationCDS(cccid.ChainID, uuid, txsim, []byte("upgraded"), true, chaincodeDeploymentSpec, blockNumber) 77 } else { 78 //there was an error, just close simulation and return that 79 endTxSimulationCDS(cccid.ChainID, uuid, txsim, []byte("upgraded"), false, chaincodeDeploymentSpec, blockNumber) 80 } 81 }() 82 83 //ignore existence errors 84 ccprovider.PutChaincodeIntoFS(chaincodeDeploymentSpec) 85 86 sysCCVers := util.GetSysCCVersion() 87 lsccid := ccprovider.NewCCContext(cccid.ChainID, cis.ChaincodeSpec.ChaincodeId.Name, sysCCVers, uuid, true, nil, nil) 88 89 var cdbytes []byte 90 //write to lscc 91 if cdbytes, _, err = ExecuteWithErrorFilter(ctx, lsccid, cis); err != nil { 92 return nil, fmt.Errorf("Error executing LSCC for upgrade: %s", err) 93 } 94 95 if cdbytes == nil { 96 return nil, fmt.Errorf("Expected ChaincodeData back from LSCC but got nil") 97 } 98 99 cd := &ccprovider.ChaincodeData{} 100 if err = proto.Unmarshal(cdbytes, cd); err != nil { 101 return nil, fmt.Errorf("getting ChaincodeData failed") 102 } 103 104 newVersion := string(cd.Version) 105 if newVersion == cccid.Version { 106 return nil, fmt.Errorf("Expected new version from LSCC but got same %s(%s)", newVersion, cccid.Version) 107 } 108 109 newcccid = ccprovider.NewCCContext(cccid.ChainID, chaincodeDeploymentSpec.ChaincodeSpec.ChaincodeId.Name, newVersion, uuid, false, nil, nil) 110 111 if _, _, err = ExecuteWithErrorFilter(ctx, newcccid, chaincodeDeploymentSpec); err != nil { 112 return nil, fmt.Errorf("Error deploying chaincode for upgrade: %s", err) 113 } 114 return 115 } 116 117 //TestUpgradeCC - test basic upgrade 118 // deploy example01 119 // do a query against 01 that'll fail 120 // upgrade to exampl02 121 // show the upgrade worked using the same query successfully 122 //This test a variety of things in addition to basic upgrade 123 // uses next version from lscc 124 // re-initializtion of the same chaincode "mycc" 125 // upgrade when "mycc" is up and running (test version based namespace) 126 func TestUpgradeCC(t *testing.T) { 127 chainID := util.GetTestChainID() 128 129 lis, err := initPeer(chainID) 130 if err != nil { 131 t.Fail() 132 t.Logf("Error creating peer: %s", err) 133 } 134 135 defer finitPeer(lis, chainID) 136 137 var ctxt = context.Background() 138 139 ccName := "mycc" 140 url := "github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example01" 141 chaincodeID := &pb.ChaincodeID{Name: ccName, Path: url, Version: "0"} 142 143 f := "init" 144 args := util.ToChaincodeArgs(f, "a", "100", "b", "200") 145 146 spec := &pb.ChaincodeSpec{Type: 1, ChaincodeId: chaincodeID, Input: &pb.ChaincodeInput{Args: args}} 147 148 cccid := ccprovider.NewCCContext(chainID, ccName, "0", "", false, nil, nil) 149 var nextBlockNumber uint64 = 1 150 _, err = deploy(ctxt, cccid, spec, nextBlockNumber) 151 152 if err != nil { 153 theChaincodeSupport.Stop(ctxt, cccid, &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec}) 154 t.Fail() 155 t.Logf("Error deploying chaincode %s(%s)", chaincodeID, err) 156 theChaincodeSupport.Stop(ctxt, cccid, &pb.ChaincodeDeploymentSpec{ChaincodeSpec: &pb.ChaincodeSpec{ChaincodeId: chaincodeID}}) 157 return 158 } 159 160 // Query example01, which should fail 161 qArgs := util.ToChaincodeArgs("query", "a") 162 163 spec = &pb.ChaincodeSpec{Type: 1, ChaincodeId: chaincodeID, Input: &pb.ChaincodeInput{Args: qArgs}} 164 165 //Do not increment block number here because, the block will not be committted because of error 166 _, _, _, err = invoke(ctxt, chainID, spec, nextBlockNumber, nil) 167 if err == nil { 168 t.Fail() 169 t.Logf("querying chaincode exampl01 should fail transaction: %s", err) 170 theChaincodeSupport.Stop(ctxt, cccid, &pb.ChaincodeDeploymentSpec{ChaincodeSpec: &pb.ChaincodeSpec{ChaincodeId: chaincodeID}}) 171 return 172 } else if !strings.Contains(err.Error(), "Invalid invoke function name. Expecting \"invoke\"") { 173 t.Fail() 174 t.Logf("expected <Invalid invoke function name. Expecting \"invoke\"> found <%s>", err) 175 theChaincodeSupport.Stop(ctxt, cccid, &pb.ChaincodeDeploymentSpec{ChaincodeSpec: &pb.ChaincodeSpec{ChaincodeId: chaincodeID}}) 176 return 177 } 178 179 //now upgrade to example02 which takes the same args as example01 but inits state vars 180 //and also allows query. 181 url = "github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02" 182 183 //Note ccName hasn't changed... 184 chaincodeID = &pb.ChaincodeID{Name: ccName, Path: url, Version: "1"} 185 spec = &pb.ChaincodeSpec{Type: 1, ChaincodeId: chaincodeID, Input: &pb.ChaincodeInput{Args: args}} 186 187 //...and get back the ccid with the new version 188 nextBlockNumber++ 189 cccid2, err := upgrade(ctxt, cccid, spec, nextBlockNumber) 190 if err != nil { 191 t.Fail() 192 t.Logf("Error upgrading chaincode %s(%s)", chaincodeID, err) 193 theChaincodeSupport.Stop(ctxt, cccid, &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec}) 194 if cccid2 != nil { 195 theChaincodeSupport.Stop(ctxt, cccid2, &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec}) 196 } 197 return 198 } 199 200 //go back and do the same query now 201 spec = &pb.ChaincodeSpec{Type: 1, ChaincodeId: chaincodeID, Input: &pb.ChaincodeInput{Args: qArgs}} 202 nextBlockNumber++ 203 _, _, _, err = invokeWithVersion(ctxt, chainID, cccid2.Version, spec, nextBlockNumber, nil) 204 205 if err != nil { 206 t.Fail() 207 t.Logf("querying chaincode exampl02 did not succeed: %s", err) 208 theChaincodeSupport.Stop(ctxt, cccid, &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec}) 209 theChaincodeSupport.Stop(ctxt, cccid2, &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec}) 210 return 211 } 212 theChaincodeSupport.Stop(ctxt, cccid, &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec}) 213 theChaincodeSupport.Stop(ctxt, cccid2, &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec}) 214 } 215 216 //TestInvalUpgradeCC - test basic upgrade 217 // upgrade to exampl02 when "mycc" is not deployed 218 // look for "not found" failure 219 func TestInvalUpgradeCC(t *testing.T) { 220 chainID := util.GetTestChainID() 221 222 lis, err := initPeer(chainID) 223 if err != nil { 224 t.Fail() 225 t.Logf("Error creating peer: %s", err) 226 } 227 228 defer finitPeer(lis, chainID) 229 230 var ctxt = context.Background() 231 232 ccName := "mycc" 233 url := "github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02" 234 235 f := "init" 236 args := util.ToChaincodeArgs(f, "a", "100", "b", "200") 237 238 cccid := ccprovider.NewCCContext(chainID, ccName, "0", "", false, nil, nil) 239 240 //Note ccName hasn't changed... 241 chaincodeID := &pb.ChaincodeID{Name: ccName, Path: url, Version: "1"} 242 spec := &pb.ChaincodeSpec{Type: 1, ChaincodeId: chaincodeID, Input: &pb.ChaincodeInput{Args: args}} 243 244 //...and get back the ccid with the new version 245 var nextBlockNumber uint64 246 cccid2, err := upgrade(ctxt, cccid, spec, nextBlockNumber) 247 if err == nil { 248 t.Fail() 249 t.Logf("Error expected upgrading to fail but it succeeded%s(%s)", chaincodeID, err) 250 theChaincodeSupport.Stop(ctxt, cccid, &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec}) 251 if cccid2 != nil { 252 theChaincodeSupport.Stop(ctxt, cccid2, &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec}) 253 } 254 return 255 } 256 257 theChaincodeSupport.Stop(ctxt, cccid, &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec}) 258 }