mirror of
https://github.com/luxfi/migrate.git
synced 2026-10-30 15:25:11 +00:00
The Exporter/Importer interfaces declared methods the concrete VM types did not all implement, breaking `go build ./...`. Remove-vs-implement decision (driven by real call sites): - ExportStateTrie / ImportStateTrie: REMOVED from the Exporter/Importer interfaces. These were aspirational — no code anywhere invokes them on an interface value (the only references were the interface decls plus RPCImporter.ImportStateTrie, which just returns ErrStateImportNotSupported). Removing them unblocks the build without inventing per-chain state-trie migration logic. RPCImporter.ImportStateTrie is kept as a harmless extra method; the TrieNode/TrieImportResult types remain (still referenced). - ExportBlocksWithState: KEPT in the Exporter interface — it has a real caller (cmd/export/main.go). Implemented on the four chains that lacked it (xchain, pchain, qchain, zool2) by delegating to ExportBlocks, mirroring the existing cchain.ExportBlocksWithState (these chains carry state in blocks / rebuild via replay, so the two are equivalent — same pattern cchain already documents). Also repaired the pre-existing (independent) build breakage in cmd/export-genesis (luxfi/geth v1.16.39 API drift): pebbleDB now implements ethdb.KeyValueStore (Stat()/SyncKeyValue/DeleteRange; dropped removed NewSnapshot) and is wrapped with rawdb.NewDatabase for the ancient-aware readers; trie.NewDatabase -> triedb.NewDatabase; StateAccount.CodeHash ([]byte) handled via common.BytesToHash; pebble NewIter's (iter, error) return handled. Fixed a go vet finding in cmd/key-sniff (redundant Println newline). go build ./... + go vet ./... + go test ./... all pass. Co-authored-by: Hanzo Dev <[email protected]>
170 lines
4.0 KiB
Go
170 lines
4.0 KiB
Go
// key-sniff analyzes key structure to find the real prefix byte offset
|
|
// Creates histograms for bytes at multiple offsets to identify where A/O/c/L prefixes live
|
|
package main
|
|
|
|
import (
|
|
"encoding/hex"
|
|
"flag"
|
|
"fmt"
|
|
"log"
|
|
"sort"
|
|
|
|
"github.com/cockroachdb/pebble"
|
|
)
|
|
|
|
func main() {
|
|
dbPath := flag.String("db", "", "PebbleDB path")
|
|
namespace := flag.String("namespace", "", "32-byte hex namespace")
|
|
maxKeys := flag.Int("max", 1000000, "Max keys to scan")
|
|
flag.Parse()
|
|
|
|
if *dbPath == "" {
|
|
log.Fatal("Usage: -db <path> [-namespace <hex>]")
|
|
}
|
|
|
|
db, err := pebble.Open(*dbPath, &pebble.Options{ReadOnly: true})
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
defer db.Close()
|
|
|
|
var iterOpts *pebble.IterOptions
|
|
if *namespace != "" {
|
|
ns, err := hex.DecodeString(*namespace)
|
|
if err != nil {
|
|
log.Fatalf("Invalid namespace: %v", err)
|
|
}
|
|
// Iterate only keys starting with namespace
|
|
upper := make([]byte, len(ns))
|
|
copy(upper, ns)
|
|
upper[len(upper)-1]++
|
|
iterOpts = &pebble.IterOptions{
|
|
LowerBound: ns,
|
|
UpperBound: upper,
|
|
}
|
|
}
|
|
|
|
iter, err := db.NewIter(iterOpts)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
defer iter.Close()
|
|
|
|
// Create histograms for bytes at offsets 32-50
|
|
// (after the 32-byte namespace)
|
|
const minOffset = 32
|
|
const maxOffset = 50
|
|
histograms := make([]map[byte]int64, maxOffset+1)
|
|
for i := range histograms {
|
|
histograms[i] = make(map[byte]int64)
|
|
}
|
|
|
|
// Also collect sample keys
|
|
sampleKeys := make([][]byte, 0, 10)
|
|
|
|
count := 0
|
|
for iter.First(); iter.Valid() && count < *maxKeys; iter.Next() {
|
|
key := iter.Key()
|
|
|
|
// Count byte values at each offset
|
|
for offset := minOffset; offset <= maxOffset && offset < len(key); offset++ {
|
|
histograms[offset][key[offset]]++
|
|
}
|
|
|
|
// Collect samples
|
|
if count < 10 {
|
|
keyCopy := make([]byte, len(key))
|
|
copy(keyCopy, key)
|
|
sampleKeys = append(sampleKeys, keyCopy)
|
|
}
|
|
|
|
count++
|
|
}
|
|
|
|
fmt.Printf("Scanned %d keys\n\n", count)
|
|
|
|
// Print sample keys
|
|
fmt.Println("=== Sample Keys ===")
|
|
for i, key := range sampleKeys {
|
|
fmt.Printf("[%d] len=%d\n", i, len(key))
|
|
fmt.Printf(" full: 0x%s\n", hex.EncodeToString(key))
|
|
if len(key) > 32 {
|
|
fmt.Printf(" after_ns: 0x%s\n", hex.EncodeToString(key[32:]))
|
|
}
|
|
}
|
|
|
|
// Find offsets where A/O/c/L show spikes (not uniform)
|
|
fmt.Println("\n=== Finding prefix byte offset ===")
|
|
fmt.Print("Looking for offsets where 0x41('A'), 0x4f('O'), 0x63('c'), 0x4c('L') show spikes\n\n")
|
|
|
|
targetBytes := []byte{'A', 'O', 'c', 'L', 'h', 'b', 'r', 'H', 'l', 'B'}
|
|
|
|
for offset := minOffset; offset <= maxOffset; offset++ {
|
|
hist := histograms[offset]
|
|
if len(hist) == 0 {
|
|
continue
|
|
}
|
|
|
|
// Calculate total and average
|
|
var total int64
|
|
for _, c := range hist {
|
|
total += c
|
|
}
|
|
avg := float64(total) / float64(len(hist))
|
|
|
|
// Check if target bytes show significant spikes (>3x average)
|
|
fmt.Printf("Offset %d: ", offset)
|
|
|
|
spikes := []string{}
|
|
for _, b := range targetBytes {
|
|
c := hist[b]
|
|
ratio := float64(c) / avg
|
|
if c > 0 && ratio > 2.0 {
|
|
spikes = append(spikes, fmt.Sprintf("'%c'=%.1fx", b, ratio))
|
|
}
|
|
}
|
|
|
|
if len(spikes) > 0 {
|
|
fmt.Printf("SPIKES: %v\n", spikes)
|
|
} else {
|
|
// Show top 5 bytes at this offset
|
|
type byteCount struct {
|
|
b byte
|
|
c int64
|
|
}
|
|
var counts []byteCount
|
|
for b, c := range hist {
|
|
counts = append(counts, byteCount{b, c})
|
|
}
|
|
sort.Slice(counts, func(i, j int) bool {
|
|
return counts[i].c > counts[j].c
|
|
})
|
|
|
|
fmt.Printf("uniform (top 5: ")
|
|
for i := 0; i < 5 && i < len(counts); i++ {
|
|
bc := counts[i]
|
|
char := "."
|
|
if bc.b >= 32 && bc.b < 127 {
|
|
char = string(bc.b)
|
|
}
|
|
fmt.Printf("0x%02x('%s')=%d ", bc.b, char, bc.c)
|
|
}
|
|
fmt.Println(")")
|
|
}
|
|
}
|
|
|
|
// Show detailed breakdown at each offset
|
|
fmt.Println("\n=== Detailed counts at each offset ===")
|
|
for offset := minOffset; offset <= 45 && offset <= maxOffset; offset++ {
|
|
hist := histograms[offset]
|
|
fmt.Printf("\nOffset %d:", offset)
|
|
|
|
// Show counts for ASCII printable chars of interest
|
|
for _, b := range []byte{'A', 'O', 'c', 'L', 'h', 'b', 'r', 'H', 'l', 'B'} {
|
|
c := hist[b]
|
|
fmt.Printf(" '%c'=%d", b, c)
|
|
}
|
|
fmt.Println()
|
|
}
|
|
}
|