github.com/theQRL/go-zond@v0.2.1/zondclient/zondclient.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 zondclient provides a client for the Zond RPC API.
    18  package zondclient
    19  
    20  import (
    21  	"context"
    22  	"encoding/json"
    23  	"errors"
    24  	"fmt"
    25  	"math/big"
    26  
    27  	"github.com/theQRL/go-zond"
    28  	"github.com/theQRL/go-zond/common"
    29  	"github.com/theQRL/go-zond/common/hexutil"
    30  	"github.com/theQRL/go-zond/core/types"
    31  	"github.com/theQRL/go-zond/rpc"
    32  )
    33  
    34  // Client defines typed wrappers for the Zond 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, "zond_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.
    84  func (ec *Client) BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) {
    85  	return ec.getBlock(ctx, "zond_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.
    93  func (ec *Client) BlockByNumber(ctx context.Context, number *big.Int) (*types.Block, error) {
    94  	return ec.getBlock(ctx, "zond_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, "zond_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  // BlockReceipts returns the receipts of a given block number or hash
   112  func (ec *Client) BlockReceipts(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) ([]*types.Receipt, error) {
   113  	var r []*types.Receipt
   114  	err := ec.c.CallContext(ctx, &r, "zond_getBlockReceipts", blockNrOrHash)
   115  	if err == nil && r == nil {
   116  		return nil, zond.NotFound
   117  	}
   118  	return r, err
   119  }
   120  
   121  type rpcBlock struct {
   122  	Hash         common.Hash         `json:"hash"`
   123  	Transactions []rpcTransaction    `json:"transactions"`
   124  	Withdrawals  []*types.Withdrawal `json:"withdrawals,omitempty"`
   125  }
   126  
   127  func (ec *Client) getBlock(ctx context.Context, method string, args ...interface{}) (*types.Block, error) {
   128  	var raw json.RawMessage
   129  	err := ec.c.CallContext(ctx, &raw, method, args...)
   130  	if err != nil {
   131  		return nil, err
   132  	}
   133  
   134  	// Decode header and transactions.
   135  	var head *types.Header
   136  	if err := json.Unmarshal(raw, &head); err != nil {
   137  		return nil, err
   138  	}
   139  	// When the block is not found, the API returns JSON null.
   140  	if head == nil {
   141  		return nil, zond.NotFound
   142  	}
   143  
   144  	var body rpcBlock
   145  	if err := json.Unmarshal(raw, &body); err != nil {
   146  		return nil, err
   147  	}
   148  	// Quick-verify transaction list. This mostly helps with debugging the server.
   149  	if head.TxHash == types.EmptyTxsHash && len(body.Transactions) > 0 {
   150  		return nil, errors.New("server returned non-empty transaction list but block header indicates no transactions")
   151  	}
   152  	if head.TxHash != types.EmptyTxsHash && len(body.Transactions) == 0 {
   153  		return nil, errors.New("server returned empty transaction list but block header indicates transactions")
   154  	}
   155  	// Fill the sender cache of transactions in the block.
   156  	txs := make([]*types.Transaction, len(body.Transactions))
   157  	for i, tx := range body.Transactions {
   158  		if tx.From != nil {
   159  			setSenderFromServer(tx.tx, *tx.From, body.Hash)
   160  		}
   161  		txs[i] = tx.tx
   162  	}
   163  	return types.NewBlockWithHeader(head).WithBody(
   164  		types.Body{
   165  			Transactions: txs,
   166  			Withdrawals:  body.Withdrawals,
   167  		}), nil
   168  }
   169  
   170  // HeaderByHash returns the block header with the given hash.
   171  func (ec *Client) HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error) {
   172  	var head *types.Header
   173  	err := ec.c.CallContext(ctx, &head, "zond_getBlockByHash", hash, false)
   174  	if err == nil && head == nil {
   175  		err = zond.NotFound
   176  	}
   177  	return head, err
   178  }
   179  
   180  // HeaderByNumber returns a block header from the current canonical chain. If number is
   181  // nil, the latest known header is returned.
   182  func (ec *Client) HeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error) {
   183  	var head *types.Header
   184  	err := ec.c.CallContext(ctx, &head, "zond_getBlockByNumber", toBlockNumArg(number), false)
   185  	if err == nil && head == nil {
   186  		err = zond.NotFound
   187  	}
   188  	return head, err
   189  }
   190  
   191  type rpcTransaction struct {
   192  	tx *types.Transaction
   193  	txExtraInfo
   194  }
   195  
   196  type txExtraInfo struct {
   197  	BlockNumber *string         `json:"blockNumber,omitempty"`
   198  	BlockHash   *common.Hash    `json:"blockHash,omitempty"`
   199  	From        *common.Address `json:"from,omitempty"`
   200  }
   201  
   202  func (tx *rpcTransaction) UnmarshalJSON(msg []byte) error {
   203  	if err := json.Unmarshal(msg, &tx.tx); err != nil {
   204  		return err
   205  	}
   206  	return json.Unmarshal(msg, &tx.txExtraInfo)
   207  }
   208  
   209  // TransactionByHash returns the transaction with the given hash.
   210  func (ec *Client) TransactionByHash(ctx context.Context, hash common.Hash) (tx *types.Transaction, isPending bool, err error) {
   211  	var json *rpcTransaction
   212  	err = ec.c.CallContext(ctx, &json, "zond_getTransactionByHash", hash)
   213  	if err != nil {
   214  		return nil, false, err
   215  	} else if json == nil {
   216  		return nil, false, zond.NotFound
   217  	} else if sig := json.tx.RawSignatureValue(); sig == nil {
   218  		return nil, false, errors.New("server returned transaction without signature")
   219  	}
   220  	if json.From != nil && json.BlockHash != nil {
   221  		setSenderFromServer(json.tx, *json.From, *json.BlockHash)
   222  	}
   223  	return json.tx, json.BlockNumber == nil, nil
   224  }
   225  
   226  // TransactionSender returns the sender address of the given transaction. The transaction
   227  // must be known to the remote node and included in the blockchain at the given block and
   228  // index. The sender is the one derived by the protocol at the time of inclusion.
   229  //
   230  // There is a fast-path for transactions retrieved by TransactionByHash and
   231  // TransactionInBlock. Getting their sender address can be done without an RPC interaction.
   232  func (ec *Client) TransactionSender(ctx context.Context, tx *types.Transaction, block common.Hash, index uint) (common.Address, error) {
   233  	// Try to load the address from the cache.
   234  	sender, err := types.Sender(&senderFromServer{blockhash: block}, tx)
   235  	if err == nil {
   236  		return sender, nil
   237  	}
   238  
   239  	// It was not found in cache, ask the server.
   240  	var meta struct {
   241  		Hash common.Hash
   242  		From common.Address
   243  	}
   244  	if err = ec.c.CallContext(ctx, &meta, "zond_getTransactionByBlockHashAndIndex", block, hexutil.Uint64(index)); err != nil {
   245  		return common.Address{}, err
   246  	}
   247  	if meta.Hash == (common.Hash{}) || meta.Hash != tx.Hash() {
   248  		return common.Address{}, errors.New("wrong inclusion block/index")
   249  	}
   250  	return meta.From, nil
   251  }
   252  
   253  // TransactionCount returns the total number of transactions in the given block.
   254  func (ec *Client) TransactionCount(ctx context.Context, blockHash common.Hash) (uint, error) {
   255  	var num hexutil.Uint
   256  	err := ec.c.CallContext(ctx, &num, "zond_getBlockTransactionCountByHash", blockHash)
   257  	return uint(num), err
   258  }
   259  
   260  // TransactionInBlock returns a single transaction at index in the given block.
   261  func (ec *Client) TransactionInBlock(ctx context.Context, blockHash common.Hash, index uint) (*types.Transaction, error) {
   262  	var json *rpcTransaction
   263  	err := ec.c.CallContext(ctx, &json, "zond_getTransactionByBlockHashAndIndex", blockHash, hexutil.Uint64(index))
   264  	if err != nil {
   265  		return nil, err
   266  	}
   267  	if json == nil {
   268  		return nil, zond.NotFound
   269  	} else if sig := json.tx.RawSignatureValue(); sig == nil {
   270  		return nil, errors.New("server returned transaction without signature")
   271  	}
   272  	if json.From != nil && json.BlockHash != nil {
   273  		setSenderFromServer(json.tx, *json.From, *json.BlockHash)
   274  	}
   275  	return json.tx, err
   276  }
   277  
   278  // TransactionReceipt returns the receipt of a transaction by transaction hash.
   279  // Note that the receipt is not available for pending transactions.
   280  func (ec *Client) TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) {
   281  	var r *types.Receipt
   282  	err := ec.c.CallContext(ctx, &r, "zond_getTransactionReceipt", txHash)
   283  	if err == nil && r == nil {
   284  		return nil, zond.NotFound
   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) (*zond.SyncProgress, error) {
   292  	var raw json.RawMessage
   293  	if err := ec.c.CallContext(ctx, &raw, "zond_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) (zond.Subscription, error) {
   311  	sub, err := ec.c.ZondSubscribe(ctx, ch, "newHeads")
   312  	if err != nil {
   313  		// Defensively prefer returning nil interface explicitly on error-path, instead
   314  		// of letting default golang behavior wrap it with non-nil interface that stores
   315  		// nil concrete type value.
   316  		return nil, err
   317  	}
   318  	return sub, nil
   319  }
   320  
   321  // State Access
   322  
   323  // NetworkID returns the network ID for this client.
   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, "zond_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, "zond_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, "zond_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, "zond_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 zond.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, "zond_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 zond.FilterQuery, ch chan<- types.Log) (zond.Subscription, error) {
   383  	arg, err := toFilterArg(q)
   384  	if err != nil {
   385  		return nil, err
   386  	}
   387  	sub, err := ec.c.ZondSubscribe(ctx, ch, "logs", arg)
   388  	if err != nil {
   389  		// Defensively prefer returning nil interface explicitly on error-path, instead
   390  		// of letting default golang behavior wrap it with non-nil interface that stores
   391  		// nil concrete type value.
   392  		return nil, err
   393  	}
   394  	return sub, nil
   395  }
   396  
   397  func toFilterArg(q zond.FilterQuery) (interface{}, error) {
   398  	arg := map[string]interface{}{
   399  		"address": q.Addresses,
   400  		"topics":  q.Topics,
   401  	}
   402  	if q.BlockHash != nil {
   403  		arg["blockHash"] = *q.BlockHash
   404  		if q.FromBlock != nil || q.ToBlock != nil {
   405  			return nil, errors.New("cannot specify both BlockHash and FromBlock/ToBlock")
   406  		}
   407  	} else {
   408  		if q.FromBlock == nil {
   409  			arg["fromBlock"] = "0x0"
   410  		} else {
   411  			arg["fromBlock"] = toBlockNumArg(q.FromBlock)
   412  		}
   413  		arg["toBlock"] = toBlockNumArg(q.ToBlock)
   414  	}
   415  	return arg, nil
   416  }
   417  
   418  // Pending State
   419  
   420  // PendingBalanceAt returns the wei balance of the given account in the pending state.
   421  func (ec *Client) PendingBalanceAt(ctx context.Context, account common.Address) (*big.Int, error) {
   422  	var result hexutil.Big
   423  	err := ec.c.CallContext(ctx, &result, "zond_getBalance", account, "pending")
   424  	return (*big.Int)(&result), err
   425  }
   426  
   427  // PendingStorageAt returns the value of key in the contract storage of the given account in the pending state.
   428  func (ec *Client) PendingStorageAt(ctx context.Context, account common.Address, key common.Hash) ([]byte, error) {
   429  	var result hexutil.Bytes
   430  	err := ec.c.CallContext(ctx, &result, "zond_getStorageAt", account, key, "pending")
   431  	return result, err
   432  }
   433  
   434  // PendingCodeAt returns the contract code of the given account in the pending state.
   435  func (ec *Client) PendingCodeAt(ctx context.Context, account common.Address) ([]byte, error) {
   436  	var result hexutil.Bytes
   437  	err := ec.c.CallContext(ctx, &result, "zond_getCode", account, "pending")
   438  	return result, err
   439  }
   440  
   441  // PendingNonceAt returns the account nonce of the given account in the pending state.
   442  // This is the nonce that should be used for the next transaction.
   443  func (ec *Client) PendingNonceAt(ctx context.Context, account common.Address) (uint64, error) {
   444  	var result hexutil.Uint64
   445  	err := ec.c.CallContext(ctx, &result, "zond_getTransactionCount", account, "pending")
   446  	return uint64(result), err
   447  }
   448  
   449  // PendingTransactionCount returns the total number of transactions in the pending state.
   450  func (ec *Client) PendingTransactionCount(ctx context.Context) (uint, error) {
   451  	var num hexutil.Uint
   452  	err := ec.c.CallContext(ctx, &num, "zond_getBlockTransactionCountByNumber", "pending")
   453  	return uint(num), err
   454  }
   455  
   456  // Contract Calling
   457  
   458  // CallContract executes a message call transaction, which is directly executed in the VM
   459  // of the node, but never mined into the blockchain.
   460  //
   461  // blockNumber selects the block height at which the call runs. It can be nil, in which
   462  // case the code is taken from the latest known block. Note that state from very old
   463  // blocks might not be available.
   464  func (ec *Client) CallContract(ctx context.Context, msg zond.CallMsg, blockNumber *big.Int) ([]byte, error) {
   465  	var hex hexutil.Bytes
   466  	err := ec.c.CallContext(ctx, &hex, "zond_call", toCallArg(msg), toBlockNumArg(blockNumber))
   467  	if err != nil {
   468  		return nil, err
   469  	}
   470  	return hex, nil
   471  }
   472  
   473  // CallContractAtHash is almost the same as CallContract except that it selects
   474  // the block by block hash instead of block height.
   475  func (ec *Client) CallContractAtHash(ctx context.Context, msg zond.CallMsg, blockHash common.Hash) ([]byte, error) {
   476  	var hex hexutil.Bytes
   477  	err := ec.c.CallContext(ctx, &hex, "zond_call", toCallArg(msg), rpc.BlockNumberOrHashWithHash(blockHash, false))
   478  	if err != nil {
   479  		return nil, err
   480  	}
   481  	return hex, nil
   482  }
   483  
   484  // PendingCallContract executes a message call transaction using the ZVM.
   485  // The state seen by the contract call is the pending state.
   486  func (ec *Client) PendingCallContract(ctx context.Context, msg zond.CallMsg) ([]byte, error) {
   487  	var hex hexutil.Bytes
   488  	err := ec.c.CallContext(ctx, &hex, "zond_call", toCallArg(msg), "pending")
   489  	if err != nil {
   490  		return nil, err
   491  	}
   492  	return hex, nil
   493  }
   494  
   495  // SuggestGasPrice retrieves the currently suggested gas price to allow a timely
   496  // execution of a transaction.
   497  func (zc *Client) SuggestGasPrice(ctx context.Context) (*big.Int, error) {
   498  	var hex hexutil.Big
   499  	if err := zc.c.CallContext(ctx, &hex, "zond_gasPrice"); err != nil {
   500  		return nil, err
   501  	}
   502  	return (*big.Int)(&hex), nil
   503  }
   504  
   505  // SuggestGasTipCap retrieves the currently suggested gas tip cap to
   506  // allow a timely execution of a transaction.
   507  func (ec *Client) SuggestGasTipCap(ctx context.Context) (*big.Int, error) {
   508  	var hex hexutil.Big
   509  	if err := ec.c.CallContext(ctx, &hex, "zond_maxPriorityFeePerGas"); err != nil {
   510  		return nil, err
   511  	}
   512  	return (*big.Int)(&hex), nil
   513  }
   514  
   515  type feeHistoryResultMarshaling struct {
   516  	OldestBlock  *hexutil.Big     `json:"oldestBlock"`
   517  	Reward       [][]*hexutil.Big `json:"reward,omitempty"`
   518  	BaseFee      []*hexutil.Big   `json:"baseFeePerGas,omitempty"`
   519  	GasUsedRatio []float64        `json:"gasUsedRatio"`
   520  }
   521  
   522  // FeeHistory retrieves the fee market history.
   523  func (ec *Client) FeeHistory(ctx context.Context, blockCount uint64, lastBlock *big.Int, rewardPercentiles []float64) (*zond.FeeHistory, error) {
   524  	var res feeHistoryResultMarshaling
   525  	if err := ec.c.CallContext(ctx, &res, "zond_feeHistory", hexutil.Uint(blockCount), toBlockNumArg(lastBlock), rewardPercentiles); err != nil {
   526  		return nil, err
   527  	}
   528  	reward := make([][]*big.Int, len(res.Reward))
   529  	for i, r := range res.Reward {
   530  		reward[i] = make([]*big.Int, len(r))
   531  		for j, r := range r {
   532  			reward[i][j] = (*big.Int)(r)
   533  		}
   534  	}
   535  	baseFee := make([]*big.Int, len(res.BaseFee))
   536  	for i, b := range res.BaseFee {
   537  		baseFee[i] = (*big.Int)(b)
   538  	}
   539  	return &zond.FeeHistory{
   540  		OldestBlock:  (*big.Int)(res.OldestBlock),
   541  		Reward:       reward,
   542  		BaseFee:      baseFee,
   543  		GasUsedRatio: res.GasUsedRatio,
   544  	}, nil
   545  }
   546  
   547  // EstimateGas tries to estimate the gas needed to execute a specific transaction based on
   548  // the current pending state of the backend blockchain. There is no guarantee that this is
   549  // the true gas limit requirement as other transactions may be added or removed by miners,
   550  // but it should provide a basis for setting a reasonable default.
   551  func (ec *Client) EstimateGas(ctx context.Context, msg zond.CallMsg) (uint64, error) {
   552  	var hex hexutil.Uint64
   553  	err := ec.c.CallContext(ctx, &hex, "zond_estimateGas", toCallArg(msg))
   554  	if err != nil {
   555  		return 0, err
   556  	}
   557  	return uint64(hex), nil
   558  }
   559  
   560  // SendTransaction injects a signed transaction into the pending pool for execution.
   561  //
   562  // If the transaction was a contract creation use the TransactionReceipt method to get the
   563  // contract address after the transaction has been mined.
   564  func (ec *Client) SendTransaction(ctx context.Context, tx *types.Transaction) error {
   565  	data, err := tx.MarshalBinary()
   566  	if err != nil {
   567  		return err
   568  	}
   569  	return ec.c.CallContext(ctx, nil, "zond_sendRawTransaction", hexutil.Encode(data))
   570  }
   571  
   572  func toBlockNumArg(number *big.Int) string {
   573  	if number == nil {
   574  		return "latest"
   575  	}
   576  	if number.Sign() >= 0 {
   577  		return hexutil.EncodeBig(number)
   578  	}
   579  	// It's negative.
   580  	if number.IsInt64() {
   581  		return rpc.BlockNumber(number.Int64()).String()
   582  	}
   583  	// It's negative and large, which is invalid.
   584  	return fmt.Sprintf("<invalid %d>", number)
   585  }
   586  
   587  func toCallArg(msg zond.CallMsg) interface{} {
   588  	arg := map[string]interface{}{
   589  		"from": msg.From,
   590  		"to":   msg.To,
   591  	}
   592  	if len(msg.Data) > 0 {
   593  		arg["input"] = hexutil.Bytes(msg.Data)
   594  	}
   595  	if msg.Value != nil {
   596  		arg["value"] = (*hexutil.Big)(msg.Value)
   597  	}
   598  	if msg.Gas != 0 {
   599  		arg["gas"] = hexutil.Uint64(msg.Gas)
   600  	}
   601  	if msg.GasFeeCap != nil {
   602  		arg["maxFeePerGas"] = (*hexutil.Big)(msg.GasFeeCap)
   603  	}
   604  	if msg.GasTipCap != nil {
   605  		arg["maxPriorityFeePerGas"] = (*hexutil.Big)(msg.GasTipCap)
   606  	}
   607  	if msg.AccessList != nil {
   608  		arg["accessList"] = msg.AccessList
   609  	}
   610  	return arg
   611  }
   612  
   613  // rpcProgress is a copy of SyncProgress with hex-encoded fields.
   614  type rpcProgress struct {
   615  	StartingBlock hexutil.Uint64
   616  	CurrentBlock  hexutil.Uint64
   617  	HighestBlock  hexutil.Uint64
   618  
   619  	PulledStates hexutil.Uint64
   620  	KnownStates  hexutil.Uint64
   621  
   622  	SyncedAccounts      hexutil.Uint64
   623  	SyncedAccountBytes  hexutil.Uint64
   624  	SyncedBytecodes     hexutil.Uint64
   625  	SyncedBytecodeBytes hexutil.Uint64
   626  	SyncedStorage       hexutil.Uint64
   627  	SyncedStorageBytes  hexutil.Uint64
   628  	HealedTrienodes     hexutil.Uint64
   629  	HealedTrienodeBytes hexutil.Uint64
   630  	HealedBytecodes     hexutil.Uint64
   631  	HealedBytecodeBytes hexutil.Uint64
   632  	HealingTrienodes    hexutil.Uint64
   633  	HealingBytecode     hexutil.Uint64
   634  }
   635  
   636  func (p *rpcProgress) toSyncProgress() *zond.SyncProgress {
   637  	if p == nil {
   638  		return nil
   639  	}
   640  	return &zond.SyncProgress{
   641  		StartingBlock:       uint64(p.StartingBlock),
   642  		CurrentBlock:        uint64(p.CurrentBlock),
   643  		HighestBlock:        uint64(p.HighestBlock),
   644  		PulledStates:        uint64(p.PulledStates),
   645  		KnownStates:         uint64(p.KnownStates),
   646  		SyncedAccounts:      uint64(p.SyncedAccounts),
   647  		SyncedAccountBytes:  uint64(p.SyncedAccountBytes),
   648  		SyncedBytecodes:     uint64(p.SyncedBytecodes),
   649  		SyncedBytecodeBytes: uint64(p.SyncedBytecodeBytes),
   650  		SyncedStorage:       uint64(p.SyncedStorage),
   651  		SyncedStorageBytes:  uint64(p.SyncedStorageBytes),
   652  		HealedTrienodes:     uint64(p.HealedTrienodes),
   653  		HealedTrienodeBytes: uint64(p.HealedTrienodeBytes),
   654  		HealedBytecodes:     uint64(p.HealedBytecodes),
   655  		HealedBytecodeBytes: uint64(p.HealedBytecodeBytes),
   656  		HealingTrienodes:    uint64(p.HealingTrienodes),
   657  		HealingBytecode:     uint64(p.HealingBytecode),
   658  	}
   659  }