github.com/defanghe/fabric@v2.1.1+incompatible/core/ledger/kvledger/txmgmt/txmgr/lockbasedtxmgr/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 lockbasedtxmgr 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/common/ledger/testutil" 15 "github.com/hyperledger/fabric/core/ledger" 16 "github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/privacyenabledstate" 17 "github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/version" 18 "github.com/hyperledger/fabric/core/ledger/mock" 19 "github.com/hyperledger/fabric/core/ledger/util" 20 "github.com/hyperledger/fabric/protoutil" 21 "github.com/stretchr/testify/assert" 22 ) 23 24 func TestStateListener(t *testing.T) { 25 testLedgerid := "testLedger" 26 ml1 := new(mock.StateListener) 27 ml1.InterestedInNamespacesStub = func() []string { return []string{"ns1", "ns2"} } 28 29 ml2 := new(mock.StateListener) 30 ml2.InterestedInNamespacesStub = func() []string { return []string{"ns2", "ns3"} } 31 32 ml3 := new(mock.StateListener) 33 ml3.InterestedInNamespacesStub = func() []string { return []string{"ns4"} } 34 35 testEnv := testEnvsMap[levelDBtestEnvName] 36 testEnv.init(t, testLedgerid, nil) 37 defer testEnv.cleanup() 38 txmgr := testEnv.getTxMgr().(*LockBasedTxMgr) 39 txmgr.stateListeners = []ledger.StateListener{ml1, ml2, ml3} 40 41 // Mimic commit of block 1 with updates in namespaces ns1, ns2, and ns3 42 // This should cause callback to ml1 and ml2 but not to ml3 43 sampleBatch := privacyenabledstate.NewUpdateBatch() 44 sampleBatch.PubUpdates.Put("ns1", "key1_1", []byte("value1_1"), version.NewHeight(1, 1)) 45 sampleBatch.PubUpdates.Put("ns1", "key1_2", []byte("value1_2"), version.NewHeight(1, 2)) 46 sampleBatch.PubUpdates.Put("ns2", "key2_1", []byte("value2_1"), version.NewHeight(1, 3)) 47 sampleBatch.PubUpdates.Put("ns3", "key3_1", []byte("value3_1"), version.NewHeight(1, 4)) 48 dummyBlock := protoutil.NewBlock(1, []byte("dummyHash")) 49 txmgr.current = ¤t{block: dummyBlock, batch: sampleBatch} 50 txmgr.invokeNamespaceListeners() 51 assert.Equal(t, 1, ml1.HandleStateUpdatesCallCount()) 52 assert.Equal(t, 1, ml2.HandleStateUpdatesCallCount()) 53 assert.Equal(t, 0, ml3.HandleStateUpdatesCallCount()) 54 expectedLedgerid, expectedStateUpdate, expectedHt := 55 testLedgerid, 56 ledger.StateUpdates{ 57 "ns1": &ledger.KVStateUpdates{ 58 PublicUpdates: []*kvrwset.KVWrite{ 59 {Key: "key1_1", Value: []byte("value1_1")}, 60 {Key: "key1_2", Value: []byte("value1_2")}, 61 }, 62 }, 63 "ns2": &ledger.KVStateUpdates{ 64 PublicUpdates: []*kvrwset.KVWrite{ 65 {Key: "key2_1", Value: []byte("value2_1")}, 66 }, 67 }, 68 }, 69 uint64(1) 70 checkHandleStateUpdatesCallback(t, ml1, 0, expectedLedgerid, expectedStateUpdate, expectedHt) 71 expectedLedgerid, expectedStateUpdate, expectedHt = 72 testLedgerid, 73 ledger.StateUpdates{ 74 "ns2": &ledger.KVStateUpdates{ 75 PublicUpdates: []*kvrwset.KVWrite{ 76 {Key: "key2_1", Value: []byte("value2_1")}, 77 }, 78 }, 79 "ns3": &ledger.KVStateUpdates{ 80 PublicUpdates: []*kvrwset.KVWrite{ 81 {Key: "key3_1", Value: []byte("value3_1")}, 82 }, 83 }, 84 }, 85 uint64(1) 86 checkHandleStateUpdatesCallback(t, ml2, 0, expectedLedgerid, expectedStateUpdate, expectedHt) 87 txmgr.Commit() 88 assert.Equal(t, 1, ml1.StateCommitDoneCallCount()) 89 assert.Equal(t, 1, ml2.StateCommitDoneCallCount()) 90 assert.Equal(t, 0, ml3.StateCommitDoneCallCount()) 91 92 // Mimic commit of block 2 with updates only in ns4 namespace 93 // This should cause callback only to ml3 94 sampleBatch = privacyenabledstate.NewUpdateBatch() 95 sampleBatch.PubUpdates.Put("ns4", "key4_1", []byte("value4_1"), version.NewHeight(2, 1)) 96 sampleBatch.HashUpdates.Put("ns4", "coll1", []byte("key-hash-1"), []byte("value-hash-1"), version.NewHeight(2, 2)) 97 sampleBatch.HashUpdates.Put("ns4", "coll1", []byte("key-hash-2"), []byte("value-hash-2"), version.NewHeight(2, 2)) 98 sampleBatch.HashUpdates.Put("ns4", "coll2", []byte("key-hash-3"), []byte("value-hash-3"), version.NewHeight(2, 3)) 99 sampleBatch.HashUpdates.Delete("ns4", "coll2", []byte("key-hash-4"), version.NewHeight(2, 4)) 100 101 txmgr.current = ¤t{block: protoutil.NewBlock(2, []byte("anotherDummyHash")), batch: sampleBatch} 102 txmgr.invokeNamespaceListeners() 103 assert.Equal(t, 1, ml1.HandleStateUpdatesCallCount()) 104 assert.Equal(t, 1, ml2.HandleStateUpdatesCallCount()) 105 assert.Equal(t, 1, ml3.HandleStateUpdatesCallCount()) 106 107 expectedLedgerid, expectedStateUpdate, expectedHt = 108 testLedgerid, 109 ledger.StateUpdates{ 110 "ns4": &ledger.KVStateUpdates{ 111 PublicUpdates: []*kvrwset.KVWrite{ 112 {Key: "key4_1", Value: []byte("value4_1")}, 113 }, 114 CollHashUpdates: map[string][]*kvrwset.KVWriteHash{ 115 "coll1": { 116 {KeyHash: []byte("key-hash-1"), ValueHash: []byte("value-hash-1")}, 117 {KeyHash: []byte("key-hash-2"), ValueHash: []byte("value-hash-2")}, 118 }, 119 "coll2": { 120 {KeyHash: []byte("key-hash-3"), ValueHash: []byte("value-hash-3")}, 121 {KeyHash: []byte("key-hash-4"), IsDelete: true}, 122 }, 123 }, 124 }, 125 }, 126 uint64(2) 127 128 checkHandleStateUpdatesCallback(t, ml3, 0, expectedLedgerid, expectedStateUpdate, expectedHt) 129 130 txmgr.Commit() 131 assert.Equal(t, 1, ml1.StateCommitDoneCallCount()) 132 assert.Equal(t, 1, ml2.StateCommitDoneCallCount()) 133 assert.Equal(t, 1, ml3.StateCommitDoneCallCount()) 134 } 135 136 func TestStateListenerQueryExecutor(t *testing.T) { 137 testEnv := testEnvsMap[levelDBtestEnvName] 138 testEnv.init(t, "testLedger", nil) 139 defer testEnv.cleanup() 140 txMgr := testEnv.getTxMgr().(*LockBasedTxMgr) 141 142 namespace := "ns" 143 populateCollConfigForTest(t, txMgr, 144 []collConfigkey{ 145 {"ns", "coll"}, 146 }, 147 version.NewHeight(1, 0), 148 ) 149 150 initialData := []*queryresult.KV{ 151 {Namespace: namespace, Key: "key1", Value: []byte("value1")}, 152 {Namespace: namespace, Key: "key2", Value: []byte("value2")}, 153 {Namespace: namespace, Key: "key3", Value: []byte("value3")}, 154 } 155 156 initialPvtdata := []*testutilPvtdata{ 157 {coll: "coll", key: "key1", value: []byte("value1")}, 158 {coll: "coll", key: "key2", value: []byte("value2")}, 159 } 160 // populate initial data in db 161 testutilPopulateDB(t, txMgr, namespace, initialData, initialPvtdata, version.NewHeight(1, 1)) 162 163 sl := new(mock.StateListener) 164 sl.InterestedInNamespacesStub = func() []string { return []string{"ns"} } 165 txMgr.stateListeners = []ledger.StateListener{sl} 166 167 // Create next block 168 sim, err := txMgr.NewTxSimulator("tx1") 169 assert.NoError(t, err) 170 sim.SetState(namespace, "key1", []byte("value1_new")) 171 sim.DeleteState(namespace, "key2") 172 sim.SetState(namespace, "key4", []byte("value4_new")) 173 sim.SetPrivateData(namespace, "coll", "key1", []byte("value1_new")) // change value for key1 174 sim.DeletePrivateData(namespace, "coll", "key2") // delete key2 175 simRes, err := sim.GetTxSimulationResults() 176 simResBytes, err := simRes.GetPubSimulationBytes() 177 assert.NoError(t, err) 178 block := testutil.ConstructBlock(t, 1, nil, [][]byte{simResBytes}, false) 179 180 // invoke ValidateAndPrepare function 181 _, _, err = txMgr.ValidateAndPrepare(&ledger.BlockAndPvtData{Block: block}, false) 182 assert.NoError(t, err) 183 184 // validate that the query executors passed to the state listener 185 trigger := sl.HandleStateUpdatesArgsForCall(0) 186 assert.NotNil(t, trigger) 187 expectedCommittedData := initialData 188 checkQueryExecutor(t, trigger.CommittedStateQueryExecutor, namespace, expectedCommittedData) 189 expectedCommittedPvtdata := initialPvtdata 190 checkQueryExecutorForPvtdataHashes(t, trigger.CommittedStateQueryExecutor, namespace, expectedCommittedPvtdata) 191 192 expectedPostCommitData := []*queryresult.KV{ 193 {Namespace: namespace, Key: "key1", Value: []byte("value1_new")}, 194 {Namespace: namespace, Key: "key3", Value: []byte("value3")}, 195 {Namespace: namespace, Key: "key4", Value: []byte("value4_new")}, 196 } 197 checkQueryExecutor(t, trigger.PostCommitQueryExecutor, namespace, expectedPostCommitData) 198 expectedPostCommitPvtdata := []*testutilPvtdata{ 199 {coll: "coll", key: "key1", value: []byte("value1_new")}, 200 {coll: "coll", key: "key2", value: nil}, 201 } 202 checkQueryExecutorForPvtdataHashes(t, trigger.PostCommitQueryExecutor, namespace, expectedPostCommitPvtdata) 203 } 204 205 func checkHandleStateUpdatesCallback(t *testing.T, ml *mock.StateListener, callNumber int, 206 expectedLedgerid string, 207 expectedUpdates ledger.StateUpdates, 208 expectedCommitHt uint64) { 209 actualTrigger := ml.HandleStateUpdatesArgsForCall(callNumber) 210 assert.Equal(t, expectedLedgerid, actualTrigger.LedgerID) 211 checkEqualUpdates(t, expectedUpdates, actualTrigger.StateUpdates) 212 assert.Equal(t, expectedCommitHt, actualTrigger.CommittingBlockNum) 213 } 214 215 func checkEqualUpdates(t *testing.T, expected, actual ledger.StateUpdates) { 216 assert.Equal(t, len(expected), len(actual)) 217 for ns, e := range expected { 218 assert.ElementsMatch(t, e.PublicUpdates, actual[ns].PublicUpdates) 219 checkEqualCollsUpdates(t, e.CollHashUpdates, actual[ns].CollHashUpdates) 220 } 221 } 222 223 func checkEqualCollsUpdates(t *testing.T, expected, actual map[string][]*kvrwset.KVWriteHash) { 224 assert.Equal(t, len(expected), len(actual)) 225 for coll, e := range expected { 226 assert.ElementsMatch(t, e, actual[coll]) 227 } 228 } 229 230 func checkQueryExecutor(t *testing.T, qe ledger.SimpleQueryExecutor, namespace string, expectedResults []*queryresult.KV) { 231 for _, kv := range expectedResults { 232 val, err := qe.GetState(namespace, kv.Key) 233 assert.NoError(t, err) 234 assert.Equal(t, kv.Value, val) 235 } 236 237 itr, err := qe.GetStateRangeScanIterator(namespace, "", "") 238 assert.NoError(t, err) 239 defer itr.Close() 240 241 actualRes := []*queryresult.KV{} 242 for { 243 res, err := itr.Next() 244 if err != nil { 245 assert.NoError(t, err) 246 } 247 if res == nil { 248 break 249 } 250 actualRes = append(actualRes, res.(*queryresult.KV)) 251 } 252 assert.Equal(t, expectedResults, actualRes) 253 } 254 255 func checkQueryExecutorForPvtdataHashes(t *testing.T, qe ledger.SimpleQueryExecutor, namespace string, expectedPvtdata []*testutilPvtdata) { 256 for _, p := range expectedPvtdata { 257 valueHash, err := qe.GetPrivateDataHash(namespace, p.coll, p.key) 258 assert.NoError(t, err) 259 if p.value == nil { 260 assert.Nil(t, valueHash) // key does not exist 261 } else { 262 assert.Equal(t, util.ComputeHash(p.value), valueHash) 263 } 264 } 265 }