OSDN Git Service

Merge pull request #33 from Bytom/dev_optimize_consensus
[bytom/vapor.git] / test / block_test_util.go
1 package test
2
3 import (
4         "github.com/vapor/consensus"
5         "github.com/vapor/crypto"
6         "github.com/vapor/crypto/ed25519/chainkd"
7         "github.com/vapor/errors"
8         "github.com/vapor/protocol"
9         "github.com/vapor/protocol/bc"
10         "github.com/vapor/protocol/bc/types"
11         "github.com/vapor/protocol/validation"
12         "github.com/vapor/protocol/vm"
13         "github.com/vapor/protocol/vm/vmutil"
14 )
15
16 // NewBlock create block according to the current status of chain
17 func NewBlock(chain *protocol.Chain, txs []*types.Tx, controlProgram []byte) (*types.Block, error) {
18         gasUsed := uint64(0)
19         txsFee := uint64(0)
20         txEntries := []*bc.Tx{nil}
21         txStatus := bc.NewTransactionStatus()
22         if err := txStatus.SetStatus(0, false); err != nil {
23                 return nil, err
24         }
25
26         preBlockHeader := chain.BestBlockHeader()
27
28         b := &types.Block{
29                 BlockHeader: types.BlockHeader{
30                         Version:           1,
31                         Height:            preBlockHeader.Height + 1,
32                         PreviousBlockHash: preBlockHeader.Hash(),
33                         Timestamp:         preBlockHeader.Timestamp + 1,
34                         BlockCommitment:   types.BlockCommitment{},
35                 },
36                 Transactions: []*types.Tx{nil},
37         }
38
39         bcBlock := &bc.Block{BlockHeader: &bc.BlockHeader{Height: preBlockHeader.Height + 1}}
40         for _, tx := range txs {
41                 gasOnlyTx := false
42                 gasStatus, err := validation.ValidateTx(tx.Tx, bcBlock)
43                 if err != nil {
44                         if !gasStatus.GasValid {
45                                 continue
46                         }
47                         gasOnlyTx = true
48                 }
49
50                 txStatus.SetStatus(len(b.Transactions), gasOnlyTx)
51                 b.Transactions = append(b.Transactions, tx)
52                 txEntries = append(txEntries, tx.Tx)
53                 gasUsed += uint64(gasStatus.GasUsed)
54                 txsFee += txFee(tx)
55         }
56
57         coinbaseTx, err := CreateCoinbaseTx(controlProgram, preBlockHeader.Height+1, txsFee)
58         if err != nil {
59                 return nil, err
60         }
61
62         b.Transactions[0] = coinbaseTx
63         txEntries[0] = coinbaseTx.Tx
64         b.TransactionsMerkleRoot, err = types.TxMerkleRoot(txEntries)
65         if err != nil {
66                 return nil, err
67         }
68
69         b.TransactionStatusHash, err = types.TxStatusMerkleRoot(txStatus.VerifyStatus)
70         proof, err := generateProof(*b)
71         if err != nil {
72                 return nil, err
73         }
74         b.Proof = proof
75         return b, err
76 }
77
78 func generateProof(block types.Block) (types.Proof, error) {
79         var xPrv chainkd.XPrv
80         if consensus.ActiveNetParams.Signer == "" {
81                 return types.Proof{}, errors.New("Signer is empty")
82         }
83         xPrv.UnmarshalText([]byte(consensus.ActiveNetParams.Signer))
84         sign := xPrv.Sign(block.BlockCommitment.TransactionsMerkleRoot.Bytes())
85         pubHash := crypto.Ripemd160(xPrv.XPub().PublicKey())
86         control, err := vmutil.P2WPKHProgram([]byte(pubHash))
87         if err != nil {
88                 return types.Proof{}, err
89         }
90         return types.Proof{Sign: sign, ControlProgram: control}, nil
91 }
92
93 // ReplaceCoinbase replace the coinbase tx of block with coinbaseTx
94 func ReplaceCoinbase(block *types.Block, coinbaseTx *types.Tx) (err error) {
95         block.Transactions[0] = coinbaseTx
96         txEntires := []*bc.Tx{coinbaseTx.Tx}
97         for i := 1; i < len(block.Transactions); i++ {
98                 txEntires = append(txEntires, block.Transactions[i].Tx)
99         }
100
101         block.TransactionsMerkleRoot, err = types.TxMerkleRoot(txEntires)
102         return
103 }
104
105 // AppendBlocks append empty blocks to chain, mainly used to mature the coinbase tx
106 func AppendBlocks(chain *protocol.Chain, num uint64) error {
107         for i := uint64(0); i < num; i++ {
108                 block, err := NewBlock(chain, nil, []byte{byte(vm.OP_TRUE)})
109                 if err != nil {
110                         return err
111                 }
112                 if err := SolveAndUpdate(chain, block); err != nil {
113                         return err
114                 }
115         }
116         return nil
117 }
118
119 // SolveAndUpdate solve difficulty and update chain status
120 func SolveAndUpdate(chain *protocol.Chain, block *types.Block) error {
121         _, err := chain.ProcessBlock(block)
122         return err
123 }