package database import ( "os" "testing" "github.com/vapor/config" dbm "github.com/vapor/database/leveldb" "github.com/vapor/database/storage" "github.com/vapor/protocol" "github.com/vapor/protocol/bc" "github.com/vapor/protocol/bc/types" "github.com/vapor/protocol/state" "github.com/vapor/testutil" ) func TestLoadBlockIndex(t *testing.T) { config.CommonConfig = config.DefaultConfig() testDB := dbm.NewDB("testdb", "leveldb", "temp") store := NewStore(testDB) defer func() { testDB.Close() os.RemoveAll("temp") }() block := config.GenesisBlock() txStatus := bc.NewTransactionStatus() if err := store.SaveBlock(block, txStatus); err != nil { t.Fatal(err) } for block.Height <= 128 { preHash := block.Hash() block.PreviousBlockHash = preHash block.Height++ if err := store.SaveBlock(block, txStatus); err != nil { t.Fatal(err) } if block.Height%32 != 0 { continue } for i := uint64(0); i < block.Height/32; i++ { block.Version++ if err := store.SaveBlock(block, txStatus); err != nil { t.Fatal(err) } } } if _, err := store.LoadBlockIndex(128); err != nil { t.Fatal(err) } } func TestLoadBlockIndexBestHeight(t *testing.T) { cases := []struct { blockBestHeight uint64 stateBestHeight uint64 }{ { blockBestHeight: 100, stateBestHeight: 90, }, { blockBestHeight: 100, stateBestHeight: 0, }, { blockBestHeight: 100, stateBestHeight: 100, }, } testDB := dbm.NewDB("testdb", "leveldb", "temp") defer func() { testDB.Close() os.RemoveAll("temp") }() store := NewStore(testDB) var savedBlocks []types.Block for _, c := range cases { block := config.GenesisBlock() txStatus := bc.NewTransactionStatus() for i := uint64(0); i < c.blockBestHeight; i++ { if err := store.SaveBlock(block, txStatus); err != nil { t.Fatal(err) } savedBlocks = append(savedBlocks, *block) block.PreviousBlockHash = block.Hash() block.Height++ } index, err := store.LoadBlockIndex(c.stateBestHeight) if err != nil { t.Fatal(err) } for _, block := range savedBlocks { blockHash := block.Hash() if block.Height <= c.stateBestHeight != index.BlockExist(&blockHash) { t.Errorf("Error in load block index") } } } } func TestLoadBlockIndexEquals(t *testing.T) { testDB := dbm.NewDB("testdb", "leveldb", "temp") store := NewStore(testDB) defer func() { testDB.Close() os.RemoveAll("temp") }() block := config.GenesisBlock() txStatus := bc.NewTransactionStatus() expectBlockIndex := state.NewBlockIndex() var parent *state.BlockNode for block.Height <= 100 { if err := store.SaveBlock(block, txStatus); err != nil { t.Fatal(err) } if block.Height != 0 { parent = expectBlockIndex.GetNode(&block.PreviousBlockHash) } node, err := state.NewBlockNode(&block.BlockHeader, parent) if err != nil { t.Fatal(err) } expectBlockIndex.AddNode(node) block.PreviousBlockHash = block.Hash() block.Height++ } index, err := store.LoadBlockIndex(100) if err != nil { t.Fatal(err) } if !testutil.DeepEqual(expectBlockIndex, index) { t.Errorf("got block index:%v, expect block index:%v", index, expectBlockIndex) } } func TestSaveChainStatus(t *testing.T) { testDB := dbm.NewDB("testdb", "leveldb", "temp") defer func() { testDB.Close() os.RemoveAll("temp") }() store := NewStore(testDB) node := &state.BlockNode{Height: 100, Hash: bc.Hash{V0: 0, V1: 1, V2: 2, V3: 3}} view := &state.UtxoViewpoint{ Entries: map[bc.Hash]*storage.UtxoEntry{ bc.Hash{V0: 1, V1: 2, V2: 3, V3: 4}: &storage.UtxoEntry{Type: storage.NormalUTXOType, BlockHeight: 100, Spent: false}, bc.Hash{V0: 1, V1: 2, V2: 3, V3: 4}: &storage.UtxoEntry{Type: storage.CoinbaseUTXOType, BlockHeight: 100, Spent: true}, bc.Hash{V0: 1, V1: 1, V2: 3, V3: 4}: &storage.UtxoEntry{Type: storage.NormalUTXOType, BlockHeight: 100, Spent: true}, bc.Hash{V0: 1, V1: 1, V2: 3, V3: 5}: &storage.UtxoEntry{Type: storage.CrosschainUTXOType, BlockHeight: 100, Spent: false}, bc.Hash{V0: 1, V1: 1, V2: 3, V3: 6}: &storage.UtxoEntry{Type: storage.CrosschainUTXOType, BlockHeight: 100, Spent: true}, bc.Hash{V0: 1, V1: 3, V2: 3, V3: 7}: &storage.UtxoEntry{Type: storage.VoteUTXOType, BlockHeight: 100, Spent: false}, bc.Hash{V0: 1, V1: 3, V2: 3, V3: 7}: &storage.UtxoEntry{Type: storage.VoteUTXOType, BlockHeight: 100, Spent: true}, }, } if err := store.SaveChainStatus(node, node, view, []*state.VoteResult{}); err != nil { t.Fatal(err) } expectStatus := &protocol.BlockStoreState{Height: node.Height, Hash: &node.Hash, IrreversibleHeight: node.Height, IrreversibleHash: &node.Hash} if !testutil.DeepEqual(store.GetStoreStatus(), expectStatus) { t.Errorf("got block status:%v, expect block status:%v", store.GetStoreStatus(), expectStatus) } for hash, utxo := range view.Entries { if (utxo.Type == storage.NormalUTXOType) && utxo.Spent { continue } if (utxo.Type == storage.CrosschainUTXOType) && (!utxo.Spent) { continue } if (utxo.Type == storage.VoteUTXOType) && (utxo.Spent) { continue } gotUtxo, err := store.GetUtxo(&hash) if err != nil { t.Fatal(err) } if !testutil.DeepEqual(utxo, gotUtxo) { t.Errorf("got utxo entry:%v, expect utxo entry:%v", gotUtxo, utxo) } } } func TestSaveBlock(t *testing.T) { testDB := dbm.NewDB("testdb", "leveldb", "temp") defer func() { testDB.Close() os.RemoveAll("temp") }() store := NewStore(testDB) block := config.GenesisBlock() status := &bc.TransactionStatus{VerifyStatus: []*bc.TxVerifyResult{{StatusFail: true}}} if err := store.SaveBlock(block, status); err != nil { t.Fatal(err) } blockHash := block.Hash() gotBlock, err := store.GetBlock(&blockHash, block.Height) if err != nil { t.Fatal(err) } gotBlock.Transactions[0].Tx.SerializedSize = 0 gotBlock.Transactions[0].SerializedSize = 0 if !testutil.DeepEqual(block, gotBlock) { t.Errorf("got block:%v, expect block:%v", gotBlock, block) } gotStatus, err := store.GetTransactionStatus(&blockHash) if err != nil { t.Fatal(err) } if !testutil.DeepEqual(status, gotStatus) { t.Errorf("got status:%v, expect status:%v", gotStatus, status) } data := store.db.Get(calcBlockHeaderKey(block.Height, &blockHash)) gotBlockHeader := types.BlockHeader{} if err := gotBlockHeader.UnmarshalText(data); err != nil { t.Fatal(err) } if !testutil.DeepEqual(block.BlockHeader, gotBlockHeader) { t.Errorf("got block header:%v, expect block header:%v", gotBlockHeader, block.BlockHeader) } }