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  }