Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
34b9560
feat: adjust second to millisecond in opbnb inner workflow
2020xibao Feb 28, 2025
3b0be5f
fix: make ut succeed
2020xibao Feb 28, 2025
8520a2f
fix: make e2e succeed
2020xibao Feb 28, 2025
a717b8c
support millisecond-level timestamps for L1 block
flywukong Mar 3, 2025
618dbe0
fix l1 header subscription
flywukong Mar 4, 2025
7115b2a
chore: polish millisecond-related code by review tips (#267)
will-2012 Mar 4, 2025
6ef4b4a
chore: refine l2 attribute millisecond timestamp setter (#268)
will-2012 Mar 5, 2025
7a188bc
fix: fix channel manager l2 milli-part parse (#269)
will-2012 Mar 6, 2025
a67eb4b
fix l1 origin time
flywukong Mar 4, 2025
374a5c7
fix: change L2OutputOracle contract l2 timestamp to millisecond
Mar 11, 2025
09bf990
revert: revert contract change (#270)
will-2012 Mar 14, 2025
32712e3
chore: fix some timestamp bug by self test (#271)
will-2012 Mar 14, 2025
d51fed4
chore: add volta fork conf
2020xibao Mar 17, 2025
7253886
feat: add rollup config base func for hard fork
joey0612 Mar 18, 2025
82404d6
fix: no config volta hard fork for funcs
joey0612 Mar 18, 2025
638b0d8
fix: compile error
joey0612 Mar 18, 2025
b4cded2
feat: derive span batch with hard fork
joey0612 Mar 18, 2025
6abc63a
fix: span batche delta real time
joey0612 Mar 18, 2025
d56ecb3
fix: max sequencer window config
joey0612 Mar 18, 2025
5310e17
chore: batcher support volta fork
2020xibao Mar 18, 2025
85ed5e2
add some log to print milliseonds timestamp info
flywukong Mar 19, 2025
c186642
feat: L2OutputOracle uses millisecond to compute l2 timestamp after v…
Mar 20, 2025
6e44689
fix: fix batcher reltime wrong calculate method (#274)
will-2012 Mar 20, 2025
8db9ba6
fix: fix constant comments
Mar 20, 2025
fedbd97
fix: update return type
Mar 20, 2025
82d902d
fix: parenct number compute error
joey0612 Mar 20, 2025
23eaf6c
fix: cr comments
joey0612 Mar 20, 2025
393cd53
fix: batcher channel has data judgment
joey0612 Mar 21, 2025
c53df4b
fix: update the logics
Mar 21, 2025
a37968f
fix: update voltaBlockNumber to 0
Mar 21, 2025
f59846f
Merge pull request #275 from bnb-chain/feat-outputoraclecontract
joey0612 Mar 21, 2025
c5935d0
Merge pull request #2 from RenRick/volta_fork
RenRick Mar 22, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions op-batcher/batcher/channel_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ type ChannelBuilder struct {
outputBytes int
}

// newChannelBuilder creates a new channel builder or returns an error if the
// NewChannelBuilder creates a new channel builder or returns an error if the
// channel out could not be created.
// it acts as a factory for either a span or singular channel out
func NewChannelBuilder(cfg ChannelConfig, rollupCfg rollup.Config, latestL1OriginBlockNum uint64) (*ChannelBuilder, error) {
Expand Down Expand Up @@ -156,7 +156,7 @@ func (c *ChannelBuilder) AddBlock(block *types.Block) (*derive.L1BlockInfo, erro
return l1info, fmt.Errorf("converting block to batch: %w", err)
}

if err = c.co.AddSingularBatch(batch, l1info.SequenceNumber); errors.Is(err, derive.ErrTooManyRLPBytes) || errors.Is(err, derive.ErrCompressorFull) {
if err = c.co.AddSingularBatch(&c.rollupCfg, batch, l1info.SequenceNumber); errors.Is(err, derive.ErrTooManyRLPBytes) || errors.Is(err, derive.ErrCompressorFull) {
c.setFullErr(err)
return l1info, c.FullErr()
} else if err != nil {
Expand Down
27 changes: 27 additions & 0 deletions op-batcher/batcher/channel_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ type channelManager struct {

// if set to true, prevents production of any new channel frames
closed bool

isVolta bool
}

func NewChannelManager(log log.Logger, metr metrics.Metricer, cfg ChannelConfig, rollupCfg *rollup.Config) *channelManager {
Expand Down Expand Up @@ -261,6 +263,14 @@ func (s *channelManager) processBlocks() error {
latestL2ref eth.L2BlockRef
)
for i, block := range s.blocks {
if !s.isVolta && s.rollupCfg.IsVolta(block.Time()) && s.currentChannel.InputBytes() != 0 {
// the current channel is before volta fork.
s.currentChannel.Close()
s.isVolta = true
log.Info("before volta fork channel", "channel_id", s.currentChannel.ID(), "block_time", block.Time())
break
}

l1info, err := s.currentChannel.AddBlock(block)
if errors.As(err, &_chFullErr) {
// current block didn't get added because channel is already full
Expand Down Expand Up @@ -298,6 +308,7 @@ func (s *channelManager) processBlocks() error {
"channel_full", s.currentChannel.IsFull(),
"input_bytes", s.currentChannel.InputBytes(),
"ready_bytes", s.currentChannel.ReadyBytes(),
"is_volta", s.isVolta,
)
return nil
}
Expand Down Expand Up @@ -354,6 +365,13 @@ func (s *channelManager) AddL2Block(block *types.Block) error {
return ErrReorg
}

if s.tip == (common.Hash{}) && s.rollupCfg.IsVolta(block.Time()) {
// set volta flag at startup
s.isVolta = true
log.Info("succeed to set is volta flag", "block_time", block.Time(),
"l2 block num", block.Number())
}

s.metr.RecordL2BlockInPendingQueue(block)
s.blocks = append(s.blocks, block)
s.tip = block.Hash()
Expand All @@ -362,11 +380,20 @@ func (s *channelManager) AddL2Block(block *types.Block) error {
}

func l2BlockRefFromBlockAndL1Info(block *types.Block, l1info *derive.L1BlockInfo) eth.L2BlockRef {
milliPart := uint64(0)
if block.MixDigest() != (common.Hash{}) {
// adapts l2 millisecond, highest 2 bytes as milli-part.
milliPart = uint64(eth.Bytes32(block.MixDigest())[0])*256 + uint64(eth.Bytes32(block.MixDigest())[1])
}

log.Debug("generate l2 block ref:", "milli-timestamp", milliPart,
"seconds-timestamp", block.Time(), "l2 block number", block.Number())
return eth.L2BlockRef{
Hash: block.Hash(),
Number: block.NumberU64(),
ParentHash: block.ParentHash(),
Time: block.Time(),
MilliTime: milliPart,
L1Origin: eth.BlockID{Hash: l1info.BlockHash, Number: l1info.Number},
SequenceNumber: l1info.SequenceNumber,
}
Expand Down
38 changes: 35 additions & 3 deletions op-chain-ops/genesis/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,31 @@ type DeployConfig struct {
UseInterop bool `json:"useInterop,omitempty"`
}

func (d *DeployConfig) L1MillisecondBlockInterval() uint64 {
// convert second to millisecond
return d.L1BlockTime * 1000
}

func (d *DeployConfig) L2MillisecondBlockInterval() uint64 {
if d.L2BlockTime > 3 {
// has been millisecond
return d.L2BlockTime
}
// convert second to millisecond
return d.L2BlockTime * 1000
}

// L2SecondBlockInterval is just used by ut&e2e test.
// TODO: ut&e2e need to be refined later.
func (d *DeployConfig) L2SecondBlockInterval() uint64 {
if d.L2BlockTime <= 3 {
// has been second
return d.L2BlockTime
}
// convert millisecond to second
return d.L2BlockTime / 1000
}

// Copy will deeply copy the DeployConfig. This does a JSON roundtrip to copy
// which makes it easier to maintain, we do not need efficiency in this case.
func (d *DeployConfig) Copy() *DeployConfig {
Expand Down Expand Up @@ -434,9 +459,15 @@ func (d *DeployConfig) Check() error {
return fmt.Errorf("%w: GovernanceToken owner cannot be address(0)", ErrInvalidDeployConfig)
}
}
if d.L2BlockTime <= 3 {
// TODO: too many tests depend it, tmp work around it
// convert ms l2 time interval
d.L2BlockTime = d.L2BlockTime * 1000
}

// L2 block time must always be smaller than L1 block time
if d.L1BlockTime < d.L2BlockTime {
return fmt.Errorf("L2 block time (%d) is larger than L1 block time (%d)", d.L2BlockTime, d.L1BlockTime)
if d.L1MillisecondBlockInterval() < d.L2MillisecondBlockInterval() {
return fmt.Errorf("L2 block interval ms (%d) is larger than L1 block interval ms (%d)", d.L2MillisecondBlockInterval(), d.L1MillisecondBlockInterval())
}
if d.RequiredProtocolVersion == (params.ProtocolVersion{}) {
log.Warn("RequiredProtocolVersion is empty")
Expand Down Expand Up @@ -585,6 +616,7 @@ func (d *DeployConfig) DeltaTime(genesisTime uint64) *uint64 {
return &v
}

// TODO judge if it is need to use milliseconds timestamp with the fork information
func (d *DeployConfig) EcotoneTime(genesisTime uint64) *uint64 {
if d.L2GenesisEcotoneTimeOffset == nil {
return nil
Expand Down Expand Up @@ -688,7 +720,7 @@ func (d *DeployConfig) RollupConfig(l1StartBlock *types.Block, l2GenesisBlockHas
GasLimit: uint64(d.L2GenesisBlockGasLimit),
},
},
BlockTime: d.L2BlockTime,
//BlockTime: d.L2BlockTime,
MaxSequencerDrift: d.MaxSequencerDrift,
SeqWindowSize: d.SequencerWindowSize,
ChannelTimeout: d.ChannelTimeout,
Expand Down
2 changes: 1 addition & 1 deletion op-e2e/actions/dencun_fork_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ func TestDencunL2ForkAfterGenesis(gt *testing.T) {
cancunOffset := hexutil.Uint64(0)
dp.DeployConfig.L1CancunTimeOffset = &cancunOffset
// This test wil fork on the second block
offset := hexutil.Uint64(dp.DeployConfig.L2BlockTime * 2)
offset := hexutil.Uint64(dp.DeployConfig.L2SecondBlockInterval() * 2)
dp.DeployConfig.L2GenesisCanyonTimeOffset = &offset
dp.DeployConfig.L2GenesisDeltaTimeOffset = &offset
dp.DeployConfig.L2GenesisEcotoneTimeOffset = &offset
Expand Down
4 changes: 2 additions & 2 deletions op-e2e/actions/l2_sequencer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ func TestL2Sequencer_SequencerDrift(gt *testing.T) {
origin := miner.l1Chain.CurrentBlock()

// L2 makes blocks to catch up
for sequencer.SyncStatus().UnsafeL2.Time+sd.RollupCfg.BlockTime < origin.Time {
for sequencer.SyncStatus().UnsafeL2.Time+sd.RollupCfg.SecondBlockInterval() < origin.Time {
makeL2BlockWithAliceTx()
require.Equal(t, uint64(0), sequencer.SyncStatus().UnsafeL2.L1Origin.Number, "no L1 origin change before time matches")
}
Expand All @@ -111,7 +111,7 @@ func TestL2Sequencer_SequencerDrift(gt *testing.T) {
sequencer.ActL1HeadSignal(t)

// Make blocks up till the sequencer drift is about to surpass, but keep the old L1 origin
for sequencer.SyncStatus().UnsafeL2.Time+sd.RollupCfg.BlockTime <= origin.Time+sd.ChainSpec.MaxSequencerDrift(origin.Time) {
for sequencer.SyncStatus().UnsafeL2.Time+sd.RollupCfg.SecondBlockInterval() <= origin.Time+sd.ChainSpec.MaxSequencerDrift(origin.Time) {
sequencer.ActL2KeepL1Origin(t)
makeL2BlockWithAliceTx()
require.Equal(t, uint64(1), sequencer.SyncStatus().UnsafeL2.L1Origin.Number, "expected to keep old L1 origin")
Expand Down
4 changes: 2 additions & 2 deletions op-e2e/actions/user_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,10 +119,10 @@ func runCrossLayerUserTest(gt *testing.T, test hardforkScheduledTest) {
dp.DeployConfig.L2GenesisFjordTimeOffset = test.fjordTime

if test.canyonTime != nil {
require.Zero(t, uint64(*test.canyonTime)%uint64(dp.DeployConfig.L2BlockTime), "canyon fork must be aligned")
require.Zero(t, uint64(*test.canyonTime)%uint64(dp.DeployConfig.L2SecondBlockInterval()), "canyon fork must be aligned")
}
if test.ecotoneTime != nil {
require.Zero(t, uint64(*test.ecotoneTime)%uint64(dp.DeployConfig.L2BlockTime), "ecotone fork must be aligned")
require.Zero(t, uint64(*test.ecotoneTime)%uint64(dp.DeployConfig.L2SecondBlockInterval()), "ecotone fork must be aligned")
}

sd := e2eutils.Setup(t, dp, defaultAlloc)
Expand Down
5 changes: 5 additions & 0 deletions op-e2e/e2eutils/setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,11 @@ func Setup(t require.TestingT, deployParams *DeployParams, alloc *AllocParams) *
PlasmaConfig: pcfg,
}

if rollupCfg.BlockTime <= 3 {
// covert to ms timestamp
rollupCfg.BlockTime = rollupCfg.BlockTime * 1000
}

require.NoError(t, rollupCfg.Check())

// Sanity check that the config is correct
Expand Down
10 changes: 5 additions & 5 deletions op-e2e/op_geth.go
Original file line number Diff line number Diff line change
Expand Up @@ -211,8 +211,8 @@ func (d *OpGeth) StartBlockBuilding(ctx context.Context, attrs *eth.PayloadAttri

// CreatePayloadAttributes creates a valid PayloadAttributes containing a L1Info deposit transaction followed by the supplied transactions.
func (d *OpGeth) CreatePayloadAttributes(txs ...*types.Transaction) (*eth.PayloadAttributes, error) {
timestamp := d.L2Head.Timestamp + 2
l1Info, err := derive.L1InfoDepositBytes(d.l2Engine.RollupConfig(), d.SystemConfig, d.sequenceNum, d.L1Head, uint64(timestamp))
milliTimestamp := d.L2Head.MillisecondTimestamp() + 2*1000 // 2000 millisecond block interval
l1Info, err := derive.L1InfoDepositBytes(d.l2Engine.RollupConfig(), d.SystemConfig, d.sequenceNum, d.L1Head, milliTimestamp)
if err != nil {
return nil, err
}
Expand All @@ -228,17 +228,17 @@ func (d *OpGeth) CreatePayloadAttributes(txs ...*types.Transaction) (*eth.Payloa
}

var withdrawals *types.Withdrawals
if d.L2ChainConfig.IsCanyon(uint64(timestamp)) {
if d.L2ChainConfig.IsCanyon(milliTimestamp / 1000) {
withdrawals = &types.Withdrawals{}
}

var parentBeaconBlockRoot *common.Hash
if d.L2ChainConfig.IsEcotone(uint64(timestamp)) {
if d.L2ChainConfig.IsEcotone(milliTimestamp / 1000) {
parentBeaconBlockRoot = d.L1Head.ParentBeaconRoot()
}

attrs := eth.PayloadAttributes{
Timestamp: timestamp,
Timestamp: eth.Uint64Quantity(milliTimestamp / 1000),
Transactions: txBytes,
NoTxPool: true,
GasLimit: (*eth.Uint64Quantity)(&d.SystemConfig.GasLimit),
Expand Down
5 changes: 5 additions & 0 deletions op-e2e/setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -547,6 +547,11 @@ func (cfg SystemConfig) Start(t *testing.T, _opts ...SystemConfigOption) (*Syste
return nil, err
}
sys.RollupConfig = &defaultConfig
if sys.RollupConfig.BlockTime <= 3 {
// TODO: too many tests depend it, tmp work around it
// covert ms timestamp
sys.RollupConfig.BlockTime = sys.RollupConfig.BlockTime * 1000
}

// Create a fake Beacon node to hold on to blobs created by the L1 miner, and to serve them to L2
bcn := fakebeacon.NewBeacon(testlog.Logger(t, log.LevelInfo).New("role", "l1_cl"),
Expand Down
2 changes: 1 addition & 1 deletion op-e2e/system_adminrpc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ func TestStopStartSequencer(t *testing.T) {
require.False(t, active, "sequencer should be inactive")

blockBefore := latestBlock(t, l2Seq)
time.Sleep(time.Duration(cfg.DeployConfig.L2BlockTime+1) * time.Second)
time.Sleep(time.Duration(cfg.DeployConfig.L2SecondBlockInterval()+1) * time.Second)
blockAfter := latestBlock(t, l2Seq)
require.Equal(t, blockAfter, blockBefore, "Chain advanced after stopping sequencer")

Expand Down
6 changes: 3 additions & 3 deletions op-node/chaincfg/chains.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ var OPBNBMainnet = rollup.Config{
GasLimit: 100000000,
},
},
BlockTime: 1,
//BlockTime: 1,
MaxSequencerDrift: 600,
SeqWindowSize: 14400,
ChannelTimeout: 1200,
Expand Down Expand Up @@ -163,7 +163,7 @@ var OPBNBTestnet = rollup.Config{
GasLimit: 100000000,
},
},
BlockTime: 1,
//BlockTime: 1,
MaxSequencerDrift: 600,
SeqWindowSize: 14400,
ChannelTimeout: 1200,
Expand Down Expand Up @@ -199,7 +199,7 @@ var OPBNBQANet = rollup.Config{
GasLimit: 100000000,
},
},
BlockTime: 1,
//BlockTime: 1,
MaxSequencerDrift: 600,
SeqWindowSize: 14400,
ChannelTimeout: 1200,
Expand Down
2 changes: 1 addition & 1 deletion op-node/p2p/app_params.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ type ApplicationScoreParams struct {
}

func LightApplicationScoreParams(cfg *rollup.Config) ApplicationScoreParams {
slot := time.Duration(cfg.BlockTime) * time.Second
slot := time.Duration(rollup.VoltBlockTime) * time.Millisecond
if slot == 0 {
slot = 2 * time.Second
}
Expand Down
2 changes: 1 addition & 1 deletion op-node/p2p/peer_params.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ func ScoreDecay(duration time.Duration, slot time.Duration) float64 {
//
// [PeerScoreParams]: https://pkg.go.dev/github.com/libp2p/go-libp2p-pubsub@v0.8.1#PeerScoreParams
func LightPeerScoreParams(cfg *rollup.Config) pubsub.PeerScoreParams {
slot := time.Duration(cfg.BlockTime) * time.Second
slot := time.Duration(rollup.VoltBlockTime) * time.Millisecond
if slot == 0 {
slot = 2 * time.Second
}
Expand Down
4 changes: 2 additions & 2 deletions op-node/p2p/sync.go
Original file line number Diff line number Diff line change
Expand Up @@ -683,7 +683,7 @@ func (s *SyncClient) doRequest(ctx context.Context, id peer.ID, expectedBlockNum
}

version := binary.LittleEndian.Uint32(versionData[:])
isCanyon := s.cfg.IsCanyon(s.cfg.TimestampForBlock(expectedBlockNum))
isCanyon := s.cfg.IsCanyon(s.cfg.MillisecondTimestampForBlock(expectedBlockNum) / 1000)
envelope, err := readExecutionPayload(version, data, isCanyon)
if err != nil {
return err
Expand Down Expand Up @@ -878,7 +878,7 @@ func (srv *ReqRespServer) handleSyncRequest(ctx context.Context, stream network.
if req < srv.cfg.Genesis.L2.Number {
return req, fmt.Errorf("cannot serve request for L2 block %d before genesis %d: %w", req, srv.cfg.Genesis.L2.Number, invalidRequestErr)
}
max, err := srv.cfg.TargetBlockNumber(uint64(time.Now().Unix()))
max, err := srv.cfg.TargetBlockNumber(uint64(time.Now().UnixMilli()))
if err != nil {
return req, fmt.Errorf("cannot determine max target block number to verify request: %w", invalidRequestErr)
}
Expand Down
9 changes: 8 additions & 1 deletion op-node/rollup/chain_spec.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ const (
Ecotone ForkName = "ecotone"
Fjord ForkName = "fjord"
Interop ForkName = "interop"
Volta ForkName = "volta"
None ForkName = "none"
)

Expand All @@ -52,7 +53,8 @@ var nextFork = map[ForkName]ForkName{
Delta: Ecotone,
Ecotone: Fjord,
Fjord: Interop,
Interop: None,
Interop: Volta,
Volta: None,
}

type ChainSpec struct {
Expand Down Expand Up @@ -134,6 +136,9 @@ func (s *ChainSpec) CheckForkActivation(log log.Logger, block eth.L2BlockRef) {
if s.config.IsInterop(block.Time) {
s.currentFork = Interop
}
if s.config.IsVolta(block.Time) {
s.currentFork = Volta
}
log.Info("Current hardfork version detected", "forkName", s.currentFork)
return
}
Expand All @@ -153,6 +158,8 @@ func (s *ChainSpec) CheckForkActivation(log log.Logger, block eth.L2BlockRef) {
foundActivationBlock = s.config.IsFjordActivationBlock(block.Time)
case Interop:
foundActivationBlock = s.config.IsInteropActivationBlock(block.Time)
case Volta:
foundActivationBlock = s.config.IsVoltaActivationBlock(block.MillisecondTimestamp())
}

if foundActivationBlock {
Expand Down
2 changes: 1 addition & 1 deletion op-node/rollup/chain_spec_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ var testConfig = Config{
GasLimit: 30_000_000,
},
},
BlockTime: 2,
BlockTime: 2000,
MaxSequencerDrift: 600,
SeqWindowSize: 3600,
ChannelTimeout: 300,
Expand Down
Loading
Loading