Skip to content

Commit

Permalink
wip: add get l1 block range hash directly from l1 client for chunk pr…
Browse files Browse the repository at this point in the history
…oposer
  • Loading branch information
lastminutedev committed Nov 17, 2023
1 parent cca5588 commit 64f4cdd
Show file tree
Hide file tree
Showing 9 changed files with 98 additions and 17 deletions.
10 changes: 10 additions & 0 deletions rollup/abi/bridge_abi.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ var (

// L2AppendMessageEventSignature = keccak256("AppendMessage(uint256,bytes32)")
L2AppendMessageEventSignature common.Hash

// L1ViewOracleABI
L1ViewOracleABI *abi.ABI
)

func init() {
Expand All @@ -60,6 +63,8 @@ func init() {
L2FailedRelayedMessageEventSignature = L2ScrollMessengerABI.Events["FailedRelayedMessage"].ID

L2AppendMessageEventSignature = L2MessageQueueABI.Events["AppendMessage"].ID

L1ViewOracleABI, _ = L1ViewOracleMetaData.GetAbi()
}

// Generated manually from abigen and only necessary events and mutable calls are kept.
Expand Down Expand Up @@ -104,6 +109,11 @@ var L1GasPriceOracleMetaData = &bind.MetaData{
ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"l1BaseFee\",\"type\":\"uint256\"}],\"name\":\"L1BaseFeeUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"overhead\",\"type\":\"uint256\"}],\"name\":\"OverheadUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_oldOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"scalar\",\"type\":\"uint256\"}],\"name\":\"ScalarUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_oldWhitelist\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_newWhitelist\",\"type\":\"address\"}],\"name\":\"UpdateWhitelist\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"getL1Fee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"getL1GasUsed\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1BaseFee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"overhead\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"scalar\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_l1BaseFee\",\"type\":\"uint256\"}],\"name\":\"setL1BaseFee\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_overhead\",\"type\":\"uint256\"}],\"name\":\"setOverhead\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_scalar\",\"type\":\"uint256\"}],\"name\":\"setScalar\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_newWhitelist\",\"type\":\"address\"}],\"name\":\"updateWhitelist\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"whitelist\",\"outputs\":[{\"internalType\":\"contract IWhitelist\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]\n",
}

// L1ViewOracleMetaData
var L1ViewOracleMetaData = &bind.MetaData{
ABI: "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"from\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"to\",\"type\":\"uint256\"}],\"name\":\"blockRangeHash\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"hash\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]",
}

