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  }