OSDN Git Service

bf0c772a616928c59d743b3c6309fd66a2d63b90
[bytom/bytom.git] / api / block_retrieve.go
1 package api
2
3 import (
4         "math/big"
5
6         "github.com/bytom/blockchain/query"
7         "github.com/bytom/consensus/difficulty"
8         chainjson "github.com/bytom/encoding/json"
9         "github.com/bytom/protocol/bc"
10         "github.com/bytom/protocol/bc/types"
11 )
12
13 // return best block hash
14 func (a *API) getBestBlockHash() Response {
15         blockHash := map[string]string{"block_hash": a.chain.BestBlockHash().String()}
16         return NewSuccessResponse(blockHash)
17 }
18
19 // return current block count
20 func (a *API) getBlockCount() Response {
21         blockHeight := map[string]uint64{"block_count": a.chain.BestBlockHeight()}
22         return NewSuccessResponse(blockHeight)
23 }
24
25 // BlockTx is the tx struct for getBlock func
26 type BlockTx struct {
27         ID         bc.Hash                  `json:"id"`
28         Version    uint64                   `json:"version"`
29         Size       uint64                   `json:"size"`
30         TimeRange  uint64                   `json:"time_range"`
31         Inputs     []*query.AnnotatedInput  `json:"inputs"`
32         Outputs    []*query.AnnotatedOutput `json:"outputs"`
33         StatusFail bool                     `json:"status_fail"`
34 }
35
36 // BlockReq is used to handle getBlock req
37 type BlockReq struct {
38         BlockHeight uint64             `json:"block_height"`
39         BlockHash   chainjson.HexBytes `json:"block_hash"`
40 }
41
42 // GetBlockResp is the resp for getBlock api
43 type GetBlockResp struct {
44         Hash                   *bc.Hash   `json:"hash"`
45         Size                   uint64     `json:"size"`
46         Version                uint64     `json:"version"`
47         Height                 uint64     `json:"height"`
48         PreviousBlockHash      *bc.Hash   `json:"previous_block_hash"`
49         Timestamp              uint64     `json:"timestamp"`
50         Nonce                  uint64     `json:"nonce"`
51         Bits                   uint64     `json:"bits"`
52         Difficulty             string     `json:"difficulty"`
53         TransactionsMerkleRoot *bc.Hash   `json:"transaction_merkle_root"`
54         TransactionStatusHash  *bc.Hash   `json:"transaction_status_hash"`
55         Transactions           []*BlockTx `json:"transactions"`
56 }
57
58 // return block by hash
59 func (a *API) getBlock(ins BlockReq) Response {
60         var err error
61         block := &types.Block{}
62         if len(ins.BlockHash) == 32 {
63                 b32 := [32]byte{}
64                 copy(b32[:], ins.BlockHash)
65                 hash := bc.NewHash(b32)
66                 block, err = a.chain.GetBlockByHash(&hash)
67         } else {
68                 block, err = a.chain.GetBlockByHeight(ins.BlockHeight)
69         }
70         if err != nil {
71                 return NewErrorResponse(err)
72         }
73
74         blockHash := block.Hash()
75         txStatus, err := a.chain.GetTransactionStatus(&blockHash)
76         rawBlock, err := block.MarshalText()
77         if err != nil {
78                 return NewErrorResponse(err)
79         }
80
81         resp := &GetBlockResp{
82                 Hash:                   &blockHash,
83                 Size:                   uint64(len(rawBlock)),
84                 Version:                block.Version,
85                 Height:                 block.Height,
86                 PreviousBlockHash:      &block.PreviousBlockHash,
87                 Timestamp:              block.Timestamp,
88                 Nonce:                  block.Nonce,
89                 Bits:                   block.Bits,
90                 Difficulty:             difficulty.CalcWork(block.Bits).String(),
91                 TransactionsMerkleRoot: &block.TransactionsMerkleRoot,
92                 TransactionStatusHash:  &block.TransactionStatusHash,
93                 Transactions:           []*BlockTx{},
94         }
95
96         for i, orig := range block.Transactions {
97                 tx := &BlockTx{
98                         ID:        orig.ID,
99                         Version:   orig.Version,
100                         Size:      orig.SerializedSize,
101                         TimeRange: orig.TimeRange,
102                         Inputs:    []*query.AnnotatedInput{},
103                         Outputs:   []*query.AnnotatedOutput{},
104                 }
105                 tx.StatusFail, err = txStatus.GetStatus(i)
106                 if err != nil {
107                         NewSuccessResponse(resp)
108                 }
109
110                 for i := range orig.Inputs {
111                         tx.Inputs = append(tx.Inputs, a.wallet.BuildAnnotatedInput(orig, uint32(i)))
112                 }
113                 for i := range orig.Outputs {
114                         tx.Outputs = append(tx.Outputs, a.wallet.BuildAnnotatedOutput(orig, i))
115                 }
116                 resp.Transactions = append(resp.Transactions, tx)
117         }
118         return NewSuccessResponse(resp)
119 }
120
121 // GetBlockHeaderResp is resp struct for getBlockHeader API
122 type GetBlockHeaderResp struct {
123         BlockHeader *types.BlockHeader `json:"block_header"`
124         Reward      uint64             `json:"reward"`
125 }
126
127 func (a *API) getBlockHeader(ins BlockReq) Response {
128         var err error
129         block := &types.Block{}
130         if len(ins.BlockHash) == 32 {
131                 b32 := [32]byte{}
132                 copy(b32[:], ins.BlockHash)
133                 hash := bc.NewHash(b32)
134                 block, err = a.chain.GetBlockByHash(&hash)
135         } else {
136                 block, err = a.chain.GetBlockByHeight(ins.BlockHeight)
137         }
138         if err != nil {
139                 return NewErrorResponse(err)
140         }
141
142         resp := &GetBlockHeaderResp{
143                 BlockHeader: &block.BlockHeader,
144                 Reward:      block.Transactions[0].Outputs[0].Amount,
145         }
146         return NewSuccessResponse(resp)
147 }
148
149 // GetDifficultyResp is resp struct for getDifficulty API
150 type GetDifficultyResp struct {
151         BlockHash   *bc.Hash `json:"hash"`
152         BlockHeight uint64   `json:"height"`
153         Bits        uint64   `json:"bits"`
154         Difficulty  string   `json:"difficulty"`
155 }
156
157 func (a *API) getDifficulty(ins *BlockReq) Response {
158         var err error
159         block := &types.Block{}
160
161         if len(ins.BlockHash) == 32 && ins.BlockHash != nil {
162                 b32 := [32]byte{}
163                 copy(b32[:], ins.BlockHash)
164                 hash := bc.NewHash(b32)
165                 block, err = a.chain.GetBlockByHash(&hash)
166         } else if ins.BlockHeight > 0 {
167                 block, err = a.chain.GetBlockByHeight(ins.BlockHeight)
168         } else {
169                 hash := a.chain.BestBlockHash()
170                 block, err = a.chain.GetBlockByHash(hash)
171         }
172
173         if err != nil {
174                 return NewErrorResponse(err)
175         }
176
177         blockHash := block.Hash()
178         resp := &GetDifficultyResp{
179                 BlockHash:   &blockHash,
180                 BlockHeight: block.Height,
181                 Bits:        block.Bits,
182                 Difficulty:  difficulty.CalcWork(block.Bits).String(),
183         }
184         return NewSuccessResponse(resp)
185 }
186
187 // getHashRateResp is resp struct for getHashRate API
188 type getHashRateResp struct {
189         BlockHash   *bc.Hash `json:"hash"`
190         BlockHeight uint64   `json:"height"`
191         HashRate    uint64   `json:"hash_rate"`
192 }
193
194 func (a *API) getHashRate(ins BlockReq) Response {
195         var err error
196         block := &types.Block{}
197
198         if len(ins.BlockHash) == 32 && ins.BlockHash != nil {
199                 b32 := [32]byte{}
200                 copy(b32[:], ins.BlockHash)
201                 hash := bc.NewHash(b32)
202                 block, err = a.chain.GetBlockByHash(&hash)
203         } else if ins.BlockHeight > 0 {
204                 block, err = a.chain.GetBlockByHeight(ins.BlockHeight)
205         } else {
206                 hash := a.chain.BestBlockHash()
207                 block, err = a.chain.GetBlockByHash(hash)
208         }
209
210         if err != nil {
211                 return NewErrorResponse(err)
212         }
213
214         preBlock, err := a.chain.GetBlockByHash(&block.PreviousBlockHash)
215         if err != nil {
216                 return NewErrorResponse(err)
217         }
218
219         diffTime := block.Timestamp - preBlock.Timestamp
220         hashCount := difficulty.CalcWork(block.Bits)
221         hashRate := new(big.Int).Div(hashCount, big.NewInt(int64(diffTime)))
222
223         blockHash := block.Hash()
224         resp := &getHashRateResp{
225                 BlockHash:   &blockHash,
226                 BlockHeight: block.Height,
227                 HashRate:    hashRate.Uint64(),
228         }
229         return NewSuccessResponse(resp)
230 }