Skip to content

Commit 9c80801

Browse files
authored
Decode coinbase from blobs (#744)
1 parent 15ce92d commit 9c80801

File tree

29 files changed

+153
-2788
lines changed

29 files changed

+153
-2788
lines changed

.github/workflows/oracle.yml

Lines changed: 0 additions & 47 deletions
This file was deleted.

go.work

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,5 @@ use (
66
./node
77
./ops/l2-genesis
88
./ops/tools
9-
./oracle
109
./tx-submitter
1110
)

node/core/batch.go

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -341,7 +341,3 @@ func (e *Executor) ConvertBlsData(blsData l2node.BlsData) (*eth.BatchSignature,
341341
}
342342
return &bs, nil
343343
}
344-
345-
func (e *Executor) isBatchUpgraded(blockTime uint64) bool {
346-
return blockTime >= e.UpgradeBatchTime
347-
}

node/derivation/batch_info.go

Lines changed: 126 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,19 @@ import (
1717
"morph-l2/node/zstd"
1818
)
1919

20+
const (
21+
// BlockContextLegacyLength is the length of a legacy block context without coinbase
22+
BlockContextLegacyLength = 60
23+
)
24+
2025
type BlockContext struct {
2126
Number uint64 `json:"number"`
2227
Timestamp uint64 `json:"timestamp"`
2328
BaseFee *big.Int
2429
GasLimit uint64
2530
txsNum uint16
2631
l1MsgNum uint16
32+
coinbase common.Address
2733

2834
SafeL2Data *catalyst.SafeL2Data
2935
L2TxHashes []byte
@@ -36,15 +42,18 @@ func (b *BlockContext) Decode(bc []byte) error {
3642
if err != nil {
3743
return err
3844
}
39-
b.Number = wb.Number
40-
b.Timestamp = wb.Timestamp
4145
b.BaseFee = wb.BaseFee
4246
b.GasLimit = wb.GasLimit
4347
b.txsNum = txsNum
4448
b.l1MsgNum = l1MsgNum
49+
b.coinbase = wb.Miner
4550
return nil
4651
}
4752

53+
func decodeCoinbase(bc []byte) (common.Address, error) {
54+
return types.DecodeCoinbase(bc)
55+
}
56+
4857
type BatchInfo struct {
4958
batchIndex uint64
5059
blockNum uint64
@@ -79,143 +88,168 @@ func (bi *BatchInfo) TxNum() uint64 {
7988
}
8089

8190
// ParseBatch This method is externally referenced for parsing Batch
82-
func (bi *BatchInfo) ParseBatch(batch geth.RPCRollupBatch) error {
91+
func (bi *BatchInfo) ParseBatch(batch geth.RPCRollupBatch, morph204Time uint64) error {
92+
if len(batch.Sidecar.Blobs) == 0 {
93+
return fmt.Errorf("blobs length can not be zero")
94+
}
95+
96+
// Parse parent batch header
8397
parentBatchHeader := types.BatchHeaderBytes(batch.ParentBatchHeader)
8498
parentBatchIndex, err := parentBatchHeader.BatchIndex()
8599
if err != nil {
86-
return fmt.Errorf("decode batch header index error:%v", err)
100+
return fmt.Errorf("decode batch header index error: %v", err)
87101
}
102+
88103
totalL1MessagePopped, err := parentBatchHeader.TotalL1MessagePopped()
89104
if err != nil {
90-
return fmt.Errorf("decode batch header totalL1MessagePopped error:%v", err)
105+
return fmt.Errorf("decode batch header totalL1MessagePopped error: %v", err)
91106
}
107+
108+
// Initialize batch info fields
92109
bi.parentTotalL1MessagePopped = totalL1MessagePopped
93110
bi.root = batch.PostStateRoot
94111
bi.batchIndex = parentBatchIndex + 1
95112
bi.withdrawalRoot = batch.WithdrawRoot
96113
bi.version = uint64(batch.Version)
114+
97115
tq := newTxQueue()
98-
var rawBlockContexts hexutil.Bytes
99-
var txsData []byte
116+
var rawBlockContextsAndTxs hexutil.Bytes
117+
118+
// Handle version upgrade scenario
119+
blobData, err := types.RetrieveBlobBytes(&batch.Sidecar.Blobs[0])
120+
if err != nil {
121+
return fmt.Errorf("retrieve blob bytes error: %v", err)
122+
}
123+
124+
batchBytes, err := zstd.DecompressBatchBytes(blobData)
125+
if err != nil {
126+
return fmt.Errorf("decompress batch bytes error: %v", err)
127+
}
128+
129+
// Calculate block count based on version
100130
var blockCount uint64
101131
if batch.Version > 0 {
102-
parentVersion, err := parentBatchHeader.Version()
103-
if err != nil {
104-
return fmt.Errorf("decode batch header version error:%v", err)
105-
}
106-
if parentVersion == 0 {
107-
if len(batch.Sidecar.Blobs) == 0 {
108-
return fmt.Errorf("blobs length can not be zero")
109-
}
110-
blobData, err := types.RetrieveBlobBytes(&batch.Sidecar.Blobs[0])
111-
if err != nil {
112-
return err
113-
}
114-
batchBytes, err := zstd.DecompressBatchBytes(blobData)
115-
if err != nil {
116-
return fmt.Errorf("decompress batch bytes error:%v", err)
117-
}
118-
var startBlock BlockContext
119-
if err := startBlock.Decode(batchBytes[:60]); err != nil {
120-
return fmt.Errorf("decode chunk block context error:%v", err)
121-
}
122-
blockCount = batch.LastBlockNumber - startBlock.Number + 1
123-
} else {
124-
parentBatchBlock, err := parentBatchHeader.LastBlockNumber()
125-
if err != nil {
126-
return fmt.Errorf("decode batch header lastBlockNumber error:%v", err)
127-
}
128-
blockCount = batch.LastBlockNumber - parentBatchBlock
132+
rawBlockContextsAndTxs = batchBytes
133+
// Ensure we have enough data for block context
134+
if len(batchBytes) < 60 {
135+
return fmt.Errorf("insufficient batch bytes for block context, got %d bytes", len(batchBytes))
129136
}
130137

131-
}
132-
// If BlockContexts is not nil, the block context should not be included in the blob.
133-
// Therefore, the required length must be zero.
134-
length := blockCount * 60
135-
for _, blob := range batch.Sidecar.Blobs {
136-
blobCopy := blob
137-
blobData, err := types.RetrieveBlobBytes(&blobCopy)
138-
if err != nil {
139-
return err
138+
var startBlock BlockContext
139+
// coinbase does not enter batch at this time
140+
if err := startBlock.Decode(batchBytes[:60]); err != nil {
141+
return fmt.Errorf("decode chunk block context error: %v", err)
140142
}
141-
batchBytes, err := zstd.DecompressBatchBytes(blobData)
142-
if err != nil {
143-
return err
144-
}
145-
reader := bytes.NewReader(batchBytes)
146-
if batch.BlockContexts == nil {
147-
if len(batchBytes) < int(length) {
148-
rawBlockContexts = append(rawBlockContexts, batchBytes...)
149-
length -= uint64(len(batchBytes))
150-
reader.Reset(nil)
151-
} else {
152-
bcBytes := make([]byte, length)
153-
_, err = reader.Read(bcBytes)
154-
if err != nil {
155-
return fmt.Errorf("read block context error:%s", err.Error())
156-
}
157-
rawBlockContexts = append(rawBlockContexts, bcBytes...)
158-
length = 0
159-
}
160-
}
161-
data, err := io.ReadAll(reader)
162-
if err != nil {
163-
return fmt.Errorf("read txBytes error:%s", err.Error())
143+
144+
blockCount = batch.LastBlockNumber - startBlock.Number + 1
145+
} else {
146+
// First 2 bytes contain the block count
147+
if len(batch.BlockContexts) < 2 {
148+
return fmt.Errorf("insufficient block contexts data: %d bytes", len(batch.BlockContexts))
164149
}
165-
txsData = append(txsData, data...)
166-
}
167-
if batch.BlockContexts != nil {
150+
168151
blockCount = uint64(binary.BigEndian.Uint16(batch.BlockContexts[:2]))
169-
rawBlockContexts = batch.BlockContexts[2 : 60*blockCount+2]
152+
rawBlockContextsAndTxs = append(rawBlockContextsAndTxs, batch.BlockContexts[2:]...)
153+
rawBlockContextsAndTxs = append(rawBlockContextsAndTxs, batchBytes...)
170154
}
171-
data, err := types.DecodeTxsFromBytes(txsData)
172-
if err != nil {
173-
return err
174-
}
175-
tq.enqueue(data)
155+
176156
var txsNum uint64
177-
var l1MsgNum uint64
178157
blockContexts := make([]*BlockContext, int(blockCount))
158+
159+
reader := bytes.NewReader(rawBlockContextsAndTxs)
160+
// Process block contexts
179161
for i := 0; i < int(blockCount); i++ {
180162
var block BlockContext
181-
if err := block.Decode(rawBlockContexts[i*60 : i*60+60]); err != nil {
182-
return fmt.Errorf("decode chunk block context error:%v", err)
163+
bcBytes := make([]byte, BlockContextLegacyLength)
164+
_, err = reader.Read(bcBytes)
165+
if err != nil {
166+
return fmt.Errorf("read block context numberAndTimeBytes error:%s", err.Error())
167+
}
168+
if err := block.Decode(bcBytes); err != nil {
169+
return fmt.Errorf("decode number and timestamp error: %v", err)
170+
}
171+
var coinbase common.Address
172+
// handle coinbase
173+
if morph204Time != 0 && block.Timestamp >= morph204Time {
174+
coinbaseBytes := make([]byte, common.AddressLength)
175+
_, err = reader.Read(coinbaseBytes)
176+
if err != nil {
177+
return fmt.Errorf("read skipped block context error:%s", err.Error())
178+
}
179+
180+
coinbase, err = decodeCoinbase(coinbaseBytes)
181+
if err != nil {
182+
return err
183+
}
183184
}
185+
186+
// Set boundary block numbers
184187
if i == 0 {
185188
bi.firstBlockNumber = block.Number
186189
}
187190
if i == int(blockCount)-1 {
188191
bi.lastBlockNumber = block.Number
189192
}
193+
194+
// Setup SafeL2Data
190195
var safeL2Data catalyst.SafeL2Data
191196
safeL2Data.Number = block.Number
192197
safeL2Data.GasLimit = block.GasLimit
193198
safeL2Data.BaseFee = block.BaseFee
194199
safeL2Data.Timestamp = block.Timestamp
200+
// TODO coinbase
201+
fmt.Println(coinbase)
202+
203+
// Handle zero BaseFee case
195204
if block.BaseFee != nil && block.BaseFee.Cmp(big.NewInt(0)) == 0 {
196205
safeL2Data.BaseFee = nil
197206
}
207+
208+
// Validate transaction numbers
198209
if block.txsNum < block.l1MsgNum {
199-
return fmt.Errorf("txsNum must be or equal to or greater than l1MsgNum,txsNum:%v,l1MsgNum:%v", block.txsNum, block.l1MsgNum)
200-
}
201-
var txs []*eth.Transaction
202-
var err error
203-
if len(batch.Sidecar.Blobs) != 0 {
204-
txs, err = tq.dequeue(int(block.txsNum) - int(block.l1MsgNum))
205-
if err != nil {
206-
return fmt.Errorf("decode txsPayload error:%v", err)
207-
}
210+
return fmt.Errorf("txsNum must be greater than or equal to l1MsgNum, txsNum: %v, l1MsgNum: %v",
211+
block.txsNum, block.l1MsgNum)
208212
}
209-
txsNum += uint64(block.txsNum)
210-
l1MsgNum += uint64(block.l1MsgNum)
211-
// l1 transactions will be inserted later in front of L2 transactions
212-
safeL2Data.Transactions = encodeTransactions(txs)
213-
block.SafeL2Data = &safeL2Data
214213

214+
block.SafeL2Data = &safeL2Data
215215
blockContexts[i] = &block
216216
}
217+
218+
// Read transaction data
219+
txsData, err := io.ReadAll(reader)
220+
if err != nil {
221+
return fmt.Errorf("read transaction data error: %s", err.Error())
222+
}
223+
224+
// Decode transactions
225+
data, err := types.DecodeTxsFromBytes(txsData)
226+
if err != nil {
227+
return fmt.Errorf("decode transactions error: %v", err)
228+
}
229+
230+
// Process transactions
231+
tq.enqueue(data)
232+
233+
for i := 0; i < int(blockCount); i++ {
234+
// Skip if index is out of bounds
235+
if i >= len(blockContexts) {
236+
return fmt.Errorf("block context index out of bounds: %d >= %d", i, len(blockContexts))
237+
}
238+
239+
txCount := int(blockContexts[i].txsNum) - int(blockContexts[i].l1MsgNum)
240+
txs, err := tq.dequeue(txCount)
241+
if err != nil {
242+
return fmt.Errorf("decode transaction payload error: %v", err)
243+
}
244+
245+
txsNum += uint64(blockContexts[i].txsNum)
246+
// l1 transactions will be inserted later in front of L2 transactions
247+
blockContexts[i].SafeL2Data.Transactions = encodeTransactions(txs)
248+
}
249+
217250
bi.txNum += txsNum
218251
bi.blockContexts = blockContexts
252+
219253
return nil
220254
}
221255

node/derivation/config.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ type Config struct {
4444
MetricsPort uint64 `json:"metrics_port"`
4545
MetricsHostname string `json:"metrics_hostname"`
4646
MetricsServerEnable bool `json:"metrics_server_enable"`
47+
Morph204Time uint64 `json:"upgrade_time"`
4748
}
4849

4950
func DefaultConfig() *Config {
@@ -91,6 +92,10 @@ func (c *Config) SetCliContext(ctx *cli.Context) error {
9192
c.BaseHeight = ctx.GlobalUint64(flags.DerivationBaseHeight.Name)
9293
}
9394

95+
if ctx.GlobalIsSet(flags.Morph204Time.Name) {
96+
c.Morph204Time = ctx.GlobalUint64(flags.Morph204Time.Name)
97+
}
98+
9499
if ctx.GlobalIsSet(flags.DerivationPollInterval.Name) {
95100
c.PollInterval = ctx.GlobalDuration(flags.DerivationPollInterval.Name)
96101
if c.PollInterval == 0 {

0 commit comments

Comments
 (0)