Skip to content

Commit

Permalink
Merge branch 'develop' into mk/fix-flakey-ccip-test
Browse files Browse the repository at this point in the history
  • Loading branch information
makramkd authored Sep 18, 2024
2 parents 1a67785 + 767aed2 commit cacaacd
Show file tree
Hide file tree
Showing 21 changed files with 163 additions and 686 deletions.
5 changes: 5 additions & 0 deletions .changeset/curly-onions-tell.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"chainlink": patch
---

#changed Make Mantle use default OP stack l1 gas oracle in core
4 changes: 2 additions & 2 deletions .github/E2E_TESTS_ON_GITHUB_CI.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,9 @@ To learn more about test configs see [CTF Test Config](https://github.com/smartc

## Test Secrets

For security reasons, test secrets and sensitive information are not stored directly within the test config TOML files. Instead, these secrets are securely injected into tests using environment variables. For a detailed explanation on managing test secrets, refer to our [Test Secrets documentation](https://github.com/smartcontractkit/chainlink-testing-framework/blob/main/config/README.md#test-secrets).
For security reasons, test secrets and sensitive information are not stored directly within the test config TOML files. Instead, these secrets are securely injected into tests using environment variables. For a detailed explanation on managing test secrets, refer to our [Test Secrets documentation](https://github.com/smartcontractkit/chainlink-testing-framework/blob/main/lib/config/README.md#test-secrets).

If you need to run a GitHub workflow using custom secrets, please refer to the [guide on running GitHub workflows with your test secrets](https://github.com/smartcontractkit/chainlink-testing-framework/blob/main/config/README.md#run-github-workflow-with-your-test-secrets).
If you need to run a GitHub workflow using custom secrets, please refer to the [guide on running GitHub workflows with your test secrets](https://github.com/smartcontractkit/chainlink-testing-framework/blob/main/lib/config/README.md#run-github-workflow-with-your-test-secrets).

## About the Reusable Workflow

Expand Down
4 changes: 4 additions & 0 deletions core/chains/evm/gas/rollups/arbitrum_l1_oracle.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,10 @@ func (o *arbitrumL1Oracle) Name() string {
return o.logger.Name()
}

func (o *arbitrumL1Oracle) ChainType(_ context.Context) chaintype.ChainType {
return o.chainType
}

func (o *arbitrumL1Oracle) Start(ctx context.Context) error {
return o.StartOnce(o.Name(), func() error {
go o.run()
Expand Down
1 change: 1 addition & 0 deletions core/chains/evm/gas/rollups/l1_oracle.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ type L1Oracle interface {

GasPrice(ctx context.Context) (*assets.Wei, error)
GetGasCost(ctx context.Context, tx *types.Transaction, blockNum *big.Int) (*assets.Wei, error)
ChainType(ctx context.Context) chaintype.ChainType
}

type l1OracleClient interface {
Expand Down
1 change: 0 additions & 1 deletion core/chains/evm/gas/rollups/l1_oracle_abi.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,3 @@ const OPBaseFeeScalarAbiString = `[{"inputs":[],"name":"baseFeeScalar","outputs"
const OPBlobBaseFeeAbiString = `[{"inputs":[],"name":"blobBaseFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]`
const OPBlobBaseFeeScalarAbiString = `[{"inputs":[],"name":"blobBaseFeeScalar","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"}]`
const OPDecimalsAbiString = `[{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"}]`
const MantleTokenRatioAbiString = `[{"inputs":[],"name":"tokenRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]`
48 changes: 48 additions & 0 deletions core/chains/evm/gas/rollups/mocks/l1_oracle.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

86 changes: 4 additions & 82 deletions core/chains/evm/gas/rollups/op_l1_oracle.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,10 +88,6 @@ const (
// decimals is a hex encoded call to:
// `function decimals() public pure returns (uint256);`
decimalsMethod = "decimals"
// tokenRatio fetches the tokenRatio used for Mantle's gas price calculation
// tokenRatio is a hex encoded call to:
// `function tokenRatio() public pure returns (uint256);`
tokenRatioMethod = "tokenRatio"
// OPGasOracleAddress is the address of the precompiled contract that exists on Optimism, Base and Mantle.
OPGasOracleAddress = "0x420000000000000000000000000000000000000F"
// KromaGasOracleAddress is the address of the precompiled contract that exists on Kroma.
Expand Down Expand Up @@ -192,16 +188,6 @@ func newOpStackL1GasOracle(lggr logger.Logger, ethClient l1OracleClient, chainTy
return nil, fmt.Errorf("failed to parse GasPriceOracle %s() calldata for chain: %s; %w", decimalsMethod, chainType, err)
}

// Encode calldata for tokenRatio method
tokenRatioMethodAbi, err := abi.JSON(strings.NewReader(MantleTokenRatioAbiString))
if err != nil {
return nil, fmt.Errorf("failed to parse GasPriceOracle %s() method ABI for chain: %s; %w", tokenRatioMethod, chainType, err)
}
tokenRatioCalldata, err := tokenRatioMethodAbi.Pack(tokenRatioMethod)
if err != nil {
return nil, fmt.Errorf("failed to parse GasPriceOracle %s() calldata for chain: %s; %w", tokenRatioMethod, chainType, err)
}

return &optimismL1Oracle{
client: ethClient,
pollPeriod: PollPeriod,
Expand All @@ -223,7 +209,6 @@ func newOpStackL1GasOracle(lggr logger.Logger, ethClient l1OracleClient, chainTy
blobBaseFeeCalldata: blobBaseFeeCalldata,
blobBaseFeeScalarCalldata: blobBaseFeeScalarCalldata,
decimalsCalldata: decimalsCalldata,
tokenRatioCalldata: tokenRatioCalldata,
isEcotoneCalldata: isEcotoneCalldata,
isEcotoneMethodAbi: isEcotoneMethodAbi,
isFjordCalldata: isFjordCalldata,
Expand All @@ -235,6 +220,10 @@ func (o *optimismL1Oracle) Name() string {
return o.logger.Name()
}

func (o *optimismL1Oracle) ChainType(_ context.Context) chaintype.ChainType {
return o.chainType
}

func (o *optimismL1Oracle) Start(ctx context.Context) error {
return o.StartOnce(o.Name(), func() error {
go o.run()
Expand Down Expand Up @@ -362,10 +351,6 @@ func (o *optimismL1Oracle) GetGasCost(ctx context.Context, tx *gethtypes.Transac
}

func (o *optimismL1Oracle) GetDAGasPrice(ctx context.Context) (*big.Int, error) {
if o.chainType == chaintype.ChainMantle {
return o.getMantleGasPrice(ctx)
}

err := o.checkForUpgrade(ctx)
if err != nil {
return nil, err
Expand Down Expand Up @@ -463,69 +448,6 @@ func (o *optimismL1Oracle) getV1GasPrice(ctx context.Context) (*big.Int, error)
return new(big.Int).SetBytes(b), nil
}

// Returns the gas price for Mantle. The formula is the same as Optimism Bedrock (getV1GasPrice), but the tokenRatio parameter is multiplied
func (o *optimismL1Oracle) getMantleGasPrice(ctx context.Context) (*big.Int, error) {
// call oracle to get l1BaseFee and tokenRatio
rpcBatchCalls := []rpc.BatchElem{
{
Method: "eth_call",
Args: []any{
map[string]interface{}{
"from": common.Address{},
"to": o.l1OracleAddress,
"data": hexutil.Bytes(o.l1BaseFeeCalldata),
},
"latest",
},
Result: new(string),
},
{
Method: "eth_call",
Args: []any{
map[string]interface{}{
"from": common.Address{},
"to": o.l1OracleAddress,
"data": hexutil.Bytes(o.tokenRatioCalldata),
},
"latest",
},
Result: new(string),
},
}

err := o.client.BatchCallContext(ctx, rpcBatchCalls)
if err != nil {
return nil, fmt.Errorf("fetch gas price parameters batch call failed: %w", err)
}
if rpcBatchCalls[0].Error != nil {
return nil, fmt.Errorf("%s call failed in a batch: %w", l1BaseFeeMethod, err)
}
if rpcBatchCalls[1].Error != nil {
return nil, fmt.Errorf("%s call failed in a batch: %w", tokenRatioMethod, err)
}

// Extract values from responses
l1BaseFeeResult := *(rpcBatchCalls[0].Result.(*string))
tokenRatioResult := *(rpcBatchCalls[1].Result.(*string))

// Decode the responses into bytes
l1BaseFeeBytes, err := hexutil.Decode(l1BaseFeeResult)
if err != nil {
return nil, fmt.Errorf("failed to decode %s rpc result: %w", l1BaseFeeMethod, err)
}
tokenRatioBytes, err := hexutil.Decode(tokenRatioResult)
if err != nil {
return nil, fmt.Errorf("failed to decode %s rpc result: %w", tokenRatioMethod, err)
}

// Convert bytes to big int for calculations
l1BaseFee := new(big.Int).SetBytes(l1BaseFeeBytes)
tokenRatio := new(big.Int).SetBytes(tokenRatioBytes)

// multiply l1BaseFee and tokenRatio and return
return new(big.Int).Mul(l1BaseFee, tokenRatio), nil
}

// Returns the scaled gas price using baseFeeScalar, l1BaseFee, blobBaseFeeScalar, and blobBaseFee fields from the oracle
// Confirmed the same calculation is used to determine gas price for both Ecotone and Fjord
func (o *optimismL1Oracle) getEcotoneFjordGasPrice(ctx context.Context) (*big.Int, error) {
Expand Down
88 changes: 0 additions & 88 deletions core/chains/evm/gas/rollups/op_l1_oracle_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,94 +111,6 @@ func TestOPL1Oracle_ReadV1GasPrice(t *testing.T) {
}
}

func TestOPL1Oracle_ReadMantleGasPrice(t *testing.T) {
l1BaseFee := big.NewInt(100)
tokenRatio := big.NewInt(40)
oracleAddress := common.HexToAddress("0x1234").String()

t.Parallel()
t.Run("correctly fetches gas price if chain is Mantle", func(t *testing.T) {
// Encode calldata for l1BaseFee method
l1BaseFeeMethodAbi, err := abi.JSON(strings.NewReader(L1BaseFeeAbiString))
require.NoError(t, err)
l1BaseFeeCalldata, err := l1BaseFeeMethodAbi.Pack(l1BaseFeeMethod)
require.NoError(t, err)

// Encode calldata for tokenRatio method
tokenRatioMethodAbi, err := abi.JSON(strings.NewReader(MantleTokenRatioAbiString))
require.NoError(t, err)
tokenRatioCalldata, err := tokenRatioMethodAbi.Pack(tokenRatioMethod)
require.NoError(t, err)

ethClient := mocks.NewL1OracleClient(t)
ethClient.On("BatchCallContext", mock.Anything, mock.IsType([]rpc.BatchElem{})).Run(func(args mock.Arguments) {
rpcElements := args.Get(1).([]rpc.BatchElem)
require.Equal(t, 2, len(rpcElements))
for _, rE := range rpcElements {
require.Equal(t, "eth_call", rE.Method)
require.Equal(t, oracleAddress, rE.Args[0].(map[string]interface{})["to"])
require.Equal(t, "latest", rE.Args[1])
}
require.Equal(t, hexutil.Bytes(l1BaseFeeCalldata), rpcElements[0].Args[0].(map[string]interface{})["data"])
require.Equal(t, hexutil.Bytes(tokenRatioCalldata), rpcElements[1].Args[0].(map[string]interface{})["data"])

res1 := common.BigToHash(l1BaseFee).Hex()
res2 := common.BigToHash(tokenRatio).Hex()

rpcElements[0].Result = &res1
rpcElements[1].Result = &res2
}).Return(nil).Once()

oracle, err := newOpStackL1GasOracle(logger.Test(t), ethClient, chaintype.ChainMantle, oracleAddress)
require.NoError(t, err)

gasPrice, err := oracle.GetDAGasPrice(tests.Context(t))
require.NoError(t, err)

assert.Equal(t, new(big.Int).Mul(l1BaseFee, tokenRatio), gasPrice)
})

t.Run("fetching Mantle price but rpc returns bad data", func(t *testing.T) {
ethClient := mocks.NewL1OracleClient(t)
ethClient.On("BatchCallContext", mock.Anything, mock.IsType([]rpc.BatchElem{})).Run(func(args mock.Arguments) {
rpcElements := args.Get(1).([]rpc.BatchElem)
var badData = "zzz"
rpcElements[0].Result = &badData
rpcElements[1].Result = &badData
}).Return(nil).Once()

oracle, err := newOpStackL1GasOracle(logger.Test(t), ethClient, chaintype.ChainMantle, oracleAddress)
require.NoError(t, err)
_, err = oracle.GetDAGasPrice(tests.Context(t))
assert.Error(t, err)
})

t.Run("fetching Mantle price but rpc parent call errors", func(t *testing.T) {
ethClient := mocks.NewL1OracleClient(t)
ethClient.On("BatchCallContext", mock.Anything, mock.IsType([]rpc.BatchElem{})).Return(fmt.Errorf("revert")).Once()

oracle, err := newOpStackL1GasOracle(logger.Test(t), ethClient, chaintype.ChainMantle, oracleAddress)
require.NoError(t, err)
_, err = oracle.GetDAGasPrice(tests.Context(t))
assert.Error(t, err)
})

t.Run("fetching Mantle price but one of the sub rpc call errors", func(t *testing.T) {
ethClient := mocks.NewL1OracleClient(t)
ethClient.On("BatchCallContext", mock.Anything, mock.IsType([]rpc.BatchElem{})).Run(func(args mock.Arguments) {
rpcElements := args.Get(1).([]rpc.BatchElem)
res := common.BigToHash(l1BaseFee).Hex()
rpcElements[0].Result = &res
rpcElements[1].Error = fmt.Errorf("revert")
}).Return(nil).Once()

oracle, err := newOpStackL1GasOracle(logger.Test(t), ethClient, chaintype.ChainMantle, oracleAddress)
require.NoError(t, err)
_, err = oracle.GetDAGasPrice(tests.Context(t))
assert.Error(t, err)
})
}

func setupUpgradeCheck(t *testing.T, oracleAddress string, isFjord, isEcotone bool) *mocks.L1OracleClient {
trueHex := "0x0000000000000000000000000000000000000000000000000000000000000001"
falseHex := "0x0000000000000000000000000000000000000000000000000000000000000000"
Expand Down
4 changes: 4 additions & 0 deletions core/chains/evm/gas/rollups/zkSync_l1_oracle.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,10 @@ func (o *zkSyncL1Oracle) Name() string {
return o.logger.Name()
}

func (o *zkSyncL1Oracle) ChainType(_ context.Context) chaintype.ChainType {
return o.chainType
}

func (o *zkSyncL1Oracle) Start(ctx context.Context) error {
return o.StartOnce(o.Name(), func() error {
go o.run()
Expand Down
Loading

0 comments on commit cacaacd

Please sign in to comment.