package main import ( "context" "flag" "git.gammaspectra.live/P2Pool/p2pool-observer/monero/client" "git.gammaspectra.live/P2Pool/p2pool-observer/p2pool/cache/archive" "git.gammaspectra.live/P2Pool/p2pool-observer/p2pool/cache/legacy" "git.gammaspectra.live/P2Pool/p2pool-observer/p2pool/sidechain" "git.gammaspectra.live/P2Pool/p2pool-observer/types" "github.com/floatdrop/lru" "log" "math" "os" ) type loadee struct { c *sidechain.Consensus cb func(block *sidechain.PoolBlock) } func (l *loadee) Consensus() *sidechain.Consensus { return l.c } func (l *loadee) AddCachedBlock(block *sidechain.PoolBlock) { l.cb(block) } func main() { inputConsensus := flag.String("consensus", "config.json", "Input config.json consensus file") inputFile := flag.String("input", "p2pool.cache", "Input p2pool.cache path") outputArchive := flag.String("output", "", "Output path for archive database") flag.Parse() cf, err := os.ReadFile(*inputConsensus) consensus, err := sidechain.NewConsensusFromJSON(cf) if err != nil { log.Panic(err) } cache, err := legacy.NewCache(*inputFile) if err != nil { log.Panic(err) } defer cache.Close() difficultyCache := lru.New[uint64, types.Difficulty](1024) getDifficultyByHeight := func(height uint64) types.Difficulty { if v := difficultyCache.Get(height); v == nil { if r, err := client.GetDefaultClient().GetBlockHeaderByHeight(height, context.Background()); err == nil { d := types.DifficultyFrom64(r.BlockHeader.Difficulty) difficultyCache.Set(height, d) return d } return types.ZeroDifficulty } else { return *v } } archiveCache, err := archive.NewCache(*outputArchive, consensus, getDifficultyByHeight) if err != nil { log.Panic(err) } defer archiveCache.Close() cachedBlocks := make(map[types.Hash]*sidechain.PoolBlock) l := &loadee{ c: consensus, cb: func(block *sidechain.PoolBlock) { expectedBlockId := types.HashFromBytes(block.CoinbaseExtra(sidechain.SideTemplateId)) calculatedBlockId := block.SideTemplateId(consensus) if expectedBlockId != calculatedBlockId { log.Printf("ERROR: block height %d, template id %s, expected %s", block.Side.Height, calculatedBlockId, expectedBlockId) } else { cachedBlocks[expectedBlockId] = block } }, } cache.LoadAll(l) var storeBlock func(b *sidechain.PoolBlock) storeBlock = func(b *sidechain.PoolBlock) { if parent := cachedBlocks[b.Side.Parent]; parent != nil { b.FillTransactionParentIndices(parent) storeBlock(parent) } b.Depth.Store(math.MaxUint64) archiveCache.Store(b) } for _, b := range cachedBlocks { if b.Depth.Load() == math.MaxUint64 { continue } storeBlock(b) } }