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
```
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 217c30d..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 {
@@ -159,27 +146,7 @@ func (fs *ChainDB) Init() (err error) {
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()
}
@@ -640,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 {
@@ -682,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))
@@ -736,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
index 2c0b443..3e7f51d 100644
--- a/config.go
+++ b/config.go
@@ -21,7 +21,7 @@ import (
)
const (
- batch = 4096 * 2 //params.SyncBatch
- delay = 12 //params.Delay
+ batch = 4096 * 16 //params.SyncBatch
+ delay = 12 //params.Delay
timeout = 30 * time.Second
)
diff --git a/go.mod b/go.mod
index bb0e518..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.7-0.20230914134745-d46c1d97e263
- 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 9c7b0d4..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.7-0.20230914134745-d46c1d97e263 h1:e6m7c5Xfi8bFNRkrKsWZbktFOGuJDlG7hJQwuBdPx/Y=
-github.com/hashicorp/golang-lru/v2 v2.0.7-0.20230914134745-d46c1d97e263/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
index 7a072f1..355edab 100644
--- a/model_srv.go
+++ b/model_srv.go
@@ -19,135 +19,178 @@ 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"
- "time"
)
func (m *Monitor) parseFileMeta(tx *types.Transaction, meta *types.FileMeta, b *types.Block) error {
- log.Debug("Monitor", "FileMeta", meta)
+ 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 {
- log.Warn("contract address is nil, waiting for indexing", "tx.Hash.String()", tx.Hash.String())
- return errors.New("contract address is 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
}
- 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)
- return nil
+ 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("Meta data", "meta", meta)
+ 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("Create file failed", "err", err)
+ 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("Create new file", "ih", meta.InfoHash, "op", op)
+ log.Debug("New file created, initiating download", "infoHash", meta.InfoHash)
- ctx, cancel := context.WithTimeout(context.Background(), timeout)
- defer cancel()
+ sizeLimit := uint64(0)
if m.mode == params.FULL {
- return m.download(ctx, meta.InfoHash, 512*1024)
- } else {
- return m.download(ctx, meta.InfoHash, 0)
+ 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
- start = mclock.Now()
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", "ih", meta.InfoHash, "number", b.Number, "meta", meta)
+ log.Debug("Data encounter", "infoHash", meta.InfoHash, "blockNumber", b.Number)
if err := m.parseFileMeta(&tx, meta, b); err != nil {
- log.Error("Parse file meta error", "err", err, "number", b.Number)
+ log.Error("Parse file meta failed", "error", err, "blockNumber", b.Number, "txHash", tx.Hash)
return false, err
}
record = true
final = append(final, tx)
- } else if tx.IsFlowControl() {
+ 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 remain failed", "err", err, "addr", (*tx.Recipient).String())
+ log.Error("Get remaining size failed", "error", err, "addr", (*tx.Recipient).String())
return false, err
}
+
if file.LeftSize > remainingSize {
file.LeftSize = remainingSize
- if _, progress, err := m.fs.AddFile(file); err != nil {
+ _, progress, err := m.fs.AddFile(file)
+ if 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 progress {
+ bytesRequested := uint64(0)
if file.Meta.RawSize > file.LeftSize {
bytesRequested = file.Meta.RawSize - file.LeftSize
}
+
+ logMsg := "Data processing..."
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)
+ 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)
- defer cancel()
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("Final txs layout", "total", len(b.Txs), "final", len(final), "num", b.Number, "txs", m.fs.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.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 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("Transactions scanning", "count", len(b.Txs), "number", b.Number, "elapsed", common.PrettyDuration(elapsed))
+ 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 91b5c47..efb5622 100644
--- a/monitor.go
+++ b/monitor.go
@@ -19,30 +19,26 @@ package robot
import (
"context"
"errors"
+ "math"
+ //"sort"
+ "fmt"
+ "path/filepath"
+ "runtime"
+ "sync"
+ "sync/atomic"
+ "time"
+
"github.com/CortexFoundation/CortexTheseus/common"
"github.com/CortexFoundation/CortexTheseus/common/mclock"
"github.com/CortexFoundation/CortexTheseus/log"
- "github.com/CortexFoundation/CortexTheseus/metrics"
"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"
- "path/filepath"
- "runtime"
- "sync"
- "sync/atomic"
- "time"
-)
-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.
@@ -116,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(),
@@ -188,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 {
@@ -206,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 {
@@ -319,7 +315,7 @@ func (m *Monitor) taskLoop() {
}
}
-func (m *Monitor) exit() {
+/*func (m *Monitor) exit() {
m.closeOnce.Do(func() {
if m.exitCh != nil {
close(m.exitCh)
@@ -351,7 +347,9 @@ func (m *Monitor) Stop() error {
// TODO dirty statics deal with
if m.engine != nil {
log.Info("Golang-kv engine close", "engine", m.engine.Name())
- return m.engine.Close()
+ if err := m.engine.Close(); err != nil {
+ return err
+ }
}
if err := m.fs.Close(); err != nil {
@@ -360,6 +358,52 @@ func (m *Monitor) Stop() error {
}
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()
+ } else {
+ log.Debug("Listener exit channel already closed")
+ }
+ })
+}
+
+func (m *Monitor) Stop() error {
+ m.lock.Lock()
+ 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()
+
+ if m.engine != nil {
+ 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 {
+ 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
}
// Start ... start ListenOn on the rpc port of a blockchain full node
@@ -450,186 +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) 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
+ // Process a single block
+ block, err := m.rpcBlockByNumber(i)
+ if err != nil {
+ return m.handleSyncError("Sync old block failed", err, i-1)
}
- if err := m.solve(rpcBlock); err != nil {
- log.Error("solve err", "err", err)
- m.lastNumber.Store(i - 1)
- return 0
+
+ if err := m.solve(block); err != nil {
+ return m.handleSyncError("solve err", err, i-1)
}
+
i++
- counter++
+ processedCount++
}
}
- //log.Debug("Last number changed", "min", minNumber, "max", maxNumber, "cur", currentNumber, "last", m.lastNumber.Load(), "batch", batch)
+
+ // Step 4: Finalize the sync operation.
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))
+ 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(),
+ )
+
return uint64(maxNumber - minNumber)
}
+
+// 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
index 07fc2c8..bf480d1 100644
--- a/rpc.go
+++ b/rpc.go
@@ -17,14 +17,17 @@
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"
- "strconv"
- "time"
)
// SetConnection method builds connection to remote or local communicator.
@@ -67,7 +70,9 @@ 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)
+ 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
}
@@ -75,7 +80,74 @@ func (m *Monitor) rpcBlockByNumber(blockNumber uint64) (*types.Block, error) {
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) {
+/*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
@@ -83,6 +155,7 @@ func (m *Monitor) rpcBatchBlockByNumber(from, to uint64) (result []*types.Block,
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
@@ -101,7 +174,9 @@ func (m *Monitor) getRemainingSize(address string) (uint64, error) {
}
var remainingSize hexutil.Uint64
rpcUploadMeter.Mark(1)
- if err := m.cl.Call(&remainingSize, "ctxc_getUpload", address, "latest"); err != nil {
+ 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)
@@ -113,13 +188,26 @@ func (m *Monitor) getRemainingSize(address string) (uint64, error) {
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 {
+ 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
@@ -127,7 +215,9 @@ func (m *Monitor) currentBlock() (uint64, bool, error) {
)
rpcCurrentMeter.Mark(1)
- if err := m.cl.Call(¤tNumber, "ctxc_blockNumber"); err != nil {
+ 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
}
diff --git a/service.go b/service.go
index 42afe5b..5938172 100644
--- a/service.go
+++ b/service.go
@@ -19,14 +19,15 @@ 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"
- "math/big"
- "strconv"
- "time"
)
// solve block from node
@@ -137,41 +138,58 @@ func (m *Monitor) forRecordService(block *types.Block) error {
}
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()
- }()
+ blockNumber := block.Number
+
+ // Step 1: Handle periodic operations (e.g., every 65536 blocks)
+ if blockNumber%65536 == 0 {
+ defer 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)
+ // 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
+ }
- 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")
- }
- }
+ // 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
+ }
- 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)
- }
+ // Step 4: Handle checkpoint logic if this is a record-carrying block
+ if record {
+ m.handleMilestoneCheckpoint(block)
+ }
- log.Trace("Confirm to seal the fs record", "number", i)
+ // 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)
}
- m.blockCache.Add(i, block.Hash.Hex())
+ 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")
+ }
+}