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