github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/core/ledger/kvledger/tests/client.go (about) 1 /* 2 Copyright hechain. 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/hechain20/hechain/common/util" 14 "github.com/hechain20/hechain/core/common/ccprovider" 15 "github.com/hechain20/hechain/core/common/privdata" 16 "github.com/hechain20/hechain/core/ledger" 17 "github.com/hechain20/hechain/protoutil" 18 "github.com/hyperledger/fabric-protos-go/common" 19 "github.com/stretchr/testify/require" 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.TxMissingPvtData 30 assert *require.Assertions 31 } 32 33 func newClient(lgr ledger.PeerLedger, lgrID string, t *testing.T) *client { 34 return &client{lgr, lgrID, nil, make(ledger.TxMissingPvtData), require.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) submitHandCraftedTx(txAndPvtdata *txAndPvtdata) { 55 c.simulatedTrans = append(c.simulatedTrans, txAndPvtdata) 56 } 57 58 func (c *client) addPostOrderTx(txid string, customTxType common.HeaderType) *txAndPvtdata { 59 if txid == "" { 60 txid = util.GenerateUUID() 61 } 62 channelHeader := protoutil.MakeChannelHeader(customTxType, 0, c.lgrID, 0) 63 channelHeader.TxId = txid 64 paylBytes := protoutil.MarshalOrPanic( 65 &common.Payload{ 66 Header: protoutil.MakePayloadHeader(channelHeader, &common.SignatureHeader{}), 67 Data: nil, 68 }, 69 ) 70 env := &common.Envelope{ 71 Payload: paylBytes, 72 Signature: nil, 73 } 74 txAndPvtdata := &txAndPvtdata{Txid: txid, Envelope: env} 75 c.simulatedTrans = append(c.simulatedTrans, txAndPvtdata) 76 return txAndPvtdata 77 } 78 79 // simulateDeployTx mimics a transction that deploys a chaincode. This in turn calls the function 'simulateDataTx' 80 // with supplying the simulation logic that mimics the invoke function of 'lscc' for the ledger tests 81 func (c *client) simulateDeployTx(ccName string, collConfs []*collConf) *txAndPvtdata { 82 ccData := &ccprovider.ChaincodeData{Name: ccName} 83 ccDataBytes, err := proto.Marshal(ccData) 84 c.assert.NoError(err) 85 86 psudoLSCCInvokeFunc := func(s *simulator) { 87 s.setState("lscc", ccName, string(ccDataBytes)) 88 if collConfs != nil { 89 protoBytes, err := convertToCollConfigProtoBytes(collConfs) 90 c.assert.NoError(err) 91 s.setState("lscc", privdata.BuildCollectionKVSKey(ccName), string(protoBytes)) 92 } 93 } 94 return c.simulateDataTx("", psudoLSCCInvokeFunc) 95 } 96 97 // simulateUpgradeTx see comments on function 'simulateDeployTx' 98 func (c *client) simulateUpgradeTx(ccName string, collConfs []*collConf) *txAndPvtdata { 99 return c.simulateDeployTx(ccName, collConfs) 100 } 101 102 func (c *client) causeMissingPvtData(txIndex uint64) { 103 pvtws := c.simulatedTrans[txIndex].Pvtws 104 for _, nsPvtRwset := range pvtws.NsPvtRwset { 105 for _, collPvtRwset := range nsPvtRwset.CollectionPvtRwset { 106 c.missingPvtData.Add(txIndex, nsPvtRwset.Namespace, collPvtRwset.CollectionName, true) 107 } 108 } 109 c.simulatedTrans[txIndex].Pvtws = nil 110 } 111 112 func (c *client) discardSimulation() { 113 c.simulatedTrans = nil 114 } 115 116 func (c *client) retrieveCommittedBlocksAndPvtdata(startNum, endNum uint64) []*ledger.BlockAndPvtData { 117 data := []*ledger.BlockAndPvtData{} 118 for i := startNum; i <= endNum; i++ { 119 d, err := c.lgr.GetPvtDataAndBlockByNum(i, nil) 120 c.assert.NoError(err) 121 data = append(data, d) 122 } 123 return data 124 } 125 126 func (c *client) currentHeight() uint64 { 127 bcInfo, err := c.lgr.GetBlockchainInfo() 128 c.assert.NoError(err) 129 return bcInfo.Height 130 } 131 132 func (c *client) currentCommitHash() []byte { 133 block, err := c.lgr.GetBlockByNumber(c.currentHeight() - 1) 134 c.assert.NoError(err) 135 if len(block.Metadata.Metadata) < int(common.BlockMetadataIndex_COMMIT_HASH+1) { 136 return nil 137 } 138 commitHash := &common.Metadata{} 139 err = proto.Unmarshal(block.Metadata.Metadata[common.BlockMetadataIndex_COMMIT_HASH], commitHash) 140 c.assert.NoError(err) 141 return commitHash.Value 142 } 143 144 /////////////////////// simulator wrapper functions /////////////////////// 145 type simulator struct { 146 ledger.TxSimulator 147 txid string 148 assert *require.Assertions 149 } 150 151 func (s *simulator) getState(ns, key string) string { 152 val, err := s.GetState(ns, key) 153 s.assert.NoError(err) 154 return string(val) 155 } 156 157 func (s *simulator) setState(ns, key string, val string) { 158 s.assert.NoError( 159 s.SetState(ns, key, []byte(val)), 160 ) 161 } 162 163 func (s *simulator) setPvtdata(ns, coll, key string, val string) { 164 s.assert.NoError( 165 s.SetPrivateData(ns, coll, key, []byte(val)), 166 ) 167 } 168 169 func (s *simulator) done() *txAndPvtdata { 170 s.Done() 171 simRes, err := s.GetTxSimulationResults() 172 s.assert.NoError(err) 173 pubRwsetBytes, err := simRes.GetPubSimulationBytes() 174 s.assert.NoError(err) 175 envelope, err := constructTransaction(s.txid, pubRwsetBytes) 176 s.assert.NoError(err) 177 txAndPvtdata := &txAndPvtdata{Txid: s.txid, Envelope: envelope, Pvtws: simRes.PvtSimulationResults} 178 return txAndPvtdata 179 }