OSDN Git Service

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