package org.bitseal.core; import java.io.ByteArrayOutputStream; import java.io.IOException; import org.bitseal.R; import org.bitseal.data.Message; import org.bitseal.data.Payload; import org.bitseal.database.PayloadProvider; import org.bitseal.network.NetworkHelper; import org.bitseal.network.ServerCommunicator; import org.bitseal.pow.POWProcessor; import org.bitseal.services.MessageStatusHandler; import org.bitseal.util.ByteUtils; import org.bitseal.util.TimeUtils; import org.bitseal.util.VarintEncoder; import android.util.Log; /** * A class which provides various methods used for processing * outgoing getpubkey objects. * * @author Jonathan Coe */ public class OutgoingGetpubkeyProcessor { /** The object type number for getpubkeys, as defined by the Bitmessage protocol */ private static final int OBJECT_TYPE_GETPUBKEY = 0; private static final String TAG = "OUTGOING_GETPUBKEY_PROCESSOR"; /** * Creates a new getpubkey object for the given Bitmessage address and * disseminates it to the rest of the Bitmessage network. * * @param getpubkeyPayload - A Payload object containing the getpubkey * object to be disseminated * * @return - A Payload object containing the newly created getpubkey object */ public void disseminateGetpubkeyRequest(Payload getpubkeyPayload) { // Disseminate the getpubkey payload ServerCommunicator servCom = new ServerCommunicator(); boolean disseminationSuccessful = servCom.disseminateGetpubkey(getpubkeyPayload.getPayload()); if (disseminationSuccessful) { getpubkeyPayload.setTime(System.currentTimeMillis() / 1000); // Set the 'time' value of the getpubkey Payload to be the last time at which the payload // was successfully disseminated. This allows us to determine when to disseminate it again. PayloadProvider payProv = PayloadProvider.get(App.getContext()); payProv.updatePayload(getpubkeyPayload); } } /** * Creates a new getpubkey object for the 'to address' of a given Message and * disseminates it to the rest of the Bitmessage network. * * @param addressString - The Message we are trying to send * @param timeToLive - The 'time to live' value (in seconds) to be used in creating * this getpubkey * * @return - A Payload object containing the newly created getpubkey object */ public Payload constructAndDisseminateGetpubkeyRequst(Message message, long timeToLive) { // We were unable to retrieve the pubkey after trying all servers. Now we must create a getpubkey // object which can be sent out to servers. We should then be able to retrieve the required pubkey. Payload getpubkeyPayload = constructGetpubkeyPayload(message.getToAddress(), timeToLive); // Save the getpubkey object to the database PayloadProvider payProv = PayloadProvider.get(App.getContext()); long id = payProv.addPayload(getpubkeyPayload); getpubkeyPayload.setId(id); // Check whether an Internet connection is available. if (NetworkHelper.checkInternetAvailability() == true) { // Update the status of this message displayed in the UI String messageStatus = App.getContext().getString(R.string.message_status_requesting_pubkey); MessageStatusHandler.updateMessageStatus(message, messageStatus); // Disseminate the getpubkey payload try { ServerCommunicator servCom = new ServerCommunicator(); boolean disseminationSuccessful = servCom.disseminateGetpubkey(getpubkeyPayload.getPayload()); if (disseminationSuccessful) { getpubkeyPayload.setTime(System.currentTimeMillis() / 1000); payProv.updatePayload(getpubkeyPayload); } return getpubkeyPayload; } catch (RuntimeException e) { Log.e(TAG, "RuntimeException occurred in PubkeyProcessor.constructAndDisseminateGetpubkeyRequst()\n" + "The exception message was: " + e.getMessage()); return getpubkeyPayload; } } else { MessageStatusHandler.updateMessageStatus(message, App.getContext().getString(R.string.message_status_waiting_for_connection)); return getpubkeyPayload; } } /** * Constructs a getpubkey object which can be sent out to servers, allowing * them to request the required pubkey, which we can then retrieve from them. * * @param addressString - A String containing the address of the pubkey which the * getpubkey object will be used to retrieve * @param timeToLive - The 'time to live' value (in seconds) to be used in creating * this getpubkey * * @return A Payload object containing the getpubkey object */ private Payload constructGetpubkeyPayload(String addressString, long timeToLive) { Log.i(TAG, "Constructing a new getpubkey Payload to request the pubkey of address " + addressString); // Get the fuzzed expiration time and encoded it into byte[] form long expirationTime = TimeUtils.getFuzzedExpirationTime(timeToLive); byte[] expirationTimeBytes = ByteUtils.longToBytes(expirationTime); // Get the address version and stream number AddressProcessor addProc = new AddressProcessor(); int[] decodedAddressNumbers = addProc.decodeAddressNumbers(addressString); int addressVersion = decodedAddressNumbers[0]; int streamNumber = decodedAddressNumbers[1]; byte[] pubkeyIdentifier = null; if (addressVersion <= 3) { pubkeyIdentifier = addProc.extractRipeHashFromAddress(addressString); } else { pubkeyIdentifier = addProc.calculateAddressTag(addressString); } byte[] payload = null; ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); try { outputStream.write(expirationTimeBytes); outputStream.write(ByteUtils.intToBytes(OBJECT_TYPE_GETPUBKEY)); outputStream.write(VarintEncoder.encode(addressVersion)); outputStream.write(VarintEncoder.encode(streamNumber)); outputStream.write(pubkeyIdentifier); payload = outputStream.toByteArray(); outputStream.close(); } catch (IOException e) { throw new RuntimeException("IOException occurred in PubkeyProcessor.constructGetpubkeyPayload()", e); } // Do the POW for the payload we have constructed POWProcessor powProc = new POWProcessor(); long powNonce = powProc.doPOW(payload, expirationTime, POWProcessor.NETWORK_NONCE_TRIALS_PER_BYTE, POWProcessor.NETWORK_EXTRA_BYTES); byte[] powNonceBytes = ByteUtils.longToBytes(powNonce); // Add the POW nonce to the payload payload = ByteUtils.concatenateByteArrays(powNonceBytes, payload); Payload getpubkeyPayload = new Payload(); getpubkeyPayload.setBelongsToMe(true); // We set the time to zero to convey that the getpubkey Payload has not yet been successfully disseminated. // This is a slightly obscure way of handling the need to record the last time at which the getpubkey was // successfully disseminated, and should perhaps be changed to something more straightforward in the future. getpubkeyPayload.setTime(0); getpubkeyPayload.setType(Payload.OBJECT_TYPE_GETPUBKEY); getpubkeyPayload.setPOWDone(true); getpubkeyPayload.setPayload(payload); return getpubkeyPayload; } }