Skip to content

Commit

Permalink
move blockContext to blob
Browse files Browse the repository at this point in the history
  • Loading branch information
FletcherMan committed Nov 27, 2024
1 parent 23c61ec commit 4d0d215
Show file tree
Hide file tree
Showing 25 changed files with 378 additions and 223 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
################## update dependencies ####################

ETHEREUM_TARGET_VERSION := v1.10.14-0.20241105040223-5c7f1bb7073e
ETHEREUM_TARGET_VERSION := v1.10.14-0.20241127093812-67d4a670e1a1
TENDERMINT_TARGET_VERSION := v0.3.1

ETHEREUM_MODULE_NAME := github.com/morph-l2/go-ethereum
Expand Down
2 changes: 1 addition & 1 deletion bindings/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ go 1.22

replace github.com/tendermint/tendermint => github.com/morph-l2/tendermint v0.3.1

require github.com/morph-l2/go-ethereum v1.10.14-0.20241105040223-5c7f1bb7073e
require github.com/morph-l2/go-ethereum v1.10.14-0.20241127093812-67d4a670e1a1

require (
github.com/VictoriaMetrics/fastcache v1.12.2 // indirect
Expand Down
4 changes: 2 additions & 2 deletions bindings/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,8 @@ github.com/mmcloughlin/addchain v0.4.0/go.mod h1:A86O+tHqZLMNO4w6ZZ4FlVQEadcoqky
github.com/mmcloughlin/profile v0.1.1/go.mod h1:IhHD7q1ooxgwTgjxQYkACGA77oFTDdFVejUS1/tS/qU=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/morph-l2/go-ethereum v1.10.14-0.20241105040223-5c7f1bb7073e h1:pV7z8mnNQr+JJO2CGUzwAlzjrPnZ0YlO92izBaq00Zs=
github.com/morph-l2/go-ethereum v1.10.14-0.20241105040223-5c7f1bb7073e/go.mod h1:sMJCfHOBzVRDkM2yF/Hy+oUk2rgC0CQZHTLs0cyzhhk=
github.com/morph-l2/go-ethereum v1.10.14-0.20241127093812-67d4a670e1a1 h1:2NHhXzEO2TQ9Rq0XRNxb+VnJpkQwHED9VNilOqWcV5M=
github.com/morph-l2/go-ethereum v1.10.14-0.20241127093812-67d4a670e1a1/go.mod h1:sMJCfHOBzVRDkM2yF/Hy+oUk2rgC0CQZHTLs0cyzhhk=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
Expand Down
2 changes: 1 addition & 1 deletion contracts/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ replace github.com/tendermint/tendermint => github.com/morph-l2/tendermint v0.3.

require (
github.com/iden3/go-iden3-crypto v0.0.16
github.com/morph-l2/go-ethereum v1.10.14-0.20241105040223-5c7f1bb7073e
github.com/morph-l2/go-ethereum v1.10.14-0.20241127093812-67d4a670e1a1
github.com/stretchr/testify v1.9.0
)

Expand Down
4 changes: 2 additions & 2 deletions contracts/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/morph-l2/go-ethereum v1.10.14-0.20241105040223-5c7f1bb7073e h1:pV7z8mnNQr+JJO2CGUzwAlzjrPnZ0YlO92izBaq00Zs=
github.com/morph-l2/go-ethereum v1.10.14-0.20241105040223-5c7f1bb7073e/go.mod h1:sMJCfHOBzVRDkM2yF/Hy+oUk2rgC0CQZHTLs0cyzhhk=
github.com/morph-l2/go-ethereum v1.10.14-0.20241127093812-67d4a670e1a1 h1:2NHhXzEO2TQ9Rq0XRNxb+VnJpkQwHED9VNilOqWcV5M=
github.com/morph-l2/go-ethereum v1.10.14-0.20241127093812-67d4a670e1a1/go.mod h1:sMJCfHOBzVRDkM2yF/Hy+oUk2rgC0CQZHTLs0cyzhhk=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
Expand Down
189 changes: 13 additions & 176 deletions node/core/batch.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,11 @@ package node
import (
"bytes"
"context"
"errors"
"fmt"
"math/big"

"morph-l2/node/types"

"github.com/morph-l2/go-ethereum/accounts/abi/bind"
"github.com/morph-l2/go-ethereum/common"
eth "github.com/morph-l2/go-ethereum/core/types"
"github.com/morph-l2/go-ethereum/crypto"
Expand Down Expand Up @@ -128,7 +126,7 @@ func (e *Executor) CalculateCapWithProposalBlock(currentBlockBytes []byte, curre
if err != nil {
return false, err
}
l1TxNum := int(totalL1MessagePopped - totalL1MessagePoppedBefore) // include skipped L1 messages
l1TxNum := int(totalL1MessagePopped - totalL1MessagePoppedBefore)
e.logger.Info("fetched block", "block height", wBlock.Number, "involved transaction count", len(transactions[i]), "l2 tx num", l2TxNum, "l1 tx num", l1TxNum)
blockContext := wBlock.BlockContextBytes(l2TxNum+l1TxNum, l1TxNum)
e.batchingCache.batchData.Append(blockContext, txsPayload, l1TxHashes)
Expand All @@ -137,7 +135,7 @@ func (e *Executor) CalculateCapWithProposalBlock(currentBlockBytes []byte, curre
}

// make sure passed block is the next block of the last packed block
curHeight, err := heightFromBCBytes(currentBlockBytes)
curHeight, err := types.HeightFromBCBytes(currentBlockBytes)
if err != nil {
return false, err
}
Expand All @@ -158,10 +156,11 @@ func (e *Executor) CalculateCapWithProposalBlock(currentBlockBytes []byte, curre
e.metrics.BatchIndex.Set(float64(e.batchingCache.parentBatchHeader.BatchIndex))
}

height, err := heightFromBCBytes(currentBlockBytes)
block, err := types.WrappedBlockFromBytes(currentBlockBytes)
if err != nil {
return false, err
}
height := block.Number
if height <= e.batchingCache.lastPackedBlockHeight {
return false, fmt.Errorf("wrong propose height passed. lastPackedBlockHeight: %d, passed height: %d", e.batchingCache.lastPackedBlockHeight, height)
} else if height > e.batchingCache.lastPackedBlockHeight+1 { // skipped some blocks, cache is dirty. need rebuild the cache
Expand All @@ -176,163 +175,13 @@ func (e *Executor) CalculateCapWithProposalBlock(currentBlockBytes []byte, curre
return false, err
}

exceeded, err := e.batchingCache.batchData.EstimateCompressedSizeWithNewPayload(e.batchingCache.currentTxsPayload)

return exceeded, err
}

// SealBatch seals the accumulated blocks into a batch
// It should be called after CalculateBatchSizeWithProposalBlock which ensure the accumulated blocks is correct.
func (e *Executor) SealBatch() ([]byte, []byte, error) {
if e.batchingCache.IsEmpty() {
return nil, nil, errors.New("failed to seal batch. No data found in batch cache")
}

sidecar, err := types.EncodeTxsPayloadToBlob(e.batchingCache.batchData.TxsPayload())
if err != nil {
return nil, nil, err
}
blobHashes := []common.Hash{types.EmptyVersionedHash}
if sidecar != nil && len(sidecar.Blobs) > 0 {
blobHashes = sidecar.BlobHashes()
}

sequencerSetVerifyHash, err := e.sequencerCaller.SequencerSetVerifyHash(nil)
if err != nil {
return nil, nil, fmt.Errorf("failed to get sequencerSetVerifyHash, err: %w", err)
}

block, err := wrappedBlockFromBytes(e.batchingCache.currentBlockBytes)
if err != nil {
return nil, nil, err
}
l1MessagePopped := e.batchingCache.totalL1MessagePopped - e.batchingCache.parentBatchHeader.TotalL1MessagePopped
var skippedL1MessageBitmap []byte
if block.Timestamp < e.UpgradeBatchTime {
e.logger.Info("waiting upgrade batch time", "upgradeBatchTime", e.UpgradeBatchTime, "current block time", block.Timestamp, "remaining seconds", e.UpgradeBatchTime-block.Timestamp)
if l1MessagePopped > 0 { // 32 zero bytes when before upgrading and has L1 message in batch
skippedL1MessageBitmap = make([]byte, 32)
}
}

batchHeader := types.BatchHeader{
Version: 0,
BatchIndex: e.batchingCache.parentBatchHeader.BatchIndex + 1,
L1MessagePopped: l1MessagePopped,
TotalL1MessagePopped: e.batchingCache.totalL1MessagePopped,
DataHash: e.batchingCache.batchData.DataHash(),
BlobVersionedHash: blobHashes[0], // currently we only have one blob
PrevStateRoot: e.batchingCache.prevStateRoot,
PostStateRoot: e.batchingCache.postStateRoot,
WithdrawalRoot: e.batchingCache.withdrawRoot,
SequencerSetVerifyHash: sequencerSetVerifyHash,
ParentBatchHash: e.batchingCache.parentBatchHeader.Hash(),
SkippedL1MessageBitmap: skippedL1MessageBitmap,
var exceeded bool
if e.isBatchUpgraded(block.Timestamp) {
exceeded, err = e.batchingCache.batchData.WillExceedCompressedSizeLimit(e.batchingCache.currentBlockContext, e.batchingCache.currentTxsPayload)
} else {
exceeded, err = e.batchingCache.batchData.EstimateCompressedSizeWithNewPayload(e.batchingCache.currentTxsPayload)
}
e.batchingCache.sealedBatchHeader = &batchHeader
e.batchingCache.sealedSidecar = sidecar
batchHash := e.batchingCache.sealedBatchHeader.Hash()
e.logger.Info("Sealed batch header", "batchHash", batchHash.Hex())
e.logger.Info(fmt.Sprintf("===batchIndex: %d \n===L1MessagePopped: %d \n===TotalL1MessagePopped: %d \n===dataHash: %x \n===blockNum: %d \n===SkippedL1MessageBitmap: %s \n===ParentBatchHash: %x \n",
batchHeader.BatchIndex,
batchHeader.L1MessagePopped,
batchHeader.TotalL1MessagePopped,
batchHeader.DataHash,
e.batchingCache.batchData.BlockNum(),
batchHeader.SkippedL1MessageBitmap,
batchHeader.ParentBatchHash))
blockContexts, _ := e.batchingCache.batchData.Encode()
e.logger.Info(fmt.Sprintf("===blockContexts: %x \n", blockContexts))

return batchHash[:], e.batchingCache.sealedBatchHeader.Encode(), nil
}

// CommitBatch commit the sealed batch. It does nothing if no batch header is sealed.
// It is supposed to be called when the current block is confirmed.
func (e *Executor) CommitBatch(currentBlockBytes []byte, currentTxs tmtypes.Txs, blsDatas []l2node.BlsData) error {
if e.batchingCache.IsEmpty() || e.batchingCache.sealedBatchHeader == nil { // nothing to commit
return nil
}

// reconstruct current block context
// it is possible that the confirmed current block is different from the existing cached current block context
if !bytes.Equal(currentBlockBytes, e.batchingCache.currentBlockBytes) ||
!bytes.Equal(currentTxs.Hash(), e.batchingCache.currentTxsHash) {
e.logger.Info("current block is changed, reconstructing current context...")
if err := e.setCurrentBlock(currentBlockBytes, currentTxs); err != nil {
return err
}
}

blockContexts, err := e.batchingCache.batchData.Encode()
if err != nil {
return err
}

curHeight, err := heightFromBCBytes(e.batchingCache.currentBlockBytes)
if err != nil {
return err
}

var batchSigs []eth.BatchSignature
if !e.devSequencer {
batchSigs, err = e.ConvertBlsDatas(blsDatas)
if err != nil {
return err
}
}

currentIndex := e.batchingCache.parentBatchHeader.BatchIndex + 1

// The batch needs the sequencer set info at the end height of the batch, which is equal to current height - 1.
callOpts := &bind.CallOpts{
BlockNumber: big.NewInt(int64(curHeight - 1)),
}
sequencerSetBytes, err := e.sequencerCaller.GetSequencerSetBytes(callOpts)
if err != nil {
e.logger.Error("failed to GetSequencerSetBytes", "query at height of", curHeight-1, "error", err)
return err
}

if err = e.l2Client.CommitBatch(context.Background(), &eth.RollupBatch{
Version: 0,
Index: currentIndex,
Hash: e.batchingCache.sealedBatchHeader.Hash(),
ParentBatchHeader: e.batchingCache.parentBatchHeader.Encode(),
CurrentSequencerSetBytes: sequencerSetBytes,
BlockContexts: blockContexts,
SkippedL1MessageBitmap: e.batchingCache.sealedBatchHeader.SkippedL1MessageBitmap,
PrevStateRoot: e.batchingCache.prevStateRoot,
PostStateRoot: e.batchingCache.postStateRoot,
WithdrawRoot: e.batchingCache.withdrawRoot,
Sidecar: e.batchingCache.sealedSidecar,
}, batchSigs); err != nil {
return err
}

// update newest batch index
e.metrics.BatchIndex.Set(float64(currentIndex))

// commit sealed batch header; move current block into the next batch
e.batchingCache.parentBatchHeader = e.batchingCache.sealedBatchHeader
e.batchingCache.prevStateRoot = e.batchingCache.postStateRoot
e.batchingCache.sealedBatchHeader = nil
e.batchingCache.sealedSidecar = nil

_, _, totalL1MessagePopped, _, err := ParsingTxs(e.batchingCache.currentTxs, e.batchingCache.totalL1MessagePopped)
if err != nil {
return err
}
e.batchingCache.totalL1MessagePopped = totalL1MessagePopped
e.batchingCache.postStateRoot = e.batchingCache.currentStateRoot
e.batchingCache.withdrawRoot = e.batchingCache.currentWithdrawRoot
e.batchingCache.lastPackedBlockHeight = curHeight
e.batchingCache.batchData = types.NewBatchData()
e.batchingCache.batchData.Append(e.batchingCache.currentBlockContext, e.batchingCache.currentTxsPayload, e.batchingCache.currentL1TxsHashes)
e.batchingCache.ClearCurrent()

e.logger.Info("Committed batch", "batchIndex", currentIndex)
return nil
return exceeded, err
}

func (e *Executor) AppendBlsData(height int64, batchHash []byte, data l2node.BlsData) error {
Expand Down Expand Up @@ -366,7 +215,7 @@ func (e *Executor) PackCurrentBlock(currentBlockBytes []byte, currentTxs tmtypes
}
}

curHeight, err := heightFromBCBytes(currentBlockBytes)
curHeight, err := types.HeightFromBCBytes(currentBlockBytes)
if err != nil {
return err
}
Expand Down Expand Up @@ -495,18 +344,6 @@ func (e *Executor) ConvertBlsData(blsData l2node.BlsData) (*eth.BatchSignature,
return &bs, nil
}

func wrappedBlockFromBytes(blockBytes []byte) (*types.WrappedBlock, error) {
var curBlock = new(types.WrappedBlock)
if err := curBlock.UnmarshalBinary(blockBytes); err != nil {
return nil, err
}
return curBlock, nil
}

func heightFromBCBytes(blockBytes []byte) (uint64, error) {
curBlock, err := wrappedBlockFromBytes(blockBytes)
if err != nil {
return 0, err
}
return curBlock.Number, nil
func (e *Executor) isBatchUpgraded(blockTime uint64) bool {
return blockTime >= e.UpgradeBatchTime
}
105 changes: 105 additions & 0 deletions node/core/batch_commit.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package node

import (
"bytes"
"context"
"fmt"
"math/big"
"morph-l2/node/types"

"github.com/morph-l2/go-ethereum/accounts/abi/bind"
eth "github.com/morph-l2/go-ethereum/core/types"
"github.com/tendermint/tendermint/l2node"
tmtypes "github.com/tendermint/tendermint/types"
)

// CommitBatch commits the sealed batch. It does nothing if no batch header is sealed.
// It should be called when the current block is confirmed.
func (e *Executor) CommitBatch(currentBlockBytes []byte, currentTxs tmtypes.Txs, blsDatas []l2node.BlsData) error {
// If no batch data is available, do nothing
if e.batchingCache.IsEmpty() || e.batchingCache.sealedBatchHeader == nil {
return nil
}

// Reconstruct current block context if needed
if !bytes.Equal(currentBlockBytes, e.batchingCache.currentBlockBytes) || !bytes.Equal(currentTxs.Hash(), e.batchingCache.currentTxsHash) {
e.logger.Info("Current block has changed. Reconstructing current context...")
if err := e.setCurrentBlock(currentBlockBytes, currentTxs); err != nil {
return fmt.Errorf("failed to set current block: %w", err)
}
}

// Get current block height
curHeight, err := types.HeightFromBCBytes(e.batchingCache.currentBlockBytes)
if err != nil {
return fmt.Errorf("failed to parse current block height: %w", err)
}

// Convert BlsData to batch signatures (if applicable)
var batchSigs []eth.BatchSignature
if !e.devSequencer {
batchSigs, err = e.ConvertBlsDatas(blsDatas)
if err != nil {
return fmt.Errorf("failed to convert BLS data: %w", err)
}
}

// Get the sequencer set at current height - 1
callOpts := &bind.CallOpts{BlockNumber: big.NewInt(int64(curHeight - 1))}
sequencerSetBytes, err := e.sequencerCaller.GetSequencerSetBytes(callOpts)
if err != nil {
e.logger.Error("Failed to GetSequencerSetBytes", "blockHeight", curHeight-1, "error", err)
return fmt.Errorf("failed to get sequencer set bytes: %w", err)
}

// Encode batch data and commit batch to L2 client
blockContexts, err := e.batchingCache.batchData.Encode()
if err != nil {
return fmt.Errorf("failed to encode block contexts: %w", err)
}

// Construct the batch and commit it
if err = e.l2Client.CommitBatch(context.Background(), &eth.RollupBatch{
Version: 0,
Index: e.batchingCache.parentBatchHeader.BatchIndex + 1,
Hash: e.batchingCache.sealedBatchHeader.Hash(),
ParentBatchHeader: e.batchingCache.parentBatchHeader.Encode(),
CurrentSequencerSetBytes: sequencerSetBytes,
BlockContexts: blockContexts,
PrevStateRoot: e.batchingCache.prevStateRoot,
PostStateRoot: e.batchingCache.postStateRoot,
WithdrawRoot: e.batchingCache.withdrawRoot,
Sidecar: e.batchingCache.sealedSidecar,
LastBlockNumber: e.batchingCache.lastPackedBlockHeight,
NumL1Messages: uint16(e.batchingCache.sealedBatchHeader.L1MessagePopped),
}, batchSigs); err != nil {
return fmt.Errorf("failed to commit batch to L2 client: %w", err)
}

// Update batch index metric
e.metrics.BatchIndex.Set(float64(e.batchingCache.parentBatchHeader.BatchIndex + 1))

// Commit the batch and reset the cache for the next batch
e.commitSealedBatch(curHeight)

e.logger.Info("Committed batch", "batchIndex", e.batchingCache.parentBatchHeader.BatchIndex+1)
return nil
}

// commitSealedBatch commits the sealed batch and resets cache for the next batch.
func (e *Executor) commitSealedBatch(curHeight uint64) {
e.batchingCache.parentBatchHeader = e.batchingCache.sealedBatchHeader
e.batchingCache.prevStateRoot = e.batchingCache.postStateRoot
e.batchingCache.sealedBatchHeader = nil
e.batchingCache.sealedSidecar = nil

e.batchingCache.totalL1MessagePopped = e.batchingCache.totalL1MessagePoppedAfterCurBlock
e.batchingCache.postStateRoot = e.batchingCache.currentStateRoot
e.batchingCache.withdrawRoot = e.batchingCache.currentWithdrawRoot
e.batchingCache.lastPackedBlockHeight = curHeight

// Reset batch data and current context
e.batchingCache.batchData = types.NewBatchData()
e.batchingCache.batchData.Append(e.batchingCache.currentBlockContext, e.batchingCache.currentTxsPayload, e.batchingCache.currentL1TxsHashes)
e.batchingCache.ClearCurrent()
}
Loading

0 comments on commit 4d0d215

Please sign in to comment.