-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
AUTO-10213 & AUTO-10214 & AUTO-10236: compare current gas price with …
…user-defined max gas price in registry 2.1 pipeline (#12952) * AUTO-10213: pass an gas estimator to registry 2.1 pipeline * update tests and add changeset * update changeset * AUTO-10214: compare max gas price with current gas price in simulation process (#12955) * AUTO-10214: compare max gas price with current gas price in simulation process * refactor and add tests * linting (#12960) * linting * 2 * fix linting * create opts with latest block * AUTO-10236: add integration tests for max gas price check (#12974) * AUTO-10214: compare max gas price with current gas price in simulation process * refactor and add tests * linting (#12960) * linting * 2 * fix linting * AUTO-10236 * fix go mod * update test json * improve max gas price integration tests * AUTO-10214: compare max gas price with current gas price in simulation process * refactor and add tests * linting (#12960) * linting * 2 * fix linting * create opts with latest block * add some logs * fix bug and update logs * update * update * update logs * fix
- Loading branch information
1 parent
c671a5c
commit 7572a50
Showing
13 changed files
with
418 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
--- | ||
"chainlink": patch | ||
--- | ||
|
||
#added | ||
compare user-defined max gas price with current gas price in automation simulation pipeline |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
--- | ||
"chainlink": patch | ||
--- | ||
|
||
#added | ||
pass a gas estimator to registry 2.1 pipeline |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"chainlink": patch | ||
--- | ||
|
||
#added an integration test for max gas price check |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
70 changes: 70 additions & 0 deletions
70
core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/gasprice/gasprice.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
package gasprice | ||
|
||
import ( | ||
"context" | ||
"math/big" | ||
|
||
"github.com/smartcontractkit/chainlink/v2/core/cbor" | ||
"github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" | ||
"github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" | ||
"github.com/smartcontractkit/chainlink/v2/core/logger" | ||
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding" | ||
) | ||
|
||
const ( | ||
// feeLimit is a placeholder when getting current price from gas estimator. it does not impact gas price calculation | ||
feeLimit = uint64(1_000_000) | ||
// maxFeePrice is a placeholder when getting current price from gas estimator. it caps the returned gas price from | ||
// the estimator. it's set to a very high value because the gas price will be compared with user-defined gas price | ||
// later. | ||
maxFeePrice = 1_000_000_000_000_000 | ||
) | ||
|
||
type UpkeepOffchainConfig struct { | ||
MaxGasPrice *big.Int `json:"maxGasPrice" cbor:"maxGasPrice"` | ||
} | ||
|
||
// CheckGasPrice retrieves the current gas price and compare against the max gas price configured in upkeep's offchain config | ||
// any errors in offchain config decoding will result in max gas price check disabled | ||
func CheckGasPrice(ctx context.Context, upkeepId *big.Int, offchainConfigBytes []byte, ge gas.EvmFeeEstimator, lggr logger.Logger) encoding.UpkeepFailureReason { | ||
if len(offchainConfigBytes) == 0 { | ||
return encoding.UpkeepFailureReasonNone | ||
} | ||
|
||
var offchainConfig UpkeepOffchainConfig | ||
if err := cbor.ParseDietCBORToStruct(offchainConfigBytes, &offchainConfig); err != nil { | ||
lggr.Errorw("failed to parse upkeep offchain config, gas price check is disabled", "upkeepId", upkeepId.String(), "err", err) | ||
return encoding.UpkeepFailureReasonNone | ||
} | ||
if offchainConfig.MaxGasPrice == nil || offchainConfig.MaxGasPrice.Int64() <= 0 { | ||
lggr.Warnw("maxGasPrice is not configured or incorrectly configured in upkeep offchain config, gas price check is disabled", "upkeepId", upkeepId.String()) | ||
return encoding.UpkeepFailureReasonNone | ||
} | ||
lggr.Debugf("successfully decode offchain config for %s, max gas price is %s", upkeepId.String(), offchainConfig.MaxGasPrice.String()) | ||
|
||
fee, _, err := ge.GetFee(ctx, []byte{}, feeLimit, assets.NewWei(big.NewInt(maxFeePrice))) | ||
if err != nil { | ||
lggr.Errorw("failed to get fee, gas price check is disabled", "upkeepId", upkeepId.String(), "err", err) | ||
return encoding.UpkeepFailureReasonNone | ||
} | ||
|
||
if fee.ValidDynamic() { | ||
lggr.Debugf("current gas price EIP-1559 is fee cap %s, tip cap %s", fee.DynamicFeeCap.String(), fee.DynamicTipCap.String()) | ||
if fee.DynamicFeeCap.Cmp(assets.NewWei(offchainConfig.MaxGasPrice)) > 0 { | ||
// current gas price is higher than max gas price | ||
lggr.Warnf("maxGasPrice %s for %s is LOWER than current gas price %d", offchainConfig.MaxGasPrice.String(), upkeepId.String(), fee.DynamicFeeCap.Int64()) | ||
return encoding.UpkeepFailureReasonGasPriceTooHigh | ||
} | ||
lggr.Debugf("maxGasPrice %s for %s is HIGHER than current gas price %d", offchainConfig.MaxGasPrice.String(), upkeepId.String(), fee.DynamicFeeCap.Int64()) | ||
} else { | ||
lggr.Debugf("current gas price legacy is %s", fee.Legacy.String()) | ||
if fee.Legacy.Cmp(assets.NewWei(offchainConfig.MaxGasPrice)) > 0 { | ||
// current gas price is higher than max gas price | ||
lggr.Warnf("maxGasPrice %s for %s is LOWER than current gas price %d", offchainConfig.MaxGasPrice.String(), upkeepId.String(), fee.Legacy.Int64()) | ||
return encoding.UpkeepFailureReasonGasPriceTooHigh | ||
} | ||
lggr.Debugf("maxGasPrice %s for %s is HIGHER than current gas price %d", offchainConfig.MaxGasPrice.String(), upkeepId.String(), fee.Legacy.Int64()) | ||
} | ||
|
||
return encoding.UpkeepFailureReasonNone | ||
} |
128 changes: 128 additions & 0 deletions
128
core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/gasprice/gasprice_test.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
package gasprice | ||
|
||
import ( | ||
"math/big" | ||
"testing" | ||
|
||
"github.com/fxamacker/cbor/v2" | ||
"github.com/pkg/errors" | ||
"github.com/stretchr/testify/assert" | ||
"github.com/stretchr/testify/mock" | ||
|
||
"github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" | ||
"github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" | ||
gasMocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas/mocks" | ||
"github.com/smartcontractkit/chainlink/v2/core/internal/testutils" | ||
"github.com/smartcontractkit/chainlink/v2/core/logger" | ||
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding" | ||
) | ||
|
||
type WrongOffchainConfig struct { | ||
MaxGasPrice1 []int `json:"maxGasPrice1" cbor:"maxGasPrice1"` | ||
} | ||
|
||
func TestGasPrice_Check(t *testing.T) { | ||
lggr := logger.TestLogger(t) | ||
uid, _ := new(big.Int).SetString("1843548457736589226156809205796175506139185429616502850435279853710366065936", 10) | ||
|
||
tests := []struct { | ||
Name string | ||
MaxGasPrice *big.Int | ||
CurrentLegacyGasPrice *big.Int | ||
CurrentDynamicGasPrice *big.Int | ||
ExpectedResult encoding.UpkeepFailureReason | ||
FailedToGetFee bool | ||
NotConfigured bool | ||
ParsingFailed bool | ||
}{ | ||
{ | ||
Name: "no offchain config", | ||
ExpectedResult: encoding.UpkeepFailureReasonNone, | ||
}, | ||
{ | ||
Name: "maxGasPrice not configured in offchain config", | ||
NotConfigured: true, | ||
ExpectedResult: encoding.UpkeepFailureReasonNone, | ||
}, | ||
{ | ||
Name: "fail to parse offchain config", | ||
ParsingFailed: true, | ||
MaxGasPrice: big.NewInt(10_000_000_000), | ||
ExpectedResult: encoding.UpkeepFailureReasonNone, | ||
}, | ||
{ | ||
Name: "fail to retrieve current gas price", | ||
MaxGasPrice: big.NewInt(8_000_000_000), | ||
FailedToGetFee: true, | ||
ExpectedResult: encoding.UpkeepFailureReasonNone, | ||
}, | ||
{ | ||
Name: "current gas price is too high - legacy", | ||
MaxGasPrice: big.NewInt(10_000_000_000), | ||
CurrentLegacyGasPrice: big.NewInt(18_000_000_000), | ||
ExpectedResult: encoding.UpkeepFailureReasonGasPriceTooHigh, | ||
}, | ||
{ | ||
Name: "current gas price is too high - dynamic", | ||
MaxGasPrice: big.NewInt(10_000_000_000), | ||
CurrentDynamicGasPrice: big.NewInt(15_000_000_000), | ||
ExpectedResult: encoding.UpkeepFailureReasonGasPriceTooHigh, | ||
}, | ||
{ | ||
Name: "current gas price is less than user's max gas price - legacy", | ||
MaxGasPrice: big.NewInt(8_000_000_000), | ||
CurrentLegacyGasPrice: big.NewInt(5_000_000_000), | ||
ExpectedResult: encoding.UpkeepFailureReasonNone, | ||
}, | ||
{ | ||
Name: "current gas price is less than user's max gas price - dynamic", | ||
MaxGasPrice: big.NewInt(10_000_000_000), | ||
CurrentDynamicGasPrice: big.NewInt(8_000_000_000), | ||
ExpectedResult: encoding.UpkeepFailureReasonNone, | ||
}, | ||
} | ||
for _, test := range tests { | ||
t.Run(test.Name, func(t *testing.T) { | ||
ctx := testutils.Context(t) | ||
ge := gasMocks.NewEvmFeeEstimator(t) | ||
if test.FailedToGetFee { | ||
ge.On("GetFee", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return( | ||
gas.EvmFee{}, | ||
feeLimit, | ||
errors.New("failed to retrieve gas price"), | ||
) | ||
} else if test.CurrentLegacyGasPrice != nil { | ||
ge.On("GetFee", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return( | ||
gas.EvmFee{ | ||
Legacy: assets.NewWei(test.CurrentLegacyGasPrice), | ||
}, | ||
feeLimit, | ||
nil, | ||
) | ||
} else if test.CurrentDynamicGasPrice != nil { | ||
ge.On("GetFee", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return( | ||
gas.EvmFee{ | ||
DynamicFeeCap: assets.NewWei(test.CurrentDynamicGasPrice), | ||
DynamicTipCap: assets.NewWei(big.NewInt(1_000_000_000)), | ||
}, | ||
feeLimit, | ||
nil, | ||
) | ||
} | ||
|
||
var oc []byte | ||
if test.ParsingFailed { | ||
oc, _ = cbor.Marshal(WrongOffchainConfig{MaxGasPrice1: []int{1, 2, 3}}) | ||
if len(oc) > 0 { | ||
oc[len(oc)-1] = 0x99 | ||
} | ||
} else if test.NotConfigured { | ||
oc = []byte{1, 2, 3, 4} // parsing this will set maxGasPrice field to nil | ||
} else if test.MaxGasPrice != nil { | ||
oc, _ = cbor.Marshal(UpkeepOffchainConfig{MaxGasPrice: test.MaxGasPrice}) | ||
} | ||
fr := CheckGasPrice(ctx, uid, oc, ge, lggr) | ||
assert.Equal(t, test.ExpectedResult, fr) | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.