Skip to content

Commit

Permalink
add check for l2batchdata limit (#691)
Browse files Browse the repository at this point in the history
  • Loading branch information
V-Staykov authored Jul 2, 2024
1 parent d5d4136 commit e2ffe0b
Show file tree
Hide file tree
Showing 5 changed files with 153 additions and 90 deletions.
98 changes: 43 additions & 55 deletions cmd/rpcdaemon/commands/zkevm_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -314,43 +314,59 @@ func (api *ZkEvmAPIImpl) GetBatchDataByNumbers(ctx context.Context, batchNumbers
return nil, err
}

// last batch last block for deltaTimestamp calc
lastBlockNoInPreviousBatch := batchBlocks[0].NumberU64() - 1
lastBlockInPreviousBatch, err := rawdb.ReadBlockByNumber(tx, lastBlockNoInPreviousBatch)
batchL2Data, err := generateBatchData(tx, hermezDb, batchBlocks, forkId)
if err != nil {
return nil, err
}

var batchL2Data []byte
for i := 0; i < len(batchBlocks); i++ {
var dTs uint32
if i == 0 {
dTs = uint32(batchBlocks[i].Time() - lastBlockInPreviousBatch.Time())
} else {
dTs = uint32(batchBlocks[i].Time() - batchBlocks[i-1].Time())
}
iti, err := hermezDb.GetBlockL1InfoTreeIndex(batchBlocks[i].NumberU64())

egTx := make(map[common.Hash]uint8)
for _, txn := range batchBlocks[i].Transactions() {
eg, err := hermezDb.GetEffectiveGasPricePercentage(txn.Hash())
if err != nil {
return nil, err
}
egTx[txn.Hash()] = eg
}
bd.BatchL2Data = batchL2Data
bds = append(bds, bd)
}

bl2d, err := zktx.GenerateBlockBatchL2Data(uint16(forkId), dTs, uint32(iti), batchBlocks[i].Transactions(), egTx)
return populateBatchDataSlimDetails(bds)
}

func generateBatchData(
tx kv.Tx,
hermezDb *hermez_db.HermezDbReader,
batchBlocks []*eritypes.Block,
forkId uint64,
) (batchL2Data []byte, err error) {
lastBlockNoInPreviousBatch := batchBlocks[0].NumberU64() - 1
lastBlockInPreviousBatch, err := rawdb.ReadBlockByNumber(tx, lastBlockNoInPreviousBatch)
if err != nil {
return nil, err
}

batchL2Data = []byte{}
for i := 0; i < len(batchBlocks); i++ {
var dTs uint32
if i == 0 {
dTs = uint32(batchBlocks[i].Time() - lastBlockInPreviousBatch.Time())
} else {
dTs = uint32(batchBlocks[i].Time() - batchBlocks[i-1].Time())
}
iti, err := hermezDb.GetBlockL1InfoTreeIndex(batchBlocks[i].NumberU64())
if err != nil {
return nil, err
}
egTx := make(map[common.Hash]uint8)
for _, txn := range batchBlocks[i].Transactions() {
eg, err := hermezDb.GetEffectiveGasPricePercentage(txn.Hash())
if err != nil {
return nil, err
}
batchL2Data = append(batchL2Data, bl2d...)
egTx[txn.Hash()] = eg
}
bd.BatchL2Data = batchL2Data
bds = append(bds, bd)

bl2d, err := zktx.GenerateBlockBatchL2Data(uint16(forkId), dTs, uint32(iti), batchBlocks[i].Transactions(), egTx)
if err != nil {
return nil, err
}
batchL2Data = append(batchL2Data, bl2d...)
}

return populateBatchDataSlimDetails(bds)
return batchL2Data, err
}

// GetBatchByNumber returns a batch from the current canonical chain. If number is nil, the
Expand Down Expand Up @@ -529,38 +545,10 @@ func (api *ZkEvmAPIImpl) GetBatchByNumber(ctx context.Context, batchNumber rpc.B
return nil, err
}

