OSDN Git Service

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