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