OSDN Git Service

0d548feb1237926a545f4cda39d91ae952fd1c14
[bytom/vapor.git] / test / bench_blockchain_test.go
1 package test
2
3 import (
4         "fmt"
5         "io/ioutil"
6         "os"
7         "testing"
8         "time"
9
10         "github.com/vapor/account"
11         "github.com/vapor/blockchain/pseudohsm"
12         "github.com/vapor/blockchain/signers"
13         "github.com/vapor/blockchain/txbuilder"
14         "github.com/vapor/config"
15         "github.com/vapor/consensus"
16         "github.com/vapor/crypto/ed25519/chainkd"
17         "github.com/vapor/database"
18         dbm "github.com/vapor/database/leveldb"
19         "github.com/vapor/database/storage"
20         "github.com/vapor/event"
21         "github.com/vapor/proposal"
22         "github.com/vapor/protocol"
23         "github.com/vapor/protocol/bc"
24         "github.com/vapor/protocol/bc/types"
25         "github.com/vapor/protocol/state"
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(storage.NormalUTXOType, 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         config.CommonConfig = config.DefaultConfig()
142         store := database.NewStore(testDB)
143         dispatcher := event.NewDispatcher()
144         txPool := protocol.NewTxPool(store, dispatcher)
145         chain, err := protocol.NewChain(store, txPool, dispatcher)
146         if err != nil {
147                 return nil, nil, nil, err
148         }
149
150         go processNewTxch(txPool)
151
152         return chain, txs, txPool, nil
153 }
154
155 func InsertChain(chain *protocol.Chain, txPool *protocol.TxPool, txs []*types.Tx) error {
156         for _, tx := range txs {
157                 if err := txbuilder.FinalizeTx(nil, chain, tx); err != nil {
158                         return err
159                 }
160         }
161
162         block, err := proposal.NewBlockTemplate(chain, txPool, nil, uint64(time.Now().UnixNano() / 1e6))
163         if err != nil {
164                 return err
165         }
166
167         blockSize, err := block.MarshalText()
168         if err != nil {
169                 return err
170         }
171
172         fmt.Println("blocksize:", uint64(len(blockSize)))
173         fmt.Println("block tx count:", uint64(len(block.Transactions)))
174         fmt.Println("coinbase txsize:", uint64(block.Transactions[0].SerializedSize))
175         if len(block.Transactions) > 1 {
176                 fmt.Println("txsize:", uint64(block.Transactions[1].SerializedSize))
177         }
178
179         if _, err := chain.ProcessBlock(block); err != nil {
180                 return err
181         }
182
183         return nil
184 }
185
186 func processNewTxch(txPool *protocol.TxPool) {
187 }
188
189 func MockSimpleUtxo(index uint64, assetID *bc.AssetID, amount uint64, ctrlProg *account.CtrlProgram) *account.UTXO {
190         if ctrlProg == nil {
191                 ctrlProg = &account.CtrlProgram{
192                         AccountID:      "",
193                         Address:        "",
194                         KeyIndex:       uint64(0),
195                         ControlProgram: []byte{81},
196                         Change:         false,
197                 }
198         }
199
200         utxo := &account.UTXO{
201                 OutputID:            bc.Hash{V0: 1},
202                 SourceID:            bc.Hash{V0: 1},
203                 AssetID:             *assetID,
204                 Amount:              amount,
205                 SourcePos:           index,
206                 ControlProgram:      ctrlProg.ControlProgram,
207                 ControlProgramIndex: ctrlProg.KeyIndex,
208                 AccountID:           ctrlProg.AccountID,
209                 Address:             ctrlProg.Address,
210                 ValidHeight:         0,
211         }
212
213         return utxo
214 }
215
216 func GenerateBaseUtxos(num int, amount uint64, ctrlProg *account.CtrlProgram) []*account.UTXO {
217         utxos := []*account.UTXO{}
218         for i := 0; i < num; i++ {
219                 utxo := MockSimpleUtxo(uint64(i), consensus.BTMAssetID, amount, ctrlProg)
220                 utxos = append(utxos, utxo)
221         }
222
223         return utxos
224 }
225
226 func GenerateOtherUtxos(typeCount, num int, amount uint64, ctrlProg *account.CtrlProgram) []*account.UTXO {
227         utxos := []*account.UTXO{}
228
229         assetID := &bc.AssetID{
230                 V0: uint64(typeCount),
231                 V1: uint64(1),
232                 V2: uint64(0),
233                 V3: uint64(1),
234         }
235
236         for i := 0; i < num; i++ {
237                 utxo := MockSimpleUtxo(uint64(typeCount*num+i), assetID, amount, ctrlProg)
238                 utxos = append(utxos, utxo)
239         }
240
241         return utxos
242 }
243
244 func AddTxInputFromUtxo(utxo *account.UTXO, singer *signers.Signer) (*types.TxInput, *txbuilder.SigningInstruction, error) {
245         txInput, signInst, err := account.UtxoToInputs(singer, utxo)
246         if err != nil {
247                 return nil, nil, err
248         }
249
250         return txInput, signInst, nil
251 }
252
253 func AddTxOutput(assetID bc.AssetID, amount uint64, controlProgram []byte) *types.TxOutput {
254         out := types.NewIntraChainOutput(assetID, amount, controlProgram)
255         return out
256 }
257
258 func CreateTxBuilder(baseUtxo *account.UTXO, btmServiceFlag bool, signer *signers.Signer) (*txbuilder.TemplateBuilder, error) {
259         tplBuilder := txbuilder.NewBuilder(time.Now())
260
261         // add input
262         txInput, signInst, err := AddTxInputFromUtxo(baseUtxo, signer)
263         if err != nil {
264                 return nil, err
265         }
266         tplBuilder.AddInput(txInput, signInst)
267
268         // if the btm is the service charge, didn't need to add the output
269         if btmServiceFlag {
270                 txOutput := AddTxOutput(baseUtxo.AssetID, 100, baseUtxo.ControlProgram)
271                 tplBuilder.AddOutput(txOutput)
272         }
273
274         return tplBuilder, nil
275 }
276
277 func AddTxBuilder(tplBuilder *txbuilder.TemplateBuilder, utxo *account.UTXO, signer *signers.Signer) error {
278         txInput, signInst, err := AddTxInputFromUtxo(utxo, signer)
279         if err != nil {
280                 return err
281         }
282         tplBuilder.AddInput(txInput, signInst)
283
284         txOutput := AddTxOutput(utxo.AssetID, utxo.Amount, utxo.ControlProgram)
285         tplBuilder.AddOutput(txOutput)
286
287         return nil
288 }
289
290 func BuildTx(baseUtxo *account.UTXO, otherUtxos []*account.UTXO, signer *signers.Signer) (*txbuilder.Template, error) {
291         btmServiceFlag := false
292         if otherUtxos == nil || len(otherUtxos) == 0 {
293                 btmServiceFlag = true
294         }
295
296         tplBuilder, err := CreateTxBuilder(baseUtxo, btmServiceFlag, signer)
297         if err != nil {
298                 return nil, err
299         }
300
301         for _, u := range otherUtxos {
302                 if err := AddTxBuilder(tplBuilder, u, signer); err != nil {
303                         return nil, err
304                 }
305         }
306
307         tpl, _, err := tplBuilder.Build()
308         if err != nil {
309                 return nil, err
310         }
311
312         return tpl, nil
313 }
314
315 func GenetrateTxbyUtxo(baseUtxo []*account.UTXO, otherUtxo [][]*account.UTXO) ([]*types.Tx, error) {
316         tmpUtxo := []*account.UTXO{}
317         txs := []*types.Tx{}
318         otherUtxoFlag := true
319
320         if len(otherUtxo) == 0 || len(otherUtxo) != len(baseUtxo) {
321                 otherUtxoFlag = false
322         }
323
324         for i := 0; i < len(baseUtxo); i++ {
325                 if otherUtxoFlag {
326                         tmpUtxo = otherUtxo[i]
327                 } else {
328                         tmpUtxo = nil
329                 }
330
331                 tpl, err := BuildTx(baseUtxo[i], tmpUtxo, nil)
332                 if err != nil {
333                         return nil, err
334                 }
335
336                 txs = append(txs, tpl.Transaction)
337         }
338
339         return txs, nil
340 }
341
342 func CreateTxbyNum(txNumber, otherAssetNum int) ([]*types.Tx, error) {
343         baseUtxos := GenerateBaseUtxos(txNumber, 1000000000, nil)
344         otherUtxos := make([][]*account.UTXO, 0, txNumber)
345         if otherAssetNum != 0 {
346                 for i := 0; i < txNumber; i++ {
347                         utxos := GenerateOtherUtxos(i, otherAssetNum, 6000, nil)
348                         otherUtxos = append(otherUtxos, utxos)
349                 }
350         }
351
352         txs, err := GenetrateTxbyUtxo(baseUtxos, otherUtxos)
353         if err != nil {
354                 return nil, err
355         }
356
357         return txs, nil
358 }
359
360 func SetUtxoView(db dbm.DB, view *state.UtxoViewpoint) error {
361         batch := db.NewBatch()
362         if err := database.SaveUtxoView(batch, view); err != nil {
363                 return err
364         }
365         batch.Write()
366         return nil
367 }
368
369 //-------------------------Mock actual transaction----------------------------------
370 func MockTxsP2PKH(keyDirPath string, testDB dbm.DB, txNumber, otherAssetNum int) ([]*types.Tx, error) {
371         accountManager := account.NewManager(testDB, nil)
372         hsm, err := pseudohsm.New(keyDirPath)
373         if err != nil {
374                 return nil, err
375         }
376
377         xpub, _, err := hsm.XCreate("TestP2PKH", "password", "en")
378         if err != nil {
379                 return nil, err
380         }
381
382         txs := []*types.Tx{}
383         for i := 0; i < txNumber; i++ {
384                 testAccountAlias := fmt.Sprintf("testAccount%d", i)
385                 testAccount, err := accountManager.Create([]chainkd.XPub{xpub.XPub}, 1, testAccountAlias, signers.BIP0044)
386                 if err != nil {
387                         return nil, err
388                 }
389
390                 controlProg, err := accountManager.CreateAddress(testAccount.ID, false)
391                 if err != nil {
392                         return nil, err
393                 }
394
395                 utxo := MockSimpleUtxo(0, consensus.BTMAssetID, 1000000000, controlProg)
396                 otherUtxos := GenerateOtherUtxos(i, otherAssetNum, 6000, controlProg)
397                 tpl, err := BuildTx(utxo, otherUtxos, testAccount.Signer)
398                 if err != nil {
399                         return nil, err
400                 }
401
402                 if _, err := MockSign(tpl, hsm, "password"); err != nil {
403                         return nil, err
404                 }
405
406                 txs = append(txs, tpl.Transaction)
407         }
408
409         return txs, nil
410 }
411
412 func MockTxsP2SH(keyDirPath string, testDB dbm.DB, txNumber, otherAssetNum int) ([]*types.Tx, error) {
413         accountManager := account.NewManager(testDB, nil)
414         hsm, err := pseudohsm.New(keyDirPath)
415         if err != nil {
416                 return nil, err
417         }
418
419         xpub1, _, err := hsm.XCreate("TestP2SH1", "password", "en")
420         if err != nil {
421                 return nil, err
422         }
423
424         xpub2, _, err := hsm.XCreate("TestP2SH2", "password", "en")
425         if err != nil {
426                 return nil, err
427         }
428
429         txs := []*types.Tx{}
430         for i := 0; i < txNumber; i++ {
431                 testAccountAlias := fmt.Sprintf("testAccount%d", i)
432                 testAccount, err := accountManager.Create([]chainkd.XPub{xpub1.XPub, xpub2.XPub}, 2, testAccountAlias, signers.BIP0044)
433                 if err != nil {
434                         return nil, err
435                 }
436
437                 controlProg, err := accountManager.CreateAddress(testAccount.ID, false)
438                 if err != nil {
439                         return nil, err
440                 }
441
442                 utxo := MockSimpleUtxo(0, consensus.BTMAssetID, 1000000000, controlProg)
443                 otherUtxos := GenerateOtherUtxos(i, otherAssetNum, 6000, controlProg)
444                 tpl, err := BuildTx(utxo, otherUtxos, testAccount.Signer)
445                 if err != nil {
446                         return nil, err
447                 }
448
449                 if _, err := MockSign(tpl, hsm, "password"); err != nil {
450                         return nil, err
451                 }
452
453                 txs = append(txs, tpl.Transaction)
454         }
455
456         return txs, nil
457 }
458
459 func MockTxsMultiSign(keyDirPath string, testDB dbm.DB, txNumber, otherAssetNum int) ([]*types.Tx, error) {
460         accountManager := account.NewManager(testDB, nil)
461         hsm, err := pseudohsm.New(keyDirPath)
462         if err != nil {
463                 return nil, err
464         }
465
466         xpub1, _, err := hsm.XCreate("TestMultilNodeSign1", "password1", "en")
467         if err != nil {
468                 return nil, err
469         }
470
471         xpub2, _, err := hsm.XCreate("TestMultilNodeSign2", "password2", "en")
472         if err != nil {
473                 return nil, err
474         }
475         txs := []*types.Tx{}
476         for i := 0; i < txNumber; i++ {
477                 testAccountAlias := fmt.Sprintf("testAccount%d", i)
478                 testAccount, err := accountManager.Create([]chainkd.XPub{xpub1.XPub, xpub2.XPub}, 2, testAccountAlias, signers.BIP0044)
479                 if err != nil {
480                         return nil, err
481                 }
482
483                 controlProg, err := accountManager.CreateAddress(testAccount.ID, false)
484                 if err != nil {
485                         return nil, err
486                 }
487
488                 utxo := MockSimpleUtxo(0, consensus.BTMAssetID, 1000000000, controlProg)
489                 otherUtxos := GenerateOtherUtxos(i, otherAssetNum, 6000, controlProg)
490                 tpl, err := BuildTx(utxo, otherUtxos, testAccount.Signer)
491                 if err != nil {
492                         return nil, err
493                 }
494
495                 if _, err := MockSign(tpl, hsm, "password1"); err != nil {
496                         return nil, err
497                 }
498
499                 if _, err := MockSign(tpl, hsm, "password2"); err != nil {
500                         return nil, err
501                 }
502
503                 txs = append(txs, tpl.Transaction)
504         }
505
506         return txs, nil
507 }