github.com/theQRL/go-zond@v0.1.1/zondclient/gzondclient/gzondclient.go (about)

     1  // Copyright 2021 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 gzondclient provides an RPC client for geth-specific APIs.
    18  package gzondclient
    19  
    20  import (
    21  	"context"
    22  	"encoding/json"
    23  	"fmt"
    24  	"math/big"
    25  	"runtime"
    26  	"runtime/debug"
    27  
    28  	"github.com/theQRL/go-zond"
    29  	"github.com/theQRL/go-zond/common"
    30  	"github.com/theQRL/go-zond/common/hexutil"
    31  	"github.com/theQRL/go-zond/core/types"
    32  	"github.com/theQRL/go-zond/p2p"
    33  	"github.com/theQRL/go-zond/rpc"
    34  )
    35  
    36  // Client is a wrapper around rpc.Client that implements geth-specific functionality.
    37  //
    38  // If you want to use the standardized Ethereum RPC functionality, use zondclient.Client instead.
    39  type Client struct {
    40  	c *rpc.Client
    41  }
    42  
    43  // New creates a client that uses the given RPC client.
    44  func New(c *rpc.Client) *Client {
    45  	return &Client{c}
    46  }
    47  
    48  // CreateAccessList tries to create an access list for a specific transaction based on the
    49  // current pending state of the blockchain.
    50  func (ec *Client) CreateAccessList(ctx context.Context, msg zond.CallMsg) (*types.AccessList, uint64, string, error) {
    51  	type accessListResult struct {
    52  		Accesslist *types.AccessList `json:"accessList"`
    53  		Error      string            `json:"error,omitempty"`
    54  		GasUsed    hexutil.Uint64    `json:"gasUsed"`
    55  	}
    56  	var result accessListResult
    57  	if err := ec.c.CallContext(ctx, &result, "zond_createAccessList", toCallArg(msg)); err != nil {
    58  		return nil, 0, "", err
    59  	}
    60  	return result.Accesslist, uint64(result.GasUsed), result.Error, nil
    61  }
    62  
    63  // AccountResult is the result of a GetProof operation.
    64  type AccountResult struct {
    65  	Address      common.Address  `json:"address"`
    66  	AccountProof []string        `json:"accountProof"`
    67  	Balance      *big.Int        `json:"balance"`
    68  	CodeHash     common.Hash     `json:"codeHash"`
    69  	Nonce        uint64          `json:"nonce"`
    70  	StorageHash  common.Hash     `json:"storageHash"`
    71  	StorageProof []StorageResult `json:"storageProof"`
    72  }
    73  
    74  // StorageResult provides a proof for a key-value pair.
    75  type StorageResult struct {
    76  	Key   string   `json:"key"`
    77  	Value *big.Int `json:"value"`
    78  	Proof []string `json:"proof"`
    79  }
    80  
    81  // GetProof returns the account and storage values of the specified account including the Merkle-proof.
    82  // The block number can be nil, in which case the value is taken from the latest known block.
    83  func (ec *Client) GetProof(ctx context.Context, account common.Address, keys []string, blockNumber *big.Int) (*AccountResult, error) {
    84  	type storageResult struct {
    85  		Key   string       `json:"key"`
    86  		Value *hexutil.Big `json:"value"`
    87  		Proof []string     `json:"proof"`
    88  	}
    89  
    90  	type accountResult struct {
    91  		Address      common.Address  `json:"address"`
    92  		AccountProof []string        `json:"accountProof"`
    93  		Balance      *hexutil.Big    `json:"balance"`
    94  		CodeHash     common.Hash     `json:"codeHash"`
    95  		Nonce        hexutil.Uint64  `json:"nonce"`
    96  		StorageHash  common.Hash     `json:"storageHash"`
    97  		StorageProof []storageResult `json:"storageProof"`
    98  	}
    99  
   100  	// Avoid keys being 'null'.
   101  	if keys == nil {
   102  		keys = []string{}
   103  	}
   104  
   105  	var res accountResult
   106  	err := ec.c.CallContext(ctx, &res, "zond_getProof", account, keys, toBlockNumArg(blockNumber))
   107  	// Turn hexutils back to normal datatypes
   108  	storageResults := make([]StorageResult, 0, len(res.StorageProof))
   109  	for _, st := range res.StorageProof {
   110  		storageResults = append(storageResults, StorageResult{
   111  			Key:   st.Key,
   112  			Value: st.Value.ToInt(),
   113  			Proof: st.Proof,
   114  		})
   115  	}
   116  	result := AccountResult{
   117  		Address:      res.Address,
   118  		AccountProof: res.AccountProof,
   119  		Balance:      res.Balance.ToInt(),
   120  		Nonce:        uint64(res.Nonce),
   121  		CodeHash:     res.CodeHash,
   122  		StorageHash:  res.StorageHash,
   123  		StorageProof: storageResults,
   124  	}
   125  	return &result, err
   126  }
   127  
   128  // CallContract executes a message call transaction, which is directly executed in the VM
   129  // of the node, but never mined into the blockchain.
   130  //
   131  // blockNumber selects the block height at which the call runs. It can be nil, in which
   132  // case the code is taken from the latest known block. Note that state from very old
   133  // blocks might not be available.
   134  //
   135  // overrides specifies a map of contract states that should be overwritten before executing
   136  // the message call.
   137  // Please use zondclient.CallContract instead if you don't need the override functionality.
   138  func (ec *Client) CallContract(ctx context.Context, msg zond.CallMsg, blockNumber *big.Int, overrides *map[common.Address]OverrideAccount) ([]byte, error) {
   139  	var hex hexutil.Bytes
   140  	err := ec.c.CallContext(
   141  		ctx, &hex, "zond_call", toCallArg(msg),
   142  		toBlockNumArg(blockNumber), overrides,
   143  	)
   144  	return hex, err
   145  }
   146  
   147  // CallContractWithBlockOverrides executes a message call transaction, which is directly executed
   148  // in the VM  of the node, but never mined into the blockchain.
   149  //
   150  // blockNumber selects the block height at which the call runs. It can be nil, in which
   151  // case the code is taken from the latest known block. Note that state from very old
   152  // blocks might not be available.
   153  //
   154  // overrides specifies a map of contract states that should be overwritten before executing
   155  // the message call.
   156  //
   157  // blockOverrides specifies block fields exposed to the EVM that can be overridden for the call.
   158  //
   159  // Please use zondclient.CallContract instead if you don't need the override functionality.
   160  func (ec *Client) CallContractWithBlockOverrides(ctx context.Context, msg zond.CallMsg, blockNumber *big.Int, overrides *map[common.Address]OverrideAccount, blockOverrides BlockOverrides) ([]byte, error) {
   161  	var hex hexutil.Bytes
   162  	err := ec.c.CallContext(
   163  		ctx, &hex, "zond_call", toCallArg(msg),
   164  		toBlockNumArg(blockNumber), overrides, blockOverrides,
   165  	)
   166  	return hex, err
   167  }
   168  
   169  // GCStats retrieves the current garbage collection stats from a geth node.
   170  func (ec *Client) GCStats(ctx context.Context) (*debug.GCStats, error) {
   171  	var result debug.GCStats
   172  	err := ec.c.CallContext(ctx, &result, "debug_gcStats")
   173  	return &result, err
   174  }
   175  
   176  // MemStats retrieves the current memory stats from a geth node.
   177  func (ec *Client) MemStats(ctx context.Context) (*runtime.MemStats, error) {
   178  	var result runtime.MemStats
   179  	err := ec.c.CallContext(ctx, &result, "debug_memStats")
   180  	return &result, err
   181  }
   182  
   183  // SetHead sets the current head of the local chain by block number.
   184  // Note, this is a destructive action and may severely damage your chain.
   185  // Use with extreme caution.
   186  func (ec *Client) SetHead(ctx context.Context, number *big.Int) error {
   187  	return ec.c.CallContext(ctx, nil, "debug_setHead", toBlockNumArg(number))
   188  }
   189  
   190  // GetNodeInfo retrieves the node info of a geth node.
   191  func (ec *Client) GetNodeInfo(ctx context.Context) (*p2p.NodeInfo, error) {
   192  	var result p2p.NodeInfo
   193  	err := ec.c.CallContext(ctx, &result, "admin_nodeInfo")
   194  	return &result, err
   195  }
   196  
   197  // SubscribeFullPendingTransactions subscribes to new pending transactions.
   198  func (ec *Client) SubscribeFullPendingTransactions(ctx context.Context, ch chan<- *types.Transaction) (*rpc.ClientSubscription, error) {
   199  	return ec.c.EthSubscribe(ctx, ch, "newPendingTransactions", true)
   200  }
   201  
   202  // SubscribePendingTransactions subscribes to new pending transaction hashes.
   203  func (ec *Client) SubscribePendingTransactions(ctx context.Context, ch chan<- common.Hash) (*rpc.ClientSubscription, error) {
   204  	return ec.c.EthSubscribe(ctx, ch, "newPendingTransactions")
   205  }
   206  
   207  func toBlockNumArg(number *big.Int) string {
   208  	if number == nil {
   209  		return "latest"
   210  	}
   211  	if number.Sign() >= 0 {
   212  		return hexutil.EncodeBig(number)
   213  	}
   214  	// It's negative.
   215  	if number.IsInt64() {
   216  		return rpc.BlockNumber(number.Int64()).String()
   217  	}
   218  	// It's negative and large, which is invalid.
   219  	return fmt.Sprintf("<invalid %d>", number)
   220  }
   221  
   222  func toCallArg(msg zond.CallMsg) interface{} {
   223  	arg := map[string]interface{}{
   224  		"from": msg.From,
   225  		"to":   msg.To,
   226  	}
   227  	if len(msg.Data) > 0 {
   228  		arg["input"] = hexutil.Bytes(msg.Data)
   229  	}
   230  	if msg.Value != nil {
   231  		arg["value"] = (*hexutil.Big)(msg.Value)
   232  	}
   233  	if msg.Gas != 0 {
   234  		arg["gas"] = hexutil.Uint64(msg.Gas)
   235  	}
   236  	if msg.GasPrice != nil {
   237  		arg["gasPrice"] = (*hexutil.Big)(msg.GasPrice)
   238  	}
   239  	return arg
   240  }
   241  
   242  // OverrideAccount specifies the state of an account to be overridden.
   243  type OverrideAccount struct {
   244  	// Nonce sets nonce of the account. Note: the nonce override will only
   245  	// be applied when it is set to a non-zero value.
   246  	Nonce uint64
   247  
   248  	// Code sets the contract code. The override will be applied
   249  	// when the code is non-nil, i.e. setting empty code is possible
   250  	// using an empty slice.
   251  	Code []byte
   252  
   253  	// Balance sets the account balance.
   254  	Balance *big.Int
   255  
   256  	// State sets the complete storage. The override will be applied
   257  	// when the given map is non-nil. Using an empty map wipes the
   258  	// entire contract storage during the call.
   259  	State map[common.Hash]common.Hash
   260  
   261  	// StateDiff allows overriding individual storage slots.
   262  	StateDiff map[common.Hash]common.Hash
   263  }
   264  
   265  func (a OverrideAccount) MarshalJSON() ([]byte, error) {
   266  	type acc struct {
   267  		Nonce     hexutil.Uint64              `json:"nonce,omitempty"`
   268  		Code      string                      `json:"code,omitempty"`
   269  		Balance   *hexutil.Big                `json:"balance,omitempty"`
   270  		State     interface{}                 `json:"state,omitempty"`
   271  		StateDiff map[common.Hash]common.Hash `json:"stateDiff,omitempty"`
   272  	}
   273  
   274  	output := acc{
   275  		Nonce:     hexutil.Uint64(a.Nonce),
   276  		Balance:   (*hexutil.Big)(a.Balance),
   277  		StateDiff: a.StateDiff,
   278  	}
   279  	if a.Code != nil {
   280  		output.Code = hexutil.Encode(a.Code)
   281  	}
   282  	if a.State != nil {
   283  		output.State = a.State
   284  	}
   285  	return json.Marshal(output)
   286  }
   287  
   288  // BlockOverrides specifies the  set of header fields to override.
   289  type BlockOverrides struct {
   290  	// Number overrides the block number.
   291  	Number *big.Int
   292  	// Difficulty overrides the block difficulty.
   293  	Difficulty *big.Int
   294  	// Time overrides the block timestamp. Time is applied only when
   295  	// it is non-zero.
   296  	Time uint64
   297  	// GasLimit overrides the block gas limit. GasLimit is applied only when
   298  	// it is non-zero.
   299  	GasLimit uint64
   300  	// Coinbase overrides the block coinbase. Coinbase is applied only when
   301  	// it is different from the zero address.
   302  	Coinbase common.Address
   303  	// Random overrides the block extra data which feeds into the RANDOM opcode.
   304  	// Random is applied only when it is a non-zero hash.
   305  	Random common.Hash
   306  	// BaseFee overrides the block base fee.
   307  	BaseFee *big.Int
   308  }
   309  
   310  func (o BlockOverrides) MarshalJSON() ([]byte, error) {
   311  	type override struct {
   312  		Number     *hexutil.Big    `json:"number,omitempty"`
   313  		Difficulty *hexutil.Big    `json:"difficulty,omitempty"`
   314  		Time       hexutil.Uint64  `json:"time,omitempty"`
   315  		GasLimit   hexutil.Uint64  `json:"gasLimit,omitempty"`
   316  		Coinbase   *common.Address `json:"coinbase,omitempty"`
   317  		Random     *common.Hash    `json:"random,omitempty"`
   318  		BaseFee    *hexutil.Big    `json:"baseFee,omitempty"`
   319  	}
   320  
   321  	output := override{
   322  		Number:     (*hexutil.Big)(o.Number),
   323  		Difficulty: (*hexutil.Big)(o.Difficulty),
   324  		Time:       hexutil.Uint64(o.Time),
   325  		GasLimit:   hexutil.Uint64(o.GasLimit),
   326  		BaseFee:    (*hexutil.Big)(o.BaseFee),
   327  	}
   328  	if o.Coinbase != (common.Address{}) {
   329  		output.Coinbase = &o.Coinbase
   330  	}
   331  	if o.Random != (common.Hash{}) {
   332  		output.Random = &o.Random
   333  	}
   334  	return json.Marshal(output)
   335  }