github.com/klaytn/klaytn@v1.10.2/api/api_public_blockchain.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  	"errors"
    26  	"fmt"
    27  	"math/big"
    28  	"time"
    29  
    30  	"github.com/klaytn/klaytn/node/cn/filters"
    31  
    32  	"github.com/klaytn/klaytn/blockchain"
    33  	"github.com/klaytn/klaytn/blockchain/types"
    34  	"github.com/klaytn/klaytn/blockchain/types/account"
    35  	"github.com/klaytn/klaytn/blockchain/types/accountkey"
    36  	"github.com/klaytn/klaytn/blockchain/vm"
    37  	"github.com/klaytn/klaytn/common"
    38  	"github.com/klaytn/klaytn/common/hexutil"
    39  	"github.com/klaytn/klaytn/common/math"
    40  	"github.com/klaytn/klaytn/log"
    41  	"github.com/klaytn/klaytn/networks/rpc"
    42  	"github.com/klaytn/klaytn/params"
    43  	"github.com/klaytn/klaytn/rlp"
    44  )
    45  
    46  const (
    47  	defaultGasPrice = 25 * params.Ston
    48  )
    49  
    50  var logger = log.NewModuleLogger(log.API)
    51  
    52  // PublicBlockChainAPI provides an API to access the Klaytn blockchain.
    53  // It offers only methods that operate on public data that is freely available to anyone.
    54  type PublicBlockChainAPI struct {
    55  	b Backend
    56  }
    57  
    58  // NewPublicBlockChainAPI creates a new Klaytn blockchain API.
    59  func NewPublicBlockChainAPI(b Backend) *PublicBlockChainAPI {
    60  	return &PublicBlockChainAPI{b}
    61  }
    62  
    63  // BlockNumber returns the block number of the chain head.
    64  func (s *PublicBlockChainAPI) BlockNumber() hexutil.Uint64 {
    65  	header, _ := s.b.HeaderByNumber(context.Background(), rpc.LatestBlockNumber) // latest header should always be available
    66  	return hexutil.Uint64(header.Number.Uint64())
    67  }
    68  
    69  // ChainID returns the chain ID of the chain from genesis file.
    70  func (s *PublicBlockChainAPI) ChainID() *hexutil.Big {
    71  	return s.ChainId()
    72  }
    73  
    74  // ChainId returns the chain ID of the chain from genesis file.
    75  // This is for compatibility with ethereum client
    76  func (s *PublicBlockChainAPI) ChainId() *hexutil.Big {
    77  	if s.b.ChainConfig() != nil {
    78  		return (*hexutil.Big)(s.b.ChainConfig().ChainID)
    79  	}
    80  	return nil
    81  }
    82  
    83  // IsContractAccount returns true if the account associated with addr has a non-empty codeHash.
    84  // It returns false otherwise.
    85  func (s *PublicBlockChainAPI) IsContractAccount(ctx context.Context, address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (bool, error) {
    86  	state, _, err := s.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
    87  	if err != nil {
    88  		return false, err
    89  	}
    90  	return state.IsContractAccount(address), state.Error()
    91  }
    92  
    93  // IsHumanReadable returns true if the account associated with addr is a human-readable account.
    94  // It returns false otherwise.
    95  // func (s *PublicBlockChainAPI) IsHumanReadable(ctx context.Context, address common.Address, blockNr rpc.BlockNumber) (bool, error) {
    96  //	state, _, err := s.b.StateAndHeaderByNumber(ctx, blockNr)
    97  //	if err != nil {
    98  //		return false, err
    99  //	}
   100  //	return state.IsHumanReadable(address), state.Error()
   101  // }
   102  
   103  // GetBlockReceipts returns all the transaction receipts for the given block hash.
   104  func (s *PublicBlockChainAPI) GetBlockReceipts(ctx context.Context, blockHash common.Hash) ([]map[string]interface{}, error) {
   105  	receipts := s.b.GetBlockReceipts(ctx, blockHash)
   106  	block, err := s.b.BlockByHash(ctx, blockHash)
   107  	if err != nil {
   108  		return nil, err
   109  	}
   110  	txs := block.Transactions()
   111  	if receipts.Len() != txs.Len() {
   112  		return nil, fmt.Errorf("the size of transactions and receipts is different in the block (%s)", blockHash.String())
   113  	}
   114  	fieldsList := make([]map[string]interface{}, 0, len(receipts))
   115  	for index, receipt := range receipts {
   116  		fields := RpcOutputReceipt(block.Header(), txs[index], blockHash, block.NumberU64(), uint64(index), receipt)
   117  		fieldsList = append(fieldsList, fields)
   118  	}
   119  	return fieldsList, nil
   120  }
   121  
   122  // GetBalance returns the amount of peb for the given address in the state of the
   123  // given block number or hash. The rpc.LatestBlockNumber and rpc.PendingBlockNumber meta
   124  // block numbers and hash are also allowed.
   125  func (s *PublicBlockChainAPI) GetBalance(ctx context.Context, address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (*hexutil.Big, error) {
   126  	state, _, err := s.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
   127  	if err != nil {
   128  		return nil, err
   129  	}
   130  	return (*hexutil.Big)(state.GetBalance(address)), state.Error()
   131  }
   132  
   133  // AccountCreated returns true if the account associated with the address is created.
   134  // It returns false otherwise.
   135  func (s *PublicBlockChainAPI) AccountCreated(ctx context.Context, address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (bool, error) {
   136  	state, _, err := s.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
   137  	if err != nil {
   138  		return false, err
   139  	}
   140  	return state.Exist(address), state.Error()
   141  }
   142  
   143  // GetAccount returns account information of an input address.
   144  func (s *PublicBlockChainAPI) GetAccount(ctx context.Context, address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (*account.AccountSerializer, error) {
   145  	state, _, err := s.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
   146  	if err != nil {
   147  		return &account.AccountSerializer{}, err
   148  	}
   149  	acc := state.GetAccount(address)
   150  	if acc == nil {
   151  		return &account.AccountSerializer{}, err
   152  	}
   153  	serAcc := account.NewAccountSerializerWithAccount(acc)
   154  	return serAcc, state.Error()
   155  }
   156  
   157  // rpcMarshalHeader converts the given header to the RPC output.
   158  func (s *PublicBlockChainAPI) rpcMarshalHeader(header *types.Header) map[string]interface{} {
   159  	fields := filters.RPCMarshalHeader(header, s.b.ChainConfig().IsEthTxTypeForkEnabled(header.Number))
   160  	return fields
   161  }
   162  
   163  // GetHeaderByNumber returns the requested canonical block header.
   164  func (s *PublicBlockChainAPI) GetHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (map[string]interface{}, error) {
   165  	header, err := s.b.HeaderByNumber(ctx, number)
   166  	if err != nil {
   167  		return nil, err
   168  	}
   169  	return s.rpcMarshalHeader(header), nil
   170  }
   171  
   172  // GetHeaderByHash returns the requested header by hash.
   173  func (s *PublicBlockChainAPI) GetHeaderByHash(ctx context.Context, hash common.Hash) (map[string]interface{}, error) {
   174  	header, err := s.b.HeaderByHash(ctx, hash)
   175  	if err != nil {
   176  		return nil, err
   177  	}
   178  	return s.rpcMarshalHeader(header), nil
   179  }
   180  
   181  // GetBlockByNumber returns the requested block. When blockNr is -1 the chain head is returned. When fullTx is true all
   182  // transactions in the block are returned in full detail, otherwise only the transaction hash is returned.
   183  func (s *PublicBlockChainAPI) GetBlockByNumber(ctx context.Context, blockNr rpc.BlockNumber, fullTx bool) (map[string]interface{}, error) {
   184  	block, err := s.b.BlockByNumber(ctx, blockNr)
   185  	if block != nil && err == nil {
   186  		response, err := s.rpcOutputBlock(block, true, fullTx)
   187  		if err == nil && blockNr == rpc.PendingBlockNumber {
   188  			// Pending blocks need to nil out a few fields
   189  			for _, field := range []string{"hash", "nonce", "miner"} {
   190  				response[field] = nil
   191  			}
   192  		}
   193  		return response, err
   194  	}
   195  	return nil, err
   196  }
   197  
   198  // GetBlockByHash returns the requested block. When fullTx is true all transactions in the block are returned in full
   199  // detail, otherwise only the transaction hash is returned.
   200  func (s *PublicBlockChainAPI) GetBlockByHash(ctx context.Context, blockHash common.Hash, fullTx bool) (map[string]interface{}, error) {
   201  	block, err := s.b.BlockByHash(ctx, blockHash)
   202  	if err != nil {
   203  		return nil, err
   204  	}
   205  	return s.rpcOutputBlock(block, true, fullTx)
   206  }
   207  
   208  // GetCode returns the code stored at the given address in the state for the given block number or hash.
   209  func (s *PublicBlockChainAPI) GetCode(ctx context.Context, address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (hexutil.Bytes, error) {
   210  	state, _, err := s.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
   211  	if err != nil {
   212  		return nil, err
   213  	}
   214  	code := state.GetCode(address)
   215  	return code, state.Error()
   216  }
   217  
   218  // GetStorageAt returns the storage from the state at the given address, key and
   219  // block number. The rpc.LatestBlockNumber and rpc.PendingBlockNumber meta block
   220  // numbers and hash are also allowed.
   221  func (s *PublicBlockChainAPI) GetStorageAt(ctx context.Context, address common.Address, key string, blockNrOrHash rpc.BlockNumberOrHash) (hexutil.Bytes, error) {
   222  	state, _, err := s.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
   223  	if err != nil {
   224  		return nil, err
   225  	}
   226  	res := state.GetState(address, common.HexToHash(key))
   227  	return res[:], state.Error()
   228  }
   229  
   230  // GetAccountKey returns the account key of EOA at a given address.
   231  // If the account of the given address is a Legacy Account or a Smart Contract Account, it will return nil.
   232  func (s *PublicBlockChainAPI) GetAccountKey(ctx context.Context, address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (*accountkey.AccountKeySerializer, error) {
   233  	state, _, err := s.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
   234  	if err != nil {
   235  		return &accountkey.AccountKeySerializer{}, err
   236  	}
   237  	if state.Exist(address) == false {
   238  		return nil, nil
   239  	}
   240  	accountKey := state.GetKey(address)
   241  	serAccKey := accountkey.NewAccountKeySerializerWithAccountKey(accountKey)
   242  	return serAccKey, state.Error()
   243  }
   244  
   245  // IsParallelDBWrite returns if parallel write is enabled or not.
   246  // If enabled, data written in WriteBlockWithState is being written in parallel manner.
   247  func (s *PublicBlockChainAPI) IsParallelDBWrite() bool {
   248  	return s.b.IsParallelDBWrite()
   249  }
   250  
   251  // IsSenderTxHashIndexingEnabled returns if senderTxHash to txHash mapping information
   252  // indexing is enabled or not.
   253  func (s *PublicBlockChainAPI) IsSenderTxHashIndexingEnabled() bool {
   254  	return s.b.IsSenderTxHashIndexingEnabled()
   255  }
   256  
   257  // CallArgs represents the arguments for a call.
   258  type CallArgs struct {
   259  	From                 common.Address  `json:"from"`
   260  	To                   *common.Address `json:"to"`
   261  	Gas                  hexutil.Uint64  `json:"gas"`
   262  	GasPrice             *hexutil.Big    `json:"gasPrice"`
   263  	MaxFeePerGas         *hexutil.Big    `json:"maxFeePerGas"`
   264  	MaxPriorityFeePerGas *hexutil.Big    `json:"maxPriorityFeePerGas"`
   265  	Value                hexutil.Big     `json:"value"`
   266  	Data                 hexutil.Bytes   `json:"data"`
   267  	Input                hexutil.Bytes   `json:"input"`
   268  }
   269  
   270  func (args *CallArgs) data() []byte {
   271  	if args.Input != nil {
   272  		return args.Input
   273  	}
   274  	if args.Data != nil {
   275  		return args.Data
   276  	}
   277  	return nil
   278  }
   279  
   280  func DoCall(ctx context.Context, b Backend, args CallArgs, blockNrOrHash rpc.BlockNumberOrHash, vmCfg vm.Config, timeout time.Duration, globalGasCap *big.Int) ([]byte, uint64, uint64, uint, error) {
   281  	defer func(start time.Time) { logger.Debug("Executing EVM call finished", "runtime", time.Since(start)) }(time.Now())
   282  
   283  	state, header, err := b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
   284  	if state == nil || err != nil {
   285  		return nil, 0, 0, 0, err
   286  	}
   287  	// Setup context so it may be cancelled the call has completed
   288  	// or, in case of unmetered gas, setup a context with a timeout.
   289  	var cancel context.CancelFunc
   290  	if timeout > 0 {
   291  		ctx, cancel = context.WithTimeout(ctx, timeout)
   292  	} else {
   293  		ctx, cancel = context.WithCancel(ctx)
   294  	}
   295  	// Make sure the context is cancelled when the call has completed
   296  	// this makes sure resources are cleaned up.
   297  	defer cancel()
   298  
   299  	intrinsicGas, err := types.IntrinsicGas(args.data(), nil, args.To == nil, b.ChainConfig().Rules(header.Number))
   300  	if err != nil {
   301  		return nil, 0, 0, 0, err
   302  	}
   303  
   304  	// header.BaseFee != nil means magma hardforked
   305  	var baseFee *big.Int
   306  	if header.BaseFee != nil {
   307  		baseFee = header.BaseFee
   308  	} else {
   309  		baseFee = new(big.Int).SetUint64(params.ZeroBaseFee)
   310  	}
   311  	msg, err := args.ToMessage(globalGasCap.Uint64(), baseFee, intrinsicGas)
   312  	if err != nil {
   313  		return nil, 0, 0, 0, err
   314  	}
   315  	var balanceBaseFee *big.Int
   316  	if header.BaseFee != nil {
   317  		balanceBaseFee = new(big.Int).Mul(baseFee, common.Big2)
   318  	} else {
   319  		balanceBaseFee = msg.GasPrice()
   320  	}
   321  	// Add gas fee to sender for estimating gasLimit/computing cost or calling a function by insufficient balance sender.
   322  	state.AddBalance(msg.ValidatedSender(), new(big.Int).Mul(new(big.Int).SetUint64(msg.Gas()), balanceBaseFee))
   323  
   324  	// The intrinsicGas is checked again later in the blockchain.ApplyMessage function,
   325  	// but we check in advance here in order to keep StateTransition.TransactionDb method as unchanged as possible
   326  	// and to clarify error reason correctly to serve eth namespace APIs.
   327  	// This case is handled by DoEstimateGas function.
   328  	if msg.Gas() < intrinsicGas {
   329  		return nil, 0, 0, 0, fmt.Errorf("%w: msg.gas %d, want %d", blockchain.ErrIntrinsicGas, msg.Gas(), intrinsicGas)
   330  	}
   331  	evm, vmError, err := b.GetEVM(ctx, msg, state, header, vmCfg)
   332  	if err != nil {
   333  		return nil, 0, 0, 0, err
   334  	}
   335  	// Wait for the context to be done and cancel the evm. Even if the
   336  	// EVM has finished, cancelling may be done (repeatedly)
   337  	go func() {
   338  		<-ctx.Done()
   339  		evm.Cancel(vm.CancelByCtxDone)
   340  	}()
   341  
   342  	// Execute the message.
   343  	res, gas, kerr := blockchain.ApplyMessage(evm, msg)
   344  	err = kerr.ErrTxInvalid
   345  	if err := vmError(); err != nil {
   346  		return nil, 0, 0, 0, err
   347  	}
   348  	// If the timer caused an abort, return an appropriate error message
   349  	if evm.Cancelled() {
   350  		return nil, 0, 0, 0, fmt.Errorf("execution aborted (timeout = %v)", timeout)
   351  	}
   352  	if err != nil {
   353  		return res, 0, 0, 0, fmt.Errorf("err: %w (supplied gas %d)", err, msg.Gas())
   354  	}
   355  	// TODO-Klaytn-Interface: Introduce ExecutionResult struct from geth to return more detail information
   356  	return res, gas, evm.GetOpCodeComputationCost(), kerr.Status, nil
   357  }
   358  
   359  // Call executes the given transaction on the state for the given block number or hash.
   360  // It doesn't make and changes in the state/blockchain and is useful to execute and retrieve values.
   361  func (s *PublicBlockChainAPI) Call(ctx context.Context, args CallArgs, blockNrOrHash rpc.BlockNumberOrHash) (hexutil.Bytes, error) {
   362  	gasCap := big.NewInt(0)
   363  	if rpcGasCap := s.b.RPCGasCap(); rpcGasCap != nil {
   364  		gasCap = rpcGasCap
   365  	}
   366  	result, _, _, status, err := DoCall(ctx, s.b, args, blockNrOrHash, vm.Config{}, s.b.RPCEVMTimeout(), gasCap)
   367  	if err != nil {
   368  		return nil, err
   369  	}
   370  
   371  	err = blockchain.GetVMerrFromReceiptStatus(status)
   372  	if err != nil && isReverted(err) && len(result) > 0 {
   373  		return nil, newRevertError(result)
   374  	}
   375  	return common.CopyBytes(result), err
   376  }
   377  
   378  func (s *PublicBlockChainAPI) EstimateComputationCost(ctx context.Context, args CallArgs, blockNrOrHash rpc.BlockNumberOrHash) (hexutil.Uint64, error) {
   379  	gasCap := big.NewInt(0)
   380  	if rpcGasCap := s.b.RPCGasCap(); rpcGasCap != nil {
   381  		gasCap = rpcGasCap
   382  	}
   383  	_, _, computationCost, _, err := DoCall(ctx, s.b, args, blockNrOrHash, vm.Config{UseOpcodeComputationCost: true}, s.b.RPCEVMTimeout(), gasCap)
   384  	return (hexutil.Uint64)(computationCost), err
   385  }
   386  
   387  // EstimateGas returns an estimate of the amount of gas needed to execute the given transaction against the latest block.
   388  func (s *PublicBlockChainAPI) EstimateGas(ctx context.Context, args CallArgs) (hexutil.Uint64, error) {
   389  	gasCap := uint64(0)
   390  	if rpcGasCap := s.b.RPCGasCap(); rpcGasCap != nil {
   391  		gasCap = rpcGasCap.Uint64()
   392  	}
   393  	return s.DoEstimateGas(ctx, s.b, args, big.NewInt(int64(gasCap)))
   394  }
   395  
   396  func (s *PublicBlockChainAPI) DoEstimateGas(ctx context.Context, b Backend, args CallArgs, gasCap *big.Int) (hexutil.Uint64, error) {
   397  	// Binary search the gas requirement, as it may be higher than the amount used
   398  	var (
   399  		lo  uint64 = params.TxGas - 1
   400  		hi  uint64
   401  		cap uint64
   402  	)
   403  	if uint64(args.Gas) >= params.TxGas {
   404  		hi = uint64(args.Gas)
   405  	} else {
   406  		// Retrieve the current pending block to act as the gas ceiling
   407  		hi = params.UpperGasLimit
   408  	}
   409  	// TODO-Klaytn: set hi value with account balance
   410  	cap = hi
   411  
   412  	// Create a helper to check if a gas allowance results in an executable transaction
   413  	executable := func(gas uint64) (bool, []byte, error, error) {
   414  		args.Gas = hexutil.Uint64(gas)
   415  		ret, _, _, status, err := DoCall(ctx, b, args, rpc.NewBlockNumberOrHashWithNumber(rpc.LatestBlockNumber), vm.Config{}, 0, gasCap)
   416  		if err != nil {
   417  			if errors.Is(err, blockchain.ErrIntrinsicGas) {
   418  				// Special case, raise gas limit
   419  				return false, ret, nil, nil
   420  			}
   421  			// Returns error when it is not VM error (less balance or wrong nonce, etc...).
   422  			return false, nil, nil, err
   423  		}
   424  		// If err is vmError, return vmError with returned data
   425  		vmErr := blockchain.GetVMerrFromReceiptStatus(status)
   426  		if vmErr != nil {
   427  			return false, ret, vmErr, nil
   428  		}
   429  		return true, ret, vmErr, nil
   430  	}
   431  	// Execute the binary search and hone in on an executable gas limit
   432  	for lo+1 < hi {
   433  		mid := (hi + lo) / 2
   434  		isExecutable, _, _, err := executable(mid)
   435  		if err != nil {
   436  			return 0, err
   437  		}
   438  		if !isExecutable {
   439  			lo = mid
   440  		} else {
   441  			hi = mid
   442  		}
   443  	}
   444  	// Reject the transaction as invalid if it still fails at the highest allowance
   445  	if hi == cap {
   446  		isExecutable, ret, vmErr, err := executable(hi)
   447  		if err != nil {
   448  			return 0, err
   449  		}
   450  		if !isExecutable {
   451  			if vmErr != nil {
   452  				// Treat vmErr as RevertError only when there was returned data from call.
   453  				if isReverted(vmErr) && len(ret) > 0 {
   454  					return 0, newRevertError(ret)
   455  				}
   456  				return 0, vmErr
   457  			}
   458  			// Otherwise, the specified gas cap is too low
   459  			return 0, fmt.Errorf("gas required exceeds allowance (%d)", cap)
   460  		}
   461  	}
   462  	return hexutil.Uint64(hi), nil
   463  }
   464  
   465  // ExecutionResult groups all structured logs emitted by the EVM
   466  // while replaying a transaction in debug mode as well as transaction
   467  // execution status, the amount of gas used and the return value
   468  type ExecutionResult struct {
   469  	Gas         uint64         `json:"gas"`
   470  	Failed      bool           `json:"failed"`
   471  	ReturnValue string         `json:"returnValue"`
   472  	StructLogs  []StructLogRes `json:"structLogs"`
   473  }
   474  
   475  // accessListResult returns an optional accesslist
   476  // Its the result of the `debug_createAccessList` RPC call.
   477  // It contains an error if the transaction itself failed.
   478  type AccessListResult struct {
   479  	Accesslist *types.AccessList `json:"accessList"`
   480  	Error      string            `json:"error,omitempty"`
   481  	GasUsed    hexutil.Uint64    `json:"gasUsed"`
   482  }
   483  
   484  // CreateAccessList creates a EIP-2930 type AccessList for the given transaction.
   485  // Reexec and BlockNrOrHash can be specified to create the accessList on top of a certain state.
   486  // TODO-Klaytn: Have to implement logic. For now, Klaytn does not implement actual access list logic, so return empty access list result.
   487  func (s *PublicBlockChainAPI) CreateAccessList(ctx context.Context, args SendTxArgs, blockNrOrHash *rpc.BlockNumberOrHash) (*AccessListResult, error) {
   488  	result := &AccessListResult{Accesslist: &types.AccessList{}, GasUsed: hexutil.Uint64(0)}
   489  	return result, nil
   490  }
   491  
   492  // StructLogRes stores a structured log emitted by the EVM while replaying a
   493  // transaction in debug mode
   494  type StructLogRes struct {
   495  	Pc      uint64             `json:"pc"`
   496  	Op      string             `json:"op"`
   497  	Gas     uint64             `json:"gas"`
   498  	GasCost uint64             `json:"gasCost"`
   499  	Depth   int                `json:"depth"`
   500  	Error   error              `json:"error,omitempty"`
   501  	Stack   *[]string          `json:"stack,omitempty"`
   502  	Memory  *[]string          `json:"memory,omitempty"`
   503  	Storage *map[string]string `json:"storage,omitempty"`
   504  }
   505  
   506  // formatLogs formats EVM returned structured logs for json output
   507  func FormatLogs(timeout time.Duration, logs []vm.StructLog) ([]StructLogRes, error) {
   508  	logTimeout := false
   509  	deadlineCtx, cancel := context.WithTimeout(context.Background(), timeout)
   510  	go func() {
   511  		<-deadlineCtx.Done()
   512  		logger.Debug("trace logger timeout", "timeout", timeout, "err", deadlineCtx.Err())
   513  		logTimeout = true
   514  	}()
   515  	defer cancel()
   516  
   517  	formatted := make([]StructLogRes, len(logs))
   518  	for index, trace := range logs {
   519  		if logTimeout {
   520  			return nil, fmt.Errorf("trace logger timeout")
   521  		}
   522  		formatted[index] = StructLogRes{
   523  			Pc:      trace.Pc,
   524  			Op:      trace.Op.String(),
   525  			Gas:     trace.Gas,
   526  			GasCost: trace.GasCost,
   527  			Depth:   trace.Depth,
   528  			Error:   trace.Err,
   529  		}
   530  		if trace.Stack != nil {
   531  			stack := make([]string, len(trace.Stack))
   532  			for i, stackValue := range trace.Stack {
   533  				stack[i] = fmt.Sprintf("%x", math.PaddedBigBytes(stackValue, 32))
   534  			}
   535  			formatted[index].Stack = &stack
   536  		}
   537  		if trace.Memory != nil {
   538  			memory := make([]string, 0, (len(trace.Memory)+31)/32)
   539  			for i := 0; i+32 <= len(trace.Memory); i += 32 {
   540  				memory = append(memory, fmt.Sprintf("%x", trace.Memory[i:i+32]))
   541  			}
   542  			formatted[index].Memory = &memory
   543  		}
   544  		if trace.Storage != nil {
   545  			storage := make(map[string]string)
   546  			for i, storageValue := range trace.Storage {
   547  				storage[fmt.Sprintf("%x", i)] = fmt.Sprintf("%x", storageValue)
   548  			}
   549  			formatted[index].Storage = &storage
   550  		}
   551  	}
   552  	return formatted, nil
   553  }
   554  
   555  func RpcOutputBlock(b *types.Block, td *big.Int, inclTx bool, fullTx bool, isEnabledEthTxTypeFork bool) (map[string]interface{}, error) {
   556  	head := b.Header() // copies the header once
   557  	fields := map[string]interface{}{
   558  		"number":           (*hexutil.Big)(head.Number),
   559  		"hash":             b.Hash(),
   560  		"parentHash":       head.ParentHash,
   561  		"logsBloom":        head.Bloom,
   562  		"stateRoot":        head.Root,
   563  		"reward":           head.Rewardbase,
   564  		"blockScore":       (*hexutil.Big)(head.BlockScore),
   565  		"totalBlockScore":  (*hexutil.Big)(td),
   566  		"extraData":        hexutil.Bytes(head.Extra),
   567  		"governanceData":   hexutil.Bytes(head.Governance),
   568  		"voteData":         hexutil.Bytes(head.Vote),
   569  		"size":             hexutil.Uint64(b.Size()),
   570  		"gasUsed":          hexutil.Uint64(head.GasUsed),
   571  		"timestamp":        (*hexutil.Big)(head.Time),
   572  		"timestampFoS":     (hexutil.Uint)(head.TimeFoS),
   573  		"transactionsRoot": head.TxHash,
   574  		"receiptsRoot":     head.ReceiptHash,
   575  	}
   576  
   577  	if inclTx {
   578  		formatTx := func(tx *types.Transaction) (interface{}, error) {
   579  			return tx.Hash(), nil
   580  		}
   581  
   582  		if fullTx {
   583  			formatTx = func(tx *types.Transaction) (interface{}, error) {
   584  				return newRPCTransactionFromBlockHash(b, tx.Hash()), nil
   585  			}
   586  		}
   587  
   588  		txs := b.Transactions()
   589  		transactions := make([]interface{}, len(txs))
   590  		var err error
   591  		for i, tx := range b.Transactions() {
   592  			if transactions[i], err = formatTx(tx); err != nil {
   593  				return nil, err
   594  			}
   595  		}
   596  		fields["transactions"] = transactions
   597  	}
   598  
   599  	if isEnabledEthTxTypeFork {
   600  		if head.BaseFee == nil {
   601  			fields["baseFeePerGas"] = (*hexutil.Big)(new(big.Int).SetUint64(params.ZeroBaseFee))
   602  		} else {
   603  			fields["baseFeePerGas"] = (*hexutil.Big)(head.BaseFee)
   604  		}
   605  	}
   606  
   607  	return fields, nil
   608  }
   609  
   610  // rpcOutputBlock converts the given block to the RPC output which depends on fullTx. If inclTx is true transactions are
   611  // returned. When fullTx is true the returned block contains full transaction details, otherwise it will only contain
   612  // transaction hashes.
   613  func (s *PublicBlockChainAPI) rpcOutputBlock(b *types.Block, inclTx bool, fullTx bool) (map[string]interface{}, error) {
   614  	return RpcOutputBlock(b, s.b.GetTd(b.Hash()), inclTx, fullTx, s.b.ChainConfig().IsEthTxTypeForkEnabled(b.Header().Number))
   615  }
   616  
   617  func getFrom(tx *types.Transaction) common.Address {
   618  	var from common.Address
   619  	if tx.IsEthereumTransaction() {
   620  		signer := types.LatestSignerForChainID(tx.ChainId())
   621  		from, _ = types.Sender(signer, tx)
   622  	} else {
   623  		from, _ = tx.From()
   624  	}
   625  	return from
   626  }
   627  
   628  // newRPCTransaction returns a transaction that will serialize to the RPC
   629  // representation, with the given location metadata set (if available).
   630  func newRPCTransaction(b *types.Block, tx *types.Transaction, blockHash common.Hash, blockNumber uint64, index uint64) map[string]interface{} {
   631  	output := tx.MakeRPCOutput()
   632  	output["senderTxHash"] = tx.SenderTxHashAll()
   633  	output["blockHash"] = blockHash
   634  	output["blockNumber"] = (*hexutil.Big)(new(big.Int).SetUint64(blockNumber))
   635  	output["from"] = getFrom(tx)
   636  	output["hash"] = tx.Hash()
   637  	output["transactionIndex"] = hexutil.Uint(index)
   638  	if tx.Type() == types.TxTypeEthereumDynamicFee {
   639  		if b != nil {
   640  			output["gasPrice"] = (*hexutil.Big)(tx.EffectiveGasPrice(b.Header()))
   641  		} else {
   642  			// transaction is not processed yet
   643  			output["gasPrice"] = (*hexutil.Big)(tx.EffectiveGasPrice(nil))
   644  		}
   645  	}
   646  
   647  	return output
   648  }
   649  
   650  // newRPCPendingTransaction returns a pending transaction that will serialize to the RPC representation
   651  func newRPCPendingTransaction(tx *types.Transaction) map[string]interface{} {
   652  	return newRPCTransaction(nil, tx, common.Hash{}, 0, 0)
   653  }
   654  
   655  // newRPCTransactionFromBlockIndex returns a transaction that will serialize to the RPC representation.
   656  func newRPCTransactionFromBlockIndex(b *types.Block, index uint64) map[string]interface{} {
   657  	txs := b.Transactions()
   658  	if index >= uint64(len(txs)) {
   659  		return nil
   660  	}
   661  	return newRPCTransaction(b, txs[index], b.Hash(), b.NumberU64(), index)
   662  }
   663  
   664  // newRPCRawTransactionFromBlockIndex returns the bytes of a transaction given a block and a transaction index.
   665  func newRPCRawTransactionFromBlockIndex(b *types.Block, index uint64) hexutil.Bytes {
   666  	txs := b.Transactions()
   667  	if index >= uint64(len(txs)) {
   668  		return nil
   669  	}
   670  	blob, _ := rlp.EncodeToBytes(txs[index])
   671  	return blob
   672  }
   673  
   674  // newRPCTransactionFromBlockHash returns a transaction that will serialize to the RPC representation.
   675  func newRPCTransactionFromBlockHash(b *types.Block, hash common.Hash) map[string]interface{} {
   676  	for idx, tx := range b.Transactions() {
   677  		if tx.Hash() == hash {
   678  			return newRPCTransactionFromBlockIndex(b, uint64(idx))
   679  		}
   680  	}
   681  	return nil
   682  }
   683  
   684  func (args *CallArgs) ToMessage(globalGasCap uint64, baseFee *big.Int, intrinsicGas uint64) (*types.Transaction, error) {
   685  	if args.GasPrice != nil && (args.MaxFeePerGas != nil || args.MaxPriorityFeePerGas != nil) {
   686  		return nil, errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified")
   687  	} else if args.MaxFeePerGas != nil && args.MaxPriorityFeePerGas != nil {
   688  		if args.MaxFeePerGas.ToInt().Cmp(args.MaxPriorityFeePerGas.ToInt()) < 0 {
   689  			return nil, errors.New("MaxPriorityFeePerGas is greater than MaxFeePerGas")
   690  		}
   691  	}
   692  
   693  	// Set sender address or use zero address if none specified.
   694  	addr := args.From
   695  
   696  	// Set default gas & gas price if none were set
   697  	gas := globalGasCap
   698  	if gas == 0 {
   699  		gas = uint64(math.MaxUint64 / 2)
   700  	}
   701  	if args.Gas != 0 {
   702  		gas = uint64(args.Gas)
   703  	}
   704  	if globalGasCap != 0 && globalGasCap < gas {
   705  		logger.Warn("Caller gas above allowance, capping", "requested", gas, "cap", globalGasCap)
   706  		gas = globalGasCap
   707  	}
   708  
   709  	// Do not update gasPrice unless any of args.GasPrice and args.MaxFeePerGas is specified.
   710  	gasPrice := new(big.Int)
   711  	if baseFee.Cmp(new(big.Int).SetUint64(params.ZeroBaseFee)) == 0 {
   712  		// If baseFee is zero, then it must be a magma hardfork
   713  		if args.GasPrice != nil {
   714  			gasPrice = args.GasPrice.ToInt()
   715  		} else if args.MaxFeePerGas != nil {
   716  			gasPrice = args.MaxFeePerGas.ToInt()
   717  		}
   718  	} else {
   719  		if args.GasPrice != nil {
   720  			gasPrice = args.GasPrice.ToInt()
   721  		} else if args.MaxFeePerGas != nil {
   722  			// User specified 1559 gas fields (or none), use those
   723  			gasPrice = args.MaxFeePerGas.ToInt()
   724  		} else {
   725  			// User specified neither GasPrice nor MaxFeePerGas, use baseFee
   726  			gasPrice = new(big.Int).Mul(baseFee, common.Big2)
   727  		}
   728  	}
   729  	value := new(big.Int)
   730  	if &args.Value != nil {
   731  		value = args.Value.ToInt()
   732  	}
   733  
   734  	// TODO-Klaytn: Klaytn does not support accessList yet.
   735  	// var accessList types.AccessList
   736  	// if args.AccessList != nil {
   737  	//	 accessList = *args.AccessList
   738  	// }
   739  	return types.NewMessage(addr, args.To, 0, value, gas, gasPrice, args.data(), false, intrinsicGas), nil
   740  }