OSDN Git Service

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