github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/core/ledger/kvledger/txmgmt/validation/tx_ops_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 "testing" 11 12 "github.com/hechain20/hechain/core/ledger/internal/version" 13 "github.com/hechain20/hechain/core/ledger/kvledger/txmgmt/privacyenabledstate" 14 "github.com/hechain20/hechain/core/ledger/kvledger/txmgmt/rwsetutil" 15 "github.com/hechain20/hechain/core/ledger/kvledger/txmgmt/statemetadata" 16 "github.com/hechain20/hechain/core/ledger/util" 17 "github.com/hyperledger/fabric-protos-go/ledger/rwset/kvrwset" 18 "github.com/stretchr/testify/require" 19 ) 20 21 func TestTxOps(t *testing.T) { 22 require := require.New(t) 23 24 txops := txOps{} 25 key1 := compositeKey{"ns1", "", "key1"} 26 key2 := compositeKey{"ns1", "coll2", "key2"} 27 key3 := compositeKey{"ns1", "coll3", "key3"} 28 key4 := compositeKey{"ns1", "coll4", "key4"} 29 30 txops.upsert(key1, []byte("key1-value1")) 31 require.True(txops[key1].isOnlyUpsert()) 32 33 txops.upsert(key2, []byte("key2-value2")) 34 require.True(txops[key2].isOnlyUpsert()) 35 txops.metadataUpdate(key2, []byte("key2-metadata")) 36 require.False(txops[key2].isOnlyUpsert()) 37 require.True(txops[key2].isUpsertAndMetadataUpdate()) 38 39 txops.upsert(key3, []byte("key3-value")) 40 require.True(txops[key3].isOnlyUpsert()) 41 txops.metadataDelete(key3) 42 require.False(txops[key3].isOnlyUpsert()) 43 require.True(txops[key3].isUpsertAndMetadataUpdate()) 44 45 txops.delete(key4) 46 require.True(txops[key4].isDelete()) 47 } 48 49 func TestTxOpsPreparationValueUpdate(t *testing.T) { 50 testDBEnv := privacyenabledstate.LevelDBTestEnv{} 51 testDBEnv.Init(t) 52 defer testDBEnv.Cleanup() 53 db := testDBEnv.GetDBHandle("TestDB") 54 55 ck1, ck2, ck3 := 56 compositeKey{ns: "ns1", key: "key1"}, 57 compositeKey{ns: "ns1", key: "key2"}, 58 compositeKey{ns: "ns1", key: "key3"} 59 60 updateBatch := privacyenabledstate.NewUpdateBatch() 61 updateBatch.PubUpdates.Put(ck1.ns, ck1.key, []byte("value1"), version.NewHeight(1, 1)) // write key1 with only value 62 updateBatch.PubUpdates.PutValAndMetadata( // write key2 with value and metadata 63 ck2.ns, ck2.key, 64 []byte("value2"), 65 testutilSerializedMetadata(t, map[string][]byte{"metadata2": []byte("metadata2")}), 66 version.NewHeight(1, 2)) 67 68 require.NoError(t, db.ApplyPrivacyAwareUpdates(updateBatch, version.NewHeight(1, 2))) // write the above initial state to db 69 precedingUpdates := newPubAndHashUpdates() 70 71 rwset := testutilBuildRwset( // A sample rwset {upsert key1, key2, key3} 72 t, 73 map[compositeKey][]byte{ 74 ck1: []byte("value1_new"), 75 ck2: []byte("value2_new"), 76 ck3: []byte("value3_new"), 77 }, 78 nil, 79 ) 80 81 txOps, err := prepareTxOps(rwset, precedingUpdates, db) 82 require.NoError(t, err) 83 require.Len(t, txOps, 3) 84 85 ck1ExpectedKeyOps := &keyOps{ // finally, key1 should have only new value 86 flag: upsertVal, 87 value: []byte("value1_new"), 88 } 89 90 ck2ExpectedKeyOps := &keyOps{ // key2 should have new value and existing metadata 91 flag: upsertVal, 92 value: []byte("value2_new"), 93 metadata: testutilSerializedMetadata(t, map[string][]byte{"metadata2": []byte("metadata2")}), 94 } 95 96 ck3ExpectedKeyOps := &keyOps{ // key3 should have new value 97 flag: upsertVal, 98 value: []byte("value3_new"), 99 } 100 101 require.Equal(t, ck1ExpectedKeyOps, txOps[ck1]) 102 require.Equal(t, ck2ExpectedKeyOps, txOps[ck2]) 103 require.Equal(t, ck3ExpectedKeyOps, txOps[ck3]) 104 } 105 106 func TestTxOpsPreparationMetadataUpdates(t *testing.T) { 107 testDBEnv := privacyenabledstate.LevelDBTestEnv{} 108 testDBEnv.Init(t) 109 defer testDBEnv.Cleanup() 110 db := testDBEnv.GetDBHandle("TestDB") 111 112 ck1, ck2, ck3 := 113 compositeKey{ns: "ns1", key: "key1"}, 114 compositeKey{ns: "ns1", key: "key2"}, 115 compositeKey{ns: "ns1", key: "key3"} 116 117 updateBatch := privacyenabledstate.NewUpdateBatch() 118 updateBatch.PubUpdates.Put(ck1.ns, ck1.key, []byte("value1"), version.NewHeight(1, 1)) // write key1 with only value 119 updateBatch.PubUpdates.PutValAndMetadata( // write key2 with value and metadata 120 ck2.ns, ck2.key, 121 []byte("value2"), 122 testutilSerializedMetadata(t, map[string][]byte{"metadata2": []byte("metadata2")}), 123 version.NewHeight(1, 2)) 124 125 require.NoError(t, db.ApplyPrivacyAwareUpdates(updateBatch, version.NewHeight(1, 2))) // write the above initial state to db 126 precedingUpdates := newPubAndHashUpdates() 127 128 rwset := testutilBuildRwset( // A sample rwset {update metadta for the three keys} 129 t, 130 nil, 131 map[compositeKey]map[string][]byte{ 132 ck1: {"metadata1": []byte("metadata1_new")}, 133 ck2: {"metadata2": []byte("metadata2_new")}, 134 ck3: {"metadata3": []byte("metadata3_new")}, 135 }, 136 ) 137 138 txOps, err := prepareTxOps(rwset, precedingUpdates, db) 139 require.NoError(t, err) 140 require.Len(t, txOps, 2) // key3 should have been removed from the txOps because, the key3 does not exist and only metadata is being updated 141 142 ck1ExpectedKeyOps := &keyOps{ // finally, key1 should have only existing value and new metadata 143 flag: metadataUpdate, 144 value: []byte("value1"), 145 metadata: testutilSerializedMetadata(t, map[string][]byte{"metadata1": []byte("metadata1_new")}), 146 } 147 148 ck2ExpectedKeyOps := &keyOps{ // key2 should have existing value and new metadata 149 flag: metadataUpdate, 150 value: []byte("value2"), 151 metadata: testutilSerializedMetadata(t, map[string][]byte{"metadata2": []byte("metadata2_new")}), 152 } 153 154 require.Equal(t, ck1ExpectedKeyOps, txOps[ck1]) 155 require.Equal(t, ck2ExpectedKeyOps, txOps[ck2]) 156 } 157 158 func TestTxOpsPreparationMetadataDelete(t *testing.T) { 159 testDBEnv := privacyenabledstate.LevelDBTestEnv{} 160 testDBEnv.Init(t) 161 defer testDBEnv.Cleanup() 162 db := testDBEnv.GetDBHandle("TestDB") 163 164 ck1, ck2, ck3 := 165 compositeKey{ns: "ns1", key: "key1"}, 166 compositeKey{ns: "ns1", key: "key2"}, 167 compositeKey{ns: "ns1", key: "key3"} 168 169 updateBatch := privacyenabledstate.NewUpdateBatch() 170 updateBatch.PubUpdates.Put(ck1.ns, ck1.key, []byte("value1"), version.NewHeight(1, 1)) // write key1 with only value 171 updateBatch.PubUpdates.PutValAndMetadata( // write key2 with value and metadata 172 ck2.ns, ck2.key, 173 []byte("value2"), 174 testutilSerializedMetadata(t, map[string][]byte{"metadata2": []byte("metadata2")}), 175 version.NewHeight(1, 2)) 176 177 require.NoError(t, db.ApplyPrivacyAwareUpdates(updateBatch, version.NewHeight(1, 2))) // write the above initial state to db 178 precedingUpdates := newPubAndHashUpdates() 179 180 rwset := testutilBuildRwset( // A sample rwset {delete metadata for the three keys} 181 t, 182 nil, 183 map[compositeKey]map[string][]byte{ 184 ck1: {}, 185 ck2: {}, 186 ck3: {}, 187 }, 188 ) 189 190 txOps, err := prepareTxOps(rwset, precedingUpdates, db) 191 require.NoError(t, err) 192 require.Len(t, txOps, 2) // key3 should have been removed from the txOps because, the key3 does not exist and only metadata is being updated 193 194 ck1ExpectedKeyOps := &keyOps{ // finally, key1 should have only existing value and no metadata 195 flag: metadataDelete, 196 value: []byte("value1"), 197 } 198 199 ck2ExpectedKeyOps := &keyOps{ // key2 should have existing value and no metadata 200 flag: metadataDelete, 201 value: []byte("value2"), 202 } 203 204 require.Equal(t, ck1ExpectedKeyOps, txOps[ck1]) 205 require.Equal(t, ck2ExpectedKeyOps, txOps[ck2]) 206 } 207 208 func TestTxOpsPreparationMixedUpdates(t *testing.T) { 209 testDBEnv := privacyenabledstate.LevelDBTestEnv{} 210 testDBEnv.Init(t) 211 defer testDBEnv.Cleanup() 212 db := testDBEnv.GetDBHandle("TestDB") 213 214 ck1, ck2, ck3, ck4 := 215 compositeKey{ns: "ns1", key: "key1"}, 216 compositeKey{ns: "ns1", key: "key2"}, 217 compositeKey{ns: "ns1", key: "key3"}, 218 compositeKey{ns: "ns1", key: "key4"} 219 220 updateBatch := privacyenabledstate.NewUpdateBatch() 221 updateBatch.PubUpdates.Put(ck1.ns, ck1.key, []byte("value1"), version.NewHeight(1, 1)) // write key1 with only value 222 updateBatch.PubUpdates.Put(ck2.ns, ck2.key, []byte("value2"), version.NewHeight(1, 2)) // write key2 with only value 223 updateBatch.PubUpdates.PutValAndMetadata( // write key3 with value and metadata 224 ck3.ns, ck3.key, 225 []byte("value3"), 226 testutilSerializedMetadata(t, map[string][]byte{"metadata3": []byte("metadata3")}), 227 version.NewHeight(1, 3)) 228 updateBatch.PubUpdates.PutValAndMetadata( // write key4 with value and metadata 229 ck4.ns, ck4.key, 230 []byte("value4"), 231 testutilSerializedMetadata(t, map[string][]byte{"metadata4": []byte("metadata4")}), 232 version.NewHeight(1, 4)) 233 234 require.NoError(t, db.ApplyPrivacyAwareUpdates(updateBatch, version.NewHeight(1, 2))) // write the above initial state to db 235 236 precedingUpdates := newPubAndHashUpdates() 237 238 rwset := testutilBuildRwset( // A sample rwset {key1:only value update, key2: value and metadata update, key3: only metadata update, key4: only value update} 239 t, 240 map[compositeKey][]byte{ 241 ck1: []byte("value1_new"), 242 ck2: []byte("value2_new"), 243 ck4: []byte("value4_new"), 244 }, 245 map[compositeKey]map[string][]byte{ 246 ck2: {"metadata2": []byte("metadata2_new")}, 247 ck3: {"metadata3": []byte("metadata3_new")}, 248 }, 249 ) 250 251 txOps, err := prepareTxOps(rwset, precedingUpdates, db) 252 require.NoError(t, err) 253 require.Len(t, txOps, 4) 254 255 ck1ExpectedKeyOps := &keyOps{ // finally, key1 should have only new value 256 flag: upsertVal, 257 value: []byte("value1_new"), 258 } 259 260 ck2ExpectedKeyOps := &keyOps{ // key2 should have new value and new metadata 261 flag: upsertVal + metadataUpdate, 262 value: []byte("value2_new"), 263 metadata: testutilSerializedMetadata(t, map[string][]byte{"metadata2": []byte("metadata2_new")}), 264 } 265 266 ck3ExpectedKeyOps := &keyOps{ // key3 should have existing value and new metadata 267 flag: metadataUpdate, 268 value: []byte("value3"), 269 metadata: testutilSerializedMetadata(t, map[string][]byte{"metadata3": []byte("metadata3_new")}), 270 } 271 272 ck4ExpectedKeyOps := &keyOps{ // key4 should have new value and existing metadata 273 flag: upsertVal, 274 value: []byte("value4_new"), 275 metadata: testutilSerializedMetadata(t, map[string][]byte{"metadata4": []byte("metadata4")}), 276 } 277 278 require.Equal(t, ck1ExpectedKeyOps, txOps[ck1]) 279 require.Equal(t, ck2ExpectedKeyOps, txOps[ck2]) 280 require.Equal(t, ck3ExpectedKeyOps, txOps[ck3]) 281 require.Equal(t, ck4ExpectedKeyOps, txOps[ck4]) 282 } 283 284 func TestTxOpsPreparationPvtdataHashes(t *testing.T) { 285 testDBEnv := privacyenabledstate.LevelDBTestEnv{} 286 testDBEnv.Init(t) 287 defer testDBEnv.Cleanup() 288 db := testDBEnv.GetDBHandle("TestDB") 289 290 ck1, ck2, ck3, ck4 := 291 compositeKey{ns: "ns1", coll: "coll1", key: "key1"}, 292 compositeKey{ns: "ns1", coll: "coll1", key: "key2"}, 293 compositeKey{ns: "ns1", coll: "coll1", key: "key3"}, 294 compositeKey{ns: "ns1", coll: "coll1", key: "key4"} 295 296 ck1Hash, ck2Hash, ck3Hash, ck4Hash := 297 compositeKey{ns: "ns1", coll: "coll1", key: string(util.ComputeStringHash("key1"))}, 298 compositeKey{ns: "ns1", coll: "coll1", key: string(util.ComputeStringHash("key2"))}, 299 compositeKey{ns: "ns1", coll: "coll1", key: string(util.ComputeStringHash("key3"))}, 300 compositeKey{ns: "ns1", coll: "coll1", key: string(util.ComputeStringHash("key4"))} 301 302 updateBatch := privacyenabledstate.NewUpdateBatch() 303 304 updateBatch.HashUpdates.Put(ck1.ns, ck1.coll, util.ComputeStringHash(ck1.key), 305 util.ComputeStringHash("value1"), version.NewHeight(1, 1)) // write key1 with only value 306 307 updateBatch.HashUpdates.Put(ck2.ns, ck2.coll, util.ComputeStringHash(ck2.key), 308 util.ComputeStringHash("value2"), version.NewHeight(1, 2)) // write key2 with only value 309 310 updateBatch.HashUpdates.PutValAndMetadata( // write key3 with value and metadata 311 ck3.ns, ck3.coll, string(util.ComputeStringHash(ck3.key)), 312 util.ComputeStringHash("value3"), 313 testutilSerializedMetadata(t, map[string][]byte{"metadata3": []byte("metadata3")}), 314 version.NewHeight(1, 3)) 315 316 updateBatch.HashUpdates.PutValAndMetadata( // write key4 with value and metadata 317 ck4.ns, ck4.coll, string(util.ComputeStringHash(ck4.key)), 318 util.ComputeStringHash("value4"), 319 testutilSerializedMetadata(t, map[string][]byte{"metadata4": []byte("metadata4")}), 320 version.NewHeight(1, 4)) 321 322 require.NoError(t, db.ApplyPrivacyAwareUpdates(updateBatch, version.NewHeight(1, 2))) // write the above initial state to db 323 324 precedingUpdates := newPubAndHashUpdates() 325 rwset := testutilBuildRwset( // A sample rwset {key1:only value update, key2: value and metadata update, key3: only metadata update, key4: only value update} 326 t, 327 map[compositeKey][]byte{ 328 ck1: []byte("value1_new"), 329 ck2: []byte("value2_new"), 330 ck4: []byte("value4_new"), 331 }, 332 map[compositeKey]map[string][]byte{ 333 ck2: {"metadata2": []byte("metadata2_new")}, 334 ck3: {"metadata3": []byte("metadata3_new")}, 335 }, 336 ) 337 338 txOps, err := prepareTxOps(rwset, precedingUpdates, db) 339 require.NoError(t, err) 340 require.Len(t, txOps, 4) 341 342 ck1ExpectedKeyOps := &keyOps{ // finally, key1 should have only new value 343 flag: upsertVal, 344 value: util.ComputeStringHash("value1_new"), 345 } 346 347 ck2ExpectedKeyOps := &keyOps{ // key2 should have new value and new metadata 348 flag: upsertVal + metadataUpdate, 349 value: util.ComputeStringHash("value2_new"), 350 metadata: testutilSerializedMetadata(t, map[string][]byte{"metadata2": []byte("metadata2_new")}), 351 } 352 353 ck3ExpectedKeyOps := &keyOps{ // key3 should have existing value and new metadata 354 flag: metadataUpdate, 355 value: util.ComputeStringHash("value3"), 356 metadata: testutilSerializedMetadata(t, map[string][]byte{"metadata3": []byte("metadata3_new")}), 357 } 358 359 ck4ExpectedKeyOps := &keyOps{ // key4 should have new value and existing metadata 360 flag: upsertVal, 361 value: util.ComputeStringHash("value4_new"), 362 metadata: testutilSerializedMetadata(t, map[string][]byte{"metadata4": []byte("metadata4")}), 363 } 364 365 require.Equal(t, ck1ExpectedKeyOps, txOps[ck1Hash]) 366 require.Equal(t, ck2ExpectedKeyOps, txOps[ck2Hash]) 367 require.Equal(t, ck3ExpectedKeyOps, txOps[ck3Hash]) 368 require.Equal(t, ck4ExpectedKeyOps, txOps[ck4Hash]) 369 } 370 371 // TestInterpretNilValueKVWritesAsDelete - See FAB-18386 372 func TestInterpretNilValueKVWritesAsDelete(t *testing.T) { 373 testcases := []struct { 374 name string 375 rwset *rwsetutil.TxRwSet 376 compositeKeysToVerify []compositeKey 377 }{ 378 { 379 name: "public_keys_writes", 380 rwset: &rwsetutil.TxRwSet{ 381 NsRwSets: []*rwsetutil.NsRwSet{ 382 { 383 NameSpace: "ns1", 384 KvRwSet: &kvrwset.KVRWSet{ 385 Writes: []*kvrwset.KVWrite{ 386 { 387 Key: "key1", 388 IsDelete: true, 389 }, 390 { 391 Key: "key2", 392 IsDelete: false, 393 Value: []byte{}, 394 }, 395 }, 396 }, 397 }, 398 }, 399 }, 400 compositeKeysToVerify: []compositeKey{ 401 {ns: "ns1", key: "key1"}, 402 {ns: "ns1", key: "key2"}, 403 }, 404 }, 405 { 406 name: "private_keys_hashes_writes", 407 rwset: &rwsetutil.TxRwSet{ 408 NsRwSets: []*rwsetutil.NsRwSet{ 409 { 410 NameSpace: "ns1", 411 KvRwSet: &kvrwset.KVRWSet{}, 412 CollHashedRwSets: []*rwsetutil.CollHashedRwSet{ 413 { 414 CollectionName: "coll1", 415 HashedRwSet: &kvrwset.HashedRWSet{ 416 HashedWrites: []*kvrwset.KVWriteHash{ 417 { 418 KeyHash: util.ComputeStringHash("key1"), 419 IsDelete: true, 420 }, 421 { 422 KeyHash: util.ComputeStringHash("key2"), 423 IsDelete: false, 424 }, 425 { 426 KeyHash: util.ComputeStringHash("key3"), 427 IsDelete: false, 428 ValueHash: util.ComputeHash([]byte{}), 429 }, 430 }, 431 }, 432 }, 433 }, 434 }, 435 }, 436 }, 437 compositeKeysToVerify: []compositeKey{ 438 {ns: "ns1", coll: "coll1", key: string(util.ComputeStringHash("key1"))}, 439 {ns: "ns1", coll: "coll1", key: string(util.ComputeStringHash("key2"))}, 440 {ns: "ns1", coll: "coll1", key: string(util.ComputeStringHash("key3"))}, 441 }, 442 }, 443 } 444 445 for _, tc := range testcases { 446 t.Run(tc.name, func(t *testing.T) { 447 txOps := txOps{} 448 err := txOps.applyTxRwset(tc.rwset) 449 require.NoError(t, err) 450 451 for _, keyToVerify := range tc.compositeKeysToVerify { 452 require.Equal(t, 453 &keyOps{flag: keyDelete}, 454 txOps[keyToVerify], 455 ) 456 } 457 }) 458 } 459 } 460 461 func testutilBuildRwset(t *testing.T, 462 kvWrites map[compositeKey][]byte, 463 metadataWrites map[compositeKey]map[string][]byte) *rwsetutil.TxRwSet { 464 rwsetBuilder := rwsetutil.NewRWSetBuilder() 465 for kvwrite, val := range kvWrites { 466 if kvwrite.coll == "" { 467 rwsetBuilder.AddToWriteSet(kvwrite.ns, kvwrite.key, val) 468 } else { 469 rwsetBuilder.AddToPvtAndHashedWriteSet(kvwrite.ns, kvwrite.coll, kvwrite.key, val) 470 } 471 } 472 473 for metadataWrite, metadataVal := range metadataWrites { 474 if metadataWrite.coll == "" { 475 rwsetBuilder.AddToMetadataWriteSet(metadataWrite.ns, metadataWrite.key, metadataVal) 476 } else { 477 rwsetBuilder.AddToHashedMetadataWriteSet(metadataWrite.ns, metadataWrite.coll, metadataWrite.key, metadataVal) 478 } 479 } 480 return rwsetBuilder.GetTxReadWriteSet() 481 } 482 483 func testutilSerializedMetadata(t *testing.T, metadataMap map[string][]byte) []byte { 484 metadataEntries := []*kvrwset.KVMetadataEntry{} 485 for metadataK, metadataV := range metadataMap { 486 metadataEntries = append(metadataEntries, &kvrwset.KVMetadataEntry{Name: metadataK, Value: metadataV}) 487 } 488 metadataBytes, err := statemetadata.Serialize(metadataEntries) 489 require.NoError(t, err) 490 return metadataBytes 491 }