diff --git a/common/version/version.go b/common/version/version.go index 249b0fdf7..8d171ee06 100644 --- a/common/version/version.go +++ b/common/version/version.go @@ -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 { diff --git a/rollup/abi/bridge_abi.go b/rollup/abi/bridge_abi.go index 3a97f0e3c..d273be718 100644 --- a/rollup/abi/bridge_abi.go +++ b/rollup/abi/bridge_abi.go @@ -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. diff --git a/rollup/internal/controller/relayer/l1_relayer.go b/rollup/internal/controller/relayer/l1_relayer.go index f10b147ae..921ccec4f 100644 --- a/rollup/internal/controller/relayer/l1_relayer.go +++ b/rollup/internal/controller/relayer/l1_relayer.go @@ -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 +} diff --git a/rollup/internal/controller/relayer/l1_relayer_metrics.go b/rollup/internal/controller/relayer/l1_relayer_metrics.go index a459ba384..433c37396 100644 --- a/rollup/internal/controller/relayer/l1_relayer_metrics.go +++ b/rollup/internal/controller/relayer/l1_relayer_metrics.go @@ -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", diff --git a/rollup/internal/controller/relayer/l2_relayer.go b/rollup/internal/controller/relayer/l2_relayer.go index aba789116..a5497fb24 100644 --- a/rollup/internal/controller/relayer/l2_relayer.go +++ b/rollup/internal/controller/relayer/l2_relayer.go @@ -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) diff --git a/rollup/internal/controller/sender/sender_test.go b/rollup/internal/controller/sender/sender_test.go index 3d75ebf54..2f27664c0 100644 --- a/rollup/internal/controller/sender/sender_test.go +++ b/rollup/internal/controller/sender/sender_test.go @@ -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) } diff --git a/rollup/mock_bridge/MockBridge.sol b/rollup/mock_bridge/MockBridge.sol index 0279fab38..b91cadff9 100644 --- a/rollup/mock_bridge/MockBridge.sol +++ b/rollup/mock_bridge/MockBridge.sol @@ -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; } /***************************** diff --git a/rollup/tests/bridge_test.go b/rollup/tests/bridge_test.go index f7a035cc8..2b4b5ae1a 100644 --- a/rollup/tests/bridge_test.go +++ b/rollup/tests/bridge_test.go @@ -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) } diff --git a/rollup/tests/gas_oracle_test.go b/rollup/tests/gas_oracle_test.go index cf4c3b6c1..c91f32bff 100644 --- a/rollup/tests/gas_oracle_test.go +++ b/rollup/tests/gas_oracle_test.go @@ -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, ¶ms.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)