github.com/Bytom/bytom@v1.1.2-0.20210127130405-ae40204c0b09/test/bench_blockchain_test.go (about)

     1  package test
     2  
     3  import (
     4  	"fmt"
     5  	"io/ioutil"
     6  	"os"
     7  	"testing"
     8  	"time"
     9  
    10  	"github.com/bytom/bytom/account"
    11  	"github.com/bytom/bytom/blockchain/pseudohsm"
    12  	"github.com/bytom/bytom/blockchain/signers"
    13  	"github.com/bytom/bytom/blockchain/txbuilder"
    14  	"github.com/bytom/bytom/consensus"
    15  	"github.com/bytom/bytom/consensus/difficulty"
    16  	"github.com/bytom/bytom/crypto/ed25519/chainkd"
    17  	"github.com/bytom/bytom/database"
    18  	"github.com/bytom/bytom/database/storage"
    19  	"github.com/bytom/bytom/event"
    20  	"github.com/bytom/bytom/mining"
    21  	"github.com/bytom/bytom/protocol"
    22  	"github.com/bytom/bytom/protocol/bc"
    23  	"github.com/bytom/bytom/protocol/bc/types"
    24  	"github.com/bytom/bytom/protocol/state"
    25  	dbm "github.com/bytom/bytom/database/leveldb"
    26  )
    27  
    28  func BenchmarkChain_CoinBaseTx_NoAsset(b *testing.B) {
    29  	benchInsertChain(b, 0, 0, "")
    30  }
    31  
    32  func BenchmarkChain_BtmTx_NoAsset_BASE(b *testing.B) {
    33  	benchInsertChain(b, 1, 0, "")
    34  }
    35  
    36  func BenchmarkChain_5000BtmTx_NoAsset_BASE(b *testing.B) {
    37  	benchInsertChain(b, 5000, 0, "")
    38  }
    39  
    40  func BenchmarkChain_5000BtmTx_1Asset_BASE(b *testing.B) {
    41  	benchInsertChain(b, 5000, 1, "")
    42  }
    43  
    44  // standard Transaction
    45  func BenchmarkChain_BtmTx_NoAsset_P2PKH(b *testing.B) {
    46  	benchInsertChain(b, 1000, 0, "P2PKH")
    47  }
    48  
    49  func BenchmarkChain_BtmTx_1Asset_P2PKH(b *testing.B) {
    50  	benchInsertChain(b, 1000, 1, "P2PKH")
    51  }
    52  
    53  func BenchmarkChain_BtmTx_NoAsset_P2SH(b *testing.B) {
    54  	benchInsertChain(b, 100, 0, "P2SH")
    55  }
    56  
    57  func BenchmarkChain_BtmTx_1Asset_P2SH(b *testing.B) {
    58  	benchInsertChain(b, 100, 1, "P2SH")
    59  }
    60  
    61  func BenchmarkChain_BtmTx_NoAsset_MultiSign(b *testing.B) {
    62  	benchInsertChain(b, 100, 0, "MultiSign")
    63  }
    64  
    65  func BenchmarkChain_BtmTx_1Asset_MultiSign(b *testing.B) {
    66  	benchInsertChain(b, 100, 1, "MultiSign")
    67  }
    68  
    69  func benchInsertChain(b *testing.B, blockTxNumber int, otherAssetNum int, txType string) {
    70  	b.StopTimer()
    71  	testNumber := b.N
    72  	totalTxNumber := testNumber * blockTxNumber
    73  
    74  	dirPath, err := ioutil.TempDir(".", "testDB")
    75  	if err != nil {
    76  		b.Fatal("create dirPath err:", err)
    77  	}
    78  	defer os.RemoveAll(dirPath)
    79  
    80  	testDB := dbm.NewDB("testdb", "leveldb", dirPath)
    81  	defer testDB.Close()
    82  
    83  	// Generate a chain test data.
    84  	chain, txs, txPool, err := GenerateChainData(dirPath, testDB, totalTxNumber, otherAssetNum, txType)
    85  	if err != nil {
    86  		b.Fatal("GenerateChainData err:", err)
    87  	}
    88  
    89  	b.ReportAllocs()
    90  	b.StartTimer()
    91  
    92  	for i := 0; i < b.N; i++ {
    93  		testTxs := txs[blockTxNumber*i : blockTxNumber*(i+1)]
    94  		if err := InsertChain(chain, txPool, testTxs); err != nil {
    95  			b.Fatal("Failed to insert block into chain:", err)
    96  		}
    97  	}
    98  }
    99  
   100  func GenerateChainData(dirPath string, testDB dbm.DB, txNumber, otherAssetNum int, txType string) (*protocol.Chain, []*types.Tx, *protocol.TxPool, error) {
   101  	var err error
   102  
   103  	// generate transactions
   104  	txs := []*types.Tx{}
   105  	switch txType {
   106  	case "P2PKH":
   107  		txs, err = MockTxsP2PKH(dirPath, testDB, txNumber, otherAssetNum)
   108  		if err != nil {
   109  			return nil, nil, nil, err
   110  		}
   111  	case "P2SH":
   112  		txs, err = MockTxsP2SH(dirPath, testDB, txNumber, otherAssetNum)
   113  		if err != nil {
   114  			return nil, nil, nil, err
   115  		}
   116  	case "MultiSign":
   117  		txs, err = MockTxsMultiSign(dirPath, testDB, txNumber, otherAssetNum)
   118  		if err != nil {
   119  			return nil, nil, nil, err
   120  		}
   121  	default:
   122  		txs, err = CreateTxbyNum(txNumber, otherAssetNum)
   123  		if err != nil {
   124  			return nil, nil, nil, err
   125  		}
   126  	}
   127  
   128  	// init UtxoViewpoint
   129  	utxoView := state.NewUtxoViewpoint()
   130  	utxoEntry := storage.NewUtxoEntry(false, 1, false)
   131  	for _, tx := range txs {
   132  		for _, id := range tx.SpentOutputIDs {
   133  			utxoView.Entries[id] = utxoEntry
   134  		}
   135  	}
   136  
   137  	if err := SetUtxoView(testDB, utxoView); err != nil {
   138  		return nil, nil, nil, err
   139  	}
   140  
   141  	store := database.NewStore(testDB)
   142  	dispatcher := event.NewDispatcher()
   143  	txPool := protocol.NewTxPool(store, dispatcher)
   144  	chain, err := protocol.NewChain(store, txPool)
   145  	if err != nil {
   146  		return nil, nil, nil, err
   147  	}
   148  
   149  	go processNewTxch(txPool)
   150  
   151  	return chain, txs, txPool, nil
   152  }
   153  
   154  func InsertChain(chain *protocol.Chain, txPool *protocol.TxPool, txs []*types.Tx) error {
   155  	for _, tx := range txs {
   156  		if err := txbuilder.FinalizeTx(nil, chain, tx); err != nil {
   157  			return err
   158  		}
   159  	}
   160  
   161  	block, err := mining.NewBlockTemplate(chain, txPool, nil)
   162  	if err != nil {
   163  		return err
   164  	}
   165  
   166  	blockSize, err := block.MarshalText()
   167  	if err != nil {
   168  		return err
   169  	}
   170  
   171  	fmt.Println("blocksize:", uint64(len(blockSize)))
   172  	fmt.Println("block tx count:", uint64(len(block.Transactions)))
   173  	fmt.Println("coinbase txsize:", uint64(block.Transactions[0].SerializedSize))
   174  	if len(block.Transactions) > 1 {
   175  		fmt.Println("txsize:", uint64(block.Transactions[1].SerializedSize))
   176  	}
   177  
   178  	seed, err := chain.CalcNextSeed(&block.PreviousBlockHash)
   179  	if err != nil {
   180  		return err
   181  	}
   182  
   183  	if err := SolveBlock(seed, block); err != nil {
   184  		return err
   185  	}
   186  
   187  	if _, err := chain.ProcessBlock(block); err != nil {
   188  		return err
   189  	}
   190  
   191  	return nil
   192  }
   193  
   194  func processNewTxch(txPool *protocol.TxPool) {
   195  }
   196  
   197  func SolveBlock(seed *bc.Hash, block *types.Block) error {
   198  	maxNonce := ^uint64(0) // 2^64 - 1
   199  	header := &block.BlockHeader
   200  	for i := uint64(0); i < maxNonce; i++ {
   201  		header.Nonce = i
   202  		headerHash := header.Hash()
   203  		if difficulty.CheckProofOfWork(&headerHash, seed, header.Bits) {
   204  			return nil
   205  		}
   206  	}
   207  	return nil
   208  }
   209  
   210  func MockSimpleUtxo(index uint64, assetID *bc.AssetID, amount uint64, ctrlProg *account.CtrlProgram) *account.UTXO {
   211  	if ctrlProg == nil {
   212  		ctrlProg = &account.CtrlProgram{
   213  			AccountID:      "",
   214  			Address:        "",
   215  			KeyIndex:       uint64(0),
   216  			ControlProgram: []byte{81},
   217  			Change:         false,
   218  		}
   219  	}
   220  
   221  	utxo := &account.UTXO{
   222  		OutputID:            bc.Hash{V0: 1},
   223  		SourceID:            bc.Hash{V0: 1},
   224  		AssetID:             *assetID,
   225  		Amount:              amount,
   226  		SourcePos:           index,
   227  		ControlProgram:      ctrlProg.ControlProgram,
   228  		ControlProgramIndex: ctrlProg.KeyIndex,
   229  		AccountID:           ctrlProg.AccountID,
   230  		Address:             ctrlProg.Address,
   231  		ValidHeight:         0,
   232  	}
   233  
   234  	return utxo
   235  }
   236  
   237  func GenerateBaseUtxos(num int, amount uint64, ctrlProg *account.CtrlProgram) []*account.UTXO {
   238  	utxos := []*account.UTXO{}
   239  	for i := 0; i < num; i++ {
   240  		utxo := MockSimpleUtxo(uint64(i), consensus.BTMAssetID, amount, ctrlProg)
   241  		utxos = append(utxos, utxo)
   242  	}
   243  
   244  	return utxos
   245  }
   246  
   247  func GenerateOtherUtxos(typeCount, num int, amount uint64, ctrlProg *account.CtrlProgram) []*account.UTXO {
   248  	utxos := []*account.UTXO{}
   249  
   250  	assetID := &bc.AssetID{
   251  		V0: uint64(typeCount),
   252  		V1: uint64(1),
   253  		V2: uint64(0),
   254  		V3: uint64(1),
   255  	}
   256  
   257  	for i := 0; i < num; i++ {
   258  		utxo := MockSimpleUtxo(uint64(typeCount*num+i), assetID, amount, ctrlProg)
   259  		utxos = append(utxos, utxo)
   260  	}
   261  
   262  	return utxos
   263  }
   264  
   265  func AddTxInputFromUtxo(utxo *account.UTXO, singer *signers.Signer) (*types.TxInput, *txbuilder.SigningInstruction, error) {
   266  	txInput, signInst, err := account.UtxoToInputs(singer, utxo)
   267  	if err != nil {
   268  		return nil, nil, err
   269  	}
   270  
   271  	return txInput, signInst, nil
   272  }
   273  
   274  func AddTxOutput(assetID bc.AssetID, amount uint64, controlProgram []byte) *types.TxOutput {
   275  	out := types.NewTxOutput(assetID, amount, controlProgram)
   276  	return out
   277  }
   278  
   279  func CreateTxBuilder(baseUtxo *account.UTXO, btmServiceFlag bool, signer *signers.Signer) (*txbuilder.TemplateBuilder, error) {
   280  	tplBuilder := txbuilder.NewBuilder(time.Now())
   281  
   282  	// add input
   283  	txInput, signInst, err := AddTxInputFromUtxo(baseUtxo, signer)
   284  	if err != nil {
   285  		return nil, err
   286  	}
   287  	tplBuilder.AddInput(txInput, signInst)
   288  
   289  	// if the btm is the service charge, didn't need to add the output
   290  	if btmServiceFlag {
   291  		txOutput := AddTxOutput(baseUtxo.AssetID, 100, baseUtxo.ControlProgram)
   292  		tplBuilder.AddOutput(txOutput)
   293  	}
   294  
   295  	return tplBuilder, nil
   296  }
   297  
   298  func AddTxBuilder(tplBuilder *txbuilder.TemplateBuilder, utxo *account.UTXO, signer *signers.Signer) error {
   299  	txInput, signInst, err := AddTxInputFromUtxo(utxo, signer)
   300  	if err != nil {
   301  		return err
   302  	}
   303  	tplBuilder.AddInput(txInput, signInst)
   304  
   305  	txOutput := AddTxOutput(utxo.AssetID, utxo.Amount, utxo.ControlProgram)
   306  	tplBuilder.AddOutput(txOutput)
   307  
   308  	return nil
   309  }
   310  
   311  func BuildTx(baseUtxo *account.UTXO, otherUtxos []*account.UTXO, signer *signers.Signer) (*txbuilder.Template, error) {
   312  	btmServiceFlag := false
   313  	if otherUtxos == nil || len(otherUtxos) == 0 {
   314  		btmServiceFlag = true
   315  	}
   316  
   317  	tplBuilder, err := CreateTxBuilder(baseUtxo, btmServiceFlag, signer)
   318  	if err != nil {
   319  		return nil, err
   320  	}
   321  
   322  	for _, u := range otherUtxos {
   323  		if err := AddTxBuilder(tplBuilder, u, signer); err != nil {
   324  			return nil, err
   325  		}
   326  	}
   327  
   328  	tpl, _, err := tplBuilder.Build()
   329  	if err != nil {
   330  		return nil, err
   331  	}
   332  
   333  	return tpl, nil
   334  }
   335  
   336  func GenetrateTxbyUtxo(baseUtxo []*account.UTXO, otherUtxo [][]*account.UTXO) ([]*types.Tx, error) {
   337  	tmpUtxo := []*account.UTXO{}
   338  	txs := []*types.Tx{}
   339  	otherUtxoFlag := true
   340  
   341  	if len(otherUtxo) == 0 || len(otherUtxo) != len(baseUtxo) {
   342  		otherUtxoFlag = false
   343  	}
   344  
   345  	for i := 0; i < len(baseUtxo); i++ {
   346  		if otherUtxoFlag {
   347  			tmpUtxo = otherUtxo[i]
   348  		} else {
   349  			tmpUtxo = nil
   350  		}
   351  
   352  		tpl, err := BuildTx(baseUtxo[i], tmpUtxo, nil)
   353  		if err != nil {
   354  			return nil, err
   355  		}
   356  
   357  		txs = append(txs, tpl.Transaction)
   358  	}
   359  
   360  	return txs, nil
   361  }
   362  
   363  func CreateTxbyNum(txNumber, otherAssetNum int) ([]*types.Tx, error) {
   364  	baseUtxos := GenerateBaseUtxos(txNumber, 1000000000, nil)
   365  	otherUtxos := make([][]*account.UTXO, 0, txNumber)
   366  	if otherAssetNum != 0 {
   367  		for i := 0; i < txNumber; i++ {
   368  			utxos := GenerateOtherUtxos(i, otherAssetNum, 6000, nil)
   369  			otherUtxos = append(otherUtxos, utxos)
   370  		}
   371  	}
   372  
   373  	txs, err := GenetrateTxbyUtxo(baseUtxos, otherUtxos)
   374  	if err != nil {
   375  		return nil, err
   376  	}
   377  
   378  	return txs, nil
   379  }
   380  
   381  func SetUtxoView(db dbm.DB, view *state.UtxoViewpoint) error {
   382  	batch := db.NewBatch()
   383  	if err := database.SaveUtxoView(batch, view); err != nil {
   384  		return err
   385  	}
   386  	batch.Write()
   387  	return nil
   388  }
   389  
   390  //-------------------------Mock actual transaction----------------------------------
   391  func MockTxsP2PKH(keyDirPath string, testDB dbm.DB, txNumber, otherAssetNum int) ([]*types.Tx, error) {
   392  	accountManager := account.NewManager(testDB, nil)
   393  	hsm, err := pseudohsm.New(keyDirPath)
   394  	if err != nil {
   395  		return nil, err
   396  	}
   397  
   398  	xpub, _, err := hsm.XCreate("TestP2PKH", "password", "en")
   399  	if err != nil {
   400  		return nil, err
   401  	}
   402  
   403  	txs := []*types.Tx{}
   404  	for i := 0; i < txNumber; i++ {
   405  		testAccountAlias := fmt.Sprintf("testAccount%d", i)
   406  		testAccount, err := accountManager.Create([]chainkd.XPub{xpub.XPub}, 1, testAccountAlias, signers.BIP0044)
   407  		if err != nil {
   408  			return nil, err
   409  		}
   410  
   411  		controlProg, err := accountManager.CreateAddress(testAccount.ID, false)
   412  		if err != nil {
   413  			return nil, err
   414  		}
   415  
   416  		utxo := MockSimpleUtxo(0, consensus.BTMAssetID, 1000000000, controlProg)
   417  		otherUtxos := GenerateOtherUtxos(i, otherAssetNum, 6000, controlProg)
   418  		tpl, err := BuildTx(utxo, otherUtxos, testAccount.Signer)
   419  		if err != nil {
   420  			return nil, err
   421  		}
   422  
   423  		if _, err := MockSign(tpl, hsm, "password"); err != nil {
   424  			return nil, err
   425  		}
   426  
   427  		txs = append(txs, tpl.Transaction)
   428  	}
   429  
   430  	return txs, nil
   431  }
   432  
   433  func MockTxsP2SH(keyDirPath string, testDB dbm.DB, txNumber, otherAssetNum int) ([]*types.Tx, error) {
   434  	accountManager := account.NewManager(testDB, nil)
   435  	hsm, err := pseudohsm.New(keyDirPath)
   436  	if err != nil {
   437  		return nil, err
   438  	}
   439  
   440  	xpub1, _, err := hsm.XCreate("TestP2SH1", "password", "en")
   441  	if err != nil {
   442  		return nil, err
   443  	}
   444  
   445  	xpub2, _, err := hsm.XCreate("TestP2SH2", "password", "en")
   446  	if err != nil {
   447  		return nil, err
   448  	}
   449  
   450  	txs := []*types.Tx{}
   451  	for i := 0; i < txNumber; i++ {
   452  		testAccountAlias := fmt.Sprintf("testAccount%d", i)
   453  		testAccount, err := accountManager.Create([]chainkd.XPub{xpub1.XPub, xpub2.XPub}, 2, testAccountAlias, signers.BIP0044)
   454  		if err != nil {
   455  			return nil, err
   456  		}
   457  
   458  		controlProg, err := accountManager.CreateAddress(testAccount.ID, false)
   459  		if err != nil {
   460  			return nil, err
   461  		}
   462  
   463  		utxo := MockSimpleUtxo(0, consensus.BTMAssetID, 1000000000, controlProg)
   464  		otherUtxos := GenerateOtherUtxos(i, otherAssetNum, 6000, controlProg)
   465  		tpl, err := BuildTx(utxo, otherUtxos, testAccount.Signer)
   466  		if err != nil {
   467  			return nil, err
   468  		}
   469  
   470  		if _, err := MockSign(tpl, hsm, "password"); err != nil {
   471  			return nil, err
   472  		}
   473  
   474  		txs = append(txs, tpl.Transaction)
   475  	}
   476  
   477  	return txs, nil
   478  }
   479  
   480  func MockTxsMultiSign(keyDirPath string, testDB dbm.DB, txNumber, otherAssetNum int) ([]*types.Tx, error) {
   481  	accountManager := account.NewManager(testDB, nil)
   482  	hsm, err := pseudohsm.New(keyDirPath)
   483  	if err != nil {
   484  		return nil, err
   485  	}
   486  
   487  	xpub1, _, err := hsm.XCreate("TestMultilNodeSign1", "password1", "en")
   488  	if err != nil {
   489  		return nil, err
   490  	}
   491  
   492  	xpub2, _, err := hsm.XCreate("TestMultilNodeSign2", "password2", "en")
   493  	if err != nil {
   494  		return nil, err
   495  	}
   496  	txs := []*types.Tx{}
   497  	for i := 0; i < txNumber; i++ {
   498  		testAccountAlias := fmt.Sprintf("testAccount%d", i)
   499  		testAccount, err := accountManager.Create([]chainkd.XPub{xpub1.XPub, xpub2.XPub}, 2, testAccountAlias, signers.BIP0044)
   500  		if err != nil {
   501  			return nil, err
   502  		}
   503  
   504  		controlProg, err := accountManager.CreateAddress(testAccount.ID, false)
   505  		if err != nil {
   506  			return nil, err
   507  		}
   508  
   509  		utxo := MockSimpleUtxo(0, consensus.BTMAssetID, 1000000000, controlProg)
   510  		otherUtxos := GenerateOtherUtxos(i, otherAssetNum, 6000, controlProg)
   511  		tpl, err := BuildTx(utxo, otherUtxos, testAccount.Signer)
   512  		if err != nil {
   513  			return nil, err
   514  		}
   515  
   516  		if _, err := MockSign(tpl, hsm, "password1"); err != nil {
   517  			return nil, err
   518  		}
   519  
   520  		if _, err := MockSign(tpl, hsm, "password2"); err != nil {
   521  			return nil, err
   522  		}
   523  
   524  		txs = append(txs, tpl.Transaction)
   525  	}
   526  
   527  	return txs, nil
   528  }