mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-28 07:36:44 +00:00
* feat(rollup): sync finalized batches from L1 * tweak * address comments * address comments * tweak * address comments * Update rollup/eventwatcher/eventwatcher.go Co-authored-by: Péter Garamvölgyi <peter@scroll.io> * address comments * address comments * address comments * add s.rollupSyncService.Stop() * add block chunk batch tests * fix goimports-lint * address comments * address comments * remove * add TestUnpackLog test * add decodeChunkRanges tests * add commit batch version check * fix goimport & golint * tweak * fixes * add TestRollupSyncServiceStartAndStop * add TestGetChunkRanges * address comments * add TestValidateBatch * add TestCalculateFinalizedBatchMeta * address comments * address comments * fix * address comments * address comments * fix * tweak log * fix * tweak logs * increase wait time * add --rollup.verify flag * add flag check in s.rollupSyncService.Stop() * bump version * refactor * tweak configs * tweak * refactor getLocalInfoForBatch * use syscall.Kill(os.Getpid(), syscall.SIGTERM) to shutdown * refactor decodeChunkBlockRanges * nit * address comments * address comments * add WithdrawRoot and StateRoot in FinalizedBatchMeta * address comments * address comments * add ctx.Err() check in retry * add configs in gen_config.go * bump version * fix goimport & golint * try to fix goimport * revert change * fix goimport & golint * tweak * bump version * add l2 block -> batch index mapping * bump version * add mainnet config * bump version * address comments * rename some vars * feat: add more detailed logs in crash case (#547) add more detailed logs in crash case * trigger ci * re-add batch finalization progress log * remove block number -> batch index mapping --------- Co-authored-by: Péter Garamvölgyi <peter@scroll.io> Co-authored-by: HAOYUatHZ <37070449+HAOYUatHZ@users.noreply.github.com>
167 lines
5.2 KiB
Go
167 lines
5.2 KiB
Go
package rollup_sync_service
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"errors"
|
|
"fmt"
|
|
"math"
|
|
"math/big"
|
|
|
|
"github.com/scroll-tech/go-ethereum/common"
|
|
"github.com/scroll-tech/go-ethereum/common/hexutil"
|
|
"github.com/scroll-tech/go-ethereum/core/types"
|
|
)
|
|
|
|
const blockContextByteSize = 60
|
|
|
|
// WrappedBlock contains the block's Header, Transactions and WithdrawTrieRoot hash.
|
|
type WrappedBlock struct {
|
|
Header *types.Header `json:"header"`
|
|
// Transactions is only used for recover types.Transactions, the from of types.TransactionData field is missing.
|
|
Transactions []*types.TransactionData `json:"transactions"`
|
|
WithdrawRoot common.Hash `json:"withdraw_trie_root,omitempty"`
|
|
}
|
|
|
|
// BlockContext represents the essential data of a block in the ScrollChain.
|
|
// It provides an overview of block attributes including hash values, block numbers, gas details, and transaction counts.
|
|
type BlockContext struct {
|
|
BlockHash common.Hash
|
|
ParentHash common.Hash
|
|
BlockNumber uint64
|
|
Timestamp uint64
|
|
BaseFee *big.Int
|
|
GasLimit uint64
|
|
NumTransactions uint16
|
|
NumL1Messages uint16
|
|
}
|
|
|
|
// numL1Messages returns the number of L1 messages in this block.
|
|
// This number is the sum of included and skipped L1 messages.
|
|
func (w *WrappedBlock) numL1Messages(totalL1MessagePoppedBefore uint64) uint64 {
|
|
var lastQueueIndex *uint64
|
|
for _, txData := range w.Transactions {
|
|
if txData.Type == types.L1MessageTxType {
|
|
lastQueueIndex = &txData.Nonce
|
|
}
|
|
}
|
|
if lastQueueIndex == nil {
|
|
return 0
|
|
}
|
|
// note: last queue index included before this block is totalL1MessagePoppedBefore - 1
|
|
// TODO: cache results
|
|
return *lastQueueIndex - totalL1MessagePoppedBefore + 1
|
|
}
|
|
|
|
// Encode encodes the WrappedBlock into RollupV2 BlockContext Encoding.
|
|
func (w *WrappedBlock) Encode(totalL1MessagePoppedBefore uint64) ([]byte, error) {
|
|
bytes := make([]byte, 60)
|
|
|
|
if !w.Header.Number.IsUint64() {
|
|
return nil, errors.New("block number is not uint64")
|
|
}
|
|
|
|
// note: numL1Messages includes skipped messages
|
|
numL1Messages := w.numL1Messages(totalL1MessagePoppedBefore)
|
|
if numL1Messages > math.MaxUint16 {
|
|
return nil, errors.New("number of L1 messages exceeds max uint16")
|
|
}
|
|
|
|
// note: numTransactions includes skipped messages
|
|
numL2Transactions := w.numL2Transactions()
|
|
numTransactions := numL1Messages + numL2Transactions
|
|
if numTransactions > math.MaxUint16 {
|
|
return nil, errors.New("number of transactions exceeds max uint16")
|
|
}
|
|
|
|
binary.BigEndian.PutUint64(bytes[0:], w.Header.Number.Uint64())
|
|
binary.BigEndian.PutUint64(bytes[8:], w.Header.Time)
|
|
// TODO: [16:47] Currently, baseFee is 0, because we disable EIP-1559.
|
|
binary.BigEndian.PutUint64(bytes[48:], w.Header.GasLimit)
|
|
binary.BigEndian.PutUint16(bytes[56:], uint16(numTransactions))
|
|
binary.BigEndian.PutUint16(bytes[58:], uint16(numL1Messages))
|
|
|
|
return bytes, nil
|
|
}
|
|
|
|
func txsToTxsData(txs types.Transactions) []*types.TransactionData {
|
|
txsData := make([]*types.TransactionData, len(txs))
|
|
for i, tx := range txs {
|
|
v, r, s := tx.RawSignatureValues()
|
|
|
|
nonce := tx.Nonce()
|
|
|
|
// We need QueueIndex in `NewBatchHeader`. However, `TransactionData`
|
|
// does not have this field. Since `L1MessageTx` do not have a nonce,
|
|
// we reuse this field for storing the queue index.
|
|
if msg := tx.AsL1MessageTx(); msg != nil {
|
|
nonce = msg.QueueIndex
|
|
}
|
|
|
|
txsData[i] = &types.TransactionData{
|
|
Type: tx.Type(),
|
|
TxHash: tx.Hash().String(),
|
|
Nonce: nonce,
|
|
ChainId: (*hexutil.Big)(tx.ChainId()),
|
|
Gas: tx.Gas(),
|
|
GasPrice: (*hexutil.Big)(tx.GasPrice()),
|
|
To: tx.To(),
|
|
Value: (*hexutil.Big)(tx.Value()),
|
|
Data: hexutil.Encode(tx.Data()),
|
|
IsCreate: tx.To() == nil,
|
|
V: (*hexutil.Big)(v),
|
|
R: (*hexutil.Big)(r),
|
|
S: (*hexutil.Big)(s),
|
|
}
|
|
}
|
|
return txsData
|
|
}
|
|
|
|
func convertTxDataToRLPEncoding(txData *types.TransactionData) ([]byte, error) {
|
|
data, err := hexutil.Decode(txData.Data)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to decode txData.Data: %s, err: %w", txData.Data, err)
|
|
}
|
|
|
|
tx := types.NewTx(&types.LegacyTx{
|
|
Nonce: txData.Nonce,
|
|
To: txData.To,
|
|
Value: txData.Value.ToInt(),
|
|
Gas: txData.Gas,
|
|
GasPrice: txData.GasPrice.ToInt(),
|
|
Data: data,
|
|
V: txData.V.ToInt(),
|
|
R: txData.R.ToInt(),
|
|
S: txData.S.ToInt(),
|
|
})
|
|
|
|
rlpTxData, err := tx.MarshalBinary()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to marshal binary of the tx: %+v, err: %w", tx, err)
|
|
}
|
|
|
|
return rlpTxData, nil
|
|
}
|
|
|
|
func (w *WrappedBlock) numL2Transactions() uint64 {
|
|
var count uint64
|
|
for _, txData := range w.Transactions {
|
|
if txData.Type != types.L1MessageTxType {
|
|
count++
|
|
}
|
|
}
|
|
return count
|
|
}
|
|
|
|
func decodeBlockContext(encodedBlockContext []byte) (*BlockContext, error) {
|
|
if len(encodedBlockContext) != blockContextByteSize {
|
|
return nil, errors.New("block encoding is not 60 bytes long")
|
|
}
|
|
|
|
return &BlockContext{
|
|
BlockNumber: binary.BigEndian.Uint64(encodedBlockContext[0:8]),
|
|
Timestamp: binary.BigEndian.Uint64(encodedBlockContext[8:16]),
|
|
GasLimit: binary.BigEndian.Uint64(encodedBlockContext[48:56]),
|
|
NumTransactions: binary.BigEndian.Uint16(encodedBlockContext[56:58]),
|
|
NumL1Messages: binary.BigEndian.Uint16(encodedBlockContext[58:60]),
|
|
}, nil
|
|
}
|