github.com/klaytn/klaytn@v1.10.2/api/api_public_klay.go (about) 1 // Modifications Copyright 2019 The klaytn Authors 2 // Copyright 2015 The go-ethereum Authors 3 // This file is part of the go-ethereum library. 4 // 5 // The go-ethereum library is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Lesser General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // The go-ethereum library is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Lesser General Public License for more details. 14 // 15 // You should have received a copy of the GNU Lesser General Public License 16 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 17 // 18 // This file is derived from internal/ethapi/api.go (2018/06/04). 19 // Modified and improved for the klaytn development. 20 21 package api 22 23 import ( 24 "context" 25 "encoding/json" 26 "errors" 27 28 "github.com/klaytn/klaytn/blockchain/types/accountkey" 29 "github.com/klaytn/klaytn/common/hexutil" 30 "github.com/klaytn/klaytn/networks/rpc" 31 "github.com/klaytn/klaytn/rlp" 32 ) 33 34 // PublicKlayAPI provides an API to access Klaytn related information. 35 // It offers only methods that operate on public data that is freely available to anyone. 36 type PublicKlayAPI struct { 37 b Backend 38 } 39 40 // NewPublicKlayAPI creates a new Klaytn protocol API. 41 func NewPublicKlayAPI(b Backend) *PublicKlayAPI { 42 return &PublicKlayAPI{b} 43 } 44 45 // GasPrice returns a suggestion for a gas price (baseFee * 2). 46 func (s *PublicKlayAPI) GasPrice(ctx context.Context) (*hexutil.Big, error) { 47 price, err := s.b.SuggestPrice(ctx) 48 return (*hexutil.Big)(price), err 49 } 50 51 func (s *PublicKlayAPI) UpperBoundGasPrice(ctx context.Context) *hexutil.Big { 52 return (*hexutil.Big)(s.b.UpperBoundGasPrice(ctx)) 53 } 54 55 func (s *PublicKlayAPI) LowerBoundGasPrice(ctx context.Context) *hexutil.Big { 56 return (*hexutil.Big)(s.b.LowerBoundGasPrice(ctx)) 57 } 58 59 // ProtocolVersion returns the current Klaytn protocol version this node supports. 60 func (s *PublicKlayAPI) ProtocolVersion() hexutil.Uint { 61 return hexutil.Uint(s.b.ProtocolVersion()) 62 } 63 64 // MaxPriorityFeePerGas returns a suggestion for a gas tip cap for dynamic fee transactions. 65 func (s *PublicKlayAPI) MaxPriorityFeePerGas(ctx context.Context) (*hexutil.Big, error) { 66 return s.GasPrice(ctx) 67 } 68 69 type FeeHistoryResult struct { 70 OldestBlock *hexutil.Big `json:"oldestBlock"` 71 Reward [][]*hexutil.Big `json:"reward,omitempty"` 72 BaseFee []*hexutil.Big `json:"baseFeePerGas,omitempty"` 73 GasUsedRatio []float64 `json:"gasUsedRatio"` 74 } 75 76 // FeeHistory returns data relevant for fee estimation based on the specified range of blocks. 77 func (s *PublicKlayAPI) FeeHistory(ctx context.Context, blockCount DecimalOrHex, lastBlock rpc.BlockNumber, rewardPercentiles []float64) (*FeeHistoryResult, error) { 78 oldest, reward, baseFee, gasUsed, err := s.b.FeeHistory(ctx, int(blockCount), lastBlock, rewardPercentiles) 79 if err != nil { 80 return nil, err 81 } 82 results := &FeeHistoryResult{ 83 OldestBlock: (*hexutil.Big)(oldest), 84 GasUsedRatio: gasUsed, 85 } 86 if reward != nil { 87 results.Reward = make([][]*hexutil.Big, len(reward)) 88 for i, w := range reward { 89 results.Reward[i] = make([]*hexutil.Big, len(w)) 90 for j, v := range w { 91 results.Reward[i][j] = (*hexutil.Big)(v) 92 } 93 } 94 } 95 if baseFee != nil { 96 results.BaseFee = make([]*hexutil.Big, len(baseFee)) 97 for i, v := range baseFee { 98 results.BaseFee[i] = (*hexutil.Big)(v) 99 } 100 } 101 return results, nil 102 } 103 104 // Syncing returns false in case the node is currently not syncing with the network. It can be up to date or has not 105 // yet received the latest block headers from its pears. In case it is synchronizing: 106 // - startingBlock: block number this node started to synchronise from 107 // - currentBlock: block number this node is currently importing 108 // - highestBlock: block number of the highest block header this node has received from peers 109 // - pulledStates: number of state entries processed until now 110 // - knownStates: number of known state entries that still need to be pulled 111 func (s *PublicKlayAPI) Syncing() (interface{}, error) { 112 progress := s.b.Progress() 113 114 // Return not syncing if the synchronisation already completed 115 if progress.CurrentBlock >= progress.HighestBlock { 116 return false, nil 117 } 118 // Otherwise gather the block sync stats 119 return map[string]interface{}{ 120 "startingBlock": hexutil.Uint64(progress.StartingBlock), 121 "currentBlock": hexutil.Uint64(progress.CurrentBlock), 122 "highestBlock": hexutil.Uint64(progress.HighestBlock), 123 "pulledStates": hexutil.Uint64(progress.PulledStates), 124 "knownStates": hexutil.Uint64(progress.KnownStates), 125 }, nil 126 } 127 128 // EncodeAccountKey gets an account key of JSON format and returns RLP encoded bytes of the key. 129 func (s *PublicKlayAPI) EncodeAccountKey(accKey accountkey.AccountKeyJSON) (hexutil.Bytes, error) { 130 if accKey.KeyType == nil { 131 return nil, errors.New("key type is not specified") 132 } 133 key, err := accountkey.NewAccountKey(*accKey.KeyType) 134 if err != nil { 135 return nil, err 136 } 137 if err := json.Unmarshal(accKey.Key, key); err != nil { 138 return nil, err 139 } 140 // Invalidate zero values of threshold and weight to prevent users' mistake 141 // JSON unmarshalling sets zero for those values if they are not exist on JSON input 142 if err := checkAccountKeyZeroValues(key, false); err != nil { 143 return nil, err 144 } 145 accKeySerializer := accountkey.NewAccountKeySerializerWithAccountKey(key) 146 encodedKey, err := rlp.EncodeToBytes(accKeySerializer) 147 if err != nil { 148 return nil, errors.New("the key probably contains an invalid public key: " + err.Error()) 149 } 150 return (hexutil.Bytes)(encodedKey), nil 151 } 152 153 // DecodeAccountKey gets an RLP encoded bytes of an account key and returns the decoded account key. 154 func (s *PublicKlayAPI) DecodeAccountKey(encodedAccKey hexutil.Bytes) (*accountkey.AccountKeySerializer, error) { 155 dec := accountkey.NewAccountKeySerializer() 156 if err := rlp.DecodeBytes(encodedAccKey, &dec); err != nil { 157 return nil, err 158 } 159 return dec, nil 160 } 161 162 // checkAccountKeyZeroValues returns errors if the input account key contains zero values of threshold or weight. 163 func checkAccountKeyZeroValues(key accountkey.AccountKey, isNested bool) error { 164 switch key.Type() { 165 case accountkey.AccountKeyTypeWeightedMultiSig: 166 multiSigKey, _ := key.(*accountkey.AccountKeyWeightedMultiSig) 167 if multiSigKey.Threshold == 0 { 168 return errors.New("invalid threshold of the multiSigKey") 169 } 170 for _, weightedKey := range multiSigKey.Keys { 171 if weightedKey.Weight == 0 { 172 return errors.New("invalid weight of the multiSigKey") 173 } 174 } 175 case accountkey.AccountKeyTypeRoleBased: 176 if isNested { 177 return errors.New("roleBasedKey cannot contains a roleBasedKey as a role key") 178 } 179 roleBasedKey, _ := key.(*accountkey.AccountKeyRoleBased) 180 for _, roleKey := range *roleBasedKey { 181 if err := checkAccountKeyZeroValues(roleKey, true); err != nil { 182 return err 183 } 184 } 185 } 186 return nil 187 }