-
Notifications
You must be signed in to change notification settings - Fork 3.8k
Commit
(cherry picked from commit 34f407d) # Conflicts: # server/v2/store/server.go # store/db/prefixdb_test.go # store/v2/root/builder.go # tests/integration/v2/distribution/fixture_test.go # tests/systemtests/go.sum
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
package store | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
|
||
"github.com/spf13/cobra" | ||
|
||
"cosmossdk.io/core/server" | ||
"cosmossdk.io/core/transaction" | ||
serverv2 "cosmossdk.io/server/v2" | ||
Check failure on line 11 in server/v2/store/server.go GitHub Actions / split-test-files
Check failure on line 11 in server/v2/store/server.go GitHub Actions / dependency-review
Check failure on line 11 in server/v2/store/server.go GitHub Actions / dependency-review
|
||
storev2 "cosmossdk.io/store/v2" | ||
Check failure on line 12 in server/v2/store/server.go GitHub Actions / split-test-files
Check failure on line 12 in server/v2/store/server.go GitHub Actions / dependency-review
Check failure on line 12 in server/v2/store/server.go GitHub Actions / dependency-review
|
||
"cosmossdk.io/store/v2/root" | ||
Check failure on line 13 in server/v2/store/server.go GitHub Actions / split-test-files
Check failure on line 13 in server/v2/store/server.go GitHub Actions / dependency-review
Check failure on line 13 in server/v2/store/server.go GitHub Actions / dependency-review
|
||
) | ||
|
||
var ( | ||
_ serverv2.ServerComponent[transaction.Tx] = (*Server[transaction.Tx])(nil) | ||
_ serverv2.HasConfig = (*Server[transaction.Tx])(nil) | ||
_ serverv2.HasCLICommands = (*Server[transaction.Tx])(nil) | ||
) | ||
|
||
const ServerName = "store" | ||
|
||
// Server manages store config and contains prune & snapshot commands | ||
type Server[T transaction.Tx] struct { | ||
config *root.Config | ||
store storev2.Backend | ||
} | ||
|
||
func New[T transaction.Tx](store storev2.Backend, cfg server.ConfigMap) (*Server[T], error) { | ||
config, err := UnmarshalConfig(cfg) | ||
if err != nil { | ||
return nil, err | ||
} | ||
return &Server[T]{ | ||
store: store, | ||
config: config, | ||
}, nil | ||
} | ||
|
||
func (s *Server[T]) Name() string { | ||
return ServerName | ||
} | ||
|
||
func (s *Server[T]) Start(context.Context) error { | ||
return nil | ||
} | ||
|
||
func (s *Server[T]) Stop(context.Context) error { | ||
return nil | ||
} | ||
|
||
func (s *Server[T]) CLICommands() serverv2.CLIConfig { | ||
return serverv2.CLIConfig{ | ||
Commands: []*cobra.Command{ | ||
s.PrunesCmd(), | ||
Check failure on line 56 in server/v2/store/server.go GitHub Actions / dependency-review
|
||
s.ExportSnapshotCmd(), | ||
Check failure on line 57 in server/v2/store/server.go GitHub Actions / dependency-review
|
||
s.DeleteSnapshotCmd(), | ||
Check failure on line 58 in server/v2/store/server.go GitHub Actions / dependency-review
|
||
s.ListSnapshotsCmd(), | ||
Check failure on line 59 in server/v2/store/server.go GitHub Actions / dependency-review
|
||
s.DumpArchiveCmd(), | ||
s.LoadArchiveCmd(), | ||
s.RestoreSnapshotCmd(), | ||
}, | ||
} | ||
} | ||
|
||
func (s *Server[T]) Config() any { | ||
if s.config == nil || s.config.AppDBBackend == "" { | ||
return root.DefaultConfig() | ||
} | ||
|
||
return s.config | ||
} | ||
|
||
// UnmarshalConfig unmarshals the store config from the given map. | ||
// If the config is not found in the map, the default config is returned. | ||
// If the home directory is found in the map, it sets the home directory in the config. | ||
// An empty home directory *is* permitted at this stage, but attempting to build | ||
// the store with an empty home directory will fail. | ||
func UnmarshalConfig(cfg map[string]any) (*root.Config, error) { | ||
config := root.DefaultConfig() | ||
if err := serverv2.UnmarshalSubConfig(cfg, ServerName, config); err != nil { | ||
return nil, fmt.Errorf("failed to unmarshal store config: %w", err) | ||
} | ||
home := cfg[serverv2.FlagHome] | ||
if home != nil { | ||
config.Home = home.(string) | ||
} | ||
return config, nil | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
package db_test | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/stretchr/testify/require" | ||
"go.uber.org/mock/gomock" | ||
|
||
"cosmossdk.io/store/db" | ||
"cosmossdk.io/store/mock" | ||
) | ||
|
||
func TestPrefixDB(t *testing.T) { | ||
mockCtrl := gomock.NewController(t) | ||
defer mockCtrl.Finish() | ||
|
||
mockDB := mock.NewMockKVStoreWithBatch(mockCtrl) | ||
prefix := []byte("test:") | ||
pdb := db.NewPrefixDB(mockDB, prefix) | ||
|
||
key := []byte("key1") | ||
value := []byte("value1") | ||
mockDB.EXPECT().Set(gomock.Eq(append(prefix, key...)), gomock.Eq(value)).Return(nil) | ||
|
||
err := pdb.Set(key, value) | ||
require.NoError(t, err) | ||
|
||
mockDB.EXPECT().Get(gomock.Eq(append(prefix, key...))).Return(value, nil) | ||
|
||
returnedValue, err := pdb.Get(key) | ||
require.NoError(t, err) | ||
require.Equal(t, value, returnedValue) | ||
|
||
mockDB.EXPECT().Has(gomock.Eq(append(prefix, key...))).Return(true, nil) | ||
|
||
has, err := pdb.Has(key) | ||
require.NoError(t, err) | ||
require.True(t, has) | ||
|
||
mockDB.EXPECT().Delete(gomock.Eq(append(prefix, key...))).Return(nil) | ||
|
||
err = pdb.Delete(key) | ||
require.NoError(t, err) | ||
|
||
mockDB.EXPECT().Has(gomock.Eq(append(prefix, key...))).Return(false, nil) | ||
|
||
has, err = pdb.Has(key) | ||
require.NoError(t, err) | ||
require.False(t, has) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
package root | ||
|
||
import ( | ||
"fmt" | ||
"path/filepath" | ||
|
||
"cosmossdk.io/log" | ||
"cosmossdk.io/store/v2" | ||
"cosmossdk.io/store/v2/db" | ||
Check failure on line 9 in store/v2/root/builder.go GitHub Actions / split-test-files
|
||
) | ||
|
||
// Builder is the interface for a store/v2 RootStore builder. | ||
// RootStores built by the Cosmos SDK typically involve a 2 phase initialization: | ||
// 1. Namespace registration | ||
// 2. Configuration and loading | ||
// | ||
// The Builder interface is used to facilitate this pattern. Namespaces (store keys) are registered | ||
// by calling RegisterKey before Build is called. Build is then called with a Config | ||
// object and a RootStore is returned. Calls to Get may return the `RootStore` if Build | ||
// was successful, but that's left up to the implementation. | ||
type Builder interface { | ||
// Build creates a new store/v2 RootStore from the given Config. | ||
Build(log.Logger, *Config) (store.RootStore, error) | ||
// RegisterKey registers a store key (namespace) to be used when building the RootStore. | ||
RegisterKey(string) | ||
// Get returns the Store. Build should be called before calling Get or the result will be nil. | ||
Get() store.RootStore | ||
} | ||
|
||
var _ Builder = (*builder)(nil) | ||
|
||
// builder is the default builder for a store/v2 RootStore satisfying the Store interface. | ||
// Tangibly it combines store key registration and a top-level Config to create a RootStore by calling | ||
// the CreateRootStore factory function. | ||
type builder struct { | ||
// input | ||
storeKeys map[string]struct{} | ||
|
||
// output | ||
store store.RootStore | ||
} | ||
|
||
func NewBuilder() Builder { | ||
return &builder{storeKeys: make(map[string]struct{})} | ||
} | ||
|
||
// Build creates a new store/v2 RootStore. | ||
func (sb *builder) Build( | ||
logger log.Logger, | ||
config *Config, | ||
) (store.RootStore, error) { | ||
if sb.store != nil { | ||
return sb.store, nil | ||
} | ||
if config.Home == "" { | ||
return nil, fmt.Errorf("home directory is required") | ||
} | ||
|
||
if len(config.AppDBBackend) == 0 { | ||
return nil, fmt.Errorf("application db backend is required") | ||
} | ||
|
||
scRawDb, err := db.NewDB( | ||
db.DBType(config.AppDBBackend), | ||
"application", | ||
filepath.Join(config.Home, "data"), | ||
nil, | ||
) | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to create SCRawDB: %w", err) | ||
} | ||
|
||
var storeKeys []string | ||
for key := range sb.storeKeys { | ||
storeKeys = append(storeKeys, key) | ||
} | ||
|
||
factoryOptions := &FactoryOptions{ | ||
Logger: logger.With("module", "store"), | ||
RootDir: config.Home, | ||
Options: config.Options, | ||
StoreKeys: storeKeys, | ||
SCRawDB: scRawDb, | ||
} | ||
|
||
rs, err := CreateRootStore(factoryOptions) | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to create root store: %w", err) | ||
} | ||
sb.store = rs | ||
return sb.store, nil | ||
} | ||
|
||
func (sb *builder) Get() store.RootStore { | ||
return sb.store | ||
} | ||
|
||
func (sb *builder) RegisterKey(key string) { | ||
sb.storeKeys[key] = struct{}{} | ||
} |