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 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"`
54 // return block by hash/height
55 func (a *API) getBlock(ins BlockReq) Response {
56 block, err := a.getBlockHelper(ins)
58 return NewErrorResponse(err)
61 blockHash := block.Hash()
62 rawBlock, err := block.MarshalText()
64 return NewErrorResponse(err)
67 var validatorPubKey string
69 validator, err := a.chain.GetValidator(&block.PreviousBlockHash, block.Timestamp)
71 return NewErrorResponse(err)
74 validatorPubKey = validator.PubKey
77 resp := &GetBlockResp{
79 Size: uint64(len(rawBlock)),
80 Version: block.Version,
82 Validator: validatorPubKey,
83 PreviousBlockHash: &block.PreviousBlockHash,
84 Timestamp: block.Timestamp,
85 TransactionsMerkleRoot: &block.TransactionsMerkleRoot,
86 Transactions: []*BlockTx{},
89 for _, orig := range block.Transactions {
92 Version: orig.Version,
93 Size: orig.SerializedSize,
94 TimeRange: orig.TimeRange,
95 Inputs: []*query.AnnotatedInput{},
96 Outputs: []*query.AnnotatedOutput{},
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
105 tx.MuxID = *out.Source.Ref
107 tx.MuxID = *out.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"`
124 Validator string `json:"validator"`
127 func (a *API) getRawBlock(ins BlockReq) Response {
128 block, err := a.getBlockHelper(ins)
130 return NewErrorResponse(err)
133 var validatorPubKey string
134 if block.Height > 0 {
135 validator, err := a.chain.GetValidator(&block.PreviousBlockHash, block.Timestamp)
137 return NewErrorResponse(err)
140 validatorPubKey = validator.PubKey
143 resp := GetRawBlockResp{
145 Validator: validatorPubKey,
147 return NewSuccessResponse(resp)
150 // GetBlockHeaderResp is resp struct for getBlockHeader API
151 type GetBlockHeaderResp struct {
152 BlockHeader *types.BlockHeader `json:"block_header"`
155 func (a *API) getBlockHeader(ins BlockReq) Response {
156 block, err := a.getBlockHelper(ins)
158 return NewErrorResponse(err)
161 resp := &GetBlockHeaderResp{
162 BlockHeader: &block.BlockHeader,
164 return NewSuccessResponse(resp)
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)
172 return a.chain.GetBlockByHeight(ins.BlockHeight)
176 func hexBytesToHash(hexBytes chainjson.HexBytes) bc.Hash {
178 copy(b32[:], hexBytes)
179 return bc.NewHash(b32)
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"`
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"`
196 func (a *API) getMerkleProof(ins MerkleBlockReq) Response {
197 blockReq := BlockReq{BlockHash: ins.BlockHash}
198 block, err := a.getBlockHelper(blockReq)
200 return NewErrorResponse(err)
203 matchedTxs := getMatchedTx(block.Transactions, ins.TxIDs)
204 var matchedTxIDs []*bc.Hash
205 for _, tx := range matchedTxs {
206 matchedTxIDs = append(matchedTxIDs, &tx.ID)
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)
215 resp := &GetMerkleBlockResp{
216 BlockHeader: block.BlockHeader,
219 MatchedTxIDs: matchedTxIDs,
221 return NewSuccessResponse(resp)
224 func getMatchedTx(txs []*types.Tx, filterTxIDs []chainjson.HexBytes) []*types.Tx {
226 for _, txID := range filterTxIDs {
227 hash := hexBytesToHash(txID)
228 txIDSet.Add(hash.String())
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)