Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(relayer): estimate l1 batch commit gas #659

Merged
merged 31 commits into from
Jul 31, 2023
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
9f3709a
feat(relayer): estimate l1 batch commit gas
colinlyguo Jul 19, 2023
ddbe3f0
add approximate calldata cost
colinlyguo Jul 21, 2023
de7a0c2
Merge branch 'develop' into feat-estimate-l1-batch-commit-gas
colinlyguo Jul 21, 2023
858a657
fix
colinlyguo Jul 21, 2023
e2d85e4
Merge branch 'develop' into feat-estimate-l1-batch-commit-gas
colinlyguo Jul 23, 2023
e33f802
tweak
colinlyguo Jul 24, 2023
2898a10
trigger ci
colinlyguo Jul 24, 2023
3cc4254
Merge branch 'develop' into feat-estimate-l1-batch-commit-gas
colinlyguo Jul 24, 2023
a10b154
Merge branch 'develop' into feat-estimate-l1-batch-commit-gas
colinlyguo Jul 25, 2023
0944ab6
fix bug
colinlyguo Jul 25, 2023
ba1c12f
Merge branch 'develop' into feat-estimate-l1-batch-commit-gas
colinlyguo Jul 25, 2023
72a638a
treat every txs calldata bytes as non-zero
colinlyguo Jul 25, 2023
7819f0d
address comments
colinlyguo Jul 25, 2023
6cce4b8
Merge branch 'develop' into feat-estimate-l1-batch-commit-gas
colinlyguo Jul 26, 2023
f1206d7
add chunk.EstimateL1CommitGas()
colinlyguo Jul 26, 2023
11c9a29
add over-estimate params
colinlyguo Jul 26, 2023
7e62898
tweak orm
colinlyguo Jul 26, 2023
d24a6d0
bump version
colinlyguo Jul 26, 2023
48c6768
trigger ci
colinlyguo Jul 27, 2023
6d87c78
Merge branch 'develop' into feat-estimate-l1-batch-commit-gas
colinlyguo Jul 27, 2023
213a174
Merge branch 'develop' into feat-estimate-l1-batch-commit-gas
colinlyguo Jul 28, 2023
d9a92c0
Merge branch 'develop' into feat-estimate-l1-batch-commit-gas
colinlyguo Jul 28, 2023
04ab9ea
fix golint and bump version again
colinlyguo Jul 28, 2023
309fe35
add l2 tx hash gas cost
colinlyguo Jul 28, 2023
79dd3de
Merge branch 'develop' into feat-estimate-l1-batch-commit-gas
colinlyguo Jul 29, 2023
b56727a
fix unnecessary conversion
HAOYUatHZ Jul 29, 2023
8a2ffd0
trigger ci
colinlyguo Jul 29, 2023
0c7d276
Merge branch 'develop' into feat-estimate-l1-batch-commit-gas
colinlyguo Jul 30, 2023
65118e1
bump version
colinlyguo Jul 31, 2023
fa61b33
trigger ci
colinlyguo Jul 31, 2023
1c76fd0
remove two unused variables
colinlyguo Jul 31, 2023
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
37 changes: 35 additions & 2 deletions bridge/internal/controller/watcher/batch_proposer.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package watcher

