diff --git a/src/BitcoinLotto.java b/src/BitcoinLotto.java new file mode 100644 index 0000000..12c85b8 --- /dev/null +++ b/src/BitcoinLotto.java @@ -0,0 +1,309 @@ +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.List; +import java.util.Timer; +import java.util.prefs.Preferences; + +import org.bitcoinj.core.Address; +import org.bitcoinj.params.MainNetParams; + +public class BitcoinLotto { + + public static void main(String[] args) { + BitcoinLotto thisLotto = new BitcoinLotto(); + thisLotto.startGui(); + } + + private Status lottoStatus = Status.MAIN_MENU; + private Boolean isInitialized = false; + private Address[] addressArray; + private SearchThread[] threadArray; + private Timer guiTimer; + + private GuiUpdateTimer guiUpdateTimer; + + private PrimaryWindow primaryWindow; + private long totalCheckCount = 0; + private long startTime = 0; + private int threadCount = 1; + + private int activeThreadCount = 0; // threads loaded and running + private long pausedTimeTotal = 0; + + private long pauseStartTime = 0; + private String prefsNode = "com/github/traxm/BitcoinLotto"; + private String prefsFileString = "filePath"; + + private String prefsThreadString = "threadCount"; + + public Address[] getAddressArray() { + return addressArray; + } + + public void initializeLookupAddresses(File thisFile) { + /* + * Read the address file and populate an array with the data + */ + + String[] addressStringArray; + Address thisAddress = null; + ArrayList
addressList = null; + + addressStringArray = readLines(thisFile); + addressList = new ArrayList
(); + + for (int i = 0; i < addressStringArray.length; i++) { + try { + thisAddress = Address.fromString(MainNetParams.get(), addressStringArray[i]); + } catch (org.bitcoinj.core.AddressFormatException ex) { + primaryWindow.showFileErrorMessage(); + return; + } + addressList.add(thisAddress); + } + + addressArray = new Address[addressList.size()]; + addressArray = addressList.toArray(addressArray); + + // Check to see if any addresses entries were read + if (addressArray == null || addressArray.length <= 0) + return; + + // Update the UI with the number of addresses loaded + primaryWindow.setTotalAddressLabel(addressArray.length); + + // Allow the user to start the lotto + primaryWindow.enableStartButton(); + + // Save the file path for future use + saveFilePath(thisFile); + + // Write a small test file to confirm that any matched addresses can be saved + writeStarterFile(); + + isInitialized = true; + } + + private Boolean isFileAvailable(String filePath) { + // Checks to see if a last address file is available to load + + if (filePath == null) + return false; + + File tempFile = new File(filePath); + return tempFile.exists(); + } + + public Boolean isInitialized() { + return isInitialized; + } + + public void logAddressCheck() { + // Track address checks + + totalCheckCount++; + } + + public void notifySuccess(String matchAddress, String matchKey) { + primaryWindow.setSuccessLabel(true, matchAddress, matchKey); + } + + public void pauseAllThreads() { + /* + * End each thread based on user input + */ + + lottoStatus = Status.PAUSED; + + for (int i = 0; i < this.threadArray.length; i++) + this.threadArray[i].stopThread(); + + pauseStartTime = System.nanoTime(); + activeThreadCount = 0; + primaryWindow.setThreadsActiveLabel(activeThreadCount); + } + + private String[] readLines(File thisFile) { + /* + * Read lines from a file + */ + + BufferedReader bufferedReader; + + FileInputStream thisStream; + List lines = null; + try { + thisStream = new FileInputStream(thisFile); + bufferedReader = new BufferedReader(new InputStreamReader(thisStream)); + + lines = new ArrayList(); + String line = null; + + while ((line = bufferedReader.readLine()) != null) { + lines.add(line); + } + + bufferedReader.close(); + } catch (FileNotFoundException e) { + primaryWindow.showFileErrorMessage(); + e.printStackTrace(); + + } catch (IOException e) { + primaryWindow.showFileErrorMessage(); + e.printStackTrace(); + } + + return lines.toArray(new String[lines.size()]); + } + + public void resumeAllThreads() { + /* + * Create and start new threads based on user input + */ + + lottoStatus = Status.RUNNING; + + this.startThreads(threadCount); + + // Update the paused time + this.pausedTimeTotal += (System.nanoTime() - this.pauseStartTime); + } + + private void saveFilePath(File thisFile) { + // Saves the file path for future use + String filePathString = thisFile.getAbsolutePath(); + + Preferences prefs = Preferences.userRoot().node(prefsNode); + prefs.put(prefsFileString, filePathString); + } + + private void saveThreadCount(int threadCount) { + // Saves the file path for future use + Preferences prefs = Preferences.userRoot().node(prefsNode); + prefs.putInt(prefsThreadString, threadCount); + } + + private void startGui() { + /* + * Create a frame and populate with components + */ + primaryWindow = new PrimaryWindow(this); + + // Check to see if an existing address file is available + Preferences prefs = Preferences.userRoot().node(prefsNode); + // Does the preference entry exist + // Is the file available + if (isFileAvailable(prefs.get(prefsFileString, null))) { + // Load the existing file + System.out.println(isFileAvailable(prefs.get(prefsFileString, null))); + primaryWindow.setAddressFile(new File(prefs.get(prefsFileString, null))); + + // Set the thread count + primaryWindow.setThreadCount(prefs.getInt(this.prefsThreadString, 4)); + } + + primaryWindow.setWindowEnabled(true); + + } + + public void startLotto(int threadCount) throws URISyntaxException { + /* + * Start the lottery process + */ + + // Swap the active panel (0 is the main menu and 1 is the working panel) + primaryWindow.setPanel(1); + + // Create the worker threads + startThreads(threadCount); + + // Set a timer to update UI components + guiTimer = new Timer(); + guiUpdateTimer = new GuiUpdateTimer(this); + guiTimer.schedule(guiUpdateTimer, 0, 20); + + // Start tracking time + startTime = System.nanoTime(); + + // Save thread count for future use + this.saveThreadCount(threadCount); + + } + + private void startThreads(int thisCount) { + /* + * Create and start worker threads + */ + + // Thread count is pulled from user input + threadCount = thisCount; + + // Create the thread array + threadArray = new SearchThread[threadCount]; + + // Create specified threads + for (int i = 0; i < threadCount; i++) { + SearchThread thisThread = new SearchThread(); // Create a Search Thread instance + threadArray[i] = thisThread; // Add the instance to the thread array + thisThread.initialize(this, (i + 1) * 1000); // Initialize the thread and pass startup delay/sleep duration + } + + // Start each of the threads + for (int i = 0; i < threadCount; i++) { + threadArray[i].start(); + } + + // Update the lotto status + lottoStatus = Status.RUNNING; + } + + public void updateGuiElements() { + // Update all gui values + + if (lottoStatus == Status.PAUSED) + return; + + this.primaryWindow.setScanAttemptsLabel(totalCheckCount); + + long duration = System.nanoTime() - startTime - this.pausedTimeTotal; + this.primaryWindow.setTimeLabel(duration / 1000000, totalCheckCount); + } + + public void updateThreadCount() { + // Called by threads at start - active threads communicated via UI + + if (activeThreadCount > threadCount) + return; + + activeThreadCount++; + primaryWindow.setThreadsActiveLabel(activeThreadCount); + } + + private void writeStarterFile() { + // Writes a blank file to confirm write process functions as intended + String thisString = "Ignore this file"; + FileWriter thisFile; + try { + thisFile = new FileWriter("testFilePleaseIgnore.txt"); + BufferedWriter writer = new BufferedWriter(thisFile); + writer.write(thisString); + writer.close(); + } catch (IOException e) { + // Exit + primaryWindow.showFileErrorMessage(); + } + } + +} + +enum Status { + MAIN_MENU, RUNNING, PAUSED; +} \ No newline at end of file diff --git a/src/GuiUpdateTimer.java b/src/GuiUpdateTimer.java new file mode 100644 index 0000000..279e760 --- /dev/null +++ b/src/GuiUpdateTimer.java @@ -0,0 +1,19 @@ +import java.util.TimerTask; + +public class GuiUpdateTimer extends TimerTask { + + private BitcoinLotto bitcoinLotto; + + public GuiUpdateTimer(BitcoinLotto thisLotto) { + bitcoinLotto = thisLotto; + } + + + @Override + public void run() { + bitcoinLotto.updateGuiElements(); + } + + + +} diff --git a/src/PrimaryWindow.java b/src/PrimaryWindow.java new file mode 100644 index 0000000..5312caa --- /dev/null +++ b/src/PrimaryWindow.java @@ -0,0 +1,431 @@ +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JLabel; +import javax.swing.JOptionPane; + +import java.awt.Font; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.io.File; +import java.net.URISyntaxException; + +import javax.swing.SwingConstants; +import javax.swing.UIManager; +import javax.swing.UIManager.LookAndFeelInfo; +import javax.swing.UnsupportedLookAndFeelException; +import javax.swing.filechooser.FileNameExtensionFilter; +import javax.swing.JButton; +import javax.swing.JTextField; +import javax.swing.SpinnerModel; +import javax.swing.SpinnerNumberModel; +import java.awt.CardLayout; +import javax.swing.JTextArea; +import javax.swing.JSeparator; +import javax.swing.JSpinner; +import javax.swing.JProgressBar; +import java.awt.Color; +import javax.swing.JFileChooser; +import java.awt.SystemColor; + +public class PrimaryWindow { + + private JFrame frmBitcoinLotto; + private JTextField fileAddressField; + private JButton startButton; + private BitcoinLotto bitcoinLotto; + private JPanel mainPanel; + private JPanel workingPanel; + private JButton pauseButton; + private JProgressBar progressBar; + private JSpinner threadSpinner; + private JButton loadFileButton; + + private JLabel totalAttemptsLabel; + private JLabel attemptsPerSecondLabel; + private JLabel totalAddressLabel; + private JLabel successLabel; + private JLabel timeLabel; + private JLabel threadCountLabel; + private JLabel matchedKeyLabel; + private JLabel matchedAddressLabel; + + /* + * Create the application. + */ + public PrimaryWindow(BitcoinLotto thisLotto) { + bitcoinLotto = thisLotto; + initialize(); + } + + public void setWindowEnabled(Boolean thisBool) { + this.frmBitcoinLotto.setVisible(thisBool); + } + + /** + * Initialize the contents of the frame. + */ + private void initialize() { + + UIManager.put("ProgressBar[Enabled+Finished].foregroundPainter", Color.black); + + try { + for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) { + if ("Nimbus".equals(info.getName())) { + UIManager.setLookAndFeel(info.getClassName()); + break; + } + } + } catch (Exception e) { + try { + UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName()); + } catch (ClassNotFoundException | InstantiationException | IllegalAccessException + | UnsupportedLookAndFeelException e1) { + e1.printStackTrace(); + } + } + + frmBitcoinLotto = new JFrame(); + frmBitcoinLotto.setTitle("Bitcoin Lotto"); + frmBitcoinLotto.setBounds(100, 100, 450, 700); + frmBitcoinLotto.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frmBitcoinLotto.getContentPane().setLayout(null); + + JPanel panel = new JPanel(); + panel.setBounds(0, 0, 434, 661); + frmBitcoinLotto.getContentPane().add(panel); + panel.setLayout(new CardLayout(0, 0)); + + mainPanel = new JPanel(); + panel.add(mainPanel, "name_432466542248400"); + mainPanel.setLayout(null); + + JLabel lblBitcoinLotto = new JLabel("Bitcoin Lotto!"); + lblBitcoinLotto.setBounds(34, 11, 365, 75); + mainPanel.add(lblBitcoinLotto); + lblBitcoinLotto.setHorizontalAlignment(SwingConstants.CENTER); + lblBitcoinLotto.setFont(new Font("Tahoma", Font.PLAIN, 62)); + + loadFileButton = new JButton("Load Address File"); + loadFileButton.setBounds(10, 513, 300, 54); + loadFileButton.addActionListener(new FileBrowserListener()); + mainPanel.add(loadFileButton); + loadFileButton.setFont(new Font("Tahoma", Font.PLAIN, 24)); + + fileAddressField = new JTextField(); + fileAddressField.setBounds(10, 472, 396, 25); + mainPanel.add(fileAddressField); + fileAddressField.setColumns(10); + + JLabel lblLottoThreads = new JLabel("Lotto Threads"); + lblLottoThreads.setBounds(10, 364, 414, 33); + mainPanel.add(lblLottoThreads); + lblLottoThreads.setHorizontalAlignment(SwingConstants.CENTER); + lblLottoThreads.setFont(new Font("Tahoma", Font.PLAIN, 24)); + + startButton = new JButton("Start Lotto!"); + startButton.setBounds(10, 585, 300, 65); + mainPanel.add(startButton); + startButton.setFont(new Font("Tahoma", Font.PLAIN, 24)); + startButton.setEnabled(false); + + JButton btnExit = new JButton("Exit"); + btnExit.setBounds(320, 585, 104, 65); + btnExit.setBackground(Color.red); + mainPanel.add(btnExit); + btnExit.setFont(new Font("Tahoma", Font.PLAIN, 24)); + + JTextArea txtrTheBitcoinLotto = new JTextArea(); + txtrTheBitcoinLotto.setFont(new Font("Monospaced", Font.PLAIN, 12)); + txtrTheBitcoinLotto.setForeground(Color.BLACK); + txtrTheBitcoinLotto.setBackground(SystemColor.controlHighlight); + txtrTheBitcoinLotto.setEditable(false); + txtrTheBitcoinLotto.setWrapStyleWord(true); + txtrTheBitcoinLotto.setLineWrap(true); + txtrTheBitcoinLotto.setText( + "The Bitcoin Lotto creates random bitcoin private/public key pairs and compares the addresses to a list of existing addresses. In the event that an address is matched, the public/private keys are saved to a text file in the program directory.\r\n\r\n- Step 1: Load a text file of bitcoin addresses which you would like to check for matches (one address per line)\r\n- Step 2: Start the lotto"); + txtrTheBitcoinLotto.setBounds(10, 97, 414, 213); + mainPanel.add(txtrTheBitcoinLotto); + + JSeparator separator = new JSeparator(); + separator.setBounds(22, 351, 390, 2); + mainPanel.add(separator); + + threadSpinner = new JSpinner(); + threadSpinner.setFont(new Font("Tahoma", Font.PLAIN, 22)); + threadSpinner.setBounds(165, 406, 104, 35); + mainPanel.add(threadSpinner); + SpinnerModel spinnerModel = new SpinnerNumberModel(4, 1, 64, 1); + threadSpinner.setModel(spinnerModel); + + ((JSpinner.DefaultEditor) threadSpinner.getEditor()).getTextField().setEditable(false); + + btnExit.addActionListener(new ExitListener()); + startButton.addActionListener(new StartListener()); + startButton.setBackground(Color.green); + + workingPanel = new JPanel(); + panel.add(workingPanel, "name_432575102303500"); + workingPanel.setLayout(null); + + JLabel lblBitcoinLotto_1 = new JLabel("Bitcoin Lotto!"); + lblBitcoinLotto_1.setBounds(76, 5, 281, 51); + lblBitcoinLotto_1.setHorizontalAlignment(SwingConstants.CENTER); + lblBitcoinLotto_1.setFont(new Font("Tahoma", Font.PLAIN, 42)); + workingPanel.add(lblBitcoinLotto_1); + + JLabel label_1 = new JLabel("Lottery Attempts"); + label_1.setBounds(10, 65, 414, 51); + label_1.setHorizontalAlignment(SwingConstants.CENTER); + label_1.setFont(new Font("Tahoma", Font.PLAIN, 32)); + workingPanel.add(label_1); + + totalAttemptsLabel = new JLabel("0"); + totalAttemptsLabel.setBounds(10, 110, 414, 34); + totalAttemptsLabel.setHorizontalAlignment(SwingConstants.CENTER); + totalAttemptsLabel.setFont(new Font("Tahoma", Font.PLAIN, 32)); + workingPanel.add(totalAttemptsLabel); + + JLabel label_3 = new JLabel("Time Elapsed"); + label_3.setBounds(152, 246, 130, 27); + label_3.setHorizontalAlignment(SwingConstants.CENTER); + label_3.setFont(new Font("Tahoma", Font.PLAIN, 22)); + workingPanel.add(label_3); + + timeLabel = new JLabel("0"); + timeLabel.setBounds(128, 270, 177, 29); + timeLabel.setHorizontalAlignment(SwingConstants.CENTER); + timeLabel.setFont(new Font("Tahoma", Font.PLAIN, 24)); + workingPanel.add(timeLabel); + + pauseButton = new JButton("Pause Lotto"); + pauseButton.setBounds(10, 541, 414, 51); + pauseButton.setFont(new Font("Tahoma", Font.PLAIN, 32)); + pauseButton.addActionListener(new PauseListener()); + pauseButton.setBackground(Color.yellow); + workingPanel.add(pauseButton); + + JButton exitButton = new JButton("Exit"); + exitButton.setBounds(312, 603, 112, 47); + exitButton.setFont(new Font("Tahoma", Font.PLAIN, 32)); + exitButton.setBackground(Color.red); + exitButton.addActionListener(new ExitListener()); + workingPanel.add(exitButton); + + progressBar = new JProgressBar(); + progressBar.setIndeterminate(true); + progressBar.setBounds(18, 164, 398, 34); + workingPanel.add(progressBar); + + JLabel lblAverageSpeedper = new JLabel("Attempts per second"); + lblAverageSpeedper.setHorizontalAlignment(SwingConstants.CENTER); + lblAverageSpeedper.setFont(new Font("Tahoma", Font.PLAIN, 18)); + lblAverageSpeedper.setBounds(10, 310, 414, 27); + workingPanel.add(lblAverageSpeedper); + + attemptsPerSecondLabel = new JLabel("0"); + attemptsPerSecondLabel.setHorizontalAlignment(SwingConstants.CENTER); + attemptsPerSecondLabel.setFont(new Font("Tahoma", Font.PLAIN, 24)); + attemptsPerSecondLabel.setBounds(128, 334, 177, 29); + workingPanel.add(attemptsPerSecondLabel); + + JLabel lblAnyMatchesThis = new JLabel("Any matches this session?"); + lblAnyMatchesThis.setHorizontalAlignment(SwingConstants.CENTER); + lblAnyMatchesThis.setFont(new Font("Tahoma", Font.PLAIN, 22)); + lblAnyMatchesThis.setBounds(10, 380, 414, 27); + workingPanel.add(lblAnyMatchesThis); + + successLabel = new JLabel("NO"); + successLabel.setForeground(Color.RED); + successLabel.setHorizontalAlignment(SwingConstants.CENTER); + successLabel.setFont(new Font("Tahoma", Font.PLAIN, 36)); + successLabel.setBounds(119, 409, 195, 47); + workingPanel.add(successLabel); + + JSeparator separator_1 = new JSeparator(); + separator_1.setBounds(26, 522, 398, 8); + workingPanel.add(separator_1); + + totalAddressLabel = new JLabel("0"); + totalAddressLabel.setHorizontalAlignment(SwingConstants.LEFT); + totalAddressLabel.setFont(new Font("Tahoma", Font.PLAIN, 12)); + totalAddressLabel.setBounds(137, 212, 122, 15); + workingPanel.add(totalAddressLabel); + + JLabel addressTotal = new JLabel("Target Addresses:"); + addressTotal.setHorizontalAlignment(SwingConstants.RIGHT); + addressTotal.setFont(new Font("Tahoma", Font.PLAIN, 12)); + addressTotal.setBounds(5, 212, 122, 15); + workingPanel.add(addressTotal); + + threadCountLabel = new JLabel("0"); + threadCountLabel.setHorizontalAlignment(SwingConstants.LEFT); + threadCountLabel.setFont(new Font("Tahoma", Font.PLAIN, 12)); + threadCountLabel.setBounds(359, 212, 57, 15); + workingPanel.add(threadCountLabel); + + JLabel lblThreadsActive = new JLabel("Threads Active:"); + lblThreadsActive.setHorizontalAlignment(SwingConstants.RIGHT); + lblThreadsActive.setFont(new Font("Tahoma", Font.PLAIN, 12)); + lblThreadsActive.setBounds(258, 212, 95, 15); + workingPanel.add(lblThreadsActive); + + JLabel matchedAddress = new JLabel("Matched Address:"); + matchedAddress.setHorizontalAlignment(SwingConstants.LEFT); + matchedAddress.setBounds(10, 441, 106, 15); + workingPanel.add(matchedAddress); + + JLabel matchedKey = new JLabel("Matched Private Key:"); + matchedKey.setHorizontalAlignment(SwingConstants.LEFT); + matchedKey.setBounds(10, 479, 152, 15); + workingPanel.add(matchedKey); + + matchedAddressLabel = new JLabel("Address"); + matchedAddressLabel.setForeground(Color.BLACK); + matchedAddressLabel.setFont(new Font("Tahoma", Font.PLAIN, 11)); + matchedAddressLabel.setHorizontalAlignment(SwingConstants.LEFT); + matchedAddressLabel.setBounds(10, 456, 414, 21); + matchedAddressLabel.setText("none"); + workingPanel.add(matchedAddressLabel); + + matchedKeyLabel = new JLabel("Address"); + matchedKeyLabel.setFont(new Font("Tahoma", Font.PLAIN, 11)); + matchedKeyLabel.setHorizontalAlignment(SwingConstants.LEFT); + matchedKeyLabel.setBounds(10, 492, 414, 21); + matchedKeyLabel.setText("none"); + workingPanel.add(matchedKeyLabel); + + } + + public void setPanel(int panelIndex) { + switch (panelIndex) { + case 0: + mainPanel.setVisible(true); + workingPanel.setVisible(false); + break; + case 1: + mainPanel.setVisible(false); + workingPanel.setVisible(true); + break; + } + } + + public void setScanAttemptsLabel(long thisLong) { + this.totalAttemptsLabel.setText(String.format("%,d", thisLong)); + } + + public void setTotalAddressLabel(long thisLong) { + this.totalAddressLabel.setText(String.format("%,d", thisLong)); + } + + public void setSuccessLabel(Boolean thisBool, String matchedAddress, String matchedPrivateKey) { + if (thisBool) { + this.successLabel.setText("YES!!!1!"); + this.successLabel.setForeground(Color.GREEN); + + this.matchedAddressLabel.setText(matchedAddress); + this.matchedKeyLabel.setText(matchedPrivateKey); + } + } + + public void setThreadsActiveLabel(int thisThreadCount) { + this.threadCountLabel.setText(String.format("%,d", thisThreadCount)); + } + + public void enableStartButton() { + startButton.setEnabled(true); + } + + public void setAddressFile(File thisFile) { + fileAddressField.setText(thisFile.getPath()); + bitcoinLotto.initializeLookupAddresses(thisFile); + } + + public void setThreadCount(int thisInt) { + threadSpinner.setValue(Integer.valueOf(thisInt)); + } + + public void setTimeLabel(long duration, long addressesChecked) { + + long second = (duration / 1000) % 60; + long minute = (duration / (1000 * 60)) % 60; + long hour = (duration / (1000 * 60 * 60)) % 24; + + String time = String.format("%02d:%02d:%02d", hour, minute, second); + this.timeLabel.setText(String.format(time)); + + // Set attempts per second + duration /= 1000; + if (duration <= 0) + return; + attemptsPerSecondLabel.setText(String.format("%,d", addressesChecked / duration)); + } + + public void showFileErrorMessage() { + JOptionPane.showMessageDialog(frmBitcoinLotto, "File read/write failed."); + } + + public void showAddressFormatMessage() { + JOptionPane.showMessageDialog(frmBitcoinLotto, "One or more addresses are have incorrect formats"); + } + + public class PauseListener implements ActionListener { + + Boolean isPaused = false; + + @Override + public void actionPerformed(ActionEvent arg0) { + + if (isPaused) { + isPaused = false; + pauseButton.setBackground(Color.yellow); + pauseButton.setText("Pause Lotto"); + progressBar.setVisible(true); + bitcoinLotto.resumeAllThreads(); + } else { + isPaused = true; + pauseButton.setBackground(Color.green); + pauseButton.setText("Resume Lotto"); + progressBar.setVisible(false); + bitcoinLotto.pauseAllThreads(); + } + } + } + + public class StartListener implements ActionListener { + @Override + public void actionPerformed(ActionEvent arg0) { + try { + int cpuThreads = (Integer) threadSpinner.getValue(); + startButton.setText("Loading..."); + bitcoinLotto.startLotto(cpuThreads); + } catch (URISyntaxException e) { + e.printStackTrace(); + } + } + } + + public class FileBrowserListener implements ActionListener { + @Override + public void actionPerformed(ActionEvent arg0) { + JFileChooser fileChooser = new JFileChooser(); + FileNameExtensionFilter filter = new FileNameExtensionFilter("TEXT FILES", "txt", "text"); + fileChooser.setFileFilter(filter); + + int returnVal = fileChooser.showOpenDialog(frmBitcoinLotto); + + if (returnVal == JFileChooser.APPROVE_OPTION) { + File thisFile = fileChooser.getSelectedFile(); + setAddressFile(thisFile); + } + } + } + + public class ExitListener implements ActionListener { + @Override + public void actionPerformed(ActionEvent arg0) { + System.exit(0); + } + } + + +} diff --git a/src/SearchThread.java b/src/SearchThread.java new file mode 100644 index 0000000..24f683a --- /dev/null +++ b/src/SearchThread.java @@ -0,0 +1,113 @@ +import java.io.BufferedWriter; +import java.io.FileWriter; +import java.io.IOException; +import java.net.URISyntaxException; +import java.util.Random; + +import org.bitcoinj.core.Address; +import org.bitcoinj.core.ECKey; +import org.bitcoinj.params.MainNetParams; +import org.bitcoinj.script.Script.ScriptType; + +public class SearchThread extends Thread { + + private BitcoinLotto bitcoinLotto; + private Address[] addressArray; + + private Boolean isInterrupted = false; + private int startDelay = 0; + + @Override + public void run() { + try { + try { + if (startDelay > 0) + Thread.sleep(startDelay); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + //If the start delay is greater than zero assume this is the initial run (ie not a resumed event) + if (startDelay > 0 && !isInterrupted) { + bitcoinLotto.updateThreadCount(); + checkAddresses(); + } + + } catch (IOException | URISyntaxException e) { + e.printStackTrace(); + } + } + + public void initialize(BitcoinLotto thisLotto, int thisStartDelay) { + bitcoinLotto = thisLotto; + addressArray = thisLotto.getAddressArray(); + startDelay = thisStartDelay; + } + + private void checkAddresses() throws IOException, URISyntaxException { + + while (!isInterrupted) { + //Generate a random address/key combination + ECKey thisKey = new ECKey(); + //Create an address object + Address pubAddress = Address.fromKey(MainNetParams.get(), thisKey, ScriptType.P2PKH); + //Compare the newly-created address against the address list + if (evaluateAddress(pubAddress)) + //If an address miraculously matches something from the address list + handleMatch(thisKey); + } + } + + private Boolean evaluateAddress(Address thisAddress) { + + bitcoinLotto.logAddressCheck(); + + for (int i = 0; i < addressArray.length; i++) { + if (thisAddress.equals(addressArray[i])) + return true; + } + return false; + } + + private void handleMatch(ECKey thisKey) throws IOException { + /* + * Called if an address match is made. Saves the info to a text file. + */ + + String thisString = ""; + + thisString += Address.fromKey(MainNetParams.get(), thisKey, ScriptType.P2PKH); + thisString += "\n"; + thisString += thisKey.getPrivateKeyAsHex(); + thisString += "\n"; + thisString += thisKey.getPublicKeyAsHex(); + thisString += "\n"; + thisString += thisKey.getPrivateKeyAsWiF(MainNetParams.get()); + + int randomInt = new Random().nextInt(9999999); + + FileWriter thisFile = new FileWriter("bitcoinLottoWinner" + randomInt + ".txt"); + BufferedWriter writer = new BufferedWriter(thisFile); + writer.write(thisString); + writer.close(); + + //Notifies the primary class so UI elements can be updated + bitcoinLotto.notifySuccess(Address.fromKey(MainNetParams.get(), thisKey, ScriptType.P2PKH).toString(), + thisKey.getPrivateKeyAsWiF(MainNetParams.get())); + } + + public void resumeThread() { + isInterrupted = false; + try { + checkAddresses(); + } catch (IOException | URISyntaxException e) { + e.printStackTrace(); + } + } + + public void stopThread() { + isInterrupted = true; + } + + +}