2017-12-01 19:25:57 +00:00
|
|
|
from os import urandom
|
|
|
|
from itertools import count
|
2017-12-02 10:49:26 +00:00
|
|
|
from base64 import b64encode, b64decode
|
2017-12-01 19:25:57 +00:00
|
|
|
from hashlib import sha256
|
|
|
|
|
|
|
|
|
2017-12-01 20:40:45 +00:00
|
|
|
class pow_base:
|
2017-12-01 22:57:52 +00:00
|
|
|
@property
|
|
|
|
def base(self):
|
|
|
|
return self._base
|
|
|
|
|
2017-12-01 23:22:33 +00:00
|
|
|
@property
|
|
|
|
def difficulty(self):
|
|
|
|
return self._difficulty
|
|
|
|
|
2017-12-01 19:45:52 +00:00
|
|
|
def __init__(self, difficulty, base=None):
|
2017-12-01 23:22:33 +00:00
|
|
|
self._difficulty = difficulty
|
2017-12-01 20:40:45 +00:00
|
|
|
self._base = urandom(self._bits//8) if not base else base
|
|
|
|
self._target = 2 ** (self._bits - difficulty)
|
2017-12-01 19:25:57 +00:00
|
|
|
|
2017-12-03 12:44:04 +00:00
|
|
|
def work(self, max_attempts=0, start=0, step=1):
|
|
|
|
cycles = count(start, step) if max_attempts == 0 else range(start, max_attempts, step)
|
2017-12-01 23:16:22 +00:00
|
|
|
for nonce in cycles:
|
2017-12-01 19:25:57 +00:00
|
|
|
if self.verify(nonce):
|
|
|
|
return nonce
|
2017-12-01 23:16:22 +00:00
|
|
|
raise RuntimeError('Failed to find a nonce in {} iterations!'.format(max_attempts))
|
2017-12-01 19:25:57 +00:00
|
|
|
|
|
|
|
def verify(self, nonce):
|
2017-12-02 16:18:12 +00:00
|
|
|
hexresult = self._hexdigest(self._base + str(nonce).encode('ascii'))
|
2017-12-01 19:25:57 +00:00
|
|
|
return int(hexresult, 16) < self._target
|
2017-12-01 20:40:45 +00:00
|
|
|
|
2017-12-02 10:49:26 +00:00
|
|
|
def export(self):
|
2017-12-02 10:59:59 +00:00
|
|
|
return str(self.difficulty) + ':' + b64encode(self.base).decode()
|
2017-12-02 10:49:26 +00:00
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def load(cls, export):
|
2017-12-02 10:59:59 +00:00
|
|
|
difficulty, base = export.split(':', 1)
|
2017-12-02 16:18:12 +00:00
|
|
|
return cls(int(difficulty), b64decode(base.encode('ascii')))
|
2017-12-02 10:49:26 +00:00
|
|
|
|
2017-12-01 20:40:45 +00:00
|
|
|
|
|
|
|
class pow_hashlib_base(pow_base):
|
|
|
|
def _hexdigest(self, data):
|
|
|
|
return self._hasher(data).hexdigest()
|
|
|
|
|
|
|
|
|
|
|
|
class pow256(pow_hashlib_base):
|
|
|
|
_bits = 256
|
|
|
|
_hasher = sha256
|