github.com/ethereumproject/go-ethereum@v5.5.2+incompatible/accounts/abi/bind/backends/remote.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 backends
    18  
    19  import (
    20  	"encoding/json"
    21  	"fmt"
    22  	"math/big"
    23  	"sync"
    24  	"sync/atomic"
    25  
    26  	"github.com/ethereumproject/go-ethereum/accounts/abi/bind"
    27  	"github.com/ethereumproject/go-ethereum/common"
    28  	"github.com/ethereumproject/go-ethereum/core/types"
    29  	"github.com/ethereumproject/go-ethereum/rlp"
    30  	"github.com/ethereumproject/go-ethereum/rpc"
    31  )
    32  
    33  // This nil assignment ensures compile time that rpcBackend implements bind.ContractBackend.
    34  var _ bind.ContractBackend = (*rpcBackend)(nil)
    35  
    36  // rpcBackend implements bind.ContractBackend, and acts as the data provider to
    37  // Ethereum contracts bound to Go structs. It uses an RPC connection to delegate
    38  // all its functionality.
    39  //
    40  // Note: The current implementation is a blocking one. This should be replaced
    41  // by a proper async version when a real RPC client is created.
    42  type rpcBackend struct {
    43  	client rpc.Client // RPC client connection to interact with an API server
    44  	autoid uint32     // ID number to use for the next API request
    45  	lock   sync.Mutex // Singleton access until we get to request multiplexing
    46  }
    47  
    48  // NewRPCBackend creates a new binding backend to an RPC provider that can be
    49  // used to interact with remote contracts.
    50  func NewRPCBackend(client rpc.Client) bind.ContractBackend {
    51  	return &rpcBackend{
    52  		client: client,
    53  	}
    54  }
    55  
    56  // request is a JSON RPC request package assembled internally from the client
    57  // method calls.
    58  type request struct {
    59  	JSONRPC string        `json:"jsonrpc"` // Version of the JSON RPC protocol, always set to 2.0
    60  	ID      int           `json:"id"`      // Auto incrementing ID number for this request
    61  	Method  string        `json:"method"`  // Remote procedure name to invoke on the server
    62  	Params  []interface{} `json:"params"`  // List of parameters to pass through (keep types simple)
    63  }
    64  
    65  // response is a JSON RPC response package sent back from the API server.
    66  type response struct {
    67  	JSONRPC string          `json:"jsonrpc"` // Version of the JSON RPC protocol, always set to 2.0
    68  	ID      int             `json:"id"`      // Auto incrementing ID number for this request
    69  	Error   *failure        `json:"error"`   // Any error returned by the remote side
    70  	Result  json.RawMessage `json:"result"`  // Whatever the remote side sends us in reply
    71  }
    72  
    73  // failure is a JSON RPC response error field sent back from the API server.
    74  type failure struct {
    75  	Code    int    `json:"code"`    // JSON RPC error code associated with the failure
    76  	Message string `json:"message"` // Specific error message of the failure
    77  }
    78  
    79  // request forwards an API request to the RPC server, and parses the response.
    80  //
    81  // This is currently painfully non-concurrent, but it will have to do until we
    82  // find the time for niceties like this :P
    83  func (b *rpcBackend) request(method string, params []interface{}) (json.RawMessage, error) {
    84  	b.lock.Lock()
    85  	defer b.lock.Unlock()
    86  
    87  	// Ugly hack to serialize an empty list properly
    88  	if params == nil {
    89  		params = []interface{}{}
    90  	}
    91  	// Assemble the request object
    92  	req := &request{
    93  		JSONRPC: "2.0",
    94  		ID:      int(atomic.AddUint32(&b.autoid, 1)),
    95  		Method:  method,
    96  		Params:  params,
    97  	}
    98  	if err := b.client.Send(req); err != nil {
    99  		return nil, err
   100  	}
   101  	res := new(response)
   102  	if err := b.client.Recv(res); err != nil {
   103  		return nil, err
   104  	}
   105  	if res.Error != nil {
   106  		if res.Error.Message == bind.ErrNoCode.Error() {
   107  			return nil, bind.ErrNoCode
   108  		}
   109  		return nil, fmt.Errorf("remote error: %s", res.Error.Message)
   110  	}
   111  	return res.Result, nil
   112  }
   113  
   114  // HasCode implements ContractVerifier.HasCode by retrieving any code associated
   115  // with the contract from the remote node, and checking its size.
   116  func (b *rpcBackend) HasCode(contract common.Address, pending bool) (bool, error) {
   117  	// Execute the RPC code retrieval
   118  	block := "latest"
   119  	if pending {
   120  		block = "pending"
   121  	}
   122  	res, err := b.request("eth_getCode", []interface{}{contract.Hex(), block})
   123  	if err != nil {
   124  		return false, err
   125  	}
   126  	var hex string
   127  	if err := json.Unmarshal(res, &hex); err != nil {
   128  		return false, err
   129  	}
   130  	// Convert the response back to a Go byte slice and return
   131  	return len(common.FromHex(hex)) > 0, nil
   132  }
   133  
   134  // ContractCall implements ContractCaller.ContractCall, delegating the execution of
   135  // a contract call to the remote node, returning the reply to for local processing.
   136  func (b *rpcBackend) ContractCall(contract common.Address, data []byte, pending bool) ([]byte, error) {
   137  	// Pack up the request into an RPC argument
   138  	args := struct {
   139  		To   common.Address `json:"to"`
   140  		Data string         `json:"data"`
   141  	}{
   142  		To:   contract,
   143  		Data: common.ToHex(data),
   144  	}
   145  	// Execute the RPC call and retrieve the response
   146  	block := "latest"
   147  	if pending {
   148  		block = "pending"
   149  	}
   150  	res, err := b.request("eth_call", []interface{}{args, block})
   151  	if err != nil {
   152  		return nil, err
   153  	}
   154  	var hex string
   155  	if err := json.Unmarshal(res, &hex); err != nil {
   156  		return nil, err
   157  	}
   158  	// Convert the response back to a Go byte slice and return
   159  	return common.FromHex(hex), nil
   160  }
   161  
   162  // PendingAccountNonce implements ContractTransactor.PendingAccountNonce, delegating
   163  // the current account nonce retrieval to the remote node.
   164  func (b *rpcBackend) PendingAccountNonce(account common.Address) (uint64, error) {
   165  	res, err := b.request("eth_getTransactionCount", []interface{}{account.Hex(), "pending"})
   166  	if err != nil {
   167  		return 0, err
   168  	}
   169  	var hex string
   170  	if err := json.Unmarshal(res, &hex); err != nil {
   171  		return 0, err
   172  	}
   173  	nonce, ok := new(big.Int).SetString(hex, 0)
   174  	if !ok {
   175  		return 0, fmt.Errorf("invalid nonce hex: %s", hex)
   176  	}
   177  	return nonce.Uint64(), nil
   178  }
   179  
   180  // SuggestGasPrice implements ContractTransactor.SuggestGasPrice, delegating the
   181  // gas price oracle request to the remote node.
   182  func (b *rpcBackend) SuggestGasPrice() (*big.Int, error) {
   183  	res, err := b.request("eth_gasPrice", nil)
   184  	if err != nil {
   185  		return nil, err
   186  	}
   187  	var hex string
   188  	if err := json.Unmarshal(res, &hex); err != nil {
   189  		return nil, err
   190  	}
   191  	price, ok := new(big.Int).SetString(hex, 0)
   192  	if !ok {
   193  		return nil, fmt.Errorf("invalid price hex: %s", hex)
   194  	}
   195  	return price, nil
   196  }
   197  
   198  // EstimateGasLimit implements ContractTransactor.EstimateGasLimit, delegating
   199  // the gas estimation to the remote node.
   200  func (b *rpcBackend) EstimateGasLimit(sender common.Address, contract *common.Address, value *big.Int, data []byte) (*big.Int, error) {
   201  	// Pack up the request into an RPC argument
   202  	args := struct {
   203  		From  common.Address  `json:"from"`
   204  		To    *common.Address `json:"to"`
   205  		Value *rpc.HexNumber  `json:"value"`
   206  		Data  string          `json:"data"`
   207  	}{
   208  		From:  sender,
   209  		To:    contract,
   210  		Data:  common.ToHex(data),
   211  		Value: rpc.NewHexNumber(value),
   212  	}
   213  	// Execute the RPC call and retrieve the response
   214  	res, err := b.request("eth_estimateGas", []interface{}{args})
   215  	if err != nil {
   216  		return nil, err
   217  	}
   218  	var hex string
   219  	if err := json.Unmarshal(res, &hex); err != nil {
   220  		return nil, err
   221  	}
   222  	estimate, ok := new(big.Int).SetString(hex, 0)
   223  	if !ok {
   224  		return nil, fmt.Errorf("invalid estimate hex: %s", hex)
   225  	}
   226  	return estimate, nil
   227  }
   228  
   229  // SendTransaction implements ContractTransactor.SendTransaction, delegating the
   230  // raw transaction injection to the remote node.
   231  func (b *rpcBackend) SendTransaction(tx *types.Transaction) error {
   232  	data, err := rlp.EncodeToBytes(tx)
   233  	if err != nil {
   234  		return err
   235  	}
   236  	res, err := b.request("eth_sendRawTransaction", []interface{}{common.ToHex(data)})
   237  	if err != nil {
   238  		return err
   239  	}
   240  	var hex string
   241  	if err := json.Unmarshal(res, &hex); err != nil {
   242  		return err
   243  	}
   244  	return nil
   245  }