github.com/n1ghtfa1l/go-vnt@v0.6.4-alpha.6/vntclient/vntclient.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 vntclient provides a client for the VNT RPC API.
    18  package vntclient
    19  
    20  import (
    21  	"context"
    22  	"encoding/json"
    23  	"errors"
    24  	"fmt"
    25  	"math/big"
    26  	"strings"
    27  
    28  	hubble "github.com/vntchain/go-vnt"
    29  	"github.com/vntchain/go-vnt/accounts/abi"
    30  	"github.com/vntchain/go-vnt/common"
    31  	"github.com/vntchain/go-vnt/common/hexutil"
    32  	"github.com/vntchain/go-vnt/core/types"
    33  	"github.com/vntchain/go-vnt/core/vm/election"
    34  	"github.com/vntchain/go-vnt/rlp"
    35  	"github.com/vntchain/go-vnt/rpc"
    36  )
    37  
    38  // Client defines typed wrappers for the VNT RPC API.
    39  type Client struct {
    40  	c *rpc.Client
    41  }
    42  
    43  // Dial connects a client to the given URL.
    44  func Dial(rawurl string) (*Client, error) {
    45  	return DialContext(context.Background(), rawurl)
    46  }
    47  
    48  func DialContext(ctx context.Context, rawurl string) (*Client, error) {
    49  	c, err := rpc.DialContext(ctx, rawurl)
    50  	if err != nil {
    51  		return nil, err
    52  	}
    53  	return NewClient(c), nil
    54  }
    55  
    56  // NewClient creates a client that uses the given RPC client.
    57  func NewClient(c *rpc.Client) *Client {
    58  	return &Client{c}
    59  }
    60  
    61  func (ec *Client) Close() {
    62  	ec.c.Close()
    63  }
    64  
    65  // Blockchain Access
    66  
    67  // BlockByHash returns the given full block.
    68  //
    69  // Note that loading full blocks requires two requests. Use HeaderByHash
    70  // if you don't need all transactions.
    71  func (ec *Client) BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) {
    72  	return ec.getBlock(ctx, "core_getBlockByHash", hash, true)
    73  }
    74  
    75  // BlockByNumber returns a block from the current canonical chain. If number is nil, the
    76  // latest known block is returned.
    77  //
    78  // Note that loading full blocks requires two requests. Use HeaderByNumber
    79  // if you don't need all transactions.
    80  func (ec *Client) BlockByNumber(ctx context.Context, number *big.Int) (*types.Block, error) {
    81  	return ec.getBlock(ctx, "core_getBlockByNumber", toBlockNumArg(number), true)
    82  }
    83  
    84  type rpcBlock struct {
    85  	Hash         common.Hash      `json:"hash"`
    86  	Transactions []rpcTransaction `json:"transactions"`
    87  }
    88  
    89  func (ec *Client) getBlock(ctx context.Context, method string, args ...interface{}) (*types.Block, error) {
    90  	var raw json.RawMessage
    91  	err := ec.c.CallContext(ctx, &raw, method, args...)
    92  	if err != nil {
    93  		return nil, err
    94  	} else if len(raw) == 0 {
    95  		return nil, hubble.NotFound
    96  	}
    97  	// Decode header and transactions.
    98  	var head *types.Header
    99  	var body rpcBlock
   100  	if err := json.Unmarshal(raw, &head); err != nil {
   101  		return nil, err
   102  	}
   103  	if err := json.Unmarshal(raw, &body); err != nil {
   104  		return nil, err
   105  	}
   106  	// Quick-verify transaction lists. This mostly helps with debugging the server.
   107  	if head.TxHash == types.EmptyRootHash && len(body.Transactions) > 0 {
   108  		return nil, fmt.Errorf("server returned non-empty transaction list but block header indicates no transactions")
   109  	}
   110  	if head.TxHash != types.EmptyRootHash && len(body.Transactions) == 0 {
   111  		return nil, fmt.Errorf("server returned empty transaction list but block header indicates transactions")
   112  	}
   113  	// Fill the sender cache of transactions in the block.
   114  	txs := make([]*types.Transaction, len(body.Transactions))
   115  	for i, tx := range body.Transactions {
   116  		if tx.From != nil {
   117  			setSenderFromServer(tx.tx, *tx.From, body.Hash)
   118  		}
   119  		txs[i] = tx.tx
   120  	}
   121  	return types.NewBlockWithHeader(head).WithBody(txs), nil
   122  }
   123  
   124  // HeaderByHash returns the block header with the given hash.
   125  func (ec *Client) HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error) {
   126  	var head *types.Header
   127  	err := ec.c.CallContext(ctx, &head, "core_getBlockByHash", hash, false)
   128  	if err == nil && head == nil {
   129  		err = hubble.NotFound
   130  	}
   131  	return head, err
   132  }
   133  
   134  // HeaderByNumber returns a block header from the current canonical chain. If number is
   135  // nil, the latest known header is returned.
   136  func (ec *Client) HeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error) {
   137  	var head *types.Header
   138  	err := ec.c.CallContext(ctx, &head, "core_getBlockByNumber", toBlockNumArg(number), false)
   139  	if err == nil && head == nil {
   140  		err = hubble.NotFound
   141  	}
   142  	return head, err
   143  }
   144  
   145  type rpcTransaction struct {
   146  	tx *types.Transaction
   147  	txExtraInfo
   148  }
   149  
   150  type txExtraInfo struct {
   151  	BlockNumber *string         `json:"blockNumber,omitempty"`
   152  	BlockHash   *common.Hash    `json:"blockHash,omitempty"`
   153  	From        *common.Address `json:"from,omitempty"`
   154  }
   155  
   156  func (tx *rpcTransaction) UnmarshalJSON(msg []byte) error {
   157  	if err := json.Unmarshal(msg, &tx.tx); err != nil {
   158  		return err
   159  	}
   160  	return json.Unmarshal(msg, &tx.txExtraInfo)
   161  }
   162  
   163  // TransactionByHash returns the transaction with the given hash.
   164  func (ec *Client) TransactionByHash(ctx context.Context, hash common.Hash) (tx *types.Transaction, isPending bool, err error) {
   165  	var json *rpcTransaction
   166  	err = ec.c.CallContext(ctx, &json, "core_getTransactionByHash", hash)
   167  	if err != nil {
   168  		return nil, false, err
   169  	} else if json == nil {
   170  		return nil, false, hubble.NotFound
   171  	} else if _, r, _ := json.tx.RawSignatureValues(); r == nil {
   172  		return nil, false, fmt.Errorf("server returned transaction without signature")
   173  	}
   174  	if json.From != nil && json.BlockHash != nil {
   175  		setSenderFromServer(json.tx, *json.From, *json.BlockHash)
   176  	}
   177  	return json.tx, json.BlockNumber == nil, nil
   178  }
   179  
   180  // TransactionSender returns the sender address of the given transaction. The transaction
   181  // must be known to the remote node and included in the blockchain at the given block and
   182  // index. The sender is the one derived by the protocol at the time of inclusion.
   183  //
   184  // There is a fast-path for transactions retrieved by TransactionByHash and
   185  // TransactionInBlock. Getting their sender address can be done without an RPC interaction.
   186  func (ec *Client) TransactionSender(ctx context.Context, tx *types.Transaction, block common.Hash, index uint) (common.Address, error) {
   187  	// Try to load the address from the cache.
   188  	sender, err := types.Sender(&senderFromServer{blockhash: block}, tx)
   189  	if err == nil {
   190  		return sender, nil
   191  	}
   192  	var meta struct {
   193  		Hash common.Hash
   194  		From common.Address
   195  	}
   196  	if err = ec.c.CallContext(ctx, &meta, "core_getTransactionByBlockHashAndIndex", block, hexutil.Uint64(index)); err != nil {
   197  		return common.Address{}, err
   198  	}
   199  	if meta.Hash == (common.Hash{}) || meta.Hash != tx.Hash() {
   200  		return common.Address{}, errors.New("wrong inclusion block/index")
   201  	}
   202  	return meta.From, nil
   203  }
   204  
   205  // TransactionCount returns the total number of transactions in the given block.
   206  func (ec *Client) TransactionCount(ctx context.Context, blockHash common.Hash) (uint, error) {
   207  	var num hexutil.Uint
   208  	err := ec.c.CallContext(ctx, &num, "core_getBlockTransactionCountByHash", blockHash)
   209  	return uint(num), err
   210  }
   211  
   212  // TransactionInBlock returns a single transaction at index in the given block.
   213  func (ec *Client) TransactionInBlock(ctx context.Context, blockHash common.Hash, index uint) (*types.Transaction, error) {
   214  	var json *rpcTransaction
   215  	err := ec.c.CallContext(ctx, &json, "core_getTransactionByBlockHashAndIndex", blockHash, hexutil.Uint64(index))
   216  	if err == nil {
   217  		if json == nil {
   218  			return nil, hubble.NotFound
   219  		} else if _, r, _ := json.tx.RawSignatureValues(); r == nil {
   220  			return nil, fmt.Errorf("server returned transaction without signature")
   221  		}
   222  	}
   223  	if json.From != nil && json.BlockHash != nil {
   224  		setSenderFromServer(json.tx, *json.From, *json.BlockHash)
   225  	}
   226  	return json.tx, err
   227  }
   228  
   229  // TransactionReceipt returns the receipt of a transaction by transaction hash.
   230  // Note that the receipt is not available for pending transactions.
   231  func (ec *Client) TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) {
   232  	var r *types.Receipt
   233  	err := ec.c.CallContext(ctx, &r, "core_getTransactionReceipt", txHash)
   234  	if err == nil {
   235  		if r == nil {
   236  			return nil, hubble.NotFound
   237  		}
   238  	}
   239  	return r, err
   240  }
   241  
   242  func toBlockNumArg(number *big.Int) string {
   243  	if number == nil {
   244  		return "latest"
   245  	}
   246  	return hexutil.EncodeBig(number)
   247  }
   248  
   249  type rpcProgress struct {
   250  	StartingBlock hexutil.Uint64
   251  	CurrentBlock  hexutil.Uint64
   252  	HighestBlock  hexutil.Uint64
   253  	PulledStates  hexutil.Uint64
   254  	KnownStates   hexutil.Uint64
   255  }
   256  
   257  // SyncProgress retrieves the current progress of the sync algorithm. If there's
   258  // no sync currently running, it returns nil.
   259  func (ec *Client) SyncProgress(ctx context.Context) (*hubble.SyncProgress, error) {
   260  	var raw json.RawMessage
   261  	if err := ec.c.CallContext(ctx, &raw, "core_syncing"); err != nil {
   262  		return nil, err
   263  	}
   264  	// Handle the possible response types
   265  	var syncing bool
   266  	if err := json.Unmarshal(raw, &syncing); err == nil {
   267  		return nil, nil // Not syncing (always false)
   268  	}
   269  	var progress *rpcProgress
   270  	if err := json.Unmarshal(raw, &progress); err != nil {
   271  		return nil, err
   272  	}
   273  	return &hubble.SyncProgress{
   274  		StartingBlock: uint64(progress.StartingBlock),
   275  		CurrentBlock:  uint64(progress.CurrentBlock),
   276  		HighestBlock:  uint64(progress.HighestBlock),
   277  		PulledStates:  uint64(progress.PulledStates),
   278  		KnownStates:   uint64(progress.KnownStates),
   279  	}, nil
   280  }
   281  
   282  // SubscribeNewHead subscribes to notifications about the current blockchain head
   283  // on the given channel.
   284  func (ec *Client) SubscribeNewHead(ctx context.Context, ch chan<- *types.Header) (hubble.Subscription, error) {
   285  	return ec.c.VntSubscribe(ctx, ch, "newHeads")
   286  }
   287  
   288  // State Access
   289  
   290  // NetworkID returns the network ID (also known as the chain ID) for this chain.
   291  func (ec *Client) NetworkID(ctx context.Context) (*big.Int, error) {
   292  	version := new(big.Int)
   293  	var ver string
   294  	if err := ec.c.CallContext(ctx, &ver, "net_version"); err != nil {
   295  		return nil, err
   296  	}
   297  	if _, ok := version.SetString(ver, 10); !ok {
   298  		return nil, fmt.Errorf("invalid net_version result %q", ver)
   299  	}
   300  	return version, nil
   301  }
   302  
   303  // BalanceAt returns the wei balance of the given account.
   304  // The block number can be nil, in which case the balance is taken from the latest known block.
   305  func (ec *Client) BalanceAt(ctx context.Context, account common.Address, blockNumber *big.Int) (*big.Int, error) {
   306  	var result hexutil.Big
   307  	err := ec.c.CallContext(ctx, &result, "core_getBalance", account, toBlockNumArg(blockNumber))
   308  	return (*big.Int)(&result), err
   309  }
   310  
   311  // StorageAt returns the value of key in the contract storage of the given account.
   312  // The block number can be nil, in which case the value is taken from the latest known block.
   313  func (ec *Client) StorageAt(ctx context.Context, account common.Address, key common.Hash, blockNumber *big.Int) ([]byte, error) {
   314  	var result hexutil.Bytes
   315  	err := ec.c.CallContext(ctx, &result, "core_getStorageAt", account, key, toBlockNumArg(blockNumber))
   316  	return result, err
   317  }
   318  
   319  // CodeAt returns the contract code of the given account.
   320  // The block number can be nil, in which case the code is taken from the latest known block.
   321  func (ec *Client) CodeAt(ctx context.Context, account common.Address, blockNumber *big.Int) ([]byte, error) {
   322  	var result hexutil.Bytes
   323  	err := ec.c.CallContext(ctx, &result, "core_getCode", account, toBlockNumArg(blockNumber))
   324  	return result, err
   325  }
   326  
   327  // AbiAt returns the contract abi of the given account.
   328  // The block number can be nil, in which case the code is taken from the latest known block.
   329  func (ec *Client) AbiAt(ctx context.Context, account common.Address, blockNumber *big.Int) ([]byte, error) {
   330  	var result hexutil.Bytes
   331  	err := ec.c.CallContext(ctx, &result, "core_getAbi", account, toBlockNumArg(blockNumber))
   332  	return result, err
   333  }
   334  
   335  // NonceAt returns the account nonce of the given account.
   336  // The block number can be nil, in which case the nonce is taken from the latest known block.
   337  func (ec *Client) NonceAt(ctx context.Context, account common.Address, blockNumber *big.Int) (uint64, error) {
   338  	var result hexutil.Uint64
   339  	err := ec.c.CallContext(ctx, &result, "core_getTransactionCount", account, toBlockNumArg(blockNumber))
   340  	return uint64(result), err
   341  }
   342  
   343  // Filters
   344  
   345  // FilterLogs executes a filter query.
   346  func (ec *Client) FilterLogs(ctx context.Context, q hubble.FilterQuery) ([]types.Log, error) {
   347  	var result []types.Log
   348  	err := ec.c.CallContext(ctx, &result, "core_getLogs", toFilterArg(q))
   349  	return result, err
   350  }
   351  
   352  // SubscribeFilterLogs subscribes to the results of a streaming filter query.
   353  func (ec *Client) SubscribeFilterLogs(ctx context.Context, q hubble.FilterQuery, ch chan<- types.Log) (hubble.Subscription, error) {
   354  	return ec.c.VntSubscribe(ctx, ch, "logs", toFilterArg(q))
   355  }
   356  
   357  func toFilterArg(q hubble.FilterQuery) interface{} {
   358  	arg := map[string]interface{}{
   359  		"fromBlock": toBlockNumArg(q.FromBlock),
   360  		"toBlock":   toBlockNumArg(q.ToBlock),
   361  		"address":   q.Addresses,
   362  		"topics":    q.Topics,
   363  	}
   364  	if q.FromBlock == nil {
   365  		arg["fromBlock"] = "0x0"
   366  	}
   367  	return arg
   368  }
   369  
   370  // Pending State
   371  
   372  // PendingBalanceAt returns the wei balance of the given account in the pending state.
   373  func (ec *Client) PendingBalanceAt(ctx context.Context, account common.Address) (*big.Int, error) {
   374  	var result hexutil.Big
   375  	err := ec.c.CallContext(ctx, &result, "core_getBalance", account, "pending")
   376  	return (*big.Int)(&result), err
   377  }
   378  
   379  // PendingStorageAt returns the value of key in the contract storage of the given account in the pending state.
   380  func (ec *Client) PendingStorageAt(ctx context.Context, account common.Address, key common.Hash) ([]byte, error) {
   381  	var result hexutil.Bytes
   382  	err := ec.c.CallContext(ctx, &result, "core_getStorageAt", account, key, "pending")
   383  	return result, err
   384  }
   385  
   386  // PendingCodeAt returns the contract code of the given account in the pending state.
   387  func (ec *Client) PendingCodeAt(ctx context.Context, account common.Address) ([]byte, error) {
   388  	var result hexutil.Bytes
   389  	err := ec.c.CallContext(ctx, &result, "core_getCode", account, "pending")
   390  	return result, err
   391  }
   392  
   393  // PendingNonceAt returns the account nonce of the given account in the pending state.
   394  // This is the nonce that should be used for the next transaction.
   395  func (ec *Client) PendingNonceAt(ctx context.Context, account common.Address) (uint64, error) {
   396  	var result hexutil.Uint64
   397  	err := ec.c.CallContext(ctx, &result, "core_getTransactionCount", account, "pending")
   398  	return uint64(result), err
   399  }
   400  
   401  // PendingTransactionCount returns the total number of transactions in the pending state.
   402  func (ec *Client) PendingTransactionCount(ctx context.Context) (uint, error) {
   403  	var num hexutil.Uint
   404  	err := ec.c.CallContext(ctx, &num, "core_getBlockTransactionCountByNumber", "pending")
   405  	return uint(num), err
   406  }
   407  
   408  // TODO: SubscribePendingTransactions (needs server side)
   409  
   410  // Contract Calling
   411  
   412  // CallContract executes a message call transaction, which is directly executed in the VM
   413  // of the node, but never produced into the blockchain.
   414  //
   415  // blockNumber selects the block height at which the call runs. It can be nil, in which
   416  // case the code is taken from the latest known block. Note that state from very old
   417  // blocks might not be available.
   418  func (ec *Client) CallContract(ctx context.Context, msg hubble.CallMsg, blockNumber *big.Int) ([]byte, error) {
   419  	var hex hexutil.Bytes
   420  	err := ec.c.CallContext(ctx, &hex, "core_call", toCallArg(msg), toBlockNumArg(blockNumber))
   421  	if err != nil {
   422  		return nil, err
   423  	}
   424  	return hex, nil
   425  }
   426  
   427  // PendingCallContract executes a message call transaction using the VM.
   428  // The state seen by the contract call is the pending state.
   429  func (ec *Client) PendingCallContract(ctx context.Context, msg hubble.CallMsg) ([]byte, error) {
   430  	var hex hexutil.Bytes
   431  	err := ec.c.CallContext(ctx, &hex, "core_call", toCallArg(msg), "pending")
   432  	if err != nil {
   433  		return nil, err
   434  	}
   435  	return hex, nil
   436  }
   437  
   438  // SuggestGasPrice retrieves the currently suggested gas price to allow a timely
   439  // execution of a transaction.
   440  func (ec *Client) SuggestGasPrice(ctx context.Context) (*big.Int, error) {
   441  	var hex hexutil.Big
   442  	if err := ec.c.CallContext(ctx, &hex, "core_gasPrice"); err != nil {
   443  		return nil, err
   444  	}
   445  	return (*big.Int)(&hex), nil
   446  }
   447  
   448  // EstimateGas tries to estimate the gas needed to execute a specific transaction based on
   449  // the current pending state of the backend blockchain. There is no guarantee that this is
   450  // the true gas limit requirement as other transactions may be added or removed by producers,
   451  // but it should provide a basis for setting a reasonable default.
   452  func (ec *Client) EstimateGas(ctx context.Context, msg hubble.CallMsg) (uint64, error) {
   453  	var hex hexutil.Uint64
   454  	err := ec.c.CallContext(ctx, &hex, "core_estimateGas", toCallArg(msg))
   455  	if err != nil {
   456  		return 0, err
   457  	}
   458  	return uint64(hex), nil
   459  }
   460  
   461  // SendTransaction injects a signed transaction into the pending pool for execution.
   462  //
   463  // If the transaction was a contract creation use the TransactionReceipt method to get the
   464  // contract address after the transaction has been produced.
   465  func (ec *Client) SendTransaction(ctx context.Context, tx *types.Transaction) error {
   466  	data, err := rlp.EncodeToBytes(tx)
   467  	if err != nil {
   468  		return err
   469  	}
   470  	return ec.c.CallContext(ctx, nil, "core_sendRawTransaction", common.ToHex(data))
   471  }
   472  
   473  func toCallArg(msg hubble.CallMsg) interface{} {
   474  	arg := map[string]interface{}{
   475  		"from": msg.From,
   476  		"to":   msg.To,
   477  	}
   478  	if len(msg.Data) > 0 {
   479  		arg["data"] = hexutil.Bytes(msg.Data)
   480  	}
   481  	if msg.Value != nil {
   482  		arg["value"] = (*hexutil.Big)(msg.Value)
   483  	}
   484  	if msg.Gas != 0 {
   485  		arg["gas"] = hexutil.Uint64(msg.Gas)
   486  	}
   487  	if msg.GasPrice != nil {
   488  		arg["gasPrice"] = (*hexutil.Big)(msg.GasPrice)
   489  	}
   490  	return arg
   491  }
   492  
   493  // NewElectionTx returns a unsigned transaction of calling election contract.
   494  //
   495  // It support all operation in election contract, such as stake/unStake, vote/cancelVote, more operation see election
   496  // abi: github.com/vntchain/go-vnt/core/vm/election.AbiJSON .
   497  //
   498  // parameter sender only used for to get nonce of the account who send this transaction. funcName name is the operation
   499  // what you want to do, and args is the parameters of funcName in election contract.
   500  func (ec *Client) NewElectionTx(ctx context.Context, sender common.Address, amount *big.Int, gasLimit uint64, gasPrice *big.Int, funcName string, args ...interface{}) (*types.Transaction, error) {
   501  	// 	Generate tx txData
   502  	electAbi, err := getElectionABI()
   503  	if err != nil {
   504  		return nil, err
   505  	}
   506  	txData, err := packInput(electAbi, funcName, args...)
   507  	if err != nil {
   508  		return nil, err
   509  	}
   510  
   511  	// 	Query nonce
   512  	nonce, err := ec.NonceAt(ctx, sender, nil)
   513  	if err != nil {
   514  		return nil, err
   515  	}
   516  
   517  	return types.NewTransaction(nonce, common.HexToAddress(election.ContractAddr), amount, gasLimit, gasPrice, txData), nil
   518  }
   519  
   520  func getElectionABI() (abi.ABI, error) {
   521  	return abi.JSON(strings.NewReader(election.ElectionAbiJSON))
   522  }
   523  
   524  func packInput(abiobj abi.ABI, name string, args ...interface{}) ([]byte, error) {
   525  	abires := abiobj
   526  	var res []byte
   527  	var err error
   528  	if len(args) == 0 {
   529  		res, err = abires.Pack(name)
   530  	} else {
   531  		res, err = abires.Pack(name, args...)
   532  	}
   533  	if err != nil {
   534  		return nil, err
   535  	}
   536  	return res, nil
   537  }
   538  
   539  // StakeAt returns the stake information of the given account.
   540  func (ec *Client) StakeAt(ctx context.Context, account common.Address) (*rpc.Stake, error) {
   541  	var ret *rpc.Stake
   542  	err := ec.c.CallContext(ctx, &ret, "core_getStake", account)
   543  	if err != nil {
   544  		return nil, err
   545  	} else if ret == nil {
   546  		return nil, hubble.NotFound
   547  	}
   548  	return ret, err
   549  }
   550  
   551  // VoteAt returns the vote information of the given account.
   552  func (ec *Client) VoteAt(ctx context.Context, account common.Address) (*rpc.Voter, error) {
   553  	var ret *rpc.Voter
   554  	err := ec.c.CallContext(ctx, &ret, "core_getVoter", account)
   555  	if err != nil {
   556  		return nil, err
   557  	} else if ret == nil {
   558  		return nil, hubble.NotFound
   559  	}
   560  	return ret, err
   561  }
   562  
   563  // WitnessCandidates returns a list of witness candidates.
   564  func (ec *Client) WitnessCandidates(ctx context.Context) ([]rpc.Candidate, error) {
   565  	var ret []rpc.Candidate
   566  	err := ec.c.CallContext(ctx, &ret, "core_getAllCandidates")
   567  	if err != nil {
   568  		return nil, err
   569  	} else if ret == nil {
   570  		return nil, hubble.NotFound
   571  	}
   572  	return ret, err
   573  }
   574  
   575  // RestVNTBounty return a integer of the left VNT bounty in wei.
   576  func (ec *Client) RestVNTBounty(ctx context.Context) (*big.Int, error) {
   577  	var ret big.Int
   578  	err := ec.c.CallContext(ctx, &ret, "core_getRestVNTBounty")
   579  	return &ret, err
   580  }