github.com/calmw/ethereum@v0.1.1/ethclient/ethclient.go (about) 1 // Copyright 2016 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 // Package ethclient provides a client for the Ethereum RPC API. 18 package ethclient 19 20 import ( 21 "context" 22 "encoding/json" 23 "errors" 24 "fmt" 25 "math/big" 26 27 "github.com/calmw/ethereum" 28 "github.com/calmw/ethereum/common" 29 "github.com/calmw/ethereum/common/hexutil" 30 "github.com/calmw/ethereum/core/types" 31 "github.com/calmw/ethereum/rpc" 32 ) 33 34 // Client defines typed wrappers for the Ethereum RPC API. 35 type Client struct { 36 c *rpc.Client 37 } 38 39 // Dial connects a client to the given URL. 40 func Dial(rawurl string) (*Client, error) { 41 return DialContext(context.Background(), rawurl) 42 } 43 44 // DialContext connects a client to the given URL with context. 45 func DialContext(ctx context.Context, rawurl string) (*Client, error) { 46 c, err := rpc.DialContext(ctx, rawurl) 47 if err != nil { 48 return nil, err 49 } 50 return NewClient(c), nil 51 } 52 53 // NewClient creates a client that uses the given RPC client. 54 func NewClient(c *rpc.Client) *Client { 55 return &Client{c} 56 } 57 58 // Close closes the underlying RPC connection. 59 func (ec *Client) Close() { 60 ec.c.Close() 61 } 62 63 // Client gets the underlying RPC client. 64 func (ec *Client) Client() *rpc.Client { 65 return ec.c 66 } 67 68 // Blockchain Access 69 70 // ChainID retrieves the current chain ID for transaction replay protection. 71 func (ec *Client) ChainID(ctx context.Context) (*big.Int, error) { 72 var result hexutil.Big 73 err := ec.c.CallContext(ctx, &result, "eth_chainId") 74 if err != nil { 75 return nil, err 76 } 77 return (*big.Int)(&result), err 78 } 79 80 // BlockByHash returns the given full block. 81 // 82 // Note that loading full blocks requires two requests. Use HeaderByHash 83 // if you don't need all transactions or uncle headers. 84 func (ec *Client) BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) { 85 return ec.getBlock(ctx, "eth_getBlockByHash", hash, true) 86 } 87 88 // BlockByNumber returns a block from the current canonical chain. If number is nil, the 89 // latest known block is returned. 90 // 91 // Note that loading full blocks requires two requests. Use HeaderByNumber 92 // if you don't need all transactions or uncle headers. 93 func (ec *Client) BlockByNumber(ctx context.Context, number *big.Int) (*types.Block, error) { 94 return ec.getBlock(ctx, "eth_getBlockByNumber", toBlockNumArg(number), true) 95 } 96 97 // BlockNumber returns the most recent block number 98 func (ec *Client) BlockNumber(ctx context.Context) (uint64, error) { 99 var result hexutil.Uint64 100 err := ec.c.CallContext(ctx, &result, "eth_blockNumber") 101 return uint64(result), err 102 } 103 104 // PeerCount returns the number of p2p peers as reported by the net_peerCount method. 105 func (ec *Client) PeerCount(ctx context.Context) (uint64, error) { 106 var result hexutil.Uint64 107 err := ec.c.CallContext(ctx, &result, "net_peerCount") 108 return uint64(result), err 109 } 110 111 type rpcBlock struct { 112 Hash common.Hash `json:"hash"` 113 Transactions []rpcTransaction `json:"transactions"` 114 UncleHashes []common.Hash `json:"uncles"` 115 Withdrawals []*types.Withdrawal `json:"withdrawals,omitempty"` 116 } 117 118 func (ec *Client) getBlock(ctx context.Context, method string, args ...interface{}) (*types.Block, error) { 119 var raw json.RawMessage 120 err := ec.c.CallContext(ctx, &raw, method, args...) 121 if err != nil { 122 return nil, err 123 } 124 125 // Decode header and transactions. 126 var head *types.Header 127 if err := json.Unmarshal(raw, &head); err != nil { 128 return nil, err 129 } 130 // When the block is not found, the API returns JSON null. 131 if head == nil { 132 return nil, ethereum.NotFound 133 } 134 135 var body rpcBlock 136 if err := json.Unmarshal(raw, &body); err != nil { 137 return nil, err 138 } 139 // Quick-verify transaction and uncle lists. This mostly helps with debugging the server. 140 if head.UncleHash == types.EmptyUncleHash && len(body.UncleHashes) > 0 { 141 return nil, fmt.Errorf("server returned non-empty uncle list but block header indicates no uncles") 142 } 143 if head.UncleHash != types.EmptyUncleHash && len(body.UncleHashes) == 0 { 144 return nil, fmt.Errorf("server returned empty uncle list but block header indicates uncles") 145 } 146 if head.TxHash == types.EmptyTxsHash && len(body.Transactions) > 0 { 147 return nil, fmt.Errorf("server returned non-empty transaction list but block header indicates no transactions") 148 } 149 if head.TxHash != types.EmptyTxsHash && len(body.Transactions) == 0 { 150 return nil, fmt.Errorf("server returned empty transaction list but block header indicates transactions") 151 } 152 // Load uncles because they are not included in the block response. 153 var uncles []*types.Header 154 if len(body.UncleHashes) > 0 { 155 uncles = make([]*types.Header, len(body.UncleHashes)) 156 reqs := make([]rpc.BatchElem, len(body.UncleHashes)) 157 for i := range reqs { 158 reqs[i] = rpc.BatchElem{ 159 Method: "eth_getUncleByBlockHashAndIndex", 160 Args: []interface{}{body.Hash, hexutil.EncodeUint64(uint64(i))}, 161 Result: &uncles[i], 162 } 163 } 164 if err := ec.c.BatchCallContext(ctx, reqs); err != nil { 165 return nil, err 166 } 167 for i := range reqs { 168 if reqs[i].Error != nil { 169 return nil, reqs[i].Error 170 } 171 if uncles[i] == nil { 172 return nil, fmt.Errorf("got null header for uncle %d of block %x", i, body.Hash[:]) 173 } 174 } 175 } 176 // Fill the sender cache of transactions in the block. 177 txs := make([]*types.Transaction, len(body.Transactions)) 178 for i, tx := range body.Transactions { 179 if tx.From != nil { 180 setSenderFromServer(tx.tx, *tx.From, body.Hash) 181 } 182 txs[i] = tx.tx 183 } 184 return types.NewBlockWithHeader(head).WithBody(txs, uncles).WithWithdrawals(body.Withdrawals), nil 185 } 186 187 // HeaderByHash returns the block header with the given hash. 188 func (ec *Client) HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error) { 189 var head *types.Header 190 err := ec.c.CallContext(ctx, &head, "eth_getBlockByHash", hash, false) 191 if err == nil && head == nil { 192 err = ethereum.NotFound 193 } 194 return head, err 195 } 196 197 // HeaderByNumber returns a block header from the current canonical chain. If number is 198 // nil, the latest known header is returned. 199 func (ec *Client) HeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error) { 200 var head *types.Header 201 err := ec.c.CallContext(ctx, &head, "eth_getBlockByNumber", toBlockNumArg(number), false) 202 if err == nil && head == nil { 203 err = ethereum.NotFound 204 } 205 return head, err 206 } 207 208 type rpcTransaction struct { 209 tx *types.Transaction 210 txExtraInfo 211 } 212 213 type txExtraInfo struct { 214 BlockNumber *string `json:"blockNumber,omitempty"` 215 BlockHash *common.Hash `json:"blockHash,omitempty"` 216 From *common.Address `json:"from,omitempty"` 217 } 218 219 func (tx *rpcTransaction) UnmarshalJSON(msg []byte) error { 220 if err := json.Unmarshal(msg, &tx.tx); err != nil { 221 return err 222 } 223 return json.Unmarshal(msg, &tx.txExtraInfo) 224 } 225 226 // TransactionByHash returns the transaction with the given hash. 227 func (ec *Client) TransactionByHash(ctx context.Context, hash common.Hash) (tx *types.Transaction, isPending bool, err error) { 228 var json *rpcTransaction 229 err = ec.c.CallContext(ctx, &json, "eth_getTransactionByHash", hash) 230 if err != nil { 231 return nil, false, err 232 } else if json == nil { 233 return nil, false, ethereum.NotFound 234 } else if _, r, _ := json.tx.RawSignatureValues(); r == nil { 235 return nil, false, fmt.Errorf("server returned transaction without signature") 236 } 237 if json.From != nil && json.BlockHash != nil { 238 setSenderFromServer(json.tx, *json.From, *json.BlockHash) 239 } 240 return json.tx, json.BlockNumber == nil, nil 241 } 242 243 // TransactionSender returns the sender address of the given transaction. The transaction 244 // must be known to the remote node and included in the blockchain at the given block and 245 // index. The sender is the one derived by the protocol at the time of inclusion. 246 // 247 // There is a fast-path for transactions retrieved by TransactionByHash and 248 // TransactionInBlock. Getting their sender address can be done without an RPC interaction. 249 func (ec *Client) TransactionSender(ctx context.Context, tx *types.Transaction, block common.Hash, index uint) (common.Address, error) { 250 // Try to load the address from the cache. 251 sender, err := types.Sender(&senderFromServer{blockhash: block}, tx) 252 if err == nil { 253 return sender, nil 254 } 255 256 // It was not found in cache, ask the server. 257 var meta struct { 258 Hash common.Hash 259 From common.Address 260 } 261 if err = ec.c.CallContext(ctx, &meta, "eth_getTransactionByBlockHashAndIndex", block, hexutil.Uint64(index)); err != nil { 262 return common.Address{}, err 263 } 264 if meta.Hash == (common.Hash{}) || meta.Hash != tx.Hash() { 265 return common.Address{}, errors.New("wrong inclusion block/index") 266 } 267 return meta.From, nil 268 } 269 270 // TransactionCount returns the total number of transactions in the given block. 271 func (ec *Client) TransactionCount(ctx context.Context, blockHash common.Hash) (uint, error) { 272 var num hexutil.Uint 273 err := ec.c.CallContext(ctx, &num, "eth_getBlockTransactionCountByHash", blockHash) 274 return uint(num), err 275 } 276 277 // TransactionInBlock returns a single transaction at index in the given block. 278 func (ec *Client) TransactionInBlock(ctx context.Context, blockHash common.Hash, index uint) (*types.Transaction, error) { 279 var json *rpcTransaction 280 err := ec.c.CallContext(ctx, &json, "eth_getTransactionByBlockHashAndIndex", blockHash, hexutil.Uint64(index)) 281 if err != nil { 282 return nil, err 283 } 284 if json == nil { 285 return nil, ethereum.NotFound 286 } else if _, r, _ := json.tx.RawSignatureValues(); r == nil { 287 return nil, fmt.Errorf("server returned transaction without signature") 288 } 289 if json.From != nil && json.BlockHash != nil { 290 setSenderFromServer(json.tx, *json.From, *json.BlockHash) 291 } 292 return json.tx, err 293 } 294 295 // TransactionReceipt returns the receipt of a transaction by transaction hash. 296 // Note that the receipt is not available for pending transactions. 297 func (ec *Client) TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) { 298 var r *types.Receipt 299 err := ec.c.CallContext(ctx, &r, "eth_getTransactionReceipt", txHash) 300 if err == nil { 301 if r == nil { 302 return nil, ethereum.NotFound 303 } 304 } 305 return r, err 306 } 307 308 // SyncProgress retrieves the current progress of the sync algorithm. If there's 309 // no sync currently running, it returns nil. 310 func (ec *Client) SyncProgress(ctx context.Context) (*ethereum.SyncProgress, error) { 311 var raw json.RawMessage 312 if err := ec.c.CallContext(ctx, &raw, "eth_syncing"); err != nil { 313 return nil, err 314 } 315 // Handle the possible response types 316 var syncing bool 317 if err := json.Unmarshal(raw, &syncing); err == nil { 318 return nil, nil // Not syncing (always false) 319 } 320 var p *rpcProgress 321 if err := json.Unmarshal(raw, &p); err != nil { 322 return nil, err 323 } 324 return p.toSyncProgress(), nil 325 } 326 327 // SubscribeNewHead subscribes to notifications about the current blockchain head 328 // on the given channel. 329 func (ec *Client) SubscribeNewHead(ctx context.Context, ch chan<- *types.Header) (ethereum.Subscription, error) { 330 sub, err := ec.c.EthSubscribe(ctx, ch, "newHeads") 331 if err != nil { 332 // Defensively prefer returning nil interface explicitly on error-path, instead 333 // of letting default golang behavior wrap it with non-nil interface that stores 334 // nil concrete type value. 335 return nil, err 336 } 337 return sub, nil 338 } 339 340 // State Access 341 342 // NetworkID returns the network ID for this client. 343 func (ec *Client) NetworkID(ctx context.Context) (*big.Int, error) { 344 version := new(big.Int) 345 var ver string 346 if err := ec.c.CallContext(ctx, &ver, "net_version"); err != nil { 347 return nil, err 348 } 349 if _, ok := version.SetString(ver, 10); !ok { 350 return nil, fmt.Errorf("invalid net_version result %q", ver) 351 } 352 return version, nil 353 } 354 355 // BalanceAt returns the wei balance of the given account. 356 // The block number can be nil, in which case the balance is taken from the latest known block. 357 func (ec *Client) BalanceAt(ctx context.Context, account common.Address, blockNumber *big.Int) (*big.Int, error) { 358 var result hexutil.Big 359 err := ec.c.CallContext(ctx, &result, "eth_getBalance", account, toBlockNumArg(blockNumber)) 360 return (*big.Int)(&result), err 361 } 362 363 // StorageAt returns the value of key in the contract storage of the given account. 364 // The block number can be nil, in which case the value is taken from the latest known block. 365 func (ec *Client) StorageAt(ctx context.Context, account common.Address, key common.Hash, blockNumber *big.Int) ([]byte, error) { 366 var result hexutil.Bytes 367 err := ec.c.CallContext(ctx, &result, "eth_getStorageAt", account, key, toBlockNumArg(blockNumber)) 368 return result, err 369 } 370 371 // CodeAt returns the contract code of the given account. 372 // The block number can be nil, in which case the code is taken from the latest known block. 373 func (ec *Client) CodeAt(ctx context.Context, account common.Address, blockNumber *big.Int) ([]byte, error) { 374 var result hexutil.Bytes 375 err := ec.c.CallContext(ctx, &result, "eth_getCode", account, toBlockNumArg(blockNumber)) 376 return result, err 377 } 378 379 // NonceAt returns the account nonce of the given account. 380 // The block number can be nil, in which case the nonce is taken from the latest known block. 381 func (ec *Client) NonceAt(ctx context.Context, account common.Address, blockNumber *big.Int) (uint64, error) { 382 var result hexutil.Uint64 383 err := ec.c.CallContext(ctx, &result, "eth_getTransactionCount", account, toBlockNumArg(blockNumber)) 384 return uint64(result), err 385 } 386 387 // Filters 388 389 // FilterLogs executes a filter query. 390 func (ec *Client) FilterLogs(ctx context.Context, q ethereum.FilterQuery) ([]types.Log, error) { 391 var result []types.Log 392 arg, err := toFilterArg(q) 393 if err != nil { 394 return nil, err 395 } 396 err = ec.c.CallContext(ctx, &result, "eth_getLogs", arg) 397 return result, err 398 } 399 400 // SubscribeFilterLogs subscribes to the results of a streaming filter query. 401 func (ec *Client) SubscribeFilterLogs(ctx context.Context, q ethereum.FilterQuery, ch chan<- types.Log) (ethereum.Subscription, error) { 402 arg, err := toFilterArg(q) 403 if err != nil { 404 return nil, err 405 } 406 sub, err := ec.c.EthSubscribe(ctx, ch, "logs", arg) 407 if err != nil { 408 // Defensively prefer returning nil interface explicitly on error-path, instead 409 // of letting default golang behavior wrap it with non-nil interface that stores 410 // nil concrete type value. 411 return nil, err 412 } 413 return sub, nil 414 } 415 416 func toFilterArg(q ethereum.FilterQuery) (interface{}, error) { 417 arg := map[string]interface{}{ 418 "address": q.Addresses, 419 "topics": q.Topics, 420 } 421 if q.BlockHash != nil { 422 arg["blockHash"] = *q.BlockHash 423 if q.FromBlock != nil || q.ToBlock != nil { 424 return nil, fmt.Errorf("cannot specify both BlockHash and FromBlock/ToBlock") 425 } 426 } else { 427 if q.FromBlock == nil { 428 arg["fromBlock"] = "0x0" 429 } else { 430 arg["fromBlock"] = toBlockNumArg(q.FromBlock) 431 } 432 arg["toBlock"] = toBlockNumArg(q.ToBlock) 433 } 434 return arg, nil 435 } 436 437 // Pending State 438 439 // PendingBalanceAt returns the wei balance of the given account in the pending state. 440 func (ec *Client) PendingBalanceAt(ctx context.Context, account common.Address) (*big.Int, error) { 441 var result hexutil.Big 442 err := ec.c.CallContext(ctx, &result, "eth_getBalance", account, "pending") 443 return (*big.Int)(&result), err 444 } 445 446 // PendingStorageAt returns the value of key in the contract storage of the given account in the pending state. 447 func (ec *Client) PendingStorageAt(ctx context.Context, account common.Address, key common.Hash) ([]byte, error) { 448 var result hexutil.Bytes 449 err := ec.c.CallContext(ctx, &result, "eth_getStorageAt", account, key, "pending") 450 return result, err 451 } 452 453 // PendingCodeAt returns the contract code of the given account in the pending state. 454 func (ec *Client) PendingCodeAt(ctx context.Context, account common.Address) ([]byte, error) { 455 var result hexutil.Bytes 456 err := ec.c.CallContext(ctx, &result, "eth_getCode", account, "pending") 457 return result, err 458 } 459 460 // PendingNonceAt returns the account nonce of the given account in the pending state. 461 // This is the nonce that should be used for the next transaction. 462 func (ec *Client) PendingNonceAt(ctx context.Context, account common.Address) (uint64, error) { 463 var result hexutil.Uint64 464 err := ec.c.CallContext(ctx, &result, "eth_getTransactionCount", account, "pending") 465 return uint64(result), err 466 } 467 468 // PendingTransactionCount returns the total number of transactions in the pending state. 469 func (ec *Client) PendingTransactionCount(ctx context.Context) (uint, error) { 470 var num hexutil.Uint 471 err := ec.c.CallContext(ctx, &num, "eth_getBlockTransactionCountByNumber", "pending") 472 return uint(num), err 473 } 474 475 // Contract Calling 476 477 // CallContract executes a message call transaction, which is directly executed in the VM 478 // of the node, but never mined into the blockchain. 479 // 480 // blockNumber selects the block height at which the call runs. It can be nil, in which 481 // case the code is taken from the latest known block. Note that state from very old 482 // blocks might not be available. 483 func (ec *Client) CallContract(ctx context.Context, msg ethereum.CallMsg, blockNumber *big.Int) ([]byte, error) { 484 var hex hexutil.Bytes 485 err := ec.c.CallContext(ctx, &hex, "eth_call", toCallArg(msg), toBlockNumArg(blockNumber)) 486 if err != nil { 487 return nil, err 488 } 489 return hex, nil 490 } 491 492 // CallContractAtHash is almost the same as CallContract except that it selects 493 // the block by block hash instead of block height. 494 func (ec *Client) CallContractAtHash(ctx context.Context, msg ethereum.CallMsg, blockHash common.Hash) ([]byte, error) { 495 var hex hexutil.Bytes 496 err := ec.c.CallContext(ctx, &hex, "eth_call", toCallArg(msg), rpc.BlockNumberOrHashWithHash(blockHash, false)) 497 if err != nil { 498 return nil, err 499 } 500 return hex, nil 501 } 502 503 // PendingCallContract executes a message call transaction using the EVM. 504 // The state seen by the contract call is the pending state. 505 func (ec *Client) PendingCallContract(ctx context.Context, msg ethereum.CallMsg) ([]byte, error) { 506 var hex hexutil.Bytes 507 err := ec.c.CallContext(ctx, &hex, "eth_call", toCallArg(msg), "pending") 508 if err != nil { 509 return nil, err 510 } 511 return hex, nil 512 } 513 514 // SuggestGasPrice retrieves the currently suggested gas price to allow a timely 515 // execution of a transaction. 516 func (ec *Client) SuggestGasPrice(ctx context.Context) (*big.Int, error) { 517 var hex hexutil.Big 518 if err := ec.c.CallContext(ctx, &hex, "eth_gasPrice"); err != nil { 519 return nil, err 520 } 521 return (*big.Int)(&hex), nil 522 } 523 524 // SuggestGasTipCap retrieves the currently suggested gas tip cap after 1559 to 525 // allow a timely execution of a transaction. 526 func (ec *Client) SuggestGasTipCap(ctx context.Context) (*big.Int, error) { 527 var hex hexutil.Big 528 if err := ec.c.CallContext(ctx, &hex, "eth_maxPriorityFeePerGas"); err != nil { 529 return nil, err 530 } 531 return (*big.Int)(&hex), nil 532 } 533 534 type feeHistoryResultMarshaling struct { 535 OldestBlock *hexutil.Big `json:"oldestBlock"` 536 Reward [][]*hexutil.Big `json:"reward,omitempty"` 537 BaseFee []*hexutil.Big `json:"baseFeePerGas,omitempty"` 538 GasUsedRatio []float64 `json:"gasUsedRatio"` 539 } 540 541 // FeeHistory retrieves the fee market history. 542 func (ec *Client) FeeHistory(ctx context.Context, blockCount uint64, lastBlock *big.Int, rewardPercentiles []float64) (*ethereum.FeeHistory, error) { 543 var res feeHistoryResultMarshaling 544 if err := ec.c.CallContext(ctx, &res, "eth_feeHistory", hexutil.Uint(blockCount), toBlockNumArg(lastBlock), rewardPercentiles); err != nil { 545 return nil, err 546 } 547 reward := make([][]*big.Int, len(res.Reward)) 548 for i, r := range res.Reward { 549 reward[i] = make([]*big.Int, len(r)) 550 for j, r := range r { 551 reward[i][j] = (*big.Int)(r) 552 } 553 } 554 baseFee := make([]*big.Int, len(res.BaseFee)) 555 for i, b := range res.BaseFee { 556 baseFee[i] = (*big.Int)(b) 557 } 558 return ðereum.FeeHistory{ 559 OldestBlock: (*big.Int)(res.OldestBlock), 560 Reward: reward, 561 BaseFee: baseFee, 562 GasUsedRatio: res.GasUsedRatio, 563 }, nil 564 } 565 566 // EstimateGas tries to estimate the gas needed to execute a specific transaction based on 567 // the current pending state of the backend blockchain. There is no guarantee that this is 568 // the true gas limit requirement as other transactions may be added or removed by miners, 569 // but it should provide a basis for setting a reasonable default. 570 func (ec *Client) EstimateGas(ctx context.Context, msg ethereum.CallMsg) (uint64, error) { 571 var hex hexutil.Uint64 572 err := ec.c.CallContext(ctx, &hex, "eth_estimateGas", toCallArg(msg)) 573 if err != nil { 574 return 0, err 575 } 576 return uint64(hex), nil 577 } 578 579 // SendTransaction injects a signed transaction into the pending pool for execution. 580 // 581 // If the transaction was a contract creation use the TransactionReceipt method to get the 582 // contract address after the transaction has been mined. 583 func (ec *Client) SendTransaction(ctx context.Context, tx *types.Transaction) error { 584 data, err := tx.MarshalBinary() 585 if err != nil { 586 return err 587 } 588 return ec.c.CallContext(ctx, nil, "eth_sendRawTransaction", hexutil.Encode(data)) 589 } 590 591 func toBlockNumArg(number *big.Int) string { 592 if number == nil { 593 return "latest" 594 } 595 pending := big.NewInt(-1) 596 if number.Cmp(pending) == 0 { 597 return "pending" 598 } 599 finalized := big.NewInt(int64(rpc.FinalizedBlockNumber)) 600 if number.Cmp(finalized) == 0 { 601 return "finalized" 602 } 603 safe := big.NewInt(int64(rpc.SafeBlockNumber)) 604 if number.Cmp(safe) == 0 { 605 return "safe" 606 } 607 return hexutil.EncodeBig(number) 608 } 609 610 func toCallArg(msg ethereum.CallMsg) interface{} { 611 arg := map[string]interface{}{ 612 "from": msg.From, 613 "to": msg.To, 614 } 615 if len(msg.Data) > 0 { 616 arg["data"] = hexutil.Bytes(msg.Data) 617 } 618 if msg.Value != nil { 619 arg["value"] = (*hexutil.Big)(msg.Value) 620 } 621 if msg.Gas != 0 { 622 arg["gas"] = hexutil.Uint64(msg.Gas) 623 } 624 if msg.GasPrice != nil { 625 arg["gasPrice"] = (*hexutil.Big)(msg.GasPrice) 626 } 627 return arg 628 } 629 630 // rpcProgress is a copy of SyncProgress with hex-encoded fields. 631 type rpcProgress struct { 632 StartingBlock hexutil.Uint64 633 CurrentBlock hexutil.Uint64 634 HighestBlock hexutil.Uint64 635 636 PulledStates hexutil.Uint64 637 KnownStates hexutil.Uint64 638 639 SyncedAccounts hexutil.Uint64 640 SyncedAccountBytes hexutil.Uint64 641 SyncedBytecodes hexutil.Uint64 642 SyncedBytecodeBytes hexutil.Uint64 643 SyncedStorage hexutil.Uint64 644 SyncedStorageBytes hexutil.Uint64 645 HealedTrienodes hexutil.Uint64 646 HealedTrienodeBytes hexutil.Uint64 647 HealedBytecodes hexutil.Uint64 648 HealedBytecodeBytes hexutil.Uint64 649 HealingTrienodes hexutil.Uint64 650 HealingBytecode hexutil.Uint64 651 } 652 653 func (p *rpcProgress) toSyncProgress() *ethereum.SyncProgress { 654 if p == nil { 655 return nil 656 } 657 return ðereum.SyncProgress{ 658 StartingBlock: uint64(p.StartingBlock), 659 CurrentBlock: uint64(p.CurrentBlock), 660 HighestBlock: uint64(p.HighestBlock), 661 PulledStates: uint64(p.PulledStates), 662 KnownStates: uint64(p.KnownStates), 663 SyncedAccounts: uint64(p.SyncedAccounts), 664 SyncedAccountBytes: uint64(p.SyncedAccountBytes), 665 SyncedBytecodes: uint64(p.SyncedBytecodes), 666 SyncedBytecodeBytes: uint64(p.SyncedBytecodeBytes), 667 SyncedStorage: uint64(p.SyncedStorage), 668 SyncedStorageBytes: uint64(p.SyncedStorageBytes), 669 HealedTrienodes: uint64(p.HealedTrienodes), 670 HealedTrienodeBytes: uint64(p.HealedTrienodeBytes), 671 HealedBytecodes: uint64(p.HealedBytecodes), 672 HealedBytecodeBytes: uint64(p.HealedBytecodeBytes), 673 HealingTrienodes: uint64(p.HealingTrienodes), 674 HealingBytecode: uint64(p.HealingBytecode), 675 } 676 }