github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/core/committer/txvalidator/v20/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  	"testing"
    11  
    12  	"github.com/golang/protobuf/proto"
    13  	"github.com/hechain20/hechain/bccsp/sw"
    14  	"github.com/hechain20/hechain/common/ledger/testutil"
    15  	"github.com/hechain20/hechain/common/semaphore"
    16  	tmocks "github.com/hechain20/hechain/core/committer/txvalidator/mocks"
    17  	"github.com/hechain20/hechain/core/committer/txvalidator/v20/mocks"
    18  	"github.com/hechain20/hechain/core/ledger/kvledger/txmgmt/rwsetutil"
    19  	mocktxvalidator "github.com/hechain20/hechain/core/mocks/txvalidator"
    20  	"github.com/hechain20/hechain/internal/pkg/txflags"
    21  	mspmgmt "github.com/hechain20/hechain/msp/mgmt"
    22  	"github.com/hechain20/hechain/protoutil"
    23  	"github.com/hyperledger/fabric-protos-go/common"
    24  	"github.com/hyperledger/fabric-protos-go/peer"
    25  	"github.com/stretchr/testify/mock"
    26  	"github.com/stretchr/testify/require"
    27  )
    28  
    29  // mockDispatcher is still useful for the parallel test. Auto-generated mocks
    30  // serialize invocations with locks but we don't need that and the test is
    31  // much faster with this mock
    32  type mockDispatcher struct {
    33  	DispatchRv  peer.TxValidationCode
    34  	DispatchErr error
    35  }
    36  
    37  func (v *mockDispatcher) Dispatch(seq int, payload *common.Payload, envBytes []byte, block *common.Block) (peer.TxValidationCode, error) {
    38  	return v.DispatchRv, v.DispatchErr
    39  }
    40  
    41  func testValidationWithNTXes(t *testing.T, nBlocks int) {
    42  	rwsb := rwsetutil.NewRWSetBuilder()
    43  	rwsb.AddToWriteSet("ns1", "key1", []byte("value1"))
    44  	rwsb.AddToWriteSet("ns1", "key2", []byte("value2"))
    45  	rwsb.AddToWriteSet("ns1", "key3", []byte("value3"))
    46  
    47  	simRes, _ := rwsb.GetTxSimulationResults()
    48  	pubSimulationResBytes, _ := simRes.GetPubSimulationBytes()
    49  	_, err := testutil.ConstructBytesProposalResponsePayload("v1", pubSimulationResBytes)
    50  	if err != nil {
    51  		t.Fatalf("Could not construct ProposalResponsePayload bytes, err: %s", err)
    52  	}
    53  
    54  	cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore())
    55  	require.NoError(t, err)
    56  
    57  	mockDispatcher := &mockDispatcher{}
    58  	mockLedger := &mocks.LedgerResources{}
    59  	mockCapabilities := &tmocks.ApplicationCapabilities{}
    60  	mockLedger.On("TxIDExists", mock.Anything).Return(false, nil)
    61  	tValidator := &TxValidator{
    62  		ChannelID:        "",
    63  		Semaphore:        semaphore.New(10),
    64  		ChannelResources: &mocktxvalidator.Support{ACVal: mockCapabilities},
    65  		Dispatcher:       mockDispatcher,
    66  		LedgerResources:  mockLedger,
    67  		CryptoProvider:   cryptoProvider,
    68  	}
    69  
    70  	sr := [][]byte{}
    71  	for i := 0; i < nBlocks; i++ {
    72  		sr = append(sr, pubSimulationResBytes)
    73  	}
    74  	block := testutil.ConstructBlock(t, 1, []byte("we stuck nor breath nor motion"), 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  	rwsb := rwsetutil.NewRWSetBuilder()
   111  	rwsb.AddToWriteSet("ns1", "key1", []byte("value1"))
   112  	rwsb.AddToWriteSet("ns1", "key2", []byte("value2"))
   113  	rwsb.AddToWriteSet("ns1", "key3", []byte("value3"))
   114  
   115  	simRes, _ := rwsb.GetTxSimulationResults()
   116  	pubSimulationResBytes, _ := simRes.GetPubSimulationBytes()
   117  	_, err := testutil.ConstructBytesProposalResponsePayload("v1", pubSimulationResBytes)
   118  	if err != nil {
   119  		t.Fatalf("Could not construct ProposalResponsePayload bytes, err: %s", err)
   120  	}
   121  
   122  	cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore())
   123  	require.NoError(t, err)
   124  
   125  	mockDispatcher := &mockDispatcher{}
   126  	mockCapabilities := &tmocks.ApplicationCapabilities{}
   127  	mockCapabilities.On("ForbidDuplicateTXIdInBlock").Return(true)
   128  	mockLedger := &mocks.LedgerResources{}
   129  	mockLedger.On("TxIDExists", mock.Anything).Return(false, nil)
   130  	tValidator := &TxValidator{
   131  		ChannelID:        "",
   132  		Semaphore:        semaphore.New(10),
   133  		ChannelResources: &mocktxvalidator.Support{ACVal: mockCapabilities},
   134  		Dispatcher:       mockDispatcher,
   135  		LedgerResources:  mockLedger,
   136  		CryptoProvider:   cryptoProvider,
   137  	}
   138  
   139  	envs := []*common.Envelope{}
   140  	env, _, err := testutil.ConstructTransaction(t, pubSimulationResBytes, "", true)
   141  	require.NoError(t, err)
   142  	envs = append(envs, env)
   143  	envs = append(envs, env)
   144  	block := testutil.NewBlock(envs, 1, []byte("Water, water everywhere and all the boards did shrink"))
   145  
   146  	tValidator.Validate(block)
   147  
   148  	txsfltr := txflags.ValidationFlags(block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER])
   149  
   150  	require.True(t, txsfltr.IsSetTo(0, peer.TxValidationCode_VALID))
   151  	require.True(t, txsfltr.IsSetTo(1, peer.TxValidationCode_DUPLICATE_TXID))
   152  }
   153  
   154  func TestBlockValidation(t *testing.T) {
   155  	// here we test validation of a block with a single tx
   156  	testValidationWithNTXes(t, 1)
   157  }
   158  
   159  func TestParallelBlockValidation(t *testing.T) {
   160  	// here we test validation of a block with 128 txes
   161  	testValidationWithNTXes(t, 128)
   162  }
   163  
   164  func TestVeryLargeParallelBlockValidation(t *testing.T) {
   165  	// here we test validation of a block with 4096 txes,
   166  	// which is larger than both the number of workers in
   167  	// the pool and the buffer in the channels
   168  	testValidationWithNTXes(t, 4096)
   169  }
   170  
   171  func TestTxValidationFailure_InvalidTxid(t *testing.T) {
   172  	cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore())
   173  	require.NoError(t, err)
   174  
   175  	mockLedger := &mocks.LedgerResources{}
   176  	mockLedger.On("TxIDExists", mock.Anything).Return(false, nil)
   177  	mockCapabilities := &tmocks.ApplicationCapabilities{}
   178  	tValidator := &TxValidator{
   179  		ChannelID:        "",
   180  		Semaphore:        semaphore.New(10),
   181  		ChannelResources: &mocktxvalidator.Support{ACVal: mockCapabilities},
   182  		Dispatcher:       &mockDispatcher{},
   183  		LedgerResources:  mockLedger,
   184  		CryptoProvider:   cryptoProvider,
   185  	}
   186  
   187  	mockSigner, err := mspmgmt.GetLocalMSP(cryptoProvider).GetDefaultSigningIdentity()
   188  	require.NoError(t, err)
   189  	mockSignerSerialized, err := mockSigner.Serialize()
   190  	require.NoError(t, err)
   191  
   192  	// Create simple endorsement transaction
   193  	payload := &common.Payload{
   194  		Header: &common.Header{
   195  			ChannelHeader: protoutil.MarshalOrPanic(&common.ChannelHeader{
   196  				TxId:      "INVALID TXID!!!",
   197  				Type:      int32(common.HeaderType_ENDORSER_TRANSACTION),
   198  				ChannelId: "testchannelid",
   199  			}),
   200  			SignatureHeader: protoutil.MarshalOrPanic(&common.SignatureHeader{
   201  				Nonce:   []byte("nonce"),
   202  				Creator: mockSignerSerialized,
   203  			}),
   204  		},
   205  		Data: []byte("test"),
   206  	}
   207  
   208  	payloadBytes, err := proto.Marshal(payload)
   209  
   210  	// Check marshaling didn't fail
   211  	require.NoError(t, err)
   212  
   213  	sig, err := mockSigner.Sign(payloadBytes)
   214  	require.NoError(t, err)
   215  
   216  	// Envelope the payload
   217  	envelope := &common.Envelope{
   218  		Payload:   payloadBytes,
   219  		Signature: sig,
   220  	}
   221  
   222  	envelopeBytes, err := proto.Marshal(envelope)
   223  
   224  	// Check marshaling didn't fail
   225  	require.NoError(t, err)
   226  
   227  	block := &common.Block{
   228  		Data: &common.BlockData{
   229  			// Enconde transactions
   230  			Data: [][]byte{envelopeBytes},
   231  		},
   232  	}
   233  
   234  	block.Header = &common.BlockHeader{
   235  		Number:   0,
   236  		DataHash: protoutil.BlockDataHash(block.Data),
   237  	}
   238  
   239  	// Initialize metadata
   240  	protoutil.InitBlockMetadata(block)
   241  	txsFilter := txflags.NewWithValues(len(block.Data.Data), peer.TxValidationCode_VALID)
   242  	block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER] = txsFilter
   243  
   244  	// Validation should invalidate transaction,
   245  	// because it's already committed
   246  	tValidator.Validate(block)
   247  
   248  	txsfltr := txflags.ValidationFlags(block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER])
   249  	require.True(t, txsfltr.IsInvalid(0))
   250  
   251  	// We expect the tx to be invalid because of a bad txid
   252  	require.True(t, txsfltr.Flag(0) == peer.TxValidationCode_BAD_PROPOSAL_TXID)
   253  }