github.com/deso-protocol/core@v1.2.9/lib/load_test.go (about)

     1  package lib
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"os"
     7  	"runtime/pprof"
     8  	"testing"
     9  	"time"
    10  
    11  	"github.com/btcsuite/btcd/btcec"
    12  	"github.com/stretchr/testify/assert"
    13  	"github.com/stretchr/testify/require"
    14  )
    15  
    16  // Increase numProfiles and numPostsPerProfile to load test
    17  func TestComputeMaxTPS(t *testing.T) {
    18  	assert := assert.New(t)
    19  	require := require.New(t)
    20  	_ = assert
    21  	_ = require
    22  
    23  	chain, params, db := NewLowDifficultyBlockchain()
    24  	mempool, miner := NewTestMiner(t, chain, params, true /*isSender*/)
    25  	_, _ = mempool, db
    26  
    27  	// Send money to 1,000 public keys
    28  	// For each public key, create a profile
    29  	// For each profile, make 1,000 posts
    30  	numProfiles := 1
    31  	numPostsPerProfile := 1000
    32  	privKeys := []*btcec.PrivateKey{}
    33  	pubKeys := []*btcec.PublicKey{}
    34  	txns := []*MsgDeSoTxn{}
    35  	for ii := 0; ii < numProfiles; ii++ {
    36  		fmt.Println("Processing top txn: ", len(txns))
    37  		// Compute a private/public key pair
    38  		privKey, err := btcec.NewPrivateKey(btcec.S256())
    39  		require.NoError(err)
    40  		privKeys = append(privKeys, privKey)
    41  		pubKeys = append(pubKeys, privKey.PubKey())
    42  		currentPubStr := PkToString(
    43  			pubKeys[len(pubKeys)-1].SerializeCompressed(), params)
    44  		currentPrivStr := PrivToString(
    45  			privKeys[len(privKeys)-1].Serialize(), params)
    46  
    47  		// Send money to this key
    48  		{
    49  			txn := _assembleBasicTransferTxnFullySigned(
    50  				t, chain, 1000000000, 100, moneyPkString,
    51  				currentPubStr, moneyPrivString, mempool)
    52  
    53  			_, err := mempool.ProcessTransaction(txn, false, false, 0, false)
    54  			require.NoError(err, "Problem adding transaction %d to mempool: %v", ii, txn)
    55  
    56  			txns = append(txns, txn)
    57  		}
    58  
    59  		// Create a profile for this key
    60  		{
    61  			txn, _, _, _, err := chain.CreateUpdateProfileTxn(
    62  				pubKeys[len(pubKeys)-1].SerializeCompressed(),
    63  				nil,
    64  				fmt.Sprintf("username_%v", ii),
    65  				"",
    66  				"",
    67  				500,
    68  				12500,
    69  				false,
    70  				0,
    71  				10,
    72  				mempool /*mempool*/,
    73  				[]*DeSoOutput{})
    74  			require.NoError(err)
    75  			_signTxn(t, txn, currentPrivStr)
    76  			_, err = mempool.ProcessTransaction(
    77  				txn, false, false, 0, false)
    78  			require.NoError(err, "Problem adding transaction %d to mempool: %v", ii, txn)
    79  
    80  			txns = append(txns, txn)
    81  		}
    82  		bodyObj := &DeSoBodySchema{Body: "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890" +
    83  			"1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890" +
    84  			"12345678901234567890123456789012345678901234567890123456789012345678901234567890"}
    85  		bodyBytes, err := json.Marshal(bodyObj)
    86  		require.NoError(err)
    87  		postExtraData := make(map[string][]byte)
    88  		// Create posts for this profile
    89  		for jj := 0; jj < numPostsPerProfile; jj++ {
    90  			fmt.Println("Processing inner txn: ", len(txns))
    91  			txn, _, _, _, err := chain.CreateSubmitPostTxn(
    92  				pubKeys[len(pubKeys)-1].SerializeCompressed(),
    93  				[]byte{},
    94  				[]byte{},
    95  				bodyBytes,
    96  				[]byte{},
    97  				false,
    98  				uint64(time.Now().UnixNano()),
    99  				postExtraData,
   100  				false,
   101  				100,
   102  				mempool,
   103  				[]*DeSoOutput{})
   104  			require.NoError(err)
   105  
   106  			// Sign the transaction now that its inputs are set up.
   107  			_signTxn(t, txn, currentPrivStr)
   108  
   109  			_, err = mempool.ProcessTransaction(
   110  				txn, false, false, 0, false)
   111  			require.NoError(err, "Problem adding transaction %d to mempool: %v", jj, txn)
   112  
   113  			txns = append(txns, txn)
   114  		}
   115  	}
   116  
   117  	// Set the read-only view to update less frequently
   118  	ReadOnlyUtxoViewRegenerationIntervalTxns = 1000
   119  	defer func() {
   120  		ReadOnlyUtxoViewRegenerationIntervalTxns = 1
   121  	}()
   122  
   123  	// Time how fast we can add transactions to a UtxoView
   124  	{
   125  		fmt.Println("woo")
   126  
   127  		ff, err := os.Create("/tmp/block-processing-profile")
   128  		require.NoError(err)
   129  		pprof.StartCPUProfile(ff)
   130  
   131  		utxoView, err := NewUtxoView(db, params, nil)
   132  		require.NoError(err)
   133  
   134  		timeStart := time.Now()
   135  		for _, tx := range txns {
   136  			_, _, _, _, err := utxoView.ConnectTransaction(tx, tx.Hash(), 0, 1, false /*verifySignature*/, false /*ignoreUtxos*/)
   137  			require.NoError(err)
   138  		}
   139  		//require.NoError(utxoView.FlushToDb())
   140  		elapsedSecs := (time.Since(timeStart)).Seconds()
   141  		fmt.Printf("UtxoView added %v txns in %v seconds with TPS: %v\n",
   142  			len(txns), elapsedSecs,
   143  			float64(len(txns))/float64((elapsedSecs)))
   144  
   145  		pprof.StopCPUProfile()
   146  	}
   147  
   148  	// At this point we have some number of transactions. Clear the mempool and see how
   149  	// long it takes to add them all to the mempool.
   150  	mempool.resetPool(NewDeSoMempool(mempool.bc, 0, /* rateLimitFeeRateNanosPerKB */
   151  		0, /* minFeeRateNanosPerKB */
   152  		"" /*blockCypherAPIKey*/, false,
   153  		"" /*dataDir*/, ""))
   154  	{
   155  		timeStart := time.Now()
   156  		for _, tx := range txns {
   157  			mempoolTxsAdded, err := mempool.processTransaction(
   158  				tx, true /*allowUnconnectedTxn*/, false /*rateLimit*/, 0, /*peerID*/
   159  				false /*verifySignatures*/)
   160  			require.NoError(err)
   161  			require.Equal(1, len(mempoolTxsAdded))
   162  		}
   163  		elapsedSecs := (time.Since(timeStart)).Seconds()
   164  		fmt.Printf("Mempool added %v txns in %v seconds with TPS: %v\n",
   165  			len(txns), elapsedSecs,
   166  			float64(len(txns))/float64((elapsedSecs)))
   167  
   168  	}
   169  
   170  	// Mine blocks until the mempool is empty.
   171  	blocksMined := []*MsgDeSoBlock{}
   172  	mempoolTxns, _, err := mempool.GetTransactionsOrderedByTimeAdded()
   173  	require.NoError(err)
   174  	for ii := 0; len(mempoolTxns) > 0; ii++ {
   175  		finalBlock1, err := miner.MineAndProcessSingleBlock(0 /*threadIndex*/, mempool)
   176  		require.NoError(err)
   177  		mempoolTxns, _, err = mempool.GetTransactionsOrderedByTimeAdded()
   178  		require.NoError(err)
   179  		blocksMined = append(blocksMined, finalBlock1)
   180  		fmt.Printf("Block %v contains %v txns\n", ii, len(finalBlock1.Txns))
   181  	}
   182  	fmt.Println(len(blocksMined))
   183  
   184  	// Apply the blocks to a new chain with timings
   185  	{
   186  
   187  		newChain, newParams, newDB := NewLowDifficultyBlockchain()
   188  		_, _ = newParams, newDB
   189  		timeStart := time.Now()
   190  		for _, blockToConnect := range blocksMined {
   191  			_, _, err := newChain.ProcessBlock(blockToConnect, true /*verifySignatures*/)
   192  			require.NoError(err)
   193  		}
   194  		elapsedSecs := (time.Since(timeStart)).Seconds()
   195  		fmt.Printf("Connected %v txns in %v seconds with TPS: %v\n",
   196  			len(txns), elapsedSecs,
   197  			float64(len(txns))/float64((elapsedSecs)))
   198  	}
   199  }
   200  
   201  // Increase numBlocksToMine to load test
   202  func TestConnectBlocksLoadTest(t *testing.T) {
   203  	assert := assert.New(t)
   204  	require := require.New(t)
   205  	_ = assert
   206  	_ = require
   207  
   208  	chain, params, db := NewLowDifficultyBlockchain()
   209  	mempool, miner := NewTestMiner(t, chain, params, true /*isSender*/)
   210  	_, _ = mempool, db
   211  
   212  	// Mine blocks until the mempool is empty.
   213  	numBlocksToMine := 10
   214  	blocksMined := []*MsgDeSoBlock{}
   215  	for ii := 0; ii < numBlocksToMine; ii++ {
   216  		finalBlock1, err := miner.MineAndProcessSingleBlock(0 /*threadIndex*/, mempool)
   217  		require.NoError(err)
   218  		blocksMined = append(blocksMined, finalBlock1)
   219  		fmt.Printf("Block %v contains %v txns\n", ii, len(finalBlock1.Txns))
   220  		fmt.Println(len(blocksMined))
   221  	}
   222  	fmt.Println(len(blocksMined))
   223  
   224  	// Apply the blocks to a new chain with timings
   225  	{
   226  		newChain, newParams, newDB := NewLowDifficultyBlockchain()
   227  		_, _ = newParams, newDB
   228  		ff, err := os.Create("/tmp/block-processing-profile")
   229  		require.NoError(err)
   230  		pprof.StartCPUProfile(ff)
   231  		timeStart := time.Now()
   232  		for _, blockToConnect := range blocksMined {
   233  			_, _, err := newChain.ProcessBlock(blockToConnect, false /*verifySignatures*/)
   234  			require.NoError(err)
   235  		}
   236  		elapsedSecs := (time.Since(timeStart)).Seconds()
   237  		fmt.Printf("Connected %v blocks in %v seconds with blocks per second: %v\n",
   238  			len(blocksMined), elapsedSecs,
   239  			float64(len(blocksMined))/float64((elapsedSecs)))
   240  		pprof.StopCPUProfile()
   241  	}
   242  }