Search in sources :

Example 6 with WalletCallException

use of com.vaklinov.zcashui.ZCashClientCaller.WalletCallException in project zencash-swing-wallet-ui by ZencashOfficial.

the class WalletOperations method importWalletPrivateKeys.

public void importWalletPrivateKeys() {
    // TODO: Will need corrections once encryption is re-enabled!!!
    int option = JOptionPane.showConfirmDialog(this.parent, "Private key import is a potentially slow operation. It may take\n" + "several minutes during which the GUI will be non-responsive.\n" + "The data to import must be in the format used by the option:\n" + "\"Export private keys...\"\n\n" + "Are you sure you wish to import private keys?", "Private key import notice...", JOptionPane.YES_NO_OPTION);
    if (option == JOptionPane.NO_OPTION) {
        return;
    }
    try {
        JFileChooser fileChooser = new JFileChooser();
        fileChooser.setDialogTitle("Import wallet private keys from file...");
        fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
        int result = fileChooser.showOpenDialog(this.parent);
        if (result != JFileChooser.APPROVE_OPTION) {
            return;
        }
        File f = fileChooser.getSelectedFile();
        Cursor oldCursor = this.parent.getCursor();
        try {
            this.parent.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
            this.clientCaller.importWallet(f.getCanonicalPath());
            this.parent.setCursor(oldCursor);
        } catch (WalletCallException wce) {
            this.parent.setCursor(oldCursor);
            Log.error("Unexpected error: ", wce);
            JOptionPane.showMessageDialog(this.parent, "An unexpected error occurred while importing wallet private keys!" + "\n" + wce.getMessage().replace(",", ",\n"), "Error in importing wallet private keys...", JOptionPane.ERROR_MESSAGE);
            return;
        }
        JOptionPane.showMessageDialog(this.parent, "Wallet private keys have been imported successfully from location:\n" + f.getCanonicalPath() + "\n\n", "Wallet private key import...", JOptionPane.INFORMATION_MESSAGE);
    } catch (Exception e) {
        this.errorReporter.reportError(e, false);
    }
}
Also used : WalletCallException(com.vaklinov.zcashui.ZCashClientCaller.WalletCallException) File(java.io.File) IOException(java.io.IOException) WalletCallException(com.vaklinov.zcashui.ZCashClientCaller.WalletCallException)

Example 7 with WalletCallException

use of com.vaklinov.zcashui.ZCashClientCaller.WalletCallException in project zencash-swing-wallet-ui by ZencashOfficial.

the class SendCashPanel method sendCash.

