Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature Relayer #179

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions relayer/gaspricer/gaspricer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package gaspricer

import "context"

type GasPricer interface {
Start(ctx context.Context)
GasPrice() uint64
}
74 changes: 74 additions & 0 deletions relayer/gaspricer/network.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package gaspricer

import (
"context"
"log"
"os"
"sync"
"time"

"github.com/umbracle/ethgo/jsonrpc"
)

func NewNetworkGasPricer(logger *log.Logger, client *jsonrpc.Eth, interval ...time.Duration) (GasPricer, error) {
if logger == nil {
logger = log.New(os.Stdout, "", log.LstdFlags)
}
n := &NetworkGasPricer{
client: client,
logger: logger,
}
if len(interval) == 1 {
n.interval = interval[0]
} else {
n.interval = 15 * time.Second
}

// try to fetch the gas price once
if err := n.updateGasPrice(); err != nil {
return nil, err
}
return n, nil
}

type NetworkGasPricer struct {
logger *log.Logger
lock sync.Mutex
client *jsonrpc.Eth
interval time.Duration
gasPrice uint64
}

func (n *NetworkGasPricer) updateGasPrice() error {
n.lock.Lock()
defer n.lock.Unlock()

gasPrice, err := n.client.GasPrice()
if err != nil {
return err
}
n.gasPrice = gasPrice
return nil
}

func (n *NetworkGasPricer) Start(ctx context.Context) {
go func() {
for {
select {
case <-time.After(n.interval):
if err := n.updateGasPrice(); err != nil {
n.logger.Printf("[ERROR]: Failed to get gas price: %v", err)
}
case <-ctx.Done():
return
}
}
}()
}

func (n *NetworkGasPricer) GasPrice() uint64 {
n.lock.Lock()
defer n.lock.Unlock()

return n.gasPrice
}
22 changes: 22 additions & 0 deletions relayer/gaspricer/network_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package gaspricer

import (
"testing"

"github.com/stretchr/testify/assert"
"github.com/umbracle/ethgo/jsonrpc"
"github.com/umbracle/ethgo/testutil"
)

func TestGasPricer_Network(t *testing.T) {
srv := testutil.NewTestServer(t, nil)
defer srv.Close()

client, err := jsonrpc.NewClient(srv.HTTPAddr())
assert.NoError(t, err)

pricer, err := NewNetworkGasPricer(nil, client.Eth())
assert.NoError(t, err)

assert.Equal(t, pricer.GasPrice(), uint64(1))
}
116 changes: 116 additions & 0 deletions relayer/relayer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
package relayer

import (
"fmt"
"log"
"os"

"github.com/umbracle/ethgo"
"github.com/umbracle/ethgo/contract"
"github.com/umbracle/ethgo/jsonrpc"
"github.com/umbracle/ethgo/relayer/gaspricer"
)

var _ contract.Provider = (*Relayer)(nil)

type Config struct {
Logger *log.Logger
Endpoint string
GasPricer gaspricer.GasPricer
}

type RelayerOption func(*Config)

func WithGasPricer(pricer gaspricer.GasPricer) RelayerOption {
return func(c *Config) {
c.GasPricer = pricer
}
}

func WithJSONRPCEndpoint(endpoint string) RelayerOption {
return func(c *Config) {
c.Endpoint = endpoint
}
}

func WithLogger(logger *log.Logger) RelayerOption {
return func(c *Config) {
c.Logger = logger
}
}

func DefaultConfig() *Config {
return &Config{
Logger: log.New(os.Stdout, "", log.LstdFlags),
Endpoint: "http://localhost:8545",
}
}

type Relayer struct {
config *Config
client *jsonrpc.Client
closeCh chan struct{}
}

func NewRelayer(configOpts ...RelayerOption) (*Relayer, error) {
config := DefaultConfig()
for _, opts := range configOpts {
opts(config)
}

client, err := jsonrpc.NewClient(config.Endpoint)
if err != nil {
return nil, err
}

// if gas pricer is not set, use the network one
if config.GasPricer == nil {
pricer, err := gaspricer.NewNetworkGasPricer(config.Logger, client.Eth())
if err != nil {
return nil, err
}
config.GasPricer = pricer
}

r := &Relayer{
config: config,
client: client,
closeCh: make(chan struct{}),
}

go r.run()

return r, nil
}

type stateTxn struct {
To ethgo.Address
key ethgo.Key
input []byte
opts *contract.TxnOpts
}

func (r *Relayer) Txn(to ethgo.Address, key ethgo.Key, input []byte, opts *contract.TxnOpts) (contract.Txn, error) {
txn := &stateTxn{}
fmt.Println(txn)
return nil, nil
}

func (r *Relayer) SendTransaction(txn *ethgo.Transaction) (ethgo.Hash, error) {
return ethgo.Hash{}, nil
}

func (r *Relayer) run() {
for {
// wait to see if anything is stucked
// after it is done move to the next pending txn
select {
case <-r.closeCh:
return
}
}
}

func (r *Relayer) Call(to ethgo.Address, input []byte, opts *contract.CallOpts) ([]byte, error) {
panic("relayer does not make calls")
}
7 changes: 7 additions & 0 deletions relayer/relayer_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package relayer

import "testing"

func TestRelayer(t *testing.T) {

}