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