github.com/osdi23p228/fabric@v0.0.0-20221218062954-77808885f5db/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/osdi23p228/fabric/bccsp/sw"
    16  	"github.com/osdi23p228/fabric/common/ledger/testutil"
    17  	"github.com/osdi23p228/fabric/common/semaphore"
    18  	tmocks "github.com/osdi23p228/fabric/core/committer/txvalidator/mocks"
    19  	"github.com/osdi23p228/fabric/core/committer/txvalidator/v20/mocks"
    20  	ledger2 "github.com/osdi23p228/fabric/core/ledger"
    21  	"github.com/osdi23p228/fabric/core/ledger/kvledger/txmgmt/rwsetutil"
    22  	mocktxvalidator "github.com/osdi23p228/fabric/core/mocks/txvalidator"
    23  	"github.com/osdi23p228/fabric/internal/pkg/txflags"
    24  	mspmgmt "github.com/osdi23p228/fabric/msp/mgmt"
    25  	"github.com/osdi23p228/fabric/protoutil"
    26  	"github.com/stretchr/testify/assert"
    27  	"github.com/stretchr/testify/mock"
    28  )
    29  
    30  // mockDispatcher is still useful for the parallel test. Auto-generated mocks
    31  // serialize invocations with locks but we don't need that and the test is
    32  // much faster with this mock
    33  type mockDispatcher struct {
    34  	DispatchRv  peer.TxValidationCode
    35  	DispatchErr error
    36  }
    37  
    38  func (v *mockDispatcher) Dispatch(seq int, payload *common.Payload, envBytes []byte, block *common.Block) (error, peer.TxValidationCode) {
    39  	return v.DispatchErr, v.DispatchRv
    40  }
    41  
    42  func testValidationWithNTXes(t *testing.T, nBlocks int) {
    43  	rwsb := rwsetutil.NewRWSetBuilder()
    44  	rwsb.AddToWriteSet("ns1", "key1", []byte("value1"))
    45  	rwsb.AddToWriteSet("ns1", "key2", []byte("value2"))
    46  	rwsb.AddToWriteSet("ns1", "key3", []byte("value3"))
    47  
    48  	simRes, _ := rwsb.GetTxSimulationResults()
    49  	pubSimulationResBytes, _ := simRes.GetPubSimulationBytes()
    50  	_, err := testutil.ConstructBytesProposalResponsePayload("v1", pubSimulationResBytes)
    51  	if err != nil {
    52  		t.Fatalf("Could not construct ProposalResponsePayload bytes, err: %s", err)
    53  	}
    54  
    55  	cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore())
    56  	assert.NoError(t, err)
    57  
    58  	mockDispatcher := &mockDispatcher{}
    59  	mockLedger := &mocks.LedgerResources{}
    60  	mockCapabilities := &tmocks.ApplicationCapabilities{}
    61  	mockLedger.On("GetTransactionByID", mock.Anything).Return(nil, ledger2.NotFoundInIndexErr("Day after day, day after day"))
    62  	tValidator := &TxValidator{
    63  		ChannelID:        "",
    64  		Semaphore:        semaphore.New(10),
    65  		ChannelResources: &mocktxvalidator.Support{ACVal: mockCapabilities},
    66  		Dispatcher:       mockDispatcher,
    67  		LedgerResources:  mockLedger,
    68  		CryptoProvider:   cryptoProvider,
    69  	}
    70  
    71  	sr := [][]byte{}
    72  	for i := 0; i < nBlocks; i++ {
    73  		sr = append(sr, pubSimulationResBytes)
    74  	}
    75  	block := testutil.ConstructBlock(t, 1, []byte("we stuck nor breath nor motion"), sr, true)
    76  
    77  	tValidator.Validate(block)
    78  
    79  	txsfltr := txflags.ValidationFlags(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 := txflags.New(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 = txflags.New(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  	rwsb := rwsetutil.NewRWSetBuilder()
   112  	rwsb.AddToWriteSet("ns1", "key1", []byte("value1"))
   113  	rwsb.AddToWriteSet("ns1", "key2", []byte("value2"))
   114  	rwsb.AddToWriteSet("ns1", "key3", []byte("value3"))
   115  
   116  	simRes, _ := rwsb.GetTxSimulationResults()
   117  	pubSimulationResBytes, _ := simRes.GetPubSimulationBytes()
   118  	_, err := testutil.ConstructBytesProposalResponsePayload("v1", pubSimulationResBytes)
   119  	if err != nil {
   120  		t.Fatalf("Could not construct ProposalResponsePayload bytes, err: %s", err)
   121  	}
   122  
   123  	cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore())
   124  	assert.NoError(t, err)
   125  
   126  	mockDispatcher := &mockDispatcher{}
   127  	mockCapabilities := &tmocks.ApplicationCapabilities{}
   128  	mockCapabilities.On("ForbidDuplicateTXIdInBlock").Return(true)
   129  	mockLedger := &mocks.LedgerResources{}
   130  	mockLedger.On("GetTransactionByID", mock.Anything).Return(nil, ledger2.NotFoundInIndexErr("As idle as a painted ship upon a painted ocean"))
   131  	tValidator := &TxValidator{
   132  		ChannelID:        "",
   133  		Semaphore:        semaphore.New(10),
   134  		ChannelResources: &mocktxvalidator.Support{ACVal: mockCapabilities},
   135  		Dispatcher:       mockDispatcher,
   136  		LedgerResources:  mockLedger,
   137  		CryptoProvider:   cryptoProvider,
   138  	}
   139  
   140  	envs := []*common.Envelope{}
   141  	env, _, err := testutil.ConstructTransaction(t, pubSimulationResBytes, "", true)
   142  	assert.NoError(t, err)
   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 := txflags.ValidationFlags(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 := txflags.NewWithValues(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 := txflags.ValidationFlags(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  }