Skip to content

Commit

Permalink
Generate L1Blocks system tx (#738)
Browse files Browse the repository at this point in the history
* init

* add l1 blocks worker to generate system tx

* finish the impl

* move the L1Blocks building to sync service

* lint

---------

Co-authored-by: Péter Garamvölgyi <peter@scroll.io>
  • Loading branch information
icemelon and Thegaram authored May 11, 2024
1 parent d104225 commit 28518b9
Show file tree
Hide file tree
Showing 13 changed files with 1,001 additions and 35 deletions.
12 changes: 3 additions & 9 deletions core/block_validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import (
"github.com/scroll-tech/go-ethereum/metrics"
"github.com/scroll-tech/go-ethereum/params"
"github.com/scroll-tech/go-ethereum/rollup/circuitcapacitychecker"
"github.com/scroll-tech/go-ethereum/rollup/rcfg"
"github.com/scroll-tech/go-ethereum/trie"
)

Expand Down Expand Up @@ -177,20 +178,13 @@ func (v *BlockValidator) ValidateSystemTxs(block *types.Block) error {
stx := tx.AsSystemTx()

found := false
for _, sender := range v.config.Scroll.SystemTx.Senders {
if stx.Sender == sender {
found = true
break
}
}

if !found {
if stx.Sender != rcfg.SystemSenderAddress {
return ErrUnknownSystemSigner
}

found = false
for _, contract := range v.config.Scroll.SystemTx.Contracts {
if *stx.To == contract {
if stx.To == contract {
found = true
break
}
Expand Down
12 changes: 12 additions & 0 deletions core/state_transition.go
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,18 @@ func (st *StateTransition) buyGas() error {

func (st *StateTransition) preCheck() error {
if st.msg.IsSystemTx() {
// Make sure this transaction's nonce is correct.
stNonce := st.state.GetNonce(st.msg.From())
if msgNonce := st.msg.Nonce(); stNonce < msgNonce {
return fmt.Errorf("%w: address %v, tx: %d state: %d", ErrNonceTooHigh,
st.msg.From().Hex(), msgNonce, stNonce)
} else if stNonce > msgNonce {
return fmt.Errorf("%w: address %v, tx: %d state: %d", ErrNonceTooLow,
st.msg.From().Hex(), msgNonce, stNonce)
} else if stNonce+1 < stNonce {
return fmt.Errorf("%w: address %v, nonce: %d", ErrNonceMax,
st.msg.From().Hex(), stNonce)
}
// system tx gas is free and not accounted for.
st.gas += st.msg.Gas()
st.initialGas = st.msg.Gas()
Expand Down
10 changes: 5 additions & 5 deletions core/types/system_tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ import (
)

type SystemTx struct {
Sender common.Address // pre-determined sender
To *common.Address // system contract
Data []byte // calldata
Sender common.Address // pre-determined sender
To common.Address // system contract address
Data []byte // calldata
}

// not accountend
Expand All @@ -22,7 +22,7 @@ func (tx *SystemTx) txType() byte { return SystemTxType }
func (tx *SystemTx) copy() TxData {
return &SystemTx{
Sender: tx.Sender,
To: copyAddressPtr(tx.To),
To: tx.To,
Data: common.CopyBytes(tx.Data),
}
}
Expand All @@ -36,7 +36,7 @@ func (tx *SystemTx) gasTipCap() *big.Int { return new(big.Int) }
func (tx *SystemTx) gasFeeCap() *big.Int { return new(big.Int) }
func (tx *SystemTx) value() *big.Int { return new(big.Int) }
func (tx *SystemTx) nonce() uint64 { return 0 }
func (tx *SystemTx) to() *common.Address { return tx.To }
func (tx *SystemTx) to() *common.Address { return &tx.To }

func (tx *SystemTx) rawSignatureValues() (v, r, s *big.Int) {
return new(big.Int), new(big.Int), new(big.Int)
Expand Down
5 changes: 4 additions & 1 deletion eth/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ type Ethereum struct {
txPool *core.TxPool
syncService *sync_service.SyncService
rollupSyncService *rollup_sync_service.RollupSyncService
l1Client sync_service.EthClient
blockchain *core.BlockChain
handler *handler
ethDialCandidates enode.Iterator
Expand Down Expand Up @@ -148,6 +149,7 @@ func New(stack *node.Node, config *ethconfig.Config, l1Client sync_service.EthCl
}
eth := &Ethereum{
config: config,
l1Client: l1Client,
chainDb: chainDb,
eventMux: stack.EventMux(),
accountManager: stack.AccountManager(),
Expand Down Expand Up @@ -218,7 +220,7 @@ func New(stack *node.Node, config *ethconfig.Config, l1Client sync_service.EthCl
eth.txPool = core.NewTxPool(config.TxPool, chainConfig, eth.blockchain)

// initialize and start L1 message sync service
eth.syncService, err = sync_service.NewSyncService(context.Background(), chainConfig, stack.Config(), eth.chainDb, l1Client)
eth.syncService, err = sync_service.NewSyncService(context.Background(), chainConfig, stack.Config(), eth.chainDb, eth.blockchain, l1Client)
if err != nil {
return nil, fmt.Errorf("cannot initialize L1 sync service: %w", err)
}
Expand Down Expand Up @@ -544,6 +546,7 @@ func (s *Ethereum) Synced() bool { return atomic.LoadU
func (s *Ethereum) ArchiveMode() bool { return s.config.NoPruning }
func (s *Ethereum) BloomIndexer() *core.ChainIndexer { return s.bloomIndexer }
func (s *Ethereum) SyncService() *sync_service.SyncService { return s.syncService }
func (s *Ethereum) L1Client() sync_service.EthClient { return s.l1Client }

// Protocols returns all the currently configured
// network protocols to start.
Expand Down
2 changes: 2 additions & 0 deletions miner/miner.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ type Backend interface {
TxPool() *core.TxPool
ChainDb() ethdb.Database
SyncService() *sync_service.SyncService
L1Client() sync_service.EthClient
}

// Config is the configuration parameters of mining.
Expand Down Expand Up @@ -75,6 +76,7 @@ type Miner struct {
}

func New(eth Backend, config *Config, chainConfig *params.ChainConfig, mux *event.TypeMux, engine consensus.Engine, isLocalBlock func(block *types.Block) bool) *Miner {
//system_contracts.NewL1BlocksWorker(context.Background(), )
miner := &Miner{
eth: eth,
mux: mux,
Expand Down
4 changes: 4 additions & 0 deletions miner/miner_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,10 @@ func (m *mockBackend) ChainDb() ethdb.Database {
return m.chainDb
}

func (m *mockBackend) L1Client() sync_service.EthClient {
return nil
}

type testBlockChain struct {
statedb *state.StateDB
gasLimit uint64
Expand Down
33 changes: 27 additions & 6 deletions miner/worker.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import (
"github.com/scroll-tech/go-ethereum/params"
"github.com/scroll-tech/go-ethereum/rollup/circuitcapacitychecker"
"github.com/scroll-tech/go-ethereum/rollup/fees"
"github.com/scroll-tech/go-ethereum/rollup/rcfg"
"github.com/scroll-tech/go-ethereum/rollup/tracing"
"github.com/scroll-tech/go-ethereum/trie"
)
Expand Down Expand Up @@ -201,6 +202,8 @@ type worker struct {
chainSideSub event.Subscription
l1MsgsCh chan core.NewL1MsgsEvent
l1MsgsSub event.Subscription
l1BlocksCh chan core.NewL1MsgsEvent
l1BlocksSub event.Subscription

// Channels
newWorkCh chan *newWorkReq
Expand Down Expand Up @@ -231,9 +234,10 @@ type worker struct {
snapshotState *state.StateDB

// atomic status counters
running int32 // The indicator whether the consensus engine is running or not.
newTxs int32 // New arrival transaction count since last sealing work submitting.
newL1Msgs int32 // New arrival L1 message count since last sealing work submitting.
running int32 // The indicator whether the consensus engine is running or not.
newTxs int32 // New arrival transaction count since last sealing work submitting.
newL1Msgs int32 // New arrival L1 message count since last sealing work submitting.
newL1BlocksTxs int32 // New arrival L1Blocks tx count since last sealing work submitting.

// noempty is the flag used to control whether the feature of pre-seal empty
// block is enabled. The default value is false(pre-seal is enabled by default).
Expand Down Expand Up @@ -271,6 +275,7 @@ func newWorker(config *Config, chainConfig *params.ChainConfig, engine consensus
pendingTasks: make(map[common.Hash]*task),
txsCh: make(chan core.NewTxsEvent, txChanSize),
l1MsgsCh: make(chan core.NewL1MsgsEvent, txChanSize),
l1BlocksCh: make(chan core.NewL1MsgsEvent, txChanSize),
chainHeadCh: make(chan core.ChainHeadEvent, chainHeadChanSize),
chainSideCh: make(chan core.ChainSideEvent, chainSideChanSize),
newWorkCh: make(chan *newWorkReq),
Expand Down Expand Up @@ -298,6 +303,17 @@ func newWorker(config *Config, chainConfig *params.ChainConfig, engine consensus
})
}

// Subscribe NewL1BlocksEvent from sync service
if s := eth.SyncService(); s != nil && chainConfig.Scroll.SystemTx.Enabled {
worker.l1BlocksSub = s.SubscribeNewL1BlocksTx(worker.l1BlocksCh)
} else {
// create an empty subscription so that the tests won't fail
worker.l1BlocksSub = event.NewSubscription(func(quit <-chan struct{}) error {
<-quit
return nil
})
}

// Subscribe events for blockchain
worker.chainHeadSub = eth.BlockChain().SubscribeChainHeadEvent(worker.chainHeadCh)
worker.chainSideSub = eth.BlockChain().SubscribeChainSideEvent(worker.chainSideCh)
Expand Down Expand Up @@ -463,6 +479,7 @@ func (w *worker) newWorkLoop(recommit time.Duration) {
timer.Reset(recommit)
atomic.StoreInt32(&w.newTxs, 0)
atomic.StoreInt32(&w.newL1Msgs, 0)
atomic.StoreInt32(&w.newL1BlocksTxs, 0)
}
// clearPending cleans the stale pending tasks.
clearPending := func(number uint64) {
Expand Down Expand Up @@ -492,7 +509,7 @@ func (w *worker) newWorkLoop(recommit time.Duration) {
// higher priced transactions. Disable this overhead for pending blocks.
if w.isRunning() && (w.chainConfig.Clique == nil || w.chainConfig.Clique.Period > 0) {
// Short circuit if no new transaction arrives.
if atomic.LoadInt32(&w.newTxs) == 0 && atomic.LoadInt32(&w.newL1Msgs) == 0 {
if atomic.LoadInt32(&w.newTxs) == 0 && atomic.LoadInt32(&w.newL1Msgs) == 0 && atomic.LoadInt32(&w.newL1BlocksTxs) == 0 {
timer.Reset(recommit)
continue
}
Expand Down Expand Up @@ -634,6 +651,9 @@ func (w *worker) mainLoop() {
case ev := <-w.l1MsgsCh:
atomic.AddInt32(&w.newL1Msgs, int32(ev.Count))

case ev := <-w.l1BlocksCh:
atomic.AddInt32(&w.newL1BlocksTxs, int32(ev.Count))

// System stopped
case <-w.exitCh:
return
Expand Down Expand Up @@ -1331,8 +1351,8 @@ func (w *worker) collectPendingL1Messages(startIndex uint64) []types.L1MessageTx
}

func (w *worker) emitSystemTxs(env *environment) []*types.SystemTx {
// TODO
return nil
latestL1BlockNumberOnL2 := env.state.GetState(rcfg.L1BlocksAddress, rcfg.LatestBlockNumberSlot).Big().Uint64()
return w.eth.SyncService().CollectL1BlocksTxs(latestL1BlockNumberOnL2, w.chainConfig.Scroll.L1Config.MaxNumL1BlocksTxPerBlock)
}

// commitNewWork generates several new sealing tasks based on the parent block.
Expand Down Expand Up @@ -1490,6 +1510,7 @@ func (w *worker) commitNewWork(interrupt *int32, noempty bool, timestamp int64)

txs := types.NewOrderedSystemTxs(systemTxs)
skipCommit, circuitCapacityReached = w.commitTransactions(txs, w.coinbase, interrupt)
// Todo: system txs should not be reverted. We probably need to handle if revert happens
if skipCommit {
l2CommitNewWorkCommitSystemTxTimer.UpdateSince(commitSystemTxStart)
return
Expand Down
1 change: 1 addition & 0 deletions miner/worker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ func (b *testWorkerBackend) BlockChain() *core.BlockChain { return b.c
func (b *testWorkerBackend) TxPool() *core.TxPool { return b.txPool }
func (b *testWorkerBackend) ChainDb() ethdb.Database { return b.db }
func (b *testWorkerBackend) SyncService() *sync_service.SyncService { return nil }
func (b *testWorkerBackend) L1Client() sync_service.EthClient { return nil }

func (b *testWorkerBackend) newRandomUncle() *types.Block {
var parent *types.Block
Expand Down
27 changes: 14 additions & 13 deletions params/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -367,10 +367,11 @@ var (
MaxTxPayloadBytesPerBlock: &ScrollMaxTxPayloadBytesPerBlock,
FeeVaultAddress: &rcfg.ScrollFeeVaultAddress,
L1Config: &L1Config{
L1ChainId: 1,
L1MessageQueueAddress: common.HexToAddress("0x0d7E906BD9cAFa154b048cFa766Cc1E54E39AF9B"),
NumL1MessagesPerBlock: 10,
ScrollChainAddress: common.HexToAddress("0xa13BAF47339d63B743e7Da8741db5456DAc1E556"),
L1ChainId: 1,
L1MessageQueueAddress: common.HexToAddress("0x0d7E906BD9cAFa154b048cFa766Cc1E54E39AF9B"),
NumL1MessagesPerBlock: 10,
MaxNumL1BlocksTxPerBlock: 5,
ScrollChainAddress: common.HexToAddress("0xa13BAF47339d63B743e7Da8741db5456DAc1E556"),
},
},
}
Expand All @@ -386,7 +387,7 @@ var (
FeeVaultAddress: nil,
MaxTxPerBlock: nil,
MaxTxPayloadBytesPerBlock: nil,
L1Config: &L1Config{5, common.HexToAddress("0x0000000000000000000000000000000000000000"), 0, common.HexToAddress("0x0000000000000000000000000000000000000000")},
L1Config: &L1Config{5, common.HexToAddress("0x0000000000000000000000000000000000000000"), 0, 0, common.HexToAddress("0x0000000000000000000000000000000000000000")},
}}

// AllCliqueProtocolChanges contains every protocol change (EIPs) introduced
Expand All @@ -400,7 +401,7 @@ var (
FeeVaultAddress: nil,
MaxTxPerBlock: nil,
MaxTxPayloadBytesPerBlock: nil,
L1Config: &L1Config{5, common.HexToAddress("0x0000000000000000000000000000000000000000"), 0, common.HexToAddress("0x0000000000000000000000000000000000000000")},
L1Config: &L1Config{5, common.HexToAddress("0x0000000000000000000000000000000000000000"), 0, 0, common.HexToAddress("0x0000000000000000000000000000000000000000")},
}}

TestChainConfig = &ChainConfig{big.NewInt(1), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, new(EthashConfig), nil,
Expand All @@ -409,7 +410,7 @@ var (
FeeVaultAddress: &common.Address{123},
MaxTxPerBlock: nil,
MaxTxPayloadBytesPerBlock: nil,
L1Config: &L1Config{5, common.HexToAddress("0x0000000000000000000000000000000000000000"), 0, common.HexToAddress("0x0000000000000000000000000000000000000000")},
L1Config: &L1Config{5, common.HexToAddress("0x0000000000000000000000000000000000000000"), 0, 0, common.HexToAddress("0x0000000000000000000000000000000000000000")},
}}
TestRules = TestChainConfig.Rules(new(big.Int))

Expand All @@ -419,7 +420,7 @@ var (
FeeVaultAddress: nil,
MaxTxPerBlock: nil,
MaxTxPayloadBytesPerBlock: nil,
L1Config: &L1Config{5, common.HexToAddress("0x0000000000000000000000000000000000000000"), 0, common.HexToAddress("0x0000000000000000000000000000000000000000")},
L1Config: &L1Config{5, common.HexToAddress("0x0000000000000000000000000000000000000000"), 0, 0, common.HexToAddress("0x0000000000000000000000000000000000000000")},
}}
)

Expand Down Expand Up @@ -540,16 +541,16 @@ type SystemTxConfig struct {
Enabled bool `json:"enabled"`

// TODO maybe move these in state (system contract)
Senders []common.Address `json:"senders"`
Contracts []common.Address `json:"contracts"`
}

// L1Config contains the l1 parameters needed to sync l1 contract events (e.g., l1 messages, commit/revert/finalize batches) in the sequencer
type L1Config struct {
L1ChainId uint64 `json:"l1ChainId,string,omitempty"`
L1MessageQueueAddress common.Address `json:"l1MessageQueueAddress,omitempty"`
NumL1MessagesPerBlock uint64 `json:"numL1MessagesPerBlock,string,omitempty"`
ScrollChainAddress common.Address `json:"scrollChainAddress,omitempty"`
L1ChainId uint64 `json:"l1ChainId,string,omitempty"`
L1MessageQueueAddress common.Address `json:"l1MessageQueueAddress,omitempty"`
NumL1MessagesPerBlock uint64 `json:"numL1MessagesPerBlock,string,omitempty"`
MaxNumL1BlocksTxPerBlock uint64 `json:"maxNumL1BlocksTxPerBlock,string,omitempty"`
ScrollChainAddress common.Address `json:"scrollChainAddress,omitempty"`
}

func (c *L1Config) String() string {
Expand Down
Loading

0 comments on commit 28518b9

Please sign in to comment.