def check_pow( block_number: int, mining_hash: Hash32, mix_hash: Hash32, nonce: bytes, difficulty: int, ) -> None: if len(mix_hash) != 32: raise ValidationError(f"Wrong length: mix_hash={mix_hash.hex()}") elif len(mining_hash) != 32: raise ValidationError(f"Wrong length: mining_hash={mining_hash.hex()}") elif len(nonce) != 8: raise ValidationError(f"Wrong length: nonce={nonce.hex()}") cache = get_cache(block_number) mining_output = hashimoto_light(block_number, cache, mining_hash, int.from_bytes(nonce, "big")) mix_digest = mining_output[b"mix digest"] if mix_digest != mix_hash: raise ValidationError( f"Invalid POW: expected={mix_digest.hex()} " f"actual={mix_hash.hex()}. " f"Mix hash calculated from block #{block_number}, " f"mine hash {mining_hash.hex()}, nonce {nonce.hex()}" f", difficulty {difficulty}, cache hash {keccak(cache).hex()}") result = int.from_bytes(mining_output[b"result"], "big") if result > 2**256 // difficulty: raise ValidationError( f"Insufficient difficulty: actual={result} required={difficulty}")
def check_pow(block_number: int, mining_hash: Hash32, mix_hash: Hash32, nonce: bytes, difficulty: int) -> None: cache = get_cache(block_number) #we get cache by block number mining_output = hashimoto_light( block_number, cache, mining_hash, big_endian_to_int( nonce)) # MISTAKE not int_to_big_endian but the other way around #big_endian_to_int(nonce) #int_to_big_endian(nonce)) #this is the hashimoto light mining output. It takes block_number, cache, mining_hash, int_to_big_endian(nonce) and hash it print("MIX Digest: ", mining_output[b'mix digest']) print("MIX HASH: ", w3.eth.getBlock(block_number).mixHash.hex()) print("RESULT: ", mining_output[b'result']) print("CONDITION: ", (2**256) // difficulty) if mining_output[ b'mix digest'] != mining_hash: #this is to say that if the mining digest is not equal to the mix hash, then... return False elif int_to_big_endian(mining_output[b'result']) <= ( 2**256 // difficulty ): #to convert the result int integer and check if it meets the condition of being less or equal to 2^256 divided by the difficulty return False else: return True #if it returns true, then all good! We could do more checks but this is enough for now. For additional checks see here https://github.com/ethereum/py-evm/blob/d553bd405bbf41a1da0c227a614baba7b43e9449/eth/consensus/pow.py
def hashimoto( block_number: int, full_size: int, cache: Union[List[List[int]], bytes], mining_hash: bytes, bin_nonce: bytes, ): return pyethash.hashimoto_light(block_number, cache, mining_hash, big_endian_to_int(bin_nonce))
def mine_pow_nonce(block_number: int, mining_hash: Hash32, difficulty: int) -> Tuple[bytes, bytes]: cache = get_cache(block_number) for nonce in range(MAX_TEST_MINE_ATTEMPTS): mining_output = hashimoto_light(block_number, cache, mining_hash, nonce) result = big_endian_to_int(mining_output[b'result']) result_cap = 2**256 // difficulty if result <= result_cap: return nonce.to_bytes(8, 'big'), mining_output[b'mix digest'] raise Exception("Too many attempts at POW mining, giving up")
def check_pow(block_number, mining_hash, mix_hash, nonce, difficulty): validate_length(mix_hash, 32) validate_length(mining_hash, 32) validate_length(nonce, 8) cache = get_cache(block_number) mining_output = hashimoto_light(block_number, cache, mining_hash, big_endian_to_int(nonce)) if mining_output[b'mix digest'] != mix_hash: raise ValidationError("mix hash mistmatch; {0} != {1}".format( encode_hex(mining_output[b'mix digest']), encode_hex(mix_hash))) result = big_endian_to_int(mining_output[b'result']) validate_lte(result, 2**256 // difficulty)
def check_pow(block_number, mining_hash, mix_hash, nonce, difficulty): validate_length(mix_hash, 32, title="Mix Hash") validate_length(mining_hash, 32, title="Mining Hash") validate_length(nonce, 8, title="POW Nonce") cache = get_cache(block_number) mining_output = hashimoto_light( block_number, cache, mining_hash, big_endian_to_int(nonce)) if mining_output[b'mix digest'] != mix_hash: raise ValidationError("mix hash mismatch; {0} != {1}".format( encode_hex(mining_output[b'mix digest']), encode_hex(mix_hash))) result = big_endian_to_int(mining_output[b'result']) validate_lte(result, 2**256 // difficulty, title="POW Difficulty")
def check_pow(block_number: int, mining_hash: Hash32, mix_hash: Hash32, nonce: bytes, difficulty: int) -> None: validate_length(mix_hash, 32, title="Mix Hash") validate_length(mining_hash, 32, title="Mining Hash") validate_length(nonce, 8, title="POW Nonce") cache = get_cache(block_number) mining_output = hashimoto_light(block_number, cache, mining_hash, big_endian_to_int(nonce)) if mining_output[b'mix digest'] != mix_hash: raise ValidationError("mix hash mismatch; {0} != {1}".format( encode_hex(mining_output[b'mix digest']), encode_hex(mix_hash))) result = big_endian_to_int(mining_output[b'result']) validate_lte(result, 2**256 // difficulty, title="POW Difficulty")
def test_light_and_full_agree(): cache = pyethash.mkcache_bytes(1024, "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~") full_size = 1024 * 32 header = "~~~~~X~~~~~~~~~~~~~~~~~~~~~~~~~~" light_result = pyethash.hashimoto_light(full_size, cache, header, 0) dataset = pyethash.calc_dataset_bytes(full_size, cache) full_result = pyethash.hashimoto_full(dataset, header, 0) assert light_result["mix digest"] != None assert len(light_result["mix digest"]) == 32 assert light_result["mix digest"] == full_result["mix digest"] assert light_result["result"] != None assert len(light_result["result"]) == 32 assert light_result["result"] == full_result["result"]
def test_light_and_full_agree(): cache = pyethash.mkcache_bytes( 1024, "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~") full_size = 1024 * 32 header = "~~~~~X~~~~~~~~~~~~~~~~~~~~~~~~~~" light_result = pyethash.hashimoto_light(full_size, cache, header, 0) dataset = pyethash.calc_dataset_bytes(full_size, cache) full_result = pyethash.hashimoto_full(dataset, header, 0) assert light_result["mix digest"] != None assert len(light_result["mix digest"]) == 32 assert light_result["mix digest"] == full_result["mix digest"] assert light_result["result"] != None assert len(light_result["result"]) == 32 assert light_result["result"] == full_result["result"]
def mine_pow_nonce(block_number: int, mining_hash: Hash32, difficulty: int) -> Tuple[bytes, bytes]: cache = get_cache(block_number) # VDF input mining_input = hashimoto_light(block_number, cache, mining_hash) vdf_input_integer = big_endian_to_int(mining_input[b'result']) # Calculate VDF Steps needed. # Adding VRF (WIP) node_vrf_seed_b64 = self.vrf.get_seed_b64(vdf_input_integer) vdf_steps = hashimoto_light(DEFAULT_DEBUG_STAKE, TOTAL_COINS, node_vrf_seed_b64) vdf_difficulty = big_endian_to_int(vdf_steps[b'result']) print('VDF Difficulty = %d' % vdf_difficulty) print("DEBUG: Mining sequential VDF (Sloth) ...") # nonce = vdf_execute(vdf_input_integer,node_vdf_steps) # VRF version nonce = vdf_execute(vdf_input_integer, vdf_difficulty) print("DEBUG: Generated NONCE = %d" % nonce) return nonce, node_vrf_seed_b64, self.vrf.get_pem_public_key( ) # , node_vrf_seed # with this
def check_pow(block_number: int, mining_hash: Hash32, mix_hash: Hash32, nonce: bytes, difficulty: int) -> None: validate_length(mix_hash, 32, title="Mix Hash") validate_length(mining_hash, 32, title="Mining Hash") validate_length(nonce, 8, title="POW Nonce") cache = get_cache(block_number) mining_output = hashimoto_light(block_number, cache, mining_hash, big_endian_to_int(nonce)) if mining_output[b'mix digest'] != mix_hash: raise ValidationError( f"mix hash mismatch; expected: {encode_hex(mining_output[b'mix digest'])} " f"!= actual: {encode_hex(mix_hash)}. " f"Mix hash calculated from block #{block_number}, " f"mine hash {encode_hex(mining_hash)}, nonce {encode_hex(nonce)}" f", difficulty {difficulty}, cache hash {encode_hex(keccak(cache))}" ) result = big_endian_to_int(mining_output[b'result']) validate_lte(result, 2**256 // difficulty, title="POW Difficulty")
from repoze.lru import lru_cache else: ETHASH_LIB = 'ethash' from functools import lru_cache if ETHASH_LIB == 'ethash': mkcache = ethash.mkcache EPOCH_LENGTH = ethash_utils.EPOCH_LENGTH hashimoto_light = ethash.hashimoto_light elif ETHASH_LIB == 'pyethash': import pyethash mkcache = pyethash.mkcache_bytes EPOCH_LENGTH = pyethash.EPOCH_LENGTH hashimoto_light = lambda s, c, h, n: \ pyethash.hashimoto_light(s, c, h, utils.big_endian_to_int(n)) else: raise Exception("invalid ethash library set") TT64M1 = 2**64 - 1 cache_seeds = ['\x00' * 32] cache_by_seed = OrderedDict() cache_by_seed.max_items = 10 def get_cache(block_number): while len(cache_seeds) <= block_number // EPOCH_LENGTH: cache_seeds.append(sha3.sha3_256(cache_seeds[-1]).digest()) seed = cache_seeds[block_number // EPOCH_LENGTH] if seed in cache_by_seed: c = cache_by_seed.pop(seed) # pop and append at end
def hashimoto_light(s, c, h, n): return \ pyethash.hashimoto_light(s, c, h, utils.big_endian_to_int(n)) else:
def pow_hash(block_number, header, nonce) -> Tuple[bytes, bytes]: """search for hash result using hashimoto_light.""" cache_bytes = get_cache(block_number) hash_ret = hashimoto_light(block_number, cache_bytes, header, nonce) return hash_ret[b"mix digest"], hash_ret[b"result"]