github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/common/ledger/testutil/test_helper.go (about)

     1  /*
     2  Copyright hechain. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package testutil
     8  
     9  import (
    10  	"fmt"
    11  	"testing"
    12  
    13  	"github.com/golang/protobuf/proto"
    14  	"github.com/hechain20/hechain/bccsp/sw"
    15  	"github.com/hechain20/hechain/common/configtx/test"
    16  	"github.com/hechain20/hechain/common/crypto"
    17  	"github.com/hechain20/hechain/internal/pkg/txflags"
    18  	"github.com/hyperledger/fabric-protos-go/common"
    19  	pb "github.com/hyperledger/fabric-protos-go/peer"
    20  
    21  	"github.com/hechain20/hechain/common/ledger/testutil/fakes"
    22  	"github.com/hechain20/hechain/msp"
    23  	mspmgmt "github.com/hechain20/hechain/msp/mgmt"
    24  	msptesttools "github.com/hechain20/hechain/msp/mgmt/testtools"
    25  	"github.com/hechain20/hechain/protoutil"
    26  	"github.com/stretchr/testify/require"
    27  )
    28  
    29  var signer msp.SigningIdentity
    30  
    31  func init() {
    32  	// setup the MSP manager so that we can sign/verify
    33  	var err error = msptesttools.LoadMSPSetupForTesting()
    34  	if err != nil {
    35  		panic(fmt.Errorf("Could not load msp config, err %s", err))
    36  	}
    37  	cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore())
    38  	if err != nil {
    39  		panic(fmt.Errorf("Initialize cryptoProvider failed: %s", err))
    40  	}
    41  	signer, err = mspmgmt.GetLocalMSP(cryptoProvider).GetDefaultSigningIdentity()
    42  	if err != nil {
    43  		panic(fmt.Errorf("Could not initialize msp/signer"))
    44  	}
    45  }
    46  
    47  // BlockGenerator generates a series of blocks for testing
    48  type BlockGenerator struct {
    49  	blockNum     uint64
    50  	previousHash []byte
    51  	signTxs      bool
    52  	t            *testing.T
    53  }
    54  
    55  type TxDetails struct {
    56  	TxID                            string
    57  	ChaincodeName, ChaincodeVersion string
    58  	SimulationResults               []byte
    59  	ChaincodeEvents                 []byte
    60  	Type                            common.HeaderType
    61  }
    62  
    63  type BlockDetails struct {
    64  	BlockNum     uint64
    65  	PreviousHash []byte
    66  	Txs          []*TxDetails
    67  }
    68  
    69  //go:generate counterfeiter -o fakes/signing_identity.go --fake-name SigningIdentity . signingIdentity
    70  
    71  type signingIdentity interface {
    72  	msp.SigningIdentity
    73  }
    74  
    75  // NewBlockGenerator instantiates new BlockGenerator for testing
    76  func NewBlockGenerator(t *testing.T, ledgerID string, signTxs bool) (*BlockGenerator, *common.Block) {
    77  	gb, err := test.MakeGenesisBlock(ledgerID)
    78  	require.NoError(t, err)
    79  	gb.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER] = txflags.NewWithValues(len(gb.Data.Data), pb.TxValidationCode_VALID)
    80  	return &BlockGenerator{1, protoutil.BlockHeaderHash(gb.GetHeader()), signTxs, t}, gb
    81  }
    82  
    83  // NextBlock constructs next block in sequence that includes a number of transactions - one per simulationResults
    84  func (bg *BlockGenerator) NextBlock(simulationResults [][]byte) *common.Block {
    85  	block := ConstructBlock(bg.t, bg.blockNum, bg.previousHash, simulationResults, bg.signTxs)
    86  	bg.blockNum++
    87  	bg.previousHash = protoutil.BlockHeaderHash(block.Header)
    88  	return block
    89  }
    90  
    91  // NextBlockWithTxid constructs next block in sequence that includes a number of transactions - one per simulationResults
    92  func (bg *BlockGenerator) NextBlockWithTxid(simulationResults [][]byte, txids []string) *common.Block {
    93  	// Length of simulationResults should be same as the length of txids.
    94  	if len(simulationResults) != len(txids) {
    95  		return nil
    96  	}
    97  	block := ConstructBlockWithTxid(bg.t, bg.blockNum, bg.previousHash, simulationResults, txids, bg.signTxs)
    98  	bg.blockNum++
    99  	bg.previousHash = protoutil.BlockHeaderHash(block.Header)
   100  	return block
   101  }
   102  
   103  // NextTestBlock constructs next block in sequence block with 'numTx' number of transactions for testing
   104  func (bg *BlockGenerator) NextTestBlock(numTx int, txSize int) *common.Block {
   105  	simulationResults := [][]byte{}
   106  	for i := 0; i < numTx; i++ {
   107  		simulationResults = append(simulationResults, ConstructRandomBytes(bg.t, txSize))
   108  	}
   109  	return bg.NextBlock(simulationResults)
   110  }
   111  
   112  // NextTestBlocks constructs 'numBlocks' number of blocks for testing
   113  func (bg *BlockGenerator) NextTestBlocks(numBlocks int) []*common.Block {
   114  	blocks := []*common.Block{}
   115  	numTx := 10
   116  	for i := 0; i < numBlocks; i++ {
   117  		block := bg.NextTestBlock(numTx, 100)
   118  		block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER] = txflags.NewWithValues(numTx, pb.TxValidationCode_VALID)
   119  		blocks = append(blocks, block)
   120  	}
   121  	return blocks
   122  }
   123  
   124  // ConstructTransaction constructs a transaction for testing
   125  func ConstructTransaction(
   126  	t *testing.T,
   127  	simulationResults []byte,
   128  	txid string,
   129  	sign bool,
   130  ) (*common.Envelope, string, error) {
   131  	return ConstructTransactionWithHeaderType(
   132  		t,
   133  		simulationResults,
   134  		txid,
   135  		sign,
   136  		common.HeaderType_ENDORSER_TRANSACTION,
   137  	)
   138  }
   139  
   140  // ConstructTransaction constructs a transaction for testing with header type
   141  func ConstructTransactionWithHeaderType(
   142  	t *testing.T,
   143  	simulationResults []byte,
   144  	txid string,
   145  	sign bool,
   146  	headerType common.HeaderType,
   147  ) (*common.Envelope, string, error) {
   148  	return ConstructTransactionFromTxDetails(
   149  		&TxDetails{
   150  			ChaincodeName:     "foo",
   151  			ChaincodeVersion:  "v1",
   152  			TxID:              txid,
   153  			SimulationResults: simulationResults,
   154  			Type:              headerType,
   155  		},
   156  		sign,
   157  	)
   158  }
   159  
   160  func ConstructTransactionFromTxDetails(txDetails *TxDetails, sign bool) (*common.Envelope, string, error) {
   161  	ccid := &pb.ChaincodeID{
   162  		Name:    txDetails.ChaincodeName,
   163  		Version: txDetails.ChaincodeVersion,
   164  	}
   165  	var txEnv *common.Envelope
   166  	var err error
   167  	var txID string
   168  	if sign {
   169  		txEnv, txID, err = ConstructSignedTxEnvWithDefaultSigner(
   170  			"testchannelid",
   171  			ccid,
   172  			nil,
   173  			txDetails.SimulationResults,
   174  			txDetails.TxID,
   175  			txDetails.ChaincodeEvents,
   176  			nil,
   177  			txDetails.Type,
   178  		)
   179  	} else {
   180  		txEnv, txID, err = ConstructUnsignedTxEnv(
   181  			"testchannelid",
   182  			ccid,
   183  			nil,
   184  			txDetails.SimulationResults,
   185  			txDetails.TxID,
   186  			txDetails.ChaincodeEvents,
   187  			nil,
   188  			txDetails.Type,
   189  		)
   190  	}
   191  	return txEnv, txID, err
   192  }
   193  
   194  func ConstructBlockFromBlockDetails(t *testing.T, blockDetails *BlockDetails, sign bool) *common.Block {
   195  	var envs []*common.Envelope
   196  	for _, txDetails := range blockDetails.Txs {
   197  		env, _, err := ConstructTransactionFromTxDetails(txDetails, sign)
   198  		if err != nil {
   199  			t.Fatalf("ConstructTestTransaction failed, err %s", err)
   200  		}
   201  		envs = append(envs, env)
   202  	}
   203  	return NewBlock(envs, blockDetails.BlockNum, blockDetails.PreviousHash)
   204  }
   205  
   206  func ConstructBlockWithTxid(
   207  	t *testing.T,
   208  	blockNum uint64,
   209  	previousHash []byte,
   210  	simulationResults [][]byte,
   211  	txids []string,
   212  	sign bool,
   213  ) *common.Block {
   214  	return ConstructBlockWithTxidHeaderType(
   215  		t,
   216  		blockNum,
   217  		previousHash,
   218  		simulationResults,
   219  		txids,
   220  		sign,
   221  		common.HeaderType_ENDORSER_TRANSACTION,
   222  	)
   223  }
   224  
   225  func ConstructBlockWithTxidHeaderType(
   226  	t *testing.T,
   227  	blockNum uint64,
   228  	previousHash []byte,
   229  	simulationResults [][]byte,
   230  	txids []string,
   231  	sign bool,
   232  	headerType common.HeaderType,
   233  ) *common.Block {
   234  	envs := []*common.Envelope{}
   235  	for i := 0; i < len(simulationResults); i++ {
   236  		env, _, err := ConstructTransactionWithHeaderType(
   237  			t,
   238  			simulationResults[i],
   239  			txids[i],
   240  			sign,
   241  			headerType,
   242  		)
   243  		if err != nil {
   244  			t.Fatalf("ConstructTestTransaction failed, err %s", err)
   245  		}
   246  		envs = append(envs, env)
   247  	}
   248  	return NewBlock(envs, blockNum, previousHash)
   249  }
   250  
   251  // ConstructBlock constructs a single block
   252  func ConstructBlock(
   253  	t *testing.T,
   254  	blockNum uint64,
   255  	previousHash []byte,
   256  	simulationResults [][]byte,
   257  	sign bool,
   258  ) *common.Block {
   259  	envs := []*common.Envelope{}
   260  	for i := 0; i < len(simulationResults); i++ {
   261  		env, _, err := ConstructTransaction(t, simulationResults[i], "", sign)
   262  		if err != nil {
   263  			t.Fatalf("ConstructTestTransaction failed, err %s", err)
   264  		}
   265  		envs = append(envs, env)
   266  	}
   267  	return NewBlock(envs, blockNum, previousHash)
   268  }
   269  
   270  // ConstructTestBlock constructs a single block with random contents
   271  func ConstructTestBlock(t *testing.T, blockNum uint64, numTx int, txSize int) *common.Block {
   272  	simulationResults := [][]byte{}
   273  	for i := 0; i < numTx; i++ {
   274  		simulationResults = append(simulationResults, ConstructRandomBytes(t, txSize))
   275  	}
   276  	return ConstructBlock(t, blockNum, ConstructRandomBytes(t, 32), simulationResults, false)
   277  }
   278  
   279  // ConstructTestBlocks returns a series of blocks starting with blockNum=0.
   280  // The first block in the returned array is a config tx block that represents a genesis block
   281  // Except the genesis block, the size of each of the block would be the same.
   282  func ConstructTestBlocks(t *testing.T, numBlocks int) []*common.Block {
   283  	bg, gb := NewBlockGenerator(t, "testchannelid", false)
   284  	blocks := []*common.Block{}
   285  	if numBlocks != 0 {
   286  		blocks = append(blocks, gb)
   287  	}
   288  	return append(blocks, bg.NextTestBlocks(numBlocks-1)...)
   289  }
   290  
   291  // ConstructBytesProposalResponsePayload constructs a ProposalResponse byte with given chaincode version and simulationResults for testing
   292  func ConstructBytesProposalResponsePayload(version string, simulationResults []byte) ([]byte, error) {
   293  	ccid := &pb.ChaincodeID{
   294  		Name:    "foo",
   295  		Version: version,
   296  	}
   297  	return constructBytesProposalResponsePayload("testchannelid", ccid, nil, simulationResults)
   298  }
   299  
   300  func NewBlock(env []*common.Envelope, blockNum uint64, previousHash []byte) *common.Block {
   301  	block := protoutil.NewBlock(blockNum, previousHash)
   302  	for i := 0; i < len(env); i++ {
   303  		txEnvBytes, _ := proto.Marshal(env[i])
   304  		block.Data.Data = append(block.Data.Data, txEnvBytes)
   305  	}
   306  	block.Header.DataHash = protoutil.BlockDataHash(block.Data)
   307  	protoutil.InitBlockMetadata(block)
   308  
   309  	block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER] = txflags.NewWithValues(len(env), pb.TxValidationCode_VALID)
   310  
   311  	return block
   312  }
   313  
   314  // constructBytesProposalResponsePayload constructs a ProposalResponsePayload byte for tests with a default signer.
   315  func constructBytesProposalResponsePayload(channelID string, ccid *pb.ChaincodeID, pResponse *pb.Response, simulationResults []byte) ([]byte, error) {
   316  	ss, err := signer.Serialize()
   317  	if err != nil {
   318  		return nil, err
   319  	}
   320  
   321  	prop, _, err := protoutil.CreateChaincodeProposal(common.HeaderType_ENDORSER_TRANSACTION, channelID, &pb.ChaincodeInvocationSpec{ChaincodeSpec: &pb.ChaincodeSpec{ChaincodeId: ccid}}, ss)
   322  	if err != nil {
   323  		return nil, err
   324  	}
   325  
   326  	presp, err := protoutil.CreateProposalResponse(prop.Header, prop.Payload, pResponse, simulationResults, nil, ccid, signer)
   327  	if err != nil {
   328  		return nil, err
   329  	}
   330  
   331  	return presp.Payload, nil
   332  }
   333  
   334  // ConstructSignedTxEnvWithDefaultSigner constructs a transaction envelop for tests with a default signer.
   335  // This method helps other modules to construct a transaction with supplied parameters
   336  func ConstructSignedTxEnvWithDefaultSigner(
   337  	chainID string,
   338  	ccid *pb.ChaincodeID,
   339  	response *pb.Response,
   340  	simulationResults []byte,
   341  	txid string,
   342  	events []byte,
   343  	visibility []byte,
   344  	headerType common.HeaderType,
   345  ) (*common.Envelope, string, error) {
   346  	return ConstructSignedTxEnv(
   347  		chainID,
   348  		ccid,
   349  		response,
   350  		simulationResults,
   351  		txid,
   352  		events,
   353  		visibility,
   354  		signer,
   355  		headerType,
   356  	)
   357  }
   358  
   359  // ConstructUnsignedTxEnv creates a Transaction envelope from given inputs
   360  func ConstructUnsignedTxEnv(
   361  	chainID string,
   362  	ccid *pb.ChaincodeID,
   363  	response *pb.Response,
   364  	simulationResults []byte,
   365  	txid string,
   366  	events []byte,
   367  	visibility []byte,
   368  	headerType common.HeaderType,
   369  ) (*common.Envelope, string, error) {
   370  	sigId := &fakes.SigningIdentity{}
   371  
   372  	return ConstructSignedTxEnv(
   373  		chainID,
   374  		ccid,
   375  		response,
   376  		simulationResults,
   377  		txid,
   378  		events,
   379  		visibility,
   380  		sigId,
   381  		headerType,
   382  	)
   383  }
   384  
   385  // ConstructSignedTxEnv constructs a transaction envelop for tests
   386  func ConstructSignedTxEnv(
   387  	channelID string,
   388  	ccid *pb.ChaincodeID,
   389  	pResponse *pb.Response,
   390  	simulationResults []byte,
   391  	txid string,
   392  	events []byte,
   393  	visibility []byte,
   394  	signer msp.SigningIdentity,
   395  	headerType common.HeaderType,
   396  ) (*common.Envelope, string, error) {
   397  	ss, err := signer.Serialize()
   398  	if err != nil {
   399  		return nil, "", err
   400  	}
   401  
   402  	var prop *pb.Proposal
   403  	if txid == "" {
   404  		// if txid is not set, then we need to generate one while creating the proposal message
   405  		prop, txid, err = protoutil.CreateChaincodeProposal(
   406  			common.HeaderType_ENDORSER_TRANSACTION,
   407  			channelID,
   408  			&pb.ChaincodeInvocationSpec{
   409  				ChaincodeSpec: &pb.ChaincodeSpec{
   410  					ChaincodeId: ccid,
   411  				},
   412  			},
   413  			ss,
   414  		)
   415  	} else {
   416  		// if txid is set, we should not generate a txid instead reuse the given txid
   417  		var nonce []byte
   418  		nonce, err = crypto.GetRandomNonce()
   419  		if err != nil {
   420  			return nil, "", err
   421  		}
   422  		prop, txid, err = protoutil.CreateChaincodeProposalWithTxIDNonceAndTransient(
   423  			txid,
   424  			headerType,
   425  			channelID,
   426  			&pb.ChaincodeInvocationSpec{
   427  				ChaincodeSpec: &pb.ChaincodeSpec{
   428  					ChaincodeId: ccid,
   429  				},
   430  			},
   431  			nonce,
   432  			ss,
   433  			nil,
   434  		)
   435  	}
   436  	if err != nil {
   437  		return nil, "", err
   438  	}
   439  
   440  	presp, err := protoutil.CreateProposalResponse(
   441  		prop.Header,
   442  		prop.Payload,
   443  		pResponse,
   444  		simulationResults,
   445  		events,
   446  		ccid,
   447  		signer,
   448  	)
   449  	if err != nil {
   450  		return nil, "", err
   451  	}
   452  
   453  	env, err := protoutil.CreateSignedTx(prop, signer, presp)
   454  	if err != nil {
   455  		return nil, "", err
   456  	}
   457  	return env, txid, nil
   458  }
   459  
   460  func SetTxID(t *testing.T, block *common.Block, txNum int, txID string) {
   461  	envelopeBytes := block.Data.Data[txNum]
   462  	envelope, err := protoutil.UnmarshalEnvelope(envelopeBytes)
   463  	if err != nil {
   464  		t.Fatalf("error unmarshalling envelope: %s", err)
   465  	}
   466  
   467  	payload, err := protoutil.UnmarshalPayload(envelope.Payload)
   468  	if err != nil {
   469  		t.Fatalf("error getting payload from envelope: %s", err)
   470  	}
   471  
   472  	channelHeader, err := protoutil.UnmarshalChannelHeader(payload.Header.ChannelHeader)
   473  	if err != nil {
   474  		t.Fatalf("error unmarshalling channel header: %s", err)
   475  	}
   476  	channelHeader.TxId = txID
   477  	channelHeaderBytes, err := proto.Marshal(channelHeader)
   478  	if err != nil {
   479  		t.Fatalf("error marshaling channel header: %s", err)
   480  	}
   481  	payload.Header.ChannelHeader = channelHeaderBytes
   482  
   483  	payloadBytes, err := proto.Marshal(payload)
   484  	if err != nil {
   485  		t.Fatalf("error marshaling payload: %s", err)
   486  	}
   487  
   488  	envelope.Payload = payloadBytes
   489  	envelopeBytes, err = proto.Marshal(envelope)
   490  	if err != nil {
   491  		t.Fatalf("error marshaling envelope: %s", err)
   492  	}
   493  	block.Data.Data[txNum] = envelopeBytes
   494  }