OSDN Git Service

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