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  }