diff --git a/cmd/rpcdaemon/commands/zkevm_api.go b/cmd/rpcdaemon/commands/zkevm_api.go index 16ee3284654..13df6aae7a8 100644 --- a/cmd/rpcdaemon/commands/zkevm_api.go +++ b/cmd/rpcdaemon/commands/zkevm_api.go @@ -581,7 +581,7 @@ func (api *ZkEvmAPIImpl) GetBatchByNumber(ctx context.Context, batchNumber rpc.B batch.GlobalExitRoot = batchGer // sequence - seq, err := hermezDb.GetSequenceByBatchNo(batchNo) + seq, err := hermezDb.GetSequenceByBatchNoOrHighest(batchNo) if err != nil { return nil, err } @@ -595,23 +595,37 @@ func (api *ZkEvmAPIImpl) GetBatchByNumber(ctx context.Context, batchNumber rpc.B // sequenced, genesis or injected batch 1 - special batches 0,1 will always be closed, if next batch has blocks, bn must be closed batch.Closed = seq != nil || batchNo == 0 || batchNo == 1 || found - // verification - ver, err := hermezDb.GetVerificationByBatchNo(batchNo) + // verification - if we can't find one, maybe this batch was verified along with a higher batch number + ver, err := hermezDb.GetVerificationByBatchNoOrHighest(batchNo) if err != nil { return nil, err } + if ver == nil { + // TODO: this is the actual unverified batch behaviour probably set 0x00 + } if ver != nil { batch.VerifyBatchTxHash = &ver.L1TxHash - } - // exit roots (MainnetExitRoot, RollupExitRoot) - infoTreeUpdate, err := hermezDb.GetL1InfoTreeUpdateByGer(batchGer) - if err != nil { - return nil, err - } - if infoTreeUpdate != nil { - batch.MainnetExitRoot = infoTreeUpdate.MainnetExitRoot - batch.RollupExitRoot = infoTreeUpdate.RollupExitRoot + verificationBatch := ver.BatchNo + verifiedBatchHighestBlock, err := hermezDb.GetHighestBlockInBatch(verificationBatch) + if err != nil { + return nil, err + } + + verifiedBatchGer, err := hermezDb.GetBlockGlobalExitRoot(verifiedBatchHighestBlock) + if err != nil { + return nil, err + } + + // exit roots (MainnetExitRoot, RollupExitRoot) + infoTreeUpdate, err := hermezDb.GetL1InfoTreeUpdateByGer(verifiedBatchGer) + if err != nil { + return nil, err + } + if infoTreeUpdate != nil { + batch.MainnetExitRoot = infoTreeUpdate.MainnetExitRoot + batch.RollupExitRoot = infoTreeUpdate.RollupExitRoot + } } // local exit root diff --git a/zk/hermez_db/db.go b/zk/hermez_db/db.go index 2e263e4be71..301ad3ce3e1 100644 --- a/zk/hermez_db/db.go +++ b/zk/hermez_db/db.go @@ -264,6 +264,52 @@ func (db *HermezDbReader) GetSequenceByBatchNo(batchNo uint64) (*types.L1BatchIn return db.getByBatchNo(L1SEQUENCES, batchNo) } +func (db *HermezDbReader) GetSequenceByBatchNoOrHighest(batchNo uint64) (*types.L1BatchInfo, error) { + seq, err := db.getByBatchNo(L1SEQUENCES, batchNo) + if err != nil { + return nil, err + } + + if seq == nil { + // start a cursor at the current batch no and then call .next to find the next highest sequence + c, err := db.tx.Cursor(L1SEQUENCES) + if err != nil { + return nil, err + } + defer c.Close() + + var k, v []byte + for k, v, err = c.Seek(Uint64ToBytes(batchNo)); k != nil; k, v, err = c.Next() { + if err != nil { + return nil, err + } + + l1Block, batch, err := SplitKey(k) + if err != nil { + return nil, err + } + + if batch > batchNo { + if len(v) != 64 { + return nil, fmt.Errorf("invalid hash length") + } + + l1TxHash := common.BytesToHash(v[:32]) + stateRoot := common.BytesToHash(v[32:64]) + + return &types.L1BatchInfo{ + BatchNo: batch, + L1BlockNo: l1Block, + StateRoot: stateRoot, + L1TxHash: l1TxHash, + }, nil + } + } + } + + return nil, nil +} + func (db *HermezDbReader) GetVerificationByL1Block(l1BlockNo uint64) (*types.L1BatchInfo, error) { return db.getByL1Block(L1VERIFICATIONS, l1BlockNo) } @@ -272,6 +318,57 @@ func (db *HermezDbReader) GetVerificationByBatchNo(batchNo uint64) (*types.L1Bat return db.getByBatchNo(L1VERIFICATIONS, batchNo) } +func (db *HermezDbReader) GetVerificationByBatchNoOrHighest(batchNo uint64) (*types.L1BatchInfo, error) { + batchInfo, err := db.getByBatchNo(L1VERIFICATIONS, batchNo) + if err != nil { + return nil, err + } + + if batchInfo == nil { + // start a cursor at the current batch no and then call .next to find the next highest verification + c, err := db.tx.Cursor(L1VERIFICATIONS) + if err != nil { + return nil, err + } + defer c.Close() + + var k, v []byte + for k, v, err = c.Seek(Uint64ToBytes(batchNo)); k != nil; k, v, err = c.Next() { + if err != nil { + return nil, err + } + + l1Block, batch, err := SplitKey(k) + if err != nil { + return nil, err + } + + if batch > batchNo { + if len(v) != 96 && len(v) != 64 { + return nil, fmt.Errorf("invalid hash length") + } + + l1TxHash := common.BytesToHash(v[:32]) + stateRoot := common.BytesToHash(v[32:64]) + var l1InfoRoot common.Hash + if len(v) > 64 { + l1InfoRoot = common.BytesToHash(v[64:]) + } + + return &types.L1BatchInfo{ + BatchNo: batch, + L1BlockNo: l1Block, + StateRoot: stateRoot, + L1TxHash: l1TxHash, + L1InfoRoot: l1InfoRoot, + }, nil + } + } + } + + return nil, nil +} + func (db *HermezDbReader) getByL1Block(table string, l1BlockNo uint64) (*types.L1BatchInfo, error) { c, err := db.tx.Cursor(table) if err != nil {