2015-01-21 18:38:25 +01:00
from __future__ import division
2013-06-21 23:32:22 +02:00
import threading
import shared
import time
2013-06-24 22:25:31 +02:00
from time import strftime , localtime , gmtime
2013-06-21 23:32:22 +02:00
import random
2013-09-30 05:01:56 +02:00
from subprocess import call # used when the API must execute an outside program
2013-06-21 23:32:22 +02:00
from addresses import *
import highlevelcrypto
import proofofwork
2013-06-23 21:52:39 +02:00
import sys
2013-06-24 21:51:01 +02:00
import tr
2017-02-22 09:34:54 +01:00
from bmconfigparser import BMConfigParser
2013-08-08 21:37:48 +02:00
from debug import logger
2017-02-08 20:37:42 +01:00
import defaults
2013-08-29 13:27:30 +02:00
from helper_sql import *
2013-09-30 05:01:56 +02:00
import helper_inbox
2014-05-02 16:46:36 +02:00
from helper_generic import addDataPadding
2016-11-14 20:23:58 +01:00
import helper_msgcoding
2015-11-24 01:55:17 +01:00
from helper_threading import *
2017-01-19 19:48:12 +01:00
from inventory import Inventory , PendingUpload
2014-08-06 04:01:01 +02:00
import l10n
2017-01-11 14:27:19 +01:00
import protocol
2017-02-08 13:41:56 +01:00
import queues
2017-01-14 23:20:15 +01:00
import state
2016-03-23 23:26:57 +01:00
from binascii import hexlify , unhexlify
2013-06-21 23:32:22 +02:00
# This thread, of which there is only one, does the heavy lifting:
# calculating POWs.
2015-11-26 02:38:55 +01:00
def sizeof_fmt ( num , suffix = ' h/s ' ) :
for unit in [ ' ' , ' k ' , ' M ' , ' G ' , ' T ' , ' P ' , ' E ' , ' Z ' ] :
if abs ( num ) < 1000.0 :
return " %3.1f %s %s " % ( num , unit , suffix )
num / = 1024.0
return " %.1f %s %s " % ( num , ' Yi ' , suffix )
2013-06-21 23:32:22 +02:00
2015-11-24 01:55:17 +01:00
class singleWorker ( threading . Thread , StoppableThread ) :
2013-06-21 23:32:22 +02:00
def __init__ ( self ) :
# QThread.__init__(self, parent)
2015-11-18 16:22:17 +01:00
threading . Thread . __init__ ( self , name = " singleWorker " )
2015-11-24 01:55:17 +01:00
self . initStop ( )
def stopThread ( self ) :
try :
2017-02-08 13:41:56 +01:00
queues . workerQueue . put ( ( " stopThread " , " data " ) )
2015-11-24 01:55:17 +01:00
except :
pass
super ( singleWorker , self ) . stopThread ( )
2013-06-21 23:32:22 +02:00
def run ( self ) :
2017-02-26 20:44:56 +01:00
while not state . sqlReady and state . shutdown == 0 :
self . stop . wait ( 2 )
if state . shutdown > 0 :
return
2015-03-09 07:35:32 +01:00
# Initialize the neededPubkeys dictionary.
2013-08-29 13:27:30 +02:00
queryreturn = sqlQuery (
2014-08-27 09:14:32 +02:00
''' SELECT DISTINCT toaddress FROM sent WHERE (status= ' awaitingpubkey ' AND folder= ' sent ' ) ''' )
2013-06-21 23:32:22 +02:00
for row in queryreturn :
2014-08-27 09:14:32 +02:00
toAddress , = row
toStatus , toAddressVersionNumber , toStreamNumber , toRipe = decodeAddress ( toAddress )
2013-09-13 06:27:34 +02:00
if toAddressVersionNumber < = 3 :
2017-01-14 23:20:15 +01:00
state . neededPubkeys [ toAddress ] = 0
2013-09-13 06:27:34 +02:00
elif toAddressVersionNumber > = 4 :
2013-09-15 03:06:26 +02:00
doubleHashOfAddressData = hashlib . sha512 ( hashlib . sha512 ( encodeVarint (
toAddressVersionNumber ) + encodeVarint ( toStreamNumber ) + toRipe ) . digest ( ) ) . digest ( )
privEncryptionKey = doubleHashOfAddressData [ : 32 ] # Note that this is the first half of the sha512 hash.
tag = doubleHashOfAddressData [ 32 : ]
2017-01-14 23:20:15 +01:00
state . neededPubkeys [ tag ] = ( toAddress , highlevelcrypto . makeCryptor ( hexlify ( privEncryptionKey ) ) ) # We'll need this for when we receive a pubkey reply: it will be encrypted and we'll need to decrypt it.
2013-06-21 23:32:22 +02:00
2014-08-27 09:14:32 +02:00
# Initialize the shared.ackdataForWhichImWatching data structure
2013-08-29 13:27:30 +02:00
queryreturn = sqlQuery (
2016-10-05 20:06:47 +02:00
''' SELECT ackdata FROM sent WHERE status = ' msgsent ' ''' )
2013-06-21 23:32:22 +02:00
for row in queryreturn :
ackdata , = row
2016-03-23 23:26:57 +01:00
logger . info ( ' Watching for ackdata ' + hexlify ( ackdata ) )
2013-06-24 21:51:01 +02:00
shared . ackdataForWhichImWatching [ ackdata ] = 0
2013-06-21 23:32:22 +02:00
2015-11-24 01:55:17 +01:00
self . stop . wait (
2015-03-09 07:35:32 +01:00
10 ) # give some time for the GUI to start before we start on existing POW tasks.
2017-01-14 23:20:15 +01:00
if state . shutdown == 0 :
2016-01-22 14:47:26 +01:00
# just in case there are any pending tasks for msg
# messages that have yet to be sent.
2017-02-08 13:41:56 +01:00
queues . workerQueue . put ( ( ' sendmessage ' , ' ' ) )
2016-01-22 14:47:26 +01:00
# just in case there are any tasks for Broadcasts
# that have yet to be sent.
2017-02-08 13:41:56 +01:00
queues . workerQueue . put ( ( ' sendbroadcast ' , ' ' ) )
2013-06-21 23:32:22 +02:00
2017-01-14 23:20:15 +01:00
while state . shutdown == 0 :
2016-04-20 15:33:01 +02:00
self . busy = 0
2017-02-08 13:41:56 +01:00
command , data = queues . workerQueue . get ( )
2016-04-20 15:33:01 +02:00
self . busy = 1
2013-06-21 23:32:22 +02:00
if command == ' sendmessage ' :
2016-04-17 20:31:25 +02:00
try :
self . sendMsg ( )
except :
pass
2013-06-21 23:32:22 +02:00
elif command == ' sendbroadcast ' :
2016-04-17 20:31:25 +02:00
try :
self . sendBroadcast ( )
except :
pass
2013-06-21 23:32:22 +02:00
elif command == ' doPOWForMyV2Pubkey ' :
2016-04-17 20:31:25 +02:00
try :
self . doPOWForMyV2Pubkey ( data )
except :
pass
2013-07-22 07:10:22 +02:00
elif command == ' sendOutOrStoreMyV3Pubkey ' :
2016-04-17 20:31:25 +02:00
try :
self . sendOutOrStoreMyV3Pubkey ( data )
except :
pass
2013-09-13 06:27:34 +02:00
elif command == ' sendOutOrStoreMyV4Pubkey ' :
2016-04-17 20:31:25 +02:00
try :
self . sendOutOrStoreMyV4Pubkey ( data )
except :
pass
2017-02-28 22:59:44 +01:00
elif command == ' resetPoW ' :
try :
proofofwork . resetPoW ( )
except :
pass
2015-11-24 01:55:17 +01:00
elif command == ' stopThread ' :
2016-04-20 15:33:01 +02:00
self . busy = 0
2015-11-24 01:55:17 +01:00
return
2013-06-21 23:32:22 +02:00
else :
2015-11-18 16:22:17 +01:00
logger . error ( ' Probable programming error: The command sent to the workerThread is weird. It is: %s \n ' % command )
2013-06-29 19:29:35 +02:00
2017-02-08 13:41:56 +01:00
queues . workerQueue . task_done ( )
2016-10-05 20:06:47 +02:00
logger . info ( " Quitting... " )
2013-06-21 23:32:22 +02:00
def doPOWForMyV2Pubkey ( self , hash ) : # This function also broadcasts out the pubkey message once it is done with the POW
# Look up my stream number based on my address hash
2017-05-15 12:18:07 +02:00
""" configSections = shared.config.addresses()
2013-06-21 23:32:22 +02:00
for addressInKeysFile in configSections :
if addressInKeysFile < > ' bitmessagesettings ' :
status , addressVersionNumber , streamNumber , hashFromThisParticularAddress = decodeAddress ( addressInKeysFile )
if hash == hashFromThisParticularAddress :
myAddress = addressInKeysFile
break """
myAddress = shared . myAddressesByHash [ hash ]
status , addressVersionNumber , streamNumber , hash = decodeAddress (
myAddress )
2014-08-27 09:14:32 +02:00
2014-11-13 22:32:31 +01:00
TTL = int ( 28 * 24 * 60 * 60 + random . randrange ( - 300 , 300 ) ) # 28 days from now plus or minus five minutes
embeddedTime = int ( time . time ( ) + TTL )
2014-08-27 09:14:32 +02:00
payload = pack ( ' >Q ' , ( embeddedTime ) )
payload + = ' \x00 \x00 \x00 \x01 ' # object type: pubkey
2013-06-21 23:32:22 +02:00
payload + = encodeVarint ( addressVersionNumber ) # Address version number
payload + = encodeVarint ( streamNumber )
2017-01-11 14:27:19 +01:00
payload + = protocol . getBitfield ( myAddress ) # bitfield of features supported by me (see the wiki).
2013-06-21 23:32:22 +02:00
try :
2017-01-11 14:27:19 +01:00
privSigningKeyBase58 = BMConfigParser ( ) . get (
2013-06-21 23:32:22 +02:00
myAddress , ' privsigningkey ' )
2017-01-11 14:27:19 +01:00
privEncryptionKeyBase58 = BMConfigParser ( ) . get (
2013-06-21 23:32:22 +02:00
myAddress , ' privencryptionkey ' )
except Exception as err :
2015-11-18 16:22:17 +01:00
logger . error ( ' Error within doPOWForMyV2Pubkey. Could not read the keys from the keys.dat file for a requested address. %s \n ' % err )
2013-06-21 23:32:22 +02:00
return
2016-03-23 23:26:57 +01:00
privSigningKeyHex = hexlify ( shared . decodeWalletImportFormat (
privSigningKeyBase58 ) )
privEncryptionKeyHex = hexlify ( shared . decodeWalletImportFormat (
privEncryptionKeyBase58 ) )
pubSigningKey = unhexlify ( highlevelcrypto . privToPub (
privSigningKeyHex ) )
pubEncryptionKey = unhexlify ( highlevelcrypto . privToPub (
privEncryptionKeyHex ) )
2013-06-21 23:32:22 +02:00
payload + = pubSigningKey [ 1 : ]
payload + = pubEncryptionKey [ 1 : ]
# Do the POW for this pubkey message
2017-02-08 20:37:42 +01:00
target = 2 * * 64 / ( defaults . networkDefaultProofOfWorkNonceTrialsPerByte * ( len ( payload ) + 8 + defaults . networkDefaultPayloadLengthExtraBytes + ( ( TTL * ( len ( payload ) + 8 + defaults . networkDefaultPayloadLengthExtraBytes ) ) / ( 2 * * 16 ) ) ) )
2015-11-18 16:22:17 +01:00
logger . info ( ' (For pubkey message) Doing proof of work... ' )
2013-06-21 23:32:22 +02:00
initialHash = hashlib . sha512 ( payload ) . digest ( )
trialValue , nonce = proofofwork . run ( target , initialHash )
2015-11-18 16:22:17 +01:00
logger . info ( ' (For pubkey message) Found proof of work ' + str ( trialValue ) , ' Nonce: ' , str ( nonce ) )
2013-06-21 23:32:22 +02:00
payload = pack ( ' >Q ' , nonce ) + payload
inventoryHash = calculateInventoryHash ( payload )
2014-08-27 09:14:32 +02:00
objectType = 1
2017-01-10 21:15:35 +01:00
Inventory ( ) [ inventoryHash ] = (
2013-09-13 06:27:34 +02:00
objectType , streamNumber , payload , embeddedTime , ' ' )
2017-01-19 19:48:12 +01:00
PendingUpload ( ) . add ( inventoryHash )
2013-06-21 23:32:22 +02:00
2016-03-23 23:26:57 +01:00
logger . info ( ' broadcasting inv with hash: ' + hexlify ( inventoryHash ) )
2013-06-29 19:29:35 +02:00
2017-05-29 03:16:14 +02:00
if BMConfigParser ( ) . get ( " network " , " asyncore " ) :
2017-05-29 00:24:07 +02:00
queues . invQueue . put ( ( streamNumber , inventoryHash ) )
else :
protocol . broadcastToSendDataQueues ( (
streamNumber , ' advertiseobject ' , inventoryHash ) )
2017-02-08 13:41:56 +01:00
queues . UISignalQueue . put ( ( ' updateStatusBar ' , ' ' ) )
2013-11-07 05:38:19 +01:00
try :
2017-01-11 14:27:19 +01:00
BMConfigParser ( ) . set (
2013-11-07 05:38:19 +01:00
myAddress , ' lastpubkeysendtime ' , str ( int ( time . time ( ) ) ) )
2017-01-15 10:50:02 +01:00
BMConfigParser ( ) . save ( )
2013-11-07 05:38:19 +01:00
except :
# The user deleted the address out of the keys.dat file before this
# finished.
pass
2013-06-21 23:32:22 +02:00
2013-07-22 07:10:22 +02:00
# If this isn't a chan address, this function assembles the pubkey data,
# does the necessary POW and sends it out. If it *is* a chan then it
# assembles the pubkey and stores is in the pubkey table so that we can
# send messages to "ourselves".
def sendOutOrStoreMyV3Pubkey ( self , hash ) :
2013-11-07 05:38:19 +01:00
try :
myAddress = shared . myAddressesByHash [ hash ]
except :
#The address has been deleted.
return
2017-01-11 14:27:19 +01:00
if BMConfigParser ( ) . safeGetBoolean ( myAddress , ' chan ' ) :
2015-11-18 16:22:17 +01:00
logger . info ( ' This is a chan address. Not sending pubkey. ' )
2013-09-30 01:24:27 +02:00
return
2013-06-21 23:32:22 +02:00
status , addressVersionNumber , streamNumber , hash = decodeAddress (
myAddress )
2014-08-27 09:14:32 +02:00
2014-11-13 22:32:31 +01:00
TTL = int ( 28 * 24 * 60 * 60 + random . randrange ( - 300 , 300 ) ) # 28 days from now plus or minus five minutes
embeddedTime = int ( time . time ( ) + TTL )
2014-08-27 09:14:32 +02:00
signedTimeForProtocolV2 = embeddedTime - TTL
"""
According to the protocol specification , the expiresTime along with the pubkey information is
signed . But to be backwards compatible during the upgrade period , we shall sign not the
expiresTime but rather the current time . There must be precisely a 28 day difference
between the two . After the upgrade period we ' ll switch to signing the whole payload with the
expiresTime time .
"""
payload = pack ( ' >Q ' , ( embeddedTime ) )
payload + = ' \x00 \x00 \x00 \x01 ' # object type: pubkey
2013-06-21 23:32:22 +02:00
payload + = encodeVarint ( addressVersionNumber ) # Address version number
payload + = encodeVarint ( streamNumber )
2017-01-11 14:27:19 +01:00
payload + = protocol . getBitfield ( myAddress ) # bitfield of features supported by me (see the wiki).
2013-06-21 23:32:22 +02:00
try :
2017-01-11 14:27:19 +01:00
privSigningKeyBase58 = BMConfigParser ( ) . get (
2013-06-21 23:32:22 +02:00
myAddress , ' privsigningkey ' )
2017-01-11 14:27:19 +01:00
privEncryptionKeyBase58 = BMConfigParser ( ) . get (
2013-06-21 23:32:22 +02:00
myAddress , ' privencryptionkey ' )
except Exception as err :
2015-11-18 16:22:17 +01:00
logger . error ( ' Error within sendOutOrStoreMyV3Pubkey. Could not read the keys from the keys.dat file for a requested address. %s \n ' % err )
2013-06-29 19:29:35 +02:00
2013-06-21 23:32:22 +02:00
return
2016-03-23 23:26:57 +01:00
privSigningKeyHex = hexlify ( shared . decodeWalletImportFormat (
privSigningKeyBase58 ) )
privEncryptionKeyHex = hexlify ( shared . decodeWalletImportFormat (
privEncryptionKeyBase58 ) )
pubSigningKey = unhexlify ( highlevelcrypto . privToPub (
privSigningKeyHex ) )
pubEncryptionKey = unhexlify ( highlevelcrypto . privToPub (
privEncryptionKeyHex ) )
2013-06-21 23:32:22 +02:00
payload + = pubSigningKey [ 1 : ]
payload + = pubEncryptionKey [ 1 : ]
2017-01-11 14:27:19 +01:00
payload + = encodeVarint ( BMConfigParser ( ) . getint (
2013-06-21 23:32:22 +02:00
myAddress , ' noncetrialsperbyte ' ) )
2017-01-11 14:27:19 +01:00
payload + = encodeVarint ( BMConfigParser ( ) . getint (
2013-06-21 23:32:22 +02:00
myAddress , ' payloadlengthextrabytes ' ) )
2014-08-27 09:14:32 +02:00
2014-12-25 09:57:34 +01:00
signature = highlevelcrypto . sign ( payload , privSigningKeyHex )
2013-06-21 23:32:22 +02:00
payload + = encodeVarint ( len ( signature ) )
payload + = signature
2013-09-30 01:24:27 +02:00
# Do the POW for this pubkey message
2017-02-08 20:37:42 +01:00
target = 2 * * 64 / ( defaults . networkDefaultProofOfWorkNonceTrialsPerByte * ( len ( payload ) + 8 + defaults . networkDefaultPayloadLengthExtraBytes + ( ( TTL * ( len ( payload ) + 8 + defaults . networkDefaultPayloadLengthExtraBytes ) ) / ( 2 * * 16 ) ) ) )
2015-11-18 16:22:17 +01:00
logger . info ( ' (For pubkey message) Doing proof of work... ' )
2013-09-30 01:24:27 +02:00
initialHash = hashlib . sha512 ( payload ) . digest ( )
trialValue , nonce = proofofwork . run ( target , initialHash )
2015-11-18 16:22:17 +01:00
logger . info ( ' (For pubkey message) Found proof of work. Nonce: ' + str ( nonce ) )
2013-06-21 23:32:22 +02:00
2013-09-30 01:24:27 +02:00
payload = pack ( ' >Q ' , nonce ) + payload
inventoryHash = calculateInventoryHash ( payload )
2014-08-27 09:14:32 +02:00
objectType = 1
2017-01-10 21:15:35 +01:00
Inventory ( ) [ inventoryHash ] = (
2013-09-30 01:24:27 +02:00
objectType , streamNumber , payload , embeddedTime , ' ' )
2017-01-19 19:48:12 +01:00
PendingUpload ( ) . add ( inventoryHash )
2013-06-21 23:32:22 +02:00
2016-03-23 23:26:57 +01:00
logger . info ( ' broadcasting inv with hash: ' + hexlify ( inventoryHash ) )
2013-06-29 19:29:35 +02:00
2017-05-29 03:16:14 +02:00
if BMConfigParser ( ) . get ( " network " , " asyncore " ) :
2017-05-29 00:24:07 +02:00
queues . invQueue . put ( ( streamNumber , inventoryHash ) )
else :
protocol . broadcastToSendDataQueues ( (
streamNumber , ' advertiseobject ' , inventoryHash ) )
2017-02-08 13:41:56 +01:00
queues . UISignalQueue . put ( ( ' updateStatusBar ' , ' ' ) )
2013-11-07 05:38:19 +01:00
try :
2017-01-11 14:27:19 +01:00
BMConfigParser ( ) . set (
2013-11-07 05:38:19 +01:00
myAddress , ' lastpubkeysendtime ' , str ( int ( time . time ( ) ) ) )
2017-01-15 10:50:02 +01:00
BMConfigParser ( ) . save ( )
2013-11-07 05:38:19 +01:00
except :
# The user deleted the address out of the keys.dat file before this
# finished.
pass
2013-06-21 23:32:22 +02:00
2013-09-13 06:27:34 +02:00
# If this isn't a chan address, this function assembles the pubkey data,
2013-09-30 01:24:27 +02:00
# does the necessary POW and sends it out.
2013-09-13 06:27:34 +02:00
def sendOutOrStoreMyV4Pubkey ( self , myAddress ) :
2017-01-11 14:27:19 +01:00
if not BMConfigParser ( ) . has_section ( myAddress ) :
2013-11-07 05:38:19 +01:00
#The address has been deleted.
return
2017-01-11 14:27:19 +01:00
if shared . BMConfigParser ( ) . safeGetBoolean ( myAddress , ' chan ' ) :
2015-11-18 16:22:17 +01:00
logger . info ( ' This is a chan address. Not sending pubkey. ' )
2013-09-30 01:24:27 +02:00
return
2013-09-13 06:27:34 +02:00
status , addressVersionNumber , streamNumber , hash = decodeAddress (
myAddress )
2014-08-27 09:14:32 +02:00
2014-11-13 22:32:31 +01:00
TTL = int ( 28 * 24 * 60 * 60 + random . randrange ( - 300 , 300 ) ) # 28 days from now plus or minus five minutes
embeddedTime = int ( time . time ( ) + TTL )
2013-09-13 06:27:34 +02:00
payload = pack ( ' >Q ' , ( embeddedTime ) )
2014-08-27 09:14:32 +02:00
payload + = ' \x00 \x00 \x00 \x01 ' # object type: pubkey
2013-09-13 06:27:34 +02:00
payload + = encodeVarint ( addressVersionNumber ) # Address version number
payload + = encodeVarint ( streamNumber )
2017-01-11 14:27:19 +01:00
dataToEncrypt = protocol . getBitfield ( myAddress )
2013-09-13 06:27:34 +02:00
try :
2017-01-11 14:27:19 +01:00
privSigningKeyBase58 = BMConfigParser ( ) . get (
2013-09-13 06:27:34 +02:00
myAddress , ' privsigningkey ' )
2017-01-11 14:27:19 +01:00
privEncryptionKeyBase58 = BMConfigParser ( ) . get (
2013-09-13 06:27:34 +02:00
myAddress , ' privencryptionkey ' )
except Exception as err :
2015-11-18 16:22:17 +01:00
logger . error ( ' Error within sendOutOrStoreMyV4Pubkey. Could not read the keys from the keys.dat file for a requested address. %s \n ' % err )
2013-09-13 06:27:34 +02:00
return
2016-03-23 23:26:57 +01:00
privSigningKeyHex = hexlify ( shared . decodeWalletImportFormat (
privSigningKeyBase58 ) )
privEncryptionKeyHex = hexlify ( shared . decodeWalletImportFormat (
privEncryptionKeyBase58 ) )
pubSigningKey = unhexlify ( highlevelcrypto . privToPub (
privSigningKeyHex ) )
pubEncryptionKey = unhexlify ( highlevelcrypto . privToPub (
privEncryptionKeyHex ) )
2013-09-13 06:27:34 +02:00
dataToEncrypt + = pubSigningKey [ 1 : ]
dataToEncrypt + = pubEncryptionKey [ 1 : ]
2017-01-11 14:27:19 +01:00
dataToEncrypt + = encodeVarint ( BMConfigParser ( ) . getint (
2013-09-13 06:27:34 +02:00
myAddress , ' noncetrialsperbyte ' ) )
2017-01-11 14:27:19 +01:00
dataToEncrypt + = encodeVarint ( BMConfigParser ( ) . getint (
2013-09-13 06:27:34 +02:00
myAddress , ' payloadlengthextrabytes ' ) )
2014-08-27 09:14:32 +02:00
# When we encrypt, we'll use a hash of the data
2013-09-30 01:24:27 +02:00
# contained in an address as a decryption key. This way in order to
# read the public keys in a pubkey message, a node must know the address
# first. We'll also tag, unencrypted, the pubkey with part of the hash
# so that nodes know which pubkey object to try to decrypt when they
# want to send a message.
doubleHashOfAddressData = hashlib . sha512 ( hashlib . sha512 ( encodeVarint (
addressVersionNumber ) + encodeVarint ( streamNumber ) + hash ) . digest ( ) ) . digest ( )
payload + = doubleHashOfAddressData [ 32 : ] # the tag
2014-12-25 09:57:34 +01:00
signature = highlevelcrypto . sign ( payload + dataToEncrypt , privSigningKeyHex )
2014-08-27 09:14:32 +02:00
dataToEncrypt + = encodeVarint ( len ( signature ) )
dataToEncrypt + = signature
2013-09-30 01:24:27 +02:00
privEncryptionKey = doubleHashOfAddressData [ : 32 ]
2014-05-21 12:15:07 +02:00
pubEncryptionKey = highlevelcrypto . pointMult ( privEncryptionKey )
2013-09-30 01:24:27 +02:00
payload + = highlevelcrypto . encrypt (
2016-03-23 23:26:57 +01:00
dataToEncrypt , hexlify ( pubEncryptionKey ) )
2013-09-18 06:04:01 +02:00
2013-09-30 01:24:27 +02:00
# Do the POW for this pubkey message
2017-02-08 20:37:42 +01:00
target = 2 * * 64 / ( defaults . networkDefaultProofOfWorkNonceTrialsPerByte * ( len ( payload ) + 8 + defaults . networkDefaultPayloadLengthExtraBytes + ( ( TTL * ( len ( payload ) + 8 + defaults . networkDefaultPayloadLengthExtraBytes ) ) / ( 2 * * 16 ) ) ) )
2015-11-18 16:22:17 +01:00
logger . info ( ' (For pubkey message) Doing proof of work... ' )
2013-09-30 01:24:27 +02:00
initialHash = hashlib . sha512 ( payload ) . digest ( )
trialValue , nonce = proofofwork . run ( target , initialHash )
2015-11-18 16:22:17 +01:00
logger . info ( ' (For pubkey message) Found proof of work ' + str ( trialValue ) + ' Nonce: ' + str ( nonce ) )
2013-09-13 06:27:34 +02:00
2013-09-30 01:24:27 +02:00
payload = pack ( ' >Q ' , nonce ) + payload
inventoryHash = calculateInventoryHash ( payload )
2014-08-27 09:14:32 +02:00
objectType = 1
2017-01-10 21:15:35 +01:00
Inventory ( ) [ inventoryHash ] = (
2013-09-30 01:24:27 +02:00
objectType , streamNumber , payload , embeddedTime , doubleHashOfAddressData [ 32 : ] )
2017-01-19 19:48:12 +01:00
PendingUpload ( ) . add ( inventoryHash )
2013-09-13 06:27:34 +02:00
2016-03-23 23:26:57 +01:00
logger . info ( ' broadcasting inv with hash: ' + hexlify ( inventoryHash ) )
2013-09-18 06:04:01 +02:00
2017-05-29 03:16:14 +02:00
if BMConfigParser ( ) . get ( " network " , " asyncore " ) :
2017-05-29 00:24:07 +02:00
queues . invQueue . put ( ( streamNumber , inventoryHash ) )
else :
protocol . broadcastToSendDataQueues ( (
streamNumber , ' advertiseobject ' , inventoryHash ) )
2017-02-08 13:41:56 +01:00
queues . UISignalQueue . put ( ( ' updateStatusBar ' , ' ' ) )
2013-10-26 01:35:59 +02:00
try :
2017-01-11 14:27:19 +01:00
BMConfigParser ( ) . set (
2013-10-26 01:35:59 +02:00
myAddress , ' lastpubkeysendtime ' , str ( int ( time . time ( ) ) ) )
2017-01-15 10:50:02 +01:00
BMConfigParser ( ) . save ( )
2013-12-06 07:52:19 +01:00
except Exception as err :
logger . error ( ' Error: Couldn \' t add the lastpubkeysendtime to the keys.dat file. Error message: %s ' % err )
2013-09-13 06:27:34 +02:00
2013-06-21 23:32:22 +02:00
def sendBroadcast ( self ) :
2016-10-05 20:06:47 +02:00
# Reset just in case
sqlExecute (
''' UPDATE sent SET status= ' broadcastqueued ' WHERE status = ' doingbroadcastpow ' ''' )
2013-08-29 13:27:30 +02:00
queryreturn = sqlQuery (
2016-11-14 20:23:58 +01:00
''' SELECT fromaddress, subject, message, ackdata, ttl, encodingtype FROM sent WHERE status=? and folder= ' sent ' ''' , ' broadcastqueued ' )
2016-10-05 20:06:47 +02:00
2013-06-21 23:32:22 +02:00
for row in queryreturn :
2016-11-14 20:23:58 +01:00
fromaddress , subject , body , ackdata , TTL , encoding = row
2013-06-21 23:32:22 +02:00
status , addressVersionNumber , streamNumber , ripe = decodeAddress (
fromaddress )
2013-07-31 18:36:51 +02:00
if addressVersionNumber < = 1 :
2015-11-18 16:22:17 +01:00
logger . error ( ' Error: In the singleWorker thread, the sendBroadcast function doesn \' t understand the address version. \n ' )
2013-07-31 18:36:51 +02:00
return
# We need to convert our private keys to public keys in order
# to include them.
try :
2017-01-11 14:27:19 +01:00
privSigningKeyBase58 = BMConfigParser ( ) . get (
2013-07-31 18:36:51 +02:00
fromaddress , ' privsigningkey ' )
2017-01-11 14:27:19 +01:00
privEncryptionKeyBase58 = BMConfigParser ( ) . get (
2013-07-31 18:36:51 +02:00
fromaddress , ' privencryptionkey ' )
except :
2017-02-08 13:41:56 +01:00
queues . UISignalQueue . put ( ( ' updateSentItemStatusByAckdata ' , (
2016-04-30 11:07:27 +02:00
ackdata , tr . _translate ( " MainWindow " , " Error! Could not find sender address (your address) in the keys.dat file. " ) ) ) )
2013-07-31 18:36:51 +02:00
continue
2016-10-05 20:06:47 +02:00
sqlExecute (
''' UPDATE sent SET status= ' doingbroadcastpow ' WHERE ackdata=? AND status= ' broadcastqueued ' ''' ,
ackdata )
2016-03-23 23:26:57 +01:00
privSigningKeyHex = hexlify ( shared . decodeWalletImportFormat (
privSigningKeyBase58 ) )
privEncryptionKeyHex = hexlify ( shared . decodeWalletImportFormat (
privEncryptionKeyBase58 ) )
2013-07-31 18:36:51 +02:00
pubSigningKey = highlevelcrypto . privToPub ( privSigningKeyHex ) . decode (
' hex ' ) # At this time these pubkeys are 65 bytes long because they include the encoding byte which we won't be sending in the broadcast message.
2016-03-23 23:26:57 +01:00
pubEncryptionKey = unhexlify ( highlevelcrypto . privToPub (
privEncryptionKeyHex ) )
2013-07-31 18:36:51 +02:00
2015-03-09 07:35:32 +01:00
if TTL > 28 * 24 * 60 * 60 :
TTL = 28 * 24 * 60 * 60
if TTL < 60 * 60 :
TTL = 60 * 60
TTL = int ( TTL + random . randrange ( - 300 , 300 ) ) # add some randomness to the TTL
2014-11-13 22:32:31 +01:00
embeddedTime = int ( time . time ( ) + TTL )
2014-08-27 09:14:32 +02:00
payload = pack ( ' >Q ' , embeddedTime )
payload + = ' \x00 \x00 \x00 \x03 ' # object type: broadcast
2014-12-25 09:57:34 +01:00
if addressVersionNumber < = 3 :
payload + = encodeVarint ( 4 ) # broadcast version
else :
payload + = encodeVarint ( 5 ) # broadcast version
2014-08-27 09:14:32 +02:00
2013-07-31 18:36:51 +02:00
payload + = encodeVarint ( streamNumber )
2013-09-15 03:06:26 +02:00
if addressVersionNumber > = 4 :
doubleHashOfAddressData = hashlib . sha512 ( hashlib . sha512 ( encodeVarint (
addressVersionNumber ) + encodeVarint ( streamNumber ) + ripe ) . digest ( ) ) . digest ( )
2013-12-01 06:45:37 +01:00
tag = doubleHashOfAddressData [ 32 : ]
payload + = tag
else :
tag = ' '
2013-07-31 18:36:51 +02:00
2014-12-25 09:57:34 +01:00
dataToEncrypt = encodeVarint ( addressVersionNumber )
2013-07-31 18:36:51 +02:00
dataToEncrypt + = encodeVarint ( streamNumber )
2017-01-11 14:27:19 +01:00
dataToEncrypt + = protocol . getBitfield ( fromaddress ) # behavior bitfield
2013-07-31 18:36:51 +02:00
dataToEncrypt + = pubSigningKey [ 1 : ]
dataToEncrypt + = pubEncryptionKey [ 1 : ]
if addressVersionNumber > = 3 :
2017-01-11 14:27:19 +01:00
dataToEncrypt + = encodeVarint ( BMConfigParser ( ) . getint ( fromaddress , ' noncetrialsperbyte ' ) )
dataToEncrypt + = encodeVarint ( BMConfigParser ( ) . getint ( fromaddress , ' payloadlengthextrabytes ' ) )
2016-11-14 20:23:58 +01:00
dataToEncrypt + = encodeVarint ( encoding ) # message encoding type
encodedMessage = helper_msgcoding . MsgEncode ( { " subject " : subject , " body " : body } , encoding )
dataToEncrypt + = encodeVarint ( encodedMessage . length )
dataToEncrypt + = encodedMessage . data
2014-12-25 09:57:34 +01:00
dataToSign = payload + dataToEncrypt
2014-08-27 09:14:32 +02:00
2013-07-31 18:36:51 +02:00
signature = highlevelcrypto . sign (
2014-08-27 09:14:32 +02:00
dataToSign , privSigningKeyHex )
2013-07-31 18:36:51 +02:00
dataToEncrypt + = encodeVarint ( len ( signature ) )
dataToEncrypt + = signature
2014-11-13 22:32:31 +01:00
# Encrypt the broadcast with the information contained in the broadcaster's address.
# Anyone who knows the address can generate the private encryption key to decrypt
# the broadcast. This provides virtually no privacy; its purpose is to keep
# questionable and illegal content from flowing through the Internet connections
# and being stored on the disk of 3rd parties.
2013-09-15 03:06:26 +02:00
if addressVersionNumber < = 3 :
privEncryptionKey = hashlib . sha512 ( encodeVarint (
addressVersionNumber ) + encodeVarint ( streamNumber ) + ripe ) . digest ( ) [ : 32 ]
else :
privEncryptionKey = doubleHashOfAddressData [ : 32 ]
2013-12-01 06:45:37 +01:00
2014-05-21 12:15:07 +02:00
pubEncryptionKey = highlevelcrypto . pointMult ( privEncryptionKey )
2013-07-31 18:36:51 +02:00
payload + = highlevelcrypto . encrypt (
2016-03-23 23:26:57 +01:00
dataToEncrypt , hexlify ( pubEncryptionKey ) )
2013-07-31 18:36:51 +02:00
2017-02-08 20:37:42 +01:00
target = 2 * * 64 / ( defaults . networkDefaultProofOfWorkNonceTrialsPerByte * ( len ( payload ) + 8 + defaults . networkDefaultPayloadLengthExtraBytes + ( ( TTL * ( len ( payload ) + 8 + defaults . networkDefaultPayloadLengthExtraBytes ) ) / ( 2 * * 16 ) ) ) )
2015-11-18 16:22:17 +01:00
logger . info ( ' (For broadcast message) Doing proof of work... ' )
2017-02-08 13:41:56 +01:00
queues . UISignalQueue . put ( ( ' updateSentItemStatusByAckdata ' , (
2016-04-30 11:07:27 +02:00
ackdata , tr . _translate ( " MainWindow " , " Doing work necessary to send broadcast... " ) ) ) )
2013-07-31 18:36:51 +02:00
initialHash = hashlib . sha512 ( payload ) . digest ( )
trialValue , nonce = proofofwork . run ( target , initialHash )
2015-11-18 16:22:17 +01:00
logger . info ( ' (For broadcast message) Found proof of work ' + str ( trialValue ) + ' Nonce: ' + str ( nonce ) )
2013-07-31 18:36:51 +02:00
payload = pack ( ' >Q ' , nonce ) + payload
2014-08-27 09:14:32 +02:00
# Sanity check. The payload size should never be larger than 256 KiB. There should
# be checks elsewhere in the code to not let the user try to send a message this large
# until we implement message continuation.
if len ( payload ) > 2 * * 18 : # 256 KiB
logger . critical ( ' This broadcast object is too large to send. This should never happen. Object size: %s ' % len ( payload ) )
continue
2013-06-29 19:29:35 +02:00
2013-07-31 18:36:51 +02:00
inventoryHash = calculateInventoryHash ( payload )
2014-08-27 09:14:32 +02:00
objectType = 3
2017-01-10 21:15:35 +01:00
Inventory ( ) [ inventoryHash ] = (
2014-08-27 09:14:32 +02:00
objectType , streamNumber , payload , embeddedTime , tag )
2017-01-19 19:48:12 +01:00
PendingUpload ( ) . add ( inventoryHash )
2016-03-23 23:26:57 +01:00
logger . info ( ' sending inv (within sendBroadcast function) for object: ' + hexlify ( inventoryHash ) )
2017-05-29 03:16:14 +02:00
if BMConfigParser ( ) . get ( " network " , " asyncore " ) :
2017-05-29 00:24:07 +02:00
queues . invQueue . put ( ( streamNumber , inventoryHash ) )
else :
protocol . broadcastToSendDataQueues ( (
streamNumber , ' advertiseobject ' , inventoryHash ) )
2013-07-31 18:36:51 +02:00
2017-02-08 13:41:56 +01:00
queues . UISignalQueue . put ( ( ' updateSentItemStatusByAckdata ' , ( ackdata , tr . _translate ( " MainWindow " , " Broadcast sent on % 1 " ) . arg ( l10n . formatTimestamp ( ) ) ) ) )
2013-07-31 18:36:51 +02:00
# Update the status of the message in the 'sent' table to have
# a 'broadcastsent' status
2013-08-29 13:27:30 +02:00
sqlExecute (
' UPDATE sent SET msgid=?, status=?, lastactiontime=? WHERE ackdata=? ' ,
inventoryHash ,
' broadcastsent ' ,
int ( time . time ( ) ) ,
ackdata )
2013-07-31 18:36:51 +02:00
2013-06-21 23:32:22 +02:00
def sendMsg ( self ) :
2016-10-05 20:06:47 +02:00
# Reset just in case
sqlExecute (
''' UPDATE sent SET status= ' msgqueued ' WHERE status IN ( ' doingpubkeypow ' , ' doingmsgpow ' ) ''' )
queryreturn = sqlQuery (
2016-11-14 20:23:58 +01:00
''' SELECT toaddress, fromaddress, subject, message, ackdata, status, ttl, retrynumber, encodingtype FROM sent WHERE (status= ' msgqueued ' or status= ' forcepow ' ) and folder= ' sent ' ''' )
2016-10-05 20:06:47 +02:00
for row in queryreturn : # while we have a msg that needs some work
2016-11-14 20:23:58 +01:00
toaddress , fromaddress , subject , message , ackdata , status , TTL , retryNumber , encoding = row
2014-08-27 09:14:32 +02:00
toStatus , toAddressVersionNumber , toStreamNumber , toRipe = decodeAddress (
toaddress )
fromStatus , fromAddressVersionNumber , fromStreamNumber , fromRipe = decodeAddress (
fromaddress )
# We may or may not already have the pubkey for this toAddress. Let's check.
if status == ' forcepow ' :
# if the status of this msg is 'forcepow' then clearly we have the pubkey already
# because the user could not have overridden the message about the POW being
# too difficult without knowing the required difficulty.
pass
2015-03-09 07:35:32 +01:00
elif status == ' doingmsgpow ' :
# We wouldn't have set the status to doingmsgpow if we didn't already have the pubkey
# so let's assume that we have it.
pass
2014-08-27 09:14:32 +02:00
# If we are sending a message to ourselves or a chan then we won't need an entry in the pubkeys table; we can calculate the needed pubkey using the private keys in our keys.dat file.
2017-01-11 14:27:19 +01:00
elif BMConfigParser ( ) . has_section ( toaddress ) :
2013-08-29 13:27:30 +02:00
sqlExecute (
''' UPDATE sent SET status= ' doingmsgpow ' WHERE toaddress=? AND status= ' msgqueued ' ''' ,
toaddress )
2014-08-27 09:14:32 +02:00
status = ' doingmsgpow '
2015-03-09 07:35:32 +01:00
elif status == ' msgqueued ' :