api.go 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  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. "fmt"
  19. "github.com/ethereum/go-ethereum/common"
  20. "github.com/ethereum/go-ethereum/consensus"
  21. "github.com/ethereum/go-ethereum/core/types"
  22. "github.com/ethereum/go-ethereum/rpc"
  23. )
  24. // API is a user facing RPC API to allow controlling the signer and voting
  25. // mechanisms of the proof-of-authority scheme.
  26. type API struct {
  27. chain consensus.ChainHeaderReader
  28. clique *Clique
  29. }
  30. // GetSnapshot retrieves the state snapshot at a given block.
  31. func (api *API) GetSnapshot(number *rpc.BlockNumber) (*Snapshot, error) {
  32. // Retrieve the requested block number (or current if none requested)
  33. var header *types.Header
  34. if number == nil || *number == rpc.LatestBlockNumber {
  35. header = api.chain.CurrentHeader()
  36. } else {
  37. header = api.chain.GetHeaderByNumber(uint64(number.Int64()))
  38. }
  39. // Ensure we have an actually valid block and return its snapshot
  40. if header == nil {
  41. return nil, errUnknownBlock
  42. }
  43. return api.clique.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil)
  44. }
  45. // GetSnapshotAtHash retrieves the state snapshot at a given block.
  46. func (api *API) GetSnapshotAtHash(hash common.Hash) (*Snapshot, error) {
  47. header := api.chain.GetHeaderByHash(hash)
  48. if header == nil {
  49. return nil, errUnknownBlock
  50. }
  51. return api.clique.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil)
  52. }
  53. // GetSigners retrieves the list of authorized signers at the specified block.
  54. func (api *API) GetSigners(number *rpc.BlockNumber) ([]common.Address, error) {
  55. // Retrieve the requested block number (or current if none requested)
  56. var header *types.Header
  57. if number == nil || *number == rpc.LatestBlockNumber {
  58. header = api.chain.CurrentHeader()
  59. } else {
  60. header = api.chain.GetHeaderByNumber(uint64(number.Int64()))
  61. }
  62. // Ensure we have an actually valid block and return the signers from its snapshot
  63. if header == nil {
  64. return nil, errUnknownBlock
  65. }
  66. snap, err := api.clique.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil)
  67. if err != nil {
  68. return nil, err
  69. }
  70. return snap.signers(), nil
  71. }
  72. // GetSignersAtHash retrieves the list of authorized signers at the specified block.
  73. func (api *API) GetSignersAtHash(hash common.Hash) ([]common.Address, error) {
  74. header := api.chain.GetHeaderByHash(hash)
  75. if header == nil {
  76. return nil, errUnknownBlock
  77. }
  78. snap, err := api.clique.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil)
  79. if err != nil {
  80. return nil, err
  81. }
  82. return snap.signers(), nil
  83. }
  84. // Proposals returns the current proposals the node tries to uphold and vote on.
  85. func (api *API) Proposals() map[common.Address]bool {
  86. api.clique.lock.RLock()
  87. defer api.clique.lock.RUnlock()
  88. proposals := make(map[common.Address]bool)
  89. for address, auth := range api.clique.proposals {
  90. proposals[address] = auth
  91. }
  92. return proposals
  93. }
  94. // Propose injects a new authorization proposal that the signer will attempt to
  95. // push through.
  96. func (api *API) Propose(address common.Address, auth bool) {
  97. api.clique.lock.Lock()
  98. defer api.clique.lock.Unlock()
  99. api.clique.proposals[address] = auth
  100. }
  101. // Discard drops a currently running proposal, stopping the signer from casting
  102. // further votes (either for or against).
  103. func (api *API) Discard(address common.Address) {
  104. api.clique.lock.Lock()
  105. defer api.clique.lock.Unlock()
  106. delete(api.clique.proposals, address)
  107. }
  108. type status struct {
  109. InturnPercent float64 `json:"inturnPercent"`
  110. SigningStatus map[common.Address]int `json:"sealerActivity"`
  111. NumBlocks uint64 `json:"numBlocks"`
  112. }
  113. // Status returns the status of the last N blocks,
  114. // - the number of active signers,
  115. // - the number of signers,
  116. // - the percentage of in-turn blocks
  117. func (api *API) Status() (*status, error) {
  118. var (
  119. numBlocks = uint64(64)
  120. header = api.chain.CurrentHeader()
  121. diff = uint64(0)
  122. optimals = 0
  123. )
  124. snap, err := api.clique.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil)
  125. if err != nil {
  126. return nil, err
  127. }
  128. var (
  129. signers = snap.signers()
  130. end = header.Number.Uint64()
  131. start = end - numBlocks
  132. )
  133. if numBlocks > end {
  134. start = 1
  135. numBlocks = end - start
  136. }
  137. signStatus := make(map[common.Address]int)
  138. for _, s := range signers {
  139. signStatus[s] = 0
  140. }
  141. for n := start; n < end; n++ {
  142. h := api.chain.GetHeaderByNumber(n)
  143. if h == nil {
  144. return nil, fmt.Errorf("missing block %d", n)
  145. }
  146. if h.Difficulty.Cmp(diffInTurn) == 0 {
  147. optimals++
  148. }
  149. diff += h.Difficulty.Uint64()
  150. sealer, err := api.clique.Author(h)
  151. if err != nil {
  152. return nil, err
  153. }
  154. signStatus[sealer]++
  155. }
  156. return &status{
  157. InturnPercent: float64(100*optimals) / float64(numBlocks),
  158. SigningStatus: signStatus,
  159. NumBlocks: numBlocks,
  160. }, nil
  161. }