4 "gopkg.in/fatih/set.v0"
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"
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 MuxID bc.Hash `json:"mux_id"`
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"`
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 PreviousBlockHash *bc.Hash `json:"previous_block_hash"`
48 Timestamp uint64 `json:"timestamp"`
49 TransactionsMerkleRoot *bc.Hash `json:"transaction_merkle_root"`
50 Transactions []*BlockTx `json:"transactions"`
53 // return block by hash/height
54 func (a *API) getBlock(ins BlockReq) Response {
55 block, err := a.getBlockHelper(ins)
57 return NewErrorResponse(err)
60 blockHash := block.Hash()
61 rawBlock, err := block.MarshalText()
63 return NewErrorResponse(err)
66 resp := &GetBlockResp{
68 Size: uint64(len(rawBlock)),
69 Version: block.Version,
71 PreviousBlockHash: &block.PreviousBlockHash,
72 Timestamp: block.Timestamp,
73 TransactionsMerkleRoot: &block.TransactionsMerkleRoot,
74 Transactions: []*BlockTx{},
77 for _, orig := range block.Transactions {
80 Version: orig.Version,
81 Size: orig.SerializedSize,
82 TimeRange: orig.TimeRange,
83 Inputs: []*query.AnnotatedInput{},
84 Outputs: []*query.AnnotatedOutput{},
87 resOutID := orig.ResultIds[0]
88 resOut, ok := orig.Entries[*resOutID].(*bc.Output)
90 tx.MuxID = *resOut.Source.Ref
92 resRetire, _ := orig.Entries[*resOutID].(*bc.Retirement)
93 tx.MuxID = *resRetire.Source.Ref
96 for i := range orig.Inputs {
97 tx.Inputs = append(tx.Inputs, a.wallet.BuildAnnotatedInput(orig, uint32(i)))
99 for i := range orig.Outputs {
100 tx.Outputs = append(tx.Outputs, a.wallet.BuildAnnotatedOutput(orig, i))
102 resp.Transactions = append(resp.Transactions, tx)
104 return NewSuccessResponse(resp)
107 // GetRawBlockResp is resp struct for getRawBlock API
108 type GetRawBlockResp struct {
109 RawBlock *types.Block `json:"raw_block"`
112 func (a *API) getRawBlock(ins BlockReq) Response {
113 block, err := a.getBlockHelper(ins)
115 return NewErrorResponse(err)
118 resp := GetRawBlockResp{
121 return NewSuccessResponse(resp)
124 // GetBlockHeaderResp is resp struct for getBlockHeader API
125 type GetBlockHeaderResp struct {
126 BlockHeader *types.BlockHeader `json:"block_header"`
127 Reward uint64 `json:"reward"`
130 func (a *API) getBlockHeader(ins BlockReq) Response {
131 block, err := a.getBlockHelper(ins)
133 return NewErrorResponse(err)
136 resp := &GetBlockHeaderResp{
137 BlockHeader: &block.BlockHeader,
138 Reward: block.Transactions[0].Outputs[0].Amount,
140 return NewSuccessResponse(resp)
143 func (a *API) getBlockHelper(ins BlockReq) (*types.Block, error) {
144 if len(ins.BlockHash) == 32 {
145 hash := hexBytesToHash(ins.BlockHash)
146 return a.chain.GetBlockByHash(&hash)
148 return a.chain.GetBlockByHeight(ins.BlockHeight)
152 func hexBytesToHash(hexBytes chainjson.HexBytes) bc.Hash {
154 copy(b32[:], hexBytes)
155 return bc.NewHash(b32)
158 // MerkleBlockReq is used to handle getTxOutProof req
159 type MerkleBlockReq struct {
160 TxIDs []chainjson.HexBytes `json:"tx_ids"`
161 BlockHash chainjson.HexBytes `json:"block_hash"`
164 // GetMerkleBlockResp is resp struct for GetTxOutProof API
165 type GetMerkleBlockResp struct {
166 BlockHeader types.BlockHeader `json:"block_header"`
167 TxHashes []*bc.Hash `json:"tx_hashes"`
168 Flags []uint32 `json:"flags"`
169 MatchedTxIDs []*bc.Hash `json:"matched_tx_ids"`
172 func (a *API) getMerkleProof(ins MerkleBlockReq) Response {
173 blockReq := BlockReq{BlockHash: ins.BlockHash}
174 block, err := a.getBlockHelper(blockReq)
176 return NewErrorResponse(err)
179 matchedTxs := getMatchedTx(block.Transactions, ins.TxIDs)
180 var matchedTxIDs []*bc.Hash
181 for _, tx := range matchedTxs {
182 matchedTxIDs = append(matchedTxIDs, &tx.ID)
185 hashes, compactFlags := types.GetTxMerkleTreeProof(block.Transactions, matchedTxs)
186 flags := make([]uint32, len(compactFlags))
187 for i, flag := range compactFlags {
188 flags[i] = uint32(flag)
191 resp := &GetMerkleBlockResp{
192 BlockHeader: block.BlockHeader,
195 MatchedTxIDs: matchedTxIDs,
197 return NewSuccessResponse(resp)
200 func getMatchedTx(txs []*types.Tx, filterTxIDs []chainjson.HexBytes) []*types.Tx {
201 txIDSet := set.New(set.ThreadSafe)
202 for _, txID := range filterTxIDs {
203 hash := hexBytesToHash(txID)
204 txIDSet.Add(hash.String())
207 var matchedTxs []*types.Tx
208 for _, tx := range txs {
209 hashStr := tx.ID.String()
210 if txIDSet.Has(hashStr) {
211 matchedTxs = append(matchedTxs, tx)