Added archive, and utilities to export cache/legacy to archive
This commit is contained in:
parent
8ee16e6d53
commit
4550fdffd0
86
cmd/cachetoarchive/cachetoarchive.go
Normal file
86
cmd/cachetoarchive/cachetoarchive.go
Normal file
|
@ -0,0 +1,86 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"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"
|
||||
"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()
|
||||
|
||||
archiveCache, err := archive.NewCache(*outputArchive, consensus)
|
||||
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)
|
||||
}
|
||||
}
|
117
cmd/legacytoarchive/legacytoarchive.go
Normal file
117
cmd/legacytoarchive/legacytoarchive.go
Normal file
|
@ -0,0 +1,117 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"flag"
|
||||
"git.gammaspectra.live/P2Pool/p2pool-observer/p2pool/cache/archive"
|
||||
"git.gammaspectra.live/P2Pool/p2pool-observer/p2pool/sidechain"
|
||||
"git.gammaspectra.live/P2Pool/p2pool-observer/types"
|
||||
"log"
|
||||
"math"
|
||||
"os"
|
||||
"path"
|
||||
)
|
||||
|
||||
func main() {
|
||||
inputConsensus := flag.String("consensus", "config.json", "Input config.json consensus file")
|
||||
inputFolder := flag.String("input", "", "Input legacy api folder with raw / failed blocks")
|
||||
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)
|
||||
}
|
||||
|
||||
archiveCache, err := archive.NewCache(*outputArchive, consensus)
|
||||
if err != nil {
|
||||
log.Panic(err)
|
||||
}
|
||||
defer archiveCache.Close()
|
||||
|
||||
processed := make(map[types.Hash]bool)
|
||||
|
||||
totalStored := 0
|
||||
|
||||
loadBlock := func(id types.Hash) *sidechain.PoolBlock {
|
||||
n := id.String()
|
||||
fPath := path.Join(*inputFolder, "blocks", n[:1], n)
|
||||
if buf, err := os.ReadFile(fPath); err != nil {
|
||||
return nil
|
||||
} else {
|
||||
if hexBuf, err := hex.DecodeString(string(buf)); err != nil {
|
||||
log.Panic(err)
|
||||
} else {
|
||||
if block, err := sidechain.NewShareFromExportedBytes(hexBuf, consensus.NetworkType); err != nil {
|
||||
log.Panic(err)
|
||||
} else {
|
||||
return block
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var storeBlock func(k types.Hash, b *sidechain.PoolBlock)
|
||||
storeBlock = func(k types.Hash, b *sidechain.PoolBlock) {
|
||||
if b == nil || processed[k] {
|
||||
return
|
||||
}
|
||||
if parent := loadBlock(b.Side.Parent); parent != nil {
|
||||
b.FillTransactionParentIndices(parent)
|
||||
storeBlock(b.Side.Parent, parent)
|
||||
}
|
||||
b.Depth.Store(math.MaxUint64)
|
||||
archiveCache.Store(b)
|
||||
totalStored++
|
||||
processed[k] = true
|
||||
}
|
||||
|
||||
for i := 0; i <= 0xf; i++ {
|
||||
n := hex.EncodeToString([]byte{byte(i)})
|
||||
dPath := path.Join(*inputFolder, "blocks", n[1:])
|
||||
if dir, err := os.ReadDir(dPath); err != nil {
|
||||
log.Panic(err)
|
||||
} else {
|
||||
for _, e := range dir {
|
||||
h, _ := hex.DecodeString(e.Name())
|
||||
id := types.HashFromBytes(h)
|
||||
|
||||
storeBlock(id, loadBlock(id))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for i := 0; i <= 0xf; i++ {
|
||||
n := hex.EncodeToString([]byte{byte(i)})
|
||||
dPath := path.Join(*inputFolder, "failed_blocks", n[1:])
|
||||
if dir, err := os.ReadDir(dPath); err != nil {
|
||||
log.Panic(err)
|
||||
} else {
|
||||
for _, e := range dir {
|
||||
fPath := path.Join(dPath, e.Name())
|
||||
log.Printf("Processing %s", fPath)
|
||||
if buf, err := os.ReadFile(path.Join(dPath, e.Name())); err != nil {
|
||||
log.Panic(err)
|
||||
} else {
|
||||
if hexBuf, err := hex.DecodeString(string(buf)); err != nil {
|
||||
log.Panic(err)
|
||||
} else {
|
||||
if block, err := sidechain.NewShareFromExportedBytes(hexBuf, consensus.NetworkType); err != nil {
|
||||
log.Panic(err)
|
||||
} else {
|
||||
block.Depth.Store(math.MaxUint64)
|
||||
archiveCache.Store(block)
|
||||
totalStored++
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log.Printf("total stored %d", totalStored)
|
||||
}
|
|
@ -27,6 +27,7 @@ func main() {
|
|||
moneroRpcPort := flag.Uint("rpc-port", 18081, "monerod RPC API port number")
|
||||
moneroZmqPort := flag.Uint("zmq-port", 18083, "monerod ZMQ pub port number")
|
||||
p2pListen := flag.String("p2p", fmt.Sprintf("0.0.0.0:%d", currentConsensus.DefaultPort()), "IP:port for p2p server to listen on.")
|
||||
createArchive := flag.String("archive", "", "If specified, create an archive store of sidechain blocks.")
|
||||
addPeers := flag.String("addpeers", "", "Comma-separated list of IP:port of other p2pool nodes to connect to")
|
||||
peerList := flag.String("peer-list", "p2pool_peers.txt", "Either a path or an URL to obtain peer lists from. If it is a path, new peers will be saved to this path")
|
||||
consensusConfigFile := flag.String("config", "", "Name of the p2pool config file")
|
||||
|
@ -87,6 +88,10 @@ func main() {
|
|||
settings["cache"] = "p2pool.cache"
|
||||
}
|
||||
|
||||
if *createArchive != "" {
|
||||
settings["archive"] = *createArchive
|
||||
}
|
||||
|
||||
if p2pool, err := p2pool2.NewP2Pool(currentConsensus, settings); err != nil {
|
||||
log.Fatalf("Could not start p2pool: %s", err)
|
||||
} else {
|
||||
|
|
|
@ -50,7 +50,7 @@ func main() {
|
|||
calculatedBlockId := block.SideTemplateId(consensus)
|
||||
|
||||
if expectedBlockId != calculatedBlockId {
|
||||
log.Printf("ERROR: block height %d ,template id %s, expected %s", block.Side.Height, calculatedBlockId, expectedBlockId)
|
||||
log.Printf("ERROR: block height %d, template id %s, expected %s", block.Side.Height, calculatedBlockId, expectedBlockId)
|
||||
} else {
|
||||
blob, err := block.MarshalBinary()
|
||||
if err != nil {
|
||||
|
|
5
go.mod
5
go.mod
|
@ -10,14 +10,15 @@ require (
|
|||
git.gammaspectra.live/P2Pool/randomx-go-bindings v0.0.0-20221027134633-11f5607e6752
|
||||
github.com/ake-persson/mapslice-json v0.0.0-20210720081907-22c8edf57807
|
||||
github.com/floatdrop/lru v1.3.0
|
||||
github.com/go-faster/xor v0.3.0
|
||||
github.com/go-faster/xor v1.0.0
|
||||
github.com/go-zeromq/zmq4 v0.15.0
|
||||
github.com/gorilla/mux v1.8.0
|
||||
github.com/holiman/uint256 v1.2.1
|
||||
github.com/jxskiss/base62 v1.1.0
|
||||
github.com/lib/pq v1.10.7
|
||||
github.com/stretchr/testify v1.7.0
|
||||
github.com/stretchr/testify v1.8.1
|
||||
github.com/tyler-sommer/stick v1.0.4
|
||||
go.etcd.io/bbolt v1.3.7
|
||||
golang.org/x/crypto v0.7.0
|
||||
golang.org/x/exp v0.0.0-20230310171629-522b1b587ee0
|
||||
golang.org/x/net v0.8.0
|
||||
|
|
14
go.sum
14
go.sum
|
@ -19,8 +19,8 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
|
|||
github.com/floatdrop/lru v1.3.0 h1:83abtaKjXcWrPmtzTAk2Ggq8DUKqI29YzrTrB8+vu0c=
|
||||
github.com/floatdrop/lru v1.3.0/go.mod h1:83zlXKA06Bm32JImNINCiTr0ldadvdAjUe5jSwIaw0s=
|
||||
github.com/fzipp/gocyclo v0.3.1/go.mod h1:DJHO6AUmbdqj2ET4Z9iArSuwWgYDRryYt2wASxc7x3E=
|
||||
github.com/go-faster/xor v0.3.0 h1:tc0bdVe31Wj999e5rEj7K3DhHyQNp2VydYyLFj3YSN8=
|
||||
github.com/go-faster/xor v0.3.0/go.mod h1:x5CaDY9UKErKzqfRfFZdfu+OSTfoZny3w5Ak7UxcipQ=
|
||||
github.com/go-faster/xor v1.0.0 h1:2o8vTOgErSGHP3/7XwA5ib1FTtUsNtwCoLLBjl31X38=
|
||||
github.com/go-faster/xor v1.0.0/go.mod h1:x5CaDY9UKErKzqfRfFZdfu+OSTfoZny3w5Ak7UxcipQ=
|
||||
github.com/go-zeromq/goczmq/v4 v4.2.2 h1:HAJN+i+3NW55ijMJJhk7oWxHKXgAuSBkoFfvr8bYj4U=
|
||||
github.com/go-zeromq/goczmq/v4 v4.2.2/go.mod h1:Sm/lxrfxP/Oxqs0tnHD6WAhwkWrx+S+1MRrKzcxoaYE=
|
||||
github.com/go-zeromq/zmq4 v0.15.0 h1:SLqukpmLTx0JsLaOaCCjwy5eBdfJ+ouJX/677HoFbJM=
|
||||
|
@ -44,13 +44,19 @@ github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9Nz
|
|||
github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=
|
||||
github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/tyler-sommer/stick v1.0.4 h1:kuHyr9FFBBPA5dWqHWNFiCdHBqj8Mr/xuCxx7uAbzIk=
|
||||
github.com/tyler-sommer/stick v1.0.4/go.mod h1:rjBy3zi6GwoxExa6OSRPPPaLqUEKNsBxTeWckhIX1us=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ=
|
||||
go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
|
|
207
p2pool/cache/archive/archive.go
vendored
Normal file
207
p2pool/cache/archive/archive.go
vendored
Normal file
|
@ -0,0 +1,207 @@
|
|||
package archive
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"git.gammaspectra.live/P2Pool/p2pool-observer/p2pool/sidechain"
|
||||
"git.gammaspectra.live/P2Pool/p2pool-observer/types"
|
||||
bolt "go.etcd.io/bbolt"
|
||||
"golang.org/x/exp/slices"
|
||||
"log"
|
||||
"math"
|
||||
"time"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// EpochSize Maximum amount of blocks without a full one
|
||||
const EpochSize = 256
|
||||
|
||||
type Cache struct {
|
||||
db *bolt.DB
|
||||
consensus *sidechain.Consensus
|
||||
}
|
||||
|
||||
var blocksByMainId = []byte("blocksByMainId")
|
||||
var refByTemplateId = []byte("refByTemplateId")
|
||||
var refBySideHeight = []byte("refBySideHeight")
|
||||
var refByMainHeight = []byte("refByMainHeight")
|
||||
|
||||
func NewCache(path string, consensus *sidechain.Consensus) (*Cache, error) {
|
||||
if db, err := bolt.Open(path, 0666, &bolt.Options{Timeout: time.Second * 5}); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
if err = db.Update(func(tx *bolt.Tx) error {
|
||||
if _, err := tx.CreateBucketIfNotExists(blocksByMainId); err != nil {
|
||||
return err
|
||||
} else if _, err := tx.CreateBucketIfNotExists(refByTemplateId); err != nil {
|
||||
return err
|
||||
} else if _, err := tx.CreateBucketIfNotExists(refBySideHeight); err != nil {
|
||||
return err
|
||||
} else if _, err := tx.CreateBucketIfNotExists(refByMainHeight); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Cache{
|
||||
db: db,
|
||||
consensus: consensus,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
type multiRecord []types.Hash
|
||||
|
||||
func multiRecordFromBytes(b []byte) multiRecord {
|
||||
if len(b) == 0 || (len(b)%types.HashSize) != 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
return slices.Clone(unsafe.Slice((*types.Hash)(unsafe.Pointer(&b[0])), len(b)/types.HashSize))
|
||||
}
|
||||
|
||||
func (r multiRecord) Contains(hash types.Hash) bool {
|
||||
return slices.Contains(r, hash)
|
||||
}
|
||||
|
||||
func (r multiRecord) Bytes() []byte {
|
||||
if len(r) == 0 {
|
||||
return nil
|
||||
}
|
||||
return slices.Clone(unsafe.Slice((*byte)(unsafe.Pointer(&r[0])), len(r)*types.HashSize))
|
||||
}
|
||||
|
||||
func (c *Cache) Store(block *sidechain.PoolBlock) {
|
||||
sideId := block.SideTemplateId(c.consensus)
|
||||
mainId := block.MainId()
|
||||
var sideHeight, mainHeight [8]byte
|
||||
binary.LittleEndian.PutUint64(sideHeight[:], block.Side.Height)
|
||||
binary.LittleEndian.PutUint64(mainHeight[:], block.Main.Coinbase.GenHeight)
|
||||
|
||||
if c.existsByMainId(mainId) {
|
||||
return
|
||||
}
|
||||
|
||||
var storePruned, storeCompact bool
|
||||
|
||||
fullBlockTemplateHeight := block.Side.Height - (block.Side.Height % EpochSize)
|
||||
|
||||
// store full blocks on epoch
|
||||
if block.Side.Height != fullBlockTemplateHeight {
|
||||
if len(block.Main.Transactions) == len(block.Main.TransactionParentIndices) && c.existsByTemplateId(block.Side.Parent) {
|
||||
storeCompact = true
|
||||
}
|
||||
|
||||
if block.Depth.Load() == math.MaxUint64 {
|
||||
//fallback
|
||||
if c.existsBySideChainHeightRange(block.Side.Height-c.consensus.ChainWindowSize-1, block.Side.Height-1) {
|
||||
storePruned = true
|
||||
}
|
||||
} else if block.Depth.Load() < c.consensus.ChainWindowSize {
|
||||
storePruned = true
|
||||
}
|
||||
}
|
||||
|
||||
if blob, err := block.MarshalBinaryFlags(storePruned, storeCompact); err == nil {
|
||||
log.Printf("[Archive Cache] Store block id = %s, template id = %s, height = %d, sidechain height %d, pruned = %t, compact = %t, blob size = %d bytes", mainId.String(), sideId.String(), block.Main.Coinbase.GenHeight, block.Side.Height, storePruned, storeCompact, len(blob))
|
||||
|
||||
if err = c.db.Update(func(tx *bolt.Tx) error {
|
||||
b1 := tx.Bucket(blocksByMainId)
|
||||
if err = b1.Put(mainId[:], blob); err != nil {
|
||||
return err
|
||||
}
|
||||
b2 := tx.Bucket(refByTemplateId)
|
||||
if records := multiRecordFromBytes(b2.Get(sideId[:])); !records.Contains(mainId) {
|
||||
records = append(records, mainId)
|
||||
if err = b2.Put(sideId[:], records.Bytes()); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
b3 := tx.Bucket(refBySideHeight)
|
||||
if records := multiRecordFromBytes(b3.Get(sideHeight[:])); !records.Contains(mainId) {
|
||||
records = append(records, mainId)
|
||||
if err = b3.Put(sideHeight[:], records.Bytes()); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
b4 := tx.Bucket(refByMainHeight)
|
||||
if records := multiRecordFromBytes(b4.Get(mainHeight[:])); !records.Contains(mainId) {
|
||||
records = append(records, mainId)
|
||||
if err = b4.Put(mainHeight[:], records.Bytes()); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}); err != nil {
|
||||
log.Printf("[Archive Cache] bolt error: %s", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Cache) RemoveByMainId(id types.Hash) {
|
||||
//TODO
|
||||
}
|
||||
func (c *Cache) RemoveByTemplateId(id types.Hash) {
|
||||
//TODO
|
||||
}
|
||||
|
||||
func (c *Cache) existsByMainId(id types.Hash) (result bool) {
|
||||
_ = c.db.View(func(tx *bolt.Tx) error {
|
||||
b := tx.Bucket(blocksByMainId)
|
||||
if b.Get(id[:]) != nil {
|
||||
result = true
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return result
|
||||
}
|
||||
|
||||
func (c *Cache) LoadByMainId(id types.Hash) *sidechain.PoolBlock {
|
||||
//TODO
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Cache) existsByTemplateId(id types.Hash) (result bool) {
|
||||
_ = c.db.View(func(tx *bolt.Tx) error {
|
||||
b := tx.Bucket(refByTemplateId)
|
||||
if b.Get(id[:]) != nil {
|
||||
result = true
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return result
|
||||
}
|
||||
|
||||
func (c *Cache) LoadByTemplateId(id types.Hash) []*sidechain.PoolBlock {
|
||||
//TODO
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Cache) existsBySideChainHeightRange(startHeight, endHeight uint64) (result bool) {
|
||||
_ = c.db.View(func(tx *bolt.Tx) error {
|
||||
b := tx.Bucket(refBySideHeight)
|
||||
var sideHeight [8]byte
|
||||
for h := startHeight; h <= endHeight; h++ {
|
||||
binary.LittleEndian.PutUint64(sideHeight[:], h)
|
||||
if b.Get(sideHeight[:]) == nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
result = true
|
||||
return nil
|
||||
})
|
||||
return result
|
||||
}
|
||||
|
||||
func (c *Cache) LoadBySideChainHeight(height uint64) []*sidechain.PoolBlock {
|
||||
//TODO
|
||||
return nil
|
||||
}
|
||||
func (c *Cache) LoadByMainChainHeight(height uint64) []*sidechain.PoolBlock {
|
||||
//TODO
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Cache) Close() {
|
||||
_ = c.db.Close()
|
||||
}
|
19
p2pool/cache/cache.go
vendored
19
p2pool/cache/cache.go
vendored
|
@ -7,10 +7,11 @@ import (
|
|||
|
||||
type Cache interface {
|
||||
Store(block *sidechain.PoolBlock)
|
||||
Close()
|
||||
}
|
||||
|
||||
type Loadee interface {
|
||||
Consensus() *sidechain.Consensus
|
||||
sidechain.ConsensusProvider
|
||||
AddCachedBlock(block *sidechain.PoolBlock)
|
||||
}
|
||||
|
||||
|
@ -20,6 +21,18 @@ type HeapCache interface {
|
|||
}
|
||||
|
||||
type AddressableCache interface {
|
||||
Remove(hash types.Hash)
|
||||
Load(hash types.Hash) *sidechain.PoolBlock
|
||||
Cache
|
||||
|
||||
RemoveByMainId(id types.Hash)
|
||||
RemoveByTemplateId(id types.Hash)
|
||||
|
||||
LoadByMainId(id types.Hash) *sidechain.PoolBlock
|
||||
// LoadByTemplateId returns a slice of loaded blocks. If more than one, these might have colliding nonce / extra nonce values
|
||||
LoadByTemplateId(id types.Hash) []*sidechain.PoolBlock
|
||||
LoadBySideChainHeight(height uint64) []*sidechain.PoolBlock
|
||||
LoadByMainChainHeight(height uint64) []*sidechain.PoolBlock
|
||||
}
|
||||
|
||||
type IndexedCache interface {
|
||||
AddressableCache
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import (
|
|||
"git.gammaspectra.live/P2Pool/p2pool-observer/monero/client/zmq"
|
||||
"git.gammaspectra.live/P2Pool/p2pool-observer/monero/transaction"
|
||||
"git.gammaspectra.live/P2Pool/p2pool-observer/p2pool/cache"
|
||||
"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/mainchain"
|
||||
"git.gammaspectra.live/P2Pool/p2pool-observer/p2pool/p2p"
|
||||
|
@ -27,6 +28,7 @@ type P2Pool struct {
|
|||
consensus *sidechain.Consensus
|
||||
sidechain *sidechain.SideChain
|
||||
mainchain *mainchain.MainChain
|
||||
archive cache.AddressableCache
|
||||
cache cache.HeapCache
|
||||
server *p2p.Server
|
||||
|
||||
|
@ -56,6 +58,13 @@ func (p *P2Pool) RemoveBlob(key []byte) (err error) {
|
|||
func (p *P2Pool) Close() {
|
||||
p.ctxCancel()
|
||||
_ = p.zmqClient.Close()
|
||||
|
||||
if p.cache != nil {
|
||||
p.cache.Close()
|
||||
}
|
||||
if p.archive != nil {
|
||||
p.archive.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func NewP2Pool(consensus *sidechain.Consensus, settings map[string]string) (*P2Pool, error) {
|
||||
|
@ -83,6 +92,12 @@ func NewP2Pool(consensus *sidechain.Consensus, settings map[string]string) (*P2P
|
|||
return nil, errors.New("could not create MainChain")
|
||||
}
|
||||
|
||||
if archivePath, ok := settings["archive"]; ok {
|
||||
if pool.archive, err = archive.NewCache(archivePath, pool.consensus); err != nil {
|
||||
return nil, fmt.Errorf("could not create cache: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
if cachePath, ok := settings["cache"]; ok {
|
||||
if pool.cache, err = legacy.NewCache(cachePath); err != nil {
|
||||
return nil, fmt.Errorf("could not create cache: %w", err)
|
||||
|
@ -408,6 +423,9 @@ func (p *P2Pool) Store(block *sidechain.PoolBlock) {
|
|||
if p.cache != nil {
|
||||
p.cache.Store(block)
|
||||
}
|
||||
if p.archive != nil {
|
||||
p.archive.Store(block)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *P2Pool) ClearCachedBlocks() {
|
||||
|
|
|
@ -12,6 +12,7 @@ import (
|
|||
"git.gammaspectra.live/P2Pool/p2pool-observer/monero/transaction"
|
||||
p2poolcrypto "git.gammaspectra.live/P2Pool/p2pool-observer/p2pool/crypto"
|
||||
"git.gammaspectra.live/P2Pool/p2pool-observer/types"
|
||||
"golang.org/x/exp/slices"
|
||||
"io"
|
||||
"log"
|
||||
"sync"
|
||||
|
@ -177,6 +178,48 @@ func NewShareFromExportedBytes(buf []byte, networkType NetworkType) (*PoolBlock,
|
|||
return b, nil
|
||||
}
|
||||
|
||||
func (b *PoolBlock) FillParentIndicesFromTransaction(parent *PoolBlock) error {
|
||||
if len(b.Main.TransactionParentIndices) > 0 && len(b.Main.TransactionParentIndices) == len(b.Main.Transactions) {
|
||||
if slices.Index(b.Main.Transactions, types.ZeroHash) != -1 { //only do this when zero hashes exist
|
||||
if parent != nil && types.HashFromBytes(parent.CoinbaseExtra(SideTemplateId)) == b.Side.Parent {
|
||||
for i, parentIndex := range b.Main.TransactionParentIndices {
|
||||
if parentIndex != 0 {
|
||||
// p2pool stores coinbase transaction hash as well, decrease
|
||||
actualIndex := parentIndex - 1
|
||||
if actualIndex > uint64(len(parent.Main.Transactions)) {
|
||||
return errors.New("index of parent transaction out of bounds")
|
||||
|
||||
}
|
||||
b.Main.Transactions[i] = parent.Main.Transactions[actualIndex]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *PoolBlock) FillTransactionParentIndices(parent *PoolBlock) bool {
|
||||
if len(b.Main.Transactions) != len(b.Main.TransactionParentIndices) {
|
||||
if parent != nil && types.HashFromBytes(parent.CoinbaseExtra(SideTemplateId)) == b.Side.Parent {
|
||||
b.Main.TransactionParentIndices = make([]uint64, len(b.Main.Transactions))
|
||||
//do not fail if not found
|
||||
for i, txHash := range b.Main.Transactions {
|
||||
if parentIndex := slices.Index(parent.Main.Transactions, txHash); parentIndex != -1 {
|
||||
//increase as p2pool stores tx hash as well
|
||||
b.Main.TransactionParentIndices[i] = uint64(parentIndex + 1)
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (b *PoolBlock) ShareVersion() ShareVersion {
|
||||
// P2Pool forks to v2 at 2023-03-18 21:00 UTC
|
||||
// Different miners can have different timestamps,
|
||||
|
|
|
@ -113,23 +113,13 @@ func (c *SideChain) PreprocessBlock(block *PoolBlock) (missingBlocks []types.Has
|
|||
}
|
||||
|
||||
if len(block.Main.TransactionParentIndices) > 0 && len(block.Main.TransactionParentIndices) == len(block.Main.Transactions) {
|
||||
if slices.Index(block.Main.Transactions, types.ZeroHash) != -1 { //only do this when zero hashes exist
|
||||
parent := c.getParent(block)
|
||||
if parent == nil {
|
||||
missingBlocks = append(missingBlocks, block.Side.Parent)
|
||||
return missingBlocks, errors.New("parent does not exist in compact block")
|
||||
}
|
||||
for i, parentIndex := range block.Main.TransactionParentIndices {
|
||||
if parentIndex != 0 {
|
||||
// p2pool stores coinbase transaction hash as well, decrease
|
||||
actualIndex := parentIndex - 1
|
||||
if actualIndex > uint64(len(parent.Main.Transactions)) {
|
||||
return nil, errors.New("index of parent transaction out of bounds")
|
||||
|
||||
}
|
||||
block.Main.Transactions[i] = parent.Main.Transactions[actualIndex]
|
||||
}
|
||||
}
|
||||
parent := c.getParent(block)
|
||||
if parent == nil {
|
||||
missingBlocks = append(missingBlocks, block.Side.Parent)
|
||||
return missingBlocks, errors.New("parent does not exist in compact block")
|
||||
}
|
||||
if err = block.FillParentIndicesFromTransaction(parent); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
// fill if not received from network
|
||||
|
@ -140,21 +130,7 @@ func (c *SideChain) PreprocessBlock(block *PoolBlock) (missingBlocks []types.Has
|
|||
}
|
||||
|
||||
func (c *SideChain) fillPoolBlockTransactionParentIndices(block *PoolBlock) {
|
||||
if len(block.Main.Transactions) != len(block.Main.TransactionParentIndices) {
|
||||
|
||||
parent := c.getParent(block)
|
||||
if parent != nil {
|
||||
block.Main.TransactionParentIndices = make([]uint64, len(block.Main.Transactions))
|
||||
//do not fail if not found
|
||||
for i, txHash := range block.Main.Transactions {
|
||||
if parentIndex := slices.Index(parent.Main.Transactions, txHash); parentIndex != -1 {
|
||||
//increase as p2pool stores tx hash as well
|
||||
block.Main.TransactionParentIndices[i] = uint64(parentIndex + 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
block.FillTransactionParentIndices(c.getParent(block))
|
||||
}
|
||||
|
||||
func (c *SideChain) isPoolBlockTransactionKeyIsDeterministic(block *PoolBlock) bool {
|
||||
|
|
Loading…
Reference in a new issue