Add zec.rocks lightwalletd server options (#1401)

- Default wallet option changed to zec.rocks:443
- Changleog update
This commit is contained in:
Honza Rychnovský 2024-04-26 13:02:07 +02:00 committed by GitHub
parent 9ca5548ca3
commit 9b2bad6f10
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 160 additions and 117 deletions

View File

@ -9,6 +9,10 @@ directly impact users rather than highlighting other key architectural updates.*
## [Unreleased] ## [Unreleased]
### Changed
- We have added one more group of server options (zec.rocks) for increased coverage and reliability
- zec.rocks:443 is now default wallet option
## [1.0 (630)] - 2024-04-24 ## [1.0 (630)] - 2024-04-24
### Changed ### Changed

View File

@ -21,9 +21,7 @@ import cash.z.ecc.android.sdk.model.WalletBalance
import cash.z.ecc.android.sdk.model.Zatoshi import cash.z.ecc.android.sdk.model.Zatoshi
import cash.z.ecc.android.sdk.model.ZcashNetwork import cash.z.ecc.android.sdk.model.ZcashNetwork
import cash.z.ecc.android.sdk.tool.DerivationTool import cash.z.ecc.android.sdk.tool.DerivationTool
import cash.z.ecc.sdk.extension.defaultForNetwork
import cash.z.ecc.sdk.type.fromResources import cash.z.ecc.sdk.type.fromResources
import co.electriccoin.lightwallet.client.model.LightWalletEndpoint
import co.electriccoin.zcash.global.getInstance import co.electriccoin.zcash.global.getInstance
import co.electriccoin.zcash.spackle.Twig import co.electriccoin.zcash.spackle.Twig
import co.electriccoin.zcash.ui.common.ANDROID_STATE_FLOW_TIMEOUT import co.electriccoin.zcash.ui.common.ANDROID_STATE_FLOW_TIMEOUT
@ -42,6 +40,7 @@ import co.electriccoin.zcash.ui.preference.StandardPreferenceSingleton
import co.electriccoin.zcash.ui.screen.account.ext.TransactionOverviewExt import co.electriccoin.zcash.ui.screen.account.ext.TransactionOverviewExt
import co.electriccoin.zcash.ui.screen.account.ext.getSortHeight import co.electriccoin.zcash.ui.screen.account.ext.getSortHeight
import co.electriccoin.zcash.ui.screen.account.state.TransactionHistorySyncState import co.electriccoin.zcash.ui.screen.account.state.TransactionHistorySyncState
import co.electriccoin.zcash.ui.screen.chooseserver.AvailableServerProvider
import kotlinx.collections.immutable.toPersistentList import kotlinx.collections.immutable.toPersistentList
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
@ -295,7 +294,7 @@ class WalletViewModel(application: Application) : AndroidViewModel(application)
PersistableWallet.new( PersistableWallet.new(
application = application, application = application,
zcashNetwork = zcashNetwork, zcashNetwork = zcashNetwork,
endpoint = LightWalletEndpoint.defaultForNetwork(zcashNetwork), endpoint = AvailableServerProvider.getDefaultServer(zcashNetwork),
walletInitMode = WalletInitMode.NewWallet walletInitMode = WalletInitMode.NewWallet
) )
persistWallet(newWallet) persistWallet(newWallet)

View File

@ -1,7 +1,6 @@
package co.electriccoin.zcash.ui.screen.chooseserver package co.electriccoin.zcash.ui.screen.chooseserver
import cash.z.ecc.android.sdk.model.ZcashNetwork import cash.z.ecc.android.sdk.model.ZcashNetwork
import cash.z.ecc.sdk.extension.Mainnet
import cash.z.ecc.sdk.extension.Testnet import cash.z.ecc.sdk.extension.Testnet
import co.electriccoin.lightwallet.client.model.LightWalletEndpoint import co.electriccoin.lightwallet.client.model.LightWalletEndpoint
import kotlinx.collections.immutable.toImmutableList import kotlinx.collections.immutable.toImmutableList
@ -9,20 +8,14 @@ import kotlinx.collections.immutable.toImmutableList
// TODO [#1273]: Add ChooseServer Tests #1273 // TODO [#1273]: Add ChooseServer Tests #1273
// TODO [#1273]: https://github.com/Electric-Coin-Company/zashi-android/issues/1273 // TODO [#1273]: https://github.com/Electric-Coin-Company/zashi-android/issues/1273
@Suppress("UnusedPrivateProperty")
object AvailableServerProvider { object AvailableServerProvider {
// North America | [na.lightwalletd.com](http://na.lightwalletd.com/) | 443 private const val ZR_HOST = "zec.rocks" // NON-NLS
// South America | [sa.lightwalletd.com](http://sa.lightwalletd.com/) | 443 private const val ZR_HOST_NA = "na.zec.rocks" // NON-NLS
// Europe & Africa | [eu.lightwalletd.com](http://eu.lightwalletd.com/) | 443 private const val ZR_HOST_SA = "sa.zec.rocks" // NON-NLS
// Asia & Oceania | [ai.lightwalletd.com](http://ai.lightwalletd.com/) | 443 private const val ZR_HOST_EU = "eu.zec.rocks" // NON-NLS
// Plus current network defaults: private const val ZR_HOST_AP = "ap.zec.rocks" // NON-NLS
// Mainnet: mainnet.lightwalletd.com | 9067 private const val ZR_PORT = 443
// Testnet: lightwalletd.testnet.electriccoin.co | 9067
private const val NH_HOST_NA = "na.lightwalletd.com" // NON-NLS
private const val NH_HOST_SA = "sa.lightwalletd.com" // NON-NLS
private const val NH_HOST_EU = "eu.lightwalletd.com" // NON-NLS
private const val NH_HOST_AI = "ai.lightwalletd.com" // NON-NLS
private const val NH_PORT = 443
private const val YW_HOST_1 = "lwd1.zcash-infra.com" // NON-NLS private const val YW_HOST_1 = "lwd1.zcash-infra.com" // NON-NLS
private const val YW_HOST_2 = "lwd2.zcash-infra.com" // NON-NLS private const val YW_HOST_2 = "lwd2.zcash-infra.com" // NON-NLS
@ -34,10 +27,24 @@ object AvailableServerProvider {
private const val YW_HOST_8 = "lwd8.zcash-infra.com" // NON-NLS private const val YW_HOST_8 = "lwd8.zcash-infra.com" // NON-NLS
private const val YW_PORT = 9067 private const val YW_PORT = 9067
// NH servers are currently unused and are subject of removal in the future
private const val NH_HOST_NA = "na.lightwalletd.com" // NON-NLS
private const val NH_HOST_SA = "sa.lightwalletd.com" // NON-NLS
private const val NH_HOST_EU = "eu.lightwalletd.com" // NON-NLS
private const val NH_HOST_AI = "ai.lightwalletd.com" // NON-NLS
private const val NH_PORT = 443
fun toList(network: ZcashNetwork) = fun toList(network: ZcashNetwork) =
buildList { buildList {
if (network == ZcashNetwork.Mainnet) { if (network == ZcashNetwork.Mainnet) {
add(LightWalletEndpoint.Mainnet) add(LightWalletEndpoint(ZR_HOST, ZR_PORT, true))
// Custom server item comes here in the view layer
add(LightWalletEndpoint(ZR_HOST_NA, ZR_PORT, true))
add(LightWalletEndpoint(ZR_HOST_SA, ZR_PORT, true))
add(LightWalletEndpoint(ZR_HOST_EU, ZR_PORT, true))
add(LightWalletEndpoint(ZR_HOST_AP, ZR_PORT, true))
add(LightWalletEndpoint(YW_HOST_1, YW_PORT, true)) add(LightWalletEndpoint(YW_HOST_1, YW_PORT, true))
add(LightWalletEndpoint(YW_HOST_2, YW_PORT, true)) add(LightWalletEndpoint(YW_HOST_2, YW_PORT, true))
@ -47,15 +54,12 @@ object AvailableServerProvider {
add(LightWalletEndpoint(YW_HOST_6, YW_PORT, true)) add(LightWalletEndpoint(YW_HOST_6, YW_PORT, true))
add(LightWalletEndpoint(YW_HOST_7, YW_PORT, true)) add(LightWalletEndpoint(YW_HOST_7, YW_PORT, true))
add(LightWalletEndpoint(YW_HOST_8, YW_PORT, true)) add(LightWalletEndpoint(YW_HOST_8, YW_PORT, true))
add(LightWalletEndpoint(NH_HOST_NA, NH_PORT, true))
add(LightWalletEndpoint(NH_HOST_SA, NH_PORT, true))
add(LightWalletEndpoint(NH_HOST_EU, NH_PORT, true))
add(LightWalletEndpoint(NH_HOST_AI, NH_PORT, true))
} else { } else {
add(LightWalletEndpoint.Testnet) add(LightWalletEndpoint.Testnet)
} }
}.toImmutableList() }.toImmutableList()
fun getDefaultServer(zcashNetwork: ZcashNetwork): LightWalletEndpoint = toList(zcashNetwork).first()
} }
// This regex validates server URLs with ports in format: <hostname>:<port> // This regex validates server URLs with ports in format: <hostname>:<port>

View File

@ -1,7 +1,10 @@
@file:Suppress("TooManyFunctions")
package co.electriccoin.zcash.ui.screen.chooseserver.view package co.electriccoin.zcash.ui.screen.chooseserver.view
import androidx.compose.animation.animateContentSize import androidx.compose.animation.animateContentSize
import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
@ -11,6 +14,9 @@ import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.DividerDefaults
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@ -25,7 +31,6 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontStyle import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import cash.z.ecc.android.sdk.internal.Twig import cash.z.ecc.android.sdk.internal.Twig
import cash.z.ecc.android.sdk.model.PersistableWallet import cash.z.ecc.android.sdk.model.PersistableWallet
@ -41,7 +46,6 @@ import co.electriccoin.zcash.ui.design.component.GradientSurface
import co.electriccoin.zcash.ui.design.component.PrimaryButton import co.electriccoin.zcash.ui.design.component.PrimaryButton
import co.electriccoin.zcash.ui.design.component.RadioButton import co.electriccoin.zcash.ui.design.component.RadioButton
import co.electriccoin.zcash.ui.design.component.SmallTopAppBar import co.electriccoin.zcash.ui.design.component.SmallTopAppBar
import co.electriccoin.zcash.ui.design.component.SubHeader
import co.electriccoin.zcash.ui.design.theme.ZcashTheme import co.electriccoin.zcash.ui.design.theme.ZcashTheme
import co.electriccoin.zcash.ui.screen.chooseserver.ChooseServerTag import co.electriccoin.zcash.ui.screen.chooseserver.ChooseServerTag
import co.electriccoin.zcash.ui.screen.chooseserver.validateCustomServerValue import co.electriccoin.zcash.ui.screen.chooseserver.validateCustomServerValue
@ -70,7 +74,7 @@ private fun PreviewChooseServer() {
} }
@Composable @Composable
@Suppress("LongParameterList") @Suppress("LongMethod", "LongParameterList")
fun ChooseServer( fun ChooseServer(
availableServers: ImmutableList<LightWalletEndpoint>, availableServers: ImmutableList<LightWalletEndpoint>,
onBack: () -> Unit, onBack: () -> Unit,
@ -82,80 +86,6 @@ fun ChooseServer(
isShowingSuccessDialog: Boolean, isShowingSuccessDialog: Boolean,
setShowSuccessDialog: (Boolean) -> Unit, setShowSuccessDialog: (Boolean) -> Unit,
walletRestoringState: WalletRestoringState, walletRestoringState: WalletRestoringState,
) {
Scaffold(
topBar = {
ChooseServerTopAppBar(
onBack = onBack,
showRestoring = walletRestoringState == WalletRestoringState.RESTORING,
)
}
) { paddingValues ->
ChooseServerMainContent(
modifier =
Modifier
.verticalScroll(
rememberScrollState()
)
.padding(
top = paddingValues.calculateTopPadding(),
bottom = paddingValues.calculateBottomPadding(),
start = ZcashTheme.dimens.screenHorizontalSpacingRegular,
end = ZcashTheme.dimens.screenHorizontalSpacingRegular
)
.fillMaxWidth(),
availableServers = availableServers,
onServerChange = onServerChange,
setShowErrorDialog = setShowErrorDialog,
validationResult = validationResult,
wallet = wallet,
)
// Show validation popups
if (isShowingErrorDialog && validationResult is ServerValidation.InValid) {
ValidationErrorDialog(
reason = validationResult.reason.message,
onDone = { setShowErrorDialog(false) }
)
} else if (isShowingSuccessDialog) {
SaveSuccessDialog(
onDone = { setShowSuccessDialog(false) }
)
}
}
}
@Composable
private fun ChooseServerTopAppBar(
onBack: () -> Unit,
showRestoring: Boolean
) {
SmallTopAppBar(
restoringLabel =
if (showRestoring) {
stringResource(id = R.string.restoring_wallet_label)
} else {
null
},
modifier = Modifier.testTag(ChooseServerTag.CHOOSE_SERVER_TOP_APP_BAR),
showTitleLogo = true,
backText = stringResource(id = R.string.choose_server_back).uppercase(),
backContentDescriptionText = stringResource(R.string.choose_server_back_content_description),
onBack = onBack,
)
}
const val CUSTOM_SERVER_OPTION_INDEX = 1
@Composable
@Suppress("LongMethod", "LongParameterList")
private fun ChooseServerMainContent(
availableServers: ImmutableList<LightWalletEndpoint>,
onServerChange: (LightWalletEndpoint) -> Unit,
validationResult: ServerValidation,
wallet: PersistableWallet,
modifier: Modifier = Modifier,
setShowErrorDialog: (Boolean) -> Unit,
) { ) {
val options = val options =
availableServers.toMutableList().apply { availableServers.toMutableList().apply {
@ -193,27 +123,84 @@ private fun ChooseServerMainContent(
mutableStateOf(initialCustomServerValue) mutableStateOf(initialCustomServerValue)
} }
Column(modifier = modifier) { Scaffold(
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingLarge)) topBar = {
ChooseServerTopAppBar(
SubHeader( onBack = onBack,
text = stringResource(id = R.string.choose_server_title), showRestoring = walletRestoringState == WalletRestoringState.RESTORING,
textAlign = TextAlign.Center, )
modifier = Modifier.fillMaxWidth() },
) bottomBar = {
ChooseServerBottomBar(
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingLarge)) customServerValue = customServerValue,
onServerChange = onServerChange,
ServerList( options = options,
selectedOption = selectedOption,
setShowErrorDialog = setShowErrorDialog,
validationResult = validationResult,
wallet = wallet
)
}
) { paddingValues ->
ChooseServerMainContent(
customServerValue = customServerValue,
modifier =
Modifier
.verticalScroll(
rememberScrollState()
)
.padding(
top = paddingValues.calculateTopPadding(),
bottom = paddingValues.calculateBottomPadding(),
start = ZcashTheme.dimens.screenHorizontalSpacingRegular,
end = ZcashTheme.dimens.screenHorizontalSpacingRegular
)
.fillMaxWidth(),
options = options, options = options,
selectedOption = selectedOption, selectedOption = selectedOption,
setSelectedOption = setSelectedOption,
customServerValue = customServerValue,
setCustomServerValue = setCustomServerValue, setCustomServerValue = setCustomServerValue,
modifier = Modifier.fillMaxWidth() setSelectedOption = setSelectedOption,
) )
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingLarge)) // Show validation popups
if (isShowingErrorDialog && validationResult is ServerValidation.InValid) {
ValidationErrorDialog(
reason = validationResult.reason.message,
onDone = { setShowErrorDialog(false) }
)
} else if (isShowingSuccessDialog) {
SaveSuccessDialog(
onDone = { setShowSuccessDialog(false) }
)
}
}
}
@Composable
@Suppress("LongParameterList")
fun ChooseServerBottomBar(
customServerValue: String,
onServerChange: (LightWalletEndpoint) -> Unit,
options: ImmutableList<LightWalletEndpoint>,
selectedOption: Int,
setShowErrorDialog: (Boolean) -> Unit,
validationResult: ServerValidation,
wallet: PersistableWallet,
modifier: Modifier = Modifier,
) {
Column(
modifier =
modifier.then(
Modifier
.background(MaterialTheme.colorScheme.surface)
)
) {
HorizontalDivider(
thickness = DividerDefaults.Thickness,
color = ZcashTheme.colors.dividerColor
)
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingSmall))
SaveButton( SaveButton(
enabled = validationResult != ServerValidation.Running, enabled = validationResult != ServerValidation.Running,
@ -227,13 +214,62 @@ private fun ChooseServerMainContent(
}, },
setShowErrorDialog = setShowErrorDialog, setShowErrorDialog = setShowErrorDialog,
selectedOption = selectedOption, selectedOption = selectedOption,
modifier = Modifier.padding(horizontal = ZcashTheme.dimens.spacingUpLarge) modifier = Modifier.padding(horizontal = ZcashTheme.dimens.screenHorizontalSpacingBig)
) )
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingHuge)) Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingHuge))
} }
} }
@Composable
private fun ChooseServerTopAppBar(
onBack: () -> Unit,
showRestoring: Boolean
) {
SmallTopAppBar(
titleText = stringResource(id = R.string.choose_server_title),
restoringLabel =
if (showRestoring) {
stringResource(id = R.string.restoring_wallet_label)
} else {
null
},
modifier = Modifier.testTag(ChooseServerTag.CHOOSE_SERVER_TOP_APP_BAR),
showTitleLogo = true,
backText = stringResource(id = R.string.choose_server_back).uppercase(),
backContentDescriptionText = stringResource(R.string.choose_server_back_content_description),
onBack = onBack,
)
}
const val CUSTOM_SERVER_OPTION_INDEX = 1
@Composable
@Suppress("LongParameterList")
private fun ChooseServerMainContent(
customServerValue: String,
options: ImmutableList<LightWalletEndpoint>,
selectedOption: Int,
setCustomServerValue: (String) -> Unit,
setSelectedOption: (Int) -> Unit,
modifier: Modifier = Modifier,
) {
Column(modifier = modifier) {
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingDefault))
ServerList(
options = options,
selectedOption = selectedOption,
setSelectedOption = setSelectedOption,
customServerValue = customServerValue,
setCustomServerValue = setCustomServerValue,
modifier = Modifier.fillMaxWidth()
)
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingDefault))
}
}
@OptIn(ExperimentalFoundationApi::class) @OptIn(ExperimentalFoundationApi::class)
@Composable @Composable
@Suppress("LongParameterList") @Suppress("LongParameterList")