github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/core/committer/txvalidator/v14/txvalidator_test.go (about) 1 /* 2 Copyright hechain. 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/hechain20/hechain/bccsp/sw" 16 "github.com/hechain20/hechain/common/configtx/test" 17 "github.com/hechain20/hechain/common/ledger/testutil" 18 "github.com/hechain20/hechain/common/semaphore" 19 util2 "github.com/hechain20/hechain/common/util" 20 "github.com/hechain20/hechain/core/committer/txvalidator/mocks" 21 "github.com/hechain20/hechain/core/common/sysccprovider" 22 ledger2 "github.com/hechain20/hechain/core/ledger" 23 "github.com/hechain20/hechain/core/ledger/ledgermgmt" 24 "github.com/hechain20/hechain/core/ledger/ledgermgmt/ledgermgmttest" 25 mocktxvalidator "github.com/hechain20/hechain/core/mocks/txvalidator" 26 "github.com/hechain20/hechain/core/mocks/validator" 27 "github.com/hechain20/hechain/internal/pkg/txflags" 28 "github.com/hechain20/hechain/msp" 29 mspmgmt "github.com/hechain20/hechain/msp/mgmt" 30 msptesttools "github.com/hechain20/hechain/msp/mgmt/testtools" 31 "github.com/hechain20/hechain/protoutil" 32 "github.com/hyperledger/fabric-protos-go/common" 33 "github.com/hyperledger/fabric-protos-go/peer" 34 "github.com/stretchr/testify/require" 35 ) 36 37 func testValidationWithNTXes(t *testing.T, ledger ledger2.PeerLedger, gbHash []byte, nBlocks int) { 38 txid := util2.GenerateUUID() 39 simulator, _ := ledger.NewTxSimulator(txid) 40 simulator.SetState("ns1", "key1", []byte("value1")) 41 simulator.SetState("ns1", "key2", []byte("value2")) 42 simulator.SetState("ns1", "key3", []byte("value3")) 43 simulator.Done() 44 45 simRes, _ := simulator.GetTxSimulationResults() 46 pubSimulationResBytes, _ := simRes.GetPubSimulationBytes() 47 _, err := testutil.ConstructBytesProposalResponsePayload("v1", pubSimulationResBytes) 48 if err != nil { 49 t.Fatalf("Could not construct ProposalResponsePayload bytes, err: %s", err) 50 } 51 52 cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore()) 53 require.NoError(t, err) 54 mockVsccValidator := &validator.MockVsccValidator{} 55 mockCapabilities := &mocks.ApplicationCapabilities{} 56 mockCapabilities.On("ForbidDuplicateTXIdInBlock").Return(false) 57 tValidator := &TxValidator{ 58 ChannelID: "", 59 Semaphore: semaphore.New(10), 60 ChannelResources: &mocktxvalidator.Support{LedgerVal: ledger, ACVal: mockCapabilities}, 61 Vscc: mockVsccValidator, 62 CryptoProvider: cryptoProvider, 63 } 64 65 bcInfo, _ := ledger.GetBlockchainInfo() 66 require.Equal(t, &common.BlockchainInfo{ 67 Height: 1, CurrentBlockHash: gbHash, PreviousBlockHash: nil, 68 }, bcInfo) 69 70 sr := [][]byte{} 71 for i := 0; i < nBlocks; i++ { 72 sr = append(sr, pubSimulationResBytes) 73 } 74 block := testutil.ConstructBlock(t, 1, gbHash, sr, true) 75 76 tValidator.Validate(block) 77 78 txsfltr := txflags.ValidationFlags(block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER]) 79 80 for i := 0; i < nBlocks; i++ { 81 require.True(t, txsfltr.IsSetTo(i, peer.TxValidationCode_VALID)) 82 } 83 } 84 85 func TestDetectTXIdDuplicates(t *testing.T) { 86 txids := []string{"", "1", "2", "3", "", "2", ""} 87 txsfltr := txflags.New(len(txids)) 88 markTXIdDuplicates(txids, txsfltr) 89 require.True(t, txsfltr.IsSetTo(0, peer.TxValidationCode_NOT_VALIDATED)) 90 require.True(t, txsfltr.IsSetTo(1, peer.TxValidationCode_NOT_VALIDATED)) 91 require.True(t, txsfltr.IsSetTo(2, peer.TxValidationCode_NOT_VALIDATED)) 92 require.True(t, txsfltr.IsSetTo(3, peer.TxValidationCode_NOT_VALIDATED)) 93 require.True(t, txsfltr.IsSetTo(4, peer.TxValidationCode_NOT_VALIDATED)) 94 require.True(t, txsfltr.IsSetTo(5, peer.TxValidationCode_DUPLICATE_TXID)) 95 require.True(t, txsfltr.IsSetTo(6, peer.TxValidationCode_NOT_VALIDATED)) 96 97 txids = []string{"", "1", "2", "3", "", "21", ""} 98 txsfltr = txflags.New(len(txids)) 99 markTXIdDuplicates(txids, txsfltr) 100 require.True(t, txsfltr.IsSetTo(0, peer.TxValidationCode_NOT_VALIDATED)) 101 require.True(t, txsfltr.IsSetTo(1, peer.TxValidationCode_NOT_VALIDATED)) 102 require.True(t, txsfltr.IsSetTo(2, peer.TxValidationCode_NOT_VALIDATED)) 103 require.True(t, txsfltr.IsSetTo(3, peer.TxValidationCode_NOT_VALIDATED)) 104 require.True(t, txsfltr.IsSetTo(4, peer.TxValidationCode_NOT_VALIDATED)) 105 require.True(t, txsfltr.IsSetTo(5, peer.TxValidationCode_NOT_VALIDATED)) 106 require.True(t, txsfltr.IsSetTo(6, peer.TxValidationCode_NOT_VALIDATED)) 107 } 108 109 func TestBlockValidationDuplicateTXId(t *testing.T) { 110 ledgerMgr, cleanup := constructLedgerMgrWithTestDefaults(t, "txvalidator") 111 defer cleanup() 112 113 gb, _ := test.MakeGenesisBlock("TestLedger") 114 gbHash := protoutil.BlockHeaderHash(gb.Header) 115 ledger, _ := ledgerMgr.CreateLedger("TestLedger", gb) 116 defer ledger.Close() 117 118 txid := util2.GenerateUUID() 119 simulator, _ := ledger.NewTxSimulator(txid) 120 simulator.SetState("ns1", "key1", []byte("value1")) 121 simulator.SetState("ns1", "key2", []byte("value2")) 122 simulator.SetState("ns1", "key3", []byte("value3")) 123 simulator.Done() 124 125 simRes, _ := simulator.GetTxSimulationResults() 126 pubSimulationResBytes, _ := simRes.GetPubSimulationBytes() 127 _, err := testutil.ConstructBytesProposalResponsePayload("v1", pubSimulationResBytes) 128 if err != nil { 129 t.Fatalf("Could not construct ProposalResponsePayload bytes, err: %s", err) 130 } 131 132 cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore()) 133 require.NoError(t, err) 134 mockVsccValidator := &validator.MockVsccValidator{} 135 acv := &mocks.ApplicationCapabilities{} 136 tValidator := &TxValidator{ 137 ChannelID: "", 138 Semaphore: semaphore.New(10), 139 ChannelResources: &mocktxvalidator.Support{LedgerVal: ledger, ACVal: acv}, 140 Vscc: mockVsccValidator, 141 CryptoProvider: cryptoProvider, 142 } 143 144 bcInfo, _ := ledger.GetBlockchainInfo() 145 require.Equal(t, &common.BlockchainInfo{ 146 Height: 1, CurrentBlockHash: gbHash, PreviousBlockHash: nil, 147 }, bcInfo) 148 149 envs := []*common.Envelope{} 150 env, _, err := testutil.ConstructTransaction(t, pubSimulationResBytes, "", true) 151 require.NoError(t, err) 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 := txflags.ValidationFlags(block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER]) 160 161 require.True(t, txsfltr.IsSetTo(0, peer.TxValidationCode_VALID)) 162 require.True(t, txsfltr.IsSetTo(1, peer.TxValidationCode_VALID)) 163 164 acv.On("ForbidDuplicateTXIdInBlock").Return(true) 165 tValidator.Validate(block) 166 167 txsfltr = txflags.ValidationFlags(block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER]) 168 169 require.True(t, txsfltr.IsSetTo(0, peer.TxValidationCode_VALID)) 170 require.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 require.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 require.NoError(t, err) 237 mockSignerSerialized, err := mockSigner.Serialize() 238 require.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 require.NoError(t, err) 260 261 sig, err := mockSigner.Sign(payloadBytes) 262 require.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 require.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 := txflags.NewWithValues(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 := txflags.ValidationFlags(block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER]) 300 require.True(t, txsfltr.IsInvalid(0)) 301 302 // We expect the tx to be invalid because of a bad txid 303 require.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 require.NoError(t, err) 341 cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore()) 342 require.NoError(t, err) 343 signer, err := mspmgmt.GetLocalMSP(cryptoProvider).GetDefaultSigningIdentity() 344 require.NoError(t, err) 345 346 channelID := "testchannelid" 347 upgradeCCName := "mycc" 348 upgradeCCVersion := "v1" 349 350 env, err := createCCUpgradeEnvelope(channelID, upgradeCCName, upgradeCCVersion, signer) 351 require.NoError(t, err) 352 353 // get the payload from the envelope 354 payload, err := protoutil.UnmarshalPayload(env.Payload) 355 require.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 require.EqualValues(t, expectInvokeCCIns, invokeCCIns) 376 require.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 := txflags.New(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 := txflags.New(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 require.NoError(t, err) 418 tValidator := &TxValidator{ 419 CryptoProvider: cryptoProvider, 420 } 421 tValidator.invalidTXsForUpgradeCC(txsChaincodeNames, upgradedChaincodes, txsfltr) 422 423 require.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 }