[Android] wallet P3A refactor

This commit is contained in:
wchen342
2022-12-06 17:27:29 +02:00
parent 81882f0c6b
commit f8a7e6d6aa
5 changed files with 216 additions and 78 deletions
@@ -216,13 +216,6 @@ public class BraveWalletActivity extends BraveWalletBaseActivity implements OnNe
}
});
}
// Delay active wallet P3A report to avoid too many RPC calls at once
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
Utils.reportActiveWalletsForP3A(BraveWalletActivity.this);
}
}, 10000);
}
@Override
@@ -342,7 +342,7 @@ public class BraveWalletPanel implements DialogInterface {
BalanceHelper.getNativeAssetsBalances(
mBraveWalletPanelServices.getJsonRpcService(),
selectedNetwork, new AccountInfo[] {selectedAccount},
nativeAssetsBalances -> {
(coinType, nativeAssetsBalances) -> {
double price = Utils.getOrDefault(assetPrices,
asset.symbol.toLowerCase(Locale.getDefault()),
0.0d);
@@ -22,6 +22,7 @@ import org.chromium.brave_wallet.mojom.TxService;
import org.chromium.mojo.bindings.Callbacks;
import java.util.HashMap;
import java.util.HashSet;
public class AsyncUtils {
private final static String TAG = "AsyncUtils";
@@ -279,7 +280,8 @@ public class AsyncUtils {
}
public static class GetNativeAssetsBalancesResponseContext extends SingleResponseBaseContext
implements Callbacks.Callback1<HashMap<String, Double>> {
implements Callbacks.Callback2<Integer, HashMap<String, Double>> {
public int coinType;
public HashMap<String, Double> nativeAssetsBalances;
public GetNativeAssetsBalancesResponseContext(Runnable responseCompleteCallback) {
@@ -287,22 +289,26 @@ public class AsyncUtils {
}
@Override
public void call(HashMap<String, Double> nativeAssetsBalances) {
public void call(Integer coinType, HashMap<String, Double> nativeAssetsBalances) {
this.coinType = coinType;
this.nativeAssetsBalances = nativeAssetsBalances;
super.fireResponseCompleteCallback();
}
}
public static class GetBlockchainTokensBalancesResponseContext extends SingleResponseBaseContext
implements Callbacks.Callback1<HashMap<String, HashMap<String, Double>>> {
implements Callbacks.Callback2<Integer, HashMap<String, HashMap<String, Double>>> {
public HashMap<String, HashMap<String, Double>> blockchainTokensBalances;
public int coinType;
public GetBlockchainTokensBalancesResponseContext(Runnable responseCompleteCallback) {
super(responseCompleteCallback);
}
@Override
public void call(HashMap<String, HashMap<String, Double>> blockchainTokensBalances) {
public void call(Integer coinType,
HashMap<String, HashMap<String, Double>> blockchainTokensBalances) {
this.coinType = coinType;
this.blockchainTokensBalances = blockchainTokensBalances;
super.fireResponseCompleteCallback();
}
@@ -368,4 +374,19 @@ public class AsyncUtils {
super.fireResponseCompleteCallback();
}
}
public static class GetP3ABalancesContext extends SingleResponseBaseContext
implements Callbacks.Callback1<HashMap<Integer, HashSet<String>>> {
public HashMap<Integer, HashSet<String>> activeAddresses;
public GetP3ABalancesContext(Runnable responseCompleteCallback) {
super(responseCompleteCallback);
}
@Override
public void call(HashMap<Integer, HashSet<String>> activeAddresses) {
this.activeAddresses = activeAddresses;
super.fireResponseCompleteCallback();
}
}
}
@@ -10,18 +10,26 @@ import org.chromium.brave_wallet.mojom.AccountInfo;
import org.chromium.brave_wallet.mojom.AssetPrice;
import org.chromium.brave_wallet.mojom.AssetPriceTimeframe;
import org.chromium.brave_wallet.mojom.AssetRatioService;
import org.chromium.brave_wallet.mojom.BlockchainRegistry;
import org.chromium.brave_wallet.mojom.BlockchainToken;
import org.chromium.brave_wallet.mojom.BraveWalletService;
import org.chromium.brave_wallet.mojom.CoinType;
import org.chromium.brave_wallet.mojom.JsonRpcService;
import org.chromium.brave_wallet.mojom.KeyringService;
import org.chromium.brave_wallet.mojom.NetworkInfo;
import org.chromium.brave_wallet.mojom.ProviderError;
import org.chromium.chrome.browser.BraveConfig;
import org.chromium.chrome.browser.crypto_wallet.activities.BraveWalletBaseActivity;
import org.chromium.chrome.browser.crypto_wallet.util.AssetUtils;
import org.chromium.chrome.browser.preferences.BravePrefServiceBridge;
import org.chromium.mojo.bindings.Callbacks;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.stream.Stream;
import java.util.Map;
public class BalanceHelper {
private static String TAG = "BalanceHelper";
@@ -31,7 +39,7 @@ public class BalanceHelper {
*/
public static void getNativeAssetsBalances(JsonRpcService jsonRpcService,
NetworkInfo selectedNetwork, AccountInfo[] accountInfos,
Callbacks.Callback1<HashMap<String, Double>> callback) {
Callbacks.Callback2<Integer, HashMap<String, Double>> callback) {
if (jsonRpcService == null) return;
HashMap<String, Double> nativeAssetsBalances = new HashMap<String, Double>();
@@ -75,7 +83,7 @@ public class BalanceHelper {
nativeAssetsBalances.put(context.accountAddress, nativeAssetBalance);
}
callback.call(nativeAssetsBalances);
callback.call(selectedNetwork.coin, nativeAssetsBalances);
});
}
@@ -86,7 +94,7 @@ public class BalanceHelper {
*/
public static void getBlockchainTokensBalances(JsonRpcService jsonRpcService,
NetworkInfo selectedNetwork, AccountInfo[] accountInfos, BlockchainToken[] tokens,
Callbacks.Callback1<HashMap<String, HashMap<String, Double>>> callback) {
Callbacks.Callback2<Integer, HashMap<String, HashMap<String, Double>>> callback) {
if (jsonRpcService == null) return;
HashMap<String, HashMap<String, Double>> blockchainTokensBalances =
new HashMap<String, HashMap<String, Double>>();
@@ -169,10 +177,93 @@ public class BalanceHelper {
}
}
callback.call(blockchainTokensBalances);
callback.call(selectedNetwork.coin, blockchainTokensBalances);
});
}
public static void getP3ABalances(BraveWalletBaseActivity activity, NetworkInfo selectedNetwork,
Callbacks.Callback1<HashMap<Integer, HashSet<String>>> callback) {
KeyringService keyringService = activity.getKeyringService();
BraveWalletService braveWalletService = activity.getBraveWalletService();
BlockchainRegistry blockchainRegistry = activity.getBlockchainRegistry();
JsonRpcService jsonRpcService = activity.getJsonRpcService();
assert braveWalletService != null && blockchainRegistry != null && keyringService != null
&& jsonRpcService != null;
boolean P3AEnabled =
BraveConfig.P3A_ENABLED && BravePrefServiceBridge.getInstance().getP3AEnabled();
HashMap<Integer, HashSet<String>> activeAddresses = new HashMap<Integer, HashSet<String>>();
for (int coinType : Utils.P3ACoinTypes)
activeAddresses.put(coinType, new HashSet<String>());
if (!P3AEnabled) {
callback.call(activeAddresses);
return;
} else {
Utils.getP3ANetworks(relevantNetworks -> {
// Exclude selectedNetwork if in relevantNetworks, also sort by CoinType
HashMap<Integer, ArrayList<NetworkInfo>> sortedNetworks =
filterAndSortNetworksP3A(relevantNetworks, selectedNetwork);
int numNetworks = 0;
for (int coinType : Utils.P3ACoinTypes)
numNetworks += sortedNetworks.get(coinType).size();
AsyncUtils.MultiResponseHandler multiResponse =
new AsyncUtils.MultiResponseHandler(numNetworks * 2);
ArrayList<AsyncUtils.GetNativeAssetsBalancesResponseContext>
nativeAssetsBalancesResponses =
new ArrayList<AsyncUtils.GetNativeAssetsBalancesResponseContext>();
ArrayList<AsyncUtils.GetBlockchainTokensBalancesResponseContext>
blockchainTokensBalancesResponses = new ArrayList<
AsyncUtils.GetBlockchainTokensBalancesResponseContext>();
for (int coinType : Utils.P3ACoinTypes) {
keyringService.getKeyringInfo(AssetUtils.getKeyringForCoinType(coinType), keyringInfo -> {
for (NetworkInfo network : sortedNetworks.get(coinType)) {
TokenUtils.getUserOrAllTokensFiltered(braveWalletService,
blockchainRegistry, network, coinType, TokenUtils.TokenType.ALL,
true, tokens -> {
AsyncUtils.GetNativeAssetsBalancesResponseContext
getNativeAssetsBalancesContext =
new AsyncUtils
.GetNativeAssetsBalancesResponseContext(
multiResponse
.singleResponseComplete);
getNativeAssetsBalances(jsonRpcService, network,
keyringInfo.accountInfos,
getNativeAssetsBalancesContext);
nativeAssetsBalancesResponses.add(
getNativeAssetsBalancesContext);
AsyncUtils.GetBlockchainTokensBalancesResponseContext
getBlockchainTokensBalancesContext =
new AsyncUtils
.GetBlockchainTokensBalancesResponseContext(
multiResponse
.singleResponseComplete);
getBlockchainTokensBalances(jsonRpcService, network,
keyringInfo.accountInfos, tokens,
getBlockchainTokensBalancesContext);
blockchainTokensBalancesResponses.add(
getBlockchainTokensBalancesContext);
});
}
});
}
multiResponse.setWhenAllCompletedAction(() -> {
updateActiveAddresses(
nativeAssetsBalancesResponses.toArray(
new AsyncUtils.GetNativeAssetsBalancesResponseContext[0]),
blockchainTokensBalancesResponses.toArray(
new AsyncUtils.GetBlockchainTokensBalancesResponseContext[0]),
activeAddresses);
callback.call(activeAddresses);
});
});
}
}
private static <T extends AsyncUtils.GetBalanceResponseBaseContext> T addBalanceResponseContext(
ArrayList<AsyncUtils.GetBalanceResponseBaseContext> contexts, T context,
String accountAddress, BlockchainToken token) {
@@ -181,4 +272,52 @@ public class BalanceHelper {
contexts.add(context);
return context;
}
private static HashMap<Integer, ArrayList<NetworkInfo>> filterAndSortNetworksP3A(
NetworkInfo[] relevantNetworks, NetworkInfo selectedNetwork) {
HashMap<Integer, ArrayList<NetworkInfo>> networksPerCoin =
new HashMap<Integer, ArrayList<NetworkInfo>>();
networksPerCoin.put(CoinType.ETH, new ArrayList<NetworkInfo>());
networksPerCoin.put(CoinType.SOL, new ArrayList<NetworkInfo>());
networksPerCoin.put(CoinType.FIL, new ArrayList<NetworkInfo>());
for (NetworkInfo network : relevantNetworks) {
if (network.chainId.equals(selectedNetwork.chainId)) continue;
switch (network.coin) {
case CoinType.ETH:
networksPerCoin.get(CoinType.ETH).add(network);
break;
case CoinType.SOL:
networksPerCoin.get(CoinType.SOL).add(network);
break;
case CoinType.FIL:
networksPerCoin.get(CoinType.FIL).add(network);
break;
}
}
return networksPerCoin;
}
public static void updateActiveAddresses(
AsyncUtils.GetNativeAssetsBalancesResponseContext[] nativeAssetsBalancesResponses,
AsyncUtils
.GetBlockchainTokensBalancesResponseContext[] blockchainTokensBalancesResponses,
HashMap<Integer, HashSet<String>> activeAddresses) {
for (AsyncUtils.GetNativeAssetsBalancesResponseContext ctx :
nativeAssetsBalancesResponses) {
for (Map.Entry<String, Double> nativeEntry : ctx.nativeAssetsBalances.entrySet()) {
if (nativeEntry.getValue() > 0.0d)
activeAddresses.get(ctx.coinType).add(nativeEntry.getKey());
}
}
for (AsyncUtils.GetBlockchainTokensBalancesResponseContext ctx :
blockchainTokensBalancesResponses) {
for (Map.Entry<String, HashMap<String, Double>> accEntry :
ctx.blockchainTokensBalances.entrySet()) {
for (Map.Entry<String, Double> tokenEntry : accEntry.getValue().entrySet()) {
if (tokenEntry.getValue() > 0.0d)
activeAddresses.get(ctx.coinType).add(accEntry.getKey());
}
}
}
}
}
@@ -94,6 +94,7 @@ import org.chromium.chrome.browser.crypto_wallet.model.WalletListItemModel;
import org.chromium.chrome.browser.crypto_wallet.observers.ApprovedTxObserver;
import org.chromium.chrome.browser.crypto_wallet.util.WalletConstants;
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.chrome.browser.util.LiveDataUtil;
import org.chromium.chrome.browser.util.TabUtils;
import org.chromium.mojo.bindings.Callbacks;
import org.chromium.ui.text.NoUnderlineClickableSpan;
@@ -162,6 +163,9 @@ public class Utils {
public static final BigInteger MAX_UINT256 =
BigInteger.ONE.shiftLeft(256).subtract(BigInteger.ONE);
// TODO(djandries): Add Filecoin when implemented
public static int[] P3ACoinTypes = {CoinType.ETH, CoinType.SOL};
private static final int CLEAR_CLIPBOARD_INTERVAL = 60000; // In milliseconds
public static List<String> getRecoveryPhraseAsList(String recoveryPhrase) {
@@ -1477,7 +1481,9 @@ public class Utils {
JsonRpcService jsonRpcService = activity.getJsonRpcService();
assert braveWalletService != null && blockchainRegistry != null && assetRatioService != null
&& jsonRpcService != null;
AsyncUtils.MultiResponseHandler multiResponse = new AsyncUtils.MultiResponseHandler(3);
BraveWalletP3a braveWalletP3A = activity.getBraveWalletP3A();
AsyncUtils.MultiResponseHandler multiResponse = new AsyncUtils.MultiResponseHandler(4);
TokenUtils.getUserOrAllTokensFiltered(braveWalletService, blockchainRegistry,
selectedNetwork, selectedNetwork.coin, TokenUtils.TokenType.ALL, userAssetsOnly,
@@ -1509,7 +1515,26 @@ public class Utils {
BalanceHelper.getBlockchainTokensBalances(jsonRpcService, selectedNetwork,
accountInfos, tokens, getBlockchainTokensBalancesContext);
AsyncUtils.GetP3ABalancesContext getP3ABalancesContext =
new AsyncUtils.GetP3ABalancesContext(
multiResponse.singleResponseComplete);
BalanceHelper.getP3ABalances(activity, selectedNetwork, getP3ABalancesContext);
multiResponse.setWhenAllCompletedAction(() -> {
// P3A active accounts
HashMap<Integer, HashSet<String>> activeAddresses =
getP3ABalancesContext.activeAddresses;
BalanceHelper.updateActiveAddresses(
new AsyncUtils.GetNativeAssetsBalancesResponseContext[] {
getNativeAssetsBalancesContext},
new AsyncUtils.GetBlockchainTokensBalancesResponseContext[] {
getBlockchainTokensBalancesContext},
activeAddresses);
for (int coinType : P3ACoinTypes) {
braveWalletP3A.recordActiveWalletCount(
activeAddresses.get(coinType).size(), coinType);
}
callback.call(fetchPricesContext.assetPrices, fullTokenList,
getNativeAssetsBalancesContext.nativeAssetsBalances,
getBlockchainTokensBalancesContext.blockchainTokensBalances);
@@ -1517,70 +1542,30 @@ public class Utils {
});
}
public static void reportActiveWalletsForP3A(BraveWalletBaseActivity activity) {
reportActiveCoinWalletsForP3A(activity, CoinType.ETH);
reportActiveCoinWalletsForP3A(activity, CoinType.SOL);
// TODO(djandries): Add Filecoin when implemented
}
private static void reportActiveCoinWalletsForP3A(
BraveWalletBaseActivity activity, int coinType) {
BraveWalletP3a braveWalletP3A = activity.getBraveWalletP3A();
KeyringService keyringService = activity.getKeyringService();
JsonRpcService jsonRpcService = activity.getJsonRpcService();
assert braveWalletP3A != null && keyringService != null && jsonRpcService != null;
public static void getP3ANetworks(Callbacks.Callback1<NetworkInfo[]> callback) {
BraveActivity activity = BraveActivity.getBraveActivity();
if (activity == null) {
callback.call(new NetworkInfo[0]);
}
ArrayList<NetworkInfo> relevantNetworks = new ArrayList<NetworkInfo>();
boolean countTestNetworks = CommandLine.getInstance().hasSwitch(
BraveWalletConstants.P3A_COUNT_TEST_NETWORKS_SWITCH);
LiveDataUtil.observeOnce(
activity.getWalletModel().getCryptoModel().getNetworkModel().mCryptoNetworks,
allNetworks -> {
for (NetworkInfo network : allNetworks) {
// Exclude testnet chain data by default.
// Testnet chain counting can be enabled via the
// --p3a-count-wallet-test-networks switch
if (countTestNetworks
|| !WalletConstants.KNOWN_TEST_CHAIN_IDS.contains(
network.chainId)) {
relevantNetworks.add(network);
}
}
keyringService.getKeyringInfo(getKeyringForCoinType(coinType), keyringInfo -> {
jsonRpcService.getAllNetworks(coinType, networks -> {
ArrayList<NetworkInfo> relevantNetworks = new ArrayList<NetworkInfo>();
for (NetworkInfo net : networks) {
// Exclude testnet chain data by default.
// Testnet chain counting can be enabled via the
// --p3a-count-wallet-test-networks switch
if (countTestNetworks
|| !WalletConstants.KNOWN_TEST_CHAIN_IDS.contains(net.chainId)) {
relevantNetworks.add(net);
}
}
AsyncUtils.MultiResponseHandler multiResponse =
new AsyncUtils.MultiResponseHandler(relevantNetworks.size());
ArrayList<AsyncUtils.GetTxExtraInfoResponseContext> txExtraInfoResponses =
new ArrayList<AsyncUtils.GetTxExtraInfoResponseContext>();
for (NetworkInfo net : relevantNetworks) {
AsyncUtils.GetTxExtraInfoResponseContext ctx =
new AsyncUtils.GetTxExtraInfoResponseContext(
multiResponse.singleResponseComplete);
getTxExtraInfo(activity, net, keyringInfo.accountInfos, null, true, ctx);
txExtraInfoResponses.add(ctx);
}
multiResponse.setWhenAllCompletedAction(() -> {
HashSet<String> activeAddresses = new HashSet();
for (AsyncUtils.GetTxExtraInfoResponseContext ctx : txExtraInfoResponses) {
// If account has a non-zero native coin balance or blockchain token
// balance, add the account address to the set.
for (Map.Entry<String, Double> entry :
ctx.nativeAssetsBalances.entrySet()) {
if (entry.getValue() > 0.0d) {
activeAddresses.add(entry.getKey());
}
}
for (Map.Entry<String, HashMap<String, Double>> accEntry :
ctx.blockchainTokensBalances.entrySet()) {
for (Map.Entry<String, Double> tokenEntry :
accEntry.getValue().entrySet()) {
if (tokenEntry.getValue() > 0.0d) {
activeAddresses.add(accEntry.getKey());
}
}
}
}
braveWalletP3A.recordActiveWalletCount(activeAddresses.size(), coinType);
callback.call(relevantNetworks.toArray(new NetworkInfo[0]));
});
});
});
}
public static boolean isNativeToken(NetworkInfo selectedNetwork, BlockchainToken token) {