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

View File

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

View File

@ -8,9 +8,7 @@ from struct import pack
from six.moves import queue, xmlrpc_client
from pybitmessage import protocol
from pybitmessage.defaults import (
networkDefaultProofOfWorkNonceTrialsPerByte,
networkDefaultPayloadLengthExtraBytes)
from pybitmessage.highlevelcrypto import calculateInventoryHash
from .partial import TestPartialRun
from .samples import sample_statusbar_msg, sample_object_data
@ -80,12 +78,14 @@ class TestAPIThread(TestPartialRun):
from inventory import Inventory
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:]
invhash = unhexlify(self.api.disseminatePreEncryptedMsg(
hexlify(update_object).decode(),
networkDefaultProofOfWorkNonceTrialsPerByte,
networkDefaultPayloadLengthExtraBytes
hexlify(update_object).decode()
))
obj_type, obj_stream, obj_data = Inventory()[invhash][:3]
self.assertEqual(obj_type, 42)