4 "gopkg.in/fatih/set.v0"
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"
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)
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)
24 // BlockTx is the tx struct for getBlock func
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"`
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"`
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 Nonce uint64 `json:"nonce"`
51 Bits uint64 `json:"bits"`
52 Difficulty string `json:"difficulty"`
53 TransactionsMerkleRoot *bc.Hash `json:"transaction_merkle_root"`
54 TransactionStatusHash *bc.Hash `json:"transaction_status_hash"`
55 Transactions []*BlockTx `json:"transactions"`
58 // return block by hash/height
59 func (a *API) getBlock(ins BlockReq) Response {
60 block, err := a.getBlockHelper(ins)
62 return NewErrorResponse(err)
65 blockHash := block.Hash()
66 txStatus, err := a.chain.GetTransactionStatus(&blockHash)
67 rawBlock, err := block.MarshalText()
69 return NewErrorResponse(err)
72 resp := &GetBlockResp{
74 Size: uint64(len(rawBlock)),
75 Version: block.Version,
77 PreviousBlockHash: &block.PreviousBlockHash,
78 Timestamp: block.Timestamp,
79 // Nonce: block.Nonce,
81 // Difficulty: difficulty.CalcWork(block.Bits).String(),
82 TransactionsMerkleRoot: &block.TransactionsMerkleRoot,
83 TransactionStatusHash: &block.TransactionStatusHash,
84 Transactions: []*BlockTx{},
87 for i, orig := range block.Transactions {
90 Version: orig.Version,
91 Size: orig.SerializedSize,
92 TimeRange: orig.TimeRange,
93 Inputs: []*query.AnnotatedInput{},
94 Outputs: []*query.AnnotatedOutput{},
96 tx.StatusFail, err = txStatus.GetStatus(i)
98 return NewSuccessResponse(resp)
101 resOutID := orig.ResultIds[0]
102 resOut, ok := orig.Entries[*resOutID].(*bc.Output)
104 tx.MuxID = *resOut.Source.Ref
106 resRetire, _ := orig.Entries[*resOutID].(*bc.Retirement)
107 tx.MuxID = *resRetire.Source.Ref
110 for i := range orig.Inputs {
111 tx.Inputs = append(tx.Inputs, a.wallet.BuildAnnotatedInput(orig, uint32(i)))
113 for i := range orig.Outputs {
114 tx.Outputs = append(tx.Outputs, a.wallet.BuildAnnotatedOutput(orig, i))
116 resp.Transactions = append(resp.Transactions, tx)
118 return NewSuccessResponse(resp)
121 // GetRawBlockResp is resp struct for getRawBlock API
122 type GetRawBlockResp struct {
123 RawBlock *types.Block `json:"raw_block"`
126 func (a *API) getRawBlock(ins BlockReq) Response {
127 block, err := a.getBlockHelper(ins)
129 return NewErrorResponse(err)
132 resp := GetRawBlockResp{RawBlock: block}
133 return NewSuccessResponse(resp)
136 // GetBlockHeaderResp is resp struct for getBlockHeader API
137 type GetBlockHeaderResp struct {
138 BlockHeader *types.BlockHeader `json:"block_header"`
139 Reward uint64 `json:"reward"`
142 func (a *API) getBlockHeader(ins BlockReq) Response {
143 block, err := a.getBlockHelper(ins)
145 return NewErrorResponse(err)
148 resp := &GetBlockHeaderResp{
149 BlockHeader: &block.BlockHeader,
150 Reward: block.Transactions[0].Outputs[0].Amount,
152 return NewSuccessResponse(resp)
155 func (a *API) getBlockHelper(ins BlockReq) (*types.Block, error) {
156 if len(ins.BlockHash) == 32 {
157 hash := hexBytesToHash(ins.BlockHash)
158 return a.chain.GetBlockByHash(&hash)
160 return a.chain.GetBlockByHeight(ins.BlockHeight)
164 func hexBytesToHash(hexBytes chainjson.HexBytes) bc.Hash {
166 copy(b32[:], hexBytes)
167 return bc.NewHash(b32)
170 // GetDifficultyResp is resp struct for getDifficulty API
171 type GetDifficultyResp struct {
172 BlockHash *bc.Hash `json:"hash"`
173 BlockHeight uint64 `json:"height"`
174 Bits uint64 `json:"bits"`
175 Difficulty string `json:"difficulty"`
178 func (a *API) getDifficulty(ins BlockReq) Response {
179 block, err := a.getBlockHelper(ins)
181 return NewErrorResponse(err)
184 blockHash := block.Hash()
185 resp := &GetDifficultyResp{
186 BlockHash: &blockHash,
187 BlockHeight: block.Height,
189 //Difficulty: difficulty.CalcWork(block.Bits).String(),
191 return NewSuccessResponse(resp)
194 // getHashRateResp is resp struct for getHashRate API
195 type getHashRateResp struct {
196 BlockHash *bc.Hash `json:"hash"`
197 BlockHeight uint64 `json:"height"`
198 HashRate uint64 `json:"hash_rate"`
201 func (a *API) getHashRate(ins BlockReq) Response {
203 if len(ins.BlockHash) != 32 && len(ins.BlockHash) != 0 {
204 err := errors.New("Block hash format error.")
205 return NewErrorResponse(err)
207 if ins.BlockHeight == 0 {
208 ins.BlockHeight = a.chain.BestBlockHeight()
211 block, err := a.getBlockHelper(ins)
213 return NewErrorResponse(err)
216 preBlock, err := a.chain.GetBlockByHash(&block.PreviousBlockHash)
218 return NewErrorResponse(err)
221 diffTime := block.Timestamp - preBlock.Timestamp
222 hashCount := difficulty.CalcWork(block.Bits)
223 hashRate := new(big.Int).Div(hashCount, big.NewInt(int64(diffTime)))
225 blockHash := block.Hash()
226 resp := &getHashRateResp{
227 BlockHash: &blockHash,
228 BlockHeight: block.Height,
229 HashRate: hashRate.Uint64(),
232 return NewSuccessResponse(resp)
234 return NewSuccessResponse(nil)
237 // MerkleBlockReq is used to handle getTxOutProof req
238 type MerkleBlockReq struct {
239 TxIDs []chainjson.HexBytes `json:"tx_ids"`
240 BlockHash chainjson.HexBytes `json:"block_hash"`
243 // GetMerkleBlockResp is resp struct for GetTxOutProof API
244 type GetMerkleBlockResp struct {
245 BlockHeader types.BlockHeader `json:"block_header"`
246 TxHashes []*bc.Hash `json:"tx_hashes"`
247 StatusHashes []*bc.Hash `json:"status_hashes"`
248 Flags []uint32 `json:"flags"`
249 MatchedTxIDs []*bc.Hash `json:"matched_tx_ids"`
252 func (a *API) getMerkleProof(ins MerkleBlockReq) Response {
253 blockReq := BlockReq{BlockHash: ins.BlockHash}
254 block, err := a.getBlockHelper(blockReq)
256 return NewErrorResponse(err)
259 matchedTxs := getMatchedTx(block.Transactions, ins.TxIDs)
260 var matchedTxIDs []*bc.Hash
261 for _, tx := range matchedTxs {
262 matchedTxIDs = append(matchedTxIDs, &tx.ID)
265 hashes, compactFlags := types.GetTxMerkleTreeProof(block.Transactions, matchedTxs)
266 flags := make([]uint32, len(compactFlags))
267 for i, flag := range compactFlags {
268 flags[i] = uint32(flag)
271 blockHash := block.Hash()
272 statuses, err := a.chain.GetTransactionStatus(&blockHash)
274 return NewErrorResponse(err)
277 statusHashes := types.GetStatusMerkleTreeProof(statuses.VerifyStatus, compactFlags)
279 resp := &GetMerkleBlockResp{
280 BlockHeader: block.BlockHeader,
282 StatusHashes: statusHashes,
284 MatchedTxIDs: matchedTxIDs,
286 return NewSuccessResponse(resp)
289 func getMatchedTx(txs []*types.Tx, filterTxIDs []chainjson.HexBytes) []*types.Tx {
291 for _, txID := range filterTxIDs {
292 hash := hexBytesToHash(txID)
293 txIDSet.Add(hash.String())
296 var matchedTxs []*types.Tx
297 for _, tx := range txs {
298 hashStr := tx.ID.String()
299 if txIDSet.Has(hashStr) {
300 matchedTxs = append(matchedTxs, tx)