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.

314 lines
8.9 KiB

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