OSDN Git Service

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