You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

364 lines
9.8 KiB

8 years ago
7 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
7 years ago
7 years ago
7 years ago
  1. package core
  2. import (
  3. "fmt"
  4. ctypes "github.com/tendermint/tendermint/rpc/core/types"
  5. "github.com/tendermint/tendermint/types"
  6. cmn "github.com/tendermint/tmlibs/common"
  7. )
  8. // Get block headers for minHeight <= height <= maxHeight.
  9. // Block headers are returned in descending order (highest first).
  10. //
  11. // ```shell
  12. // curl 'localhost:46657/blockchain?minHeight=10&maxHeight=10'
  13. // ```
  14. //
  15. // ```go
  16. // client := client.NewHTTP("tcp://0.0.0.0:46657", "/websocket")
  17. // info, err := client.BlockchainInfo(10, 10)
  18. // ```
  19. //
  20. // > The above command returns JSON structured like this:
  21. //
  22. // ```json
  23. // {
  24. // "error": "",
  25. // "result": {
  26. // "block_metas": [
  27. // {
  28. // "header": {
  29. // "app_hash": "",
  30. // "chain_id": "test-chain-6UTNIN",
  31. // "height": 10,
  32. // "time": "2017-05-29T15:05:53.877Z",
  33. // "num_txs": 0,
  34. // "last_block_id": {
  35. // "parts": {
  36. // "hash": "3C78F00658E06744A88F24FF97A0A5011139F34A",
  37. // "total": 1
  38. // },
  39. // "hash": "F70588DAB36BDA5A953D548A16F7D48C6C2DFD78"
  40. // },
  41. // "last_commit_hash": "F31CC4282E50B3F2A58D763D233D76F26D26CABE",
  42. // "data_hash": "",
  43. // "validators_hash": "9365FC80F234C967BD233F5A3E2AB2F1E4B0E5AA"
  44. // },
  45. // "block_id": {
  46. // "parts": {
  47. // "hash": "277A4DBEF91483A18B85F2F5677ABF9694DFA40F",
  48. // "total": 1
  49. // },
  50. // "hash": "96B1D2F2D201BA4BC383EB8224139DB1294944E5"
  51. // }
  52. // }
  53. // ],
  54. // "last_height": 5493
  55. // },
  56. // "id": "",
  57. // "jsonrpc": "2.0"
  58. // }
  59. // ```
  60. //
  61. // <aside class="notice">Returns at most 20 items.</aside>
  62. func BlockchainInfo(minHeight, maxHeight int64) (*ctypes.ResultBlockchainInfo, error) {
  63. if minHeight == 0 {
  64. minHeight = 1
  65. }
  66. if maxHeight == 0 {
  67. maxHeight = blockStore.Height()
  68. } else {
  69. maxHeight = cmn.MinInt64(blockStore.Height(), maxHeight)
  70. }
  71. // maximum 20 block metas
  72. const limit int64 = 20
  73. minHeight = cmn.MaxInt64(minHeight, maxHeight-limit)
  74. logger.Debug("BlockchainInfoHandler", "maxHeight", maxHeight, "minHeight", minHeight)
  75. if minHeight > maxHeight {
  76. return nil, fmt.Errorf("min height %d can't be greater than max height %d", minHeight, maxHeight)
  77. }
  78. blockMetas := []*types.BlockMeta{}
  79. for height := maxHeight; height >= minHeight; height-- {
  80. blockMeta := blockStore.LoadBlockMeta(height)
  81. blockMetas = append(blockMetas, blockMeta)
  82. }
  83. return &ctypes.ResultBlockchainInfo{blockStore.Height(), blockMetas}, nil
  84. }
  85. // Get block at a given height.
  86. // If no height is provided, it will fetch the latest block.
  87. //
  88. // ```shell
  89. // curl 'localhost:46657/block?height=10'
  90. // ```
  91. //
  92. // ```go
  93. // client := client.NewHTTP("tcp://0.0.0.0:46657", "/websocket")
  94. // info, err := client.Block(10)
  95. // ```
  96. //
  97. // > The above command returns JSON structured like this:
  98. //
  99. // ```json
  100. // {
  101. // "error": "",
  102. // "result": {
  103. // "block": {
  104. // "last_commit": {
  105. // "precommits": [
  106. // {
  107. // "signature": {
  108. // "data": "12C0D8893B8A38224488DC1DE6270DF76BB1A5E9DB1C68577706A6A97C6EC34FFD12339183D5CA8BC2F46148773823DE905B7F6F5862FD564038BB7AE03BF50D",
  109. // "type": "ed25519"
  110. // },
  111. // "block_id": {
  112. // "parts": {
  113. // "hash": "3C78F00658E06744A88F24FF97A0A5011139F34A",
  114. // "total": 1
  115. // },
  116. // "hash": "F70588DAB36BDA5A953D548A16F7D48C6C2DFD78"
  117. // },
  118. // "type": 2,
  119. // "round": 0,
  120. // "height": 9,
  121. // "validator_index": 0,
  122. // "validator_address": "E89A51D60F68385E09E716D353373B11F8FACD62"
  123. // }
  124. // ],
  125. // "blockID": {
  126. // "parts": {
  127. // "hash": "3C78F00658E06744A88F24FF97A0A5011139F34A",
  128. // "total": 1
  129. // },
  130. // "hash": "F70588DAB36BDA5A953D548A16F7D48C6C2DFD78"
  131. // }
  132. // },
  133. // "data": {
  134. // "txs": []
  135. // },
  136. // "header": {
  137. // "app_hash": "",
  138. // "chain_id": "test-chain-6UTNIN",
  139. // "height": 10,
  140. // "time": "2017-05-29T15:05:53.877Z",
  141. // "num_txs": 0,
  142. // "last_block_id": {
  143. // "parts": {
  144. // "hash": "3C78F00658E06744A88F24FF97A0A5011139F34A",
  145. // "total": 1
  146. // },
  147. // "hash": "F70588DAB36BDA5A953D548A16F7D48C6C2DFD78"
  148. // },
  149. // "last_commit_hash": "F31CC4282E50B3F2A58D763D233D76F26D26CABE",
  150. // "data_hash": "",
  151. // "validators_hash": "9365FC80F234C967BD233F5A3E2AB2F1E4B0E5AA"
  152. // }
  153. // },
  154. // "block_meta": {
  155. // "header": {
  156. // "app_hash": "",
  157. // "chain_id": "test-chain-6UTNIN",
  158. // "height": 10,
  159. // "time": "2017-05-29T15:05:53.877Z",
  160. // "num_txs": 0,
  161. // "last_block_id": {
  162. // "parts": {
  163. // "hash": "3C78F00658E06744A88F24FF97A0A5011139F34A",
  164. // "total": 1
  165. // },
  166. // "hash": "F70588DAB36BDA5A953D548A16F7D48C6C2DFD78"
  167. // },
  168. // "last_commit_hash": "F31CC4282E50B3F2A58D763D233D76F26D26CABE",
  169. // "data_hash": "",
  170. // "validators_hash": "9365FC80F234C967BD233F5A3E2AB2F1E4B0E5AA"
  171. // },
  172. // "block_id": {
  173. // "parts": {
  174. // "hash": "277A4DBEF91483A18B85F2F5677ABF9694DFA40F",
  175. // "total": 1
  176. // },
  177. // "hash": "96B1D2F2D201BA4BC383EB8224139DB1294944E5"
  178. // }
  179. // }
  180. // },
  181. // "id": "",
  182. // "jsonrpc": "2.0"
  183. // }
  184. // ```
  185. func Block(heightPtr *int64) (*ctypes.ResultBlock, error) {
  186. storeHeight := blockStore.Height()
  187. height, err := getHeight(storeHeight, heightPtr)
  188. if err != nil {
  189. return nil, err
  190. }
  191. blockMeta := blockStore.LoadBlockMeta(height)
  192. block := blockStore.LoadBlock(height)
  193. return &ctypes.ResultBlock{blockMeta, block}, nil
  194. }
  195. // Get block commit at a given height.
  196. // If no height is provided, it will fetch the commit for the latest block.
  197. //
  198. // ```shell
  199. // curl 'localhost:46657/commit?height=11'
  200. // ```
  201. //
  202. // ```go
  203. // client := client.NewHTTP("tcp://0.0.0.0:46657", "/websocket")
  204. // info, err := client.Commit(11)
  205. // ```
  206. //
  207. // > The above command returns JSON structured like this:
  208. //
  209. // ```json
  210. // {
  211. // "error": "",
  212. // "result": {
  213. // "canonical": true,
  214. // "commit": {
  215. // "precommits": [
  216. // {
  217. // "signature": {
  218. // "data": "00970429FEC652E9E21D106A90AE8C5413759A7488775CEF4A3F44DC46C7F9D941070E4FBE9ED54DF247FA3983359A0C3A238D61DE55C75C9116D72ABC9CF50F",
  219. // "type": "ed25519"
  220. // },
  221. // "block_id": {
  222. // "parts": {
  223. // "hash": "9E37CBF266BC044A779E09D81C456E653B89E006",
  224. // "total": 1
  225. // },
  226. // "hash": "CC6E861E31CA4334E9888381B4A9137D1458AB6A"
  227. // },
  228. // "type": 2,
  229. // "round": 0,
  230. // "height": 11,
  231. // "validator_index": 0,
  232. // "validator_address": "E89A51D60F68385E09E716D353373B11F8FACD62"
  233. // }
  234. // ],
  235. // "blockID": {
  236. // "parts": {
  237. // "hash": "9E37CBF266BC044A779E09D81C456E653B89E006",
  238. // "total": 1
  239. // },
  240. // "hash": "CC6E861E31CA4334E9888381B4A9137D1458AB6A"
  241. // }
  242. // },
  243. // "header": {
  244. // "app_hash": "",
  245. // "chain_id": "test-chain-6UTNIN",
  246. // "height": 11,
  247. // "time": "2017-05-29T15:05:54.893Z",
  248. // "num_txs": 0,
  249. // "last_block_id": {
  250. // "parts": {
  251. // "hash": "277A4DBEF91483A18B85F2F5677ABF9694DFA40F",
  252. // "total": 1
  253. // },
  254. // "hash": "96B1D2F2D201BA4BC383EB8224139DB1294944E5"
  255. // },
  256. // "last_commit_hash": "3CE0C9727CE524BA9CB7C91E28F08E2B94001087",
  257. // "data_hash": "",
  258. // "validators_hash": "9365FC80F234C967BD233F5A3E2AB2F1E4B0E5AA"
  259. // }
  260. // },
  261. // "id": "",
  262. // "jsonrpc": "2.0"
  263. // }
  264. // ```
  265. func Commit(heightPtr *int64) (*ctypes.ResultCommit, error) {
  266. storeHeight := blockStore.Height()
  267. height, err := getHeight(storeHeight, heightPtr)
  268. if err != nil {
  269. return nil, err
  270. }
  271. header := blockStore.LoadBlockMeta(height).Header
  272. // If the next block has not been committed yet,
  273. // use a non-canonical commit
  274. if height == storeHeight {
  275. commit := blockStore.LoadSeenCommit(height)
  276. return ctypes.NewResultCommit(header, commit, false), nil
  277. }
  278. // Return the canonical commit (comes from the block at height+1)
  279. commit := blockStore.LoadBlockCommit(height)
  280. return ctypes.NewResultCommit(header, commit, true), nil
  281. }
  282. // BlockResults gets ABCIResults at a given height.
  283. // If no height is provided, it will fetch results for the latest block.
  284. //
  285. // Results are for the height of the block containing the txs.
  286. // Thus response.results[5] is the results of executing getBlock(h).Txs[5]
  287. //
  288. // ```shell
  289. // curl 'localhost:46657/block_results?height=10'
  290. // ```
  291. //
  292. // ```go
  293. // client := client.NewHTTP("tcp://0.0.0.0:46657", "/websocket")
  294. // info, err := client.BlockResults(10)
  295. // ```
  296. //
  297. //
  298. // > The above command returns JSON structured like this:
  299. //
  300. // ```json
  301. // {
  302. // "height": 10,
  303. // "results": [
  304. // {
  305. // "code": 0,
  306. // "data": "CAFE00F00D"
  307. // },
  308. // {
  309. // "code": 102,
  310. // "data": ""
  311. // }
  312. // ]
  313. // }
  314. // ```
  315. func BlockResults(heightPtr *int64) (*ctypes.ResultBlockResults, error) {
  316. storeHeight := blockStore.Height()
  317. height, err := getHeight(storeHeight, heightPtr)
  318. if err != nil {
  319. return nil, err
  320. }
  321. // load the results
  322. state := consensusState.GetState()
  323. results, err := state.LoadABCIResponses(height)
  324. if err != nil {
  325. return nil, err
  326. }
  327. res := &ctypes.ResultBlockResults{
  328. Height: height,
  329. Results: results,
  330. }
  331. return res, nil
  332. }
  333. func getHeight(storeHeight int64, heightPtr *int64) (int64, error) {
  334. if heightPtr != nil {
  335. height := *heightPtr
  336. if height <= 0 {
  337. return 0, fmt.Errorf("Height must be greater than 0")
  338. }
  339. if height > storeHeight {
  340. return 0, fmt.Errorf("Height must be less than or equal to the current blockchain height")
  341. }
  342. return height, nil
  343. }
  344. return storeHeight, nil
  345. }