github.com/osdi23p228/fabric@v0.0.0-20221218062954-77808885f5db/core/ledger/kvledger/history/db_test.go (about) 1 /* 2 Copyright IBM Corp. 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 "github.com/hyperledger/fabric-protos-go/common" 18 "github.com/hyperledger/fabric-protos-go/ledger/queryresult" 19 "github.com/hyperledger/fabric-protos-go/ledger/rwset" 20 "github.com/hyperledger/fabric-protos-go/ledger/rwset/kvrwset" 21 "github.com/hyperledger/fabric-protos-go/peer" 22 configtxtest "github.com/osdi23p228/fabric/common/configtx/test" 23 "github.com/osdi23p228/fabric/common/flogging" 24 "github.com/osdi23p228/fabric/common/ledger/testutil" 25 util2 "github.com/osdi23p228/fabric/common/util" 26 "github.com/osdi23p228/fabric/core/ledger" 27 "github.com/osdi23p228/fabric/internal/pkg/txflags" 28 "github.com/stretchr/testify/assert" 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 assert.NoError(t, err, "Error upon historyDatabase.GetLastSavepoint()") 45 assert.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 assert.NoError(t, err, "Error upon historyDatabase.ShouldRecover()") 50 assert.True(t, status) 51 assert.Equal(t, uint64(0), blockNum) 52 53 bg, gb := testutil.NewBlockGenerator(t, "testLedger", false) 54 assert.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 assert.NoError(t, err, "Error upon historyDatabase.GetLastSavepoint()") 58 assert.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 simulator.SetState("ns1", "key1", []byte("value1")) 64 simulator.Done() 65 simRes, _ := simulator.GetTxSimulationResults() 66 pubSimResBytes, _ := simRes.GetPubSimulationBytes() 67 block1 := bg.NextBlock([][]byte{pubSimResBytes}) 68 assert.NoError(t, env.testHistoryDB.Commit(block1)) 69 savepoint, err = env.testHistoryDB.GetLastSavepoint() 70 assert.NoError(t, err, "Error upon historyDatabase.GetLastSavepoint()") 71 assert.Equal(t, uint64(1), savepoint.BlockNum) 72 73 // Should Recover should return false 74 status, blockNum, err = env.testHistoryDB.ShouldRecover(1) 75 assert.NoError(t, err, "Error upon historyDatabase.ShouldRecover()") 76 assert.False(t, status) 77 assert.Equal(t, uint64(2), blockNum) 78 79 // create the next block (block 2) 80 txid = util2.GenerateUUID() 81 simulator, _ = env.txmgr.NewTxSimulator(txid) 82 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 env.testHistoryDB.CommitLostBlock(&ledger.BlockAndPvtData{Block: block2}) 90 savepoint, err = env.testHistoryDB.GetLastSavepoint() 91 assert.NoError(t, err, "Error upon historyDatabase.GetLastSavepoint()") 92 assert.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 assert.NoError(t, err, "Error upon historyDatabase.ShouldRecover()") 97 assert.True(t, status) 98 assert.Equal(t, uint64(3), blockNum) 99 } 100 101 func TestHistory(t *testing.T) { 102 env := newTestHistoryEnv(t) 103 defer env.cleanup() 104 provider := env.testBlockStorageEnv.provider 105 ledger1id := "ledger1" 106 store1, err := provider.Open(ledger1id) 107 assert.NoError(t, err, "Error upon provider.OpenBlockStore()") 108 defer store1.Shutdown() 109 assert.Equal(t, "history", env.testHistoryDB.Name()) 110 111 bg, gb := testutil.NewBlockGenerator(t, ledger1id, false) 112 assert.NoError(t, store1.AddBlock(gb)) 113 assert.NoError(t, env.testHistoryDB.Commit(gb)) 114 115 //block1 116 txid := util2.GenerateUUID() 117 simulator, _ := env.txmgr.NewTxSimulator(txid) 118 value1 := []byte("value1") 119 simulator.SetState("ns1", "key7", value1) 120 simulator.Done() 121 simRes, _ := simulator.GetTxSimulationResults() 122 pubSimResBytes, _ := simRes.GetPubSimulationBytes() 123 block1 := bg.NextBlock([][]byte{pubSimResBytes}) 124 err = store1.AddBlock(block1) 125 assert.NoError(t, err) 126 err = env.testHistoryDB.Commit(block1) 127 assert.NoError(t, err) 128 129 //block2 tran1 130 simulationResults := [][]byte{} 131 txid = util2.GenerateUUID() 132 simulator, _ = env.txmgr.NewTxSimulator(txid) 133 value2 := []byte("value2") 134 simulator.SetState("ns1", "key7", value2) 135 simulator.Done() 136 simRes, _ = simulator.GetTxSimulationResults() 137 pubSimResBytes, _ = simRes.GetPubSimulationBytes() 138 simulationResults = append(simulationResults, pubSimResBytes) 139 //block2 tran2 140 txid2 := util2.GenerateUUID() 141 simulator2, _ := env.txmgr.NewTxSimulator(txid2) 142 value3 := []byte("value3") 143 simulator2.SetState("ns1", "key7", value3) 144 simulator2.Done() 145 simRes2, _ := simulator2.GetTxSimulationResults() 146 pubSimResBytes2, _ := simRes2.GetPubSimulationBytes() 147 simulationResults = append(simulationResults, pubSimResBytes2) 148 block2 := bg.NextBlock(simulationResults) 149 err = store1.AddBlock(block2) 150 assert.NoError(t, err) 151 err = env.testHistoryDB.Commit(block2) 152 assert.NoError(t, err) 153 154 //block3 155 txid = util2.GenerateUUID() 156 simulator, _ = env.txmgr.NewTxSimulator(txid) 157 simulator.DeleteState("ns1", "key7") 158 simulator.Done() 159 simRes, _ = simulator.GetTxSimulationResults() 160 pubSimResBytes, _ = simRes.GetPubSimulationBytes() 161 block3 := bg.NextBlock([][]byte{pubSimResBytes}) 162 err = store1.AddBlock(block3) 163 assert.NoError(t, err) 164 err = env.testHistoryDB.Commit(block3) 165 assert.NoError(t, err) 166 t.Logf("Inserted all 3 blocks") 167 168 qhistory, err := env.testHistoryDB.NewQueryExecutor(store1) 169 assert.NoError(t, err, "Error upon NewQueryExecutor") 170 171 itr, err2 := qhistory.GetHistoryForKey("ns1", "key7") 172 assert.NoError(t, err2, "Error upon GetHistoryForKey()") 173 174 count := 0 175 for { 176 // iterator will return entries in the order of newest to oldest 177 kmod, _ := itr.Next() 178 if kmod == nil { 179 break 180 } 181 txid = kmod.(*queryresult.KeyModification).TxId 182 retrievedValue := kmod.(*queryresult.KeyModification).Value 183 retrievedTimestamp := kmod.(*queryresult.KeyModification).Timestamp 184 retrievedIsDelete := kmod.(*queryresult.KeyModification).IsDelete 185 t.Logf("Retrieved history record for key=key7 at TxId=%s with value %v and timestamp %v", 186 txid, retrievedValue, retrievedTimestamp) 187 count++ 188 if count != 1 { 189 // entries 2, 3, 4 are block2:tran2, block2:tran1 and block1:tran1 190 expectedValue := []byte("value" + strconv.Itoa(5-count)) 191 assert.Equal(t, expectedValue, retrievedValue) 192 assert.NotNil(t, retrievedTimestamp) 193 assert.False(t, retrievedIsDelete) 194 } else { 195 // entry 1 is block3:tran1 196 assert.Equal(t, []uint8(nil), retrievedValue) 197 assert.NotNil(t, retrievedTimestamp) 198 assert.True(t, retrievedIsDelete) 199 } 200 } 201 assert.Equal(t, 4, count) 202 203 t.Run("test-iter-error-path", func(t *testing.T) { 204 env.testHistoryDBProvider.Close() 205 qhistory, err = env.testHistoryDB.NewQueryExecutor(store1) 206 itr, err = qhistory.GetHistoryForKey("ns1", "key7") 207 require.EqualError(t, err, "internal leveldb error while obtaining db iterator: leveldb: closed") 208 require.Nil(t, itr) 209 210 }) 211 } 212 213 func TestHistoryForInvalidTran(t *testing.T) { 214 env := newTestHistoryEnv(t) 215 defer env.cleanup() 216 provider := env.testBlockStorageEnv.provider 217 ledger1id := "ledger1" 218 store1, err := provider.Open(ledger1id) 219 assert.NoError(t, err, "Error upon provider.OpenBlockStore()") 220 defer store1.Shutdown() 221 222 bg, gb := testutil.NewBlockGenerator(t, ledger1id, false) 223 assert.NoError(t, store1.AddBlock(gb)) 224 assert.NoError(t, env.testHistoryDB.Commit(gb)) 225 226 //block1 227 txid := util2.GenerateUUID() 228 simulator, _ := env.txmgr.NewTxSimulator(txid) 229 value1 := []byte("value1") 230 simulator.SetState("ns1", "key7", value1) 231 simulator.Done() 232 simRes, _ := simulator.GetTxSimulationResults() 233 pubSimResBytes, _ := simRes.GetPubSimulationBytes() 234 block1 := bg.NextBlock([][]byte{pubSimResBytes}) 235 236 //for this invalid tran test, set the transaction to invalid 237 txsFilter := txflags.ValidationFlags(block1.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER]) 238 txsFilter.SetFlag(0, peer.TxValidationCode_INVALID_OTHER_REASON) 239 block1.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER] = txsFilter 240 241 err = store1.AddBlock(block1) 242 assert.NoError(t, err) 243 err = env.testHistoryDB.Commit(block1) 244 assert.NoError(t, err) 245 246 qhistory, err := env.testHistoryDB.NewQueryExecutor(store1) 247 assert.NoError(t, err, "Error upon NewQueryExecutor") 248 249 itr, err2 := qhistory.GetHistoryForKey("ns1", "key7") 250 assert.NoError(t, err2, "Error upon GetHistoryForKey()") 251 252 // test that there are no history values, since the tran was marked as invalid 253 kmod, _ := itr.Next() 254 assert.Nil(t, kmod) 255 } 256 257 //TestGenesisBlockNoError tests that Genesis blocks are ignored by history processing 258 // since we only persist history of chaincode key writes 259 func TestGenesisBlockNoError(t *testing.T) { 260 env := newTestHistoryEnv(t) 261 defer env.cleanup() 262 block, err := configtxtest.MakeGenesisBlock("test_chainid") 263 assert.NoError(t, err) 264 err = env.testHistoryDB.Commit(block) 265 assert.NoError(t, err) 266 } 267 268 // TestHistoryWithKeyContainingNilBytes tests historydb when keys contains nil bytes (FAB-11244) - 269 // which happens to be used as a separator in the composite keys that is formed for the entries in the historydb 270 func TestHistoryWithKeyContainingNilBytes(t *testing.T) { 271 env := newTestHistoryEnv(t) 272 defer env.cleanup() 273 provider := env.testBlockStorageEnv.provider 274 ledger1id := "ledger1" 275 store1, err := provider.Open(ledger1id) 276 assert.NoError(t, err, "Error upon provider.OpenBlockStore()") 277 defer store1.Shutdown() 278 279 bg, gb := testutil.NewBlockGenerator(t, ledger1id, false) 280 assert.NoError(t, store1.AddBlock(gb)) 281 assert.NoError(t, env.testHistoryDB.Commit(gb)) 282 283 //block1 284 txid := util2.GenerateUUID() 285 simulator, _ := env.txmgr.NewTxSimulator(txid) 286 simulator.SetState("ns1", "key", []byte("value1")) // add a key <key> that contains no nil byte 287 simulator.Done() 288 simRes, _ := simulator.GetTxSimulationResults() 289 pubSimResBytes, _ := simRes.GetPubSimulationBytes() 290 block1 := bg.NextBlock([][]byte{pubSimResBytes}) 291 err = store1.AddBlock(block1) 292 assert.NoError(t, err) 293 err = env.testHistoryDB.Commit(block1) 294 assert.NoError(t, err) 295 296 //block2 tran1 297 simulationResults := [][]byte{} 298 txid = util2.GenerateUUID() 299 simulator, _ = env.txmgr.NewTxSimulator(txid) 300 simulator.SetState("ns1", "key", []byte("value2")) // add another value for the key <key> 301 simulator.Done() 302 simRes, _ = simulator.GetTxSimulationResults() 303 pubSimResBytes, _ = simRes.GetPubSimulationBytes() 304 simulationResults = append(simulationResults, pubSimResBytes) 305 306 //block2 tran2 307 txid2 := util2.GenerateUUID() 308 simulator2, _ := env.txmgr.NewTxSimulator(txid2) 309 310 // key1 should not fall in the range 311 key1 := "\x00key\x00\x01\x01\x15" 312 simulator2.SetState("ns1", key1, []byte("dummyVal1")) 313 314 // add other keys that contain nil byte(s) - such that when a range query is formed, these keys fall in the range 315 // key2 is skipped due to tran num decoding error (decode size 21 > 8) 316 // blockNumTranNumBytes are 0x1, 0x1, 0x15, 0x0 (separator), 0x1, 0x2, 0x1, 0x1 317 key2 := "key\x00\x01\x01\x15" // \x15 is 21 318 simulator2.SetState("ns1", key2, []byte("dummyVal2")) 319 320 // key3 is skipped due to block num decoding error (decoded size 12 > 8) 321 // blockNumTranNumBytes are 0xc, 0x0 (separtor), 0x1, 0x2, 0x1, 0x1 322 key3 := "key\x00\x0c" // \x0c is 12 323 simulator2.SetState("ns1", key3, []byte("dummyVal3")) 324 325 // key4 is skipped because blockBytesConsumed (2) + tranBytesConsumed (2) != len(blockNumTranNum) (6) 326 // blockNumTranNumBytes are 0x1, 0x0 (separator), 0x1, 0x2, 0x1, 0x1 327 key4 := "key\x00\x01" 328 simulator2.SetState("ns1", key4, []byte("dummyVal4")) 329 330 // key5 is skipped due to ErrNotFoundInIndex, where history key is <ns, key\x00\x04\x01, 2, 1>, same as <ns, key, 16777474, 1>. 331 // blockNumTranNumBytes are 0x4, 0x1, 0x0 (separator), 0x1, 0x2, 0x1, 0x1 332 key5 := "key\x00\x04\x01" 333 simulator2.SetState("ns1", key5, []byte("dummyVal5")) 334 335 // commit block2 336 simulator2.Done() 337 simRes2, _ := simulator2.GetTxSimulationResults() 338 pubSimResBytes2, _ := simRes2.GetPubSimulationBytes() 339 simulationResults = append(simulationResults, pubSimResBytes2) 340 block2 := bg.NextBlock(simulationResults) 341 err = store1.AddBlock(block2) 342 assert.NoError(t, err) 343 err = env.testHistoryDB.Commit(block2) 344 assert.NoError(t, err) 345 346 qhistory, err := env.testHistoryDB.NewQueryExecutor(store1) 347 assert.NoError(t, err, "Error upon NewQueryExecutor") 348 349 // verify the results for each key, in the order of newest to oldest 350 testutilVerifyResults(t, qhistory, "ns1", "key", []string{"value2", "value1"}) 351 testutilVerifyResults(t, qhistory, "ns1", key1, []string{"dummyVal1"}) 352 testutilVerifyResults(t, qhistory, "ns1", key2, []string{"dummyVal2"}) 353 testutilVerifyResults(t, qhistory, "ns1", key3, []string{"dummyVal3"}) 354 testutilVerifyResults(t, qhistory, "ns1", key4, []string{"dummyVal4"}) 355 testutilVerifyResults(t, qhistory, "ns1", key5, []string{"dummyVal5"}) 356 357 // verify none of key1-key5 falls in the range of history query for "key" 358 testutilCheckKeyNotInRange(t, qhistory, "ns1", "key", key1) 359 testutilCheckKeyNotInRange(t, qhistory, "ns1", "key", key2) 360 testutilCheckKeyNotInRange(t, qhistory, "ns1", "key", key3) 361 testutilCheckKeyNotInRange(t, qhistory, "ns1", "key", key4) 362 testutilCheckKeyNotInRange(t, qhistory, "ns1", "key", key5) 363 } 364 365 // TestHistoryWithBlockNumber256 creates 256 blocks and then 366 // queries historydb to verify that all 256 blocks are returned in the right orderer. 367 // This test also verifies that block256 is returned correctly even if its key contains nil byte. 368 func TestHistoryWithBlockNumber256(t *testing.T) { 369 env := newTestHistoryEnv(t) 370 defer env.cleanup() 371 provider := env.testBlockStorageEnv.provider 372 ledger1id := "ledger1" 373 store1, err := provider.Open(ledger1id) 374 assert.NoError(t, err, "Error upon provider.OpenBlockStore()") 375 defer store1.Shutdown() 376 377 bg, gb := testutil.NewBlockGenerator(t, ledger1id, false) 378 assert.NoError(t, store1.AddBlock(gb)) 379 assert.NoError(t, env.testHistoryDB.Commit(gb)) 380 381 // add 256 blocks, each block has 1 transaction setting state for "ns1" and "key", value is "value<blockNum>" 382 for i := 1; i <= 256; i++ { 383 txid := util2.GenerateUUID() 384 simulator, _ := env.txmgr.NewTxSimulator(txid) 385 value := fmt.Sprintf("value%d", i) 386 simulator.SetState("ns1", "key", []byte(value)) 387 simulator.Done() 388 simRes, _ := simulator.GetTxSimulationResults() 389 pubSimResBytes, _ := simRes.GetPubSimulationBytes() 390 block := bg.NextBlock([][]byte{pubSimResBytes}) 391 err = store1.AddBlock(block) 392 assert.NoError(t, err) 393 err = env.testHistoryDB.Commit(block) 394 assert.NoError(t, err) 395 } 396 397 // query history db for "ns1", "key" 398 qhistory, err := env.testHistoryDB.NewQueryExecutor(store1) 399 assert.NoError(t, err, "Error upon NewQueryExecutor") 400 401 // verify history query returns the expected results in the orderer of block256, 255, 254 .... 1. 402 expectedHistoryResults := make([]string, 0) 403 for i := 256; i >= 1; i-- { 404 expectedHistoryResults = append(expectedHistoryResults, fmt.Sprintf("value%d", i)) 405 } 406 testutilVerifyResults(t, qhistory, "ns1", "key", expectedHistoryResults) 407 } 408 409 func TestName(t *testing.T) { 410 env := newTestHistoryEnv(t) 411 defer env.cleanup() 412 assert.Equal(t, "history", env.testHistoryDB.Name()) 413 } 414 415 // TestHistoryWithKVWriteOfNilValue - See FAB-18386 for details 416 func TestHistoryWithKVWriteOfNilValue(t *testing.T) { 417 env := newTestHistoryEnv(t) 418 defer env.cleanup() 419 provider := env.testBlockStorageEnv.provider 420 store, err := provider.Open("ledger1") 421 require.NoError(t, err) 422 defer store.Shutdown() 423 424 bg, gb := testutil.NewBlockGenerator(t, "ledger1", false) 425 426 kvRWSet := &kvrwset.KVRWSet{ 427 Writes: []*kvrwset.KVWrite{ 428 // explicitly set IsDelete to false while the value to nil. As this will never be generated by simulation 429 {Key: "key1", IsDelete: false, Value: nil}, 430 }, 431 } 432 kvRWsetBytes, err := proto.Marshal(kvRWSet) 433 require.NoError(t, err) 434 435 txRWSet := &rwset.TxReadWriteSet{ 436 NsRwset: []*rwset.NsReadWriteSet{ 437 { 438 Namespace: "ns1", 439 Rwset: kvRWsetBytes, 440 }, 441 }, 442 } 443 444 txRWSetBytes, err := proto.Marshal(txRWSet) 445 require.NoError(t, err) 446 447 block1 := bg.NextBlockWithTxid([][]byte{txRWSetBytes}, []string{"txid1"}) 448 449 historydb, err := env.testHistoryDBProvider.GetDBHandle("ledger1") 450 require.NoError(t, err) 451 require.NoError(t, store.AddBlock(gb)) 452 require.NoError(t, historydb.Commit(gb)) 453 require.NoError(t, store.AddBlock(block1)) 454 require.NoError(t, historydb.Commit(block1)) 455 456 historydbQE, err := historydb.NewQueryExecutor(store) 457 require.NoError(t, err) 458 itr, err := historydbQE.GetHistoryForKey("ns1", "key1") 459 require.NoError(t, err) 460 kmod, err := itr.Next() 461 require.NoError(t, err) 462 keyModification := kmod.(*queryresult.KeyModification) 463 // despite IsDelete set to "false" in the write-set, historydb results should set this to "true" 464 require.True(t, keyModification.IsDelete) 465 466 kmod, err = itr.Next() 467 require.NoError(t, err) 468 require.Nil(t, kmod) 469 } 470 471 // verify history results 472 func testutilVerifyResults(t *testing.T, hqe ledger.HistoryQueryExecutor, ns, key string, expectedVals []string) { 473 itr, err := hqe.GetHistoryForKey(ns, key) 474 assert.NoError(t, err, "Error upon GetHistoryForKey()") 475 retrievedVals := []string{} 476 for { 477 kmod, _ := itr.Next() 478 if kmod == nil { 479 break 480 } 481 txid := kmod.(*queryresult.KeyModification).TxId 482 retrievedValue := string(kmod.(*queryresult.KeyModification).Value) 483 retrievedVals = append(retrievedVals, retrievedValue) 484 t.Logf("Retrieved history record at TxId=%s with value %s", txid, retrievedValue) 485 } 486 assert.Equal(t, expectedVals, retrievedVals) 487 } 488 489 // testutilCheckKeyNotInRange verifies that a (false) key is not returned in range query when searching for the desired key 490 func testutilCheckKeyNotInRange(t *testing.T, hqe ledger.HistoryQueryExecutor, ns, desiredKey, falseKey string) { 491 itr, err := hqe.GetHistoryForKey(ns, desiredKey) 492 assert.NoError(t, err, "Error upon GetHistoryForKey()") 493 scanner := itr.(*historyScanner) 494 rangeScanKeys := constructRangeScan(ns, falseKey) 495 for { 496 if !scanner.dbItr.Next() { 497 break 498 } 499 historyKey := scanner.dbItr.Key() 500 if bytes.Contains(historyKey, rangeScanKeys.startKey) { 501 assert.Failf(t, "false key %s should not be returned in range query for key %s", falseKey, desiredKey) 502 } 503 } 504 }