github.com/ewagmig/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  }