From a0e6430c83b8c7aa60a26d5520ad1a87bee2a9a0 Mon Sep 17 00:00:00 2001 From: Jonathan Warren Date: Wed, 29 May 2013 17:18:44 -0400 Subject: [PATCH 01/16] Refactored message status-related code --- src/bitmessagemain.py | 422 ++++++++++++++++++----------------- src/bitmessageqt/__init__.py | 22 +- 2 files changed, 235 insertions(+), 209 deletions(-) diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index 110b4921..3c920520 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -21,7 +21,6 @@ import sys import ConfigParser import Queue from addresses import * -#from shared import * import shared from defaultKnownNodes import * import time @@ -321,101 +320,104 @@ class receiveDataThread(threading.Thread): #print 'self.data is currently ', repr(self.data) #shared.printLock.release() if len(self.data) < 20: #if so little of the data has arrived that we can't even unpack the payload length - pass - elif self.data[0:4] != '\xe9\xbe\xb4\xd9': + return + if self.data[0:4] != '\xe9\xbe\xb4\xd9': if verbose >= 1: shared.printLock.acquire() sys.stderr.write('The magic bytes were not correct. First 40 bytes of data: %s\n' % repr(self.data[0:40])) print 'self.data:', self.data.encode('hex') shared.printLock.release() self.data = "" - else: - self.payloadLength, = unpack('>L',self.data[16:20]) - if len(self.data) >= self.payloadLength+24: #check if the whole message has arrived yet. If it has,... - if self.data[20:24] == hashlib.sha512(self.data[24:self.payloadLength+24]).digest()[0:4]:#test the checksum in the message. If it is correct... - #print 'message checksum is correct' - #The time we've last seen this node is obviously right now since we just received valid data from it. So update the knownNodes list so that other peers can be made aware of its existance. - if self.initiatedConnection and self.connectionIsOrWasFullyEstablished: #The remote port is only something we should share with others if it is the remote node's incoming port (rather than some random operating-system-assigned outgoing port). - shared.knownNodesLock.acquire() - shared.knownNodes[self.streamNumber][self.HOST] = (self.PORT,int(time.time())) - shared.knownNodesLock.release() - if self.payloadLength <= 180000000: #If the size of the message is greater than 180MB, ignore it. (I get memory errors when processing messages much larger than this though it is concievable that this value will have to be lowered if some systems are less tolarant of large messages.) - remoteCommand = self.data[4:16] - shared.printLock.acquire() - print 'remoteCommand', repr(remoteCommand.replace('\x00','')), ' from', self.HOST - shared.printLock.release() - if remoteCommand == 'version\x00\x00\x00\x00\x00': - self.recversion(self.data[24:self.payloadLength+24]) - elif remoteCommand == 'verack\x00\x00\x00\x00\x00\x00': - self.recverack() - elif remoteCommand == 'addr\x00\x00\x00\x00\x00\x00\x00\x00' and self.connectionIsOrWasFullyEstablished: - self.recaddr(self.data[24:self.payloadLength+24]) - elif remoteCommand == 'getpubkey\x00\x00\x00' and self.connectionIsOrWasFullyEstablished: - self.recgetpubkey(self.data[24:self.payloadLength+24]) - elif remoteCommand == 'pubkey\x00\x00\x00\x00\x00\x00' and self.connectionIsOrWasFullyEstablished: - self.recpubkey(self.data[24:self.payloadLength+24]) - elif remoteCommand == 'inv\x00\x00\x00\x00\x00\x00\x00\x00\x00' and self.connectionIsOrWasFullyEstablished: - self.recinv(self.data[24:self.payloadLength+24]) - elif remoteCommand == 'getdata\x00\x00\x00\x00\x00' and self.connectionIsOrWasFullyEstablished: - self.recgetdata(self.data[24:self.payloadLength+24]) - elif remoteCommand == 'msg\x00\x00\x00\x00\x00\x00\x00\x00\x00' and self.connectionIsOrWasFullyEstablished: - self.recmsg(self.data[24:self.payloadLength+24]) - elif remoteCommand == 'broadcast\x00\x00\x00' and self.connectionIsOrWasFullyEstablished: - self.recbroadcast(self.data[24:self.payloadLength+24]) - elif remoteCommand == 'ping\x00\x00\x00\x00\x00\x00\x00\x00' and self.connectionIsOrWasFullyEstablished: - self.sendpong() - elif remoteCommand == 'pong\x00\x00\x00\x00\x00\x00\x00\x00' and self.connectionIsOrWasFullyEstablished: - pass - elif remoteCommand == 'alert\x00\x00\x00\x00\x00\x00\x00' and self.connectionIsOrWasFullyEstablished: - pass + return + self.payloadLength, = unpack('>L',self.data[16:20]) + if len(self.data) < self.payloadLength+24: #check if the whole message has arrived yet. + return + if self.data[20:24] != hashlib.sha512(self.data[24:self.payloadLength+24]).digest()[0:4]:#test the checksum in the message. If it is correct... + print 'Checksum incorrect. Clearing this message.' + self.data = self.data[self.payloadLength+24:] + self.processData() + return + #The time we've last seen this node is obviously right now since we just received valid data from it. So update the knownNodes list so that other peers can be made aware of its existance. + if self.initiatedConnection and self.connectionIsOrWasFullyEstablished: #The remote port is only something we should share with others if it is the remote node's incoming port (rather than some random operating-system-assigned outgoing port). + shared.knownNodesLock.acquire() + shared.knownNodes[self.streamNumber][self.HOST] = (self.PORT,int(time.time())) + shared.knownNodesLock.release() + if self.payloadLength <= 180000000: #If the size of the message is greater than 180MB, ignore it. (I get memory errors when processing messages much larger than this though it is concievable that this value will have to be lowered if some systems are less tolarant of large messages.) + remoteCommand = self.data[4:16] + shared.printLock.acquire() + print 'remoteCommand', repr(remoteCommand.replace('\x00','')), ' from', self.HOST + shared.printLock.release() + if remoteCommand == 'version\x00\x00\x00\x00\x00': + self.recversion(self.data[24:self.payloadLength+24]) + elif remoteCommand == 'verack\x00\x00\x00\x00\x00\x00': + self.recverack() + elif remoteCommand == 'addr\x00\x00\x00\x00\x00\x00\x00\x00' and self.connectionIsOrWasFullyEstablished: + self.recaddr(self.data[24:self.payloadLength+24]) + elif remoteCommand == 'getpubkey\x00\x00\x00' and self.connectionIsOrWasFullyEstablished: + self.recgetpubkey(self.data[24:self.payloadLength+24]) + elif remoteCommand == 'pubkey\x00\x00\x00\x00\x00\x00' and self.connectionIsOrWasFullyEstablished: + self.recpubkey(self.data[24:self.payloadLength+24]) + elif remoteCommand == 'inv\x00\x00\x00\x00\x00\x00\x00\x00\x00' and self.connectionIsOrWasFullyEstablished: + self.recinv(self.data[24:self.payloadLength+24]) + elif remoteCommand == 'getdata\x00\x00\x00\x00\x00' and self.connectionIsOrWasFullyEstablished: + self.recgetdata(self.data[24:self.payloadLength+24]) + elif remoteCommand == 'msg\x00\x00\x00\x00\x00\x00\x00\x00\x00' and self.connectionIsOrWasFullyEstablished: + self.recmsg(self.data[24:self.payloadLength+24]) + elif remoteCommand == 'broadcast\x00\x00\x00' and self.connectionIsOrWasFullyEstablished: + self.recbroadcast(self.data[24:self.payloadLength+24]) + elif remoteCommand == 'ping\x00\x00\x00\x00\x00\x00\x00\x00' and self.connectionIsOrWasFullyEstablished: + self.sendpong() + elif remoteCommand == 'pong\x00\x00\x00\x00\x00\x00\x00\x00' and self.connectionIsOrWasFullyEstablished: + pass + elif remoteCommand == 'alert\x00\x00\x00\x00\x00\x00\x00' and self.connectionIsOrWasFullyEstablished: + pass - self.data = self.data[self.payloadLength+24:]#take this message out and then process the next message - if self.data == '': - while len(self.objectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave) > 0: - random.seed() - objectHash, = random.sample(self.objectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave, 1) - if objectHash in shared.inventory: - shared.printLock.acquire() - print 'Inventory (in memory) already has object listed in inv message.' - shared.printLock.release() - del self.objectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave[objectHash] - elif isInSqlInventory(objectHash): - if verbose >= 3: - shared.printLock.acquire() - print 'Inventory (SQL on disk) already has object listed in inv message.' - shared.printLock.release() - del self.objectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave[objectHash] - else: - self.sendgetdata(objectHash) - del self.objectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave[objectHash] #It is possible that the remote node doesn't respond with the object. In that case, we'll very likely get it from someone else anyway. - if len(self.objectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave) == 0: - shared.printLock.acquire() - print '(concerning', self.HOST + ')', 'number of objectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave is now', len(self.objectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave) - shared.printLock.release() - try: - del numberOfObjectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHavePerPeer[self.HOST] #this data structure is maintained so that we can keep track of how many total objects, across all connections, are currently outstanding. If it goes too high it can indicate that we are under attack by multiple nodes working together. - except: - pass - break - if len(self.objectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave) == 0: - shared.printLock.acquire() - print '(concerning', self.HOST + ')', 'number of objectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave is now', len(self.objectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave) - shared.printLock.release() - try: - del numberOfObjectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHavePerPeer[self.HOST] #this data structure is maintained so that we can keep track of how many total objects, across all connections, are currently outstanding. If it goes too high it can indicate that we are under attack by multiple nodes working together. - except: - pass - if len(self.objectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave) > 0: - shared.printLock.acquire() - print '(concerning', self.HOST + ')', 'number of objectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave is now', len(self.objectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave) - shared.printLock.release() - numberOfObjectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHavePerPeer[self.HOST] = len(self.objectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave) #this data structure is maintained so that we can keep track of how many total objects, across all connections, are currently outstanding. If it goes too high it can indicate that we are under attack by multiple nodes working together. - if len(self.ackDataThatWeHaveYetToSend) > 0: - self.data = self.ackDataThatWeHaveYetToSend.pop() - self.processData() + self.data = self.data[self.payloadLength+24:]#take this message out and then process the next message + if self.data == '': + while len(self.objectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave) > 0: + random.seed() + objectHash, = random.sample(self.objectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave, 1) + if objectHash in shared.inventory: + shared.printLock.acquire() + print 'Inventory (in memory) already has object listed in inv message.' + shared.printLock.release() + del self.objectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave[objectHash] + elif isInSqlInventory(objectHash): + if verbose >= 3: + shared.printLock.acquire() + print 'Inventory (SQL on disk) already has object listed in inv message.' + shared.printLock.release() + del self.objectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave[objectHash] else: - print 'Checksum incorrect. Clearing this message.' - self.data = self.data[self.payloadLength+24:] + self.sendgetdata(objectHash) + del self.objectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave[objectHash] #It is possible that the remote node doesn't respond with the object. In that case, we'll very likely get it from someone else anyway. + if len(self.objectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave) == 0: + shared.printLock.acquire() + print '(concerning', self.HOST + ')', 'number of objectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave is now', len(self.objectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave) + shared.printLock.release() + try: + del numberOfObjectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHavePerPeer[self.HOST] #this data structure is maintained so that we can keep track of how many total objects, across all connections, are currently outstanding. If it goes too high it can indicate that we are under attack by multiple nodes working together. + except: + pass + break + if len(self.objectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave) == 0: + shared.printLock.acquire() + print '(concerning', self.HOST + ')', 'number of objectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave is now', len(self.objectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave) + shared.printLock.release() + try: + del numberOfObjectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHavePerPeer[self.HOST] #this data structure is maintained so that we can keep track of how many total objects, across all connections, are currently outstanding. If it goes too high it can indicate that we are under attack by multiple nodes working together. + except: + pass + if len(self.objectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave) > 0: + shared.printLock.acquire() + print '(concerning', self.HOST + ')', 'number of objectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave is now', len(self.objectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave) + shared.printLock.release() + numberOfObjectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHavePerPeer[self.HOST] = len(self.objectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave) #this data structure is maintained so that we can keep track of how many total objects, across all connections, are currently outstanding. If it goes too high it can indicate that we are under attack by multiple nodes working together. + if len(self.ackDataThatWeHaveYetToSend) > 0: + self.data = self.ackDataThatWeHaveYetToSend.pop() + self.processData() + + def isProofOfWorkSufficient(self,data,nonceTrialsPerByte=0,payloadLengthExtraBytes=0): if nonceTrialsPerByte < shared.networkDefaultProofOfWorkNonceTrialsPerByte: @@ -941,8 +943,7 @@ class receiveDataThread(threading.Thread): shared.sqlReturnQueue.get() shared.sqlSubmitQueue.put('commit') shared.sqlLock.release() - #self.emit(SIGNAL("updateSentItemStatusByAckdata(PyQt_PyObject,PyQt_PyObject)"),encryptedData[readPosition:],'Acknowledgement of the message received just now.') - shared.UISignalQueue.put(('updateSentItemStatusByAckdata',(encryptedData[readPosition:],'Acknowledgement of the message received just now.'))) + shared.UISignalQueue.put(('updateSentItemStatusByAckdata',(encryptedData[readPosition:],'Acknowledgement of the message received just now. '+ unicode(strftime(shared.config.get('bitmessagesettings', 'timeformat'),localtime(int(time.time()))),'utf-8')))) return else: shared.printLock.acquire() @@ -1152,7 +1153,7 @@ class receiveDataThread(threading.Thread): #self.emit(SIGNAL("displayNewSentMessage(PyQt_PyObject,PyQt_PyObject,PyQt_PyObject,PyQt_PyObject,PyQt_PyObject,PyQt_PyObject)"),toAddress,'[Broadcast subscribers]',fromAddress,subject,message,ackdata) shared.UISignalQueue.put(('displayNewSentMessage',(toAddress,'[Broadcast subscribers]',fromAddress,subject,message,ackdata))) - shared.workerQueue.put(('sendbroadcast',(fromAddress,subject,message))) + shared.workerQueue.put(('sendbroadcast','')) if self.isAckDataValid(ackData): print 'ackData is valid. Will process it.' @@ -1505,11 +1506,17 @@ class receiveDataThread(threading.Thread): #We have received an inv message def recinv(self,data): totalNumberOfObjectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave = 0 - print 'number of keys(hosts) in numberOfObjectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHavePerPeer:', len(numberOfObjectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHavePerPeer) for key, value in numberOfObjectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHavePerPeer.items(): totalNumberOfObjectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave += value - print 'totalNumberOfObjectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave = ', totalNumberOfObjectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave + if len(numberOfObjectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHavePerPeer) > 0: + shared.printLock.acquire() + print 'number of keys(hosts) in numberOfObjectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHavePerPeer:', len(numberOfObjectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHavePerPeer) + print 'totalNumberOfObjectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave = ', totalNumberOfObjectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave + shared.printLock.release() numberOfItemsInInv, lengthOfVarint = decodeVarint(data[:10]) + if numberOfItemsInInv > 50000: + sys.stderr.write('Too many items in inv message!') + return if len(data) < lengthOfVarint + (numberOfItemsInInv * 32): print 'inv message doesn\'t contain enough data. Ignoring.' return @@ -2562,7 +2569,7 @@ class singleCleaner(threading.Thread): shared.sqlSubmitQueue.put('commit') t = () - shared.sqlSubmitQueue.put('''select toaddress, toripe, fromaddress, subject, message, ackdata, lastactiontime, status, pubkeyretrynumber, msgretrynumber FROM sent WHERE ((status='findingpubkey' OR status='sentmessage') AND folder='sent') ''') #If the message's folder='trash' then we'll ignore it. + shared.sqlSubmitQueue.put('''select toaddress, toripe, fromaddress, subject, message, ackdata, lastactiontime, status, pubkeyretrynumber, msgretrynumber FROM sent WHERE ((status='awaitingpubkey' OR status='msgsent') AND folder='sent') ''') #If the message's folder='trash' then we'll ignore it. shared.sqlSubmitQueue.put(t) queryreturn = shared.sqlReturnQueue.get() for row in queryreturn: @@ -2573,28 +2580,31 @@ class singleCleaner(threading.Thread): shared.printLock.release() break toaddress, toripe, fromaddress, subject, message, ackdata, lastactiontime, status, pubkeyretrynumber, msgretrynumber = row - if status == 'findingpubkey': + if status == 'awaitingpubkey': if int(time.time()) - lastactiontime > (maximumAgeOfAnObjectThatIAmWillingToAccept * (2 ** (pubkeyretrynumber))): print 'It has been a long time and we haven\'t heard a response to our getpubkey request. Sending again.' try: del neededPubkeys[toripe] #We need to take this entry out of the neededPubkeys structure because the shared.workerQueue checks to see whether the entry is already present and will not do the POW and send the message because it assumes that it has already done it recently. except: pass - shared.workerQueue.put(('sendmessage',toaddress)) + #self.emit(SIGNAL("updateStatusBar(PyQt_PyObject)"),"Doing work necessary to again attempt to request a public key...") shared.UISignalQueue.put(('updateStatusBar','Doing work necessary to again attempt to request a public key...')) t = (int(time.time()),pubkeyretrynumber+1,toripe) - shared.sqlSubmitQueue.put('''UPDATE sent SET lastactiontime=?, pubkeyretrynumber=? WHERE toripe=?''') + shared.sqlSubmitQueue.put('''UPDATE sent SET lastactiontime=?, pubkeyretrynumber=?, status='msgqueued' WHERE toripe=?''') shared.sqlSubmitQueue.put(t) shared.sqlReturnQueue.get() - else:# status == sentmessage + shared.sqlSubmitQueue.put('commit') + shared.workerQueue.put(('sendmessage','')) + else:# status == msgsent if int(time.time()) - lastactiontime > (maximumAgeOfAnObjectThatIAmWillingToAccept * (2 ** (msgretrynumber))): print 'It has been a long time and we haven\'t heard an acknowledgement to our msg. Sending again.' - t = (int(time.time()),msgretrynumber+1,'findingpubkey',ackdata) + t = (int(time.time()),msgretrynumber+1,'msgqueued',ackdata) shared.sqlSubmitQueue.put('''UPDATE sent SET lastactiontime=?, msgretrynumber=?, status=? WHERE ackdata=?''') shared.sqlSubmitQueue.put(t) shared.sqlReturnQueue.get() - shared.workerQueue.put(('sendmessage',toaddress)) + shared.sqlSubmitQueue.put('commit') + shared.workerQueue.put(('sendmessage','')) #self.emit(SIGNAL("updateStatusBar(PyQt_PyObject)"),"Doing work necessary to again attempt to deliver a message...") shared.UISignalQueue.put(('updateStatusBar','Doing work necessary to again attempt to deliver a message...')) shared.sqlSubmitQueue.put('commit') @@ -2608,85 +2618,34 @@ class singleWorker(threading.Thread): threading.Thread.__init__(self) def run(self): - time.sleep(10) shared.sqlLock.acquire() - shared.sqlSubmitQueue.put('''SELECT toripe FROM sent WHERE (status=? AND folder='sent')''') - shared.sqlSubmitQueue.put(('findingpubkey',)) + shared.sqlSubmitQueue.put('''SELECT toripe FROM sent WHERE (status='awaitingpubkey' AND folder='sent')''') + shared.sqlSubmitQueue.put('') queryreturn = shared.sqlReturnQueue.get() shared.sqlLock.release() for row in queryreturn: toripe, = row - #It is possible for the status of a message in our sent folder (which is also our 'outbox' folder) to have a status of 'findingpubkey' even if we have the pubkey. This can - #happen if the worker thread is working on the POW for an earlier message and does not get to the message in question before the user closes Bitmessage. In this case, the - #status will still be 'findingpubkey' but Bitmessage will never have checked to see whether it actually already has the pubkey. We should therefore check here. - shared.sqlLock.acquire() - shared.sqlSubmitQueue.put('''SELECT hash FROM pubkeys WHERE hash=? ''') - shared.sqlSubmitQueue.put((toripe,)) - queryreturn = shared.sqlReturnQueue.get() - shared.sqlLock.release() - if queryreturn != []: #If we have the pubkey then send the message otherwise put the hash in the neededPubkeys data structure so that we will pay attention to it if it comes over the wire. - self.sendMsg(toripe) - else: - neededPubkeys[toripe] = 0 + neededPubkeys[toripe] = 0 - self.sendBroadcast() #just in case there are any proof of work tasks for Broadcasts that have yet to be sent. - - #Now let us see if there are any proofs of work for msg messages that we have yet to complete.. shared.sqlLock.acquire() - t = ('doingpow',) - shared.sqlSubmitQueue.put('''SELECT toripe FROM sent WHERE status=? and folder='sent' ''') - shared.sqlSubmitQueue.put(t) + shared.sqlSubmitQueue.put('''SELECT DISTINCT toaddress FROM sent WHERE (status='doingpubkeypow' AND folder='sent')''') + shared.sqlSubmitQueue.put('') queryreturn = shared.sqlReturnQueue.get() shared.sqlLock.release() for row in queryreturn: - toripe, = row - #Evidentially there is a remote possibility that we may, for some reason, no longer have the recipient's pubkey. Let us make sure we still have it or else the sendMsg function will appear to freeze. - shared.sqlLock.acquire() - shared.sqlSubmitQueue.put('''SELECT hash FROM pubkeys WHERE hash=? ''') - shared.sqlSubmitQueue.put((toripe,)) - queryreturn = shared.sqlReturnQueue.get() - shared.sqlLock.release() - if queryreturn != []: - #We have the needed pubkey - self.sendMsg(toripe) - else: - shared.printLock.acquire() - sys.stderr.write('For some reason, the status of a message in our outbox is \'doingpow\' even though we lack the pubkey. Here is the RIPE hash of the needed pubkey: %s\n' % toripe.encode('hex')) - shared.printLock.release() + toaddress, = row + self.requestPubKey(toaddress) + + time.sleep(10) #give some time for the GUI to start before we start on any existing POW tasks. + + self.sendMsg() #just in case there are any pending tasks for msg messages that have yet to be sent. + self.sendBroadcast() #just in case there are any tasks for Broadcasts that have yet to be sent. while True: command, data = shared.workerQueue.get() - #statusbar = 'The singleWorker thread is working on work.' - #self.emit(SIGNAL("updateStatusBar(PyQt_PyObject)"),statusbar) if command == 'sendmessage': - toAddress = data - toStatus,toAddressVersionNumber,toStreamNumber,toRipe = decodeAddress(toAddress) - #print 'message type', type(message) - #print repr(message.toUtf8()) - #print str(message.toUtf8()) - shared.sqlLock.acquire() - shared.sqlSubmitQueue.put('SELECT hash FROM pubkeys WHERE hash=?') - shared.sqlSubmitQueue.put((toRipe,)) - queryreturn = shared.sqlReturnQueue.get() - shared.sqlLock.release() - #print 'queryreturn', queryreturn - if queryreturn == []: - #We'll need to request the pub key because we don't have it. - if not toRipe in neededPubkeys: - neededPubkeys[toRipe] = 0 - print 'requesting pubkey:', toRipe.encode('hex') - self.requestPubKey(toAddressVersionNumber,toStreamNumber,toRipe) - else: - print 'We have already requested this pubkey (the ripe hash is in neededPubkeys). We will re-request again soon.' - #self.emit(SIGNAL("updateSentItemStatusByHash(PyQt_PyObject,PyQt_PyObject)"),toRipe,'Public key was requested earlier. Receiver must be offline. Will retry.') - shared.UISignalQueue.put(('updateSentItemStatusByHash',(toRipe,'Public key was requested earlier. Receiver must be offline. Will retry.'))) - - else: - print 'We already have the necessary public key.' - self.sendMsg(toRipe) #by calling this function, we are asserting that we already have the pubkey for toRipe + self.sendMsg() elif command == 'sendbroadcast': - print 'Within WorkerThread, processing sendbroadcast command.' - fromAddress,subject,message = data self.sendBroadcast() elif command == 'doPOWForMyV2Pubkey': self.doPOWForMyV2Pubkey(data) @@ -2697,7 +2656,14 @@ class singleWorker(threading.Thread): if toRipe in neededPubkeys: print 'We have been awaiting the arrival of this pubkey.' del neededPubkeys[toRipe] - self.sendMsg(toRipe) + t = (toRipe,) + shared.sqlLock.acquire() + shared.sqlSubmitQueue.put('''UPDATE sent SET status='doingmsgpow' WHERE toripe=? AND status='awaitingpubkey' and folder='sent' ''') + shared.sqlSubmitQueue.put(t) + shared.sqlReturnQueue.get() + shared.sqlSubmitQueue.put('commit') + shared.sqlLock.release() + self.sendMsg() else: shared.printLock.acquire() print 'We don\'t need this pub key. We didn\'t ask for it. Pubkey hash:', toRipe.encode('hex') @@ -2706,7 +2672,6 @@ class singleWorker(threading.Thread): shared.printLock.acquire() sys.stderr.write('Probable programming error: The command sent to the workerThread is weird. It is: %s\n' % command) shared.printLock.release() - shared.workerQueue.task_done() def doPOWForMyV2Pubkey(self,hash): #This function also broadcasts out the pubkey message once it is done with the POW @@ -2902,7 +2867,7 @@ class singleWorker(threading.Thread): inventoryHash = calculateInventoryHash(payload) objectType = 'broadcast' shared.inventory[inventoryHash] = (objectType, streamNumber, payload, int(time.time())) - print 'sending inv (within sendBroadcast function)' + print 'Broadcasting inv for my broadcast (within sendBroadcast function):', inventoryHash.encode('hex') shared.broadcastToSendDataQueues((streamNumber, 'sendinv', inventoryHash)) #self.emit(SIGNAL("updateSentItemStatusByAckdata(PyQt_PyObject,PyQt_PyObject)"),ackdata,'Broadcast sent on '+unicode(strftime(shared.config.get('bitmessagesettings', 'timeformat'),localtime(int(time.time()))),'utf-8')) @@ -2992,25 +2957,83 @@ class singleWorker(threading.Thread): sys.stderr.write('Error: In the singleWorker thread, the sendBroadcast function doesn\'t understand the address version.\n') shared.printLock.release() - def sendMsg(self,toRipe): + def sendMsg(self): + #Check to see if there are any messages queued to be sent shared.sqlLock.acquire() - t = ('doingpow','findingpubkey',toRipe) - shared.sqlSubmitQueue.put('''UPDATE sent SET status=? WHERE status=? AND toripe=? and folder='sent' ''') - shared.sqlSubmitQueue.put(t) + shared.sqlSubmitQueue.put('''SELECT toaddress FROM sent WHERE (status='msgqueued' AND folder='sent')''') + shared.sqlSubmitQueue.put('') queryreturn = shared.sqlReturnQueue.get() - shared.sqlSubmitQueue.put('commit') - - t = ('doingpow',toRipe) - shared.sqlSubmitQueue.put('''SELECT toaddress, fromaddress, subject, message, ackdata FROM sent WHERE status=? AND toripe=? and folder='sent' ''') - shared.sqlSubmitQueue.put(t) + shared.sqlLock.release() + for row in queryreturn: #For each address to which we need to send a message, check to see if we have its pubkey already. + toaddress, = row + toripe = decodeAddress(toaddress)[3] + shared.sqlLock.acquire() + shared.sqlSubmitQueue.put('''SELECT hash FROM pubkeys WHERE hash=? ''') + shared.sqlSubmitQueue.put((toripe,)) + queryreturn = shared.sqlReturnQueue.get() + shared.sqlLock.release() + if queryreturn != []: #If we have the needed pubkey, set the status to doingmsgpow (we'll do it further down) + t = (toaddress,) + shared.sqlLock.acquire() + shared.sqlSubmitQueue.put('''UPDATE sent SET status='doingmsgpow' WHERE toaddress=? AND status='msgqueued' ''') + shared.sqlSubmitQueue.put(t) + shared.sqlReturnQueue.get() + shared.sqlSubmitQueue.put('commit') + shared.sqlLock.release() + else: #We don't have the needed pubkey. Set the status to 'awaitingpubkey' and request it if we haven't already + if toripe in neededPubkeys: + #We already sent a request for the pubkey + t = (toaddress,) + shared.sqlLock.acquire() + shared.sqlSubmitQueue.put('''UPDATE sent SET status='awaitingpubkey' WHERE toaddress=? AND status='msgqueued' ''') + shared.sqlSubmitQueue.put(t) + shared.sqlReturnQueue.get() + shared.sqlSubmitQueue.put('commit') + shared.sqlLock.release() + shared.UISignalQueue.put(('updateSentItemStatusByHash',(toripe,'Encryption key was requested earlier.'))) + else: + #We have not yet sent a request for the pubkey + t = (toaddress,) + shared.sqlLock.acquire() + shared.sqlSubmitQueue.put('''UPDATE sent SET status='doingpubkeypow' WHERE toaddress=? AND status='msgqueued' ''') + shared.sqlSubmitQueue.put(t) + shared.sqlReturnQueue.get() + shared.sqlSubmitQueue.put('commit') + shared.sqlLock.release() + shared.UISignalQueue.put(('updateSentItemStatusByHash',(toripe,'Sending a request for the recipient\'s encryption key.'))) + self.requestPubKey(toaddress) + shared.sqlLock.acquire() + shared.sqlSubmitQueue.put('''SELECT toaddress, toripe, fromaddress, subject, message, ackdata FROM sent WHERE status='doingmsgpow' and folder='sent' ''') + shared.sqlSubmitQueue.put('') queryreturn = shared.sqlReturnQueue.get() shared.sqlLock.release() for row in queryreturn: - toaddress, fromaddress, subject, message, ackdata = row + toaddress, toripe, fromaddress, subject, message, ackdata = row + + #Evidently there is a remote possibility that we may no longer have the recipient's pubkey. Let us make sure we still have it or else the sendMsg function will appear to freeze. + shared.sqlLock.acquire() + shared.sqlSubmitQueue.put('''SELECT hash FROM pubkeys WHERE hash=? ''') + shared.sqlSubmitQueue.put((toripe,)) + queryreturn = shared.sqlReturnQueue.get() + shared.sqlLock.release() + if queryreturn == []: + #We no longer have the needed pubkey + shared.printLock.acquire() + sys.stderr.write('For some reason, the status of a message in our outbox is \'doingmsgpow\' even though we lack the pubkey. Here is the RIPE hash of the needed pubkey: %s\n' % toripe.encode('hex')) + shared.printLock.release() + t = (toaddress,) + shared.sqlLock.acquire() + shared.sqlSubmitQueue.put('''UPDATE sent SET status='msgqueued' WHERE toaddress=? AND status='doingmsgpow' ''') + shared.sqlSubmitQueue.put(t) + shared.sqlReturnQueue.get() + shared.sqlSubmitQueue.put('commit') + shared.sqlLock.release() + shared.UISignalQueue.put(('updateSentItemStatusByHash',(toripe,'Sending a request for the recipient\'s encryption key.'))) + self.requestPubKey(toaddress) + return ackdataForWhichImWatching[ackdata] = 0 toStatus,toAddressVersionNumber,toStreamNumber,toHash = decodeAddress(toaddress) fromStatus,fromAddressVersionNumber,fromStreamNumber,fromHash = decodeAddress(fromaddress) - #self.emit(SIGNAL("updateSentItemStatusByAckdata(PyQt_PyObject,PyQt_PyObject)"),ackdata,'Doing work necessary to send the message.') shared.UISignalQueue.put(('updateSentItemStatusByAckdata',(ackdata,'Doing work necessary to send the message.'))) shared.printLock.acquire() print 'Found a message in our database that needs to be sent with this pubkey.' @@ -3102,7 +3125,7 @@ class singleWorker(threading.Thread): if toAddressVersionNumber == 2 or toAddressVersionNumber == 3: shared.sqlLock.acquire() shared.sqlSubmitQueue.put('SELECT transmitdata FROM pubkeys WHERE hash=?') - shared.sqlSubmitQueue.put((toRipe,)) + shared.sqlSubmitQueue.put((toripe,)) queryreturn = shared.sqlReturnQueue.get() shared.sqlLock.release() if queryreturn == []: @@ -3164,17 +3187,17 @@ class singleWorker(threading.Thread): shared.inventory[inventoryHash] = (objectType, toStreamNumber, payload, int(time.time())) #self.emit(SIGNAL("updateSentItemStatusByAckdata(PyQt_PyObject,PyQt_PyObject)"),ackdata,'Message sent. Waiting on acknowledgement. Sent on ' + unicode(strftime(shared.config.get('bitmessagesettings', 'timeformat'),localtime(int(time.time()))),'utf-8')) shared.UISignalQueue.put(('updateSentItemStatusByAckdata',(ackdata,'Message sent. Waiting on acknowledgement. Sent on ' + unicode(strftime(shared.config.get('bitmessagesettings', 'timeformat'),localtime(int(time.time()))),'utf-8')))) - print 'sending inv (within sendmsg function)' + print 'Broadcasting inv for my msg(within sendmsg function):', inventoryHash.encode('hex') shared.broadcastToSendDataQueues((streamNumber, 'sendinv', inventoryHash)) #Update the status of the message in the 'sent' table to have a 'sent' status shared.sqlLock.acquire() - t = ('sentmessage',toaddress, fromaddress, subject, message,'doingpow') + t = ('msgsent',toaddress, fromaddress, subject, message,'doingmsgpow') shared.sqlSubmitQueue.put('UPDATE sent SET status=? WHERE toaddress=? AND fromaddress=? AND subject=? AND message=? AND status=?') shared.sqlSubmitQueue.put(t) queryreturn = shared.sqlReturnQueue.get() - t = (toRipe,) + t = (toripe,) shared.sqlSubmitQueue.put('''UPDATE pubkeys SET usedpersonally='yes' WHERE hash=?''') shared.sqlSubmitQueue.put(t) queryreturn = shared.sqlReturnQueue.get() @@ -3182,7 +3205,9 @@ class singleWorker(threading.Thread): shared.sqlLock.release() - def requestPubKey(self,addressVersionNumber,streamNumber,ripe): + def requestPubKey(self,toAddress): + toStatus,addressVersionNumber,streamNumber,ripe = decodeAddress(toAddress) + neededPubkeys[ripe] = 0 payload = pack('>I',(int(time.time())+random.randrange(-300, 300)))#the current time plus or minus five minutes. payload += encodeVarint(addressVersionNumber) payload += encodeVarint(streamNumber) @@ -3194,10 +3219,8 @@ class singleWorker(threading.Thread): trialValue = 99999999999999999999 #print 'trial value', trialValue statusbar = 'Doing the computations necessary to request the recipient\'s public key.' - #self.emit(SIGNAL("updateStatusBar(PyQt_PyObject)"),statusbar) shared.UISignalQueue.put(('updateStatusBar',statusbar)) - #self.emit(SIGNAL("updateSentItemStatusByHash(PyQt_PyObject,PyQt_PyObject)"),ripe,'Doing work necessary to request public key.') - shared.UISignalQueue.put(('updateSentItemStatusByHash',(ripe,'Doing work necessary to request public key.'))) + shared.UISignalQueue.put(('updateSentItemStatusByHash',(ripe,'Doing work necessary to request encryption key.'))) print 'Doing proof-of-work necessary to send getpubkey message.' target = 2**64 / ((len(payload)+shared.networkDefaultPayloadLengthExtraBytes+8) * shared.networkDefaultProofOfWorkNonceTrialsPerByte) initialHash = hashlib.sha512(payload).digest() @@ -3215,9 +3238,15 @@ class singleWorker(threading.Thread): print 'sending inv (for the getpubkey message)' shared.broadcastToSendDataQueues((streamNumber, 'sendinv', inventoryHash)) - #self.emit(SIGNAL("updateStatusBar(PyQt_PyObject)"),'Broacasting the public key request. This program will auto-retry if they are offline.') + t = (toAddress,) + shared.sqlLock.acquire() + shared.sqlSubmitQueue.put('''UPDATE sent SET status='awaitingpubkey' WHERE toaddress=? AND status='doingpubkeypow' ''') + shared.sqlSubmitQueue.put(t) + shared.sqlReturnQueue.get() + shared.sqlSubmitQueue.put('commit') + shared.sqlLock.release() + shared.UISignalQueue.put(('updateStatusBar','Broacasting the public key request. This program will auto-retry if they are offline.')) - #self.emit(SIGNAL("updateSentItemStatusByHash(PyQt_PyObject,PyQt_PyObject)"),ripe,'Sending public key request. Waiting for reply. Requested at ' + unicode(strftime(shared.config.get('bitmessagesettings', 'timeformat'),localtime(int(time.time()))),'utf-8')) shared.UISignalQueue.put(('updateSentItemStatusByHash',(ripe,'Sending public key request. Waiting for reply. Requested at ' + unicode(strftime(shared.config.get('bitmessagesettings', 'timeformat'),localtime(int(time.time()))),'utf-8')))) def generateFullAckMessage(self,ackdata,toStreamNumber,embeddedTime): @@ -3725,7 +3754,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): ackdata = OpenSSL.rand(32) shared.sqlLock.acquire() - t = ('',toAddress,toRipe,fromAddress,subject,message,ackdata,int(time.time()),'findingpubkey',1,1,'sent',2) + t = ('',toAddress,toRipe,fromAddress,subject,message,ackdata,int(time.time()),'msgqueued',1,1,'sent',2) shared.sqlSubmitQueue.put('''INSERT INTO sent VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)''') shared.sqlSubmitQueue.put(t) shared.sqlReturnQueue.get() @@ -3799,7 +3828,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): #apiSignalQueue.put(('displayNewSentMessage',(toAddress,toLabel,fromAddress,subject,message,ackdata))) #self.emit(SIGNAL("displayNewSentMessage(PyQt_PyObject,PyQt_PyObject,PyQt_PyObject,PyQt_PyObject,PyQt_PyObject,PyQt_PyObject)"),toAddress,toLabel,fromAddress,subject,message,ackdata) shared.UISignalQueue.put(('displayNewSentMessage',(toAddress,toLabel,fromAddress,subject,message,ackdata))) - shared.workerQueue.put(('sendbroadcast',(fromAddress,subject,message))) + shared.workerQueue.put(('sendbroadcast','')) return ackdata.encode('hex') elif method == 'getStatus': @@ -3817,16 +3846,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): return 'notFound' for row in queryreturn: status, = row - if status == 'findingpubkey': - return 'findingPubkey' - if status == 'doingpow': - return 'doingPow' - if status == 'sentmessage': - return 'sentMessage' - if status == 'ackreceived': - return 'ackReceived' - else: - return 'otherStatus: '+status + return status elif method == 'addSubscription': if len(params) == 0: return 'API Error 0000: I need parameters!' @@ -4056,7 +4076,7 @@ if __name__ == "__main__": shared.reloadBroadcastSendersForWhichImWatching() #Initialize the ackdataForWhichImWatching data structure using data from the sql database. - shared.sqlSubmitQueue.put('''SELECT ackdata FROM sent where (status='sentmessage' OR status='doingpow')''') + shared.sqlSubmitQueue.put('''SELECT ackdata FROM sent where (status='msgsent' OR status='doingmsgpow')''') shared.sqlSubmitQueue.put('') queryreturn = shared.sqlReturnQueue.get() for row in queryreturn: diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index add21421..586c81d6 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -358,16 +358,20 @@ class MyForm(QtGui.QMainWindow): newItem.setData(Qt.UserRole,unicode(message,'utf-8)')) newItem.setFlags( QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled ) self.ui.tableWidgetSent.setItem(0,2,newItem) - if status == 'findingpubkey': - newItem = myTableWidgetItem('Waiting on their public key. Will request it again soon.') - elif status == 'sentmessage': + if status == 'awaitingpubkey': + newItem = myTableWidgetItem('Waiting on their encryption key. Will request it again soon.') + elif status == 'doingpowforpubkey': + newItem = myTableWidgetItem('Encryption key request queued.') + elif status == 'msgqueued': + newItem = myTableWidgetItem('Queued.') + elif status == 'msgsent': newItem = myTableWidgetItem('Message sent. Waiting on acknowledgement. Sent at ' + unicode(strftime(shared.config.get('bitmessagesettings', 'timeformat'),localtime(lastactiontime)),'utf-8')) - elif status == 'doingpow': + elif status == 'doingmsgpow': newItem = myTableWidgetItem('Need to do work to send message. Work is queued.') elif status == 'ackreceived': newItem = myTableWidgetItem('Acknowledgement of the message received ' + unicode(strftime(shared.config.get('bitmessagesettings', 'timeformat'),localtime(int(lastactiontime))),'utf-8')) - elif status == 'broadcastpending': - newItem = myTableWidgetItem('Doing the work necessary to send broadcast...') + elif status == 'broadcastqueued': + newItem = myTableWidgetItem('Broadcast queued.') elif status == 'broadcastsent': newItem = myTableWidgetItem('Broadcast on ' + unicode(strftime(shared.config.get('bitmessagesettings', 'timeformat'),localtime(int(lastactiontime))),'utf-8')) else: @@ -770,6 +774,7 @@ class MyForm(QtGui.QMainWindow): def click_actionDeleteAllTrashedMessages(self): if QtGui.QMessageBox.question(self, 'Delete trash?',"Are you sure you want to delete all trashed messages?", QtGui.QMessageBox.Yes, QtGui.QMessageBox.No) == QtGui.QMessageBox.No: return + self.statusBar().showMessage('Deleting messages and freeing empty space...') shared.sqlLock.acquire() shared.sqlSubmitQueue.put('''delete from inbox where folder='trash' ''') shared.sqlSubmitQueue.put('') @@ -781,6 +786,7 @@ class MyForm(QtGui.QMainWindow): shared.sqlSubmitQueue.put('vacuum') shared.sqlSubmitQueue.put('') shared.sqlReturnQueue.get() + self.statusBar().showMessage('') shared.sqlLock.release() def click_actionRegenerateDeterministicAddresses(self): @@ -1104,7 +1110,7 @@ class MyForm(QtGui.QMainWindow): self.statusBar().showMessage('Warning: You are currently not connected. Bitmessage will do the work necessary to send the message but it won\'t send until you connect.') ackdata = OpenSSL.rand(32) shared.sqlLock.acquire() - t = ('',toAddress,ripe,fromAddress,subject,message,ackdata,int(time.time()),'findingpubkey',1,1,'sent',2) + t = ('',toAddress,ripe,fromAddress,subject,message,ackdata,int(time.time()),'msgqueued',1,1,'sent',2) shared.sqlSubmitQueue.put('''INSERT INTO sent VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)''') shared.sqlSubmitQueue.put(t) shared.sqlReturnQueue.get() @@ -1151,7 +1157,7 @@ class MyForm(QtGui.QMainWindow): shared.sqlSubmitQueue.put('commit') shared.sqlLock.release() - shared.workerQueue.put(('sendbroadcast',(fromAddress,subject,message))) + shared.workerQueue.put(('sendbroadcast','')) try: fromLabel = shared.config.get(fromAddress, 'label') From ad2457361f8c1bc09a04591c39f893615b130f88 Mon Sep 17 00:00:00 2001 From: Jonathan Warren Date: Thu, 30 May 2013 16:25:42 -0400 Subject: [PATCH 02/16] Multi-core POW --- src/bitmessagemain.py | 16 +++++++---- src/bitmessageqt/__init__.py | 23 +++++++++++++++ src/proofofwork.py | 44 +++++++++++++++++++---------- src/settings.py | 34 +++++++++++++++++++++-- src/settings.ui | 54 ++++++++++++++++++++++++++++++++++++ src/shared.py | 7 ++++- 6 files changed, 155 insertions(+), 23 deletions(-) diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index ba31f7a9..0eb78101 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -1506,10 +1506,10 @@ class receiveDataThread(threading.Thread): #We have received an inv message def recinv(self,data): - totalNumberOfObjectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave = 0 - for key, value in numberOfObjectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHavePerPeer.items(): - totalNumberOfObjectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave += value + totalNumberOfObjectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave = 0 # ..from all peers, counting duplicates seperately (because they take up memory) if len(numberOfObjectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHavePerPeer) > 0: + for key, value in numberOfObjectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHavePerPeer.items(): + totalNumberOfObjectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave += value shared.printLock.acquire() print 'number of keys(hosts) in numberOfObjectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHavePerPeer:', len(numberOfObjectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHavePerPeer) print 'totalNumberOfObjectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave = ', totalNumberOfObjectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave @@ -2434,6 +2434,13 @@ class sqlThread(threading.Thread): print 'Vacuuming message.dat. You might notice that the file size gets much smaller.' self.cur.execute( ''' VACUUM ''') + #After code refactoring, the possible status values for sent messages as changed. + self.cur.execute( '''update sent set status='doingmsgpow' where status='doingpow' ''') + self.cur.execute( '''update sent set status='msgsent' where status='sentmessage' ''') + self.cur.execute( '''update sent set status='doingpubkeypow' where status='findingpubkey' ''') + self.cur.execute( '''update sent set status='broadcastqueued' where status='broadcastpending' ''') + self.conn.commit() + try: testpayload = '\x00\x00' t = ('1234',testpayload,'12345678','no') @@ -2545,7 +2552,6 @@ class singleCleaner(threading.Thread): shared.sqlReturnQueue.get() del shared.inventory[hash] shared.sqlSubmitQueue.put('commit') - #self.emit(SIGNAL("updateStatusBar(PyQt_PyObject)"),"") shared.UISignalQueue.put(('updateStatusBar','')) shared.sqlLock.release() shared.broadcastToSendDataQueues((0, 'pong', 'no data')) #commands the sendData threads to send out a pong message if they haven't sent anything else in the last five minutes. The socket timeout-time is 10 minutes. @@ -2556,7 +2562,7 @@ class singleCleaner(threading.Thread): timeWeLastClearedInventoryAndPubkeysTables = int(time.time()) #inventory (moves data from the inventory data structure to the on-disk sql database) shared.sqlLock.acquire() - #inventory (clears data more than 2 days and 12 hours old) + #inventory (clears pubkeys after 28 days and everything else after 2 days and 12 hours) t = (int(time.time())-lengthOfTimeToLeaveObjectsInInventory,int(time.time())-lengthOfTimeToHoldOnToAllPubkeys) shared.sqlSubmitQueue.put('''DELETE FROM inventory WHERE (receivedtime'pubkey') OR (receivedtime= 1: shared.config.set('bitmessagesettings', 'defaultpayloadlengthextrabytes',str(int(float(self.settingsDialogInstance.ui.lineEditSmallMessageDifficulty.text())*shared.networkDefaultPayloadLengthExtraBytes))) + if str(self.settingsDialogInstance.ui.comboBoxMaxCores.currentText()) == 'All': + shared.config.set('bitmessagesettings', 'maxcores', '99999') + else: + shared.config.set('bitmessagesettings', 'maxcores', str(self.settingsDialogInstance.ui.comboBoxMaxCores.currentText())) with open(shared.appdata + 'keys.dat', 'wb') as configfile: shared.config.write(configfile) @@ -2167,6 +2171,25 @@ class settingsDialog(QtGui.QDialog): self.ui.lineEditTotalDifficulty.setText(str((float(shared.config.getint('bitmessagesettings', 'defaultnoncetrialsperbyte'))/shared.networkDefaultProofOfWorkNonceTrialsPerByte))) self.ui.lineEditSmallMessageDifficulty.setText(str((float(shared.config.getint('bitmessagesettings', 'defaultpayloadlengthextrabytes'))/shared.networkDefaultPayloadLengthExtraBytes))) + + #On the System tab + try: + maxCores = shared.config.getint('bitmessagesettings', 'maxcores') + except: + maxCores = 99999 + if maxCores <= 1: + self.ui.comboBoxMaxCores.setCurrentIndex(0) + elif maxCores == 2: + self.ui.comboBoxMaxCores.setCurrentIndex(1) + elif maxCores <= 4: + self.ui.comboBoxMaxCores.setCurrentIndex(2) + elif maxCores <= 8: + self.ui.comboBoxMaxCores.setCurrentIndex(3) + elif maxCores <= 16: + self.ui.comboBoxMaxCores.setCurrentIndex(4) + else: + self.ui.comboBoxMaxCores.setCurrentIndex(5) + QtGui.QWidget.resize(self,QtGui.QWidget.sizeHint(self)) def comboBoxProxyTypeChanged(self,comboBoxIndex): diff --git a/src/proofofwork.py b/src/proofofwork.py index 03d7c22d..144c7d79 100644 --- a/src/proofofwork.py +++ b/src/proofofwork.py @@ -1,28 +1,42 @@ +import shared +import time +from multiprocessing import Pool, cpu_count +import hashlib +from struct import unpack, pack + def _pool_worker(nonce, initialHash, target, pool_size): - import hashlib - from struct import unpack, pack trialValue = 99999999999999999999 while trialValue > target: - nonce += pool_size - trialValue, = unpack('>Q',hashlib.sha512(hashlib.sha512(pack('>Q',nonce) + initialHash).digest()).digest()[0:8]) + nonce += pool_size + trialValue, = unpack('>Q',hashlib.sha512(hashlib.sha512(pack('>Q',nonce) + initialHash).digest()).digest()[0:8]) return [trialValue, nonce] def run(target, initialHash): - from multiprocessing import Pool, cpu_count - import time try: - pool_size = cpu_count() + pool_size = cpu_count() except: - pool_size = 4 + pool_size = 4 + + try: + maxCores = config.getint('bitmessagesettings', 'maxcores') + except: + maxCores = 99999 + if pool_size > maxCores: + pool_size = maxCores + pool = Pool(processes=pool_size) result = [] for i in range(pool_size): - result.append(pool.apply_async(_pool_worker, args = (i, initialHash, target, pool_size))) + result.append(pool.apply_async(_pool_worker, args = (i, initialHash, target, pool_size))) while True: - for i in range(pool_size): - if result[i].ready(): - result = result[i].get() - pool.terminate() - return result[0], result[1] - time.sleep(1) + for i in range(pool_size): + if shared.shutdown: + pool.terminate() + time.sleep(5) #Don't return anything (doing so will cause exceptions because we'll return an unusable response). Sit here and wait for this thread to close. + return + if result[i].ready(): + result = result[i].get() + pool.terminate() + return result[0], result[1] + time.sleep(0.2) diff --git a/src/settings.py b/src/settings.py index 0cd7b07e..dac0f788 100644 --- a/src/settings.py +++ b/src/settings.py @@ -2,8 +2,8 @@ # Form implementation generated from reading ui file 'settings.ui' # -# Created: Sat May 25 13:20:18 2013 -# by: PyQt4 UI code generator 4.9.5 +# Created: Thu May 30 15:50:32 2013 +# by: PyQt4 UI code generator 4.9.4 # # WARNING! All changes made in this file will be lost! @@ -172,6 +172,28 @@ class Ui_settingsDialog(object): self.label_10.setObjectName(_fromUtf8("label_10")) self.gridLayout_6.addWidget(self.label_10, 2, 0, 1, 3) self.tabWidgetSettings.addTab(self.tab, _fromUtf8("")) + self.tab_2 = QtGui.QWidget() + self.tab_2.setObjectName(_fromUtf8("tab_2")) + self.formLayout = QtGui.QFormLayout(self.tab_2) + self.formLayout.setObjectName(_fromUtf8("formLayout")) + self.label_13 = QtGui.QLabel(self.tab_2) + self.label_13.setObjectName(_fromUtf8("label_13")) + self.formLayout.setWidget(0, QtGui.QFormLayout.LabelRole, self.label_13) + self.comboBoxMaxCores = QtGui.QComboBox(self.tab_2) + sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.comboBoxMaxCores.sizePolicy().hasHeightForWidth()) + self.comboBoxMaxCores.setSizePolicy(sizePolicy) + self.comboBoxMaxCores.setObjectName(_fromUtf8("comboBoxMaxCores")) + self.comboBoxMaxCores.addItem(_fromUtf8("")) + self.comboBoxMaxCores.addItem(_fromUtf8("")) + self.comboBoxMaxCores.addItem(_fromUtf8("")) + self.comboBoxMaxCores.addItem(_fromUtf8("")) + self.comboBoxMaxCores.addItem(_fromUtf8("")) + self.comboBoxMaxCores.addItem(_fromUtf8("")) + self.formLayout.setWidget(0, QtGui.QFormLayout.FieldRole, self.comboBoxMaxCores) + self.tabWidgetSettings.addTab(self.tab_2, _fromUtf8("")) self.gridLayout.addWidget(self.tabWidgetSettings, 0, 0, 1, 1) self.retranslateUi(settingsDialog) @@ -222,4 +244,12 @@ class Ui_settingsDialog(object): self.label_12.setText(QtGui.QApplication.translate("settingsDialog", "The \'Small message difficulty\' mostly only affects the difficulty of sending small messages. Doubling this value makes it almost twice as difficult to send a small message but doesn\'t really affect large messages.", None, QtGui.QApplication.UnicodeUTF8)) self.label_10.setText(QtGui.QApplication.translate("settingsDialog", "The \'Total difficulty\' affects the absolute amount of work the sender must complete. Doubling this value doubles the amount of work.", None, QtGui.QApplication.UnicodeUTF8)) self.tabWidgetSettings.setTabText(self.tabWidgetSettings.indexOf(self.tab), QtGui.QApplication.translate("settingsDialog", "Demanded difficulty", None, QtGui.QApplication.UnicodeUTF8)) + self.label_13.setText(QtGui.QApplication.translate("settingsDialog", "Maximum number of CPU cores to use when doing work:", None, QtGui.QApplication.UnicodeUTF8)) + self.comboBoxMaxCores.setItemText(0, QtGui.QApplication.translate("settingsDialog", "1", None, QtGui.QApplication.UnicodeUTF8)) + self.comboBoxMaxCores.setItemText(1, QtGui.QApplication.translate("settingsDialog", "2", None, QtGui.QApplication.UnicodeUTF8)) + self.comboBoxMaxCores.setItemText(2, QtGui.QApplication.translate("settingsDialog", "4", None, QtGui.QApplication.UnicodeUTF8)) + self.comboBoxMaxCores.setItemText(3, QtGui.QApplication.translate("settingsDialog", "8", None, QtGui.QApplication.UnicodeUTF8)) + self.comboBoxMaxCores.setItemText(4, QtGui.QApplication.translate("settingsDialog", "16", None, QtGui.QApplication.UnicodeUTF8)) + self.comboBoxMaxCores.setItemText(5, QtGui.QApplication.translate("settingsDialog", "All", None, QtGui.QApplication.UnicodeUTF8)) + self.tabWidgetSettings.setTabText(self.tabWidgetSettings.indexOf(self.tab_2), QtGui.QApplication.translate("settingsDialog", "System", None, QtGui.QApplication.UnicodeUTF8)) diff --git a/src/settings.ui b/src/settings.ui index 971480bd..61419bb6 100644 --- a/src/settings.ui +++ b/src/settings.ui @@ -373,6 +373,60 @@ + + + System + + + + + + Maximum number of CPU cores to use when doing work: + + + + + + + + 0 + 0 + + + + + 1 + + + + + 2 + + + + + 4 + + + + + 8 + + + + + 16 + + + + + All + + + + + + diff --git a/src/shared.py b/src/shared.py index 850c84f3..df524c5d 100644 --- a/src/shared.py +++ b/src/shared.py @@ -7,6 +7,7 @@ import highlevelcrypto import Queue import pickle import os +import time myECCryptorObjects = {} MyECSubscriptionCryptorObjects = {} @@ -27,6 +28,7 @@ printLock = threading.Lock() appdata = '' #holds the location of the application data storage directory statusIconColor = 'red' connectedHostsList = {} #List of hosts to which we are connected. Used to guarantee that the outgoingSynSender threads won't connect to the same remote node twice. +shutdown = 0 #Set to 1 by the doCleanShutdown function. Used to tell the proof of work worker threads to exit. #If changed, these values will cause particularly unexpected behavior: You won't be able to either send or receive messages because the proof of work you do (or demand) won't match that done or demanded by others. Don't change them! networkDefaultProofOfWorkNonceTrialsPerByte = 320 #The amount of work that should be performed (and demanded) per byte of the payload. Double this number to double the work. @@ -141,6 +143,8 @@ def reloadBroadcastSendersForWhichImWatching(): MyECSubscriptionCryptorObjects[hash] = highlevelcrypto.makeCryptor(privEncryptionKey.encode('hex')) def doCleanShutdown(): + global shutdown + shutdown = 1 #Used to tell proof of work worker threads to exit. knownNodesLock.acquire() UISignalQueue.put(('updateStatusBar','Saving the knownNodes list of peers to disk...')) output = open(appdata + 'knownnodes.dat', 'wb') @@ -172,7 +176,8 @@ def doCleanShutdown(): printLock.acquire() print 'Finished flushing inventory.' printLock.release() - + + time.sleep(.25) #Wait long enough to guarantee that any running proof of work worker threads will check the shutdown variable and exit. If the main thread closes before they do then they won't stop. if safeConfigGetBoolean('bitmessagesettings','daemon'): printLock.acquire() From a99e3d77801214bd4239dd4d920d93839423f56c Mon Sep 17 00:00:00 2001 From: Jonathan Warren Date: Thu, 30 May 2013 16:42:24 -0400 Subject: [PATCH 03/16] Multi-core POW --- src/proofofwork.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/proofofwork.py b/src/proofofwork.py index 144c7d79..20abf169 100644 --- a/src/proofofwork.py +++ b/src/proofofwork.py @@ -29,11 +29,11 @@ def run(target, initialHash): for i in range(pool_size): result.append(pool.apply_async(_pool_worker, args = (i, initialHash, target, pool_size))) while True: + if shared.shutdown: + pool.terminate() + time.sleep(5) #Don't return anything (doing so will cause exceptions because we'll return an unusable response). Sit here and wait for this thread to close. + return for i in range(pool_size): - if shared.shutdown: - pool.terminate() - time.sleep(5) #Don't return anything (doing so will cause exceptions because we'll return an unusable response). Sit here and wait for this thread to close. - return if result[i].ready(): result = result[i].get() pool.terminate() From de384c1c560a31af58725bcdedc262640bcf37bb Mon Sep 17 00:00:00 2001 From: Jonathan Warren Date: Fri, 31 May 2013 14:38:08 -0400 Subject: [PATCH 04/16] Multi-core POW --- src/bitmessagemain.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index 0eb78101..c7ce958e 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -3150,6 +3150,7 @@ class singleWorker(threading.Thread): requiredAverageProofOfWorkNonceTrialsPerByte = shared.networkDefaultProofOfWorkNonceTrialsPerByte if requiredPayloadLengthExtraBytes < shared.networkDefaultPayloadLengthExtraBytes: requiredPayloadLengthExtraBytes = shared.networkDefaultPayloadLengthExtraBytes + #todo: pull yet-to-be-added values out of config: maximumacceptabletotaldifficult and maximumacceptablesmallmessagedifficulty and compare. encrypted = highlevelcrypto.encrypt(payload,"04"+pubEncryptionKeyBase256.encode('hex')) #We are now dropping the unencrypted data in payload since it has already been encrypted and replacing it with the encrypted payload that we will send out. From 3f5b7a5936888cf77a6dcfc7d9cba4942da67d3d Mon Sep 17 00:00:00 2001 From: Jonathan Warren Date: Sun, 2 Jun 2013 23:22:28 -0400 Subject: [PATCH 05/16] Remove remaining references to the old myapp.trayIcon --- src/bitmessageqt/__init__.py | 39 +----------------------------------- 1 file changed, 1 insertion(+), 38 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 4d78d9f3..2326bf53 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -71,17 +71,6 @@ class MyForm(QtGui.QMainWindow): #startup for linux pass - """self.trayIcon = QtGui.QSystemTrayIcon(self) - self.trayIcon.setIcon( QtGui.QIcon(':/newPrefix/images/can-icon-16px.png') ) - traySignal = "activated(QSystemTrayIcon::ActivationReason)" - QtCore.QObject.connect(self.trayIcon, QtCore.SIGNAL(traySignal), self.__icon_activated) - menu = QtGui.QMenu() - self.exitAction = menu.addAction("Quit", self.quit) - self.trayIcon.setContextMenu(menu) - #I'm currently under the impression that Mac users have different expectations for the tray icon. They don't necessairly expect it to open the main window when clicked and they still expect a program showing a tray icon to also be in the dock. - if 'darwin' in sys.platform: - self.trayIcon.show()""" - self.ui.labelSendBroadcastWarning.setVisible(False) #FILE MENU and other buttons @@ -831,23 +820,6 @@ class MyForm(QtGui.QMainWindow): self.actionShow.setChecked(not self.actionShow.isChecked()) self.appIndicatorShowOrHideWindow() - """if 'linux' in sys.platform: - self.trayIcon.hide() - self.setWindowFlags(Qt.Window) - self.show() - elif 'win32' in sys.platform or 'win64' in sys.platform: - self.trayIcon.hide() - self.setWindowFlags(Qt.Window) - self.show() - self.setWindowState(self.windowState() & ~QtCore.Qt.WindowMinimized | QtCore.Qt.WindowActive) - self.activateWindow() - elif 'darwin' in sys.platform: - #self.trayIcon.hide() #this line causes a segmentation fault - #self.setWindowFlags(Qt.Window) - #self.show() - self.setWindowState(self.windowState() & ~QtCore.Qt.WindowMinimized | QtCore.Qt.WindowActive) - self.activateWindow()""" - def incrementNumberOfMessagesProcessed(self): self.numberOfMessagesProcessed += 1 self.ui.labelMessageCount.setText('Processed ' + str(self.numberOfMessagesProcessed) + ' person-to-person messages.') @@ -922,7 +894,6 @@ class MyForm(QtGui.QMainWindow): if self.actionStatus != None: self.actionStatus.setText('Not Connected') self.tray.setIcon(QtGui.QIcon(":/newPrefix/images/can-icon-24px-red.png")) - #self.trayIcon.show() if color == 'yellow': if self.statusBar().currentMessage() == 'Warning: You are currently not connected. Bitmessage will do the work necessary to send the message but it won\'t send until you connect.': self.statusBar().showMessage('') @@ -1650,7 +1621,6 @@ class MyForm(QtGui.QMainWindow): # unregister the messaging system if self.mmapp is not None: self.mmapp.unregister() - #self.trayIcon.hide() self.statusBar().showMessage('All done. Closing user interface...') os._exit(0) @@ -2139,12 +2109,10 @@ class settingsDialog(QtGui.QDialog): self.ui.checkBoxStartOnLogon.setDisabled(True) self.ui.checkBoxMinimizeToTray.setDisabled(True) self.ui.checkBoxShowTrayNotifications.setDisabled(True) - self.ui.checkBoxStartInTray.setDisabled(True) self.ui.labelSettingsNote.setText('Options have been disabled because they either aren\'t applicable or because they haven\'t yet been implimented for your operating system.') elif 'linux' in sys.platform: self.ui.checkBoxStartOnLogon.setDisabled(True) self.ui.checkBoxMinimizeToTray.setDisabled(True) - self.ui.checkBoxStartInTray.setDisabled(True) self.ui.labelSettingsNote.setText('Options have been disabled because they either aren\'t applicable or because they haven\'t yet been implimented for your operating system.') #On the Network settings tab: self.ui.lineEditTCPPort.setText(str(shared.config.get('bitmessagesettings', 'port'))) @@ -2331,12 +2299,7 @@ def run(): app.setStyleSheet("QStatusBar::item { border: 0px solid black }") myapp = MyForm() - if shared.config.getboolean('bitmessagesettings', 'startintray'): - if not myapp.isUbuntu(): - myapp.trayIcon.show() - if 'win32' in sys.platform or 'win64' in sys.platform: - myapp.setWindowFlags(Qt.ToolTip) - else: + if not shared.config.getboolean('bitmessagesettings', 'startintray'): myapp.show() myapp.appIndicatorInit(app) From 433d55d35191a708632173de90f4ca6fbfd7ba4f Mon Sep 17 00:00:00 2001 From: Jonathan Warren Date: Mon, 3 Jun 2013 01:04:22 -0400 Subject: [PATCH 06/16] Low priority POW threads --- src/bitmessagemain.py | 2 +- src/proofofwork.py | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index c7ce958e..100d6d30 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -3822,7 +3822,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): queryreturn = shared.sqlReturnQueue.get() shared.sqlLock.release() if queryreturn == []: - return 'notFound' + return 'notfound' for row in queryreturn: status, = row return status diff --git a/src/proofofwork.py b/src/proofofwork.py index 20abf169..5aef6dc4 100644 --- a/src/proofofwork.py +++ b/src/proofofwork.py @@ -3,8 +3,21 @@ import time from multiprocessing import Pool, cpu_count import hashlib from struct import unpack, pack +import sys +import os + +def _set_idle(): + try: + sys.getwindowsversion() + import win32api,win32process,win32con + pid = win32api.GetCurrentProcessId() + handle = win32api.OpenProcess(win32con.PROCESS_ALL_ACCESS, True, pid) + win32process.SetPriorityClass(handle, win32process.IDLE_PRIORITY_CLASS) + except: + os.nice(20) def _pool_worker(nonce, initialHash, target, pool_size): + _set_idle() trialValue = 99999999999999999999 while trialValue > target: nonce += pool_size From 816967dd9840db5aa48a28e57d726ca1ce00c851 Mon Sep 17 00:00:00 2001 From: Jonathan Warren Date: Mon, 3 Jun 2013 11:54:29 -0400 Subject: [PATCH 07/16] Increment version number to 0.3.2 --- Makefile | 2 +- debian.sh | 2 +- debian/changelog | 71 ++++++++++++++++++++++++++++++++++++++++++++++++ src/shared.py | 2 +- 4 files changed, 74 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 5031881c..07ce9fcf 100755 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ APP=pybitmessage -VERSION=0.3.1 +VERSION=0.3.2 DEST_SHARE=/usr/share DEST_APP=$(DEST_SHARE)/$(APP) diff --git a/debian.sh b/debian.sh index ac2121d5..7c71a3d4 100755 --- a/debian.sh +++ b/debian.sh @@ -7,7 +7,7 @@ #!/bin/bash APP=pybitmessage -VERSION=0.3.1 +VERSION=0.3.2 ARCH_TYPE=all # Create a source archive diff --git a/debian/changelog b/debian/changelog index c90ca319..b2c4984f 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,74 @@ +pybitmessage (0.3.2-1) raring; urgency=low + + * Bugfix: Remove remaining references to the old myapp.trayIcon + + * Refactored message status-related code. API function getStatus + now returns one of these strings: notfound, msgqueued, + broadcastqueued, broadcastsent, doingpubkeypow, awaitingpubkey, + doingmsgpow, msgsent, or ackreceived + + * Moved proof of work to low-priority multi-threaded child + processes + + * Added menu option to delete all trashed messages + + * Added inv flooding attack mitigation + + * On Linux, when selecting Show Bitmessage, do not maximize + automatically + + * Store tray icons in bitmessage_icons_rc.py + + -- Jonathan Warren (4096 bits) Mon, 03 June 2013 12:06:00 +0100 + +pybitmessage (0.3.1-1) raring; urgency=low + + * Added new API commands: getDeterministicAddress, + addSubscription, deleteSubscription + + * TCP Connection timeout for non-fully-established connections + now 20 seconds + + * Don't update the time we last communicated with a node unless + the connection is fully established. This will allow us to + forget about active but non-Bitmessage nodes which have made + it into our knownNodes file. + + * Prevent incoming connection flooding from crashing + singleListener thread. Client will now only accept one + connection per remote node IP + + * Bugfix: Worker thread crashed when doing a POW to send out + a v2 pubkey (bug introduced in 0.3.0) + + * Wrap all sock.shutdown functions in error handlers + + * Put all 'commit' commands within SQLLocks + + * Bugfix: If address book label is blank, Bitmessage wouldn't + show message (bug introduced in 0.3.0) + + * Messaging menu item selects the oldest unread message + + * Standardize on 'Quit' rather than 'Exit' + + * [OSX] Try to seek homebrew installation of OpenSSL + + * Prevent multiple instances of the application from running + + * Show 'Connected' or 'Connection Lost' indicators + + * Use only 9 half-open connections on Windows but 32 for + everyone else + + * Added appIndicator (a more functional tray icon) and Ubuntu + Messaging Menu integration + + * Changed Debian install directory and run script name based + on Github issue #135 + + -- Jonathan Warren (4096 bits) Sat, 25 May 2013 12:06:00 +0100 + pybitmessage (0.3.0-1) raring; urgency=low * Added new API function: getStatus diff --git a/src/shared.py b/src/shared.py index df524c5d..815cd637 100644 --- a/src/shared.py +++ b/src/shared.py @@ -1,4 +1,4 @@ -softwareVersion = '0.3.1' +softwareVersion = '0.3.2' import threading import sys From eb2d16c574e4f93692917574f532848a4ca9a50b Mon Sep 17 00:00:00 2001 From: fuzzgun Date: Mon, 3 Jun 2013 20:13:52 +0100 Subject: [PATCH 08/16] debian build script improvements --- Makefile | 6 +++--- debian.sh | 12 +++++++++++- src/shared.py | 2 +- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 07ce9fcf..0991ad56 100755 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ APP=pybitmessage -VERSION=0.3.2 -DEST_SHARE=/usr/share +VERSION=0.3.211 +DEST_SHARE=$(DESTDIR)/usr/share DEST_APP=$(DEST_SHARE)/$(APP) all: @@ -8,7 +8,7 @@ all: debug: source: - tar -cvzf ../$(APP)_$(VERSION).orig.tar.gz ../$(APP)-$(VERSION) --exclude=.git + tar -cvzf ../$(APP)_$(VERSION).orig.tar.gz ../$(APP)-$(VERSION) --exclude-vcs install: mkdir -m 755 -p $(DEST_APP) diff --git a/debian.sh b/debian.sh index 7c71a3d4..69bdcba8 100755 --- a/debian.sh +++ b/debian.sh @@ -7,15 +7,25 @@ #!/bin/bash APP=pybitmessage +PREV_VERSION=0.3.2 VERSION=0.3.2 ARCH_TYPE=all +#update version numbers automatically - so you don't have to +sed -i 's/VERSION='${PREV_VERSION}'/VERSION='${VERSION}'/g' Makefile +sed -i 's/'''${PREV_VERSION}'''/'''${VERSION}'''/g' src/shared.py + # Create a source archive make clean +# change the directory name to pybitmessage-version +mv ../PyBitmessage ../${APP}-${VERSION} make source # Build the package -fakeroot dpkg-buildpackage -A +dpkg-buildpackage -A + +# change the directory name back +mv ../${APP}-${VERSION} ../PyBitmessage gpg -ba ../${APP}_${VERSION}-1_${ARCH_TYPE}.deb gpg -ba ../${APP}_${VERSION}.orig.tar.gz diff --git a/src/shared.py b/src/shared.py index 815cd637..1aaa0d3a 100644 --- a/src/shared.py +++ b/src/shared.py @@ -1,4 +1,4 @@ -softwareVersion = '0.3.2' +softwareVersion = '0.3.211' import threading import sys From b296d9d39ff4177230a1dc159583c2ade35a5da6 Mon Sep 17 00:00:00 2001 From: fuzzgun Date: Mon, 3 Jun 2013 20:22:02 +0100 Subject: [PATCH 09/16] Remove invalid characters from debian/changelog --- Makefile | 2 +- debian/changelog | 94 ++++++++++++++++++++++++------------------------ 2 files changed, 48 insertions(+), 48 deletions(-) diff --git a/Makefile b/Makefile index 0991ad56..6f415786 100755 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ APP=pybitmessage -VERSION=0.3.211 +VERSION=0.3.2 DEST_SHARE=$(DESTDIR)/usr/share DEST_APP=$(DEST_SHARE)/$(APP) diff --git a/debian/changelog b/debian/changelog index b2c4984f..8c78203e 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,71 +1,71 @@ pybitmessage (0.3.2-1) raring; urgency=low * Bugfix: Remove remaining references to the old myapp.trayIcon - - * Refactored message status-related code. API function getStatus - now returns one of these strings: notfound, msgqueued, - broadcastqueued, broadcastsent, doingpubkeypow, awaitingpubkey, - doingmsgpow, msgsent, or ackreceived - - * Moved proof of work to low-priority multi-threaded child - processes - - * Added menu option to delete all trashed messages - - * Added inv flooding attack mitigation - - * On Linux, when selecting Show Bitmessage, do not maximize - automatically - - * Store tray icons in bitmessage_icons_rc.py - -- Jonathan Warren (4096 bits) Mon, 03 June 2013 12:06:00 +0100 + * Refactored message status-related code. API function getStatus + now returns one of these strings: notfound, msgqueued, + broadcastqueued, broadcastsent, doingpubkeypow, awaitingpubkey, + doingmsgpow, msgsent, or ackreceived + + * Moved proof of work to low-priority multi-threaded child + processes + + * Added menu option to delete all trashed messages + + * Added inv flooding attack mitigation + + * On Linux, when selecting Show Bitmessage, do not maximize + automatically + + * Store tray icons in bitmessage_icons_rc.py + + -- Bob Mottram (4096 bits) Mon, 03 June 2013 20:17:00 +0100 pybitmessage (0.3.1-1) raring; urgency=low - * Added new API commands: getDeterministicAddress, + * Added new API commands: getDeterministicAddress, addSubscription, deleteSubscription - - * TCP Connection timeout for non-fully-established connections + + * TCP Connection timeout for non-fully-established connections now 20 seconds - - * Don't update the time we last communicated with a node unless - the connection is fully established. This will allow us to - forget about active but non-Bitmessage nodes which have made - it into our knownNodes file. - - * Prevent incoming connection flooding from crashing - singleListener thread. Client will now only accept one - connection per remote node IP - - * Bugfix: Worker thread crashed when doing a POW to send out + + * Don't update the time we last communicated with a node unless + the connection is fully established. This will allow us to + forget about active but non-Bitmessage nodes which have made + it into our knownNodes file. + + * Prevent incoming connection flooding from crashing + singleListener thread. Client will now only accept one + connection per remote node IP + + * Bugfix: Worker thread crashed when doing a POW to send out a v2 pubkey (bug introduced in 0.3.0) - + * Wrap all sock.shutdown functions in error handlers - + * Put all 'commit' commands within SQLLocks - + * Bugfix: If address book label is blank, Bitmessage wouldn't show message (bug introduced in 0.3.0) - + * Messaging menu item selects the oldest unread message - + * Standardize on 'Quit' rather than 'Exit' - + * [OSX] Try to seek homebrew installation of OpenSSL - + * Prevent multiple instances of the application from running - + * Show 'Connected' or 'Connection Lost' indicators - - * Use only 9 half-open connections on Windows but 32 for + + * Use only 9 half-open connections on Windows but 32 for everyone else - - * Added appIndicator (a more functional tray icon) and Ubuntu + + * Added appIndicator (a more functional tray icon) and Ubuntu Messaging Menu integration - - * Changed Debian install directory and run script name based - on Github issue #135 + + * Changed Debian install directory and run script name based + on Github issue #135 -- Jonathan Warren (4096 bits) Sat, 25 May 2013 12:06:00 +0100 From 483e51ad0473426373deabd8efc7dc025346510a Mon Sep 17 00:00:00 2001 From: Jonathan Warren Date: Mon, 3 Jun 2013 15:48:53 -0400 Subject: [PATCH 10/16] initilize the ackdataForWhichImWatching data structure within the single worker thread --- src/bitmessagemain.py | 31 +++++++++++++++++++------------ src/bitmessageqt/__init__.py | 4 ++-- 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index 100d6d30..c12be4d3 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -2626,7 +2626,7 @@ class singleWorker(threading.Thread): def run(self): shared.sqlLock.acquire() - shared.sqlSubmitQueue.put('''SELECT toripe FROM sent WHERE (status='awaitingpubkey' AND folder='sent')''') + shared.sqlSubmitQueue.put('''SELECT toripe FROM sent WHERE ((status='awaitingpubkey' OR status='doingpubkeypow') AND folder='sent')''') shared.sqlSubmitQueue.put('') queryreturn = shared.sqlReturnQueue.get() shared.sqlLock.release() @@ -2634,6 +2634,17 @@ class singleWorker(threading.Thread): toripe, = row neededPubkeys[toripe] = 0 + #Initialize the ackdataForWhichImWatching data structure using data from the sql database. + shared.sqlLock.acquire() + shared.sqlSubmitQueue.put('''SELECT ackdata FROM sent where (status='msgsent' OR status='doingmsgpow')''') + shared.sqlSubmitQueue.put('') + queryreturn = shared.sqlReturnQueue.get() + shared.sqlLock.release() + for row in queryreturn: + ackdata, = row + print 'Watching for ackdata', ackdata.encode('hex') + ackdataForWhichImWatching[ackdata] = 0 + shared.sqlLock.acquire() shared.sqlSubmitQueue.put('''SELECT DISTINCT toaddress FROM sent WHERE (status='doingpubkeypow' AND folder='sent')''') shared.sqlSubmitQueue.put('') @@ -2643,7 +2654,7 @@ class singleWorker(threading.Thread): toaddress, = row self.requestPubKey(toaddress) - time.sleep(10) #give some time for the GUI to start before we start on any existing POW tasks. + time.sleep(10) #give some time for the GUI to start before we start on existing POW tasks. self.sendMsg() #just in case there are any pending tasks for msg messages that have yet to be sent. self.sendBroadcast() #just in case there are any tasks for Broadcasts that have yet to be sent. @@ -2950,7 +2961,7 @@ class singleWorker(threading.Thread): def sendMsg(self): #Check to see if there are any messages queued to be sent shared.sqlLock.acquire() - shared.sqlSubmitQueue.put('''SELECT toaddress FROM sent WHERE (status='msgqueued' AND folder='sent')''') + shared.sqlSubmitQueue.put('''SELECT DISTINCT toaddress FROM sent WHERE (status='msgqueued' AND folder='sent')''') shared.sqlSubmitQueue.put('') queryreturn = shared.sqlReturnQueue.get() shared.sqlLock.release() @@ -3194,6 +3205,11 @@ class singleWorker(threading.Thread): def requestPubKey(self,toAddress): toStatus,addressVersionNumber,streamNumber,ripe = decodeAddress(toAddress) + if toStatus != 'success': + shared.printLock.acquire() + sys.stderr.write('Very abnormal error occurred in requestPubKey. toAddress is: '+repr(toAddress)+'. Please report this error to Atheros.') + shared.printLock.release() + return neededPubkeys[ripe] = 0 payload = pack('>I',(int(time.time())+random.randrange(-300, 300)))#the current time plus or minus five minutes. payload += encodeVarint(addressVersionNumber) @@ -4054,15 +4070,6 @@ if __name__ == "__main__": shared.reloadMyAddressHashes() shared.reloadBroadcastSendersForWhichImWatching() - #Initialize the ackdataForWhichImWatching data structure using data from the sql database. - shared.sqlSubmitQueue.put('''SELECT ackdata FROM sent where (status='msgsent' OR status='doingmsgpow')''') - shared.sqlSubmitQueue.put('') - queryreturn = shared.sqlReturnQueue.get() - for row in queryreturn: - ackdata, = row - print 'Watching for ackdata', ackdata.encode('hex') - ackdataForWhichImWatching[ackdata] = 0 - if shared.safeConfigGetBoolean('bitmessagesettings','apienabled'): try: apiNotifyPath = shared.config.get('bitmessagesettings','apinotifypath') diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 2326bf53..0179ff7f 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -529,7 +529,7 @@ class MyForm(QtGui.QMainWindow): # create application indicator def appIndicatorInit(self,app): - self.tray = QSystemTrayIcon(QtGui.QIcon("images/can-icon-24px-red.png"), app) + self.tray = QSystemTrayIcon(QtGui.QIcon(":/newPrefix/images/can-icon-24px-red.png"), app) if sys.platform[0:3] == 'win': traySignal = "activated(QSystemTrayIcon::ActivationReason)" QtCore.QObject.connect(self.tray, QtCore.SIGNAL(traySignal), self.__icon_activated) @@ -1979,7 +1979,7 @@ class MyForm(QtGui.QMainWindow): if len(self.ui.tableWidgetInbox.item(currentRow,2).data(Qt.UserRole).toPyObject()) < 30000: self.ui.textEditInboxMessage.setPlainText(self.ui.tableWidgetInbox.item(currentRow,2).data(Qt.UserRole).toPyObject())#Only show the first 30K characters else: - self.ui.textEditInboxMessage.setPlainText(self.ui.tableWidgetInbox.item(currentRow,2).data(Qt.UserRole).toPyObject()[:30000]+'\n\nDisplay of the remainder of the message truncated because it is too long.')#Only show the first 30K characters + self.ui.textEditInboxMessage.setPlainText(self.ui.tableWidgetInbox.item(currentRow,2).data(Qt.UserRole).toPyObject()[:30000]+'\n\nDisplay of the remainder of the message truncated because it is too long.')#Only show the first 30K characters font = QFont() font.setBold(False) From 32efdca33cd7881d6a034aec0864f98979e3cb9e Mon Sep 17 00:00:00 2001 From: Jonathan Warren Date: Mon, 3 Jun 2013 20:41:39 -0400 Subject: [PATCH 11/16] Emergency fix for 64-bit Windows systems --- src/proofofwork.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/proofofwork.py b/src/proofofwork.py index 5aef6dc4..8f316096 100644 --- a/src/proofofwork.py +++ b/src/proofofwork.py @@ -14,7 +14,12 @@ def _set_idle(): handle = win32api.OpenProcess(win32con.PROCESS_ALL_ACCESS, True, pid) win32process.SetPriorityClass(handle, win32process.IDLE_PRIORITY_CLASS) except: - os.nice(20) + try: + #Linux + os.nice(20) + except: + #Windows 64-bit + pass def _pool_worker(nonce, initialHash, target, pool_size): _set_idle() From 21559e09f18cd0cccbc229c35a9b2f521572f5ef Mon Sep 17 00:00:00 2001 From: Jonathan Warren Date: Mon, 3 Jun 2013 23:14:24 -0400 Subject: [PATCH 12/16] Remove multi-core POW support --- src/bitmessagemain.py | 2 ++ src/bitmessageqt/__init__.py | 14 +++++----- src/proofofwork.py | 20 ++++++++----- src/settings.py | 34 ++--------------------- src/settings.ui | 54 ------------------------------------ 5 files changed, 24 insertions(+), 100 deletions(-) diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index c12be4d3..df36dfc1 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -47,6 +47,7 @@ import json from subprocess import call #used when the API must execute an outside program import singleton import proofofwork +import multiprocessing.forking #For each stream to which we connect, several outgoingSynSender threads will exist and will collectively create 8 connections with peers. class outgoingSynSender(threading.Thread): @@ -3939,6 +3940,7 @@ if useVeryEasyProofOfWorkForTesting: shared.networkDefaultProofOfWorkNonceTrialsPerByte = int(shared.networkDefaultProofOfWorkNonceTrialsPerByte / 16) shared.networkDefaultPayloadLengthExtraBytes = int(shared.networkDefaultPayloadLengthExtraBytes / 7000) + if __name__ == "__main__": # is the application already running? If yes then exit. thisapp = singleton.singleinstance() diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 0179ff7f..435ebec5 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -1431,10 +1431,10 @@ class MyForm(QtGui.QMainWindow): shared.config.set('bitmessagesettings', 'defaultnoncetrialsperbyte',str(int(float(self.settingsDialogInstance.ui.lineEditTotalDifficulty.text())*shared.networkDefaultProofOfWorkNonceTrialsPerByte))) if float(self.settingsDialogInstance.ui.lineEditSmallMessageDifficulty.text()) >= 1: shared.config.set('bitmessagesettings', 'defaultpayloadlengthextrabytes',str(int(float(self.settingsDialogInstance.ui.lineEditSmallMessageDifficulty.text())*shared.networkDefaultPayloadLengthExtraBytes))) - if str(self.settingsDialogInstance.ui.comboBoxMaxCores.currentText()) == 'All': - shared.config.set('bitmessagesettings', 'maxcores', '99999') - else: - shared.config.set('bitmessagesettings', 'maxcores', str(self.settingsDialogInstance.ui.comboBoxMaxCores.currentText())) + #if str(self.settingsDialogInstance.ui.comboBoxMaxCores.currentText()) == 'All': + # shared.config.set('bitmessagesettings', 'maxcores', '99999') + #else: + # shared.config.set('bitmessagesettings', 'maxcores', str(self.settingsDialogInstance.ui.comboBoxMaxCores.currentText())) with open(shared.appdata + 'keys.dat', 'wb') as configfile: shared.config.write(configfile) @@ -2140,8 +2140,8 @@ class settingsDialog(QtGui.QDialog): self.ui.lineEditTotalDifficulty.setText(str((float(shared.config.getint('bitmessagesettings', 'defaultnoncetrialsperbyte'))/shared.networkDefaultProofOfWorkNonceTrialsPerByte))) self.ui.lineEditSmallMessageDifficulty.setText(str((float(shared.config.getint('bitmessagesettings', 'defaultpayloadlengthextrabytes'))/shared.networkDefaultPayloadLengthExtraBytes))) - #On the System tab - try: + #'System' tab removed for now. + """try: maxCores = shared.config.getint('bitmessagesettings', 'maxcores') except: maxCores = 99999 @@ -2156,7 +2156,7 @@ class settingsDialog(QtGui.QDialog): elif maxCores <= 16: self.ui.comboBoxMaxCores.setCurrentIndex(4) else: - self.ui.comboBoxMaxCores.setCurrentIndex(5) + self.ui.comboBoxMaxCores.setCurrentIndex(5)""" QtGui.QWidget.resize(self,QtGui.QWidget.sizeHint(self)) diff --git a/src/proofofwork.py b/src/proofofwork.py index 8f316096..5fd7e43a 100644 --- a/src/proofofwork.py +++ b/src/proofofwork.py @@ -1,10 +1,10 @@ -import shared -import time -from multiprocessing import Pool, cpu_count +#import shared +#import time +#from multiprocessing import Pool, cpu_count import hashlib from struct import unpack, pack -import sys -import os +#import sys +#import os def _set_idle(): try: @@ -30,7 +30,13 @@ def _pool_worker(nonce, initialHash, target, pool_size): return [trialValue, nonce] def run(target, initialHash): - try: + nonce = 0 + trialValue = 99999999999999999999 + while trialValue > target: + nonce += 1 + trialValue, = unpack('>Q',hashlib.sha512(hashlib.sha512(pack('>Q',nonce) + initialHash).digest()).digest()[0:8]) + return [trialValue, nonce] + """try: pool_size = cpu_count() except: pool_size = 4 @@ -56,5 +62,5 @@ def run(target, initialHash): result = result[i].get() pool.terminate() return result[0], result[1] - time.sleep(0.2) + time.sleep(0.2)""" diff --git a/src/settings.py b/src/settings.py index dac0f788..d8f86efc 100644 --- a/src/settings.py +++ b/src/settings.py @@ -2,8 +2,8 @@ # Form implementation generated from reading ui file 'settings.ui' # -# Created: Thu May 30 15:50:32 2013 -# by: PyQt4 UI code generator 4.9.4 +# Created: Mon Jun 03 23:09:01 2013 +# by: PyQt4 UI code generator 4.9.5 # # WARNING! All changes made in this file will be lost! @@ -172,28 +172,6 @@ class Ui_settingsDialog(object): self.label_10.setObjectName(_fromUtf8("label_10")) self.gridLayout_6.addWidget(self.label_10, 2, 0, 1, 3) self.tabWidgetSettings.addTab(self.tab, _fromUtf8("")) - self.tab_2 = QtGui.QWidget() - self.tab_2.setObjectName(_fromUtf8("tab_2")) - self.formLayout = QtGui.QFormLayout(self.tab_2) - self.formLayout.setObjectName(_fromUtf8("formLayout")) - self.label_13 = QtGui.QLabel(self.tab_2) - self.label_13.setObjectName(_fromUtf8("label_13")) - self.formLayout.setWidget(0, QtGui.QFormLayout.LabelRole, self.label_13) - self.comboBoxMaxCores = QtGui.QComboBox(self.tab_2) - sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.comboBoxMaxCores.sizePolicy().hasHeightForWidth()) - self.comboBoxMaxCores.setSizePolicy(sizePolicy) - self.comboBoxMaxCores.setObjectName(_fromUtf8("comboBoxMaxCores")) - self.comboBoxMaxCores.addItem(_fromUtf8("")) - self.comboBoxMaxCores.addItem(_fromUtf8("")) - self.comboBoxMaxCores.addItem(_fromUtf8("")) - self.comboBoxMaxCores.addItem(_fromUtf8("")) - self.comboBoxMaxCores.addItem(_fromUtf8("")) - self.comboBoxMaxCores.addItem(_fromUtf8("")) - self.formLayout.setWidget(0, QtGui.QFormLayout.FieldRole, self.comboBoxMaxCores) - self.tabWidgetSettings.addTab(self.tab_2, _fromUtf8("")) self.gridLayout.addWidget(self.tabWidgetSettings, 0, 0, 1, 1) self.retranslateUi(settingsDialog) @@ -244,12 +222,4 @@ class Ui_settingsDialog(object): self.label_12.setText(QtGui.QApplication.translate("settingsDialog", "The \'Small message difficulty\' mostly only affects the difficulty of sending small messages. Doubling this value makes it almost twice as difficult to send a small message but doesn\'t really affect large messages.", None, QtGui.QApplication.UnicodeUTF8)) self.label_10.setText(QtGui.QApplication.translate("settingsDialog", "The \'Total difficulty\' affects the absolute amount of work the sender must complete. Doubling this value doubles the amount of work.", None, QtGui.QApplication.UnicodeUTF8)) self.tabWidgetSettings.setTabText(self.tabWidgetSettings.indexOf(self.tab), QtGui.QApplication.translate("settingsDialog", "Demanded difficulty", None, QtGui.QApplication.UnicodeUTF8)) - self.label_13.setText(QtGui.QApplication.translate("settingsDialog", "Maximum number of CPU cores to use when doing work:", None, QtGui.QApplication.UnicodeUTF8)) - self.comboBoxMaxCores.setItemText(0, QtGui.QApplication.translate("settingsDialog", "1", None, QtGui.QApplication.UnicodeUTF8)) - self.comboBoxMaxCores.setItemText(1, QtGui.QApplication.translate("settingsDialog", "2", None, QtGui.QApplication.UnicodeUTF8)) - self.comboBoxMaxCores.setItemText(2, QtGui.QApplication.translate("settingsDialog", "4", None, QtGui.QApplication.UnicodeUTF8)) - self.comboBoxMaxCores.setItemText(3, QtGui.QApplication.translate("settingsDialog", "8", None, QtGui.QApplication.UnicodeUTF8)) - self.comboBoxMaxCores.setItemText(4, QtGui.QApplication.translate("settingsDialog", "16", None, QtGui.QApplication.UnicodeUTF8)) - self.comboBoxMaxCores.setItemText(5, QtGui.QApplication.translate("settingsDialog", "All", None, QtGui.QApplication.UnicodeUTF8)) - self.tabWidgetSettings.setTabText(self.tabWidgetSettings.indexOf(self.tab_2), QtGui.QApplication.translate("settingsDialog", "System", None, QtGui.QApplication.UnicodeUTF8)) diff --git a/src/settings.ui b/src/settings.ui index 61419bb6..971480bd 100644 --- a/src/settings.ui +++ b/src/settings.ui @@ -373,60 +373,6 @@ - - - System - - - - - - Maximum number of CPU cores to use when doing work: - - - - - - - - 0 - 0 - - - - - 1 - - - - - 2 - - - - - 4 - - - - - 8 - - - - - 16 - - - - - All - - - - - - From 55de3ad9c7e695dd8d92f42af1b376c6c45f300a Mon Sep 17 00:00:00 2001 From: Jonathan Warren Date: Mon, 3 Jun 2013 23:38:10 -0400 Subject: [PATCH 13/16] Remove multi-core POW support --- src/bitmessagemain.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index df36dfc1..c12be4d3 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -47,7 +47,6 @@ import json from subprocess import call #used when the API must execute an outside program import singleton import proofofwork -import multiprocessing.forking #For each stream to which we connect, several outgoingSynSender threads will exist and will collectively create 8 connections with peers. class outgoingSynSender(threading.Thread): @@ -3940,7 +3939,6 @@ if useVeryEasyProofOfWorkForTesting: shared.networkDefaultProofOfWorkNonceTrialsPerByte = int(shared.networkDefaultProofOfWorkNonceTrialsPerByte / 16) shared.networkDefaultPayloadLengthExtraBytes = int(shared.networkDefaultPayloadLengthExtraBytes / 7000) - if __name__ == "__main__": # is the application already running? If yes then exit. thisapp = singleton.singleinstance() From da7c1514649611074e8bfc4ad2c8ab776d22670b Mon Sep 17 00:00:00 2001 From: Justus Ranvier Date: Tue, 4 Jun 2013 15:13:16 -0500 Subject: [PATCH 14/16] Update Makefile to correct sandbox violations when built via Portage (Gentoo) --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 6f415786..6485c2c9 100755 --- a/Makefile +++ b/Makefile @@ -34,7 +34,7 @@ install: install -m 644 src/pyelliptic/*.py $(DEST_APP)/pyelliptic install -m 644 src/socks/*.py $(DEST_APP)/socks install -m 644 src/bitmessageqt/*.py $(DEST_APP)/bitmessageqt - install -m 755 debian/pybm /usr/bin/pybitmessage + install -m 755 debian/pybm $(DESTDIR)/usr/bin/$(APP) install -m 644 desktop/$(APP).desktop $(DEST_SHARE)/applications/$(APP).desktop install -m 644 src/images/can-icon-24px.png $(DEST_SHARE)/icons/hicolor/24x24/apps/$(APP).png From 354c82d85b68ca155a5ae83b3f04b602e77505a4 Mon Sep 17 00:00:00 2001 From: Justus Ranvier Date: Tue, 4 Jun 2013 15:21:53 -0500 Subject: [PATCH 15/16] Ensure $(DESTDIR)/usr/bin exists --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index 6485c2c9..d49f63fc 100755 --- a/Makefile +++ b/Makefile @@ -11,6 +11,7 @@ source: tar -cvzf ../$(APP)_$(VERSION).orig.tar.gz ../$(APP)-$(VERSION) --exclude-vcs install: + mkdir -m 755 -p $(DESTDIR)/usr/bin mkdir -m 755 -p $(DEST_APP) mkdir -m 755 -p $(DEST_SHARE)/applications mkdir -m 755 -p $(DEST_APP)/images From 41792697b63dfd1de242ac04d691e1ea01708b12 Mon Sep 17 00:00:00 2001 From: Justus Ranvier Date: Tue, 4 Jun 2013 15:32:14 -0500 Subject: [PATCH 16/16] Add missing trailing semicolons to pybitmessage.desktop --- desktop/pybitmessage.desktop | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/desktop/pybitmessage.desktop b/desktop/pybitmessage.desktop index 363908dd..2b1b6902 100644 --- a/desktop/pybitmessage.desktop +++ b/desktop/pybitmessage.desktop @@ -7,12 +7,12 @@ Comment=Send encrypted messages to another person or to many subscribers Exec=pybitmessage %U Icon=pybitmessage Terminal=false -Categories=Network;Email;Application -Keywords=Email;E-mail;Newsgroup;Messaging +Categories=Network;Email;Application; +Keywords=Email;E-mail;Newsgroup;Messaging; X-MessagingMenu-UsesChatSection=true X-Ubuntu-Gettext-Domain=pybitmessage -Actions=Send;Subscribe;AddressBook +Actions=Send;Subscribe;AddressBook; [Desktop Action Send] Name=Send @@ -27,4 +27,4 @@ OnlyShowIn=Unity; [Desktop Action AddressBook] Name=Address Book Exec=pybitmessage -a -OnlyShowIn=Unity; \ No newline at end of file +OnlyShowIn=Unity;