OSDN Git Service

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