OSDN Git Service

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