github.com/iotexproject/iotex-core@v1.14.1-rc1/e2etest/local_test.go (about)

     1  // Copyright (c) 2019 IoTeX Foundation
     2  // This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability
     3  // or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed.
     4  // This source code is governed by Apache License 2.0 that can be found in the LICENSE file.
     5  
     6  package e2etest
     7  
     8  import (
     9  	"context"
    10  	"math/big"
    11  	"strings"
    12  	"testing"
    13  	"time"
    14  
    15  	"github.com/libp2p/go-libp2p-core/peer"
    16  	"github.com/multiformats/go-multiaddr"
    17  	"github.com/stretchr/testify/require"
    18  	"google.golang.org/protobuf/proto"
    19  
    20  	"github.com/iotexproject/go-pkgs/crypto"
    21  	"github.com/iotexproject/go-pkgs/hash"
    22  
    23  	"github.com/iotexproject/iotex-core/action"
    24  	"github.com/iotexproject/iotex-core/action/protocol"
    25  	"github.com/iotexproject/iotex-core/action/protocol/account"
    26  	accountutil "github.com/iotexproject/iotex-core/action/protocol/account/util"
    27  	"github.com/iotexproject/iotex-core/action/protocol/rewarding"
    28  	"github.com/iotexproject/iotex-core/action/protocol/rolldpos"
    29  	"github.com/iotexproject/iotex-core/actpool"
    30  	"github.com/iotexproject/iotex-core/blockchain"
    31  	"github.com/iotexproject/iotex-core/blockchain/block"
    32  	"github.com/iotexproject/iotex-core/blockchain/blockdao"
    33  	"github.com/iotexproject/iotex-core/blockchain/filedao"
    34  	"github.com/iotexproject/iotex-core/blockchain/genesis"
    35  	"github.com/iotexproject/iotex-core/config"
    36  	"github.com/iotexproject/iotex-core/db"
    37  	"github.com/iotexproject/iotex-core/p2p"
    38  	"github.com/iotexproject/iotex-core/pkg/unit"
    39  	"github.com/iotexproject/iotex-core/server/itx"
    40  	"github.com/iotexproject/iotex-core/state/factory"
    41  	"github.com/iotexproject/iotex-core/test/identityset"
    42  	"github.com/iotexproject/iotex-core/testutil"
    43  )
    44  
    45  const (
    46  	_dBPath     = "db.test"
    47  	_dBPath2    = "db.test2"
    48  	_triePath   = "trie.test"
    49  	_triePath2  = "trie.test2"
    50  	_disabledIP = "169.254."
    51  )
    52  
    53  func TestLocalCommit(t *testing.T) {
    54  	require := require.New(t)
    55  
    56  	cfg, err := newTestConfig()
    57  	require.NoError(err)
    58  	testTriePath, err := testutil.PathOfTempFile(_triePath)
    59  	require.NoError(err)
    60  	testDBPath, err := testutil.PathOfTempFile(_dBPath)
    61  	require.NoError(err)
    62  	indexDBPath, err := testutil.PathOfTempFile(_dBPath)
    63  	require.NoError(err)
    64  	contractIndexDBPath, err := testutil.PathOfTempFile(_dBPath)
    65  	require.NoError(err)
    66  	indexSGDDBPath, err := testutil.PathOfTempFile(_dBPath + "_sgd")
    67  	require.NoError(err)
    68  	cfg.Chain.TrieDBPatchFile = ""
    69  	cfg.Chain.TrieDBPath = testTriePath
    70  	cfg.Chain.ChainDBPath = testDBPath
    71  	cfg.Chain.IndexDBPath = indexDBPath
    72  	cfg.Chain.ContractStakingIndexDBPath = contractIndexDBPath
    73  	cfg.Chain.SGDIndexDBPath = indexSGDDBPath
    74  	defer func() {
    75  		testutil.CleanupPath(testTriePath)
    76  		testutil.CleanupPath(testDBPath)
    77  		testutil.CleanupPath(indexDBPath)
    78  		testutil.CleanupPath(contractIndexDBPath)
    79  		testutil.CleanupPath(indexSGDDBPath)
    80  	}()
    81  
    82  	// create server
    83  	ctx := genesis.WithGenesisContext(context.Background(), cfg.Genesis)
    84  	svr, err := itx.NewServer(cfg)
    85  	require.NoError(err)
    86  	require.NoError(svr.Start(ctx))
    87  	defer func() {
    88  		require.NoError(svr.Stop(ctx))
    89  	}()
    90  	cs := svr.ChainService(cfg.Chain.ID)
    91  	bc := cs.Blockchain()
    92  	sf := cs.StateFactory()
    93  	ap := cs.ActionPool()
    94  	require.NotNil(bc)
    95  	require.NotNil(sf)
    96  	require.NotNil(ap)
    97  
    98  	i27State, err := accountutil.AccountState(ctx, sf, identityset.Address(27))
    99  	require.NoError(err)
   100  	require.NoError(addTestingTsfBlocks(bc, ap))
   101  	require.EqualValues(5, bc.TipHeight())
   102  
   103  	// check balance
   104  	change := &big.Int{}
   105  	for _, v := range []struct {
   106  		addrIndex int
   107  		balance   string
   108  	}{
   109  		{28, "23"},
   110  		{29, "34"},
   111  		{30, "47"},
   112  		{31, "69"},
   113  		{32, "100"},
   114  		{33, "5242883"},
   115  	} {
   116  		s, err := accountutil.AccountState(ctx, sf, identityset.Address(v.addrIndex))
   117  		require.NoError(err)
   118  		require.Equal(v.balance, s.Balance.String())
   119  		change.Add(change, s.Balance)
   120  	}
   121  	s, err := accountutil.AccountState(ctx, sf, identityset.Address(27))
   122  	require.NoError(err)
   123  	change.Add(change, s.Balance)
   124  	change.Sub(change, i27State.Balance)
   125  	require.Equal(unit.ConvertIotxToRau(90000000), change)
   126  
   127  	// create client
   128  	cfg, err = newTestConfig()
   129  	require.NoError(err)
   130  	addrs, err := svr.P2PAgent().Self()
   131  	require.NoError(err)
   132  	cfg.Network.BootstrapNodes = []string{validNetworkAddr(addrs)}
   133  	p := p2p.NewAgent(
   134  		cfg.Network,
   135  		cfg.Chain.ID,
   136  		cfg.Genesis.Hash(),
   137  		func(_ context.Context, _ uint32, _ string, _ proto.Message) {
   138  		},
   139  		func(_ context.Context, _ uint32, _ peer.AddrInfo, _ proto.Message) {
   140  		},
   141  	)
   142  	require.NotNil(p)
   143  	require.NoError(p.Start(ctx))
   144  	defer func() {
   145  		require.NoError(p.Stop(ctx))
   146  	}()
   147  
   148  	// create local chain
   149  	testTriePath2, err := testutil.PathOfTempFile(_triePath2)
   150  	require.NoError(err)
   151  	testDBPath2, err := testutil.PathOfTempFile(_dBPath2)
   152  	require.NoError(err)
   153  	indexDBPath2, err := testutil.PathOfTempFile(_dBPath2)
   154  	require.NoError(err)
   155  	defer func() {
   156  		testutil.CleanupPath(testTriePath2)
   157  		testutil.CleanupPath(testDBPath2)
   158  		testutil.CleanupPath(indexDBPath2)
   159  	}()
   160  	cfg.Chain.TrieDBPath = testTriePath2
   161  	cfg.Chain.ChainDBPath = testDBPath2
   162  	cfg.Chain.IndexDBPath = indexDBPath2
   163  	require.NoError(copyDB(testTriePath, testTriePath2))
   164  	require.NoError(copyDB(testDBPath, testDBPath2))
   165  	require.NoError(copyDB(indexDBPath, indexDBPath2))
   166  	registry := protocol.NewRegistry()
   167  	factoryCfg := factory.GenerateConfig(cfg.Chain, cfg.Genesis)
   168  	db1, err := db.CreateKVStoreWithCache(cfg.DB, cfg.Chain.TrieDBPath, cfg.Chain.StateDBCacheSize)
   169  	require.NoError(err)
   170  	sf2, err := factory.NewStateDB(factoryCfg, db1, factory.RegistryStateDBOption(registry))
   171  	require.NoError(err)
   172  	ap2, err := actpool.NewActPool(cfg.Genesis, sf2, cfg.ActPool)
   173  	require.NoError(err)
   174  	dbcfg := cfg.DB
   175  	dbcfg.DbPath = cfg.Chain.ChainDBPath
   176  	store, err := filedao.NewFileDAO(dbcfg, block.NewDeserializer(cfg.Chain.EVMNetworkID))
   177  	require.NoError(err)
   178  	dao := blockdao.NewBlockDAOWithIndexersAndCache(store, []blockdao.BlockIndexer{sf2}, dbcfg.MaxCacheSize)
   179  	chain := blockchain.NewBlockchain(
   180  		cfg.Chain,
   181  		cfg.Genesis,
   182  		dao,
   183  		factory.NewMinter(sf2, ap2),
   184  		blockchain.BlockValidatorOption(block.NewValidator(
   185  			sf2,
   186  			protocol.NewGenericValidator(sf2, accountutil.AccountState),
   187  		)),
   188  	)
   189  	rolldposProtocol := rolldpos.NewProtocol(
   190  		cfg.Genesis.NumCandidateDelegates,
   191  		cfg.Genesis.NumDelegates,
   192  		cfg.Genesis.NumSubEpochs,
   193  	)
   194  	require.NoError(rolldposProtocol.Register(registry))
   195  	rewardingProtocol := rewarding.NewProtocol(cfg.Genesis.Rewarding)
   196  	require.NoError(rewardingProtocol.Register(registry))
   197  	acc := account.NewProtocol(rewarding.DepositGas)
   198  	require.NoError(acc.Register(registry))
   199  	require.NoError(chain.Start(ctx))
   200  	require.EqualValues(5, chain.TipHeight())
   201  	defer func() {
   202  		require.NoError(chain.Stop(ctx))
   203  	}()
   204  
   205  	// transfer 1
   206  	// C --> A
   207  	s, _ = accountutil.AccountState(ctx, sf, identityset.Address(30))
   208  	tsf1, err := action.SignedTransfer(identityset.Address(28).String(), identityset.PrivateKey(30), s.PendingNonce(), big.NewInt(1), []byte{}, 100000, big.NewInt(0))
   209  	require.NoError(err)
   210  
   211  	require.NoError(ap2.Add(context.Background(), tsf1))
   212  	act1 := tsf1.Proto()
   213  	err = testutil.WaitUntil(10*time.Millisecond, 2*time.Second, func() (bool, error) {
   214  		if err := p.BroadcastOutbound(ctx, act1); err != nil {
   215  			return false, err
   216  		}
   217  		acts := ap.PendingActionMap()
   218  		return lenPendingActionMap(acts) == 1, nil
   219  	})
   220  	require.NoError(err)
   221  
   222  	blk1, err := chain.MintNewBlock(testutil.TimestampNow())
   223  	require.NoError(err)
   224  	require.NoError(chain.CommitBlock(blk1))
   225  
   226  	// transfer 2
   227  	// F --> D
   228  	s, _ = accountutil.AccountState(ctx, sf, identityset.Address(33))
   229  	tsf2, err := action.SignedTransfer(identityset.Address(31).String(), identityset.PrivateKey(33), s.PendingNonce(), big.NewInt(1), []byte{}, 100000, big.NewInt(0))
   230  	require.NoError(err)
   231  
   232  	require.NoError(ap2.Add(context.Background(), tsf2))
   233  	blk2, err := chain.MintNewBlock(testutil.TimestampNow())
   234  	require.NoError(err)
   235  	require.NoError(chain.CommitBlock(blk2))
   236  	// broadcast to P2P
   237  	act2 := tsf2.Proto()
   238  	err = testutil.WaitUntil(100*time.Millisecond, 60*time.Second, func() (bool, error) {
   239  		if err := p.BroadcastOutbound(ctx, act2); err != nil {
   240  			return false, err
   241  		}
   242  		acts := ap.PendingActionMap()
   243  		return lenPendingActionMap(acts) == 2, nil
   244  	})
   245  	require.NoError(err)
   246  
   247  	// transfer 3
   248  	// B --> B
   249  	s, _ = accountutil.AccountState(ctx, sf, identityset.Address(29))
   250  	tsf3, err := action.SignedTransfer(identityset.Address(29).String(), identityset.PrivateKey(29), s.PendingNonce(), big.NewInt(1), []byte{}, 100000, big.NewInt(0))
   251  	require.NoError(err)
   252  
   253  	require.NoError(ap2.Add(context.Background(), tsf3))
   254  	blk3, err := chain.MintNewBlock(testutil.TimestampNow())
   255  	require.NoError(err)
   256  	require.NoError(chain.CommitBlock(blk3))
   257  	// broadcast to P2P
   258  	act3 := tsf3.Proto()
   259  	err = testutil.WaitUntil(100*time.Millisecond, 60*time.Second, func() (bool, error) {
   260  		if err := p.BroadcastOutbound(ctx, act3); err != nil {
   261  			return false, err
   262  		}
   263  		acts := ap.PendingActionMap()
   264  		return lenPendingActionMap(acts) == 3, nil
   265  	})
   266  	require.NoError(err)
   267  
   268  	// transfer 4
   269  	// test --> E
   270  	s, _ = accountutil.AccountState(ctx, sf, identityset.Address(27))
   271  	tsf4, err := action.SignedTransfer(identityset.Address(32).String(), identityset.PrivateKey(27), s.PendingNonce(), big.NewInt(1), []byte{}, 100000, big.NewInt(0))
   272  	require.NoError(err)
   273  
   274  	require.NoError(ap2.Add(context.Background(), tsf4))
   275  	blk4, err := chain.MintNewBlock(testutil.TimestampNow())
   276  	require.NoError(err)
   277  	require.NoError(chain.CommitBlock(blk4))
   278  	// broadcast to P2P
   279  	act4 := tsf4.Proto()
   280  	err = testutil.WaitUntil(100*time.Millisecond, 60*time.Second, func() (bool, error) {
   281  		if err := p.BroadcastOutbound(ctx, act4); err != nil {
   282  			return false, err
   283  		}
   284  		acts := ap.PendingActionMap()
   285  		return lenPendingActionMap(acts) == 4, nil
   286  	})
   287  	require.NoError(err)
   288  	// wait 4 blocks being picked and committed
   289  	require.NoError(p.BroadcastOutbound(ctx, blk2.ConvertToBlockPb()))
   290  	require.NoError(p.BroadcastOutbound(ctx, blk4.ConvertToBlockPb()))
   291  	require.NoError(p.BroadcastOutbound(ctx, blk1.ConvertToBlockPb()))
   292  	require.NoError(p.BroadcastOutbound(ctx, blk3.ConvertToBlockPb()))
   293  	err = testutil.WaitUntil(100*time.Millisecond, 60*time.Second, func() (bool, error) {
   294  		height := bc.TipHeight()
   295  		return int(height) == 9, nil
   296  	})
   297  	require.NoError(err)
   298  	require.True(9 == bc.TipHeight())
   299  
   300  	// check balance
   301  	change.SetBytes(nil)
   302  	for _, v := range []struct {
   303  		addrIndex int
   304  		balance   string
   305  	}{
   306  		{28, "24"},
   307  		{29, "34"},
   308  		{30, "46"},
   309  		{31, "70"},
   310  		{32, "101"},
   311  		{33, "5242882"},
   312  	} {
   313  		s, err = accountutil.AccountState(ctx, sf, identityset.Address(v.addrIndex))
   314  		require.NoError(err)
   315  		require.Equal(v.balance, s.Balance.String())
   316  		change.Add(change, s.Balance)
   317  	}
   318  	s, err = accountutil.AccountState(ctx, sf, identityset.Address(27))
   319  	require.NoError(err)
   320  	change.Add(change, s.Balance)
   321  	change.Sub(change, i27State.Balance)
   322  	require.Equal(unit.ConvertIotxToRau(90000000), change)
   323  }
   324  
   325  func TestLocalSync(t *testing.T) {
   326  	require := require.New(t)
   327  
   328  	cfg, err := newTestConfig()
   329  	require.NoError(err)
   330  	testTriePath, err := testutil.PathOfTempFile(_triePath)
   331  	require.NoError(err)
   332  	testDBPath, err := testutil.PathOfTempFile(_dBPath)
   333  	require.NoError(err)
   334  	indexDBPath, err := testutil.PathOfTempFile(_dBPath)
   335  	require.NoError(err)
   336  	contractIndexDBPath, err := testutil.PathOfTempFile(_dBPath)
   337  	require.NoError(err)
   338  	indexSGDDBPath, err := testutil.PathOfTempFile(_dBPath + "_sgd")
   339  	require.NoError(err)
   340  	cfg.Chain.TrieDBPatchFile = ""
   341  	cfg.Chain.TrieDBPath = testTriePath
   342  	cfg.Chain.ChainDBPath = testDBPath
   343  	cfg.Chain.IndexDBPath = indexDBPath
   344  	cfg.Chain.ContractStakingIndexDBPath = contractIndexDBPath
   345  	cfg.Chain.SGDIndexDBPath = indexSGDDBPath
   346  	defer func() {
   347  		testutil.CleanupPath(testTriePath)
   348  		testutil.CleanupPath(testDBPath)
   349  		testutil.CleanupPath(indexDBPath)
   350  		testutil.CleanupPath(contractIndexDBPath)
   351  		testutil.CleanupPath(indexSGDDBPath)
   352  	}()
   353  
   354  	// bootnode
   355  	ctx := context.Background()
   356  	bootnodePort := testutil.RandomPort()
   357  	bootnode := p2p.NewAgent(p2p.Config{
   358  		Host:              "127.0.0.1",
   359  		Port:              bootnodePort,
   360  		ReconnectInterval: 150 * time.Second},
   361  		cfg.Chain.ID,
   362  		hash.ZeroHash256,
   363  		func(_ context.Context, _ uint32, _ string, msg proto.Message) {},
   364  		func(_ context.Context, _ uint32, _ peer.AddrInfo, _ proto.Message) {})
   365  	require.NoError(bootnode.Start(ctx))
   366  	addrs, err := bootnode.Self()
   367  	require.NoError(err)
   368  	cfg.Network.BootstrapNodes = []string{validNetworkAddr(addrs)}
   369  
   370  	// Create server
   371  	svr, err := itx.NewServer(cfg)
   372  	require.NoError(err)
   373  	require.NoError(svr.Start(ctx))
   374  
   375  	sChain := svr.ChainService(cfg.Chain.ID)
   376  	bc := sChain.Blockchain()
   377  	sf := sChain.StateFactory()
   378  	ap := sChain.ActionPool()
   379  	dao := sChain.BlockDAO()
   380  	require.NotNil(bc)
   381  	require.NotNil(sf)
   382  	require.NotNil(ap)
   383  	require.NotNil(dao)
   384  	require.NotNil(svr.P2PAgent())
   385  	require.NoError(addTestingTsfBlocks(bc, ap))
   386  
   387  	var blkHash [5]hash.Hash256
   388  	for i := uint64(1); i <= 5; i++ {
   389  		blk, err := dao.GetBlockByHeight(i)
   390  		require.NoError(err)
   391  		blkHash[i-1] = blk.HashBlock()
   392  	}
   393  
   394  	testDBPath2, err := testutil.PathOfTempFile(_dBPath2)
   395  	require.NoError(err)
   396  	testTriePath2, err := testutil.PathOfTempFile(_triePath2)
   397  	require.NoError(err)
   398  	indexDBPath2, err := testutil.PathOfTempFile(_dBPath2)
   399  	require.NoError(err)
   400  	contractIndexDBPath2, err := testutil.PathOfTempFile(_dBPath2)
   401  	require.NoError(err)
   402  	indexSGDDBPath2, err := testutil.PathOfTempFile(_dBPath2 + "_sgd")
   403  	require.NoError(err)
   404  	cfg, err = newTestConfig()
   405  	require.NoError(err)
   406  	cfg.Chain.TrieDBPatchFile = ""
   407  	cfg.Chain.TrieDBPath = testTriePath2
   408  	cfg.Chain.ChainDBPath = testDBPath2
   409  	cfg.Chain.IndexDBPath = indexDBPath2
   410  	cfg.Chain.ContractStakingIndexDBPath = contractIndexDBPath2
   411  	cfg.Chain.SGDIndexDBPath = indexSGDDBPath2
   412  	defer func() {
   413  		testutil.CleanupPath(testTriePath2)
   414  		testutil.CleanupPath(testDBPath2)
   415  		testutil.CleanupPath(indexDBPath2)
   416  		testutil.CleanupPath(contractIndexDBPath2)
   417  		testutil.CleanupPath(indexSGDDBPath2)
   418  	}()
   419  
   420  	// Create client
   421  	cfg.Network.BootstrapNodes = []string{validNetworkAddr(addrs)}
   422  	cfg.BlockSync.Interval = 1 * time.Second
   423  	cli, err := itx.NewServer(cfg)
   424  	require.NoError(err)
   425  	require.NoError(cli.Start(ctx))
   426  	nChain := cli.ChainService(cfg.Chain.ID)
   427  	require.NotNil(nChain.Blockchain())
   428  	require.NotNil(cli.P2PAgent())
   429  	require.Zero(nChain.Blockchain().TipHeight())
   430  	defer func() {
   431  		require.NoError(cli.Stop(ctx))
   432  		require.NoError(svr.Stop(ctx))
   433  	}()
   434  
   435  	err = testutil.WaitUntil(time.Millisecond*100, time.Second*60, func() (bool, error) {
   436  		peers, err := svr.P2PAgent().ConnectedPeers()
   437  		return len(peers) >= 1, err
   438  	})
   439  	require.NoError(err)
   440  	nDao := nChain.BlockDAO()
   441  	check := testutil.CheckCondition(func() (bool, error) {
   442  		for i := uint64(1); i <= 5; i++ {
   443  			blk, err := nDao.GetBlockByHeight(i)
   444  			if err != nil {
   445  				return false, nil
   446  			}
   447  			if blk.HashBlock() != blkHash[i-1] {
   448  				return false, nil
   449  			}
   450  		}
   451  		return true, nil
   452  	})
   453  	require.NoError(testutil.WaitUntil(time.Millisecond*100, time.Second*60, check))
   454  	require.EqualValues(5, nChain.Blockchain().TipHeight())
   455  }
   456  
   457  func TestStartExistingBlockchain(t *testing.T) {
   458  	require := require.New(t)
   459  	ctx := context.Background()
   460  	testDBPath, err := testutil.PathOfTempFile(_dBPath)
   461  	require.NoError(err)
   462  	testTriePath, err := testutil.PathOfTempFile(_triePath)
   463  	require.NoError(err)
   464  	testIndexPath, err := testutil.PathOfTempFile(_dBPath)
   465  	require.NoError(err)
   466  	testContractStakeIndexPath, err := testutil.PathOfTempFile(_dBPath)
   467  	require.NoError(err)
   468  	testSGDIndexPath, err := testutil.PathOfTempFile(_dBPath + "_sgd")
   469  	require.NoError(err)
   470  	// Disable block reward to make bookkeeping easier
   471  	cfg := config.Default
   472  	cfg.Chain.TrieDBPatchFile = ""
   473  	cfg.Chain.TrieDBPath = testTriePath
   474  	cfg.Chain.ChainDBPath = testDBPath
   475  	cfg.Chain.IndexDBPath = testIndexPath
   476  	cfg.Chain.ContractStakingIndexDBPath = testContractStakeIndexPath
   477  	cfg.Chain.SGDIndexDBPath = testSGDIndexPath
   478  	cfg.Chain.EnableAsyncIndexWrite = false
   479  	cfg.ActPool.MinGasPriceStr = "0"
   480  	cfg.Consensus.Scheme = config.NOOPScheme
   481  	cfg.Network.Port = testutil.RandomPort()
   482  
   483  	svr, err := itx.NewServer(cfg)
   484  	require.NoError(err)
   485  	require.NoError(svr.Start(ctx))
   486  	cs := svr.ChainService(cfg.Chain.ID)
   487  	bc := cs.Blockchain()
   488  	ap := cs.ActionPool()
   489  	require.NotNil(bc)
   490  	require.NotNil(cs.StateFactory())
   491  	require.NotNil(ap)
   492  	require.NotNil(cs.BlockDAO())
   493  
   494  	defer func() {
   495  		testutil.CleanupPath(testTriePath)
   496  		testutil.CleanupPath(testDBPath)
   497  		testutil.CleanupPath(testIndexPath)
   498  		testutil.CleanupPath(testContractStakeIndexPath)
   499  		testutil.CleanupPath(testSGDIndexPath)
   500  	}()
   501  
   502  	require.NoError(addTestingTsfBlocks(bc, ap))
   503  	require.Equal(uint64(5), bc.TipHeight())
   504  
   505  	require.NoError(svr.Stop(ctx))
   506  	// Delete state db and recover to tip
   507  	testutil.CleanupPath(testTriePath)
   508  	testutil.CleanupPath(testContractStakeIndexPath)
   509  
   510  	require.NoError(cs.Blockchain().Start(ctx))
   511  	height, _ := cs.StateFactory().Height()
   512  	require.Equal(bc.TipHeight(), height)
   513  	require.Equal(uint64(5), height)
   514  	require.NoError(cs.Blockchain().Stop(ctx))
   515  
   516  	// Recover to height 3 from empty state DB
   517  	cfg.DB.DbPath = cfg.Chain.ChainDBPath
   518  	deser := block.NewDeserializer(cfg.Chain.EVMNetworkID)
   519  	dao, err := filedao.NewFileDAO(cfg.DB, deser)
   520  	require.NoError(err)
   521  	require.NoError(dao.Start(protocol.WithBlockchainCtx(
   522  		genesis.WithGenesisContext(ctx, cfg.Genesis),
   523  		protocol.BlockchainCtx{
   524  			ChainID: cfg.Chain.ID,
   525  		})))
   526  	for {
   527  		height, err := dao.Height()
   528  		require.NoError(err)
   529  		if height <= 3 {
   530  			break
   531  		}
   532  		require.NoError(dao.DeleteTipBlock())
   533  	}
   534  	require.NoError(dao.Stop(ctx))
   535  
   536  	// Build states from height 1 to 3
   537  	testutil.CleanupPath(testTriePath)
   538  	testutil.CleanupPath(testContractStakeIndexPath)
   539  	testutil.CleanupPath(testSGDIndexPath)
   540  	svr, err = itx.NewServer(cfg)
   541  	require.NoError(err)
   542  	require.NoError(svr.Start(ctx))
   543  	cs = svr.ChainService(cfg.Chain.ID)
   544  	height, _ = cs.StateFactory().Height()
   545  	require.Equal(cs.Blockchain().TipHeight(), height)
   546  	require.Equal(uint64(3), height)
   547  
   548  	// Recover to height 2 from an existing state DB with Height 3
   549  	require.NoError(svr.Stop(ctx))
   550  	cfg.DB.DbPath = cfg.Chain.ChainDBPath
   551  	dao, err = filedao.NewFileDAO(cfg.DB, deser)
   552  	require.NoError(err)
   553  	require.NoError(dao.Start(protocol.WithBlockchainCtx(
   554  		genesis.WithGenesisContext(ctx, cfg.Genesis),
   555  		protocol.BlockchainCtx{
   556  			ChainID: cfg.Chain.ID,
   557  		})))
   558  	for {
   559  		height, err := dao.Height()
   560  		require.NoError(err)
   561  		if height <= 2 {
   562  			break
   563  		}
   564  		require.NoError(dao.DeleteTipBlock())
   565  	}
   566  	require.NoError(dao.Stop(ctx))
   567  	testutil.CleanupPath(testTriePath)
   568  	testutil.CleanupPath(testContractStakeIndexPath)
   569  	testutil.CleanupPath(testSGDIndexPath)
   570  	svr, err = itx.NewServer(cfg)
   571  	require.NoError(err)
   572  	// Build states from height 1 to 2
   573  	require.NoError(svr.Start(ctx))
   574  	cs = svr.ChainService(cfg.Chain.ID)
   575  	height, _ = cs.StateFactory().Height()
   576  	require.Equal(cs.Blockchain().TipHeight(), height)
   577  	require.Equal(uint64(2), height)
   578  	require.NoError(svr.Stop(ctx))
   579  }
   580  
   581  func newTestConfig() (config.Config, error) {
   582  	cfg := config.Default
   583  	cfg.Chain.TrieDBPath = _triePath
   584  	cfg.Chain.ChainDBPath = _dBPath
   585  	cfg.ActPool.MinGasPriceStr = "0"
   586  	cfg.Consensus.Scheme = config.NOOPScheme
   587  	cfg.Network.Port = testutil.RandomPort()
   588  	cfg.API.GRPCPort = testutil.RandomPort()
   589  	cfg.API.HTTPPort = testutil.RandomPort()
   590  	cfg.API.WebSocketPort = testutil.RandomPort()
   591  	cfg.Genesis.EnableGravityChainVoting = false
   592  	cfg.Genesis.MidwayBlockHeight = 1
   593  	sk, err := crypto.GenerateKey()
   594  
   595  	if err != nil {
   596  		return config.Config{}, err
   597  	}
   598  	cfg.Chain.ProducerPrivKey = sk.HexString()
   599  	return cfg, nil
   600  }
   601  
   602  func validNetworkAddr(addrs []multiaddr.Multiaddr) (ret string) {
   603  	for _, addr := range addrs {
   604  		if !strings.Contains(addr.String(), _disabledIP) {
   605  			return addr.String()
   606  		}
   607  	}
   608  	return
   609  }