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 }