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)
Ejemplo n.º 2
0
    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