Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

backend/frontend: add option to restart in testnet #3157

Merged
merged 1 commit into from
Feb 6, 2025
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
- Fix the copy buttons in the Pocket order confirmation page
- Android: handle device disconnect while the app is in the background
- Improve send result view show relevant infos and options to make a new transaction or go back
- Added an option in advanced settings to allow the app to start in testnet at the next restart.

# 4.46.3
- Fix camera access on linux
Expand Down
4 changes: 2 additions & 2 deletions backend/accounts.go
Original file line number Diff line number Diff line change
Expand Up @@ -1196,7 +1196,7 @@ outer:
// a user-facing setting. Now we simply use it for migration to decide which coins to add by
// default.
func (backend *Backend) persistDefaultAccountConfigs(keystore keystore.Keystore, accountsConfig *config.AccountsConfig) error {
if backend.arguments.Testing() {
if backend.Testing() {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I replaced all occurrences of backend.arguments.Testing() with backend.Testing. Prior to this PR the two calls are the same (backend.Testing() calls backend.arguments.Testing()) but with this new PR there is more logic in backend.Testing() - The alternative would have be to change the field arguments.testing but since everything in arguments is unexported I prefer not to

if backend.arguments.Regtest() {
if backend.config.AppConfig().Backend.DeprecatedCoinActive(coinpkg.CodeRBTC) {
if _, err := backend.createAndPersistAccountConfig(
Expand Down Expand Up @@ -1458,7 +1458,7 @@ func (backend *Backend) maybeAddHiddenUnusedAccounts() {
switch {
case backend.arguments.Regtest():
coinCodes = []coinpkg.Code{coinpkg.CodeRBTC}
case backend.arguments.Testing():
case backend.Testing():
coinCodes = []coinpkg.Code{coinpkg.CodeTBTC, coinpkg.CodeTLTC}
default:
coinCodes = []coinpkg.Code{coinpkg.CodeBTC, coinpkg.CodeLTC}
Expand Down
28 changes: 20 additions & 8 deletions backend/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -232,20 +232,23 @@ type Backend struct {
tstCheckAccountUsed func(accounts.Interface) bool
// For unit tests, called when `backend.maybeAddHiddenUnusedAccounts()` has run.
tstMaybeAddHiddenUnusedAccounts func()

// testing tells us whether the app is in testing mode
testing bool
}

// NewBackend creates a new backend with the given arguments.
func NewBackend(arguments *arguments.Arguments, environment Environment) (*Backend, error) {
log := logging.Get().WithGroup("backend")
config, err := config.NewConfig(arguments.AppConfigFilename(), arguments.AccountsConfigFilename())
backendConfig, err := config.NewConfig(arguments.AppConfigFilename(), arguments.AccountsConfigFilename())
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

renaming because I later need to use config as an import name

if err != nil {
return nil, errp.WithStack(err)
}
log.Infof("backend config: %+v", config.AppConfig().Backend)
log.Infof("frontend config: %+v", config.AppConfig().Frontend)
log.Infof("backend config: %+v", backendConfig.AppConfig().Backend)
log.Infof("frontend config: %+v", backendConfig.AppConfig().Frontend)
backendProxy := socksproxy.NewSocksProxy(
config.AppConfig().Backend.Proxy.UseProxy,
config.AppConfig().Backend.Proxy.ProxyAddress,
backendConfig.AppConfig().Backend.Proxy.UseProxy,
backendConfig.AppConfig().Backend.Proxy.ProxyAddress,
)
hclient, err := backendProxy.GetHTTPClient()
if err != nil {
Expand All @@ -255,7 +258,7 @@ func NewBackend(arguments *arguments.Arguments, environment Environment) (*Backe
backend := &Backend{
arguments: arguments,
environment: environment,
config: config,
config: backendConfig,
events: make(chan interface{}, 1000),

devices: map[string]device.Interface{},
Expand All @@ -271,7 +274,10 @@ func NewBackend(arguments *arguments.Arguments, environment Environment) (*Backe
},

log: log,

testing: backendConfig.AppConfig().Backend.StartInTestnet || arguments.Testing(),
}

notifier, err := NewNotifier(filepath.Join(arguments.MainDirectoryPath(), "notifier.db"))
if err != nil {
return nil, err
Expand Down Expand Up @@ -540,7 +546,7 @@ func (backend *Backend) Coin(code coinpkg.Code) (coinpkg.Coin, error) {
// Calling this is a no-op for coins that are already connected.
func (backend *Backend) ManualReconnect() {
var electrumCoinCodes []coinpkg.Code
if backend.arguments.Testing() {
if backend.Testing() {
electrumCoinCodes = []coinpkg.Code{
coinpkg.CodeTBTC,
coinpkg.CodeTLTC,
Expand Down Expand Up @@ -574,7 +580,7 @@ func (backend *Backend) ManualReconnect() {

// Testing returns whether this backend is for testing only.
func (backend *Backend) Testing() bool {
return backend.arguments.Testing()
return backend.testing
}

// Accounts returns the current accounts of the backend.
Expand Down Expand Up @@ -638,6 +644,12 @@ func (backend *Backend) Start() <-chan interface{} {
backend.configureHistoryExchangeRates()

backend.environment.OnAuthSettingChanged(backend.config.AppConfig().Backend.Authentication)

if backend.DefaultAppConfig().Backend.StartInTestnet {
if err := backend.config.ModifyAppConfig(func(c *config.AppConfig) error { c.Backend.StartInTestnet = false; return nil }); err != nil {
backend.log.WithError(err).Error("Can't set StartInTestnet to false")
}
}
return backend.events
}

Expand Down
4 changes: 4 additions & 0 deletions backend/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,10 @@ type Backend struct {

// BtcUnit is the unit used to represent Bitcoin amounts. See `coin.BtcUnit` for details.
BtcUnit coin.BtcUnit `json:"btcUnit"`

// StartInTestnet represents whether the app should launch in testnet on the next start.
// It resets to `false` after the app starts.
StartInTestnet bool `json:"startInTestnet"`
}

// DeprecatedCoinActive returns the Active setting for a coin by code. This call is should not be
Expand Down
4 changes: 4 additions & 0 deletions frontends/web/src/locales/en/app.json
Original file line number Diff line number Diff line change
Expand Up @@ -1318,6 +1318,9 @@
"customFees": {
"description": "Lets you enter your own fee when sending."
},
"restartInTestnet": {
"description": "Explore and test features by using testnet."
},
"torProxy": {
"description": "Connect over Tor for better privacy."
}
Expand Down Expand Up @@ -1725,6 +1728,7 @@
"title": "Export logs"
},
"fee": "Enable custom fees",
"restartInTestnet": "Testnet mode",
"setProxyAddress": "Set proxy address",
"title": "Expert settings",
"useProxy": "Enable tor proxy",
Expand Down
4 changes: 3 additions & 1 deletion frontends/web/src/routes/settings/advanced-settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import { EnableCustomFeesToggleSetting } from './components/advanced-settings/en
import { EnableCoinControlSetting } from './components/advanced-settings/enable-coin-control-setting';
import { ConnectFullNodeSetting } from './components/advanced-settings/connect-full-node-setting';
import { EnableTorProxySetting } from './components/advanced-settings/enable-tor-proxy-setting';
import { RestartInTestnetSetting } from './components/advanced-settings/restart-in-testnet-setting';
import { ExportLogSetting } from './components/advanced-settings/export-log-setting';
import { getConfig } from '@/utils/config';
import { MobileHeader } from './components/mobile-header';
Expand All @@ -47,7 +48,7 @@ export type TFrontendConfig = {
export type TBackendConfig = {
proxy?: TProxyConfig
authentication?: boolean;

restartInTestnet?: boolean;
}

export type TConfig = {
Expand Down Expand Up @@ -94,6 +95,7 @@ export const AdvancedSettings = ({ deviceIDs, hasAccounts }: TPagePropsWithSetti
<EnableCoinControlSetting frontendConfig={frontendConfig} onChangeConfig={setConfig} />
<EnableAuthSetting backendConfig={backendConfig} onChangeConfig={setConfig} />
<EnableTorProxySetting proxyConfig={proxyConfig} onChangeConfig={setConfig} />
<RestartInTestnetSetting backendConfig={backendConfig} onChangeConfig={setConfig} />
<ConnectFullNodeSetting />
<ExportLogSetting />
</WithSettingsTabs>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@

/**
* Copyright 2025 Shift Crypto AG
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { ChangeEvent, Dispatch } from 'react';
import { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { SettingsItem } from '@/routes/settings/components/settingsItem/settingsItem';
import { Toggle } from '@/components/toggle/toggle';
import { TConfig, TBackendConfig } from '@/routes/settings/advanced-settings';
import { Message } from '@/components/message/message';
import { setConfig } from '@/utils/config';
import styles from './enable-tor-proxy-setting.module.css';

type TProps = {
backendConfig?: TBackendConfig;
onChangeConfig: Dispatch<TConfig>;
}

export const RestartInTestnetSetting = ({ backendConfig, onChangeConfig }: TProps) => {
const { t } = useTranslation();
const [showRestartMessage, setShowRestartMessage] = useState(false);


const handleToggleRestartInTestnet = async (e: ChangeEvent<HTMLInputElement>) => {
setShowRestartMessage(e.target.checked);
const config = await setConfig({
backend: {
'restartInTestnet': e.target.checked
},
}) as TConfig;
onChangeConfig(config);
};
return (
<>
{ showRestartMessage ? (
<Message type="warning">
{t('settings.restart')}
</Message>
) : null }
<SettingsItem
className={styles.settingItem}
settingName={t('settings.expert.restartInTestnet')}
secondaryText={t('newSettings.advancedSettings.restartInTestnet.description')}
extraComponent={
backendConfig !== undefined ? (
<Toggle
checked={backendConfig?.restartInTestnet || false}
onChange={handleToggleRestartInTestnet}
/>
) : null
}
/>
</>
);
};