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