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 }