mirror of
https://github.com/pezkuwichain/pezkuwi-wallet-android.git
synced 2026-07-22 18:25:50 +00:00
fix: cloud backup schema dropped Tron address/keypair on every round trip
WalletPublicInfo/WalletPrivateInfo had no tron field at all, so any wallet created via the (default) cloud-backup wallet creation flow, or restored from a cloud backup, silently lost its Tron address and keypair even though AccountSecretsFactory/SecretsMetaAccountLocalFactory derived them correctly moments earlier - this is why TRX/USDT-TRC20 never appeared for any wallet, new or old, confirmed via a device-side diagnostic dump of the actual DB row (tronAddress=NULL) after a fresh wallet creation. Also reserves (but does not wire up) solana/bitcoin fields in the same schema, since native derivation for those doesn't exist yet - adding them now means that work won't need another silent-drop-prone pass through this same schema later. Adds a regression test exercising the exact apply-diff path that lost the data, plus tron support in the shared cloud-backup test builder DSL.
This commit is contained in:
+55
-3
@@ -23,7 +23,19 @@ data class CloudBackup(
|
||||
val ethereumPublicKey: ByteArray?,
|
||||
val name: String,
|
||||
val type: Type,
|
||||
val chainAccounts: Set<ChainAccountInfo>
|
||||
val chainAccounts: Set<ChainAccountInfo>,
|
||||
// All three below are nullable and defaulted so that Gson deserializing a backup written before that
|
||||
// particular chain family existed - which has no such field in its JSON at all - lands on null here
|
||||
// rather than failing. Solana/bitcoin have no derivation anywhere in this codebase yet (no native
|
||||
// support, unlike Tron) - the fields are reserved now purely so that adding that support later never
|
||||
// needs another silent-drop-prone trip through every call site that touches this schema, the way Tron
|
||||
// did when it was bolted onto a schema that only knew about substrate/ethereum.
|
||||
val tronAddress: ByteArray? = null,
|
||||
val tronPublicKey: ByteArray? = null,
|
||||
val solanaAddress: ByteArray? = null,
|
||||
val solanaPublicKey: ByteArray? = null,
|
||||
val bitcoinAddress: ByteArray? = null,
|
||||
val bitcoinPublicKey: ByteArray? = null,
|
||||
) : Identifiable {
|
||||
|
||||
override val identifier: String = walletId
|
||||
@@ -72,7 +84,13 @@ data class CloudBackup(
|
||||
ethereumPublicKey.contentEquals(other.ethereumPublicKey) &&
|
||||
name == other.name &&
|
||||
type == other.type &&
|
||||
chainAccounts == other.chainAccounts
|
||||
chainAccounts == other.chainAccounts &&
|
||||
tronAddress.contentEquals(other.tronAddress) &&
|
||||
tronPublicKey.contentEquals(other.tronPublicKey) &&
|
||||
solanaAddress.contentEquals(other.solanaAddress) &&
|
||||
solanaPublicKey.contentEquals(other.solanaPublicKey) &&
|
||||
bitcoinAddress.contentEquals(other.bitcoinAddress) &&
|
||||
bitcoinPublicKey.contentEquals(other.bitcoinPublicKey)
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
@@ -85,6 +103,12 @@ data class CloudBackup(
|
||||
result = 31 * result + name.hashCode()
|
||||
result = 31 * result + type.hashCode()
|
||||
result = 31 * result + chainAccounts.hashCode()
|
||||
result = 31 * result + (tronAddress?.contentHashCode() ?: 0)
|
||||
result = 31 * result + (tronPublicKey?.contentHashCode() ?: 0)
|
||||
result = 31 * result + (solanaAddress?.contentHashCode() ?: 0)
|
||||
result = 31 * result + (solanaPublicKey?.contentHashCode() ?: 0)
|
||||
result = 31 * result + (bitcoinAddress?.contentHashCode() ?: 0)
|
||||
result = 31 * result + (bitcoinPublicKey?.contentHashCode() ?: 0)
|
||||
result = 31 * result + identifier.hashCode()
|
||||
return result
|
||||
}
|
||||
@@ -100,6 +124,11 @@ data class CloudBackup(
|
||||
val substrate: SubstrateSecrets?,
|
||||
val ethereum: EthereumSecrets?,
|
||||
val chainAccounts: List<ChainAccountSecrets>,
|
||||
// See the matching comment on WalletPublicInfo: tron is fully wired end to end, solana/bitcoin are
|
||||
// schema-only reservations until native derivation for them exists.
|
||||
val tron: TronSecrets? = null,
|
||||
val solana: SolanaSecrets? = null,
|
||||
val bitcoin: BitcoinSecrets? = null,
|
||||
) : Identifiable {
|
||||
|
||||
override val identifier: String = walletId
|
||||
@@ -118,6 +147,9 @@ data class CloudBackup(
|
||||
if (substrate != other.substrate) return false
|
||||
if (ethereum != other.ethereum) return false
|
||||
if (chainAccounts != other.chainAccounts) return false
|
||||
if (tron != other.tron) return false
|
||||
if (solana != other.solana) return false
|
||||
if (bitcoin != other.bitcoin) return false
|
||||
return identifier == other.identifier
|
||||
}
|
||||
|
||||
@@ -127,6 +159,9 @@ data class CloudBackup(
|
||||
result = 31 * result + (substrate?.hashCode() ?: 0)
|
||||
result = 31 * result + (ethereum?.hashCode() ?: 0)
|
||||
result = 31 * result + chainAccounts.hashCode()
|
||||
result = 31 * result + (tron?.hashCode() ?: 0)
|
||||
result = 31 * result + (solana?.hashCode() ?: 0)
|
||||
result = 31 * result + (bitcoin?.hashCode() ?: 0)
|
||||
result = 31 * result + identifier.hashCode()
|
||||
return result
|
||||
}
|
||||
@@ -201,6 +236,23 @@ data class CloudBackup(
|
||||
val derivationPath: String?,
|
||||
)
|
||||
|
||||
data class TronSecrets(
|
||||
val keypair: KeyPairSecrets,
|
||||
val derivationPath: String?,
|
||||
)
|
||||
|
||||
// Reserved shape for when native Solana derivation is added - unused until then, see the class-level comment.
|
||||
data class SolanaSecrets(
|
||||
val keypair: KeyPairSecrets,
|
||||
val derivationPath: String?,
|
||||
)
|
||||
|
||||
// Reserved shape for when native Bitcoin derivation is added - unused until then, see the class-level comment.
|
||||
data class BitcoinSecrets(
|
||||
val keypair: KeyPairSecrets,
|
||||
val derivationPath: String?,
|
||||
)
|
||||
|
||||
data class KeyPairSecrets(
|
||||
val publicKey: ByteArray,
|
||||
val privateKey: ByteArray,
|
||||
@@ -234,5 +286,5 @@ data class CloudBackup(
|
||||
}
|
||||
|
||||
fun CloudBackup.WalletPrivateInfo.isCompletelyEmpty(): Boolean {
|
||||
return entropy == null && substrate == null && ethereum == null && chainAccounts.isEmpty()
|
||||
return entropy == null && substrate == null && ethereum == null && tron == null && chainAccounts.isEmpty()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user