github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/mobile/ethclient.go (about) 1 2 //<developer> 3 // <name>linapex 曹一峰</name> 4 // <email>linapex@163.com</email> 5 // <wx>superexc</wx> 6 // <qqgroup>128148617</qqgroup> 7 // <url>https://jsq.ink</url> 8 // <role>pku engineer</role> 9 // <date>2019-03-16 12:09:43</date> 10 //</624342653747597312> 11 12 13 //包含以太坊客户端的包装。 14 15 package geth 16 17 import ( 18 "math/big" 19 20 "github.com/ethereum/go-ethereum/core/types" 21 "github.com/ethereum/go-ethereum/ethclient" 22 ) 23 24 //以太坊客户端提供对以太坊API的访问。 25 type EthereumClient struct { 26 client *ethclient.Client 27 } 28 29 //newethereumclient将客户机连接到给定的URL。 30 func NewEthereumClient(rawurl string) (client *EthereumClient, _ error) { 31 rawClient, err := ethclient.Dial(rawurl) 32 return &EthereumClient{rawClient}, err 33 } 34 35 //GetBlockByHash返回给定的完整块。 36 func (ec *EthereumClient) GetBlockByHash(ctx *Context, hash *Hash) (block *Block, _ error) { 37 rawBlock, err := ec.client.BlockByHash(ctx.context, hash.hash) 38 return &Block{rawBlock}, err 39 } 40 41 //GetBlockByNumber返回当前规范链中的块。如果数字小于0,则 42 //返回最新的已知块。 43 func (ec *EthereumClient) GetBlockByNumber(ctx *Context, number int64) (block *Block, _ error) { 44 if number < 0 { 45 rawBlock, err := ec.client.BlockByNumber(ctx.context, nil) 46 return &Block{rawBlock}, err 47 } 48 rawBlock, err := ec.client.BlockByNumber(ctx.context, big.NewInt(number)) 49 return &Block{rawBlock}, err 50 } 51 52 //GetHeaderByHash返回具有给定哈希的块头。 53 func (ec *EthereumClient) GetHeaderByHash(ctx *Context, hash *Hash) (header *Header, _ error) { 54 rawHeader, err := ec.client.HeaderByHash(ctx.context, hash.hash) 55 return &Header{rawHeader}, err 56 } 57 58 //GetHeaderByNumber返回当前规范链的块头。如果数字小于0, 59 //返回最新的已知头。 60 func (ec *EthereumClient) GetHeaderByNumber(ctx *Context, number int64) (header *Header, _ error) { 61 if number < 0 { 62 rawHeader, err := ec.client.HeaderByNumber(ctx.context, nil) 63 return &Header{rawHeader}, err 64 } 65 rawHeader, err := ec.client.HeaderByNumber(ctx.context, big.NewInt(number)) 66 return &Header{rawHeader}, err 67 } 68 69 //GetTransactionByHash返回具有给定哈希的事务。 70 func (ec *EthereumClient) GetTransactionByHash(ctx *Context, hash *Hash) (tx *Transaction, _ error) { 71 //TODO(karalabe):句柄显示 72 rawTx, _, err := ec.client.TransactionByHash(ctx.context, hash.hash) 73 return &Transaction{rawTx}, err 74 } 75 76 //GetTransactionSsender返回事务的发件人地址。交易必须 77 //在给定的块和索引中包含在区块链中。 78 func (ec *EthereumClient) GetTransactionSender(ctx *Context, tx *Transaction, blockhash *Hash, index int) (sender *Address, _ error) { 79 addr, err := ec.client.TransactionSender(ctx.context, tx.tx, blockhash.hash, uint(index)) 80 return &Address{addr}, err 81 } 82 83 //GetTransactionCount返回给定块中的事务总数。 84 func (ec *EthereumClient) GetTransactionCount(ctx *Context, hash *Hash) (count int, _ error) { 85 rawCount, err := ec.client.TransactionCount(ctx.context, hash.hash) 86 return int(rawCount), err 87 } 88 89 //GetTransactionInBlock返回给定块中索引处的单个事务。 90 func (ec *EthereumClient) GetTransactionInBlock(ctx *Context, hash *Hash, index int) (tx *Transaction, _ error) { 91 rawTx, err := ec.client.TransactionInBlock(ctx.context, hash.hash, uint(index)) 92 return &Transaction{rawTx}, err 93 94 } 95 96 //GetTransactionReceipt按事务哈希返回事务的接收。 97 //请注意,收据不可用于待处理的交易。 98 func (ec *EthereumClient) GetTransactionReceipt(ctx *Context, hash *Hash) (receipt *Receipt, _ error) { 99 rawReceipt, err := ec.client.TransactionReceipt(ctx.context, hash.hash) 100 return &Receipt{rawReceipt}, err 101 } 102 103 //SyncProgress检索同步算法的当前进度。如果有 104 //当前没有运行同步,它返回零。 105 func (ec *EthereumClient) SyncProgress(ctx *Context) (progress *SyncProgress, _ error) { 106 rawProgress, err := ec.client.SyncProgress(ctx.context) 107 if rawProgress == nil { 108 return nil, err 109 } 110 return &SyncProgress{*rawProgress}, err 111 } 112 113 //NewHeadHandler是一个客户端订阅回调,用于在事件和 114 //订阅失败。 115 type NewHeadHandler interface { 116 OnNewHead(header *Header) 117 OnError(failure string) 118 } 119 120 //订阅订阅当前区块链头的通知 121 //在给定的频道上。 122 func (ec *EthereumClient) SubscribeNewHead(ctx *Context, handler NewHeadHandler, buffer int) (sub *Subscription, _ error) { 123 //在内部订阅事件 124 ch := make(chan *types.Header, buffer) 125 rawSub, err := ec.client.SubscribeNewHead(ctx.context, ch) 126 if err != nil { 127 return nil, err 128 } 129 //启动一个调度器以反馈回拨 130 go func() { 131 for { 132 select { 133 case header := <-ch: 134 handler.OnNewHead(&Header{header}) 135 136 case err := <-rawSub.Err(): 137 handler.OnError(err.Error()) 138 return 139 } 140 } 141 }() 142 return &Subscription{rawSub}, nil 143 } 144 145 //状态访问 146 147 //getbalanceat返回给定帐户的wei余额。 148 //块编号可以小于0,在这种情况下,余额取自最新的已知块。 149 func (ec *EthereumClient) GetBalanceAt(ctx *Context, account *Address, number int64) (balance *BigInt, _ error) { 150 if number < 0 { 151 rawBalance, err := ec.client.BalanceAt(ctx.context, account.address, nil) 152 return &BigInt{rawBalance}, err 153 } 154 rawBalance, err := ec.client.BalanceAt(ctx.context, account.address, big.NewInt(number)) 155 return &BigInt{rawBalance}, err 156 } 157 158 //GetStorageAt返回给定帐户的合同存储中密钥的值。 159 //块编号可以小于0,在这种情况下,该值取自最新的已知块。 160 func (ec *EthereumClient) GetStorageAt(ctx *Context, account *Address, key *Hash, number int64) (storage []byte, _ error) { 161 if number < 0 { 162 return ec.client.StorageAt(ctx.context, account.address, key.hash, nil) 163 } 164 return ec.client.StorageAt(ctx.context, account.address, key.hash, big.NewInt(number)) 165 } 166 167 //getcodeat返回给定帐户的合同代码。 168 //块编号可以小于0,在这种情况下,代码取自最新的已知块。 169 func (ec *EthereumClient) GetCodeAt(ctx *Context, account *Address, number int64) (code []byte, _ error) { 170 if number < 0 { 171 return ec.client.CodeAt(ctx.context, account.address, nil) 172 } 173 return ec.client.CodeAt(ctx.context, account.address, big.NewInt(number)) 174 } 175 176 //getnonceat返回给定帐户的nonce帐户。 177 //块号可以小于0,在这种情况下,nonce是从最新的已知块中获取的。 178 func (ec *EthereumClient) GetNonceAt(ctx *Context, account *Address, number int64) (nonce int64, _ error) { 179 if number < 0 { 180 rawNonce, err := ec.client.NonceAt(ctx.context, account.address, nil) 181 return int64(rawNonce), err 182 } 183 rawNonce, err := ec.client.NonceAt(ctx.context, account.address, big.NewInt(number)) 184 return int64(rawNonce), err 185 } 186 187 //过滤器 188 189 //filterlogs执行筛选器查询。 190 func (ec *EthereumClient) FilterLogs(ctx *Context, query *FilterQuery) (logs *Logs, _ error) { 191 rawLogs, err := ec.client.FilterLogs(ctx.context, query.query) 192 if err != nil { 193 return nil, err 194 } 195 //由于vm.logs为[]*vm.log,临时黑客 196 res := make([]*types.Log, len(rawLogs)) 197 for i := range rawLogs { 198 res[i] = &rawLogs[i] 199 } 200 return &Logs{res}, nil 201 } 202 203 //filterlogshandler是一个客户端订阅回调,用于在事件和 204 //订阅失败。 205 type FilterLogsHandler interface { 206 OnFilterLogs(log *Log) 207 OnError(failure string) 208 } 209 210 //subscribeFilterLogs订阅流式筛选查询的结果。 211 func (ec *EthereumClient) SubscribeFilterLogs(ctx *Context, query *FilterQuery, handler FilterLogsHandler, buffer int) (sub *Subscription, _ error) { 212 //在内部订阅事件 213 ch := make(chan types.Log, buffer) 214 rawSub, err := ec.client.SubscribeFilterLogs(ctx.context, query.query, ch) 215 if err != nil { 216 return nil, err 217 } 218 //启动一个调度器以反馈回拨 219 go func() { 220 for { 221 select { 222 case log := <-ch: 223 handler.OnFilterLogs(&Log{&log}) 224 225 case err := <-rawSub.Err(): 226 handler.OnError(err.Error()) 227 return 228 } 229 } 230 }() 231 return &Subscription{rawSub}, nil 232 } 233 234 //预备状态 235 236 //getPendingBalanceAt返回处于挂起状态的给定帐户的wei余额。 237 func (ec *EthereumClient) GetPendingBalanceAt(ctx *Context, account *Address) (balance *BigInt, _ error) { 238 rawBalance, err := ec.client.PendingBalanceAt(ctx.context, account.address) 239 return &BigInt{rawBalance}, err 240 } 241 242 //GetPendingStorageAt返回处于挂起状态的给定帐户的合同存储中键的值。 243 func (ec *EthereumClient) GetPendingStorageAt(ctx *Context, account *Address, key *Hash) (storage []byte, _ error) { 244 return ec.client.PendingStorageAt(ctx.context, account.address, key.hash) 245 } 246 247 //GetPendingCodeAt返回处于挂起状态的给定帐户的合同代码。 248 func (ec *EthereumClient) GetPendingCodeAt(ctx *Context, account *Address) (code []byte, _ error) { 249 return ec.client.PendingCodeAt(ctx.context, account.address) 250 } 251 252 //GetPendingOnCate返回处于挂起状态的给定帐户的帐户nonce。 253 //这是应该用于下一个事务的nonce。 254 func (ec *EthereumClient) GetPendingNonceAt(ctx *Context, account *Address) (nonce int64, _ error) { 255 rawNonce, err := ec.client.PendingNonceAt(ctx.context, account.address) 256 return int64(rawNonce), err 257 } 258 259 //GetPendingtTransactionCount返回处于挂起状态的事务总数。 260 func (ec *EthereumClient) GetPendingTransactionCount(ctx *Context) (count int, _ error) { 261 rawCount, err := ec.client.PendingTransactionCount(ctx.context) 262 return int(rawCount), err 263 } 264 265 //合同呼叫 266 267 //CallContract执行消息调用事务,该事务直接在VM中执行 268 //但从未开发到区块链中。 269 // 270 //BlockNumber选择运行调用的块高度。它可以小于0,其中 271 //如果代码取自最新的已知块。注意这个状态从很老 272 //块可能不可用。 273 func (ec *EthereumClient) CallContract(ctx *Context, msg *CallMsg, number int64) (output []byte, _ error) { 274 if number < 0 { 275 return ec.client.CallContract(ctx.context, msg.msg, nil) 276 } 277 return ec.client.CallContract(ctx.context, msg.msg, big.NewInt(number)) 278 } 279 280 //PendingCallContract使用EVM执行消息调用事务。 281 //合同调用所看到的状态是挂起状态。 282 func (ec *EthereumClient) PendingCallContract(ctx *Context, msg *CallMsg) (output []byte, _ error) { 283 return ec.client.PendingCallContract(ctx.context, msg.msg) 284 } 285 286 //SuggestGasprice检索当前建议的天然气价格,以便及时 287 //交易的执行。 288 func (ec *EthereumClient) SuggestGasPrice(ctx *Context) (price *BigInt, _ error) { 289 rawPrice, err := ec.client.SuggestGasPrice(ctx.context) 290 return &BigInt{rawPrice}, err 291 } 292 293 //EstimateGas试图根据 294 //后端区块链的当前挂起状态。不能保证这是 295 //矿工可能增加或移除的其他交易的实际气体限制要求, 296 //但它应为设定合理违约提供依据。 297 func (ec *EthereumClient) EstimateGas(ctx *Context, msg *CallMsg) (gas int64, _ error) { 298 rawGas, err := ec.client.EstimateGas(ctx.context, msg.msg) 299 return int64(rawGas), err 300 } 301 302 //sendTransaction将签名的事务注入挂起池以执行。 303 // 304 //如果事务是合同创建,请使用TransactionReceipt方法获取 305 //挖掘交易记录后的合同地址。 306 func (ec *EthereumClient) SendTransaction(ctx *Context, tx *Transaction) error { 307 return ec.client.SendTransaction(ctx.context, tx.tx) 308 } 309