fix(blockchain): separate implicit testnet data dir
Some checks are pending
Security Scan / security (push) Waiting to run
Test / Test (push) Waiting to run

Co-Authored-By: Charon <charon@lethean.io>
This commit is contained in:
Virgil 2026-04-04 17:44:57 +00:00
parent c259098269
commit 1db746cbe8
6 changed files with 50 additions and 9 deletions

View file

@ -30,6 +30,7 @@ const chainExplorerCommandName = "explorer"
const chainSyncCommandName = "sync"
const defaultChainSeed = "seeds.lthn.io:36942"
const defaultChainTestnetSeed = "localhost:46942"
const defaultChainDataDirHelp = "store chain data and sync state in this directory (defaults to ~/.lethean/chain, or ~/.lethean/testnet/chain with --testnet)"
const chainCommandPath = AppName + " " + ChainCommandName
const chainExplorerCommandPath = chainCommandPath + " " + chainExplorerCommandName
const chainSyncCommandPath = chainCommandPath + " " + chainSyncCommandName
@ -71,7 +72,7 @@ func AddChainCommands(root *cobra.Command) {
Args: cobra.NoArgs,
}
chainCmd.PersistentFlags().StringVar(&dataDir, "data-dir", defaultChainDataDirPath(), "store chain data and sync state in this directory")
chainCmd.PersistentFlags().StringVar(&dataDir, "data-dir", defaultChainDataDirPath(), defaultChainDataDirHelp)
chainCmd.PersistentFlags().StringVar(&seed, "seed", defaultChainSeed, "connect to this seed peer first (host:port)")
chainCmd.PersistentFlags().BoolVar(&testnet, "testnet", false, "use the Lethean testnet and its default seed ("+defaultChainTestnetSeed+")")
@ -94,10 +95,17 @@ func chainConfigForSeed(testnet bool, seed string) (config.ChainConfig, []config
}
func defaultChainDataDirPath() string {
return defaultChainDataDirPathForNetwork(false)
}
func defaultChainDataDirPathForNetwork(testnet bool) string {
home, err := os.UserHomeDir()
if err != nil {
return ".lethean"
}
if testnet {
return filepath.Join(home, ".lethean", "testnet", "chain")
}
return filepath.Join(home, ".lethean", "chain")
}
@ -123,6 +131,13 @@ func resolveChainDataDir(dataDir string) (string, error) {
return filepath.Clean(dataDir), nil
}
func resolveChainCommandDataDir(dataDir string, testnet, explicit bool) (string, error) {
if !explicit {
dataDir = defaultChainDataDirPathForNetwork(testnet)
}
return resolveChainDataDir(dataDir)
}
func ensureChainDataDirExists(dataDir string) error {
if err := coreio.Local.EnsureDir(dataDir); err != nil {
return coreerr.E("ensureChainDataDirExists", "create data dir", err)

View file

@ -129,6 +129,24 @@ func TestResolveChainDataDir_Good_ExpandsEnvVars(t *testing.T) {
assert.Equal(t, "/tmp/lethean/node", got)
}
func TestResolveChainCommandDataDir_Good_UsesMainnetDefaultWhenImplicit(t *testing.T) {
got, err := resolveChainCommandDataDir(defaultChainDataDirPath(), false, false)
require.NoError(t, err)
assert.Equal(t, defaultChainDataDirPathForNetwork(false), got)
}
func TestResolveChainCommandDataDir_Good_UsesTestnetDefaultWhenImplicit(t *testing.T) {
got, err := resolveChainCommandDataDir(defaultChainDataDirPath(), true, false)
require.NoError(t, err)
assert.Equal(t, defaultChainDataDirPathForNetwork(true), got)
}
func TestResolveChainCommandDataDir_Good_KeepsExplicitDataDirOnTestnet(t *testing.T) {
got, err := resolveChainCommandDataDir("/tmp/custom-chain", true, true)
require.NoError(t, err)
assert.Equal(t, "/tmp/custom-chain", got)
}
func TestValidateChainSyncModeSelection_Good(t *testing.T) {
err := validateChainSyncModeSelection(true, false)
require.NoError(t, err)
@ -223,7 +241,7 @@ func TestAddChainCommands_Good_PersistentFlagHelp(t *testing.T) {
chainCmd, _, _ := root.Find([]string{ChainCommandName})
assert.Equal(t, "store chain data and sync state in this directory", chainCmd.PersistentFlags().Lookup("data-dir").Usage)
assert.Equal(t, defaultChainDataDirHelp, chainCmd.PersistentFlags().Lookup("data-dir").Usage)
assert.Equal(t, "connect to this seed peer first (host:port)", chainCmd.PersistentFlags().Lookup("seed").Usage)
assert.Equal(t, "use the Lethean testnet and its default seed (localhost:46942)", chainCmd.PersistentFlags().Lookup("testnet").Usage)
}

View file

@ -40,7 +40,11 @@ func newChainExplorerCommand(dataDir, seed *string, testnet *bool) *cobra.Comman
Example: chainExplorerExample,
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
return runChainExplorer(*dataDir, *seed, *testnet)
resolvedDataDir, err := resolveChainCommandDataDir(*dataDir, *testnet, cmd.Flags().Changed("data-dir"))
if err != nil {
return err
}
return runChainExplorer(resolvedDataDir, *seed, *testnet)
},
}
}

View file

@ -47,16 +47,20 @@ func newChainSyncCommand(dataDir, seed *string, testnet *bool) *cobra.Command {
Example: chainSyncExample,
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
resolvedDataDir, err := resolveChainCommandDataDir(*dataDir, *testnet, cmd.Flags().Changed("data-dir"))
if err != nil {
return err
}
if err := validateChainSyncModeSelection(runAsDaemon, stopDaemon); err != nil {
return err
}
if stopDaemon {
return stopChainSyncDaemon(*dataDir)
return stopChainSyncDaemon(resolvedDataDir)
}
if runAsDaemon {
return runChainSyncDaemon(*dataDir, *seed, *testnet)
return runChainSyncDaemon(resolvedDataDir, *seed, *testnet)
}
return runChainSyncForeground(*dataDir, *seed, *testnet)
return runChainSyncForeground(resolvedDataDir, *seed, *testnet)
},
}

View file

@ -49,7 +49,7 @@ func (m *StatusModel) Update(msg tea.Msg) (cli.FrameModel, tea.Cmd) {
// not yet received a status snapshot, so it shows a placeholder.
func (m *StatusModel) View(width, height int) string {
var line string
if height == 0 {
if m.status.Height == 0 {
line = " height 0 | syncing..."
} else {
s := m.status

View file

@ -17,8 +17,8 @@ func TestStatusModel_View_Good_Initial(t *testing.T) {
m := NewStatusModel(n)
got := m.View(80, 1)
if !strings.Contains(got, "syncing") && !strings.Contains(got, "0") {
t.Errorf("initial View should contain \"syncing\" or \"0\", got %q", got)
if !strings.Contains(got, "syncing") {
t.Errorf("initial View should contain \"syncing\", got %q", got)
}
}