github.com/neatio-net/neatio@v1.7.3-0.20231114194659-f4d7a2226baa/neatcli/neatcli.go (about)

     1  package neatcli
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"errors"
     7  	"fmt"
     8  	"math/big"
     9  
    10  	"github.com/neatio-net/neatio"
    11  	"github.com/neatio-net/neatio/chain/core/types"
    12  	"github.com/neatio-net/neatio/network/rpc"
    13  	"github.com/neatio-net/neatio/utilities/common"
    14  	"github.com/neatio-net/neatio/utilities/common/hexutil"
    15  	"github.com/neatio-net/neatio/utilities/rlp"
    16  )
    17  
    18  type Client struct {
    19  	c *rpc.Client
    20  }
    21  
    22  func Dial(rawurl string) (*Client, error) {
    23  	c, err := rpc.Dial(rawurl)
    24  	if err != nil {
    25  		return nil, err
    26  	}
    27  	return NewClient(c), nil
    28  }
    29  
    30  func NewClient(c *rpc.Client) *Client {
    31  	return &Client{c}
    32  }
    33  
    34  func (ec *Client) BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) {
    35  	return ec.getBlock(ctx, "eth_getBlockByHash", hash, true)
    36  }
    37  
    38  func (ec *Client) BlockByNumber(ctx context.Context, number *big.Int) (*types.Block, error) {
    39  	return ec.getBlock(ctx, "eth_getBlockByNumber", toBlockNumArg(number), true)
    40  }
    41  
    42  type rpcBlock struct {
    43  	Hash         common.Hash      `json:"hash"`
    44  	Transactions []rpcTransaction `json:"transactions"`
    45  	UncleHashes  []common.Hash    `json:"uncles"`
    46  }
    47  
    48  func (ec *Client) getBlock(ctx context.Context, method string, args ...interface{}) (*types.Block, error) {
    49  	var raw json.RawMessage
    50  	err := ec.c.CallContext(ctx, &raw, method, args...)
    51  	if err != nil {
    52  		return nil, err
    53  	} else if len(raw) == 0 {
    54  		return nil, neatio.NotFound
    55  	}
    56  
    57  	var head *types.Header
    58  	var body rpcBlock
    59  	if err := json.Unmarshal(raw, &head); err != nil {
    60  		return nil, err
    61  	}
    62  	if err := json.Unmarshal(raw, &body); err != nil {
    63  		return nil, err
    64  	}
    65  
    66  	if head.UncleHash == types.EmptyUncleHash && len(body.UncleHashes) > 0 {
    67  		return nil, fmt.Errorf("server returned non-empty uncle list but block header indicates no uncles")
    68  	}
    69  	if head.UncleHash != types.EmptyUncleHash && len(body.UncleHashes) == 0 {
    70  		return nil, fmt.Errorf("server returned empty uncle list but block header indicates uncles")
    71  	}
    72  	if head.TxHash == types.EmptyRootHash && len(body.Transactions) > 0 {
    73  		return nil, fmt.Errorf("server returned non-empty transaction list but block header indicates no transactions")
    74  	}
    75  	if head.TxHash != types.EmptyRootHash && len(body.Transactions) == 0 {
    76  		return nil, fmt.Errorf("server returned empty transaction list but block header indicates transactions")
    77  	}
    78  
    79  	var uncles []*types.Header
    80  	if len(body.UncleHashes) > 0 {
    81  		uncles = make([]*types.Header, len(body.UncleHashes))
    82  		reqs := make([]rpc.BatchElem, len(body.UncleHashes))
    83  		for i := range reqs {
    84  			reqs[i] = rpc.BatchElem{
    85  				Method: "eth_getUncleByBlockHashAndIndex",
    86  				Args:   []interface{}{body.Hash, hexutil.EncodeUint64(uint64(i))},
    87  				Result: &uncles[i],
    88  			}
    89  		}
    90  		if err := ec.c.BatchCallContext(ctx, reqs); err != nil {
    91  			return nil, err
    92  		}
    93  		for i := range reqs {
    94  			if reqs[i].Error != nil {
    95  				return nil, reqs[i].Error
    96  			}
    97  			if uncles[i] == nil {
    98  				return nil, fmt.Errorf("got null header for uncle %d of block %x", i, body.Hash[:])
    99  			}
   100  		}
   101  	}
   102  
   103  	txs := make([]*types.Transaction, len(body.Transactions))
   104  	for i, tx := range body.Transactions {
   105  		setSenderFromServer(tx.tx, tx.From, body.Hash)
   106  		txs[i] = tx.tx
   107  	}
   108  	return types.NewBlockWithHeader(head).WithBody(txs, uncles), nil
   109  }
   110  
   111  func (ec *Client) HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error) {
   112  	var head *types.Header
   113  	err := ec.c.CallContext(ctx, &head, "eth_getBlockByHash", hash, false)
   114  	if err == nil && head == nil {
   115  		err = neatio.NotFound
   116  	}
   117  	return head, err
   118  }
   119  
   120  func (ec *Client) HeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error) {
   121  	var head *types.Header
   122  	err := ec.c.CallContext(ctx, &head, "eth_getBlockByNumber", toBlockNumArg(number), false)
   123  	if err == nil && head == nil {
   124  		err = neatio.NotFound
   125  	}
   126  	return head, err
   127  }
   128  
   129  type rpcTransaction struct {
   130  	tx *types.Transaction
   131  	txExtraInfo
   132  }
   133  
   134  type txExtraInfo struct {
   135  	BlockNumber *string
   136  	BlockHash   common.Hash
   137  	From        common.Address
   138  }
   139  
   140  func (tx *rpcTransaction) UnmarshalJSON(msg []byte) error {
   141  	if err := json.Unmarshal(msg, &tx.tx); err != nil {
   142  		return err
   143  	}
   144  	return json.Unmarshal(msg, &tx.txExtraInfo)
   145  }
   146  
   147  func (ec *Client) TransactionByHash(ctx context.Context, hash common.Hash) (tx *types.Transaction, isPending bool, err error) {
   148  	var json *rpcTransaction
   149  	err = ec.c.CallContext(ctx, &json, "eth_getTransactionByHash", hash)
   150  	if err != nil {
   151  		return nil, false, err
   152  	} else if json == nil {
   153  		return nil, false, neatio.NotFound
   154  	} else if _, r, _ := json.tx.RawSignatureValues(); r == nil {
   155  		return nil, false, fmt.Errorf("server returned transaction without signature")
   156  	}
   157  	setSenderFromServer(json.tx, json.From, json.BlockHash)
   158  	return json.tx, json.BlockNumber == nil, nil
   159  }
   160  
   161  func (ec *Client) TransactionSender(ctx context.Context, tx *types.Transaction, block common.Hash, index uint) (common.Address, error) {
   162  
   163  	sender, err := types.Sender(&senderFromServer{blockhash: block}, tx)
   164  	if err == nil {
   165  		return sender, nil
   166  	}
   167  	var meta struct {
   168  		Hash common.Hash
   169  		From common.Address
   170  	}
   171  	if err = ec.c.CallContext(ctx, &meta, "eth_getTransactionByBlockHashAndIndex", block, hexutil.Uint64(index)); err != nil {
   172  		return common.Address{}, err
   173  	}
   174  	if meta.Hash == (common.Hash{}) || meta.Hash != tx.Hash() {
   175  		return common.Address{}, errors.New("wrong inclusion block/index")
   176  	}
   177  	return meta.From, nil
   178  }
   179  
   180  func (ec *Client) TransactionCount(ctx context.Context, blockHash common.Hash) (uint, error) {
   181  	var num hexutil.Uint
   182  	err := ec.c.CallContext(ctx, &num, "eth_getBlockTransactionCountByHash", blockHash)
   183  	return uint(num), err
   184  }
   185  
   186  func (ec *Client) TransactionInBlock(ctx context.Context, blockHash common.Hash, index uint) (*types.Transaction, error) {
   187  	var json *rpcTransaction
   188  	err := ec.c.CallContext(ctx, &json, "eth_getTransactionByBlockHashAndIndex", blockHash, hexutil.Uint64(index))
   189  	if err == nil {
   190  		if json == nil {
   191  			return nil, neatio.NotFound
   192  		} else if _, r, _ := json.tx.RawSignatureValues(); r == nil {
   193  			return nil, fmt.Errorf("server returned transaction without signature")
   194  		}
   195  	}
   196  	setSenderFromServer(json.tx, json.From, json.BlockHash)
   197  	return json.tx, err
   198  }
   199  
   200  func (ec *Client) TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) {
   201  	var r *types.Receipt
   202  	err := ec.c.CallContext(ctx, &r, "eth_getTransactionReceipt", txHash)
   203  	if err == nil {
   204  		if r == nil {
   205  			return nil, neatio.NotFound
   206  		}
   207  	}
   208  	return r, err
   209  }
   210  
   211  func toBlockNumArg(number *big.Int) string {
   212  	if number == nil {
   213  		return "latest"
   214  	}
   215  	return hexutil.EncodeBig(number)
   216  }
   217  
   218  type rpcProgress struct {
   219  	StartingBlock hexutil.Uint64
   220  	CurrentBlock  hexutil.Uint64
   221  	HighestBlock  hexutil.Uint64
   222  	PulledStates  hexutil.Uint64
   223  	KnownStates   hexutil.Uint64
   224  }
   225  
   226  func (ec *Client) SyncProgress(ctx context.Context) (*neatio.SyncProgress, error) {
   227  	var raw json.RawMessage
   228  	if err := ec.c.CallContext(ctx, &raw, "eth_syncing"); err != nil {
   229  		return nil, err
   230  	}
   231  
   232  	var syncing bool
   233  	if err := json.Unmarshal(raw, &syncing); err == nil {
   234  		return nil, nil
   235  	}
   236  	var progress *rpcProgress
   237  	if err := json.Unmarshal(raw, &progress); err != nil {
   238  		return nil, err
   239  	}
   240  	return &neatio.SyncProgress{
   241  		StartingBlock: uint64(progress.StartingBlock),
   242  		CurrentBlock:  uint64(progress.CurrentBlock),
   243  		HighestBlock:  uint64(progress.HighestBlock),
   244  		PulledStates:  uint64(progress.PulledStates),
   245  		KnownStates:   uint64(progress.KnownStates),
   246  	}, nil
   247  }
   248  
   249  func (ec *Client) SubscribeNewHead(ctx context.Context, ch chan<- *types.Header) (neatio.Subscription, error) {
   250  	return ec.c.EthSubscribe(ctx, ch, "newHeads", map[string]struct{}{})
   251  }
   252  
   253  func (ec *Client) NetworkID(ctx context.Context) (*big.Int, error) {
   254  	version := new(big.Int)
   255  	var ver string
   256  	if err := ec.c.CallContext(ctx, &ver, "net_version"); err != nil {
   257  		return nil, err
   258  	}
   259  	if _, ok := version.SetString(ver, 10); !ok {
   260  		return nil, fmt.Errorf("invalid net_version result %q", ver)
   261  	}
   262  	return version, nil
   263  }
   264  
   265  func (ec *Client) BalanceAt(ctx context.Context, account common.Address, blockNumber *big.Int) (*big.Int, error) {
   266  	var result hexutil.Big
   267  	err := ec.c.CallContext(ctx, &result, "eth_getBalance", account, toBlockNumArg(blockNumber))
   268  	return (*big.Int)(&result), err
   269  }
   270  
   271  func (ec *Client) StorageAt(ctx context.Context, account common.Address, key common.Hash, blockNumber *big.Int) ([]byte, error) {
   272  	var result hexutil.Bytes
   273  	err := ec.c.CallContext(ctx, &result, "eth_getStorageAt", account, key, toBlockNumArg(blockNumber))
   274  	return result, err
   275  }
   276  
   277  func (ec *Client) CodeAt(ctx context.Context, account common.Address, blockNumber *big.Int) ([]byte, error) {
   278  	var result hexutil.Bytes
   279  	err := ec.c.CallContext(ctx, &result, "eth_getCode", account, toBlockNumArg(blockNumber))
   280  	return result, err
   281  }
   282  
   283  func (ec *Client) NonceAt(ctx context.Context, account common.Address, blockNumber *big.Int) (uint64, error) {
   284  	var result hexutil.Uint64
   285  	err := ec.c.CallContext(ctx, &result, "eth_getTransactionCount", account, toBlockNumArg(blockNumber))
   286  	return uint64(result), err
   287  }
   288  
   289  func (ec *Client) FilterLogs(ctx context.Context, q neatio.FilterQuery) ([]types.Log, error) {
   290  	var result []types.Log
   291  	err := ec.c.CallContext(ctx, &result, "eth_getLogs", toFilterArg(q))
   292  	return result, err
   293  }
   294  
   295  func (ec *Client) SubscribeFilterLogs(ctx context.Context, q neatio.FilterQuery, ch chan<- types.Log) (neatio.Subscription, error) {
   296  	return ec.c.EthSubscribe(ctx, ch, "logs", toFilterArg(q))
   297  }
   298  
   299  func toFilterArg(q neatio.FilterQuery) interface{} {
   300  	arg := map[string]interface{}{
   301  		"fromBlock": toBlockNumArg(q.FromBlock),
   302  		"toBlock":   toBlockNumArg(q.ToBlock),
   303  		"address":   q.Addresses,
   304  		"topics":    q.Topics,
   305  	}
   306  	if q.FromBlock == nil {
   307  		arg["fromBlock"] = "0x0"
   308  	}
   309  	return arg
   310  }
   311  
   312  func (ec *Client) PendingBalanceAt(ctx context.Context, account common.Address) (*big.Int, error) {
   313  	var result hexutil.Big
   314  	err := ec.c.CallContext(ctx, &result, "eth_getBalance", account, "pending")
   315  	return (*big.Int)(&result), err
   316  }
   317  
   318  func (ec *Client) PendingStorageAt(ctx context.Context, account common.Address, key common.Hash) ([]byte, error) {
   319  	var result hexutil.Bytes
   320  	err := ec.c.CallContext(ctx, &result, "eth_getStorageAt", account, key, "pending")
   321  	return result, err
   322  }
   323  
   324  func (ec *Client) PendingCodeAt(ctx context.Context, account common.Address) ([]byte, error) {
   325  	var result hexutil.Bytes
   326  	err := ec.c.CallContext(ctx, &result, "eth_getCode", account, "pending")
   327  	return result, err
   328  }
   329  
   330  func (ec *Client) PendingNonceAt(ctx context.Context, account common.Address) (uint64, error) {
   331  	var result hexutil.Uint64
   332  	err := ec.c.CallContext(ctx, &result, "eth_getTransactionCount", account, "pending")
   333  	return uint64(result), err
   334  }
   335  
   336  func (ec *Client) PendingTransactionCount(ctx context.Context) (uint, error) {
   337  	var num hexutil.Uint
   338  	err := ec.c.CallContext(ctx, &num, "eth_getBlockTransactionCountByNumber", "pending")
   339  	return uint(num), err
   340  }
   341  
   342  func (ec *Client) CallContract(ctx context.Context, msg neatio.CallMsg, blockNumber *big.Int) ([]byte, error) {
   343  	var hex hexutil.Bytes
   344  	err := ec.c.CallContext(ctx, &hex, "eth_call", toCallArg(msg), toBlockNumArg(blockNumber))
   345  	if err != nil {
   346  		return nil, err
   347  	}
   348  	return hex, nil
   349  }
   350  
   351  func (ec *Client) PendingCallContract(ctx context.Context, msg neatio.CallMsg) ([]byte, error) {
   352  	var hex hexutil.Bytes
   353  	err := ec.c.CallContext(ctx, &hex, "eth_call", toCallArg(msg), "pending")
   354  	if err != nil {
   355  		return nil, err
   356  	}
   357  	return hex, nil
   358  }
   359  
   360  func (ec *Client) SuggestGasPrice(ctx context.Context) (*big.Int, error) {
   361  	var hex hexutil.Big
   362  	if err := ec.c.CallContext(ctx, &hex, "eth_gasPrice"); err != nil {
   363  		return nil, err
   364  	}
   365  	return (*big.Int)(&hex), nil
   366  }
   367  
   368  func (ec *Client) EstimateGas(ctx context.Context, msg neatio.CallMsg) (uint64, error) {
   369  	var hex hexutil.Uint64
   370  	err := ec.c.CallContext(ctx, &hex, "eth_estimateGas", toCallArg(msg))
   371  	if err != nil {
   372  		return 0, err
   373  	}
   374  	return uint64(hex), nil
   375  }
   376  
   377  func (ec *Client) SendTransaction(ctx context.Context, tx *types.Transaction) error {
   378  	fmt.Printf("transaction args Client tx %v\n", tx)
   379  	data, err := rlp.EncodeToBytes(tx)
   380  	if err != nil {
   381  		return err
   382  	}
   383  	return ec.c.CallContext(ctx, nil, "eth_sendRawTransaction", common.ToHex(data))
   384  }
   385  
   386  func toCallArg(msg neatio.CallMsg) interface{} {
   387  	arg := map[string]interface{}{
   388  		"from": msg.From,
   389  		"to":   msg.To,
   390  	}
   391  	if len(msg.Data) > 0 {
   392  		arg["data"] = hexutil.Bytes(msg.Data)
   393  	}
   394  	if msg.Value != nil {
   395  		arg["value"] = (*hexutil.Big)(msg.Value)
   396  	}
   397  	if msg.Gas != 0 {
   398  		arg["gas"] = hexutil.Uint64(msg.Gas)
   399  	}
   400  	if msg.GasPrice != nil {
   401  		arg["gasPrice"] = (*hexutil.Big)(msg.GasPrice)
   402  	}
   403  	return arg
   404  }