# yet contain logic to expand into further streams.
# The software version variable is now held in shared.py
verbose=1
maximumAgeOfAnObjectThatIAmWillingToAccept=216000# Equals two days and 12 hours.
lengthOfTimeToLeaveObjectsInInventory=237600# Equals two days and 18 hours. This should be longer than maximumAgeOfAnObjectThatIAmWillingToAccept so that we don't process messages twice.
lengthOfTimeToHoldOnToAllPubkeys=2419200# Equals 4 weeks. You could make this longer if you want but making it shorter would not be advisable because there is a very small possibility that it could keep you from obtaining a needed pubkey for a period of time.
maximumAgeOfObjectsThatIAdvertiseToOthers=216000# Equals two days and 12 hours
maximumAgeOfNodesThatIAdvertiseToOthers=10800# Equals three hours
useVeryEasyProofOfWorkForTesting=False# If you set this to True while on the normal network, you won't be able to send or sometimes receive messages.
encryptedBroadcastSwitchoverTime=1369735200
alreadyAttemptedConnectionsList={
}# This is a list of nodes to which we have already attempted a connection
@ -729,50 +663,14 @@ class singleAPI(threading.Thread):
se.register_introspection_functions()
se.serve_forever()
# This is used so that the translateText function can be used when we are in daemon mode and not using any QT functions.
classtranslateClass:
def__init__(self,context,text):
self.context=context
self.text=text
defarg(self,argument):
if'%'inself.text:
returntranslateClass(self.context,self.text.replace('%','',1))# This doesn't actually do anything with the arguments because we don't have a UI in which to display this information anyway.
else:
returnself.text
selfInitiatedConnections={}
# This is a list of current connections (the thread pointers at least)
print'PyBitmessage requires PyQt unless you want to run it as a daemon and interact with it using the API. You can download PyQt from http://www.riverbankcomputing.com/software/pyqt/download or by searching Google for \'PyQt Download\'. If you want to run in daemon mode, see https://bitmessage.org/wiki/Daemon'
]# A list of the amounts of time it took to successfully decrypt msg messages
apiAddressGeneratorReturnQueue=Queue.Queue(
)# The address generator thread uses this queue to get information back to the API thread.
alreadyAttemptedConnectionsListResetTime=int(
time.time())# used to clear out the alreadyAttemptedConnectionsList periodically so that we will retry connecting to hosts to which we have already tried to connect.
]# When we receive a message bound for us, we store the acknowledgement that we need to send (the ackdata) here until we are done processing all other data received from this peer.
print'Inventory (SQL on disk) already has object listed in inv message.'
shared.printLock.release()
@ -199,7 +197,7 @@ class receiveDataThread(threading.Thread):
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
@ -209,7 +207,7 @@ class receiveDataThread(threading.Thread):
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
@ -217,7 +215,7 @@ class receiveDataThread(threading.Thread):
shared.printLock.acquire()
print'(concerning',self.HOST+')','number of objectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave is now',len(self.objectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave)
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.
iflen(self.ackDataThatWeHaveYetToSend)>0:
self.data=self.ackDataThatWeHaveYetToSend.pop()
@ -285,8 +283,8 @@ class receiveDataThread(threading.Thread):
shared.sqlLock.acquire()
# Select all hashes which are younger than two days old and in this
@ -821,13 +819,13 @@ class receiveDataThread(threading.Thread):
shared.sqlReturnQueue.get()
shared.sqlSubmitQueue.put('commit')
shared.sqlLock.release()
shared.UISignalQueue.put(('updateSentItemStatusByAckdata',(encryptedData[readPosition:],bitmessagemain.translateText("MainWindow",'Acknowledgement of the message received. %1').arg(unicode(
shared.UISignalQueue.put(('updateSentItemStatusByAckdata',(encryptedData[readPosition:],tr.translateText("MainWindow",'Acknowledgement of the message received. %1').arg(unicode(
print'number of keys(hosts) in numberOfObjectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHavePerPeer:',len(numberOfObjectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHavePerPeer)
print'number of keys(hosts) in shared.numberOfObjectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHavePerPeer:',len(shared.numberOfObjectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHavePerPeer)
@ -1472,13 +1470,13 @@ class receiveDataThread(threading.Thread):
print'We already have',totalNumberOfObjectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave,'items yet to retrieve from peers and over 1000 from this node in particular. Ignoring this inv message.'
@ -1491,11 +1489,11 @@ class receiveDataThread(threading.Thread):
print'We already have',totalNumberOfObjectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave,'items yet to retrieve from peers and over',len(self.objectsThatWeHaveYetToCheckAndSeeWhetherWeAlreadyHave),'from this node in particular. Ignoring the rest of this inv message.'
@ -147,6 +147,7 @@ class sendDataThread(threading.Thread):
print'sendDataThread thread (ID:',str(id(self))+') ending now. Was connected to',self.HOST
break
elifcommand=='pong':
self.someObjectsOfWhichThisRemoteNodeIsAlreadyAware.clear()# To save memory, let us clear this data structure from time to time. As its function is to help us keep from sending inv messages to peers which sent us the same inv message mere seconds earlier, it will be fine to clear this data structure from time to time.
ifself.lastTimeISentData<(int(time.time())-298):
# Send out a pong message to keep the connection alive.
'''The singleCleaner class is a timer-driven thread that cleans data structures to free memory, resends messages when a remote node doesn't respond, and sends pong messages to keep connections alive if the network isn't busy.
@ -58,15 +56,15 @@ class singleCleaner(threading.Thread):
shared.sqlLock.acquire()
# inventory (clears pubkeys after 28 days and everything else
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.
delshared.neededPubkeys[
toripe]# We need to take this entry out of the shared.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
@ -107,7 +105,7 @@ class singleCleaner(threading.Thread):
ackdata,bitmessagemain.translateText("MainWindow","Doing work necessary to send message.\nThere is no required difficulty for version 2 addresses like this."))))
ackdata,tr.translateText("MainWindow","Doing work necessary to send message.\nThere is no required difficulty for version 2 addresses like this."))))
shared.UISignalQueue.put(('updateSentItemStatusByAckdata',(ackdata,bitmessagemain.translateText("MainWindow","Doing work necessary to send message.\nReceiver\'s required difficulty: %1 and %2").arg(str(float(
shared.UISignalQueue.put(('updateSentItemStatusByAckdata',(ackdata,tr.translateText("MainWindow","Doing work necessary to send message.\nReceiver\'s required difficulty: %1 and %2").arg(str(float(
@ -619,7 +617,7 @@ class singleWorker(threading.Thread):
shared.sqlReturnQueue.get()
shared.sqlSubmitQueue.put('commit')
shared.sqlLock.release()
shared.UISignalQueue.put(('updateSentItemStatusByAckdata',(ackdata,bitmessagemain.translateText("MainWindow","Problem: The work demanded by the recipient (%1 and %2) is more difficult than you are willing to do.").arg(str(float(requiredAverageProofOfWorkNonceTrialsPerByte)/shared.networkDefaultProofOfWorkNonceTrialsPerByte)).arg(str(float(
shared.UISignalQueue.put(('updateSentItemStatusByAckdata',(ackdata,tr.translateText("MainWindow","Problem: The work demanded by the recipient (%1 and %2) is more difficult than you are willing to do.").arg(str(float(requiredAverageProofOfWorkNonceTrialsPerByte)/shared.networkDefaultProofOfWorkNonceTrialsPerByte)).arg(str(float(
@ -743,7 +741,7 @@ class singleWorker(threading.Thread):
queryreturn=shared.sqlReturnQueue.get()
shared.sqlSubmitQueue.put('commit')
shared.sqlLock.release()
shared.UISignalQueue.put(('updateSentItemStatusByAckdata',(ackdata,bitmessagemain.translateText("MainWindow",'Problem: The recipient\'s encryption key is no good. Could not encrypt message. %1').arg(unicode(strftime(shared.config.get('bitmessagesettings','timeformat'),localtime(int(time.time()))),'utf-8')))))
shared.UISignalQueue.put(('updateSentItemStatusByAckdata',(ackdata,tr.translateText("MainWindow",'Problem: The recipient\'s encryption key is no good. Could not encrypt message. %1').arg(unicode(strftime(shared.config.get('bitmessagesettings','timeformat'),localtime(int(time.time()))),'utf-8')))))
shared.UISignalQueue.put(('updateSentItemStatusByAckdata',(ackdata,bitmessagemain.translateText("MainWindow","Message sent. Waiting on acknowledgement. Sent on %1").arg(unicode(
shared.UISignalQueue.put(('updateSentItemStatusByAckdata',(ackdata,tr.translateText("MainWindow","Message sent. Waiting on acknowledgement. Sent on %1").arg(unicode(
@ -832,8 +830,8 @@ class singleWorker(threading.Thread):
shared.sqlLock.release()
shared.UISignalQueue.put((
'updateStatusBar',bitmessagemain.translateText("MainWindow",'Broacasting the public key request. This program will auto-retry if they are offline.')))
shared.UISignalQueue.put(('updateSentItemStatusByHash',(ripe,bitmessagemain.translateText("MainWindow",'Sending public key request. Waiting for reply. Requested at %1').arg(unicode(
'updateStatusBar',tr.translateText("MainWindow",'Broacasting the public key request. This program will auto-retry if they are offline.')))
shared.UISignalQueue.put(('updateSentItemStatusByHash',(ripe,tr.translateText("MainWindow",'Sending public key request. Waiting for reply. Requested at %1').arg(unicode(
maximumAgeOfAnObjectThatIAmWillingToAccept=216000# Equals two days and 12 hours.
lengthOfTimeToLeaveObjectsInInventory=237600# Equals two days and 18 hours. This should be longer than maximumAgeOfAnObjectThatIAmWillingToAccept so that we don't process messages twice.
lengthOfTimeToHoldOnToAllPubkeys=2419200# Equals 4 weeks. You could make this longer if you want but making it shorter would not be advisable because there is a very small possibility that it could keep you from obtaining a needed pubkey for a period of time.
maximumAgeOfObjectsThatIAdvertiseToOthers=216000# Equals two days and 12 hours
maximumAgeOfNodesThatIAdvertiseToOthers=10800# Equals three hours
useVeryEasyProofOfWorkForTesting=False# If you set this to True while on the normal network, you won't be able to send or sometimes receive messages.
importthreading
importsys
@ -9,6 +17,10 @@ import pickle
importos
importtime
importConfigParser
importsocket
importrandom
importhighlevelcrypto
importshared
config=ConfigParser.SafeConfigParser()
myECCryptorObjects={}
@ -31,11 +43,74 @@ 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.
alreadyAttemptedConnectionsList={
}# This is a list of nodes to which we have already attempted a connection
time.time())# used to clear out the alreadyAttemptedConnectionsList periodically so that we will retry connecting to hosts to which we have already tried to connect.
]# A list of the amounts of time it took to successfully decrypt msg messages
apiAddressGeneratorReturnQueue=Queue.Queue(
)# The address generator thread uses this queue to get information back to the API thread.
ackdataForWhichImWatching={}
#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.
networkDefaultPayloadLengthExtraBytes=14000#To make sending short messages a little more difficult, this value is added to the payload length for use in calculating the proof of work target.
defisInSqlInventory(hash):
t=(hash,)
shared.sqlLock.acquire()
shared.sqlSubmitQueue.put('''select hash from inventory where hash=?''')