Skip to content

Commit

Permalink
Merge branch 'fdc-testing' into 'main'
Browse files Browse the repository at this point in the history
Support for Ethereum and Avalanche based chains

See merge request flarenetwork/flare-system-c-chain-indexer!49
  • Loading branch information
tilenflare committed Aug 22, 2024
2 parents e960399 + e37bcdf commit bdf5c85
Show file tree
Hide file tree
Showing 15 changed files with 416 additions and 88 deletions.
2 changes: 1 addition & 1 deletion .gitlab-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ variables:
GOPATH: /go
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: flare_ftso_indexer_test
GOLANG_VERSION: "1.21.11"
GOLANG_VERSION: "1.21.12"
GOLINT_VERSION: "v1.59.1"

.gocache:
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ console = true
[chain]
node_url = "http://127.0.0.1:8545/" # or NODE_URL environment variable
# api_key = ... or NODE_API_KEY environment variable
# chain_type = 1 # default Avalanche based chain=1, Ethereum based chain=2

[timeout]
backoff_max_elapsed_time_seconds = 300 # optional, defaults to 300s = 5 minutes. Affects how long the indexer will keep retrying in case of a complete outage of the node provider. Set to 0 to retry indefinitely.
Expand Down
5 changes: 2 additions & 3 deletions benchmarks/songbird_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,12 @@ package benchmarks

import (
"context"
"flare-ftso-indexer/chain"
"flare-ftso-indexer/config"
"flare-ftso-indexer/database"
"flare-ftso-indexer/indexer"
"flare-ftso-indexer/logger"
"testing"

"github.com/ava-labs/coreth/ethclient"
)

