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