package org.bitseal.pow;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.NumberFormat;
import org.bitseal.util.ByteUtils;
import android.util.Log;
/**
* A worker class to parallelize POW calculation.
*
* @author Sebastian Schmidt, modified by Jonathan Coe
*/
public class POWWorker implements Runnable
{
protected boolean POWSuccessful;
/** The collision quality that should be achieved. */
private long target;
/** The POW nonce. */
private volatile long nonce;
/** The initial hash value. */
private byte[] initialHash;
/** The increment that should be used for finding the next nonce. */
private long increment;
/** True if the calculation is running. */
private volatile boolean running;
/** A stop request can be made by setting this to true. */
private volatile boolean stop;
/** The listener to inform if we found the result. */
private POWListener listener;
private MessageDigest sha512;
/** The number of double SHA-512 hashes calculated by this worker so far. */
private int doubleHashesCalculated = 0;
private static final String TAG = "POW_WORKER";
/**
* Creates a new POWWorker.
*
* @param target - A long representing the target collision quality.
* @param startNonce - A long representing the nonce to start with.
* @param increment - A long representing the step size. A POW worker calculates with: startNonce,
* startNonce + increment, startNonce + 2 * increment.
* @param initialHash - A byte[] containing the hash of the message.
* @param listener - The POWListener object to inform if a result was found.
*/
public POWWorker(long target, long startNonce, long increment, byte[] initialHash, POWListener listener)
{
if (listener == null)
{
throw new NullPointerException("The listener field in POWWorker must not be null.");
}
this.target = target;
this.nonce = startNonce;
this.increment = increment;
this.initialHash = initialHash;
this.listener = listener;
try
{
sha512 = MessageDigest.getInstance("SHA-512");
}
catch (NoSuchAlgorithmException e)
{
throw new RuntimeException("NoSuchAlgorithmException occurred in POWWorker constructor", e);
}
}
/**
* Returns true if the worker is actually calculating the POW.
*
* @return True if the worker is actually calculating the POW.
*/
public boolean isRunning()
{
return running;
}
/**
* Request the worker to stop.
*/
public void stop()
{
stop = true;
}
/**
* Returns the current nonce. Note that it can be wrong if isRunning()
* returns true or no success was reported.
*
* @return The current nonce.
*/
public long getNonce()
{
return nonce;
}
public boolean getSuccessResult()
{
return POWSuccessful;
}
public int getDoubleHashesCalculated()
{
return doubleHashesCalculated;
}
/**
* Calculates the POW.
*/
@Override
public void run()
{
running = true;
long nonce = this.nonce;
while (!stop)
{
// Calculate the double SHA512 hash of the current nonce concatenated with the payload (initial) hash
sha512.reset();
sha512.update(ByteUtils.longToBytes(nonce));
byte[] hash = sha512.digest(initialHash);
sha512.reset();
hash = sha512.digest(hash);
doubleHashesCalculated ++;
// Get the resulting hash as a long
long result = ByteUtils.bytesToLong(hash);
// Check whether the current nonce gives a result that meets the POW target
if (result <= target && result >= 0)
{
Log.d(TAG, "Found a valid nonce! : " + NumberFormat.getIntegerInstance().format(nonce));
stop();
this.nonce = nonce;
POWSuccessful = true;
listener.powFinished(this);
break;
}
// Increment the POW nonce
else
{
nonce += increment;
}
}
running = false;
}
}