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;
+ }
+
+
+}