Skip to content
This repository has been archived by the owner on Jul 13, 2022. It is now read-only.

1559 Txs #690

Merged
merged 10 commits into from
Aug 4, 2021
58 changes: 54 additions & 4 deletions connections/ethereum/connection.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ func (c *Connection) Connect() error {
if c.http {
rpcClient, err = rpc.DialHTTP(c.endpoint)
} else {
rpcClient, err = rpc.DialWebsocket(context.Background(), c.endpoint, "/ws")
rpcClient, err = rpc.DialContext(context.Background(), c.endpoint)
}
if err != nil {
return err
Expand Down Expand Up @@ -165,6 +165,38 @@ func (c *Connection) SafeEstimateGas(ctx context.Context) (*big.Int, error) {
}
}

func (c *Connection) EstimateGasLondon(ctx context.Context, baseFee *big.Int) (*big.Int, *big.Int, error) {
var maxPriorityFeePerGas *big.Int
var maxFeePerGas *big.Int

if c.maxGasPrice.Cmp(baseFee) < 0 {
P1sar marked this conversation as resolved.
Show resolved Hide resolved
maxPriorityFeePerGas = big.NewInt(1)
maxFeePerGas = new(big.Int).Add(baseFee, maxPriorityFeePerGas)
return maxPriorityFeePerGas, maxFeePerGas, nil
}

maxPriorityFeePerGas, err := c.conn.SuggestGasTipCap(context.TODO())
if err != nil {
return nil, nil, err
}

maxFeePerGas = new(big.Int).Add(
maxPriorityFeePerGas,
new(big.Int).Mul(baseFee, big.NewInt(2)),
P1sar marked this conversation as resolved.
Show resolved Hide resolved
)

if maxFeePerGas.Cmp(maxPriorityFeePerGas) < 0 {
return nil, nil, fmt.Errorf("maxFeePerGas (%v) < maxPriorityFeePerGas (%v)", maxFeePerGas, maxPriorityFeePerGas)
}

// Check we aren't exceeding our limit
if maxFeePerGas.Cmp(c.maxGasPrice) == 1 {
maxPriorityFeePerGas.Sub(c.maxGasPrice, baseFee)
maxFeePerGas = c.maxGasPrice
}
return maxPriorityFeePerGas, maxFeePerGas, nil
}

func multiplyGasPrice(gasEstimate *big.Int, gasMultiplier *big.Float) *big.Int {

gasEstimateFloat := new(big.Float).SetInt(gasEstimate)
Expand All @@ -183,12 +215,30 @@ func multiplyGasPrice(gasEstimate *big.Int, gasMultiplier *big.Float) *big.Int {
func (c *Connection) LockAndUpdateOpts() error {
c.optsLock.Lock()

gasPrice, err := c.SafeEstimateGas(context.TODO())
head, err := c.conn.HeaderByNumber(context.TODO(), nil)
if err != nil {
c.optsLock.Unlock()
c.UnlockOpts()
return err
}
c.opts.GasPrice = gasPrice

if head.BaseFee != nil {
c.opts.GasTipCap, c.opts.GasFeeCap, err = c.EstimateGasLondon(context.TODO(), head.BaseFee)
if err != nil {
c.UnlockOpts()
return err
}

// Both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) cannot be specified: https://github.com/ethereum/go-ethereum/blob/95bbd46eabc5d95d9fb2108ec232dd62df2f44ab/accounts/abi/bind/base.go#L254
c.opts.GasPrice = nil
} else {
var gasPrice *big.Int
gasPrice, err = c.SafeEstimateGas(context.TODO())
if err != nil {
c.UnlockOpts()
return err
}
c.opts.GasPrice = gasPrice
}

nonce, err := c.conn.PendingNonceAt(context.Background(), c.opts.From)
if err != nil {
Expand Down
100 changes: 100 additions & 0 deletions connections/ethereum/connection_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,3 +97,103 @@ func TestConnection_SafeEstimateGasMax(t *testing.T) {
t.Fatalf("Gas price should equal max. Suggested: %s Max: %s", price.String(), maxPrice.String())
}
}

func TestConnection_EstimateGasLondon(t *testing.T) {
// Set TestEndpoint to Goerli endpoint when testing as the current Github CI doesn't use the London version of geth
// Goerli commonly has a base fee of 7 gwei with maxPriorityFeePerGas of 4.999999993 gwei
maxGasPrice := big.NewInt(100000000000)
conn := NewConnection(TestEndpoint, false, AliceKp, log15.Root(), GasLimit, maxGasPrice, GasMultipler, "", "")
err := conn.Connect()
if err != nil {
t.Fatal(err)
}
defer conn.Close()

head, err := conn.conn.HeaderByNumber(context.Background(), nil)
if err != nil {
t.Fatal(err)
}

// This is here as the current dev network is an old version of geth and will keep the test failing on the CI
if head.BaseFee != nil {
_, suggestedGasFeeCap, err := conn.EstimateGasLondon(context.Background(), head.BaseFee)
if err != nil {
t.Fatal(err)
}

if suggestedGasFeeCap.Cmp(maxGasPrice) >= 0 {
t.Fatalf("Gas fee cap should be less than max gas price. Suggested: %s Max: %s", suggestedGasFeeCap.String(), maxGasPrice.String())
}
}
}

func TestConnection_EstimateGasLondonMax(t *testing.T) {
// Set TestEndpoint to Goerli endpoint when testing as the current Github CI doesn't use the London version of geth
// Goerli commonly has a base fee of 7 gwei with maxPriorityFeePerGas of 4.999999993 gwei
maxGasPrice := big.NewInt(100)
conn := NewConnection(TestEndpoint, false, AliceKp, log15.Root(), GasLimit, maxGasPrice, GasMultipler, "", "")
err := conn.Connect()
if err != nil {
t.Fatal(err)
}
defer conn.Close()

head, err := conn.conn.HeaderByNumber(context.Background(), nil)
if err != nil {
t.Fatal(err)
}

// This is here as the current dev network is an old version of geth and will keep the test failing on the CI
if head.BaseFee != nil {
suggestedGasTip, suggestedGasFeeCap, err := conn.EstimateGasLondon(context.Background(), head.BaseFee)
if err != nil {
t.Fatal(err)
}

maxPriorityFeePerGas := new(big.Int).Sub(maxGasPrice, head.BaseFee)
if suggestedGasTip.Cmp(maxPriorityFeePerGas) != 0 {
t.Fatalf("Gas tip cap should equal max - baseFee. Suggested: %s Max Tip: %s", suggestedGasTip.String(), maxPriorityFeePerGas.String())
}

if suggestedGasFeeCap.Cmp(maxGasPrice) != 0 {
t.Fatalf("Gas fee cap should equal max gas price. Suggested: %s Max: %s", suggestedGasFeeCap.String(), maxGasPrice.String())
}

}
}

func TestConnection_EstimateGasLondonMin(t *testing.T) {
// Set TestEndpoint to Goerli endpoint when testing as the current Github CI doesn't use the London version of geth
// Goerli commonly has a base fee of 7 gwei with maxPriorityFeePerGas of 4.999999993 gwei
maxGasPrice := big.NewInt(1)
conn := NewConnection(TestEndpoint, false, AliceKp, log15.Root(), GasLimit, maxGasPrice, GasMultipler, "", "")
err := conn.Connect()
if err != nil {
t.Fatal(err)
}
defer conn.Close()

head, err := conn.conn.HeaderByNumber(context.Background(), nil)
if err != nil {
t.Fatal(err)
}

// This is here as the current dev network is an old version of geth and will keep the test failing on the CI
if head.BaseFee != nil {
suggestedGasTip, suggestedGasFeeCap, err := conn.EstimateGasLondon(context.Background(), head.BaseFee)
if err != nil {
t.Fatal(err)
}

maxPriorityFeePerGas := big.NewInt(1)
maxFeePerGas := new(big.Int).Add(head.BaseFee, maxPriorityFeePerGas)

if suggestedGasTip.Cmp(maxPriorityFeePerGas) != 0 {
t.Fatalf("Gas tip cap should be equal to 1. Suggested: %s Max Tip: %s", suggestedGasTip.String(), maxPriorityFeePerGas)
}

if suggestedGasFeeCap.Cmp(maxFeePerGas) != 0 {
t.Fatalf("Gas fee cap should be 1 greater than the base fee. Suggested: %s Max: %s", suggestedGasFeeCap.String(), maxFeePerGas.String())
}
}
}
5 changes: 1 addition & 4 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,10 @@ require (
github.com/ChainSafe/chainbridge-substrate-events v0.0.0-20200715141113-87198532025e
github.com/ChainSafe/chainbridge-utils v1.0.6
github.com/ChainSafe/log15 v1.0.0
github.com/aristanetworks/goarista v0.0.0-20200609010056-95bcf8053598 // indirect
github.com/centrifuge/go-substrate-rpc-client v2.0.0+incompatible
github.com/deckarep/golang-set v1.7.1 // indirect
github.com/ethereum/go-ethereum v1.9.25
github.com/gorilla/websocket v1.4.2 // indirect
github.com/ethereum/go-ethereum v1.10.6
github.com/prometheus/client_golang v1.4.1
github.com/rs/cors v1.7.0 // indirect
github.com/stretchr/testify v1.7.0
github.com/urfave/cli/v2 v2.3.0
)
Loading