github.com/true-sqn/fabric@v2.1.1+incompatible/core/ledger/kvledger/tests/client.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package tests 8 9 import ( 10 "testing" 11 12 "github.com/golang/protobuf/proto" 13 "github.com/hyperledger/fabric-protos-go/common" 14 "github.com/hyperledger/fabric/common/util" 15 "github.com/hyperledger/fabric/core/common/ccprovider" 16 "github.com/hyperledger/fabric/core/common/privdata" 17 "github.com/hyperledger/fabric/core/ledger" 18 "github.com/hyperledger/fabric/protoutil" 19 "github.com/stretchr/testify/assert" 20 ) 21 22 // client helps in a transction simulation. The client keeps accumlating the results of each simulated transaction 23 // in a slice and at a later stage can be used to cut a test block for committing. 24 // In a test, for each instantiated ledger, a single instance of a client is typically sufficient. 25 type client struct { 26 lgr ledger.PeerLedger 27 lgrID string 28 simulatedTrans []*txAndPvtdata // accumulates the results of transactions simulations 29 missingPvtData ledger.TxMissingPvtDataMap 30 assert *assert.Assertions 31 } 32 33 func newClient(lgr ledger.PeerLedger, lgrID string, t *testing.T) *client { 34 return &client{lgr, lgrID, nil, make(ledger.TxMissingPvtDataMap), assert.New(t)} 35 } 36 37 // simulateDataTx takes a simulation logic and wraps it between 38 // (A) the pre-simulation tasks (such as obtaining a fresh simulator) and 39 // (B) the post simulation tasks (such as gathering (public and pvt) simulation results and constructing a transaction) 40 // Since (A) and (B) both are handled in this function, the test code can be kept simple by just supplying the simulation logic 41 func (c *client) simulateDataTx(txid string, simulationLogic func(s *simulator)) *txAndPvtdata { 42 if txid == "" { 43 txid = util.GenerateUUID() 44 } 45 ledgerSimulator, err := c.lgr.NewTxSimulator(txid) 46 c.assert.NoError(err) 47 sim := &simulator{ledgerSimulator, txid, c.assert} 48 simulationLogic(sim) 49 txAndPvtdata := sim.done() 50 c.simulatedTrans = append(c.simulatedTrans, txAndPvtdata) 51 return txAndPvtdata 52 } 53 54 func (c *client) addPostOrderTx(txid string, customTxType common.HeaderType) *txAndPvtdata { 55 if txid == "" { 56 txid = util.GenerateUUID() 57 } 58 channelHeader := protoutil.MakeChannelHeader(customTxType, 0, c.lgrID, 0) 59 channelHeader.TxId = txid 60 paylBytes := protoutil.MarshalOrPanic( 61 &common.Payload{ 62 Header: protoutil.MakePayloadHeader(channelHeader, &common.SignatureHeader{}), 63 Data: nil, 64 }, 65 ) 66 env := &common.Envelope{ 67 Payload: paylBytes, 68 Signature: nil, 69 } 70 txAndPvtdata := &txAndPvtdata{Txid: txid, Envelope: env} 71 c.simulatedTrans = append(c.simulatedTrans, txAndPvtdata) 72 return txAndPvtdata 73 } 74 75 // simulateDeployTx mimics a transction that deploys a chaincode. This in turn calls the function 'simulateDataTx' 76 // with supplying the simulation logic that mimics the inoke funciton of 'lscc' for the ledger tests 77 func (c *client) simulateDeployTx(ccName string, collConfs []*collConf) *txAndPvtdata { 78 ccData := &ccprovider.ChaincodeData{Name: ccName} 79 ccDataBytes, err := proto.Marshal(ccData) 80 c.assert.NoError(err) 81 82 psudoLSCCInvokeFunc := func(s *simulator) { 83 s.setState("lscc", ccName, string(ccDataBytes)) 84 if collConfs != nil { 85 protoBytes, err := convertToCollConfigProtoBytes(collConfs) 86 c.assert.NoError(err) 87 s.setState("lscc", privdata.BuildCollectionKVSKey(ccName), string(protoBytes)) 88 } 89 } 90 return c.simulateDataTx("", psudoLSCCInvokeFunc) 91 } 92 93 // simulateUpgradeTx see comments on function 'simulateDeployTx' 94 func (c *client) simulateUpgradeTx(ccName string, collConfs []*collConf) *txAndPvtdata { 95 return c.simulateDeployTx(ccName, collConfs) 96 } 97 98 func (c *client) causeMissingPvtData(txIndex uint64) { 99 pvtws := c.simulatedTrans[txIndex].Pvtws 100 for _, nsPvtRwset := range pvtws.NsPvtRwset { 101 for _, collPvtRwset := range nsPvtRwset.CollectionPvtRwset { 102 c.missingPvtData.Add(txIndex, nsPvtRwset.Namespace, collPvtRwset.CollectionName, true) 103 } 104 } 105 c.simulatedTrans[txIndex].Pvtws = nil 106 } 107 108 /////////////////////// simulator wrapper functions /////////////////////// 109 type simulator struct { 110 ledger.TxSimulator 111 txid string 112 assert *assert.Assertions 113 } 114 115 func (s *simulator) getState(ns, key string) string { 116 val, err := s.GetState(ns, key) 117 s.assert.NoError(err) 118 return string(val) 119 } 120 121 func (s *simulator) setState(ns, key string, val string) { 122 s.assert.NoError( 123 s.SetState(ns, key, []byte(val)), 124 ) 125 } 126 127 func (s *simulator) setPvtdata(ns, coll, key string, val string) { 128 s.assert.NoError( 129 s.SetPrivateData(ns, coll, key, []byte(val)), 130 ) 131 } 132 133 func (s *simulator) done() *txAndPvtdata { 134 s.Done() 135 simRes, err := s.GetTxSimulationResults() 136 s.assert.NoError(err) 137 pubRwsetBytes, err := simRes.GetPubSimulationBytes() 138 s.assert.NoError(err) 139 envelope, err := constructTransaction(s.txid, pubRwsetBytes) 140 s.assert.NoError(err) 141 txAndPvtdata := &txAndPvtdata{Txid: s.txid, Envelope: envelope, Pvtws: simRes.PvtSimulationResults} 142 return txAndPvtdata 143 }