github.com/bytom/bytom@v1.1.2-0.20221014091027-bbcba3df6075/api/block_retrieve.go (about) 1 package api 2 3 import ( 4 "gopkg.in/fatih/set.v0" 5 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" 10 ) 11 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) 16 } 17 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) 22 } 23 24 // BlockTx is the tx struct for getBlock func 25 type BlockTx struct { 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"` 33 } 34 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"` 39 } 40 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"` 52 } 53 54 // return block by hash/height 55 func (a *API) getBlock(ins BlockReq) Response { 56 block, err := a.getBlockHelper(ins) 57 if err != nil { 58 return NewErrorResponse(err) 59 } 60 61 blockHash := block.Hash() 62 rawBlock, err := block.MarshalText() 63 if err != nil { 64 return NewErrorResponse(err) 65 } 66 67 var validatorPubKey string 68 if block.Height > 0 { 69 validator, err := a.chain.GetValidator(&block.PreviousBlockHash, block.Timestamp) 70 if err != nil { 71 return NewErrorResponse(err) 72 } 73 74 validatorPubKey = validator.PubKey 75 } 76 77 resp := &GetBlockResp{ 78 Hash: &blockHash, 79 Size: uint64(len(rawBlock)), 80 Version: block.Version, 81 Height: block.Height, 82 Validator: validatorPubKey, 83 PreviousBlockHash: &block.PreviousBlockHash, 84 Timestamp: block.Timestamp, 85 TransactionsMerkleRoot: &block.TransactionsMerkleRoot, 86 Transactions: []*BlockTx{}, 87 } 88 89 for _, orig := range block.Transactions { 90 tx := &BlockTx{ 91 ID: orig.ID, 92 Version: orig.Version, 93 Size: orig.SerializedSize, 94 TimeRange: orig.TimeRange, 95 Inputs: []*query.AnnotatedInput{}, 96 Outputs: []*query.AnnotatedOutput{}, 97 } 98 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 104 case *bc.VoteOutput: 105 tx.MuxID = *out.Source.Ref 106 case *bc.Retirement: 107 tx.MuxID = *out.Source.Ref 108 } 109 110 for i := range orig.Inputs { 111 tx.Inputs = append(tx.Inputs, a.wallet.BuildAnnotatedInput(orig, uint32(i))) 112 } 113 for i := range orig.Outputs { 114 tx.Outputs = append(tx.Outputs, a.wallet.BuildAnnotatedOutput(orig, i)) 115 } 116 resp.Transactions = append(resp.Transactions, tx) 117 } 118 return NewSuccessResponse(resp) 119 } 120 121 // GetRawBlockResp is resp struct for getRawBlock API 122 type GetRawBlockResp struct { 123 RawBlock *types.Block `json:"raw_block"` 124 Validator string `json:"validator"` 125 } 126 127 func (a *API) getRawBlock(ins BlockReq) Response { 128 block, err := a.getBlockHelper(ins) 129 if err != nil { 130 return NewErrorResponse(err) 131 } 132 133 var validatorPubKey string 134 if block.Height > 0 { 135 validator, err := a.chain.GetValidator(&block.PreviousBlockHash, block.Timestamp) 136 if err != nil { 137 return NewErrorResponse(err) 138 } 139 140 validatorPubKey = validator.PubKey 141 } 142 143 resp := GetRawBlockResp{ 144 RawBlock: block, 145 Validator: validatorPubKey, 146 } 147 return NewSuccessResponse(resp) 148 } 149 150 // GetBlockHeaderResp is resp struct for getBlockHeader API 151 type GetBlockHeaderResp struct { 152 BlockHeader *types.BlockHeader `json:"block_header"` 153 } 154 155 func (a *API) getBlockHeader(ins BlockReq) Response { 156 block, err := a.getBlockHelper(ins) 157 if err != nil { 158 return NewErrorResponse(err) 159 } 160 161 resp := &GetBlockHeaderResp{ 162 BlockHeader: &block.BlockHeader, 163 } 164 return NewSuccessResponse(resp) 165 } 166 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) 171 } else { 172 return a.chain.GetBlockByHeight(ins.BlockHeight) 173 } 174 } 175 176 func hexBytesToHash(hexBytes chainjson.HexBytes) bc.Hash { 177 b32 := [32]byte{} 178 copy(b32[:], hexBytes) 179 return bc.NewHash(b32) 180 } 181 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"` 186 } 187 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"` 194 } 195 196 func (a *API) getMerkleProof(ins MerkleBlockReq) Response { 197 blockReq := BlockReq{BlockHash: ins.BlockHash} 198 block, err := a.getBlockHelper(blockReq) 199 if err != nil { 200 return NewErrorResponse(err) 201 } 202 203 matchedTxs := getMatchedTx(block.Transactions, ins.TxIDs) 204 var matchedTxIDs []*bc.Hash 205 for _, tx := range matchedTxs { 206 matchedTxIDs = append(matchedTxIDs, &tx.ID) 207 } 208 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) 213 } 214 215 resp := &GetMerkleBlockResp{ 216 BlockHeader: block.BlockHeader, 217 TxHashes: hashes, 218 Flags: flags, 219 MatchedTxIDs: matchedTxIDs, 220 } 221 return NewSuccessResponse(resp) 222 } 223 224 func getMatchedTx(txs []*types.Tx, filterTxIDs []chainjson.HexBytes) []*types.Tx { 225 txIDSet := set.New() 226 for _, txID := range filterTxIDs { 227 hash := hexBytesToHash(txID) 228 txIDSet.Add(hash.String()) 229 } 230 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) 236 } 237 } 238 return matchedTxs 239 }