diff --git a/go.mod b/go.mod index add132c85..ef8736137 100644 --- a/go.mod +++ b/go.mod @@ -203,6 +203,7 @@ require ( github.com/tklauser/go-sysconf v0.3.12 // indirect github.com/tklauser/numcpus v0.6.1 // indirect github.com/yeqown/reedsolomon v1.0.0 // indirect + github.com/yusufpapurcu/wmi v1.2.4 // indirect github.com/zquestz/grab v0.0.0-20190224022517-abcee96e61b1 // indirect golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa // indirect golang.org/x/net v0.28.0 // indirect diff --git a/go.sum b/go.sum index 052ca180d..dfd0a5af3 100644 --- a/go.sum +++ b/go.sum @@ -713,6 +713,7 @@ github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM= github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= 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-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= @@ -1449,6 +1450,8 @@ github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c/go.mod h1:/PevMnwAx github.com/shirou/gopsutil v0.0.0-20180427012116-c95755e4bcd7/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible h1:Bn1aCHHRnjv4Bl16T8rcaFjYSrGrIZvpiGO6P3Q4GpU= github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= +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/shirou/gopsutil/v3 v3.21.4/go.mod h1:ghfMypLDrFSWN2c9cDYFLHyynQ+QUht0cv/18ZqVczw= github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc= github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= @@ -1612,6 +1615,8 @@ github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1 github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13 h1:fVcFKWvrslecOb/tg+Cc05dkeYx540o0FuFt3nUVDoE= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= +github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= github.com/zquestz/grab v0.0.0-20190224022517-abcee96e61b1 h1:1qKTeMTSIEvRIjvVYzgcRp0xVp0eoiRTTiHSncb5gD8= github.com/zquestz/grab v0.0.0-20190224022517-abcee96e61b1/go.mod h1:bslhAiUxakrA6z6CHmVyvkfpnxx18RJBwVyx2TluJWw= go.etcd.io/bbolt v1.3.0/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= diff --git a/libwallet/assets/wallet/wallet_config.go b/libwallet/assets/wallet/wallet_config.go index f2f50c8e9..e0bc8f588 100644 --- a/libwallet/assets/wallet/wallet_config.go +++ b/libwallet/assets/wallet/wallet_config.go @@ -55,6 +55,7 @@ const ( DarkModeConfigKey = "dark_mode" HideTotalBalanceConfigKey = "hideTotalUSDBalance" IsCEXFirstVisitConfigKey = "is_cex_first_visit" + DBDriverConfigKey = "db_driver" PassphraseTypePin int32 = 0 PassphraseTypePass int32 = 1 diff --git a/libwallet/assets_config.go b/libwallet/assets_config.go index d1f91ae3c..f89fe2807 100644 --- a/libwallet/assets_config.go +++ b/libwallet/assets_config.go @@ -296,3 +296,19 @@ func (mgr *AssetsManager) SetTotalBalanceVisibility(data bool) { func genKey(prefix, identifier interface{}) string { return fmt.Sprintf("%v-%v", prefix, identifier) } + +// GetDBDriver returns the saved db driver. +func (mgr *AssetsManager) GetDBDriver() string { + var dbDriver string + mgr.ReadAppConfigValue(sharedW.DBDriverConfigKey, &dbDriver) + if dbDriver == "" { + // return default db driver if no option is stored. + return BoltDB + } + return dbDriver +} + +// SetDBDriver sets the db driver. +func (mgr *AssetsManager) SetDBDriver(dbDriver string) { + mgr.SaveAppConfigValue(sharedW.DBDriverConfigKey, dbDriver) +} diff --git a/libwallet/assets_manager.go b/libwallet/assets_manager.go index c2bf1d41b..8876565db 100644 --- a/libwallet/assets_manager.go +++ b/libwallet/assets_manager.go @@ -396,6 +396,11 @@ func (mgr *AssetsManager) LogDir() string { return filepath.Join(mgr.params.RootDir, logFileName) } +// DBDriver returns the db driver in use +func (mgr *AssetsManager) DBDriver() string { + return mgr.params.DbDriver +} + // OpenWallets opens all wallets in the assets manager. func (mgr *AssetsManager) OpenWallets(startupPassphrase string) error { for _, wallet := range mgr.AllWallets() { @@ -1028,3 +1033,11 @@ func (mgr *AssetsManager) RemoveAssetChange() { // Remove listener on rate notification mgr.RateSource.RemoveRateListener(assetIdentifier) } + +func (mgr *AssetsManager) BadgerDB() string { + return BadgerDB +} + +func (mgr *AssetsManager) BoltDB() string { + return BoltDB +} diff --git a/ui/page/start_page.go b/ui/page/start_page.go index c3c02c98e..923477f1c 100644 --- a/ui/page/start_page.go +++ b/ui/page/start_page.go @@ -6,6 +6,7 @@ import ( "strings" "time" + gioApp "gioui.org/app" "gioui.org/font" "gioui.org/layout" "gioui.org/text" @@ -14,6 +15,7 @@ import ( "golang.org/x/text/language" "github.com/crypto-power/cryptopower/app" + "github.com/crypto-power/cryptopower/appos" sharedW "github.com/crypto-power/cryptopower/libwallet/assets/wallet" libutils "github.com/crypto-power/cryptopower/libwallet/utils" "github.com/crypto-power/cryptopower/ui/cryptomaterial" @@ -24,6 +26,7 @@ import ( "github.com/crypto-power/cryptopower/ui/page/settings" "github.com/crypto-power/cryptopower/ui/preference" "github.com/crypto-power/cryptopower/ui/values" + "github.com/shirou/gopsutil/mem" ) const ( @@ -140,12 +143,14 @@ func (sp *startPage) OnNavigatedTo() { sp.setLanguagePref(true) // Set the log levels. sp.AssetsManager.GetLogLevels() - if sp.AssetsManager.IsStartupSecuritySet() { - sp.unlock() - } else { - sp.loading = true - go func() { _ = sp.openWalletsAndDisplayHomePage("") }() + // Mobile devices typically have limited RAM available for applications. + // To optimize memory usage, ensure mobile users are using BadgerDB, + // as it is efficient and designed for low-memory environments. + if appos.Current().IsMobile() { + sp.checkDBFile() + return } + sp.checkStartupSecurityAndStartApp() } else { sp.loading = false } @@ -222,7 +227,9 @@ func (sp *startPage) openWalletsAndDisplayHomePage(password string) error { err := sp.AssetsManager.OpenWallets(password) if err != nil { log.Errorf("Error opening wallet: %v", err) - // show err dialog + if appos.Current().IsMobile() { + sp.showRemoveWalletWarning() + } return err } @@ -729,3 +736,76 @@ func (sp *startPage) updateSettings() { sp.AssetsManager.SetHTTPAPIPrivacyMode(libutils.VspAPI, true) sp.AssetsManager.SetHTTPAPIPrivacyMode(libutils.UpdateAPI, true) } + +func (sp *startPage) checkDBFile() { + dbDriver := sp.AssetsManager.GetDBDriver() + + isNewDB := dbDriver == sp.AssetsManager.BadgerDB() + numberOfRAM, err := getNumberOfRam() + if err != nil { + log.Errorf("Error getting number of ram: %v", err) + return + } + + if numberOfRAM < 4 && !isNewDB { + sp.showRemoveWalletWarning() + return + } + + sp.checkStartupSecurityAndStartApp() +} + +func (sp *startPage) checkStartupSecurityAndStartApp() { + if sp.AssetsManager.IsStartupSecuritySet() { + sp.unlock() + } else { + sp.loading = true + go func() { _ = sp.openWalletsAndDisplayHomePage("") }() + } +} + +func (sp *startPage) clearAppDir() { + homeDir, err := gioApp.DataDir() + if err != nil { + log.Error("unable to get home dir: %v", err) + } + + err = os.RemoveAll(homeDir) + if err != nil { + log.Error("unable to remove home dir: %v", err) + return + } +} + +func (sp *startPage) showRemoveWalletWarning() { + warningModal := modal.NewCustomModal(sp.Load). + Title(values.String(values.StrDataFileErrorTitle)). + Body(values.String(values.StrDataFileErrorBody)). + SetNegativeButtonText(values.String(values.StrNo)). + SetPositiveButtonText(values.String(values.StrYes)). + PositiveButtonStyle(sp.Theme.Color.Surface, sp.Theme.Color.Danger) + + warningModal.SetNegativeButtonCallback(func() { + sp.checkStartupSecurityAndStartApp() + sp.AssetsManager.SetDBDriver("bdb") + warningModal.Dismiss() + }) + + warningModal.SetPositiveButtonCallback(func(_ bool, _ *modal.InfoModal) bool { + sp.clearAppDir() + sp.AssetsManager.SetDBDriver("badgerdb") + return true + }) + + sp.ParentWindow().ShowModal(warningModal) +} + +// Function to get the number of RAM in GB +func getNumberOfRam() (int, error) { + vmStat, err := mem.VirtualMemory() + if err != nil { + return 0, err + } + // Convert bytes to gigabytes + return int(vmStat.Total / (1024 * 1024 * 1024)), nil +} diff --git a/ui/page/wallet/wallet_settings_page.go b/ui/page/wallet/wallet_settings_page.go index c7455ab7d..0aa13f441 100644 --- a/ui/page/wallet/wallet_settings_page.go +++ b/ui/page/wallet/wallet_settings_page.go @@ -230,6 +230,25 @@ func (pg *SettingsPage) generalSection() layout.Widget { func (pg *SettingsPage) debug() layout.Widget { dim := func(gtx C) D { return layout.Flex{Axis: layout.Vertical}.Layout(gtx, + layout.Rigid(func(gtx C) D { + return layout.Inset{ + Bottom: values.MarginPadding24, + }.Layout(gtx, func(gtx C) D { + return layout.Flex{Axis: layout.Horizontal}.Layout(gtx, + layout.Rigid(func(gtx layout.Context) layout.Dimensions { + databaseTypeLabel := pg.Theme.Label(values.TextSizeTransform(pg.Load.IsMobileView(), values.TextSize16), values.String(values.StrDatabaseType)) + return databaseTypeLabel.Layout(gtx) + }), + layout.Flexed(1, func(gtx C) D { + return layout.E.Layout(gtx, func(gtx C) D { + dbDriverLabel := pg.Theme.Label(values.TextSizeTransform(pg.Load.IsMobileView(), values.TextSize16), pg.AssetsManager.DBDriver()) + dbDriverLabel.Color = pg.Theme.Color.GrayText2 + return dbDriverLabel.Layout(gtx) + }) + }), + ) + }) + }), layout.Rigid(pg.sectionContent(pg.rescan, values.String(values.StrRescanBlockchain))), layout.Rigid(func(gtx C) D { if pg.wallet.GetAssetType() == libutils.DCRWalletAsset { diff --git a/ui/values/localizable/en.go b/ui/values/localizable/en.go index 0ab09c2cc..9aded56db 100644 --- a/ui/values/localizable/en.go +++ b/ui/values/localizable/en.go @@ -959,4 +959,7 @@ const EN = ` "removeRecipientWarning" = "Are you sure you want to proceed with removing the recipient?" "unexpectedErrorMsgFmt" = "Something unexpected happened: %s" "unexpectedError" = "Unexpected Error" +"dataFileErrorTitle" = "Data file error" +"dataFileErrorBody" = "We have detected a problem with your data files from an older version. To fix it, you will need to re-enter your wallet seed phrase. Can you do this now?" +"databaseType" = "Database type" ` diff --git a/ui/values/strings.go b/ui/values/strings.go index ccea4fed6..04fe32a8e 100644 --- a/ui/values/strings.go +++ b/ui/values/strings.go @@ -1068,4 +1068,7 @@ const ( StrRemoveRecipientWarning = "removeRecipientWarning" StrUnexpectedErrorMsgFmt = "unexpectedErrorMsgFmt" StrUnexpectedError = "unexpectedError" + StrDataFileErrorTitle = "dataFileErrorTitle" + StrDataFileErrorBody = "dataFileErrorBody" + StrDatabaseType = "databaseType" )