/* * * Copyright 2014 http://Bither.net * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * / */ package net.bither.viewsystem.froms; import net.bither.BitherSetting; import net.bither.BitherUI; import net.bither.bitherj.crypto.SecureCharSequence; import net.bither.bitherj.delegate.IPasswordGetterDelegate; import net.bither.bitherj.factory.ImportPrivateKey; import net.bither.bitherj.utils.Utils; import net.bither.factory.ImportPrivateKeyDesktop; import net.bither.fonts.AwesomeIcon; import net.bither.languages.MessageKey; import net.bither.model.OpenCLDevice; import net.bither.platform.builder.OSUtils; import net.bither.utils.BitherVanitygen; import net.bither.utils.LocaliserUtils; import net.bither.utils.StringUtil; import net.bither.utils.SystemUtil; import net.bither.viewsystem.TextBoxes; import net.bither.viewsystem.base.Buttons; import net.bither.viewsystem.base.FontSizer; import net.bither.viewsystem.base.Labels; import net.bither.viewsystem.base.Panels; import net.bither.viewsystem.base.renderer.SelectAddressImage; import net.bither.viewsystem.components.ScrollBarUIDecorator; import net.bither.viewsystem.dialogs.DialogConfirmTask; import net.bither.viewsystem.dialogs.MessageDialog; import net.bither.viewsystem.themes.Themes; import net.miginfocom.swing.MigLayout; import org.joda.time.Period; import org.joda.time.PeriodType; import org.joda.time.format.PeriodFormatter; import org.joda.time.format.PeriodFormatterBuilder; import javax.swing.*; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import javax.swing.table.AbstractTableModel; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.text.DecimalFormat; import java.util.ArrayList; public class VanitygenPanel extends WizardPanel implements IPasswordGetterDelegate, ListSelectionListener, ActionListener, BitherVanitygen.IVanitygenListener, VanityOptionPanel.IVanityOptionListener { private PasswordPanel.PasswordGetter passwordGetter; private JTextField textField; private JCheckBox caseInsensitiveBox; private JLabel lblTimeRemain; private JLabel lblSpeed; private JLabel lblDifficulty; private JLabel lblGenerated; private JLabel lblOne; private JProgressBar pb; private JLabel lblSelectDevice; private JCheckBox cbxCPU; private JCheckBox cbxGPU; private JLabel lblLoadingDevices; private JTable tbDevices; private JScrollPane sp; private OpenCLDevice selectedDevice; private JButton btnOption; private boolean isInCalculatingView; private int threadNum; private BitherSetting.ECKeyType ecKeyType = BitherSetting.ECKeyType.Compressed; private ArrayList<OpenCLDevice> devices = new ArrayList<OpenCLDevice>(); private PeriodFormatter remainingTimeFormatter; private JPanel panel; private Thread computingThread; private BitherVanitygen bitherVanitygen; private String privateKeyStr; private String addressStr; public VanitygenPanel() { super(MessageKey.vanity_address, AwesomeIcon.VIMEO_SQUARE); passwordGetter = new PasswordPanel.PasswordGetter(VanitygenPanel.this); remainingTimeFormatter = new PeriodFormatterBuilder().printZeroNever().appendYears().appendSuffix (LocaliserUtils.getString("vanity_time_year_suffix")).appendMonths().appendSuffix (LocaliserUtils.getString("vanity_time_month_suffix")).appendDays().appendSuffix (LocaliserUtils.getString("vanity_time_day_suffix")).appendHours().appendSuffix (LocaliserUtils.getString("vanity_time_hour_suffix")).appendMinutes() .appendSuffix(LocaliserUtils.getString("vanity_time_minute_suffix")) .appendSeconds().appendSuffix(LocaliserUtils.getString ("vanity_time_second_suffix")).toFormatter(); setOkAction(new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { if (isInCalculatingView) { generateAddress(); } else { showCalculate(); } } }); if (OSUtils.isWindows() && SystemUtil.isSystem32()) { ecKeyType = BitherSetting.ECKeyType.UNCompressed; } } @Override public void initialiseContent(JPanel panel) { this.panel = panel; panel.setLayout(new MigLayout(Panels.migXYLayout(), "[][grow][]", // Column constraints "20[][][]20[grow][][][][][grow]20[]20" // Row constraints )); lblOne = Labels.newValueLabel("1"); caseInsensitiveBox = new JCheckBox(LocaliserUtils.getString("vanity_case_insensitive")); btnOption = Buttons.newOptionsButton(new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { VanityOptionPanel vanityOptionPanel = new VanityOptionPanel(VanitygenPanel.this); vanityOptionPanel.showPanel(); } }); pb = new JProgressBar(); pb.setValue(0); pb.setMaximum(1000); pb.setVisible(false); textField = TextBoxes.newEnterAddress(new DocumentListener() { @Override public void insertUpdate(DocumentEvent e) { } @Override public void removeUpdate(DocumentEvent e) { } @Override public void changedUpdate(DocumentEvent e) { } }); lblDifficulty = Labels.newValueLabel(""); lblGenerated = Labels.newValueLabel(""); lblSpeed = Labels.newValueLabel(""); lblTimeRemain = Labels.newValueLabel(""); lblSelectDevice = Labels.newValueLabel(LocaliserUtils.getString ("vanity_select_computation_device")); Font font = lblSelectDevice.getFont(); lblSelectDevice.setFont(font.deriveFont(14.0f)); lblLoadingDevices = Labels.newSpinner(Themes.currentTheme.fadedText(), BitherUI .NORMAL_PLUS_ICON_SIZE); cbxCPU = new JCheckBox("CPU"); cbxCPU.addActionListener(this); cbxGPU = new JCheckBox("GPU (OpenCL)"); cbxGPU.addActionListener(this); tbDevices = new JTable(selectDeviceTableModel); tbDevices.getColumnModel().getColumn(0).setResizable(true); tbDevices.getColumnModel().getColumn(1).setResizable(true); tbDevices.getColumnModel().getColumn(1).setMinWidth(1); tbDevices.getColumnModel().getColumn(1).setPreferredWidth(Integer.MAX_VALUE); tbDevices.getColumnModel().getColumn(0).setMinWidth(20); tbDevices.getColumnModel().getColumn(0).setPreferredWidth(20); tbDevices.getColumnModel().getColumn(0).setCellRenderer(new SelectAddressImage()); tbDevices.setOpaque(true); tbDevices.setAutoCreateColumnsFromModel(true); tbDevices.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS); tbDevices.setAutoscrolls(true); tbDevices.setBorder(BorderFactory.createEmptyBorder()); tbDevices.setComponentOrientation(ComponentOrientation.getOrientation(LocaliserUtils .getLocale())); tbDevices.setRowHeight(Math.max(BitherSetting.MINIMUM_ICON_HEIGHT, panel.getFontMetrics (FontSizer.INSTANCE.getAdjustedDefaultFont()).getHeight()) + BitherSetting .HEIGHT_DELTA * 2); sp = new JScrollPane(); sp.setViewportView(tbDevices); ScrollBarUIDecorator.apply(sp, false); tbDevices.getSelectionModel().addListSelectionListener(this); showSelectDevice(); } private void showSelectDevice() { isInCalculatingView = false; panel.add(lblSelectDevice, "align center, cell 0 0 3 1, wrap"); panel.add(lblLoadingDevices, "align center, cell 0 1 3 1, wrap"); panel.add(cbxCPU, "align left, cell 0 2, wrap"); panel.add(cbxGPU, "align left, cell 0 3, wrap"); panel.add(sp, "cell 0 4 3 8, grow"); lblLoadingDevices.setVisible(false); sp.setVisible(false); cbxCPU.setVisible(false); cbxGPU.setVisible(false); setOkEnabled(false); refreshDevices(); } private void showCalculate() { isInCalculatingView = true; lblSelectDevice.setVisible(false); lblLoadingDevices.setVisible(false); sp.setVisible(false); cbxCPU.setVisible(false); cbxGPU.setVisible(false); panel.remove(lblSelectDevice); panel.remove(lblLoadingDevices); panel.remove(sp); panel.remove(cbxCPU); panel.remove(cbxGPU); panel.add(lblOne, "align right,cell 0 2,wrap"); panel.add(textField, "align center,cell 1 2,grow"); panel.add(btnOption, "align center,cell 2 2"); panel.add(caseInsensitiveBox, "align center,cell 3 2"); panel.add(lblDifficulty, "align left,cell 0 4 3 1,wrap,gapleft 20"); panel.add(lblGenerated, "align left,cell 0 5 3 1,wrap,gapleft 20"); panel.add(lblSpeed, "align left,cell 0 6 3 1,wrap,gapleft 20"); panel.add(lblTimeRemain, "align left,cell 0 7 3 1,wrap,gapleft 20"); panel.add(pb, "align center,cell 0 9 3 1,gapleft 10,gapright 10,h 20!,grow,span"); panel.doLayout(); textField.requestFocus(); } private void generateAddress() { if (textField.getText().length() <= 0) { new MessageDialog(LocaliserUtils.getString("vanity_address_not_empty")).showMsg(); return; } final String input = "1" + textField.getText(); String vaildBitcoinAddress = StringUtil.validBicoinAddressBegin(input); if (!Utils.isEmpty(vaildBitcoinAddress)) { String prompt = Utils.format(LocaliserUtils.getString("vanity_address_not_contains"), vaildBitcoinAddress); new MessageDialog(prompt).showMsg(); return; } pb.setVisible(true); textField.setEnabled(false); caseInsensitiveBox.setEnabled(false); setOkEnabled(false); computingThread = new Thread() { @Override public void run() { boolean useOpenCL = shouldUseOpenCL(); boolean igoreCase = caseInsensitiveBox.isSelected(); String openclConfig = null; if (selectedDevice != null) { openclConfig = selectedDevice.getConfigureString(); } bitherVanitygen = new BitherVanitygen(input, useOpenCL, igoreCase, threadNum, ecKeyType, openclConfig, VanitygenPanel.this); bitherVanitygen.generateAddress(); } }; computingThread.start(); } private AbstractTableModel selectDeviceTableModel = new AbstractTableModel() { @Override public int getRowCount() { return devices == null ? 0 : devices.size(); } @Override public int getColumnCount() { return 2; } @Override public Object getValueAt(int rowIndex, int columnIndex) { switch (columnIndex) { case 1: return devices.get(rowIndex).getPlatformName() + " : " + devices.get (rowIndex).getDeviceName(); case 0: return devices.get(rowIndex).equals(selectedDevice); } return null; } @Override public String getColumnName(int column) { return ""; } }; private void refreshDevices() { lblLoadingDevices.setVisible(true); sp.setVisible(false); cbxGPU.setVisible(false); cbxCPU.setVisible(false); setOkEnabled(false); new Thread() { @Override public void run() { devices.clear(); devices.addAll(BitherVanitygen.getCLDevices()); SwingUtilities.invokeLater(new Runnable() { @Override public void run() { setOkEnabled(true); if (devices.size() <= 1) { showCalculate(); return; } selectedDevice = findGPUDevice(); cbxCPU.setSelected(selectedDevice == null); cbxGPU.setSelected(selectedDevice != null); sp.setVisible(true); cbxGPU.setVisible(true); cbxCPU.setVisible(true); lblLoadingDevices.setVisible(false); selectDeviceTableModel.fireTableDataChanged(); } }); } }.start(); } private boolean shouldUseOpenCL() { return selectedDevice != null; } @Override public void closePanel() { if (!Utils.isEmpty(privateKeyStr)) { Runnable okRunable = new Runnable() { @Override public void run() { importPrivateKey(); } }; Runnable cancelRunable = new Runnable() { @Override public void run() { privateKeyStr = null; SwingUtilities.invokeLater(new Runnable() { @Override public void run() { quit(); } }); } }; String msg = Utils.format(LocaliserUtils.getString("vantiy_is_not_add"), addressStr); DialogConfirmTask dialogConfirmTask = new DialogConfirmTask(msg, okRunable, cancelRunable); dialogConfirmTask.pack(); dialogConfirmTask.setVisible(true); } else { quit(); } } private void quit() { privateKeyStr = null; super.closePanel(); if (bitherVanitygen != null) { bitherVanitygen.stop(); } if (computingThread != null && computingThread.isAlive() && !computingThread .isInterrupted()) { bitherVanitygen.stop(); computingThread.interrupt(); } } @Override public void valueChanged(ListSelectionEvent e) { ListSelectionModel lsm = (ListSelectionModel) e.getSource(); if (!lsm.isSelectionEmpty()) { int minIndex = lsm.getMinSelectionIndex(); int maxIndex = lsm.getMaxSelectionIndex(); for (int i = minIndex; i <= maxIndex; i++) { if (lsm.isSelectedIndex(i)) { selectedDevice = devices.get(i); break; } } if (selectedDevice != null) { cbxCPU.setSelected(false); cbxGPU.setSelected(true); } selectDeviceTableModel.fireTableDataChanged(); } } @Override public void actionPerformed(ActionEvent e) { if (e.getSource() == cbxCPU) { if (cbxCPU.isSelected()) { selectedDevice = null; cbxGPU.setSelected(false); selectDeviceTableModel.fireTableDataChanged(); } else { cbxCPU.setSelected(true); } return; } else if (e.getSource() == cbxGPU) { if (cbxGPU.isSelected()) { if (devices.size() < 1) { cbxGPU.setSelected(false); cbxCPU.setSelected(true); return; } if (selectedDevice == null) { selectedDevice = findGPUDevice(); if (selectedDevice == null) { selectedDevice = devices.get(0); } } cbxCPU.setSelected(false); selectDeviceTableModel.fireTableDataChanged(); } else { cbxGPU.setSelected(true); } return; } } private OpenCLDevice findGPUDevice() { if (devices == null) { return null; } for (OpenCLDevice d : devices) { if (d.isGPU()) { return d; } } return null; } @Override public void beforePasswordDialogShow() { } @Override public void afterPasswordDialogDismiss() { } @Override public void onProgress(final String speed, final long generated, final double progress, final int nextPossibility, final String nextTimePeriodSeconds) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { pb.setValue((int) (pb.getMinimum() + (progress / 100) * (pb .getMaximum() - pb.getMinimum()))); lblGenerated.setText(String.format(LocaliserUtils.getString ("vanity_generated"), generated, progress)); lblSpeed.setText(String.format(LocaliserUtils.getString ("vanity_speed"), speed)); lblTimeRemain.setText(String.format(LocaliserUtils.getString("vanity_time_remain"), nextPossibility, nextTimePeriodSeconds)); } }); } private void importPrivateKey() { new Thread(new Runnable() { @Override public void run() { final SecureCharSequence password = passwordGetter.getPassword(); if (password != null) { ImportPrivateKeyDesktop importPrivateKey = new ImportPrivateKeyDesktop (ImportPrivateKey.ImportPrivateKeyType.Text, privateKeyStr, password, new ImportPrivateKeyDesktop.ImportPrivateKeyListener() { @Override public void importSuccess() { privateKeyStr = null; SwingUtilities.invokeLater(new Runnable() { @Override public void run() { closePanel(); } }); } }); importPrivateKey.importPrivateKey(); } else { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { closePanel(); } }); } } }).start(); } @Override public void getAddress(String address) { addressStr = address; } @Override public void getPrivateKey(final String privateKey, final long useTime) { privateKeyStr = privateKey; final Runnable okRunnable = new Runnable() { @Override public void run() { importPrivateKey(); } }; final Runnable cancelRunnable = new Runnable() { @Override public void run() { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { closePanel(); } }); } }; SwingUtilities.invokeLater(new Runnable() { @Override public void run() { System.out.println("time:" + useTime); long seconds = useTime / 1000; if (seconds == 0) { seconds = 1; } String str = Utils.format(LocaliserUtils.getString("vanitygen_address_generate_success"), addressStr); DialogConfirmTask dialogConfirmTask = new DialogConfirmTask(str, okRunnable, cancelRunnable); dialogConfirmTask.pack(); dialogConfirmTask.setVisible(true); } }); } @Override public void onDifficulty(final String difficulty) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { lblDifficulty.setText(String.format(LocaliserUtils.getString ("vanity_difficulty"), difficulty)); } }); } @Override public void error(String error) { new MessageDialog(error).showMsg(); SwingUtilities.invokeLater(new Runnable() { @Override public void run() { closePanel(); } }); } @Override public void selectOption(BitherSetting.ECKeyType ecKeyType, int threadNum) { this.ecKeyType = ecKeyType; this.threadNum = threadNum; } @Override public boolean useOpenCl() { return shouldUseOpenCL(); } private String speedToString(double speed) { String[] KMG = new String[]{"", "k", "M", "G"}; int i = 0; while (speed >= 1000) { i++; speed /= 1000.0; } return String.format("%s%s", new DecimalFormat("#.##").format(speed), KMG[i]); } private String secondsToString(long seconds) { long now = System.currentTimeMillis(); return remainingTimeFormatter.print(new Period(now, now + seconds * 1000, PeriodType.yearMonthDayTime())); } }