private void sendCash() throws WalletCallException, IOException, InterruptedException {
    if (balanceAddressCombo.getItemCount() <= 0) {
        JOptionPane.showMessageDialog(SendCashPanel.this.getRootPane().getParent(), langUtil.getString("send.cash.panel.option.pane.no.funds.text"), langUtil.getString("send.cash.panel.option.pane.no.funds.title"), JOptionPane.ERROR_MESSAGE);
        return;
    }
    if (this.balanceAddressCombo.getSelectedIndex() < 0) {
        JOptionPane.showMessageDialog(SendCashPanel.this.getRootPane().getParent(), langUtil.getString("send.cash.panel.option.pane.select.source.text"), langUtil.getString("send.cash.panel.option.pane.select.source.title"), JOptionPane.ERROR_MESSAGE);
        return;
    }
    final String sourceAddress = this.lastAddressBalanceData[this.balanceAddressCombo.getSelectedIndex()][1];
    final String destinationAddress = this.destinationAddressField.getText();
    final String memo = this.destinationMemoField.getText();
    final String amount = this.destinationAmountField.getText();
    final String fee = this.transactionFeeField.getText();
    // Verify general correctness.
    String errorMessage = null;
    if ((sourceAddress == null) || (sourceAddress.trim().length() <= 20)) {
        errorMessage = langUtil.getString("send.cash.panel.option.pane.error.source.address.invalid");
    } else if (sourceAddress.length() > 512) {
        errorMessage = langUtil.getString("send.cash.panel.option.pane.error.source.address.too.long");
    }
    // TODO: full address validation
    if ((destinationAddress == null) || (destinationAddress.trim().length() <= 0)) {
        errorMessage = langUtil.getString("send.cash.panel.option.pane.error.destination.address.invalid");
    } else if (destinationAddress.trim().length() <= 20) {
        errorMessage = langUtil.getString("send.cash.panel.option.pane.error.destination.address.too.short");
    } else if (destinationAddress.length() > 512) {
        errorMessage = langUtil.getString("send.cash.panel.option.pane.error.destination.address.too.long");
    } else if (destinationAddress.trim().length() != destinationAddress.length()) {
        errorMessage = langUtil.getString("send.cash.panel.option.pane.error.destination.address.has.spaces");
    }
    if ((amount == null) || (amount.trim().length() <= 0)) {
        errorMessage = langUtil.getString("send.cash.panel.option.pane.error.amount.invalid");
    } else {
        try {
            double d = Double.valueOf(amount);
        } catch (NumberFormatException nfe) {
            errorMessage = langUtil.getString("send.cash.panel.option.pane.error.amount.not.number");
        }
    }
    if ((fee == null) || (fee.trim().length() <= 0)) {
        errorMessage = langUtil.getString("send.cash.panel.option.pane.error.fee.invalid");
    } else {
        try {
            double d = Double.valueOf(fee);
        } catch (NumberFormatException nfe) {
            errorMessage = langUtil.getString("send.cash.panel.option.pane.error.fee.not.number");
        }
    }
    if (errorMessage != null) {
        JOptionPane.showMessageDialog(SendCashPanel.this.getRootPane().getParent(), errorMessage, langUtil.getString("send.cash.panel.option.pane.error.incorrect.sending.parameters"), JOptionPane.ERROR_MESSAGE);
        return;
    }
    // ZClassic compatibility
    if (!installationObserver.isOnTestNet()) {
        if (!(destinationAddress.startsWith("zc") || destinationAddress.startsWith("zn") || destinationAddress.startsWith("zs"))) {
            Object[] options = { "OK" };
            JOptionPane.showOptionDialog(SendCashPanel.this.getRootPane().getParent(), langUtil.getString("send.cash.panel.option.pane.error.destination.address.incorrect.text", destinationAddress), langUtil.getString("send.cash.panel.option.pane.error.destination.address.incorrect.title"), JOptionPane.DEFAULT_OPTION, JOptionPane.ERROR_MESSAGE, null, options, options[0]);
            // Do not send anything!
            return;
        }
    }
    // If a memo is specified, make sure the destination is a Z address.
    if ((!installationObserver.isOnTestNet()) && (!Util.stringIsEmpty(memo)) && (!Util.isZAddress(destinationAddress))) {
        int reply = JOptionPane.showConfirmDialog(SendCashPanel.this.getRootPane().getParent(), langUtil.getString("send.cash.panel.option.pane.error.destination.address.notz.text", destinationAddress), langUtil.getString("send.cash.panel.option.pane.error.destination.address.notz.title"), JOptionPane.YES_NO_OPTION);
        if (reply == JOptionPane.NO_OPTION) {
            return;
        }
    }
    // Check for encrypted wallet
    final boolean bEncryptedWallet = this.clientCaller.isWalletEncrypted();
    if (bEncryptedWallet) {
        PasswordDialog pd = new PasswordDialog((JFrame) (SendCashPanel.this.getRootPane().getParent()));
        pd.setVisible(true);
        if (!pd.isOKPressed()) {
            return;
        }
        this.clientCaller.unlockWallet(pd.getPassword());
    }
    // Call the wallet send method
    operationStatusID = this.clientCaller.sendCash(sourceAddress, destinationAddress, amount, memo, fee);
    // Make sure the keypool has spare addresses
    if ((this.backupTracker.getNumTransactionsSinceLastBackup() % 5) == 0) {
        this.clientCaller.keypoolRefill(100);
    }
    // Disable controls after send
    sendButton.setEnabled(false);
    balanceAddressCombo.setEnabled(false);
    destinationAddressField.setEnabled(false);
    destinationAmountField.setEnabled(false);
    destinationMemoField.setEnabled(false);
    transactionFeeField.setEnabled(false);
    // Start a data gathering thread specific to the operation being executed - this is done is a separate
    // thread since the server responds more slowly during JoinSPlits and this blocks he GUI somewhat.
    final DataGatheringThread<Boolean> opFollowingThread = new DataGatheringThread<Boolean>(new DataGatheringThread.DataGatherer<Boolean>() {

        public Boolean gatherData() throws Exception {
            long start = System.currentTimeMillis();
            Boolean result = clientCaller.isSendingOperationComplete(operationStatusID);
            long end = System.currentTimeMillis();
            Log.info("Checking for operation " + operationStatusID + " status done in " + (end - start) + "ms.");
            return result;
        }
    }, this.errorReporter, 2000, true);
    // Start a timer to update the progress of the operation
    operationStatusCounter = 0;
    operationStatusTimer = new Timer(2000, new ActionListener() {

        @Override
        public void actionPerformed(ActionEvent e) {
            try {
                // TODO: Handle errors in case of restarted server while wallet is sending ...
                Boolean opComplete = opFollowingThread.getLastData();
                if ((opComplete != null) && opComplete.booleanValue()) {
                    // End the special thread used to follow the operation
                    opFollowingThread.setSuspended(true);
                    SendCashPanel.this.reportCompleteOperationToTheUser(amount, sourceAddress, destinationAddress);
                    // Lock the wallet again
                    if (bEncryptedWallet) {
                        SendCashPanel.this.clientCaller.lockWallet();
                    }
                    // Restore controls etc.
                    operationStatusCounter = 0;
                    operationStatusID = null;
                    operationStatusTimer.stop();
                    operationStatusTimer = null;
                    operationStatusProhgressBar.setValue(0);
                    sendButton.setEnabled(true);
                    balanceAddressCombo.setEnabled(true);
                    destinationAddressField.setEnabled(true);
                    destinationAmountField.setEnabled(true);
                    transactionFeeField.setEnabled(true);
                    destinationMemoField.setEnabled(true);
                } else {
                    // Update the progress
                    operationStatusLabel.setText(langUtil.getString("send.cash.panel.operation.status.progress.label"));
                    operationStatusCounter += 2;
                    int progress = 0;
                    if (operationStatusCounter <= 100) {
                        progress = operationStatusCounter;
                    } else {
                        progress = 100 + (((operationStatusCounter - 100) * 6) / 10);
                    }
                    operationStatusProhgressBar.setValue(progress);
                }
                SendCashPanel.this.repaint();
            } catch (Exception ex) {
                Log.error("Unexpected error: ", ex);
                SendCashPanel.this.errorReporter.reportError(ex);
            }
        }
    });
    operationStatusTimer.setInitialDelay(0);
    operationStatusTimer.start();
}
Also used : ActionEvent(java.awt.event.ActionEvent) URISyntaxException(java.net.URISyntaxException) IOException(java.io.IOException) WalletCallException(com.vaklinov.zcashui.ZCashClientCaller.WalletCallException) Timer(javax.swing.Timer) ActionListener(java.awt.event.ActionListener)

