4 set "gopkg.in/fatih/set.v0"
6 "github.com/bytom/vapor/blockchain/query"
7 chainjson "github.com/bytom/vapor/encoding/json"
8 "github.com/bytom/vapor/protocol/bc"
9 "github.com/bytom/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 Witness []chainjson.HexBytes `json:"witness"`
51 Blocker string `json:"blocker"`
52 TransactionsMerkleRoot *bc.Hash `json:"transaction_merkle_root"`
53 TransactionStatusHash *bc.Hash `json:"transaction_status_hash"`
54 Transactions []*BlockTx `json:"transactions"`
57 // return block by hash/height
58 func (a *API) getBlock(ins BlockReq) Response {
59 block, err := a.getBlockHelper(ins)
61 return NewErrorResponse(err)
64 blockHash := block.Hash()
65 txStatus, err := a.chain.GetTransactionStatus(&blockHash)
66 rawBlock, err := block.MarshalText()
68 return NewErrorResponse(err)
71 witness := make([]chainjson.HexBytes, len(block.Witness))
72 for i, w := range block.Witness {
77 if blocker, err = a.chain.GetBlocker(&block.PreviousBlockHash, block.Timestamp); err != nil {
78 return NewErrorResponse(err)
82 resp := &GetBlockResp{
84 Size: uint64(len(rawBlock)),
85 Version: block.Version,
87 PreviousBlockHash: &block.PreviousBlockHash,
88 Timestamp: block.Timestamp,
91 TransactionsMerkleRoot: &block.TransactionsMerkleRoot,
92 TransactionStatusHash: &block.TransactionStatusHash,
93 Transactions: []*BlockTx{},
96 for i, orig := range block.Transactions {
99 Version: orig.Version,
100 Size: orig.SerializedSize,
101 TimeRange: orig.TimeRange,
102 Inputs: []*query.AnnotatedInput{},
103 Outputs: []*query.AnnotatedOutput{},
105 tx.StatusFail, err = txStatus.GetStatus(i)
107 return NewSuccessResponse(resp)
110 resOutID := orig.ResultIds[0]
111 switch resOut := orig.Entries[*resOutID].(type) {
112 case *bc.IntraChainOutput:
113 tx.MuxID = *resOut.Source.Ref
114 case *bc.CrossChainOutput:
115 tx.MuxID = *resOut.Source.Ref
117 tx.MuxID = *resOut.Source.Ref
119 resRetire, _ := orig.Entries[*resOutID].(*bc.Retirement)
120 tx.MuxID = *resRetire.Source.Ref
123 for i := range orig.Inputs {
124 tx.Inputs = append(tx.Inputs, a.wallet.BuildAnnotatedInput(orig, uint32(i)))
126 for i := range orig.Outputs {
127 tx.Outputs = append(tx.Outputs, a.wallet.BuildAnnotatedOutput(orig, i))
129 resp.Transactions = append(resp.Transactions, tx)
131 return NewSuccessResponse(resp)
134 // GetRawBlockResp is resp struct for getRawBlock API
135 type GetRawBlockResp struct {
136 RawBlock *types.Block `json:"raw_block"`
137 TransactionStatus *bc.TransactionStatus `json:"transaction_status"`
140 func (a *API) getRawBlock(ins BlockReq) Response {
141 block, err := a.getBlockHelper(ins)
143 return NewErrorResponse(err)
146 blockHash := block.Hash()
147 txStatus, err := a.chain.GetTransactionStatus(&blockHash)
149 return NewErrorResponse(err)
152 resp := GetRawBlockResp{
154 TransactionStatus: txStatus,
156 return NewSuccessResponse(resp)
159 // GetBlockHeaderResp is resp struct for getBlockHeader API
160 type GetBlockHeaderResp struct {
161 BlockHeader *types.BlockHeader `json:"block_header"`
162 Reward uint64 `json:"reward"`
165 func (a *API) getBlockHeader(ins BlockReq) Response {
166 block, err := a.getBlockHelper(ins)
168 return NewErrorResponse(err)
171 resp := &GetBlockHeaderResp{
172 BlockHeader: &block.BlockHeader,
173 Reward: block.Transactions[0].Outputs[0].AssetAmount().Amount,
175 return NewSuccessResponse(resp)
178 func (a *API) getBlockHelper(ins BlockReq) (*types.Block, error) {
179 if len(ins.BlockHash) == 32 {
180 hash := hexBytesToHash(ins.BlockHash)
181 return a.chain.GetBlockByHash(&hash)
183 return a.chain.GetBlockByHeight(ins.BlockHeight)
187 func hexBytesToHash(hexBytes chainjson.HexBytes) bc.Hash {
189 copy(b32[:], hexBytes)
190 return bc.NewHash(b32)
193 // MerkleBlockReq is used to handle getTxOutProof req
194 type MerkleBlockReq struct {
195 TxIDs []chainjson.HexBytes `json:"tx_ids"`
196 BlockHash chainjson.HexBytes `json:"block_hash"`
199 // GetMerkleBlockResp is resp struct for GetTxOutProof API
200 type GetMerkleBlockResp struct {
201 BlockHeader types.BlockHeader `json:"block_header"`
202 TxHashes []*bc.Hash `json:"tx_hashes"`
203 StatusHashes []*bc.Hash `json:"status_hashes"`
204 Flags []uint32 `json:"flags"`
205 MatchedTxIDs []*bc.Hash `json:"matched_tx_ids"`
208 func (a *API) getMerkleProof(ins MerkleBlockReq) Response {
209 blockReq := BlockReq{BlockHash: ins.BlockHash}
210 block, err := a.getBlockHelper(blockReq)
212 return NewErrorResponse(err)
215 matchedTxs := getMatchedTx(block.Transactions, ins.TxIDs)
216 var matchedTxIDs []*bc.Hash
217 for _, tx := range matchedTxs {
218 matchedTxIDs = append(matchedTxIDs, &tx.ID)
221 hashes, compactFlags := types.GetTxMerkleTreeProof(block.Transactions, matchedTxs)
222 flags := make([]uint32, len(compactFlags))
223 for i, flag := range compactFlags {
224 flags[i] = uint32(flag)
227 blockHash := block.Hash()
228 statuses, err := a.chain.GetTransactionStatus(&blockHash)
230 return NewErrorResponse(err)
233 statusHashes := types.GetStatusMerkleTreeProof(statuses.VerifyStatus, compactFlags)
235 resp := &GetMerkleBlockResp{
236 BlockHeader: block.BlockHeader,
238 StatusHashes: statusHashes,
240 MatchedTxIDs: matchedTxIDs,
242 return NewSuccessResponse(resp)
245 func getMatchedTx(txs []*types.Tx, filterTxIDs []chainjson.HexBytes) []*types.Tx {
247 for _, txID := range filterTxIDs {
248 hash := hexBytesToHash(txID)
249 txIDSet.Add(hash.String())
252 var matchedTxs []*types.Tx
253 for _, tx := range txs {
254 hashStr := tx.ID.String()
255 if txIDSet.Has(hashStr) {
256 matchedTxs = append(matchedTxs, tx)