github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/integration/ledger/snapshot_test.go (about) 1 /* 2 Copyright hechain All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package ledger 8 9 import ( 10 "context" 11 "encoding/base64" 12 "encoding/json" 13 "fmt" 14 "io/ioutil" 15 "math" 16 "os" 17 "path/filepath" 18 "strconv" 19 "strings" 20 "syscall" 21 "time" 22 23 docker "github.com/fsouza/go-dockerclient" 24 "github.com/hechain20/hechain/core/ledger/util" 25 "github.com/hechain20/hechain/integration/chaincode/kvexecutor" 26 "github.com/hechain20/hechain/integration/nwo" 27 "github.com/hechain20/hechain/integration/nwo/commands" 28 "github.com/hechain20/hechain/integration/nwo/runner" 29 "github.com/hechain20/hechain/integration/pvtdata/marblechaincodeutil" 30 "github.com/hechain20/hechain/protoutil" 31 cb "github.com/hyperledger/fabric-protos-go/common" 32 ab "github.com/hyperledger/fabric-protos-go/orderer" 33 pb "github.com/hyperledger/fabric-protos-go/peer" 34 . "github.com/onsi/ginkgo" 35 . "github.com/onsi/gomega" 36 "github.com/onsi/gomega/gbytes" 37 "github.com/onsi/gomega/gexec" 38 "github.com/tedsuo/ifrit" 39 ) 40 41 const testchannelID = "testchannel" 42 43 var _ = Describe("Snapshot Generation and Bootstrap", func() { 44 var ( 45 setup *setup 46 helper *marblesTestHelper 47 couchProcess []ifrit.Process 48 legacyChaincode nwo.Chaincode 49 newlifecycleChaincode nwo.Chaincode 50 ) 51 52 BeforeEach(func() { 53 By("initializing and starting the network") 54 setup = initAndStartFourOrgsNetwork() 55 56 helper = &marblesTestHelper{ 57 networkHelper: &networkHelper{ 58 Network: setup.network, 59 orderer: setup.orderer, 60 peers: setup.peers, 61 testDir: setup.testDir, 62 channelID: setup.channelID, 63 }, 64 } 65 }) 66 67 AfterEach(func() { 68 setup.cleanup() 69 for _, proc := range couchProcess { 70 proc.Signal(syscall.SIGTERM) 71 Eventually(proc.Wait(), setup.network.EventuallyTimeout).Should(Receive()) 72 } 73 os.RemoveAll(setup.network.RootDir) 74 }) 75 76 When("chaincode has no private data collections", func() { 77 BeforeEach(func() { 78 legacyChaincode = nwo.Chaincode{ 79 Name: "marbles", 80 Version: "0.0", 81 Path: chaincodePathWithIndex, 82 Ctor: `{"Args":[]}`, 83 Policy: `OR ('Org1MSP.member','Org2MSP.member','Org3MSP.member','Org4MSP.member')`, 84 PackageFile: filepath.Join(setup.testDir, "marbles_legacy.tar.gz"), 85 } 86 87 newlifecycleChaincode = nwo.Chaincode{ 88 Name: "marbles", 89 Version: "0.0", 90 Path: components.Build(chaincodePathWithIndex), 91 Lang: "binary", 92 CodeFiles: filesWithIndex, 93 PackageFile: filepath.Join(setup.testDir, "marbles.tar.gz"), 94 SignaturePolicy: `OR ('Org1MSP.member','Org2MSP.member','Org3MSP.member','Org4MSP.member')`, 95 Sequence: "1", 96 Label: "marbles", 97 } 98 99 By("deploying legacy chaincode on initial peers (stateleveldb)") 100 nwo.DeployChaincodeLegacy(setup.network, testchannelID, setup.orderer, legacyChaincode) 101 }) 102 103 // Below test does the following when peers are using either leveldb or couchdb. 104 // Note that we do not support a channel with mixed DBs. However, for testing, 105 // it would be fine to use mixed DBs to test with both couchdb and leveldb 106 // - create snapshots on the 2 peers and verify they are same 107 // - bootstrap a peer (couchdb) in an existing org from the snapshot 108 // - bootstrap a peer (leveldb) in a new org from the snapshot 109 // - verify couchdb index exists 110 // - verify chaincode invocation, history, qscc, channel config update 111 // - upgrade to new lifecycle chaincode 112 // - create a new snapshot again from a peer (couchdb) bootstrapped from a snapshot 113 // - bootstrap peers (couchdb) in existing org and new org from the new snapshot 114 // - verify couchdb index exists 115 // - verify chaincode invocation, history, qscc 116 // - verify chaincode upgrade and new chaincode install on all peers 117 It("generates snapshot and bootstraps from snapshots", func() { 118 org1peer0 := setup.network.Peer("Org1", "peer0") 119 org2peer0 := setup.network.Peer("Org2", "peer0") 120 121 By("invoking marbles chaincode") 122 testKey := "marble-0" 123 helper.invokeMarblesChaincode(legacyChaincode.Name, org1peer0, "initMarble", "marble-0", "blue", "35", "tom") 124 helper.invokeMarblesChaincode(legacyChaincode.Name, org1peer0, "initMarble", "marble-1", "red", "100", "tom") 125 126 By("getting an existing transaction from a block before snapshot is generated") 127 txenvBeforeSnapshot, txidBeforeSnapshot := getTxFromLastBlock(setup.network, org1peer0) 128 129 // verify snapshot commands with different parameters") 130 blockNum := nwo.GetLedgerHeight(setup.network, org1peer0, testchannelID) - 1 131 verifySnapshotRequestCmds(setup.network, org1peer0, testchannelID, blockNum) 132 133 // test 1: generate snapshots on 2 peers for the same blockNum and verify they are same 134 _, snapshotDir := generateAndCompareSnapshots(setup.network, org1peer0, org2peer0, blockNum) 135 136 // test 2: bootstrap a peer in an existing org from snapshot and verify 137 By("starting new peer org2peer1 in existing org2 (couchdb)") 138 org2peer1, couchProc := startPeer(setup, "Org2", "peer1", testchannelID, true) 139 couchProcess = append(couchProcess, couchProc) 140 141 By("installing legacy chaincode on new peer org2peer1") 142 nwo.InstallChaincodeLegacy(setup.network, legacyChaincode, org2peer1) 143 144 By("joining new peer org2peer1 to the channel") 145 joinBySnapshot(setup.network, setup.orderer, org2peer1, testchannelID, snapshotDir, blockNum) 146 147 By("verifying index created on org2peer1") 148 verifySizeIndexExists(setup.network, testchannelID, setup.orderer, org2peer1, "marbles") 149 150 By("invoking marbles chaincode on bootstrapped peer org2peer1") 151 helper.invokeMarblesChaincode(legacyChaincode.Name, org2peer1, "transferMarble", testKey, "newowner2") 152 153 By("verifying history on peer org2peer1") 154 expectedHistory := []*marbleHistoryResult{ 155 {IsDelete: "false", Value: newMarble(testKey, "blue", 35, "newowner2")}, 156 } 157 helper.assertGetHistoryForMarble(legacyChaincode.Name, org2peer1, expectedHistory, testKey) 158 159 verifyQSCC(setup.network, org2peer1, testchannelID, blockNum, txidBeforeSnapshot) 160 161 // test 3: bootstrap a peer in a new org from snapshot and verify 162 By("starting a peer Org3.peer0 in new org3 (stateleveldb)") 163 org3peer0, _ := startPeer(setup, "Org3", "peer0", testchannelID, false) 164 165 By("installing legacy chaincode on new peer org3peer0") 166 nwo.InstallChaincodeLegacy(setup.network, legacyChaincode, org3peer0) 167 168 By("joining new peer org3peer0 to the channel") 169 joinBySnapshot(setup.network, setup.orderer, org3peer0, testchannelID, snapshotDir, blockNum) 170 171 By("invoking marbles chaincode on bootstrapped peer org3peer0") 172 helper.invokeMarblesChaincode(legacyChaincode.Name, org3peer0, "transferMarble", testKey, "newowner3") 173 174 By("getting an existing transaction from a block after snapshot is generated") 175 txenvAfterSnapshot, txidAfterSnapshot := getTxFromLastBlock(setup.network, org1peer0) 176 177 By("verifying history on peer org3peer0") 178 expectedHistory = []*marbleHistoryResult{ 179 {IsDelete: "false", Value: newMarble(testKey, "blue", 35, "newowner3")}, 180 {IsDelete: "false", Value: newMarble(testKey, "blue", 35, "newowner2")}, 181 } 182 helper.assertGetHistoryForMarble(legacyChaincode.Name, org3peer0, expectedHistory, testKey) 183 184 verifyQSCC(setup.network, org3peer0, testchannelID, blockNum, txidBeforeSnapshot) 185 186 // verify DUPLICATE_TXID error when resubmitting old tx on a peer bootstrapped from snapshot (v1_4 capability) 187 By("resubmitting an old transaction committed before snapshot, expecting duplicated txid error") 188 err := commitTx(setup.network, setup.orderer, org3peer0, testchannelID, txenvBeforeSnapshot, txidBeforeSnapshot) 189 Expect(err.Error()).To(ContainSubstring("transaction invalidated with status (DUPLICATE_TXID)")) 190 By("resubmitting an old transaction committed after snapshot, expecting duplicated txid error") 191 err = commitTx(setup.network, setup.orderer, org3peer0, testchannelID, txenvAfterSnapshot, txidAfterSnapshot) 192 Expect(err.Error()).To(Equal("transaction invalidated with status (DUPLICATE_TXID)")) 193 194 // test 4: upgrade legacy chaincode to new lifecycle 195 By("enabling V2_0 capabilities") 196 channelPeers := setup.network.PeersWithChannel(testchannelID) 197 nwo.EnableCapabilities(setup.network, testchannelID, "Application", "V2_0", setup.orderer, channelPeers...) 198 199 By("upgrading legacy chaincode to new lifecycle chaincode") 200 nwo.DeployChaincode(setup.network, testchannelID, setup.orderer, newlifecycleChaincode, channelPeers...) 201 202 By("invoking chaincode after upgraded to new lifecycle chaincode") 203 helper.invokeMarblesChaincode(newlifecycleChaincode.Name, org1peer0, "initMarble", "marble-upgrade", "blue", "35", "tom") 204 205 // test 5: generate snapshot again on a peer bootstrapped from a snapshot and upgraded to new lifecycle chaincode 206 blockNumForNextSnapshot := nwo.GetLedgerHeight(setup.network, org2peer1, testchannelID) 207 By(fmt.Sprintf("generating a snapshot at blockNum %d on org2peer1 that was bootstrapped by a snapshot", blockNumForNextSnapshot)) 208 submitSnapshotRequest(setup.network, testchannelID, blockNumForNextSnapshot, org2peer1, false, "Snapshot request submitted successfully") 209 210 // invoke chaincode to trigger snapshot generation 211 // 1st call should be committed before snapshot generation, 2nd call should be committed after snapshot generation 212 helper.invokeMarblesChaincode(newlifecycleChaincode.Name, org2peer1, "transferMarble", testKey, "newowner_beforesnapshot") 213 helper.invokeMarblesChaincode(newlifecycleChaincode.Name, org2peer1, "transferMarble", testKey, "newowner_aftersnapshot") 214 215 By("verifying snapshot completed on org2peer1") 216 verifyNoPendingSnapshotRequest(setup.network, org2peer1, testchannelID) 217 nextSnapshotDir := filepath.Join(setup.network.PeerDir(org2peer1), "filesystem", "snapshots", "completed", testchannelID, strconv.Itoa(blockNumForNextSnapshot)) 218 219 By("getting an existing transaction from a block after new snapshot is generated") 220 helper.invokeMarblesChaincode(legacyChaincode.Name, org2peer1, "initMarble", "marble-3", "red", "100", "tom") 221 txenvAfterSnapshot, txidAfterSnapshot = getTxFromLastBlock(setup.network, org1peer0) 222 223 // test 6: bootstrap a peer in a different org from the new snapshot 224 By("starting a peer (org1peer1) in existing org1 (couchdb)") 225 org1peer1, couchProc := startPeer(setup, "Org1", "peer1", testchannelID, true) 226 couchProcess = append(couchProcess, couchProc) 227 228 By("installing new lifecycle chaincode on peer org1peer1") 229 nwo.InstallChaincode(setup.network, newlifecycleChaincode, org1peer1) 230 231 By("joining new peer org1peer1 to the channel") 232 joinBySnapshot(setup.network, setup.orderer, org1peer1, testchannelID, nextSnapshotDir, blockNumForNextSnapshot) 233 234 By("verifying index created on org1peer1") 235 verifySizeIndexExists(setup.network, testchannelID, setup.orderer, org1peer1, "marbles") 236 237 By("verifying history on peer org1peer1") 238 expectedHistory = []*marbleHistoryResult{ 239 {IsDelete: "false", Value: newMarble(testKey, "blue", 35, "newowner_aftersnapshot")}, 240 } 241 helper.assertGetHistoryForMarble(newlifecycleChaincode.Name, org1peer1, expectedHistory, testKey) 242 243 verifyQSCC(setup.network, org1peer1, testchannelID, blockNumForNextSnapshot, txidBeforeSnapshot) 244 245 // test 7: bootstrap a peer in a new org from the new snapshot 246 By("starting a peer (org4peer0) in new org4 (couchdb)") 247 org4peer0, couchProc := startPeer(setup, "Org4", "peer0", testchannelID, true) 248 couchProcess = append(couchProcess, couchProc) 249 250 By("joining new peer org4peer0 to the channel") 251 joinBySnapshot(setup.network, setup.orderer, org4peer0, testchannelID, nextSnapshotDir, blockNumForNextSnapshot) 252 253 By("installing and approving chaincode on new peer org4peer0") 254 installAndApproveChaincode(setup.network, setup.orderer, org4peer0, testchannelID, newlifecycleChaincode, []string{"Org1", "Org2", "Org3", "Org4"}) 255 256 By("verifying index created on org4peer0") 257 verifySizeIndexExists(setup.network, testchannelID, setup.orderer, org2peer1, "marbles") 258 259 By("invoking chaincode on bootstrapped peer org4peer0") 260 helper.invokeMarblesChaincode(newlifecycleChaincode.Name, org4peer0, "delete", testKey) 261 262 By("verifying history on peer org4peer0") 263 expectedHistory = []*marbleHistoryResult{ 264 {IsDelete: "true"}, 265 {IsDelete: "false", Value: newMarble(testKey, "blue", 35, "newowner_aftersnapshot")}, 266 } 267 helper.assertGetHistoryForMarble(newlifecycleChaincode.Name, org4peer0, expectedHistory, testKey) 268 269 verifyQSCC(setup.network, org4peer0, testchannelID, blockNumForNextSnapshot, txidBeforeSnapshot) 270 271 // verify DUPLICATE_TXID error when resubmitting old tx on a peer bootstrapped from snapshot (v_20 capability) 272 By("resubmitting an old transaction committed before snapshot, expecting duplicated txid error") 273 err = commitTx(setup.network, setup.orderer, org4peer0, testchannelID, txenvBeforeSnapshot, txidBeforeSnapshot) 274 Expect(err.Error()).To(ContainSubstring("transaction invalidated with status (DUPLICATE_TXID)")) 275 By("resubmitting an old transaction committed after snapshot, expecting duplicated txid error") 276 err = commitTx(setup.network, setup.orderer, org4peer0, testchannelID, txenvAfterSnapshot, txidAfterSnapshot) 277 Expect(err.Error()).To(Equal("transaction invalidated with status (DUPLICATE_TXID)")) 278 279 // test 8: verify cscc works correctly to get an orderer endpoint from the channel config 280 // even if the peer does not have a channel config block when bootstrapped from snapshot 281 By("invoking chaincode without passing orderer endpoint on org4peer0") 282 invokeWithoutPassingOrdererEndPoint(setup.network, org4peer0, testchannelID, newlifecycleChaincode.Name, "initMarble", "marble-cscctest", "blue", "35", "tom") 283 284 // test 9: verify chaincode upgrade and install after bootstrapping 285 By("upgrading chaincode to version 2.0 on all peers after bootstrapping from snapshot") 286 newlifecycleChaincode.Version = "2.0" 287 newlifecycleChaincode.Sequence = "2" 288 nwo.DeployChaincode(setup.network, testchannelID, setup.orderer, newlifecycleChaincode) 289 290 By("deploying a new chaincode on all the peers after bootstrapping from snapshot") 291 cc2 := nwo.Chaincode{ 292 Name: "kvexecutor", 293 Version: "1.0", 294 Path: components.Build("github.com/hechain20/hechain/integration/chaincode/kvexecutor/cmd"), 295 Lang: "binary", 296 SignaturePolicy: `OR ('Org1MSP.member','Org2MSP.member', 'Org3MSP.member', 'Org4MSP.member')`, 297 PackageFile: filepath.Join(setup.testDir, "kvexecutor20.tar.gz"), 298 Label: "kvexecutor-20", 299 Sequence: "1", 300 } 301 nwo.DeployChaincode(setup.network, testchannelID, setup.orderer, cc2) 302 303 By("invoking the new chaincode") 304 kvdata := []kvexecutor.KVData{ 305 {Key: "key1", Value: "value1"}, 306 {Key: "key2", Value: "value2"}, 307 } 308 invokeAndQueryKVExecutorChaincode(setup.network, setup.orderer, testchannelID, cc2, kvdata, setup.network.PeersWithChannel(testchannelID)...) 309 }) 310 }) 311 312 When("chaincode has private data collections", func() { 313 BeforeEach(func() { 314 newlifecycleChaincode = nwo.Chaincode{ 315 Name: "marblesp", 316 Version: "1.0", 317 Path: components.Build("github.com/hechain20/hechain/integration/chaincode/marbles_private/cmd"), 318 Lang: "binary", 319 PackageFile: filepath.Join(setup.testDir, "marbles-pvtdata.tar.gz"), 320 Label: "marbles-private-20", 321 SignaturePolicy: `OR ('Org1MSP.member','Org2MSP.member')`, 322 CollectionsConfig: filepath.Join("testdata", "collection_configs", "collections_config1.json"), 323 Sequence: "1", 324 } 325 326 // start org3peer0 so that we have majority number of orgs (3 out of 4) to satify the channel config update policy 327 org3peer0, _ := startPeer(setup, "Org3", "peer0", testchannelID, false) 328 setup.network.JoinChannel(testchannelID, setup.orderer, org3peer0) 329 330 By("enabling V2_0 capabilities") 331 channelPeers := setup.network.PeersWithChannel(testchannelID) 332 nwo.EnableCapabilities(setup.network, testchannelID, "Application", "V2_0", setup.orderer, channelPeers...) 333 334 By("deploying newlifecycle chaincode on initial peers (leveldb)") 335 nwo.DeployChaincode(setup.network, testchannelID, setup.orderer, newlifecycleChaincode) 336 }) 337 338 // This test verifies the following: 339 // bootstrapped peer can pull private data 340 // bootstrapped peer can supply private data to other bootstrapped peer 341 It("generates snapshot and bootstraps from snapshots", func() { 342 org1peer0 := setup.network.Peer("Org1", "peer0") 343 org2peer0 := setup.network.Peer("Org2", "peer0") 344 channelPeers := setup.network.PeersWithChannel(testchannelID) 345 346 // prepare test data: add and delete marble1, add and transfer marble1 347 By("adding marble1") 348 marblechaincodeutil.AddMarble(setup.network, setup.orderer, testchannelID, newlifecycleChaincode.Name, 349 `{"name":"marble1", "color":"blue", "size":35, "owner":"tom", "price":99}`, org2peer0) 350 By("deleting marble1") 351 marblechaincodeutil.DeleteMarble(setup.network, setup.orderer, testchannelID, newlifecycleChaincode.Name, 352 `{"name":"marble1"}`, org2peer0) 353 354 By("verifying the deletion of marble1") 355 marblechaincodeutil.AssertDoesNotExistInCollectionM(setup.network, testchannelID, newlifecycleChaincode.Name, "marble1", channelPeers...) 356 marblechaincodeutil.AssertDoesNotExistInCollectionMPD(setup.network, testchannelID, newlifecycleChaincode.Name, "marble1", channelPeers...) 357 358 By("adding marble2") 359 marblechaincodeutil.AddMarble(setup.network, setup.orderer, testchannelID, newlifecycleChaincode.Name, 360 `{"name":"marble2", "color":"blue", "size":35, "owner":"tom", "price":99}`, org2peer0) 361 By("transferring marble2") 362 marblechaincodeutil.TransferMarble(setup.network, setup.orderer, testchannelID, newlifecycleChaincode.Name, 363 `{"name":"marble2", "owner":"jerry"}`, org2peer0) 364 365 assertPvtdataPresencePerCollectionConfig1(setup.network, newlifecycleChaincode.Name, "marble2") 366 367 By("verifying the new ownership of marble2") 368 marblechaincodeutil.AssertOwnershipInCollectionM(setup.network, testchannelID, newlifecycleChaincode.Name, "marble2", "jerry", org1peer0, org2peer0) 369 370 // test 1: generate snapshots on 2 peers for the same blockNum and verify they are same 371 blockNum := nwo.GetLedgerHeight(setup.network, org2peer0, testchannelID) - 1 372 _, snapshotDir := generateAndCompareSnapshots(setup.network, org1peer0, org2peer0, blockNum) 373 374 // test 2: bootstrap a new peer org2peer1 from snapshot and verify pvtdata 375 By("starting new peer org2peer1 (couchdb)") 376 org2peer1, couchProc := startPeer(setup, "Org2", "peer1", testchannelID, true) 377 couchProcess = append(couchProcess, couchProc) 378 379 By("installing chaincode on peer org2peer1") 380 nwo.InstallChaincode(setup.network, newlifecycleChaincode, org2peer1) 381 382 By("joining peer org2peer1 to the channel by snapshot") 383 joinBySnapshot(setup.network, setup.orderer, org2peer1, testchannelID, snapshotDir, blockNum) 384 385 By("waiting for pvtdata to be reconciled on org2peer1") 386 waitForMarblePvtdataReconciliation(setup.network, org2peer1, testchannelID, newlifecycleChaincode.Name, []string{"marble2"}) 387 388 // verify pvtdata reconciliation after joinbysnapshot 389 By("verifying marble2 pvtdata reconciliation on org2peer1") 390 assertPvtdataPresencePerCollectionConfig1(setup.network, newlifecycleChaincode.Name, "marble2", org2peer1) 391 By("verifying the new ownership of marble2") 392 marblechaincodeutil.AssertOwnershipInCollectionM(setup.network, testchannelID, newlifecycleChaincode.Name, "marble2", "jerry", org2peer1) 393 394 By("verifying marble1 does not exist") 395 marblechaincodeutil.AssertDoesNotExistInCollectionM(setup.network, testchannelID, newlifecycleChaincode.Name, "marble1", org2peer1) 396 marblechaincodeutil.AssertDoesNotExistInCollectionMPD(setup.network, testchannelID, newlifecycleChaincode.Name, "marble1", org2peer1) 397 398 // test 3: submit a request to generate snapshot again on a peer (org2peer1) bootstrapped from a snapshot 399 blockNumForNextSnapshot := nwo.GetLedgerHeight(setup.network, org2peer1, testchannelID) 400 By(fmt.Sprintf("generating a snapshot at blockNum %d on org2peer1 that was bootstrapped by a snapshot", blockNumForNextSnapshot)) 401 submitSnapshotRequest(setup.network, testchannelID, blockNumForNextSnapshot, org2peer1, false, "Snapshot request submitted successfully") 402 403 // block for marble3 tx is in snapshot, but block for marble4 tx is post snapshot 404 By("adding marble3") 405 marblechaincodeutil.AddMarble(setup.network, setup.orderer, testchannelID, newlifecycleChaincode.Name, 406 `{"name":"marble3", "color":"blue", "size":35, "owner":"tom", "price":99}`, org2peer1) 407 assertPvtdataPresencePerCollectionConfig1(setup.network, newlifecycleChaincode.Name, "marble3") 408 409 By("adding marble4") 410 marblechaincodeutil.AddMarble(setup.network, setup.orderer, testchannelID, newlifecycleChaincode.Name, 411 `{"name":"marble4", "color":"blue", "size":35, "owner":"tom", "price":99}`, org2peer1) 412 assertPvtdataPresencePerCollectionConfig1(setup.network, newlifecycleChaincode.Name, "marble4") 413 414 By("verifying snapshot completed on org2peer1") 415 verifyNoPendingSnapshotRequest(setup.network, org2peer1, testchannelID) 416 nextSnapshotDir := filepath.Join(setup.network.PeerDir(org2peer1), "filesystem", "snapshots", "completed", testchannelID, strconv.Itoa(blockNumForNextSnapshot)) 417 418 // stop all the peers and only restart org2peer1 419 setup.stopPeers() 420 setup.startPeer(org2peer1) 421 setup.peers = []*nwo.Peer{org2peer1} 422 setup.network.Peers = setup.peers 423 424 // test 4: bootstrap a new peer org2peer2 by snapshot and verify pvtdata reconciliation 425 By("starting a peer (org2peer2) in existing org (leveldb)") 426 org2peer2, _ := startPeer(setup, "Org2", "peer2", testchannelID, false) 427 428 By("installing new lifecycle chaincode2 on peer org2peer2") 429 nwo.InstallChaincode(setup.network, newlifecycleChaincode, org2peer2) 430 431 By("joining peer org2peer2 to the channel by snapshot") 432 joinBySnapshot(setup.network, setup.orderer, org2peer2, testchannelID, nextSnapshotDir, blockNumForNextSnapshot) 433 434 By("waiting for pvtdata to be reconciled on org2peer2") 435 waitForMarblePvtdataReconciliation(setup.network, org2peer2, testchannelID, newlifecycleChaincode.Name, []string{"marble2", "marble3", "marble4"}) 436 437 By("verifying marble4 pvtdata reconciliation on org2peer2") 438 assertPvtdataPresencePerCollectionConfig1(setup.network, newlifecycleChaincode.Name, "marble4", org2peer2) 439 By("verifying marble3 pvtdata reconciliation on org2peer2") 440 assertPvtdataPresencePerCollectionConfig1(setup.network, newlifecycleChaincode.Name, "marble3", org2peer2) 441 By("verifying marble2 pvtdata reconciliation on org2peer2") 442 assertPvtdataPresencePerCollectionConfig1(setup.network, newlifecycleChaincode.Name, "marble2", org2peer2) 443 By("verifying the new ownership of marble2") 444 marblechaincodeutil.AssertOwnershipInCollectionM(setup.network, testchannelID, newlifecycleChaincode.Name, "marble2", "jerry", org2peer2) 445 By("verifying marble1 does not exist") 446 marblechaincodeutil.AssertDoesNotExistInCollectionM(setup.network, testchannelID, newlifecycleChaincode.Name, "marble1", org2peer2) 447 marblechaincodeutil.AssertDoesNotExistInCollectionMPD(setup.network, testchannelID, newlifecycleChaincode.Name, "marble1", org2peer2) 448 449 // test 5: bootstrap a new peer Org2peer3 from genesis block to verify pvtdata reconciliation 450 By("startinging a peer Org2peer3 in an new org (leveldb)") 451 org2peer3, _ := startPeer(setup, "Org2", "peer3", testchannelID, false) 452 453 By("installing newlifecycleChaincode on new peer Org2peer3") 454 nwo.InstallChaincode(setup.network, newlifecycleChaincode, org2peer3) 455 456 By("joining peer Org2peer3 to the channel by genesis block") 457 setup.network.JoinChannel(testchannelID, setup.orderer, org2peer3) 458 459 By("waiting for the new peer to have the same ledger height") 460 channelHeight := nwo.GetMaxLedgerHeight(setup.network, testchannelID, org2peer1) 461 nwo.WaitUntilEqualLedgerHeight(setup.network, testchannelID, channelHeight, org2peer3) 462 463 By("waiting for pvtdata to be reconciled on org2peer3") 464 waitForMarblePvtdataReconciliation(setup.network, org2peer3, testchannelID, newlifecycleChaincode.Name, []string{"marble2", "marble3", "marble4"}) 465 466 By("verifying marble4 pvtdata reconciliation on org2peer3") 467 assertPvtdataPresencePerCollectionConfig1(setup.network, newlifecycleChaincode.Name, "marble4", org2peer3) 468 By("verifying marble3 pvtdata reconciliation on org2peer3") 469 assertPvtdataPresencePerCollectionConfig1(setup.network, newlifecycleChaincode.Name, "marble3", org2peer3) 470 By("verifying marble2 pvtdata reconciliation on org2peer3") 471 assertPvtdataPresencePerCollectionConfig1(setup.network, newlifecycleChaincode.Name, "marble2", org2peer3) 472 By("verifying the new ownership of marble2") 473 marblechaincodeutil.AssertOwnershipInCollectionM(setup.network, testchannelID, newlifecycleChaincode.Name, "marble2", "jerry", org2peer3) 474 By("verifying marble1 does not exist") 475 marblechaincodeutil.AssertDoesNotExistInCollectionM(setup.network, testchannelID, newlifecycleChaincode.Name, "marble1", org2peer3) 476 marblechaincodeutil.AssertDoesNotExistInCollectionMPD(setup.network, testchannelID, newlifecycleChaincode.Name, "marble1", org2peer3) 477 478 // verify pvtdata hash on bootstrapped peers 479 peers := []*nwo.Peer{org2peer1, org2peer2, org2peer3} 480 for i := 2; i <= 4; i++ { 481 name := fmt.Sprintf("marble%d", i) 482 owner := "tom" 483 if name == "marble2" { 484 owner = "jerry" 485 } 486 487 By(fmt.Sprintf("verifying getMarbleHash for %s from all peers that has the chaincode instantiated", name)) 488 expectedBytes := util.ComputeStringHash(fmt.Sprintf(`{"docType":"marble","name":"%s","color":"blue","size":35,"owner":"%s"}`, name, owner)) 489 marblechaincodeutil.AssertMarblesPrivateHashM(setup.network, testchannelID, newlifecycleChaincode.Name, name, expectedBytes, peers) 490 491 By(fmt.Sprintf("verifying getMarblePrivateDetailsHash for %s from all peers that has the chaincode instantiated", name)) 492 expectedBytes = util.ComputeStringHash(fmt.Sprintf(`{"docType":"marblePrivateDetails","name":"%s","price":99}`, name)) 493 marblechaincodeutil.AssertMarblesPrivateDetailsHashMPD(setup.network, testchannelID, newlifecycleChaincode.Name, name, expectedBytes, peers) 494 } 495 }) 496 }) 497 }) 498 499 func configPeerWithCouchDB(s *setup, peer *nwo.Peer) ifrit.Process { 500 couchDB := &runner.CouchDB{} 501 couchProc := ifrit.Invoke(couchDB) 502 Eventually(couchProc.Ready(), runner.DefaultStartTimeout).Should(BeClosed()) 503 Consistently(couchProc.Wait()).ShouldNot(Receive()) 504 505 core := s.network.ReadPeerConfig(peer) 506 core.Ledger.State.StateDatabase = "CouchDB" 507 core.Ledger.State.CouchDBConfig.CouchDBAddress = couchDB.Address() 508 509 By("configuring peer to couchdb address " + couchDB.Address()) 510 s.network.WritePeerConfig(peer, core) 511 512 return couchProc 513 } 514 515 // initAndStartFourOrgsNetwork creates a network with multiple orgs. 516 // Initially only start Org1.peer0 and Org2.peer0 are started and join the channel. 517 func initAndStartFourOrgsNetwork() *setup { 518 var err error 519 testDir, err := ioutil.TempDir("", "snapshot") 520 Expect(err).NotTo(HaveOccurred()) 521 522 client, err := docker.NewClientFromEnv() 523 Expect(err).NotTo(HaveOccurred()) 524 525 config := nwo.BasicSolo() 526 527 config.Channels = []*nwo.Channel{ 528 {Name: testchannelID, Profile: "TwoOrgsChannel"}, 529 } 530 531 for _, peer := range config.Peers { 532 peer.Channels = []*nwo.PeerChannel{ 533 {Name: testchannelID, Anchor: true}, 534 } 535 } 536 537 // add more peers to Org1 and Org2 538 config.Peers = append( 539 config.Peers, 540 &nwo.Peer{ 541 Name: "peer1", 542 Organization: "Org1", 543 Channels: []*nwo.PeerChannel{}, 544 }, 545 &nwo.Peer{ 546 Name: "peer1", 547 Organization: "Org2", 548 Channels: []*nwo.PeerChannel{}, 549 }, 550 &nwo.Peer{ 551 Name: "peer2", 552 Organization: "Org2", 553 Channels: []*nwo.PeerChannel{}, 554 }, 555 &nwo.Peer{ 556 Name: "peer3", 557 Organization: "Org2", 558 Channels: []*nwo.PeerChannel{}, 559 }, 560 ) 561 562 // add org3 with one peer 563 config.Organizations = append(config.Organizations, &nwo.Organization{ 564 Name: "Org3", 565 MSPID: "Org3MSP", 566 Domain: "org3.example.com", 567 EnableNodeOUs: true, 568 Users: 2, 569 CA: &nwo.CA{Hostname: "ca"}, 570 }) 571 config.Consortiums[0].Organizations = append(config.Consortiums[0].Organizations, "Org3") 572 config.Profiles[1].Organizations = append(config.Profiles[1].Organizations, "Org3") 573 config.Peers = append(config.Peers, &nwo.Peer{ 574 Name: "peer0", 575 Organization: "Org3", 576 Channels: []*nwo.PeerChannel{ 577 {Name: testchannelID, Anchor: true}, 578 }, 579 }) 580 581 // add org4 with one peer 582 config.Organizations = append(config.Organizations, &nwo.Organization{ 583 Name: "Org4", 584 MSPID: "Org4MSP", 585 Domain: "org4.example.com", 586 EnableNodeOUs: true, 587 Users: 2, 588 CA: &nwo.CA{Hostname: "ca"}, 589 }) 590 config.Consortiums[0].Organizations = append(config.Consortiums[0].Organizations, "Org4") 591 config.Profiles[1].Organizations = append(config.Profiles[1].Organizations, "Org4") 592 config.Peers = append(config.Peers, &nwo.Peer{ 593 Name: "peer0", 594 Organization: "Org4", 595 Channels: []*nwo.PeerChannel{ 596 {Name: testchannelID, Anchor: true}, 597 }, 598 }) 599 600 n := nwo.New(config, testDir, client, StartPort(), components) 601 n.GenerateConfigTree() 602 n.Bootstrap() 603 604 // set ReconcileSleepInterval to 1 second to reconcile pvtdata faster 605 // set DeprioritizedDataReconcilerInterval to 2 seconds to resume reconciliation quickly 606 // to prevent CI flake in case peer connection is temporarily lost. 607 for _, p := range n.Peers { 608 core := n.ReadPeerConfig(p) 609 core.Peer.Gossip.PvtData.ReconcileSleepInterval = 1 * time.Second 610 core.Ledger.PvtdataStore.DeprioritizedDataReconcilerInterval = 2 * time.Second 611 n.WritePeerConfig(p, core) 612 } 613 614 // set org2peer2 and org2peer3's gossip bootstrap endpoints pointing to org2peer1 615 org2peer1 := n.Peer("Org2", "peer1") 616 for _, p := range []*nwo.Peer{n.Peer("Org2", "peer2"), n.Peer("Org2", "peer3")} { 617 core := n.ReadPeerConfig(p) 618 core.Peer.Gossip.Bootstrap = n.PeerAddress(org2peer1, nwo.ListenPort) 619 n.WritePeerConfig(p, core) 620 } 621 622 // only keep Org1.peer0 and Org2.peer0 so we can add other peers back later to test join channel by snapshot 623 peers := []*nwo.Peer{} 624 for _, p := range n.Peers { 625 if p.ID() == "Org1.peer0" || p.ID() == "Org2.peer0" { 626 peers = append(peers, p) 627 } 628 } 629 n.Peers = peers 630 631 setup := &setup{ 632 testDir: testDir, 633 network: n, 634 peers: peers, 635 channelID: testchannelID, 636 } 637 Expect(setup.testDir).To(Equal(setup.network.RootDir)) 638 639 By("starting broker and orderer") 640 setup.startBrokerAndOrderer() 641 642 By("starting peers") 643 setup.startPeers() 644 645 orderer := n.Orderer("orderer") 646 setup.orderer = orderer 647 648 By("creating and joining testchannel") 649 n.CreateAndJoinChannel(orderer, testchannelID) 650 n.UpdateChannelAnchors(orderer, testchannelID) 651 652 By("verifying membership for testchannel") 653 n.VerifyMembership(n.PeersWithChannel(testchannelID), testchannelID) 654 655 return setup 656 } 657 658 // verifySnapshotRequestCmds invokes snapshot commands and verify the expected rersults. 659 // At the end, there will be no pending request. 660 func verifySnapshotRequestCmds(n *nwo.Network, peer *nwo.Peer, channel string, blockNum int) { 661 By("submitting snaphost request for a future blockNum, expecting success") 662 submitSnapshotRequest(n, channel, blockNum+10, peer, false, "Snapshot request submitted successfully") 663 By("submitting snaphost request at same blockNum again, expecting error") 664 submitSnapshotRequest(n, channel, blockNum+10, peer, true, 665 fmt.Sprintf("duplicate snapshot request for block number %d", blockNum+10)) 666 By("submitting snaphost request for a previous blockNum, expecting error") 667 submitSnapshotRequest(n, channel, blockNum-1, peer, true, 668 fmt.Sprintf("requested snapshot for block number %d cannot be less than the last committed block number %d", blockNum-1, blockNum)) 669 By("listing pending snaphost requests, expecting success") 670 pendingRequests := listPendingSnapshotRequests(n, channel, peer, n.PeerAddress(peer, nwo.ListenPort), false) 671 Expect(pendingRequests).To(ContainSubstring(fmt.Sprintf("Successfully got pending snapshot requests: [%d]\n", blockNum+10))) 672 By("canceling a pending snaphost request, expecting success") 673 cancelSnapshotRequest(n, channel, blockNum+10, peer, n.PeerAddress(peer, nwo.ListenPort), false, "Snapshot request cancelled successfully") 674 By("canceling the same snaphost request, expecting error") 675 cancelSnapshotRequest(n, channel, blockNum+10, peer, n.PeerAddress(peer, nwo.ListenPort), true, 676 fmt.Sprintf("no snapshot request exists for block number %d", blockNum+10)) 677 By("listing pending snaphost requests, expecting success") 678 pendingRequests = listPendingSnapshotRequests(n, channel, peer, n.PeerAddress(peer, nwo.ListenPort), false) 679 Expect(pendingRequests).To(ContainSubstring("Successfully got pending snapshot requests: []\n")) 680 } 681 682 func generateAndCompareSnapshots(n *nwo.Network, peer1, peer2 *nwo.Peer, blockNumForSnapshot int) (string, string) { 683 By(fmt.Sprintf("submitting snapshot request at blockNum %d on peer %s", blockNumForSnapshot, peer1.ID())) 684 submitSnapshotRequest(n, testchannelID, blockNumForSnapshot, peer1, false, "Snapshot request submitted successfully") 685 686 By(fmt.Sprintf("submitting snaphost request at blockNum %d on peer %s", blockNumForSnapshot, peer2.ID())) 687 submitSnapshotRequest(n, testchannelID, blockNumForSnapshot, peer2, false, "Snapshot request submitted successfully") 688 689 By("verifying snapshot completed on peer1") 690 verifyNoPendingSnapshotRequest(n, peer1, testchannelID) 691 692 By("verifying snapshot completed on peer2") 693 verifyNoPendingSnapshotRequest(n, peer2, testchannelID) 694 695 By("comparing snapshot metadata generated on different peers for the same block number") 696 snapshotDir1 := filepath.Join(n.PeerDir(peer1), "filesystem", "snapshots", "completed", testchannelID, strconv.Itoa(blockNumForSnapshot)) 697 snapshotDir2 := filepath.Join(n.PeerDir(peer2), "filesystem", "snapshots", "completed", testchannelID, strconv.Itoa(blockNumForSnapshot)) 698 compareSnapshotMetadata(snapshotDir1, snapshotDir2) 699 700 return snapshotDir1, snapshotDir2 701 } 702 703 func verifyNoPendingSnapshotRequest(n *nwo.Network, peer *nwo.Peer, channelID string) { 704 checkPending := func() []byte { 705 return listPendingSnapshotRequests(n, channelID, peer, n.PeerAddress(peer, nwo.ListenPort), false) 706 } 707 Eventually(checkPending, n.EventuallyTimeout, 10*time.Second).Should(ContainSubstring("Successfully got pending snapshot requests: []\n")) 708 } 709 710 func submitSnapshotRequest(n *nwo.Network, channel string, blockNum int, peer *nwo.Peer, expectedError bool, expectedMsg string) { 711 sess, err := n.PeerAdminSession(peer, commands.SnapshotSubmitRequest{ 712 ChannelID: channel, 713 BlockNumber: strconv.Itoa(blockNum), 714 ClientAuth: n.ClientAuthRequired, 715 PeerAddress: n.PeerAddress(peer, nwo.ListenPort), 716 }) 717 Expect(err).NotTo(HaveOccurred()) 718 if !expectedError { 719 Eventually(sess, n.EventuallyTimeout).Should(gexec.Exit(0)) 720 Expect(sess).To(gbytes.Say(expectedMsg)) 721 } else { 722 Eventually(sess, n.EventuallyTimeout).Should(gexec.Exit(1)) 723 Expect(sess.Err).To(gbytes.Say(expectedMsg)) 724 } 725 } 726 727 func cancelSnapshotRequest(n *nwo.Network, channel string, blockNum int, peer *nwo.Peer, peerAddress string, expectedError bool, expectedMsg string) { 728 sess, err := n.PeerAdminSession(peer, commands.SnapshotCancelRequest{ 729 ChannelID: channel, 730 BlockNumber: strconv.Itoa(blockNum), 731 ClientAuth: n.ClientAuthRequired, 732 PeerAddress: peerAddress, 733 }) 734 Expect(err).NotTo(HaveOccurred()) 735 if !expectedError { 736 Eventually(sess, n.EventuallyTimeout).Should(gexec.Exit(0)) 737 Expect(sess).To(gbytes.Say(expectedMsg)) 738 } else { 739 Eventually(sess, n.EventuallyTimeout).Should(gexec.Exit(1)) 740 Expect(sess.Err).To(gbytes.Say(expectedMsg)) 741 } 742 } 743 744 func listPendingSnapshotRequests(n *nwo.Network, channel string, peer *nwo.Peer, peerAddress string, expectedError bool) []byte { 745 sess, err := n.PeerAdminSession(peer, commands.SnapshotListPending{ 746 ChannelID: channel, 747 ClientAuth: n.ClientAuthRequired, 748 PeerAddress: peerAddress, 749 }) 750 Expect(err).NotTo(HaveOccurred()) 751 752 if expectedError { 753 Eventually(sess, n.EventuallyTimeout).Should(gexec.Exit(1)) 754 return sess.Err.Contents() 755 } 756 Eventually(sess, n.EventuallyTimeout).Should(gexec.Exit(0)) 757 return sess.Buffer().Contents() 758 } 759 760 func compareSnapshotMetadata(snapshotDir1, snapshotDir2 string) { 761 for _, snapshotDir := range []string{snapshotDir1, snapshotDir2} { 762 By("verifying snapshot dir exists: " + snapshotDir) 763 Expect(snapshotDir).To(BeADirectory()) 764 } 765 766 // compare metadata files 767 for _, file := range []string{"_snapshot_signable_metadata.json", "_snapshot_additional_metadata.json"} { 768 By("comparing metadata file from snapshots on multiple peers: " + file) 769 fileContent1, err := ioutil.ReadFile(filepath.Join(snapshotDir1, file)) 770 Expect(err).NotTo(HaveOccurred()) 771 fileContent2, err := ioutil.ReadFile(filepath.Join(snapshotDir2, file)) 772 Expect(err).NotTo(HaveOccurred()) 773 Expect(fileContent1).To(Equal(fileContent2)) 774 } 775 } 776 777 // startPeer starts a peer to prepare for join channel test 778 func startPeer(s *setup, orgName, peerName, channelID string, useCouchDB bool) (*nwo.Peer, ifrit.Process) { 779 peer := &nwo.Peer{ 780 Name: peerName, 781 Organization: orgName, 782 Channels: []*nwo.PeerChannel{ 783 {Name: channelID}, 784 }, 785 } 786 s.network.Peers = append(s.network.Peers, peer) 787 s.peers = append(s.peers, peer) 788 789 var couchProc ifrit.Process 790 if useCouchDB { 791 By("starting couch process and configuring it for peer " + peer.ID()) 792 couchProc = configPeerWithCouchDB(s, peer) 793 } 794 795 By("starting the new peer " + peer.ID()) 796 s.startPeer(peer) 797 798 return peer, couchProc 799 } 800 801 func joinBySnapshot(n *nwo.Network, orderer *nwo.Orderer, peer *nwo.Peer, channelID string, snapshotDir string, lastBlockInSnapshot int) { 802 channelHeight := nwo.GetMaxLedgerHeight(n, channelID, n.PeersWithChannel(channelID)...) 803 804 By(fmt.Sprintf("joining a peer via snapshot %s", snapshotDir)) 805 n.JoinChannelBySnapshot(snapshotDir, peer) 806 807 By("calling JoinBySnapshotStatus") 808 checkStatus := func() string { return n.JoinBySnapshotStatus(peer) } 809 Eventually(checkStatus, n.EventuallyTimeout, 10*time.Second).Should(ContainSubstring("No joinbysnapshot operation is in progress")) 810 811 By("waiting for the new peer to have the same ledger height") 812 nwo.WaitUntilEqualLedgerHeight(n, channelID, channelHeight, peer) 813 814 By("verifying blockchain info on peer " + peer.ID()) 815 sess, err := n.PeerUserSession(peer, "Admin", commands.ChannelInfo{ 816 ChannelID: channelID, 817 }) 818 Expect(err).NotTo(HaveOccurred()) 819 Eventually(sess, n.EventuallyTimeout).Should(gexec.Exit(0)) 820 channelInfoStr := strings.TrimPrefix(string(sess.Buffer().Contents()[:]), "Blockchain info:") 821 bcInfo := cb.BlockchainInfo{} 822 err = json.Unmarshal([]byte(channelInfoStr), &bcInfo) 823 Expect(err).NotTo(HaveOccurred()) 824 Expect(bcInfo.Height).To(Equal(uint64(channelHeight))) 825 Expect(bcInfo.BootstrappingSnapshotInfo.LastBlockInSnapshot).To(Equal(uint64(lastBlockInSnapshot))) 826 } 827 828 func verifyQSCC(n *nwo.Network, peer *nwo.Peer, channelID string, lastBlockInSnapshot int, txidBeforeSnapshot string) { 829 peerID := peer.ID() 830 By("verifying qscc GetBlockByNumber returns an error for block number before snapshot on peer " + peerID) 831 resp := callQSCC(n, peer, "qscc", "GetBlockByNumber", 1, channelID, strconv.Itoa(lastBlockInSnapshot)) 832 Expect(resp).To(ContainSubstring(fmt.Sprintf("The ledger is bootstrapped from a snapshot. First available block = [%d]", lastBlockInSnapshot+1))) 833 834 By("verifying qscc GetBlockByNumber succeeds for a block number after snapshot on peer " + peerID) 835 callQSCC(n, peer, "qscc", "GetBlockByNumber", 0, channelID, fmt.Sprintf("%d", lastBlockInSnapshot+1)) 836 837 By("verifying qscc GetBlockByTxID returns an error for a txid before snapshot on peer " + peerID) 838 resp = callQSCC(n, peer, "qscc", "GetBlockByTxID", 1, channelID, txidBeforeSnapshot) 839 Expect(resp).To(ContainSubstring(fmt.Sprintf("Failed to get block for txID %s, error details for the TXID [%s] not available. Ledger bootstrapped from a snapshot. First available block = [%d]", 840 txidBeforeSnapshot, txidBeforeSnapshot, lastBlockInSnapshot+1))) 841 842 By("verifying qscc GetBlockByTxID succeeds for a txid after snapshot on peer " + peerID) 843 _, newTxid := getTxFromLastBlock(n, peer) 844 callQSCC(n, peer, "qscc", "GetBlockByTxID", 0, channelID, newTxid) 845 846 By("verifying qscc GetTransactionByID returns an error for a txid before snapshot on peer " + peerID) 847 resp = callQSCC(n, peer, "qscc", "GetTransactionByID", 1, channelID, txidBeforeSnapshot) 848 Expect(resp).To(ContainSubstring(fmt.Sprintf("Failed to get transaction with id %s, error details for the TXID [%s] not available. Ledger bootstrapped from a snapshot. First available block = [%d]", 849 txidBeforeSnapshot, txidBeforeSnapshot, lastBlockInSnapshot+1))) 850 851 By("verifying qscc GetTransactionByID succeeds for a txid after snapshot on peer " + peerID) 852 callQSCC(n, peer, "qscc", "GetTransactionByID", 0, channelID, newTxid) 853 } 854 855 func installAndApproveChaincode(n *nwo.Network, orderer *nwo.Orderer, peer *nwo.Peer, channelID string, chaincode nwo.Chaincode, orgNames []string) { 856 nwo.InstallChaincode(n, chaincode, peer) 857 checkOrgs := make([]*nwo.Organization, len(orgNames)) 858 for i, orgName := range orgNames { 859 checkOrgs[i] = n.Organization(orgName) 860 } 861 nwo.ApproveChaincodeForMyOrg(n, channelID, orderer, chaincode, n.PeersInOrg(peer.Organization)...) 862 nwo.EnsureChaincodeCommitted(n, channelID, chaincode.Name, chaincode.Version, chaincode.Sequence, checkOrgs, peer) 863 } 864 865 // getTxFromLastBlock gets a transaction id from the latest block that has been 866 // marshaled and stored on the filesystem 867 func getTxFromLastBlock(n *nwo.Network, peer *nwo.Peer) (*cb.Envelope, string) { 868 blockfile := filepath.Join(n.RootDir, "newest_block.pb") 869 fetchNewest := commands.ChannelFetch{ 870 ChannelID: "testchannel", 871 Block: "newest", 872 OutputFile: blockfile, 873 } 874 sess, err := n.PeerAdminSession(peer, fetchNewest) 875 Expect(err).NotTo(HaveOccurred()) 876 Eventually(sess, n.EventuallyTimeout).Should(gexec.Exit(0)) 877 Expect(sess.Err).To(gbytes.Say("Received block: ")) 878 879 block := nwo.UnmarshalBlockFromFile(blockfile) 880 txEnvelope, err := protoutil.UnmarshalEnvelope(block.Data.Data[0]) 881 Expect(err).NotTo(HaveOccurred()) 882 txID, err := protoutil.GetOrComputeTxIDFromEnvelope(block.Data.Data[0]) 883 Expect(err).NotTo(HaveOccurred()) 884 885 return txEnvelope, txID 886 } 887 888 func invokeAndQueryKVExecutorChaincode(n *nwo.Network, orderer *nwo.Orderer, channelID string, chaincode nwo.Chaincode, kvdata []kvexecutor.KVData, peers ...*nwo.Peer) { 889 By("invoking kvexecutor chaincode") 890 writeInputBytes, err := json.Marshal(kvdata) 891 Expect(err).NotTo(HaveOccurred()) 892 writeInputBase64 := base64.StdEncoding.EncodeToString(writeInputBytes) 893 894 peerAddresses := make([]string, 0) 895 for _, peer := range peers { 896 peerAddresses = append(peerAddresses, n.PeerAddress(peer, nwo.ListenPort)) 897 } 898 899 invokeCommand := commands.ChaincodeInvoke{ 900 ChannelID: channelID, 901 Orderer: n.OrdererAddress(orderer, nwo.ListenPort), 902 Name: chaincode.Name, 903 Ctor: fmt.Sprintf(`{"Args":["readWriteKVs","%s","%s"]}`, "", writeInputBase64), 904 PeerAddresses: peerAddresses, 905 WaitForEvent: true, 906 } 907 invokeChaincode(n, peers[0], invokeCommand) 908 909 channelPeers := n.PeersWithChannel(channelID) 910 nwo.WaitUntilEqualLedgerHeight(n, channelID, nwo.GetLedgerHeight(n, peers[0], channelID), channelPeers...) 911 912 By("querying kvexecutor chaincode") 913 expectedMsg, err := json.Marshal(kvdata) 914 Expect(err).NotTo(HaveOccurred()) 915 916 readInputBytes, err := json.Marshal(kvdata) 917 Expect(err).NotTo(HaveOccurred()) 918 readInputBase64 := base64.StdEncoding.EncodeToString(readInputBytes) 919 920 querycommand := commands.ChaincodeQuery{ 921 ChannelID: channelID, 922 Name: chaincode.Name, 923 Ctor: fmt.Sprintf(`{"Args":["readWriteKVs","%s","%s"]}`, readInputBase64, ""), 924 } 925 queryChaincode(n, peers[0], querycommand, string(expectedMsg), true) 926 } 927 928 func invokeChaincode(n *nwo.Network, peer *nwo.Peer, command commands.ChaincodeInvoke) { 929 sess, err := n.PeerUserSession(peer, "User1", command) 930 Expect(err).NotTo(HaveOccurred()) 931 Eventually(sess, n.EventuallyTimeout).Should(gexec.Exit(0)) 932 Expect(sess.Err).To(gbytes.Say("Chaincode invoke successful.")) 933 } 934 935 func queryChaincode(n *nwo.Network, peer *nwo.Peer, command commands.ChaincodeQuery, expectedMessage string, expectSuccess bool) { 936 sess, err := n.PeerUserSession(peer, "User1", command) 937 Expect(err).NotTo(HaveOccurred()) 938 if expectSuccess { 939 Eventually(sess, n.EventuallyTimeout).Should(gexec.Exit(0)) 940 Expect(sess).To(gbytes.Say(expectedMessage)) 941 } else { 942 Eventually(sess, n.EventuallyTimeout).Should(gexec.Exit()) 943 Expect(sess.Err).To(gbytes.Say(expectedMessage)) 944 } 945 } 946 947 func callQSCC(n *nwo.Network, peer *nwo.Peer, scc, operation string, retCode int, args ...string) []byte { 948 args = append([]string{operation}, args...) 949 chaincodeQuery := commands.ChaincodeQuery{ 950 ChannelID: testchannelID, 951 Name: scc, 952 Ctor: toCLIChaincodeArgs(args...), 953 } 954 955 sess, err := n.PeerAdminSession(peer, chaincodeQuery) 956 Expect(err).NotTo(HaveOccurred()) 957 Eventually(sess, n.EventuallyTimeout).Should(gexec.Exit(retCode)) 958 if retCode != 0 { 959 return sess.Err.Contents() 960 } 961 return sess.Out.Contents() 962 } 963 964 func toCLIChaincodeArgs(args ...string) string { 965 type cliArgs struct { 966 Args []string 967 } 968 cArgs := &cliArgs{Args: args} 969 cArgsJSON, err := json.Marshal(cArgs) 970 Expect(err).NotTo(HaveOccurred()) 971 return string(cArgsJSON) 972 } 973 974 // waitForMarblePvtdataReconciliation queries the chaincode until it returns a success exit code, which means the data is available. 975 func waitForMarblePvtdataReconciliation(n *nwo.Network, peer *nwo.Peer, channelID, chaincodeName string, marbleNames []string) { 976 for _, marbleName := range marbleNames { 977 for _, funcName := range []string{"readMarble", "readMarblePrivateDetails"} { 978 query := fmt.Sprintf(`{"Args":["%s","%s"]}`, funcName, marbleName) 979 command := commands.ChaincodeQuery{ 980 ChannelID: channelID, 981 Name: chaincodeName, 982 Ctor: query, 983 } 984 queryData := func() int { 985 sess, err := n.PeerUserSession(peer, "User1", command) 986 Expect(err).NotTo(HaveOccurred()) 987 return sess.Wait(n.EventuallyTimeout).ExitCode() 988 } 989 Eventually(queryData, n.EventuallyTimeout).Should(Equal(0)) 990 } 991 } 992 } 993 994 func assertPvtdataPresencePerCollectionConfig1(n *nwo.Network, chaincodeName, marbleName string, peers ...*nwo.Peer) { 995 if len(peers) == 0 { 996 peers = n.Peers 997 } 998 for _, peer := range peers { 999 switch peer.Organization { 1000 case "Org1": 1001 By("asserting collection data M in org1 peer " + peer.ID() + " for " + marbleName) 1002 marblechaincodeutil.AssertPresentInCollectionM(n, testchannelID, chaincodeName, marbleName, peer) 1003 By("asserting no collection data MPD in org1 peer " + peer.ID() + " for " + marbleName) 1004 marblechaincodeutil.AssertNotPresentInCollectionMPD(n, testchannelID, chaincodeName, marbleName, peer) 1005 1006 case "Org2": 1007 By("asserting collection data M in org2 peer " + peer.ID() + " for " + marbleName) 1008 marblechaincodeutil.AssertPresentInCollectionM(n, testchannelID, chaincodeName, marbleName, peer) 1009 By("asserting collection data MPD in org2 peer " + peer.ID() + " for " + marbleName) 1010 marblechaincodeutil.AssertPresentInCollectionMPD(n, testchannelID, chaincodeName, marbleName, peer) 1011 1012 case "Org3": 1013 By("asserting no collection data M in org3 peer " + peer.ID() + " for " + marbleName) 1014 marblechaincodeutil.AssertNotPresentInCollectionM(n, testchannelID, chaincodeName, marbleName, peer) 1015 By("asserting collection data MPD in org3 peer " + peer.ID() + " for " + marbleName) 1016 marblechaincodeutil.AssertPresentInCollectionMPD(n, testchannelID, chaincodeName, marbleName, peer) 1017 } 1018 } 1019 } 1020 1021 // invokeWithoutPassingOrdererEndPoint does not pass orderer endpoint to a chaincode invoke command. 1022 // As a result, the command will send a cscc query to the peer and cscc will return the orderer endpoint from the channel config. 1023 func invokeWithoutPassingOrdererEndPoint(n *nwo.Network, peer *nwo.Peer, channelID, chaincodeName string, funcAndArgs ...string) { 1024 command := commands.ChaincodeInvoke{ 1025 ChannelID: channelID, 1026 Name: chaincodeName, 1027 Ctor: prepareChaincodeInvokeArgs(funcAndArgs...), 1028 PeerAddresses: []string{ 1029 n.PeerAddress(peer, nwo.ListenPort), 1030 }, 1031 WaitForEvent: true, 1032 } 1033 invokeChaincode(n, peer, command) 1034 nwo.WaitUntilEqualLedgerHeight(n, channelID, nwo.GetLedgerHeight(n, peer, channelID), n.PeersWithChannel(channelID)...) 1035 } 1036 1037 // commitTx commits a transaction for a given transaction envelope 1038 func commitTx(n *nwo.Network, orderer *nwo.Orderer, peer *nwo.Peer, channelID string, tx *cb.Envelope, txid string) error { 1039 By("getting the signer for user1 on peer " + peer.ID()) 1040 signer := n.PeerUserSigner(peer, "User1") 1041 1042 By("creating the deliver client to peer " + peer.ID()) 1043 pcc := n.PeerClientConn(peer) 1044 defer pcc.Close() 1045 ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) 1046 defer cancel() 1047 df, err := pb.NewDeliverClient(pcc).DeliverFiltered(ctx) 1048 Expect(err).NotTo(HaveOccurred()) 1049 defer df.CloseSend() 1050 1051 By("starting filtered delivery on peer " + peer.ID()) 1052 deliverEnvelope, err := protoutil.CreateSignedEnvelope( 1053 cb.HeaderType_DELIVER_SEEK_INFO, 1054 channelID, 1055 signer, 1056 &ab.SeekInfo{ 1057 Behavior: ab.SeekInfo_BLOCK_UNTIL_READY, 1058 Start: &ab.SeekPosition{ 1059 Type: &ab.SeekPosition_Newest{Newest: &ab.SeekNewest{}}, 1060 }, 1061 Stop: &ab.SeekPosition{ 1062 Type: &ab.SeekPosition_Specified{ 1063 Specified: &ab.SeekSpecified{Number: math.MaxUint64}, 1064 }, 1065 }, 1066 }, 1067 0, 1068 0, 1069 ) 1070 Expect(err).NotTo(HaveOccurred()) 1071 err = df.Send(deliverEnvelope) 1072 Expect(err).NotTo(HaveOccurred()) 1073 1074 By("creating orderer client and send transaction to the orderer" + orderer.ID()) 1075 occ := n.OrdererClientConn(orderer) 1076 defer occ.Close() 1077 broadcastClient, err := ab.NewAtomicBroadcastClient(occ).Broadcast(context.Background()) 1078 Expect(err).NotTo(HaveOccurred()) 1079 1080 err = broadcastClient.Send(tx) 1081 Expect(err).NotTo(HaveOccurred()) 1082 1083 By("waiting for deliver event on peer " + peer.ID()) 1084 for { 1085 resp, err := df.Recv() 1086 if err != nil { 1087 return err 1088 } 1089 fb, ok := resp.Type.(*pb.DeliverResponse_FilteredBlock) 1090 if !ok { 1091 return fmt.Errorf("unexpected filtered block, received %T", resp.Type) 1092 } 1093 for _, tx := range fb.FilteredBlock.FilteredTransactions { 1094 if tx.Txid != txid { 1095 continue 1096 } 1097 if tx.TxValidationCode != pb.TxValidationCode_VALID { 1098 return fmt.Errorf("transaction invalidated with status (%s)", tx.TxValidationCode) 1099 } 1100 return nil 1101 } 1102 } 1103 }