github.com/palisadeinc/bor@v0.0.0-20230615125219-ab7196213d15/consensus/bor/api.go (about) 1 package bor 2 3 import ( 4 "encoding/hex" 5 "math" 6 "math/big" 7 "sort" 8 "strconv" 9 "sync" 10 11 "github.com/ethereum/go-ethereum/common" 12 "github.com/ethereum/go-ethereum/consensus" 13 "github.com/ethereum/go-ethereum/consensus/bor/valset" 14 "github.com/ethereum/go-ethereum/core/types" 15 "github.com/ethereum/go-ethereum/crypto" 16 "github.com/ethereum/go-ethereum/rpc" 17 18 lru "github.com/hashicorp/golang-lru" 19 "github.com/xsleonard/go-merkle" 20 "golang.org/x/crypto/sha3" 21 ) 22 23 var ( 24 // MaxCheckpointLength is the maximum number of blocks that can be requested for constructing a checkpoint root hash 25 MaxCheckpointLength = uint64(math.Pow(2, 15)) 26 ) 27 28 // API is a user facing RPC API to allow controlling the signer and voting 29 // mechanisms of the proof-of-authority scheme. 30 type API struct { 31 chain consensus.ChainHeaderReader 32 bor *Bor 33 rootHashCache *lru.ARCCache 34 } 35 36 // GetSnapshot retrieves the state snapshot at a given block. 37 func (api *API) GetSnapshot(number *rpc.BlockNumber) (*Snapshot, error) { 38 // Retrieve the requested block number (or current if none requested) 39 var header *types.Header 40 if number == nil || *number == rpc.LatestBlockNumber { 41 header = api.chain.CurrentHeader() 42 } else { 43 header = api.chain.GetHeaderByNumber(uint64(number.Int64())) 44 } 45 // Ensure we have an actually valid block and return its snapshot 46 if header == nil { 47 return nil, errUnknownBlock 48 } 49 50 return api.bor.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil) 51 } 52 53 type BlockSigners struct { 54 Signers []difficultiesKV 55 Diff int 56 Author common.Address 57 } 58 59 type difficultiesKV struct { 60 Signer common.Address 61 Difficulty uint64 62 } 63 64 func rankMapDifficulties(values map[common.Address]uint64) []difficultiesKV { 65 ss := make([]difficultiesKV, 0, len(values)) 66 for k, v := range values { 67 ss = append(ss, difficultiesKV{k, v}) 68 } 69 70 sort.Slice(ss, func(i, j int) bool { 71 return ss[i].Difficulty > ss[j].Difficulty 72 }) 73 74 return ss 75 } 76 77 // GetSnapshotProposerSequence retrieves the in-turn signers of all sprints in a span 78 func (api *API) GetSnapshotProposerSequence(blockNrOrHash *rpc.BlockNumberOrHash) (BlockSigners, error) { 79 var header *types.Header 80 //nolint:nestif 81 if blockNrOrHash == nil { 82 header = api.chain.CurrentHeader() 83 } else { 84 if blockNr, ok := blockNrOrHash.Number(); ok { 85 if blockNr == rpc.LatestBlockNumber { 86 header = api.chain.CurrentHeader() 87 } else { 88 header = api.chain.GetHeaderByNumber(uint64(blockNr)) 89 } 90 } else { 91 if blockHash, ok := blockNrOrHash.Hash(); ok { 92 header = api.chain.GetHeaderByHash(blockHash) 93 } 94 } 95 } 96 97 if header == nil { 98 return BlockSigners{}, errUnknownBlock 99 } 100 101 snapNumber := rpc.BlockNumber(header.Number.Int64() - 1) 102 snap, err := api.GetSnapshot(&snapNumber) 103 104 var difficulties = make(map[common.Address]uint64) 105 106 if err != nil { 107 return BlockSigners{}, err 108 } 109 110 proposer := snap.ValidatorSet.GetProposer().Address 111 proposerIndex, _ := snap.ValidatorSet.GetByAddress(proposer) 112 113 signers := snap.signers() 114 for i := 0; i < len(signers); i++ { 115 tempIndex := i 116 if tempIndex < proposerIndex { 117 tempIndex = tempIndex + len(signers) 118 } 119 120 difficulties[signers[i]] = uint64(len(signers) - (tempIndex - proposerIndex)) 121 } 122 123 rankedDifficulties := rankMapDifficulties(difficulties) 124 125 author, err := api.GetAuthor(blockNrOrHash) 126 if err != nil { 127 return BlockSigners{}, err 128 } 129 130 diff := int(difficulties[*author]) 131 blockSigners := &BlockSigners{ 132 Signers: rankedDifficulties, 133 Diff: diff, 134 Author: *author, 135 } 136 137 return *blockSigners, nil 138 } 139 140 // GetSnapshotProposer retrieves the in-turn signer at a given block. 141 func (api *API) GetSnapshotProposer(blockNrOrHash *rpc.BlockNumberOrHash) (common.Address, error) { 142 var header *types.Header 143 //nolint:nestif 144 if blockNrOrHash == nil { 145 header = api.chain.CurrentHeader() 146 } else { 147 if blockNr, ok := blockNrOrHash.Number(); ok { 148 if blockNr == rpc.LatestBlockNumber { 149 header = api.chain.CurrentHeader() 150 } else { 151 header = api.chain.GetHeaderByNumber(uint64(blockNr)) 152 } 153 } else { 154 if blockHash, ok := blockNrOrHash.Hash(); ok { 155 header = api.chain.GetHeaderByHash(blockHash) 156 } 157 } 158 } 159 160 if header == nil { 161 return common.Address{}, errUnknownBlock 162 } 163 164 snapNumber := rpc.BlockNumber(header.Number.Int64() - 1) 165 snap, err := api.GetSnapshot(&snapNumber) 166 167 if err != nil { 168 return common.Address{}, err 169 } 170 171 return snap.ValidatorSet.GetProposer().Address, nil 172 } 173 174 // GetAuthor retrieves the author a block. 175 func (api *API) GetAuthor(blockNrOrHash *rpc.BlockNumberOrHash) (*common.Address, error) { 176 // Retrieve the requested block number (or current if none requested) 177 var header *types.Header 178 179 //nolint:nestif 180 if blockNrOrHash == nil { 181 header = api.chain.CurrentHeader() 182 } else { 183 if blockNr, ok := blockNrOrHash.Number(); ok { 184 header = api.chain.GetHeaderByNumber(uint64(blockNr)) 185 if blockNr == rpc.LatestBlockNumber { 186 header = api.chain.CurrentHeader() 187 } 188 } else { 189 if blockHash, ok := blockNrOrHash.Hash(); ok { 190 header = api.chain.GetHeaderByHash(blockHash) 191 } 192 } 193 } 194 195 // Ensure we have an actually valid block and return its snapshot 196 if header == nil { 197 return nil, errUnknownBlock 198 } 199 200 author, err := api.bor.Author(header) 201 202 return &author, err 203 } 204 205 // GetSnapshotAtHash retrieves the state snapshot at a given block. 206 func (api *API) GetSnapshotAtHash(hash common.Hash) (*Snapshot, error) { 207 header := api.chain.GetHeaderByHash(hash) 208 if header == nil { 209 return nil, errUnknownBlock 210 } 211 212 return api.bor.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil) 213 } 214 215 // GetSigners retrieves the list of authorized signers at the specified block. 216 func (api *API) GetSigners(number *rpc.BlockNumber) ([]common.Address, error) { 217 // Retrieve the requested block number (or current if none requested) 218 var header *types.Header 219 if number == nil || *number == rpc.LatestBlockNumber { 220 header = api.chain.CurrentHeader() 221 } else { 222 header = api.chain.GetHeaderByNumber(uint64(number.Int64())) 223 } 224 // Ensure we have an actually valid block and return the signers from its snapshot 225 if header == nil { 226 return nil, errUnknownBlock 227 } 228 229 snap, err := api.bor.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil) 230 231 if err != nil { 232 return nil, err 233 } 234 235 return snap.signers(), nil 236 } 237 238 // GetSignersAtHash retrieves the list of authorized signers at the specified block. 239 func (api *API) GetSignersAtHash(hash common.Hash) ([]common.Address, error) { 240 header := api.chain.GetHeaderByHash(hash) 241 if header == nil { 242 return nil, errUnknownBlock 243 } 244 245 snap, err := api.bor.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil) 246 247 if err != nil { 248 return nil, err 249 } 250 251 return snap.signers(), nil 252 } 253 254 // GetCurrentProposer gets the current proposer 255 func (api *API) GetCurrentProposer() (common.Address, error) { 256 snap, err := api.GetSnapshot(nil) 257 if err != nil { 258 return common.Address{}, err 259 } 260 261 return snap.ValidatorSet.GetProposer().Address, nil 262 } 263 264 // GetCurrentValidators gets the current validators 265 func (api *API) GetCurrentValidators() ([]*valset.Validator, error) { 266 snap, err := api.GetSnapshot(nil) 267 if err != nil { 268 return make([]*valset.Validator, 0), err 269 } 270 271 return snap.ValidatorSet.Validators, nil 272 } 273 274 // GetRootHash returns the merkle root of the start to end block headers 275 func (api *API) GetRootHash(start uint64, end uint64) (string, error) { 276 if err := api.initializeRootHashCache(); err != nil { 277 return "", err 278 } 279 280 key := getRootHashKey(start, end) 281 282 if root, known := api.rootHashCache.Get(key); known { 283 return root.(string), nil 284 } 285 286 length := end - start + 1 287 288 if length > MaxCheckpointLength { 289 return "", &MaxCheckpointLengthExceededError{start, end} 290 } 291 292 currentHeaderNumber := api.chain.CurrentHeader().Number.Uint64() 293 294 if start > end || end > currentHeaderNumber { 295 return "", &valset.InvalidStartEndBlockError{Start: start, End: end, CurrentHeader: currentHeaderNumber} 296 } 297 298 blockHeaders := make([]*types.Header, end-start+1) 299 wg := new(sync.WaitGroup) 300 concurrent := make(chan bool, 20) 301 302 for i := start; i <= end; i++ { 303 wg.Add(1) 304 concurrent <- true 305 306 go func(number uint64) { 307 blockHeaders[number-start] = api.chain.GetHeaderByNumber(number) 308 309 <-concurrent 310 wg.Done() 311 }(i) 312 } 313 wg.Wait() 314 close(concurrent) 315 316 headers := make([][32]byte, nextPowerOfTwo(length)) 317 318 for i := 0; i < len(blockHeaders); i++ { 319 blockHeader := blockHeaders[i] 320 header := crypto.Keccak256(appendBytes32( 321 blockHeader.Number.Bytes(), 322 new(big.Int).SetUint64(blockHeader.Time).Bytes(), 323 blockHeader.TxHash.Bytes(), 324 blockHeader.ReceiptHash.Bytes(), 325 )) 326 327 var arr [32]byte 328 329 copy(arr[:], header) 330 headers[i] = arr 331 } 332 333 tree := merkle.NewTreeWithOpts(merkle.TreeOptions{EnableHashSorting: false, DisableHashLeaves: true}) 334 if err := tree.Generate(convert(headers), sha3.NewLegacyKeccak256()); err != nil { 335 return "", err 336 } 337 338 root := hex.EncodeToString(tree.Root().Hash) 339 api.rootHashCache.Add(key, root) 340 341 return root, nil 342 } 343 344 func (api *API) initializeRootHashCache() error { 345 var err error 346 if api.rootHashCache == nil { 347 api.rootHashCache, err = lru.NewARC(10) 348 } 349 350 return err 351 } 352 353 func getRootHashKey(start uint64, end uint64) string { 354 return strconv.FormatUint(start, 10) + "-" + strconv.FormatUint(end, 10) 355 }