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 }