Make PoW optional in disseminatePreEncryptedMsg API command #2211

Merged
PeterSurda merged 5 commits from gitea-80 into v0.6 2024-04-14 03:40:55 +02:00
3 changed files with 75 additions and 69 deletions

View File

@ -66,12 +66,11 @@ import socket
import subprocess # nosec B404 import subprocess # nosec B404
import time import time
from binascii import hexlify, unhexlify from binascii import hexlify, unhexlify
from struct import pack from struct import pack, unpack
import six import six
from six.moves import configparser, http_client, xmlrpc_server from six.moves import configparser, http_client, xmlrpc_server
import defaults
import helper_inbox import helper_inbox
import helper_sent import helper_sent
import protocol import protocol
@ -89,6 +88,9 @@ from addresses import (
) )
from bmconfigparser import config from bmconfigparser import config
from debug import logger from debug import logger
from defaults import (
networkDefaultProofOfWorkNonceTrialsPerByte,
networkDefaultPayloadLengthExtraBytes)
from helper_sql import ( from helper_sql import (
SqlBulkExecute, sqlExecute, sqlQuery, sqlStoredProcedure, sql_ready) SqlBulkExecute, sqlExecute, sqlQuery, sqlStoredProcedure, sql_ready)
from highlevelcrypto import calculateInventoryHash from highlevelcrypto import calculateInventoryHash
@ -657,13 +659,11 @@ class BMRPCDispatcher(object):
nonceTrialsPerByte = self.config.get( nonceTrialsPerByte = self.config.get(
'bitmessagesettings', 'defaultnoncetrialsperbyte' 'bitmessagesettings', 'defaultnoncetrialsperbyte'
) if not totalDifficulty else int( ) if not totalDifficulty else int(
defaults.networkDefaultProofOfWorkNonceTrialsPerByte networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty)
* totalDifficulty)
payloadLengthExtraBytes = self.config.get( payloadLengthExtraBytes = self.config.get(
'bitmessagesettings', 'defaultpayloadlengthextrabytes' 'bitmessagesettings', 'defaultpayloadlengthextrabytes'
) if not smallMessageDifficulty else int( ) if not smallMessageDifficulty else int(
defaults.networkDefaultPayloadLengthExtraBytes networkDefaultPayloadLengthExtraBytes * smallMessageDifficulty)
* smallMessageDifficulty)
if not isinstance(eighteenByteRipe, bool): if not isinstance(eighteenByteRipe, bool):
raise APIError( raise APIError(
@ -705,13 +705,11 @@ class BMRPCDispatcher(object):
nonceTrialsPerByte = self.config.get( nonceTrialsPerByte = self.config.get(
'bitmessagesettings', 'defaultnoncetrialsperbyte' 'bitmessagesettings', 'defaultnoncetrialsperbyte'
) if not totalDifficulty else int( ) if not totalDifficulty else int(
defaults.networkDefaultProofOfWorkNonceTrialsPerByte networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty)
* totalDifficulty)
payloadLengthExtraBytes = self.config.get( payloadLengthExtraBytes = self.config.get(
'bitmessagesettings', 'defaultpayloadlengthextrabytes' 'bitmessagesettings', 'defaultpayloadlengthextrabytes'
) if not smallMessageDifficulty else int( ) if not smallMessageDifficulty else int(
defaults.networkDefaultPayloadLengthExtraBytes networkDefaultPayloadLengthExtraBytes * smallMessageDifficulty)
* smallMessageDifficulty)
if not passphrase: if not passphrase:
raise APIError(1, 'The specified passphrase is blank.') raise APIError(1, 'The specified passphrase is blank.')
@ -1284,46 +1282,53 @@ class BMRPCDispatcher(object):
}) })
return {'subscriptions': data} return {'subscriptions': data}
@command('disseminatePreEncryptedMsg') @command('disseminatePreEncryptedMsg', 'disseminatePreparedObject')
def HandleDisseminatePreEncryptedMsg( def HandleDisseminatePreparedObject(
self, encryptedPayload, requiredAverageProofOfWorkNonceTrialsPerByte, self, encryptedPayload,
requiredPayloadLengthExtraBytes): nonceTrialsPerByte=networkDefaultProofOfWorkNonceTrialsPerByte,
"""Handle a request to disseminate an encrypted message""" payloadLengthExtraBytes=networkDefaultPayloadLengthExtraBytes
):
"""
Handle a request to disseminate an encrypted message.
# The device issuing this command to PyBitmessage supplies a msg The device issuing this command to PyBitmessage supplies an object
# object that has already been encrypted but which still needs the POW that has already been encrypted but which may still need the PoW
# to be done. PyBitmessage accepts this msg object and sends it out to be done. PyBitmessage accepts this object and sends it out
# to the rest of the Bitmessage network as if it had generated to the rest of the Bitmessage network as if it had generated
# the message itself. Please do not yet add this to the api doc. the message itself.
encryptedPayload = b'\x00' * 8 + self._decode(encryptedPayload, "hex")
# compatibility stub ^, since disseminatePreEncryptedMsg *encryptedPayload* is a hex encoded string starting with the nonce,
# still expects the encryptedPayload without a nonce 8 zero bytes in case of no PoW done.
"""
encryptedPayload = self._decode(encryptedPayload, "hex")
nonce, = unpack('>Q', encryptedPayload[:8])
objectType, toStreamNumber, expiresTime = \ objectType, toStreamNumber, expiresTime = \
protocol.decodeObjectParameters(encryptedPayload) protocol.decodeObjectParameters(encryptedPayload)
if nonce == 0: # Let us do the POW and attach it to the front
encryptedPayload = encryptedPayload[8:] encryptedPayload = encryptedPayload[8:]
TTL = expiresTime - time.time() + 300 # a bit of extra padding TTL = expiresTime - time.time() + 300 # a bit of extra padding
# Let us do the POW and attach it to the front # Let us do the POW and attach it to the front
target = 2**64 / (
requiredAverageProofOfWorkNonceTrialsPerByte * (
len(encryptedPayload) + 8
+ requiredPayloadLengthExtraBytes + ((
TTL * (
len(encryptedPayload) + 8
+ requiredPayloadLengthExtraBytes
)) / (2 ** 16))
))
logger.debug("expiresTime: %s", expiresTime) logger.debug("expiresTime: %s", expiresTime)
logger.debug("TTL: %s", TTL) logger.debug("TTL: %s", TTL)
logger.debug("objectType: %s", objectType) logger.debug("objectType: %s", objectType)
logger.info( logger.info(
'(For msg message via API) Doing proof of work. Total required' '(For msg message via API) Doing proof of work. Total required'
' difficulty: %s\nRequired small message difficulty: %s', ' difficulty: %s\nRequired small message difficulty: %s',
float(requiredAverageProofOfWorkNonceTrialsPerByte) float(nonceTrialsPerByte)
/ defaults.networkDefaultProofOfWorkNonceTrialsPerByte, / networkDefaultProofOfWorkNonceTrialsPerByte,
float(requiredPayloadLengthExtraBytes) float(payloadLengthExtraBytes)
/ defaults.networkDefaultPayloadLengthExtraBytes, / networkDefaultPayloadLengthExtraBytes,
) )
powStartTime = time.time() powStartTime = time.time()
target = 2**64 / (
nonceTrialsPerByte * (
len(encryptedPayload) + 8 + payloadLengthExtraBytes + ((
TTL * (
len(encryptedPayload) + 8 + payloadLengthExtraBytes
)) / (2 ** 16))
))
initialHash = hashlib.sha512(encryptedPayload).digest() initialHash = hashlib.sha512(encryptedPayload).digest()
trialValue, nonce = proofofwork.run(target, initialHash) trialValue, nonce = proofofwork.run(target, initialHash)
logger.info( logger.info(
@ -1333,6 +1338,7 @@ class BMRPCDispatcher(object):
nonce / (time.time() - powStartTime) nonce / (time.time() - powStartTime)
) )
encryptedPayload = pack('>Q', nonce) + encryptedPayload encryptedPayload = pack('>Q', nonce) + encryptedPayload
inventoryHash = calculateInventoryHash(encryptedPayload) inventoryHash = calculateInventoryHash(encryptedPayload)
Inventory()[inventoryHash] = ( Inventory()[inventoryHash] = (
objectType, toStreamNumber, encryptedPayload, objectType, toStreamNumber, encryptedPayload,
@ -1365,8 +1371,8 @@ class BMRPCDispatcher(object):
# Let us do the POW # Let us do the POW
target = 2 ** 64 / (( target = 2 ** 64 / ((
len(payload) + defaults.networkDefaultPayloadLengthExtraBytes + 8 len(payload) + networkDefaultPayloadLengthExtraBytes + 8
) * defaults.networkDefaultProofOfWorkNonceTrialsPerByte) ) * networkDefaultProofOfWorkNonceTrialsPerByte)
logger.info('(For pubkey message via API) Doing proof of work...') logger.info('(For pubkey message via API) Doing proof of work...')
initialHash = hashlib.sha512(payload).digest() initialHash = hashlib.sha512(payload).digest()
trialValue, nonce = proofofwork.run(target, initialHash) trialValue, nonce = proofofwork.run(target, initialHash)

View File

@ -20,11 +20,11 @@ sample_addr_data = unhexlify(
# These keys are from addresses test script # These keys are from addresses test script
sample_pubsigningkey = unhexlify( sample_pubsigningkey = unhexlify(
'044a367f049ec16cb6b6118eb734a9962d10b8db59c890cd08f210c43ff08bdf09d' '044a367f049ec16cb6b6118eb734a9962d10b8db59c890cd08f210c43ff08bdf09'
'16f502ca26cd0713f38988a1237f1fc8fa07b15653c996dc4013af6d15505ce') 'd16f502ca26cd0713f38988a1237f1fc8fa07b15653c996dc4013af6d15505ce')
sample_pubencryptionkey = unhexlify( sample_pubencryptionkey = unhexlify(
'044597d59177fc1d89555d38915f581b5ff2286b39d022ca0283d2bdd5c36be5d3c' '044597d59177fc1d89555d38915f581b5ff2286b39d022ca0283d2bdd5c36be5d3'
'e7b9b97792327851a562752e4b79475d1f51f5a71352482b241227f45ed36a9') 'ce7b9b97792327851a562752e4b79475d1f51f5a71352482b241227f45ed36a9')
sample_privsigningkey = \ sample_privsigningkey = \
b'93d0b61371a54b53df143b954035d612f8efa8a3ed1cf842c2186bfd8f876665' b'93d0b61371a54b53df143b954035d612f8efa8a3ed1cf842c2186bfd8f876665'
sample_privencryptionkey = \ sample_privencryptionkey = \

View File

@ -8,9 +8,7 @@ from struct import pack
from six.moves import queue, xmlrpc_client from six.moves import queue, xmlrpc_client
from pybitmessage import protocol from pybitmessage import protocol
from pybitmessage.defaults import ( from pybitmessage.highlevelcrypto import calculateInventoryHash
networkDefaultProofOfWorkNonceTrialsPerByte,
networkDefaultPayloadLengthExtraBytes)
from .partial import TestPartialRun from .partial import TestPartialRun
from .samples import sample_statusbar_msg, sample_object_data from .samples import sample_statusbar_msg, sample_object_data
@ -80,12 +78,14 @@ class TestAPIThread(TestPartialRun):
from inventory import Inventory from inventory import Inventory
proofofwork.init() proofofwork.init()
update_object = pack( self.assertEqual(
unhexlify(self.api.disseminatePreparedObject(
hexlify(sample_object_data).decode())),
calculateInventoryHash(sample_object_data))
update_object = b'\x00' * 8 + pack(
'>Q', int(time.time() + 7200)) + sample_object_data[16:] '>Q', int(time.time() + 7200)) + sample_object_data[16:]
invhash = unhexlify(self.api.disseminatePreEncryptedMsg( invhash = unhexlify(self.api.disseminatePreEncryptedMsg(
hexlify(update_object).decode(), hexlify(update_object).decode()
networkDefaultProofOfWorkNonceTrialsPerByte,
networkDefaultPayloadLengthExtraBytes
)) ))
obj_type, obj_stream, obj_data = Inventory()[invhash][:3] obj_type, obj_stream, obj_data = Inventory()[invhash][:3]
self.assertEqual(obj_type, 42) self.assertEqual(obj_type, 42)