// IL1ScrollMessengerL2MessageProof is an auto generated low-level Go binding around an user-defined struct.
type IL1ScrollMessengerL2MessageProof struct {
BatchIndex *big.Int
Expand Down
9 changes: 8 additions & 1 deletion rollup/cmd/rollup_relayer/app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,13 @@ func action(ctx *cli.Context) error {
registry := prometheus.DefaultRegisterer
observability.Server(ctx, db)

// Init l1geth connection
l1client, err := ethclient.Dial(cfg.L1Config.Endpoint)
if err != nil {
log.Error("failed to connect l1 geth", "config file", cfgFile, "error", err)
return err
}

// Init l2geth connection
l2client, err := ethclient.Dial(cfg.L2Config.Endpoint)
if err != nil {
Expand All @@ -80,7 +87,7 @@ func action(ctx *cli.Context) error {
return err
}

chunkProposer := watcher.NewChunkProposer(subCtx, l2client, cfg.L2Config.ChunkProposerConfig, db, registry)
chunkProposer, err := watcher.NewChunkProposer(subCtx, l1client, cfg.L2Config.ChunkProposerConfig, cfg.L1Config.L1ViewOracleAddress, db, registry)
if err != nil {
log.Error("failed to create chunkProposer", "config file", cfgFile, "error", err)
return err
Expand Down
1 change: 1 addition & 0 deletions rollup/conf/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"confirmations": "0x6",
"endpoint": "DUMMY_ENDPOINT",
"l1_message_queue_address": "0x0000000000000000000000000000000000000000",
"l1_view_oracle_address": "0x0000000000000000000000000000000000000000",
"scroll_chain_address": "0x0000000000000000000000000000000000000000",
"start_height": 0,
"relayer_config": {
Expand Down
2 changes: 2 additions & 0 deletions rollup/internal/config/l1.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,6 @@ type L1Config struct {
ScrollChainContractAddress common.Address `json:"scroll_chain_address"`
// The relayer config
RelayerConfig *RelayerConfig `json:"relayer_config"`
// The L1ViewOracle contract address deployed on layer 1 chain.
L1ViewOracleAddress common.Address `json:"l1_view_oracle_address"`
}
12 changes: 8 additions & 4 deletions rollup/internal/controller/watcher/batch_proposer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,15 +94,17 @@ func testBatchProposerLimits(t *testing.T) {
err := l2BlockOrm.InsertL2Blocks(context.Background(), []*types.WrappedBlock{wrappedBlock1, wrappedBlock2})
assert.NoError(t, err)

cp := NewChunkProposer(context.Background(), l2Cli, &config.ChunkProposerConfig{
cp, err := NewChunkProposer(context.Background(), l1Cli, &config.ChunkProposerConfig{
MaxBlockNumPerChunk: 1,
MaxTxNumPerChunk: 10000,
MaxL1CommitGasPerChunk: 50000000000,
MaxL1CommitCalldataSizePerChunk: 1000000,
MaxRowConsumptionPerChunk: 1000000,
ChunkTimeoutSec: 300,
GasCostIncreaseMultiplier: 1.2,
}, db, nil)
}, cfg.L1Config.L1ViewOracleAddress, db, nil)
assert.NoError(t, err)

cp.TryProposeChunk() // chunk1 contains block1
cp.TryProposeChunk() // chunk2 contains block2

Expand Down Expand Up @@ -153,15 +155,17 @@ func testBatchCommitGasAndCalldataSizeEstimation(t *testing.T) {
err := l2BlockOrm.InsertL2Blocks(context.Background(), []*types.WrappedBlock{wrappedBlock1, wrappedBlock2})
assert.NoError(t, err)

cp := NewChunkProposer(context.Background(), l2Cli, &config.ChunkProposerConfig{
cp, err := NewChunkProposer(context.Background(), l1Cli, &config.ChunkProposerConfig{
MaxBlockNumPerChunk: 1,
MaxTxNumPerChunk: 10000,
MaxL1CommitGasPerChunk: 50000000000,
MaxL1CommitCalldataSizePerChunk: 1000000,
MaxRowConsumptionPerChunk: 1000000,
ChunkTimeoutSec: 300,
GasCostIncreaseMultiplier: 1.2,
}, db, nil)
}, cfg.L1Config.L1ViewOracleAddress, db, nil)
assert.NoError(t, err)

cp.TryProposeChunk() // chunk1 contains block1
cp.TryProposeChunk() // chunk2 contains block2

Expand Down
63 changes: 55 additions & 8 deletions rollup/internal/controller/watcher/chunk_proposer.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,16 @@ import (

"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
"github.com/scroll-tech/go-ethereum"
"github.com/scroll-tech/go-ethereum/accounts/abi"
"github.com/scroll-tech/go-ethereum/common"
gethTypes "github.com/scroll-tech/go-ethereum/core/types"
"github.com/scroll-tech/go-ethereum/ethclient"
"github.com/scroll-tech/go-ethereum/log"
"gorm.io/gorm"

"scroll-tech/common/types"
bridgeAbi "scroll-tech/rollup/abi"

"scroll-tech/rollup/internal/config"
"scroll-tech/rollup/internal/orm"
Expand Down Expand Up @@ -51,9 +55,11 @@ type ChunkProposer struct {
db *gorm.DB

*ethclient.Client
l1ViewOracleAddress common.Address

chunkOrm *orm.Chunk
l2BlockOrm *orm.L2Block
chunkOrm *orm.Chunk
l2BlockOrm *orm.L2Block
l1ViewOracleABI *abi.ABI

maxBlockNumPerChunk uint64
maxTxNumPerChunk uint64
Expand All @@ -78,18 +84,25 @@ type ChunkProposer struct {
}

// NewChunkProposer creates a new ChunkProposer instance.
func NewChunkProposer(ctx context.Context, client *ethclient.Client, cfg *config.ChunkProposerConfig, db *gorm.DB, reg prometheus.Registerer) *ChunkProposer {
func NewChunkProposer(ctx context.Context, client *ethclient.Client, cfg *config.ChunkProposerConfig, l1ViewOracleAddress common.Address, db *gorm.DB, reg prometheus.Registerer) (*ChunkProposer, error) {
if l1ViewOracleAddress == (common.Address{}) {
return nil, errors.New("must pass non-zero l1ViewOracleAddress to BridgeClient")
}

log.Debug("new chunk proposer",
"maxTxNumPerChunk", cfg.MaxTxNumPerChunk,
"maxL1CommitGasPerChunk", cfg.MaxL1CommitGasPerChunk,
"maxL1CommitCalldataSizePerChunk", cfg.MaxL1CommitCalldataSizePerChunk,
"maxRowConsumptionPerChunk", cfg.MaxRowConsumptionPerChunk,
"chunkTimeoutSec", cfg.ChunkTimeoutSec,
"gasCostIncreaseMultiplier", cfg.GasCostIncreaseMultiplier)
"gasCostIncreaseMultiplier", cfg.GasCostIncreaseMultiplier,
)

return &ChunkProposer{
ctx: ctx,
Client: client,
l1ViewOracleAddress: l1ViewOracleAddress,
l1ViewOracleABI: bridgeAbi.L1ViewOracleABI,
db: db,
chunkOrm: orm.NewChunk(db),
l2BlockOrm: orm.NewL2Block(db),
Expand Down Expand Up @@ -149,7 +162,7 @@ func NewChunkProposer(ctx context.Context, client *ethclient.Client, cfg *config
Name: "rollup_propose_chunk_blocks_propose_not_enough_total",
Help: "Total number of chunk block propose not enough",
}),
}
}, nil
}

// TryProposeChunk tries to propose a new chunk.
Expand Down Expand Up @@ -227,10 +240,10 @@ func (p *ChunkProposer) proposeChunk(parentChunk *orm.Chunk) (*types.Chunk, erro
}
}

l1BlockRangeHash, err := p.Client.GetL1BlockRangeHash(p.ctx, big.NewInt(int64(l1BlockRangeHashFrom)), big.NewInt(int64(lastAppliedL1Block)))
l1BlockRangeHash, err := p.GetL1BlockRangeHash(p.ctx, l1BlockRangeHashFrom, lastAppliedL1Block)
if err != nil {
log.Error("failed to get block range hash", "err", err)
return nil, fmt.Errorf("chunk-proposer failed to get block range hash error: %w", err)
log.Error("failed to get l1 block range hash", "err", err)
return nil, fmt.Errorf("chunk-proposer failed to get l1 block range hash error: %w", err)
}

chunk.LastAppliedL1Block = lastAppliedL1Block
Expand Down Expand Up @@ -351,3 +364,37 @@ func (p *ChunkProposer) proposeChunk(parentChunk *orm.Chunk) (*types.Chunk, erro
p.chunkBlocksProposeNotEnoughTotal.Inc()
return nil, nil
}

// GetL1BlockRangeHash gets l1 block range hash from l1 view oracle smart contract.
func (p *ChunkProposer) GetL1BlockRangeHash(ctx context.Context, from uint64, to uint64) (*common.Hash, error) {
input, err := p.l1ViewOracleABI.Pack("blockRangeHash", big.NewInt(int64(from)), big.NewInt(int64(to)))
if err != nil {
return nil, err
}

output, err := p.Client.CallContract(ctx, ethereum.CallMsg{
To: &p.l1ViewOracleAddress,
Data: input,
}, nil)
if err != nil {
return nil, err
}
if len(output) == 0 {
if code, err := p.Client.CodeAt(ctx, p.l1ViewOracleAddress, nil); err != nil {
return nil, err
} else if len(code) == 0 {
return nil, fmt.Errorf(
"l1 view oracle contract unknown, address: %v",
p.l1ViewOracleAddress,
)
}
}

var l1BlockRangeHash common.Hash
err = p.l1ViewOracleABI.UnpackIntoInterface(l1BlockRangeHash, "blockRangeHash", output)
if err != nil {
return nil, err
}

return &l1BlockRangeHash, nil
}
6 changes: 4 additions & 2 deletions rollup/internal/controller/watcher/chunk_proposer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,15 +152,17 @@ func testChunkProposerLimits(t *testing.T) {
err := l2BlockOrm.InsertL2Blocks(context.Background(), []*types.WrappedBlock{wrappedBlock1, wrappedBlock2})
assert.NoError(t, err)

cp := NewChunkProposer(context.Background(), l2Cli, &config.ChunkProposerConfig{
cp, err := NewChunkProposer(context.Background(), l1Cli, &config.ChunkProposerConfig{
MaxBlockNumPerChunk: tt.maxBlockNum,
MaxTxNumPerChunk: tt.maxTxNum,
MaxL1CommitGasPerChunk: tt.maxL1CommitGas,
MaxL1CommitCalldataSizePerChunk: tt.maxL1CommitCalldataSize,
MaxRowConsumptionPerChunk: tt.maxRowConsumption,
ChunkTimeoutSec: tt.chunkTimeoutSec,
GasCostIncreaseMultiplier: 1.2,
}, db, nil)
}, cfg.L1Config.L1ViewOracleAddress, db, nil)
assert.NoError(t, err)

cp.TryProposeChunk()

chunkOrm := orm.NewChunk(db)
Expand Down
6 changes: 6 additions & 0 deletions rollup/internal/controller/watcher/watcher_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ var (

base *docker.App

// l1geth client
l1Cli *ethclient.Client

// l2geth client
l2Cli *ethclient.Client

Expand All @@ -47,6 +50,9 @@ func setupEnv(t *testing.T) (err error) {
MaxOpenNum: base.DBConfig.MaxOpenNum,
MaxIdleNum: base.DBConfig.MaxIdleNum,
}
// Create l1geth client.
l1Cli, err = base.L1Client()
assert.NoError(t, err)

// Create l2geth client.
l2Cli, err = base.L2Client()
Expand Down
6 changes: 4 additions & 2 deletions rollup/tests/rollup_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,14 +56,16 @@ func testCommitBatchAndFinalizeBatch(t *testing.T) {
err = l2BlockOrm.InsertL2Blocks(context.Background(), wrappedBlocks)
assert.NoError(t, err)

cp := watcher.NewChunkProposer(context.Background(), l2Client, &config.ChunkProposerConfig{
cp, err := watcher.NewChunkProposer(context.Background(), l1Client, &config.ChunkProposerConfig{
MaxBlockNumPerChunk: 100,
MaxTxNumPerChunk: 10000,
MaxL1CommitGasPerChunk: 50000000000,
MaxL1CommitCalldataSizePerChunk: 1000000,
MaxRowConsumptionPerChunk: 1048319,
ChunkTimeoutSec: 300,
}, db, nil)
}, l1Cfg.L1ViewOracleAddress, db, nil)
assert.NoError(t, err)

cp.TryProposeChunk()

batchOrm := orm.NewBatch(db)
Expand Down

0 comments on commit 64f4cdd

Please sign in to comment.