def test_pow(self): block_num = 22 header = crypto.hex_str_to_bytes("372eca2454ead349c3df0ab5d00b0b706b23e49d469387db91811cee0358fc6d") excepted_result = crypto.hex_str_to_bytes("00000b184f1fdd88bfd94c86c39e65db0c36144d5e43f745f722196e730cb614") excepted_mix = b'/t\xcd\xeb\x19\x8a\xf0\xb9\xab\xe6]"\xd3r\xe2/\xb2\xd4t7\x17t\xa9X<\x1c\xc4\'\xa0y9\xf5' nonce = 0x495732e0ed7a801c boundary20 = ethash.difficulty_to_boundary(20) boundary21 = ethash.difficulty_to_boundary(21) calc_mix_digest, calc_result = ethash.pow_hash(block_num, header, nonce) assert calc_result == excepted_result assert calc_mix_digest == excepted_mix assert ethash.verify_pow_work(block_num, header, excepted_mix, nonce, boundary20) assert not ethash.verify_pow_work(block_num, header, excepted_mix, nonce, boundary21) assert ethash.verify_pow_work(0, header, excepted_mix, nonce, boundary20) assert ethash.verify_pow_work(29999, header, excepted_mix, nonce, boundary20) assert not ethash.verify_pow_work(30000, header, excepted_mix, nonce, boundary20) assert not ethash.verify_pow_work(30001, header, excepted_mix, nonce, boundary20)
async def eth_submitWork(request, nonce: str, header: str, mix_digest: str, boundary: str = "", miner_wallet: str = "", worker_name: str = "") -> bool: assert (len(nonce) == 18 and len(header) == 66 and len(mix_digest) == 66 and len(boundary) in [0, 66] and len(miner_wallet) in [0, 40, 42] and len(worker_name) < 64) if not miner_wallet: miner_wallet = default_miner if config["zilliqa"]["enabled"]: if not blockchain.Zilliqa.is_pow_window(): return False # 1. validate user input parameters nonce_int = h2i(nonce) worker_name = valid_worker_name(worker_name) miner_wallet_bytes = h2b(miner_wallet) mix_digest_bytes = h2b(mix_digest) # 2. get or create miner/worker _miner = miner.Miner.get_or_create(miner_wallet, worker_name) _worker = miner.Worker.get_or_create(miner_wallet, worker_name) if not _miner or not _worker: logging.warning( "miner/worker not found, {worker_name}@{miner_wallet}") return False if _worker is not None: _worker.update_stat(inc_submitted=1) # 3. check work existing work = pow.PowWork.find_work_by_header_boundary(header=header, boundary=boundary, check_expired=True) if not work: logging.warning(f"work not found or expired, {header} {boundary}") _worker.update_stat(inc_failed=1) return False # 4. verify result seed, header = h2b(work.seed), h2b(work.header) boundary_bytes = h2b(work.boundary) block_num = ethash.seed_to_block_num(seed) hash_result = ethash.verify_pow_work(block_num, header, mix_digest_bytes, nonce_int, boundary_bytes) if not hash_result: logging.warning( f"wrong result from miner {miner_wallet}-{worker_name}, {work}" ) _worker.update_stat(inc_failed=1) return False # 5. check the result if lesser than old one if work.finished: prev_result = pow.PowResult.get_pow_result(work.header, work.boundary) if prev_result: if prev_result.verified: logging.info( f"submitted too late, work is verified. {work.header} {work.boundary}" ) _worker.update_stat(inc_failed=1) return False if ethash.is_less_or_equal(prev_result.hash_result, hash_result): logging.info( f"submitted result > old result, ignored. {work.header} {work.boundary}" ) _worker.update_stat(inc_failed=1) return False # 6. save to database hash_result_str = b2h(hash_result, prefix="0x") if not work.save_result(nonce, mix_digest, hash_result_str, miner_wallet, worker_name): logging.warning(f"failed to save result for miner " f"{miner_wallet}-{worker_name}, {work}") return False logging.critical(f"Work submitted, {work.header} {work.boundary}") _worker.update_stat(inc_finished=1) # 6. todo: miner reward return True
def process_submit(self, jsonMsg): work = None mix_digest = None miner_wallet = self.miner_wallet worker_name = None hash_result = None _worker = None if jsonMsg["id"] is None: logging.warning("Submitted result message without id") return id = jsonMsg["id"] if self.stratumMiner._stratusVersion == STRATUM_BASIC: nonce = jsonMsg["params"][2] nonce_int = h2i(nonce) header = jsonMsg["params"][3] mix_digest = jsonMsg["params"][4] boundary = self.stratumMiner._boundary mix_digest_bytes = h2b(mix_digest) worker_name = jsonMsg["worker"] _worker = miner.Worker.get_or_create(miner_wallet, worker_name) # 3. check work existing work = pow.PowWork.find_work_by_header_boundary(header=header, boundary=boundary, check_expired=True) if not work: logging.warning( f"work not found or expired, {header} {boundary}") _worker.update_stat(inc_failed=1) return False # 4. verify result seed, header = h2b(work.seed), h2b(work.header) boundary_bytes = h2b(work.boundary) block_num = ethash.seed_to_block_num(seed) hash_result = ethash.verify_pow_work(block_num, header, mix_digest_bytes, nonce_int, boundary_bytes) if not hash_result: logging.warning( f"wrong result from miner {miner_wallet}-{worker_name}, {work}" ) _worker.update_stat(inc_failed=1) return False elif self.stratumMiner._stratusVersion == STRATUM_NICEHASH: if jsonMsg["params"] is None: logging.critical("The message is without params section") return False worker_name = jsonMsg["params"][0] strJobId = jsonMsg["params"][1] joibId = ObjectId(strJobId) nonce = jsonMsg["params"][2] if self.strExtraNonceHex is not None: nonce = self.strExtraNonceHex + nonce nonce_int = h2i(nonce) logging.info(f"worker_name {worker_name}") _worker = miner.Worker.get_or_create(miner_wallet, worker_name) # 3. check work existing work = pow.PowWork.find_work_by_id(joibId, check_expired=True) if not work: logging.warning(f"work not found or expired, {strJobId}") _worker.update_stat(inc_failed=1) return False # 4. verify result seed, header = h2b(work.seed), h2b(work.header) calc_mix_digest, calc_result = ethash.pow_hash( work.block_num, header, nonce_int) boundary_bytes = h2b(work.boundary) block_num = ethash.seed_to_block_num(seed) hash_result = ethash.verify_pow_work(block_num, header, calc_mix_digest, nonce_int, boundary_bytes) if not hash_result: logging.warning( f"wrong result from miner {miner_wallet}-{worker_name}, {work}" ) _worker.update_stat(inc_failed=1) return False mix_digest = b2h(calc_mix_digest) # 5. check the result if lesser than old one if work.finished: prev_result = pow.PowResult.get_pow_result(work.header, work.boundary) if prev_result: if prev_result.verified: logging.info( f"submitted too late, work is verified. {work.header} {work.boundary}" ) _worker.update_stat(inc_failed=1) return False if ethash.is_less_or_equal(prev_result.hash_result, hash_result): logging.info( f"submitted result > old result, ignored. {work.header} {work.boundary}" ) _worker.update_stat(inc_failed=1) return False # 6. save to database hash_result_str = b2h(hash_result, prefix="0x") if not work.save_result(nonce, mix_digest, hash_result_str, miner_wallet, worker_name): logging.warning(f"failed to save result for miner " f"{miner_wallet}-{worker_name}, {work}") return False logging.critical(f"Work submitted, {work.header} {work.boundary}") self.send_success_reply(id) _worker.update_stat(inc_finished=1) self.stratumMiner.set_workDone(work) # 6. todo: miner reward return True