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 }