github.com/ewagmig/fabric@v2.1.1+incompatible/core/ledger/kvledger/state_listener_test.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package kvledger 8 9 import ( 10 "testing" 11 12 "github.com/hyperledger/fabric-protos-go/ledger/queryresult" 13 "github.com/hyperledger/fabric-protos-go/ledger/rwset/kvrwset" 14 "github.com/hyperledger/fabric/bccsp/sw" 15 "github.com/hyperledger/fabric/common/ledger/testutil" 16 "github.com/hyperledger/fabric/common/metrics/disabled" 17 "github.com/hyperledger/fabric/core/ledger" 18 "github.com/hyperledger/fabric/core/ledger/mock" 19 "github.com/stretchr/testify/assert" 20 ) 21 22 func TestStateListener(t *testing.T) { 23 conf, cleanup := testConfig(t) 24 defer cleanup() 25 26 // create a listener and register it to listen to state change in a namespace 27 channelid := "testLedger" 28 namespace := "testchaincode" 29 mockListener := &mockStateListener{namespace: namespace} 30 31 cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore()) 32 assert.NoError(t, err) 33 provider, err := NewProvider( 34 &ledger.Initializer{ 35 DeployedChaincodeInfoProvider: &mock.DeployedChaincodeInfoProvider{}, 36 StateListeners: []ledger.StateListener{mockListener}, 37 MetricsProvider: &disabled.Provider{}, 38 Config: conf, 39 Hasher: cryptoProvider, 40 }, 41 ) 42 if err != nil { 43 t.Fatalf("Failed to create new Provider: %s", err) 44 } 45 46 bg, gb := testutil.NewBlockGenerator(t, channelid, false) 47 lgr, err := provider.Create(gb) 48 // Simulate tx1 49 sim1, err := lgr.NewTxSimulator("test_tx_1") 50 assert.NoError(t, err) 51 sim1.GetState(namespace, "key1") 52 sim1.SetState(namespace, "key1", []byte("value1")) 53 sim1.SetState(namespace, "key2", []byte("value2")) 54 sim1.Done() 55 56 // Simulate tx2 - this has a conflict with tx1 because it reads "key1" 57 sim2, err := lgr.NewTxSimulator("test_tx_2") 58 assert.NoError(t, err) 59 sim2.GetState(namespace, "key1") 60 sim2.SetState(namespace, "key3", []byte("value3")) 61 sim2.Done() 62 63 // Simulate tx3 - this neighter conflicts with tx1 nor with tx2 64 sim3, err := lgr.NewTxSimulator("test_tx_3") 65 assert.NoError(t, err) 66 sim3.SetState(namespace, "key4", []byte("value4")) 67 sim3.Done() 68 69 // commit tx1 and this should cause mock listener to recieve the state changes made by tx1 70 mockListener.reset() 71 sim1Res, _ := sim1.GetTxSimulationResults() 72 sim1ResBytes, _ := sim1Res.GetPubSimulationBytes() 73 assert.NoError(t, err) 74 blk1 := bg.NextBlock([][]byte{sim1ResBytes}) 75 assert.NoError(t, lgr.CommitLegacy(&ledger.BlockAndPvtData{Block: blk1}, &ledger.CommitOptions{})) 76 assert.Equal(t, channelid, mockListener.channelName) 77 assert.Contains(t, mockListener.kvWrites, &kvrwset.KVWrite{Key: "key1", Value: []byte("value1")}) 78 assert.Contains(t, mockListener.kvWrites, &kvrwset.KVWrite{Key: "key2", Value: []byte("value2")}) 79 // commit tx2 and this should not cause mock listener to recieve the state changes made by tx2 80 // (because, tx2 should be found as invalid) 81 mockListener.reset() 82 sim2Res, _ := sim2.GetTxSimulationResults() 83 sim2ResBytes, _ := sim2Res.GetPubSimulationBytes() 84 assert.NoError(t, err) 85 blk2 := bg.NextBlock([][]byte{sim2ResBytes}) 86 assert.NoError(t, lgr.CommitLegacy(&ledger.BlockAndPvtData{Block: blk2}, &ledger.CommitOptions{})) 87 assert.Equal(t, "", mockListener.channelName) 88 assert.Nil(t, mockListener.kvWrites) 89 90 // commit tx3 and this should cause mock listener to recieve changes made by tx3 91 mockListener.reset() 92 sim3Res, _ := sim3.GetTxSimulationResults() 93 sim3ResBytes, _ := sim3Res.GetPubSimulationBytes() 94 assert.NoError(t, err) 95 blk3 := bg.NextBlock([][]byte{sim3ResBytes}) 96 assert.NoError(t, lgr.CommitLegacy(&ledger.BlockAndPvtData{Block: blk3}, &ledger.CommitOptions{})) 97 assert.Equal(t, channelid, mockListener.channelName) 98 assert.Equal(t, []*kvrwset.KVWrite{ 99 {Key: "key4", Value: []byte("value4")}, 100 }, mockListener.kvWrites) 101 102 provider.Close() 103 104 provider, err = NewProvider( 105 &ledger.Initializer{ 106 DeployedChaincodeInfoProvider: &mock.DeployedChaincodeInfoProvider{}, 107 StateListeners: []ledger.StateListener{mockListener}, 108 MetricsProvider: &disabled.Provider{}, 109 Config: conf, 110 Hasher: cryptoProvider, 111 }, 112 ) 113 if err != nil { 114 t.Fatalf("Failed to create new Provider: %s", err) 115 } 116 defer provider.Close() 117 lgr, err = provider.Open(channelid) 118 assert.NoError(t, err) 119 defer lgr.Close() 120 assert.NoError(t, err) 121 assert.Equal(t, 122 []*queryresult.KV{ 123 { 124 Namespace: namespace, 125 Key: "key1", 126 Value: []byte("value1"), 127 }, 128 { 129 Namespace: namespace, 130 Key: "key2", 131 Value: []byte("value2"), 132 }, 133 { 134 Namespace: namespace, 135 Key: "key4", 136 Value: []byte("value4"), 137 }, 138 }, 139 mockListener.queryResultsInInitializeFunc, 140 ) 141 } 142 143 type mockStateListener struct { 144 channelName string 145 namespace string 146 kvWrites []*kvrwset.KVWrite 147 queryResultsInInitializeFunc []*queryresult.KV 148 } 149 150 func (l *mockStateListener) Initialize(ledgerID string, qe ledger.SimpleQueryExecutor) error { 151 _, err := qe.GetPrivateDataHash(l.namespace, "random-coll", "random-key") 152 if err != nil { 153 return err 154 } 155 l.channelName = ledgerID 156 itr, err := qe.GetStateRangeScanIterator(l.namespace, "", "") 157 if err != nil { 158 return err 159 } 160 for { 161 res, err := itr.Next() 162 if err != nil { 163 return err 164 } 165 if res == nil { 166 break 167 } 168 kv := res.(*queryresult.KV) 169 l.queryResultsInInitializeFunc = append(l.queryResultsInInitializeFunc, 170 kv, 171 ) 172 } 173 return nil 174 } 175 176 func (l *mockStateListener) InterestedInNamespaces() []string { 177 return []string{l.namespace} 178 } 179 180 func (l *mockStateListener) HandleStateUpdates(trigger *ledger.StateUpdateTrigger) error { 181 channelName, stateUpdates := trigger.LedgerID, trigger.StateUpdates 182 l.channelName = channelName 183 l.kvWrites = stateUpdates[l.namespace].PublicUpdates 184 return nil 185 } 186 187 func (l *mockStateListener) StateCommitDone(channelID string) { 188 // NOOP 189 } 190 191 func (l *mockStateListener) reset() { 192 l.channelName = "" 193 l.kvWrites = nil 194 l.queryResultsInInitializeFunc = nil 195 }