diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..8c0bb09 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,29 @@ +name: CI + +on: [push, pull_request] + +jobs: + build-test-lint: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version: '1.25' + cache: true # built-in module caching + + - name: Install golangci-lint + uses: golangci/golangci-lint-action@v4 + with: + version: v1.59.0 + args: --timeout=5m + + - name: Test + run: go test -v ./... + + - name: Build + run: go build -v ./... + diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index d8e7f86..4e24408 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -19,7 +19,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v3 with: - go-version: 1.19 + go-version: 1.22 - name: Build run: go build -v ./... diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..a0ff13a --- /dev/null +++ b/Makefile @@ -0,0 +1,24 @@ +.PHONY: fmt lint test bench build docker + +fmt: +ifeq ($(shell test -e go.mod && echo yes),yes) + gofmt -s -w . +else + prettier --write . +endif + +lint: + golangci-lint run ./... + +test: + go test ./... + +bench: + go test -bench . -benchmem ./... + +build: + go build -o bin/app ./cmd/... + +docker: + docker build -t myorg/robot:latest . + diff --git a/README.md b/README.md index 5ad016a..26797d0 100644 --- a/README.md +++ b/README.md @@ -4,9 +4,12 @@ Robot of cortex full node ## How to use it ? Make sure config the right cortex RPC service endpoint +``` +go install github.com/CortexFoundation/robot/cmd/robot@latest +``` ``` -go run cmd/main.go +go run cmd/robot/main.go ``` image diff --git a/backend/block.go b/backend/block.go new file mode 100644 index 0000000..5225ec1 --- /dev/null +++ b/backend/block.go @@ -0,0 +1,205 @@ +// Copyright 2023 The CortexTheseus Authors +// This file is part of the CortexTheseus library. +// +// The CortexTheseus library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The CortexTheseus library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the CortexTheseus library. If not, see . + +package backend + +import ( + "encoding/json" + "fmt" + "sort" + "strconv" + "time" + + "github.com/CortexFoundation/CortexTheseus/log" + "github.com/CortexFoundation/torrentfs/types" + bolt "go.etcd.io/bbolt" +) + +func (fs *ChainDB) Blocks() []*types.Block { + return fs.blocks +} + +func (fs *ChainDB) Txs() uint64 { + return fs.txs.Load() +} + +func (fs *ChainDB) GetBlockByNumber(blockNum uint64) *types.Block { + var block types.Block + + cb := func(tx *bolt.Tx) error { + buk := tx.Bucket([]byte(BLOCKS_ + fs.version)) + if buk == nil { + return ErrReadDataFromBoltDB + } + k := uint64ToBytes(blockNum) + + v := buk.Get(k) + + if v == nil { + return ErrReadDataFromBoltDB + } + if err := json.Unmarshal(v, &block); err != nil { + return err + } + + return nil + } + + if err := fs.db.View(cb); err != nil { + return nil + } + return &block +} + +// func (fs *ChainDB) addBlock(b *Block, record bool) error { +func (fs *ChainDB) AddBlock(b *types.Block) error { + if fs.metrics { + defer func(start time.Time) { fs.treeUpdates += time.Since(start) }(time.Now()) + } + //i := sort.Search(len(fs.blocks), func(i int) bool { return fs.blocks[i].Number > b.Number }) + //if i == len(fs.blocks) { + //todo + //} else { + // log.Warn("Encounter ancient block (dup)", "cur", b.Number, "index", i, "len", len(fs.blocks), "ckp", fs.CheckPoint) + // return nil + //} + ancient := fs.GetBlockByNumber(b.Number) + if ancient != nil && ancient.Hash == b.Hash { + fs.addLeaf(b, false, true) + return nil + } + + if err := fs.db.Update(func(tx *bolt.Tx) error { + buk, err := tx.CreateBucketIfNotExists([]byte(BLOCKS_ + fs.version)) + if err != nil { + return err + } + v, err := json.Marshal(b) + if err != nil { + return err + } + k := uint64ToBytes(b.Number) + + return buk.Put(k, v) + }); err == nil { + fs.blocks = append(fs.blocks, b) + fs.txs.Add(uint64(len(b.Txs))) + mes := false + if b.Number < fs.checkPoint.Load() { + mes = true + } + + fs.addLeaf(b, mes, false) + } else { + return err + } + if b.Number > fs.lastListenBlockNumber.Load() { + fs.lastListenBlockNumber.Store(b.Number) + if err := fs.Flush(); err != nil { + return err + } + } + return nil +} + +func (fs *ChainDB) initBlocks() error { + return fs.db.Update(func(tx *bolt.Tx) error { + if buk, err := tx.CreateBucketIfNotExists([]byte(BLOCKS_ + fs.version)); err != nil { + return err + } else { + c := buk.Cursor() + + for k, v := c.First(); k != nil; k, v = c.Next() { + + var x types.Block + + if err := json.Unmarshal(v, &x); err != nil { + return err + } + fs.blocks = append(fs.blocks, &x) + fs.txs.Add(uint64(len(x.Txs))) + } + sort.Slice(fs.blocks, func(i, j int) bool { + return fs.blocks[i].Number < fs.blocks[j].Number + }) + log.Info("Fs blocks initializing ... ...", "blocks", len(fs.blocks), "txs", fs.txs.Load()) + return nil + } + }) +} + +func (fs *ChainDB) InitBlockNumber() error { + return fs.db.Update(func(tx *bolt.Tx) error { + buk, err := tx.CreateBucketIfNotExists([]byte(CUR_BLOCK_NUM_ + fs.version)) + if err != nil { + return err + } + + v := buk.Get([]byte("key")) + + if v == nil { + log.Warn("Start from block number (default:0)") + return nil + } + + number, err := strconv.ParseUint(string(v), 16, 64) + if err != nil { + return err + } + + fs.lastListenBlockNumber.Store(number) + log.Info("Start from block number (default:0)", "num", number) + + return nil + }) +} + +func (fs *ChainDB) SkipPrint() { + var ( + str string + from uint64 + ) + for _, b := range fs.blocks { + // if b.Number < 395964 { + // continue + // } + //Skip{From: 160264, To: 395088}, + if b.Number-from > 1000 { + str = str + "{From:" + strconv.FormatUint(from, 10) + ",To:" + strconv.FormatUint(b.Number, 10) + "}," + } + from = b.Number + //fmt.Println(b.Number, ":true,") + } + + if fs.lastListenBlockNumber.Load()-from > 1000 { + str = str + "{From:" + strconv.FormatUint(from, 10) + ",To:" + strconv.FormatUint(fs.lastListenBlockNumber.Load(), 10) + "}," + } + + //log.Info("Skip chart", "skips", str) + fmt.Println(str) +} + +func (fs *ChainDB) CheckPoint() uint64 { + return fs.checkPoint.Load() +} + +func (fs *ChainDB) LastListenBlockNumber() uint64 { + return fs.lastListenBlockNumber.Load() +} + +func (fs *ChainDB) Anchor(n uint64) { + fs.lastListenBlockNumber.Store(n) +} diff --git a/backend/chaindb.go b/backend/chaindb.go index d6dd84d..324ad65 100644 --- a/backend/chaindb.go +++ b/backend/chaindb.go @@ -18,35 +18,22 @@ package backend import ( "encoding/binary" - "encoding/json" - "errors" - "github.com/CortexFoundation/CortexTheseus/common/hexutil" + "os" + "path/filepath" + "strconv" + "sync" + "sync/atomic" + "time" + "github.com/CortexFoundation/merkletree" "github.com/CortexFoundation/torrentfs/params" "github.com/CortexFoundation/torrentfs/types" - "strings" - "sync" - "sync/atomic" + //lru "github.com/hashicorp/golang-lru" - "fmt" "github.com/CortexFoundation/CortexTheseus/common" "github.com/CortexFoundation/CortexTheseus/log" "github.com/google/uuid" bolt "go.etcd.io/bbolt" - "os" - "path/filepath" - "sort" - "strconv" - "time" -) - -const ( - FILES_ = "files_" - BLOCKS_ = "blocks_" - ID_ = "id_" - VERSION_ = "version_" - TORRENT_ = "torrent_" - CUR_BLOCK_NUM_ = "currentBlockNumber_" ) type ChainDB struct { @@ -129,8 +116,6 @@ func NewChainDB(config *params.Config) (*ChainDB, error) { //fs.history() - log.Info("Storage ID generated", "id", fs.id.Load(), "version", fs.version) - return fs, nil } @@ -154,32 +139,14 @@ func (fs *ChainDB) Init() (err error) { log.Error("Init node id error", "err", err) //return err } + + log.Info("Storage ID generated", "id", fs.id.Load(), "version", fs.version) }) return } -func (fs *ChainDB) Files() []*types.FileInfo { - return fs.files -} - -func (fs *ChainDB) Blocks() []*types.Block { - return fs.blocks -} - -func (fs *ChainDB) Torrents() map[string]uint64 { - return fs.torrents -} - -func (fs *ChainDB) Leaves() []merkletree.Content { - return fs.leaves -} - -func (fs *ChainDB) Txs() uint64 { - return fs.txs.Load() -} - -func (fs *ChainDB) Reset() error { +/*func (fs *ChainDB) Reset() error { fs.blocks = nil fs.checkPoint.Store(0) fs.lastListenBlockNumber.Store(0) @@ -188,142 +155,7 @@ func (fs *ChainDB) Reset() error { } log.Warn("Storage status reset") return nil -} - -func (fs *ChainDB) NewFileInfo(fileMeta *types.FileMeta) *types.FileInfo { - ret := &types.FileInfo{Meta: fileMeta, LeftSize: fileMeta.RawSize} - return ret -} - -func (fs *ChainDB) initMerkleTree() error { - if err := fs.initBlocks(); err != nil { - return err - } - - fs.leaves = nil - fs.leaves = append(fs.leaves, merkletree.NewContent(params.MainnetGenesisHash.String(), uint64(0))) //BlockContent{X: params.MainnetGenesisHash.String()}) //"0x21d6ce908e2d1464bd74bbdbf7249845493cc1ba10460758169b978e187762c1"}) - tr, err := merkletree.NewTree(fs.leaves) - if err != nil { - return err - } - fs.tree = tr - for _, block := range fs.blocks { - if err := fs.addLeaf(block, false, false); err != nil { - panic("Storage merkletree construct failed") - } - } - - log.Info("Storage merkletree initialization", "root", hexutil.Encode(fs.tree.MerkleRoot()), "number", fs.lastListenBlockNumber.Load(), "checkpoint", fs.checkPoint.Load(), "version", fs.version, "len", len(fs.blocks)) - - return nil -} - -func (fs *ChainDB) Metrics() time.Duration { - return fs.treeUpdates -} - -// Make sure the block group is increasing by number -func (fs *ChainDB) addLeaf(block *types.Block, mes bool, dup bool) error { - if fs.tree == nil { - return errors.New("mkt is nil") - } - - number := block.Number - leaf := merkletree.NewContent(block.Hash.String(), number) - - l, e := fs.tree.VerifyContent(leaf) - if !l { - if !dup { - fs.leaves = append(fs.leaves, leaf) - } - } else { - log.Debug("Node is already in the tree", "num", number, "len", len(fs.blocks), "leaf", len(fs.leaves), "ckp", fs.checkPoint.Load(), "mes", mes, "dup", dup, "err", e) - if !mes { - return nil - } - } - - if mes { - log.Debug("Messing", "num", number, "len", len(fs.blocks), "leaf", len(fs.leaves), "ckp", fs.checkPoint.Load(), "mes", mes, "dup", dup) - sort.Slice(fs.leaves, func(i, j int) bool { - return fs.leaves[i].(*merkletree.BlockContent).N() < fs.leaves[j].(*merkletree.BlockContent).N() - }) - - i := sort.Search(len(fs.leaves), func(i int) bool { return fs.leaves[i].(*merkletree.BlockContent).N() > number }) - - if i > len(fs.leaves) { - i = len(fs.leaves) - } - - log.Warn("Messing solved", "num", number, "len", len(fs.blocks), "leaf", len(fs.leaves), "ckp", fs.checkPoint.Load(), "mes", mes, "dup", dup, "i", i) - - if err := fs.tree.RebuildTreeWith(fs.leaves[0:i]); err != nil { - return err - } - - } else { - if err := fs.tree.AddNode(leaf); err != nil { - return err - } - - // TODO - - if number > fs.checkPoint.Load() { - fs.checkPoint.Store(number) - } - } - - if err := fs.writeRoot(number, fs.tree.MerkleRoot()); err != nil { - return err - } - return nil -} - -func (fs *ChainDB) Root() common.Hash { - if fs.tree == nil { - return common.EmptyHash - } - return common.BytesToHash(fs.tree.MerkleRoot()) -} - -func (fs *ChainDB) AddFile(x *types.FileInfo) (uint64, bool, error) { - if fs.metrics { - defer func(start time.Time) { fs.treeUpdates += time.Since(start) }(time.Now()) - } - - addr := *x.ContractAddr - if _, ok := fs.filesContractAddr[addr]; ok { - update, err := fs.progress(x, false) - if err != nil { - return 0, update, err - } - - fs.filesContractAddr[addr] = x - return 0, update, nil - } - - update, err := fs.progress(x, true) - if err != nil { - return 0, update, err - } - - fs.filesContractAddr[addr] = x - - if !update { - return 0, update, nil - } - - fs.files = append(fs.files, x) - - return 1, update, nil -} - -func (fs *ChainDB) GetFileByAddr(addr common.Address) *types.FileInfo { - if f, ok := fs.filesContractAddr[addr]; ok { - return f - } - return nil -} +}*/ func (fs *ChainDB) Close() error { defer fs.db.Close() @@ -331,246 +163,10 @@ func (fs *ChainDB) Close() error { return fs.Flush() } -var ( - ErrReadDataFromBoltDB = errors.New("bolt DB Read Error") -) - -func uint64ToBytes(i uint64) []byte { - var buf [8]byte - binary.BigEndian.PutUint64(buf[:], i) - return buf[:] -} - -func (fs *ChainDB) GetBlockByNumber(blockNum uint64) *types.Block { - var block types.Block - - cb := func(tx *bolt.Tx) error { - buk := tx.Bucket([]byte(BLOCKS_ + fs.version)) - if buk == nil { - return ErrReadDataFromBoltDB - } - k := uint64ToBytes(blockNum) - - v := buk.Get(k) - - if v == nil { - return ErrReadDataFromBoltDB - } - if err := json.Unmarshal(v, &block); err != nil { - return err - } - - return nil - } - - if err := fs.db.View(cb); err != nil { - return nil - } - return &block -} - -func (fs *ChainDB) progress(f *types.FileInfo, init bool) (bool, error) { - update := false - err := fs.db.Update(func(tx *bolt.Tx) error { - buk, err := tx.CreateBucketIfNotExists([]byte(FILES_ + fs.version)) - if err != nil { - log.Error("Progress bucket failed", "err", err) - return err - } - - k := []byte(f.Meta.InfoHash) - var v []byte - bef := buk.Get(k) - if bef == nil { - update = true - v, err = json.Marshal(f) - if err != nil { - log.Error("Progress json failed", "err", err) - return err - } - return buk.Put(k, v) - } else { - var info types.FileInfo - if err := json.Unmarshal(bef, &info); err != nil { - update = true - return buk.Put(k, v) - } - - if info.LeftSize > f.LeftSize { - update = true - if *info.ContractAddr != *f.ContractAddr { - var insert = true - for _, addr := range info.Relate { - if *f.ContractAddr == addr { - insert = false - break - } - } - if insert { - log.Debug("New relate file found and progressing", "hash", info.Meta.InfoHash, "old", info.ContractAddr, "new", f.ContractAddr, "relate", len(info.Relate), "init", init) - f.Relate = append(f.Relate, *info.ContractAddr) - } else { - log.Debug("Address changed and progressing", "hash", info.Meta.InfoHash, "old", info.ContractAddr, "new", f.ContractAddr, "relate", len(info.Relate), "init", init) - } - } - v, err = json.Marshal(f) - if err != nil { - return err - } - return buk.Put(k, v) - } else { - if *info.ContractAddr != *f.ContractAddr { - for _, addr := range info.Relate { - if *f.ContractAddr == addr { - return nil - } - } - info.Relate = append(info.Relate, *f.ContractAddr) - v, err = json.Marshal(info) - if err != nil { - return err - } - log.Debug("New relate file found", "hash", info.Meta.InfoHash, "old", info.ContractAddr, "new", f.ContractAddr, "r", len(info.Relate), "l", info.LeftSize, "r", len(f.Relate), "l", f.LeftSize, "init", init) - f.Relate = info.Relate - return buk.Put(k, v) - } - } - } - return nil - }) - - return update, err -} - -// func (fs *ChainDB) addBlock(b *Block, record bool) error { -func (fs *ChainDB) AddBlock(b *types.Block) error { - if fs.metrics { - defer func(start time.Time) { fs.treeUpdates += time.Since(start) }(time.Now()) - } - //i := sort.Search(len(fs.blocks), func(i int) bool { return fs.blocks[i].Number > b.Number }) - //if i == len(fs.blocks) { - //todo - //} else { - // log.Warn("Encounter ancient block (dup)", "cur", b.Number, "index", i, "len", len(fs.blocks), "ckp", fs.CheckPoint) - // return nil - //} - ancient := fs.GetBlockByNumber(b.Number) - if ancient != nil && ancient.Hash == b.Hash { - fs.addLeaf(b, false, true) - return nil - } - - if err := fs.db.Update(func(tx *bolt.Tx) error { - buk, err := tx.CreateBucketIfNotExists([]byte(BLOCKS_ + fs.version)) - if err != nil { - return err - } - v, err := json.Marshal(b) - if err != nil { - return err - } - k := uint64ToBytes(b.Number) - - return buk.Put(k, v) - }); err == nil { - fs.blocks = append(fs.blocks, b) - fs.txs.Add(uint64(len(b.Txs))) - mes := false - if b.Number < fs.checkPoint.Load() { - mes = true - } - - fs.addLeaf(b, mes, false) - } else { - return err - } - if b.Number > fs.lastListenBlockNumber.Load() { - fs.lastListenBlockNumber.Store(b.Number) - if err := fs.Flush(); err != nil { - return err - } - } - return nil -} - func (fs *ChainDB) Version() string { return fs.version } -func (fs *ChainDB) initBlocks() error { - return fs.db.Update(func(tx *bolt.Tx) error { - if buk, err := tx.CreateBucketIfNotExists([]byte(BLOCKS_ + fs.version)); err != nil { - return err - } else { - c := buk.Cursor() - - for k, v := c.First(); k != nil; k, v = c.Next() { - - var x types.Block - - if err := json.Unmarshal(v, &x); err != nil { - return err - } - fs.blocks = append(fs.blocks, &x) - fs.txs.Add(uint64(len(x.Txs))) - } - sort.Slice(fs.blocks, func(i, j int) bool { - return fs.blocks[i].Number < fs.blocks[j].Number - }) - log.Info("Fs blocks initializing ... ...", "blocks", len(fs.blocks), "txs", fs.txs.Load()) - return nil - } - }) -} - -func (fs *ChainDB) history() error { - return fs.db.Update(func(tx *bolt.Tx) error { - if buk, err := tx.CreateBucketIfNotExists([]byte(VERSION_ + fs.version)); err != nil { - return err - } else { - c := buk.Cursor() - - for k, v := c.First(); k != nil; k, v = c.Next() { - log.Info("History", "k", string(k), "v", common.BytesToHash(v)) - } - return nil - } - }) -} - -func (fs *ChainDB) initFiles() error { - return fs.db.Update(func(tx *bolt.Tx) error { - if buk, err := tx.CreateBucketIfNotExists([]byte(FILES_ + fs.version)); buk == nil || err != nil { - return err - } else { - c := buk.Cursor() - - for k, v := c.First(); k != nil; k, v = c.Next() { - - var x types.FileInfo - if err := json.Unmarshal(v, &x); err != nil { - log.Error("Json unmarshal error", "err", err) - return err - } - fs.filesContractAddr[*x.ContractAddr] = &x - fs.files = append(fs.files, &x) - if x.Relate == nil { - x.Relate = append(x.Relate, *x.ContractAddr) - } - for _, addr := range x.Relate { - if _, ok := fs.filesContractAddr[addr]; !ok { - tmp := x - tmp.ContractAddr = &addr - fs.filesContractAddr[addr] = &tmp - } - } - } - log.Info("File init finished", "files", len(fs.files), "total", len(fs.filesContractAddr)) - return nil - } - }) -} - func (fs *ChainDB) ID() uint64 { return fs.id.Load() } @@ -609,6 +205,8 @@ func (fs *ChainDB) initID() error { return err } id := binary.LittleEndian.Uint64([]byte(uid[:])) + + log.Info("New random id generated !!!", "key", ID_+fs.version, "id", id) e := buk.Put([]byte("key"), []byte(strconv.FormatUint(id, 16))) fs.id.Store(id) //binary.LittleEndian.Uint64([]byte(id[:]))//uint64(id[:]) @@ -638,37 +236,11 @@ func (fs *ChainDB) initID() error { fs.CheckPoint = number log.Info("Start from check point (default:0)", "num", number) - return nil - }) -}*/ - -func (fs *ChainDB) InitBlockNumber() error { - return fs.db.Update(func(tx *bolt.Tx) error { - buk, err := tx.CreateBucketIfNotExists([]byte(CUR_BLOCK_NUM_ + fs.version)) - if err != nil { - return err - } - - v := buk.Get([]byte("key")) - - if v == nil { - log.Warn("Start from block number (default:0)") - return nil - } - - number, err := strconv.ParseUint(string(v), 16, 64) - if err != nil { - return err - } - - fs.lastListenBlockNumber.Store(number) - log.Info("Start from block number (default:0)", "num", number) - return nil }) } -/*func (fs *ChainDB) writeCheckPoint() error { +func (fs *ChainDB) writeCheckPoint() error { return fs.db.Update(func(tx *bolt.Tx) error { buk, err := tx.CreateBucketIfNotExists([]byte("checkpoint_" + fs.version)) if err != nil { @@ -680,48 +252,6 @@ func (fs *ChainDB) InitBlockNumber() error { }) }*/ -func (fs *ChainDB) writeRoot(number uint64, root []byte) error { - //fs.rootCache.Add(number, root) - return fs.db.Update(func(tx *bolt.Tx) error { - buk, err := tx.CreateBucketIfNotExists([]byte(VERSION_ + fs.version)) - if err != nil { - return err - } - e := buk.Put([]byte(strconv.FormatUint(number, 16)), root) - - if e == nil { - log.Debug("Root update", "number", number, "root", common.BytesToHash(root)) - } - - return e - }) -} - -func (fs *ChainDB) GetRoot(number uint64) (root []byte) { - //if root, suc := fs.rootCache.Get(number); suc { - // return root.([]byte) - //} - cb := func(tx *bolt.Tx) error { - buk := tx.Bucket([]byte(VERSION_ + fs.version)) - if buk == nil { - return errors.New("root bucket not exist") - } - - v := buk.Get([]byte(strconv.FormatUint(number, 16))) - if v == nil { - return errors.New("root value not exist") - } - - root = v - return nil - } - if err := fs.db.View(cb); err != nil { - return nil - } - - return root -} - func (fs *ChainDB) Flush() error { return fs.db.Update(func(tx *bolt.Tx) error { buk, err := tx.CreateBucketIfNotExists([]byte(CUR_BLOCK_NUM_ + fs.version)) @@ -734,145 +264,3 @@ func (fs *ChainDB) Flush() error { return e }) } - -func (fs *ChainDB) SkipPrint() { - var ( - str string - from uint64 - ) - for _, b := range fs.blocks { - // if b.Number < 395964 { - // continue - // } - //Skip{From: 160264, To: 395088}, - if b.Number-from > 1000 { - str = str + "{From:" + strconv.FormatUint(from, 10) + ",To:" + strconv.FormatUint(b.Number, 10) + "}," - } - from = b.Number - //fmt.Println(b.Number, ":true,") - } - - if fs.lastListenBlockNumber.Load()-from > 1000 { - str = str + "{From:" + strconv.FormatUint(from, 10) + ",To:" + strconv.FormatUint(fs.lastListenBlockNumber.Load(), 10) + "}," - } - - //log.Info("Skip chart", "skips", str) - fmt.Println(str) -} - -// SetTorrent is for recording torrent latest status -func (fs *ChainDB) SetTorrentProgress(ih string, size uint64) (bool, uint64, error) { - fs.lock.Lock() - defer fs.lock.Unlock() - - if s, ok := fs.torrents[ih]; ok { - if s >= size { - return false, s, nil - } - } - if err := fs.db.Update(func(tx *bolt.Tx) error { - buk, err := tx.CreateBucketIfNotExists([]byte(TORRENT_ + fs.version)) - if err != nil { - return err - } - v := buk.Get([]byte(ih)) - - if v == nil { - err = buk.Put([]byte(ih), []byte(strconv.FormatUint(size, 16))) - } else { - s, err := strconv.ParseUint(string(v), 16, 64) - if err != nil { - return err - } - if size > s { - err = buk.Put([]byte(ih), []byte(strconv.FormatUint(size, 16))) - } else { - size = s - } - } - - return err - }); err != nil { - return false, 0, err - } - - fs.torrents[ih] = size - - log.Debug("File status has been changed", "ih", ih, "size", size, "count", len(fs.torrents)) - - return true, size, nil -} - -// GetTorrent return the torrent status by uint64, if return 0 for torrent not exist -func (fs *ChainDB) GetTorrentProgress(ih string) (progress uint64, err error) { - fs.lock.RLock() - defer fs.lock.RUnlock() - - //TODO - ih = strings.ToLower(ih) - - if s, ok := fs.torrents[ih]; ok { - return s, nil - } - cb := func(tx *bolt.Tx) error { - buk := tx.Bucket([]byte(TORRENT_ + fs.version)) - if buk == nil { - return errors.New("root bucket not exist") - } - - v := buk.Get([]byte(ih)) - - if v == nil { - return errors.New("No torrent record found") - } - - s, err := strconv.ParseUint(string(v), 16, 64) - if err != nil { - return err - } - - progress = s - - return nil - } - if err := fs.db.View(cb); err != nil { - return 0, err - } - - return progress, nil -} - -func (fs *ChainDB) InitTorrents() (map[string]uint64, error) { - err := fs.db.Update(func(tx *bolt.Tx) error { - if buk, err := tx.CreateBucketIfNotExists([]byte(TORRENT_ + fs.version)); err != nil { - return err - } else { - c := buk.Cursor() - for k, v := c.First(); k != nil; k, v = c.Next() { - size, err := strconv.ParseUint(string(v), 16, 64) - if err != nil { - return err - } - fs.torrents[string(k)] = size - } - log.Debug("Torrent initializing ... ...", "torrents", len(fs.torrents)) - return nil - } - }) - if err != nil { - return nil, err - } - return fs.torrents, nil -} - -func (fs *ChainDB) CheckPoint() uint64 { - return fs.checkPoint.Load() -} - -func (fs *ChainDB) LastListenBlockNumber() uint64 { - return fs.lastListenBlockNumber.Load() -} - -func (fs *ChainDB) Anchor(n uint64) { - fs.lastListenBlockNumber.Store(n) -} diff --git a/backend/common.go b/backend/common.go new file mode 100644 index 0000000..2b55735 --- /dev/null +++ b/backend/common.go @@ -0,0 +1,32 @@ +// Copyright 2023 The CortexTheseus Authors +// This file is part of the CortexTheseus library. +// +// The CortexTheseus library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The CortexTheseus library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the CortexTheseus library. If not, see . + +package backend + +import ( + "encoding/binary" + "strconv" +) + +func uint64ToBytes(i uint64) []byte { + var buf [8]byte + binary.BigEndian.PutUint64(buf[:], i) + return buf[:] +} + +func uint64ToHex(i uint64) []byte { + return []byte(strconv.FormatUint(i, 16)) +} diff --git a/backend/const.go b/backend/const.go new file mode 100644 index 0000000..3eaafce --- /dev/null +++ b/backend/const.go @@ -0,0 +1,26 @@ +// Copyright 2023 The CortexTheseus Authors +// This file is part of the CortexTheseus library. +// +// The CortexTheseus library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The CortexTheseus library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the CortexTheseus library. If not, see . + +package backend + +const ( + FILES_ = "files_" + BLOCKS_ = "blocks_" + ID_ = "id_" + VERSION_ = "version_" + TORRENT_ = "torrent_" + CUR_BLOCK_NUM_ = "currentBlockNumber_" +) diff --git a/backend/errors.go b/backend/errors.go new file mode 100644 index 0000000..bf83435 --- /dev/null +++ b/backend/errors.go @@ -0,0 +1,25 @@ +// Copyright 2023 The CortexTheseus Authors +// This file is part of the CortexTheseus library. +// +// The CortexTheseus library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The CortexTheseus library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the CortexTheseus library. If not, see . + +package backend + +import ( + "errors" +) + +var ( + ErrReadDataFromBoltDB = errors.New("bolt DB Read Error") +) diff --git a/backend/file.go b/backend/file.go new file mode 100644 index 0000000..420d22e --- /dev/null +++ b/backend/file.go @@ -0,0 +1,181 @@ +// Copyright 2023 The CortexTheseus Authors +// This file is part of the CortexTheseus library. +// +// The CortexTheseus library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The CortexTheseus library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the CortexTheseus library. If not, see . + +package backend + +import ( + "encoding/json" + "time" + + "github.com/CortexFoundation/CortexTheseus/common" + "github.com/CortexFoundation/CortexTheseus/log" + "github.com/CortexFoundation/torrentfs/types" + bolt "go.etcd.io/bbolt" +) + +func (fs *ChainDB) Files() []*types.FileInfo { + return fs.files +} + +func (fs *ChainDB) NewFileInfo(fileMeta *types.FileMeta) *types.FileInfo { + ret := &types.FileInfo{Meta: fileMeta, LeftSize: fileMeta.RawSize} + return ret +} + +func (fs *ChainDB) AddFile(x *types.FileInfo) (uint64, bool, error) { + if fs.metrics { + defer func(start time.Time) { fs.treeUpdates += time.Since(start) }(time.Now()) + } + + addr := *x.ContractAddr + if _, ok := fs.filesContractAddr[addr]; ok { + update, err := fs.progress(x, false) + if err != nil { + return 0, update, err + } + + fs.filesContractAddr[addr] = x + return 0, update, nil + } + + update, err := fs.progress(x, true) + if err != nil { + return 0, update, err + } + + fs.filesContractAddr[addr] = x + + if !update { + return 0, update, nil + } + + fs.files = append(fs.files, x) + + return 1, update, nil +} + +func (fs *ChainDB) GetFileByAddr(addr common.Address) *types.FileInfo { + if f, ok := fs.filesContractAddr[addr]; ok { + return f + } + return nil +} + +func (fs *ChainDB) progress(f *types.FileInfo, init bool) (bool, error) { + update := false + err := fs.db.Update(func(tx *bolt.Tx) error { + buk, err := tx.CreateBucketIfNotExists([]byte(FILES_ + fs.version)) + if err != nil { + log.Error("Progress bucket failed", "err", err) + return err + } + + k := []byte(f.Meta.InfoHash) + var v []byte + bef := buk.Get(k) + if bef == nil { + update = true + v, err = json.Marshal(f) + if err != nil { + log.Error("Progress json failed", "err", err) + return err + } + return buk.Put(k, v) + } else { + var info types.FileInfo + if err := json.Unmarshal(bef, &info); err != nil { + update = true + return buk.Put(k, v) + } + + if info.LeftSize > f.LeftSize { + update = true + if *info.ContractAddr != *f.ContractAddr { + var insert = true + for _, addr := range info.Relate { + if *f.ContractAddr == addr { + insert = false + break + } + } + if insert { + log.Debug("New relate file found and progressing", "hash", info.Meta.InfoHash, "old", info.ContractAddr, "new", f.ContractAddr, "relate", len(info.Relate), "init", init) + f.Relate = append(f.Relate, *info.ContractAddr) + } else { + log.Debug("Address changed and progressing", "hash", info.Meta.InfoHash, "old", info.ContractAddr, "new", f.ContractAddr, "relate", len(info.Relate), "init", init) + } + } + v, err = json.Marshal(f) + if err != nil { + return err + } + return buk.Put(k, v) + } else { + if *info.ContractAddr != *f.ContractAddr { + for _, addr := range info.Relate { + if *f.ContractAddr == addr { + return nil + } + } + info.Relate = append(info.Relate, *f.ContractAddr) + v, err = json.Marshal(info) + if err != nil { + return err + } + log.Debug("New relate file found", "hash", info.Meta.InfoHash, "old", info.ContractAddr, "new", f.ContractAddr, "r", len(info.Relate), "l", info.LeftSize, "r", len(f.Relate), "l", f.LeftSize, "init", init) + f.Relate = info.Relate + return buk.Put(k, v) + } + } + } + return nil + }) + + return update, err +} + +func (fs *ChainDB) initFiles() error { + return fs.db.Update(func(tx *bolt.Tx) error { + if buk, err := tx.CreateBucketIfNotExists([]byte(FILES_ + fs.version)); buk == nil || err != nil { + return err + } else { + c := buk.Cursor() + + for k, v := c.First(); k != nil; k, v = c.Next() { + + var x types.FileInfo + if err := json.Unmarshal(v, &x); err != nil { + log.Error("Json unmarshal error", "err", err) + return err + } + fs.filesContractAddr[*x.ContractAddr] = &x + fs.files = append(fs.files, &x) + if x.Relate == nil { + x.Relate = append(x.Relate, *x.ContractAddr) + } + for _, addr := range x.Relate { + if _, ok := fs.filesContractAddr[addr]; !ok { + tmp := x + tmp.ContractAddr = &addr + fs.filesContractAddr[addr] = &tmp + } + } + } + log.Info("File init finished", "files", len(fs.files), "total", len(fs.filesContractAddr)) + return nil + } + }) +} diff --git a/backend/torrent.go b/backend/torrent.go new file mode 100644 index 0000000..22e4bb7 --- /dev/null +++ b/backend/torrent.go @@ -0,0 +1,137 @@ +// Copyright 2023 The CortexTheseus Authors +// This file is part of the CortexTheseus library. +// +// The CortexTheseus library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The CortexTheseus library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the CortexTheseus library. If not, see . + +package backend + +import ( + "errors" + "strconv" + "strings" + + //lru "github.com/hashicorp/golang-lru" + + "github.com/CortexFoundation/CortexTheseus/log" + bolt "go.etcd.io/bbolt" +) + +func (fs *ChainDB) Torrents() map[string]uint64 { + return fs.torrents +} + +// SetTorrent is for recording torrent latest status +func (fs *ChainDB) SetTorrentProgress(ih string, size uint64) (bool, uint64, error) { + fs.lock.Lock() + defer fs.lock.Unlock() + + if s, ok := fs.torrents[ih]; ok { + if s >= size { + return false, s, nil + } + } + if err := fs.db.Update(func(tx *bolt.Tx) error { + buk, err := tx.CreateBucketIfNotExists([]byte(TORRENT_ + fs.version)) + if err != nil { + return err + } + v := buk.Get([]byte(ih)) + + if v == nil { + err = buk.Put([]byte(ih), uint64ToHex(size)) + } else { + s, err := strconv.ParseUint(string(v), 16, 64) + if err != nil { + return err + } + if size > s { + err = buk.Put([]byte(ih), uint64ToHex(size)) + } else { + size = s + } + } + + return err + }); err != nil { + return false, 0, err + } + + fs.torrents[ih] = size + + log.Debug("File status has been changed", "ih", ih, "size", size, "count", len(fs.torrents)) + + return true, size, nil +} + +// GetTorrent return the torrent status by uint64, if return 0 for torrent not exist +func (fs *ChainDB) GetTorrentProgress(ih string) (progress uint64, err error) { + fs.lock.RLock() + defer fs.lock.RUnlock() + + //TODO + ih = strings.ToLower(ih) + + if s, ok := fs.torrents[ih]; ok { + return s, nil + } + cb := func(tx *bolt.Tx) error { + buk := tx.Bucket([]byte(TORRENT_ + fs.version)) + if buk == nil { + return errors.New("root bucket not exist") + } + + v := buk.Get([]byte(ih)) + + if v == nil { + return errors.New("No torrent record found") + } + + s, err := strconv.ParseUint(string(v), 16, 64) + if err != nil { + return err + } + + progress = s + + return nil + } + if err := fs.db.View(cb); err != nil { + return 0, err + } + + return progress, nil +} + +func (fs *ChainDB) InitTorrents() (map[string]uint64, error) { + err := fs.db.Update(func(tx *bolt.Tx) error { + if buk, err := tx.CreateBucketIfNotExists([]byte(TORRENT_ + fs.version)); err != nil { + return err + } else { + c := buk.Cursor() + for k, v := c.First(); k != nil; k, v = c.Next() { + size, err := strconv.ParseUint(string(v), 16, 64) + if err != nil { + return err + } + fs.torrents[string(k)] = size + } + log.Debug("Torrent initializing ... ...", "torrents", len(fs.torrents)) + return nil + } + }) + if err != nil { + return nil, err + } + return fs.torrents, nil +} diff --git a/backend/tree.go b/backend/tree.go new file mode 100644 index 0000000..be685b8 --- /dev/null +++ b/backend/tree.go @@ -0,0 +1,202 @@ +// Copyright 2023 The CortexTheseus Authors +// This file is part of the CortexTheseus library. +// +// The CortexTheseus library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The CortexTheseus library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the CortexTheseus library. If not, see . + +package backend + +import ( + "errors" + "fmt" + "sort" + "time" + + "github.com/CortexFoundation/CortexTheseus/common" + "github.com/CortexFoundation/CortexTheseus/common/hexutil" + "github.com/CortexFoundation/CortexTheseus/log" + "github.com/CortexFoundation/merkletree" + "github.com/CortexFoundation/torrentfs/params" + "github.com/CortexFoundation/torrentfs/types" + bolt "go.etcd.io/bbolt" +) + +func (fs *ChainDB) Leaves() []merkletree.Content { + return fs.leaves +} + +func (fs *ChainDB) initMerkleTree() error { + if err := fs.initBlocks(); err != nil { + return err + } + + fs.leaves = nil + fs.leaves = append(fs.leaves, merkletree.NewContent(params.MainnetGenesisHash.String(), uint64(0))) //BlockContent{X: params.MainnetGenesisHash.String()}) //"0x21d6ce908e2d1464bd74bbdbf7249845493cc1ba10460758169b978e187762c1"}) + tr, err := merkletree.NewTree(fs.leaves) + if err != nil { + return err + } + fs.tree = tr + for _, block := range fs.blocks { + if err := fs.addLeaf(block, false, false); err != nil { + panic("Storage merkletree construct failed") + } + } + + log.Info("Storage merkletree initialization", "root", hexutil.Encode(fs.tree.MerkleRoot()), "number", fs.lastListenBlockNumber.Load(), "checkpoint", fs.checkPoint.Load(), "version", fs.version, "len", len(fs.blocks)) + + return nil +} + +func (fs *ChainDB) Metrics() time.Duration { + return fs.treeUpdates +} + +// handleNormalAdd handles the standard adding of a new leaf to the Merkle tree. +func (fs *ChainDB) handleNormalAdd(leaf *merkletree.BlockContent, number uint64) error { + // Add the new node to the tree. + if err := fs.tree.AddNode(leaf); err != nil { + return fmt.Errorf("failed to add node to Merkle tree: %w", err) + } + + // Update the checkpoint if the current block number is higher. + if number > fs.checkPoint.Load() { + fs.checkPoint.Store(number) + } + + return nil +} + +// handleMessing handles the special "messing" logic by rebuilding the tree from a sorted leaf list. +func (fs *ChainDB) handleMessing(leaf *merkletree.BlockContent, number uint64, dup bool) error { + log.Debug("Messing mode activated, preparing to rebuild tree", "number", number) + + // Add the leaf if it's not a duplicate. This logic is moved here. + if !dup { + fs.leaves = append(fs.leaves, leaf) + } + + // Sort the leaves by block number. + sort.Slice(fs.leaves, func(i, j int) bool { + return fs.leaves[i].(*merkletree.BlockContent).N() < fs.leaves[j].(*merkletree.BlockContent).N() + }) + + // Find the insertion point for the current block number. + i := sort.Search(len(fs.leaves), func(i int) bool { return fs.leaves[i].(*merkletree.BlockContent).N() >= number }) + if i >= len(fs.leaves) { + i = len(fs.leaves) + } + + log.Warn("Messing solved, rebuilding tree", "number", number, "leaves_count", len(fs.leaves), "rebuild_until_index", i) + + // Rebuild the tree with the sorted and filtered leaves. + if err := fs.tree.RebuildTreeWith(fs.leaves[0:i]); err != nil { + return fmt.Errorf("failed to rebuild Merkle tree: %w", err) + } + + return nil +} + +func (fs *ChainDB) addLeaf(block *types.Block, mes bool, dup bool) error { + if fs.tree == nil { + return errors.New("mkt is nil") + } + + number := block.Number + leaf := merkletree.NewContent(block.Hash.String(), number) + + // Verify if the content already exists in the tree. + inTree, verifyErr := fs.tree.VerifyContent(leaf) + if inTree { + log.Debug("Node is already in the tree", "num", number, "mes", mes, "dup", dup, "err", verifyErr) + if !mes { + // If not in messing mode, we can simply return if the node is a duplicate. + return nil + } + } else { + // If the node is not in the tree, we need to add it to the leaves list for the `mes` logic. + // The `dup` parameter seems to control this, but the logic is a bit confusing. + // Assuming `!dup` means it's a new leaf that needs to be appended. + if !dup { + fs.leaves = append(fs.leaves, leaf) + } + } + + // Choose the appropriate handler based on the `mes` flag. + var err error + if mes { + err = fs.handleMessing(leaf, number, dup) + } else { + err = fs.handleNormalAdd(leaf, number) + } + + if err != nil { + return err + } + + // Write the root after all operations. + if err := fs.writeRoot(number, fs.tree.MerkleRoot()); err != nil { + return fmt.Errorf("failed to write root: %w", err) + } + + return nil +} + +func (fs *ChainDB) Root() common.Hash { + if fs.tree == nil { + return common.EmptyHash + } + return common.BytesToHash(fs.tree.MerkleRoot()) +} + +func (fs *ChainDB) writeRoot(number uint64, root []byte) error { + //fs.rootCache.Add(number, root) + return fs.db.Update(func(tx *bolt.Tx) error { + buk, err := tx.CreateBucketIfNotExists([]byte(VERSION_ + fs.version)) + if err != nil { + return err + } + e := buk.Put([]byte(hexutil.EncodeUint64(number)), root) + + if e == nil { + log.Debug("Root update", "number", number, "root", common.BytesToHash(root)) + } + + return e + }) +} + +func (fs *ChainDB) GetRoot(number uint64) (root []byte) { + //if root, suc := fs.rootCache.Get(number); suc { + // return root.([]byte) + //} + cb := func(tx *bolt.Tx) error { + buk := tx.Bucket([]byte(VERSION_ + fs.version)) + if buk == nil { + return errors.New("root bucket not exist") + } + + v := buk.Get([]byte(hexutil.EncodeUint64(number))) + if v == nil { + return errors.New("root value not exist") + } + + root = v + return nil + } + if err := fs.db.View(cb); err != nil { + return nil + } + + return root +} diff --git a/cmd/main.go b/cmd/robot/main.go similarity index 83% rename from cmd/main.go rename to cmd/robot/main.go index 8b016b1..36b91a9 100644 --- a/cmd/main.go +++ b/cmd/robot/main.go @@ -7,15 +7,13 @@ import ( "time" "github.com/CortexFoundation/CortexTheseus/log" - "github.com/CortexFoundation/robot" "github.com/CortexFoundation/torrentfs/params" + + "github.com/CortexFoundation/robot" ) func main() { - glogger := log.NewGlogHandler(log.StreamHandler(os.Stderr, log.TerminalFormat(true))) - glogger.Verbosity(log.LvlInfo) - glogger.Vmodule("") - log.Root().SetHandler(glogger) + log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelInfo, true))) cfg := ¶ms.DefaultConfig cfg.DataDir = ".storage" diff --git a/cmd/w3/main.go b/cmd/w3/main.go new file mode 100644 index 0000000..28568a4 --- /dev/null +++ b/cmd/w3/main.go @@ -0,0 +1,34 @@ +package main + +import ( + "fmt" + "math/big" + + "github.com/lmittmann/w3" + "github.com/lmittmann/w3/module/eth" +) + +func main() { + addr := w3.A("0x0000000000000000000000000000000000000000") + + // 1. Connect to an RPC endpoint + client, err := w3.Dial("http://mainnet.cortexlabs.ai:30089") + if err != nil { + // handle error + } + defer client.Close() + + // 2. Make a batch request + var ( + balance *big.Int + nonce uint64 + ) + if err := client.Call( + eth.Balance(addr, nil).Returns(&balance), + eth.Nonce(addr, nil).Returns(&nonce), + ); err != nil { + // handle error + } + + fmt.Printf("balance: %s\nnonce: %d\n", w3.FromWei(balance, 18), nonce) +} diff --git a/config.go b/config.go new file mode 100644 index 0000000..3e7f51d --- /dev/null +++ b/config.go @@ -0,0 +1,27 @@ +// Copyright 2023 The CortexTheseus Authors +// This file is part of the CortexTheseus library. +// +// The CortexTheseus library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The CortexTheseus library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the CortexTheseus library. If not, see . + +package robot + +import ( + "time" +) + +const ( + batch = 4096 * 16 //params.SyncBatch + delay = 12 //params.Delay + timeout = 30 * time.Second +) diff --git a/go.mod b/go.mod index 8d20a90..81c248f 100644 --- a/go.mod +++ b/go.mod @@ -1,75 +1,88 @@ module github.com/CortexFoundation/robot -go 1.20 +go 1.24.4 + +toolchain go1.24.6 require ( - github.com/CortexFoundation/CortexTheseus v1.10.46 - github.com/CortexFoundation/merkletree v0.0.0-20230724124840-b6e80265a137 - github.com/CortexFoundation/torrentfs v1.0.54-0.20230828094241-b6396d4130ec - github.com/google/uuid v1.3.0 - github.com/hashicorp/golang-lru/v2 v2.0.6-0.20230823180716-8f8764ff4ea3 - github.com/ucwong/golang-kv v1.0.23-0.20230827081935-0ebb6ae028c9 - go.etcd.io/bbolt v1.3.7 + github.com/CortexFoundation/CortexTheseus v1.10.64 + github.com/CortexFoundation/merkletree v0.0.0-20250807103550-396f9f0ba0f1 + github.com/CortexFoundation/torrentfs v1.0.71-0.20250817133626-2413d8feb601 + github.com/google/uuid v1.6.0 + github.com/hashicorp/golang-lru/v2 v2.0.7 + github.com/lmittmann/w3 v0.20.2 + github.com/ucwong/golang-kv v1.0.24-0.20250813143538-d7c3af16d0ff + go.etcd.io/bbolt v1.4.2 ) require ( - github.com/DataDog/zstd v1.5.6-0.20230622172052-ea68dcab66c0 // indirect - github.com/antlabs/stl v0.0.1 // indirect - github.com/antlabs/timer v0.0.11 // indirect + github.com/DataDog/zstd v1.5.7 // indirect + github.com/Microsoft/go-winio v0.6.2 // indirect + github.com/antlabs/stl v0.0.2 // indirect + github.com/antlabs/timer v0.1.4 // indirect github.com/beorn7/perks v1.0.1 // indirect + github.com/bits-and-blooms/bitset v1.24.0 // indirect github.com/bwmarrin/snowflake v0.3.0 // indirect - github.com/cespare/xxhash/v2 v2.2.0 // indirect - github.com/cockroachdb/errors v1.10.0 // indirect - github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect - github.com/cockroachdb/pebble v0.0.0-20230826001808-0b401ee526b8 // indirect - github.com/cockroachdb/redact v1.1.5 // indirect - github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 // indirect - github.com/deckarep/golang-set/v2 v2.3.1 // indirect - github.com/dgraph-io/badger/v4 v4.2.1-0.20230808010956-340ba1ae4c03 // indirect - github.com/dgraph-io/ristretto v0.1.1 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/cockroachdb/errors v1.12.0 // indirect + github.com/cockroachdb/fifo v0.0.0-20240816210425-c5d0cb0b6fc0 // indirect + github.com/cockroachdb/logtags v0.0.0-20241215232642-bb51bb14a506 // indirect + github.com/cockroachdb/pebble v1.1.5 // indirect + github.com/cockroachdb/redact v1.1.6 // indirect + github.com/cockroachdb/tokenbucket v0.0.0-20250429170803-42689b6311bb // indirect + github.com/consensys/gnark-crypto v0.18.0 // indirect + github.com/crate-crypto/go-eth-kzg v1.3.0 // indirect + github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a // indirect + github.com/deckarep/golang-set/v2 v2.8.0 // indirect + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect + github.com/dgraph-io/badger/v4 v4.8.1-0.20250813063812-ba57eda11382 // indirect + github.com/dgraph-io/ristretto/v2 v2.2.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect - github.com/emirpasic/gods v1.18.1 // indirect - github.com/getsentry/sentry-go v0.22.0 // indirect - github.com/go-ole/go-ole v1.2.6 // indirect - github.com/go-stack/stack v1.8.1 // indirect - github.com/gofrs/flock v0.8.1 // indirect + github.com/ethereum/c-kzg-4844/v2 v2.1.1 // indirect + github.com/ethereum/go-ethereum v1.16.2 // indirect + github.com/ethereum/go-verkle v0.2.2 // indirect + github.com/getsentry/sentry-go v0.35.1 // indirect + github.com/go-logr/logr v1.4.3 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-ole/go-ole v1.3.0 // indirect + github.com/gofrs/flock v0.12.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang/glog v1.1.1 // indirect - github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect - github.com/golang/protobuf v1.5.3 // indirect - github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect - github.com/google/flatbuffers v23.5.26+incompatible // indirect - github.com/gorilla/websocket v1.5.0 // indirect - github.com/holiman/uint256 v1.2.3 // indirect - github.com/klauspost/compress v1.16.7 // indirect + github.com/golang/snappy v1.0.0 // indirect + github.com/google/flatbuffers v25.2.10+incompatible // indirect + github.com/gorilla/websocket v1.5.3 // indirect + github.com/holiman/uint256 v1.3.2 // indirect + github.com/klauspost/compress v1.18.0 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/kr/text v0.2.0 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect - github.com/nutsdb/nutsdb v0.13.2-0.20230824154404-d1808de99379 // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/nutsdb/nutsdb v1.0.4 // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/prometheus/client_golang v1.16.0 // indirect - github.com/prometheus/client_model v0.4.0 // indirect - github.com/prometheus/common v0.44.0 // indirect - github.com/prometheus/procfs v0.11.0 // indirect - github.com/rogpeppe/go-internal v1.11.0 // indirect - github.com/rosedblabs/go-immutable-radix/v2 v2.0.1-0.20230614125820-f2a7bc058c90 // indirect - github.com/rosedblabs/rosedb/v2 v2.2.2 // indirect - github.com/rosedblabs/wal v1.3.1 // indirect + github.com/prometheus/client_golang v1.23.0 // indirect + github.com/prometheus/client_model v0.6.2 // indirect + github.com/prometheus/common v0.65.0 // indirect + github.com/prometheus/procfs v0.17.0 // indirect + github.com/rogpeppe/go-internal v1.14.1 // indirect github.com/shirou/gopsutil v3.21.11+incompatible // indirect + github.com/supranational/blst v0.3.15 // indirect github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect - github.com/tidwall/btree v1.6.0 // indirect - github.com/tklauser/go-sysconf v0.3.11 // indirect - github.com/tklauser/numcpus v0.6.1 // indirect + github.com/tidwall/btree v1.8.1 // indirect + github.com/tklauser/go-sysconf v0.3.15 // indirect + github.com/tklauser/numcpus v0.10.0 // indirect github.com/ucwong/go-ttlmap v1.0.2-0.20221020173635-331e7ddde2bb // indirect github.com/xujiajun/mmap-go v1.0.1 // indirect github.com/xujiajun/utils v0.0.0-20220904132955-5f7c5b914235 // indirect - github.com/yusufpapurcu/wmi v1.2.3 // indirect - go.opencensus.io v0.24.0 // indirect - golang.org/x/crypto v0.11.0 // indirect - golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 // indirect - golang.org/x/net v0.12.0 // indirect - golang.org/x/sys v0.11.0 // indirect - golang.org/x/text v0.11.0 // indirect - google.golang.org/protobuf v1.31.0 // indirect + github.com/yusufpapurcu/wmi v1.2.4 // indirect + go.opentelemetry.io/auto/sdk v1.1.0 // indirect + go.opentelemetry.io/otel v1.37.0 // indirect + go.opentelemetry.io/otel/metric v1.37.0 // indirect + go.opentelemetry.io/otel/trace v1.37.0 // indirect + golang.org/x/crypto v0.41.0 // indirect + golang.org/x/exp v0.0.0-20250813145105-42675adae3e6 // indirect + golang.org/x/net v0.43.0 // indirect + golang.org/x/sync v0.16.0 // indirect + golang.org/x/sys v0.35.0 // indirect + golang.org/x/text v0.28.0 // indirect + golang.org/x/time v0.12.0 // indirect + google.golang.org/protobuf v1.36.7 // indirect gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect ) diff --git a/go.sum b/go.sum index 0443a2d..819fd65 100644 --- a/go.sum +++ b/go.sum @@ -1,140 +1,177 @@ -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/CortexFoundation/CortexTheseus v1.10.46 h1:d9hM58WZcZ5DahED1qOmfb6X0dA4U823naiAyAN1Cjs= -github.com/CortexFoundation/CortexTheseus v1.10.46/go.mod h1:+QixLq8iCOCLhFRkVT9QqrYg1m9j01k+UwuJvl145tw= -github.com/CortexFoundation/merkletree v0.0.0-20230724124840-b6e80265a137 h1:GdrLwJRKPrUSd4V/cBpPyzhNQEo8IDT7Le15hmuC+/4= -github.com/CortexFoundation/merkletree v0.0.0-20230724124840-b6e80265a137/go.mod h1:OwfhC316GcEJ9QVNWPqj6QV7sorcXBnc0P9p8dPfSbM= -github.com/CortexFoundation/torrentfs v1.0.54-0.20230828094241-b6396d4130ec h1:pjtw/AJOaP4+gbb0+dYVnDstkHVk2/qNdCH42W0T3OA= -github.com/CortexFoundation/torrentfs v1.0.54-0.20230828094241-b6396d4130ec/go.mod h1:psN0USlF1R40uM7cuaRNkiohd9Tt3FMYHaITo8Un3Yc= -github.com/DataDog/zstd v1.5.6-0.20230622172052-ea68dcab66c0 h1:ye3LRgDs6Og7SKC1wBQH8oMaGczhCRpPpnU74l4rma8= -github.com/DataDog/zstd v1.5.6-0.20230622172052-ea68dcab66c0/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= -github.com/antlabs/stl v0.0.1 h1:TRD3csCrjREeLhLoQ/supaoCvFhNLBTNIwuRGrDIs6Q= -github.com/antlabs/stl v0.0.1/go.mod h1:wvVwP1loadLG3cRjxUxK8RL4Co5xujGaZlhbztmUEqQ= -github.com/antlabs/timer v0.0.11 h1:z75oGFLeTqJHMOcWzUPBKsBbQAz4Ske3AfqJ7bsdcwU= -github.com/antlabs/timer v0.0.11/go.mod h1:JNV8J3yGvMKhCavGXgj9HXrVZkfdQyKCcqXBT8RdyuU= +github.com/CortexFoundation/CortexTheseus v1.10.64 h1:LSgipa1XRhcNbsrwFK4e5UurpqSgVNwai4FFRL2Y1pM= +github.com/CortexFoundation/CortexTheseus v1.10.64/go.mod h1:ox+8dMcL4xlHGnJ+IqnNuY6ubsic4HDx+XaNOXWtfMk= +github.com/CortexFoundation/merkletree v0.0.0-20250807103550-396f9f0ba0f1 h1:Pl3f7uSQ6YgC8WJcjxU6uKJFC/9fTDOBLfK458UPemQ= +github.com/CortexFoundation/merkletree v0.0.0-20250807103550-396f9f0ba0f1/go.mod h1:H/XQUOyyWqFweHqa39mLPewU3q9GTY4wvf8KQduuuPQ= +github.com/CortexFoundation/torrentfs v1.0.71-0.20250817133626-2413d8feb601 h1:jLHGBWbFd8b1t2pU+vflseLiEpOjMDIeJCT+TR5nEbc= +github.com/CortexFoundation/torrentfs v1.0.71-0.20250817133626-2413d8feb601/go.mod h1:hiMusDwTqMvoIINoaBCE0AfeLPuhDZQ9Pc65bGiOTqU= +github.com/DataDog/zstd v1.5.7 h1:ybO8RBeh29qrxIhCA9E8gKY6xfONU9T6G6aP9DTKfLE= +github.com/DataDog/zstd v1.5.7/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= +github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= +github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= +github.com/VictoriaMetrics/fastcache v1.12.4 h1:2xvmwZBW+9QtHsXggfzAZRs1FZWCsBs8QDg22bMidf0= +github.com/VictoriaMetrics/fastcache v1.12.4/go.mod h1:K+JGPBn0sueFlLjZ8rcVM0cKkWKNElKyQXmw57QOoYI= +github.com/antlabs/stl v0.0.2 h1:sna1AXR5yIkNE9lWhCcKbheFJSVfCa3vugnGyakI79s= +github.com/antlabs/stl v0.0.2/go.mod h1:kKrO4xrn9cfS1mJVo+/BqePZjAYMXqD0amGF2Ouq7ac= +github.com/antlabs/timer v0.1.4 h1:MHdE00MDnNfhJCmqSOdLXs35uGNwfkMwfbynxrGmQ1c= +github.com/antlabs/timer v0.1.4/go.mod h1:mpw4zlD5KVjstEyUDp43DGLWsY076Mdo4bS78NTseRE= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bits-and-blooms/bitset v1.24.0 h1:H4x4TuulnokZKvHLfzVRTHJfFfnHEeSYJizujEZvmAM= +github.com/bits-and-blooms/bitset v1.24.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= github.com/bwmarrin/snowflake v0.3.0 h1:xm67bEhkKh6ij1790JB83OujPR5CzNe8QuQqAgISZN0= github.com/bwmarrin/snowflake v0.3.0/go.mod h1:NdZxfVWX+oR6y2K0o6qAYv6gIOP9rjG0/E9WsDpxqwE= -github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= -github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f h1:otljaYPt5hWxV3MUfO5dFPFiOXg9CyG5/kCfayTqsJ4= -github.com/cockroachdb/errors v1.10.0 h1:lfxS8zZz1+OjtV4MtNWgboi/W5tyLEB6VQZBXN+0VUU= -github.com/cockroachdb/errors v1.10.0/go.mod h1:lknhIsEVQ9Ss/qKDBQS/UqFSvPQjOwNq2qyKAxtHRqE= -github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE= -github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= -github.com/cockroachdb/pebble v0.0.0-20230826001808-0b401ee526b8 h1:ilhlTIOOfIxuOCo72EnV2oPNCMwiOy6sO19P8RmM/Xw= -github.com/cockroachdb/pebble v0.0.0-20230826001808-0b401ee526b8/go.mod h1:EDjiaAXc0FXiRmxDzcu1wIEJ093ohHMUWxrI6iku0XA= -github.com/cockroachdb/redact v1.1.5 h1:u1PMllDkdFfPWaNGMyLD1+so+aq3uUItthCFqzwPJ30= -github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= -github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 h1:zuQyyAKVxetITBuuhv3BI9cMrmStnpT18zmgmTxunpo= -github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ= +github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU= +github.com/cockroachdb/errors v1.12.0 h1:d7oCs6vuIMUQRVbi6jWWWEJZahLCfJpnJSVobd1/sUo= +github.com/cockroachdb/errors v1.12.0/go.mod h1:SvzfYNNBshAVbZ8wzNc/UPK3w1vf0dKDUP41ucAIf7g= +github.com/cockroachdb/fifo v0.0.0-20240816210425-c5d0cb0b6fc0 h1:pU88SPhIFid6/k0egdR5V6eALQYq2qbSmukrkgIh/0A= +github.com/cockroachdb/fifo v0.0.0-20240816210425-c5d0cb0b6fc0/go.mod h1:9/y3cnZ5GKakj/H4y9r9GTjCvAFta7KLgSHPJJYc52M= +github.com/cockroachdb/logtags v0.0.0-20241215232642-bb51bb14a506 h1:ASDL+UJcILMqgNeV5jiqR4j+sTuvQNHdf2chuKj1M5k= +github.com/cockroachdb/logtags v0.0.0-20241215232642-bb51bb14a506/go.mod h1:Mw7HqKr2kdtu6aYGn3tPmAftiP3QPX63LdK/zcariIo= +github.com/cockroachdb/pebble v1.1.5 h1:5AAWCBWbat0uE0blr8qzufZP5tBjkRyy/jWe1QWLnvw= +github.com/cockroachdb/pebble v1.1.5/go.mod h1:17wO9el1YEigxkP/YtV8NtCivQDgoCyBg5c4VR/eOWo= +github.com/cockroachdb/redact v1.1.6 h1:zXJBwDZ84xJNlHl1rMyCojqyIxv+7YUpQiJLQ7n4314= +github.com/cockroachdb/redact v1.1.6/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= +github.com/cockroachdb/tokenbucket v0.0.0-20250429170803-42689b6311bb h1:3bCgBvB8PbJVMX1ouCcSIxvsqKPYM7gs72o0zC76n9g= +github.com/cockroachdb/tokenbucket v0.0.0-20250429170803-42689b6311bb/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ= +github.com/consensys/gnark-crypto v0.18.0 h1:vIye/FqI50VeAr0B3dx+YjeIvmc3LWz4yEfbWBpTUf0= +github.com/consensys/gnark-crypto v0.18.0/go.mod h1:L3mXGFTe1ZN+RSJ+CLjUt9x7PNdx8ubaYfDROyp2Z8c= +github.com/crate-crypto/go-eth-kzg v1.3.0 h1:05GrhASN9kDAidaFJOda6A4BEvgvuXbazXg/0E3OOdI= +github.com/crate-crypto/go-eth-kzg v1.3.0/go.mod h1:J9/u5sWfznSObptgfa92Jq8rTswn6ahQWEuiLHOjCUI= +github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a h1:W8mUrRp6NOVl3J+MYp5kPMoUZPp7aOYHtaua31lwRHg= +github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a/go.mod h1:sTwzHBvIzm2RfVCGNEBZgRyjwK40bVoun3ZnGOCafNM= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= -github.com/deckarep/golang-set/v2 v2.3.1 h1:vjmkvJt/IV27WXPyYQpAh4bRyWJc5Y435D17XQ9QU5A= -github.com/deckarep/golang-set/v2 v2.3.1/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= -github.com/dgraph-io/badger/v4 v4.2.1-0.20230808010956-340ba1ae4c03 h1:Cly/ijkVwsus9M55uex7BguxcJIXSX4Bvj6uWKU8P1s= -github.com/dgraph-io/badger/v4 v4.2.1-0.20230808010956-340ba1ae4c03/go.mod h1:qfCqhPoWDFJRx1gp5QwwyGo8xk1lbHUxvK9nK0OGAak= -github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWajOK8= -github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA= -github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA= -github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= -github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/deckarep/golang-set/v2 v2.8.0 h1:swm0rlPCmdWn9mESxKOjWk8hXSqoxOp+ZlfuyaAdFlQ= +github.com/deckarep/golang-set/v2 v2.8.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= +github.com/decred/dcrd/crypto/blake256 v1.1.0 h1:zPMNGQCm0g4QTY27fOCorQW7EryeQ/U0x++OzVrdms8= +github.com/decred/dcrd/crypto/blake256 v1.1.0/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 h1:NMZiJj8QnKe1LgsbDayM4UoHwbvwDRwnI3hwNaAHRnc= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0/go.mod h1:ZXNYxsqcloTdSy/rNShjYzMhyjf0LaoftYK0p+A3h40= +github.com/dgraph-io/badger/v4 v4.8.1-0.20250813063812-ba57eda11382 h1:0EbRlvESQ9LgDjiFe7yxEoRp0aZzDdswy904mFEfOHI= +github.com/dgraph-io/badger/v4 v4.8.1-0.20250813063812-ba57eda11382/go.mod h1:ch7TVZFJHVHWbbDbr2XLv9ugyNVDVj+9kcHVFMI6zKo= +github.com/dgraph-io/ristretto/v2 v2.2.0 h1:bkY3XzJcXoMuELV8F+vS8kzNgicwQFAaGINAEJdWGOM= +github.com/dgraph-io/ristretto/v2 v2.2.0/go.mod h1:RZrm63UmcBAaYWC1DotLYBmTvgkrs0+XhBd7Npn7/zI= +github.com/dgryski/go-farm v0.0.0-20240924180020-3414d57e47da h1:aIftn67I1fkbMa512G+w+Pxci9hJPB8oMnkcP3iZF38= +github.com/dgryski/go-farm v0.0.0-20240924180020-3414d57e47da/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= -github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= -github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= -github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= -github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/emicklei/dot v1.8.0 h1:HnD60yAKFAevNeT+TPYr9pb8VB9bqdeSo0nzwIW6IOI= +github.com/emicklei/dot v1.8.0/go.mod h1:DeV7GvQtIw4h2u73RKBkkFdvVAz0D9fzeJrgPW6gy/s= +github.com/ethereum/c-kzg-4844/v2 v2.1.1 h1:KhzBVjmURsfr1+S3k/VE35T02+AW2qU9t9gr4R6YpSo= +github.com/ethereum/c-kzg-4844/v2 v2.1.1/go.mod h1:TC48kOKjJKPbN7C++qIgt0TJzZ70QznYR7Ob+WXl57E= +github.com/ethereum/go-ethereum v1.16.2 h1:VDHqj86DaQiMpnMgc7l0rwZTg0FRmlz74yupSG5SnzI= +github.com/ethereum/go-ethereum v1.16.2/go.mod h1:X5CIOyo8SuK1Q5GnaEizQVLHT/DfsiGWuNeVdQcEMNA= +github.com/ethereum/go-verkle v0.2.2 h1:I2W0WjnrFUIzzVPwm8ykY+7pL2d4VhlsePn4j7cnFk8= +github.com/ethereum/go-verkle v0.2.2/go.mod h1:M3b90YRnzqKyyzBEWJGqj8Qff4IDeXnzFw0P9bFw3uk= +github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= +github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= +github.com/ferranbt/fastssz v0.1.4 h1:OCDB+dYDEQDvAgtAGnTSidK1Pe2tW3nFV40XyMkTeDY= +github.com/ferranbt/fastssz v0.1.4/go.mod h1:Ea3+oeoRGGLGm5shYAeDgu6PGUlcvQhE2fILyD9+tGg= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= -github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= -github.com/getsentry/sentry-go v0.22.0 h1:XNX9zKbv7baSEI65l+H1GEJgSeIC1c7EN5kluWaP6dM= -github.com/getsentry/sentry-go v0.22.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY= +github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= +github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= +github.com/getsentry/sentry-go v0.35.1 h1:iopow6UVLE2aXu46xKVIs8Z9D/YZkJrHkgozrxa+tOQ= +github.com/getsentry/sentry-go v0.35.1/go.mod h1:C55omcY9ChRQIUcVcGcs+Zdy4ZpQGvNJ7JYHIoSWOtE= github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= -github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= +github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= +github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= -github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw= -github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= +github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= +github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= -github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= -github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= +github.com/gofrs/flock v0.12.1 h1:MTLVXXHf8ekldpJk3AKicLij9MdwOWkZ+a/jHHZby9E= +github.com/gofrs/flock v0.12.1/go.mod h1:9zxTsyu5xtJ9DK+1tFZyibEV7y3uwDxPPfbxeeHCoD0= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/glog v1.1.1 h1:jxpi2eWoU84wbX9iIEyAeeoac3FLuifZpY9tcNUD9kw= -github.com/golang/glog v1.1.1/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb h1:PBC98N2aIaM3XXiurYmW7fx4GZkL8feAMVq7nEjURHk= -github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/google/flatbuffers v23.5.26+incompatible h1:M9dgRyhJemaM4Sw8+66GHBu8ioaQmyPLg1b8VwK5WJg= -github.com/google/flatbuffers v23.5.26+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs= +github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/flatbuffers v25.2.10+incompatible h1:F3vclr7C3HpB1k9mxCGRMXq6FdUalZ6H/pNX4FP1v0Q= +github.com/google/flatbuffers v25.2.10+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/gofuzz v1.2.1-0.20210524182514-9eed411d8615 h1:wYGmpV7xVK9thRotFJwvBAkm2xxCIaIUWZBwnXmNGL8= +github.com/google/gofuzz v1.2.1-0.20210524182514-9eed411d8615/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= -github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= -github.com/hashicorp/golang-lru/v2 v2.0.6-0.20230823180716-8f8764ff4ea3 h1:sHOTvKvKt5/WMmHevcxRUnbN0LCVlKVv0ZaNELm1/jc= -github.com/hashicorp/golang-lru/v2 v2.0.6-0.20230823180716-8f8764ff4ea3/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= -github.com/holiman/uint256 v1.2.3 h1:K8UWO1HUJpRMXBxbmaY1Y8IAMZC/RsKB+ArEnnK4l5o= -github.com/holiman/uint256 v1.2.3/go.mod h1:SC8Ryt4n+UBbPbIBKaG9zbbDlp4jOru9xFZmPzLUTxw= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= +github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= +github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= +github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao= +github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA= +github.com/holiman/uint256 v1.3.2 h1:a9EgMPSC1AAaj1SZL5zIQD3WbwTuHrMGOerLjGmM/TA= +github.com/holiman/uint256 v1.3.2/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I= -github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= +github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= +github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y= +github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= -github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= -github.com/nutsdb/nutsdb v0.13.2-0.20230824154404-d1808de99379 h1:f5IETeS9bOEObtfQPhIlLf1rDOnlY6+Na8Hyy5oLcOU= -github.com/nutsdb/nutsdb v0.13.2-0.20230824154404-d1808de99379/go.mod h1:6inOji9rFBporXeHDjJny4g50RpQbkjSK5jI1hht0j8= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/leanovate/gopter v0.2.11 h1:vRjThO1EKPb/1NsDXuDrzldR28RLkBflWYcU9CvzWu4= +github.com/leanovate/gopter v0.2.11/go.mod h1:aK3tzZP/C+p1m3SPRE4SYZFGP7jjkuSI4f7Xvpt0S9c= +github.com/lmittmann/w3 v0.20.2 h1:1IGdZOaRCa00xVcugFuj+xw177iGm+0eDk0h0gh79jI= +github.com/lmittmann/w3 v0.20.2/go.mod h1:iRHUwrimSYgRBSQ0QatEP7BUItCL3ahs0J4YXOI9IAI= +github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= +github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= +github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM= +github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/nutsdb/nutsdb v1.0.4 h1:BurzkxijXJY1/AkIXe1ek+U1ta3WGi6nJt4nCLqkxQ8= +github.com/nutsdb/nutsdb v1.0.4/go.mod h1:jIbbpBXajzTMZ0o33Yn5zoYIo3v0Dz4WstkVce+sYuQ= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/olekukonko/errors v1.1.0 h1:RNuGIh15QdDenh+hNvKrJkmxxjV4hcS50Db478Ou5sM= +github.com/olekukonko/errors v1.1.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y= +github.com/olekukonko/ll v0.0.8 h1:sbGZ1Fx4QxJXEqL/6IG8GEFnYojUSQ45dJVwN2FH2fc= +github.com/olekukonko/ll v0.0.8/go.mod h1:En+sEW0JNETl26+K8eZ6/W4UQ7CYSrrgg/EdIYT2H8g= +github.com/olekukonko/tablewriter v1.0.7 h1:HCC2e3MM+2g72M81ZcJU11uciw6z/p82aEnm4/ySDGw= +github.com/olekukonko/tablewriter v1.0.7/go.mod h1:H428M+HzoUXC6JU2Abj9IT9ooRmdq9CxuDmKMtrOCMs= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= @@ -144,108 +181,95 @@ github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3 github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= +github.com/onsi/gomega v1.19.0 h1:4ieX6qQjPP/BfC3mpsAtIGGlxTWPeA3Inl/7DtXw1tw= github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= -github.com/onsi/gomega v1.20.0 h1:8W0cWlwFkflGPLltQvLRB7ZVD5HuP6ng320w2IS245Q= github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= +github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8= -github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc= -github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY= -github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= -github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY= -github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY= -github.com/prometheus/procfs v0.11.0 h1:5EAgkfkMl659uZPbe9AS2N68a7Cc1TJbPEuGzFuRbyk= -github.com/prometheus/procfs v0.11.0/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM= +github.com/prometheus/client_golang v1.23.0 h1:ust4zpdl9r4trLY/gSjlm07PuiBq2ynaXXlptpfy8Uc= +github.com/prometheus/client_golang v1.23.0/go.mod h1:i/o0R9ByOnHX0McrTMTyhYvKE4haaf2mW08I+jGAjEE= +github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= +github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= +github.com/prometheus/common v0.65.0 h1:QDwzd+G1twt//Kwj/Ww6E9FQq1iVMmODnILtW1t2VzE= +github.com/prometheus/common v0.65.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8= +github.com/prometheus/procfs v0.17.0 h1:FuLQ+05u4ZI+SS/w9+BWEM2TXiHKsUQ9TADiRH7DuK0= +github.com/prometheus/procfs v0.17.0/go.mod h1:oPQLaDAMRbA+u8H5Pbfq+dl3VDAvHxMUOVhe0wYB2zw= +github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= +github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= -github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= -github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= -github.com/rosedblabs/go-immutable-radix/v2 v2.0.1-0.20230614125820-f2a7bc058c90 h1:AeuxZLgpVnxCjR6mvRJiDQATgOeSme59HX/rWCBjjvw= -github.com/rosedblabs/go-immutable-radix/v2 v2.0.1-0.20230614125820-f2a7bc058c90/go.mod h1:Hk7adp95/ngEfetvapVWdgneuZb15mi9nH/keSH/KqI= -github.com/rosedblabs/rosedb/v2 v2.2.2 h1:LtzL5fya57RZ5aRH+V+opUcB6G+yxs5Wk/t5Yt5+kas= -github.com/rosedblabs/rosedb/v2 v2.2.2/go.mod h1:O62E80aqxZC2L6P4yMiyYM3dzbCaFNT/LnOWKzmmVHk= -github.com/rosedblabs/wal v1.3.1 h1:QFAmnEPGJgUYfbn9WRO/43VkDdXVo9AacRcB0FfCNTI= -github.com/rosedblabs/wal v1.3.1/go.mod h1:tYh0WapCkDQrID7PNsNHpsZDlkTczJVAFaTySmwaD7U= +github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= +github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI= github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -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.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/supranational/blst v0.3.15 h1:rd9viN6tfARE5wv3KZJ9H8e1cg0jXW8syFCcsbHa76o= +github.com/supranational/blst v0.3.15/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d h1:vfofYNRScrDdvS342BElfbETmL1Aiz3i2t0zfRj16Hs= github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d/go.mod h1:RRCYJbIwD5jmqPI9XoAFR0OcDxqUctll6zUj/+B4S48= -github.com/tidwall/btree v1.6.0 h1:LDZfKfQIBHGHWSwckhXI0RPSXzlo+KYdjK7FWSqOzzg= -github.com/tidwall/btree v1.6.0/go.mod h1:twD9XRA5jj9VUQGELzDO4HPQTNJsoWWfYEL+EUQ2cKY= -github.com/tklauser/go-sysconf v0.3.11 h1:89WgdJhk5SNwJfu+GKyYveZ4IaJ7xAkecBo+KdJV0CM= -github.com/tklauser/go-sysconf v0.3.11/go.mod h1:GqXfhXY3kiPa0nAXPDIQIWzJbMCB7AmcWpGR8lSZfqI= -github.com/tklauser/numcpus v0.6.0/go.mod h1:FEZLMke0lhOUG6w2JadTzp0a+Nl8PF/GFkQ5UVIcaL4= -github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= -github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= +github.com/tidwall/btree v1.8.1 h1:27ehoXvm5AG/g+1VxLS1SD3vRhp/H7LuEfwNvddEdmA= +github.com/tidwall/btree v1.8.1/go.mod h1:jBbTdUWhSZClZWoDg54VnvV7/54modSOzDN7VXftj1A= +github.com/tklauser/go-sysconf v0.3.15 h1:VE89k0criAymJ/Os65CSn1IXaol+1wrsFHEB8Ol49K4= +github.com/tklauser/go-sysconf v0.3.15/go.mod h1:Dmjwr6tYFIseJw7a3dRLJfsHAMXZ3nEnL/aZY+0IuI4= +github.com/tklauser/numcpus v0.10.0 h1:18njr6LDBk1zuna922MgdjQuJFjrdppsZG60sHGfjso= +github.com/tklauser/numcpus v0.10.0/go.mod h1:BiTKazU708GQTYF4mB+cmlpT2Is1gLk7XVuEeem8LsQ= github.com/ucwong/go-ttlmap v1.0.2-0.20221020173635-331e7ddde2bb h1:dVZH3AH9f7zB3VBmsjn25B7lfcAyMP4QxdFYTrfj7tg= github.com/ucwong/go-ttlmap v1.0.2-0.20221020173635-331e7ddde2bb/go.mod h1:3yswsBsVuwsOjDvFfC5Na9XSEf4HC7mj3W3g6jvSY/s= -github.com/ucwong/golang-kv v1.0.23-0.20230827081935-0ebb6ae028c9 h1:7hAuCyafHw18lJ7X+oGR1+glU1gT8mYio9nsLuSdDGg= -github.com/ucwong/golang-kv v1.0.23-0.20230827081935-0ebb6ae028c9/go.mod h1:D9Q8lNtacTHgZmUzPWSl8eCRCH0k+woz2C0pwsdZoZ0= +github.com/ucwong/golang-kv v1.0.24-0.20250813143538-d7c3af16d0ff h1:5kxvQ+dCXHftLBIh9tixbb3+qNtfT0aWFvBT98Awh4w= +github.com/ucwong/golang-kv v1.0.24-0.20250813143538-d7c3af16d0ff/go.mod h1:xOaSX6r/Q9RHC3myStUvqPJKgkP8RjOzao267eOS4Mk= github.com/xujiajun/mmap-go v1.0.1 h1:7Se7ss1fLPPRW+ePgqGpCkfGIZzJV6JPq9Wq9iv/WHc= github.com/xujiajun/mmap-go v1.0.1/go.mod h1:CNN6Sw4SL69Sui00p0zEzcZKbt+5HtEnYUsc6BKKRMg= github.com/xujiajun/utils v0.0.0-20220904132955-5f7c5b914235 h1:w0si+uee0iAaCJO9q86T6yrhdadgcsoNuh47LrUykzg= github.com/xujiajun/utils v0.0.0-20220904132955-5f7c5b914235/go.mod h1:MR4+0R6A9NS5IABnIM3384FfOq8QFVnm7WDrBOhIaMU= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw= -github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= -go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ= -go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= -go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= -go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= +github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= +github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= +go.etcd.io/bbolt v1.4.2 h1:IrUHp260R8c+zYx/Tm8QZr04CX+qWS5PGfPdevhdm1I= +go.etcd.io/bbolt v1.4.2/go.mod h1:Is8rSHO/b4f3XigBC0lL0+4FwAQv3HXEEIgFMuKHceM= +go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= +go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= +go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ= +go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I= +go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE= +go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E= +go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4= +go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= 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= -golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA= -golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 h1:MGwJjxBy0HJshjDNfLsYO8xppfqWlA5ZT9OhtUUhTNw= -golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4= +golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc= +golang.org/x/exp v0.0.0-20250813145105-42675adae3e6 h1:SbTAbRFnd5kjQXbczszQ0hdk3ctwYf3qBNH9jIsGclE= +golang.org/x/exp v0.0.0-20250813145105-42675adae3e6/go.mod h1:4QTo5u+SEIbbKW1RacMZq1YEfOBqeXa19JeshGi+zc4= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50= -golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE= +golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= +golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181221143128-b4a75ba826a6/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -264,24 +288,20 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= -golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI= +golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4= -golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng= +golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU= +golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE= +golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= @@ -291,33 +311,20 @@ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= -google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= -google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.36.7 h1:IgrO7UwFQGJdRNXH/sQux4R1Dj1WAKcLElzeeRaXV2A= +google.golang.org/protobuf v1.36.7/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM= gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU= gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= @@ -325,9 +332,7 @@ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWD gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/metrics.go b/metrics.go new file mode 100644 index 0000000..7f2219f --- /dev/null +++ b/metrics.go @@ -0,0 +1,28 @@ +// Copyright 2023 The CortexTheseus Authors +// This file is part of the CortexTheseus library. +// +// The CortexTheseus library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The CortexTheseus library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the CortexTheseus library. If not, see . + +package robot + +import ( + "github.com/CortexFoundation/CortexTheseus/metrics" +) + +var ( + rpcBlockMeter = metrics.NewRegisteredMeter("torrent/block/call", nil) + rpcCurrentMeter = metrics.NewRegisteredMeter("torrent/current/call", nil) + rpcUploadMeter = metrics.NewRegisteredMeter("torrent/upload/call", nil) + rpcReceiptMeter = metrics.NewRegisteredMeter("torrent/receipt/call", nil) +) diff --git a/model_srv.go b/model_srv.go new file mode 100644 index 0000000..355edab --- /dev/null +++ b/model_srv.go @@ -0,0 +1,196 @@ +// Copyright 2023 The CortexTheseus Authors +// This file is part of the CortexTheseus library. +// +// The CortexTheseus library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The CortexTheseus library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the CortexTheseus library. If not, see . + +package robot + +import ( + "context" + "errors" + "time" + + "github.com/CortexFoundation/CortexTheseus/common" + "github.com/CortexFoundation/CortexTheseus/common/mclock" + "github.com/CortexFoundation/CortexTheseus/log" + "github.com/CortexFoundation/torrentfs/params" + "github.com/CortexFoundation/torrentfs/types" +) + +func (m *Monitor) parseFileMeta(tx *types.Transaction, meta *types.FileMeta, b *types.Block) error { + log.Debug("Parsing FileMeta", "infoHash", meta.InfoHash) + + // Step 1: Get transaction receipt + receipt, err := m.getReceipt(tx.Hash.String()) + if err != nil { + log.Error("Failed to get receipt", "txHash", tx.Hash.String(), "err", err) + return err + } + + // Step 2: Validate receipt + if receipt.ContractAddr == nil { + // More descriptive error message is better + err = errors.New("contract address is nil") + log.Warn("Contract address is nil, unable to proceed", "txHash", tx.Hash.String()) + return err + } + + if receipt.Status != 1 { + log.Warn("Transaction receipt status is not successful", "txHash", tx.Hash.String(), "status", receipt.Status) + return nil // Return nil for unsuccessful transactions as it's a valid state + } + + log.Debug("Transaction receipt OK", "address", receipt.ContractAddr.String(), "gas", receipt.GasUsed) + + // Step 3: Create and add file information + info := m.fs.NewFileInfo(meta) + info.LeftSize = meta.RawSize + info.ContractAddr = receipt.ContractAddr + info.Relate = append(info.Relate, *info.ContractAddr) + + op, update, err := m.fs.AddFile(info) + if err != nil { + log.Warn("Failed to add file to filesystem", "infoHash", meta.InfoHash, "err", err) + return err + } + + // Step 4: Handle file download if it's a new file + if update && op == 1 { + log.Debug("New file created, initiating download", "infoHash", meta.InfoHash) + + sizeLimit := uint64(0) + if m.mode == params.FULL { + sizeLimit = 512 * 1024 // Set a specific size limit for full mode + } + + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + + return m.download(ctx, meta.InfoHash, sizeLimit) + } + + return nil +} + +func (m *Monitor) parseBlockTorrentInfo(b *types.Block) (bool, error) { + start := mclock.Now() + var ( + record bool + final []types.Transaction + ) + + for _, tx := range b.Txs { + // Attempt to parse transaction for file metadata + if meta := tx.Parse(); meta != nil { + log.Debug("Data encounter", "infoHash", meta.InfoHash, "blockNumber", b.Number) + if err := m.parseFileMeta(&tx, meta, b); err != nil { + log.Error("Parse file meta failed", "error", err, "blockNumber", b.Number, "txHash", tx.Hash) + return false, err + } + record = true + final = append(final, tx) + continue + } + + // Handle flow control transactions + if tx.IsFlowControl() { + // Use guard clauses to reduce nesting + if tx.Recipient == nil { + continue + } + + file := m.fs.GetFileByAddr(*tx.Recipient) + if file == nil { + continue + } + + receipt, err := m.getReceipt(tx.Hash.String()) + if err != nil { + log.Error("Failed to get receipt for flow control tx", "error", err, "txHash", tx.Hash) + return false, err + } + + if receipt.Status != 1 || receipt.GasUsed != params.UploadGas { + continue + } + + // All checks passed, process the flow control transaction + remainingSize, err := m.getRemainingSize((*tx.Recipient).String()) + if err != nil { + log.Error("Get remaining size failed", "error", err, "addr", (*tx.Recipient).String()) + return false, err + } + + if file.LeftSize > remainingSize { + file.LeftSize = remainingSize + _, progress, err := m.fs.AddFile(file) + if err != nil { + return false, err + } + + if progress { + bytesRequested := uint64(0) + if file.Meta.RawSize > file.LeftSize { + bytesRequested = file.Meta.RawSize - file.LeftSize + } + + logMsg := "Data processing..." + if file.LeftSize == 0 { + logMsg = "Data processing completed!" + } + + log.Debug(logMsg, + "infoHash", file.Meta.InfoHash, + "addr", (*tx.Recipient).String(), + "remain", common.StorageSize(remainingSize), + "request", common.StorageSize(bytesRequested), + "raw", common.StorageSize(file.Meta.RawSize), + "blockNumber", b.Number) + + ctx, cancel := context.WithTimeout(context.Background(), timeout) + if err := m.download(ctx, file.Meta.InfoHash, bytesRequested); err != nil { + cancel() // Ensure cancel is called on error + return false, err + } + cancel() // Call cancel when download is successful + } + } + record = true + final = append(final, tx) + } + } + + // Update block transactions if necessary + if len(final) > 0 && len(final) < len(b.Txs) { + log.Debug("Txs filtered", "total", len(b.Txs), "final", len(final), "blockNumber", b.Number) + b.Txs = final + } + + // Add block to filesystem if any relevant transactions were found + if record { + if err := m.fs.AddBlock(b); err != nil { + log.Warn("Block added failed", "blockNumber", b.Number, "blockHash", b.Hash, "root", m.fs.Root(), "error", err) + return false, err // Return the error if adding the block fails + } + log.Debug("Block added to filesystem", "blockNumber", b.Number, "blockHash", b.Hash, "root", m.fs.Root()) + } + + // Log transaction scanning time + if len(b.Txs) > 0 { + elapsed := time.Duration(mclock.Now()) - time.Duration(start) + log.Trace("Transaction scanning complete", "count", len(b.Txs), "blockNumber", b.Number, "elapsed", common.PrettyDuration(elapsed)) + } + + return record, nil +} diff --git a/monitor.go b/monitor.go index ddee68a..efb5622 100644 --- a/monitor.go +++ b/monitor.go @@ -18,42 +18,27 @@ package robot import ( "context" - "encoding/json" "errors" + "math" + //"sort" + "fmt" + "path/filepath" + "runtime" + "sync" + "sync/atomic" + "time" + "github.com/CortexFoundation/CortexTheseus/common" - "github.com/CortexFoundation/CortexTheseus/common/hexutil" "github.com/CortexFoundation/CortexTheseus/common/mclock" "github.com/CortexFoundation/CortexTheseus/log" - "github.com/CortexFoundation/CortexTheseus/metrics" - params1 "github.com/CortexFoundation/CortexTheseus/params" "github.com/CortexFoundation/CortexTheseus/rpc" - "github.com/CortexFoundation/robot/backend" "github.com/CortexFoundation/torrentfs/params" "github.com/CortexFoundation/torrentfs/types" lru "github.com/hashicorp/golang-lru/v2" ttl "github.com/hashicorp/golang-lru/v2/expirable" "github.com/ucwong/golang-kv" - "math" - "math/big" - "path/filepath" - "runtime" - "strconv" - "sync" - "sync/atomic" - "time" -) -const ( - batch = 4096 * 2 //params.SyncBatch - delay = 12 //params.Delay - timeout = 30 * time.Second -) - -var ( - rpcBlockMeter = metrics.NewRegisteredMeter("torrent/block/call", nil) - rpcCurrentMeter = metrics.NewRegisteredMeter("torrent/current/call", nil) - rpcUploadMeter = metrics.NewRegisteredMeter("torrent/upload/call", nil) - rpcReceiptMeter = metrics.NewRegisteredMeter("torrent/receipt/call", nil) + "github.com/CortexFoundation/robot/backend" ) // Monitor observes the data changes on the blockchain and synchronizes. @@ -127,7 +112,7 @@ func New(flag *params.Config, cache, compress, listen bool, callback chan any) ( exitCh: make(chan any), srvCh: make(chan int), //exitSyncCh: make(chan any), - scope: uint64(math.Max(float64(runtime.NumCPU()*2), float64(4))), + scope: uint64(math.Max(float64(runtime.NumCPU()*2), float64(8))), //taskCh: make(chan *types.Block, batch), //taskCh: make(chan *types.Block, 1), //start: mclock.Now(), @@ -141,6 +126,9 @@ func New(flag *params.Config, cache, compress, listen bool, callback chan any) ( } else { m.fs = fs_ } + + m.fs.Init() + m.lastNumber.Store(0) m.currentNumber.Store(0) m.startNumber.Store(0) @@ -196,7 +184,7 @@ func (m *Monitor) Callback() chan any { return m.callback } -func (m *Monitor) loadHistory() error { +/*func (m *Monitor) loadHistory() error { torrents, _ := m.fs.InitTorrents() if m.mode != params.LAZY { for k, v := range torrents { @@ -214,7 +202,7 @@ func (m *Monitor) loadHistory() error { } return nil -} +}*/ func (m *Monitor) download(ctx context.Context, k string, v uint64) error { if m.mode != params.LAZY && m.callback != nil { @@ -327,264 +315,94 @@ func (m *Monitor) taskLoop() { } } -// SetConnection method builds connection to remote or local communicator. -func (m *Monitor) buildConnection(ipcpath string, rpcuri string) (*rpc.Client, error) { - log.Debug("Building connection", "terminated", m.terminated.Load()) - - if len(ipcpath) > 0 { - for i := 0; i < 30; i++ { - time.Sleep(time.Second * params.QueryTimeInterval * 2) - cl, err := rpc.Dial(ipcpath) - if err != nil { - log.Warn("Building internal ipc connection ... ", "ipc", ipcpath, "rpc", rpcuri, "error", err, "terminated", m.terminated.Load()) - } else { - m.local = true - log.Info("Internal ipc connection established", "ipc", ipcpath, "rpc", rpcuri, "local", m.local) - return cl, nil - } - - if m.terminated.Load() { - log.Info("Connection builder break") - return nil, errors.New("ipc connection terminated") - } +/*func (m *Monitor) exit() { + m.closeOnce.Do(func() { + if m.exitCh != nil { + close(m.exitCh) + m.wg.Wait() + m.exitCh = nil + } else { + log.Warn("Listener has already been stopped") } - } else { - log.Warn("IPC is empty, try remote RPC instead") - } - - cl, err := rpc.Dial(rpcuri) - if err != nil { - log.Warn("Building internal rpc connection ... ", "ipc", ipcpath, "rpc", rpcuri, "error", err, "terminated", m.terminated.Load()) - } else { - log.Info("Internal rpc connection established", "ipc", ipcpath, "rpc", rpcuri, "local", m.local) - return cl, nil - } - - return nil, errors.New("building internal ipc connection failed") -} - -func (m *Monitor) rpcBlockByNumber(blockNumber uint64) (*types.Block, error) { - block := &types.Block{} - - rpcBlockMeter.Mark(1) - err := m.cl.Call(block, "ctxc_getBlockByNumber", "0x"+strconv.FormatUint(blockNumber, 16), true) - if err == nil { - return block, nil - } - - return nil, err //errors.New("[ Internal IPC Error ] try to get block out of times") -} - -func (m *Monitor) rpcBatchBlockByNumber(from, to uint64) (result []*types.Block, err error) { - batch := to - from - result = make([]*types.Block, batch) - var e error = nil - for i := 0; i < int(batch); i++ { - m.rpcWg.Add(1) - go func(index int) { - defer m.rpcWg.Done() - result[index], e = m.rpcBlockByNumber(from + uint64(index)) - if e != nil { - err = e - } - }(i) - } - - m.rpcWg.Wait() - - return -} - -func (m *Monitor) getRemainingSize(address string) (uint64, error) { - if size, suc := m.sizeCache.Get(address); suc && size == 0 { - return size, nil - } - var remainingSize hexutil.Uint64 - rpcUploadMeter.Mark(1) - if err := m.cl.Call(&remainingSize, "ctxc_getUpload", address, "latest"); err != nil { - return 0, err - } - remain := uint64(remainingSize) - if remain == 0 { - m.sizeCache.Add(address, remain) - } - return remain, nil -} - -func (m *Monitor) getReceipt(tx string) (receipt types.Receipt, err error) { - rpcReceiptMeter.Mark(1) - if err = m.cl.Call(&receipt, "ctxc_getTransactionReceipt", tx); err != nil { - log.Warn("R is nil", "R", tx, "err", err) - } - - return + }) } -func (m *Monitor) parseFileMeta(tx *types.Transaction, meta *types.FileMeta, b *types.Block) error { - log.Debug("Monitor", "FileMeta", meta) - - receipt, err := m.getReceipt(tx.Hash.String()) - if err != nil { - return err - } - - if receipt.ContractAddr == nil { - log.Warn("contract address is nil, waiting for indexing", "tx.Hash.String()", tx.Hash.String()) - return errors.New("contract address is nil") - } - - log.Debug("Transaction Receipt", "address", receipt.ContractAddr.String(), "gas", receipt.GasUsed, "status", receipt.Status) //, "tx", receipt.TxHash.String()) - - if receipt.Status != 1 { - log.Warn("receipt.Status is wrong", "receipt.Status", receipt.Status) +func (m *Monitor) Stop() error { + m.lock.Lock() + defer m.lock.Unlock() + if m.terminated.Swap(true) { return nil } - log.Debug("Meta data", "meta", meta) - - info := m.fs.NewFileInfo(meta) + m.exit() + log.Info("Monitor is waiting to be closed") + m.blockCache.Purge() + m.sizeCache.Purge() - info.LeftSize = meta.RawSize - info.ContractAddr = receipt.ContractAddr - info.Relate = append(info.Relate, *info.ContractAddr) - op, update, err := m.fs.AddFile(info) - if err != nil { - log.Warn("Create file failed", "err", err) - return err - } - if update && op == 1 { - log.Debug("Create new file", "ih", meta.InfoHash, "op", op) + //log.Info("Fs client listener synchronizing closing") + //if err := m.dl.Close(); err != nil { + // log.Error("Monitor Fs Manager closed", "error", err) + //} - ctx, cancel := context.WithTimeout(context.Background(), timeout) - defer cancel() - if m.mode == params.FULL { - return m.download(ctx, meta.InfoHash, 512*1024) - } else { - return m.download(ctx, meta.InfoHash, 0) + // TODO dirty statics deal with + if m.engine != nil { + log.Info("Golang-kv engine close", "engine", m.engine.Name()) + if err := m.engine.Close(); err != nil { + return err } } - return nil -} -func (m *Monitor) parseBlockTorrentInfo(b *types.Block) (bool, error) { - var ( - record bool - start = mclock.Now() - final []types.Transaction - ) - for _, tx := range b.Txs { - if meta := tx.Parse(); meta != nil { - log.Debug("Data encounter", "ih", meta.InfoHash, "number", b.Number, "meta", meta) - if err := m.parseFileMeta(&tx, meta, b); err != nil { - log.Error("Parse file meta error", "err", err, "number", b.Number) - return false, err - } - record = true - final = append(final, tx) - } else if tx.IsFlowControl() { - if tx.Recipient == nil { - continue - } - file := m.fs.GetFileByAddr(*tx.Recipient) - if file == nil { - continue - } - receipt, err := m.getReceipt(tx.Hash.String()) - if err != nil { - return false, err - } - if receipt.Status != 1 || receipt.GasUsed != params.UploadGas { - continue - } - remainingSize, err := m.getRemainingSize((*tx.Recipient).String()) - if err != nil { - log.Error("Get remain failed", "err", err, "addr", (*tx.Recipient).String()) - return false, err - } - if file.LeftSize > remainingSize { - file.LeftSize = remainingSize - if _, progress, err := m.fs.AddFile(file); err != nil { - return false, err - } else if progress { // && progress { - log.Debug("Update storage success", "ih", file.Meta.InfoHash, "left", file.LeftSize) - var bytesRequested uint64 - if file.Meta.RawSize > file.LeftSize { - bytesRequested = file.Meta.RawSize - file.LeftSize - } - if file.LeftSize == 0 { - log.Debug("Data processing completed !!!", "ih", file.Meta.InfoHash, "addr", (*tx.Recipient).String(), "remain", common.StorageSize(remainingSize), "request", common.StorageSize(bytesRequested), "raw", common.StorageSize(file.Meta.RawSize), "number", b.Number) - } else { - log.Debug("Data processing ...", "ih", file.Meta.InfoHash, "addr", (*tx.Recipient).String(), "remain", common.StorageSize(remainingSize), "request", common.StorageSize(bytesRequested), "raw", common.StorageSize(file.Meta.RawSize), "number", b.Number) - } - ctx, cancel := context.WithTimeout(context.Background(), timeout) - defer cancel() - if err := m.download(ctx, file.Meta.InfoHash, bytesRequested); err != nil { - return false, err - } - } - } - record = true - final = append(final, tx) - } - } - if len(final) > 0 && len(final) < len(b.Txs) { - log.Debug("Final txs layout", "total", len(b.Txs), "final", len(final), "num", b.Number, "txs", m.fs.Txs()) - b.Txs = final - } - if record { - if err := m.fs.AddBlock(b); err == nil { - log.Info("Root has been changed", "number", b.Number, "hash", b.Hash, "root", m.fs.Root()) - } else { - log.Warn("Block added failed", "number", b.Number, "hash", b.Hash, "root", m.fs.Root(), "err", err) - } - } - if len(b.Txs) > 0 { - elapsed := time.Duration(mclock.Now()) - time.Duration(start) - log.Trace("Transactions scanning", "count", len(b.Txs), "number", b.Number, "elapsed", common.PrettyDuration(elapsed)) + if err := m.fs.Close(); err != nil { + log.Error("Monitor File Storage closed", "error", err) + return err } - return record, nil -} + log.Info("Fs listener synchronizing closed") + return nil +}*/ func (m *Monitor) exit() { m.closeOnce.Do(func() { if m.exitCh != nil { close(m.exitCh) m.wg.Wait() - m.exitCh = nil } else { - log.Warn("Listener has already been stopped") + log.Debug("Listener exit channel already closed") } }) } func (m *Monitor) Stop() error { m.lock.Lock() - defer m.lock.Unlock() if m.terminated.Swap(true) { + m.lock.Unlock() return nil } + m.lock.Unlock() m.exit() log.Info("Monitor is waiting to be closed") + + var errs []error + m.blockCache.Purge() m.sizeCache.Purge() - //log.Info("Fs client listener synchronizing closing") - //if err := m.dl.Close(); err != nil { - // log.Error("Monitor Fs Manager closed", "error", err) - //} - - // TODO dirty statics deal with if m.engine != nil { - log.Info("Golang-kv engine close", "engine", m.engine.Name()) - return m.engine.Close() + log.Info("Closing Golang-kv engine", "engine", m.engine.Name()) + if err := m.engine.Close(); err != nil { + errs = append(errs, fmt.Errorf("engine close: %w", err)) + } } if err := m.fs.Close(); err != nil { - log.Error("Monitor File Storage closed", "error", err) - return err + errs = append(errs, fmt.Errorf("fs close: %w", err)) } + log.Info("Fs listener synchronizing closed") + + if len(errs) > 0 { + return errors.Join(errs...) + } return nil } @@ -599,7 +417,7 @@ func (m *Monitor) Start() error { m.wg.Add(1) go func() { defer m.wg.Done() - m.fs.Init() + //m.fs.Init() if err := m.run(); err != nil { log.Error("Fs monitor start failed", "err", err) } @@ -676,357 +494,203 @@ func (m *Monitor) syncLatestBlock() { defer m.wg.Done() timer := time.NewTimer(time.Second * params.QueryTimeInterval) defer timer.Stop() - progress, counter, end := uint64(0), 0, false + + counter := 0 + + // Helper function to determine the next delay based on sync progress + getNextDelay := func(progress uint64) time.Duration { + if progress >= delay { + return 0 // Trigger immediately + } + if progress > 1 { + return time.Millisecond * 2000 + } + if progress == 1 { + return time.Millisecond * 6750 + } + + // If progress is 0, check for listener and checkpoint status + if !m.listen && ((m.ckp != nil && m.currentNumber.Load() >= m.ckp.TfsCheckPoint) || (m.ckp == nil && m.currentNumber.Load() > 0)) { + // This part seems to have a specific termination or pause logic + // The original code has some commented-out `return`, so I'm assuming it's a "steady state" delay. + return time.Millisecond * 6750 + } + + return time.Millisecond * 6750 // Default case for other conditions + } + for { select { case sv := <-m.srvCh: if err := m.doSwitch(sv); err != nil { log.Error("Service switch failed", "srv", sv, "err", err) } + case <-timer.C: - progress = m.syncLastBlock() - // Avoid sync in full mode, fresh interval may be less. - if progress >= delay { - end = false - timer.Reset(time.Millisecond * 0) - } else if progress > 1 { - end = false - timer.Reset(time.Millisecond * 2000) - } else if progress == 1 { - end = true - timer.Reset(time.Millisecond * 6750) - } else { - if !m.listen { - if (m.ckp != nil && m.currentNumber.Load() >= m.ckp.TfsCheckPoint) || (m.ckp == nil && m.currentNumber.Load() > 0) { - if !end { - end = true - timer.Reset(time.Millisecond * 6750) - continue - } - m.fs.Flush() - //elapsed := time.Duration(mclock.Now()) - time.Duration(m.start) - //log.Debug("Finish sync, listener will be paused", "current", m.currentNumber.Load(), "elapsed", common.PrettyDuration(elapsed), "progress", progress, "end", end, "last", m.lastNumber.Load()) - //return - timer.Reset(time.Millisecond * 6750) - end = false - continue - } - } - timer.Reset(time.Millisecond * 6750) - } - counter++ - if counter%100 == 0 { - log.Info("Monitor status", "blocks", progress, "current", m.CurrentNumber(), "latest", m.lastNumber.Load(), "end", end, "txs", m.fs.Txs(), "ckp", m.fs.CheckPoint(), "last", m.fs.LastListenBlockNumber()) + progress := m.syncLastBlock() + + // Determine the next delay and reset the timer + nextDelay := getNextDelay(progress) + timer.Reset(nextDelay) + + // Log status periodically + counter += int(progress) + if counter > 65536 { + log.Info("Monitor status", "blocks", progress, "current", m.CurrentNumber(), "latest", m.lastNumber.Load(), "txs", m.fs.Txs(), "ckp", m.fs.CheckPoint(), "last", m.fs.LastListenBlockNumber(), "progress", progress, "root", m.fs.Root()) counter = 0 } - m.fs.Flush() + // Always flush at the end of a timer cycle + //m.fs.Anchor(m.lastNumber.Load()) + //m.fs.Flush() + case <-m.exitCh: - log.Info("Block syncer stopped") return } } } -func (m *Monitor) currentBlock() (uint64, bool, error) { - var ( - currentNumber hexutil.Uint64 - update bool - ) - - rpcCurrentMeter.Mark(1) - if err := m.cl.Call(¤tNumber, "ctxc_blockNumber"); err != nil { - log.Error("Call ipc method ctxc_blockNumber failed", "error", err) - return m.currentNumber.Load(), false, err - } - if m.currentNumber.Load() != uint64(currentNumber) { - m.currentNumber.Store(uint64(currentNumber)) - update = true - } - - return uint64(currentNumber), update, nil -} - -func (m *Monitor) skip(i uint64) bool { +func (m *Monitor) skip(num uint64) (bool, uint64) { if m.srv.Load() != SRV_MODEL { - return false + return false, 0 } - if len(m.ckp.Skips) == 0 || i > m.ckp.Skips[len(m.ckp.Skips)-1].To || i < m.ckp.Skips[0].From { - return false + if len(m.ckp.Skips) == 0 || num > m.ckp.Skips[len(m.ckp.Skips)-1].To || num < m.ckp.Skips[0].From { + return false, 0 } for _, skip := range m.ckp.Skips { - if i > skip.From && i < skip.To { - //m.lastNumber = i - 1 - return true + if num > skip.From && num < skip.To { + return true, skip.To } } - return false + return false, 0 } func (m *Monitor) syncLastBlock() uint64 { - /*currentNumber, err := m.currentBlock() - if err != nil { - return 0 - }*/ - currentNumber := m.currentNumber.Load() + lastNumber := m.lastNumber.Load() - if currentNumber < m.lastNumber.Load() { - log.Warn("Fs sync rollback", "current", currentNumber, "last", m.lastNumber.Load(), "offset", m.lastNumber.Load()-currentNumber) + // Step 1: Handle rollback logic if current block number is less than the last processed number. + if currentNumber < lastNumber { + log.Warn("Fs sync rollback detected", "current", currentNumber, "last", lastNumber, "offset", lastNumber-currentNumber) + rollbackNumber := uint64(0) if currentNumber > 65536 { - m.lastNumber.Store(currentNumber - 65536) - } else { - m.lastNumber.Store(0) + rollbackNumber = currentNumber - 65536 } - m.startNumber.Store(m.lastNumber.Load()) + m.lastNumber.Store(rollbackNumber) + m.startNumber.Store(rollbackNumber) } + // Step 2: Determine the block range for this sync batch. minNumber := m.lastNumber.Load() + 1 - maxNumber := uint64(0) + maxNumber := currentNumber if currentNumber > delay { maxNumber = currentNumber - delay - //maxNumber = currentNumber } + // If the last processed block is unexpectedly higher than the current block (after rollback check), + // this indicates a need to sync backward from the last number. if m.lastNumber.Load() > currentNumber { - if m.lastNumber.Load() > batch { - minNumber = m.lastNumber.Load() - batch + minNumber = m.lastNumber.Load() - batch + if m.lastNumber.Load() < batch { + minNumber = 0 // Avoids underflow if lastNumber is smaller than batch } } - if maxNumber > batch+minNumber { + // Adjust maxNumber to not exceed the batch size. + if maxNumber > minNumber+batch { maxNumber = minNumber + batch } - // replay - if minNumber >= delay { - //minNumber = minNumber - delay - } - if maxNumber < minNumber { return 0 } - //if m.start == 0 { m.start = mclock.Now() - //} - counter := 0 - for i := minNumber; i <= maxNumber; { // i++ { + processedCount := 0 + for i := minNumber; i <= maxNumber; { if m.terminated.Load() { - log.Warn("Fs scan terminated", "number", i) + log.Warn("Fs scan terminated by signal", "lastProcessed", i-1) m.lastNumber.Store(i - 1) return 0 } - //if maxNumber > minNumber && i%2048 == 0 { - // log.Info("Running", "min", minNumber, "max", maxNumber, "cur", currentNumber, "last", m.lastNumber.Load(), "batch", batch, "i", i, "srv", m.srv.Load(), "count", maxNumber-minNumber, "progress", float64(i)/float64(currentNumber)) - //} - if m.ckp != nil && m.skip(i) { - i++ - continue + + if m.ckp != nil { + if skip, to := m.skip(i); skip { + i = to + continue + } } - if maxNumber-i >= m.scope { - blocks, rpcErr := m.rpcBatchBlockByNumber(i, i+m.scope) - if rpcErr != nil { - log.Error("Sync old block failed", "number", i, "error", rpcErr) - m.lastNumber.Store(i - 1) - return 0 + // Step 3: Fetch blocks in a batch or individually based on remaining scope. + remainingScope := maxNumber - i + if remainingScope >= m.scope { + // Process a batch of blocks + blocks, err := m.rpcBatchBlockByNumber(i, i+m.scope) + if err != nil { + return m.handleSyncError("Batch sync old block failed", err, i-1) } - // batch blocks operation according service category - for _, rpcBlock := range blocks { - m.taskCh <- rpcBlock + // Send blocks to the processing channel + for _, block := range blocks { + m.taskCh <- block } - for n := 0; n < len(blocks); n++ { + // Wait for the processing results for the entire batch + for range blocks { select { case err := <-m.errCh: if err != nil { - m.lastNumber.Store(i - 1) - log.Error("solve err", "err", err, "last", m.lastNumber.Load(), "i", i, "scope", m.scope, "min", minNumber, "max", maxNumber, "cur", currentNumber) - return 0 + return m.handleSyncError("Processing error", err, i-1) } case <-m.exitCh: + log.Info("Task checker quit signal received") m.lastNumber.Store(i - 1) - log.Info("Task checker quit") return 0 } } + i += uint64(len(blocks)) - counter += len(blocks) + processedCount += len(blocks) } else { - rpcBlock, rpcErr := m.rpcBlockByNumber(i) - if rpcErr != nil { - log.Error("Sync old block failed", "number", i, "error", rpcErr) - m.lastNumber.Store(i - 1) - return 0 - } - if err := m.solve(rpcBlock); err != nil { - log.Error("solve err", "err", err) - m.lastNumber.Store(i - 1) - return 0 - } - i++ - counter++ - } - } - //log.Debug("Last number changed", "min", minNumber, "max", maxNumber, "cur", currentNumber, "last", m.lastNumber.Load(), "batch", batch) - m.lastNumber.Store(maxNumber) - elapsedA := time.Duration(mclock.Now()) - time.Duration(m.start) - log.Debug("Chain segment frozen", "from", minNumber, "to", maxNumber, "range", uint64(maxNumber-minNumber+1), "counter", counter, "scope", m.scope, "current", m.CurrentNumber(), "prog", float64(maxNumber)/float64(m.CurrentNumber()), "last", m.lastNumber.Load(), "bps", float64(counter)*1000*1000*1000/float64(elapsedA), "elapsed", common.PrettyDuration(elapsedA)) - return uint64(maxNumber - minNumber) -} - -// solve block from node -func (m *Monitor) solve(block *types.Block) error { - switch m.srv.Load() { - case SRV_MODEL: - return m.forModelService(block) - //case 1: - // return m.forExplorerService(block) // others service, explorer, exchange, zkp, nft, etc. - //case 2: - // return m.forExchangeService(block) - case SRV_RECORD: - return m.forRecordService(block) - default: - return errors.New("no block operation service found") - } -} - -func (m *Monitor) SwitchService(srv int) error { - log.Debug("Srv switch start", "srv", srv, "ch", cap(m.srvCh)) - select { - case m.srvCh <- srv: - case <-m.exitCh: - return nil - } - log.Debug("Srv switch end", "srv", srv, "ch", cap(m.srvCh)) - return nil -} - -func (m *Monitor) doSwitch(srv int) error { - if m.srv.Load() != int32(srv) { - switch m.srv.Load() { - case SRV_MODEL: - if m.lastNumber.Load() > 0 { - m.fs.Anchor(m.lastNumber.Load()) - m.fs.Flush() - log.Debug("Model srv flush", "last", m.lastNumber.Load()) - } - case SRV_RECORD: - if m.lastNumber.Load() > 0 { - log.Debug("Record srv flush", "last", m.lastNumber.Load()) - m.engine.Set([]byte("srv_record_last"), []byte(strconv.FormatUint(m.lastNumber.Load(), 16))) + // Process a single block + block, err := m.rpcBlockByNumber(i) + if err != nil { + return m.handleSyncError("Sync old block failed", err, i-1) } - default: - return errors.New("Invalid current service") - } - switch srv { - case SRV_MODEL: - m.fs.InitBlockNumber() - m.lastNumber.Store(m.fs.LastListenBlockNumber()) - log.Debug("Model srv load", "last", m.lastNumber.Load()) - case SRV_RECORD: - if v := m.engine.Get([]byte("srv_record_last")); v != nil { - if number, err := strconv.ParseUint(string(v), 16, 64); err == nil { - m.lastNumber.Store(number) - } else { - m.lastNumber.Store(0) - } - } else { - m.lastNumber.Store(0) + if err := m.solve(block); err != nil { + return m.handleSyncError("solve err", err, i-1) } - log.Debug("Record srv load", "last", m.lastNumber.Load()) - default: - return errors.New("Unknow service") - } - m.srv.Store(int32(srv)) - log.Info("Service switch", "srv", m.srv.Load(), "last", m.lastNumber.Load()) - } - return nil -} - -func (m *Monitor) storeLastNumber(last uint64) { - log.Info("Last number changed", "last", last) - m.lastNumber.Store(last) -} - -// only for examples -func (m *Monitor) forExplorerService(block *types.Block) error { - return errors.New("not support") -} - -func (m *Monitor) forExchangeService(block *types.Block) error { - return errors.New("not support") -} - -func (m *Monitor) forRecordService(block *types.Block) error { - if block.Number%4096 == 0 { - log.Info("Block record", "num", block.Number, "hash", block.Hash, "txs", len(block.Txs), "last", m.lastNumber.Load()) - } - if len(block.Txs) > 0 { - for _, t := range block.Txs { - x := new(big.Float).Quo(new(big.Float).SetInt(t.Amount), new(big.Float).SetInt(big.NewInt(params1.Cortex))) - log.Debug("Tx record", "hash", t.Hash, "amount", x, "gas", t.GasLimit, "receipt", t.Recipient, "payload", t.Payload) - - if v, err := json.Marshal(t); err != nil { - return err - } else { - m.engine.Set(t.Hash.Bytes(), v) - } + i++ + processedCount++ } } - if v, err := json.Marshal(block); err != nil { - return err - } else { - m.engine.Set(block.Hash.Bytes(), v) - } + // Step 4: Finalize the sync operation. + m.lastNumber.Store(maxNumber) + elapsed := time.Duration(mclock.Now()) - time.Duration(m.start) + + log.Debug("Chain segment frozen", + "from", minNumber, + "to", maxNumber, + "totalBlocks", uint64(maxNumber-minNumber+1), + "processed", processedCount, + "scope", m.scope, + "current", m.CurrentNumber(), + "last", m.lastNumber.Load(), + "elapsed", common.PrettyDuration(elapsed), + "bps", float64(processedCount)/elapsed.Seconds(), + ) - m.engine.Set([]byte("srv_record_last"), []byte(strconv.FormatUint(block.Number, 16))) - return nil + return uint64(maxNumber - minNumber) } -func (m *Monitor) forModelService(block *types.Block) error { - i := block.Number - if i%65536 == 0 { - defer func() { - //elapsedA := time.Duration(mclock.Now()) - time.Duration(m.start) - //log.Info("Nas monitor", "start", m.startNumber.Load(), "max", uint64(m.CurrentNumber()), "last", m.lastNumber.Load(), "cur", i, "bps", math.Abs(float64(i)-float64(m.startNumber.Load()))*1000*1000*1000/float64(elapsedA), "elapsed", common.PrettyDuration(elapsedA), "scope", m.scope, "db", common.PrettyDuration(m.fs.Metrics()), "blocks", len(m.fs.Blocks()), "txs", m.fs.Txs(), "files", len(m.fs.Files()), "root", m.fs.Root()) - m.fs.SkipPrint() - }() - } - - if hash, suc := m.blockCache.Get(i); !suc || hash != block.Hash.Hex() { - if record, parseErr := m.parseBlockTorrentInfo(block); parseErr != nil { - log.Error("Parse new block", "number", block.Number, "block", block, "error", parseErr) - return parseErr - } else if record { - elapsed := time.Duration(mclock.Now()) - time.Duration(m.start) - - if m.ckp != nil && m.ckp.TfsCheckPoint > 0 && i == m.ckp.TfsCheckPoint { - if common.BytesToHash(m.fs.GetRoot(i)) == m.ckp.TfsRoot { - log.Warn("FIRST MILESTONE PASS", "number", i, "root", m.fs.Root(), "blocks", len(m.fs.Blocks()), "txs", m.fs.Txs(), "files", len(m.fs.Files()), "elapsed", common.PrettyDuration(elapsed)) - } else { - log.Error("Fs checkpoint failed", "number", i, "root", m.fs.Root(), "blocks", len(m.fs.Blocks()), "files", len(m.fs.Files()), "txs", m.fs.Txs(), "elapsed", common.PrettyDuration(elapsed), "exp", m.ckp.TfsRoot, "leaves", len(m.fs.Leaves())) - panic("FIRST MILESTONE ERROR, run './cortex removedb' command to solve this problem") - } - } - - log.Debug("Seal fs record", "number", i, "record", record, "root", m.fs.Root().Hex(), "blocks", len(m.fs.Blocks()), "txs", m.fs.Txs(), "files", len(m.fs.Files()), "ckp", m.fs.CheckPoint()) - } else { - if m.fs.LastListenBlockNumber() < i { - m.fs.Anchor(i) - } - - log.Trace("Confirm to seal the fs record", "number", i) - } - m.blockCache.Add(i, block.Hash.Hex()) - } - - return nil +// handleSyncError is a helper function to log an error, update the last processed block number, and return 0. +func (m *Monitor) handleSyncError(msg string, err error, lastBlock uint64) uint64 { + log.Error(msg, "error", err, "lastProcessed", lastBlock) + m.lastNumber.Store(lastBlock) + return 0 } diff --git a/rpc.go b/rpc.go new file mode 100644 index 0000000..bf480d1 --- /dev/null +++ b/rpc.go @@ -0,0 +1,230 @@ +// Copyright 2023 The CortexTheseus Authors +// This file is part of the CortexTheseus library. +// +// The CortexTheseus library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The CortexTheseus library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the CortexTheseus library. If not, see . + +package robot + +import ( + "context" + "errors" + "fmt" + //"strconv" + "time" + + "github.com/CortexFoundation/CortexTheseus/common/hexutil" + "github.com/CortexFoundation/CortexTheseus/log" + "github.com/CortexFoundation/CortexTheseus/rpc" + "github.com/CortexFoundation/torrentfs/params" + "github.com/CortexFoundation/torrentfs/types" +) + +// SetConnection method builds connection to remote or local communicator. +func (m *Monitor) buildConnection(ipcpath string, rpcuri string) (*rpc.Client, error) { + log.Debug("Building connection", "terminated", m.terminated.Load()) + + if len(ipcpath) > 0 { + for i := 0; i < 30; i++ { + time.Sleep(time.Second * params.QueryTimeInterval * 2) + cl, err := rpc.Dial(ipcpath) + if err != nil { + log.Warn("Building internal ipc connection ... ", "ipc", ipcpath, "rpc", rpcuri, "error", err, "terminated", m.terminated.Load()) + } else { + m.local = true + log.Info("Internal ipc connection established", "ipc", ipcpath, "rpc", rpcuri, "local", m.local) + return cl, nil + } + + if m.terminated.Load() { + log.Info("Connection builder break") + return nil, errors.New("ipc connection terminated") + } + } + } else { + log.Warn("IPC is empty, try remote RPC instead") + } + + cl, err := rpc.Dial(rpcuri) + if err != nil { + log.Warn("Building internal rpc connection ... ", "ipc", ipcpath, "rpc", rpcuri, "error", err, "terminated", m.terminated.Load()) + } else { + log.Info("Internal rpc connection established", "ipc", ipcpath, "rpc", rpcuri, "local", m.local) + return cl, nil + } + + return nil, errors.New("building internal ipc connection failed") +} + +func (m *Monitor) rpcBlockByNumber(blockNumber uint64) (*types.Block, error) { + block := &types.Block{} + + rpcBlockMeter.Mark(1) + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + err := m.cl.CallContext(ctx, block, "ctxc_getBlockByNumber", hexutil.EncodeUint64(blockNumber), true) + if err == nil { + return block, nil + } + + return nil, err //errors.New("[ Internal IPC Error ] try to get block out of times") +} + +/*func (m *Monitor) rpcBatchBlockByNumber(from, to uint64) ([]*types.Block, error) { + batch := to - from + result := make([]*types.Block, batch) + reqs := make([]rpc.BatchElem, batch) + for i := range reqs { + reqs[i] = rpc.BatchElem{ + Method: "ctxc_getBlockByNumber", + Args: []any{hexutil.EncodeUint64(from + uint64(i)), true}, + Result: &result[i], + } + } + + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + if err := m.cl.BatchCallContext(ctx, reqs); err != nil { + return nil, err + } + + for i, req := range reqs { + if req.Error != nil { + return nil, req.Error + } + if result[i] == nil { + return nil, fmt.Errorf("got null block %d", i) + } + } + + return result, nil +}*/ + +func (m *Monitor) rpcBatchBlockByNumber(from, to uint64) ([]*types.Block, error) { + if from >= to { + return nil, nil + } + + batch := to - from + result := make([]*types.Block, batch) + reqs := make([]rpc.BatchElem, batch) + + for i := uint64(0); i < batch; i++ { + blockNum := from + i + reqs[i] = rpc.BatchElem{ + Method: "ctxc_getBlockByNumber", + Args: []any{hexutil.EncodeUint64(blockNum), true}, + Result: &result[i], + } + } + + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + + if err := m.cl.BatchCallContext(ctx, reqs); err != nil { + return nil, fmt.Errorf("failed to make batch RPC call: %w", err) + } + + for i, req := range reqs { + if req.Error != nil { + return nil, fmt.Errorf("batch RPC call for block %d failed: %w", from+uint64(i), req.Error) + } + if result[i] == nil { + return nil, fmt.Errorf("batch RPC call returned nil for block %d", from+uint64(i)) + } + } + + return result, nil +} + +func (m *Monitor) rpcBatchBlockByNumberLegacy(from, to uint64) (result []*types.Block, err error) { + batch := to - from + result = make([]*types.Block, batch) + var e error = nil + for i := 0; i < int(batch); i++ { + m.rpcWg.Add(1) + go func(index int) { + defer m.rpcWg.Done() + //log.Info("bach rpc", "from", from, "to", to, "i", index) + result[index], e = m.rpcBlockByNumber(from + uint64(index)) + if e != nil { + err = e + } + }(i) + } + + m.rpcWg.Wait() + + return +} + +func (m *Monitor) getRemainingSize(address string) (uint64, error) { + if size, suc := m.sizeCache.Get(address); suc && size == 0 { + return size, nil + } + var remainingSize hexutil.Uint64 + rpcUploadMeter.Mark(1) + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + if err := m.cl.CallContext(ctx, &remainingSize, "ctxc_getUpload", address, "latest"); err != nil { + return 0, err + } + remain := uint64(remainingSize) + if remain == 0 { + m.sizeCache.Add(address, remain) + } + return remain, nil +} + +func (m *Monitor) getReceipt(tx string) (receipt types.Receipt, err error) { + rpcReceiptMeter.Mark(1) + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + if err = m.cl.CallContext(ctx, &receipt, "ctxc_getTransactionReceipt", tx); err != nil { + log.Warn("R is nil", "R", tx, "err", err) + } + + return +} + +func (m *Monitor) getBlockReceipts(hash string) (receipt []types.Receipt, err error) { + rpcReceiptMeter.Mark(1) + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + if err = m.cl.CallContext(ctx, &receipt, "ctxc_getBlockReceipts", hash); err != nil { + log.Warn("R array is nil", "R", hash, "err", err) + } + + return +} + +func (m *Monitor) currentBlock() (uint64, bool, error) { + var ( + currentNumber hexutil.Uint64 + update bool + ) + + rpcCurrentMeter.Mark(1) + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + if err := m.cl.CallContext(ctx, ¤tNumber, "ctxc_blockNumber"); err != nil { + log.Error("Call ipc method ctxc_blockNumber failed", "error", err) + return m.currentNumber.Load(), false, err + } + if m.currentNumber.Load() != uint64(currentNumber) { + m.currentNumber.Store(uint64(currentNumber)) + update = true + } + + return uint64(currentNumber), update, nil +} diff --git a/service.go b/service.go new file mode 100644 index 0000000..5938172 --- /dev/null +++ b/service.go @@ -0,0 +1,195 @@ +// Copyright 2023 The CortexTheseus Authors +// This file is part of the CortexTheseus library. +// +// The CortexTheseus library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The CortexTheseus library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the CortexTheseus library. If not, see . + +package robot + +import ( + "encoding/json" + "errors" + "math/big" + "strconv" + "time" + + "github.com/CortexFoundation/CortexTheseus/common" + "github.com/CortexFoundation/CortexTheseus/common/mclock" + "github.com/CortexFoundation/CortexTheseus/log" + params1 "github.com/CortexFoundation/CortexTheseus/params" + "github.com/CortexFoundation/torrentfs/types" +) + +// solve block from node +func (m *Monitor) solve(block *types.Block) error { + switch m.srv.Load() { + case SRV_MODEL: + return m.forModelService(block) + //case 1: + // return m.forExplorerService(block) // others service, explorer, exchange, zkp, nft, etc. + //case 2: + // return m.forExchangeService(block) + case SRV_RECORD: + return m.forRecordService(block) + default: + return errors.New("no block operation service found") + } +} + +func (m *Monitor) SwitchService(srv int) error { + log.Debug("Srv switch start", "srv", srv, "ch", cap(m.srvCh)) + select { + case m.srvCh <- srv: + case <-m.exitCh: + return nil + } + log.Debug("Srv switch end", "srv", srv, "ch", cap(m.srvCh)) + return nil +} + +func (m *Monitor) doSwitch(srv int) error { + if m.srv.Load() != int32(srv) { + switch m.srv.Load() { + case SRV_MODEL: + if m.lastNumber.Load() > 0 { + m.fs.Anchor(m.lastNumber.Load()) + m.fs.Flush() + log.Debug("Model srv flush", "last", m.lastNumber.Load()) + } + case SRV_RECORD: + if m.lastNumber.Load() > 0 { + log.Debug("Record srv flush", "last", m.lastNumber.Load()) + m.engine.Set([]byte("srv_record_last"), []byte(strconv.FormatUint(m.lastNumber.Load(), 16))) + } + default: + return errors.New("Invalid current service") + } + + switch srv { + case SRV_MODEL: + m.fs.InitBlockNumber() + m.lastNumber.Store(m.fs.LastListenBlockNumber()) + log.Debug("Model srv load", "last", m.lastNumber.Load()) + case SRV_RECORD: + if v := m.engine.Get([]byte("srv_record_last")); v != nil { + if number, err := strconv.ParseUint(string(v), 16, 64); err == nil { + m.lastNumber.Store(number) + } else { + m.lastNumber.Store(0) + } + } else { + m.lastNumber.Store(0) + } + log.Debug("Record srv load", "last", m.lastNumber.Load()) + default: + return errors.New("Unknow service") + } + m.srv.Store(int32(srv)) + log.Info("Service switch", "srv", m.srv.Load(), "last", m.lastNumber.Load()) + } + + return nil +} + +// only for examples +func (m *Monitor) forExplorerService(block *types.Block) error { + return errors.New("not support") +} + +func (m *Monitor) forExchangeService(block *types.Block) error { + return errors.New("not support") +} + +func (m *Monitor) forRecordService(block *types.Block) error { + if block.Number%4096 == 0 { + log.Info("Block record", "num", block.Number, "hash", block.Hash, "txs", len(block.Txs), "last", m.lastNumber.Load()) + } + if len(block.Txs) > 0 { + for _, t := range block.Txs { + x := new(big.Float).Quo(new(big.Float).SetInt(t.Amount), new(big.Float).SetInt(big.NewInt(params1.Cortex))) + log.Debug("Tx record", "hash", t.Hash, "amount", x, "gas", t.GasLimit, "receipt", t.Recipient, "payload", t.Payload) + + if v, err := json.Marshal(t); err != nil { + return err + } else { + m.engine.Set(t.Hash.Bytes(), v) + } + } + } + + if v, err := json.Marshal(block); err != nil { + return err + } else { + m.engine.Set(block.Hash.Bytes(), v) + } + + m.engine.Set([]byte("srv_record_last"), []byte(strconv.FormatUint(block.Number, 16))) + return nil +} + +func (m *Monitor) forModelService(block *types.Block) error { + blockNumber := block.Number + + // Step 1: Handle periodic operations (e.g., every 65536 blocks) + if blockNumber%65536 == 0 { + defer m.fs.SkipPrint() + } + + // Step 2: Check if block is already processed in cache + hashInCache, found := m.blockCache.Get(blockNumber) + if found && hashInCache == block.Hash.Hex() { + return nil // Block already processed, do nothing + } + + // Step 3: Parse transactions in the block + record, parseErr := m.parseBlockTorrentInfo(block) + if parseErr != nil { + log.Error("Failed to parse block transactions", "number", blockNumber, "error", parseErr) + return parseErr + } + + // Step 4: Handle checkpoint logic if this is a record-carrying block + if record { + m.handleMilestoneCheckpoint(block) + } + + // Step 5: Seal the record or anchor the filesystem + if record { + log.Debug("Sealing fs record", "number", blockNumber, "root", m.fs.Root().Hex(), "blocks", len(m.fs.Blocks()), "txs", m.fs.Txs(), "files", len(m.fs.Files()), "ckp", m.fs.CheckPoint()) + } else { + if m.fs.LastListenBlockNumber() < blockNumber { + m.fs.Anchor(blockNumber) + } + log.Trace("Confirmed to seal fs record", "number", blockNumber) + } + + // Step 6: Add the new block to the cache + m.blockCache.Add(blockNumber, block.Hash.Hex()) + return nil +} + +// handleMilestoneCheckpoint encapsulates the logic for the TFS checkpoint. +func (m *Monitor) handleMilestoneCheckpoint(block *types.Block) { + if m.ckp == nil || m.ckp.TfsCheckPoint == 0 || block.Number != m.ckp.TfsCheckPoint { + return // Not at a checkpoint + } + + elapsed := time.Duration(mclock.Now()) - time.Duration(m.start) + + if common.BytesToHash(m.fs.GetRoot(block.Number)) == m.ckp.TfsRoot { + log.Warn("FIRST MILESTONE PASSED successfully", "number", block.Number, "root", m.fs.Root(), "blocks", len(m.fs.Blocks()), "txs", m.fs.Txs(), "files", len(m.fs.Files()), "elapsed", common.PrettyDuration(elapsed)) + } else { + log.Error("Filesystem checkpoint failed", "number", block.Number, "root", m.fs.Root(), "blocks", len(m.fs.Blocks()), "files", len(m.fs.Files()), "txs", m.fs.Txs(), "elapsed", common.PrettyDuration(elapsed), "expected", m.ckp.TfsRoot, "leaves", len(m.fs.Leaves())) + panic("FIRST MILESTONE ERROR, run './cortex removedb' command to solve this problem") + } +}