github.com/klaytn/klaytn@v1.12.1/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 price, err := s.b.SuggestTipCap(ctx) 67 return (*hexutil.Big)(price), err 68 } 69 70 type FeeHistoryResult struct { 71 OldestBlock *hexutil.Big `json:"oldestBlock"` 72 Reward [][]*hexutil.Big `json:"reward,omitempty"` 73 BaseFee []*hexutil.Big `json:"baseFeePerGas,omitempty"` 74 GasUsedRatio []float64 `json:"gasUsedRatio"` 75 } 76 77 // FeeHistory returns data relevant for fee estimation based on the specified range of blocks. 78 func (s *PublicKlayAPI) FeeHistory(ctx context.Context, blockCount DecimalOrHex, lastBlock rpc.BlockNumber, rewardPercentiles []float64) (*FeeHistoryResult, error) { 79 oldest, reward, baseFee, gasUsed, err := s.b.FeeHistory(ctx, int(blockCount), lastBlock, rewardPercentiles) 80 if err != nil { 81 return nil, err 82 } 83 results := &FeeHistoryResult{ 84 OldestBlock: (*hexutil.Big)(oldest), 85 GasUsedRatio: gasUsed, 86 } 87 if reward != nil { 88 results.Reward = make([][]*hexutil.Big, len(reward)) 89 for i, w := range reward { 90 results.Reward[i] = make([]*hexutil.Big, len(w)) 91 for j, v := range w { 92 results.Reward[i][j] = (*hexutil.Big)(v) 93 } 94 } 95 } 96 if baseFee != nil { 97 results.BaseFee = make([]*hexutil.Big, len(baseFee)) 98 for i, v := range baseFee { 99 results.BaseFee[i] = (*hexutil.Big)(v) 100 } 101 } 102 return results, nil 103 } 104 105 // Syncing returns false in case the node is currently not syncing with the network. It can be up to date or has not 106 // yet received the latest block headers from its pears. In case it is synchronizing: 107 // - startingBlock: block number this node started to synchronise from 108 // - currentBlock: block number this node is currently importing 109 // - highestBlock: block number of the highest block header this node has received from peers 110 // - pulledStates: number of state entries processed until now 111 // - knownStates: number of known state entries that still need to be pulled 112 func (s *PublicKlayAPI) Syncing() (interface{}, error) { 113 progress := s.b.Progress() 114 115 // Return not syncing if the synchronisation already completed 116 if progress.CurrentBlock >= progress.HighestBlock { 117 return false, nil 118 } 119 // Otherwise gather the block sync stats 120 return map[string]interface{}{ 121 "startingBlock": hexutil.Uint64(progress.StartingBlock), 122 "currentBlock": hexutil.Uint64(progress.CurrentBlock), 123 "highestBlock": hexutil.Uint64(progress.HighestBlock), 124 "pulledStates": hexutil.Uint64(progress.PulledStates), 125 "knownStates": hexutil.Uint64(progress.KnownStates), 126 }, nil 127 } 128 129 // EncodeAccountKey gets an account key of JSON format and returns RLP encoded bytes of the key. 130 func (s *PublicKlayAPI) EncodeAccountKey(accKey accountkey.AccountKeyJSON) (hexutil.Bytes, error) { 131 if accKey.KeyType == nil { 132 return nil, errors.New("key type is not specified") 133 } 134 key, err := accountkey.NewAccountKey(*accKey.KeyType) 135 if err != nil { 136 return nil, err 137 } 138 if err := json.Unmarshal(accKey.Key, key); err != nil { 139 return nil, err 140 } 141 // Invalidate zero values of threshold and weight to prevent users' mistake 142 // JSON unmarshalling sets zero for those values if they are not exist on JSON input 143 if err := checkAccountKeyZeroValues(key, false); err != nil { 144 return nil, err 145 } 146 accKeySerializer := accountkey.NewAccountKeySerializerWithAccountKey(key) 147 encodedKey, err := rlp.EncodeToBytes(accKeySerializer) 148 if err != nil { 149 return nil, errors.New("the key probably contains an invalid public key: " + err.Error()) 150 } 151 return (hexutil.Bytes)(encodedKey), nil 152 } 153 154 // DecodeAccountKey gets an RLP encoded bytes of an account key and returns the decoded account key. 155 func (s *PublicKlayAPI) DecodeAccountKey(encodedAccKey hexutil.Bytes) (*accountkey.AccountKeySerializer, error) { 156 dec := accountkey.NewAccountKeySerializer() 157 if err := rlp.DecodeBytes(encodedAccKey, &dec); err != nil { 158 return nil, err 159 } 160 return dec, nil 161 } 162 163 // checkAccountKeyZeroValues returns errors if the input account key contains zero values of threshold or weight. 164 func checkAccountKeyZeroValues(key accountkey.AccountKey, isNested bool) error { 165 switch key.Type() { 166 case accountkey.AccountKeyTypeWeightedMultiSig: 167 multiSigKey, _ := key.(*accountkey.AccountKeyWeightedMultiSig) 168 if multiSigKey.Threshold == 0 { 169 return errors.New("invalid threshold of the multiSigKey") 170 } 171 for _, weightedKey := range multiSigKey.Keys { 172 if weightedKey.Weight == 0 { 173 return errors.New("invalid weight of the multiSigKey") 174 } 175 } 176 case accountkey.AccountKeyTypeRoleBased: 177 if isNested { 178 return errors.New("roleBasedKey cannot contains a roleBasedKey as a role key") 179 } 180 roleBasedKey, _ := key.(*accountkey.AccountKeyRoleBased) 181 for _, roleKey := range *roleBasedKey { 182 if err := checkAccountKeyZeroValues(roleKey, true); err != nil { 183 return err 184 } 185 } 186 } 187 return nil 188 }