func BenchmarkBlockRequests(b *testing.B) {
Expand All @@ -31,7 +30,7 @@ func BenchmarkBlockRequests(b *testing.B) {
logger.Fatal("Database connect and initialize error: %s", err)
}

ethClient, err := ethclient.Dial(cfg.Chain.NodeURL)
ethClient, err := chain.DialRPCNode(cfg)
if err != nil {
logger.Fatal("Eth client error: %s", err)
}
Expand Down
333 changes: 333 additions & 0 deletions chain/chain.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,333 @@
package chain

import (
"context"
"errors"
"flare-ftso-indexer/config"
"fmt"
"math/big"

avxClient "github.com/ava-labs/coreth/ethclient"
"github.com/ava-labs/coreth/interfaces"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common"
ethClient "github.com/ethereum/go-ethereum/ethclient"

avxTypes "github.com/ava-labs/coreth/core/types"
ethTypes "github.com/ethereum/go-ethereum/core/types"
)

type ChainType int

const (
ChainTypeAvax ChainType = iota + 1 // Add 1 to skip 0 - avoids the zero value defaulting to Avax
ChainTypeEth
)

type Client struct {
chain ChainType
eth *ethClient.Client
avx avxClient.Client
}

type Block struct {
chain ChainType
eth *ethTypes.Block
avx *avxTypes.Block
}

type Header struct {
chain ChainType
eth *ethTypes.Header
avx *avxTypes.Header
}

type Receipt struct {
chain ChainType
eth *ethTypes.Receipt
avx *avxTypes.Receipt
}

type Transaction struct {
chain ChainType
eth *ethTypes.Transaction
avx *avxTypes.Transaction
}

func DialRPCNode(cfg *config.Config) (*Client, error) {
nodeURL, err := cfg.Chain.FullNodeURL()
if err != nil {
return nil, err
}
c := &Client{chain: ChainType(cfg.Chain.ChainType)}
switch c.chain {
case ChainTypeAvax:
c.avx, err = avxClient.Dial(nodeURL.String())
case ChainTypeEth:
c.eth, err = ethClient.Dial(nodeURL.String())
default:
return nil, errors.New("invalid chain")
}

return c, err
}

func (c *Client) BlockByNumber(ctx context.Context, number *big.Int) (*Block, error) {
block := &Block{chain: c.chain}
var err error
switch c.chain {
case ChainTypeAvax:
block.avx, err = c.avx.BlockByNumber(ctx, number)
case ChainTypeEth:
block.eth, err = c.eth.BlockByNumber(ctx, number)
default:
return nil, errors.New("invalid chain")
}

return block, err
}

func (c *Client) HeaderByNumber(ctx context.Context, number *big.Int) (*Header, error) {
block := &Header{chain: c.chain}
var err error
switch c.chain {
case ChainTypeAvax:
block.avx, err = c.avx.HeaderByNumber(ctx, number)
case ChainTypeEth:
block.eth, err = c.eth.HeaderByNumber(ctx, number)
default:
return nil, errors.New("invalid chain")
}

return block, err
}

func (c *Client) TransactionReceipt(ctx context.Context, txHash common.Hash) (*Receipt, error) {
receipt := &Receipt{chain: c.chain}
var err error
switch c.chain {
case ChainTypeAvax:
receipt.avx, err = c.avx.TransactionReceipt(ctx, txHash)
case ChainTypeEth:
receipt.eth, err = c.eth.TransactionReceipt(ctx, txHash)
default:
return nil, errors.New("invalid chain")
}

return receipt, err
}

func (c *Client) FilterLogs(ctx context.Context, q interfaces.FilterQuery) ([]avxTypes.Log, error) {
switch c.chain {
case ChainTypeAvax:
return c.avx.FilterLogs(ctx, q)
case ChainTypeEth:
ethLogs, err := c.eth.FilterLogs(ctx, ethereum.FilterQuery(q))
if err != nil {
return nil, err
}
logs := make([]avxTypes.Log, len(ethLogs))
for i, e := range ethLogs {
logs[i] = avxTypes.Log(e)
}
return logs, nil

default:
return nil, errors.New("invalid chain")
}
}

func (b *Header) Number() *big.Int {
switch b.chain {
case ChainTypeAvax:
return b.avx.Number
case ChainTypeEth:
return b.eth.Number
default:
return nil
}
}

func (b *Header) Time() uint64 {
switch b.chain {
case ChainTypeAvax:
return b.avx.Time
case ChainTypeEth:
return b.eth.Time
default:
return 0
}
}

func (b *Block) Number() *big.Int {
switch b.chain {
case ChainTypeAvax:
return b.avx.Number()
case ChainTypeEth:
return b.eth.Number()
default:
return nil
}
}

func (b *Block) Time() uint64 {
switch b.chain {
case ChainTypeAvax:
return b.avx.Time()
case ChainTypeEth:
return b.eth.Time()
default:
return 0
}
}

func (b *Block) Hash() common.Hash {
switch b.chain {
case ChainTypeAvax:
return b.avx.Hash()
case ChainTypeEth:
return b.eth.Hash()
default:
return common.Hash{}
}
}

func (r *Receipt) Status() uint64 {
switch r.chain {
case ChainTypeAvax:
return r.avx.Status
case ChainTypeEth:
return r.eth.Status
default:
return 0
}
}

func (r *Receipt) Logs() []*avxTypes.Log {
switch r.chain {
case ChainTypeAvax:
return r.avx.Logs
case ChainTypeEth:
logs := make([]*avxTypes.Log, len(r.eth.Logs))
for i, e := range r.eth.Logs {
log := avxTypes.Log(*e)
logs[i] = &log
}
return logs
default:
return nil
}
}

func (b *Block) Transactions() []*Transaction {
switch b.chain {
case ChainTypeAvax:
txsAvx := b.avx.Transactions()
txs := make([]*Transaction, len(txsAvx))
for i, e := range txsAvx {
txs[i] = &Transaction{}
txs[i].chain = b.chain
txs[i].avx = e
}
return txs
case ChainTypeEth:
txsEth := b.eth.Transactions()
txs := make([]*Transaction, len(txsEth))
for i, e := range txsEth {
txs[i] = &Transaction{}
txs[i].chain = b.chain
txs[i].eth = e
}
return txs
default:
return nil
}
}

func (t *Transaction) Hash() common.Hash {
switch t.chain {
case ChainTypeAvax:
return t.avx.Hash()
case ChainTypeEth:
return t.eth.Hash()
default:
return common.Hash{}
}
}

func (t *Transaction) To() *common.Address {
switch t.chain {
case ChainTypeAvax:
return t.avx.To()
case ChainTypeEth:
return t.eth.To()
default:
return nil
}
}

func (t *Transaction) Data() []byte {
switch t.chain {
case ChainTypeAvax:
return t.avx.Data()
case ChainTypeEth:
return t.eth.Data()
default:
return nil
}
}

func (t *Transaction) ChainId() *big.Int {
switch t.chain {
case ChainTypeAvax:
return t.avx.ChainId()
case ChainTypeEth:
return t.eth.ChainId()
default:
return nil
}
}

func (t *Transaction) Value() *big.Int {
switch t.chain {
case ChainTypeAvax:
return t.avx.Value()
case ChainTypeEth:
return t.eth.Value()
default:
return nil
}
}

func (t *Transaction) GasPrice() *big.Int {
switch t.chain {
case ChainTypeAvax:
return t.avx.GasPrice()
case ChainTypeEth:
return t.eth.GasPrice()
default:
return nil
}
}

func (t *Transaction) Gas() uint64 {
switch t.chain {
case ChainTypeAvax:
return t.avx.Gas()
case ChainTypeEth:
return t.eth.Gas()
default:
return 0
}
}

func (t *Transaction) FromAddress() (common.Address, error) {
switch t.chain {
case ChainTypeAvax:
return avxTypes.Sender(avxTypes.LatestSignerForChainID(t.avx.ChainId()), t.avx)
case ChainTypeEth:
return ethTypes.Sender(ethTypes.LatestSignerForChainID(t.eth.ChainId()), t.eth)
default:
return common.Address{}, fmt.Errorf("wrong chain")
}
}
Loading

0 comments on commit bdf5c85

Please sign in to comment.