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  }