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 }