OSDN Git Service

delete some black utxo (#2129)
[bytom/bytom.git] / api / block_retrieve.go
1 package api
2
3 import (
4         "gopkg.in/fatih/set.v0"
5
6         "github.com/bytom/bytom/blockchain/query"
7         chainjson "github.com/bytom/bytom/encoding/json"
8         "github.com/bytom/bytom/protocol/bc"
9         "github.com/bytom/bytom/protocol/bc/types"
10 )
11
12 // return best block hash
13 func (a *API) getBestBlockHash() Response {
14         blockHash := map[string]string{"block_hash": a.chain.BestBlockHash().String()}
15         return NewSuccessResponse(blockHash)
16 }
17
18 // return current block count
19 func (a *API) getBlockCount() Response {
20         blockHeight := map[string]uint64{"block_count": a.chain.BestBlockHeight()}
21         return NewSuccessResponse(blockHeight)
22 }
23
24 // BlockTx is the tx struct for getBlock func
25 type BlockTx struct {
26         ID        bc.Hash                  `json:"id"`
27         Version   uint64                   `json:"version"`
28         Size      uint64                   `json:"size"`
29         TimeRange uint64                   `json:"time_range"`
30         Inputs    []*query.AnnotatedInput  `json:"inputs"`
31         Outputs   []*query.AnnotatedOutput `json:"outputs"`
32         MuxID     bc.Hash                  `json:"mux_id"`
33 }
34
35 // BlockReq is used to handle getBlock req
36 type BlockReq struct {
37         BlockHeight uint64             `json:"block_height"`
38         BlockHash   chainjson.HexBytes `json:"block_hash"`
39 }
40
41 // GetBlockResp is the resp for getBlock api
42 type GetBlockResp struct {
43         Hash                   *bc.Hash   `json:"hash"`
44         Size                   uint64     `json:"size"`
45         Version                uint64     `json:"version"`
46         Height                 uint64     `json:"height"`
47         Validator              string     `json:"validator"`
48         PreviousBlockHash      *bc.Hash   `json:"previous_block_hash"`
49         Timestamp              uint64     `json:"timestamp"`
50         TransactionsMerkleRoot *bc.Hash   `json:"transaction_merkle_root"`
51         Transactions           []*BlockTx `json:"transactions"`
52 }
53
54 // return block by hash/height
55 func (a *API) getBlock(ins BlockReq) Response {
56         block, err := a.getBlockHelper(ins)
57         if err != nil {
58                 return NewErrorResponse(err)
59         }
60
61         blockHash := block.Hash()
62         rawBlock, err := block.MarshalText()
63         if err != nil {
64                 return NewErrorResponse(err)
65         }
66
67         var validatorPubKey string
68         if block.Height > 0 {
69                 validator, err := a.chain.GetValidator(&block.PreviousBlockHash, block.Timestamp)
70                 if err != nil {
71                         return NewErrorResponse(err)
72                 }
73
74                 validatorPubKey = validator.PubKey
75         }
76
77         resp := &GetBlockResp{
78                 Hash:                   &blockHash,
79                 Size:                   uint64(len(rawBlock)),
80                 Version:                block.Version,
81                 Height:                 block.Height,
82                 Validator:              validatorPubKey,
83                 PreviousBlockHash:      &block.PreviousBlockHash,
84                 Timestamp:              block.Timestamp,
85                 TransactionsMerkleRoot: &block.TransactionsMerkleRoot,
86                 Transactions:           []*BlockTx{},
87         }
88
89         for _, orig := range block.Transactions {
90                 tx := &BlockTx{
91                         ID:        orig.ID,
92                         Version:   orig.Version,
93                         Size:      orig.SerializedSize,
94                         TimeRange: orig.TimeRange,
95                         Inputs:    []*query.AnnotatedInput{},
96                         Outputs:   []*query.AnnotatedOutput{},
97                 }
98
99                 resOutID := orig.ResultIds[0]
100                 resOut := orig.Entries[*resOutID]
101                 switch out :=resOut.(type) {
102                 case *bc.OriginalOutput:
103                         tx.MuxID = *out.Source.Ref
104                 case *bc.VoteOutput:
105                         tx.MuxID = *out.Source.Ref
106                 case *bc.Retirement:
107                         tx.MuxID = *out.Source.Ref
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 // GetRawBlockResp is resp struct for getRawBlock API
122 type GetRawBlockResp struct {
123         RawBlock  *types.Block `json:"raw_block"`
124         Validator string       `json:"validator"`
125 }
126
127 func (a *API) getRawBlock(ins BlockReq) Response {
128         block, err := a.getBlockHelper(ins)
129         if err != nil {
130                 return NewErrorResponse(err)
131         }
132
133         var validatorPubKey string
134         if block.Height > 0 {
135                 validator, err := a.chain.GetValidator(&block.PreviousBlockHash, block.Timestamp)
136                 if err != nil {
137                         return NewErrorResponse(err)
138                 }
139
140                 validatorPubKey = validator.PubKey
141         }
142
143         resp := GetRawBlockResp{
144                 RawBlock:  block,
145                 Validator: validatorPubKey,
146         }
147         return NewSuccessResponse(resp)
148 }
149
150 // GetBlockHeaderResp is resp struct for getBlockHeader API
151 type GetBlockHeaderResp struct {
152         BlockHeader *types.BlockHeader `json:"block_header"`
153 }
154
155 func (a *API) getBlockHeader(ins BlockReq) Response {
156         block, err := a.getBlockHelper(ins)
157         if err != nil {
158                 return NewErrorResponse(err)
159         }
160
161         resp := &GetBlockHeaderResp{
162                 BlockHeader: &block.BlockHeader,
163         }
164         return NewSuccessResponse(resp)
165 }
166
167 func (a *API) getBlockHelper(ins BlockReq) (*types.Block, error) {
168         if len(ins.BlockHash) == 32 {
169                 hash := hexBytesToHash(ins.BlockHash)
170                 return a.chain.GetBlockByHash(&hash)
171         } else {
172                 return a.chain.GetBlockByHeight(ins.BlockHeight)
173         }
174 }
175
176 func hexBytesToHash(hexBytes chainjson.HexBytes) bc.Hash {
177         b32 := [32]byte{}
178         copy(b32[:], hexBytes)
179         return bc.NewHash(b32)
180 }
181
182 // MerkleBlockReq is used to handle getTxOutProof req
183 type MerkleBlockReq struct {
184         TxIDs     []chainjson.HexBytes `json:"tx_ids"`
185         BlockHash chainjson.HexBytes   `json:"block_hash"`
186 }
187
188 // GetMerkleBlockResp is resp struct for GetTxOutProof API
189 type GetMerkleBlockResp struct {
190         BlockHeader  types.BlockHeader `json:"block_header"`
191         TxHashes     []*bc.Hash        `json:"tx_hashes"`
192         Flags        []uint32          `json:"flags"`
193         MatchedTxIDs []*bc.Hash        `json:"matched_tx_ids"`
194 }
195
196 func (a *API) getMerkleProof(ins MerkleBlockReq) Response {
197         blockReq := BlockReq{BlockHash: ins.BlockHash}
198         block, err := a.getBlockHelper(blockReq)
199         if err != nil {
200                 return NewErrorResponse(err)
201         }
202
203         matchedTxs := getMatchedTx(block.Transactions, ins.TxIDs)
204         var matchedTxIDs []*bc.Hash
205         for _, tx := range matchedTxs {
206                 matchedTxIDs = append(matchedTxIDs, &tx.ID)
207         }
208
209         hashes, compactFlags := types.GetTxMerkleTreeProof(block.Transactions, matchedTxs)
210         flags := make([]uint32, len(compactFlags))
211         for i, flag := range compactFlags {
212                 flags[i] = uint32(flag)
213         }
214
215         resp := &GetMerkleBlockResp{
216                 BlockHeader:  block.BlockHeader,
217                 TxHashes:     hashes,
218                 Flags:        flags,
219                 MatchedTxIDs: matchedTxIDs,
220         }
221         return NewSuccessResponse(resp)
222 }
223
224 func getMatchedTx(txs []*types.Tx, filterTxIDs []chainjson.HexBytes) []*types.Tx {
225         txIDSet := set.New()
226         for _, txID := range filterTxIDs {
227                 hash := hexBytesToHash(txID)
228                 txIDSet.Add(hash.String())
229         }
230
231         var matchedTxs []*types.Tx
232         for _, tx := range txs {
233                 hashStr := tx.ID.String()
234                 if txIDSet.Has(hashStr) {
235                         matchedTxs = append(matchedTxs, tx)
236                 }
237         }
238         return matchedTxs
239 }