OSDN Git Service

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