// last batch last block for deltaTimestamp calc
lastBlockNoInPreviousBatch := batchBlocks[0].NumberU64() - 1
lastBlockInPreviousBatch, err := rawdb.ReadBlockByNumber(tx, lastBlockNoInPreviousBatch)
batchL2Data, err := generateBatchData(tx, hermezDb, batchBlocks, forkId)
if err != nil {
return nil, err
}

var batchL2Data []byte
for i := 0; i < len(batchBlocks); i++ {
var dTs uint32
if i == 0 {
dTs = uint32(batchBlocks[i].Time() - lastBlockInPreviousBatch.Time())
} else {
dTs = uint32(batchBlocks[i].Time() - batchBlocks[i-1].Time())
}
iti, err := hermezDb.GetBlockL1InfoTreeIndex(batchBlocks[i].NumberU64())

egTx := make(map[common.Hash]uint8)
for _, txn := range batchBlocks[i].Transactions() {
eg, err := hermezDb.GetEffectiveGasPricePercentage(txn.Hash())
if err != nil {
return nil, err
}
egTx[txn.Hash()] = eg
}

bl2d, err := zktx.GenerateBlockBatchL2Data(uint16(forkId), dTs, uint32(iti), batchBlocks[i].Transactions(), egTx)
if err != nil {
return nil, err
}
batchL2Data = append(batchL2Data, bl2d...)
}
batch.BatchL2Data = batchL2Data

// currently gives 'error execution reverted' when calling the L1
Expand Down
14 changes: 8 additions & 6 deletions zk/stages/stage_l1syncer.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"github.com/ledgerwatch/erigon/eth/stagedsync/stages"
"github.com/ledgerwatch/erigon/zk/contracts"
"github.com/ledgerwatch/erigon/zk/hermez_db"
"github.com/ledgerwatch/erigon/zk/sequencer"
"github.com/ledgerwatch/erigon/zk/types"
)

Expand Down Expand Up @@ -413,12 +414,13 @@ func verifyAgainstLocalBlocks(tx kv.RwTx, hermezDb *hermez_db.HermezDb, logPrefi
return nil
}

err = blockComparison(tx, hermezDb, blockToCheck, logPrefix)

