feat(gas-oracle): add gas price update after Curie (#1344)

This commit is contained in:
colin
2024-05-29 17:55:06 +08:00
committed by GitHub
parent c48ae961a5
commit 1ddfe57e5b
9 changed files with 177 additions and 42 deletions

View File

@@ -5,7 +5,7 @@ import (
"runtime/debug"
)
var tag = "v4.4.7"
var tag = "v4.4.8"
var commit = func() string {
if info, ok := debug.ReadBuildInfo(); ok {

View File

@@ -101,7 +101,7 @@ var L2MessageQueueMetaData = &bind.MetaData{
// L1GasPriceOracleMetaData contains all meta data concerning the L1GasPriceOracle contract.
var L1GasPriceOracleMetaData = &bind.MetaData{
ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"l1BaseFee\",\"type\":\"uint256\"}],\"name\":\"L1BaseFeeUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"overhead\",\"type\":\"uint256\"}],\"name\":\"OverheadUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_oldOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"scalar\",\"type\":\"uint256\"}],\"name\":\"ScalarUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_oldWhitelist\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_newWhitelist\",\"type\":\"address\"}],\"name\":\"UpdateWhitelist\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"getL1Fee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"getL1GasUsed\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1BaseFee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"overhead\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"scalar\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_l1BaseFee\",\"type\":\"uint256\"}],\"name\":\"setL1BaseFee\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_overhead\",\"type\":\"uint256\"}],\"name\":\"setOverhead\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_scalar\",\"type\":\"uint256\"}],\"name\":\"setScalar\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_newWhitelist\",\"type\":\"address\"}],\"name\":\"updateWhitelist\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"whitelist\",\"outputs\":[{\"internalType\":\"contract IWhitelist\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]\n",
ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"scalar\",\"type\":\"uint256\"}],\"name\":\"BlobScalarUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"scalar\",\"type\":\"uint256\"}],\"name\":\"CommitScalarUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"l1BaseFee\",\"type\":\"uint256\"}],\"name\":\"L1BaseFeeUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"l1BlobBaseFee\",\"type\":\"uint256\"}],\"name\":\"L1BlobBaseFeeUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"overhead\",\"type\":\"uint256\"}],\"name\":\"OverheadUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"scalar\",\"type\":\"uint256\"}],\"name\":\"ScalarUpdated\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"blobScalar\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"commitScalar\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"getL1Fee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"getL1GasUsed\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1BaseFee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1BlobBaseFee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"overhead\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"scalar\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_l1BaseFee\",\"type\":\"uint256\"}],\"name\":\"setL1BaseFee\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_l1BaseFee\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_l1BlobBaseFee\",\"type\":\"uint256\"}],\"name\":\"setL1BaseFeeAndBlobBaseFee\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]",
}
// IL1ScrollMessengerL2MessageProof is an auto generated low-level Go binding around an user-defined struct.

View File

@@ -36,7 +36,8 @@ type Layer1Relayer struct {
gasOracleSender *sender.Sender
l1GasOracleABI *abi.ABI
lastGasPrice uint64
lastBaseFee uint64
lastBlobBaseFee uint64
minGasPrice uint64
gasPriceDiff uint64
l1BaseFeeWeight float64
@@ -130,37 +131,45 @@ func (r *Layer1Relayer) ProcessGasPriceOracle() {
block := blocks[0]
if types.GasOracleStatus(block.GasOracleStatus) == types.GasOraclePending {
expectedDelta := r.lastGasPrice * r.gasPriceDiff / gasPriceDiffPrecision
if r.lastGasPrice > 0 && expectedDelta == 0 {
expectedDelta = 1
}
latestL2Height, err := r.l2BlockOrm.GetL2BlocksLatestHeight(r.ctx)
if err != nil {
log.Warn("Failed to fetch latest L2 block height from db", "err", err)
return
}
var isBernoulli = r.chainCfg.IsBernoulli(new(big.Int).SetUint64(latestL2Height))
var isBernoulli = block.BlobBaseFee > 0 && r.chainCfg.IsBernoulli(new(big.Int).SetUint64(latestL2Height))
var isCurie = block.BlobBaseFee > 0 && r.chainCfg.IsCurie(new(big.Int).SetUint64(latestL2Height))
var baseFee uint64
if isBernoulli && block.BlobBaseFee != 0 {
var blobBaseFee uint64
if isCurie {
baseFee = block.BaseFee
blobBaseFee = block.BlobBaseFee
} else if isBernoulli {
baseFee = uint64(math.Ceil(r.l1BaseFeeWeight*float64(block.BaseFee) + r.l1BlobBaseFeeWeight*float64(block.BlobBaseFee)))
} else {
baseFee = block.BaseFee
}
// last is undefined or (baseFee >= minGasPrice && exceed diff)
if r.lastGasPrice == 0 || (baseFee >= r.minGasPrice && (baseFee >= r.lastGasPrice+expectedDelta || baseFee <= r.lastGasPrice-expectedDelta)) {
data, err := r.l1GasOracleABI.Pack("setL1BaseFee", new(big.Int).SetUint64(baseFee))
if err != nil {
log.Error("Failed to pack setL1BaseFee", "block.Hash", block.Hash, "block.Height", block.Number, "block.BaseFee", baseFee, "isBernoulli", isBernoulli, "err", err)
return
if r.shouldUpdateGasOracle(baseFee, blobBaseFee, isCurie) {
var data []byte
if isCurie {
data, err = r.l1GasOracleABI.Pack("setL1BaseFeeAndBlobBaseFee", new(big.Int).SetUint64(baseFee), new(big.Int).SetUint64(blobBaseFee))
if err != nil {
log.Error("Failed to pack setL1BaseFeeAndBlobBaseFee", "block.Hash", block.Hash, "block.Height", block.Number, "block.BaseFee", baseFee, "block.BlobBaseFee", blobBaseFee, "isBernoulli", isBernoulli, "isCurie", isCurie, "err", err)
return
}
} else {
data, err = r.l1GasOracleABI.Pack("setL1BaseFee", new(big.Int).SetUint64(baseFee))
if err != nil {
log.Error("Failed to pack setL1BaseFee", "block.Hash", block.Hash, "block.Height", block.Number, "block.BaseFee", baseFee, "block.BlobBaseFee", blobBaseFee, "isBernoulli", isBernoulli, "isCurie", isCurie, "err", err)
return
}
}
hash, err := r.gasOracleSender.SendTransaction(block.Hash, &r.cfg.GasPriceOracleContractAddress, data, nil, 0)
if err != nil {
log.Error("Failed to send setL1BaseFee tx to layer2 ", "block.Hash", block.Hash, "block.Height", block.Number, "err", err)
log.Error("Failed to send gas oracle update tx to layer2", "block.Hash", block.Hash, "block.Height", block.Number, "block.BaseFee", baseFee, "block.BlobBaseFee", blobBaseFee, "isBernoulli", isBernoulli, "isCurie", isCurie, "err", err)
return
}
@@ -169,9 +178,12 @@ func (r *Layer1Relayer) ProcessGasPriceOracle() {
log.Error("UpdateGasOracleStatusAndOracleTxHash failed", "block.Hash", block.Hash, "block.Height", block.Number, "err", err)
return
}
r.lastGasPrice = baseFee
r.metrics.rollupL1RelayerLastGasPrice.Set(float64(r.lastGasPrice))
log.Info("Update l1 base fee", "txHash", hash.String(), "baseFee", baseFee, "isBernoulli", isBernoulli)
r.lastBaseFee = baseFee
r.lastBlobBaseFee = blobBaseFee
r.metrics.rollupL1RelayerLatestBaseFee.Set(float64(r.lastBaseFee))
r.metrics.rollupL1RelayerLatestBlobBaseFee.Set(float64(r.lastBlobBaseFee))
log.Info("Update l1 base fee", "txHash", hash.String(), "baseFee", baseFee, "blobBaseFee", blobBaseFee, "isBernoulli", isBernoulli, "isCurie", isCurie)
}
}
}
@@ -219,3 +231,34 @@ func (r *Layer1Relayer) StopSenders() {
r.gasOracleSender.Stop()
}
}
func (r *Layer1Relayer) shouldUpdateGasOracle(baseFee uint64, blobBaseFee uint64, isCurie bool) bool {
// Right after restarting.
if r.lastBaseFee == 0 {
return true
}
expectedBaseFeeDelta := r.lastBaseFee*r.gasPriceDiff/gasPriceDiffPrecision + 1
if baseFee >= r.minGasPrice && (baseFee >= r.lastBaseFee+expectedBaseFeeDelta || baseFee+expectedBaseFeeDelta <= r.lastBaseFee) {
return true
}
// Omitting blob base fee checks before Curie.
if !isCurie {
return false
}
// Right after enabling Curie.
if r.lastBlobBaseFee == 0 {
return true
}
expectedBlobBaseFeeDelta := r.lastBlobBaseFee * r.gasPriceDiff / gasPriceDiffPrecision
// Plus a minimum of 0.01 gwei, since the blob base fee is usually low, preventing short-time flunctuation.
expectedBlobBaseFeeDelta += 10000000
if blobBaseFee >= r.minGasPrice && (blobBaseFee >= r.lastBlobBaseFee+expectedBlobBaseFeeDelta || blobBaseFee+expectedBlobBaseFeeDelta <= r.lastBlobBaseFee) {
return true
}
return false
}

View File

@@ -9,7 +9,8 @@ import (
type l1RelayerMetrics struct {
rollupL1RelayerGasPriceOraclerRunTotal prometheus.Counter
rollupL1RelayerLastGasPrice prometheus.Gauge
rollupL1RelayerLatestBaseFee prometheus.Gauge
rollupL1RelayerLatestBlobBaseFee prometheus.Gauge
rollupL1UpdateGasOracleConfirmedTotal prometheus.Counter
rollupL1UpdateGasOracleConfirmedFailedTotal prometheus.Counter
}
@@ -26,9 +27,13 @@ func initL1RelayerMetrics(reg prometheus.Registerer) *l1RelayerMetrics {
Name: "rollup_layer1_gas_price_oracler_total",
Help: "The total number of layer1 gas price oracler run total",
}),
rollupL1RelayerLastGasPrice: promauto.With(reg).NewGauge(prometheus.GaugeOpts{
Name: "rollup_layer1_gas_price_latest_gas_price",
Help: "The latest gas price of rollup relayer l1",
rollupL1RelayerLatestBaseFee: promauto.With(reg).NewGauge(prometheus.GaugeOpts{
Name: "rollup_layer1_latest_base_fee",
Help: "The latest base fee of l1 rollup relayer",
}),
rollupL1RelayerLatestBlobBaseFee: promauto.With(reg).NewGauge(prometheus.GaugeOpts{
Name: "rollup_layer1_latest_blob_base_fee",
Help: "The latest blob base fee of l1 rollup relayer",
}),
rollupL1UpdateGasOracleConfirmedTotal: promauto.With(reg).NewCounter(prometheus.CounterOpts{
Name: "rollup_layer1_update_gas_oracle_confirmed_total",

View File

@@ -309,7 +309,7 @@ func (r *Layer2Relayer) ProcessGasPriceOracle() {
}
// last is undefine or (suggestGasPriceUint64 >= minGasPrice && exceed diff)
if r.lastGasPrice == 0 || (suggestGasPriceUint64 >= r.minGasPrice && (suggestGasPriceUint64 >= r.lastGasPrice+expectedDelta || suggestGasPriceUint64 <= r.lastGasPrice-expectedDelta)) {
if r.lastGasPrice == 0 || (suggestGasPriceUint64 >= r.minGasPrice && (suggestGasPriceUint64 >= r.lastGasPrice+expectedDelta || suggestGasPriceUint64+expectedDelta <= r.lastGasPrice)) {
data, err := r.l2GasOracleABI.Pack("setL2BaseFee", suggestGasPrice)
if err != nil {
log.Error("Failed to pack setL2BaseFee", "batch.Hash", batch.Hash, "GasPrice", suggestGasPrice.Uint64(), "err", err)

View File

@@ -319,10 +319,10 @@ func testAccessListTransactionGasLimit(t *testing.T) {
assert.NoError(t, err)
if txType == LegacyTxType { // Legacy transactions can not have an access list.
assert.Equal(t, uint64(43956), gasLimit)
assert.Equal(t, uint64(43935), gasLimit)
assert.Nil(t, accessList)
} else { // Dynamic fee and blob transactions can have an access list.
assert.Equal(t, uint64(43479), gasLimit)
assert.Equal(t, uint64(43458), gasLimit)
assert.NotNil(t, accessList)
}

View File

@@ -1,5 +1,5 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity =0.8.24;
pragma solidity ^0.8.24;
import {BatchHeaderV0Codec} from "../../../contracts/src/libraries/codec/BatchHeaderV0Codec.sol";
import {BatchHeaderV1Codec} from "../../../contracts/src/libraries/codec/BatchHeaderV1Codec.sol";
@@ -82,14 +82,25 @@ contract MockBridge {
/// point evaluation precompile
uint256 constant BLS_MODULUS = 52435875175126190479447740508185965837690552500527637822603658699938581184513;
uint256 public l1BaseFee;
uint256 public l1BlobBaseFee;
uint256 public l2BaseFee;
uint256 public lastFinalizedBatchIndex;
mapping(uint256 => bytes32) public committedBatches;
mapping(uint256 => bytes32) public finalizedStateRoots;
mapping(uint256 => bytes32) public withdrawRoots;
function setL2BaseFee(uint256 _newL2BaseFee) external {
l2BaseFee = _newL2BaseFee;
function setL1BaseFee(uint256 _l1BaseFee) external {
l1BaseFee = _l1BaseFee;
}
function setL1BaseFeeAndBlobBaseFee(uint256 _l1BaseFee, uint256 _l1BlobBaseFee) external {
l1BaseFee = _l1BaseFee;
l1BlobBaseFee = _l1BlobBaseFee;
}
function setL2BaseFee(uint256 _l2BaseFee) external {
l2BaseFee = _l2BaseFee;
}
/*****************************

View File

@@ -40,8 +40,8 @@ var (
l1Client *ethclient.Client
l2Client *ethclient.Client
// l1Auth
l1Auth *bind.TransactOpts
l2Auth *bind.TransactOpts
)
func setupDB(t *testing.T) *gorm.DB {
@@ -82,6 +82,7 @@ func setupEnv(t *testing.T) {
var (
err error
l1GethChainID *big.Int
l2GethChainID *big.Int
)
testApps = tc.NewTestcontainerApps()
@@ -96,6 +97,8 @@ func setupEnv(t *testing.T) {
assert.NoError(t, err)
l1GethChainID, err = l1Client.ChainID(context.Background())
assert.NoError(t, err)
l2GethChainID, err = l2Client.ChainID(context.Background())
assert.NoError(t, err)
l1Cfg, l2Cfg := rollupApp.Config.L1Config, rollupApp.Config.L2Config
l1Cfg.Confirmations = 0
@@ -103,17 +106,16 @@ func setupEnv(t *testing.T) {
l2Cfg.Confirmations = 0
l2Cfg.RelayerConfig.SenderConfig.Confirmations = 0
l1Auth, err = bind.NewKeyedTransactorWithChainID(rollupApp.Config.L2Config.RelayerConfig.CommitSenderPrivateKey, l1GethChainID)
l1Auth, err = bind.NewKeyedTransactorWithChainID(l2Cfg.RelayerConfig.CommitSenderPrivateKey, l1GethChainID)
assert.NoError(t, err)
rollupApp.Config.L1Config.Endpoint, err = testApps.GetPoSL1EndPoint()
assert.NoError(t, err)
rollupApp.Config.L2Config.RelayerConfig.SenderConfig.Endpoint, err = testApps.GetPoSL1EndPoint()
l2Auth, err = bind.NewKeyedTransactorWithChainID(l1Cfg.RelayerConfig.GasOracleSenderPrivateKey, l2GethChainID)
assert.NoError(t, err)
port, err := rand.Int(rand.Reader, big.NewInt(10000))
assert.NoError(t, err)
svrPort := strconv.FormatInt(port.Int64()+40000, 10)
rollupApp.Config.L2Config.RelayerConfig.ChainMonitor.BaseURL = "http://localhost:" + svrPort
l2Cfg.RelayerConfig.ChainMonitor.BaseURL = "http://localhost:" + svrPort
}
func mockChainMonitorServer(baseURL string) (*http.Server, error) {
@@ -137,7 +139,7 @@ func prepareContracts(t *testing.T) {
// L1 ScrolChain contract
nonce, err := l1Client.PendingNonceAt(context.Background(), l1Auth.From)
assert.NoError(t, err)
scrollChainAddress := crypto.CreateAddress(l1Auth.From, nonce)
mockL1ContractAddress := crypto.CreateAddress(l1Auth.From, nonce)
tx := types.NewContractCreation(nonce, big.NewInt(0), 10000000, big.NewInt(1000000000), common.FromHex(mock_bridge.MockBridgeMetaData.Bin))
signedTx, err := l1Auth.Signer(l1Auth.From, tx)
assert.NoError(t, err)
@@ -145,23 +147,51 @@ func prepareContracts(t *testing.T) {
assert.NoError(t, err)
assert.Eventually(t, func() bool {
_, isPending, err := l1Client.TransactionByHash(context.Background(), signedTx.Hash())
_, isPending, getErr := l1Client.TransactionByHash(context.Background(), signedTx.Hash())
return getErr == nil && !isPending
}, 30*time.Second, time.Second)
assert.Eventually(t, func() bool {
receipt, getErr := l1Client.TransactionReceipt(context.Background(), signedTx.Hash())
return getErr == nil && receipt.Status == gethTypes.ReceiptStatusSuccessful
}, 30*time.Second, time.Second)
assert.Eventually(t, func() bool {
code, getErr := l1Client.CodeAt(context.Background(), mockL1ContractAddress, nil)
return getErr == nil && len(code) > 0
}, 30*time.Second, time.Second)
// L2 ScrolChain contract
nonce, err = l2Client.PendingNonceAt(context.Background(), l2Auth.From)
assert.NoError(t, err)
mockL2ContractAddress := crypto.CreateAddress(l2Auth.From, nonce)
tx = types.NewContractCreation(nonce, big.NewInt(0), 2000000, big.NewInt(1000000000), common.FromHex(mock_bridge.MockBridgeMetaData.Bin))
signedTx, err = l2Auth.Signer(l2Auth.From, tx)
assert.NoError(t, err)
err = l2Client.SendTransaction(context.Background(), signedTx)
assert.NoError(t, err)
assert.Eventually(t, func() bool {
_, isPending, err := l2Client.TransactionByHash(context.Background(), signedTx.Hash())
return err == nil && !isPending
}, 30*time.Second, time.Second)
assert.Eventually(t, func() bool {
receipt, err := l1Client.TransactionReceipt(context.Background(), signedTx.Hash())
receipt, err := l2Client.TransactionReceipt(context.Background(), signedTx.Hash())
return err == nil && receipt.Status == gethTypes.ReceiptStatusSuccessful
}, 30*time.Second, time.Second)
assert.Eventually(t, func() bool {
code, err := l1Client.CodeAt(context.Background(), scrollChainAddress, nil)
code, err := l2Client.CodeAt(context.Background(), mockL2ContractAddress, nil)
return err == nil && len(code) > 0
}, 30*time.Second, time.Second)
l1Config, l2Config := rollupApp.Config.L1Config, rollupApp.Config.L2Config
l1Config.ScrollChainContractAddress = scrollChainAddress
l2Config.RelayerConfig.RollupContractAddress = scrollChainAddress
l1Config.ScrollChainContractAddress = mockL1ContractAddress
l2Config.RelayerConfig.RollupContractAddress = mockL1ContractAddress
l2Config.RelayerConfig.GasPriceOracleContractAddress = mockL1ContractAddress
l1Config.RelayerConfig.GasPriceOracleContractAddress = mockL2ContractAddress
}
func TestFunction(t *testing.T) {
@@ -182,5 +212,6 @@ func TestFunction(t *testing.T) {
// l1/l2 gas oracle
t.Run("TestImportL1GasPrice", testImportL1GasPrice)
t.Run("TestImportL1GasPriceAfterCurie", testImportL1GasPriceAfterCurie)
t.Run("TestImportL2GasPrice", testImportL2GasPrice)
}

View File

@@ -64,6 +64,51 @@ func testImportL1GasPrice(t *testing.T) {
assert.Equal(t, types.GasOracleStatus(blocks[0].GasOracleStatus), types.GasOracleImporting)
}
func testImportL1GasPriceAfterCurie(t *testing.T) {
db := setupDB(t)
defer database.CloseDB(db)
prepareContracts(t)
l1Cfg := rollupApp.Config.L1Config
// Create L1Relayer
l1Relayer, err := relayer.NewLayer1Relayer(context.Background(), db, l1Cfg.RelayerConfig, &params.ChainConfig{BernoulliBlock: big.NewInt(0), CurieBlock: big.NewInt(0)}, relayer.ServiceTypeL1GasOracle, nil)
assert.NoError(t, err)
defer l1Relayer.StopSenders()
// Create L1Watcher
startHeight, err := l1Client.BlockNumber(context.Background())
assert.NoError(t, err)
l1Watcher := watcher.NewL1WatcherClient(context.Background(), l1Client, startHeight-1, 0, l1Cfg.L1MessageQueueAddress, l1Cfg.ScrollChainContractAddress, db, nil)
// fetch new blocks
number, err := l1Client.BlockNumber(context.Background())
assert.Greater(t, number, startHeight-1)
assert.NoError(t, err)
err = l1Watcher.FetchBlockHeader(number)
assert.NoError(t, err)
l1BlockOrm := orm.NewL1Block(db)
// check db status
latestBlockHeight, err := l1BlockOrm.GetLatestL1BlockHeight(context.Background())
assert.NoError(t, err)
assert.Equal(t, number, latestBlockHeight)
blocks, err := l1BlockOrm.GetL1Blocks(context.Background(), map[string]interface{}{"number": latestBlockHeight})
assert.NoError(t, err)
assert.Equal(t, len(blocks), 1)
assert.Empty(t, blocks[0].OracleTxHash)
assert.Equal(t, types.GasOracleStatus(blocks[0].GasOracleStatus), types.GasOraclePending)
// relay gas price
l1Relayer.ProcessGasPriceOracle()
blocks, err = l1BlockOrm.GetL1Blocks(context.Background(), map[string]interface{}{"number": latestBlockHeight})
assert.NoError(t, err)
assert.Equal(t, len(blocks), 1)
assert.NotEmpty(t, blocks[0].OracleTxHash)
assert.Equal(t, types.GasOracleStatus(blocks[0].GasOracleStatus), types.GasOracleImporting)
}
func testImportL2GasPrice(t *testing.T) {
db := setupDB(t)
defer database.CloseDB(db)