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 }