Example 8 with WalletCallException

use of com.vaklinov.zcashui.ZCashClientCaller.WalletCallException in project zencash-swing-wallet-ui by ZencashOfficial.

the class MessagingPanel method collectAndStoreNewReceivedMessages.

private void collectAndStoreNewReceivedMessages(MessagingIdentity groupIdentity) throws IOException, WalletCallException, InterruptedException {
    MessagingIdentity ownIdentity = this.messagingStorage.getOwnIdentity();
    // Check to make sure the Z address of the messaging identity is valid
    if ((ownIdentity != null) && (!this.identityZAddressValidityChecked)) {
        String ownZAddress = ownIdentity.getSendreceiveaddress();
        String[] walletZaddresses = this.clientCaller.getWalletZAddresses();
        boolean bFound = false;
        for (String address : walletZaddresses) {
            if (ownZAddress.equals(address)) {
                bFound = true;
            }
        }
        if (!bFound) {
            JOptionPane.showMessageDialog(MessagingPanel.this.getRootPane().getParent(), "The messaging identity send/receive address: \n" + ownZAddress + "\n" + "is not found in the wallet.dat. The reason may be that after a mesaging identity\n" + "was created the wallet.dat was changed or the ZEN node configuration was changed\n" + "(e.g. mainnet -> testnet). If such a change was made, the messaging identity can no\n" + "longer be used. To avoid this error mesage, you may rename the directory:\n" + OSUtil.getSettingsDirectory() + File.separator + "messaging" + "\n" + "until the configuration or wallet.dat is restored! Directory may only be renamed when\n" + "the wallet is stopped!", "Messaging identity address is not found in walet!", JOptionPane.ERROR_MESSAGE);
            return;
        }
        this.identityZAddressValidityChecked = true;
    }
    // Get the transaction IDs from all received transactions in the local storage
    // TODO: optimize/cache this
    Set<String> storedTransactionIDs = new HashSet<String>();
    for (MessagingIdentity identity : this.messagingStorage.getContactIdentities(true)) {
        for (Message localMessage : this.messagingStorage.getAllMessagesForContact(identity)) {
            if ((localMessage.getDirection() == DIRECTION_TYPE.RECEIVED) && (!Util.stringIsEmpty(localMessage.getTransactionID()))) {
                storedTransactionIDs.add(localMessage.getTransactionID());
            }
        }
    }
    if (ownIdentity == null) {
        Log.warning("Own messaging identity does not exist yet. No received messages collected!");
        return;
    }
    String ZAddress = (groupIdentity != null) ? groupIdentity.getSendreceiveaddress() : ownIdentity.getSendreceiveaddress();
    // Get all known transactions received from the wallet
    // TODO: there seems to be no way to limit the number of transactions returned!
    JsonObject[] walletTransactions = this.clientCaller.getTransactionMessagingDataForZaddress(ZAddress);
    // Filter the transactions to obtain only those that have memos parsable as JSON
    // and being real messages. In addition only those remain that are not registered before
    List<Message> filteredMessages = new ArrayList<Message>();
    for (JsonObject trans : walletTransactions) {
        String memoHex = trans.getString("memo", "ERROR");
        String transactionID = trans.getString("txid", "ERROR");
        if (!memoHex.equals("ERROR")) {
            String decodedMemo = Util.decodeHexMemo(memoHex);
            JsonObject jsonMessage = null;
            try {
                if (decodedMemo != null) {
                    jsonMessage = Util.parseJsonObject(decodedMemo);
                }
            } catch (Exception ex) {
                Log.warningOneTime("Decoded memo is not parsable: {0}, due to {1}: {2}", decodedMemo, ex.getClass().getName(), ex.getMessage());
            }
            if ((jsonMessage != null) && ((jsonMessage.get("zenmsg") != null) && (!storedTransactionIDs.contains(transactionID)))) {
                JsonObject innerZenmsg = jsonMessage.get("zenmsg").asObject();
                if (Message.isValidZENMessagingProtocolMessage(innerZenmsg)) {
                    // Finally test that the message has all attributes required
                    Message message = new Message(innerZenmsg);
                    // Set additional message attributes not available over the wire
                    message.setDirection(DIRECTION_TYPE.RECEIVED);
                    message.setTransactionID(transactionID);
                    String UNIXDate = this.clientCaller.getWalletTransactionTime(transactionID);
                    message.setTime(new Date(Long.valueOf(UNIXDate).longValue() * 1000L));
                    // TODO: additional sanity check that T/Z addresses are valid etc.
                    filteredMessages.add(message);
                } else {
                    // Warn of unexpected message content
                    Log.warningOneTime("Ignoring received mesage with invalid or incomplete content: {0}", jsonMessage.toString());
                }
            }
        }
    // End if (!memoHex.equals("ERROR"))
    }
    // for (JsonObject trans : walletTransactions)
    MessagingOptions msgOptions = this.messagingStorage.getMessagingOptions();
    // Finally we have all messages that are new and unprocessed. For every message we find out
    // who the sender is, verify it and store it
    boolean bNewContactCreated = false;
    // Loop for processing standard (not anonymous messages)
    standard_message_loop: for (Message message : filteredMessages) {
        if (message.isAnonymous()) {
            continue standard_message_loop;
        }
        MessagingIdentity contactID = this.messagingStorage.getContactIdentityForSenderIDAddress(message.getFrom());
        // Check for ignored contact messages
        if ((groupIdentity == null) && (contactID == null)) {
            MessagingIdentity ignoredContact = this.messagingStorage.getIgnoredContactForMessage(message);
            if (ignoredContact != null) {
                Log.warningOneTime("Message detected from an ignored contact. Message will be ignored. " + "Message: {0}, Ignored contact: {1}", message.toJSONObject(false).toString(), ignoredContact.toJSONObject(false).toString());
                continue standard_message_loop;
            }
        }
        // Skip message if from an unknown user and options are not set
        if ((groupIdentity == null) && (contactID == null) && (!msgOptions.isAutomaticallyAddUsersIfNotExplicitlyImported())) {
            Log.warningOneTime("Message is from an unknown user, but options do not allow adding new users: {0}", message.toJSONObject(false).toString());
            continue standard_message_loop;
        }
        if ((groupIdentity == null) && (contactID == null)) {
            // Update list of contacts with an unknown remote user ... to be updated later
            Log.warning("Message is from unknown contact: {0} . " + "A new Unknown_xxx contact will be created!", message.toJSONObject(false).toString());
            contactID = this.messagingStorage.createAndStoreUnknownContactIdentity(message.getFrom());
            bNewContactCreated = true;
        }
        // Verify the message signature
        if (this.clientCaller.verifyMessage(message.getFrom(), message.getSign(), Util.encodeHexString(message.getMessage()).toUpperCase())) {
            // Handle the special case of a messaging identity sent as payload - update identity then
            if ((groupIdentity == null) && this.isZENIdentityMessage(message.getMessage())) {
                this.updateAndStoreExistingIdentityFromIDMessage(contactID, message.getMessage());
            }
            message.setVerification(VERIFICATION_TYPE.VERIFICATION_OK);
        } else {
            // Set verification status permanently - store even invalid messages
            Log.error("Message signature is invalid {0} . Message will be stored as invalid!", message.toJSONObject(false).toString());
            message.setVerification(VERIFICATION_TYPE.VERIFICATION_FAILED);
        }
        this.messagingStorage.writeNewReceivedMessageForContact((groupIdentity == null) ? contactID : groupIdentity, message);
    }
    // Loop for processing anonymous messages
    anonymus_message_loop: for (Message message : filteredMessages) {
        if (!message.isAnonymous()) {
            continue anonymus_message_loop;
        }
        // It is possible that it will find a normal identity to which we previously sent the first
        // anonymous message (send scenario) or maybe an anonymous identity created by incoming
        // message etc.
        MessagingIdentity anonContctID = this.messagingStorage.findAnonymousOrNormalContactIdentityByThreadID(message.getThreadID());
        // Check for ignored contact messages
        if ((groupIdentity == null) && (anonContctID == null)) {
            MessagingIdentity ignoredContact = this.messagingStorage.getIgnoredContactForMessage(message);
            if (ignoredContact != null) {
                Log.warningOneTime("Message detected from an ignored contact. Message will be ignored. " + "Message: {0}, Ignored contact: {1}", message.toJSONObject(false).toString(), ignoredContact.toJSONObject(false).toString());
                continue anonymus_message_loop;
            }
        }
        // Skip message if from an unknown user and options are not set
        if ((groupIdentity == null) && (anonContctID == null) && (!msgOptions.isAutomaticallyAddUsersIfNotExplicitlyImported())) {
            Log.warningOneTime("Anonymous message is from an unknown user, but options do not allow adding new users: {0}", message.toJSONObject(false).toString());
            continue anonymus_message_loop;
        }
        if ((groupIdentity == null) && (anonContctID == null)) {
            // Return address may be empty but we pass it
            anonContctID = this.messagingStorage.createAndStoreAnonumousContactIdentity(message.getThreadID(), message.getReturnAddress());
            Log.info("Created new anonymous contact identity: ", anonContctID.toJSONObject(false).toString());
            bNewContactCreated = true;
        } else if ((groupIdentity == null) && Util.stringIsEmpty(anonContctID.getSendreceiveaddress())) {
            if (!Util.stringIsEmpty(message.getReturnAddress())) {
                anonContctID.setSendreceiveaddress(message.getReturnAddress());
                this.messagingStorage.updateAnonumousContactIdentityForThreadID(anonContctID.getThreadID(), anonContctID);
                Log.info("Updated anonymous contact identity: ", anonContctID.toJSONObject(false).toString());
            }
        }
        this.messagingStorage.writeNewReceivedMessageForContact((groupIdentity == null) ? anonContctID : groupIdentity, message);
    }
    if (bNewContactCreated) {
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                try {
                    MessagingPanel.this.contactList.reloadMessagingIdentities();
                } catch (Exception e) {
                    Log.error("Unexpected error in reloading contacts after gathering messages: ", e);
                    MessagingPanel.this.errorReporter.reportError(e);
                }
            }
        });
    }
    // TODO: Call this only if anything was changed - e.g. new messages saved
    SwingUtilities.invokeLater(new Runnable() {

        @Override
        public void run() {
            try {
                // Reload the messages for the currently selected user
                final MessagingIdentity selectedContact = MessagingPanel.this.contactList.getSelectedContact();
                if (selectedContact != null) {
                    MessagingPanel.this.displayMessagesForContact(selectedContact);
                }
            } catch (Exception e) {
                Log.error("Unexpected error in updating message pane after gathering messages: ", e);
                MessagingPanel.this.errorReporter.reportError(e);
            }
        }
    });
}
Also used : ArrayList(java.util.ArrayList) JsonObject(com.eclipsesource.json.JsonObject) URISyntaxException(java.net.URISyntaxException) WalletCallException(com.vaklinov.zcashui.ZCashClientCaller.WalletCallException) IOException(java.io.IOException) Date(java.util.Date) HashSet(java.util.HashSet)

