6 "gopkg.in/fatih/set.v0"
8 "github.com/vapor/blockchain/query"
9 "github.com/vapor/consensus/difficulty"
10 chainjson "github.com/vapor/encoding/json"
11 "github.com/vapor/errors"
12 "github.com/vapor/protocol/bc"
13 "github.com/vapor/protocol/bc/types"
16 // return best block hash
17 func (a *API) getBestBlockHash() Response {
18 blockHash := map[string]string{"block_hash": a.chain.BestBlockHash().String()}
19 return NewSuccessResponse(blockHash)
22 // return current block count
23 func (a *API) getBlockCount() Response {
24 blockHeight := map[string]uint64{"block_count": a.chain.BestBlockHeight()}
25 return NewSuccessResponse(blockHeight)
28 // BlockTx is the tx struct for getBlock func
30 ID bc.Hash `json:"id"`
31 Version uint64 `json:"version"`
32 Size uint64 `json:"size"`
33 TimeRange uint64 `json:"time_range"`
34 Inputs []*query.AnnotatedInput `json:"inputs"`
35 Outputs []*query.AnnotatedOutput `json:"outputs"`
36 StatusFail bool `json:"status_fail"`
37 MuxID bc.Hash `json:"mux_id"`
40 // BlockReq is used to handle getBlock req
41 type BlockReq struct {
42 BlockHeight uint64 `json:"block_height"`
43 BlockHash chainjson.HexBytes `json:"block_hash"`
46 // GetBlockResp is the resp for getBlock api
47 type GetBlockResp struct {
48 Hash *bc.Hash `json:"hash"`
49 Size uint64 `json:"size"`
50 Version uint64 `json:"version"`
51 Height uint64 `json:"height"`
52 PreviousBlockHash *bc.Hash `json:"previous_block_hash"`
53 Timestamp uint64 `json:"timestamp"`
54 Nonce uint64 `json:"nonce"`
55 Bits uint64 `json:"bits"`
56 Difficulty string `json:"difficulty"`
57 TransactionsMerkleRoot *bc.Hash `json:"transaction_merkle_root"`
58 TransactionStatusHash *bc.Hash `json:"transaction_status_hash"`
59 Transactions []*BlockTx `json:"transactions"`
62 // return block by hash/height
63 func (a *API) getBlock(ins BlockReq) Response {
64 block, err := a.getBlockHelper(ins)
66 return NewErrorResponse(err)
69 blockHash := block.Hash()
70 txStatus, err := a.chain.GetTransactionStatus(&blockHash)
71 rawBlock, err := block.MarshalText()
73 return NewErrorResponse(err)
76 resp := &GetBlockResp{
78 Size: uint64(len(rawBlock)),
79 Version: block.Version,
81 PreviousBlockHash: &block.PreviousBlockHash,
82 Timestamp: block.Timestamp,
85 Difficulty: difficulty.CalcWork(block.Bits).String(),
86 TransactionsMerkleRoot: &block.TransactionsMerkleRoot,
87 TransactionStatusHash: &block.TransactionStatusHash,
88 Transactions: []*BlockTx{},
91 for i, orig := range block.Transactions {
94 Version: orig.Version,
95 Size: orig.SerializedSize,
96 TimeRange: orig.TimeRange,
97 Inputs: []*query.AnnotatedInput{},
98 Outputs: []*query.AnnotatedOutput{},
100 tx.StatusFail, err = txStatus.GetStatus(i)
102 return NewSuccessResponse(resp)
105 resOutID := orig.ResultIds[0]
106 resOut, ok := orig.Entries[*resOutID].(*bc.Output)
108 tx.MuxID = *resOut.Source.Ref
110 resRetire, _ := orig.Entries[*resOutID].(*bc.Retirement)
111 tx.MuxID = *resRetire.Source.Ref
114 for i := range orig.Inputs {
115 tx.Inputs = append(tx.Inputs, a.wallet.BuildAnnotatedInput(orig, uint32(i)))
117 for i := range orig.Outputs {
118 tx.Outputs = append(tx.Outputs, a.wallet.BuildAnnotatedOutput(orig, i))
120 resp.Transactions = append(resp.Transactions, tx)
122 return NewSuccessResponse(resp)
125 // GetRawBlockResp is resp struct for getRawBlock API
126 type GetRawBlockResp struct {
127 RawBlock *types.Block `json:"raw_block"`
128 TransactionStatus *bc.TransactionStatus `json:"transaction_status"`
131 func (a *API) getRawBlock(ins BlockReq) Response {
132 block, err := a.getBlockHelper(ins)
134 return NewErrorResponse(err)
137 blockHash := block.Hash()
138 txStatus, err := a.chain.GetTransactionStatus(&blockHash)
140 return NewErrorResponse(err)
143 resp := GetRawBlockResp{
145 TransactionStatus: txStatus,
147 return NewSuccessResponse(resp)
150 // GetBlockHeaderResp is resp struct for getBlockHeader API
151 type GetBlockHeaderResp struct {
152 BlockHeader *types.BlockHeader `json:"block_header"`
153 Reward uint64 `json:"reward"`
156 func (a *API) getBlockHeader(ins BlockReq) Response {
157 block, err := a.getBlockHelper(ins)
159 return NewErrorResponse(err)
162 resp := &GetBlockHeaderResp{
163 BlockHeader: &block.BlockHeader,
164 Reward: block.Transactions[0].Outputs[0].Amount,
166 return NewSuccessResponse(resp)
169 func (a *API) getBlockHelper(ins BlockReq) (*types.Block, error) {
170 if len(ins.BlockHash) == 32 {
171 hash := hexBytesToHash(ins.BlockHash)
172 return a.chain.GetBlockByHash(&hash)
174 return a.chain.GetBlockByHeight(ins.BlockHeight)
178 func hexBytesToHash(hexBytes chainjson.HexBytes) bc.Hash {
180 copy(b32[:], hexBytes)
181 return bc.NewHash(b32)
184 // GetDifficultyResp is resp struct for getDifficulty API
185 type GetDifficultyResp struct {
186 BlockHash *bc.Hash `json:"hash"`
187 BlockHeight uint64 `json:"height"`
188 Bits uint64 `json:"bits"`
189 Difficulty string `json:"difficulty"`
192 func (a *API) getDifficulty(ins BlockReq) Response {
193 block, err := a.getBlockHelper(ins)
195 return NewErrorResponse(err)
198 blockHash := block.Hash()
199 resp := &GetDifficultyResp{
200 BlockHash: &blockHash,
201 BlockHeight: block.Height,
203 Difficulty: difficulty.CalcWork(block.Bits).String(),
205 return NewSuccessResponse(resp)
208 // getHashRateResp is resp struct for getHashRate API
209 type getHashRateResp struct {
210 BlockHash *bc.Hash `json:"hash"`
211 BlockHeight uint64 `json:"height"`
212 HashRate uint64 `json:"hash_rate"`
215 func (a *API) getHashRate(ins BlockReq) Response {
216 if len(ins.BlockHash) != 32 && len(ins.BlockHash) != 0 {
217 err := errors.New("Block hash format error.")
218 return NewErrorResponse(err)
220 if ins.BlockHeight == 0 {
221 ins.BlockHeight = a.chain.BestBlockHeight()
224 block, err := a.getBlockHelper(ins)
226 return NewErrorResponse(err)
229 preBlock, err := a.chain.GetBlockByHash(&block.PreviousBlockHash)
231 return NewErrorResponse(err)
234 diffTime := block.Timestamp - preBlock.Timestamp
235 if preBlock.Timestamp >= block.Timestamp {
238 hashCount := difficulty.CalcWork(block.Bits)
239 hashRate := new(big.Int).Div(hashCount, big.NewInt(int64(diffTime)))
241 blockHash := block.Hash()
242 resp := &getHashRateResp{
243 BlockHash: &blockHash,
244 BlockHeight: block.Height,
245 HashRate: hashRate.Uint64(),
247 return NewSuccessResponse(resp)
250 // MerkleBlockReq is used to handle getTxOutProof req
251 type MerkleBlockReq struct {
252 TxIDs []chainjson.HexBytes `json:"tx_ids"`
253 BlockHash chainjson.HexBytes `json:"block_hash"`
256 // GetMerkleBlockResp is resp struct for GetTxOutProof API
257 type GetMerkleBlockResp struct {
258 BlockHeader types.BlockHeader `json:"block_header"`
259 TxHashes []*bc.Hash `json:"tx_hashes"`
260 StatusHashes []*bc.Hash `json:"status_hashes"`
261 Flags []uint32 `json:"flags"`
262 MatchedTxIDs []*bc.Hash `json:"matched_tx_ids"`
265 func (a *API) getMerkleProof(ins MerkleBlockReq) Response {
266 blockReq := BlockReq{BlockHash: ins.BlockHash}
267 block, err := a.getBlockHelper(blockReq)
269 return NewErrorResponse(err)
272 matchedTxs := getMatchedTx(block.Transactions, ins.TxIDs)
273 var matchedTxIDs []*bc.Hash
274 for _, tx := range matchedTxs {
275 matchedTxIDs = append(matchedTxIDs, &tx.ID)
278 hashes, compactFlags := types.GetTxMerkleTreeProof(block.Transactions, matchedTxs)
279 flags := make([]uint32, len(compactFlags))
280 for i, flag := range compactFlags {
281 flags[i] = uint32(flag)
284 blockHash := block.Hash()
285 statuses, err := a.chain.GetTransactionStatus(&blockHash)
287 return NewErrorResponse(err)
290 statusHashes := types.GetStatusMerkleTreeProof(statuses.VerifyStatus, compactFlags)
292 resp := &GetMerkleBlockResp{
293 BlockHeader: block.BlockHeader,
295 StatusHashes: statusHashes,
297 MatchedTxIDs: matchedTxIDs,
299 return NewSuccessResponse(resp)
302 func getMatchedTx(txs []*types.Tx, filterTxIDs []chainjson.HexBytes) []*types.Tx {
304 for _, txID := range filterTxIDs {
305 hash := hexBytesToHash(txID)
306 txIDSet.Add(hash.String())
309 var matchedTxs []*types.Tx
310 for _, tx := range txs {
311 hashStr := tx.ID.String()
312 if txIDSet.Has(hashStr) {
313 matchedTxs = append(matchedTxs, tx)