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

Introduce custom Ethereum client interface #55

Merged
merged 1 commit into from
Nov 10, 2020
Merged
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
6 changes: 3 additions & 3 deletions pkg/chain/ethereum/blockcounter/blockcounter.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ package blockcounter
import (
"context"
"fmt"
"github.com/ethereum/go-ethereum"
"strconv"
"sync"
"time"

"github.com/ipfs/go-log"

"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethclient"
)

var logger = log.Logger("keep-block-counter")
Expand Down Expand Up @@ -155,7 +155,7 @@ func (ebc *EthereumBlockCounter) receiveBlocks() {
}

// subscribeBlocks creates a subscription to Geth to get each block.
func (ebc *EthereumBlockCounter) subscribeBlocks(ctx context.Context, client *ethclient.Client) error {
func (ebc *EthereumBlockCounter) subscribeBlocks(ctx context.Context, client ethereum.ChainReader) error {
errorChan := make(chan error)
newBlockChan := make(chan *types.Header)

Expand Down Expand Up @@ -213,7 +213,7 @@ func (ebc *EthereumBlockCounter) subscribeBlocks(ctx context.Context, client *et
return nil
}

func CreateBlockCounter(client *ethclient.Client) (*EthereumBlockCounter, error) {
func CreateBlockCounter(client ethereum.ChainReader) (*EthereumBlockCounter, error) {
ctx := context.Background()

startupBlock, err := client.BlockByNumber(
Expand Down
23 changes: 16 additions & 7 deletions pkg/chain/ethereum/ethutil/ethutil.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,15 @@ import (

var logger = log.Logger("keep-ethutil")

// EthereumClient wraps the core `bind.ContractBackend` interface with
// some other interfaces allowing to expose additional methods provided
// by client implementations.
type EthereumClient interface {
bind.ContractBackend
ethereum.ChainReader
ethereum.TransactionReader
pdyraga marked this conversation as resolved.
Show resolved Hide resolved
}

// AddressFromHex converts the passed string to a common.Address and returns it,
// unless it is not a valid address, in which case it returns an error. Compare
// to common.HexToAddress, which assumes the address is valid and does not
Expand Down Expand Up @@ -170,13 +179,13 @@ func EstimateGas(
}

type loggingWrapper struct {
bind.ContractBackend
EthereumClient

logger log.EventLogger
}

func (lw *loggingWrapper) SuggestGasPrice(ctx context.Context) (*big.Int, error) {
price, err := lw.ContractBackend.SuggestGasPrice(ctx)
price, err := lw.EthereumClient.SuggestGasPrice(ctx)

if err != nil {
lw.logger.Debugf("error requesting gas price suggestion: [%v]", err)
Expand All @@ -188,7 +197,7 @@ func (lw *loggingWrapper) SuggestGasPrice(ctx context.Context) (*big.Int, error)
}

func (lw *loggingWrapper) EstimateGas(ctx context.Context, msg ethereum.CallMsg) (uint64, error) {
gas, err := lw.ContractBackend.EstimateGas(ctx, msg)
gas, err := lw.EthereumClient.EstimateGas(ctx, msg)

if err != nil {
return 0, err
Expand All @@ -198,9 +207,9 @@ func (lw *loggingWrapper) EstimateGas(ctx context.Context, msg ethereum.CallMsg)
return gas, nil
}

// WrapCallLogging wraps certain call-related methods on the given `backend`
// WrapCallLogging wraps certain call-related methods on the given `client`
// with debug logging sent to the given `logger`. Actual functionality is
// delegated to the passed backend.
func WrapCallLogging(logger log.EventLogger, backend bind.ContractBackend) bind.ContractBackend {
return &loggingWrapper{backend, logger}
// delegated to the passed client.
func WrapCallLogging(logger log.EventLogger, client EthereumClient) EthereumClient {
return &loggingWrapper{client, logger}
}
145 changes: 131 additions & 14 deletions pkg/chain/ethereum/ethutil/rate_limiter.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"context"
"fmt"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"golang.org/x/sync/semaphore"
Expand All @@ -14,7 +13,7 @@ import (
)

type rateLimiter struct {
bind.ContractBackend
EthereumClient

limiter *rate.Limiter
semaphore *semaphore.Weighted
Expand Down Expand Up @@ -43,10 +42,10 @@ type RateLimiterConfig struct {
// All types of requests to the contract are rate-limited,
// including view function calls.
func WrapRateLimiting(
backend bind.ContractBackend,
client EthereumClient,
config *RateLimiterConfig,
) bind.ContractBackend {
rateLimiter := &rateLimiter{ContractBackend: backend}
) EthereumClient {
rateLimiter := &rateLimiter{EthereumClient: client}

if config.RequestsPerSecondLimit > 0 {
rateLimiter.limiter = rate.NewLimiter(
Expand Down Expand Up @@ -111,7 +110,7 @@ func (rl *rateLimiter) CodeAt(
}
defer rl.releasePermit()

return rl.ContractBackend.CodeAt(ctx, contract, blockNumber)
return rl.EthereumClient.CodeAt(ctx, contract, blockNumber)
}

func (rl *rateLimiter) CallContract(
Expand All @@ -125,7 +124,7 @@ func (rl *rateLimiter) CallContract(
}
defer rl.releasePermit()

return rl.ContractBackend.CallContract(ctx, call, blockNumber)
return rl.EthereumClient.CallContract(ctx, call, blockNumber)
}

func (rl *rateLimiter) PendingCodeAt(
Expand All @@ -138,7 +137,7 @@ func (rl *rateLimiter) PendingCodeAt(
}
defer rl.releasePermit()

return rl.ContractBackend.PendingCodeAt(ctx, account)
return rl.EthereumClient.PendingCodeAt(ctx, account)
}

func (rl *rateLimiter) PendingNonceAt(
Expand All @@ -151,7 +150,7 @@ func (rl *rateLimiter) PendingNonceAt(
}
defer rl.releasePermit()

return rl.ContractBackend.PendingNonceAt(ctx, account)
return rl.EthereumClient.PendingNonceAt(ctx, account)
}

func (rl *rateLimiter) SuggestGasPrice(
Expand All @@ -163,7 +162,7 @@ func (rl *rateLimiter) SuggestGasPrice(
}
defer rl.releasePermit()

return rl.ContractBackend.SuggestGasPrice(ctx)
return rl.EthereumClient.SuggestGasPrice(ctx)
}

func (rl *rateLimiter) EstimateGas(
Expand All @@ -176,7 +175,7 @@ func (rl *rateLimiter) EstimateGas(
}
defer rl.releasePermit()

return rl.ContractBackend.EstimateGas(ctx, call)
return rl.EthereumClient.EstimateGas(ctx, call)
}

func (rl *rateLimiter) SendTransaction(
Expand All @@ -189,7 +188,7 @@ func (rl *rateLimiter) SendTransaction(
}
defer rl.releasePermit()

return rl.ContractBackend.SendTransaction(ctx, tx)
return rl.EthereumClient.SendTransaction(ctx, tx)
}

func (rl *rateLimiter) FilterLogs(
Expand All @@ -202,7 +201,7 @@ func (rl *rateLimiter) FilterLogs(
}
defer rl.releasePermit()

return rl.ContractBackend.FilterLogs(ctx, query)
return rl.EthereumClient.FilterLogs(ctx, query)
}

func (rl *rateLimiter) SubscribeFilterLogs(
Expand All @@ -216,5 +215,123 @@ func (rl *rateLimiter) SubscribeFilterLogs(
}
defer rl.releasePermit()

return rl.ContractBackend.SubscribeFilterLogs(ctx, query, ch)
return rl.EthereumClient.SubscribeFilterLogs(ctx, query, ch)
}

func (rl *rateLimiter) BlockByHash(
ctx context.Context,
hash common.Hash,
) (*types.Block, error) {
err := rl.acquirePermit()
if err != nil {
return nil, fmt.Errorf("cannot acquire rate limiter permit: [%v]", err)
}
defer rl.releasePermit()

return rl.EthereumClient.BlockByHash(ctx, hash)
}

func (rl *rateLimiter) BlockByNumber(
ctx context.Context,
number *big.Int,
) (*types.Block, error) {
err := rl.acquirePermit()
if err != nil {
return nil, fmt.Errorf("cannot acquire rate limiter permit: [%v]", err)
}
defer rl.releasePermit()

return rl.EthereumClient.BlockByNumber(ctx, number)
}

func (rl *rateLimiter) HeaderByHash(
ctx context.Context,
hash common.Hash,
) (*types.Header, error) {
err := rl.acquirePermit()
if err != nil {
return nil, fmt.Errorf("cannot acquire rate limiter permit: [%v]", err)
}
defer rl.releasePermit()

return rl.EthereumClient.HeaderByHash(ctx, hash)
}

func (rl *rateLimiter) HeaderByNumber(
ctx context.Context,
number *big.Int,
) (*types.Header, error) {
err := rl.acquirePermit()
if err != nil {
return nil, fmt.Errorf("cannot acquire rate limiter permit: [%v]", err)
}
defer rl.releasePermit()

return rl.EthereumClient.HeaderByNumber(ctx, number)
}

func (rl *rateLimiter) TransactionCount(
ctx context.Context,
blockHash common.Hash,
) (uint, error) {
err := rl.acquirePermit()
if err != nil {
return 0, fmt.Errorf("cannot acquire rate limiter permit: [%v]", err)
}
defer rl.releasePermit()

return rl.EthereumClient.TransactionCount(ctx, blockHash)
}

func (rl *rateLimiter) TransactionInBlock(
ctx context.Context,
blockHash common.Hash,
index uint,
) (*types.Transaction, error) {
err := rl.acquirePermit()
if err != nil {
return nil, fmt.Errorf("cannot acquire rate limiter permit: [%v]", err)
}
defer rl.releasePermit()

return rl.EthereumClient.TransactionInBlock(ctx, blockHash, index)
}

func (rl *rateLimiter) SubscribeNewHead(
ctx context.Context,
ch chan<- *types.Header,
) (ethereum.Subscription, error) {
err := rl.acquirePermit()
if err != nil {
return nil, fmt.Errorf("cannot acquire rate limiter permit: [%v]", err)
}
defer rl.releasePermit()

return rl.EthereumClient.SubscribeNewHead(ctx, ch)
}

func (rl *rateLimiter) TransactionByHash(
ctx context.Context,
txHash common.Hash,
) (*types.Transaction, bool, error) {
err := rl.acquirePermit()
if err != nil {
return nil, false, fmt.Errorf("cannot acquire rate limiter permit: [%v]", err)
}
defer rl.releasePermit()

return rl.EthereumClient.TransactionByHash(ctx, txHash)
}

func (rl *rateLimiter) TransactionReceipt(
ctx context.Context,
txHash common.Hash,
) (*types.Receipt, error) {
err := rl.acquirePermit()
if err != nil {
return nil, fmt.Errorf("cannot acquire rate limiter permit: [%v]", err)
}
defer rl.releasePermit()

return rl.EthereumClient.TransactionReceipt(ctx, txHash)
}
Loading