github.com/sykesm/fabric@v1.1.0-preview.0.20200129034918-2aa12b1a0181/core/committer/txvalidator/v14/txvalidator_test.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package txvalidator 8 9 import ( 10 "io/ioutil" 11 "os" 12 "testing" 13 14 "github.com/golang/protobuf/proto" 15 "github.com/hyperledger/fabric-protos-go/common" 16 "github.com/hyperledger/fabric-protos-go/peer" 17 "github.com/hyperledger/fabric/bccsp/sw" 18 "github.com/hyperledger/fabric/common/configtx/test" 19 "github.com/hyperledger/fabric/common/ledger/testutil" 20 "github.com/hyperledger/fabric/common/semaphore" 21 util2 "github.com/hyperledger/fabric/common/util" 22 "github.com/hyperledger/fabric/core/committer/txvalidator/mocks" 23 "github.com/hyperledger/fabric/core/common/sysccprovider" 24 ledger2 "github.com/hyperledger/fabric/core/ledger" 25 "github.com/hyperledger/fabric/core/ledger/ledgermgmt" 26 "github.com/hyperledger/fabric/core/ledger/ledgermgmt/ledgermgmttest" 27 "github.com/hyperledger/fabric/core/ledger/util" 28 ledgerUtil "github.com/hyperledger/fabric/core/ledger/util" 29 mocktxvalidator "github.com/hyperledger/fabric/core/mocks/txvalidator" 30 "github.com/hyperledger/fabric/core/mocks/validator" 31 "github.com/hyperledger/fabric/msp" 32 mspmgmt "github.com/hyperledger/fabric/msp/mgmt" 33 msptesttools "github.com/hyperledger/fabric/msp/mgmt/testtools" 34 "github.com/hyperledger/fabric/protoutil" 35 "github.com/stretchr/testify/assert" 36 ) 37 38 func testValidationWithNTXes(t *testing.T, ledger ledger2.PeerLedger, gbHash []byte, nBlocks int) { 39 txid := util2.GenerateUUID() 40 simulator, _ := ledger.NewTxSimulator(txid) 41 simulator.SetState("ns1", "key1", []byte("value1")) 42 simulator.SetState("ns1", "key2", []byte("value2")) 43 simulator.SetState("ns1", "key3", []byte("value3")) 44 simulator.Done() 45 46 simRes, _ := simulator.GetTxSimulationResults() 47 pubSimulationResBytes, _ := simRes.GetPubSimulationBytes() 48 _, err := testutil.ConstructBytesProposalResponsePayload("v1", pubSimulationResBytes) 49 if err != nil { 50 t.Fatalf("Could not construct ProposalResponsePayload bytes, err: %s", err) 51 } 52 53 cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore()) 54 assert.NoError(t, err) 55 mockVsccValidator := &validator.MockVsccValidator{} 56 mockCapabilities := &mocks.ApplicationCapabilities{} 57 mockCapabilities.On("ForbidDuplicateTXIdInBlock").Return(false) 58 tValidator := &TxValidator{ 59 ChannelID: "", 60 Semaphore: semaphore.New(10), 61 ChannelResources: &mocktxvalidator.Support{LedgerVal: ledger, ACVal: mockCapabilities}, 62 Vscc: mockVsccValidator, 63 CryptoProvider: cryptoProvider, 64 } 65 66 bcInfo, _ := ledger.GetBlockchainInfo() 67 assert.Equal(t, &common.BlockchainInfo{ 68 Height: 1, CurrentBlockHash: gbHash, PreviousBlockHash: nil, 69 }, bcInfo) 70 71 sr := [][]byte{} 72 for i := 0; i < nBlocks; i++ { 73 sr = append(sr, pubSimulationResBytes) 74 } 75 block := testutil.ConstructBlock(t, 1, gbHash, sr, true) 76 77 tValidator.Validate(block) 78 79 txsfltr := util.TxValidationFlags(block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER]) 80 81 for i := 0; i < nBlocks; i++ { 82 assert.True(t, txsfltr.IsSetTo(i, peer.TxValidationCode_VALID)) 83 } 84 } 85 86 func TestDetectTXIdDuplicates(t *testing.T) { 87 txids := []string{"", "1", "2", "3", "", "2", ""} 88 txsfltr := ledgerUtil.NewTxValidationFlags(len(txids)) 89 markTXIdDuplicates(txids, txsfltr) 90 assert.True(t, txsfltr.IsSetTo(0, peer.TxValidationCode_NOT_VALIDATED)) 91 assert.True(t, txsfltr.IsSetTo(1, peer.TxValidationCode_NOT_VALIDATED)) 92 assert.True(t, txsfltr.IsSetTo(2, peer.TxValidationCode_NOT_VALIDATED)) 93 assert.True(t, txsfltr.IsSetTo(3, peer.TxValidationCode_NOT_VALIDATED)) 94 assert.True(t, txsfltr.IsSetTo(4, peer.TxValidationCode_NOT_VALIDATED)) 95 assert.True(t, txsfltr.IsSetTo(5, peer.TxValidationCode_DUPLICATE_TXID)) 96 assert.True(t, txsfltr.IsSetTo(6, peer.TxValidationCode_NOT_VALIDATED)) 97 98 txids = []string{"", "1", "2", "3", "", "21", ""} 99 txsfltr = ledgerUtil.NewTxValidationFlags(len(txids)) 100 markTXIdDuplicates(txids, txsfltr) 101 assert.True(t, txsfltr.IsSetTo(0, peer.TxValidationCode_NOT_VALIDATED)) 102 assert.True(t, txsfltr.IsSetTo(1, peer.TxValidationCode_NOT_VALIDATED)) 103 assert.True(t, txsfltr.IsSetTo(2, peer.TxValidationCode_NOT_VALIDATED)) 104 assert.True(t, txsfltr.IsSetTo(3, peer.TxValidationCode_NOT_VALIDATED)) 105 assert.True(t, txsfltr.IsSetTo(4, peer.TxValidationCode_NOT_VALIDATED)) 106 assert.True(t, txsfltr.IsSetTo(5, peer.TxValidationCode_NOT_VALIDATED)) 107 assert.True(t, txsfltr.IsSetTo(6, peer.TxValidationCode_NOT_VALIDATED)) 108 } 109 110 func TestBlockValidationDuplicateTXId(t *testing.T) { 111 ledgerMgr, cleanup := constructLedgerMgrWithTestDefaults(t, "txvalidator") 112 defer cleanup() 113 114 gb, _ := test.MakeGenesisBlock("TestLedger") 115 gbHash := protoutil.BlockHeaderHash(gb.Header) 116 ledger, _ := ledgerMgr.CreateLedger("TestLedger", gb) 117 defer ledger.Close() 118 119 txid := util2.GenerateUUID() 120 simulator, _ := ledger.NewTxSimulator(txid) 121 simulator.SetState("ns1", "key1", []byte("value1")) 122 simulator.SetState("ns1", "key2", []byte("value2")) 123 simulator.SetState("ns1", "key3", []byte("value3")) 124 simulator.Done() 125 126 simRes, _ := simulator.GetTxSimulationResults() 127 pubSimulationResBytes, _ := simRes.GetPubSimulationBytes() 128 _, err := testutil.ConstructBytesProposalResponsePayload("v1", pubSimulationResBytes) 129 if err != nil { 130 t.Fatalf("Could not construct ProposalResponsePayload bytes, err: %s", err) 131 } 132 133 cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore()) 134 assert.NoError(t, err) 135 mockVsccValidator := &validator.MockVsccValidator{} 136 acv := &mocks.ApplicationCapabilities{} 137 tValidator := &TxValidator{ 138 ChannelID: "", 139 Semaphore: semaphore.New(10), 140 ChannelResources: &mocktxvalidator.Support{LedgerVal: ledger, ACVal: acv}, 141 Vscc: mockVsccValidator, 142 CryptoProvider: cryptoProvider, 143 } 144 145 bcInfo, _ := ledger.GetBlockchainInfo() 146 assert.Equal(t, &common.BlockchainInfo{ 147 Height: 1, CurrentBlockHash: gbHash, PreviousBlockHash: nil, 148 }, bcInfo) 149 150 envs := []*common.Envelope{} 151 env, _, err := testutil.ConstructTransaction(t, pubSimulationResBytes, "", true) 152 envs = append(envs, env) 153 envs = append(envs, env) 154 block := testutil.NewBlock(envs, 1, gbHash) 155 156 acv.On("ForbidDuplicateTXIdInBlock").Return(false).Once() 157 tValidator.Validate(block) 158 159 txsfltr := util.TxValidationFlags(block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER]) 160 161 assert.True(t, txsfltr.IsSetTo(0, peer.TxValidationCode_VALID)) 162 assert.True(t, txsfltr.IsSetTo(1, peer.TxValidationCode_VALID)) 163 164 acv.On("ForbidDuplicateTXIdInBlock").Return(true) 165 tValidator.Validate(block) 166 167 txsfltr = util.TxValidationFlags(block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER]) 168 169 assert.True(t, txsfltr.IsSetTo(0, peer.TxValidationCode_VALID)) 170 assert.True(t, txsfltr.IsSetTo(1, peer.TxValidationCode_DUPLICATE_TXID)) 171 } 172 173 func TestBlockValidation(t *testing.T) { 174 ledgerMgr, cleanup := constructLedgerMgrWithTestDefaults(t, "txvalidator") 175 defer cleanup() 176 177 gb, _ := test.MakeGenesisBlock("TestLedger") 178 gbHash := protoutil.BlockHeaderHash(gb.Header) 179 ledger, _ := ledgerMgr.CreateLedger("TestLedger", gb) 180 defer ledger.Close() 181 182 // here we test validation of a block with a single tx 183 testValidationWithNTXes(t, ledger, gbHash, 1) 184 } 185 186 func TestParallelBlockValidation(t *testing.T) { 187 ledgerMgr, cleanup := constructLedgerMgrWithTestDefaults(t, "txvalidator") 188 defer cleanup() 189 190 gb, _ := test.MakeGenesisBlock("TestLedger") 191 gbHash := protoutil.BlockHeaderHash(gb.Header) 192 ledger, _ := ledgerMgr.CreateLedger("TestLedger", gb) 193 defer ledger.Close() 194 195 // here we test validation of a block with 128 txes 196 testValidationWithNTXes(t, ledger, gbHash, 128) 197 } 198 199 func TestVeryLargeParallelBlockValidation(t *testing.T) { 200 ledgerMgr, cleanup := constructLedgerMgrWithTestDefaults(t, "txvalidator") 201 defer cleanup() 202 203 gb, _ := test.MakeGenesisBlock("TestLedger") 204 gbHash := protoutil.BlockHeaderHash(gb.Header) 205 ledger, _ := ledgerMgr.CreateLedger("TestLedger", gb) 206 defer ledger.Close() 207 208 // here we test validation of a block with 4096 txes, 209 // which is larger than both the number of workers in 210 // the pool and the buffer in the channels 211 testValidationWithNTXes(t, ledger, gbHash, 4096) 212 } 213 214 func TestTxValidationFailure_InvalidTxid(t *testing.T) { 215 ledgerMgr, cleanup := constructLedgerMgrWithTestDefaults(t, "txvalidator") 216 defer cleanup() 217 218 gb, _ := test.MakeGenesisBlock("TestLedger") 219 ledger, _ := ledgerMgr.CreateLedger("TestLedger", gb) 220 221 defer ledger.Close() 222 223 mockCapabilities := &mocks.ApplicationCapabilities{} 224 mockCapabilities.On("ForbidDuplicateTXIdInBlock").Return(false) 225 cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore()) 226 assert.NoError(t, err) 227 tValidator := &TxValidator{ 228 ChannelID: "", 229 Semaphore: semaphore.New(10), 230 ChannelResources: &mocktxvalidator.Support{LedgerVal: ledger, ACVal: mockCapabilities}, 231 Vscc: &validator.MockVsccValidator{}, 232 CryptoProvider: cryptoProvider, 233 } 234 235 mockSigner, err := mspmgmt.GetLocalMSP(cryptoProvider).GetDefaultSigningIdentity() 236 assert.NoError(t, err) 237 mockSignerSerialized, err := mockSigner.Serialize() 238 assert.NoError(t, err) 239 240 // Create simple endorsement transaction 241 payload := &common.Payload{ 242 Header: &common.Header{ 243 ChannelHeader: protoutil.MarshalOrPanic(&common.ChannelHeader{ 244 TxId: "INVALID TXID!!!", 245 Type: int32(common.HeaderType_ENDORSER_TRANSACTION), 246 ChannelId: "testchannelid", 247 }), 248 SignatureHeader: protoutil.MarshalOrPanic(&common.SignatureHeader{ 249 Nonce: []byte("nonce"), 250 Creator: mockSignerSerialized, 251 }), 252 }, 253 Data: []byte("test"), 254 } 255 256 payloadBytes, err := proto.Marshal(payload) 257 258 // Check marshaling didn't fail 259 assert.NoError(t, err) 260 261 sig, err := mockSigner.Sign(payloadBytes) 262 assert.NoError(t, err) 263 264 // Envelope the payload 265 envelope := &common.Envelope{ 266 Payload: payloadBytes, 267 Signature: sig, 268 } 269 270 envelopeBytes, err := proto.Marshal(envelope) 271 272 // Check marshaling didn't fail 273 assert.NoError(t, err) 274 275 block := &common.Block{ 276 Data: &common.BlockData{ 277 // Enconde transactions 278 Data: [][]byte{envelopeBytes}, 279 }, 280 } 281 282 block.Header = &common.BlockHeader{ 283 Number: 0, 284 DataHash: protoutil.BlockDataHash(block.Data), 285 } 286 287 // Initialize metadata 288 protoutil.InitBlockMetadata(block) 289 txsFilter := util.NewTxValidationFlagsSetValue(len(block.Data.Data), peer.TxValidationCode_VALID) 290 block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER] = txsFilter 291 292 // Commit block to the ledger 293 ledger.CommitLegacy(&ledger2.BlockAndPvtData{Block: block}, &ledger2.CommitOptions{}) 294 295 // Validation should invalidate transaction, 296 // because it's already committed 297 tValidator.Validate(block) 298 299 txsfltr := util.TxValidationFlags(block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER]) 300 assert.True(t, txsfltr.IsInvalid(0)) 301 302 // We expect the tx to be invalid because of a bad txid 303 assert.True(t, txsfltr.Flag(0) == peer.TxValidationCode_BAD_PROPOSAL_TXID) 304 } 305 306 func createCCUpgradeEnvelope(channelID, chaincodeName, chaincodeVersion string, signer msp.SigningIdentity) (*common.Envelope, error) { 307 creator, err := signer.Serialize() 308 if err != nil { 309 return nil, err 310 } 311 312 spec := &peer.ChaincodeSpec{ 313 Type: peer.ChaincodeSpec_Type(peer.ChaincodeSpec_Type_value["GOLANG"]), 314 ChaincodeId: &peer.ChaincodeID{ 315 Path: "github.com/codePath", 316 Name: chaincodeName, 317 Version: chaincodeVersion, 318 }, 319 } 320 321 cds := &peer.ChaincodeDeploymentSpec{ChaincodeSpec: spec, CodePackage: []byte{}} 322 prop, _, err := protoutil.CreateUpgradeProposalFromCDS(channelID, cds, creator, []byte{}, []byte{}, []byte{}, nil) 323 if err != nil { 324 return nil, err 325 } 326 327 proposalResponse := &peer.ProposalResponse{ 328 Response: &peer.Response{ 329 Status: 200, // endorsed successfully 330 }, 331 Endorsement: &peer.Endorsement{}, 332 } 333 334 return protoutil.CreateSignedTx(prop, signer, proposalResponse) 335 } 336 337 func TestGetTxCCInstance(t *testing.T) { 338 // setup the MSP manager so that we can sign/verify 339 err := msptesttools.LoadMSPSetupForTesting() 340 assert.NoError(t, err) 341 cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore()) 342 assert.NoError(t, err) 343 signer, err := mspmgmt.GetLocalMSP(cryptoProvider).GetDefaultSigningIdentity() 344 assert.NoError(t, err) 345 346 channelID := "testchannelid" 347 upgradeCCName := "mycc" 348 upgradeCCVersion := "v1" 349 350 env, err := createCCUpgradeEnvelope(channelID, upgradeCCName, upgradeCCVersion, signer) 351 assert.NoError(t, err) 352 353 // get the payload from the envelope 354 payload, err := protoutil.UnmarshalPayload(env.Payload) 355 assert.NoError(t, err) 356 357 expectInvokeCCIns := &sysccprovider.ChaincodeInstance{ 358 ChannelID: channelID, 359 ChaincodeName: "lscc", 360 ChaincodeVersion: "", 361 } 362 expectUpgradeCCIns := &sysccprovider.ChaincodeInstance{ 363 ChannelID: channelID, 364 ChaincodeName: upgradeCCName, 365 ChaincodeVersion: upgradeCCVersion, 366 } 367 368 tValidator := &TxValidator{ 369 CryptoProvider: cryptoProvider, 370 } 371 invokeCCIns, upgradeCCIns, err := tValidator.getTxCCInstance(payload) 372 if err != nil { 373 t.Fatalf("Get chaincode from tx error: %s", err) 374 } 375 assert.EqualValues(t, expectInvokeCCIns, invokeCCIns) 376 assert.EqualValues(t, expectUpgradeCCIns, upgradeCCIns) 377 } 378 379 func TestInvalidTXsForUpgradeCC(t *testing.T) { 380 txsChaincodeNames := map[int]*sysccprovider.ChaincodeInstance{ 381 0: {ChannelID: "chain0", ChaincodeName: "cc0", ChaincodeVersion: "v0"}, // invoke cc0/chain0:v0, should not be affected by upgrade tx in other chain 382 1: {ChannelID: "chain1", ChaincodeName: "cc0", ChaincodeVersion: "v0"}, // invoke cc0/chain1:v0, should be invalided by cc1/chain1 upgrade tx 383 2: {ChannelID: "chain1", ChaincodeName: "lscc", ChaincodeVersion: ""}, // upgrade cc0/chain1 to v1, should be invalided by latter cc0/chain1 upgtade tx 384 3: {ChannelID: "chain1", ChaincodeName: "cc0", ChaincodeVersion: "v0"}, // invoke cc0/chain1:v0, should be invalided by cc1/chain1 upgrade tx 385 4: {ChannelID: "chain1", ChaincodeName: "cc0", ChaincodeVersion: "v1"}, // invoke cc0/chain1:v1, should be invalided by cc1/chain1 upgrade tx 386 5: {ChannelID: "chain1", ChaincodeName: "cc1", ChaincodeVersion: "v0"}, // invoke cc1/chain1:v0, should not be affected by other chaincode upgrade tx 387 6: {ChannelID: "chain1", ChaincodeName: "lscc", ChaincodeVersion: ""}, // upgrade cc0/chain1 to v2, should be invalided by latter cc0/chain1 upgtade tx 388 7: {ChannelID: "chain1", ChaincodeName: "lscc", ChaincodeVersion: ""}, // upgrade cc0/chain1 to v3 389 } 390 upgradedChaincodes := map[int]*sysccprovider.ChaincodeInstance{ 391 2: {ChannelID: "chain1", ChaincodeName: "cc0", ChaincodeVersion: "v1"}, 392 6: {ChannelID: "chain1", ChaincodeName: "cc0", ChaincodeVersion: "v2"}, 393 7: {ChannelID: "chain1", ChaincodeName: "cc0", ChaincodeVersion: "v3"}, 394 } 395 396 txsfltr := ledgerUtil.NewTxValidationFlags(8) 397 txsfltr.SetFlag(0, peer.TxValidationCode_VALID) 398 txsfltr.SetFlag(1, peer.TxValidationCode_VALID) 399 txsfltr.SetFlag(2, peer.TxValidationCode_VALID) 400 txsfltr.SetFlag(3, peer.TxValidationCode_VALID) 401 txsfltr.SetFlag(4, peer.TxValidationCode_VALID) 402 txsfltr.SetFlag(5, peer.TxValidationCode_VALID) 403 txsfltr.SetFlag(6, peer.TxValidationCode_VALID) 404 txsfltr.SetFlag(7, peer.TxValidationCode_VALID) 405 406 expectTxsFltr := ledgerUtil.NewTxValidationFlags(8) 407 expectTxsFltr.SetFlag(0, peer.TxValidationCode_VALID) 408 expectTxsFltr.SetFlag(1, peer.TxValidationCode_CHAINCODE_VERSION_CONFLICT) 409 expectTxsFltr.SetFlag(2, peer.TxValidationCode_CHAINCODE_VERSION_CONFLICT) 410 expectTxsFltr.SetFlag(3, peer.TxValidationCode_CHAINCODE_VERSION_CONFLICT) 411 expectTxsFltr.SetFlag(4, peer.TxValidationCode_CHAINCODE_VERSION_CONFLICT) 412 expectTxsFltr.SetFlag(5, peer.TxValidationCode_VALID) 413 expectTxsFltr.SetFlag(6, peer.TxValidationCode_CHAINCODE_VERSION_CONFLICT) 414 expectTxsFltr.SetFlag(7, peer.TxValidationCode_VALID) 415 416 cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore()) 417 assert.NoError(t, err) 418 tValidator := &TxValidator{ 419 CryptoProvider: cryptoProvider, 420 } 421 tValidator.invalidTXsForUpgradeCC(txsChaincodeNames, upgradedChaincodes, txsfltr) 422 423 assert.EqualValues(t, expectTxsFltr, txsfltr) 424 } 425 426 func constructLedgerMgrWithTestDefaults(t *testing.T, testDir string) (*ledgermgmt.LedgerMgr, func()) { 427 testDir, err := ioutil.TempDir("", testDir) 428 if err != nil { 429 t.Fatalf("Failed to create ledger directory: %s", err) 430 } 431 initializer := ledgermgmttest.NewInitializer(testDir) 432 ledgerMgr := ledgermgmt.NewLedgerMgr(initializer) 433 cleanup := func() { 434 ledgerMgr.Close() 435 os.RemoveAll(testDir) 436 } 437 return ledgerMgr, cleanup 438 }