Skip to content

Commit

Permalink
Merge pull request #74 from okx/zkevm-rpc/v1.1.5.9-proper
Browse files Browse the repository at this point in the history
merge upstream v1.1.5.9-proper
  • Loading branch information
KamiD committed Jul 23, 2024
2 parents aa43181 + 76514fe commit 82b45fd
Show file tree
Hide file tree
Showing 6 changed files with 265 additions and 63 deletions.
94 changes: 51 additions & 43 deletions cmd/rpcdaemon/commands/zkevm_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,31 @@ func (api *ZkEvmAPIImpl) GetBatchDataByNumbers(ctx context.Context, batchNumbers

hermezDb := hermez_db.NewHermezDbReader(tx)

// use inbuilt rpc.BlockNumber type to implement the 'latest' behaviour
// highest block/batch tied to last block synced
// unless the node is still syncing - in which case 'current block' is used
// this is the batch number of stage progress of the Finish stage

highestBlock, err := rawdb.ReadLastBlockSynced(tx)
if err != nil {
return nil, err
}

highestBatchNo, err := hermezDb.GetBatchNoByL2Block(highestBlock.NumberU64())
if err != nil {
return nil, err
}

// check sync status of node
syncing, err := api.ethApi.Syncing(ctx)
if err != nil {
return nil, err
}
if syncing != nil && syncing != false {
bn := syncing.(map[string]interface{})["currentBlock"]
highestBatchNo, err = hermezDb.GetBatchNoByL2Block(uint64(bn.(hexutil.Uint64)))
}

bds := make([]*types.BatchDataSlim, 0, len(batchNumbers))

for _, batchNumber := range batchNumbers {
Expand All @@ -244,15 +269,6 @@ func (api *ZkEvmAPIImpl) GetBatchDataByNumbers(ctx context.Context, batchNumbers
Empty: false,
}

highestBlock, err := rawdb.ReadLastBlockSynced(tx)
if err != nil {
return nil, err
}
highestBatchNo, err := hermezDb.GetBatchNoByL2Block(highestBlock.NumberU64())
if err != nil {
return nil, err
}

// return null if we're not at this block height yet
if batchNumber > rpc.BlockNumber(highestBatchNo) {
bd.Empty = true
Expand Down Expand Up @@ -363,16 +379,30 @@ func (api *ZkEvmAPIImpl) GetBatchByNumber(ctx context.Context, batchNumber rpc.B
defer tx.Rollback()
hermezDb := hermez_db.NewHermezDbReader(tx)

// use inbuilt rpc.BlockNumber type to implement the 'latest' behaviour
// highest block/batch tied to last block synced
// unless the node is still syncing - in which case 'current block' is used
// this is the batch number of stage progress of the Finish stage

highestBlock, err := rawdb.ReadLastBlockSynced(tx)
if err != nil {
return nil, err
}

highestBatchNo, err := hermezDb.GetBatchNoByL2Block(highestBlock.NumberU64())
if err != nil {
return nil, err
}

// return null if we're not at this block height yet
// check sync status of node
syncing, err := api.ethApi.Syncing(ctx)
if err != nil {
return nil, err
}
if syncing != nil && syncing != false {
bn := syncing.(map[string]interface{})["currentBlock"]
highestBatchNo, err = hermezDb.GetBatchNoByL2Block(uint64(bn.(hexutil.Uint64)))
}
if batchNumber > rpc.BlockNumber(highestBatchNo) {
return nil, nil
}
Expand Down Expand Up @@ -411,6 +441,8 @@ func (api *ZkEvmAPIImpl) GetBatchByNumber(ctx context.Context, batchNumber rpc.B
// last block in batch data
batch.Coinbase = block.Coinbase()
batch.StateRoot = block.Root()

// TODO: this logic is wrong it is the L1 verification timestamp we need
batch.Timestamp = types.ArgUint64(block.Time())

// block numbers in batch
Expand Down Expand Up @@ -516,40 +548,12 @@ func (api *ZkEvmAPIImpl) GetBatchByNumber(ctx context.Context, batchNumber rpc.B
}

// global exit root of batch
batchGer, foundBatchGerNumber, err := hermezDb.GetLastBatchGlobalExitRoot(batchNo)
if err != nil {
return nil, err
}

// get last block in batch
lastBlockInbatch, err := hermezDb.GetHighestBlockInBatch(batchNo)
if err != nil {
return nil, err
}

// get latest found ger by block
latestBlockHer, blockNum, err := hermezDb.GetLastBlockGlobalExitRoot(lastBlockInbatch)
if err != nil {
return nil, err
}

//get latest block ger batch number
latestBlockGerBatchNumber, err := hermezDb.GetBatchNoByL2Block(blockNum)
batchGer, _, err := hermezDb.GetLastBlockGlobalExitRoot(blockNo)
if err != nil {
return nil, err
}

var ger *common.Hash
if batchGer != nil {
ger = &batchGer.GlobalExitRoot
}
if foundBatchGerNumber < latestBlockGerBatchNumber {
ger = &latestBlockHer
}

if ger != nil {
batch.GlobalExitRoot = *ger
}
batch.GlobalExitRoot = batchGer

// sequence
seq, err := hermezDb.GetSequenceByBatchNo(batchNo)
Expand All @@ -576,7 +580,7 @@ func (api *ZkEvmAPIImpl) GetBatchByNumber(ctx context.Context, batchNumber rpc.B
}

// exit roots (MainnetExitRoot, RollupExitRoot)
infoTreeUpdate, err := hermezDb.GetL1InfoTreeUpdateByGer(batch.GlobalExitRoot)
infoTreeUpdate, err := hermezDb.GetL1InfoTreeUpdateByGer(batchGer)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -644,12 +648,16 @@ func (api *ZkEvmAPIImpl) GetBatchByNumber(ctx context.Context, batchNumber rpc.B
if forkId < 12 {
// get the previous batches exit roots
prevBatchNo := batchNo - 1
prevBatchGer, _, err := hermezDb.GetLastBatchGlobalExitRoot(prevBatchNo)
prevBatchHighestBlock, err := hermezDb.GetHighestBlockInBatch(prevBatchNo)
if err != nil {
return nil, err
}
prevBatchGer, _, err := hermezDb.GetLastBlockGlobalExitRoot(prevBatchHighestBlock)
if err != nil {
return nil, err
}

itu, err := hermezDb.GetL1InfoTreeUpdateByGer(prevBatchGer.GlobalExitRoot)
itu, err := hermezDb.GetL1InfoTreeUpdateByGer(prevBatchGer)
if err != nil {
return nil, err
}
Expand Down
181 changes: 181 additions & 0 deletions zk/debug_tools/rpc-batch-compare/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
package main

import (
"bytes"
"encoding/json"
"flag"
"fmt"
"log"
"math/big"
"net/http"
"os"

"github.com/google/go-cmp/cmp"
"io"
)

func getBatchNumber(url string) (*big.Int, error) {
requestBody, _ := json.Marshal(map[string]interface{}{
"jsonrpc": "2.0",
"method": "zkevm_batchNumber",
"params": []interface{}{},
"id": 1,
})

resp, err := http.Post(url, "application/json", bytes.NewBuffer(requestBody))
if err != nil {
return nil, err
}
defer resp.Body.Close()

body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("failed to read response body: %v", err)
}

var result map[string]interface{}
if err := json.Unmarshal(body, &result); err != nil {
return nil, fmt.Errorf("failed to unmarshal response: %v", err)
}

if errorField, ok := result["error"]; ok {
return nil, fmt.Errorf("node error: %v", errorField)
}

batchNumberHex, ok := result["result"].(string)
if !ok {
return nil, fmt.Errorf("invalid response format")
}

batchNumber := new(big.Int)
if _, ok := batchNumber.SetString(batchNumberHex[2:], 16); !ok {
return nil, fmt.Errorf("failed to convert batch number to big.Int")
}
return batchNumber, nil
}

func getBatchByNumber(url string, number *big.Int) (map[string]interface{}, error) {
requestBody, _ := json.Marshal(map[string]interface{}{
"jsonrpc": "2.0",
"method": "zkevm_getBatchByNumber",
"params": []interface{}{number.String(), true},
"id": 1,
})

resp, err := http.Post(url, "application/json", bytes.NewBuffer(requestBody))
if err != nil {
return nil, err
}
defer resp.Body.Close()

body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("failed to read response body: %v", err)
}

var result map[string]interface{}
if err := json.Unmarshal(body, &result); err != nil {
return nil, fmt.Errorf("failed to unmarshal response: %v", err)
}

if errorField, ok := result["error"]; ok {
return nil, fmt.Errorf("node error: %v", errorField)
}

batchData, ok := result["result"].(map[string]interface{})
if !ok || batchData == nil {
return nil, fmt.Errorf("batch not found")
}

return batchData, nil
}

func compareBatches(erigonURL, legacyURL string, batchNumber *big.Int) (string, error) {
batch1, err := getBatchByNumber(erigonURL, batchNumber)
if err != nil {
return "", fmt.Errorf("Error getting batch %d from Erigon node: %v", batchNumber, err)
}

batch2, err := getBatchByNumber(legacyURL, batchNumber)
if err != nil {
return "", fmt.Errorf("Error getting batch %d from Legacy node: %v", batchNumber, err)
}

// ignore list
il := []string{
"timestamp",
"verifyBatchTxHash",
"sendSequencesTxHash",
"accInputHash",
"globalExitRoot",
"mainnetExitRoot",
"rollupExitRoot",
}
for _, i := range il {
delete(batch1, i)
delete(batch2, i)
}

if !cmp.Equal(batch1, batch2) {
return fmt.Sprintf("Mismatch at batch %d:\nErigon vs Legacy:\n%s",
batchNumber, cmp.Diff(batch1, batch2)), nil
}
return "", nil
}

func main() {
erigonURL := flag.String("erigon", "http://localhost:8545", "RPC URL of the Erigon node")
legacyURL := flag.String("legacy", "http://localhost:8546", "RPC URL of the Legacy node")
skip := flag.Int("skip", 1, "Number of batches to skip between each check")
numBatches := flag.Int("batches", 1000, "Number of batches to check")
startOffset := flag.Int("offset", 0, "Offset from highest getBatchNumber")
overrideStartAt := flag.Int("override", 0, "Override start batch number")
flag.Parse()

erigonLatestBatch, err := getBatchNumber(*erigonURL)
if err != nil {
log.Fatalf("Failed to get latest batch number from Erigon node: %v", err)
}
log.Println("Erigon latest batch number: ", erigonLatestBatch)

legacyLatestBatch, err := getBatchNumber(*legacyURL)
if err != nil {
log.Fatalf("Failed to get latest batch number from Legacy node: %v", err)
}
log.Println("Legacy latest batch number: ", legacyLatestBatch)

startBatch := legacyLatestBatch
if erigonLatestBatch.Cmp(startBatch) < 0 {
startBatch = erigonLatestBatch
}

// offset start batch
startBatch = new(big.Int).Sub(startBatch, big.NewInt(int64(*startOffset)))

if *overrideStartAt != 0 {
startBatch = big.NewInt(int64(*overrideStartAt))
log.Println("Overriding start batch to", startBatch)
}

log.Printf("Checking %d batches\n", *numBatches)
log.Printf("Starting from batch %d\n", startBatch)
log.Printf("Skipping %d batches\n", *skip)

for i := 0; i < *numBatches; i++ {
log.Println("Checking batch", i+1, "of", *numBatches)
batchNumber := new(big.Int).Sub(startBatch, big.NewInt(int64(i**skip)))
diff, err := compareBatches(*erigonURL, *legacyURL, batchNumber)
if err != nil {
log.Println(err)
os.Exit(1)
}
if diff != "" {
log.Println(diff)
os.Exit(1)
}
log.Println("Batch", batchNumber, "matches")
}

log.Println("No differences found")
os.Exit(0)
}
3 changes: 3 additions & 0 deletions zk/hermez_db/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -748,6 +748,7 @@ func (db *HermezDb) WriteBatchGlobalExitRoot(batchNumber uint64, ger dstypes.Ger
return db.tx.Put(GLOBAL_EXIT_ROOTS_BATCHES, Uint64ToBytes(batchNumber), ger.EncodeToBytes())
}

// deprecated: post etrog this will not work
func (db *HermezDbReader) GetBatchGlobalExitRoots(fromBatchNum, toBatchNum uint64) (*[]dstypes.GerUpdate, error) {
c, err := db.tx.Cursor(GLOBAL_EXIT_ROOTS_BATCHES)
if err != nil {
Expand Down Expand Up @@ -775,6 +776,7 @@ func (db *HermezDbReader) GetBatchGlobalExitRoots(fromBatchNum, toBatchNum uint6
return &gers, err
}

// GetLastBatchGlobalExitRoot deprecated: post etrog this will not work
func (db *HermezDbReader) GetLastBatchGlobalExitRoot(batchNum uint64) (*dstypes.GerUpdate, uint64, error) {
c, err := db.tx.Cursor(GLOBAL_EXIT_ROOTS_BATCHES)
if err != nil {
Expand Down Expand Up @@ -820,6 +822,7 @@ func (db *HermezDbReader) GetBatchGlobalExitRootsProto(fromBatchNum, toBatchNum
return gersProto, nil
}

// GetBatchGlobalExitRoot deprecated: post etrog this will not work
func (db *HermezDbReader) GetBatchGlobalExitRoot(batchNum uint64) (*dstypes.GerUpdate, error) {
gerUpdateBytes, err := db.tx.GetOne(GLOBAL_EXIT_ROOTS_BATCHES, Uint64ToBytes(batchNum))
if err != nil {
Expand Down
3 changes: 2 additions & 1 deletion zk/stages/stage_batches.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ const (
preForkId7BlockGasLimit = 30_000_000
forkId7BlockGasLimit = 18446744073709551615 // 0xffffffffffffffff
forkId8BlockGasLimit = 1125899906842624 // 0x4000000000000
HIGHEST_KNOWN_FORK = 9
HIGHEST_KNOWN_FORK = 11
STAGE_PROGRESS_SAVE = 3000000
)

type ErigonDb interface {
Expand Down
Loading

0 comments on commit 82b45fd

Please sign in to comment.