OSDN Git Service

init delete the pow related (#55)
[bytom/vapor.git] / api / block_retrieve.go
1 package api
2
3 import (
4         "gopkg.in/fatih/set.v0"
5
6         "github.com/vapor/blockchain/query"
7         chainjson "github.com/vapor/encoding/json"
8         "github.com/vapor/protocol/bc"
9         "github.com/vapor/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         StatusFail bool                     `json:"status_fail"`
33         MuxID      bc.Hash                  `json:"mux_id"`
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         TransactionsMerkleRoot *bc.Hash   `json:"transaction_merkle_root"`
51         TransactionStatusHash  *bc.Hash   `json:"transaction_status_hash"`
52         Transactions           []*BlockTx `json:"transactions"`
53 }
54
55 // return block by hash/height
56 func (a *API) getBlock(ins BlockReq) Response {
57         block, err := a.getBlockHelper(ins)
58         if err != nil {
59                 return NewErrorResponse(err)
60         }
61
62         blockHash := block.Hash()
63         txStatus, err := a.chain.GetTransactionStatus(&blockHash)
64         rawBlock, err := block.MarshalText()
65         if err != nil {
66                 return NewErrorResponse(err)
67         }
68
69         resp := &GetBlockResp{
70                 Hash:                   &blockHash,
71                 Size:                   uint64(len(rawBlock)),
72                 Version:                block.Version,
73                 Height:                 block.Height,
74                 PreviousBlockHash:      &block.PreviousBlockHash,
75                 Timestamp:              block.Timestamp,
76                 TransactionsMerkleRoot: &block.TransactionsMerkleRoot,
77                 TransactionStatusHash:  &block.TransactionStatusHash,
78                 Transactions:           []*BlockTx{},
79         }
80
81         for i, orig := range block.Transactions {
82                 tx := &BlockTx{
83                         ID:        orig.ID,
84                         Version:   orig.Version,
85                         Size:      orig.SerializedSize,
86                         TimeRange: orig.TimeRange,
87                         Inputs:    []*query.AnnotatedInput{},
88                         Outputs:   []*query.AnnotatedOutput{},
89                 }
90                 tx.StatusFail, err = txStatus.GetStatus(i)
91                 if err != nil {
92                         return NewSuccessResponse(resp)
93                 }
94
95                 resOutID := orig.ResultIds[0]
96                 resOut, ok := orig.Entries[*resOutID].(*bc.Output)
97                 if ok {
98                         tx.MuxID = *resOut.Source.Ref
99                 } else {
100                         resRetire, _ := orig.Entries[*resOutID].(*bc.Retirement)
101                         tx.MuxID = *resRetire.Source.Ref
102                 }
103
104                 for i := range orig.Inputs {
105                         tx.Inputs = append(tx.Inputs, a.wallet.BuildAnnotatedInput(orig, uint32(i)))
106                 }
107                 for i := range orig.Outputs {
108                         tx.Outputs = append(tx.Outputs, a.wallet.BuildAnnotatedOutput(orig, i))
109                 }
110                 resp.Transactions = append(resp.Transactions, tx)
111         }
112         return NewSuccessResponse(resp)
113 }
114
115 // GetRawBlockResp is resp struct for getRawBlock API
116 type GetRawBlockResp struct {
117         RawBlock          *types.Block          `json:"raw_block"`
118         TransactionStatus *bc.TransactionStatus `json:"transaction_status"`
119 }
120
121 func (a *API) getRawBlock(ins BlockReq) Response {
122         block, err := a.getBlockHelper(ins)
123         if err != nil {
124                 return NewErrorResponse(err)
125         }
126
127         blockHash := block.Hash()
128         txStatus, err := a.chain.GetTransactionStatus(&blockHash)
129         if err != nil {
130                 return NewErrorResponse(err)
131         }
132
133         resp := GetRawBlockResp{
134                 RawBlock:          block,
135                 TransactionStatus: txStatus,
136         }
137         return NewSuccessResponse(resp)
138 }
139
140 // GetBlockHeaderResp is resp struct for getBlockHeader API
141 type GetBlockHeaderResp struct {
142         BlockHeader *types.BlockHeader `json:"block_header"`
143         Reward      uint64             `json:"reward"`
144 }
145
146 func (a *API) getBlockHeader(ins BlockReq) Response {
147         block, err := a.getBlockHelper(ins)
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 func (a *API) getBlockHelper(ins BlockReq) (*types.Block, error) {
160         if len(ins.BlockHash) == 32 {
161                 hash := hexBytesToHash(ins.BlockHash)
162                 return a.chain.GetBlockByHash(&hash)
163         } else {
164                 return a.chain.GetBlockByHeight(ins.BlockHeight)
165         }
166 }
167
168 func hexBytesToHash(hexBytes chainjson.HexBytes) bc.Hash {
169         b32 := [32]byte{}
170         copy(b32[:], hexBytes)
171         return bc.NewHash(b32)
172 }
173
174 // MerkleBlockReq is used to handle getTxOutProof req
175 type MerkleBlockReq struct {
176         TxIDs     []chainjson.HexBytes `json:"tx_ids"`
177         BlockHash chainjson.HexBytes   `json:"block_hash"`
178 }
179
180 // GetMerkleBlockResp is resp struct for GetTxOutProof API
181 type GetMerkleBlockResp struct {
182         BlockHeader  types.BlockHeader `json:"block_header"`
183         TxHashes     []*bc.Hash        `json:"tx_hashes"`
184         StatusHashes []*bc.Hash        `json:"status_hashes"`
185         Flags        []uint32          `json:"flags"`
186         MatchedTxIDs []*bc.Hash        `json:"matched_tx_ids"`
187 }
188
189 func (a *API) getMerkleProof(ins MerkleBlockReq) Response {
190         blockReq := BlockReq{BlockHash: ins.BlockHash}
191         block, err := a.getBlockHelper(blockReq)
192         if err != nil {
193                 return NewErrorResponse(err)
194         }
195
196         matchedTxs := getMatchedTx(block.Transactions, ins.TxIDs)
197         var matchedTxIDs []*bc.Hash
198         for _, tx := range matchedTxs {
199                 matchedTxIDs = append(matchedTxIDs, &tx.ID)
200         }
201
202         hashes, compactFlags := types.GetTxMerkleTreeProof(block.Transactions, matchedTxs)
203         flags := make([]uint32, len(compactFlags))
204         for i, flag := range compactFlags {
205                 flags[i] = uint32(flag)
206         }
207
208         blockHash := block.Hash()
209         statuses, err := a.chain.GetTransactionStatus(&blockHash)
210         if err != nil {
211                 return NewErrorResponse(err)
212         }
213
214         statusHashes := types.GetStatusMerkleTreeProof(statuses.VerifyStatus, compactFlags)
215
216         resp := &GetMerkleBlockResp{
217                 BlockHeader:  block.BlockHeader,
218                 TxHashes:     hashes,
219                 StatusHashes: statusHashes,
220                 Flags:        flags,
221                 MatchedTxIDs: matchedTxIDs,
222         }
223         return NewSuccessResponse(resp)
224 }
225
226 func getMatchedTx(txs []*types.Tx, filterTxIDs []chainjson.HexBytes) []*types.Tx {
227         txIDSet := set.New()
228         for _, txID := range filterTxIDs {
229                 hash := hexBytesToHash(txID)
230                 txIDSet.Add(hash.String())
231         }
232
233         var matchedTxs []*types.Tx
234         for _, tx := range txs {
235                 hashStr := tx.ID.String()
236                 if txIDSet.Has(hashStr) {
237                         matchedTxs = append(matchedTxs, tx)
238                 }
239         }
240         return matchedTxs
241 }