OSDN Git Service

4108efe4fbf45311fd42b61df61f6408de81c005
[bytom/bytom-spv.git] / blockchain / blockchain_reactor.go
1 package blockchain
2
3 import (
4         log "github.com/sirupsen/logrus"
5
6         "github.com/bytom/api"
7         "github.com/bytom/blockchain/query"
8         "github.com/bytom/wallet"
9         "github.com/bytom/consensus"
10         "github.com/bytom/consensus/difficulty"
11         chainjson "github.com/bytom/encoding/json"
12         "github.com/bytom/protocol/bc"
13         "github.com/bytom/protocol/bc/types"
14 )
15
16 func (bcr *BlockchainReactor) GetNodeInfo() *api.NetInfo {
17         return &api.NetInfo{
18                 Listening:    bcr.sw.IsListening(),
19                 Syncing:      bcr.blockKeeper.IsCaughtUp(),
20                 Mining:       bcr.mining.IsMining(),
21                 PeerCount:    len(bcr.sw.Peers().List()),
22                 CurrentBlock: bcr.blockKeeper.chainHeight,
23                 HighestBlock: bcr.blockKeeper.maxPeerHeight,
24         }
25 }
26
27 func (bcr *BlockchainReactor) IsMining() bool {
28         return bcr.mining.IsMining()
29 }
30
31 // return network infomation
32 func (a *API) getNetInfo() Response {
33         return NewSuccessResponse(a.bcr.GetNodeInfo())
34 }
35
36 // return best block hash
37 func (a *API) getBestBlockHash() Response {
38         blockHash := map[string]string{"blockHash": a.chain.BestBlockHash().String()}
39         return NewSuccessResponse(blockHash)
40 }
41
42 // return block header by hash
43 func (a *API) getBlockHeaderByHash(strHash string) Response {
44         hash := bc.Hash{}
45         if err := hash.UnmarshalText([]byte(strHash)); err != nil {
46                 log.WithField("error", err).Error("Error occurs when transforming string hash to hash struct")
47                 return NewErrorResponse(err)
48         }
49         block, err := a.chain.GetBlockByHash(&hash)
50         if err != nil {
51                 log.WithField("error", err).Error("Fail to get block by hash")
52                 return NewErrorResponse(err)
53         }
54
55         bcBlock := types.MapBlock(block)
56         return NewSuccessResponse(bcBlock.BlockHeader)
57 }
58
59 // BlockTx is the tx struct for getBlock func
60 type BlockTx struct {
61         ID         bc.Hash                  `json:"id"`
62         Version    uint64                   `json:"version"`
63         Size       uint64                   `json:"size"`
64         TimeRange  uint64                   `json:"time_range"`
65         Inputs     []*query.AnnotatedInput  `json:"inputs"`
66         Outputs    []*query.AnnotatedOutput `json:"outputs"`
67         StatusFail bool                     `json:"status_fail"`
68 }
69
70 // GetBlockReq is used to handle getBlock req
71 type GetBlockReq struct {
72         BlockHeight uint64             `json:"block_height"`
73         BlockHash   chainjson.HexBytes `json:"block_hash"`
74 }
75
76 // GetBlockResp is the resp for getBlock api
77 type GetBlockResp struct {
78         Hash                   *bc.Hash   `json:"hash"`
79         Size                   uint64     `json:"size"`
80         Version                uint64     `json:"version"`
81         Height                 uint64     `json:"height"`
82         PreviousBlockHash      *bc.Hash   `json:"previous_block_hash"`
83         Timestamp              uint64     `json:"timestamp"`
84         Nonce                  uint64     `json:"nonce"`
85         Bits                   uint64     `json:"bits"`
86         Difficulty             string     `json:"difficulty"`
87         TransactionsMerkleRoot *bc.Hash   `json:"transaction_merkle_root"`
88         TransactionStatusHash  *bc.Hash   `json:"transaction_status_hash"`
89         Transactions           []*BlockTx `json:"transactions"`
90 }
91
92 // return block by hash
93 func (a *API) getBlock(ins GetBlockReq) Response {
94         var err error
95         block := &types.Block{}
96         if len(ins.BlockHash) == 32 {
97                 b32 := [32]byte{}
98                 copy(b32[:], ins.BlockHash)
99                 hash := bc.NewHash(b32)
100                 block, err = a.chain.GetBlockByHash(&hash)
101         } else {
102                 block, err = a.chain.GetBlockByHeight(ins.BlockHeight)
103         }
104         if err != nil {
105                 return NewErrorResponse(err)
106         }
107
108         blockHash := block.Hash()
109         txStatus, err := a.chain.GetTransactionStatus(&blockHash)
110         rawBlock, err := block.MarshalText()
111         if err != nil {
112                 return NewErrorResponse(err)
113         }
114
115         resp := &GetBlockResp{
116                 Hash:                   &blockHash,
117                 Size:                   uint64(len(rawBlock)),
118                 Version:                block.Version,
119                 Height:                 block.Height,
120                 PreviousBlockHash:      &block.PreviousBlockHash,
121                 Timestamp:              block.Timestamp,
122                 Nonce:                  block.Nonce,
123                 Bits:                   block.Bits,
124                 Difficulty:             difficulty.CompactToBig(block.Bits).String(),
125                 TransactionsMerkleRoot: &block.TransactionsMerkleRoot,
126                 TransactionStatusHash:  &block.TransactionStatusHash,
127                 Transactions:           []*BlockTx{},
128         }
129
130         for i, orig := range block.Transactions {
131                 tx := &BlockTx{
132                         ID:        orig.ID,
133                         Version:   orig.Version,
134                         Size:      orig.SerializedSize,
135                         TimeRange: orig.TimeRange,
136                         Inputs:    []*query.AnnotatedInput{},
137                         Outputs:   []*query.AnnotatedOutput{},
138                 }
139                 tx.StatusFail, err = txStatus.GetStatus(i)
140                 if err != nil {
141                         NewSuccessResponse(resp)
142                 }
143
144                 for i := range orig.Inputs {
145                         tx.Inputs = append(tx.Inputs, wallet.BuildAnnotatedInput(orig, uint32(i)))
146                 }
147                 for i := range orig.Outputs {
148                         tx.Outputs = append(tx.Outputs, wallet.BuildAnnotatedOutput(orig, i))
149                 }
150                 resp.Transactions = append(resp.Transactions, tx)
151         }
152         return NewSuccessResponse(resp)
153 }
154
155 // return block transactions count by hash
156 func (a *API) getBlockTransactionsCountByHash(strHash string) Response {
157         hash := bc.Hash{}
158         if err := hash.UnmarshalText([]byte(strHash)); err != nil {
159                 log.WithField("error", err).Error("Error occurs when transforming string hash to hash struct")
160                 return NewErrorResponse(err)
161         }
162
163         legacyBlock, err := a.chain.GetBlockByHash(&hash)
164         if err != nil {
165                 log.WithField("error", err).Error("Fail to get block by hash")
166                 return NewErrorResponse(err)
167         }
168
169         count := map[string]int{"count": len(legacyBlock.Transactions)}
170         return NewSuccessResponse(count)
171 }
172
173 // return block transactions count by height
174 func (a *API) getBlockTransactionsCountByHeight(height uint64) Response {
175         legacyBlock, err := a.chain.GetBlockByHeight(height)
176         if err != nil {
177                 log.WithField("error", err).Error("Fail to get block by hash")
178                 return NewErrorResponse(err)
179         }
180
181         count := map[string]int{"count": len(legacyBlock.Transactions)}
182         return NewSuccessResponse(count)
183 }
184
185 // return current block count
186 func (a *API) getBlockCount() Response {
187         blockHeight := map[string]uint64{"block_count": a.chain.Height()}
188         return NewSuccessResponse(blockHeight)
189 }
190
191 // return is in mining or not
192 func (a *API) isMining() Response {
193         IsMining := map[string]bool{"isMining": a.bcr.IsMining()}
194         return NewSuccessResponse(IsMining)
195 }
196
197 // return gasRate
198 func (a *API) gasRate() Response {
199         gasrate := map[string]int64{"gasRate": consensus.VMGasRate}
200         return NewSuccessResponse(gasrate)
201 }