Integrate bitmsghash.bmpow - PyBitmessage's CPoW extension,

define a threading.Thread subclass Worker() for that.
This commit is contained in:
Lee Miller 2023-10-05 12:57:53 +03:00
parent d7ee73843e
commit df34857d6a
Signed by untrusted user: lee.miller
GPG Key ID: 4F97A5EA88F4AB63
3 changed files with 250 additions and 22 deletions

View File

@ -0,0 +1,166 @@
// bitmessage cracker, build with g++ or MSVS to a shared library,
// use via minode.proofofwork module
#ifdef _WIN32
#include "winsock.h"
#include "windows.h"
#define uint64_t unsigned __int64
#else
#include <arpa/inet.h>
#include <pthread.h>
#include <stdint.h>
#endif
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#if defined(__APPLE__) || defined(__FreeBSD__) || defined (__DragonFly__) || defined (__OpenBSD__) || defined (__NetBSD__)
#include <sys/types.h>
#include <sys/sysctl.h>
#endif
#include "openssl/sha.h"
#define HASH_SIZE 64
#define BUFLEN 16384
#if defined(__GNUC__)
#define EXPORT __attribute__ ((__visibility__("default")))
#elif defined(_WIN32)
#define EXPORT __declspec(dllexport)
#endif
#ifndef __APPLE__
#define ntohll(x) ( ( (uint64_t)(ntohl( (unsigned int)((x << 32) >> 32) )) << 32) | ntohl( ((unsigned int)(x >> 32)) ) )
#endif
unsigned long long max_val;
unsigned char *initialHash;
unsigned long long successval = 0;
unsigned int numthreads = 0;
#ifdef _WIN32
DWORD WINAPI threadfunc(LPVOID param) {
#else
void * threadfunc(void* param) {
#endif
unsigned int incamt = *((unsigned int*)param);
SHA512_CTX sha;
unsigned char buf[HASH_SIZE + sizeof(uint64_t)] = { 0 };
unsigned char output[HASH_SIZE] = { 0 };
memcpy(buf + sizeof(uint64_t), initialHash, HASH_SIZE);
unsigned long long tmpnonce = incamt;
unsigned long long * nonce = (unsigned long long *)buf;
unsigned long long * hash = (unsigned long long *)output;
while (successval == 0) {
tmpnonce += numthreads;
(*nonce) = ntohll(tmpnonce); /* increment nonce */
SHA512_Init(&sha);
SHA512_Update(&sha, buf, HASH_SIZE + sizeof(uint64_t));
SHA512_Final(output, &sha);
SHA512_Init(&sha);
SHA512_Update(&sha, output, HASH_SIZE);
SHA512_Final(output, &sha);
if (ntohll(*hash) < max_val) {
successval = tmpnonce;
}
}
#ifdef _WIN32
return 0;
#else
return NULL;
#endif
}
void getnumthreads()
{
#ifdef _WIN32
DWORD_PTR dwProcessAffinity, dwSystemAffinity;
#elif __linux__
cpu_set_t dwProcessAffinity;
#elif __OpenBSD__
int mib[2], core_count = 0;
int dwProcessAffinity = 0;
size_t len2;
#else
int dwProcessAffinity = 0;
int32_t core_count = 0;
#endif
size_t len = sizeof(dwProcessAffinity);
if (numthreads > 0)
return;
#ifdef _WIN32
GetProcessAffinityMask(GetCurrentProcess(), &dwProcessAffinity, &dwSystemAffinity);
#elif __linux__
sched_getaffinity(0, len, &dwProcessAffinity);
#elif __OpenBSD__
len2 = sizeof(core_count);
mib[0] = CTL_HW;
mib[1] = HW_NCPU;
if (sysctl(mib, 2, &core_count, &len2, 0, 0) == 0)
numthreads = core_count;
#else
if (sysctlbyname("hw.logicalcpu", &core_count, &len, 0, 0) == 0)
numthreads = core_count;
else if (sysctlbyname("hw.ncpu", &core_count, &len, 0, 0) == 0)
numthreads = core_count;
#endif
for (unsigned int i = 0; i < len * 8; i++)
#if defined(_WIN32)
#if defined(_MSC_VER)
if (dwProcessAffinity & (1i64 << i))
#else // CYGWIN/MINGW
if (dwProcessAffinity & (1ULL << i))
#endif
#elif defined __linux__
if (CPU_ISSET(i, &dwProcessAffinity))
#else
if (dwProcessAffinity & (1 << i))
#endif
numthreads++;
if (numthreads == 0) // something failed
numthreads = 1;
printf("Number of threads: %i\n", (int)numthreads);
}
extern "C" EXPORT unsigned long long BitmessagePOW(unsigned char * starthash, unsigned long long target)
{
successval = 0;
max_val = target;
getnumthreads();
initialHash = (unsigned char *)starthash;
# ifdef _WIN32
HANDLE* threads = (HANDLE*)calloc(sizeof(HANDLE), numthreads);
# else
pthread_t* threads = (pthread_t*)calloc(sizeof(pthread_t), numthreads);
struct sched_param schparam;
schparam.sched_priority = 0;
# endif
unsigned int *threaddata = (unsigned int *)calloc(sizeof(unsigned int), numthreads);
for (unsigned int i = 0; i < numthreads; i++) {
threaddata[i] = i;
# ifdef _WIN32
threads[i] = CreateThread(NULL, 0, threadfunc, (LPVOID)&threaddata[i], 0, NULL);
SetThreadPriority(threads[i], THREAD_PRIORITY_IDLE);
# else
pthread_create(&threads[i], NULL, threadfunc, (void*)&threaddata[i]);
# ifdef __linux__
pthread_setschedparam(threads[i], SCHED_IDLE, &schparam);
# else
pthread_setschedparam(threads[i], SCHED_RR, &schparam);
# endif
# endif
}
# ifdef _WIN32
WaitForMultipleObjects(numthreads, threads, TRUE, INFINITE);
# else
for (unsigned int i = 0; i < numthreads; i++) {
pthread_join(threads[i], NULL);
}
# endif
free(threads);
free(threaddata);
return successval;
}

View File

@ -1,6 +1,8 @@
"""Doing proof of work"""
import base64
import ctypes
import hashlib
import importlib
import logging
import multiprocessing
import struct
@ -25,30 +27,75 @@ def _pow_worker(target, initial_hash, q):
q.put(struct.pack('>Q', nonce))
def _worker(obj):
q = multiprocessing.Queue()
p = multiprocessing.Process(
target=_pow_worker, args=(obj.pow_target(), obj.pow_initial_hash(), q))
class Worker(threading.Thread):
def __init__(self, obj=None):
self.obj = obj
super().__init__(
name='Worker' if not self.obj
else 'Worker-%s' % (base64.b16encode(obj.vector).decode())
)
self.bmpow = bso = None
try:
bitmsglib = importlib.util.find_spec('minode.bitmsghash').origin
except AttributeError:
return
logging.debug('Starting POW process')
t = time.time()
p.start()
nonce = q.get()
p.join()
try:
bso = ctypes.CDLL(bitmsglib)
except Exception: # pylint: disable=broad-exception-caught
logging.warning('Error loading bitmsghash', exc_info=True)
try:
# MSVS on Windows
bso = ctypes.WinDLL(bitmsglib)
except (AttributeError, TypeError, ValueError):
return
logging.debug(
'Finished doing POW, nonce: %s, time: %ss', nonce, time.time() - t)
obj = structure.Object(
nonce, obj.expires_time, obj.object_type, obj.version,
obj.stream_number, obj.object_payload)
logging.debug(
'Object vector is %s', base64.b16encode(obj.vector).decode())
self.bmpow = bso.BitmessagePOW
self.bmpow.restype = ctypes.c_ulonglong
with shared.objects_lock:
shared.objects[obj.vector] = obj
shared.vector_advertise_queue.put(obj.vector)
@staticmethod
def _worker_result(obj):
q = multiprocessing.Queue()
p = multiprocessing.Process(target=_pow_worker, args=(
obj.pow_target(), obj.pow_initial_hash(), q))
p.start()
nonce = q.get()
p.join()
return nonce
def add_pow(self, obj):
t = time.time()
if not self.bmpow:
logging.debug('Starting PoW process')
nonce = self._worker_result(obj)
else:
logging.debug('Calling PoW extension')
nonce = struct.pack('>Q', self.bmpow(
ctypes.pointer(
ctypes.create_string_buffer(obj.pow_initial_hash(), 64)),
ctypes.c_ulonglong(obj.pow_target())
))
logging.debug(
'Finished doing PoW, nonce: %s, time: %ss', nonce, time.time() - t)
obj = structure.Object(
nonce, obj.expires_time, obj.object_type, obj.version,
obj.stream_number, obj.object_payload)
logging.debug(
'Object vector is %s', base64.b16encode(obj.vector).decode())
return obj
def run(self):
if self.obj:
obj = self.add_pow(self.obj)
with shared.objects_lock:
shared.objects[obj.vector] = obj
shared.vector_advertise_queue.put(obj.vector)
def do_pow_and_publish(obj):
t = threading.Thread(target=_worker, args=(obj, ))
t.start()
Worker(obj).start()

View File

@ -1,8 +1,9 @@
#!/usr/bin/env python
import os
import sys
from setuptools import setup, find_packages
from setuptools import Extension, find_packages, setup
from minode import shared
@ -12,6 +13,19 @@ README = open(os.path.join(
name, version = shared.user_agent.strip(b'/').split(b':')
bitmsghash = Extension(
'minode.bitmsghash',
sources=['minode/bitmsghash/bitmsghash.cpp'],
libraries=['pthread', 'crypto'],
)
if sys.platform[:3] == 'win':
bitmsghash.libraries = ['libeay32', 'ws2_32']
openssl_dir = os.getenv('OPENSSL_DIR')
if openssl_dir:
bitmsghash.library_dirs = [os.path.join(openssl_dir, 'lib')]
bitmsghash.include_dirs = [os.path.join(openssl_dir, 'include')]
setup(
name=name.decode('utf-8'),
version=version.decode('utf-8'),
@ -23,6 +37,7 @@ setup(
url='https://git.bitmessage.org/lee.miller/MiNode',
packages=find_packages(exclude=('*tests',)),
package_data={'': ['*.csv', 'tls/*.pem']},
ext_modules=[bitmsghash],
entry_points={'console_scripts': ['minode = minode.main:main']},
classifiers=[
"License :: OSI Approved :: MIT License"