class Block(Logger): """Block and header definition.""" NONCE_SIZE = 4 def __init__(self, blockchain=None, name='block', height=0, version=0, coinbase=None, corners=None, timestamp=0, previous_hash=pycryptonight.cn_slow_hash(b''), nonce=(0).to_bytes(NONCE_SIZE, 'big')): super().__init__(f"{name} - {height} :") self.blockchain = blockchain self.version = version self.timestamp = timestamp self.previous_hash = previous_hash self.nonce = nonce self.coinbase = coinbase self._corners = [] if corners is None else corners self.merkle_tree = MerkleTree(self.corners, fast_hash) self.hash = self.get_hash() self.difficulty = 4 @property def corners(self): return [self.coinbase] + self._corners def compute_tree(self, new_data=None): if new_data is None: self.merkle_tree = MerkleTree(self.corners, fast_hash) else: self.merkle_tree.extend(new_data) @property def header(self): res = self.version.to_bytes(2, 'big') res += self.timestamp.to_bytes(8, 'big') res += len(self.corners).to_bytes(3, 'big') res += bytes.fromhex(self.merkle_tree.merkle_root) res += self.previous_hash res += self.nonce return res def random_nonce(self): self.timestamp = time.time_ns() self.nonce = os.urandom(self.NONCE_SIZE) def mine(self, difficulty=None): difficulty = self.difficulty if difficulty is None else difficulty while int.from_bytes(self.get_hash(), 'big') >= (1 << (256 - difficulty)): self.log(f"new hash : {self.hash.hex()}") self.random_nonce() self.log(f"Mined !! : {self.hash.hex()}") def get_hash(self): self.hash = pycryptonight.cn_slow_hash(self.header, 4) return self.hash
# --------------- GENERATE FROM LIST TEST -------------------- # print("\n--------------- GENERATE FROM LIST TEST --------------------") # This test simulates accumulating nonces in a single list # Instantiate empty list data = [] # Initialize testing list newData = ["aoibune", "24pot309grtjb", "poegijshbn", "oqfh8vyu", "0298f7gvublnk", "pq09483f7guvbl"] # Instantiate empty Merkle tree for appending listTree = MerkleTree(data, hashfunc) # Add list data to merkle tree listTree.extend(newData); # Print MerkleTree print("\nPrinting Merkle Tree") beautify(listTree) print("\nPrinting root") print(listTree.merkle_root) print("\nPrinting leaves") print(listTree.leaves) # Generate an audit proof for the string print("\nGenerating audit proof for poegijshbn") proof = listTree.get_proof('poegijshbn') print("\nProof: ") print(proof)
class Block(Logger): """Block and header definition.""" NONCE_SIZE = 4 def __init__(self, blockchain=None, name: str = 'block', height: int = 0, version: int = 0, coinbase: Corner = None, corners: list = None, timestamp=0, previous_hash=pycryptonight.cn_slow_hash(b''), nonce=(0).to_bytes(NONCE_SIZE, 'big')): """ Initialises a Block instance. :param blockchain: Blockchain :param name: str :param height: int :param version: int :param coinbase: Corner :param corners: Corner list :param timestamp: int :param previous_hash: bytes :param nonce: bytes """ super().__init__(f"{name} - {height} :") self.blockchain = blockchain self.version = version self.timestamp = timestamp self.previous_hash = previous_hash self.nonce = nonce self.coinbase = coinbase self._corners = [] if corners is None else corners self.merkle_tree = MerkleTree(self.corners, fast_hash) self.hash = self.get_hash() self.difficulty = 4 @property def corners(self): """ list of coinbase and other corners. :return: Corner list """ return [self.coinbase] + self._corners def compute_tree(self, new_data=None): """ Computes the Merkle Tree associated with the corners in the block. :param new_data: Corner list :return: None """ if new_data is None: self.merkle_tree = MerkleTree(self.corners, fast_hash) else: self.merkle_tree.extend(new_data) @property def header(self): """ Raw representation of block header based on the Discorn Protocol. :return: bytes """ res = self.version.to_bytes(2, 'big') res += self.timestamp.to_bytes(8, 'big') res += len(self.corners).to_bytes(3, 'big') res += bytes.fromhex(self.merkle_tree.merkle_root) res += self.previous_hash res += self.nonce return res def random_nonce(self): """ Generates a random nonce for this block. (Mining OP) :return: None """ self.timestamp = time.time_ns() self.nonce = os.urandom(self.NONCE_SIZE) def mine(self, difficulty=None): """ Mines the given block for the given difficulty. :param difficulty: int :return: None """ difficulty = self.difficulty if difficulty is None else difficulty while int.from_bytes(self.get_hash(), 'big') >= (1 << (256 - difficulty)): self.log(f"new hash : {self.hash.hex()}") self.random_nonce() self.log(f"Mined !! : {self.hash.hex()}") def get_hash(self): """ Calculates the block's hash. :return: bytes """ self.hash = pycryptonight.cn_slow_hash(self.header, 4) return self.hash