github.com/ewagmig/fabric@v2.1.1+incompatible/core/ledger/kvledger/tests/customtx_processor_test.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package tests 8 9 import ( 10 "fmt" 11 "testing" 12 13 "github.com/hyperledger/fabric-protos-go/common" 14 protopeer "github.com/hyperledger/fabric-protos-go/peer" 15 "github.com/hyperledger/fabric/bccsp/sw" 16 "github.com/hyperledger/fabric/core/ledger" 17 "github.com/hyperledger/fabric/core/ledger/ledgermgmt" 18 "github.com/hyperledger/fabric/core/ledger/mock" 19 "github.com/stretchr/testify/assert" 20 ) 21 22 func TestReadWriteCustomTxProcessor(t *testing.T) { 23 fakeTxProcessor := &mock.CustomTxProcessor{} 24 25 cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore()) 26 assert.NoError(t, err) 27 28 env := newEnvWithInitializer( 29 t, 30 &ledgermgmt.Initializer{ 31 CustomTxProcessors: map[common.HeaderType]ledger.CustomTxProcessor{ 32 100: fakeTxProcessor, 33 }, 34 Hasher: cryptoProvider, 35 }, 36 ) 37 defer env.cleanup() 38 env.initLedgerMgmt() 39 40 h := env.newTestHelperCreateLgr("ledger1", t) 41 h.simulateDataTx("tx0", func(s *simulator) { 42 s.setState("ns", "key1", "value1") 43 s.setState("ns", "key2", "value2") 44 s.setState("ns", "key3", "value3") 45 }) 46 h.cutBlockAndCommitLegacy() // commit block-1 to populate initial state 47 48 valueCounter := 0 49 fakeTxProcessor.GenerateSimulationResultsStub = 50 // tx processor reads and modifies key1 51 func(txEnvelop *common.Envelope, s ledger.TxSimulator, initializingLedger bool) error { 52 valKey1, err := s.GetState("ns", "key1") 53 assert.NoError(t, err) 54 assert.Equal(t, []byte("value1"), valKey1) 55 valueCounter++ 56 return s.SetState("ns", "key1", []byte(fmt.Sprintf("value1_%d", valueCounter))) 57 } 58 59 // block-2 with two post order transactions 60 h.addPostOrderTx("tx1", 100) 61 h.addPostOrderTx("tx2", 100) 62 h.cutBlockAndCommitLegacy() 63 64 // Tx1 should be valid and tx2 should be marked as invalid because, tx1 has already modified key1 65 // in the same block 66 h.verifyTxValidationCode("tx1", protopeer.TxValidationCode_VALID) 67 h.verifyTxValidationCode("tx2", protopeer.TxValidationCode_MVCC_READ_CONFLICT) 68 h.verifyPubState("ns", "key1", "value1_1") 69 } 70 71 func TestRangeReadAndWriteCustomTxProcessor(t *testing.T) { 72 fakeTxProcessor1 := &mock.CustomTxProcessor{} 73 fakeTxProcessor2 := &mock.CustomTxProcessor{} 74 fakeTxProcessor3 := &mock.CustomTxProcessor{} 75 76 cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore()) 77 assert.NoError(t, err) 78 79 env := newEnvWithInitializer( 80 t, 81 &ledgermgmt.Initializer{ 82 CustomTxProcessors: map[common.HeaderType]ledger.CustomTxProcessor{ 83 101: fakeTxProcessor1, 84 102: fakeTxProcessor2, 85 103: fakeTxProcessor3, 86 }, 87 Hasher: cryptoProvider, 88 }, 89 ) 90 defer env.cleanup() 91 env.initLedgerMgmt() 92 93 h := env.newTestHelperCreateLgr("ledger1", t) 94 h.simulateDataTx("tx0", func(s *simulator) { 95 s.setState("ns", "key1", "value1") 96 s.setState("ns", "key2", "value2") 97 s.setState("ns", "key3", "value3") 98 }) 99 h.cutBlockAndCommitLegacy() // commit block-1 to populate initial state 100 101 fakeTxProcessor1.GenerateSimulationResultsStub = 102 // tx processor for txtype 101 sets key1 103 func(txEnvelop *common.Envelope, s ledger.TxSimulator, initializingLedger bool) error { 104 return s.SetState("ns", "key1", []byte("value1_new")) 105 } 106 107 fakeTxProcessor2.GenerateSimulationResultsStub = 108 // tx processor for txtype 102 reads a range (that covers key1) and sets key2 109 func(txEnvelop *common.Envelope, s ledger.TxSimulator, initializingLedger bool) error { 110 itr, err := s.GetStateRangeScanIterator("ns", "key1", "key2") 111 assert.NoError(t, err) 112 for { 113 res, err := itr.Next() 114 assert.NoError(t, err) 115 if res == nil { 116 break 117 } 118 } 119 return s.SetState("ns", "key2", []byte("value2_new")) 120 } 121 122 fakeTxProcessor3.GenerateSimulationResultsStub = 123 // tx processor for txtype 103 reads a range (that does not include key1) and sets key2 124 func(txEnvelop *common.Envelope, s ledger.TxSimulator, initializingLedger bool) error { 125 itr, err := s.GetStateRangeScanIterator("ns", "key2", "key3") 126 assert.NoError(t, err) 127 for { 128 res, err := itr.Next() 129 assert.NoError(t, err) 130 if res == nil { 131 break 132 } 133 } 134 return s.SetState("ns", "key3", []byte("value3_new")) 135 } 136 137 // block-2 with three post order transactions 138 h.addPostOrderTx("tx1", 101) 139 h.addPostOrderTx("tx2", 102) 140 h.addPostOrderTx("tx3", 103) 141 h.cutBlockAndCommitLegacy() 142 143 // Tx1 should be valid and tx2 should be marked as invalid because, tx1 has already modified key1 144 // in the same block (and tx2 does a range iteration that includes key1) 145 // However, tx3 should be fine as this performs a range itertaes that does not include key1 146 h.verifyTxValidationCode("tx1", protopeer.TxValidationCode_VALID) 147 h.verifyTxValidationCode("tx2", protopeer.TxValidationCode_PHANTOM_READ_CONFLICT) 148 h.verifyTxValidationCode("tx3", protopeer.TxValidationCode_VALID) 149 h.verifyPubState("ns", "key1", "value1_new") 150 h.verifyPubState("ns", "key2", "value2") 151 h.verifyPubState("ns", "key3", "value3_new") 152 }