Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changelog/6321.feature.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
go/oasis-node: Add new command for offline pruning of consensus databases

A new experimental command `oasis-node storage prune-experimental`
was added, enabling offline pruning as specified in the configuration.

Operators are encouraged to run this command whenever they change pruning
configuration, to ensure node is healthy when it starts.
25 changes: 24 additions & 1 deletion docs/oasis-node/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,7 @@ oasis1qqncl383h8458mr9cytatygctzwsx02n4c5f8ed7

### compact-experimental

Run
Run (when the node is not running):

```sh
oasis-node storage compact-experimental --config /path/to/config/file
Expand Down Expand Up @@ -364,3 +364,26 @@ may stay constant or not be reclaimed for a very long time.

This command gives operators manual control to release disk space during
maintenance periods.

### prune-experimental

Run (when the node is not running):

```sh
oasis-node storage prune-experimental --config /path/to/config/file
```

to trigger manual pruning of consensus database instances:

```sh
{"caller":"storage.go:433","level":"info","module":"cmd/storage", \
"msg":"Starting consensus databases pruning. This may take a while...", \
"ts":"2025-10-23T11:02:11.129822974Z"}
```

Operators should run this whenever they change pruning configuration, e.g. when
enabling it for the first time, or later changing it to retain less data. This
way they guarantee the node is healthy when it starts.

Following successful pruning, to release disk space, they are encouraged to run
[the compaction command](#compact-experimental).
2 changes: 2 additions & 0 deletions go/consensus/cometbft/abci/prune.go
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,8 @@ func (p *genericPruner) canPrune(v int64) error {
return nil
}

// Warning: When registering new handler DO NOT forget to update the logic for
// "oasis-node storage prune" command as well.
func (p *genericPruner) RegisterHandler(handler consensus.StatePruneHandler) {
p.Lock()
defer p.Unlock()
Expand Down
46 changes: 42 additions & 4 deletions go/consensus/cometbft/db/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,61 @@
package db

import (
"fmt"

dbm "github.com/cometbft/cometbft-db"
cmtconfig "github.com/cometbft/cometbft/config"
"github.com/cometbft/cometbft/node"
cmtnode "github.com/cometbft/cometbft/node"
"github.com/cometbft/cometbft/state"

"github.com/oasisprotocol/oasis-core/go/consensus/cometbft/db/badger"
)

// GetBackendName returns the currently configured CometBFT database backend.
func GetBackendName() string {
// BackendName returns the currently configured CometBFT database backend.
func BackendName() string {
return badger.BackendName
}

// GetProvider returns the currently configured CometBFT DBProvider.
func GetProvider() (node.DBProvider, error) {
// Provider returns the currently configured CometBFT DBProvider.
func Provider() (node.DBProvider, error) {
return badger.DBProvider, nil
}

// New constructs a new CometBFT DB with the configured backend.
func New(fn string, noSuffix bool) (dbm.DB, error) {
return badger.New(fn, noSuffix)
}

// OpenBlockstoreDB opens a CometBFT managed blockstore DB.
//
// This function is a hack as CometBFT does not expose a way to access the underlying databases.
func OpenBlockstoreDB(provider cmtnode.DBProvider, cfg *cmtconfig.Config) (dbm.DB, error) {
// NOTE: DBContext uses a full CometBFT config but the only thing that is actually used
// is the data dir field.
db, err := provider(&cmtnode.DBContext{ID: "blockstore", Config: cfg})
if err != nil {
return nil, fmt.Errorf("failed to open blockstore: %w", err)
}

return db, nil
}

// OpenStateDB opens a CometBFT managed state DB.
//
// This function is a hack as CometBFT does not expose a way to access the underlying databases.
func OpenStateDB(provider cmtnode.DBProvider, cfg *cmtconfig.Config) (dbm.DB, error) {
// NOTE: DBContext uses a full CometBFT config but the only thing that is actually used
// is the data dir field.
db, err := provider(&cmtnode.DBContext{ID: "state", Config: cfg})
if err != nil {
return nil, fmt.Errorf("failed to open state db: %w", err)
}

return db, nil
}

// OpenStateStore constructs a new state store using default options.
func OpenStateStore(stateDB dbm.DB) state.Store {
return state.NewStore(stateDB, state.StoreOptions{})
}
22 changes: 8 additions & 14 deletions go/consensus/cometbft/full/archive.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,9 @@ import (
"sync"
"time"

dbm "github.com/cometbft/cometbft-db"
abcicli "github.com/cometbft/cometbft/abci/client"
cmtconfig "github.com/cometbft/cometbft/config"
cmtsync "github.com/cometbft/cometbft/libs/sync"
cmtnode "github.com/cometbft/cometbft/node"
cmtproxy "github.com/cometbft/cometbft/proxy"
cmtcore "github.com/cometbft/cometbft/rpc/core"
"github.com/cometbft/cometbft/state"
Expand Down Expand Up @@ -194,31 +192,27 @@ func NewArchive(ctx context.Context, cfg ArchiveConfig) (consensusAPI.Service, e
logger := tmcommon.NewLogAdapter(!config.GlobalConfig.Consensus.LogDebug)
srv.abciClient = abcicli.NewLocalClient(new(cmtsync.Mutex), srv.mux.Mux())

dbProvider, err := db.GetProvider()
if err != nil {
return nil, err
}
cmtConfig := cmtconfig.DefaultConfig()
_ = viper.Unmarshal(&cmtConfig)
cmtConfig.SetRoot(filepath.Join(srv.dataDir, tmcommon.StateDir))

// NOTE: DBContext uses a full CometBFT config but the only thing that is actually used
// is the data dir field.
srv.blockStoreDB, err = dbProvider(&cmtnode.DBContext{ID: "blockstore", Config: cmtConfig})
dbProvider, err := db.Provider()
if err != nil {
return nil, fmt.Errorf("failed to obtain db provider: %w", err)
}

srv.blockStoreDB, err = db.OpenBlockstoreDB(dbProvider, cmtConfig)
if err != nil {
return nil, err
}
srv.blockStoreDB = db.WithCloser(srv.blockStoreDB, srv.dbCloser)

// NOTE: DBContext uses a full CometBFT config but the only thing that is actually used
// is the data dir field.
var stateDB dbm.DB
stateDB, err = dbProvider(&cmtnode.DBContext{ID: "state", Config: cmtConfig})
stateDB, err := db.OpenStateDB(dbProvider, cmtConfig)
if err != nil {
return nil, err
}
stateDB = db.WithCloser(stateDB, srv.dbCloser)
srv.stateStore = state.NewStore(stateDB, state.StoreOptions{})
srv.stateStore = db.OpenStateStore(stateDB)

srv.eb = cmttypes.NewEventBus()
// Setup minimal CometBFT environment needed to support consensus queries.
Expand Down
2 changes: 1 addition & 1 deletion go/consensus/cometbft/full/full.go
Original file line number Diff line number Diff line change
Expand Up @@ -668,7 +668,7 @@ func (t *fullService) lazyInit() error { // nolint: gocyclo
return t.genesisDoc, nil
}

dbProvider, err := db.GetProvider()
dbProvider, err := db.Provider()
if err != nil {
t.Logger.Error("failed to obtain database provider",
"err", err,
Expand Down
16 changes: 16 additions & 0 deletions go/oasis-node/cmd/common/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
package common

import (
"errors"
"fmt"
"io"
"io/fs"
"os"
"path/filepath"
"strings"
Expand Down Expand Up @@ -71,6 +73,20 @@ func InternalSocketPath() string {
return filepath.Join(DataDir(), InternalSocketName)
}

// IsNodeRunning returns true when the node is running.
func IsNodeRunning() (bool, error) {
path := InternalSocketPath()

if _, err := os.Stat(path); err != nil {
if errors.Is(err, fs.ErrNotExist) {
return false, nil
}
return false, fmt.Errorf("stat %s: %w", path, err)
}

return true, nil
}

// IsNodeCmd returns true iff the current command is the ekiden node.
func IsNodeCmd() bool {
return isNodeCmd
Expand Down
Loading
Loading