use MoneroThreadPoolExecutor for wallet creation (#53)

This commit is contained in:
m2049r 2017-09-10 09:49:21 +02:00 committed by GitHub
parent 7a9bb22da7
commit eb2b3b5675
3 changed files with 99 additions and 57 deletions

View File

@ -47,6 +47,7 @@ import com.m2049r.xmrwallet.model.WalletManager;
import com.m2049r.xmrwallet.service.WalletService; import com.m2049r.xmrwallet.service.WalletService;
import com.m2049r.xmrwallet.util.AsyncExchangeRate; import com.m2049r.xmrwallet.util.AsyncExchangeRate;
import com.m2049r.xmrwallet.util.Helper; import com.m2049r.xmrwallet.util.Helper;
import com.m2049r.xmrwallet.util.MoneroThreadPoolExecutor;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
@ -196,7 +197,7 @@ public class LoginActivity extends AppCompatActivity
// copy + delete seems safer than rename because we call rollback easily // copy + delete seems safer than rename because we call rollback easily
boolean renameWallet(File walletFile, String newName) { boolean renameWallet(File walletFile, String newName) {
if (copyWallet(walletFile, new File(walletFile.getParentFile(), newName), false, true)) { if (copyWallet(walletFile, new File(walletFile.getParentFile(), newName), false)) {
deleteWallet(walletFile); deleteWallet(walletFile);
return true; return true;
} else { } else {
@ -300,7 +301,7 @@ public class LoginActivity extends AppCompatActivity
// TODO probably better to copy to a new file and then rename // TODO probably better to copy to a new file and then rename
// then if something fails we have the old backup at least // then if something fails we have the old backup at least
// or just create a new backup every time and keep n old backups // or just create a new backup every time and keep n old backups
return copyWallet(walletFile, backupFile, true, true); return copyWallet(walletFile, backupFile, true);
} }
@Override @Override
@ -501,14 +502,15 @@ public class LoginActivity extends AppCompatActivity
super.onPause(); super.onPause();
} }
AsyncTask asyncWaitTask = null; AsyncTask asyncWaitTask = null; // TODO should this really be set from all AsyncTasks here?
@Override @Override
protected void onResume() { protected void onResume() {
super.onResume(); super.onResume();
Log.d(TAG, "onResume()"); Log.d(TAG, "onResume()");
// wait for WalletService to finish
if (WalletService.Running && (asyncWaitTask == null)) { if (WalletService.Running && (asyncWaitTask == null)) {
Log.d(TAG, "new process dialog"); // and show a progress dialog, but only if there isn't one already
new AsyncWaitForService().execute(); new AsyncWaitForService().execute();
} }
} }
@ -658,45 +660,87 @@ public class LoginActivity extends AppCompatActivity
////////////////////////////////////////// //////////////////////////////////////////
static final String MNEMONIC_LANGUAGE = "English"; // see mnemonics/electrum-words.cpp for more static final String MNEMONIC_LANGUAGE = "English"; // see mnemonics/electrum-words.cpp for more
// TODO make this an AsyncTask?
public void createWallet(final String name, final String password, final WalletCreator walletCreator) { private class AsyncCreateWallet extends AsyncTask<Void, Void, Boolean> {
final GenerateFragment genFragment = (GenerateFragment) String walletName;
getSupportFragmentManager().findFragmentById(R.id.fragment_container); String walletPassword;
File newWalletFolder = new File(getStorageRoot(), ".new"); WalletCreator walletCreator;
if (!newWalletFolder.exists()) {
if (!newWalletFolder.mkdir()) { File newWalletFile;
Log.e(TAG, "Cannot create new wallet dir " + newWalletFolder.getAbsolutePath());
genFragment.walletGenerateError(); public AsyncCreateWallet(String name, String password, WalletCreator walletCreator) {
return; super();
this.walletName = name;
this.walletPassword = password;
this.walletCreator = walletCreator;
}
@Override
protected void onPreExecute() {
super.onPreExecute();
}
@Override
protected Boolean doInBackground(Void... params) {
File newWalletFolder = new File(getStorageRoot(), ".new");
if (!newWalletFolder.exists()) {
if (!newWalletFolder.mkdir()) {
Log.e(TAG, "Cannot create new wallet dir " + newWalletFolder.getAbsolutePath());
return false;
}
}
if (!newWalletFolder.isDirectory()) {
Log.e(TAG, "New wallet dir " + newWalletFolder.getAbsolutePath() + "is not a directory");
return false;
}
File cacheFile = new File(newWalletFolder, walletName);
cacheFile.delete();
File keysFile = new File(newWalletFolder, walletName + ".keys");
keysFile.delete();
File addressFile = new File(newWalletFolder, walletName + ".address.txt");
addressFile.delete();
if (cacheFile.exists() || keysFile.exists() || addressFile.exists()) {
Log.e(TAG, "Cannot remove all old wallet files: " + cacheFile.getAbsolutePath());
return false;
}
newWalletFile = new File(newWalletFolder, walletName);
boolean success = walletCreator.createWallet(newWalletFile, walletPassword);
if (success) {
return true;
} else {
Toast.makeText(LoginActivity.this,
getString(R.string.generate_wallet_create_failed), Toast.LENGTH_LONG).show();
Log.e(TAG, "Could not create new wallet in " + newWalletFile.getAbsolutePath());
return false;
} }
} }
if (!newWalletFolder.isDirectory()) {
Log.e(TAG, "New wallet dir " + newWalletFolder.getAbsolutePath() + "is not a directory");
genFragment.walletGenerateError();
return;
}
File cacheFile = new File(newWalletFolder, name);
cacheFile.delete();
File keysFile = new File(newWalletFolder, name + ".keys");
keysFile.delete();
File addressFile = new File(newWalletFolder, name + ".address.txt");
addressFile.delete();
if (cacheFile.exists() || keysFile.exists() || addressFile.exists()) { @Override
Log.e(TAG, "Cannot remove all old wallet files: " + cacheFile.getAbsolutePath()); protected void onPostExecute(Boolean result) {
genFragment.walletGenerateError(); super.onPostExecute(result);
return; if (result) {
startDetails(newWalletFile, walletPassword, GenerateReviewFragment.VIEW_TYPE_ACCEPT);
} else {
walletGenerateError();
}
LoginActivity.this.asyncWaitTask = null;
} }
}
File newWalletFile = new File(newWalletFolder, name); public void createWallet(String name, String password, WalletCreator walletCreator) {
boolean success = walletCreator.createWallet(newWalletFile, password); new AsyncCreateWallet(name, password, walletCreator)
if (success) { .executeOnExecutor(MoneroThreadPoolExecutor.MONERO_THREAD_POOL_EXECUTOR);
startDetails(newWalletFile, password, GenerateReviewFragment.VIEW_TYPE_ACCEPT); }
} else {
Toast.makeText(LoginActivity.this, void walletGenerateError() {
getString(R.string.generate_wallet_create_failed), Toast.LENGTH_LONG).show(); try {
Log.e(TAG, "Could not create new wallet in " + newWalletFile.getAbsolutePath()); GenerateFragment genFragment = (GenerateFragment)
getSupportFragmentManager().findFragmentById(R.id.fragment_container);
genFragment.walletGenerateError(); genFragment.walletGenerateError();
} catch (ClassCastException ex) {
Log.e(TAG, "walletGenerateError() but not in GenerateFragment");
} }
} }
@ -761,15 +805,18 @@ public class LoginActivity extends AppCompatActivity
}); });
} }
@Override @Override
public void onAccept(final String name, final String password) { public void onAccept(final String name, final String password) {
final File newWalletFile = new File(new File(getStorageRoot(), ".new"), name); File newWalletFile = new File(new File(getStorageRoot(), ".new"), name);
final File walletFolder = getStorageRoot(); File walletFolder = getStorageRoot();
final File walletFile = new File(walletFolder, name); File walletFile = new File(walletFolder, name);
final boolean rc = copyWallet(newWalletFile, walletFile, false, false) boolean rc = copyWallet(newWalletFile, walletFile, false);
&& if (rc) {
(testWallet(walletFile.getAbsolutePath(), password) == Wallet.Status.Status_Ok); walletFile.delete(); // when recovering wallets, the cache seems corrupt
// TODO: figure out why this is so? Only for a private testnet?
rc = testWallet(walletFile.getAbsolutePath(), password) == Wallet.Status.Status_Ok;
}
if (rc) { if (rc) {
popFragmentStack(GENERATE_STACK); popFragmentStack(GENERATE_STACK);
Toast.makeText(LoginActivity.this, Toast.makeText(LoginActivity.this,
@ -811,7 +858,7 @@ public class LoginActivity extends AppCompatActivity
} }
} }
boolean copyWallet(File srcWallet, File dstWallet, boolean overwrite, boolean full) { boolean copyWallet(File srcWallet, File dstWallet, boolean overwrite) {
//Log.d(TAG, "src=" + srcWallet.exists() + " dst=" + dstWallet.exists()); //Log.d(TAG, "src=" + srcWallet.exists() + " dst=" + dstWallet.exists());
if (walletExists(dstWallet, true) && !overwrite) return false; if (walletExists(dstWallet, true) && !overwrite) return false;
if (!walletExists(srcWallet, false)) return false; if (!walletExists(srcWallet, false)) return false;
@ -822,13 +869,7 @@ public class LoginActivity extends AppCompatActivity
File dstDir = dstWallet.getParentFile(); File dstDir = dstWallet.getParentFile();
String dstName = dstWallet.getName(); String dstName = dstWallet.getName();
try { try {
if (full) { copyFile(new File(srcDir, srcName), new File(dstDir, dstName));
// the cache is corrupt if we recover (!!) from seed
// the cache is ok if we immediately do a full refresh()
// recoveryheight is ignored but not on watchonly wallet ?! - find out why
// so we just ignore the cache file and rebuild it on first sync
copyFile(new File(srcDir, srcName), new File(dstDir, dstName));
}
copyFile(new File(srcDir, srcName + ".keys"), new File(dstDir, dstName + ".keys")); copyFile(new File(srcDir, srcName + ".keys"), new File(dstDir, dstName + ".keys"));
copyFile(new File(srcDir, srcName + ".address.txt"), new File(dstDir, dstName + ".address.txt")); copyFile(new File(srcDir, srcName + ".address.txt"), new File(dstDir, dstName + ".address.txt"));
success = true; success = true;

View File

@ -239,7 +239,6 @@ public class LoginFragment extends Fragment {
displayedList.clear(); displayedList.clear();
String x = isMainNet() ? "4" : "9A"; String x = isMainNet() ? "4" : "9A";
for (String s : walletList) { for (String s : walletList) {
// Log.d(TAG, "filtering " + s);
if (x.indexOf(s.charAt(1)) >= 0) displayedList.add(s); if (x.indexOf(s.charAt(1)) >= 0) displayedList.add(s);
} }
} }
@ -252,12 +251,14 @@ public class LoginFragment extends Fragment {
walletList.clear(); walletList.clear();
for (WalletManager.WalletInfo walletInfo : walletInfos) { for (WalletManager.WalletInfo walletInfo : walletInfos) {
// Log.d(TAG, walletInfo.address); // ONCE the walletInfo.address was null - because the address.txt was empty
// this was before the wallet generation was in its own therad with huge stack
// TODO: keep an eye on Wallet.getAddress() returning empty
String displayAddress = walletInfo.address; String displayAddress = walletInfo.address;
if (displayAddress.length() == 95) { if ((displayAddress != null) && displayAddress.length() == 95) {
displayAddress = walletInfo.address.substring(0, 6); displayAddress = walletInfo.address.substring(0, 6);
walletList.add("[" + displayAddress + "] " + walletInfo.name);
} }
walletList.add("[" + displayAddress + "] " + walletInfo.name);
} }
filterList(); filterList();
((BaseAdapter) listView.getAdapter()).notifyDataSetChanged(); ((BaseAdapter) listView.getAdapter()).notifyDataSetChanged();

View File

@ -305,7 +305,7 @@ public class ReceiveFragment extends Fragment implements AsyncExchangeRate.Liste
} }
private void show(String walletPath, String password) { private void show(String walletPath, String password) {
new ReceiveFragment.AsyncShow().executeOnExecutor(MoneroThreadPoolExecutor.MONERO_THREAD_POOL_EXECUTOR, new AsyncShow().executeOnExecutor(MoneroThreadPoolExecutor.MONERO_THREAD_POOL_EXECUTOR,
walletPath, password); walletPath, password);
} }