OSDN Git Service

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