mirror of
https://github.com/scroll-tech/scroll.git
synced 2026-01-15 00:48:01 -05:00
232 lines
7.4 KiB
Go
232 lines
7.4 KiB
Go
package utils
|
|
|
|
import (
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/scroll-tech/da-codec/encoding"
|
|
"github.com/scroll-tech/go-ethereum/common"
|
|
)
|
|
|
|
// ChunkMetrics indicates the metrics for proposing a chunk.
|
|
type ChunkMetrics struct {
|
|
NumBlocks uint64
|
|
TxNum uint64
|
|
L2Gas uint64
|
|
CrcMax uint64
|
|
FirstBlockTimestamp uint64
|
|
|
|
L1CommitCalldataSize uint64
|
|
L1CommitGas uint64
|
|
|
|
L1CommitBlobSize uint64
|
|
L1CommitUncompressedBatchBytesSize uint64
|
|
|
|
// timing metrics
|
|
EstimateGasTime time.Duration
|
|
EstimateCalldataSizeTime time.Duration
|
|
EstimateBlobSizeTime time.Duration
|
|
}
|
|
|
|
// CalculateChunkMetrics calculates chunk metrics.
|
|
func CalculateChunkMetrics(chunk *encoding.Chunk, codecVersion encoding.CodecVersion) (*ChunkMetrics, error) {
|
|
metrics := &ChunkMetrics{
|
|
TxNum: chunk.NumTransactions(),
|
|
NumBlocks: uint64(len(chunk.Blocks)),
|
|
FirstBlockTimestamp: chunk.Blocks[0].Header.Time,
|
|
}
|
|
|
|
// Get total L2 gas for chunk
|
|
for _, block := range chunk.Blocks {
|
|
metrics.L2Gas += block.Header.GasUsed
|
|
}
|
|
|
|
var err error
|
|
metrics.CrcMax, err = chunk.CrcMax()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to get crc max, version: %v, err: %w", codecVersion, err)
|
|
}
|
|
|
|
codec, err := encoding.CodecFromVersion(codecVersion)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to get codec from version: %v, err: %w", codecVersion, err)
|
|
}
|
|
|
|
metrics.EstimateGasTime, err = measureTime(func() error {
|
|
metrics.L1CommitGas, err = codec.EstimateChunkL1CommitGas(chunk)
|
|
return err
|
|
})
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to estimate chunk L1 commit gas, version: %v, err: %w", codecVersion, err)
|
|
}
|
|
|
|
metrics.EstimateCalldataSizeTime, err = measureTime(func() error {
|
|
metrics.L1CommitCalldataSize, err = codec.EstimateChunkL1CommitCalldataSize(chunk)
|
|
return err
|
|
})
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to estimate chunk L1 commit calldata size, version: %v, err: %w", codecVersion, err)
|
|
}
|
|
|
|
metrics.EstimateBlobSizeTime, err = measureTime(func() error {
|
|
metrics.L1CommitUncompressedBatchBytesSize, metrics.L1CommitBlobSize, err = codec.EstimateChunkL1CommitBatchSizeAndBlobSize(chunk)
|
|
return err
|
|
})
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to estimate chunk L1 commit batch size and blob size, version: %v, err: %w", codecVersion, err)
|
|
}
|
|
|
|
return metrics, nil
|
|
}
|
|
|
|
// BatchMetrics indicates the metrics for proposing a batch.
|
|
type BatchMetrics struct {
|
|
NumChunks uint64
|
|
FirstBlockTimestamp uint64
|
|
|
|
L1CommitCalldataSize uint64
|
|
L1CommitGas uint64
|
|
|
|
L1CommitBlobSize uint64
|
|
L1CommitUncompressedBatchBytesSize uint64
|
|
|
|
// timing metrics
|
|
EstimateGasTime time.Duration
|
|
EstimateCalldataSizeTime time.Duration
|
|
EstimateBlobSizeTime time.Duration
|
|
}
|
|
|
|
// CalculateBatchMetrics calculates batch metrics.
|
|
func CalculateBatchMetrics(batch *encoding.Batch, codecVersion encoding.CodecVersion) (*BatchMetrics, error) {
|
|
metrics := &BatchMetrics{
|
|
NumChunks: uint64(len(batch.Chunks)),
|
|
FirstBlockTimestamp: batch.Chunks[0].Blocks[0].Header.Time,
|
|
}
|
|
|
|
codec, err := encoding.CodecFromVersion(codecVersion)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to get codec from version: %v, err: %w", codecVersion, err)
|
|
}
|
|
|
|
metrics.EstimateGasTime, err = measureTime(func() error {
|
|
metrics.L1CommitGas, err = codec.EstimateBatchL1CommitGas(batch)
|
|
return err
|
|
})
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to estimate batch L1 commit gas, version: %v, err: %w", codecVersion, err)
|
|
}
|
|
|
|
metrics.EstimateCalldataSizeTime, err = measureTime(func() error {
|
|
metrics.L1CommitCalldataSize, err = codec.EstimateBatchL1CommitCalldataSize(batch)
|
|
return err
|
|
})
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to estimate batch L1 commit calldata size, version: %v, err: %w", codecVersion, err)
|
|
}
|
|
|
|
metrics.EstimateBlobSizeTime, err = measureTime(func() error {
|
|
metrics.L1CommitUncompressedBatchBytesSize, metrics.L1CommitBlobSize, err = codec.EstimateBatchL1CommitBatchSizeAndBlobSize(batch)
|
|
return err
|
|
})
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to estimate batch L1 commit batch size and blob size, version: %v, err: %w", codecVersion, err)
|
|
}
|
|
|
|
return metrics, nil
|
|
}
|
|
|
|
// GetChunkHash retrieves the hash of a chunk.
|
|
func GetChunkHash(chunk *encoding.Chunk, totalL1MessagePoppedBefore uint64, codecVersion encoding.CodecVersion) (common.Hash, error) {
|
|
codec, err := encoding.CodecFromVersion(codecVersion)
|
|
if err != nil {
|
|
return common.Hash{}, fmt.Errorf("failed to get codec from version: %v, err: %w", codecVersion, err)
|
|
}
|
|
|
|
daChunk, err := codec.NewDAChunk(chunk, totalL1MessagePoppedBefore)
|
|
if err != nil {
|
|
return common.Hash{}, fmt.Errorf("failed to create DA chunk, version: %v, err: %w", codecVersion, err)
|
|
}
|
|
|
|
chunkHash, err := daChunk.Hash()
|
|
if err != nil {
|
|
return common.Hash{}, fmt.Errorf("failed to get DA chunk hash, version: %v, err: %w", codecVersion, err)
|
|
}
|
|
|
|
return chunkHash, nil
|
|
}
|
|
|
|
// BatchMetadata represents the metadata of a batch.
|
|
type BatchMetadata struct {
|
|
BatchHash common.Hash
|
|
BatchDataHash common.Hash
|
|
BatchBlobDataProof []byte
|
|
BatchBytes []byte
|
|
StartChunkHash common.Hash
|
|
EndChunkHash common.Hash
|
|
BlobBytes []byte
|
|
ChallengeDigest common.Hash
|
|
}
|
|
|
|
// GetBatchMetadata retrieves the metadata of a batch.
|
|
func GetBatchMetadata(batch *encoding.Batch, codecVersion encoding.CodecVersion) (*BatchMetadata, error) {
|
|
codec, err := encoding.CodecFromVersion(codecVersion)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to get codec from version: %v, err: %w", codecVersion, err)
|
|
}
|
|
|
|
daBatch, err := codec.NewDABatch(batch)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to create DA batch, version: %v, err: %w", codecVersion, err)
|
|
}
|
|
|
|
batchMeta := &BatchMetadata{
|
|
BatchHash: daBatch.Hash(),
|
|
BatchDataHash: daBatch.DataHash(),
|
|
BatchBytes: daBatch.Encode(),
|
|
BlobBytes: daBatch.BlobBytes(),
|
|
ChallengeDigest: daBatch.ChallengeDigest(),
|
|
}
|
|
|
|
batchMeta.BatchBlobDataProof, err = daBatch.BlobDataProofForPointEvaluation()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to get blob data proof, version: %v, err: %w", codecVersion, err)
|
|
}
|
|
|
|
numChunks := len(batch.Chunks)
|
|
if numChunks == 0 {
|
|
return nil, fmt.Errorf("batch contains no chunks, version: %v, index: %v", codecVersion, batch.Index)
|
|
}
|
|
|
|
startDAChunk, err := codec.NewDAChunk(batch.Chunks[0], batch.TotalL1MessagePoppedBefore)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to create start DA chunk, version: %v, err: %w", codecVersion, err)
|
|
}
|
|
|
|
batchMeta.StartChunkHash, err = startDAChunk.Hash()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to get start DA chunk hash, version: %v, err: %w", codecVersion, err)
|
|
}
|
|
|
|
totalL1MessagePoppedBeforeEndDAChunk := batch.TotalL1MessagePoppedBefore
|
|
for i := 0; i < len(batch.Chunks)-1; i++ {
|
|
totalL1MessagePoppedBeforeEndDAChunk += batch.Chunks[i].NumL1Messages(totalL1MessagePoppedBeforeEndDAChunk)
|
|
}
|
|
endDAChunk, err := codec.NewDAChunk(batch.Chunks[numChunks-1], totalL1MessagePoppedBeforeEndDAChunk)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to create end DA chunk, version: %v, err: %w", codecVersion, err)
|
|
}
|
|
|
|
batchMeta.EndChunkHash, err = endDAChunk.Hash()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to get end DA chunk hash, version: %v, err: %w", codecVersion, err)
|
|
}
|
|
|
|
return batchMeta, nil
|
|
}
|
|
|
|
func measureTime(operation func() error) (time.Duration, error) {
|
|
start := time.Now()
|
|
err := operation()
|
|
return time.Since(start), err
|
|
}
|