github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/core/ledger/kvledger/txmgmt/validation/validator_test.go (about) 1 /* 2 Copyright hechain. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package validation 8 9 import ( 10 "crypto/sha256" 11 "fmt" 12 "os" 13 "testing" 14 15 "github.com/hechain20/hechain/common/flogging" 16 "github.com/hechain20/hechain/core/ledger/internal/version" 17 "github.com/hechain20/hechain/core/ledger/kvledger/txmgmt/privacyenabledstate" 18 "github.com/hechain20/hechain/core/ledger/kvledger/txmgmt/rwsetutil" 19 "github.com/hechain20/hechain/core/ledger/kvledger/txmgmt/statedb" 20 "github.com/hechain20/hechain/core/ledger/util" 21 "github.com/hyperledger/fabric-protos-go/ledger/rwset/kvrwset" 22 "github.com/hyperledger/fabric-protos-go/peer" 23 "github.com/stretchr/testify/require" 24 ) 25 26 type keyValue struct { 27 namespace string 28 collection string 29 key string 30 keyHash []byte 31 value []byte 32 version *version.Height 33 } 34 35 const ( 36 levelDBtestEnvName = "levelDB_LockBasedTxMgr" 37 couchDBtestEnvName = "couchDB_LockBasedTxMgr" 38 ) 39 40 var ( 41 // Tests will be run against each environment in this array 42 // For example, to skip CouchDB tests, remove &couchDBLockBasedEnv{} 43 testEnvs = map[string]privacyenabledstate.TestEnv{ 44 levelDBtestEnvName: &privacyenabledstate.LevelDBTestEnv{}, 45 couchDBtestEnvName: &privacyenabledstate.CouchDBTestEnv{}, 46 } 47 48 testHashFunc = func(data []byte) ([]byte, error) { 49 h := sha256.New() 50 if _, err := h.Write(data); err != nil { 51 return nil, err 52 } 53 return h.Sum(nil), nil 54 } 55 ) 56 57 func TestMain(m *testing.M) { 58 flogging.ActivateSpec("statevalidator,statebasedval,statecouchdb=debug") 59 exitCode := m.Run() 60 for _, testEnv := range testEnvs { 61 testEnv.StopExternalResource() 62 } 63 os.Exit(exitCode) 64 } 65 66 func TestValidatorBulkLoadingOfCache(t *testing.T) { 67 testDBEnv := testEnvs[couchDBtestEnvName] 68 testDBEnv.Init(t) 69 defer testDBEnv.Cleanup() 70 db := testDBEnv.GetDBHandle("testdb") 71 72 testValidator := &validator{db: db, hashFunc: testHashFunc} 73 74 // populate db with initial data 75 batch := privacyenabledstate.NewUpdateBatch() 76 77 // Create two public KV pairs 78 pubKV1 := keyValue{namespace: "ns1", key: "key1", value: []byte("value1"), version: version.NewHeight(1, 0)} 79 pubKV2 := keyValue{namespace: "ns1", key: "key2", value: []byte("value2"), version: version.NewHeight(1, 1)} 80 81 // Create two hashed KV pairs 82 hashedKV1 := keyValue{ 83 namespace: "ns2", collection: "col1", key: "hashedPvtKey1", 84 keyHash: util.ComputeStringHash("hashedPvtKey1"), value: []byte("value1"), 85 version: version.NewHeight(1, 2), 86 } 87 hashedKV2 := keyValue{ 88 namespace: "ns2", collection: "col2", key: "hashedPvtKey2", 89 keyHash: util.ComputeStringHash("hashedPvtKey2"), value: []byte("value2"), 90 version: version.NewHeight(1, 3), 91 } 92 93 // Store the public and hashed KV pairs to DB 94 batch.PubUpdates.Put(pubKV1.namespace, pubKV1.key, pubKV1.value, pubKV1.version) 95 batch.PubUpdates.Put(pubKV2.namespace, pubKV2.key, pubKV2.value, pubKV2.version) 96 batch.HashUpdates.Put(hashedKV1.namespace, hashedKV1.collection, hashedKV1.keyHash, hashedKV1.value, hashedKV1.version) 97 batch.HashUpdates.Put(hashedKV2.namespace, hashedKV2.collection, hashedKV2.keyHash, hashedKV2.value, hashedKV2.version) 98 99 require.NoError(t, db.ApplyPrivacyAwareUpdates(batch, version.NewHeight(1, 4))) 100 101 // Construct read set for transaction 1. It contains two public KV pairs (pubKV1, pubKV2) and two 102 // hashed KV pairs (hashedKV1, hashedKV2). 103 rwsetBuilder1 := rwsetutil.NewRWSetBuilder() 104 rwsetBuilder1.AddToReadSet(pubKV1.namespace, pubKV1.key, pubKV1.version) 105 rwsetBuilder1.AddToReadSet(pubKV2.namespace, pubKV2.key, pubKV2.version) 106 rwsetBuilder1.AddToHashedReadSet(hashedKV1.namespace, hashedKV1.collection, hashedKV1.key, hashedKV1.version) 107 rwsetBuilder1.AddToHashedReadSet(hashedKV2.namespace, hashedKV2.collection, hashedKV2.key, hashedKV2.version) 108 109 // Construct read set for transaction 1. It contains KV pairs which are not in the state db. 110 rwsetBuilder2 := rwsetutil.NewRWSetBuilder() 111 rwsetBuilder2.AddToReadSet("ns3", "key1", nil) 112 rwsetBuilder2.AddToHashedReadSet("ns3", "col1", "hashedPvtKey1", nil) 113 114 // Construct internal block 115 transRWSets := getTestPubSimulationRWSet(t, rwsetBuilder1, rwsetBuilder2) 116 var trans []*transaction 117 for i, tranRWSet := range transRWSets { 118 tx := &transaction{ 119 id: fmt.Sprintf("txid-%d", i), 120 indexInBlock: i, 121 validationCode: peer.TxValidationCode_VALID, 122 rwset: tranRWSet, 123 } 124 trans = append(trans, tx) 125 } 126 blk := &block{num: 1, txs: trans} 127 128 if testValidator.db.IsBulkOptimizable() { 129 130 db := testValidator.db 131 bulkOptimizable, _ := db.VersionedDB.(statedb.BulkOptimizable) 132 133 // Clear cache loaded during ApplyPrivacyAwareUpdates() 134 testValidator.db.ClearCachedVersions() 135 136 require.NoError(t, testValidator.preLoadCommittedVersionOfRSet(blk)) 137 138 // pubKV1 should be found in cache 139 version, keyFound := bulkOptimizable.GetCachedVersion(pubKV1.namespace, pubKV1.key) 140 require.True(t, keyFound) 141 require.Equal(t, pubKV1.version, version) 142 143 // pubKV2 should be found in cache 144 version, keyFound = bulkOptimizable.GetCachedVersion(pubKV2.namespace, pubKV2.key) 145 require.True(t, keyFound) 146 require.Equal(t, pubKV2.version, version) 147 148 // [ns3, key1] should be found in cache as it was in the readset of transaction 1 though it is 149 // not in the state db but the version would be nil 150 version, keyFound = bulkOptimizable.GetCachedVersion("ns3", "key1") 151 require.True(t, keyFound) 152 require.Nil(t, version) 153 154 // [ns4, key1] should not be found in cache as it was not loaded 155 version, keyFound = bulkOptimizable.GetCachedVersion("ns4", "key1") 156 require.False(t, keyFound) 157 require.Nil(t, version) 158 159 // hashedKV1 should be found in cache 160 version, keyFound = testValidator.db.GetCachedKeyHashVersion(hashedKV1.namespace, 161 hashedKV1.collection, hashedKV1.keyHash) 162 require.True(t, keyFound) 163 require.Equal(t, hashedKV1.version, version) 164 165 // hashedKV2 should be found in cache 166 version, keyFound = testValidator.db.GetCachedKeyHashVersion(hashedKV2.namespace, 167 hashedKV2.collection, hashedKV2.keyHash) 168 require.True(t, keyFound) 169 require.Equal(t, hashedKV2.version, version) 170 171 // [ns3, col1, hashedPvtKey1] should be found in cache as it was in the readset of transaction 2 though it is 172 // not in the state db 173 version, keyFound = testValidator.db.GetCachedKeyHashVersion("ns3", "col1", util.ComputeStringHash("hashedPvtKey1")) 174 require.True(t, keyFound) 175 require.Nil(t, version) 176 177 // [ns4, col, key1] should not be found in cache as it was not loaded 178 version, keyFound = testValidator.db.GetCachedKeyHashVersion("ns4", "col1", util.ComputeStringHash("key1")) 179 require.False(t, keyFound) 180 require.Nil(t, version) 181 182 // Clear cache 183 testValidator.db.ClearCachedVersions() 184 185 // pubKV1 should not be found in cache as cahce got emptied 186 version, keyFound = bulkOptimizable.GetCachedVersion(pubKV1.namespace, pubKV1.key) 187 require.False(t, keyFound) 188 require.Nil(t, version) 189 190 // [ns3, col1, key1] should not be found in cache as cahce got emptied 191 version, keyFound = testValidator.db.GetCachedKeyHashVersion("ns3", "col1", util.ComputeStringHash("hashedPvtKey1")) 192 require.False(t, keyFound) 193 require.Nil(t, version) 194 } 195 } 196 197 func TestValidator(t *testing.T) { 198 testDBEnv := testEnvs[levelDBtestEnvName] 199 testDBEnv.Init(t) 200 defer testDBEnv.Cleanup() 201 db := testDBEnv.GetDBHandle("TestDB") 202 203 // populate db with initial data 204 batch := privacyenabledstate.NewUpdateBatch() 205 batch.PubUpdates.Put("ns1", "key1", []byte("value1"), version.NewHeight(1, 0)) 206 batch.PubUpdates.Put("ns1", "key2", []byte("value2"), version.NewHeight(1, 1)) 207 batch.PubUpdates.Put("ns1", "key3", []byte("value3"), version.NewHeight(1, 2)) 208 batch.PubUpdates.Put("ns1", "key4", []byte("value4"), version.NewHeight(1, 3)) 209 batch.PubUpdates.Put("ns1", "key5", []byte("value5"), version.NewHeight(1, 4)) 210 require.NoError(t, db.ApplyPrivacyAwareUpdates(batch, version.NewHeight(1, 4))) 211 212 testValidator := &validator{db: db, hashFunc: testHashFunc} 213 214 // rwset1 should be valid 215 rwsetBuilder1 := rwsetutil.NewRWSetBuilder() 216 rwsetBuilder1.AddToReadSet("ns1", "key1", version.NewHeight(1, 0)) 217 rwsetBuilder1.AddToReadSet("ns2", "key2", nil) 218 checkValidation(t, testValidator, getTestPubSimulationRWSet(t, rwsetBuilder1), []int{}) 219 220 // rwset2 should not be valid 221 rwsetBuilder2 := rwsetutil.NewRWSetBuilder() 222 rwsetBuilder2.AddToReadSet("ns1", "key1", version.NewHeight(1, 1)) 223 checkValidation(t, testValidator, getTestPubSimulationRWSet(t, rwsetBuilder2), []int{0}) 224 225 // rwset3 should not be valid 226 rwsetBuilder3 := rwsetutil.NewRWSetBuilder() 227 rwsetBuilder3.AddToReadSet("ns1", "key1", nil) 228 checkValidation(t, testValidator, getTestPubSimulationRWSet(t, rwsetBuilder3), []int{0}) 229 230 // rwset4 and rwset5 within same block - rwset4 should be valid and makes rwset5 as invalid 231 rwsetBuilder4 := rwsetutil.NewRWSetBuilder() 232 rwsetBuilder4.AddToReadSet("ns1", "key1", version.NewHeight(1, 0)) 233 rwsetBuilder4.AddToWriteSet("ns1", "key1", []byte("value1_new")) 234 235 rwsetBuilder5 := rwsetutil.NewRWSetBuilder() 236 rwsetBuilder5.AddToReadSet("ns1", "key1", version.NewHeight(1, 0)) 237 checkValidation(t, testValidator, getTestPubSimulationRWSet(t, rwsetBuilder4, rwsetBuilder5), []int{1}) 238 } 239 240 func TestPhantomValidation(t *testing.T) { 241 testDBEnv := testEnvs[levelDBtestEnvName] 242 testDBEnv.Init(t) 243 defer testDBEnv.Cleanup() 244 db := testDBEnv.GetDBHandle("TestDB") 245 246 // populate db with initial data 247 batch := privacyenabledstate.NewUpdateBatch() 248 batch.PubUpdates.Put("ns1", "key1", []byte("value1"), version.NewHeight(1, 0)) 249 batch.PubUpdates.Put("ns1", "key2", []byte("value2"), version.NewHeight(1, 1)) 250 batch.PubUpdates.Put("ns1", "key3", []byte("value3"), version.NewHeight(1, 2)) 251 batch.PubUpdates.Put("ns1", "key4", []byte("value4"), version.NewHeight(1, 3)) 252 batch.PubUpdates.Put("ns1", "key5", []byte("value5"), version.NewHeight(1, 4)) 253 require.NoError(t, db.ApplyPrivacyAwareUpdates(batch, version.NewHeight(1, 4))) 254 255 testValidator := &validator{db: db, hashFunc: testHashFunc} 256 257 // rwset1 should be valid 258 rwsetBuilder1 := rwsetutil.NewRWSetBuilder() 259 rqi1 := &kvrwset.RangeQueryInfo{StartKey: "key2", EndKey: "key4", ItrExhausted: true} 260 rwsetutil.SetRawReads(rqi1, []*kvrwset.KVRead{ 261 rwsetutil.NewKVRead("key2", version.NewHeight(1, 1)), 262 rwsetutil.NewKVRead("key3", version.NewHeight(1, 2)), 263 }) 264 rwsetBuilder1.AddToRangeQuerySet("ns1", rqi1) 265 checkValidation(t, testValidator, getTestPubSimulationRWSet(t, rwsetBuilder1), []int{}) 266 267 // rwset2 should not be valid - Version of key4 changed 268 rwsetBuilder2 := rwsetutil.NewRWSetBuilder() 269 rqi2 := &kvrwset.RangeQueryInfo{StartKey: "key2", EndKey: "key4", ItrExhausted: false} 270 rwsetutil.SetRawReads(rqi2, []*kvrwset.KVRead{ 271 rwsetutil.NewKVRead("key2", version.NewHeight(1, 1)), 272 rwsetutil.NewKVRead("key3", version.NewHeight(1, 2)), 273 rwsetutil.NewKVRead("key4", version.NewHeight(1, 2)), 274 }) 275 rwsetBuilder2.AddToRangeQuerySet("ns1", rqi2) 276 checkValidation(t, testValidator, getTestPubSimulationRWSet(t, rwsetBuilder2), []int{0}) 277 278 // rwset3 should not be valid - simulate key3 got committed to db 279 rwsetBuilder3 := rwsetutil.NewRWSetBuilder() 280 rqi3 := &kvrwset.RangeQueryInfo{StartKey: "key2", EndKey: "key4", ItrExhausted: false} 281 rwsetutil.SetRawReads(rqi3, []*kvrwset.KVRead{ 282 rwsetutil.NewKVRead("key2", version.NewHeight(1, 1)), 283 rwsetutil.NewKVRead("key4", version.NewHeight(1, 3)), 284 }) 285 rwsetBuilder3.AddToRangeQuerySet("ns1", rqi3) 286 checkValidation(t, testValidator, getTestPubSimulationRWSet(t, rwsetBuilder3), []int{0}) 287 288 // //Remove a key in rwset4 and rwset5 should become invalid 289 rwsetBuilder4 := rwsetutil.NewRWSetBuilder() 290 rwsetBuilder4.AddToWriteSet("ns1", "key3", nil) 291 rwsetBuilder5 := rwsetutil.NewRWSetBuilder() 292 rqi5 := &kvrwset.RangeQueryInfo{StartKey: "key2", EndKey: "key4", ItrExhausted: false} 293 rwsetutil.SetRawReads(rqi5, []*kvrwset.KVRead{ 294 rwsetutil.NewKVRead("key2", version.NewHeight(1, 1)), 295 rwsetutil.NewKVRead("key3", version.NewHeight(1, 2)), 296 rwsetutil.NewKVRead("key4", version.NewHeight(1, 3)), 297 }) 298 rwsetBuilder5.AddToRangeQuerySet("ns1", rqi5) 299 checkValidation(t, testValidator, getTestPubSimulationRWSet(t, rwsetBuilder4, rwsetBuilder5), []int{1}) 300 301 // Add a key in rwset6 and rwset7 should become invalid 302 rwsetBuilder6 := rwsetutil.NewRWSetBuilder() 303 rwsetBuilder6.AddToWriteSet("ns1", "key2_1", []byte("value2_1")) 304 305 rwsetBuilder7 := rwsetutil.NewRWSetBuilder() 306 rqi7 := &kvrwset.RangeQueryInfo{StartKey: "key2", EndKey: "key4", ItrExhausted: false} 307 rwsetutil.SetRawReads(rqi7, []*kvrwset.KVRead{ 308 rwsetutil.NewKVRead("key2", version.NewHeight(1, 1)), 309 rwsetutil.NewKVRead("key3", version.NewHeight(1, 2)), 310 rwsetutil.NewKVRead("key4", version.NewHeight(1, 3)), 311 }) 312 rwsetBuilder7.AddToRangeQuerySet("ns1", rqi7) 313 checkValidation(t, testValidator, getTestPubSimulationRWSet(t, rwsetBuilder6, rwsetBuilder7), []int{1}) 314 } 315 316 func TestPhantomHashBasedValidation(t *testing.T) { 317 testDBEnv := testEnvs[levelDBtestEnvName] 318 testDBEnv.Init(t) 319 defer testDBEnv.Cleanup() 320 db := testDBEnv.GetDBHandle("TestDB") 321 322 // populate db with initial data 323 batch := privacyenabledstate.NewUpdateBatch() 324 batch.PubUpdates.Put("ns1", "key1", []byte("value1"), version.NewHeight(1, 0)) 325 batch.PubUpdates.Put("ns1", "key2", []byte("value2"), version.NewHeight(1, 1)) 326 batch.PubUpdates.Put("ns1", "key3", []byte("value3"), version.NewHeight(1, 2)) 327 batch.PubUpdates.Put("ns1", "key4", []byte("value4"), version.NewHeight(1, 3)) 328 batch.PubUpdates.Put("ns1", "key5", []byte("value5"), version.NewHeight(1, 4)) 329 batch.PubUpdates.Put("ns1", "key6", []byte("value6"), version.NewHeight(1, 5)) 330 batch.PubUpdates.Put("ns1", "key7", []byte("value7"), version.NewHeight(1, 6)) 331 batch.PubUpdates.Put("ns1", "key8", []byte("value8"), version.NewHeight(1, 7)) 332 batch.PubUpdates.Put("ns1", "key9", []byte("value9"), version.NewHeight(1, 8)) 333 require.NoError(t, db.ApplyPrivacyAwareUpdates(batch, version.NewHeight(1, 8))) 334 335 testValidator := &validator{db: db, hashFunc: testHashFunc} 336 337 rwsetBuilder1 := rwsetutil.NewRWSetBuilder() 338 rqi1 := &kvrwset.RangeQueryInfo{StartKey: "key2", EndKey: "key9", ItrExhausted: true} 339 kvReadsDuringSimulation1 := []*kvrwset.KVRead{ 340 rwsetutil.NewKVRead("key2", version.NewHeight(1, 1)), 341 rwsetutil.NewKVRead("key3", version.NewHeight(1, 2)), 342 rwsetutil.NewKVRead("key4", version.NewHeight(1, 3)), 343 rwsetutil.NewKVRead("key5", version.NewHeight(1, 4)), 344 rwsetutil.NewKVRead("key6", version.NewHeight(1, 5)), 345 rwsetutil.NewKVRead("key7", version.NewHeight(1, 6)), 346 rwsetutil.NewKVRead("key8", version.NewHeight(1, 7)), 347 } 348 rwsetutil.SetMerkelSummary(rqi1, buildTestHashResults(t, 2, kvReadsDuringSimulation1)) 349 rwsetBuilder1.AddToRangeQuerySet("ns1", rqi1) 350 checkValidation(t, testValidator, getTestPubSimulationRWSet(t, rwsetBuilder1), []int{}) 351 352 rwsetBuilder2 := rwsetutil.NewRWSetBuilder() 353 rqi2 := &kvrwset.RangeQueryInfo{StartKey: "key1", EndKey: "key9", ItrExhausted: false} 354 kvReadsDuringSimulation2 := []*kvrwset.KVRead{ 355 rwsetutil.NewKVRead("key1", version.NewHeight(1, 0)), 356 rwsetutil.NewKVRead("key2", version.NewHeight(1, 1)), 357 rwsetutil.NewKVRead("key3", version.NewHeight(1, 1)), 358 rwsetutil.NewKVRead("key4", version.NewHeight(1, 3)), 359 rwsetutil.NewKVRead("key5", version.NewHeight(1, 4)), 360 rwsetutil.NewKVRead("key6", version.NewHeight(1, 5)), 361 rwsetutil.NewKVRead("key7", version.NewHeight(1, 6)), 362 rwsetutil.NewKVRead("key8", version.NewHeight(1, 7)), 363 rwsetutil.NewKVRead("key9", version.NewHeight(1, 8)), 364 } 365 rwsetutil.SetMerkelSummary(rqi2, buildTestHashResults(t, 2, kvReadsDuringSimulation2)) 366 rwsetBuilder2.AddToRangeQuerySet("ns1", rqi2) 367 checkValidation(t, testValidator, getTestPubSimulationRWSet(t, rwsetBuilder2), []int{0}) 368 } 369 370 func checkValidation(t *testing.T, val *validator, transRWSets []*rwsetutil.TxRwSet, expectedInvalidTxIndexes []int) { 371 var trans []*transaction 372 for i, tranRWSet := range transRWSets { 373 tx := &transaction{ 374 id: fmt.Sprintf("txid-%d", i), 375 indexInBlock: i, 376 validationCode: peer.TxValidationCode_VALID, 377 rwset: tranRWSet, 378 } 379 trans = append(trans, tx) 380 } 381 blk := &block{num: 1, txs: trans} 382 _, err := val.validateAndPrepareBatch(blk, true) 383 require.NoError(t, err) 384 t.Logf("block.Txs[0].ValidationCode = %d", blk.txs[0].validationCode) 385 var invalidTxs []int 386 for _, tx := range blk.txs { 387 if tx.validationCode != peer.TxValidationCode_VALID { 388 invalidTxs = append(invalidTxs, tx.indexInBlock) 389 } 390 } 391 require.Equal(t, len(expectedInvalidTxIndexes), len(invalidTxs)) 392 require.ElementsMatch(t, invalidTxs, expectedInvalidTxIndexes) 393 } 394 395 func buildTestHashResults(t *testing.T, maxDegree int, kvReads []*kvrwset.KVRead) *kvrwset.QueryReadsMerkleSummary { 396 if len(kvReads) <= maxDegree { 397 t.Fatal("This method should be called with number of KVReads more than maxDegree; Else, hashing won't be performedrwset") 398 } 399 helper, _ := rwsetutil.NewRangeQueryResultsHelper(true, uint32(maxDegree), testHashFunc) 400 for _, kvRead := range kvReads { 401 require.NoError(t, helper.AddResult(kvRead)) 402 } 403 _, h, err := helper.Done() 404 require.NoError(t, err) 405 require.NotNil(t, h) 406 return h 407 } 408 409 func getTestPubSimulationRWSet(t *testing.T, builders ...*rwsetutil.RWSetBuilder) []*rwsetutil.TxRwSet { 410 var pubRWSets []*rwsetutil.TxRwSet 411 for _, b := range builders { 412 s, e := b.GetTxSimulationResults() 413 require.NoError(t, e) 414 sBytes, err := s.GetPubSimulationBytes() 415 require.NoError(t, err) 416 pubRWSet := &rwsetutil.TxRwSet{} 417 require.NoError(t, pubRWSet.FromProtoBytes(sBytes)) 418 pubRWSets = append(pubRWSets, pubRWSet) 419 } 420 return pubRWSets 421 }