Compare commits

..

27 Commits

Author SHA1 Message Date
colin
3e64f32b85 fix(coordinator): concurrent map write (#360)
Co-authored-by: HAOYUatHZ <37070449+HAOYUatHZ@users.noreply.github.com>
2023-03-14 06:04:47 +08:00
HAOYUatHZ
31c6d965a7 Update version.go 2023-03-14 05:59:54 +08:00
HAOYUatHZ
06a1b47ffa Merge pull request #359 from scroll-tech/staging
merge staging into alpha
2023-03-13 17:51:00 +08:00
HAOYUatHZ
1d2886cbb2 Update version.go 2023-03-13 17:43:38 +08:00
Jerry Ho
ba87e8ea25 feat(coordinator): early return of CollectProofs before timeout (#342)
Co-authored-by: maskpp <maskpp266@gmail.com>
Co-authored-by: HAOYUatHZ <37070449+HAOYUatHZ@users.noreply.github.com>
Co-authored-by: HAOYUatHZ <haoyu@protonmail.com>
Co-authored-by: colinlyguo <651734127@qq.com>
Co-authored-by: colin <102356659+colinlyguo@users.noreply.github.com>
2023-03-13 17:35:32 +08:00
HAOYUatHZ
0f98d0c5e5 Merge pull request #356 from scroll-tech/alpha
fix(sender): Update estimate gas logic. (#354)
2023-03-10 20:41:50 +08:00
maskpp
4df23100d1 fix(sender): Update estimate gas logic. (#354)
Co-authored-by: HAOYUatHZ <37070449+HAOYUatHZ@users.noreply.github.com>
2023-03-10 20:37:36 +08:00
Péter Garamvölgyi
8f807c8ee0 Add weth deploy script (#355) 2023-03-10 10:13:12 +01:00
Xi Lin
a62ff312a6 feat(contracts): refund unused fee to tx.origin (#353)
Co-authored-by: maskpp <maskpp266@gmail.com>
Co-authored-by: HAOYUatHZ <37070449+HAOYUatHZ@users.noreply.github.com>
2023-03-10 14:41:52 +08:00
ChuhanJin
d3c84dd013 refactor(common): Add docker app into common for test cases (#351)
Co-authored-by: vincent <419436363@qq.com>
Co-authored-by: colinlyguo <651734127@qq.com>
Co-authored-by: colin <102356659+colinlyguo@users.noreply.github.com>
2023-03-10 10:05:46 +08:00
HAOYUatHZ
b922f59686 Merge pull request #348 from scroll-tech/alpha
fix(roller): fix stack bug (#320)
2023-03-06 20:01:33 +08:00
Lawliet-Chan
ee4c00eb6b fix(roller): fix stack bug (#320)
Co-authored-by: HAOYUatHZ <37070449+HAOYUatHZ@users.noreply.github.com>
2023-03-06 19:59:33 +08:00
HAOYUatHZ
357066e9c8 Merge pull request #346 from scroll-tech/alpha
fix(contract): forbid to call message queue and l2 messenger from l1 …
2023-03-06 14:33:27 +08:00
Xi Lin
e1ec4d1f05 fix(contract): forbid to call message queue and l2 messenger from l1 (#341)
Co-authored-by: HAOYUatHZ <37070449+HAOYUatHZ@users.noreply.github.com>
2023-03-06 14:31:33 +08:00
maskpp
551e2ba784 fix(cmd bug): Wait until sub process exited. (#337)
Co-authored-by: colinlyguo <651734127@qq.com>
2023-03-06 11:01:30 +08:00
HAOYUatHZ
58315eadce Merge pull request #345 from scroll-tech/alpha
bugfix(libzkp): fix difficulty (#343)
2023-03-06 10:58:07 +08:00
Lawliet-Chan
44e27b1110 bugfix(libzkp): fix difficulty (#343) 2023-03-03 22:09:29 +08:00
HAOYUatHZ
ddad2552bb Merge pull request #336 from scroll-tech/alpha
fix: reduce finalize batch tx frequency (#332)
2023-03-01 17:32:19 +08:00
Péter Garamvölgyi
e78cff529c fix: reduce finalize batch tx frequency (#332) 2023-03-01 09:01:15 +01:00
HAOYUatHZ
f61d917b92 Merge pull request #335 from scroll-tech/alpha
Alpha
2023-03-01 15:09:12 +08:00
ChuhanJin
4c0ff9306b fix(build): jenkinsfile tag job optimized and fix (#331)
Co-authored-by: vincent <419436363@qq.com>
Co-authored-by: HAOYUatHZ <37070449+HAOYUatHZ@users.noreply.github.com>
2023-03-01 14:39:43 +08:00
Lawliet-Chan
669f3f45b4 Fix(zkevm): fix zkevm bug for goerli. (#334) 2023-03-01 14:28:18 +08:00
HAOYUatHZ
0eaf220382 Merge pull request #329 from scroll-tech/alpha
fix(db): fix `SetMaxOpenConns` (#328)
2023-02-28 15:58:07 +08:00
HAOYUatHZ
24c7a632f2 fix(db): fix SetMaxOpenConns (#328) 2023-02-28 15:15:15 +08:00
HAOYUatHZ
7f6c219d56 Merge pull request #326 from scroll-tech/alpha
merge `alpha` into `staging`
2023-02-27 19:22:46 +08:00
Haichen Shen
cc64c29f56 feat(batch proposer): add time limit to commit batches (#323) 2023-02-25 16:25:09 +08:00
HAOYUatHZ
780d6b326f fix(bridge): fix typos (#321) 2023-02-23 19:41:12 +08:00
55 changed files with 1027 additions and 508 deletions

View File

@@ -24,6 +24,7 @@
"min_gas_price": 0,
"gas_price_diff": 50000
},
"finalize_batch_interval_sec": 0,
"message_sender_private_keys": [
"1212121212121212121212121212121212121212121212121212121212121212"
],
@@ -56,6 +57,7 @@
"min_gas_price": 0,
"gas_price_diff": 50000
},
"finalize_batch_interval_sec": 0,
"message_sender_private_keys": [
"1212121212121212121212121212121212121212121212121212121212121212"
],
@@ -71,6 +73,7 @@
"batch_gas_threshold": 3000000,
"batch_tx_num_threshold": 44,
"batch_time_sec": 300,
"batch_commit_time_sec": 1200,
"batch_blocks_limit": 100,
"commit_tx_calldata_size_limit": 200000,
"public_input_config": {
@@ -81,6 +84,8 @@
},
"db_config": {
"driver_name": "postgres",
"dsn": "postgres://admin:123456@localhost/test?sslmode=disable"
"dsn": "postgres://admin:123456@localhost/test?sslmode=disable",
"maxOpenNum": 200,
"maxIdleNum": 20
}
}

View File

@@ -34,6 +34,8 @@ type BatchProposerConfig struct {
BatchGasThreshold uint64 `json:"batch_gas_threshold"`
// Time waited to generate a batch even if gas_threshold not met
BatchTimeSec uint64 `json:"batch_time_sec"`
// Time waited to commit batches before the calldata met CommitTxCalldataSizeLimit
BatchCommitTimeSec uint64 `json:"batch_commit_time_sec"`
// Max number of blocks in a batch
BatchBlocksLimit uint64 `json:"batch_blocks_limit"`
// Commit tx calldata size limit in bytes, target to cap the gas use of commit tx at 2M gas

View File

@@ -47,6 +47,8 @@ type RelayerConfig struct {
SenderConfig *SenderConfig `json:"sender_config"`
// gas oracle config
GasOracleConfig *GasOracleConfig `json:"gas_oracle_config"`
// The interval in which we send finalize batch transactions.
FinalizeBatchIntervalSec uint64 `json:"finalize_batch_interval_sec"`
// The private key of the relayer
MessageSenderPrivateKeys []*ecdsa.PrivateKey `json:"-"`
GasOracleSenderPrivateKeys []*ecdsa.PrivateKey `json:"-"`

View File

@@ -15,42 +15,27 @@ var (
cfg *config.Config
// docker consider handler.
l1gethImg docker.ImgInstance
l2gethImg docker.ImgInstance
dbImg docker.ImgInstance
base *docker.App
)
func TestMain(m *testing.M) {
base = docker.NewDockerApp()
m.Run()
base.Free()
}
func setupEnv(t *testing.T) {
// Load config.
var err error
cfg, err = config.NewConfig("../config.json")
assert.NoError(t, err)
base.RunImages(t)
// Create l1geth container.
l1gethImg = docker.NewTestL1Docker(t)
cfg.L2Config.RelayerConfig.SenderConfig.Endpoint = l1gethImg.Endpoint()
cfg.L1Config.Endpoint = l1gethImg.Endpoint()
// Create l2geth container.
l2gethImg = docker.NewTestL2Docker(t)
cfg.L1Config.RelayerConfig.SenderConfig.Endpoint = l2gethImg.Endpoint()
cfg.L2Config.Endpoint = l2gethImg.Endpoint()
// Create db container.
dbImg = docker.NewTestDBDocker(t, cfg.DBConfig.DriverName)
cfg.DBConfig.DSN = dbImg.Endpoint()
}
func free(t *testing.T) {
if dbImg != nil {
assert.NoError(t, dbImg.Stop())
}
if l1gethImg != nil {
assert.NoError(t, l1gethImg.Stop())
}
if l2gethImg != nil {
assert.NoError(t, l2gethImg.Stop())
}
cfg.L2Config.RelayerConfig.SenderConfig.Endpoint = base.L1GethEndpoint()
cfg.L1Config.RelayerConfig.SenderConfig.Endpoint = base.L2GethEndpoint()
cfg.DBConfig.DSN = base.DBEndpoint()
}
func TestL1(t *testing.T) {
@@ -58,8 +43,4 @@ func TestL1(t *testing.T) {
t.Run("testCreateNewL1Relayer", testCreateNewL1Relayer)
t.Run("testStartWatcher", testStartWatcher)
t.Cleanup(func() {
free(t)
})
}

View File

@@ -69,7 +69,7 @@ func NewLayer1Relayer(ctx context.Context, db database.OrmFactory, cfg *config.R
gasOracleSender, err := sender.NewSender(ctx, cfg.SenderConfig, cfg.GasOracleSenderPrivateKeys)
if err != nil {
addr := crypto.PubkeyToAddress(cfg.GasOracleSenderPrivateKeys[0].PublicKey)
log.Error("new MessageSender failed", "main address", addr.String(), "err", err)
log.Error("new GasOracleSender failed", "main address", addr.String(), "err", err)
return nil, err
}

View File

@@ -18,7 +18,7 @@ func testStartWatcher(t *testing.T) {
assert.NoError(t, migrate.ResetDB(db.GetDB().DB))
defer db.Close()
client, err := ethclient.Dial(l1gethImg.Endpoint())
client, err := ethclient.Dial(base.L1GethEndpoint())
assert.NoError(t, err)
l1Cfg := cfg.L1Config

View File

@@ -64,6 +64,7 @@ type BatchProposer struct {
batchGasThreshold uint64
batchTxNumThreshold uint64
batchBlocksLimit uint64
batchCommitTimeSec uint64
commitCalldataSizeLimit uint64
batchDataBufferSizeLimit uint64
@@ -86,6 +87,7 @@ func NewBatchProposer(ctx context.Context, cfg *config.BatchProposerConfig, rela
batchGasThreshold: cfg.BatchGasThreshold,
batchTxNumThreshold: cfg.BatchTxNumThreshold,
batchBlocksLimit: cfg.BatchBlocksLimit,
batchCommitTimeSec: cfg.BatchCommitTimeSec,
commitCalldataSizeLimit: cfg.CommitTxCalldataSizeLimit,
batchDataBufferSizeLimit: 100*cfg.CommitTxCalldataSizeLimit + 1*1024*1024, // @todo: determine the value.
proofGenerationFreq: cfg.ProofGenerationFreq,
@@ -124,6 +126,7 @@ func (p *BatchProposer) Start() {
case <-ticker.C:
p.tryProposeBatch()
p.tryCommitBatches()
}
}
}(ctx)
@@ -225,11 +228,16 @@ func (p *BatchProposer) tryProposeBatch() {
p.proposeBatch(blocks)
}
p.tryCommitBatches()
}
func (p *BatchProposer) tryCommitBatches() {
p.mutex.Lock()
defer p.mutex.Unlock()
if len(p.batchDataBuffer) == 0 {
return
}
// estimate the calldata length to determine whether to commit the pending batches
index := 0
commit := false
@@ -249,7 +257,7 @@ func (p *BatchProposer) tryCommitBatches() {
break
}
}
if !commit {
if !commit && p.batchDataBuffer[0].Timestamp()+p.batchCommitTimeSec > uint64(time.Now().Unix()) {
return
}
@@ -287,14 +295,13 @@ func (p *BatchProposer) proposeBatch(blocks []*types.BlockInfo) {
return
}
var (
length = len(blocks)
gasUsed, txNum uint64
)
var gasUsed, txNum uint64
reachThreshold := false
// add blocks into batch until reach batchGasThreshold
for i, block := range blocks {
if (gasUsed+block.GasUsed > p.batchGasThreshold) || (txNum+block.TxNum > p.batchTxNumThreshold) {
blocks = blocks[:i]
reachThreshold = true
break
}
gasUsed += block.GasUsed
@@ -304,7 +311,7 @@ func (p *BatchProposer) proposeBatch(blocks []*types.BlockInfo) {
// if too few gas gathered, but we don't want to halt, we then check the first block in the batch:
// if it's not old enough we will skip proposing the batch,
// otherwise we will still propose a batch
if length == len(blocks) && blocks[0].BlockTimestamp+p.batchTimeSec > uint64(time.Now().Unix()) {
if !reachThreshold && blocks[0].BlockTimestamp+p.batchTimeSec > uint64(time.Now().Unix()) {
return
}

View File

@@ -20,10 +20,7 @@ var (
// config
cfg *config.Config
// docker consider handler.
l1gethImg docker.ImgInstance
l2gethImg docker.ImgInstance
dbImg docker.ImgInstance
base *docker.App
// l2geth client
l2Cli *ethclient.Client
@@ -42,22 +39,14 @@ func setupEnv(t *testing.T) (err error) {
cfg, err = config.NewConfig("../config.json")
assert.NoError(t, err)
// Create l1geth container.
l1gethImg = docker.NewTestL1Docker(t)
cfg.L2Config.RelayerConfig.SenderConfig.Endpoint = l1gethImg.Endpoint()
cfg.L1Config.Endpoint = l1gethImg.Endpoint()
base.RunImages(t)
// Create l2geth container.
l2gethImg = docker.NewTestL2Docker(t)
cfg.L1Config.RelayerConfig.SenderConfig.Endpoint = l2gethImg.Endpoint()
cfg.L2Config.Endpoint = l2gethImg.Endpoint()
// Create db container.
dbImg = docker.NewTestDBDocker(t, cfg.DBConfig.DriverName)
cfg.DBConfig.DSN = dbImg.Endpoint()
cfg.L2Config.RelayerConfig.SenderConfig.Endpoint = base.L1GethEndpoint()
cfg.L1Config.RelayerConfig.SenderConfig.Endpoint = base.L2GethEndpoint()
cfg.DBConfig.DSN = base.DBEndpoint()
// Create l2geth client.
l2Cli, err = ethclient.Dial(cfg.L2Config.Endpoint)
l2Cli, err = base.L2Client()
assert.NoError(t, err)
templateBlockTrace1, err := os.ReadFile("../../common/testdata/blockTrace_02.json")
@@ -97,16 +86,12 @@ func setupEnv(t *testing.T) (err error) {
return err
}
func free(t *testing.T) {
if dbImg != nil {
assert.NoError(t, dbImg.Stop())
}
if l1gethImg != nil {
assert.NoError(t, l1gethImg.Stop())
}
if l2gethImg != nil {
assert.NoError(t, l2gethImg.Stop())
}
func TestMain(m *testing.M) {
base = docker.NewDockerApp()
m.Run()
base.Free()
}
func TestFunction(t *testing.T) {
@@ -129,7 +114,4 @@ func TestFunction(t *testing.T) {
t.Run("TestBatchProposerProposeBatch", testBatchProposerProposeBatch)
t.Run("TestBatchProposerGracefulRestart", testBatchProposerGracefulRestart)
t.Cleanup(func() {
free(t)
})
}

View File

@@ -354,22 +354,29 @@ func (r *Layer2Relayer) ProcessCommittedBatches() {
}
// batches are sorted by batch index in increasing order
batches, err := r.db.GetCommittedBatches(1)
batchHashes, err := r.db.GetCommittedBatches(1)
if err != nil {
log.Error("Failed to fetch committed L2 batches", "err", err)
return
}
if len(batches) == 0 {
if len(batchHashes) == 0 {
return
}
hash := batches[0]
hash := batchHashes[0]
// @todo add support to relay multiple batches
status, err := r.db.GetProvingStatusByHash(hash)
batches, err := r.db.GetBlockBatches(map[string]interface{}{"hash": hash}, "LIMIT 1")
if err != nil {
log.Error("GetProvingStatusByHash failed", "hash", hash, "err", err)
log.Error("Failed to fetch committed L2 batch", "hash", hash, "err", err)
return
}
if len(batches) == 0 {
log.Error("Unexpected result for GetBlockBatches", "hash", hash, "len", 0)
return
}
batch := batches[0]
status := batch.ProvingStatus
switch status {
case types.ProvingTaskUnassigned, types.ProvingTaskAssigned:
@@ -392,6 +399,34 @@ func (r *Layer2Relayer) ProcessCommittedBatches() {
log.Info("Start to roll up zk proof", "hash", hash)
success := false
previousBatch, err := r.db.GetLatestFinalizingOrFinalizedBatch()
// skip submitting proof
if err == nil && uint64(batch.CreatedAt.Sub(*previousBatch.CreatedAt).Seconds()) < r.cfg.FinalizeBatchIntervalSec {
log.Info(
"Not enough time passed, skipping",
"hash", hash,
"createdAt", batch.CreatedAt,
"lastFinalizingHash", previousBatch.Hash,
"lastFinalizingStatus", previousBatch.RollupStatus,
"lastFinalizingCreatedAt", previousBatch.CreatedAt,
)
if err = r.db.UpdateRollupStatus(r.ctx, hash, types.RollupFinalizationSkipped); err != nil {
log.Warn("UpdateRollupStatus failed", "hash", hash, "err", err)
} else {
success = true
}
return
}
// handle unexpected db error
if err != nil && err.Error() != "sql: no rows in result set" {
log.Error("Failed to get latest finalized batch", "err", err)
return
}
defer func() {
// TODO: need to revisit this and have a more fine-grained error handling
if !success {

View File

@@ -0,0 +1,69 @@
package sender
import (
"math/big"
"sync/atomic"
"github.com/scroll-tech/go-ethereum"
"github.com/scroll-tech/go-ethereum/accounts/abi/bind"
"github.com/scroll-tech/go-ethereum/common"
)
func (s *Sender) estimateLegacyGas(auth *bind.TransactOpts, contract *common.Address, value *big.Int, input []byte) (*FeeData, error) {
gasPrice, err := s.client.SuggestGasPrice(s.ctx)
if err != nil {
return nil, err
}
gasLimit, err := s.estimateGasLimit(auth, contract, input, gasPrice, nil, nil, value)
if err != nil {
return nil, err
}
return &FeeData{
gasPrice: gasPrice,
gasLimit: gasLimit,
}, nil
}
func (s *Sender) estimateDynamicGas(auth *bind.TransactOpts, contract *common.Address, value *big.Int, input []byte) (*FeeData, error) {
gasTipCap, err := s.client.SuggestGasTipCap(s.ctx)
if err != nil {
return nil, err
}
baseFee := big.NewInt(0)
if feeGas := atomic.LoadUint64(&s.baseFeePerGas); feeGas != 0 {
baseFee.SetUint64(feeGas)
}
gasFeeCap := new(big.Int).Add(
gasTipCap,
new(big.Int).Mul(baseFee, big.NewInt(2)),
)
gasLimit, err := s.estimateGasLimit(auth, contract, input, nil, gasTipCap, gasFeeCap, value)
if err != nil {
return nil, err
}
return &FeeData{
gasLimit: gasLimit,
gasTipCap: gasTipCap,
gasFeeCap: gasFeeCap,
}, nil
}
func (s *Sender) estimateGasLimit(opts *bind.TransactOpts, contract *common.Address, input []byte, gasPrice, gasTipCap, gasFeeCap, value *big.Int) (uint64, error) {
msg := ethereum.CallMsg{
From: opts.From,
To: contract,
GasPrice: gasPrice,
GasTipCap: gasTipCap,
GasFeeCap: gasFeeCap,
Value: value,
Data: input,
}
gasLimit, err := s.client.EstimateGas(s.ctx, msg)
if err != nil {
return 0, err
}
gasLimit = gasLimit * 15 / 10 // 50% extra gas to void out of gas error
return gasLimit, nil
}

View File

@@ -12,10 +12,8 @@ import (
"sync/atomic"
"time"
geth "github.com/scroll-tech/go-ethereum"
"github.com/scroll-tech/go-ethereum/accounts/abi/bind"
"github.com/scroll-tech/go-ethereum/common"
"github.com/scroll-tech/go-ethereum/common/math"
"github.com/scroll-tech/go-ethereum/core/types"
"github.com/scroll-tech/go-ethereum/ethclient"
"github.com/scroll-tech/go-ethereum/log"
@@ -153,37 +151,10 @@ func (s *Sender) NumberOfAccounts() int {
}
func (s *Sender) getFeeData(auth *bind.TransactOpts, target *common.Address, value *big.Int, data []byte) (*FeeData, error) {
// estimate gas limit
gasLimit, err := s.client.EstimateGas(s.ctx, geth.CallMsg{From: auth.From, To: target, Value: value, Data: data})
if err != nil {
return nil, err
if s.config.TxType == DynamicFeeTxType {
return s.estimateDynamicGas(auth, target, value, data)
}
gasLimit = gasLimit * 15 / 10 // 50% extra gas to void out of gas error
// @todo change it when Scroll enable EIP1559
if s.config.TxType != DynamicFeeTxType {
// estimate gas price
var gasPrice *big.Int
gasPrice, err = s.client.SuggestGasPrice(s.ctx)
if err != nil {
return nil, err
}
return &FeeData{
gasPrice: gasPrice,
gasLimit: gasLimit,
}, nil
}
gasTipCap, err := s.client.SuggestGasTipCap(s.ctx)
if err != nil {
return nil, err
}
// Make sure feeCap is bigger than txpool's gas price. 1000000000 is l2geth's default pool.gas value.
baseFee := atomic.LoadUint64(&s.baseFeePerGas)
maxFeePerGas := math.BigMax(big.NewInt(int64(baseFee)), big.NewInt(1000000000))
return &FeeData{
gasFeeCap: math.BigMax(maxFeePerGas, gasTipCap),
gasTipCap: math.BigMin(maxFeePerGas, gasTipCap),
gasLimit: gasLimit,
}, nil
return s.estimateLegacyGas(auth, target, value, data)
}
// SendTransaction send a signed L2tL1 transaction.

View File

@@ -28,21 +28,28 @@ const TXBatch = 50
var (
privateKeys []*ecdsa.PrivateKey
cfg *config.Config
l2gethImg docker.ImgInstance
base *docker.App
)
func TestMain(m *testing.M) {
base = docker.NewDockerApp()
m.Run()
base.Free()
}
func setupEnv(t *testing.T) {
var err error
cfg, err = config.NewConfig("../config.json")
assert.NoError(t, err)
base.RunImages(t)
priv, err := crypto.HexToECDSA("1212121212121212121212121212121212121212121212121212121212121212")
assert.NoError(t, err)
// Load default private key.
privateKeys = []*ecdsa.PrivateKey{priv}
l2gethImg = docker.NewTestL2Docker(t)
cfg.L1Config.RelayerConfig.SenderConfig.Endpoint = l2gethImg.Endpoint()
cfg.L1Config.RelayerConfig.SenderConfig.Endpoint = base.L2GethEndpoint()
}
func TestSender(t *testing.T) {
@@ -52,11 +59,6 @@ func TestSender(t *testing.T) {
t.Run("test 1 account sender", func(t *testing.T) { testBatchSender(t, 1) })
t.Run("test 3 account sender", func(t *testing.T) { testBatchSender(t, 3) })
t.Run("test 8 account sender", func(t *testing.T) { testBatchSender(t, 8) })
// Teardown
t.Cleanup(func() {
assert.NoError(t, l2gethImg.Stop())
})
}
func testBatchSender(t *testing.T, batchSize int) {

View File

@@ -26,11 +26,7 @@ var (
// private key
privateKey *ecdsa.PrivateKey
// docker consider handler.
l1gethImg docker.ImgInstance
l2gethImg docker.ImgInstance
dbImg docker.ImgInstance
base *docker.App
// clients
l1Client *ethclient.Client
@@ -53,6 +49,14 @@ var (
l2MessengerAddress common.Address
)
func TestMain(m *testing.M) {
base = docker.NewDockerApp()
m.Run()
base.Free()
}
func setupEnv(t *testing.T) {
var err error
privateKey, err = crypto.ToECDSA(common.FromHex("1212121212121212121212121212121212121212121212121212121212121212"))
@@ -75,20 +79,18 @@ func setupEnv(t *testing.T) {
cfg.L2Config.RelayerConfig.MessageSenderPrivateKeys = []*ecdsa.PrivateKey{messagePrivateKey}
cfg.L2Config.RelayerConfig.RollupSenderPrivateKeys = []*ecdsa.PrivateKey{rollupPrivateKey}
cfg.L2Config.RelayerConfig.GasOracleSenderPrivateKeys = []*ecdsa.PrivateKey{gasOraclePrivateKey}
base.RunImages(t)
// Create l1geth container.
l1gethImg = docker.NewTestL1Docker(t)
cfg.L2Config.RelayerConfig.SenderConfig.Endpoint = l1gethImg.Endpoint()
cfg.L1Config.Endpoint = l1gethImg.Endpoint()
cfg.L2Config.RelayerConfig.SenderConfig.Endpoint = base.L1GethEndpoint()
cfg.L1Config.Endpoint = base.L1GethEndpoint()
// Create l2geth container.
l2gethImg = docker.NewTestL2Docker(t)
cfg.L1Config.RelayerConfig.SenderConfig.Endpoint = l2gethImg.Endpoint()
cfg.L2Config.Endpoint = l2gethImg.Endpoint()
cfg.L1Config.RelayerConfig.SenderConfig.Endpoint = base.L2GethEndpoint()
cfg.L2Config.Endpoint = base.L2GethEndpoint()
// Create db container.
dbImg = docker.NewTestDBDocker(t, cfg.DBConfig.DriverName)
cfg.DBConfig.DSN = dbImg.Endpoint()
cfg.DBConfig.DSN = base.DBEndpoint()
// Create l1geth and l2geth client.
l1Client, err = ethclient.Dial(cfg.L1Config.Endpoint)
@@ -144,18 +146,6 @@ func transferEther(t *testing.T, auth *bind.TransactOpts, client *ethclient.Clie
}
}
func free(t *testing.T) {
if dbImg != nil {
assert.NoError(t, dbImg.Stop())
}
if l1gethImg != nil {
assert.NoError(t, l1gethImg.Stop())
}
if l2gethImg != nil {
assert.NoError(t, l2gethImg.Stop())
}
}
func prepareContracts(t *testing.T) {
var err error
var tx *types.Transaction
@@ -217,7 +207,4 @@ func TestFunction(t *testing.T) {
t.Run("TestImportL1GasPrice", testImportL1GasPrice)
t.Run("TestImportL2GasPrice", testImportL2GasPrice)
t.Cleanup(func() {
free(t)
})
}

View File

@@ -1,6 +1,6 @@
imagePrefix = 'scrolltech'
credentialDocker = 'dockerhub'
TAGNAME = ''
pipeline {
agent any
options {
@@ -41,16 +41,38 @@ pipeline {
if (TAGNAME == ""){
return;
}
sh "docker login --username=${dockerUser} --password=${dockerPassword}"
sh "make -C bridge docker"
sh "make -C coordinator docker"
sh "docker tag scrolltech/bridge:latest scrolltech/bridge:${TAGNAME}"
sh "docker tag scrolltech/coordinator:latest scrolltech/coordinator:${TAGNAME}"
sh "docker push scrolltech/bridge:${TAGNAME}"
sh "docker push scrolltech/coordinator:${TAGNAME}"
sh "docker login --username=$dockerUser --password=$dockerPassword"
catchError(buildResult: 'SUCCESS', stageResult: 'SUCCESS') {
script {
try {
sh "docker manifest inspect scrolltech/bridge:$TAGNAME > /dev/null"
} catch (e) {
// only build if the tag non existed
//sh "docker login --username=${dockerUser} --password=${dockerPassword}"
sh "make -C bridge docker"
sh "docker tag scrolltech/bridge:latest scrolltech/bridge:${TAGNAME}"
sh "docker push scrolltech/bridge:${TAGNAME}"
throw e
}
}
}
catchError(buildResult: 'SUCCESS', stageResult: 'SUCCESS') {
script {
try {
sh "docker manifest inspect scrolltech/coordinator:$TAGNAME > /dev/null"
} catch (e) {
// only build if the tag non existed
//sh "docker login --username=${dockerUser} --password=${dockerPassword}"
sh "make -C coordinator docker"
sh "docker tag scrolltech/coordinator:latest scrolltech/coordinator:${TAGNAME}"
sh "docker push scrolltech/coordinator:${TAGNAME}"
throw e
}
}
}
}
}
}
}
}
}
}

View File

@@ -45,6 +45,7 @@ func (t *Cmd) WaitExit() {
// Send interrupt signal.
t.mu.Lock()
_ = t.cmd.Process.Signal(os.Interrupt)
_, _ = t.cmd.Process.Wait()
t.mu.Unlock()
}

234
common/docker/docker_app.go Normal file
View File

@@ -0,0 +1,234 @@
package docker
import (
"context"
"crypto/rand"
"encoding/json"
"fmt"
"math/big"
"os"
"testing"
"time"
"github.com/jmoiron/sqlx"
"github.com/modern-go/reflect2"
"github.com/scroll-tech/go-ethereum/ethclient"
"github.com/stretchr/testify/assert"
"scroll-tech/database"
"scroll-tech/common/cmd"
"scroll-tech/common/utils"
)
var (
l1StartPort = 10000
l2StartPort = 20000
dbStartPort = 30000
)
// App is collection struct of runtime docker images
type App struct {
l1gethImg ImgInstance
l2gethImg ImgInstance
dbImg ImgInstance
dbConfig *database.DBConfig
dbFile string
// common time stamp.
timestamp int
}
// NewDockerApp returns new instance of dokerApp struct
func NewDockerApp() *App {
timestamp := time.Now().Nanosecond()
return &App{
timestamp: timestamp,
dbFile: fmt.Sprintf("/tmp/%d_db-config.json", timestamp),
}
}
// RunImages runs all images togather
func (b *App) RunImages(t *testing.T) {
b.runDBImage(t)
b.runL1Geth(t)
b.runL2Geth(t)
}
func (b *App) runDBImage(t *testing.T) {
if b.dbImg != nil {
return
}
b.dbImg = newTestDBDocker(t, "postgres")
if err := b.mockDBConfig(); err != nil {
_ = b.dbImg.Stop()
b.dbImg = nil
_ = os.Remove(b.dbFile)
t.Fatal(err)
}
}
// RunDBApp runs DB app with command
func (b *App) RunDBApp(t *testing.T, option, keyword string) {
args := []string{option, "--config", b.dbFile}
app := cmd.NewCmd(t, "db_cli-test", args...)
defer app.WaitExit()
// Wait expect result.
app.ExpectWithTimeout(true, time.Second*3, keyword)
app.RunApp(nil)
}
// Free clear all running images
func (b *App) Free() {
if b.l1gethImg != nil {
_ = b.l1gethImg.Stop()
b.l1gethImg = nil
}
if b.l2gethImg != nil {
_ = b.l2gethImg.Stop()
b.l2gethImg = nil
}
if b.dbImg != nil {
_ = b.dbImg.Stop()
b.dbImg = nil
_ = os.Remove(b.dbFile)
}
}
// L1GethEndpoint returns l1gethimg endpoint
func (b *App) L1GethEndpoint() string {
if b.l1gethImg != nil {
return b.l1gethImg.Endpoint()
}
return ""
}
// L2GethEndpoint returns l2gethimg endpoint
func (b *App) L2GethEndpoint() string {
if b.l2gethImg != nil {
return b.l2gethImg.Endpoint()
}
return ""
}
// DBEndpoint returns the endpoint of the dbimg
func (b *App) DBEndpoint() string {
return b.dbImg.Endpoint()
}
func (b *App) runL1Geth(t *testing.T) {
if b.l1gethImg != nil {
return
}
b.l1gethImg = newTestL1Docker(t)
}
// L1Client returns a ethclient by dialing running l1geth
func (b *App) L1Client() (*ethclient.Client, error) {
if b.l1gethImg == nil || reflect2.IsNil(b.l1gethImg) {
return nil, fmt.Errorf("l1 geth is not running")
}
client, err := ethclient.Dial(b.l1gethImg.Endpoint())
if err != nil {
return nil, err
}
return client, nil
}
func (b *App) runL2Geth(t *testing.T) {
if b.l2gethImg != nil {
return
}
b.l2gethImg = newTestL2Docker(t)
}
// L2Client returns a ethclient by dialing running l2geth
func (b *App) L2Client() (*ethclient.Client, error) {
if b.l2gethImg == nil || reflect2.IsNil(b.l2gethImg) {
return nil, fmt.Errorf("l2 geth is not running")
}
client, err := ethclient.Dial(b.l2gethImg.Endpoint())
if err != nil {
return nil, err
}
return client, nil
}
func (b *App) mockDBConfig() error {
if b.dbConfig == nil {
b.dbConfig = &database.DBConfig{
DSN: "",
DriverName: "postgres",
MaxOpenNum: 200,
MaxIdleNum: 20,
}
}
if b.dbImg != nil {
b.dbConfig.DSN = b.dbImg.Endpoint()
}
data, err := json.Marshal(b.dbConfig)
if err != nil {
return err
}
return os.WriteFile(b.dbFile, data, 0644) //nolint:gosec
}
func newTestL1Docker(t *testing.T) ImgInstance {
id, _ := rand.Int(rand.Reader, big.NewInt(2000))
imgL1geth := NewImgGeth(t, "scroll_l1geth", "", "", 0, l1StartPort+int(id.Int64()))
assert.NoError(t, imgL1geth.Start())
// try 3 times to get chainID until is ok.
utils.TryTimes(3, func() bool {
client, _ := ethclient.Dial(imgL1geth.Endpoint())
if client != nil {
if _, err := client.ChainID(context.Background()); err == nil {
return true
}
}
return false
})
return imgL1geth
}
func newTestL2Docker(t *testing.T) ImgInstance {
id, _ := rand.Int(rand.Reader, big.NewInt(2000))
imgL2geth := NewImgGeth(t, "scroll_l2geth", "", "", 0, l2StartPort+int(id.Int64()))
assert.NoError(t, imgL2geth.Start())
// try 3 times to get chainID until is ok.
utils.TryTimes(3, func() bool {
client, _ := ethclient.Dial(imgL2geth.Endpoint())
if client != nil {
if _, err := client.ChainID(context.Background()); err == nil {
return true
}
}
return false
})
return imgL2geth
}
func newTestDBDocker(t *testing.T, driverName string) ImgInstance {
id, _ := rand.Int(rand.Reader, big.NewInt(2000))
imgDB := NewImgDB(t, driverName, "123456", "test_db", dbStartPort+int(id.Int64()))
assert.NoError(t, imgDB.Start())
// try 5 times until the db is ready.
utils.TryTimes(5, func() bool {
db, _ := sqlx.Open(driverName, imgDB.Endpoint())
if db != nil {
return db.Ping() == nil
}
return false
})
return imgDB
}

View File

@@ -1,4 +1,4 @@
package docker
package docker_test
import (
"context"
@@ -6,13 +6,36 @@ import (
"github.com/jmoiron/sqlx"
_ "github.com/lib/pq" //nolint:golint
"github.com/scroll-tech/go-ethereum/ethclient"
"github.com/stretchr/testify/assert"
_ "scroll-tech/database/cmd/app"
"scroll-tech/common/docker"
)
func TestDocker(t *testing.T) {
t.Parallel()
var (
base *docker.App
)
func TestMain(m *testing.M) {
base = docker.NewDockerApp()
m.Run()
base.Free()
}
func TestStartProcess(t *testing.T) {
base.RunImages(t)
// migrate db.
base.RunDBApp(t, "reset", "successful to reset")
base.RunDBApp(t, "migrate", "current version:")
}
func TestDocker(t *testing.T) {
base.RunImages(t)
t.Parallel()
t.Run("testL1Geth", testL1Geth)
t.Run("testL2Geth", testL2Geth)
t.Run("testDB", testDB)
@@ -22,10 +45,7 @@ func testL1Geth(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
img := NewTestL1Docker(t)
defer img.Stop()
client, err := ethclient.Dial(img.Endpoint())
client, err := base.L1Client()
assert.NoError(t, err)
chainID, err := client.ChainID(ctx)
@@ -37,10 +57,7 @@ func testL2Geth(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
img := NewTestL2Docker(t)
defer img.Stop()
client, err := ethclient.Dial(img.Endpoint())
client, err := base.L2Client()
assert.NoError(t, err)
chainID, err := client.ChainID(ctx)
@@ -50,10 +67,8 @@ func testL2Geth(t *testing.T) {
func testDB(t *testing.T) {
driverName := "postgres"
dbImg := NewTestDBDocker(t, driverName)
defer dbImg.Stop()
db, err := sqlx.Open(driverName, dbImg.Endpoint())
db, err := sqlx.Open(driverName, base.DBEndpoint())
assert.NoError(t, err)
assert.NoError(t, db.Ping())
}

View File

@@ -1,78 +0,0 @@
package docker
import (
"context"
"crypto/rand"
"math/big"
"testing"
"github.com/jmoiron/sqlx"
"github.com/scroll-tech/go-ethereum/ethclient"
"github.com/stretchr/testify/assert"
"scroll-tech/common/utils"
)
var (
l1StartPort = 10000
l2StartPort = 20000
dbStartPort = 30000
)
// NewTestL1Docker starts and returns l1geth docker
func NewTestL1Docker(t *testing.T) ImgInstance {
id, _ := rand.Int(rand.Reader, big.NewInt(2000))
imgL1geth := NewImgGeth(t, "scroll_l1geth", "", "", 0, l1StartPort+int(id.Int64()))
assert.NoError(t, imgL1geth.Start())
// try 3 times to get chainID until is ok.
utils.TryTimes(3, func() bool {
client, _ := ethclient.Dial(imgL1geth.Endpoint())
if client != nil {
if _, err := client.ChainID(context.Background()); err == nil {
return true
}
}
return false
})
return imgL1geth
}
// NewTestL2Docker starts and returns l2geth docker
func NewTestL2Docker(t *testing.T) ImgInstance {
id, _ := rand.Int(rand.Reader, big.NewInt(2000))
imgL2geth := NewImgGeth(t, "scroll_l2geth", "", "", 0, l2StartPort+int(id.Int64()))
assert.NoError(t, imgL2geth.Start())
// try 3 times to get chainID until is ok.
utils.TryTimes(3, func() bool {
client, _ := ethclient.Dial(imgL2geth.Endpoint())
if client != nil {
if _, err := client.ChainID(context.Background()); err == nil {
return true
}
}
return false
})
return imgL2geth
}
// NewTestDBDocker starts and returns database docker
func NewTestDBDocker(t *testing.T, driverName string) ImgInstance {
id, _ := rand.Int(rand.Reader, big.NewInt(2000))
imgDB := NewImgDB(t, driverName, "123456", "test_db", dbStartPort+int(id.Int64()))
assert.NoError(t, imgDB.Start())
// try 5 times until the db is ready.
utils.TryTimes(5, func() bool {
db, _ := sqlx.Open(driverName, imgDB.Endpoint())
if db != nil {
return db.Ping() == nil
}
return false
})
return imgDB
}

View File

@@ -8,6 +8,7 @@ require (
github.com/lib/pq v1.10.6
github.com/mattn/go-colorable v0.1.13
github.com/mattn/go-isatty v0.0.16
github.com/modern-go/reflect2 v1.0.1
github.com/orcaman/concurrent-map v1.0.0
github.com/scroll-tech/go-ethereum v1.10.14-0.20230220082843-ec9254b0b1c6
github.com/stretchr/testify v1.8.0
@@ -55,6 +56,7 @@ require (
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/mitchellh/pointerstructure v1.2.0 // indirect
github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/morikuni/aec v1.0.0 // indirect
github.com/olekukonko/tablewriter v0.0.5 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect

View File

@@ -335,7 +335,9 @@ github.com/mitchellh/pointerstructure v1.2.0 h1:O+i9nHnXS3l/9Wu7r4NrEdwA2VFTicjU
github.com/mitchellh/pointerstructure v1.2.0/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4=
github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae h1:O4SWKdcHVCvYqyDV+9CJA1fcDN2L11Bule0iFy3YlAI=
github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=

View File

@@ -368,9 +368,9 @@ checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae"
[[package]]
name = "bounded-collections"
version = "0.1.5"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a071c348a5ef6da1d3a87166b408170b46002382b1dda83992b5c2208cefb370"
checksum = "de2aff4807e40f478132150d80b031f2461d88f061851afcab537d7600c24120"
dependencies = [
"log",
"parity-scale-codec",
@@ -2902,9 +2902,9 @@ dependencies = [
[[package]]
name = "parity-scale-codec"
version = "3.4.0"
version = "3.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "637935964ff85a605d114591d4d2c13c5d1ba2806dae97cea6bf180238a749ac"
checksum = "c3840933452adf7b3b9145e27086a5a3376c619dca1a21b1e5a5af0d54979bed"
dependencies = [
"arrayvec 0.7.2",
"bitvec 1.0.1",
@@ -5014,7 +5014,7 @@ checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987"
[[package]]
name = "types"
version = "0.1.0"
source = "git+https://github.com/scroll-tech/scroll-zkevm?branch=goerli-0215#d0d3338663a0b3eee51e9d044ab96a7899d70252"
source = "git+https://github.com/scroll-tech/scroll-zkevm?branch=goerli-0215#1f7a3c7da2370860087555a11346bd5d96f609fd"
dependencies = [
"base64 0.13.0",
"blake2",
@@ -5682,7 +5682,7 @@ dependencies = [
[[package]]
name = "zkevm"
version = "0.1.0"
source = "git+https://github.com/scroll-tech/scroll-zkevm?branch=goerli-0215#d0d3338663a0b3eee51e9d044ab96a7899d70252"
source = "git+https://github.com/scroll-tech/scroll-zkevm?branch=goerli-0215#1f7a3c7da2370860087555a11346bd5d96f609fd"
dependencies = [
"anyhow",
"blake2",

View File

@@ -39,6 +39,14 @@ type BatchData struct {
piCfg *PublicInputHashConfig
}
// Timestamp returns the timestamp of the first block in the BlockData.
func (b *BatchData) Timestamp() uint64 {
if len(b.Batch.Blocks) == 0 {
return 0
}
return b.Batch.Blocks[0].Timestamp
}
// Hash calculates the hash of this batch.
func (b *BatchData) Hash() *common.Hash {
if b.hash != nil {

View File

@@ -5,7 +5,7 @@ import (
"runtime/debug"
)
var tag = "alpha-v1.8"
var tag = "alpha-v1.18"
var commit = func() string {
if info, ok := debug.ReadBuildInfo(); ok {

View File

@@ -0,0 +1,30 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.10;
import { Script } from "forge-std/Script.sol";
import { console } from "forge-std/console.sol";
import { WETH9 } from "../../src/L2/predeploys/WETH9.sol";
contract DeployWeth is Script {
address L1_WETH_ADDR = vm.envAddress("L1_WETH_ADDR");
address L2_WETH_ADDR = vm.envAddress("L2_WETH_ADDR");
function run() external {
// deploy weth only if we're running a private L1 network
if (L1_WETH_ADDR == address(0)) {
uint256 L1_WETH_DEPLOYER_PRIVATE_KEY = vm.envUint("L1_WETH_DEPLOYER_PRIVATE_KEY");
vm.startBroadcast(L1_WETH_DEPLOYER_PRIVATE_KEY);
WETH9 weth = new WETH9();
L1_WETH_ADDR = address(weth);
vm.stopBroadcast();
}
logAddress("L1_WETH_ADDR", L1_WETH_ADDR);
logAddress("L2_WETH_ADDR", L2_WETH_ADDR);
}
function logAddress(string memory name, address addr) internal view {
console.log(string(abi.encodePacked(name, "=", vm.toString(address(addr)))));
}
}

View File

@@ -105,9 +105,21 @@ contract L1ScrollMessenger is PausableUpgradeable, ScrollMessengerBase, IL1Scrol
// record the message hash for future use.
bytes32 _xDomainCalldataHash = keccak256(_xDomainCalldata);
// normally this won't happen, since each message has different nonce, but just in case.
require(!isL1MessageSent[_xDomainCalldataHash], "Duplicated message");
isL1MessageSent[_xDomainCalldataHash] = true;
emit SentMessage(msg.sender, _to, _value, _messageNonce, _gasLimit, _message);
// refund fee to tx.origin
unchecked {
uint256 _refund = msg.value - _fee - _value;
if (_refund > 0) {
(bool _success, ) = tx.origin.call{ value: _refund }("");
require(_success, "Failed to refund the fee");
}
}
}
/// @inheritdoc IL1ScrollMessenger

View File

@@ -175,19 +175,29 @@ contract L2ScrollMessenger is ScrollMessengerBase, PausableUpgradeable, IL2Scrol
uint256 _fee = _gasLimit * IL1GasPriceOracle(gasOracle).l1BaseFee();
require(msg.value >= _value + _fee, "Insufficient msg.value");
if (_fee > 0) {
(bool _success, ) = feeVault.call{ value: msg.value - _value }("");
(bool _success, ) = feeVault.call{ value: _fee }("");
require(_success, "Failed to deduct the fee");
}
uint256 _nonce = L2MessageQueue(messageQueue).nextMessageIndex();
bytes32 _xDomainCalldataHash = keccak256(_encodeXDomainCalldata(msg.sender, _to, _value, _nonce, _message));
// normally this won't happen, since each message has different nonce, but just in case.
require(!isL2MessageSent[_xDomainCalldataHash], "Duplicated message");
isL2MessageSent[_xDomainCalldataHash] = true;
L2MessageQueue(messageQueue).appendMessage(_xDomainCalldataHash);
emit SentMessage(msg.sender, _to, _value, _nonce, _gasLimit, _message);
// refund fee to tx.origin
unchecked {
uint256 _refund = msg.value - _fee - _value;
if (_refund > 0) {
(bool _success, ) = tx.origin.call{ value: _refund }("");
require(_success, "Failed to refund the fee");
}
}
}
/// @inheritdoc IL2ScrollMessenger
@@ -262,7 +272,9 @@ contract L2ScrollMessenger is ScrollMessengerBase, PausableUpgradeable, IL2Scrol
bytes memory _message,
bytes32 _xDomainCalldataHash
) internal {
// @todo check `_to` address to avoid attack.
// @todo check more `_to` address to avoid attack.
require(_to != messageQueue, "Forbid to call message queue");
require(_to != address(this), "Forbid to call self");
// @note This usually will never happen, just in case.
require(_from != xDomainMessageSender, "Invalid message sender");

View File

@@ -342,18 +342,18 @@ contract L1CustomERC20GatewayTest is L1GatewayTestBase {
hevm.expectRevert("no corresponding l2 token");
if (useRouter) {
router.depositERC20{ value: feeToPay }(address(l1Token), amount, gasLimit);
router.depositERC20{ value: feeToPay + extraValue }(address(l1Token), amount, gasLimit);
} else {
gateway.depositERC20{ value: feeToPay }(address(l1Token), amount, gasLimit);
gateway.depositERC20{ value: feeToPay + extraValue }(address(l1Token), amount, gasLimit);
}
gateway.updateTokenMapping(address(l1Token), address(l2Token));
if (amount == 0) {
hevm.expectRevert("deposit zero amount");
if (useRouter) {
router.depositERC20{ value: feeToPay }(address(l1Token), amount, gasLimit);
router.depositERC20{ value: feeToPay + extraValue }(address(l1Token), amount, gasLimit);
} else {
gateway.depositERC20{ value: feeToPay }(address(l1Token), amount, gasLimit);
gateway.depositERC20{ value: feeToPay + extraValue }(address(l1Token), amount, gasLimit);
}
} else {
// emit QueueTransaction from L1MessageQueue
@@ -377,9 +377,9 @@ contract L1CustomERC20GatewayTest is L1GatewayTestBase {
uint256 feeVaultBalance = address(feeVault).balance;
assertBoolEq(false, l1Messenger.isL1MessageSent(keccak256(xDomainCalldata)));
if (useRouter) {
router.depositERC20{ value: feeToPay }(address(l1Token), amount, gasLimit);
router.depositERC20{ value: feeToPay + extraValue }(address(l1Token), amount, gasLimit);
} else {
gateway.depositERC20{ value: feeToPay }(address(l1Token), amount, gasLimit);
gateway.depositERC20{ value: feeToPay + extraValue }(address(l1Token), amount, gasLimit);
}
assertEq(amount + gatewayBalance, l1Token.balanceOf(address(gateway)));
assertEq(feeToPay + feeVaultBalance, address(feeVault).balance);
@@ -421,18 +421,18 @@ contract L1CustomERC20GatewayTest is L1GatewayTestBase {
hevm.expectRevert("no corresponding l2 token");
if (useRouter) {
router.depositERC20{ value: feeToPay }(address(l1Token), amount, gasLimit);
router.depositERC20{ value: feeToPay + extraValue }(address(l1Token), amount, gasLimit);
} else {
gateway.depositERC20{ value: feeToPay }(address(l1Token), amount, gasLimit);
gateway.depositERC20{ value: feeToPay + extraValue }(address(l1Token), amount, gasLimit);
}
gateway.updateTokenMapping(address(l1Token), address(l2Token));
if (amount == 0) {
hevm.expectRevert("deposit zero amount");
if (useRouter) {
router.depositERC20{ value: feeToPay }(address(l1Token), recipient, amount, gasLimit);
router.depositERC20{ value: feeToPay + extraValue }(address(l1Token), recipient, amount, gasLimit);
} else {
gateway.depositERC20{ value: feeToPay }(address(l1Token), recipient, amount, gasLimit);
gateway.depositERC20{ value: feeToPay + extraValue }(address(l1Token), recipient, amount, gasLimit);
}
} else {
// emit QueueTransaction from L1MessageQueue
@@ -456,9 +456,9 @@ contract L1CustomERC20GatewayTest is L1GatewayTestBase {
uint256 feeVaultBalance = address(feeVault).balance;
assertBoolEq(false, l1Messenger.isL1MessageSent(keccak256(xDomainCalldata)));
if (useRouter) {
router.depositERC20{ value: feeToPay }(address(l1Token), recipient, amount, gasLimit);
router.depositERC20{ value: feeToPay + extraValue }(address(l1Token), recipient, amount, gasLimit);
} else {
gateway.depositERC20{ value: feeToPay }(address(l1Token), recipient, amount, gasLimit);
gateway.depositERC20{ value: feeToPay + extraValue }(address(l1Token), recipient, amount, gasLimit);
}
assertEq(amount + gatewayBalance, l1Token.balanceOf(address(gateway)));
assertEq(feeToPay + feeVaultBalance, address(feeVault).balance);
@@ -501,18 +501,30 @@ contract L1CustomERC20GatewayTest is L1GatewayTestBase {
hevm.expectRevert("no corresponding l2 token");
if (useRouter) {
router.depositERC20{ value: feeToPay }(address(l1Token), amount, gasLimit);
router.depositERC20{ value: feeToPay + extraValue }(address(l1Token), amount, gasLimit);
} else {
gateway.depositERC20{ value: feeToPay }(address(l1Token), amount, gasLimit);
gateway.depositERC20{ value: feeToPay + extraValue }(address(l1Token), amount, gasLimit);
}
gateway.updateTokenMapping(address(l1Token), address(l2Token));
if (amount == 0) {
hevm.expectRevert("deposit zero amount");
if (useRouter) {
router.depositERC20AndCall{ value: feeToPay }(address(l1Token), recipient, amount, dataToCall, gasLimit);
router.depositERC20AndCall{ value: feeToPay + extraValue }(
address(l1Token),
recipient,
amount,
dataToCall,
gasLimit
);
} else {
gateway.depositERC20AndCall{ value: feeToPay }(address(l1Token), recipient, amount, dataToCall, gasLimit);
gateway.depositERC20AndCall{ value: feeToPay + extraValue }(
address(l1Token),
recipient,
amount,
dataToCall,
gasLimit
);
}
} else {
// emit QueueTransaction from L1MessageQueue
@@ -536,9 +548,21 @@ contract L1CustomERC20GatewayTest is L1GatewayTestBase {
uint256 feeVaultBalance = address(feeVault).balance;
assertBoolEq(false, l1Messenger.isL1MessageSent(keccak256(xDomainCalldata)));
if (useRouter) {
router.depositERC20AndCall{ value: feeToPay }(address(l1Token), recipient, amount, dataToCall, gasLimit);
router.depositERC20AndCall{ value: feeToPay + extraValue }(
address(l1Token),
recipient,
amount,
dataToCall,
gasLimit
);
} else {
gateway.depositERC20AndCall{ value: feeToPay }(address(l1Token), recipient, amount, dataToCall, gasLimit);
gateway.depositERC20AndCall{ value: feeToPay + extraValue }(
address(l1Token),
recipient,
amount,
dataToCall,
gasLimit
);
}
assertEq(amount + gatewayBalance, l1Token.balanceOf(address(gateway)));
assertEq(feeToPay + feeVaultBalance, address(feeVault).balance);

View File

@@ -623,7 +623,7 @@ contract L1ERC1155GatewayTest is L1GatewayTestBase, ERC1155TokenReceiver {
if (amount == 0) {
hevm.expectRevert("deposit zero amount");
gateway.depositERC1155{ value: feeToPay }(address(l1Token), tokenId, amount, gasLimit);
gateway.depositERC1155{ value: feeToPay + extraValue }(address(l1Token), tokenId, amount, gasLimit);
} else {
hevm.expectRevert("token not supported");
gateway.depositERC1155(address(l1Token), tokenId, amount, gasLimit);
@@ -649,7 +649,7 @@ contract L1ERC1155GatewayTest is L1GatewayTestBase, ERC1155TokenReceiver {
uint256 gatewayBalance = l1Token.balanceOf(address(gateway), tokenId);
uint256 feeVaultBalance = address(feeVault).balance;
assertBoolEq(false, l1Messenger.isL1MessageSent(keccak256(xDomainCalldata)));
gateway.depositERC1155{ value: feeToPay }(address(l1Token), tokenId, amount, gasLimit);
gateway.depositERC1155{ value: feeToPay + extraValue }(address(l1Token), tokenId, amount, gasLimit);
assertEq(amount + gatewayBalance, l1Token.balanceOf(address(gateway), tokenId));
assertEq(feeToPay + feeVaultBalance, address(feeVault).balance);
assertBoolEq(true, l1Messenger.isL1MessageSent(keccak256(xDomainCalldata)));
@@ -691,7 +691,7 @@ contract L1ERC1155GatewayTest is L1GatewayTestBase, ERC1155TokenReceiver {
if (amount == 0) {
hevm.expectRevert("deposit zero amount");
gateway.depositERC1155{ value: feeToPay }(address(l1Token), recipient, tokenId, amount, gasLimit);
gateway.depositERC1155{ value: feeToPay + extraValue }(address(l1Token), recipient, tokenId, amount, gasLimit);
} else {
hevm.expectRevert("token not supported");
gateway.depositERC1155(address(l1Token), tokenId, amount, gasLimit);
@@ -717,7 +717,7 @@ contract L1ERC1155GatewayTest is L1GatewayTestBase, ERC1155TokenReceiver {
uint256 gatewayBalance = l1Token.balanceOf(address(gateway), tokenId);
uint256 feeVaultBalance = address(feeVault).balance;
assertBoolEq(false, l1Messenger.isL1MessageSent(keccak256(xDomainCalldata)));
gateway.depositERC1155{ value: feeToPay }(address(l1Token), recipient, tokenId, amount, gasLimit);
gateway.depositERC1155{ value: feeToPay + extraValue }(address(l1Token), recipient, tokenId, amount, gasLimit);
assertEq(amount + gatewayBalance, l1Token.balanceOf(address(gateway), tokenId));
assertEq(feeToPay + feeVaultBalance, address(feeVault).balance);
assertBoolEq(true, l1Messenger.isL1MessageSent(keccak256(xDomainCalldata)));
@@ -800,7 +800,7 @@ contract L1ERC1155GatewayTest is L1GatewayTestBase, ERC1155TokenReceiver {
}
uint256 feeVaultBalance = address(feeVault).balance;
assertBoolEq(false, l1Messenger.isL1MessageSent(keccak256(xDomainCalldata)));
gateway.batchDepositERC1155{ value: feeToPay }(address(l1Token), _tokenIds, _amounts, gasLimit);
gateway.batchDepositERC1155{ value: feeToPay + extraValue }(address(l1Token), _tokenIds, _amounts, gasLimit);
for (uint256 i = 0; i < tokenCount; i++) {
assertEq(gatewayBalances[i] + amount, l1Token.balanceOf(address(gateway), i));
}
@@ -885,7 +885,13 @@ contract L1ERC1155GatewayTest is L1GatewayTestBase, ERC1155TokenReceiver {
}
uint256 feeVaultBalance = address(feeVault).balance;
assertBoolEq(false, l1Messenger.isL1MessageSent(keccak256(xDomainCalldata)));
gateway.batchDepositERC1155{ value: feeToPay }(address(l1Token), recipient, _tokenIds, _amounts, gasLimit);
gateway.batchDepositERC1155{ value: feeToPay + extraValue }(
address(l1Token),
recipient,
_tokenIds,
_amounts,
gasLimit
);
for (uint256 i = 0; i < tokenCount; i++) {
assertEq(gatewayBalances[i] + amount, l1Token.balanceOf(address(gateway), i));
}

View File

@@ -602,7 +602,7 @@ contract L1ERC721GatewayTest is L1GatewayTestBase {
uint256 gatewayBalance = l1Token.balanceOf(address(gateway));
uint256 feeVaultBalance = address(feeVault).balance;
assertBoolEq(false, l1Messenger.isL1MessageSent(keccak256(xDomainCalldata)));
gateway.depositERC721{ value: feeToPay }(address(l1Token), tokenId, gasLimit);
gateway.depositERC721{ value: feeToPay + extraValue }(address(l1Token), tokenId, gasLimit);
assertEq(address(gateway), l1Token.ownerOf(tokenId));
assertEq(1 + gatewayBalance, l1Token.balanceOf(address(gateway)));
assertEq(feeToPay + feeVaultBalance, address(feeVault).balance);
@@ -665,7 +665,7 @@ contract L1ERC721GatewayTest is L1GatewayTestBase {
uint256 gatewayBalance = l1Token.balanceOf(address(gateway));
uint256 feeVaultBalance = address(feeVault).balance;
assertBoolEq(false, l1Messenger.isL1MessageSent(keccak256(xDomainCalldata)));
gateway.depositERC721{ value: feeToPay }(address(l1Token), recipient, tokenId, gasLimit);
gateway.depositERC721{ value: feeToPay + extraValue }(address(l1Token), recipient, tokenId, gasLimit);
assertEq(address(gateway), l1Token.ownerOf(tokenId));
assertEq(1 + gatewayBalance, l1Token.balanceOf(address(gateway)));
assertEq(feeToPay + feeVaultBalance, address(feeVault).balance);
@@ -737,7 +737,7 @@ contract L1ERC721GatewayTest is L1GatewayTestBase {
uint256 gatewayBalance = l1Token.balanceOf(address(gateway));
uint256 feeVaultBalance = address(feeVault).balance;
assertBoolEq(false, l1Messenger.isL1MessageSent(keccak256(xDomainCalldata)));
gateway.batchDepositERC721{ value: feeToPay }(address(l1Token), _tokenIds, gasLimit);
gateway.batchDepositERC721{ value: feeToPay + extraValue }(address(l1Token), _tokenIds, gasLimit);
for (uint256 i = 0; i < tokenCount; i++) {
assertEq(l1Token.ownerOf(i), address(gateway));
}
@@ -812,7 +812,7 @@ contract L1ERC721GatewayTest is L1GatewayTestBase {
uint256 gatewayBalance = l1Token.balanceOf(address(gateway));
uint256 feeVaultBalance = address(feeVault).balance;
assertBoolEq(false, l1Messenger.isL1MessageSent(keccak256(xDomainCalldata)));
gateway.batchDepositERC721{ value: feeToPay }(address(l1Token), recipient, _tokenIds, gasLimit);
gateway.batchDepositERC721{ value: feeToPay + extraValue }(address(l1Token), recipient, _tokenIds, gasLimit);
for (uint256 i = 0; i < tokenCount; i++) {
assertEq(l1Token.ownerOf(i), address(gateway));
}

View File

@@ -192,12 +192,8 @@ contract L1ETHGatewayTest is L1GatewayTestBase {
uint256 amount,
bytes memory dataToCall
) public {
uint256 size;
assembly {
size := extcodesize(recipient)
}
hevm.assume(size == 0);
hevm.assume(recipient != address(0));
hevm.assume(recipient.code.length == 0);
hevm.assume(uint256(uint160(recipient)) > 100); // ignore some precompile contracts
amount = bound(amount, 1, address(this).balance / 2);
@@ -305,9 +301,9 @@ contract L1ETHGatewayTest is L1GatewayTestBase {
uint256 feeVaultBalance = address(feeVault).balance;
assertBoolEq(false, l1Messenger.isL1MessageSent(keccak256(xDomainCalldata)));
if (useRouter) {
router.depositETH{ value: amount + feeToPay }(amount, gasLimit);
router.depositETH{ value: amount + feeToPay + extraValue }(amount, gasLimit);
} else {
gateway.depositETH{ value: amount + feeToPay }(amount, gasLimit);
gateway.depositETH{ value: amount + feeToPay + extraValue }(amount, gasLimit);
}
assertEq(amount + messengerBalance, address(l1Messenger).balance);
assertEq(feeToPay + feeVaultBalance, address(feeVault).balance);
@@ -374,9 +370,9 @@ contract L1ETHGatewayTest is L1GatewayTestBase {
uint256 feeVaultBalance = address(feeVault).balance;
assertBoolEq(false, l1Messenger.isL1MessageSent(keccak256(xDomainCalldata)));
if (useRouter) {
router.depositETH{ value: amount + feeToPay }(recipient, amount, gasLimit);
router.depositETH{ value: amount + feeToPay + extraValue }(recipient, amount, gasLimit);
} else {
gateway.depositETH{ value: amount + feeToPay }(recipient, amount, gasLimit);
gateway.depositETH{ value: amount + feeToPay + extraValue }(recipient, amount, gasLimit);
}
assertEq(amount + messengerBalance, address(l1Messenger).balance);
assertEq(feeToPay + feeVaultBalance, address(feeVault).balance);
@@ -444,9 +440,9 @@ contract L1ETHGatewayTest is L1GatewayTestBase {
uint256 feeVaultBalance = address(feeVault).balance;
assertBoolEq(false, l1Messenger.isL1MessageSent(keccak256(xDomainCalldata)));
if (useRouter) {
router.depositETHAndCall{ value: amount + feeToPay }(recipient, amount, dataToCall, gasLimit);
router.depositETHAndCall{ value: amount + feeToPay + extraValue }(recipient, amount, dataToCall, gasLimit);
} else {
gateway.depositETHAndCall{ value: amount + feeToPay }(recipient, amount, dataToCall, gasLimit);
gateway.depositETHAndCall{ value: amount + feeToPay + extraValue }(recipient, amount, dataToCall, gasLimit);
}
assertEq(amount + messengerBalance, address(l1Messenger).balance);
assertEq(feeToPay + feeVaultBalance, address(feeVault).balance);

View File

@@ -34,6 +34,9 @@ abstract contract L1GatewayTestBase is DSTestPlus {
event RelayedMessage(bytes32 indexed messageHash);
event FailedRelayedMessage(bytes32 indexed messageHash);
// pay 0.1 extra ETH to test refund
uint256 internal constant extraValue = 1e17;
L1ScrollMessenger internal l1Messenger;
L1MessageQueue internal messageQueue;
L2GasPriceOracle internal gasOracle;

View File

@@ -418,9 +418,9 @@ contract L1StandardERC20GatewayTest is L1GatewayTestBase {
if (amount == 0) {
hevm.expectRevert("deposit zero amount");
if (useRouter) {
router.depositERC20{ value: feeToPay }(address(l1Token), amount, gasLimit);
router.depositERC20{ value: feeToPay + extraValue }(address(l1Token), amount, gasLimit);
} else {
gateway.depositERC20{ value: feeToPay }(address(l1Token), amount, gasLimit);
gateway.depositERC20{ value: feeToPay + extraValue }(address(l1Token), amount, gasLimit);
}
} else {
// emit QueueTransaction from L1MessageQueue
@@ -444,9 +444,9 @@ contract L1StandardERC20GatewayTest is L1GatewayTestBase {
uint256 feeVaultBalance = address(feeVault).balance;
assertBoolEq(false, l1Messenger.isL1MessageSent(keccak256(xDomainCalldata)));
if (useRouter) {
router.depositERC20{ value: feeToPay }(address(l1Token), amount, gasLimit);
router.depositERC20{ value: feeToPay + extraValue }(address(l1Token), amount, gasLimit);
} else {
gateway.depositERC20{ value: feeToPay }(address(l1Token), amount, gasLimit);
gateway.depositERC20{ value: feeToPay + extraValue }(address(l1Token), amount, gasLimit);
}
assertEq(amount + gatewayBalance, l1Token.balanceOf(address(gateway)));
assertEq(feeToPay + feeVaultBalance, address(feeVault).balance);
@@ -489,9 +489,9 @@ contract L1StandardERC20GatewayTest is L1GatewayTestBase {
if (amount == 0) {
hevm.expectRevert("deposit zero amount");
if (useRouter) {
router.depositERC20{ value: feeToPay }(address(l1Token), recipient, amount, gasLimit);
router.depositERC20{ value: feeToPay + extraValue }(address(l1Token), recipient, amount, gasLimit);
} else {
gateway.depositERC20{ value: feeToPay }(address(l1Token), recipient, amount, gasLimit);
gateway.depositERC20{ value: feeToPay + extraValue }(address(l1Token), recipient, amount, gasLimit);
}
} else {
// emit QueueTransaction from L1MessageQueue
@@ -515,9 +515,9 @@ contract L1StandardERC20GatewayTest is L1GatewayTestBase {
uint256 feeVaultBalance = address(feeVault).balance;
assertBoolEq(false, l1Messenger.isL1MessageSent(keccak256(xDomainCalldata)));
if (useRouter) {
router.depositERC20{ value: feeToPay }(address(l1Token), recipient, amount, gasLimit);
router.depositERC20{ value: feeToPay + extraValue }(address(l1Token), recipient, amount, gasLimit);
} else {
gateway.depositERC20{ value: feeToPay }(address(l1Token), recipient, amount, gasLimit);
gateway.depositERC20{ value: feeToPay + extraValue }(address(l1Token), recipient, amount, gasLimit);
}
assertEq(amount + gatewayBalance, l1Token.balanceOf(address(gateway)));
assertEq(feeToPay + feeVaultBalance, address(feeVault).balance);
@@ -561,9 +561,21 @@ contract L1StandardERC20GatewayTest is L1GatewayTestBase {
if (amount == 0) {
hevm.expectRevert("deposit zero amount");
if (useRouter) {
router.depositERC20AndCall{ value: feeToPay }(address(l1Token), recipient, amount, dataToCall, gasLimit);
router.depositERC20AndCall{ value: feeToPay + extraValue }(
address(l1Token),
recipient,
amount,
dataToCall,
gasLimit
);
} else {
gateway.depositERC20AndCall{ value: feeToPay }(address(l1Token), recipient, amount, dataToCall, gasLimit);
gateway.depositERC20AndCall{ value: feeToPay + extraValue }(
address(l1Token),
recipient,
amount,
dataToCall,
gasLimit
);
}
} else {
// emit QueueTransaction from L1MessageQueue
@@ -587,9 +599,21 @@ contract L1StandardERC20GatewayTest is L1GatewayTestBase {
uint256 feeVaultBalance = address(feeVault).balance;
assertBoolEq(false, l1Messenger.isL1MessageSent(keccak256(xDomainCalldata)));
if (useRouter) {
router.depositERC20AndCall{ value: feeToPay }(address(l1Token), recipient, amount, dataToCall, gasLimit);
router.depositERC20AndCall{ value: feeToPay + extraValue }(
address(l1Token),
recipient,
amount,
dataToCall,
gasLimit
);
} else {
gateway.depositERC20AndCall{ value: feeToPay }(address(l1Token), recipient, amount, dataToCall, gasLimit);
gateway.depositERC20AndCall{ value: feeToPay + extraValue }(
address(l1Token),
recipient,
amount,
dataToCall,
gasLimit
);
}
assertEq(amount + gatewayBalance, l1Token.balanceOf(address(gateway)));
assertEq(feeToPay + feeVaultBalance, address(feeVault).balance);

View File

@@ -369,9 +369,9 @@ contract L1WETHGatewayTest is L1GatewayTestBase {
if (amount == 0) {
hevm.expectRevert("deposit zero amount");
if (useRouter) {
router.depositERC20{ value: feeToPay }(address(l1weth), amount, gasLimit);
router.depositERC20{ value: feeToPay + extraValue }(address(l1weth), amount, gasLimit);
} else {
gateway.depositERC20{ value: feeToPay }(address(l1weth), amount, gasLimit);
gateway.depositERC20{ value: feeToPay + extraValue }(address(l1weth), amount, gasLimit);
}
} else {
// token is not l1WETH
@@ -399,9 +399,9 @@ contract L1WETHGatewayTest is L1GatewayTestBase {
uint256 feeVaultBalance = address(feeVault).balance;
assertBoolEq(false, l1Messenger.isL1MessageSent(keccak256(xDomainCalldata)));
if (useRouter) {
router.depositERC20{ value: feeToPay }(address(l1weth), amount, gasLimit);
router.depositERC20{ value: feeToPay + extraValue }(address(l1weth), amount, gasLimit);
} else {
gateway.depositERC20{ value: feeToPay }(address(l1weth), amount, gasLimit);
gateway.depositERC20{ value: feeToPay + extraValue }(address(l1weth), amount, gasLimit);
}
assertEq(amount + messengerBalance, address(l1Messenger).balance);
assertEq(feeToPay + feeVaultBalance, address(feeVault).balance);
@@ -444,9 +444,9 @@ contract L1WETHGatewayTest is L1GatewayTestBase {
if (amount == 0) {
hevm.expectRevert("deposit zero amount");
if (useRouter) {
router.depositERC20{ value: feeToPay }(address(l1weth), recipient, amount, gasLimit);
router.depositERC20{ value: feeToPay + extraValue }(address(l1weth), recipient, amount, gasLimit);
} else {
gateway.depositERC20{ value: feeToPay }(address(l1weth), recipient, amount, gasLimit);
gateway.depositERC20{ value: feeToPay + extraValue }(address(l1weth), recipient, amount, gasLimit);
}
} else {
// token is not l1WETH
@@ -474,9 +474,9 @@ contract L1WETHGatewayTest is L1GatewayTestBase {
uint256 feeVaultBalance = address(feeVault).balance;
assertBoolEq(false, l1Messenger.isL1MessageSent(keccak256(xDomainCalldata)));
if (useRouter) {
router.depositERC20{ value: feeToPay }(address(l1weth), recipient, amount, gasLimit);
router.depositERC20{ value: feeToPay + extraValue }(address(l1weth), recipient, amount, gasLimit);
} else {
gateway.depositERC20{ value: feeToPay }(address(l1weth), recipient, amount, gasLimit);
gateway.depositERC20{ value: feeToPay + extraValue }(address(l1weth), recipient, amount, gasLimit);
}
assertEq(amount + messengerBalance, address(l1Messenger).balance);
assertEq(feeToPay + feeVaultBalance, address(feeVault).balance);
@@ -520,9 +520,21 @@ contract L1WETHGatewayTest is L1GatewayTestBase {
if (amount == 0) {
hevm.expectRevert("deposit zero amount");
if (useRouter) {
router.depositERC20AndCall{ value: feeToPay }(address(l1weth), recipient, amount, dataToCall, gasLimit);
router.depositERC20AndCall{ value: feeToPay + extraValue }(
address(l1weth),
recipient,
amount,
dataToCall,
gasLimit
);
} else {
gateway.depositERC20AndCall{ value: feeToPay }(address(l1weth), recipient, amount, dataToCall, gasLimit);
gateway.depositERC20AndCall{ value: feeToPay + extraValue }(
address(l1weth),
recipient,
amount,
dataToCall,
gasLimit
);
}
} else {
// token is not l1WETH
@@ -550,9 +562,21 @@ contract L1WETHGatewayTest is L1GatewayTestBase {
uint256 feeVaultBalance = address(feeVault).balance;
assertBoolEq(false, l1Messenger.isL1MessageSent(keccak256(xDomainCalldata)));
if (useRouter) {
router.depositERC20AndCall{ value: feeToPay }(address(l1weth), recipient, amount, dataToCall, gasLimit);
router.depositERC20AndCall{ value: feeToPay + extraValue }(
address(l1weth),
recipient,
amount,
dataToCall,
gasLimit
);
} else {
gateway.depositERC20AndCall{ value: feeToPay }(address(l1weth), recipient, amount, dataToCall, gasLimit);
gateway.depositERC20AndCall{ value: feeToPay + extraValue }(
address(l1weth),
recipient,
amount,
dataToCall,
gasLimit
);
}
assertEq(amount + messengerBalance, address(l1Messenger).balance);
assertEq(feeToPay + feeVaultBalance, address(feeVault).balance);

View File

@@ -237,6 +237,7 @@ contract L2CustomERC20GatewayTest is L2GatewayTestBase {
) public {
// blacklist some addresses
hevm.assume(recipient != address(0));
hevm.assume(recipient != address(gateway));
gateway.updateTokenMapping(address(l2Token), address(l1Token));
@@ -315,18 +316,18 @@ contract L2CustomERC20GatewayTest is L2GatewayTestBase {
hevm.expectRevert("no corresponding l1 token");
if (useRouter) {
router.withdrawERC20{ value: feeToPay }(address(l2Token), amount, gasLimit);
router.withdrawERC20{ value: feeToPay + extraValue }(address(l2Token), amount, gasLimit);
} else {
gateway.withdrawERC20{ value: feeToPay }(address(l2Token), amount, gasLimit);
gateway.withdrawERC20{ value: feeToPay + extraValue }(address(l2Token), amount, gasLimit);
}
gateway.updateTokenMapping(address(l2Token), address(l1Token));
if (amount == 0) {
hevm.expectRevert("withdraw zero amount");
if (useRouter) {
router.withdrawERC20{ value: feeToPay }(address(l2Token), amount, gasLimit);
router.withdrawERC20{ value: feeToPay + extraValue }(address(l2Token), amount, gasLimit);
} else {
gateway.withdrawERC20{ value: feeToPay }(address(l2Token), amount, gasLimit);
gateway.withdrawERC20{ value: feeToPay + extraValue }(address(l2Token), amount, gasLimit);
}
} else {
// emit AppendMessage from L2MessageQueue
@@ -349,9 +350,9 @@ contract L2CustomERC20GatewayTest is L2GatewayTestBase {
uint256 feeVaultBalance = address(feeVault).balance;
assertBoolEq(false, l2Messenger.isL2MessageSent(keccak256(xDomainCalldata)));
if (useRouter) {
router.withdrawERC20{ value: feeToPay }(address(l2Token), amount, gasLimit);
router.withdrawERC20{ value: feeToPay + extraValue }(address(l2Token), amount, gasLimit);
} else {
gateway.withdrawERC20{ value: feeToPay }(address(l2Token), amount, gasLimit);
gateway.withdrawERC20{ value: feeToPay + extraValue }(address(l2Token), amount, gasLimit);
}
assertEq(gatewayBalance, l1Token.balanceOf(address(gateway)));
assertEq(feeToPay + feeVaultBalance, address(feeVault).balance);
@@ -393,18 +394,18 @@ contract L2CustomERC20GatewayTest is L2GatewayTestBase {
hevm.expectRevert("no corresponding l1 token");
if (useRouter) {
router.withdrawERC20{ value: feeToPay }(address(l2Token), amount, gasLimit);
router.withdrawERC20{ value: feeToPay + extraValue }(address(l2Token), amount, gasLimit);
} else {
gateway.withdrawERC20{ value: feeToPay }(address(l2Token), amount, gasLimit);
gateway.withdrawERC20{ value: feeToPay + extraValue }(address(l2Token), amount, gasLimit);
}
gateway.updateTokenMapping(address(l2Token), address(l1Token));
if (amount == 0) {
hevm.expectRevert("withdraw zero amount");
if (useRouter) {
router.withdrawERC20{ value: feeToPay }(address(l2Token), recipient, amount, gasLimit);
router.withdrawERC20{ value: feeToPay + extraValue }(address(l2Token), recipient, amount, gasLimit);
} else {
gateway.withdrawERC20{ value: feeToPay }(address(l2Token), recipient, amount, gasLimit);
gateway.withdrawERC20{ value: feeToPay + extraValue }(address(l2Token), recipient, amount, gasLimit);
}
} else {
// emit AppendMessage from L2MessageQueue
@@ -427,9 +428,9 @@ contract L2CustomERC20GatewayTest is L2GatewayTestBase {
uint256 feeVaultBalance = address(feeVault).balance;
assertBoolEq(false, l2Messenger.isL2MessageSent(keccak256(xDomainCalldata)));
if (useRouter) {
router.withdrawERC20{ value: feeToPay }(address(l2Token), recipient, amount, gasLimit);
router.withdrawERC20{ value: feeToPay + extraValue }(address(l2Token), recipient, amount, gasLimit);
} else {
gateway.withdrawERC20{ value: feeToPay }(address(l2Token), recipient, amount, gasLimit);
gateway.withdrawERC20{ value: feeToPay + extraValue }(address(l2Token), recipient, amount, gasLimit);
}
assertEq(gatewayBalance, l2Token.balanceOf(address(gateway)));
assertEq(feeToPay + feeVaultBalance, address(feeVault).balance);
@@ -472,18 +473,30 @@ contract L2CustomERC20GatewayTest is L2GatewayTestBase {
hevm.expectRevert("no corresponding l1 token");
if (useRouter) {
router.withdrawERC20{ value: feeToPay }(address(l2Token), amount, gasLimit);
router.withdrawERC20{ value: feeToPay + extraValue }(address(l2Token), amount, gasLimit);
} else {
gateway.withdrawERC20{ value: feeToPay }(address(l2Token), amount, gasLimit);
gateway.withdrawERC20{ value: feeToPay + extraValue }(address(l2Token), amount, gasLimit);
}
gateway.updateTokenMapping(address(l2Token), address(l1Token));
if (amount == 0) {
hevm.expectRevert("withdraw zero amount");
if (useRouter) {
router.withdrawERC20AndCall{ value: feeToPay }(address(l2Token), recipient, amount, dataToCall, gasLimit);
router.withdrawERC20AndCall{ value: feeToPay + extraValue }(
address(l2Token),
recipient,
amount,
dataToCall,
gasLimit
);
} else {
gateway.withdrawERC20AndCall{ value: feeToPay }(address(l2Token), recipient, amount, dataToCall, gasLimit);
gateway.withdrawERC20AndCall{ value: feeToPay + extraValue }(
address(l2Token),
recipient,
amount,
dataToCall,
gasLimit
);
}
} else {
// emit AppendMessage from L2MessageQueue
@@ -506,9 +519,21 @@ contract L2CustomERC20GatewayTest is L2GatewayTestBase {
uint256 feeVaultBalance = address(feeVault).balance;
assertBoolEq(false, l2Messenger.isL2MessageSent(keccak256(xDomainCalldata)));
if (useRouter) {
router.withdrawERC20AndCall{ value: feeToPay }(address(l2Token), recipient, amount, dataToCall, gasLimit);
router.withdrawERC20AndCall{ value: feeToPay + extraValue }(
address(l2Token),
recipient,
amount,
dataToCall,
gasLimit
);
} else {
gateway.withdrawERC20AndCall{ value: feeToPay }(address(l2Token), recipient, amount, dataToCall, gasLimit);
gateway.withdrawERC20AndCall{ value: feeToPay + extraValue }(
address(l2Token),
recipient,
amount,
dataToCall,
gasLimit
);
}
assertEq(gatewayBalance, l2Token.balanceOf(address(gateway)));
assertEq(feeToPay + feeVaultBalance, address(feeVault).balance);

View File

@@ -178,8 +178,8 @@ contract L2ETHGatewayTest is L2GatewayTestBase {
uint256 amount,
bytes memory dataToCall
) public {
hevm.assume(recipient != address(0));
hevm.assume(recipient.code.length == 0);
hevm.assume(uint256(uint160(recipient)) > 100); // ignore some precompile contracts
amount = bound(amount, 1, address(this).balance / 2);
@@ -281,9 +281,9 @@ contract L2ETHGatewayTest is L2GatewayTestBase {
uint256 feeVaultBalance = address(feeVault).balance;
assertBoolEq(false, l2Messenger.isL2MessageSent(keccak256(xDomainCalldata)));
if (useRouter) {
router.withdrawETH{ value: amount + feeToPay }(amount, gasLimit);
router.withdrawETH{ value: amount + feeToPay + extraValue }(amount, gasLimit);
} else {
gateway.withdrawETH{ value: amount + feeToPay }(amount, gasLimit);
gateway.withdrawETH{ value: amount + feeToPay + extraValue }(amount, gasLimit);
}
assertEq(amount + messengerBalance, address(l2Messenger).balance);
assertEq(feeToPay + feeVaultBalance, address(feeVault).balance);
@@ -349,9 +349,9 @@ contract L2ETHGatewayTest is L2GatewayTestBase {
uint256 feeVaultBalance = address(feeVault).balance;
assertBoolEq(false, l2Messenger.isL2MessageSent(keccak256(xDomainCalldata)));
if (useRouter) {
router.withdrawETH{ value: amount + feeToPay }(recipient, amount, gasLimit);
router.withdrawETH{ value: amount + feeToPay + extraValue }(recipient, amount, gasLimit);
} else {
gateway.withdrawETH{ value: amount + feeToPay }(recipient, amount, gasLimit);
gateway.withdrawETH{ value: amount + feeToPay + extraValue }(recipient, amount, gasLimit);
}
assertEq(amount + messengerBalance, address(l2Messenger).balance);
assertEq(feeToPay + feeVaultBalance, address(feeVault).balance);
@@ -418,9 +418,9 @@ contract L2ETHGatewayTest is L2GatewayTestBase {
uint256 feeVaultBalance = address(feeVault).balance;
assertBoolEq(false, l2Messenger.isL2MessageSent(keccak256(xDomainCalldata)));
if (useRouter) {
router.withdrawETHAndCall{ value: amount + feeToPay }(recipient, amount, dataToCall, gasLimit);
router.withdrawETHAndCall{ value: amount + feeToPay + extraValue }(recipient, amount, dataToCall, gasLimit);
} else {
gateway.withdrawETHAndCall{ value: amount + feeToPay }(recipient, amount, dataToCall, gasLimit);
gateway.withdrawETHAndCall{ value: amount + feeToPay + extraValue }(recipient, amount, dataToCall, gasLimit);
}
assertEq(amount + messengerBalance, address(l2Messenger).balance);
assertEq(feeToPay + feeVaultBalance, address(feeVault).balance);

View File

@@ -27,6 +27,9 @@ abstract contract L2GatewayTestBase is DSTestPlus {
event RelayedMessage(bytes32 indexed messageHash);
event FailedRelayedMessage(bytes32 indexed messageHash);
// pay 0.1 extra ETH to test refund
uint256 internal constant extraValue = 1e17;
L1ScrollMessenger internal l1Messenger;
address internal feeVault;

View File

@@ -0,0 +1,50 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { DSTestPlus } from "solmate/test/utils/DSTestPlus.sol";
import { L1BlockContainer } from "../L2/predeploys/L1BlockContainer.sol";
import { L1GasPriceOracle } from "../L2/predeploys/L1GasPriceOracle.sol";
import { L2MessageQueue } from "../L2/predeploys/L2MessageQueue.sol";
import { Whitelist } from "../L2/predeploys/Whitelist.sol";
import { L1ScrollMessenger } from "../L1/L1ScrollMessenger.sol";
import { L2ScrollMessenger } from "../L2/L2ScrollMessenger.sol";
contract L2ScrollMessengerTest is DSTestPlus {
L1ScrollMessenger internal l1Messenger;
address internal feeVault;
Whitelist private whitelist;
L2ScrollMessenger internal l2Messenger;
L1BlockContainer internal l1BlockContainer;
L2MessageQueue internal l2MessageQueue;
L1GasPriceOracle internal l1GasOracle;
function setUp() public {
// Deploy L1 contracts
l1Messenger = new L1ScrollMessenger();
// Deploy L2 contracts
whitelist = new Whitelist(address(this));
l1BlockContainer = new L1BlockContainer(address(this));
l2MessageQueue = new L2MessageQueue(address(this));
l1GasOracle = new L1GasPriceOracle(address(this));
l2Messenger = new L2ScrollMessenger(address(l1BlockContainer), address(l1GasOracle), address(l2MessageQueue));
// Initialize L2 contracts
l2Messenger.initialize(address(l1Messenger), feeVault);
l2MessageQueue.initialize();
l2MessageQueue.updateMessenger(address(l2Messenger));
l1GasOracle.updateWhitelist(address(whitelist));
}
function testForbidCallFromL1() external {
hevm.expectRevert("Forbid to call message queue");
l2Messenger.relayMessage(address(this), address(l2MessageQueue), 0, 0, new bytes(0));
hevm.expectRevert("Forbid to call self");
l2Messenger.relayMessage(address(this), address(l2Messenger), 0, 0, new bytes(0));
}
}

View File

@@ -269,6 +269,7 @@ contract L2StandardERC20GatewayTest is L2GatewayTestBase {
) public {
// blacklist some addresses
hevm.assume(recipient != address(0));
hevm.assume(recipient != address(gateway));
amount = bound(amount, 1, l2Token.balanceOf(address(this)));
@@ -346,16 +347,16 @@ contract L2StandardERC20GatewayTest is L2GatewayTestBase {
if (amount == 0) {
hevm.expectRevert("withdraw zero amount");
if (useRouter) {
router.withdrawERC20{ value: feeToPay }(address(l2Token), amount, gasLimit);
router.withdrawERC20{ value: feeToPay + extraValue }(address(l2Token), amount, gasLimit);
} else {
gateway.withdrawERC20{ value: feeToPay }(address(l2Token), amount, gasLimit);
gateway.withdrawERC20{ value: feeToPay + extraValue }(address(l2Token), amount, gasLimit);
}
} else {
hevm.expectRevert("no corresponding l1 token");
if (useRouter) {
router.withdrawERC20{ value: feeToPay }(address(l1Token), amount, gasLimit);
router.withdrawERC20{ value: feeToPay + extraValue }(address(l1Token), amount, gasLimit);
} else {
gateway.withdrawERC20{ value: feeToPay }(address(l1Token), amount, gasLimit);
gateway.withdrawERC20{ value: feeToPay + extraValue }(address(l1Token), amount, gasLimit);
}
// emit AppendMessage from L2MessageQueue
@@ -378,9 +379,9 @@ contract L2StandardERC20GatewayTest is L2GatewayTestBase {
uint256 feeVaultBalance = address(feeVault).balance;
assertBoolEq(false, l2Messenger.isL2MessageSent(keccak256(xDomainCalldata)));
if (useRouter) {
router.withdrawERC20{ value: feeToPay }(address(l2Token), amount, gasLimit);
router.withdrawERC20{ value: feeToPay + extraValue }(address(l2Token), amount, gasLimit);
} else {
gateway.withdrawERC20{ value: feeToPay }(address(l2Token), amount, gasLimit);
gateway.withdrawERC20{ value: feeToPay + extraValue }(address(l2Token), amount, gasLimit);
}
assertEq(gatewayBalance, l2Token.balanceOf(address(gateway)));
assertEq(feeToPay + feeVaultBalance, address(feeVault).balance);
@@ -423,16 +424,16 @@ contract L2StandardERC20GatewayTest is L2GatewayTestBase {
if (amount == 0) {
hevm.expectRevert("withdraw zero amount");
if (useRouter) {
router.withdrawERC20{ value: feeToPay }(address(l2Token), recipient, amount, gasLimit);
router.withdrawERC20{ value: feeToPay + extraValue }(address(l2Token), recipient, amount, gasLimit);
} else {
gateway.withdrawERC20{ value: feeToPay }(address(l2Token), recipient, amount, gasLimit);
gateway.withdrawERC20{ value: feeToPay + extraValue }(address(l2Token), recipient, amount, gasLimit);
}
} else {
hevm.expectRevert("no corresponding l1 token");
if (useRouter) {
router.withdrawERC20{ value: feeToPay }(address(l1Token), recipient, amount, gasLimit);
router.withdrawERC20{ value: feeToPay + extraValue }(address(l1Token), recipient, amount, gasLimit);
} else {
gateway.withdrawERC20{ value: feeToPay }(address(l1Token), recipient, amount, gasLimit);
gateway.withdrawERC20{ value: feeToPay + extraValue }(address(l1Token), recipient, amount, gasLimit);
}
// emit AppendMessage from L2MessageQueue
@@ -455,9 +456,9 @@ contract L2StandardERC20GatewayTest is L2GatewayTestBase {
uint256 feeVaultBalance = address(feeVault).balance;
assertBoolEq(false, l2Messenger.isL2MessageSent(keccak256(xDomainCalldata)));
if (useRouter) {
router.withdrawERC20{ value: feeToPay }(address(l2Token), recipient, amount, gasLimit);
router.withdrawERC20{ value: feeToPay + extraValue }(address(l2Token), recipient, amount, gasLimit);
} else {
gateway.withdrawERC20{ value: feeToPay }(address(l2Token), recipient, amount, gasLimit);
gateway.withdrawERC20{ value: feeToPay + extraValue }(address(l2Token), recipient, amount, gasLimit);
}
assertEq(gatewayBalance, l2Token.balanceOf(address(gateway)));
assertEq(feeToPay + feeVaultBalance, address(feeVault).balance);
@@ -501,16 +502,40 @@ contract L2StandardERC20GatewayTest is L2GatewayTestBase {
if (amount == 0) {
hevm.expectRevert("withdraw zero amount");
if (useRouter) {
router.withdrawERC20AndCall{ value: feeToPay }(address(l2Token), recipient, amount, dataToCall, gasLimit);
router.withdrawERC20AndCall{ value: feeToPay + extraValue }(
address(l2Token),
recipient,
amount,
dataToCall,
gasLimit
);
} else {
gateway.withdrawERC20AndCall{ value: feeToPay }(address(l2Token), recipient, amount, dataToCall, gasLimit);
gateway.withdrawERC20AndCall{ value: feeToPay + extraValue }(
address(l2Token),
recipient,
amount,
dataToCall,
gasLimit
);
}
} else {
hevm.expectRevert("no corresponding l1 token");
if (useRouter) {
router.withdrawERC20AndCall{ value: feeToPay }(address(l1Token), recipient, amount, dataToCall, gasLimit);
router.withdrawERC20AndCall{ value: feeToPay + extraValue }(
address(l1Token),
recipient,
amount,
dataToCall,
gasLimit
);
} else {
gateway.withdrawERC20AndCall{ value: feeToPay }(address(l1Token), recipient, amount, dataToCall, gasLimit);
gateway.withdrawERC20AndCall{ value: feeToPay + extraValue }(
address(l1Token),
recipient,
amount,
dataToCall,
gasLimit
);
}
// emit AppendMessage from L2MessageQueue
@@ -533,9 +558,21 @@ contract L2StandardERC20GatewayTest is L2GatewayTestBase {
uint256 feeVaultBalance = address(feeVault).balance;
assertBoolEq(false, l2Messenger.isL2MessageSent(keccak256(xDomainCalldata)));
if (useRouter) {
router.withdrawERC20AndCall{ value: feeToPay }(address(l2Token), recipient, amount, dataToCall, gasLimit);
router.withdrawERC20AndCall{ value: feeToPay + extraValue }(
address(l2Token),
recipient,
amount,
dataToCall,
gasLimit
);
} else {
gateway.withdrawERC20AndCall{ value: feeToPay }(address(l2Token), recipient, amount, dataToCall, gasLimit);
gateway.withdrawERC20AndCall{ value: feeToPay + extraValue }(
address(l2Token),
recipient,
amount,
dataToCall,
gasLimit
);
}
assertEq(gatewayBalance, l2Token.balanceOf(address(gateway)));
assertEq(feeToPay + feeVaultBalance, address(feeVault).balance);

View File

@@ -223,6 +223,7 @@ contract L2WETHGatewayTest is L2GatewayTestBase {
) public {
// blacklist some addresses
hevm.assume(recipient != address(0));
hevm.assume(recipient != address(gateway));
amount = bound(amount, 1, l2weth.balanceOf(address(this)));
@@ -350,9 +351,9 @@ contract L2WETHGatewayTest is L2GatewayTestBase {
if (amount == 0) {
hevm.expectRevert("withdraw zero amount");
if (useRouter) {
router.withdrawERC20{ value: feeToPay }(address(l2weth), amount, gasLimit);
router.withdrawERC20{ value: feeToPay + extraValue }(address(l2weth), amount, gasLimit);
} else {
gateway.withdrawERC20{ value: feeToPay }(address(l2weth), amount, gasLimit);
gateway.withdrawERC20{ value: feeToPay + extraValue }(address(l2weth), amount, gasLimit);
}
} else {
// token is not l2WETH
@@ -379,9 +380,9 @@ contract L2WETHGatewayTest is L2GatewayTestBase {
uint256 feeVaultBalance = address(feeVault).balance;
assertBoolEq(false, l2Messenger.isL2MessageSent(keccak256(xDomainCalldata)));
if (useRouter) {
router.withdrawERC20{ value: feeToPay }(address(l2weth), amount, gasLimit);
router.withdrawERC20{ value: feeToPay + extraValue }(address(l2weth), amount, gasLimit);
} else {
gateway.withdrawERC20{ value: feeToPay }(address(l2weth), amount, gasLimit);
gateway.withdrawERC20{ value: feeToPay + extraValue }(address(l2weth), amount, gasLimit);
}
assertEq(amount + messengerBalance, address(l2Messenger).balance);
assertEq(feeToPay + feeVaultBalance, address(feeVault).balance);
@@ -424,9 +425,9 @@ contract L2WETHGatewayTest is L2GatewayTestBase {
if (amount == 0) {
hevm.expectRevert("withdraw zero amount");
if (useRouter) {
router.withdrawERC20{ value: feeToPay }(address(l2weth), recipient, amount, gasLimit);
router.withdrawERC20{ value: feeToPay + extraValue }(address(l2weth), recipient, amount, gasLimit);
} else {
gateway.withdrawERC20{ value: feeToPay }(address(l2weth), recipient, amount, gasLimit);
gateway.withdrawERC20{ value: feeToPay + extraValue }(address(l2weth), recipient, amount, gasLimit);
}
} else {
// token is not l1WETH
@@ -453,9 +454,9 @@ contract L2WETHGatewayTest is L2GatewayTestBase {
uint256 feeVaultBalance = address(feeVault).balance;
assertBoolEq(false, l2Messenger.isL2MessageSent(keccak256(xDomainCalldata)));
if (useRouter) {
router.withdrawERC20{ value: feeToPay }(address(l2weth), recipient, amount, gasLimit);
router.withdrawERC20{ value: feeToPay + extraValue }(address(l2weth), recipient, amount, gasLimit);
} else {
gateway.withdrawERC20{ value: feeToPay }(address(l2weth), recipient, amount, gasLimit);
gateway.withdrawERC20{ value: feeToPay + extraValue }(address(l2weth), recipient, amount, gasLimit);
}
assertEq(amount + messengerBalance, address(l2Messenger).balance);
assertEq(feeToPay + feeVaultBalance, address(feeVault).balance);
@@ -499,9 +500,21 @@ contract L2WETHGatewayTest is L2GatewayTestBase {
if (amount == 0) {
hevm.expectRevert("withdraw zero amount");
if (useRouter) {
router.withdrawERC20AndCall{ value: feeToPay }(address(l2weth), recipient, amount, dataToCall, gasLimit);
router.withdrawERC20AndCall{ value: feeToPay + extraValue }(
address(l2weth),
recipient,
amount,
dataToCall,
gasLimit
);
} else {
gateway.withdrawERC20AndCall{ value: feeToPay }(address(l2weth), recipient, amount, dataToCall, gasLimit);
gateway.withdrawERC20AndCall{ value: feeToPay + extraValue }(
address(l2weth),
recipient,
amount,
dataToCall,
gasLimit
);
}
} else {
// token is not l1WETH
@@ -528,9 +541,21 @@ contract L2WETHGatewayTest is L2GatewayTestBase {
uint256 feeVaultBalance = address(feeVault).balance;
assertBoolEq(false, l2Messenger.isL2MessageSent(keccak256(xDomainCalldata)));
if (useRouter) {
router.withdrawERC20AndCall{ value: feeToPay }(address(l2weth), recipient, amount, dataToCall, gasLimit);
router.withdrawERC20AndCall{ value: feeToPay + extraValue }(
address(l2weth),
recipient,
amount,
dataToCall,
gasLimit
);
} else {
gateway.withdrawERC20AndCall{ value: feeToPay }(address(l2weth), recipient, amount, dataToCall, gasLimit);
gateway.withdrawERC20AndCall{ value: feeToPay + extraValue }(
address(l2weth),
recipient,
amount,
dataToCall,
gasLimit
);
}
assertEq(amount + messengerBalance, address(l2Messenger).balance);
assertEq(feeToPay + feeVaultBalance, address(feeVault).balance);

View File

@@ -12,7 +12,9 @@
},
"db_config": {
"driver_name": "postgres",
"dsn": "postgres://admin:123456@localhost/test?sslmode=disable"
"dsn": "postgres://admin:123456@localhost/test?sslmode=disable",
"maxOpenNum": 200,
"maxIdleNum": 20
},
"l2_config": {
"endpoint": "/var/lib/jenkins/workspace/SequencerPipeline/MyPrivateNetwork/geth.ipc"

View File

@@ -325,53 +325,38 @@ func (m *Manager) handleZkProof(pk string, msg *message.ProofDetail) error {
// CollectProofs collects proofs corresponding to a proof generation session.
func (m *Manager) CollectProofs(sess *session) {
//Cleanup roller sessions before return.
defer func() {
// TODO: remove the clean-up, rollers report healthy status.
m.mu.Lock()
for pk := range sess.info.Rollers {
m.freeTaskIDForRoller(pk, sess.info.ID)
}
delete(m.sessions, sess.info.ID)
m.mu.Unlock()
}()
for {
select {
//Execute after timeout, set in config.json. Consider all rollers failed.
case <-time.After(time.Duration(m.cfg.CollectionTime) * time.Minute):
m.mu.Lock()
defer func() {
// TODO: remove the clean-up, rollers report healthy status.
for pk := range sess.info.Rollers {
m.freeTaskIDForRoller(pk, sess.info.ID)
}
delete(m.sessions, sess.info.ID)
m.mu.Unlock()
}()
// Pick a random winner.
// First, round up the keys that actually sent in a valid proof.
var participatingRollers []string
for pk, roller := range sess.info.Rollers {
if roller.Status == types.RollerProofValid {
participatingRollers = append(participatingRollers, pk)
}
// record failed session.
errMsg := "proof generation session ended without receiving any valid proofs"
m.addFailedSession(sess, errMsg)
log.Warn(errMsg, "session id", sess.info.ID)
// Set status as skipped.
// Note that this is only a workaround for testnet here.
// TODO: In real cases we should reset to orm.ProvingTaskUnassigned
// so as to re-distribute the task in the future
if err := m.orm.UpdateProvingStatus(sess.info.ID, types.ProvingTaskFailed); err != nil {
log.Error("fail to reset task_status as Unassigned", "id", sess.info.ID, "err", err)
}
// Ensure we got at least one proof before selecting a winner.
if len(participatingRollers) == 0 {
// record failed session.
errMsg := "proof generation session ended without receiving any valid proofs"
m.addFailedSession(sess, errMsg)
log.Warn(errMsg, "session id", sess.info.ID)
// Set status as skipped.
// Note that this is only a workaround for testnet here.
// TODO: In real cases we should reset to orm.ProvingTaskUnassigned
// so as to re-distribute the task in the future
if err := m.orm.UpdateProvingStatus(sess.info.ID, types.ProvingTaskFailed); err != nil {
log.Error("fail to reset task_status as Unassigned", "id", sess.info.ID, "err", err)
}
return
}
// Now, select a random index for this slice.
randIndex := mathrand.Intn(len(participatingRollers))
_ = participatingRollers[randIndex]
// TODO: reward winner
return
//Execute after one of the roller finishes sending proof, return early if all rollers had sent results.
case ret := <-sess.finishChan:
m.mu.Lock()
sess.info.Rollers[ret.pk].Status = ret.status
if m.isSessionFailed(sess.info) {
if sess.isSessionFailed() {
if err := m.orm.UpdateProvingStatus(ret.id, types.ProvingTaskFailed); err != nil {
log.Error("failed to update proving_status as failed", "msg.ID", ret.id, "error", err)
}
@@ -379,13 +364,44 @@ func (m *Manager) CollectProofs(sess *session) {
if err := m.orm.SetSessionInfo(sess.info); err != nil {
log.Error("db set session info fail", "pk", ret.pk, "error", err)
}
//Check if all rollers have finished their tasks, and rollers with valid results are indexed by public key.
finished, validRollers := sess.isRollersFinished()
//When all rollers have finished submitting their tasks, select a winner within rollers with valid proof, and return, terminate the for loop.
if finished && len(validRollers) > 0 {
//Select a random index for this slice.
randIndex := mathrand.Intn(len(validRollers))
_ = validRollers[randIndex]
// TODO: reward winner
m.mu.Unlock()
return
}
m.mu.Unlock()
}
}
}
func (m *Manager) isSessionFailed(info *types.SessionInfo) bool {
for _, roller := range info.Rollers {
// isRollersFinished checks if all rollers have finished submitting proofs, check their validity, and record rollers who produce valid proof.
// When rollersLeft reaches 0, it means all rollers have finished their tasks.
// validRollers also records the public keys of rollers who have finished their tasks correctly as index.
func (s *session) isRollersFinished() (bool, []string) {
var validRollers []string
for pk, roller := range s.info.Rollers {
if roller.Status == types.RollerProofValid {
validRollers = append(validRollers, pk)
continue
}
if roller.Status == types.RollerProofInvalid {
continue
}
// Some rollers are still proving.
return false, nil
}
return true, validRollers
}
func (s *session) isSessionFailed() bool {
for _, roller := range s.info.Rollers {
if roller.Status != types.RollerProofInvalid {
return false
}
@@ -527,6 +543,8 @@ func (m *Manager) IsRollerIdle(hexPk string) bool {
}
func (m *Manager) addFailedSession(sess *session, errMsg string) {
m.mu.Lock()
defer m.mu.Unlock()
m.failedSessionInfos[sess.info.ID] = newSessionInfo(sess, types.ProvingTaskFailed, errMsg, true)
}

View File

@@ -39,8 +39,8 @@ import (
)
var (
cfg *bridge_config.Config
dbImg docker.ImgInstance
cfg *bridge_config.Config
base *docker.App
batchData *types.BatchData
)
@@ -54,10 +54,10 @@ func setEnv(t *testing.T) (err error) {
// Load config.
cfg, err = bridge_config.NewConfig("../bridge/config.json")
assert.NoError(t, err)
base.RunImages(t)
// Create db container.
dbImg = docker.NewTestDBDocker(t, cfg.DBConfig.DriverName)
cfg.DBConfig.DSN = dbImg.Endpoint()
cfg.DBConfig.DSN = base.DBEndpoint()
templateBlockTrace, err := os.ReadFile("../common/testdata/blockTrace_02.json")
if err != nil {
@@ -80,6 +80,7 @@ func setEnv(t *testing.T) (err error) {
func TestApis(t *testing.T) {
// Set up the test environment.
base = docker.NewDockerApp()
assert.True(t, assert.NoError(t, setEnv(t)), "failed to setup the test environment.")
t.Run("TestHandshake", testHandshake)
@@ -94,7 +95,7 @@ func TestApis(t *testing.T) {
// Teardown
t.Cleanup(func() {
dbImg.Stop()
base.Free()
})
}

View File

@@ -10,10 +10,10 @@ import (
)
func TestRunDatabase(t *testing.T) {
bridge := cmd.NewCmd(t, "db_cli-test", "--version")
defer bridge.WaitExit()
dbcli := cmd.NewCmd(t, "db_cli-test", "--version")
defer dbcli.WaitExit()
// wait result
bridge.ExpectWithTimeout(true, time.Second*3, fmt.Sprintf("db_cli version %s", version.Version))
bridge.RunApp(nil)
dbcli.ExpectWithTimeout(true, time.Second*3, fmt.Sprintf("db_cli version %s", version.Version))
dbcli.RunApp(nil)
}

View File

@@ -12,8 +12,8 @@ type DBConfig struct {
DSN string `json:"dsn"`
DriverName string `json:"driver_name"`
MaxOpenNum int `json:"maxOpenNum" default:"200"`
MaxIdleNum int `json:"maxIdleNum" default:"20"`
MaxOpenNum int `json:"maxOpenNum"`
MaxIdleNum int `json:"maxIdleNum"`
}
// NewConfig returns a new instance of Config.

View File

@@ -1,4 +1,6 @@
{
"dsn": "postgres://postgres:123456@localhost:5444/test?sslmode=disable",
"driver_name": "postgres"
"driver_name": "postgres",
"maxOpenNum": 200,
"maxIdleNum": 20
}

View File

@@ -13,18 +13,18 @@ import (
)
var (
pgDB *sqlx.DB
dbImg docker.ImgInstance
base *docker.App
pgDB *sqlx.DB
)
func initEnv(t *testing.T) error {
// Start db container.
dbImg = docker.NewTestDBDocker(t, "postgres")
base.RunImages(t)
// Create db orm handler.
factory, err := database.NewOrmFactory(&database.DBConfig{
DriverName: "postgres",
DSN: dbImg.Endpoint(),
DSN: base.DBEndpoint(),
})
if err != nil {
return err
@@ -34,6 +34,7 @@ func initEnv(t *testing.T) error {
}
func TestMigrate(t *testing.T) {
base = docker.NewDockerApp()
if err := initEnv(t); err != nil {
t.Fatal(err)
}
@@ -45,9 +46,7 @@ func TestMigrate(t *testing.T) {
t.Run("testRollback", testRollback)
t.Cleanup(func() {
if dbImg != nil {
assert.NoError(t, dbImg.Stop())
}
base.Free()
})
}

View File

@@ -194,6 +194,15 @@ func (o *blockBatchOrm) GetLatestFinalizedBatch() (*types.BlockBatch, error) {
return batch, nil
}
func (o *blockBatchOrm) GetLatestFinalizingOrFinalizedBatch() (*types.BlockBatch, error) {
row := o.db.QueryRowx(`select * from block_batch where index = (select max(index) from block_batch where rollup_status = $1 or rollup_status = $2);`, types.RollupFinalizing, types.RollupFinalized)
batch := &types.BlockBatch{}
if err := row.StructScan(batch); err != nil {
return nil, err
}
return batch, nil
}
func (o *blockBatchOrm) GetCommittedBatches(limit uint64) ([]string, error) {
rows, err := o.db.Queryx(`SELECT hash FROM block_batch WHERE rollup_status = $1 ORDER BY index ASC LIMIT $2`, types.RollupCommitted, limit)
if err != nil {

View File

@@ -63,6 +63,7 @@ type BlockBatchOrm interface {
GetLatestBatch() (*types.BlockBatch, error)
GetLatestCommittedBatch() (*types.BlockBatch, error)
GetLatestFinalizedBatch() (*types.BlockBatch, error)
GetLatestFinalizingOrFinalizedBatch() (*types.BlockBatch, error)
UpdateRollupStatus(ctx context.Context, hash string, status types.RollupStatus) error
UpdateCommitTxHashAndRollupStatus(ctx context.Context, hash string, commitTxHash string, status types.RollupStatus) error
UpdateFinalizeTxHashAndRollupStatus(ctx context.Context, hash string, finalizeTxHash string, status types.RollupStatus) error

View File

@@ -38,7 +38,7 @@ func NewOrmFactory(cfg *DBConfig) (OrmFactory, error) {
return nil, err
}
db.SetMaxIdleConns(cfg.MaxOpenNum)
db.SetMaxOpenConns(cfg.MaxOpenNum)
db.SetMaxIdleConns(cfg.MaxIdleNum)
if err = db.Ping(); err != nil {
return nil, err

View File

@@ -77,7 +77,7 @@ var (
batchData2 *types.BatchData
dbConfig *database.DBConfig
dbImg docker.ImgInstance
base *docker.App
ormBlock orm.BlockTraceOrm
ormLayer1 orm.L1MessageOrm
ormLayer2 orm.L2MessageOrm
@@ -88,8 +88,8 @@ var (
func setupEnv(t *testing.T) error {
// Init db config and start db container.
dbConfig = &database.DBConfig{DriverName: "postgres"}
dbImg = docker.NewTestDBDocker(t, dbConfig.DriverName)
dbConfig.DSN = dbImg.Endpoint()
base.RunImages(t)
dbConfig.DSN = base.DBEndpoint()
// Create db handler and reset db.
factory, err := database.NewOrmFactory(dbConfig)
@@ -156,10 +156,9 @@ func setupEnv(t *testing.T) error {
// TestOrmFactory run several test cases.
func TestOrmFactory(t *testing.T) {
base = docker.NewDockerApp()
defer func() {
if dbImg != nil {
assert.NoError(t, dbImg.Stop())
}
base.Free()
}()
if err := setupEnv(t); err != nil {
t.Fatal(err)

View File

@@ -241,7 +241,7 @@ func (r *Roller) prove() error {
}
} else {
// when the roller has more than 3 times panic,
// it will omit to prove the task, submit StatusProofError and then Pop the task.
// it will omit to prove the task, submit StatusProofError and then Delete the task.
proofMsg = &message.ProofDetail{
Status: message.StatusProofError,
Error: "zk proving panic",
@@ -251,7 +251,7 @@ func (r *Roller) prove() error {
}
defer func() {
_, err = r.stack.Pop()
err = r.stack.Delete(task.Task.ID)
if err != nil {
log.Error("roller stack pop failed!", "err", err)
}

View File

@@ -81,28 +81,12 @@ func (s *Stack) Peek() (*ProvingTask, error) {
return traces, nil
}
// Pop pops the proving-task on the top of Stack.
func (s *Stack) Pop() (*ProvingTask, error) {
var value []byte
if err := s.Update(func(tx *bbolt.Tx) error {
var key []byte
// Delete pops the proving-task on the top of Stack.
func (s *Stack) Delete(taskID string) error {
return s.Update(func(tx *bbolt.Tx) error {
bu := tx.Bucket(bucket)
c := bu.Cursor()
key, value = c.Last()
return bu.Delete(key)
}); err != nil {
return nil, err
}
if len(value) == 0 {
return nil, ErrEmpty
}
task := &ProvingTask{}
err := json.Unmarshal(value, task)
if err != nil {
return nil, err
}
return task, nil
return bu.Delete([]byte(taskID))
})
}
// UpdateTimes udpates the roller prove times of the proving task.

View File

@@ -36,10 +36,12 @@ func TestStack(t *testing.T) {
}
for i := 2; i >= 0; i-- {
var pop *ProvingTask
pop, err = s.Pop()
var peek *ProvingTask
peek, err = s.Peek()
assert.NoError(t, err)
assert.Equal(t, strconv.Itoa(i), peek.Task.ID)
err = s.Delete(strconv.Itoa(i))
assert.NoError(t, err)
assert.Equal(t, strconv.Itoa(i), pop.Task.ID)
}
// test times
@@ -52,18 +54,13 @@ func TestStack(t *testing.T) {
}
err = s.Push(task)
assert.NoError(t, err)
pop, err := s.Pop()
assert.NoError(t, err)
err = s.Push(pop)
assert.NoError(t, err)
peek, err := s.Peek()
assert.NoError(t, err)
pop2, err := s.Pop()
assert.Equal(t, 0, peek.Times)
err = s.UpdateTimes(peek, 3)
assert.NoError(t, err)
assert.Equal(t, peek, pop2)
s.UpdateTimes(pop2, 1)
peek2, err := s.Peek()
assert.NoError(t, err)
assert.Equal(t, 1, pop2.Times)
assert.Equal(t, 3, peek2.Times)
}

View File

@@ -34,9 +34,7 @@ import (
)
var (
l1gethImg docker.ImgInstance
l2gethImg docker.ImgInstance
dbImg docker.ImgInstance
base *docker.App
timestamp int
wsPort int64
@@ -51,9 +49,7 @@ var (
func setupEnv(t *testing.T) {
// Start l1geth l2geth and postgres.
l1gethImg = docker.NewTestL1Docker(t)
l2gethImg = docker.NewTestL2Docker(t)
dbImg = docker.NewTestDBDocker(t, "postgres")
base.RunImages(t)
// Create a random ws port.
port, _ := rand.Int(rand.Reader, big.NewInt(2000))
@@ -68,9 +64,7 @@ func setupEnv(t *testing.T) {
}
func free(t *testing.T) {
assert.NoError(t, l1gethImg.Stop())
assert.NoError(t, l2gethImg.Stop())
assert.NoError(t, dbImg.Stop())
base.Free()
// Delete temporary files.
assert.NoError(t, os.Remove(bridgeFile))
@@ -134,17 +128,11 @@ func mockBridgeConfig(t *testing.T) string {
cfg, err := bridgeConfig.NewConfig("../../bridge/config.json")
assert.NoError(t, err)
if l1gethImg != nil {
cfg.L1Config.Endpoint = l1gethImg.Endpoint()
cfg.L2Config.RelayerConfig.SenderConfig.Endpoint = l1gethImg.Endpoint()
}
if l2gethImg != nil {
cfg.L2Config.Endpoint = l2gethImg.Endpoint()
cfg.L1Config.RelayerConfig.SenderConfig.Endpoint = l2gethImg.Endpoint()
}
if dbImg != nil {
cfg.DBConfig.DSN = dbImg.Endpoint()
}
cfg.L1Config.Endpoint = base.L1GethEndpoint()
cfg.L2Config.RelayerConfig.SenderConfig.Endpoint = base.L1GethEndpoint()
cfg.L2Config.Endpoint = base.L2GethEndpoint()
cfg.L1Config.RelayerConfig.SenderConfig.Endpoint = base.L2GethEndpoint()
cfg.DBConfig.DSN = base.DBEndpoint()
// Store changed bridge config into a temp file.
data, err := json.Marshal(cfg)
@@ -161,13 +149,10 @@ func mockCoordinatorConfig(t *testing.T) string {
assert.NoError(t, err)
cfg.RollerManagerConfig.Verifier.MockMode = true
if dbImg != nil {
cfg.DBConfig.DSN = dbImg.Endpoint()
}
if l2gethImg != nil {
cfg.L2Config.Endpoint = l2gethImg.Endpoint()
}
cfg.DBConfig.DSN = base.DBEndpoint()
cfg.L2Config.Endpoint = base.L2GethEndpoint()
data, err := json.Marshal(cfg)
assert.NoError(t, err)
@@ -182,9 +167,8 @@ func mockCoordinatorConfig(t *testing.T) string {
func mockDatabaseConfig(t *testing.T) string {
cfg, err := database.NewConfig("../../database/config.json")
assert.NoError(t, err)
if dbImg != nil {
cfg.DSN = dbImg.Endpoint()
}
cfg.DSN = base.DBEndpoint()
data, err := json.Marshal(cfg)
assert.NoError(t, err)

View File

@@ -11,9 +11,12 @@ import (
"time"
"github.com/stretchr/testify/assert"
"scroll-tech/common/docker"
)
func TestIntegration(t *testing.T) {
base = docker.NewDockerApp()
setupEnv(t)
// test db_cli migrate cmd.