2015-01-21 18:38:25 +01:00
|
|
|
from __future__ import division
|
|
|
|
|
2013-06-21 23:32:22 +02:00
|
|
|
import time
|
2017-09-21 17:24:51 +02:00
|
|
|
import threading
|
|
|
|
import hashlib
|
|
|
|
from struct import pack
|
|
|
|
# used when the API must execute an outside program
|
|
|
|
from subprocess import call
|
|
|
|
from binascii import hexlify, unhexlify
|
|
|
|
|
2013-06-24 21:51:01 +02:00
|
|
|
import tr
|
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
|
2017-09-21 17:24:51 +02:00
|
|
|
import shared
|
|
|
|
import defaults
|
|
|
|
import highlevelcrypto
|
|
|
|
import proofofwork
|
|
|
|
import helper_inbox
|
2018-03-21 12:52:23 +01:00
|
|
|
import helper_random
|
2017-09-21 17:24:51 +02:00
|
|
|
import helper_msgcoding
|
|
|
|
from bmconfigparser import BMConfigParser
|
|
|
|
from debug import logger
|
|
|
|
from inventory import Inventory
|
|
|
|
from addresses import (
|
|
|
|
decodeAddress, encodeVarint, decodeVarint, calculateInventoryHash
|
|
|
|
)
|
|
|
|
# from helper_generic import addDataPadding
|
|
|
|
from helper_threading import StoppableThread
|
|
|
|
from helper_sql import sqlQuery, sqlExecute
|
|
|
|
|
2013-06-21 23:32:22 +02:00
|
|
|
|
|
|
|
# This thread, of which there is only one, does the heavy lifting:
|
|
|
|
# calculating POWs.
|
|
|
|
|
2017-09-21 17:24:51 +02:00
|
|
|
|
2015-11-26 02:38:55 +01:00
|
|
|
def sizeof_fmt(num, suffix='h/s'):
|
2017-09-21 17:24:51 +02:00
|
|
|
for unit in ['', 'k', 'M', 'G', 'T', 'P', 'E', 'Z']:
|
2015-11-26 02:38:55 +01:00
|
|
|
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
|
|
|
|
2017-09-21 17:24:51 +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()
|
2017-08-15 12:24:43 +02:00
|
|
|
proofofwork.init()
|
2015-11-24 01:55:17 +01:00
|
|
|
|
|
|
|
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
|
2017-09-21 17:24:51 +02:00
|
|
|
|
2015-03-09 07:35:32 +01:00
|
|
|
# Initialize the neededPubkeys dictionary.
|
2013-08-29 13:27:30 +02:00
|
|
|
queryreturn = sqlQuery(
|
2017-09-21 17:24:51 +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
|
2017-09-21 17:24:51 +02:00
|
|
|
toStatus, toAddressVersionNumber, toStreamNumber, toRipe = \
|
|
|
|
decodeAddress(toAddress)
|
|
|
|
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:
|
2017-09-21 17:24:51 +02:00
|
|
|
doubleHashOfAddressData = hashlib.sha512(hashlib.sha512(
|
|
|
|
encodeVarint(toAddressVersionNumber) +
|
|
|
|
encodeVarint(toStreamNumber) + toRipe
|
|
|
|
).digest()).digest()
|
|
|
|
# Note that this is the first half of the sha512 hash.
|
|
|
|
privEncryptionKey = doubleHashOfAddressData[:32]
|
2013-09-15 03:06:26 +02:00
|
|
|
tag = doubleHashOfAddressData[32:]
|
2017-09-21 17:24:51 +02:00
|
|
|
# We'll need this for when we receive a pubkey reply:
|
|
|
|
# it will be encrypted and we'll need to decrypt it.
|
|
|
|
state.neededPubkeys[tag] = (
|
|
|
|
toAddress,
|
|
|
|
highlevelcrypto.makeCryptor(
|
|
|
|
hexlify(privEncryptionKey))
|
|
|
|
)
|
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
|
|
|
|
2017-09-30 11:19:44 +02:00
|
|
|
# Fix legacy (headerless) watched ackdata to include header
|
|
|
|
for oldack in shared.ackdataForWhichImWatching.keys():
|
2017-09-21 17:24:51 +02:00
|
|
|
if (len(oldack) == 32):
|
2017-09-30 11:19:44 +02:00
|
|
|
# attach legacy header, always constant (msg/1/1)
|
|
|
|
newack = '\x00\x00\x00\x02\x01\x01' + oldack
|
|
|
|
shared.ackdataForWhichImWatching[newack] = 0
|
2017-09-21 17:24:51 +02:00
|
|
|
sqlExecute(
|
|
|
|
'UPDATE sent SET ackdata=? WHERE ackdata=?',
|
|
|
|
newack, oldack
|
|
|
|
)
|
2017-09-30 11:19:44 +02:00
|
|
|
del shared.ackdataForWhichImWatching[oldack]
|
|
|
|
|
2017-09-21 17:24:51 +02:00
|
|
|
# give some time for the GUI to start
|
|
|
|
# before we start on existing POW tasks.
|
|
|
|
self.stop.wait(10)
|
2015-03-09 07:35:32 +01:00
|
|
|
|
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:
|
2017-09-21 17:24:51 +02: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
|
|
|
|
2017-09-21 17:24:51 +02:00
|
|
|
# This function also broadcasts out the pubkey message
|
|
|
|
# once it is done with the POW
|
|
|
|
def doPOWForMyV2Pubkey(self, hash):
|
2013-06-21 23:32:22 +02:00
|
|
|
# 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:
|
2017-09-21 17:24:51 +02:00
|
|
|
if addressInKeysFile != 'bitmessagesettings':
|
|
|
|
status, addressVersionNumber, streamNumber, \
|
|
|
|
hashFromThisParticularAddress = \
|
|
|
|
decodeAddress(addressInKeysFile)
|
2013-06-21 23:32:22 +02:00
|
|
|
if hash == hashFromThisParticularAddress:
|
|
|
|
myAddress = addressInKeysFile
|
|
|
|
break"""
|
|
|
|
myAddress = shared.myAddressesByHash[hash]
|
|
|
|
status, addressVersionNumber, streamNumber, hash = decodeAddress(
|
|
|
|
myAddress)
|
2018-03-21 12:52:23 +01:00
|
|
|
|
2017-09-21 17:24:51 +02:00
|
|
|
# 28 days from now plus or minus five minutes
|
|
|
|
TTL = int(28 * 24 * 60 * 60 + helper_random.randomrandrange(-300, 300))
|
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))
|
2017-09-21 17:24:51 +02:00
|
|
|
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-09-21 17:24:51 +02:00
|
|
|
# bitfield of features supported by me (see the wiki).
|
|
|
|
payload += protocol.getBitfield(myAddress)
|
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:
|
2017-09-21 17:24:51 +02: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-09-21 17:24:51 +02: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)
|
2017-09-21 17:24:51 +02:00
|
|
|
logger.info(
|
|
|
|
'(For pubkey message) Found proof of work %s Nonce: %s',
|
|
|
|
trialValue, 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] = (
|
2017-09-21 17:24:51 +02:00
|
|
|
objectType, streamNumber, payload, embeddedTime, '')
|
2013-06-21 23:32:22 +02:00
|
|
|
|
2017-09-21 17:24:51 +02:00
|
|
|
logger.info('broadcasting inv with hash: %s', hexlify(inventoryHash))
|
2013-06-29 19:29:35 +02:00
|
|
|
|
2017-08-09 17:36:52 +02:00
|
|
|
queues.invQueue.put((streamNumber, 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:
|
2017-09-21 17:24:51 +02:00
|
|
|
# The user deleted the address out of the keys.dat file
|
|
|
|
# before this finished.
|
2013-11-07 05:38:19 +01:00
|
|
|
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".
|
2017-09-21 17:24:51 +02:00
|
|
|
def sendOutOrStoreMyV3Pubkey(self, hash):
|
2013-11-07 05:38:19 +01:00
|
|
|
try:
|
|
|
|
myAddress = shared.myAddressesByHash[hash]
|
|
|
|
except:
|
2017-09-21 17:24:51 +02:00
|
|
|
# The address has been deleted.
|
2013-11-07 05:38:19 +01:00
|
|
|
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)
|
2018-03-21 12:52:23 +01:00
|
|
|
|
|
|
|
# 28 days from now plus or minus five minutes
|
2017-09-21 17:24:51 +02:00
|
|
|
TTL = int(28 * 24 * 60 * 60 + helper_random.randomrandrange(-300, 300))
|
2014-11-13 22:32:31 +01:00
|
|
|
embeddedTime = int(time.time() + TTL)
|
2017-09-21 17:24:51 +02:00
|
|
|
# signedTimeForProtocolV2 = embeddedTime - TTL
|
2014-08-27 09:14:32 +02:00
|
|
|
"""
|
2017-09-21 17:24:51 +02:00
|
|
|
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
|
2014-08-27 09:14:32 +02:00
|
|
|
expiresTime time.
|
|
|
|
"""
|
|
|
|
payload = pack('>Q', (embeddedTime))
|
2017-09-21 17:24:51 +02:00
|
|
|
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-09-21 17:24:51 +02:00
|
|
|
# bitfield of features supported by me (see the wiki).
|
|
|
|
payload += protocol.getBitfield(myAddress)
|
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:
|
2017-09-21 17:24:51 +02: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-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'))
|
2017-09-21 17:24:51 +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-09-21 17:24:51 +02: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)
|
2017-09-21 17:24:51 +02:00
|
|
|
logger.info(
|
|
|
|
'(For pubkey message) Found proof of work. Nonce: %s',
|
|
|
|
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] = (
|
2017-09-21 17:24:51 +02:00
|
|
|
objectType, streamNumber, payload, embeddedTime, '')
|
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-08-09 17:36:52 +02:00
|
|
|
queues.invQueue.put((streamNumber, 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
|
|
|
|
2017-09-21 17:24:51 +02:00
|
|
|
# If this isn't a chan address, this function assembles
|
|
|
|
# the pubkey data, 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):
|
2017-09-21 17:24:51 +02:00
|
|
|
# The address has been deleted.
|
2013-11-07 05:38:19 +01:00
|
|
|
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)
|
2017-09-21 17:24:51 +02:00
|
|
|
|
2018-03-21 12:52:23 +01:00
|
|
|
# 28 days from now plus or minus five minutes
|
2017-09-21 17:24:51 +02:00
|
|
|
TTL = int(28 * 24 * 60 * 60 + helper_random.randomrandrange(-300, 300))
|
2014-11-13 22:32:31 +01:00
|
|
|
embeddedTime = int(time.time() + TTL)
|
2013-09-13 06:27:34 +02:00
|
|
|
payload = pack('>Q', (embeddedTime))
|
2017-09-21 17:24:51 +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:
|
2017-09-21 17:24:51 +02: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'))
|
2017-09-21 17:24:51 +02:00
|
|
|
|
2014-08-27 09:14:32 +02:00
|
|
|
# When we encrypt, we'll use a hash of the data
|
2017-09-21 17:24:51 +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
|
|
|
|
signature = highlevelcrypto.sign(
|
|
|
|
payload + dataToEncrypt, privSigningKeyHex
|
|
|
|
)
|
2014-08-27 09:14:32 +02:00
|
|
|
dataToEncrypt += encodeVarint(len(signature))
|
|
|
|
dataToEncrypt += signature
|
2017-09-21 17:24:51 +02:00
|
|
|
|
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-09-21 17:24:51 +02: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)
|
2017-09-21 17:24:51 +02:00
|
|
|
logger.info(
|
|
|
|
'(For pubkey message) Found proof of work %s Nonce: %s',
|
|
|
|
trialValue, 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] = (
|
2017-09-21 17:24:51 +02:00
|
|
|
objectType, streamNumber, payload, embeddedTime,
|
|
|
|
doubleHashOfAddressData[32:]
|
|
|
|
)
|
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-08-09 17:36:52 +02:00
|
|
|
queues.invQueue.put((streamNumber, 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:
|
2017-09-21 17:24:51 +02:00
|
|
|
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(
|
2017-09-21 17:24:51 +02:00
|
|
|
'''UPDATE sent SET status='broadcastqueued' '''
|
|
|
|
'''WHERE status = 'doingbroadcastpow' ''')
|
2013-08-29 13:27:30 +02:00
|
|
|
queryreturn = sqlQuery(
|
2017-09-21 17:24:51 +02: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
|
2017-09-21 17:24:51 +02:00
|
|
|
status, addressVersionNumber, streamNumber, ripe = \
|
|
|
|
decodeAddress(fromaddress)
|
2013-07-31 18:36:51 +02:00
|
|
|
if addressVersionNumber <= 1:
|
2017-09-21 17:24:51 +02: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-09-21 17:24:51 +02:00
|
|
|
queues.UISignalQueue.put((
|
|
|
|
'updateSentItemStatusByAckdata', (
|
|
|
|
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(
|
2017-09-21 17:24:51 +02:00
|
|
|
'''UPDATE sent SET status='doingbroadcastpow' '''
|
|
|
|
''' WHERE ackdata=? AND status='broadcastqueued' ''',
|
2016-10-05 20:06:47 +02:00
|
|
|
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
|
|
|
|
2017-09-21 17:24:51 +02:00
|
|
|
# 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.
|
|
|
|
pubSigningKey = \
|
|
|
|
highlevelcrypto.privToPub(privSigningKeyHex).decode('hex')
|
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
|
2017-09-21 17:24:51 +02:00
|
|
|
if TTL < 60 * 60:
|
|
|
|
TTL = 60 * 60
|
2018-03-21 12:52:23 +01:00
|
|
|
# add some randomness to the TTL
|
2017-09-21 17:24:51 +02:00
|
|
|
TTL = int(TTL + helper_random.randomrandrange(-300, 300))
|
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)
|
2017-09-21 17:24:51 +02:00
|
|
|
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
|
2017-09-21 17:24:51 +02:00
|
|
|
|
2013-07-31 18:36:51 +02:00
|
|
|
payload += encodeVarint(streamNumber)
|
2013-09-15 03:06:26 +02:00
|
|
|
if addressVersionNumber >= 4:
|
2017-09-21 17:24:51 +02:00
|
|
|
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-09-21 17:24:51 +02:00
|
|
|
# behavior bitfield
|
|
|
|
dataToEncrypt += protocol.getBitfield(fromaddress)
|
2013-07-31 18:36:51 +02:00
|
|
|
dataToEncrypt += pubSigningKey[1:]
|
|
|
|
dataToEncrypt += pubEncryptionKey[1:]
|
|
|
|
if addressVersionNumber >= 3:
|
2017-09-21 17:24:51 +02:00
|
|
|
dataToEncrypt += encodeVarint(BMConfigParser().getint(
|
|
|
|
fromaddress, 'noncetrialsperbyte'))
|
|
|
|
dataToEncrypt += encodeVarint(BMConfigParser().getint(
|
|
|
|
fromaddress, 'payloadlengthextrabytes'))
|
|
|
|
# message encoding type
|
|
|
|
dataToEncrypt += encodeVarint(encoding)
|
|
|
|
encodedMessage = helper_msgcoding.MsgEncode(
|
|
|
|
{"subject": subject, "body": body}, encoding)
|
2016-11-14 20:23:58 +01:00
|
|
|
dataToEncrypt += encodeVarint(encodedMessage.length)
|
|
|
|
dataToEncrypt += encodedMessage.data
|
2014-12-25 09:57:34 +01:00
|
|
|
dataToSign = payload + dataToEncrypt
|
2017-09-21 17:24:51 +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
|
|
|
|
|
2017-09-21 17:24:51 +02: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:
|
2017-09-21 17:24:51 +02:00
|
|
|
privEncryptionKey = hashlib.sha512(
|
|
|
|
encodeVarint(addressVersionNumber) +
|
|
|
|
encodeVarint(streamNumber) + ripe
|
|
|
|
).digest()[:32]
|
2013-09-15 03:06:26 +02:00
|
|
|
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-09-21 17:24:51 +02: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-09-21 17:24:51 +02:00
|
|
|
queues.UISignalQueue.put((
|
|
|
|
'updateSentItemStatusByAckdata', (
|
|
|
|
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)
|
2017-09-21 17:24:51 +02:00
|
|
|
logger.info(
|
|
|
|
'(For broadcast message) Found proof of work %s Nonce: %s',
|
|
|
|
trialValue, nonce
|
|
|
|
)
|
2013-07-31 18:36:51 +02:00
|
|