github.com/arieschain/arieschain@v0.0.0-20191023063405-37c074544356/mobile/ethclient.go (about)

     1  // Contains a wrapper for the Ethereum client.
     2  
     3  package geth
     4  
     5  import (
     6  	"math/big"
     7  
     8  	"github.com/quickchainproject/quickchain/core/types"
     9  	"github.com/quickchainproject/quickchain/qctclient"
    10  )
    11  
    12  // EthereumClient provides access to the Ethereum APIs.
    13  type EthereumClient struct {
    14  	client *qctclient.Client
    15  }
    16  
    17  // NewEthereumClient connects a client to the given URL.
    18  func NewEthereumClient(rawurl string) (client *EthereumClient, _ error) {
    19  	rawClient, err := qctclient.Dial(rawurl)
    20  	return &EthereumClient{rawClient}, err
    21  }
    22  
    23  // GetBlockByHash returns the given full block.
    24  func (ec *EthereumClient) GetBlockByHash(ctx *Context, hash *Hash) (block *Block, _ error) {
    25  	rawBlock, err := ec.client.BlockByHash(ctx.context, hash.hash)
    26  	return &Block{rawBlock}, err
    27  }
    28  
    29  // GetBlockByNumber returns a block from the current canonical chain. If number is <0, the
    30  // latest known block is returned.
    31  func (ec *EthereumClient) GetBlockByNumber(ctx *Context, number int64) (block *Block, _ error) {
    32  	if number < 0 {
    33  		rawBlock, err := ec.client.BlockByNumber(ctx.context, nil)
    34  		return &Block{rawBlock}, err
    35  	}
    36  	rawBlock, err := ec.client.BlockByNumber(ctx.context, big.NewInt(number))
    37  	return &Block{rawBlock}, err
    38  }
    39  
    40  // GetHeaderByHash returns the block header with the given hash.
    41  func (ec *EthereumClient) GetHeaderByHash(ctx *Context, hash *Hash) (header *Header, _ error) {
    42  	rawHeader, err := ec.client.HeaderByHash(ctx.context, hash.hash)
    43  	return &Header{rawHeader}, err
    44  }
    45  
    46  // GetHeaderByNumber returns a block header from the current canonical chain. If number is <0,
    47  // the latest known header is returned.
    48  func (ec *EthereumClient) GetHeaderByNumber(ctx *Context, number int64) (header *Header, _ error) {
    49  	if number < 0 {
    50  		rawHeader, err := ec.client.HeaderByNumber(ctx.context, nil)
    51  		return &Header{rawHeader}, err
    52  	}
    53  	rawHeader, err := ec.client.HeaderByNumber(ctx.context, big.NewInt(number))
    54  	return &Header{rawHeader}, err
    55  }
    56  
    57  // GetTransactionByHash returns the transaction with the given hash.
    58  func (ec *EthereumClient) GetTransactionByHash(ctx *Context, hash *Hash) (tx *Transaction, _ error) {
    59  	// TODO(karalabe): handle isPending
    60  	rawTx, _, err := ec.client.TransactionByHash(ctx.context, hash.hash)
    61  	return &Transaction{rawTx}, err
    62  }
    63  
    64  // GetTransactionSender returns the sender address of a transaction. The transaction must
    65  // be included in blockchain at the given block and index.
    66  func (ec *EthereumClient) GetTransactionSender(ctx *Context, tx *Transaction, blockhash *Hash, index int) (sender *Address, _ error) {
    67  	addr, err := ec.client.TransactionSender(ctx.context, tx.tx, blockhash.hash, uint(index))
    68  	return &Address{addr}, err
    69  }
    70  
    71  // GetTransactionCount returns the total number of transactions in the given block.
    72  func (ec *EthereumClient) GetTransactionCount(ctx *Context, hash *Hash) (count int, _ error) {
    73  	rawCount, err := ec.client.TransactionCount(ctx.context, hash.hash)
    74  	return int(rawCount), err
    75  }
    76  
    77  // GetTransactionInBlock returns a single transaction at index in the given block.
    78  func (ec *EthereumClient) GetTransactionInBlock(ctx *Context, hash *Hash, index int) (tx *Transaction, _ error) {
    79  	rawTx, err := ec.client.TransactionInBlock(ctx.context, hash.hash, uint(index))
    80  	return &Transaction{rawTx}, err
    81  
    82  }
    83  
    84  // GetTransactionReceipt returns the receipt of a transaction by transaction hash.
    85  // Note that the receipt is not available for pending transactions.
    86  func (ec *EthereumClient) GetTransactionReceipt(ctx *Context, hash *Hash) (receipt *Receipt, _ error) {
    87  	rawReceipt, err := ec.client.TransactionReceipt(ctx.context, hash.hash)
    88  	return &Receipt{rawReceipt}, err
    89  }
    90  
    91  // SyncProgress retrieves the current progress of the sync algorithm. If there's
    92  // no sync currently running, it returns nil.
    93  func (ec *EthereumClient) SyncProgress(ctx *Context) (progress *SyncProgress, _ error) {
    94  	rawProgress, err := ec.client.SyncProgress(ctx.context)
    95  	if rawProgress == nil {
    96  		return nil, err
    97  	}
    98  	return &SyncProgress{*rawProgress}, err
    99  }
   100  
   101  // NewHeadHandler is a client-side subscription callback to invoke on events and
   102  // subscription failure.
   103  type NewHeadHandler interface {
   104  	OnNewHead(header *Header)
   105  	OnError(failure string)
   106  }
   107  
   108  // SubscribeNewHead subscribes to notifications about the current blockchain head
   109  // on the given channel.
   110  func (ec *EthereumClient) SubscribeNewHead(ctx *Context, handler NewHeadHandler, buffer int) (sub *Subscription, _ error) {
   111  	// Subscribe to the event internally
   112  	ch := make(chan *types.Header, buffer)
   113  	rawSub, err := ec.client.SubscribeNewHead(ctx.context, ch)
   114  	if err != nil {
   115  		return nil, err
   116  	}
   117  	// Start up a dispatcher to feed into the callback
   118  	go func() {
   119  		for {
   120  			select {
   121  			case header := <-ch:
   122  				handler.OnNewHead(&Header{header})
   123  
   124  			case err := <-rawSub.Err():
   125  				handler.OnError(err.Error())
   126  				return
   127  			}
   128  		}
   129  	}()
   130  	return &Subscription{rawSub}, nil
   131  }
   132  
   133  // State Access
   134  
   135  // GetBalanceAt returns the wei balance of the given account.
   136  // The block number can be <0, in which case the balance is taken from the latest known block.
   137  func (ec *EthereumClient) GetBalanceAt(ctx *Context, account *Address, number int64) (balance *BigInt, _ error) {
   138  	if number < 0 {
   139  		rawBalance, err := ec.client.BalanceAt(ctx.context, account.address, nil)
   140  		return &BigInt{rawBalance}, err
   141  	}
   142  	rawBalance, err := ec.client.BalanceAt(ctx.context, account.address, big.NewInt(number))
   143  	return &BigInt{rawBalance}, err
   144  }
   145  
   146  // GetStorageAt returns the value of key in the contract storage of the given account.
   147  // The block number can be <0, in which case the value is taken from the latest known block.
   148  func (ec *EthereumClient) GetStorageAt(ctx *Context, account *Address, key *Hash, number int64) (storage []byte, _ error) {
   149  	if number < 0 {
   150  		return ec.client.StorageAt(ctx.context, account.address, key.hash, nil)
   151  	}
   152  	return ec.client.StorageAt(ctx.context, account.address, key.hash, big.NewInt(number))
   153  }
   154  
   155  // GetCodeAt returns the contract code of the given account.
   156  // The block number can be <0, in which case the code is taken from the latest known block.
   157  func (ec *EthereumClient) GetCodeAt(ctx *Context, account *Address, number int64) (code []byte, _ error) {
   158  	if number < 0 {
   159  		return ec.client.CodeAt(ctx.context, account.address, nil)
   160  	}
   161  	return ec.client.CodeAt(ctx.context, account.address, big.NewInt(number))
   162  }
   163  
   164  // GetNonceAt returns the account nonce of the given account.
   165  // The block number can be <0, in which case the nonce is taken from the latest known block.
   166  func (ec *EthereumClient) GetNonceAt(ctx *Context, account *Address, number int64) (nonce int64, _ error) {
   167  	if number < 0 {
   168  		rawNonce, err := ec.client.NonceAt(ctx.context, account.address, nil)
   169  		return int64(rawNonce), err
   170  	}
   171  	rawNonce, err := ec.client.NonceAt(ctx.context, account.address, big.NewInt(number))
   172  	return int64(rawNonce), err
   173  }
   174  
   175  // Filters
   176  
   177  // FilterLogs executes a filter query.
   178  func (ec *EthereumClient) FilterLogs(ctx *Context, query *FilterQuery) (logs *Logs, _ error) {
   179  	rawLogs, err := ec.client.FilterLogs(ctx.context, query.query)
   180  	if err != nil {
   181  		return nil, err
   182  	}
   183  	// Temp hack due to vm.Logs being []*vm.Log
   184  	res := make([]*types.Log, len(rawLogs))
   185  	for i := range rawLogs {
   186  		res[i] = &rawLogs[i]
   187  	}
   188  	return &Logs{res}, nil
   189  }
   190  
   191  // FilterLogsHandler is a client-side subscription callback to invoke on events and
   192  // subscription failure.
   193  type FilterLogsHandler interface {
   194  	OnFilterLogs(log *Log)
   195  	OnError(failure string)
   196  }
   197  
   198  // SubscribeFilterLogs subscribes to the results of a streaming filter query.
   199  func (ec *EthereumClient) SubscribeFilterLogs(ctx *Context, query *FilterQuery, handler FilterLogsHandler, buffer int) (sub *Subscription, _ error) {
   200  	// Subscribe to the event internally
   201  	ch := make(chan types.Log, buffer)
   202  	rawSub, err := ec.client.SubscribeFilterLogs(ctx.context, query.query, ch)
   203  	if err != nil {
   204  		return nil, err
   205  	}
   206  	// Start up a dispatcher to feed into the callback
   207  	go func() {
   208  		for {
   209  			select {
   210  			case log := <-ch:
   211  				handler.OnFilterLogs(&Log{&log})
   212  
   213  			case err := <-rawSub.Err():
   214  				handler.OnError(err.Error())
   215  				return
   216  			}
   217  		}
   218  	}()
   219  	return &Subscription{rawSub}, nil
   220  }
   221  
   222  // Pending State
   223  
   224  // GetPendingBalanceAt returns the wei balance of the given account in the pending state.
   225  func (ec *EthereumClient) GetPendingBalanceAt(ctx *Context, account *Address) (balance *BigInt, _ error) {
   226  	rawBalance, err := ec.client.PendingBalanceAt(ctx.context, account.address)
   227  	return &BigInt{rawBalance}, err
   228  }
   229  
   230  // GetPendingStorageAt returns the value of key in the contract storage of the given account in the pending state.
   231  func (ec *EthereumClient) GetPendingStorageAt(ctx *Context, account *Address, key *Hash) (storage []byte, _ error) {
   232  	return ec.client.PendingStorageAt(ctx.context, account.address, key.hash)
   233  }
   234  
   235  // GetPendingCodeAt returns the contract code of the given account in the pending state.
   236  func (ec *EthereumClient) GetPendingCodeAt(ctx *Context, account *Address) (code []byte, _ error) {
   237  	return ec.client.PendingCodeAt(ctx.context, account.address)
   238  }
   239  
   240  // GetPendingNonceAt returns the account nonce of the given account in the pending state.
   241  // This is the nonce that should be used for the next transaction.
   242  func (ec *EthereumClient) GetPendingNonceAt(ctx *Context, account *Address) (nonce int64, _ error) {
   243  	rawNonce, err := ec.client.PendingNonceAt(ctx.context, account.address)
   244  	return int64(rawNonce), err
   245  }
   246  
   247  // GetPendingTransactionCount returns the total number of transactions in the pending state.
   248  func (ec *EthereumClient) GetPendingTransactionCount(ctx *Context) (count int, _ error) {
   249  	rawCount, err := ec.client.PendingTransactionCount(ctx.context)
   250  	return int(rawCount), err
   251  }
   252  
   253  // Contract Calling
   254  
   255  // CallContract executes a message call transaction, which is directly executed in the VM
   256  // of the node, but never mined into the blockchain.
   257  //
   258  // blockNumber selects the block height at which the call runs. It can be <0, in which
   259  // case the code is taken from the latest known block. Note that state from very old
   260  // blocks might not be available.
   261  func (ec *EthereumClient) CallContract(ctx *Context, msg *CallMsg, number int64) (output []byte, _ error) {
   262  	if number < 0 {
   263  		return ec.client.CallContract(ctx.context, msg.msg, nil)
   264  	}
   265  	return ec.client.CallContract(ctx.context, msg.msg, big.NewInt(number))
   266  }
   267  
   268  // PendingCallContract executes a message call transaction using the EVM.
   269  // The state seen by the contract call is the pending state.
   270  func (ec *EthereumClient) PendingCallContract(ctx *Context, msg *CallMsg) (output []byte, _ error) {
   271  	return ec.client.PendingCallContract(ctx.context, msg.msg)
   272  }
   273  
   274  // SuggestGasPrice retrieves the currently suggested gas price to allow a timely
   275  // execution of a transaction.
   276  func (ec *EthereumClient) SuggestGasPrice(ctx *Context) (price *BigInt, _ error) {
   277  	rawPrice, err := ec.client.SuggestGasPrice(ctx.context)
   278  	return &BigInt{rawPrice}, err
   279  }
   280  
   281  // EstimateGas tries to estimate the gas needed to execute a specific transaction based on
   282  // the current pending state of the backend blockchain. There is no guarantee that this is
   283  // the true gas limit requirement as other transactions may be added or removed by miners,
   284  // but it should provide a basis for setting a reasonable default.
   285  func (ec *EthereumClient) EstimateGas(ctx *Context, msg *CallMsg) (gas int64, _ error) {
   286  	rawGas, err := ec.client.EstimateGas(ctx.context, msg.msg)
   287  	return int64(rawGas), err
   288  }
   289  
   290  // SendTransaction injects a signed transaction into the pending pool for execution.
   291  //
   292  // If the transaction was a contract creation use the TransactionReceipt method to get the
   293  // contract address after the transaction has been mined.
   294  func (ec *EthereumClient) SendTransaction(ctx *Context, tx *Transaction) error {
   295  	return ec.client.SendTransaction(ctx.context, tx.tx)
   296  }