github.com/sykesm/fabric@v1.1.0-preview.0.20200129034918-2aa12b1a0181/common/ledger/testutil/test_helper.go (about)

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