github.com/ImPedro29/bor@v0.2.7/consensus/bor/api.go (about) 1 package bor 2 3 import ( 4 "encoding/hex" 5 "math" 6 "math/big" 7 "strconv" 8 "sync" 9 10 "github.com/ethereum/go-ethereum/common" 11 "github.com/ethereum/go-ethereum/consensus" 12 "github.com/ethereum/go-ethereum/core/types" 13 "github.com/ethereum/go-ethereum/crypto" 14 "github.com/ethereum/go-ethereum/rpc" 15 lru "github.com/hashicorp/golang-lru" 16 "github.com/xsleonard/go-merkle" 17 "golang.org/x/crypto/sha3" 18 ) 19 20 var ( 21 // MaxCheckpointLength is the maximum number of blocks that can be requested for constructing a checkpoint root hash 22 MaxCheckpointLength = uint64(math.Pow(2, 15)) 23 ) 24 25 // API is a user facing RPC API to allow controlling the signer and voting 26 // mechanisms of the proof-of-authority scheme. 27 type API struct { 28 chain consensus.ChainHeaderReader 29 bor *Bor 30 rootHashCache *lru.ARCCache 31 } 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.bor.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil) 47 } 48 49 // GetAuthor retrieves the author a block. 50 func (api *API) GetAuthor(number *rpc.BlockNumber) (*common.Address, error) { 51 // Retrieve the requested block number (or current if none requested) 52 var header *types.Header 53 if number == nil || *number == rpc.LatestBlockNumber { 54 header = api.chain.CurrentHeader() 55 } else { 56 header = api.chain.GetHeaderByNumber(uint64(number.Int64())) 57 } 58 // Ensure we have an actually valid block and return its snapshot 59 if header == nil { 60 return nil, errUnknownBlock 61 } 62 author, err := api.bor.Author(header) 63 return &author, err 64 } 65 66 // GetSnapshotAtHash retrieves the state snapshot at a given block. 67 func (api *API) GetSnapshotAtHash(hash common.Hash) (*Snapshot, error) { 68 header := api.chain.GetHeaderByHash(hash) 69 if header == nil { 70 return nil, errUnknownBlock 71 } 72 return api.bor.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil) 73 } 74 75 // GetSigners retrieves the list of authorized signers at the specified block. 76 func (api *API) GetSigners(number *rpc.BlockNumber) ([]common.Address, error) { 77 // Retrieve the requested block number (or current if none requested) 78 var header *types.Header 79 if number == nil || *number == rpc.LatestBlockNumber { 80 header = api.chain.CurrentHeader() 81 } else { 82 header = api.chain.GetHeaderByNumber(uint64(number.Int64())) 83 } 84 // Ensure we have an actually valid block and return the signers from its snapshot 85 if header == nil { 86 return nil, errUnknownBlock 87 } 88 snap, err := api.bor.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil) 89 if err != nil { 90 return nil, err 91 } 92 return snap.signers(), nil 93 } 94 95 // GetSignersAtHash retrieves the list of authorized signers at the specified block. 96 func (api *API) GetSignersAtHash(hash common.Hash) ([]common.Address, error) { 97 header := api.chain.GetHeaderByHash(hash) 98 if header == nil { 99 return nil, errUnknownBlock 100 } 101 snap, err := api.bor.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil) 102 if err != nil { 103 return nil, err 104 } 105 return snap.signers(), nil 106 } 107 108 // GetCurrentProposer gets the current proposer 109 func (api *API) GetCurrentProposer() (common.Address, error) { 110 snap, err := api.GetSnapshot(nil) 111 if err != nil { 112 return common.Address{}, err 113 } 114 return snap.ValidatorSet.GetProposer().Address, nil 115 } 116 117 // GetCurrentValidators gets the current validators 118 func (api *API) GetCurrentValidators() ([]*Validator, error) { 119 snap, err := api.GetSnapshot(nil) 120 if err != nil { 121 return make([]*Validator, 0), err 122 } 123 return snap.ValidatorSet.Validators, nil 124 } 125 126 // GetRootHash returns the merkle root of the start to end block headers 127 func (api *API) GetRootHash(start uint64, end uint64) (string, error) { 128 if err := api.initializeRootHashCache(); err != nil { 129 return "", err 130 } 131 key := getRootHashKey(start, end) 132 if root, known := api.rootHashCache.Get(key); known { 133 return root.(string), nil 134 } 135 length := uint64(end - start + 1) 136 if length > MaxCheckpointLength { 137 return "", &MaxCheckpointLengthExceededError{start, end} 138 } 139 currentHeaderNumber := api.chain.CurrentHeader().Number.Uint64() 140 if start > end || end > currentHeaderNumber { 141 return "", &InvalidStartEndBlockError{start, end, currentHeaderNumber} 142 } 143 blockHeaders := make([]*types.Header, end-start+1) 144 wg := new(sync.WaitGroup) 145 concurrent := make(chan bool, 20) 146 for i := start; i <= end; i++ { 147 wg.Add(1) 148 concurrent <- true 149 go func(number uint64) { 150 blockHeaders[number-start] = api.chain.GetHeaderByNumber(uint64(number)) 151 <-concurrent 152 wg.Done() 153 }(i) 154 } 155 wg.Wait() 156 close(concurrent) 157 158 headers := make([][32]byte, nextPowerOfTwo(length)) 159 for i := 0; i < len(blockHeaders); i++ { 160 blockHeader := blockHeaders[i] 161 header := crypto.Keccak256(appendBytes32( 162 blockHeader.Number.Bytes(), 163 new(big.Int).SetUint64(blockHeader.Time).Bytes(), 164 blockHeader.TxHash.Bytes(), 165 blockHeader.ReceiptHash.Bytes(), 166 )) 167 168 var arr [32]byte 169 copy(arr[:], header) 170 headers[i] = arr 171 } 172 173 tree := merkle.NewTreeWithOpts(merkle.TreeOptions{EnableHashSorting: false, DisableHashLeaves: true}) 174 if err := tree.Generate(convert(headers), sha3.NewLegacyKeccak256()); err != nil { 175 return "", err 176 } 177 root := hex.EncodeToString(tree.Root().Hash) 178 api.rootHashCache.Add(key, root) 179 return root, nil 180 } 181 182 func (api *API) initializeRootHashCache() error { 183 var err error 184 if api.rootHashCache == nil { 185 api.rootHashCache, err = lru.NewARC(10) 186 } 187 return err 188 } 189 190 func getRootHashKey(start uint64, end uint64) string { 191 return strconv.FormatUint(start, 10) + "-" + strconv.FormatUint(end, 10) 192 }