gitlab.com/flarenetwork/coreth@v0.1.1/ethclient/ethclient.go (about) 1 // (c) 2019-2020, Ava Labs, Inc. 2 // 3 // This file is a derived work, based on the go-ethereum library whose original 4 // notices appear below. 5 // 6 // It is distributed under a license compatible with the licensing terms of the 7 // original code from which it is derived. 8 // 9 // Much love to the original authors for their work. 10 // ********** 11 // Copyright 2016 The go-ethereum Authors 12 // This file is part of the go-ethereum library. 13 // 14 // The go-ethereum library is free software: you can redistribute it and/or modify 15 // it under the terms of the GNU Lesser General Public License as published by 16 // the Free Software Foundation, either version 3 of the License, or 17 // (at your option) any later version. 18 // 19 // The go-ethereum library is distributed in the hope that it will be useful, 20 // but WITHOUT ANY WARRANTY; without even the implied warranty of 21 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 // GNU Lesser General Public License for more details. 23 // 24 // You should have received a copy of the GNU Lesser General Public License 25 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 26 27 // Package ethclient provides a client for the Ethereum RPC API. 28 package ethclient 29 30 import ( 31 "context" 32 "encoding/json" 33 "errors" 34 "fmt" 35 "math/big" 36 37 "github.com/ava-labs/avalanchego/ids" 38 "github.com/ethereum/go-ethereum/common" 39 "github.com/ethereum/go-ethereum/common/hexutil" 40 "gitlab.com/flarenetwork/coreth/core/types" 41 "gitlab.com/flarenetwork/coreth/interfaces" 42 "gitlab.com/flarenetwork/coreth/rpc" 43 ) 44 45 // Client defines typed wrappers for the Ethereum RPC API. 46 type Client struct { 47 c *rpc.Client 48 } 49 50 // Dial connects a client to the given URL. 51 func Dial(rawurl string) (*Client, error) { 52 return DialContext(context.Background(), rawurl) 53 } 54 55 func DialContext(ctx context.Context, rawurl string) (*Client, error) { 56 c, err := rpc.DialContext(ctx, rawurl) 57 if err != nil { 58 return nil, err 59 } 60 return NewClient(c), nil 61 } 62 63 // NewClient creates a client that uses the given RPC client. 64 func NewClient(c *rpc.Client) *Client { 65 return &Client{c} 66 } 67 68 func (ec *Client) Close() { 69 ec.c.Close() 70 } 71 72 // Blockchain Access 73 74 // ChainId retrieves the current chain ID for transaction replay protection. 75 func (ec *Client) ChainID(ctx context.Context) (*big.Int, error) { 76 var result hexutil.Big 77 err := ec.c.CallContext(ctx, &result, "eth_chainId") 78 if err != nil { 79 return nil, err 80 } 81 return (*big.Int)(&result), err 82 } 83 84 // BlockByHash returns the given full block. 85 // 86 // Note that loading full blocks requires two requests. Use HeaderByHash 87 // if you don't need all transactions or uncle headers. 88 func (ec *Client) BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) { 89 return ec.getBlock(ctx, "eth_getBlockByHash", hash, true) 90 } 91 92 // BlockByNumber returns a block from the current canonical chain. If number is nil, the 93 // latest known block is returned. 94 // 95 // Note that loading full blocks requires two requests. Use HeaderByNumber 96 // if you don't need all transactions or uncle headers. 97 func (ec *Client) BlockByNumber(ctx context.Context, number *big.Int) (*types.Block, error) { 98 return ec.getBlock(ctx, "eth_getBlockByNumber", ToBlockNumArg(number), true) 99 } 100 101 // BlockNumber returns the most recent block number 102 func (ec *Client) BlockNumber(ctx context.Context) (uint64, error) { 103 var result hexutil.Uint64 104 err := ec.c.CallContext(ctx, &result, "eth_blockNumber") 105 return uint64(result), err 106 } 107 108 type rpcBlock struct { 109 Hash common.Hash `json:"hash"` 110 Transactions []rpcTransaction `json:"transactions"` 111 UncleHashes []common.Hash `json:"uncles"` 112 Version uint32 `json:"version"` 113 BlockExtraData *hexutil.Bytes `json:"blockExtraData"` 114 } 115 116 func (ec *Client) getBlock(ctx context.Context, method string, args ...interface{}) (*types.Block, error) { 117 var raw json.RawMessage 118 err := ec.c.CallContext(ctx, &raw, method, args...) 119 if err != nil { 120 return nil, err 121 } else if len(raw) == 0 { 122 return nil, interfaces.NotFound 123 } 124 // Decode header and transactions. 125 var head *types.Header 126 var body rpcBlock 127 if err := json.Unmarshal(raw, &head); err != nil { 128 return nil, err 129 } 130 if err := json.Unmarshal(raw, &body); err != nil { 131 return nil, err 132 } 133 // Quick-verify transaction and uncle lists. This mostly helps with debugging the server. 134 if head.UncleHash == types.EmptyUncleHash && len(body.UncleHashes) > 0 { 135 return nil, fmt.Errorf("server returned non-empty uncle list but block header indicates no uncles") 136 } 137 if head.UncleHash != types.EmptyUncleHash && len(body.UncleHashes) == 0 { 138 return nil, fmt.Errorf("server returned empty uncle list but block header indicates uncles") 139 } 140 if head.TxHash == types.EmptyRootHash && len(body.Transactions) > 0 { 141 return nil, fmt.Errorf("server returned non-empty transaction list but block header indicates no transactions") 142 } 143 if head.TxHash != types.EmptyRootHash && len(body.Transactions) == 0 { 144 return nil, fmt.Errorf("server returned empty transaction list but block header indicates transactions") 145 } 146 // Load uncles because they are not included in the block response. 147 var uncles []*types.Header 148 if len(body.UncleHashes) > 0 { 149 uncles = make([]*types.Header, len(body.UncleHashes)) 150 reqs := make([]rpc.BatchElem, len(body.UncleHashes)) 151 for i := range reqs { 152 reqs[i] = rpc.BatchElem{ 153 Method: "eth_getUncleByBlockHashAndIndex", 154 Args: []interface{}{body.Hash, hexutil.EncodeUint64(uint64(i))}, 155 Result: &uncles[i], 156 } 157 } 158 if err := ec.c.BatchCallContext(ctx, reqs); err != nil { 159 return nil, err 160 } 161 for i := range reqs { 162 if reqs[i].Error != nil { 163 return nil, reqs[i].Error 164 } 165 if uncles[i] == nil { 166 return nil, fmt.Errorf("got null header for uncle %d of block %x", i, body.Hash[:]) 167 } 168 } 169 } 170 // Fill the sender cache of transactions in the block. 171 txs := make([]*types.Transaction, len(body.Transactions)) 172 for i, tx := range body.Transactions { 173 if tx.From != nil { 174 setSenderFromServer(tx.tx, *tx.From, body.Hash) 175 } 176 txs[i] = tx.tx 177 } 178 return types.NewBlockWithHeader(head).WithBody(txs, uncles, body.Version, (*[]byte)(body.BlockExtraData)), nil 179 } 180 181 // HeaderByHash returns the block header with the given hash. 182 func (ec *Client) HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error) { 183 var head *types.Header 184 err := ec.c.CallContext(ctx, &head, "eth_getBlockByHash", hash, false) 185 if err == nil && head == nil { 186 err = interfaces.NotFound 187 } 188 return head, err 189 } 190 191 // HeaderByNumber returns a block header from the current canonical chain. If number is 192 // nil, the latest known header is returned. 193 func (ec *Client) HeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error) { 194 var head *types.Header 195 err := ec.c.CallContext(ctx, &head, "eth_getBlockByNumber", ToBlockNumArg(number), false) 196 if err == nil && head == nil { 197 err = interfaces.NotFound 198 } 199 return head, err 200 } 201 202 type rpcTransaction struct { 203 tx *types.Transaction 204 txExtraInfo 205 } 206 207 type txExtraInfo struct { 208 BlockNumber *string `json:"blockNumber,omitempty"` 209 BlockHash *common.Hash `json:"blockHash,omitempty"` 210 From *common.Address `json:"from,omitempty"` 211 } 212 213 func (tx *rpcTransaction) UnmarshalJSON(msg []byte) error { 214 if err := json.Unmarshal(msg, &tx.tx); err != nil { 215 return err 216 } 217 return json.Unmarshal(msg, &tx.txExtraInfo) 218 } 219 220 // TransactionByHash returns the transaction with the given hash. 221 func (ec *Client) TransactionByHash(ctx context.Context, hash common.Hash) (tx *types.Transaction, isPending bool, err error) { 222 var json *rpcTransaction 223 err = ec.c.CallContext(ctx, &json, "eth_getTransactionByHash", hash) 224 if err != nil { 225 return nil, false, err 226 } else if json == nil { 227 return nil, false, interfaces.NotFound 228 } else if _, r, _ := json.tx.RawSignatureValues(); r == nil { 229 return nil, false, fmt.Errorf("server returned transaction without signature") 230 } 231 if json.From != nil && json.BlockHash != nil { 232 setSenderFromServer(json.tx, *json.From, *json.BlockHash) 233 } 234 return json.tx, json.BlockNumber == nil, nil 235 } 236 237 // TransactionSender returns the sender address of the given transaction. The transaction 238 // must be known to the remote node and included in the blockchain at the given block and 239 // index. The sender is the one derived by the protocol at the time of inclusion. 240 // 241 // There is a fast-path for transactions retrieved by TransactionByHash and 242 // TransactionInBlock. Getting their sender address can be done without an RPC interaction. 243 func (ec *Client) TransactionSender(ctx context.Context, tx *types.Transaction, block common.Hash, index uint) (common.Address, error) { 244 // Try to load the address from the cache. 245 sender, err := types.Sender(&senderFromServer{blockhash: block}, tx) 246 if err == nil { 247 return sender, nil 248 } 249 var meta struct { 250 Hash common.Hash 251 From common.Address 252 } 253 if err = ec.c.CallContext(ctx, &meta, "eth_getTransactionByBlockHashAndIndex", block, hexutil.Uint64(index)); err != nil { 254 return common.Address{}, err 255 } 256 if meta.Hash == (common.Hash{}) || meta.Hash != tx.Hash() { 257 return common.Address{}, errors.New("wrong inclusion block/index") 258 } 259 return meta.From, nil 260 } 261 262 // TransactionCount returns the total number of transactions in the given block. 263 func (ec *Client) TransactionCount(ctx context.Context, blockHash common.Hash) (uint, error) { 264 var num hexutil.Uint 265 err := ec.c.CallContext(ctx, &num, "eth_getBlockTransactionCountByHash", blockHash) 266 return uint(num), err 267 } 268 269 // TransactionInBlock returns a single transaction at index in the given block. 270 func (ec *Client) TransactionInBlock(ctx context.Context, blockHash common.Hash, index uint) (*types.Transaction, error) { 271 var json *rpcTransaction 272 err := ec.c.CallContext(ctx, &json, "eth_getTransactionByBlockHashAndIndex", blockHash, hexutil.Uint64(index)) 273 if err != nil { 274 return nil, err 275 } 276 if json == nil { 277 return nil, interfaces.NotFound 278 } else if _, r, _ := json.tx.RawSignatureValues(); r == nil { 279 return nil, fmt.Errorf("server returned transaction without signature") 280 } 281 if json.From != nil && json.BlockHash != nil { 282 setSenderFromServer(json.tx, *json.From, *json.BlockHash) 283 } 284 return json.tx, err 285 } 286 287 // TransactionReceipt returns the receipt of a transaction by transaction hash. 288 // Note that the receipt is not available for pending transactions. 289 func (ec *Client) TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) { 290 var r *types.Receipt 291 err := ec.c.CallContext(ctx, &r, "eth_getTransactionReceipt", txHash) 292 if err == nil { 293 if r == nil { 294 return nil, interfaces.NotFound 295 } 296 } 297 return r, err 298 } 299 300 // SubscribeNewAcceptedTransactions subscribes to notifications about the accepted transaction hashes on the given channel. 301 func (ec *Client) SubscribeNewAcceptedTransactions(ctx context.Context, ch chan<- *common.Hash) (interfaces.Subscription, error) { 302 return ec.c.EthSubscribe(ctx, ch, "newAcceptedTransactions") 303 } 304 305 // SubscribeNewAcceptedTransactions subscribes to notifications about the accepted transaction hashes on the given channel. 306 func (ec *Client) SubscribeNewPendingTransactions(ctx context.Context, ch chan<- *common.Hash) (interfaces.Subscription, error) { 307 return ec.c.EthSubscribe(ctx, ch, "newPendingTransactions") 308 } 309 310 // SubscribeNewHead subscribes to notifications about the current blockchain head 311 // on the given channel. 312 func (ec *Client) SubscribeNewHead(ctx context.Context, ch chan<- *types.Header) (interfaces.Subscription, error) { 313 return ec.c.EthSubscribe(ctx, ch, "newHeads") 314 } 315 316 // State Access 317 318 // NetworkID returns the network ID (also known as the chain ID) for this chain. 319 func (ec *Client) NetworkID(ctx context.Context) (*big.Int, error) { 320 version := new(big.Int) 321 var ver string 322 if err := ec.c.CallContext(ctx, &ver, "net_version"); err != nil { 323 return nil, err 324 } 325 if _, ok := version.SetString(ver, 10); !ok { 326 return nil, fmt.Errorf("invalid net_version result %q", ver) 327 } 328 return version, nil 329 } 330 331 // BalanceAt returns the wei balance of the given account. 332 // The block number can be nil, in which case the balance is taken from the latest known block. 333 func (ec *Client) BalanceAt(ctx context.Context, account common.Address, blockNumber *big.Int) (*big.Int, error) { 334 var result hexutil.Big 335 err := ec.c.CallContext(ctx, &result, "eth_getBalance", account, ToBlockNumArg(blockNumber)) 336 return (*big.Int)(&result), err 337 } 338 339 // AssetBalanceAt returns the [assetID] balance of the given account 340 // The block number can be nil, in which case the balance is taken from the latest known block. 341 func (ec *Client) AssetBalanceAt(ctx context.Context, account common.Address, assetID ids.ID, blockNumber *big.Int) (*big.Int, error) { 342 var result hexutil.Big 343 err := ec.c.CallContext(ctx, &result, "eth_getAssetBalance", account, ToBlockNumArg(blockNumber), assetID) 344 return (*big.Int)(&result), err 345 } 346 347 // StorageAt returns the value of key in the contract storage of the given account. 348 // The block number can be nil, in which case the value is taken from the latest known block. 349 func (ec *Client) StorageAt(ctx context.Context, account common.Address, key common.Hash, blockNumber *big.Int) ([]byte, error) { 350 var result hexutil.Bytes 351 err := ec.c.CallContext(ctx, &result, "eth_getStorageAt", account, key, ToBlockNumArg(blockNumber)) 352 return result, err 353 } 354 355 // CodeAt returns the contract code of the given account. 356 // The block number can be nil, in which case the code is taken from the latest known block. 357 func (ec *Client) CodeAt(ctx context.Context, account common.Address, blockNumber *big.Int) ([]byte, error) { 358 var result hexutil.Bytes 359 err := ec.c.CallContext(ctx, &result, "eth_getCode", account, ToBlockNumArg(blockNumber)) 360 return result, err 361 } 362 363 // NonceAt returns the account nonce of the given account. 364 // The block number can be nil, in which case the nonce is taken from the latest known block. 365 func (ec *Client) NonceAt(ctx context.Context, account common.Address, blockNumber *big.Int) (uint64, error) { 366 var result hexutil.Uint64 367 err := ec.c.CallContext(ctx, &result, "eth_getTransactionCount", account, ToBlockNumArg(blockNumber)) 368 return uint64(result), err 369 } 370 371 // Filters 372 373 // FilterLogs executes a filter query. 374 func (ec *Client) FilterLogs(ctx context.Context, q interfaces.FilterQuery) ([]types.Log, error) { 375 var result []types.Log 376 arg, err := toFilterArg(q) 377 if err != nil { 378 return nil, err 379 } 380 err = ec.c.CallContext(ctx, &result, "eth_getLogs", arg) 381 return result, err 382 } 383 384 // SubscribeFilterLogs subscribes to the results of a streaming filter query. 385 func (ec *Client) SubscribeFilterLogs(ctx context.Context, q interfaces.FilterQuery, ch chan<- types.Log) (interfaces.Subscription, error) { 386 arg, err := toFilterArg(q) 387 if err != nil { 388 return nil, err 389 } 390 return ec.c.EthSubscribe(ctx, ch, "logs", arg) 391 } 392 393 func toFilterArg(q interfaces.FilterQuery) (interface{}, error) { 394 arg := map[string]interface{}{ 395 "address": q.Addresses, 396 "topics": q.Topics, 397 } 398 if q.BlockHash != nil { 399 arg["blockHash"] = *q.BlockHash 400 if q.FromBlock != nil || q.ToBlock != nil { 401 return nil, fmt.Errorf("cannot specify both BlockHash and FromBlock/ToBlock") 402 } 403 } else { 404 if q.FromBlock == nil { 405 arg["fromBlock"] = "0x0" 406 } else { 407 arg["fromBlock"] = ToBlockNumArg(q.FromBlock) 408 } 409 arg["toBlock"] = ToBlockNumArg(q.ToBlock) 410 } 411 return arg, nil 412 } 413 414 // Contract Calling 415 416 // CallContract executes a message call transaction, which is directly executed in the VM 417 // of the node, but never mined into the blockchain. 418 // 419 // blockNumber selects the block height at which the call runs. It can be nil, in which 420 // case the code is taken from the latest known block. Note that state from very old 421 // blocks might not be available. 422 func (ec *Client) CallContract(ctx context.Context, msg interfaces.CallMsg, blockNumber *big.Int) ([]byte, error) { 423 var hex hexutil.Bytes 424 err := ec.c.CallContext(ctx, &hex, "eth_call", toCallArg(msg), ToBlockNumArg(blockNumber)) 425 if err != nil { 426 return nil, err 427 } 428 return hex, nil 429 } 430 431 // SuggestGasPrice retrieves the currently suggested gas price to allow a timely 432 // execution of a transaction. 433 func (ec *Client) SuggestGasPrice(ctx context.Context) (*big.Int, error) { 434 var hex hexutil.Big 435 if err := ec.c.CallContext(ctx, &hex, "eth_gasPrice"); err != nil { 436 return nil, err 437 } 438 return (*big.Int)(&hex), nil 439 } 440 441 // SuggestGasTipCap retrieves the currently suggested gas tip cap after 1559 to 442 // allow a timely execution of a transaction. 443 func (ec *Client) SuggestGasTipCap(ctx context.Context) (*big.Int, error) { 444 var hex hexutil.Big 445 if err := ec.c.CallContext(ctx, &hex, "eth_maxPriorityFeePerGas"); err != nil { 446 return nil, err 447 } 448 return (*big.Int)(&hex), nil 449 } 450 451 // EstimateGas tries to estimate the gas needed to execute a specific transaction based on 452 // the current pending state of the backend blockchain. There is no guarantee that this is 453 // the true gas limit requirement as other transactions may be added or removed by miners, 454 // but it should provide a basis for setting a reasonable default. 455 func (ec *Client) EstimateGas(ctx context.Context, msg interfaces.CallMsg) (uint64, error) { 456 var hex hexutil.Uint64 457 err := ec.c.CallContext(ctx, &hex, "eth_estimateGas", toCallArg(msg)) 458 if err != nil { 459 return 0, err 460 } 461 return uint64(hex), nil 462 } 463 464 // EstimateBaseFee tries to estimate the base fee for the next block if it were created 465 // immediately. There is no guarantee that this will be the base fee used in the next block 466 // or that the next base fee will be higher or lower than the returned value. 467 func (ec *Client) EstimateBaseFee(ctx context.Context) (*big.Int, error) { 468 var hex hexutil.Big 469 err := ec.c.CallContext(ctx, &hex, "eth_baseFee") 470 if err != nil { 471 return nil, err 472 } 473 return (*big.Int)(&hex), nil 474 } 475 476 // SendTransaction injects a signed transaction into the pending pool for execution. 477 // 478 // If the transaction was a contract creation use the TransactionReceipt method to get the 479 // contract address after the transaction has been mined. 480 func (ec *Client) SendTransaction(ctx context.Context, tx *types.Transaction) error { 481 data, err := tx.MarshalBinary() 482 if err != nil { 483 return err 484 } 485 return ec.c.CallContext(ctx, nil, "eth_sendRawTransaction", hexutil.Encode(data)) 486 } 487 488 func ToBlockNumArg(number *big.Int) string { 489 // The Ethereum implementation uses a different mapping from 490 // negative numbers to special strings (latest, pending) then is 491 // used on its server side. See rpc/types.go for the comparison. 492 // In Coreth, latest, pending, and accepted are all treated the same 493 // therefore, if [number] is nil or a negative number in [-3, -1] 494 // we want the latest accepted block 495 if number == nil { 496 return "latest" 497 } 498 low := big.NewInt(-3) 499 high := big.NewInt(-1) 500 if number.Cmp(low) >= 0 && number.Cmp(high) <= 0 { 501 return "latest" 502 } 503 return hexutil.EncodeBig(number) 504 } 505 506 func toCallArg(msg interfaces.CallMsg) interface{} { 507 arg := map[string]interface{}{ 508 "from": msg.From, 509 "to": msg.To, 510 } 511 if len(msg.Data) > 0 { 512 arg["data"] = hexutil.Bytes(msg.Data) 513 } 514 if msg.Value != nil { 515 arg["value"] = (*hexutil.Big)(msg.Value) 516 } 517 if msg.Gas != 0 { 518 arg["gas"] = hexutil.Uint64(msg.Gas) 519 } 520 if msg.GasPrice != nil { 521 arg["gasPrice"] = (*hexutil.Big)(msg.GasPrice) 522 } 523 return arg 524 }