OSDN Git Service

Merge pull request #987 from Bytom/dev-sourceid
[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         MuxID      bc.Hash                  `json:"mux_id"`
35 }
36
37 // BlockReq is used to handle getBlock req
38 type BlockReq struct {
39         BlockHeight uint64             `json:"block_height"`
40         BlockHash   chainjson.HexBytes `json:"block_hash"`
41 }
42
43 // GetBlockResp is the resp for getBlock api
44 type GetBlockResp struct {
45         Hash                   *bc.Hash   `json:"hash"`
46         Size                   uint64     `json:"size"`
47         Version                uint64     `json:"version"`
48         Height                 uint64     `json:"height"`
49         PreviousBlockHash      *bc.Hash   `json:"previous_block_hash"`
50         Timestamp              uint64     `json:"timestamp"`
51         Nonce                  uint64     `json:"nonce"`
52         Bits                   uint64     `json:"bits"`
53         Difficulty             string     `json:"difficulty"`
54         TransactionsMerkleRoot *bc.Hash   `json:"transaction_merkle_root"`
55         TransactionStatusHash  *bc.Hash   `json:"transaction_status_hash"`
56         Transactions           []*BlockTx `json:"transactions"`
57 }
58
59 // return block by hash
60 func (a *API) getBlock(ins BlockReq) Response {
61         var err error
62         block := &types.Block{}
63         if len(ins.BlockHash) == 32 {
64                 b32 := [32]byte{}
65                 copy(b32[:], ins.BlockHash)
66                 hash := bc.NewHash(b32)
67                 block, err = a.chain.GetBlockByHash(&hash)
68         } else {
69                 block, err = a.chain.GetBlockByHeight(ins.BlockHeight)
70         }
71         if err != nil {
72                 return NewErrorResponse(err)
73         }
74
75         blockHash := block.Hash()
76         txStatus, err := a.chain.GetTransactionStatus(&blockHash)
77         rawBlock, err := block.MarshalText()
78         if err != nil {
79                 return NewErrorResponse(err)
80         }
81
82         resp := &GetBlockResp{
83                 Hash:                   &blockHash,
84                 Size:                   uint64(len(rawBlock)),
85                 Version:                block.Version,
86                 Height:                 block.Height,
87                 PreviousBlockHash:      &block.PreviousBlockHash,
88                 Timestamp:              block.Timestamp,
89                 Nonce:                  block.Nonce,
90                 Bits:                   block.Bits,
91                 Difficulty:             difficulty.CalcWork(block.Bits).String(),
92                 TransactionsMerkleRoot: &block.TransactionsMerkleRoot,
93                 TransactionStatusHash:  &block.TransactionStatusHash,
94                 Transactions:           []*BlockTx{},
95         }
96
97         for i, orig := range block.Transactions {
98                 tx := &BlockTx{
99                         ID:        orig.ID,
100                         Version:   orig.Version,
101                         Size:      orig.SerializedSize,
102                         TimeRange: orig.TimeRange,
103                         Inputs:    []*query.AnnotatedInput{},
104                         Outputs:   []*query.AnnotatedOutput{},
105                 }
106                 tx.StatusFail, err = txStatus.GetStatus(i)
107                 if err != nil {
108                         NewSuccessResponse(resp)
109                 }
110
111                 resOutID := orig.ResultIds[0]
112                 resOut, ok := orig.Entries[*resOutID].(*bc.Output)
113                 if ok {
114                         tx.MuxID = *resOut.Source.Ref
115                 } else {
116                         resRetire, _ := orig.Entries[*resOutID].(*bc.Retirement)
117                         tx.MuxID = *resRetire.Source.Ref
118                 }
119
120                 for i := range orig.Inputs {
121                         tx.Inputs = append(tx.Inputs, a.wallet.BuildAnnotatedInput(orig, uint32(i)))
122                 }
123                 for i := range orig.Outputs {
124                         tx.Outputs = append(tx.Outputs, a.wallet.BuildAnnotatedOutput(orig, i))
125                 }
126                 resp.Transactions = append(resp.Transactions, tx)
127         }
128         return NewSuccessResponse(resp)
129 }
130
131 // GetBlockHeaderResp is resp struct for getBlockHeader API
132 type GetBlockHeaderResp struct {
133         BlockHeader *types.BlockHeader `json:"block_header"`
134         Reward      uint64             `json:"reward"`
135 }
136
137 func (a *API) getBlockHeader(ins BlockReq) Response {
138         var err error
139         block := &types.Block{}
140         if len(ins.BlockHash) == 32 {
141                 b32 := [32]byte{}
142                 copy(b32[:], ins.BlockHash)
143                 hash := bc.NewHash(b32)
144                 block, err = a.chain.GetBlockByHash(&hash)
145         } else {
146                 block, err = a.chain.GetBlockByHeight(ins.BlockHeight)
147         }
148         if err != nil {
149                 return NewErrorResponse(err)
150         }
151
152         resp := &GetBlockHeaderResp{
153                 BlockHeader: &block.BlockHeader,
154                 Reward:      block.Transactions[0].Outputs[0].Amount,
155         }
156         return NewSuccessResponse(resp)
157 }
158
159 // GetDifficultyResp is resp struct for getDifficulty API
160 type GetDifficultyResp struct {
161         BlockHash   *bc.Hash `json:"hash"`
162         BlockHeight uint64   `json:"height"`
163         Bits        uint64   `json:"bits"`
164         Difficulty  string   `json:"difficulty"`
165 }
166
167 func (a *API) getDifficulty(ins *BlockReq) Response {
168         var err error
169         block := &types.Block{}
170
171         if len(ins.BlockHash) == 32 && ins.BlockHash != nil {
172                 b32 := [32]byte{}
173                 copy(b32[:], ins.BlockHash)
174                 hash := bc.NewHash(b32)
175                 block, err = a.chain.GetBlockByHash(&hash)
176         } else if ins.BlockHeight > 0 {
177                 block, err = a.chain.GetBlockByHeight(ins.BlockHeight)
178         } else {
179                 hash := a.chain.BestBlockHash()
180                 block, err = a.chain.GetBlockByHash(hash)
181         }
182
183         if err != nil {
184                 return NewErrorResponse(err)
185         }
186
187         blockHash := block.Hash()
188         resp := &GetDifficultyResp{
189                 BlockHash:   &blockHash,
190                 BlockHeight: block.Height,
191                 Bits:        block.Bits,
192                 Difficulty:  difficulty.CalcWork(block.Bits).String(),
193         }
194         return NewSuccessResponse(resp)
195 }
196
197 // getHashRateResp is resp struct for getHashRate API
198 type getHashRateResp struct {
199         BlockHash   *bc.Hash `json:"hash"`
200         BlockHeight uint64   `json:"height"`
201         HashRate    uint64   `json:"hash_rate"`
202 }
203
204 func (a *API) getHashRate(ins BlockReq) Response {
205         var err error
206         block := &types.Block{}
207
208         if len(ins.BlockHash) == 32 && ins.BlockHash != nil {
209                 b32 := [32]byte{}
210                 copy(b32[:], ins.BlockHash)
211                 hash := bc.NewHash(b32)
212                 block, err = a.chain.GetBlockByHash(&hash)
213         } else if ins.BlockHeight > 0 {
214                 block, err = a.chain.GetBlockByHeight(ins.BlockHeight)
215         } else {
216                 hash := a.chain.BestBlockHash()
217                 block, err = a.chain.GetBlockByHash(hash)
218         }
219
220         if err != nil {
221                 return NewErrorResponse(err)
222         }
223
224         preBlock, err := a.chain.GetBlockByHash(&block.PreviousBlockHash)
225         if err != nil {
226                 return NewErrorResponse(err)
227         }
228
229         diffTime := block.Timestamp - preBlock.Timestamp
230         hashCount := difficulty.CalcWork(block.Bits)
231         hashRate := new(big.Int).Div(hashCount, big.NewInt(int64(diffTime)))
232
233         blockHash := block.Hash()
234         resp := &getHashRateResp{
235                 BlockHash:   &blockHash,
236                 BlockHeight: block.Height,
237                 HashRate:    hashRate.Uint64(),
238         }
239         return NewSuccessResponse(resp)
240 }