api.go 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  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 clique
  17. import (
  18. "encoding/json"
  19. "fmt"
  20. "github.com/ethereum/go-ethereum/common"
  21. "github.com/ethereum/go-ethereum/common/hexutil"
  22. "github.com/ethereum/go-ethereum/consensus"
  23. "github.com/ethereum/go-ethereum/core/types"
  24. "github.com/ethereum/go-ethereum/rlp"
  25. "github.com/ethereum/go-ethereum/rpc"
  26. )
  27. // API is a user facing RPC API to allow controlling the signer and voting
  28. // mechanisms of the proof-of-authority scheme.
  29. type API struct {
  30. chain consensus.ChainHeaderReader
  31. clique *Clique
  32. }
  33. // GetSnapshot retrieves the state snapshot at a given block.
  34. func (api *API) GetSnapshot(number *rpc.BlockNumber) (*Snapshot, error) {
  35. // Retrieve the requested block number (or current if none requested)
  36. var header *types.Header
  37. if number == nil || *number == rpc.LatestBlockNumber {
  38. header = api.chain.CurrentHeader()
  39. } else {
  40. header = api.chain.GetHeaderByNumber(uint64(number.Int64()))
  41. }
  42. // Ensure we have an actually valid block and return its snapshot
  43. if header == nil {
  44. return nil, errUnknownBlock
  45. }
  46. return api.clique.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil)
  47. }
  48. // GetSnapshotAtHash retrieves the state snapshot at a given block.
  49. func (api *API) GetSnapshotAtHash(hash common.Hash) (*Snapshot, error) {
  50. header := api.chain.GetHeaderByHash(hash)
  51. if header == nil {
  52. return nil, errUnknownBlock
  53. }
  54. return api.clique.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil)
  55. }
  56. // GetSigners retrieves the list of authorized signers at the specified block.
  57. func (api *API) GetSigners(number *rpc.BlockNumber) ([]common.Address, error) {
  58. // Retrieve the requested block number (or current if none requested)
  59. var header *types.Header
  60. if number == nil || *number == rpc.LatestBlockNumber {
  61. header = api.chain.CurrentHeader()
  62. } else {
  63. header = api.chain.GetHeaderByNumber(uint64(number.Int64()))
  64. }
  65. // Ensure we have an actually valid block and return the signers from its snapshot
  66. if header == nil {
  67. return nil, errUnknownBlock
  68. }
  69. snap, err := api.clique.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil)
  70. if err != nil {
  71. return nil, err
  72. }
  73. return snap.signers(), nil
  74. }
  75. // GetSignersAtHash retrieves the list of authorized signers at the specified block.
  76. func (api *API) GetSignersAtHash(hash common.Hash) ([]common.Address, error) {
  77. header := api.chain.GetHeaderByHash(hash)
  78. if header == nil {
  79. return nil, errUnknownBlock
  80. }
  81. snap, err := api.clique.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil)
  82. if err != nil {
  83. return nil, err
  84. }
  85. return snap.signers(), nil
  86. }
  87. // Proposals returns the current proposals the node tries to uphold and vote on.
  88. func (api *API) Proposals() map[common.Address]bool {
  89. api.clique.lock.RLock()
  90. defer api.clique.lock.RUnlock()
  91. proposals := make(map[common.Address]bool)
  92. for address, auth := range api.clique.proposals {
  93. proposals[address] = auth
  94. }
  95. return proposals
  96. }
  97. // Propose injects a new authorization proposal that the signer will attempt to
  98. // push through.
  99. func (api *API) Propose(address common.Address, auth bool) {
  100. api.clique.lock.Lock()
  101. defer api.clique.lock.Unlock()
  102. api.clique.proposals[address] = auth
  103. }
  104. // Discard drops a currently running proposal, stopping the signer from casting
  105. // further votes (either for or against).
  106. func (api *API) Discard(address common.Address) {
  107. api.clique.lock.Lock()
  108. defer api.clique.lock.Unlock()
  109. delete(api.clique.proposals, address)
  110. }
  111. type status struct {
  112. InturnPercent float64 `json:"inturnPercent"`
  113. SigningStatus map[common.Address]int `json:"sealerActivity"`
  114. NumBlocks uint64 `json:"numBlocks"`
  115. }
  116. // Status returns the status of the last N blocks,
  117. // - the number of active signers,
  118. // - the number of signers,
  119. // - the percentage of in-turn blocks
  120. func (api *API) Status() (*status, error) {
  121. var (
  122. numBlocks = uint64(64)
  123. header = api.chain.CurrentHeader()
  124. diff = uint64(0)
  125. optimals = 0
  126. )
  127. snap, err := api.clique.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil)
  128. if err != nil {
  129. return nil, err
  130. }
  131. var (
  132. signers = snap.signers()
  133. end = header.Number.Uint64()
  134. start = end - numBlocks
  135. )
  136. if numBlocks > end {
  137. start = 1
  138. numBlocks = end - start
  139. }
  140. signStatus := make(map[common.Address]int)
  141. for _, s := range signers {
  142. signStatus[s] = 0
  143. }
  144. for n := start; n < end; n++ {
  145. h := api.chain.GetHeaderByNumber(n)
  146. if h == nil {
  147. return nil, fmt.Errorf("missing block %d", n)
  148. }
  149. if h.Difficulty.Cmp(diffInTurn) == 0 {
  150. optimals++
  151. }
  152. diff += h.Difficulty.Uint64()
  153. sealer, err := api.clique.Author(h)
  154. if err != nil {
  155. return nil, err
  156. }
  157. signStatus[sealer]++
  158. }
  159. return &status{
  160. InturnPercent: float64(100*optimals) / float64(numBlocks),
  161. SigningStatus: signStatus,
  162. NumBlocks: numBlocks,
  163. }, nil
  164. }
  165. type blockNumberOrHashOrRLP struct {
  166. *rpc.BlockNumberOrHash
  167. RLP hexutil.Bytes `json:"rlp,omitempty"`
  168. }
  169. func (sb *blockNumberOrHashOrRLP) UnmarshalJSON(data []byte) error {
  170. bnOrHash := new(rpc.BlockNumberOrHash)
  171. // Try to unmarshal bNrOrHash
  172. if err := bnOrHash.UnmarshalJSON(data); err == nil {
  173. sb.BlockNumberOrHash = bnOrHash
  174. return nil
  175. }
  176. // Try to unmarshal RLP
  177. var input string
  178. if err := json.Unmarshal(data, &input); err != nil {
  179. return err
  180. }
  181. blob, err := hexutil.Decode(input)
  182. if err != nil {
  183. return err
  184. }
  185. sb.RLP = blob
  186. return nil
  187. }
  188. // GetSigner returns the signer for a specific clique block.
  189. // Can be called with either a blocknumber, blockhash or an rlp encoded blob.
  190. // The RLP encoded blob can either be a block or a header.
  191. func (api *API) GetSigner(rlpOrBlockNr *blockNumberOrHashOrRLP) (common.Address, error) {
  192. if len(rlpOrBlockNr.RLP) == 0 {
  193. blockNrOrHash := rlpOrBlockNr.BlockNumberOrHash
  194. var header *types.Header
  195. if blockNrOrHash == nil {
  196. header = api.chain.CurrentHeader()
  197. } else if hash, ok := blockNrOrHash.Hash(); ok {
  198. header = api.chain.GetHeaderByHash(hash)
  199. } else if number, ok := blockNrOrHash.Number(); ok {
  200. header = api.chain.GetHeaderByNumber(uint64(number.Int64()))
  201. }
  202. if header == nil {
  203. return common.Address{}, fmt.Errorf("missing block %v", blockNrOrHash.String())
  204. }
  205. return api.clique.Author(header)
  206. }
  207. block := new(types.Block)
  208. if err := rlp.DecodeBytes(rlpOrBlockNr.RLP, block); err == nil {
  209. return api.clique.Author(block.Header())
  210. }
  211. header := new(types.Header)
  212. if err := rlp.DecodeBytes(rlpOrBlockNr.RLP, header); err != nil {
  213. return common.Address{}, err
  214. }
  215. return api.clique.Author(header)
  216. }