Files
zeekay 786e0850c9 Add import-rpc tool for C-Chain block import via RPC
- import-rpc: Converts JSONL (base64, PascalCase) to API format (hex, lowercase) and calls migrate_importBlocks RPC
- rpcserver: Development RPC server for testing
- export/import/debug: CLI tools for block export/import operations
- Enhanced subnetevm/exporter.go with legacy header decoding support

Successfully imported 1,074,616 C-Chain blocks via RPC with periodic blockchain reload.
2025-12-11 01:08:18 +00:00

190 lines
4.9 KiB
Go

// Command debug inspects PebbleDB database keys
package main
import (
"encoding/binary"
"encoding/hex"
"flag"
"fmt"
"log"
"os"
"strings"
"github.com/cockroachdb/pebble"
)
var knownPrefixes = map[string]string{
"h": "header",
"H": "headerNumber",
"b": "blockBody",
"r": "receipts",
"c": "code",
"l": "txLookup",
"a": "snapshotAccount",
"o": "snapshotStorage",
"LastBlock": "headBlock",
"LastHeader": "headHeader",
"ethereum-config-": "chainConfig",
"SnapshotRoot": "snapshotRoot",
"SecureTrie": "secureTrie",
"DatabaseVersion": "dbVersion",
"HeadBlockHash": "headBlockHash",
"HeadHeaderHash": "headHeaderHash",
"HeadFastBlockHash": "headFastBlockHash",
}
func main() {
var (
dbPath = flag.String("db", "", "Path to PebbleDB database")
limit = flag.Int("limit", 100, "Maximum number of keys to show")
prefix = flag.String("prefix", "", "Filter by key prefix (hex)")
)
flag.Parse()
if *dbPath == "" {
fmt.Println("Usage: debug -db <path> [-limit N] [-prefix hex]")
os.Exit(1)
}
// Open database read-only
db, err := pebble.Open(*dbPath, &pebble.Options{ReadOnly: true})
if err != nil {
log.Fatalf("Failed to open database: %v", err)
}
defer db.Close()
// Look for specific keys
fmt.Println("=== Looking for known keys ===")
knownKeys := []string{
"LastBlock",
"LastHeader",
"HeadBlockHash",
"HeadHeaderHash",
"HeadFastBlockHash",
"SnapshotRoot",
"DatabaseVersion",
}
for _, key := range knownKeys {
val, closer, err := db.Get([]byte(key))
if err == nil {
defer closer.Close()
fmt.Printf("Found: %s = %s\n", key, hex.EncodeToString(val))
}
}
// Try to find genesis (block 0)
fmt.Println("\n=== Looking for genesis block ===")
// headerPrefix + num (0) + headerHashSuffix
genesisHashKey := []byte("h")
genesisHashKey = append(genesisHashKey, make([]byte, 8)...) // block 0
genesisHashKey = append(genesisHashKey, []byte("n")...)
val, closer, err := db.Get(genesisHashKey)
if err == nil {
defer closer.Close()
fmt.Printf("Genesis hash (h0n): %s\n", hex.EncodeToString(val))
} else {
fmt.Printf("Genesis hash key not found: %v\n", err)
}
// Scan all keys
fmt.Printf("\n=== Scanning keys (limit: %d) ===\n", *limit)
var lower, upper []byte
if *prefix != "" {
lower, _ = hex.DecodeString(*prefix)
upper = append(lower, 0xff)
}
iter, err := db.NewIter(&pebble.IterOptions{
LowerBound: lower,
UpperBound: upper,
})
if err != nil {
log.Fatalf("Failed to create iterator: %v", err)
}
defer iter.Close()
prefixCounts := make(map[string]int)
count := 0
for iter.First(); iter.Valid() && count < *limit; iter.Next() {
key := iter.Key()
keyStr := string(key)
keyHex := hex.EncodeToString(key)
// Identify prefix
prefixName := "unknown"
for p, name := range knownPrefixes {
if strings.HasPrefix(keyStr, p) {
prefixName = name
break
}
}
prefixCounts[prefixName]++
// Print key details
if count < 50 { // Only print first 50
valLen := len(iter.Value())
// Decode special cases
extra := ""
if prefixName == "header" && len(key) == 1+8+1 {
// h + number + n = canonical hash lookup
num := binary.BigEndian.Uint64(key[1:9])
extra = fmt.Sprintf(" (block %d hash key)", num)
} else if prefixName == "header" && len(key) == 1+8+32 {
// h + number + hash = header
num := binary.BigEndian.Uint64(key[1:9])
extra = fmt.Sprintf(" (block %d header)", num)
} else if prefixName == "blockBody" && len(key) == 1+8+32 {
num := binary.BigEndian.Uint64(key[1:9])
extra = fmt.Sprintf(" (block %d body)", num)
}
fmt.Printf("%s: %s (len=%d, val_len=%d)%s\n", prefixName, keyHex, len(key), valLen, extra)
}
count++
}
fmt.Printf("\n=== Key Prefix Counts (first %d keys) ===\n", *limit)
for name, cnt := range prefixCounts {
fmt.Printf(" %s: %d\n", name, cnt)
}
// Try to find the highest block by iterating headers
fmt.Println("\n=== Finding block range ===")
headerIter, err := db.NewIter(&pebble.IterOptions{
LowerBound: []byte("h"),
UpperBound: []byte("i"),
})
if err != nil {
log.Fatalf("Failed to create header iterator: %v", err)
}
defer headerIter.Close()
var minBlock, maxBlock uint64 = ^uint64(0), 0
headerCount := 0
for headerIter.First(); headerIter.Valid(); headerIter.Next() {
key := headerIter.Key()
// Looking for h + 8 bytes + "n" pattern (canonical hash keys)
if len(key) == 10 && key[9] == 'n' {
num := binary.BigEndian.Uint64(key[1:9])
if num < minBlock {
minBlock = num
}
if num > maxBlock {
maxBlock = num
}
headerCount++
}
}
if headerCount > 0 {
fmt.Printf("Found %d canonical header entries\n", headerCount)
fmt.Printf("Block range: %d to %d\n", minBlock, maxBlock)
} else {
fmt.Println("No canonical header entries found")
}
}