OSDN Git Service

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