if err == nil {
log.Info(fmt.Sprintf("[%s] State root verified in block %d", logPrefix, blockToCheck))
if err := stages.SaveStageProgress(tx, stages.VerificationsStateRootCheck, verifiedBlockNo); err != nil {
return fmt.Errorf("failed to save stage progress, %w", err)
if !sequencer.IsSequencer() {
err = blockComparison(tx, hermezDb, blockToCheck, logPrefix)
if err == nil {
log.Info(fmt.Sprintf("[%s] State root verified in block %d", logPrefix, blockToCheck))
if err := stages.SaveStageProgress(tx, stages.VerificationsStateRootCheck, verifiedBlockNo); err != nil {
return fmt.Errorf("failed to save stage progress, %w", err)
}
}
}

Expand Down
69 changes: 46 additions & 23 deletions zk/stages/stage_sequence_execute.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ import (
"github.com/ledgerwatch/erigon/eth/stagedsync/stages"
"github.com/ledgerwatch/erigon/zk"
"github.com/ledgerwatch/erigon/zk/datastream/server"
"github.com/ledgerwatch/erigon/zk/l1_data"
zktx "github.com/ledgerwatch/erigon/zk/tx"
"github.com/ledgerwatch/erigon/zk/utils"
"github.com/ledgerwatch/erigon/zk/l1_data"
)

var SpecialZeroIndexHash = common.HexToHash("0x27AE5BA08D7291C96C8CBDDCC148BF48A6D68C7974B94356F53754EF6171D757")
Expand Down Expand Up @@ -207,6 +207,11 @@ func SpawnSequencingStage(
}
}

blockDataSizeChecker := NewBlockDataChecker()

prevHeader := rawdb.ReadHeaderByNumber(tx, executionAt)
batchDataOverflow := false

log.Info(fmt.Sprintf("[%s] Starting batch %d...", logPrefix, thisBatch))

for blockNumber := executionAt; runLoopBlocks; blockNumber++ {
Expand All @@ -223,6 +228,11 @@ func SpawnSequencingStage(
blockTransactions = decodedBlock.Transactions
}

l1InfoIndex, err := sdb.hermezDb.GetBlockL1InfoTreeIndex(lastStartedBn)
if err != nil {
return err
}

log.Info(fmt.Sprintf("[%s] Starting block %d...", logPrefix, blockNumber+1))

reRunBlockAfterOverflow := blockNumber == lastStartedBn
Expand All @@ -237,6 +247,12 @@ func SpawnSequencingStage(
if err != nil {
return err
}

// run this only once the first time, do not add it on rerun
if batchDataOverflow = blockDataSizeChecker.AddBlockStartData(uint16(forkId), uint32(prevHeader.Time-header.Time), uint32(l1InfoIndex)); batchDataOverflow {
log.Info(fmt.Sprintf("[%s] BatchL2Data limit reached. Stopping.", logPrefix), "blockNumber", blockNumber)
break
}
} else {
batchCounters = clonedBatchCounters

Expand All @@ -251,11 +267,6 @@ func SpawnSequencingStage(
}
}

l1InfoIndex, err := sdb.hermezDb.GetBlockL1InfoTreeIndex(lastStartedBn)
if err != nil {
return err
}

overflowOnNewBlock, err := batchCounters.StartNewBlock(l1InfoIndex != 0)
if err != nil {
return err
Expand Down Expand Up @@ -357,26 +368,38 @@ func SpawnSequencingStage(
effectiveGas = DeriveEffectiveGasPrice(cfg, transaction)
}

receipt, overflow, err = attemptAddTransaction(cfg, sdb, ibs, batchCounters, &blockContext, header, transaction, effectiveGas, l1Recovery, forkId, l1InfoIndex)
if err != nil {
if limboRecovery {
panic("limbo transaction has already been executed once so they must not fail while re-executing")
}
// run this only once the first time, do not add it on rerun
if batchDataOverflow, err = blockDataSizeChecker.AddTransactionData(transaction, uint16(forkId), effectiveGas); err != nil {
return err
}

// if we are in recovery just log the error as a warning. If the data is on the L1 then we should consider it as confirmed.
// The executor/prover would simply skip a TX with an invalid nonce for example so we don't need to worry about that here.
if l1Recovery {
log.Warn(fmt.Sprintf("[%s] error adding transaction to batch during recovery: %v", logPrefix, err),
"hash", transaction.Hash(),
"to", transaction.GetTo(),
)
continue
}
if !batchDataOverflow {
receipt, overflow, err = attemptAddTransaction(cfg, sdb, ibs, batchCounters, &blockContext, header, transaction, effectiveGas, l1Recovery, forkId, l1InfoIndex)
if err != nil {
if limboRecovery {
panic("limbo transaction has already been executed once so they must not fail while re-executing")
}

i++ // leave current tx in yielded set
reRunBlock = true
// if we are in recovery just log the error as a warning. If the data is on the L1 then we should consider it as confirmed.
// The executor/prover would simply skip a TX with an invalid nonce for example so we don't need to worry about that here.
if l1Recovery {
log.Warn(fmt.Sprintf("[%s] error adding transaction to batch during recovery: %v", logPrefix, err),
"hash", transaction.Hash(),
"to", transaction.GetTo(),
)
continue
}

i++ // leave current tx in yielded set
reRunBlock = true
}
} else {
log.Info(fmt.Sprintf("[%s] BatchL2Data limit reached. Not adding last transaction", logPrefix), "txHash", transaction.Hash())
}
if !reRunBlock && overflow {

anyOverflow := overflow || batchDataOverflow

if !reRunBlock && anyOverflow {
if limboRecovery {
panic("limbo transaction has already been executed once so they must not overflow counters while re-executing")
}
Expand Down
45 changes: 44 additions & 1 deletion zk/stages/stage_sequence_execute_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,12 @@ import (
"github.com/ledgerwatch/erigon/turbo/shards"
"github.com/ledgerwatch/erigon/turbo/stages/headerdownload"
"github.com/ledgerwatch/erigon/zk/hermez_db"
"github.com/ledgerwatch/erigon/zk/tx"
zktx "github.com/ledgerwatch/erigon/zk/tx"
"github.com/ledgerwatch/erigon/zk/txpool"
zktypes "github.com/ledgerwatch/erigon/zk/types"
"github.com/ledgerwatch/log/v3"
"github.com/ledgerwatch/erigon/zk/utils"
"github.com/ledgerwatch/log/v3"
)

const (
Expand Down Expand Up @@ -421,3 +422,45 @@ func checkForBadBatch(

return false, nil
}

var (
LIMIT_128_KB = uint64(128 * 1024)
)

type BlockDataChecker struct {
limit uint64 // amount of bytes
bytes []byte
}

func NewBlockDataChecker() *BlockDataChecker {
return &BlockDataChecker{
limit: LIMIT_128_KB,
bytes: make([]byte, 0),
}
}

// adds bytes amounting to the block data and checks if the limit is reached
// if the limit is reached, the data is not added, so this can be reused again for next check
func (bdc *BlockDataChecker) AddBlockStartData(forkId uint16, deltaTimestamp, l1InfoTreeIndex uint32) bool {
newBytes := tx.GenerateStartBlockBatchL2Data(forkId, deltaTimestamp, l1InfoTreeIndex)

if uint64(len(bdc.bytes)+len(newBytes)) > bdc.limit {
return true
}

bdc.bytes = append(bdc.bytes, newBytes...)
return false
}

func (bdc *BlockDataChecker) AddTransactionData(transaction types.Transaction, forkId uint16, effectiveGasPrice uint8) (bool, error) {
encoded, err := tx.TransactionToL2Data(transaction, forkId, effectiveGasPrice)
if err != nil {
return false, err
}
if uint64(len(bdc.bytes)+len(encoded)) > bdc.limit {
return true, nil
}

bdc.bytes = append(bdc.bytes, encoded...)
return false, nil
}
17 changes: 12 additions & 5 deletions zk/tx/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -383,12 +383,8 @@ func GetDecodedV(tx types.Transaction, v *uint256.Int) *uint256.Int {
}

func GenerateBlockBatchL2Data(forkId uint16, deltaTimestamp uint32, l1InfoTreeIndex uint32, transactions []types.Transaction, egTx map[common.Hash]uint8) ([]byte, error) {
var result []byte

// add in the changeL2Block transaction
result = append(result, changeL2BlockTxType)
result = binary.BigEndian.AppendUint32(result, deltaTimestamp)
result = binary.BigEndian.AppendUint32(result, l1InfoTreeIndex)
result := GenerateStartBlockBatchL2Data(forkId, deltaTimestamp, l1InfoTreeIndex)

for _, transaction := range transactions {
encoded, err := TransactionToL2Data(transaction, forkId, egTx[transaction.Hash()])
Expand All @@ -401,6 +397,17 @@ func GenerateBlockBatchL2Data(forkId uint16, deltaTimestamp uint32, l1InfoTreeIn
return result, nil
}

func GenerateStartBlockBatchL2Data(forkId uint16, deltaTimestamp uint32, l1InfoTreeIndex uint32) []byte {
var result []byte

// add in the changeL2Block transaction
result = append(result, changeL2BlockTxType)
result = binary.BigEndian.AppendUint32(result, deltaTimestamp)
result = binary.BigEndian.AppendUint32(result, l1InfoTreeIndex)

return result
}

func ComputeL2TxHash(
chainId *big.Int,
value, gasPrice *uint256.Int,
Expand Down

0 comments on commit e2ffe0b

Please sign in to comment.