140 lines
3.3 KiB
Python

"""placeholder module for compilation"""
from __future__ import annotations
import datetime
import hashlib
import struct
import time
import dopt_basics.datetime
def float_to_bytes(num: float):
return struct.pack(">d", num)
class Block:
__slots__ = (
"_index",
"_timestamp",
"_data",
"_prev_hash",
"_nonce",
"_hash",
)
def __init__(
self,
index: int,
data: str,
previous_hash: str,
nonce: int,
):
self._index = index
self._timestamp = datetime.datetime(2025, 12, 1, 12, 0, 0).timestamp()
# self._timestamp = dopt_basics.datetime.current_time_tz().timestamp()
self._data = data
self._prev_hash = previous_hash
self._nonce = nonce
self._hash = ""
def _perform_hash(self):
parts = bytearray()
parts.extend(self._index.to_bytes(8, "big"))
parts.extend(float_to_bytes(self._timestamp))
parts.extend(self._data.encode("UTF-8"))
parts.extend(self._prev_hash.encode("UTF-8"))
parts.extend(self._nonce.to_bytes(8, "big"))
return hashlib.sha256(parts)
def compute_hash_bytes(self):
return self._perform_hash().digest()
def compute_hash(self):
return self._perform_hash().hexdigest()
# Python public API
@property
def index(self) -> int:
return self._index
@property
def timestamp(self) -> datetime.datetime:
return datetime.datetime.fromtimestamp(self._timestamp)
@property
def data(self) -> str:
return self._data
@property
def prev_hash(self) -> str:
return self._prev_hash
@property
def nonce(self):
return self._nonce
@nonce.setter
def nonce(self, value: int):
self._nonce = value
@property
def hash(self) -> str:
return self._hash
@hash.setter
def hash(self, value: str) -> None:
if not isinstance(value, str):
raise TypeError("No string")
self._hash = value
class Blockchain:
def __init__(
self,
difficulty: int = 1,
) -> None:
self.chain: list[Block] = []
# self.difficulty = difficulty.to_bytes(8, "big")
self.difficulty = difficulty
def create_genesis_block(self):
genesis = Block(
index=0,
data="Genesis Block",
previous_hash="0",
nonce=0,
)
genesis.hash = genesis.compute_hash()
self.chain.append(genesis)
def proof_of_work(
self,
block: Block,
) -> str:
prefix = "0" * self.difficulty
while True:
block_hash = block.compute_hash()
if block_hash.startswith(prefix):
return block_hash
block.nonce += 1
def add_block(self, data: str) -> Block:
new_block = Block(
index=len(self.chain),
data=data,
previous_hash=self.chain[-1].hash,
nonce=0,
)
start = time.perf_counter()
new_block.hash = self.proof_of_work(new_block)
elapsed = time.perf_counter() - start
self.chain.append(new_block)
print(f"Mined block {new_block.index} in {elapsed:.3f}s with nonce={new_block.nonce}")
return new_block