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 }