github.com/iotexproject/iotex-core@v1.14.1-rc1/blockchain/integrity/benchmark_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 integrity
     7  
     8  import (
     9  	"context"
    10  	"encoding/hex"
    11  	"math/big"
    12  	"math/rand"
    13  	"testing"
    14  	"time"
    15  
    16  	"github.com/pkg/errors"
    17  	"github.com/stretchr/testify/require"
    18  
    19  	ethCrypto "github.com/iotexproject/go-pkgs/crypto"
    20  	"github.com/iotexproject/iotex-address/address"
    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/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/blockindex"
    36  	"github.com/iotexproject/iotex-core/config"
    37  	"github.com/iotexproject/iotex-core/db"
    38  	"github.com/iotexproject/iotex-core/pkg/unit"
    39  	"github.com/iotexproject/iotex-core/state/factory"
    40  	"github.com/iotexproject/iotex-core/test/identityset"
    41  	"github.com/iotexproject/iotex-core/testutil"
    42  )
    43  
    44  var (
    45  	_totalActionPair  = 2000
    46  	_contractByteCode = "60806040526101f4600055603260015534801561001b57600080fd5b506102558061002b6000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c806358931c461461003b5780637f353d5514610045575b600080fd5b61004361004f565b005b61004d610097565b005b60006001905060005b6000548110156100935760028261006f9190610114565b915060028261007e91906100e3565b9150808061008b90610178565b915050610058565b5050565b60005b6001548110156100e057600281908060018154018082558091505060019003906000526020600020016000909190919091505580806100d890610178565b91505061009a565b50565b60006100ee8261016e565b91506100f98361016e565b925082610109576101086101f0565b5b828204905092915050565b600061011f8261016e565b915061012a8361016e565b9250817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615610163576101626101c1565b5b828202905092915050565b6000819050919050565b60006101838261016e565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8214156101b6576101b56101c1565b5b600182019050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fdfea2646970667358221220cb9cada3f1d447c978af17aa3529d6fe4f25f9c5a174085443e371b6940ae99b64736f6c63430008070033"
    47  	_contractAddr     string
    48  
    49  	_randAccountSize  = 50
    50  	_randAccountsAddr = make([]address.Address, 0)
    51  	_randAccountsPvk  = make([]ethCrypto.PrivateKey, 0)
    52  	userA             = identityset.Address(28)
    53  	priKeyA           = identityset.PrivateKey(28)
    54  	userB             = identityset.Address(29)
    55  	priKeyB           = identityset.PrivateKey(29)
    56  
    57  	opAppend, _ = hex.DecodeString("7f353d55")
    58  	opMul, _    = hex.DecodeString("58931c46")
    59  )
    60  
    61  func init() {
    62  	for i := 0; i < _randAccountSize; i++ {
    63  		pvk, _ := ethCrypto.GenerateKey()
    64  		_randAccountsPvk = append(_randAccountsPvk, pvk)
    65  		_randAccountsAddr = append(_randAccountsAddr, pvk.PublicKey().Address())
    66  	}
    67  }
    68  
    69  func BenchmarkMintAndCommitBlock(b *testing.B) {
    70  	require := require.New(b)
    71  	rand.Seed(time.Now().Unix())
    72  	bc, ap, err := newChainInDB()
    73  	require.NoError(err)
    74  	nonceMap := make(map[string]uint64)
    75  
    76  	for n := 0; n < b.N; n++ {
    77  		err = injectMultipleAccountsTransfer(nonceMap, ap)
    78  		require.NoError(err)
    79  
    80  		blk, err := bc.MintNewBlock(testutil.TimestampNow())
    81  		require.NoError(err)
    82  		err = bc.ValidateBlock(blk)
    83  		require.NoError(err)
    84  		err = bc.CommitBlock(blk)
    85  		require.NoError(err)
    86  	}
    87  }
    88  
    89  func BenchmarkMintBlock(b *testing.B) {
    90  	require := require.New(b)
    91  	rand.Seed(time.Now().Unix())
    92  	bc, ap, err := newChainInDB()
    93  	require.NoError(err)
    94  	nonceMap := make(map[string]uint64)
    95  
    96  	err = injectMultipleAccountsTransfer(nonceMap, ap)
    97  	require.NoError(err)
    98  
    99  	for n := 0; n < b.N; n++ {
   100  		_, err := bc.MintNewBlock(testutil.TimestampNow())
   101  		require.NoError(err)
   102  	}
   103  }
   104  
   105  func BenchmarkValidateBlock(b *testing.B) {
   106  	require := require.New(b)
   107  	rand.Seed(time.Now().Unix())
   108  	bc, ap, err := newChainInDB()
   109  	require.NoError(err)
   110  	nonceMap := make(map[string]uint64)
   111  
   112  	err = injectTransfer(nonceMap, ap)
   113  	require.NoError(err)
   114  
   115  	blk, err := bc.MintNewBlock(testutil.TimestampNow())
   116  	require.NoError(err)
   117  
   118  	for n := 0; n < b.N; n++ {
   119  		err = bc.ValidateBlock(blk)
   120  		require.NoError(err)
   121  	}
   122  }
   123  
   124  func injectTransfer(nonceMap map[string]uint64, ap actpool.ActPool) error {
   125  	for i := 0; i < _totalActionPair; i++ {
   126  		nonceMap[userA.String()]++
   127  		tsf1, err := action.SignedTransfer(userB.String(), priKeyA, nonceMap[userA.String()], big.NewInt(int64(rand.Intn(2))), []byte{}, testutil.TestGasLimit, big.NewInt(testutil.TestGasPriceInt64))
   128  		if err != nil {
   129  			return err
   130  		}
   131  		err = ap.Add(context.Background(), tsf1)
   132  		if err != nil {
   133  			return err
   134  		}
   135  		nonceMap[userB.String()]++
   136  		tsf2, err := action.SignedTransfer(userA.String(), priKeyB, nonceMap[userB.String()], big.NewInt(int64(rand.Intn(2))), []byte{}, testutil.TestGasLimit, big.NewInt(testutil.TestGasPriceInt64))
   137  		if err != nil {
   138  			return err
   139  		}
   140  		err = ap.Add(context.Background(), tsf2)
   141  		if err != nil {
   142  			return err
   143  		}
   144  	}
   145  	return nil
   146  }
   147  
   148  func injectMultipleAccountsTransfer(nonceMap map[string]uint64, ap actpool.ActPool) error {
   149  	rand.Seed(time.Now().UnixNano())
   150  	for i := 0; i < 2*_totalActionPair; i++ {
   151  		senderIdx := rand.Intn(_randAccountSize)
   152  		recipientIdx := senderIdx
   153  		for ; recipientIdx != senderIdx; recipientIdx = rand.Intn(_randAccountSize) {
   154  		}
   155  		nonceMap[_randAccountsAddr[senderIdx].String()]++
   156  		tsf, err := action.SignedTransfer(
   157  			_randAccountsAddr[recipientIdx].String(),
   158  			_randAccountsPvk[senderIdx],
   159  			nonceMap[_randAccountsAddr[senderIdx].String()],
   160  			big.NewInt(int64(rand.Intn(2))),
   161  			[]byte{},
   162  			testutil.TestGasLimit,
   163  			big.NewInt(testutil.TestGasPriceInt64))
   164  		if err != nil {
   165  			return err
   166  		}
   167  		if err = ap.Add(context.Background(), tsf); err != nil {
   168  			return err
   169  		}
   170  	}
   171  	return nil
   172  }
   173  
   174  // Todo: get precise gaslimit by estimateGas
   175  func injectExecution(nonceMap map[string]uint64, ap actpool.ActPool) error {
   176  	for i := 0; i < _totalActionPair; i++ {
   177  		nonceMap[userA.String()]++
   178  		ex1, err := action.SignedExecution(_contractAddr, priKeyA, nonceMap[userA.String()], big.NewInt(0), 2e6, big.NewInt(testutil.TestGasPriceInt64), opAppend)
   179  		if err != nil {
   180  			return err
   181  		}
   182  		err = ap.Add(context.Background(), ex1)
   183  		if err != nil {
   184  			return err
   185  		}
   186  		nonceMap[userB.String()]++
   187  		ex2, err := action.SignedExecution(_contractAddr, priKeyB, nonceMap[userB.String()], big.NewInt(0), 2e6, big.NewInt(testutil.TestGasPriceInt64), opAppend)
   188  		if err != nil {
   189  			return err
   190  		}
   191  		err = ap.Add(context.Background(), ex2)
   192  		if err != nil {
   193  			return err
   194  		}
   195  	}
   196  	return nil
   197  }
   198  
   199  func newChainInDB() (blockchain.Blockchain, actpool.ActPool, error) {
   200  	cfg := config.Default
   201  	testTriePath, err := testutil.PathOfTempFile("trie")
   202  	if err != nil {
   203  		return nil, nil, err
   204  	}
   205  	testDBPath, err := testutil.PathOfTempFile("db")
   206  	if err != nil {
   207  		return nil, nil, err
   208  	}
   209  	testIndexPath, err := testutil.PathOfTempFile("index")
   210  	if err != nil {
   211  		return nil, nil, err
   212  	}
   213  	defer func() {
   214  		testutil.CleanupPath(testTriePath)
   215  		testutil.CleanupPath(testDBPath)
   216  		testutil.CleanupPath(testIndexPath)
   217  	}()
   218  
   219  	cfg.DB.DbPath = testTriePath
   220  	cfg.Chain.ChainDBPath = testDBPath
   221  	cfg.Chain.IndexDBPath = testIndexPath
   222  	cfg.Chain.EnableArchiveMode = true
   223  	cfg.Consensus.Scheme = config.RollDPoSScheme
   224  	cfg.Genesis.BlockGasLimit = genesis.Default.BlockGasLimit * 100
   225  	cfg.ActPool.MinGasPriceStr = "0"
   226  	cfg.ActPool.MaxNumActsPerAcct = 10000
   227  	cfg.Genesis.EnableGravityChainVoting = false
   228  	registry := protocol.NewRegistry()
   229  	var sf factory.Factory
   230  	kv := db.NewBoltDB(cfg.DB)
   231  	factoryCfg := factory.GenerateConfig(cfg.Chain, cfg.Genesis)
   232  	sf, err = factory.NewStateDB(factoryCfg, kv, factory.RegistryStateDBOption(registry), factory.DisableWorkingSetCacheOption())
   233  	if err != nil {
   234  		return nil, nil, err
   235  	}
   236  
   237  	ap, err := actpool.NewActPool(cfg.Genesis, sf, cfg.ActPool)
   238  	if err != nil {
   239  		return nil, nil, err
   240  	}
   241  	acc := account.NewProtocol(rewarding.DepositGas)
   242  	if err = acc.Register(registry); err != nil {
   243  		return nil, nil, err
   244  	}
   245  	rp := rolldpos.NewProtocol(cfg.Genesis.NumCandidateDelegates, cfg.Genesis.NumDelegates, cfg.Genesis.NumSubEpochs)
   246  	if err = rp.Register(registry); err != nil {
   247  		return nil, nil, err
   248  	}
   249  	var indexer blockindex.Indexer
   250  	indexers := []blockdao.BlockIndexer{sf}
   251  	if _, gateway := cfg.Plugins[config.GatewayPlugin]; gateway && !cfg.Chain.EnableAsyncIndexWrite {
   252  		// create indexer
   253  		cfg.DB.DbPath = cfg.Chain.IndexDBPath
   254  		indexer, err = blockindex.NewIndexer(db.NewBoltDB(cfg.DB), cfg.Genesis.Hash())
   255  		if err != nil {
   256  			return nil, nil, err
   257  		}
   258  		indexers = append(indexers, indexer)
   259  	}
   260  	cfg.Genesis.InitBalanceMap[identityset.Address(27).String()] = unit.ConvertIotxToRau(1000000000000).String()
   261  	// create BlockDAO
   262  	cfg.DB.DbPath = cfg.Chain.ChainDBPath
   263  	deser := block.NewDeserializer(cfg.Chain.EVMNetworkID)
   264  	store, err := filedao.NewFileDAO(cfg.DB, deser)
   265  	if err != nil {
   266  		return nil, nil, err
   267  	}
   268  	dao := blockdao.NewBlockDAOWithIndexersAndCache(store, indexers, cfg.DB.MaxCacheSize)
   269  	if dao == nil {
   270  		return nil, nil, errors.New("pointer is nil")
   271  	}
   272  	bc := blockchain.NewBlockchain(
   273  		cfg.Chain,
   274  		cfg.Genesis,
   275  		dao,
   276  		factory.NewMinter(sf, ap),
   277  		blockchain.BlockValidatorOption(block.NewValidator(
   278  			sf,
   279  			protocol.NewGenericValidator(sf, accountutil.AccountState),
   280  		)),
   281  	)
   282  	if bc == nil {
   283  		return nil, nil, errors.New("pointer is nil")
   284  	}
   285  	ep := execution.NewProtocol(dao.GetBlockHash, rewarding.DepositGasWithSGD, nil, fakeGetBlockTime)
   286  	if err = ep.Register(registry); err != nil {
   287  		return nil, nil, err
   288  	}
   289  	if err = bc.Start(context.Background()); err != nil {
   290  		return nil, nil, err
   291  	}
   292  
   293  	genesisPriKey := identityset.PrivateKey(27)
   294  	var genesisNonce uint64 = 1
   295  
   296  	// make a transfer from genesisAccount to a and b,because stateTX cannot store data in height 0
   297  	tsf, err := action.SignedTransfer(userA.String(), genesisPriKey, genesisNonce, big.NewInt(1e17), []byte{}, testutil.TestGasLimit, big.NewInt(testutil.TestGasPriceInt64))
   298  	if err != nil {
   299  		return nil, nil, err
   300  	}
   301  	if err = ap.Add(context.Background(), tsf); err != nil {
   302  		return nil, nil, err
   303  	}
   304  	genesisNonce++
   305  	tsf2, err := action.SignedTransfer(userB.String(), genesisPriKey, genesisNonce, big.NewInt(1e17), []byte{}, testutil.TestGasLimit, big.NewInt(testutil.TestGasPriceInt64))
   306  	if err != nil {
   307  		return nil, nil, err
   308  	}
   309  	if err = ap.Add(context.Background(), tsf2); err != nil {
   310  		return nil, nil, err
   311  	}
   312  	for i := 0; i < _randAccountSize; i++ {
   313  		genesisNonce++
   314  		tsf, err := action.SignedTransfer(_randAccountsAddr[i].String(), genesisPriKey, genesisNonce, big.NewInt(1e17), []byte{}, testutil.TestGasLimit, big.NewInt(testutil.TestGasPriceInt64))
   315  		if err != nil {
   316  			return nil, nil, err
   317  		}
   318  		if err = ap.Add(context.Background(), tsf); err != nil {
   319  			return nil, nil, err
   320  		}
   321  	}
   322  	// deploy contract
   323  	data, err := hex.DecodeString(_contractByteCode)
   324  	if err != nil {
   325  		return nil, nil, err
   326  	}
   327  	genesisNonce++
   328  	ex1, err := action.SignedExecution(action.EmptyAddress, genesisPriKey, genesisNonce, big.NewInt(0), 500000, big.NewInt(testutil.TestGasPriceInt64), data)
   329  	if err != nil {
   330  		return nil, nil, err
   331  	}
   332  	if err := ap.Add(context.Background(), ex1); err != nil {
   333  		return nil, nil, err
   334  	}
   335  
   336  	blk, err := bc.MintNewBlock(testutil.TimestampNow())
   337  	if err != nil {
   338  		return nil, nil, err
   339  	}
   340  	if err = bc.CommitBlock(blk); err != nil {
   341  		return nil, nil, err
   342  	}
   343  
   344  	ex1Hash, err := ex1.Hash()
   345  	if err != nil {
   346  		return nil, nil, err
   347  	}
   348  	var receipt *action.Receipt
   349  	for _, r := range blk.Receipts {
   350  		if r.ActionHash == ex1Hash {
   351  			receipt = r
   352  			break
   353  		}
   354  	}
   355  	if receipt == nil {
   356  		return nil, nil, errors.Errorf("failed to find receipt for %x", ex1Hash)
   357  	}
   358  	_contractAddr = receipt.ContractAddress
   359  
   360  	return bc, ap, nil
   361  }