--- /dev/null
+package test
+
+import (
+ "os"
+ "testing"
+
+ "github.com/bytom/vapor/application/mov"
+ movDatabase "github.com/bytom/vapor/application/mov/database"
+ "github.com/bytom/vapor/database"
+ dbm "github.com/bytom/vapor/database/leveldb"
+ "github.com/bytom/vapor/protocol"
+ "github.com/bytom/vapor/protocol/bc"
+ "github.com/bytom/vapor/protocol/bc/types"
+ "github.com/bytom/vapor/protocol/state"
+ "github.com/bytom/vapor/testutil"
+)
+
+type chainStatus struct {
+ blockHeight uint64
+ blockHash bc.Hash
+}
+
+type chainBlock struct {
+ block *types.Block
+ inMainChain bool
+}
+
+var blocks = map[uint64][]*types.Block{
+ 0: {
+ {
+ BlockHeader: types.BlockHeader{
+ Height: 0,
+ Timestamp: 1585814309,
+ PreviousBlockHash: bc.Hash{},
+ },
+ },
+ },
+ 1: {
+ // prev block is [0][0]
+ {
+ BlockHeader: types.BlockHeader{
+ Height: 1,
+ Timestamp: 1585814310,
+ PreviousBlockHash: testutil.MustDecodeHash("2e5406c82fe34f6ee44fe694b05ffc8fb5918a026415b086df03fb03760b42a9"),
+ },
+ },
+ // prev block is [0][0]
+ {
+ BlockHeader: types.BlockHeader{
+ Height: 1,
+ Timestamp: 1585814311,
+ PreviousBlockHash: testutil.MustDecodeHash("2e5406c82fe34f6ee44fe694b05ffc8fb5918a026415b086df03fb03760b42a9"),
+ },
+ },
+ },
+ 2: {
+ // prev block is [1][0]
+ {
+ BlockHeader: types.BlockHeader{
+ Height: 2,
+ Timestamp: 1585814320,
+ PreviousBlockHash: testutil.MustDecodeHash("5bc198f4c0198e7e8b52173a82836cfd3f124d88bf052f53390948d845bf6fe0"),
+ },
+ },
+ },
+}
+
+func TestSyncProtocolStatus(t *testing.T) {
+ cases := []struct {
+ desc string
+ savedBlocks []*chainBlock
+ startHeight uint64
+ startHash *bc.Hash
+ wantChainStatus *chainStatus
+ }{
+ {
+ desc: "start height from 0, mov is not init",
+ savedBlocks: []*chainBlock{
+ {
+ block: blocks[0][0],
+ inMainChain: true,
+ },
+ {
+ block: blocks[1][0],
+ inMainChain: true,
+ },
+ {
+ block: blocks[2][0],
+ inMainChain: true,
+ },
+ },
+ startHeight: 0,
+ wantChainStatus: &chainStatus{
+ blockHeight: 2,
+ blockHash: blocks[2][0].Hash(),
+ },
+ },
+ {
+ desc: "start height from 1, mov is not init",
+ savedBlocks: []*chainBlock{
+ {
+ block: blocks[0][0],
+ inMainChain: true,
+ },
+ {
+ block: blocks[1][0],
+ inMainChain: true,
+ },
+ {
+ block: blocks[2][0],
+ inMainChain: true,
+ },
+ },
+ startHeight: 1,
+ wantChainStatus: &chainStatus{
+ blockHeight: 2,
+ blockHash: blocks[2][0].Hash(),
+ },
+ },
+ {
+ desc: "start height from 1, state of mov is not sync completed",
+ savedBlocks: []*chainBlock{
+ {
+ block: blocks[0][0],
+ inMainChain: true,
+ },
+ {
+ block: blocks[1][0],
+ inMainChain: true,
+ },
+ {
+ block: blocks[2][0],
+ inMainChain: true,
+ },
+ },
+ startHeight: 1,
+ startHash: hashPtr(blocks[1][0].Hash()),
+ wantChainStatus: &chainStatus{
+ blockHeight: 2,
+ blockHash: blocks[2][0].Hash(),
+ },
+ },
+ {
+ desc: "chain status of mov is forked",
+ savedBlocks: []*chainBlock{
+ {
+ block: blocks[0][0],
+ inMainChain: true,
+ },
+ {
+ block: blocks[1][0],
+ inMainChain: true,
+ },
+ {
+ block: blocks[1][1],
+ inMainChain: false,
+ },
+ {
+ block: blocks[2][0],
+ inMainChain: true,
+ },
+ },
+ startHeight: 1,
+ startHash: hashPtr(blocks[1][1].Hash()),
+ wantChainStatus: &chainStatus{
+ blockHeight: 2,
+ blockHash: blocks[2][0].Hash(),
+ },
+ },
+ }
+
+ defer os.RemoveAll("temp")
+
+ for i, c := range cases {
+ chainDB := dbm.NewDB("core", "leveldb", "temp")
+ store := database.NewStore(chainDB)
+ if err := initStore(store, c.savedBlocks); err != nil {
+ t.Fatal(err)
+ }
+
+ movDB := dbm.NewDB("mov", "leveldb", "temp")
+ movCore := mov.NewCoreWithDB(movDatabase.NewLevelDBMovStore(movDB), c.startHeight)
+ if c.startHash != nil {
+ if err := movCore.InitChainStatus(c.startHash); err != nil {
+ t.Fatal(err)
+ }
+ }
+
+ _, err := protocol.NewChain(store, nil, []protocol.SubProtocol{movCore}, nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ gotHeight, gotHash, err := movCore.ChainStatus()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if gotHeight != c.wantChainStatus.blockHeight || *gotHash != c.wantChainStatus.blockHash {
+ t.Logf("#%d(%s): got chain status of sub protocol is not equals want chain status", i, c.desc)
+ }
+
+ movDB.Close()
+ chainDB.Close()
+ os.RemoveAll("temp")
+ }
+}
+
+func initStore(store *database.Store, savedBlocks []*chainBlock) error {
+ var mainBlockHeaders []*types.BlockHeader
+ for _, block := range savedBlocks {
+ if err := store.SaveBlock(block.block, bc.NewTransactionStatus()); err != nil {
+ return err
+ }
+
+ if block.inMainChain {
+ mainBlockHeaders = append(mainBlockHeaders, &block.block.BlockHeader)
+ }
+
+ last := len(mainBlockHeaders) - 1
+ if err := store.SaveChainStatus(mainBlockHeaders[last], mainBlockHeaders[last], mainBlockHeaders, state.NewUtxoViewpoint(), nil); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func hashPtr(hash bc.Hash) *bc.Hash {
+ return &hash
+}
+
+func TestBlockHash(t *testing.T) {
+ blockHash := blocks[1][0].Hash()
+ t.Log(blockHash.String())
+}