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