github.com/true-sqn/fabric@v2.1.1+incompatible/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/hyperledger/fabric-protos-go/common" 17 "github.com/hyperledger/fabric-protos-go/ledger/queryresult" 18 "github.com/hyperledger/fabric-protos-go/peer" 19 configtxtest "github.com/hyperledger/fabric/common/configtx/test" 20 "github.com/hyperledger/fabric/common/flogging" 21 "github.com/hyperledger/fabric/common/ledger/testutil" 22 util2 "github.com/hyperledger/fabric/common/util" 23 "github.com/hyperledger/fabric/core/ledger" 24 "github.com/hyperledger/fabric/core/ledger/util" 25 "github.com/stretchr/testify/assert" 26 ) 27 28 func TestMain(m *testing.M) { 29 flogging.ActivateSpec("leveldbhelper,history=debug") 30 os.Exit(m.Run()) 31 } 32 33 //TestSavepoint tests that save points get written after each block and get returned via GetBlockNumfromSavepoint 34 func TestSavepoint(t *testing.T) { 35 env := newTestHistoryEnv(t) 36 defer env.cleanup() 37 38 // read the savepoint, it should not exist and should return nil Height object 39 savepoint, err := env.testHistoryDB.GetLastSavepoint() 40 assert.NoError(t, err, "Error upon historyDatabase.GetLastSavepoint()") 41 assert.Nil(t, savepoint) 42 43 // ShouldRecover should return true when no savepoint is found and recovery from block 0 44 status, blockNum, err := env.testHistoryDB.ShouldRecover(0) 45 assert.NoError(t, err, "Error upon historyDatabase.ShouldRecover()") 46 assert.True(t, status) 47 assert.Equal(t, uint64(0), blockNum) 48 49 bg, gb := testutil.NewBlockGenerator(t, "testLedger", false) 50 assert.NoError(t, env.testHistoryDB.Commit(gb)) 51 // read the savepoint, it should now exist and return a Height object with BlockNum 0 52 savepoint, err = env.testHistoryDB.GetLastSavepoint() 53 assert.NoError(t, err, "Error upon historyDatabase.GetLastSavepoint()") 54 assert.Equal(t, uint64(0), savepoint.BlockNum) 55 56 // create the next block (block 1) 57 txid := util2.GenerateUUID() 58 simulator, _ := env.txmgr.NewTxSimulator(txid) 59 simulator.SetState("ns1", "key1", []byte("value1")) 60 simulator.Done() 61 simRes, _ := simulator.GetTxSimulationResults() 62 pubSimResBytes, _ := simRes.GetPubSimulationBytes() 63 block1 := bg.NextBlock([][]byte{pubSimResBytes}) 64 assert.NoError(t, env.testHistoryDB.Commit(block1)) 65 savepoint, err = env.testHistoryDB.GetLastSavepoint() 66 assert.NoError(t, err, "Error upon historyDatabase.GetLastSavepoint()") 67 assert.Equal(t, uint64(1), savepoint.BlockNum) 68 69 // Should Recover should return false 70 status, blockNum, err = env.testHistoryDB.ShouldRecover(1) 71 assert.NoError(t, err, "Error upon historyDatabase.ShouldRecover()") 72 assert.False(t, status) 73 assert.Equal(t, uint64(2), blockNum) 74 75 // create the next block (block 2) 76 txid = util2.GenerateUUID() 77 simulator, _ = env.txmgr.NewTxSimulator(txid) 78 simulator.SetState("ns1", "key1", []byte("value2")) 79 simulator.Done() 80 simRes, _ = simulator.GetTxSimulationResults() 81 pubSimResBytes, _ = simRes.GetPubSimulationBytes() 82 block2 := bg.NextBlock([][]byte{pubSimResBytes}) 83 84 // assume that the peer failed to commit this block to historyDB and is being recovered now 85 env.testHistoryDB.CommitLostBlock(&ledger.BlockAndPvtData{Block: block2}) 86 savepoint, err = env.testHistoryDB.GetLastSavepoint() 87 assert.NoError(t, err, "Error upon historyDatabase.GetLastSavepoint()") 88 assert.Equal(t, uint64(2), savepoint.BlockNum) 89 90 //Pass high blockNum, ShouldRecover should return true with 3 as blocknum to recover from 91 status, blockNum, err = env.testHistoryDB.ShouldRecover(10) 92 assert.NoError(t, err, "Error upon historyDatabase.ShouldRecover()") 93 assert.True(t, status) 94 assert.Equal(t, uint64(3), blockNum) 95 } 96 97 func TestHistory(t *testing.T) { 98 env := newTestHistoryEnv(t) 99 defer env.cleanup() 100 provider := env.testBlockStorageEnv.provider 101 ledger1id := "ledger1" 102 store1, err := provider.OpenBlockStore(ledger1id) 103 assert.NoError(t, err, "Error upon provider.OpenBlockStore()") 104 defer store1.Shutdown() 105 assert.Equal(t, "history", env.testHistoryDB.Name()) 106 107 bg, gb := testutil.NewBlockGenerator(t, ledger1id, false) 108 assert.NoError(t, store1.AddBlock(gb)) 109 assert.NoError(t, env.testHistoryDB.Commit(gb)) 110 111 //block1 112 txid := util2.GenerateUUID() 113 simulator, _ := env.txmgr.NewTxSimulator(txid) 114 value1 := []byte("value1") 115 simulator.SetState("ns1", "key7", value1) 116 simulator.Done() 117 simRes, _ := simulator.GetTxSimulationResults() 118 pubSimResBytes, _ := simRes.GetPubSimulationBytes() 119 block1 := bg.NextBlock([][]byte{pubSimResBytes}) 120 err = store1.AddBlock(block1) 121 assert.NoError(t, err) 122 err = env.testHistoryDB.Commit(block1) 123 assert.NoError(t, err) 124 125 //block2 tran1 126 simulationResults := [][]byte{} 127 txid = util2.GenerateUUID() 128 simulator, _ = env.txmgr.NewTxSimulator(txid) 129 value2 := []byte("value2") 130 simulator.SetState("ns1", "key7", value2) 131 simulator.Done() 132 simRes, _ = simulator.GetTxSimulationResults() 133 pubSimResBytes, _ = simRes.GetPubSimulationBytes() 134 simulationResults = append(simulationResults, pubSimResBytes) 135 //block2 tran2 136 txid2 := util2.GenerateUUID() 137 simulator2, _ := env.txmgr.NewTxSimulator(txid2) 138 value3 := []byte("value3") 139 simulator2.SetState("ns1", "key7", value3) 140 simulator2.Done() 141 simRes2, _ := simulator2.GetTxSimulationResults() 142 pubSimResBytes2, _ := simRes2.GetPubSimulationBytes() 143 simulationResults = append(simulationResults, pubSimResBytes2) 144 block2 := bg.NextBlock(simulationResults) 145 err = store1.AddBlock(block2) 146 assert.NoError(t, err) 147 err = env.testHistoryDB.Commit(block2) 148 assert.NoError(t, err) 149 150 //block3 151 txid = util2.GenerateUUID() 152 simulator, _ = env.txmgr.NewTxSimulator(txid) 153 simulator.DeleteState("ns1", "key7") 154 simulator.Done() 155 simRes, _ = simulator.GetTxSimulationResults() 156 pubSimResBytes, _ = simRes.GetPubSimulationBytes() 157 block3 := bg.NextBlock([][]byte{pubSimResBytes}) 158 err = store1.AddBlock(block3) 159 assert.NoError(t, err) 160 err = env.testHistoryDB.Commit(block3) 161 assert.NoError(t, err) 162 t.Logf("Inserted all 3 blocks") 163 164 qhistory, err := env.testHistoryDB.NewQueryExecutor(store1) 165 assert.NoError(t, err, "Error upon NewQueryExecutor") 166 167 itr, err2 := qhistory.GetHistoryForKey("ns1", "key7") 168 assert.NoError(t, err2, "Error upon GetHistoryForKey()") 169 170 count := 0 171 for { 172 // iterator will return entries in the order of newest to oldest 173 kmod, _ := itr.Next() 174 if kmod == nil { 175 break 176 } 177 txid = kmod.(*queryresult.KeyModification).TxId 178 retrievedValue := kmod.(*queryresult.KeyModification).Value 179 retrievedTimestamp := kmod.(*queryresult.KeyModification).Timestamp 180 retrievedIsDelete := kmod.(*queryresult.KeyModification).IsDelete 181 t.Logf("Retrieved history record for key=key7 at TxId=%s with value %v and timestamp %v", 182 txid, retrievedValue, retrievedTimestamp) 183 count++ 184 if count != 1 { 185 // entries 2, 3, 4 are block2:tran2, block2:tran1 and block1:tran1 186 expectedValue := []byte("value" + strconv.Itoa(5-count)) 187 assert.Equal(t, expectedValue, retrievedValue) 188 assert.NotNil(t, retrievedTimestamp) 189 assert.False(t, retrievedIsDelete) 190 } else { 191 // entry 1 is block3:tran1 192 assert.Equal(t, []uint8(nil), retrievedValue) 193 assert.NotNil(t, retrievedTimestamp) 194 assert.True(t, retrievedIsDelete) 195 } 196 } 197 assert.Equal(t, 4, count) 198 } 199 200 func TestHistoryForInvalidTran(t *testing.T) { 201 env := newTestHistoryEnv(t) 202 defer env.cleanup() 203 provider := env.testBlockStorageEnv.provider 204 ledger1id := "ledger1" 205 store1, err := provider.OpenBlockStore(ledger1id) 206 assert.NoError(t, err, "Error upon provider.OpenBlockStore()") 207 defer store1.Shutdown() 208 209 bg, gb := testutil.NewBlockGenerator(t, ledger1id, false) 210 assert.NoError(t, store1.AddBlock(gb)) 211 assert.NoError(t, env.testHistoryDB.Commit(gb)) 212 213 //block1 214 txid := util2.GenerateUUID() 215 simulator, _ := env.txmgr.NewTxSimulator(txid) 216 value1 := []byte("value1") 217 simulator.SetState("ns1", "key7", value1) 218 simulator.Done() 219 simRes, _ := simulator.GetTxSimulationResults() 220 pubSimResBytes, _ := simRes.GetPubSimulationBytes() 221 block1 := bg.NextBlock([][]byte{pubSimResBytes}) 222 223 //for this invalid tran test, set the transaction to invalid 224 txsFilter := util.TxValidationFlags(block1.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER]) 225 txsFilter.SetFlag(0, peer.TxValidationCode_INVALID_OTHER_REASON) 226 block1.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER] = txsFilter 227 228 err = store1.AddBlock(block1) 229 assert.NoError(t, err) 230 err = env.testHistoryDB.Commit(block1) 231 assert.NoError(t, err) 232 233 qhistory, err := env.testHistoryDB.NewQueryExecutor(store1) 234 assert.NoError(t, err, "Error upon NewQueryExecutor") 235 236 itr, err2 := qhistory.GetHistoryForKey("ns1", "key7") 237 assert.NoError(t, err2, "Error upon GetHistoryForKey()") 238 239 // test that there are no history values, since the tran was marked as invalid 240 kmod, _ := itr.Next() 241 assert.Nil(t, kmod) 242 } 243 244 //TestGenesisBlockNoError tests that Genesis blocks are ignored by history processing 245 // since we only persist history of chaincode key writes 246 func TestGenesisBlockNoError(t *testing.T) { 247 env := newTestHistoryEnv(t) 248 defer env.cleanup() 249 block, err := configtxtest.MakeGenesisBlock("test_chainid") 250 assert.NoError(t, err) 251 err = env.testHistoryDB.Commit(block) 252 assert.NoError(t, err) 253 } 254 255 // TestHistoryWithKeyContainingNilBytes tests historydb when keys contains nil bytes (FAB-11244) - 256 // which happens to be used as a separator in the composite keys that is formed for the entries in the historydb 257 func TestHistoryWithKeyContainingNilBytes(t *testing.T) { 258 env := newTestHistoryEnv(t) 259 defer env.cleanup() 260 provider := env.testBlockStorageEnv.provider 261 ledger1id := "ledger1" 262 store1, err := provider.OpenBlockStore(ledger1id) 263 assert.NoError(t, err, "Error upon provider.OpenBlockStore()") 264 defer store1.Shutdown() 265 266 bg, gb := testutil.NewBlockGenerator(t, ledger1id, false) 267 assert.NoError(t, store1.AddBlock(gb)) 268 assert.NoError(t, env.testHistoryDB.Commit(gb)) 269 270 //block1 271 txid := util2.GenerateUUID() 272 simulator, _ := env.txmgr.NewTxSimulator(txid) 273 simulator.SetState("ns1", "key", []byte("value1")) // add a key <key> that contains no nil byte 274 simulator.Done() 275 simRes, _ := simulator.GetTxSimulationResults() 276 pubSimResBytes, _ := simRes.GetPubSimulationBytes() 277 block1 := bg.NextBlock([][]byte{pubSimResBytes}) 278 err = store1.AddBlock(block1) 279 assert.NoError(t, err) 280 err = env.testHistoryDB.Commit(block1) 281 assert.NoError(t, err) 282 283 //block2 tran1 284 simulationResults := [][]byte{} 285 txid = util2.GenerateUUID() 286 simulator, _ = env.txmgr.NewTxSimulator(txid) 287 simulator.SetState("ns1", "key", []byte("value2")) // add another value for the key <key> 288 simulator.Done() 289 simRes, _ = simulator.GetTxSimulationResults() 290 pubSimResBytes, _ = simRes.GetPubSimulationBytes() 291 simulationResults = append(simulationResults, pubSimResBytes) 292 293 //block2 tran2 294 txid2 := util2.GenerateUUID() 295 simulator2, _ := env.txmgr.NewTxSimulator(txid2) 296 297 // key1 should not fall in the range 298 key1 := "\x00key\x00\x01\x01\x15" 299 simulator2.SetState("ns1", key1, []byte("dummyVal1")) 300 301 // add other keys that contain nil byte(s) - such that when a range query is formed, these keys fall in the range 302 // key2 is skipped due to tran num decoding error (decode size 21 > 8) 303 // blockNumTranNumBytes are 0x1, 0x1, 0x15, 0x0 (separator), 0x1, 0x2, 0x1, 0x1 304 key2 := "key\x00\x01\x01\x15" // \x15 is 21 305 simulator2.SetState("ns1", key2, []byte("dummyVal2")) 306 307 // key3 is skipped due to block num decoding error (decoded size 12 > 8) 308 // blockNumTranNumBytes are 0xc, 0x0 (separtor), 0x1, 0x2, 0x1, 0x1 309 key3 := "key\x00\x0c" // \x0c is 12 310 simulator2.SetState("ns1", key3, []byte("dummyVal3")) 311 312 // key4 is skipped because blockBytesConsumed (2) + tranBytesConsumed (2) != len(blockNumTranNum) (6) 313 // blockNumTranNumBytes are 0x1, 0x0 (separator), 0x1, 0x2, 0x1, 0x1 314 key4 := "key\x00\x01" 315 simulator2.SetState("ns1", key4, []byte("dummyVal4")) 316 317 // key5 is skipped due to ErrNotFoundInIndex, where history key is <ns, key\x00\x04\x01, 2, 1>, same as <ns, key, 16777474, 1>. 318 // blockNumTranNumBytes are 0x4, 0x1, 0x0 (separator), 0x1, 0x2, 0x1, 0x1 319 key5 := "key\x00\x04\x01" 320 simulator2.SetState("ns1", key5, []byte("dummyVal5")) 321 322 // commit block2 323 simulator2.Done() 324 simRes2, _ := simulator2.GetTxSimulationResults() 325 pubSimResBytes2, _ := simRes2.GetPubSimulationBytes() 326 simulationResults = append(simulationResults, pubSimResBytes2) 327 block2 := bg.NextBlock(simulationResults) 328 err = store1.AddBlock(block2) 329 assert.NoError(t, err) 330 err = env.testHistoryDB.Commit(block2) 331 assert.NoError(t, err) 332 333 qhistory, err := env.testHistoryDB.NewQueryExecutor(store1) 334 assert.NoError(t, err, "Error upon NewQueryExecutor") 335 336 // verify the results for each key, in the order of newest to oldest 337 testutilVerifyResults(t, qhistory, "ns1", "key", []string{"value2", "value1"}) 338 testutilVerifyResults(t, qhistory, "ns1", key1, []string{"dummyVal1"}) 339 testutilVerifyResults(t, qhistory, "ns1", key2, []string{"dummyVal2"}) 340 testutilVerifyResults(t, qhistory, "ns1", key3, []string{"dummyVal3"}) 341 testutilVerifyResults(t, qhistory, "ns1", key4, []string{"dummyVal4"}) 342 testutilVerifyResults(t, qhistory, "ns1", key5, []string{"dummyVal5"}) 343 344 // verify none of key1-key5 falls in the range of history query for "key" 345 testutilCheckKeyNotInRange(t, qhistory, "ns1", "key", key1) 346 testutilCheckKeyNotInRange(t, qhistory, "ns1", "key", key2) 347 testutilCheckKeyNotInRange(t, qhistory, "ns1", "key", key3) 348 testutilCheckKeyNotInRange(t, qhistory, "ns1", "key", key4) 349 testutilCheckKeyNotInRange(t, qhistory, "ns1", "key", key5) 350 } 351 352 // TestHistoryWithBlockNumber256 creates 256 blocks and then 353 // queries historydb to verify that all 256 blocks are returned in the right orderer. 354 // This test also verifies that block256 is returned correctly even if its key contains nil byte. 355 func TestHistoryWithBlockNumber256(t *testing.T) { 356 env := newTestHistoryEnv(t) 357 defer env.cleanup() 358 provider := env.testBlockStorageEnv.provider 359 ledger1id := "ledger1" 360 store1, err := provider.OpenBlockStore(ledger1id) 361 assert.NoError(t, err, "Error upon provider.OpenBlockStore()") 362 defer store1.Shutdown() 363 364 bg, gb := testutil.NewBlockGenerator(t, ledger1id, false) 365 assert.NoError(t, store1.AddBlock(gb)) 366 assert.NoError(t, env.testHistoryDB.Commit(gb)) 367 368 // add 256 blocks, each block has 1 transaction setting state for "ns1" and "key", value is "value<blockNum>" 369 for i := 1; i <= 256; i++ { 370 txid := util2.GenerateUUID() 371 simulator, _ := env.txmgr.NewTxSimulator(txid) 372 value := fmt.Sprintf("value%d", i) 373 simulator.SetState("ns1", "key", []byte(value)) 374 simulator.Done() 375 simRes, _ := simulator.GetTxSimulationResults() 376 pubSimResBytes, _ := simRes.GetPubSimulationBytes() 377 block := bg.NextBlock([][]byte{pubSimResBytes}) 378 err = store1.AddBlock(block) 379 assert.NoError(t, err) 380 err = env.testHistoryDB.Commit(block) 381 assert.NoError(t, err) 382 } 383 384 // query history db for "ns1", "key" 385 qhistory, err := env.testHistoryDB.NewQueryExecutor(store1) 386 assert.NoError(t, err, "Error upon NewQueryExecutor") 387 388 // verify history query returns the expected results in the orderer of block256, 255, 254 .... 1. 389 expectedHistoryResults := make([]string, 0) 390 for i := 256; i >= 1; i-- { 391 expectedHistoryResults = append(expectedHistoryResults, fmt.Sprintf("value%d", i)) 392 } 393 testutilVerifyResults(t, qhistory, "ns1", "key", expectedHistoryResults) 394 } 395 396 func TestName(t *testing.T) { 397 env := newTestHistoryEnv(t) 398 defer env.cleanup() 399 assert.Equal(t, "history", env.testHistoryDB.Name()) 400 } 401 402 // verify history results 403 func testutilVerifyResults(t *testing.T, hqe ledger.HistoryQueryExecutor, ns, key string, expectedVals []string) { 404 itr, err := hqe.GetHistoryForKey(ns, key) 405 assert.NoError(t, err, "Error upon GetHistoryForKey()") 406 retrievedVals := []string{} 407 for { 408 kmod, _ := itr.Next() 409 if kmod == nil { 410 break 411 } 412 txid := kmod.(*queryresult.KeyModification).TxId 413 retrievedValue := string(kmod.(*queryresult.KeyModification).Value) 414 retrievedVals = append(retrievedVals, retrievedValue) 415 t.Logf("Retrieved history record at TxId=%s with value %s", txid, retrievedValue) 416 } 417 assert.Equal(t, expectedVals, retrievedVals) 418 } 419 420 // testutilCheckKeyNotInRange verifies that a (false) key is not returned in range query when searching for the desired key 421 func testutilCheckKeyNotInRange(t *testing.T, hqe ledger.HistoryQueryExecutor, ns, desiredKey, falseKey string) { 422 itr, err := hqe.GetHistoryForKey(ns, desiredKey) 423 assert.NoError(t, err, "Error upon GetHistoryForKey()") 424 scanner := itr.(*historyScanner) 425 rangeScanKeys := constructRangeScan(ns, falseKey) 426 for { 427 if !scanner.dbItr.Next() { 428 break 429 } 430 historyKey := scanner.dbItr.Key() 431 if bytes.Contains(historyKey, rangeScanKeys.startKey) { 432 assert.Failf(t, "false key %s should not be returned in range query for key %s", falseKey, desiredKey) 433 } 434 } 435 }