package org.bitseal.pow; import java.text.NumberFormat; import org.bitseal.util.TimeUtils; import android.util.Log; /** * Does the POW calculation, uses multiple threads. * * @author Sebastian Schmidt, modified by Jonathan Coe */ public class POWCalculator implements POWListener { /** The number of threads to use per CPU. */ private static final int THREADS_PER_CPU = 1; /** The target collision quality. */ private long target; /** The hash of the message. */ private byte[] initialHash; /** The worker that found a valid nonce. */ private POWWorker finishedWorker; /** The number of double SHA-512 hashes calculated. */ private int doubleHashesCalculated = 0; private static final String TAG = "POW_CALCULATOR"; public void setTarget(long newTarget) { target = newTarget; } public void setInitialHash(byte[] newInitialHash) { initialHash = newInitialHash; } /** * Do the Proof of Work calculations.<br><br> * <b>WARNING: This can take a long time.</b><br><br> * * <b>Note: If POW is not completed within the time allowed, this method will return 0.</b> * * @return A long containing a nonce that fulfils the collision quality condition. */ public synchronized long execute() { // Create a new worker thread for each CPU core POWWorker[] workers = new POWWorker[Runtime.getRuntime().availableProcessors() * THREADS_PER_CPU]; long startTime = System.currentTimeMillis(); // Start the worker threads for (int i = 0; i < workers.length; i++) { workers[i] = new POWWorker(target, i, workers.length, initialHash, this); new Thread(workers[i], "POW Worker No. " + i).start(); } // Wait for POW to be completed try { wait(); } catch (InterruptedException e) { throw new RuntimeException("InterruptedException occurred in POWCalculator.execute()", e); } // Once POW has completed successfully or been interrupted, stop any worker threads that are still running for (POWWorker w : workers) { w.stop(); doubleHashesCalculated = doubleHashesCalculated + w.getDoubleHashesCalculated(); } // Calculate the time statistics for this POW session long endTime = System.currentTimeMillis(); long totalTime = (endTime - startTime) / 1000; Log.d(TAG, "Double hashes calculated : " + NumberFormat.getIntegerInstance().format(doubleHashesCalculated)); Log.d(TAG, "Time taken : " + TimeUtils.getTimeMessage(totalTime)); Log.d(TAG, "Hash rate : " + NumberFormat.getIntegerInstance().format((doubleHashesCalculated / totalTime)) + " double-hashes per second"); return finishedWorker.getNonce(); } @Override public synchronized void powFinished(POWWorker powWorker) { if (finishedWorker == null) { finishedWorker = powWorker; } notifyAll(); } }