github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/core/ledger/kvledger/history/db_test.go (about) 1 /* 2 Copyright hechain. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package history 8 9 import ( 10 "bytes" 11 "fmt" 12 "os" 13 "strconv" 14 "testing" 15 16 "github.com/golang/protobuf/proto" 17 configtxtest "github.com/hechain20/hechain/common/configtx/test" 18 "github.com/hechain20/hechain/common/flogging" 19 "github.com/hechain20/hechain/common/ledger/testutil" 20 util2 "github.com/hechain20/hechain/common/util" 21 "github.com/hechain20/hechain/core/ledger" 22 "github.com/hechain20/hechain/core/ledger/internal/version" 23 "github.com/hechain20/hechain/internal/pkg/txflags" 24 "github.com/hyperledger/fabric-protos-go/common" 25 "github.com/hyperledger/fabric-protos-go/ledger/queryresult" 26 "github.com/hyperledger/fabric-protos-go/ledger/rwset" 27 "github.com/hyperledger/fabric-protos-go/ledger/rwset/kvrwset" 28 "github.com/hyperledger/fabric-protos-go/peer" 29 "github.com/stretchr/testify/require" 30 ) 31 32 func TestMain(m *testing.M) { 33 flogging.ActivateSpec("leveldbhelper,history=debug") 34 os.Exit(m.Run()) 35 } 36 37 // TestSavepoint tests that save points get written after each block and get returned via GetBlockNumfromSavepoint 38 func TestSavepoint(t *testing.T) { 39 env := newTestHistoryEnv(t) 40 defer env.cleanup() 41 42 // read the savepoint, it should not exist and should return nil Height object 43 savepoint, err := env.testHistoryDB.GetLastSavepoint() 44 require.NoError(t, err, "Error upon historyDatabase.GetLastSavepoint()") 45 require.Nil(t, savepoint) 46 47 // ShouldRecover should return true when no savepoint is found and recovery from block 0 48 status, blockNum, err := env.testHistoryDB.ShouldRecover(0) 49 require.NoError(t, err, "Error upon historyDatabase.ShouldRecover()") 50 require.True(t, status) 51 require.Equal(t, uint64(0), blockNum) 52 53 bg, gb := testutil.NewBlockGenerator(t, "testLedger", false) 54 require.NoError(t, env.testHistoryDB.Commit(gb)) 55 // read the savepoint, it should now exist and return a Height object with BlockNum 0 56 savepoint, err = env.testHistoryDB.GetLastSavepoint() 57 require.NoError(t, err, "Error upon historyDatabase.GetLastSavepoint()") 58 require.Equal(t, uint64(0), savepoint.BlockNum) 59 60 // create the next block (block 1) 61 txid := util2.GenerateUUID() 62 simulator, _ := env.txmgr.NewTxSimulator(txid) 63 require.NoError(t, simulator.SetState("ns1", "key1", []byte("value1"))) 64 simulator.Done() 65 simRes, _ := simulator.GetTxSimulationResults() 66 pubSimResBytes, _ := simRes.GetPubSimulationBytes() 67 block1 := bg.NextBlock([][]byte{pubSimResBytes}) 68 require.NoError(t, env.testHistoryDB.Commit(block1)) 69 savepoint, err = env.testHistoryDB.GetLastSavepoint() 70 require.NoError(t, err, "Error upon historyDatabase.GetLastSavepoint()") 71 require.Equal(t, uint64(1), savepoint.BlockNum) 72 73 // Should Recover should return false 74 status, blockNum, err = env.testHistoryDB.ShouldRecover(1) 75 require.NoError(t, err, "Error upon historyDatabase.ShouldRecover()") 76 require.False(t, status) 77 require.Equal(t, uint64(2), blockNum) 78 79 // create the next block (block 2) 80 txid = util2.GenerateUUID() 81 simulator, _ = env.txmgr.NewTxSimulator(txid) 82 require.NoError(t, simulator.SetState("ns1", "key1", []byte("value2"))) 83 simulator.Done() 84 simRes, _ = simulator.GetTxSimulationResults() 85 pubSimResBytes, _ = simRes.GetPubSimulationBytes() 86 block2 := bg.NextBlock([][]byte{pubSimResBytes}) 87 88 // assume that the peer failed to commit this block to historyDB and is being recovered now 89 require.NoError(t, env.testHistoryDB.CommitLostBlock(&ledger.BlockAndPvtData{Block: block2})) 90 savepoint, err = env.testHistoryDB.GetLastSavepoint() 91 require.NoError(t, err, "Error upon historyDatabase.GetLastSavepoint()") 92 require.Equal(t, uint64(2), savepoint.BlockNum) 93 94 // Pass high blockNum, ShouldRecover should return true with 3 as blocknum to recover from 95 status, blockNum, err = env.testHistoryDB.ShouldRecover(10) 96 require.NoError(t, err, "Error upon historyDatabase.ShouldRecover()") 97 require.True(t, status) 98 require.Equal(t, uint64(3), blockNum) 99 } 100 101 func TestMarkStartingSavepoint(t *testing.T) { 102 t.Run("normal-case", func(t *testing.T) { 103 env := newTestHistoryEnv(t) 104 defer env.cleanup() 105 106 p := env.testHistoryDBProvider 107 require.NoError(t, p.MarkStartingSavepoint("testLedger", version.NewHeight(25, 30))) 108 109 db := p.GetDBHandle("testLedger") 110 height, err := db.GetLastSavepoint() 111 require.NoError(t, err) 112 require.Equal(t, version.NewHeight(25, 30), height) 113 }) 114 115 t.Run("error-case", func(t *testing.T) { 116 env := newTestHistoryEnv(t) 117 defer env.cleanup() 118 p := env.testHistoryDBProvider 119 p.Close() 120 err := p.MarkStartingSavepoint("testLedger", version.NewHeight(25, 30)) 121 require.Contains(t, 122 err.Error(), 123 "error while writing the starting save point for ledger [testLedger]", 124 ) 125 }) 126 } 127 128 func TestHistory(t *testing.T) { 129 env := newTestHistoryEnv(t) 130 defer env.cleanup() 131 provider := env.testBlockStorageEnv.provider 132 ledger1id := "ledger1" 133 store1, err := provider.Open(ledger1id) 134 require.NoError(t, err, "Error upon provider.OpenBlockStore()") 135 defer store1.Shutdown() 136 require.Equal(t, "history", env.testHistoryDB.Name()) 137 138 bg, gb := testutil.NewBlockGenerator(t, ledger1id, false) 139 require.NoError(t, store1.AddBlock(gb)) 140 require.NoError(t, env.testHistoryDB.Commit(gb)) 141 142 // block1 143 txid := util2.GenerateUUID() 144 simulator, _ := env.txmgr.NewTxSimulator(txid) 145 value1 := []byte("value1") 146 require.NoError(t, simulator.SetState("ns1", "key7", value1)) 147 simulator.Done() 148 simRes, _ := simulator.GetTxSimulationResults() 149 pubSimResBytes, _ := simRes.GetPubSimulationBytes() 150 block1 := bg.NextBlock([][]byte{pubSimResBytes}) 151 err = store1.AddBlock(block1) 152 require.NoError(t, err) 153 err = env.testHistoryDB.Commit(block1) 154 require.NoError(t, err) 155 156 // block2 tran1 157 simulationResults := [][]byte{} 158 txid = util2.GenerateUUID() 159 simulator, _ = env.txmgr.NewTxSimulator(txid) 160 value2 := []byte("value2") 161 require.NoError(t, simulator.SetState("ns1", "key7", value2)) 162 simulator.Done() 163 simRes, _ = simulator.GetTxSimulationResults() 164 pubSimResBytes, _ = simRes.GetPubSimulationBytes() 165 simulationResults = append(simulationResults, pubSimResBytes) 166 // block2 tran2 167 txid2 := util2.GenerateUUID() 168 simulator2, _ := env.txmgr.NewTxSimulator(txid2) 169 value3 := []byte("value3") 170 require.NoError(t, simulator2.SetState("ns1", "key7", value3)) 171 simulator2.Done() 172 simRes2, _ := simulator2.GetTxSimulationResults() 173 pubSimResBytes2, _ := simRes2.GetPubSimulationBytes() 174 simulationResults = append(simulationResults, pubSimResBytes2) 175 block2 := bg.NextBlock(simulationResults) 176 err = store1.AddBlock(block2) 177 require.NoError(t, err) 178 err = env.testHistoryDB.Commit(block2) 179 require.NoError(t, err) 180 181 // block3 182 txid = util2.GenerateUUID() 183 simulator, _ = env.txmgr.NewTxSimulator(txid) 184 require.NoError(t, simulator.DeleteState("ns1", "key7")) 185 simulator.Done() 186 simRes, _ = simulator.GetTxSimulationResults() 187 pubSimResBytes, _ = simRes.GetPubSimulationBytes() 188 block3 := bg.NextBlock([][]byte{pubSimResBytes}) 189 err = store1.AddBlock(block3) 190 require.NoError(t, err) 191 err = env.testHistoryDB.Commit(block3) 192 require.NoError(t, err) 193 t.Logf("Inserted all 3 blocks") 194 195 qhistory, err := env.testHistoryDB.NewQueryExecutor(store1) 196 require.NoError(t, err, "Error upon NewQueryExecutor") 197 198 itr, err2 := qhistory.GetHistoryForKey("ns1", "key7") 199 require.NoError(t, err2, "Error upon GetHistoryForKey()") 200 201 count := 0 202 for { 203 // iterator will return entries in the order of newest to oldest 204 kmod, _ := itr.Next() 205 if kmod == nil { 206 break 207 } 208 txid = kmod.(*queryresult.KeyModification).TxId 209 retrievedValue := kmod.(*queryresult.KeyModification).Value 210 retrievedTimestamp := kmod.(*queryresult.KeyModification).Timestamp 211 retrievedIsDelete := kmod.(*queryresult.KeyModification).IsDelete 212 t.Logf("Retrieved history record for key=key7 at TxId=%s with value %v and timestamp %v", 213 txid, retrievedValue, retrievedTimestamp) 214 count++ 215 if count != 1 { 216 // entries 2, 3, 4 are block2:tran2, block2:tran1 and block1:tran1 217 expectedValue := []byte("value" + strconv.Itoa(5-count)) 218 require.Equal(t, expectedValue, retrievedValue) 219 require.NotNil(t, retrievedTimestamp) 220 require.False(t, retrievedIsDelete) 221 } else { 222 // entry 1 is block3:tran1 223 require.Equal(t, []uint8(nil), retrievedValue) 224 require.NotNil(t, retrievedTimestamp) 225 require.True(t, retrievedIsDelete) 226 } 227 } 228 require.Equal(t, 4, count) 229 230 t.Run("test-iter-error-path", func(t *testing.T) { 231 env.testHistoryDBProvider.Close() 232 qhistory, err = env.testHistoryDB.NewQueryExecutor(store1) 233 itr, err = qhistory.GetHistoryForKey("ns1", "key7") 234 require.EqualError(t, err, "internal leveldb error while obtaining db iterator: leveldb: closed") 235 require.Nil(t, itr) 236 }) 237 } 238 239 func TestHistoryForInvalidTran(t *testing.T) { 240 env := newTestHistoryEnv(t) 241 defer env.cleanup() 242 provider := env.testBlockStorageEnv.provider 243 ledger1id := "ledger1" 244 store1, err := provider.Open(ledger1id) 245 require.NoError(t, err, "Error upon provider.OpenBlockStore()") 246 defer store1.Shutdown() 247 248 bg, gb := testutil.NewBlockGenerator(t, ledger1id, false) 249 require.NoError(t, store1.AddBlock(gb)) 250 require.NoError(t, env.testHistoryDB.Commit(gb)) 251 252 // block1 253 txid := util2.GenerateUUID() 254 simulator, _ := env.txmgr.NewTxSimulator(txid) 255 value1 := []byte("value1") 256 require.NoError(t, simulator.SetState("ns1", "key7", value1)) 257 simulator.Done() 258 simRes, _ := simulator.GetTxSimulationResults() 259 pubSimResBytes, _ := simRes.GetPubSimulationBytes() 260 block1 := bg.NextBlock([][]byte{pubSimResBytes}) 261 262 // for this invalid tran test, set the transaction to invalid 263 txsFilter := txflags.ValidationFlags(block1.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER]) 264 txsFilter.SetFlag(0, peer.TxValidationCode_INVALID_OTHER_REASON) 265 block1.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER] = txsFilter 266 267 err = store1.AddBlock(block1) 268 require.NoError(t, err) 269 err = env.testHistoryDB.Commit(block1) 270 require.NoError(t, err) 271 272 qhistory, err := env.testHistoryDB.NewQueryExecutor(store1) 273 require.NoError(t, err, "Error upon NewQueryExecutor") 274 275 itr, err2 := qhistory.GetHistoryForKey("ns1", "key7") 276 require.NoError(t, err2, "Error upon GetHistoryForKey()") 277 278 // test that there are no history values, since the tran was marked as invalid 279 kmod, _ := itr.Next() 280 require.Nil(t, kmod) 281 } 282 283 // TestGenesisBlockNoError tests that Genesis blocks are ignored by history processing 284 // since we only persist history of chaincode key writes 285 func TestGenesisBlockNoError(t *testing.T) { 286 env := newTestHistoryEnv(t) 287 defer env.cleanup() 288 block, err := configtxtest.MakeGenesisBlock("test_chainid") 289 require.NoError(t, err) 290 err = env.testHistoryDB.Commit(block) 291 require.NoError(t, err) 292 } 293 294 // TestHistoryWithKeyContainingNilBytes tests historydb when keys contains nil bytes (FAB-11244) - 295 // which happens to be used as a separator in the composite keys that is formed for the entries in the historydb 296 func TestHistoryWithKeyContainingNilBytes(t *testing.T) { 297 env := newTestHistoryEnv(t) 298 defer env.cleanup() 299 provider := env.testBlockStorageEnv.provider 300 ledger1id := "ledger1" 301 store1, err := provider.Open(ledger1id) 302 require.NoError(t, err, "Error upon provider.OpenBlockStore()") 303 defer store1.Shutdown() 304 305 bg, gb := testutil.NewBlockGenerator(t, ledger1id, false) 306 require.NoError(t, store1.AddBlock(gb)) 307 require.NoError(t, env.testHistoryDB.Commit(gb)) 308 309 // block1 310 txid := util2.GenerateUUID() 311 simulator, _ := env.txmgr.NewTxSimulator(txid) 312 require.NoError(t, simulator.SetState("ns1", "key", []byte("value1"))) // add a key <key> that contains no nil byte 313 simulator.Done() 314 simRes, _ := simulator.GetTxSimulationResults() 315 pubSimResBytes, _ := simRes.GetPubSimulationBytes() 316 block1 := bg.NextBlock([][]byte{pubSimResBytes}) 317 err = store1.AddBlock(block1) 318 require.NoError(t, err) 319 err = env.testHistoryDB.Commit(block1) 320 require.NoError(t, err) 321 322 // block2 tran1 323 simulationResults := [][]byte{} 324 txid = util2.GenerateUUID() 325 simulator, _ = env.txmgr.NewTxSimulator(txid) 326 require.NoError(t, simulator.SetState("ns1", "key", []byte("value2"))) // add another value for the key <key> 327 simulator.Done() 328 simRes, _ = simulator.GetTxSimulationResults() 329 pubSimResBytes, _ = simRes.GetPubSimulationBytes() 330 simulationResults = append(simulationResults, pubSimResBytes) 331 332 // block2 tran2 333 txid2 := util2.GenerateUUID() 334 simulator2, _ := env.txmgr.NewTxSimulator(txid2) 335 336 // key1 should not fall in the range 337 key1 := "\x00key\x00\x01\x01\x15" 338 require.NoError(t, simulator2.SetState("ns1", key1, []byte("dummyVal1"))) 339 340 // add other keys that contain nil byte(s) - such that when a range query is formed, these keys fall in the range 341 // key2 is skipped due to tran num decoding error (decode size 21 > 8) 342 // blockNumTranNumBytes are 0x1, 0x1, 0x15, 0x0 (separator), 0x1, 0x2, 0x1, 0x1 343 key2 := "key\x00\x01\x01\x15" // \x15 is 21 344 require.NoError(t, simulator2.SetState("ns1", key2, []byte("dummyVal2"))) 345 346 // key3 is skipped due to block num decoding error (decoded size 12 > 8) 347 // blockNumTranNumBytes are 0xc, 0x0 (separtor), 0x1, 0x2, 0x1, 0x1 348 key3 := "key\x00\x0c" // \x0c is 12 349 require.NoError(t, simulator2.SetState("ns1", key3, []byte("dummyVal3"))) 350 351 // key4 is skipped because blockBytesConsumed (2) + tranBytesConsumed (2) != len(blockNumTranNum) (6) 352 // blockNumTranNumBytes are 0x1, 0x0 (separator), 0x1, 0x2, 0x1, 0x1 353 key4 := "key\x00\x01" 354 require.NoError(t, simulator2.SetState("ns1", key4, []byte("dummyVal4"))) 355 356 // key5 is skipped due to ErrNotFoundInIndex, where history key is <ns, key\x00\x04\x01, 2, 1>, same as <ns, key, 16777474, 1>. 357 // blockNumTranNumBytes are 0x4, 0x1, 0x0 (separator), 0x1, 0x2, 0x1, 0x1 358 key5 := "key\x00\x04\x01" 359 require.NoError(t, simulator2.SetState("ns1", key5, []byte("dummyVal5"))) 360 361 // commit block2 362 simulator2.Done() 363 simRes2, _ := simulator2.GetTxSimulationResults() 364 pubSimResBytes2, _ := simRes2.GetPubSimulationBytes() 365 simulationResults = append(simulationResults, pubSimResBytes2) 366 block2 := bg.NextBlock(simulationResults) 367 err = store1.AddBlock(block2) 368 require.NoError(t, err) 369 err = env.testHistoryDB.Commit(block2) 370 require.NoError(t, err) 371 372 qhistory, err := env.testHistoryDB.NewQueryExecutor(store1) 373 require.NoError(t, err, "Error upon NewQueryExecutor") 374 375 // verify the results for each key, in the order of newest to oldest 376 testutilVerifyResults(t, qhistory, "ns1", "key", []string{"value2", "value1"}) 377 testutilVerifyResults(t, qhistory, "ns1", key1, []string{"dummyVal1"}) 378 testutilVerifyResults(t, qhistory, "ns1", key2, []string{"dummyVal2"}) 379 testutilVerifyResults(t, qhistory, "ns1", key3, []string{"dummyVal3"}) 380 testutilVerifyResults(t, qhistory, "ns1", key4, []string{"dummyVal4"}) 381 testutilVerifyResults(t, qhistory, "ns1", key5, []string{"dummyVal5"}) 382 383 // verify none of key1-key5 falls in the range of history query for "key" 384 testutilCheckKeyNotInRange(t, qhistory, "ns1", "key", key1) 385 testutilCheckKeyNotInRange(t, qhistory, "ns1", "key", key2) 386 testutilCheckKeyNotInRange(t, qhistory, "ns1", "key", key3) 387 testutilCheckKeyNotInRange(t, qhistory, "ns1", "key", key4) 388 testutilCheckKeyNotInRange(t, qhistory, "ns1", "key", key5) 389 } 390 391 // TestHistoryWithBlockNumber256 creates 256 blocks and then 392 // queries historydb to verify that all 256 blocks are returned in the right orderer. 393 // This test also verifies that block256 is returned correctly even if its key contains nil byte. 394 func TestHistoryWithBlockNumber256(t *testing.T) { 395 env := newTestHistoryEnv(t) 396 defer env.cleanup() 397 provider := env.testBlockStorageEnv.provider 398 ledger1id := "ledger1" 399 store1, err := provider.Open(ledger1id) 400 require.NoError(t, err, "Error upon provider.OpenBlockStore()") 401 defer store1.Shutdown() 402 403 bg, gb := testutil.NewBlockGenerator(t, ledger1id, false) 404 require.NoError(t, store1.AddBlock(gb)) 405 require.NoError(t, env.testHistoryDB.Commit(gb)) 406 407 // add 256 blocks, each block has 1 transaction setting state for "ns1" and "key", value is "value<blockNum>" 408 for i := 1; i <= 256; i++ { 409 txid := util2.GenerateUUID() 410 simulator, _ := env.txmgr.NewTxSimulator(txid) 411 value := fmt.Sprintf("value%d", i) 412 require.NoError(t, simulator.SetState("ns1", "key", []byte(value))) 413 simulator.Done() 414 simRes, _ := simulator.GetTxSimulationResults() 415 pubSimResBytes, _ := simRes.GetPubSimulationBytes() 416 block := bg.NextBlock([][]byte{pubSimResBytes}) 417 err = store1.AddBlock(block) 418 require.NoError(t, err) 419 err = env.testHistoryDB.Commit(block) 420 require.NoError(t, err) 421 } 422 423 // query history db for "ns1", "key" 424 qhistory, err := env.testHistoryDB.NewQueryExecutor(store1) 425 require.NoError(t, err, "Error upon NewQueryExecutor") 426 427 // verify history query returns the expected results in the orderer of block256, 255, 254 .... 1. 428 expectedHistoryResults := make([]string, 0) 429 for i := 256; i >= 1; i-- { 430 expectedHistoryResults = append(expectedHistoryResults, fmt.Sprintf("value%d", i)) 431 } 432 testutilVerifyResults(t, qhistory, "ns1", "key", expectedHistoryResults) 433 } 434 435 func TestName(t *testing.T) { 436 env := newTestHistoryEnv(t) 437 defer env.cleanup() 438 require.Equal(t, "history", env.testHistoryDB.Name()) 439 } 440 441 func TestDrop(t *testing.T) { 442 env := newTestHistoryEnv(t) 443 defer env.cleanup() 444 provider := env.testBlockStorageEnv.provider 445 446 // create ledger data for "ledger1" and "ledger2" 447 for _, ledgerid := range []string{"ledger1", "ledger2"} { 448 store, err := provider.Open(ledgerid) 449 require.NoError(t, err) 450 defer store.Shutdown() 451 bg, gb := testutil.NewBlockGenerator(t, ledgerid, false) 452 txid := util2.GenerateUUID() 453 simulator, err := env.txmgr.NewTxSimulator(txid) 454 require.NoError(t, err) 455 require.NoError(t, simulator.SetState("ns1", "key1", []byte("value1"))) 456 require.NoError(t, simulator.SetState("ns2", "key2", []byte("value2"))) 457 simulator.Done() 458 simRes, err := simulator.GetTxSimulationResults() 459 require.NoError(t, err) 460 pubSimResBytes, err := simRes.GetPubSimulationBytes() 461 require.NoError(t, err) 462 block1 := bg.NextBlock([][]byte{pubSimResBytes}) 463 464 historydb := env.testHistoryDBProvider.GetDBHandle(ledgerid) 465 require.NoError(t, store.AddBlock(gb)) 466 require.NoError(t, historydb.Commit(gb)) 467 require.NoError(t, store.AddBlock(block1)) 468 require.NoError(t, historydb.Commit(block1)) 469 470 historydbQE, err := historydb.NewQueryExecutor(store) 471 require.NoError(t, err) 472 testutilVerifyResults(t, historydbQE, "ns1", "key1", []string{"value1"}) 473 testutilVerifyResults(t, historydbQE, "ns2", "key2", []string{"value2"}) 474 475 store.Shutdown() 476 } 477 478 require.NoError(t, env.testHistoryDBProvider.Drop("ledger1")) 479 480 // verify ledger1 historydb has no entries and ledger2 historydb remains same 481 historydb := env.testHistoryDBProvider.GetDBHandle("ledger1") 482 store, err := provider.Open("ledger1") 483 require.NoError(t, err) 484 historydbQE, err := historydb.NewQueryExecutor(store) 485 require.NoError(t, err) 486 testutilVerifyResults(t, historydbQE, "ns1", "key1", []string{}) 487 testutilVerifyResults(t, historydbQE, "ns2", "key2", []string{}) 488 empty, err := historydb.levelDB.IsEmpty() 489 require.NoError(t, err) 490 require.True(t, empty) 491 492 historydb2 := env.testHistoryDBProvider.GetDBHandle("ledger2") 493 store2, err := provider.Open("ledger2") 494 require.NoError(t, err) 495 historydbQE2, err := historydb2.NewQueryExecutor(store2) 496 require.NoError(t, err) 497 testutilVerifyResults(t, historydbQE2, "ns1", "key1", []string{"value1"}) 498 testutilVerifyResults(t, historydbQE2, "ns2", "key2", []string{"value2"}) 499 500 // drop again is not an error 501 require.NoError(t, env.testHistoryDBProvider.Drop("ledger1")) 502 503 env.testHistoryDBProvider.Close() 504 require.EqualError(t, env.testHistoryDBProvider.Drop("ledger2"), "internal leveldb error while obtaining db iterator: leveldb: closed") 505 } 506 507 // TestHistoryWithKVWriteOfNilValue - See FAB-18386 for details 508 func TestHistoryWithKVWriteOfNilValue(t *testing.T) { 509 env := newTestHistoryEnv(t) 510 defer env.cleanup() 511 provider := env.testBlockStorageEnv.provider 512 store, err := provider.Open("ledger1") 513 require.NoError(t, err) 514 defer store.Shutdown() 515 516 bg, gb := testutil.NewBlockGenerator(t, "ledger1", false) 517 518 kvRWSet := &kvrwset.KVRWSet{ 519 Writes: []*kvrwset.KVWrite{ 520 // explicitly set IsDelete to false while the value to nil. As this will never be generated by simulation 521 {Key: "key1", IsDelete: false, Value: nil}, 522 }, 523 } 524 kvRWsetBytes, err := proto.Marshal(kvRWSet) 525 require.NoError(t, err) 526 527 txRWSet := &rwset.TxReadWriteSet{ 528 NsRwset: []*rwset.NsReadWriteSet{ 529 { 530 Namespace: "ns1", 531 Rwset: kvRWsetBytes, 532 }, 533 }, 534 } 535 536 txRWSetBytes, err := proto.Marshal(txRWSet) 537 require.NoError(t, err) 538 539 block1 := bg.NextBlockWithTxid([][]byte{txRWSetBytes}, []string{"txid1"}) 540 541 historydb := env.testHistoryDBProvider.GetDBHandle("ledger1") 542 require.NoError(t, store.AddBlock(gb)) 543 require.NoError(t, historydb.Commit(gb)) 544 require.NoError(t, store.AddBlock(block1)) 545 require.NoError(t, historydb.Commit(block1)) 546 547 historydbQE, err := historydb.NewQueryExecutor(store) 548 require.NoError(t, err) 549 itr, err := historydbQE.GetHistoryForKey("ns1", "key1") 550 require.NoError(t, err) 551 kmod, err := itr.Next() 552 require.NoError(t, err) 553 keyModification := kmod.(*queryresult.KeyModification) 554 // despite IsDelete set to "false" in the write-set, historydb results should set this to "true" 555 require.True(t, keyModification.IsDelete) 556 557 kmod, err = itr.Next() 558 require.NoError(t, err) 559 require.Nil(t, kmod) 560 } 561 562 // verify history results 563 func testutilVerifyResults(t *testing.T, hqe ledger.HistoryQueryExecutor, ns, key string, expectedVals []string) { 564 itr, err := hqe.GetHistoryForKey(ns, key) 565 require.NoError(t, err, "Error upon GetHistoryForKey()") 566 retrievedVals := []string{} 567 for { 568 kmod, _ := itr.Next() 569 if kmod == nil { 570 break 571 } 572 txid := kmod.(*queryresult.KeyModification).TxId 573 retrievedValue := string(kmod.(*queryresult.KeyModification).Value) 574 retrievedVals = append(retrievedVals, retrievedValue) 575 t.Logf("Retrieved history record at TxId=%s with value %s", txid, retrievedValue) 576 } 577 require.Equal(t, expectedVals, retrievedVals) 578 } 579 580 // testutilCheckKeyNotInRange verifies that a (false) key is not returned in range query when searching for the desired key 581 func testutilCheckKeyNotInRange(t *testing.T, hqe ledger.HistoryQueryExecutor, ns, desiredKey, falseKey string) { 582 itr, err := hqe.GetHistoryForKey(ns, desiredKey) 583 require.NoError(t, err, "Error upon GetHistoryForKey()") 584 scanner := itr.(*historyScanner) 585 rangeScanKeys := constructRangeScan(ns, falseKey) 586 for { 587 if !scanner.dbItr.Next() { 588 break 589 } 590 historyKey := scanner.dbItr.Key() 591 if bytes.Contains(historyKey, rangeScanKeys.startKey) { 592 require.Failf(t, "false key %s should not be returned in range query for key %s", falseKey, desiredKey) 593 } 594 } 595 }