api.go 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. // Copyright 2017 The go-ethereum Authors
  2. // This file is part of the go-ethereum library.
  3. //
  4. // The go-ethereum library is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU Lesser General Public License as published by
  6. // the Free Software Foundation, either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // The go-ethereum library is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU Lesser General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU Lesser General Public License
  15. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
  16. package backend
  17. import (
  18. "errors"
  19. "github.com/ethereum/go-ethereum/common"
  20. "github.com/ethereum/go-ethereum/consensus"
  21. istanbulcommon "github.com/ethereum/go-ethereum/consensus/istanbul/common"
  22. "github.com/ethereum/go-ethereum/core/types"
  23. "github.com/ethereum/go-ethereum/rpc"
  24. )
  25. // API is a user facing RPC API to dump Istanbul state
  26. type API struct {
  27. chain consensus.ChainHeaderReader
  28. backend *Backend
  29. }
  30. // BlockSigners is contains who created and who signed a particular block, denoted by its number and hash
  31. type BlockSigners struct {
  32. Number uint64
  33. Hash common.Hash
  34. Author common.Address
  35. Committers []common.Address
  36. }
  37. type Status struct {
  38. SigningStatus map[common.Address]int `json:"sealerActivity"`
  39. NumBlocks uint64 `json:"numBlocks"`
  40. }
  41. // NodeAddress returns the public address that is used to sign block headers in IBFT
  42. func (api *API) NodeAddress() common.Address {
  43. return api.backend.Address()
  44. }
  45. // GetSignersFromBlock returns the signers and minter for a given block number, or the
  46. // latest block available if none is specified
  47. func (api *API) GetSignersFromBlock(number *rpc.BlockNumber) (*BlockSigners, error) {
  48. // Retrieve the requested block number (or current if none requested)
  49. var header *types.Header
  50. if number == nil || *number == rpc.LatestBlockNumber {
  51. header = api.chain.CurrentHeader()
  52. } else {
  53. header = api.chain.GetHeaderByNumber(uint64(number.Int64()))
  54. }
  55. if header == nil {
  56. return nil, istanbulcommon.ErrUnknownBlock
  57. }
  58. return api.signers(header)
  59. }
  60. // GetSignersFromBlockByHash returns the signers and minter for a given block hash
  61. func (api *API) GetSignersFromBlockByHash(hash common.Hash) (*BlockSigners, error) {
  62. header := api.chain.GetHeaderByHash(hash)
  63. if header == nil {
  64. return nil, istanbulcommon.ErrUnknownBlock
  65. }
  66. return api.signers(header)
  67. }
  68. func (api *API) signers(header *types.Header) (*BlockSigners, error) {
  69. author, err := api.backend.Author(header)
  70. if err != nil {
  71. return nil, err
  72. }
  73. committers, err := api.backend.Signers(header)
  74. if err != nil {
  75. return nil, err
  76. }
  77. return &BlockSigners{
  78. Number: header.Number.Uint64(),
  79. Hash: header.Hash(),
  80. Author: author,
  81. Committers: committers,
  82. }, nil
  83. }
  84. // GetSnapshot retrieves the state snapshot at a given block.
  85. func (api *API) GetSnapshot(number *rpc.BlockNumber) (*Snapshot, error) {
  86. // Retrieve the requested block number (or current if none requested)
  87. var header *types.Header
  88. if number == nil || *number == rpc.LatestBlockNumber {
  89. header = api.chain.CurrentHeader()
  90. } else {
  91. header = api.chain.GetHeaderByNumber(uint64(number.Int64()))
  92. }
  93. // Ensure we have an actually valid block and return its snapshot
  94. if header == nil {
  95. return nil, istanbulcommon.ErrUnknownBlock
  96. }
  97. return api.backend.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil)
  98. }
  99. // GetSnapshotAtHash retrieves the state snapshot at a given block.
  100. func (api *API) GetSnapshotAtHash(hash common.Hash) (*Snapshot, error) {
  101. header := api.chain.GetHeaderByHash(hash)
  102. if header == nil {
  103. return nil, istanbulcommon.ErrUnknownBlock
  104. }
  105. return api.backend.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil)
  106. }
  107. // GetValidators retrieves the list of authorized validators at the specified block.
  108. func (api *API) GetValidators(number *rpc.BlockNumber) ([]common.Address, error) {
  109. // Retrieve the requested block number (or current if none requested)
  110. var header *types.Header
  111. if number == nil || *number == rpc.LatestBlockNumber {
  112. header = api.chain.CurrentHeader()
  113. } else {
  114. header = api.chain.GetHeaderByNumber(uint64(number.Int64()))
  115. }
  116. // Ensure we have an actually valid block and return the validators from its snapshot
  117. if header == nil {
  118. return nil, istanbulcommon.ErrUnknownBlock
  119. }
  120. snap, err := api.backend.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil)
  121. if err != nil {
  122. return nil, err
  123. }
  124. return snap.validators(), nil
  125. }
  126. // GetValidatorsAtHash retrieves the state snapshot at a given block.
  127. func (api *API) GetValidatorsAtHash(hash common.Hash) ([]common.Address, error) {
  128. header := api.chain.GetHeaderByHash(hash)
  129. if header == nil {
  130. return nil, istanbulcommon.ErrUnknownBlock
  131. }
  132. snap, err := api.backend.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil)
  133. if err != nil {
  134. return nil, err
  135. }
  136. return snap.validators(), nil
  137. }
  138. // Candidates returns the current candidates the node tries to uphold and vote on.
  139. func (api *API) Candidates() map[common.Address]bool {
  140. api.backend.candidatesLock.RLock()
  141. defer api.backend.candidatesLock.RUnlock()
  142. proposals := make(map[common.Address]bool)
  143. for address, auth := range api.backend.candidates {
  144. proposals[address] = auth
  145. }
  146. return proposals
  147. }
  148. // Propose injects a new authorization candidate that the validator will attempt to
  149. // push through.
  150. func (api *API) Propose(address common.Address, auth bool) {
  151. api.backend.candidatesLock.Lock()
  152. defer api.backend.candidatesLock.Unlock()
  153. api.backend.candidates[address] = auth
  154. }
  155. // Discard drops a currently running candidate, stopping the validator from casting
  156. // further votes (either for or against).
  157. func (api *API) Discard(address common.Address) {
  158. api.backend.candidatesLock.Lock()
  159. defer api.backend.candidatesLock.Unlock()
  160. delete(api.backend.candidates, address)
  161. }
  162. func (api *API) Status(startBlockNum *rpc.BlockNumber, endBlockNum *rpc.BlockNumber) (*Status, error) {
  163. var (
  164. numBlocks uint64
  165. header = api.chain.CurrentHeader()
  166. start uint64
  167. end uint64
  168. blockNumber rpc.BlockNumber
  169. )
  170. if startBlockNum != nil && endBlockNum == nil {
  171. return nil, errors.New("pass the end block number")
  172. }
  173. if startBlockNum == nil && endBlockNum != nil {
  174. return nil, errors.New("pass the start block number")
  175. }
  176. if startBlockNum == nil && endBlockNum == nil {
  177. numBlocks = uint64(64)
  178. header = api.chain.CurrentHeader()
  179. end = header.Number.Uint64()
  180. start = end - numBlocks
  181. blockNumber = rpc.BlockNumber(header.Number.Int64())
  182. } else {
  183. end = uint64(*endBlockNum)
  184. start = uint64(*startBlockNum)
  185. if start > end {
  186. return nil, errors.New("start block number should be less than end block number")
  187. }
  188. if end > api.chain.CurrentHeader().Number.Uint64() {
  189. return nil, errors.New("end block number should be less than or equal to current block height")
  190. }
  191. numBlocks = end - start
  192. header = api.chain.GetHeaderByNumber(end)
  193. blockNumber = rpc.BlockNumber(end)
  194. }
  195. signers, err := api.GetValidators(&blockNumber)
  196. if err != nil {
  197. return nil, err
  198. }
  199. if numBlocks >= end {
  200. start = 1
  201. if end > start {
  202. numBlocks = end - start
  203. } else {
  204. numBlocks = 0
  205. }
  206. }
  207. signStatus := make(map[common.Address]int)
  208. for _, s := range signers {
  209. signStatus[s] = 0
  210. }
  211. for n := start; n < end; n++ {
  212. blockNum := rpc.BlockNumber(int64(n))
  213. s, _ := api.GetSignersFromBlock(&blockNum)
  214. signStatus[s.Author]++
  215. }
  216. return &Status{
  217. SigningStatus: signStatus,
  218. NumBlocks: numBlocks,
  219. }, nil
  220. }
  221. func (api *API) IsValidator(blockNum *rpc.BlockNumber) (bool, error) {
  222. var blockNumber rpc.BlockNumber
  223. if blockNum != nil {
  224. blockNumber = *blockNum
  225. } else {
  226. header := api.chain.CurrentHeader()
  227. blockNumber = rpc.BlockNumber(header.Number.Int64())
  228. }
  229. s, _ := api.GetValidators(&blockNumber)
  230. for _, v := range s {
  231. if v == api.backend.address {
  232. return true, nil
  233. }
  234. }
  235. return false, nil
  236. }