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

     1  // Copyright (c) 2022 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 api
     7  
     8  import (
     9  	"context"
    10  	"encoding/hex"
    11  	"math/big"
    12  	"testing"
    13  	"time"
    14  
    15  	"github.com/iotexproject/go-pkgs/crypto"
    16  	"github.com/iotexproject/go-pkgs/hash"
    17  	"github.com/iotexproject/iotex-proto/golang/iotextypes"
    18  	"github.com/pkg/errors"
    19  	"github.com/stretchr/testify/require"
    20  	"google.golang.org/protobuf/proto"
    21  
    22  	"github.com/iotexproject/iotex-core/action"
    23  	"github.com/iotexproject/iotex-core/action/protocol"
    24  	"github.com/iotexproject/iotex-core/action/protocol/account"
    25  	accountutil "github.com/iotexproject/iotex-core/action/protocol/account/util"
    26  	"github.com/iotexproject/iotex-core/action/protocol/execution"
    27  	"github.com/iotexproject/iotex-core/action/protocol/poll"
    28  	"github.com/iotexproject/iotex-core/action/protocol/rewarding"
    29  	"github.com/iotexproject/iotex-core/action/protocol/rolldpos"
    30  	"github.com/iotexproject/iotex-core/actpool"
    31  	"github.com/iotexproject/iotex-core/blockchain"
    32  	"github.com/iotexproject/iotex-core/blockchain/block"
    33  	"github.com/iotexproject/iotex-core/blockchain/blockdao"
    34  	"github.com/iotexproject/iotex-core/blockchain/filedao"
    35  	"github.com/iotexproject/iotex-core/blockchain/genesis"
    36  	"github.com/iotexproject/iotex-core/blockindex"
    37  	"github.com/iotexproject/iotex-core/consensus"
    38  	"github.com/iotexproject/iotex-core/db"
    39  	"github.com/iotexproject/iotex-core/pkg/unit"
    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  type testConfig struct {
    46  	api       Config
    47  	genesis   genesis.Genesis
    48  	actPoll   actpool.Config
    49  	chain     blockchain.Config
    50  	consensus consensus.Config
    51  	db        db.Config
    52  	indexer   blockindex.Config
    53  }
    54  
    55  var (
    56  	_testTransfer1, _ = action.SignedTransfer(identityset.Address(30).String(), identityset.PrivateKey(27), 1,
    57  		big.NewInt(10), []byte{}, testutil.TestGasLimit, big.NewInt(testutil.TestGasPriceInt64))
    58  	_transferHash1, _ = _testTransfer1.Hash()
    59  	_testTransfer2, _ = action.SignedTransfer(identityset.Address(30).String(), identityset.PrivateKey(30), 5,
    60  		big.NewInt(2), []byte{}, testutil.TestGasLimit, big.NewInt(testutil.TestGasPriceInt64))
    61  	_transferHash2, _ = _testTransfer2.Hash()
    62  
    63  	_testExecution1, _ = action.SignedExecution(identityset.Address(31).String(), identityset.PrivateKey(30), 6,
    64  		big.NewInt(1), testutil.TestGasLimit, big.NewInt(testutil.TestGasPriceInt64), []byte{1})
    65  	_executionHash1, _ = _testExecution1.Hash()
    66  	_testExecution3, _ = action.SignedExecution(identityset.Address(31).String(), identityset.PrivateKey(28), 2,
    67  		big.NewInt(1), testutil.TestGasLimit, big.NewInt(testutil.TestGasPriceInt64), []byte{1})
    68  	_executionHash3, _ = _testExecution3.Hash()
    69  
    70  	_blkHash      = map[uint64]string{}
    71  	_implicitLogs = map[hash.Hash256]*block.TransactionLog{}
    72  )
    73  
    74  func addTestingBlocks(bc blockchain.Blockchain, ap actpool.ActPool) error {
    75  	ctx := context.Background()
    76  	addr0 := identityset.Address(27).String()
    77  	addr1 := identityset.Address(28).String()
    78  	addr2 := identityset.Address(29).String()
    79  	addr3 := identityset.Address(30).String()
    80  	priKey3 := identityset.PrivateKey(30)
    81  	addr4 := identityset.Address(31).String()
    82  	// Add block 1
    83  	// Producer transfer--> C
    84  	_implicitLogs[_transferHash1] = block.NewTransactionLog(_transferHash1,
    85  		[]*block.TokenTxRecord{block.NewTokenTxRecord(iotextypes.TransactionLogType_NATIVE_TRANSFER, "10", addr0, addr3)},
    86  	)
    87  
    88  	blk1Time := testutil.TimestampNow()
    89  	if err := ap.Add(ctx, _testTransfer1); err != nil {
    90  		return err
    91  	}
    92  	blk, err := bc.MintNewBlock(blk1Time)
    93  	if err != nil {
    94  		return err
    95  	}
    96  	if err := bc.CommitBlock(blk); err != nil {
    97  		return err
    98  	}
    99  	ap.Reset()
   100  	h := blk.HashBlock()
   101  	_blkHash[1] = hex.EncodeToString(h[:])
   102  
   103  	// Add block 2
   104  	// Charlie transfer--> A, B, D, P
   105  	// Charlie transfer--> C
   106  	// Charlie exec--> D
   107  	recipients := []string{addr1, addr2, addr4, addr0}
   108  	for i, recipient := range recipients {
   109  		selp, err := action.SignedTransfer(recipient, priKey3, uint64(i+1), big.NewInt(1), []byte{}, testutil.TestGasLimit, big.NewInt(testutil.TestGasPriceInt64))
   110  		if err != nil {
   111  			return err
   112  		}
   113  		if err := ap.Add(ctx, selp); err != nil {
   114  			return err
   115  		}
   116  		selpHash, err := selp.Hash()
   117  		if err != nil {
   118  			return err
   119  		}
   120  		_implicitLogs[selpHash] = block.NewTransactionLog(selpHash,
   121  			[]*block.TokenTxRecord{block.NewTokenTxRecord(iotextypes.TransactionLogType_NATIVE_TRANSFER, "1", addr3, recipient)},
   122  		)
   123  	}
   124  	_implicitLogs[_transferHash2] = block.NewTransactionLog(_transferHash2,
   125  		[]*block.TokenTxRecord{block.NewTokenTxRecord(iotextypes.TransactionLogType_NATIVE_TRANSFER, "2", addr3, addr3)},
   126  	)
   127  	if err := ap.Add(ctx, _testTransfer2); err != nil {
   128  		return err
   129  	}
   130  	_implicitLogs[_executionHash1] = block.NewTransactionLog(
   131  		_executionHash1,
   132  		[]*block.TokenTxRecord{block.NewTokenTxRecord(iotextypes.TransactionLogType_IN_CONTRACT_TRANSFER, "1", addr3, addr4)},
   133  	)
   134  	if err := ap.Add(ctx, _testExecution1); err != nil {
   135  		return err
   136  	}
   137  	if blk, err = bc.MintNewBlock(blk1Time.Add(time.Second)); err != nil {
   138  		return err
   139  	}
   140  	if err := bc.CommitBlock(blk); err != nil {
   141  		return err
   142  	}
   143  	ap.Reset()
   144  	h = blk.HashBlock()
   145  	_blkHash[2] = hex.EncodeToString(h[:])
   146  
   147  	// Add block 3
   148  	// Empty actions
   149  	if blk, err = bc.MintNewBlock(blk1Time.Add(time.Second * 2)); err != nil {
   150  		return err
   151  	}
   152  	if err := bc.CommitBlock(blk); err != nil {
   153  		return err
   154  	}
   155  	ap.Reset()
   156  	h = blk.HashBlock()
   157  	_blkHash[3] = hex.EncodeToString(h[:])
   158  
   159  	// Add block 4
   160  	// Charlie transfer--> C
   161  	// Alfa transfer--> A
   162  	// Charlie exec--> D
   163  	// Alfa exec--> D
   164  	tsf1, err := action.SignedTransfer(addr3, priKey3, uint64(7), big.NewInt(1), []byte{}, testutil.TestGasLimit, big.NewInt(testutil.TestGasPriceInt64))
   165  	if err != nil {
   166  		return err
   167  	}
   168  	tsf1Hash, err := tsf1.Hash()
   169  	if err != nil {
   170  		return err
   171  	}
   172  	_implicitLogs[tsf1Hash] = block.NewTransactionLog(tsf1Hash,
   173  		[]*block.TokenTxRecord{block.NewTokenTxRecord(iotextypes.TransactionLogType_NATIVE_TRANSFER, "1", addr3, addr3)},
   174  	)
   175  	if err := ap.Add(ctx, tsf1); err != nil {
   176  		return err
   177  	}
   178  	tsf2, err := action.SignedTransfer(addr1, identityset.PrivateKey(28), uint64(1), big.NewInt(1), []byte{}, testutil.TestGasLimit, big.NewInt(testutil.TestGasPriceInt64))
   179  	if err != nil {
   180  		return err
   181  	}
   182  	tsf2Hash, err := tsf2.Hash()
   183  	if err != nil {
   184  		return err
   185  	}
   186  	_implicitLogs[tsf2Hash] = block.NewTransactionLog(tsf2Hash,
   187  		[]*block.TokenTxRecord{block.NewTokenTxRecord(iotextypes.TransactionLogType_NATIVE_TRANSFER, "1", addr1, addr1)},
   188  	)
   189  	if err := ap.Add(ctx, tsf2); err != nil {
   190  		return err
   191  	}
   192  	execution1, err := action.SignedExecution(addr4, priKey3, 8,
   193  		big.NewInt(2), testutil.TestGasLimit, big.NewInt(testutil.TestGasPriceInt64), []byte{1})
   194  	if err != nil {
   195  		return err
   196  	}
   197  	execution1Hash, err := execution1.Hash()
   198  	if err != nil {
   199  		return err
   200  	}
   201  	_implicitLogs[execution1Hash] = block.NewTransactionLog(
   202  		execution1Hash,
   203  		[]*block.TokenTxRecord{block.NewTokenTxRecord(iotextypes.TransactionLogType_IN_CONTRACT_TRANSFER, "2", addr3, addr4)},
   204  	)
   205  	if err := ap.Add(ctx, execution1); err != nil {
   206  		return err
   207  	}
   208  	_implicitLogs[_executionHash3] = block.NewTransactionLog(
   209  		_executionHash3,
   210  		[]*block.TokenTxRecord{block.NewTokenTxRecord(iotextypes.TransactionLogType_IN_CONTRACT_TRANSFER, "1", addr1, addr4)},
   211  	)
   212  	if err := ap.Add(ctx, _testExecution3); err != nil {
   213  		return err
   214  	}
   215  	if blk, err = bc.MintNewBlock(blk1Time.Add(time.Second * 3)); err != nil {
   216  		return err
   217  	}
   218  	h = blk.HashBlock()
   219  	_blkHash[4] = hex.EncodeToString(h[:])
   220  	return bc.CommitBlock(blk)
   221  }
   222  
   223  func deployContractV2(bc blockchain.Blockchain, dao blockdao.BlockDAO, actPool actpool.ActPool, key crypto.PrivateKey, nonce, height uint64, code string) (string, error) {
   224  	data, _ := hex.DecodeString(code)
   225  	ex1, err := action.SignedExecution(action.EmptyAddress, key, nonce, big.NewInt(0), 500000, big.NewInt(testutil.TestGasPriceInt64), data)
   226  	if err != nil {
   227  		return "", err
   228  	}
   229  	h1, err := ex1.Hash()
   230  	if err != nil {
   231  		return "", err
   232  	}
   233  	if err := actPool.Add(context.Background(), ex1); err != nil {
   234  		return "", err
   235  	}
   236  	blk, err := bc.MintNewBlock(testutil.TimestampNow())
   237  	if err != nil {
   238  		return "", err
   239  	}
   240  	if err := bc.CommitBlock(blk); err != nil {
   241  		return "", err
   242  	}
   243  	actPool.Reset()
   244  	// get deployed contract address
   245  	for _, receipt := range blk.Receipts {
   246  		if receipt.ActionHash == h1 {
   247  			return receipt.ContractAddress, nil
   248  		}
   249  	}
   250  	return "", errors.New("failed to find execution receipt")
   251  }
   252  
   253  func addActsToActPool(ctx context.Context, ap actpool.ActPool) error {
   254  	// Producer transfer--> A
   255  	tsf1, err := action.SignedTransfer(identityset.Address(28).String(), identityset.PrivateKey(27), 2, big.NewInt(20), []byte{}, testutil.TestGasLimit, big.NewInt(testutil.TestGasPriceInt64))
   256  	if err != nil {
   257  		return err
   258  	}
   259  	// Producer transfer--> P
   260  	tsf2, err := action.SignedTransfer(identityset.Address(27).String(), identityset.PrivateKey(27), 3, big.NewInt(20), []byte{}, testutil.TestGasLimit, big.NewInt(testutil.TestGasPriceInt64))
   261  	if err != nil {
   262  		return err
   263  	}
   264  	// Producer transfer--> B
   265  	tsf3, err := action.SignedTransfer(identityset.Address(29).String(), identityset.PrivateKey(27), 4, big.NewInt(20), []byte{}, testutil.TestGasLimit, big.NewInt(testutil.TestGasPriceInt64))
   266  	if err != nil {
   267  		return err
   268  	}
   269  	// Producer exec--> D
   270  	execution1, err := action.SignedExecution(identityset.Address(31).String(), identityset.PrivateKey(27), 5,
   271  		big.NewInt(1), testutil.TestGasLimit, big.NewInt(10), []byte{1})
   272  	if err != nil {
   273  		return err
   274  	}
   275  
   276  	if err := ap.Add(ctx, tsf1); err != nil {
   277  		return err
   278  	}
   279  	if err := ap.Add(ctx, tsf2); err != nil {
   280  		return err
   281  	}
   282  	if err := ap.Add(ctx, tsf3); err != nil {
   283  		return err
   284  	}
   285  	return ap.Add(ctx, execution1)
   286  }
   287  
   288  func setupChain(cfg testConfig) (blockchain.Blockchain, blockdao.BlockDAO, blockindex.Indexer, blockindex.BloomFilterIndexer, factory.Factory, actpool.ActPool, *protocol.Registry, string, error) {
   289  	cfg.chain.ProducerPrivKey = hex.EncodeToString(identityset.PrivateKey(0).Bytes())
   290  	registry := protocol.NewRegistry()
   291  	factoryCfg := factory.GenerateConfig(cfg.chain, cfg.genesis)
   292  	sf, err := factory.NewFactory(factoryCfg, db.NewMemKVStore(), factory.RegistryOption(registry))
   293  	if err != nil {
   294  		return nil, nil, nil, nil, nil, nil, nil, "", err
   295  	}
   296  	ap, err := setupActPool(cfg.genesis, sf, cfg.actPoll)
   297  	if err != nil {
   298  		return nil, nil, nil, nil, nil, nil, nil, "", err
   299  	}
   300  	cfg.genesis.InitBalanceMap[identityset.Address(27).String()] = unit.ConvertIotxToRau(10000000000).String()
   301  	cfg.genesis.InitBalanceMap[identityset.Address(28).String()] = unit.ConvertIotxToRau(10000000000).String()
   302  	// create indexer
   303  	indexer, err := blockindex.NewIndexer(db.NewMemKVStore(), cfg.genesis.Hash())
   304  	if err != nil {
   305  		return nil, nil, nil, nil, nil, nil, nil, "", errors.New("failed to create indexer")
   306  	}
   307  	testPath, _ := testutil.PathOfTempFile("bloomfilter")
   308  	cfg.db.DbPath = testPath
   309  	bfIndexer, err := blockindex.NewBloomfilterIndexer(db.NewBoltDB(cfg.db), cfg.indexer)
   310  	if err != nil {
   311  		return nil, nil, nil, nil, nil, nil, nil, "", errors.New("failed to create bloomfilter indexer")
   312  	}
   313  	// create BlockDAO
   314  	store, err := filedao.NewFileDAOInMemForTest()
   315  	if err != nil {
   316  		return nil, nil, nil, nil, nil, nil, nil, "", errors.Wrap(err, "failed to create dao in memory")
   317  	}
   318  	dao := blockdao.NewBlockDAOWithIndexersAndCache(store, []blockdao.BlockIndexer{sf, indexer, bfIndexer}, 16)
   319  	if dao == nil {
   320  		return nil, nil, nil, nil, nil, nil, nil, "", errors.New("failed to create blockdao")
   321  	}
   322  	// create chain
   323  	bc := blockchain.NewBlockchain(
   324  		cfg.chain,
   325  		cfg.genesis,
   326  		dao,
   327  		factory.NewMinter(sf, ap),
   328  		blockchain.BlockValidatorOption(block.NewValidator(
   329  			sf,
   330  			protocol.NewGenericValidator(sf, accountutil.AccountState),
   331  		)),
   332  	)
   333  	if bc == nil {
   334  		return nil, nil, nil, nil, nil, nil, nil, "", errors.New("failed to create blockchain")
   335  	}
   336  	defer func() {
   337  		testutil.CleanupPath(testPath)
   338  	}()
   339  
   340  	acc := account.NewProtocol(rewarding.DepositGas)
   341  	evm := execution.NewProtocol(dao.GetBlockHash, rewarding.DepositGasWithSGD, nil, func(u uint64) (time.Time, error) { return time.Time{}, nil })
   342  	p := poll.NewLifeLongDelegatesProtocol(cfg.genesis.Delegates)
   343  	rolldposProtocol := rolldpos.NewProtocol(
   344  		genesis.Default.NumCandidateDelegates,
   345  		genesis.Default.NumDelegates,
   346  		genesis.Default.NumSubEpochs,
   347  		rolldpos.EnableDardanellesSubEpoch(cfg.genesis.DardanellesBlockHeight, cfg.genesis.DardanellesNumSubEpochs),
   348  	)
   349  	r := rewarding.NewProtocol(cfg.genesis.Rewarding)
   350  
   351  	if err := rolldposProtocol.Register(registry); err != nil {
   352  		return nil, nil, nil, nil, nil, nil, nil, "", err
   353  	}
   354  	if err := acc.Register(registry); err != nil {
   355  		return nil, nil, nil, nil, nil, nil, nil, "", err
   356  	}
   357  	if err := evm.Register(registry); err != nil {
   358  		return nil, nil, nil, nil, nil, nil, nil, "", err
   359  	}
   360  	if err := r.Register(registry); err != nil {
   361  		return nil, nil, nil, nil, nil, nil, nil, "", err
   362  	}
   363  	if err := p.Register(registry); err != nil {
   364  		return nil, nil, nil, nil, nil, nil, nil, "", err
   365  	}
   366  
   367  	return bc, dao, indexer, bfIndexer, sf, ap, registry, testPath, nil
   368  }
   369  
   370  func setupActPool(g genesis.Genesis, sf factory.Factory, cfg actpool.Config) (actpool.ActPool, error) {
   371  	ap, err := actpool.NewActPool(g, sf, cfg)
   372  	if err != nil {
   373  		return nil, err
   374  	}
   375  
   376  	ap.AddActionEnvelopeValidators(protocol.NewGenericValidator(sf, accountutil.AccountState))
   377  
   378  	return ap, nil
   379  }
   380  
   381  func newConfig() testConfig {
   382  	cfg := testConfig{
   383  		api:       DefaultConfig,
   384  		genesis:   genesis.Default,
   385  		actPoll:   actpool.DefaultConfig,
   386  		chain:     blockchain.DefaultConfig,
   387  		consensus: consensus.DefaultConfig,
   388  		db:        db.DefaultConfig,
   389  		indexer:   blockindex.DefaultConfig,
   390  	}
   391  
   392  	testTriePath, err := testutil.PathOfTempFile("trie")
   393  	if err != nil {
   394  		panic(err)
   395  	}
   396  	testDBPath, err := testutil.PathOfTempFile("db")
   397  	if err != nil {
   398  		panic(err)
   399  	}
   400  	testIndexPath, err := testutil.PathOfTempFile("index")
   401  	if err != nil {
   402  		panic(err)
   403  	}
   404  	testSystemLogPath, err := testutil.PathOfTempFile("systemlog")
   405  	if err != nil {
   406  		panic(err)
   407  	}
   408  	defer func() {
   409  		testutil.CleanupPath(testTriePath)
   410  		testutil.CleanupPath(testDBPath)
   411  		testutil.CleanupPath(testIndexPath)
   412  		testutil.CleanupPath(testSystemLogPath)
   413  	}()
   414  
   415  	cfg.chain.TrieDBPath = testTriePath
   416  	cfg.chain.ChainDBPath = testDBPath
   417  	cfg.chain.IndexDBPath = testIndexPath
   418  	cfg.chain.EVMNetworkID = _evmNetworkID
   419  	cfg.chain.EnableAsyncIndexWrite = false
   420  	cfg.genesis.EnableGravityChainVoting = true
   421  	cfg.actPoll.MinGasPriceStr = "0"
   422  	cfg.api.RangeQueryLimit = 100
   423  	cfg.api.GRPCPort = 0
   424  	cfg.api.HTTPPort = 0
   425  	cfg.api.WebSocketPort = 0
   426  	return cfg
   427  }
   428  
   429  func createServerV2(cfg testConfig, needActPool bool) (*ServerV2, blockchain.Blockchain, blockdao.BlockDAO, blockindex.Indexer, *protocol.Registry, actpool.ActPool, string, error) {
   430  	// TODO (zhi): revise
   431  	bc, dao, indexer, bfIndexer, sf, ap, registry, bfIndexFile, err := setupChain(cfg)
   432  	if err != nil {
   433  		return nil, nil, nil, nil, nil, nil, "", err
   434  	}
   435  
   436  	ctx := context.Background()
   437  
   438  	// Start blockchain
   439  	if err := bc.Start(ctx); err != nil {
   440  		return nil, nil, nil, nil, nil, nil, "", err
   441  	}
   442  	// Add testing blocks
   443  	if err := addTestingBlocks(bc, ap); err != nil {
   444  		return nil, nil, nil, nil, nil, nil, "", err
   445  	}
   446  
   447  	if needActPool {
   448  		// Add actions to actpool
   449  		ctx = protocol.WithRegistry(ctx, registry)
   450  		if err := addActsToActPool(ctx, ap); err != nil {
   451  			return nil, nil, nil, nil, nil, nil, "", err
   452  		}
   453  	}
   454  	opts := []Option{WithBroadcastOutbound(func(ctx context.Context, chainID uint32, msg proto.Message) error {
   455  		return nil
   456  	})}
   457  	svr, err := NewServerV2(cfg.api, bc, nil, sf, dao, indexer, bfIndexer, ap, registry, func(u uint64) (time.Time, error) { return time.Time{}, nil }, opts...)
   458  	if err != nil {
   459  		return nil, nil, nil, nil, nil, nil, "", err
   460  	}
   461  	return svr, bc, dao, indexer, registry, ap, bfIndexFile, nil
   462  }
   463  
   464  func TestServerV2Integrity(t *testing.T) {
   465  	require := require.New(t)
   466  	cfg := newConfig()
   467  	cfg.api.GRPCPort = testutil.RandomPort()
   468  	svr, _, _, _, _, _, bfIndexFile, err := createServerV2(cfg, false)
   469  	require.NoError(err)
   470  	defer func() {
   471  		testutil.CleanupPath(bfIndexFile)
   472  	}()
   473  	ctx := context.Background()
   474  
   475  	err = svr.Start(ctx)
   476  	require.NoError(err)
   477  
   478  	err = testutil.WaitUntil(100*time.Millisecond, 3*time.Second, func() (bool, error) {
   479  		err = svr.Stop(ctx)
   480  		return err == nil, err
   481  	})
   482  	require.NoError(err)
   483  }