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  }