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 }