Aggregations

WalletCallException (com.vaklinov.zcashui.ZCashClientCaller.WalletCallException)8 IOException (java.io.IOException)8 File (java.io.File)4 JsonObject (com.eclipsesource.json.JsonObject)3 URISyntaxException (java.net.URISyntaxException)3 Date (java.util.Date)3 OS_TYPE (com.vaklinov.zcashui.OSUtil.OS_TYPE)2 ActionEvent (java.awt.event.ActionEvent)2 ActionListener (java.awt.event.ActionListener)2 Timer (javax.swing.Timer)2 JsonValue (com.eclipsesource.json.JsonValue)1 DataGatheringThread (com.vaklinov.zcashui.DataGatheringThread)1 NetworkAndBlockchainInfo (com.vaklinov.zcashui.ZCashClientCaller.NetworkAndBlockchainInfo)1 DaemonInfo (com.vaklinov.zcashui.ZCashInstallationObserver.DaemonInfo)1 InstallationDetectionException (com.vaklinov.zcashui.ZCashInstallationObserver.InstallationDetectionException)1 Cursor (java.awt.Cursor)1 UnsupportedEncodingException (java.io.UnsupportedEncodingException)1 InvocationTargetException (java.lang.reflect.InvocationTargetException)1 ArrayList (java.util.ArrayList)1 HashSet (java.util.HashSet)1