Skip to content

Commit 472264b

Browse files
authored
Merge pull request #282 from bnb-chain/develop
feat: merge for releasing v0.5.3
2 parents cd221b5 + a7356d9 commit 472264b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+799
-326
lines changed

CHANGELOG.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,30 @@
11
# Changelog
22

3+
## v0.5.3
4+
5+
This release introduces the implementation of [BEP-543](https://github.com/bnb-chain/BEPs/blob/master/BEPs/BEP-543.md), effectively reducing the block time from 1 second to an impressive 500 milliseconds.
6+
This enhancement significantly improves transaction efficiency and overall network performance, allowing for faster processing and a more seamless experience for users.
7+
8+
It is set to be activated on both the opBNB Mainnet and Testnet environments according to the following schedule:
9+
10+
- Testnet: Apr-02-2025 03:00 AM +UTC
11+
- Mainnet: Mid-Apr-2025
12+
13+
All mainnet and testnet nodes must upgrade to this release before the hardfork time.
14+
Also note that the `op-geth` should be upgraded to v0.5.7 accordingly, check [this](https://github.com/bnb-chain/op-geth/releases/tag/v0.5.7) for more details.
15+
16+
### What's Changed
17+
18+
#### FEATURE
19+
* [\#265](https://github.com/bnb-chain/opbnb/pull/265) BEP-543 to shorten block interval
20+
21+
### Docker Images
22+
- ghcr.io/bnb-chain/op-node:v0.5.3
23+
- ghcr.io/bnb-chain/op-batcher:v0.5.3
24+
- ghcr.io/bnb-chain/op-proposer:v0.5.3
25+
26+
**Full Changelog**: https://github.com/bnb-chain/opbnb/compare/v0.5.2...v0.5.3
27+
328
## v0.5.2
429

530
This is a minor release and must upgrade to this release before the Pascal & Prague hardforks time of BSC, supports EIP-7702.

op-batcher/batcher/channel_builder.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ type ChannelBuilder struct {
7676
outputBytes int
7777
}
7878

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

159-
if err = c.co.AddSingularBatch(batch, l1info.SequenceNumber); errors.Is(err, derive.ErrTooManyRLPBytes) || errors.Is(err, derive.ErrCompressorFull) {
159+
if err = c.co.AddSingularBatch(&c.rollupCfg, batch, l1info.SequenceNumber); errors.Is(err, derive.ErrTooManyRLPBytes) || errors.Is(err, derive.ErrCompressorFull) {
160160
c.setFullErr(err)
161161
return l1info, c.FullErr()
162162
} else if err != nil {

op-batcher/batcher/channel_builder_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -782,7 +782,7 @@ func ChannelBuilder_InputBytes(t *testing.T, batchType uint) {
782782
require.NoError(err)
783783
err = spanBatch.AppendSingularBatch(singularBatch, l1Info.SequenceNumber)
784784
require.NoError(err)
785-
rawSpanBatch, err := spanBatch.ToRawSpanBatch()
785+
rawSpanBatch, err := spanBatch.ToRawSpanBatch(&defaultTestRollupConfig)
786786
require.NoError(err)
787787
batch := derive.NewBatchData(rawSpanBatch)
788788
var buf bytes.Buffer

op-batcher/batcher/channel_manager.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ type channelManager struct {
4848

4949
// if set to true, prevents production of any new channel frames
5050
closed bool
51+
52+
isVolta bool
5153
}
5254

5355
func NewChannelManager(log log.Logger, metr metrics.Metricer, cfg ChannelConfig, rollupCfg *rollup.Config) *channelManager {
@@ -261,6 +263,14 @@ func (s *channelManager) processBlocks() error {
261263
latestL2ref eth.L2BlockRef
262264
)
263265
for i, block := range s.blocks {
266+
if !s.isVolta && s.rollupCfg.IsVolta(block.Time()) && s.currentChannel.InputBytes() != 0 {
267+
// the current channel is before volta fork.
268+
s.currentChannel.Close()
269+
s.isVolta = true
270+
log.Info("before volta fork channel", "channel_id", s.currentChannel.ID(), "block_time", block.Time())
271+
break
272+
}
273+
264274
l1info, err := s.currentChannel.AddBlock(block)
265275
if errors.As(err, &_chFullErr) {
266276
// current block didn't get added because channel is already full
@@ -298,6 +308,7 @@ func (s *channelManager) processBlocks() error {
298308
"channel_full", s.currentChannel.IsFull(),
299309
"input_bytes", s.currentChannel.InputBytes(),
300310
"ready_bytes", s.currentChannel.ReadyBytes(),
311+
"is_volta", s.isVolta,
301312
)
302313
return nil
303314
}
@@ -354,6 +365,13 @@ func (s *channelManager) AddL2Block(block *types.Block) error {
354365
return ErrReorg
355366
}
356367

368+
if s.tip == (common.Hash{}) && s.rollupCfg.IsVolta(block.Time()) {
369+
// set volta flag at startup
370+
s.isVolta = true
371+
log.Info("succeed to set is_volta flag", "block_time", block.Time(),
372+
"l2 block num", block.Number())
373+
}
374+
357375
s.metr.RecordL2BlockInPendingQueue(block)
358376
s.blocks = append(s.blocks, block)
359377
s.tip = block.Hash()
@@ -362,11 +380,20 @@ func (s *channelManager) AddL2Block(block *types.Block) error {
362380
}
363381

364382
func l2BlockRefFromBlockAndL1Info(block *types.Block, l1info *derive.L1BlockInfo) eth.L2BlockRef {
383+
milliPart := uint64(0)
384+
if block.MixDigest() != (common.Hash{}) {
385+
// adapts l2 millisecond, highest 2 bytes as milli-part.
386+
milliPart = uint64(eth.Bytes32(block.MixDigest())[0])*256 + uint64(eth.Bytes32(block.MixDigest())[1])
387+
}
388+
389+
log.Debug("generate l2 block ref:", "milli-timestamp", milliPart,
390+
"seconds-timestamp", block.Time(), "l2 block number", block.Number())
365391
return eth.L2BlockRef{
366392
Hash: block.Hash(),
367393
Number: block.NumberU64(),
368394
ParentHash: block.ParentHash(),
369395
Time: block.Time(),
396+
MilliTime: milliPart,
370397
L1Origin: eth.BlockID{Hash: l1info.BlockHash, Number: l1info.Number},
371398
SequenceNumber: l1info.SequenceNumber,
372399
}

op-chain-ops/genesis/config.go

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,31 @@ type DeployConfig struct {
305305
UseInterop bool `json:"useInterop,omitempty"`
306306
}
307307

308+
func (d *DeployConfig) L1MillisecondBlockInterval() uint64 {
309+
// convert second to millisecond
310+
return d.L1BlockTime * 1000
311+
}
312+
313+
func (d *DeployConfig) L2MillisecondBlockInterval() uint64 {
314+
if d.L2BlockTime > 3 {
315+
// has been millisecond
316+
return d.L2BlockTime
317+
}
318+
// convert second to millisecond
319+
return d.L2BlockTime * 1000
320+
}
321+
322+
// L2SecondBlockInterval is just used by ut&e2e test.
323+
// TODO: ut&e2e need to be refined later.
324+
func (d *DeployConfig) L2SecondBlockInterval() uint64 {
325+
if d.L2BlockTime <= 3 {
326+
// has been second
327+
return d.L2BlockTime
328+
}
329+
// convert millisecond to second
330+
return d.L2BlockTime / 1000
331+
}
332+
308333
// Copy will deeply copy the DeployConfig. This does a JSON roundtrip to copy
309334
// which makes it easier to maintain, we do not need efficiency in this case.
310335
func (d *DeployConfig) Copy() *DeployConfig {
@@ -434,9 +459,10 @@ func (d *DeployConfig) Check() error {
434459
return fmt.Errorf("%w: GovernanceToken owner cannot be address(0)", ErrInvalidDeployConfig)
435460
}
436461
}
462+
437463
// L2 block time must always be smaller than L1 block time
438-
if d.L1BlockTime < d.L2BlockTime {
439-
return fmt.Errorf("L2 block time (%d) is larger than L1 block time (%d)", d.L2BlockTime, d.L1BlockTime)
464+
if d.L1MillisecondBlockInterval() < d.L2MillisecondBlockInterval() {
465+
return fmt.Errorf("L2 block interval ms (%d) is larger than L1 block interval ms (%d)", d.L2MillisecondBlockInterval(), d.L1MillisecondBlockInterval())
440466
}
441467
if d.RequiredProtocolVersion == (params.ProtocolVersion{}) {
442468
log.Warn("RequiredProtocolVersion is empty")
@@ -585,6 +611,7 @@ func (d *DeployConfig) DeltaTime(genesisTime uint64) *uint64 {
585611
return &v
586612
}
587613

614+
// TODO judge if it is need to use milliseconds timestamp with the fork information
588615
func (d *DeployConfig) EcotoneTime(genesisTime uint64) *uint64 {
589616
if d.L2GenesisEcotoneTimeOffset == nil {
590617
return nil

op-e2e/actions/dencun_fork_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ func TestDencunL2ForkAfterGenesis(gt *testing.T) {
124124
cancunOffset := hexutil.Uint64(0)
125125
dp.DeployConfig.L1CancunTimeOffset = &cancunOffset
126126
// This test wil fork on the second block
127-
offset := hexutil.Uint64(dp.DeployConfig.L2BlockTime * 2)
127+
offset := hexutil.Uint64(dp.DeployConfig.L2SecondBlockInterval() * 2)
128128
dp.DeployConfig.L2GenesisCanyonTimeOffset = &offset
129129
dp.DeployConfig.L2GenesisDeltaTimeOffset = &offset
130130
dp.DeployConfig.L2GenesisEcotoneTimeOffset = &offset

op-e2e/actions/l2_sequencer_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ func TestL2Sequencer_SequencerDrift(gt *testing.T) {
9898
origin := miner.l1Chain.CurrentBlock()
9999

100100
// L2 makes blocks to catch up
101-
for sequencer.SyncStatus().UnsafeL2.Time+sd.RollupCfg.BlockTime < origin.Time {
101+
for sequencer.SyncStatus().UnsafeL2.Time+dp.DeployConfig.L2SecondBlockInterval() < origin.Time {
102102
makeL2BlockWithAliceTx()
103103
require.Equal(t, uint64(0), sequencer.SyncStatus().UnsafeL2.L1Origin.Number, "no L1 origin change before time matches")
104104
}
@@ -111,7 +111,7 @@ func TestL2Sequencer_SequencerDrift(gt *testing.T) {
111111
sequencer.ActL1HeadSignal(t)
112112

113113
// Make blocks up till the sequencer drift is about to surpass, but keep the old L1 origin
114-
for sequencer.SyncStatus().UnsafeL2.Time+sd.RollupCfg.BlockTime <= origin.Time+sd.ChainSpec.MaxSequencerDrift(origin.Time) {
114+
for sequencer.SyncStatus().UnsafeL2.Time+dp.DeployConfig.L2SecondBlockInterval() <= origin.Time+sd.ChainSpec.MaxSequencerDrift(origin.Time) {
115115
sequencer.ActL2KeepL1Origin(t)
116116
makeL2BlockWithAliceTx()
117117
require.Equal(t, uint64(1), sequencer.SyncStatus().UnsafeL2.L1Origin.Number, "expected to keep old L1 origin")

op-e2e/actions/user_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,10 +119,10 @@ func runCrossLayerUserTest(gt *testing.T, test hardforkScheduledTest) {
119119
dp.DeployConfig.L2GenesisFjordTimeOffset = test.fjordTime
120120

121121
if test.canyonTime != nil {
122-
require.Zero(t, uint64(*test.canyonTime)%uint64(dp.DeployConfig.L2BlockTime), "canyon fork must be aligned")
122+
require.Zero(t, uint64(*test.canyonTime)%uint64(dp.DeployConfig.L2SecondBlockInterval()), "canyon fork must be aligned")
123123
}
124124
if test.ecotoneTime != nil {
125-
require.Zero(t, uint64(*test.ecotoneTime)%uint64(dp.DeployConfig.L2BlockTime), "ecotone fork must be aligned")
125+
require.Zero(t, uint64(*test.ecotoneTime)%uint64(dp.DeployConfig.L2SecondBlockInterval()), "ecotone fork must be aligned")
126126
}
127127

128128
sd := e2eutils.Setup(t, dp, defaultAlloc)

op-e2e/op_geth.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -211,8 +211,8 @@ func (d *OpGeth) StartBlockBuilding(ctx context.Context, attrs *eth.PayloadAttri
211211

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

230230
var withdrawals *types.Withdrawals
231-
if d.L2ChainConfig.IsCanyon(uint64(timestamp)) {
231+
if d.L2ChainConfig.IsCanyon(milliTimestamp / 1000) {
232232
withdrawals = &types.Withdrawals{}
233233
}
234234

235235
var parentBeaconBlockRoot *common.Hash
236-
if d.L2ChainConfig.IsEcotone(uint64(timestamp)) {
236+
if d.L2ChainConfig.IsEcotone(milliTimestamp / 1000) {
237237
parentBeaconBlockRoot = d.L1Head.ParentBeaconRoot()
238238
}
239239

240240
attrs := eth.PayloadAttributes{
241-
Timestamp: timestamp,
241+
Timestamp: eth.Uint64Quantity(milliTimestamp / 1000),
242242
Transactions: txBytes,
243243
NoTxPool: true,
244244
GasLimit: (*eth.Uint64Quantity)(&d.SystemConfig.GasLimit),

op-e2e/system_adminrpc_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ func TestStopStartSequencer(t *testing.T) {
5656
require.False(t, active, "sequencer should be inactive")
5757

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

0 commit comments

Comments
 (0)