Skip to content

Commit

Permalink
skip Goerli unknown tx type and Mumbai empty block
Browse files Browse the repository at this point in the history
  • Loading branch information
ws4charlie committed Jan 19, 2024
1 parent c85ec11 commit ad42b52
Show file tree
Hide file tree
Showing 4 changed files with 452 additions and 55 deletions.
137 changes: 137 additions & 0 deletions zetaclient/ethrpc/ethrpc.go
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)
}
40 changes: 40 additions & 0 deletions zetaclient/ethrpc/helper.go
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")
}
157 changes: 157 additions & 0 deletions zetaclient/ethrpc/types.go
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))
}
Loading

0 comments on commit ad42b52

Please sign in to comment.