-
Notifications
You must be signed in to change notification settings - Fork 108
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
skip Goerli unknown tx type and Mumbai empty block
- Loading branch information
1 parent
c85ec11
commit ad42b52
Showing
4 changed files
with
452 additions
and
55 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
package ethrpc | ||
|
||
import ( | ||
"bytes" | ||
"encoding/json" | ||
"fmt" | ||
"io" | ||
"net/http" | ||
) | ||
|
||
// EthError - ethereum error | ||
type EthError struct { | ||
Code int `json:"code"` | ||
Message string `json:"message"` | ||
} | ||
|
||
func (err EthError) Error() string { | ||
return fmt.Sprintf("Error %d (%s)", err.Code, err.Message) | ||
} | ||
|
||
type ethResponse struct { | ||
ID int `json:"id"` | ||
JSONRPC string `json:"jsonrpc"` | ||
Result json.RawMessage `json:"result"` | ||
Error *EthError `json:"error"` | ||
} | ||
|
||
type ethRequest struct { | ||
ID int `json:"id"` | ||
JSONRPC string `json:"jsonrpc"` | ||
Method string `json:"method"` | ||
Params []interface{} `json:"params"` | ||
} | ||
|
||
// EthRPC - Ethereum rpc client | ||
type EthRPC struct { | ||
url string | ||
client *http.Client | ||
} | ||
|
||
// New create new rpc client with given url | ||
func New(url string, options ...func(rpc *EthRPC)) *EthRPC { | ||
rpc := &EthRPC{ | ||
url: url, | ||
client: http.DefaultClient, | ||
} | ||
for _, option := range options { | ||
option(rpc) | ||
} | ||
|
||
return rpc | ||
} | ||
|
||
// NewEthRPC create new rpc client with given url | ||
func NewEthRPC(url string, options ...func(rpc *EthRPC)) *EthRPC { | ||
return New(url, options...) | ||
} | ||
|
||
// URL returns client url | ||
func (rpc *EthRPC) URL() string { | ||
return rpc.url | ||
} | ||
|
||
// Call returns raw response of method call | ||
func (rpc *EthRPC) Call(method string, params ...interface{}) (json.RawMessage, error) { | ||
request := ethRequest{ | ||
ID: 1, | ||
JSONRPC: "2.0", | ||
Method: method, | ||
Params: params, | ||
} | ||
|
||
body, err := json.Marshal(request) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
response, err := rpc.client.Post(rpc.url, "application/json", bytes.NewBuffer(body)) | ||
if response != nil { | ||
defer response.Body.Close() | ||
} | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
data, err := io.ReadAll(response.Body) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
resp := new(ethResponse) | ||
if err := json.Unmarshal(data, resp); err != nil { | ||
return nil, err | ||
} | ||
|
||
if resp.Error != nil { | ||
return nil, *resp.Error | ||
} | ||
|
||
return resp.Result, nil | ||
|
||
} | ||
|
||
// RawCall returns raw response of method call (Deprecated) | ||
func (rpc *EthRPC) RawCall(method string, params ...interface{}) (json.RawMessage, error) { | ||
return rpc.Call(method, params...) | ||
} | ||
|
||
func (rpc *EthRPC) getBlock(method string, withTransactions bool, params ...interface{}) (*Block, error) { | ||
result, err := rpc.RawCall(method, params...) | ||
if err != nil { | ||
return nil, err | ||
} | ||
if bytes.Equal(result, []byte("null")) { | ||
return nil, nil | ||
} | ||
|
||
var response proxyBlock | ||
if withTransactions { | ||
response = new(proxyBlockWithTransactions) | ||
} else { | ||
response = new(proxyBlockWithoutTransactions) | ||
} | ||
|
||
err = json.Unmarshal(result, response) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
block := response.toBlock() | ||
return &block, nil | ||
} | ||
|
||
// EthGetBlockByNumber returns information about a block by block number. | ||
func (rpc *EthRPC) EthGetBlockByNumber(number uint64, withTransactions bool) (*Block, error) { | ||
return rpc.getBlock("eth_getBlockByNumber", withTransactions, IntToHex(number), withTransactions) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
package ethrpc | ||
|
||
import ( | ||
"fmt" | ||
"math/big" | ||
"strconv" | ||
"strings" | ||
) | ||
|
||
// ParseInt parse hex string value to uint64 | ||
func ParseInt(value string) (uint64, error) { | ||
i, err := strconv.ParseUint(strings.TrimPrefix(value, "0x"), 16, 64) | ||
if err != nil { | ||
return 0, err | ||
} | ||
|
||
return i, nil | ||
} | ||
|
||
// ParseBigInt parse hex string value to big.Int | ||
func ParseBigInt(value string) (big.Int, error) { | ||
i := big.Int{} | ||
_, err := fmt.Sscan(value, &i) | ||
|
||
return i, err | ||
} | ||
|
||
// IntToHex convert int to hexadecimal representation | ||
func IntToHex(i uint64) string { | ||
return fmt.Sprintf("0x%x", i) | ||
} | ||
|
||
// BigToHex covert big.Int to hexadecimal representation | ||
func BigToHex(bigInt big.Int) string { | ||
if bigInt.BitLen() == 0 { | ||
return "0x0" | ||
} | ||
|
||
return "0x" + strings.TrimPrefix(fmt.Sprintf("%x", bigInt.Bytes()), "0") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,157 @@ | ||
package ethrpc | ||
|
||
import ( | ||
"bytes" | ||
"math/big" | ||
"unsafe" | ||
) | ||
|
||
// Transaction - transaction object | ||
type Transaction struct { | ||
Hash string | ||
Nonce int | ||
BlockHash string | ||
BlockNumber *int | ||
TransactionIndex *int | ||
From string | ||
To string | ||
Value big.Int | ||
Gas int | ||
GasPrice big.Int | ||
Input string | ||
} | ||
|
||
// Block - block object | ||
type Block struct { | ||
Number uint64 | ||
Hash string | ||
ParentHash string | ||
Nonce string | ||
Sha3Uncles string | ||
LogsBloom string | ||
TransactionsRoot string | ||
StateRoot string | ||
Miner string | ||
Difficulty big.Int | ||
TotalDifficulty big.Int | ||
ExtraData string | ||
Size int | ||
GasLimit int | ||
GasUsed int | ||
Timestamp int | ||
Uncles []string | ||
Transactions []Transaction | ||
} | ||
|
||
type hexInt uint64 | ||
|
||
func (i *hexInt) UnmarshalJSON(data []byte) error { | ||
result, err := ParseInt(string(bytes.Trim(data, `"`))) | ||
*i = hexInt(result) | ||
|
||
return err | ||
} | ||
|
||
type hexBig big.Int | ||
|
||
func (i *hexBig) UnmarshalJSON(data []byte) error { | ||
result, err := ParseBigInt(string(bytes.Trim(data, `"`))) | ||
*i = hexBig(result) | ||
|
||
return err | ||
} | ||
|
||
type proxyBlock interface { | ||
toBlock() Block | ||
} | ||
|
||
type proxyBlockWithTransactions struct { | ||
Number hexInt `json:"number"` | ||
Hash string `json:"hash"` | ||
ParentHash string `json:"parentHash"` | ||
Nonce string `json:"nonce"` | ||
Sha3Uncles string `json:"sha3Uncles"` | ||
LogsBloom string `json:"logsBloom"` | ||
TransactionsRoot string `json:"transactionsRoot"` | ||
StateRoot string `json:"stateRoot"` | ||
Miner string `json:"miner"` | ||
Difficulty hexBig `json:"difficulty"` | ||
TotalDifficulty hexBig `json:"totalDifficulty"` | ||
ExtraData string `json:"extraData"` | ||
Size hexInt `json:"size"` | ||
GasLimit hexInt `json:"gasLimit"` | ||
GasUsed hexInt `json:"gasUsed"` | ||
Timestamp hexInt `json:"timestamp"` | ||
Uncles []string `json:"uncles"` | ||
Transactions []proxyTransaction `json:"transactions"` | ||
} | ||
|
||
type proxyBlockWithoutTransactions struct { | ||
Number hexInt `json:"number"` | ||
Hash string `json:"hash"` | ||
ParentHash string `json:"parentHash"` | ||
Nonce string `json:"nonce"` | ||
Sha3Uncles string `json:"sha3Uncles"` | ||
LogsBloom string `json:"logsBloom"` | ||
TransactionsRoot string `json:"transactionsRoot"` | ||
StateRoot string `json:"stateRoot"` | ||
Miner string `json:"miner"` | ||
Difficulty hexBig `json:"difficulty"` | ||
TotalDifficulty hexBig `json:"totalDifficulty"` | ||
ExtraData string `json:"extraData"` | ||
Size hexInt `json:"size"` | ||
GasLimit hexInt `json:"gasLimit"` | ||
GasUsed hexInt `json:"gasUsed"` | ||
Timestamp hexInt `json:"timestamp"` | ||
Uncles []string `json:"uncles"` | ||
Transactions []string `json:"transactions"` | ||
} | ||
|
||
func (proxy *proxyBlockWithoutTransactions) toBlock() Block { | ||
block := Block{ | ||
Number: uint64(proxy.Number), | ||
Hash: proxy.Hash, | ||
ParentHash: proxy.ParentHash, | ||
Nonce: proxy.Nonce, | ||
Sha3Uncles: proxy.Sha3Uncles, | ||
LogsBloom: proxy.LogsBloom, | ||
TransactionsRoot: proxy.TransactionsRoot, | ||
StateRoot: proxy.StateRoot, | ||
Miner: proxy.Miner, | ||
Difficulty: big.Int(proxy.Difficulty), | ||
TotalDifficulty: big.Int(proxy.TotalDifficulty), | ||
ExtraData: proxy.ExtraData, | ||
Size: int(proxy.Size), | ||
GasLimit: int(proxy.GasLimit), | ||
GasUsed: int(proxy.GasUsed), | ||
Timestamp: int(proxy.Timestamp), | ||
Uncles: proxy.Uncles, | ||
} | ||
|
||
block.Transactions = make([]Transaction, len(proxy.Transactions)) | ||
for i := range proxy.Transactions { | ||
block.Transactions[i] = Transaction{ | ||
Hash: proxy.Transactions[i], | ||
} | ||
} | ||
|
||
return block | ||
} | ||
|
||
type proxyTransaction struct { | ||
Hash string `json:"hash"` | ||
Nonce hexInt `json:"nonce"` | ||
BlockHash string `json:"blockHash"` | ||
BlockNumber *hexInt `json:"blockNumber"` | ||
TransactionIndex *hexInt `json:"transactionIndex"` | ||
From string `json:"from"` | ||
To string `json:"to"` | ||
Value hexBig `json:"value"` | ||
Gas hexInt `json:"gas"` | ||
GasPrice hexBig `json:"gasPrice"` | ||
Input string `json:"input"` | ||
} | ||
|
||
func (proxy *proxyBlockWithTransactions) toBlock() Block { | ||
return *(*Block)(unsafe.Pointer(proxy)) | ||
} |
Oops, something went wrong.