import (
"context"
"errors"
"fmt"
"time"

Expand Down Expand Up @@ -99,7 +100,32 @@ func (p *BatchProposer) proposeBatchChunks() ([]*orm.Chunk, error) {
firstChunk := dbChunks[0]
totalL1CommitCalldataSize := firstChunk.TotalL1CommitCalldataSize
totalL1CommitGas := firstChunk.TotalL1CommitGas
var totalChunks uint64 = 1
totalChunks := uint64(1)
totalL1MessagePopped := firstChunk.TotalL1MessagesPoppedBefore + uint64(firstChunk.TotalL1MessagesPoppedInChunk)

parentBatch, err := p.batchOrm.GetLatestBatch(p.ctx)
if err != nil && !errors.Is(errors.Unwrap(err), gorm.ErrRecordNotFound) {
HAOYUatHZ marked this conversation as resolved.
Show resolved Hide resolved
return nil, err
}

getKeccakGas := func(size uint64) uint64 {
return 30 + 6*((size+31)/32) // 30 + 6 * ceil(size / 32)
}

// Add extra gas costs
totalL1CommitGas += 4 * 2100 // 4 one-time cold sload for commitBatch
totalL1CommitGas += 20000 // 1 time sstore
// adjusting gas:
// add 1 time cold sload (2100 gas) for L1MessageQueue
// add 1 time cold address access (2600 gas) for L1MessageQueue
// minus 1 time warm sload (100 gas) & 1 time warm address access (100 gas)
totalL1CommitGas += (2100 + 2600 - 100 - 100)
totalL1CommitGas += getKeccakGas(32 * totalChunks) // batch data hash
if parentBatch != nil { // parent batch header hash
Thegaram marked this conversation as resolved.
Show resolved Hide resolved
totalL1CommitGas += getKeccakGas(uint64(len(parentBatch.BatchHeader)))
}
// batch header size: 89 + 32 * ceil(l1MessagePopped / 256)
totalL1CommitGas += getKeccakGas(89 + 32*(totalL1MessagePopped+255)/256)
Thegaram marked this conversation as resolved.
Show resolved Hide resolved

// Check if the first chunk breaks hard limits.
// If so, it indicates there are bugs in chunk-proposer, manual fix is needed.
Expand All @@ -124,9 +150,16 @@ func (p *BatchProposer) proposeBatchChunks() ([]*orm.Chunk, error) {
}

for i, chunk := range dbChunks[1:] {
totalChunks++
totalL1CommitCalldataSize += chunk.TotalL1CommitCalldataSize
totalL1CommitGas += chunk.TotalL1CommitGas
// adjust batch data hash gas cost: add one chunk
totalL1CommitGas -= getKeccakGas(32 * totalChunks)
totalChunks++
totalL1CommitGas += getKeccakGas(32 * totalChunks)
zimpha marked this conversation as resolved.
Show resolved Hide resolved
// adjust batch header hash gas cost: adjust totalL1MessagePopped in calculating header length
totalL1CommitGas -= getKeccakGas(89 + 32*(totalL1MessagePopped+255)/256)
totalL1MessagePopped += uint64(chunk.TotalL1MessagesPoppedInChunk)
totalL1CommitGas += getKeccakGas(89 + 32*(totalL1MessagePopped+255)/256)
if totalChunks > p.maxChunkNumPerBatch ||
totalL1CommitCalldataSize > p.maxL1CommitCalldataSizePerBatch ||
totalL1CommitGas > p.maxL1CommitGasPerBatch {
Expand Down
25 changes: 25 additions & 0 deletions bridge/internal/controller/watcher/chunk_proposer.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package watcher

import (
"context"
"errors"
"fmt"
"time"

Expand Down Expand Up @@ -88,11 +89,29 @@ func (p *ChunkProposer) proposeChunk() (*types.Chunk, error) {
return nil, nil
}

parentChunk, err := p.chunkOrm.GetLatestChunk(p.ctx)
if err != nil && !errors.Is(errors.Unwrap(err), gorm.ErrRecordNotFound) {
return nil, err
}
Thegaram marked this conversation as resolved.
Show resolved Hide resolved

firstBlock := blocks[0]
totalTxGasUsed := firstBlock.Header.GasUsed
totalL2TxNum := firstBlock.L2TxsNum()
totalL1CommitCalldataSize := firstBlock.EstimateL1CommitCalldataSize()
totalBlocks := uint64(1)
totalL1CommitGas := firstBlock.EstimateL1CommitGas()
totalL1CommitGas += 100 // warm sload per block

getKeccakGas := func(size uint64) uint64 {
return 30 + 6*((size+31)/32) // 30 + 6 * ceil(size / 32)
}

var totalL1MessagesPoppedBefore uint64
if parentChunk != nil {
totalL1MessagesPoppedBefore = parentChunk.TotalL1MessagesPoppedBefore + uint64(parentChunk.TotalL1MessagesPoppedInChunk)
}
totalL1MessagesPoppedInChunk := firstBlock.NumL1Messages(totalL1MessagesPoppedBefore)
totalL1CommitGas += getKeccakGas(58*totalBlocks + 32*(totalL1MessagesPoppedInChunk+totalL2TxNum))
zimpha marked this conversation as resolved.
Show resolved Hide resolved
Thegaram marked this conversation as resolved.
Show resolved Hide resolved

// Check if the first block breaks hard limits.
// If so, it indicates there are bugs in sequencer, manual fix is needed.
Expand Down Expand Up @@ -138,6 +157,12 @@ func (p *ChunkProposer) proposeChunk() (*types.Chunk, error) {
totalL2TxNum += block.L2TxsNum()
Thegaram marked this conversation as resolved.
Show resolved Hide resolved
totalL1CommitCalldataSize += block.EstimateL1CommitCalldataSize()
totalL1CommitGas += block.EstimateL1CommitGas()
totalL1CommitGas += 100 // warm sload per block
// adjust chunk hash gas cost: add one block
totalL1CommitGas -= getKeccakGas(58*totalBlocks + 32*(totalL1MessagesPoppedInChunk+totalL2TxNum))
Thegaram marked this conversation as resolved.
Show resolved Hide resolved
totalBlocks++
totalL1MessagesPoppedInChunk += block.NumL1Messages(totalL1MessagesPoppedBefore + totalL1MessagesPoppedInChunk)
totalL1CommitGas += getKeccakGas(58*totalBlocks + 32*(totalL1MessagesPoppedInChunk+totalL2TxNum))
Thegaram marked this conversation as resolved.
Show resolved Hide resolved
if totalTxGasUsed > p.maxTxGasPerChunk ||
totalL2TxNum > p.maxL2TxNumPerChunk ||
totalL1CommitCalldataSize > p.maxL1CommitCalldataSizePerChunk ||
Expand Down
15 changes: 13 additions & 2 deletions bridge/internal/orm/chunk.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,18 @@ func (o *Chunk) InsertChunk(ctx context.Context, chunk *types.Chunk, dbTX ...*go
totalL1CommitGas += block.EstimateL1CommitGas()
}

numBlocks := len(chunk.Blocks)
numBlocks := uint64(len(chunk.Blocks))

// Calculate additional gas costs
totalL1CommitGas += numBlocks * 100 // numBlocks times warm sload

getKeccakGas := func(size uint64) uint64 {
return 30 + 6*((size+31)/32) // 30 + 6 * ceil(size / 32)
}

totalL1MessagesPoppedInChunk := chunk.NumL1Messages(totalL1MessagePoppedBefore)
Thegaram marked this conversation as resolved.
Show resolved Hide resolved
totalL1CommitGas += getKeccakGas(58*numBlocks + 32*(totalL1MessagesPoppedInChunk+totalL2TxNum)) // chunk hash

newChunk := Chunk{
Index: chunkIndex,
Hash: hash.Hex(),
Expand All @@ -163,7 +174,7 @@ func (o *Chunk) InsertChunk(ctx context.Context, chunk *types.Chunk, dbTX ...*go
TotalL1CommitGas: totalL1CommitGas,
StartBlockTime: chunk.Blocks[0].Header.Time,
TotalL1MessagesPoppedBefore: totalL1MessagePoppedBefore,
TotalL1MessagesPoppedInChunk: uint32(chunk.NumL1Messages(totalL1MessagePoppedBefore)),
TotalL1MessagesPoppedInChunk: uint32(totalL1MessagesPoppedInChunk),
ProvingStatus: int16(types.ProvingTaskUnassigned),
}

Expand Down
26 changes: 16 additions & 10 deletions common/types/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,6 @@ import (
"github.com/scroll-tech/go-ethereum/core/types"
)

const nonZeroByteGas uint64 = 16
const zeroByteGas uint64 = 4

// WrappedBlock contains the block's Header, Transactions and WithdrawTrieRoot hash.
type WrappedBlock struct {
Header *types.Header `json:"header"`
Expand Down Expand Up @@ -79,15 +76,15 @@ func (w *WrappedBlock) EstimateL1CommitCalldataSize() uint64 {
}

// EstimateL1CommitGas calculates the calldata gas in l1 commit approximately.
// TODO: This will need to be adjusted.
// The part added here is only the calldata cost,
// but we have execution cost for verifying blocks / chunks / batches and storing the batch hash.
func (w *WrappedBlock) EstimateL1CommitGas() uint64 {
var total uint64
var numL1Messages uint64
for _, txData := range w.Transactions {
if txData.Type == types.L1MessageTxType {
numL1Messages++
continue
}

data, _ := hexutil.Decode(txData.Data)
tx := types.NewTx(&types.LegacyTx{
Nonce: txData.Nonce,
Expand All @@ -102,11 +99,12 @@ func (w *WrappedBlock) EstimateL1CommitGas() uint64 {
})
rlpTxData, _ := tx.MarshalBinary()

// approximate calldata gas cost
for _, b := range rlpTxData {
if b == 0 {
total += zeroByteGas
total += 4
HAOYUatHZ marked this conversation as resolved.
Show resolved Hide resolved
} else {
total += nonZeroByteGas
total += 16
}
}

Expand All @@ -115,12 +113,20 @@ func (w *WrappedBlock) EstimateL1CommitGas() uint64 {

for _, b := range txLen {
if b == 0 {
total += zeroByteGas
total += 4
} else {
total += nonZeroByteGas
total += 16
}
}
}
Thegaram marked this conversation as resolved.
Show resolved Hide resolved

// sload
total += numL1Messages * 2100 // numL1Messages times cold sload in L1MessageQueue

// staticcall
total += numL1Messages * 100 // numL1Messages times call to L1MessageQueue
total += numL1Messages * 100 // numL1Messages times warm address access to L1MessageQueue

return total
}

Expand Down
Loading