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.

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