Exemple #1
0
    async def get_farmer(self, request_obj) -> web.Response:
        # TODO(pool): add rate limiting
        launcher_id = hexstr_to_bytes(request_obj.rel_url.query["launcher_id"])
        authentication_token = uint64(request_obj.rel_url.query["authentication_token"])

        authentication_token_error: Optional[web.Response] = check_authentication_token(
            launcher_id, authentication_token, self.pool.authentication_token_timeout
        )
        if authentication_token_error is not None:
            return authentication_token_error

        farmer_record: Optional[FarmerRecord] = await self.pool.store.get_farmer_record(launcher_id)
        if farmer_record is None:
            return error_response(
                PoolErrorCode.FARMER_NOT_KNOWN, f"Farmer with launcher_id {launcher_id.hex()} unknown."
            )

        # Validate provided signature
        signature: G2Element = G2Element.from_bytes(hexstr_to_bytes(request_obj.rel_url.query["signature"]))
        message = std_hash(launcher_id + bytes(authentication_token))
        if not AugSchemeMPL.verify(farmer_record.authentication_public_key, message, signature):
            return error_response(
                PoolErrorCode.INVALID_SIGNATURE,
                f"Failed to verify signature {signature} for launcher_id {launcher_id.hex()}.",
            )

        response: GetFarmerResponse = GetFarmerResponse(
            farmer_record.authentication_public_key,
            farmer_record.payout_instructions,
            farmer_record.difficulty,
            farmer_record.points,
        )

        self.pool.log.info(f"get_farmer response {response.to_json_dict()}, " f"launcher_id: {launcher_id.hex()}")
        return obj_to_response(response)
    async def post_partial(self, request_obj) -> web.Response:
        # TODO(pool): add rate limiting
        start_time = time.time()
        request = await request_obj.json()
        partial: PostPartialRequest = PostPartialRequest.from_json_dict(
            request)

        authentication_token_error = check_authentication_token(
            partial.payload.launcher_id,
            partial.payload.authentication_token,
            self.pool.authentication_token_timeout,
        )
        if authentication_token_error is not None:
            return authentication_token_error

        farmer_record: Optional[
            FarmerRecord] = await self.pool.store.get_farmer_record(
                partial.payload.launcher_id)
        if farmer_record is None:
            return error_response(
                PoolErrorCode.FARMER_NOT_KNOWN,
                f"Farmer with launcher_id {partial.payload.launcher_id.hex()} not known.",
            )

        post_partial_response = await self.pool.process_partial(
            partial, farmer_record, uint64(int(start_time)))

        self.pool.log.info(
            f"post_partial response {post_partial_response}, time: {time.time() - start_time} "
            f"launcher_id: {request['payload']['launcher_id']}")
        return obj_to_response(post_partial_response)
Exemple #3
0
    async def get_login(self, request_obj) -> web.Response:
        # TODO(pool): add rate limiting
        launcher_id = request_obj.rel_url.query["launcher_id"]
        authentication_token = request_obj.rel_url.query["authentication_token"]
        authentication_token_error = check_authentication_token(
            launcher_id, authentication_token, self.pool.authentication_token_timeout
        )
        if authentication_token_error is not None:
            return authentication_token_error

        farmer_record: Optional[FarmerRecord] = await self.pool.store.get_farmer_record(launcher_id)
        if farmer_record is None:
            return error_response(PoolErrorCode.FARMER_NOT_KNOWN, f"Farmer with launcher_id {launcher_id} unknown.")

        # Validate provided signature
        signature = request_obj.rel_url.query["signature"]
        message = std_hash(launcher_id + bytes(authentication_token))
        if not AugSchemeMPL.verify(farmer_record.authentication_public_key, message, signature):
            return error_response(
                PoolErrorCode.INVALID_SIGNATURE,
                f"Failed to verify signature {signature} for launcher_id {launcher_id}.",
            )

        self.pool.log.info(f"Login successful for launcher_id: {launcher_id}")

        # TODO(pool) Do what ever you like with the successful login
        return obj_to_response({"login_data", "Put server side login information here?"})
    async def login_response(self, launcher_id):
        record: Optional[
            FarmerRecord] = await self.pool.store.get_farmer_record(launcher_id
                                                                    )
        response = {}
        if record is not None:
            response["farmer_record"] = record
            recent_partials = await self.pool.store.get_recent_partials(
                launcher_id, 20)
            response["recent_partials"] = recent_partials

        return obj_to_response(response)
Exemple #5
0
 async def get_pool_info(self, _) -> web.Response:
     res: PoolInfo = PoolInfo(
         "The Reference Pool",
         "https://www.chia.net/img/chia_logo.svg",
         uint64(self.pool.min_difficulty),
         uint32(self.pool.relative_lock_height),
         "1.0.0",
         str(self.pool.pool_fee),
         "(example) The Reference Pool allows you to pool with low fees, paying out daily using Chia.",
         self.pool.default_pool_puzzle_hash,
     )
     return obj_to_response(res)
 async def get_pool_info(self, _) -> web.Response:
     res: GetPoolInfoResponse = GetPoolInfoResponse(
         self.pool.info_name,
         self.pool.info_logo_url,
         uint64(self.pool.min_difficulty),
         uint32(self.pool.relative_lock_height),
         POOL_PROTOCOL_VERSION,
         str(self.pool.pool_fee),
         self.pool.info_description,
         self.pool.default_target_puzzle_hash,
         self.pool.authentication_token_timeout,
     )
     return obj_to_response(res)
Exemple #7
0
    async def get_login(self, request_obj) -> web.Response:
        # TODO(pool): add rate limiting
        launcher_id: bytes32 = hexstr_to_bytes(
            request_obj.rel_url.query["launcher_id"])
        authentication_token: uint64 = uint64(
            request_obj.rel_url.query["authentication_token"])
        authentication_token_error = check_authentication_token(
            launcher_id, authentication_token,
            self.pool.authentication_token_timeout)
        if authentication_token_error is not None:
            return authentication_token_error

        farmer_record: Optional[
            FarmerRecord] = await self.pool.store.get_farmer_record(launcher_id
                                                                    )
        if farmer_record is None:
            return error_response(
                PoolErrorCode.FARMER_NOT_KNOWN,
                f"Farmer with launcher_id {launcher_id.hex()} unknown.")

        # Validate provided signature
        signature: G2Element = G2Element.from_bytes(
            hexstr_to_bytes(request_obj.rel_url.query["signature"]))
        message: bytes32 = std_hash(
            AuthenticationPayload("get_login", launcher_id,
                                  self.pool.default_target_puzzle_hash,
                                  authentication_token))
        if not AugSchemeMPL.verify(farmer_record.authentication_public_key,
                                   message, signature):
            return error_response(
                PoolErrorCode.INVALID_SIGNATURE,
                f"Failed to verify signature {signature} for launcher_id {launcher_id.hex()}.",
            )

        self.pool.log.info(
            f"Login successful for launcher_id: {launcher_id.hex()}")

        record: Optional[
            FarmerRecord] = await self.pool.store.get_farmer_record(launcher_id
                                                                    )
        response = {}
        if record is not None:
            response["farmer_record"] = record
            recent_partials = await self.pool.store.get_recent_partials(
                launcher_id, 20)
            response["recent_partials"] = recent_partials

        # TODO(pool) Do what ever you like with the successful login
        return obj_to_response(response)
Exemple #8
0
        async def inner(request) -> aiohttp.web.Response:
            request_data = await request.json()
            try:
                res_object = await f(request_data)
                if res_object is None:
                    res_object = {}
                if "success" not in res_object:
                    res_object["success"] = True
            except Exception as e:
                tb = traceback.format_exc()
                self.log.warning(f"Error while handling message: {tb}")
                if len(e.args) > 0:
                    res_object = {"success": False, "error": f"{e.args[0]}"}
                else:
                    res_object = {"success": False, "error": f"{e}"}

            return obj_to_response(res_object)
Exemple #9
0
    async def submit_partial(self, request_obj) -> web.Response:
        start_time = time.time()
        request = await request_obj.json()
        # TODO(pool): add rate limiting
        partial: SubmitPartial = SubmitPartial.from_json_dict(request)
        time_received_partial = uint64(int(time.time()))

        # It's important that on the first request from this farmer, the default difficulty is used. Changing the
        # difficulty requires a few minutes, otherwise farmers can abuse by setting the difficulty right under the
        # proof that they found.
        farmer_record: Optional[
            FarmerRecord] = await self.pool.store.get_farmer_record(
                partial.payload.singleton_genesis)
        if farmer_record is not None:
            curr_difficulty: uint64 = farmer_record.difficulty
            balance = farmer_record.points
        else:
            curr_difficulty = self.pool.default_difficulty
            balance = uint64(0)

        async def await_and_call(cor, *args):
            # 10 seconds gives our node some time to get the signage point, in case we are slightly slowed down
            await asyncio.sleep(10)
            res = await cor(args)
            self.pool.log.info(f"Delayed response: {res}")

        res_dict = await self.pool.process_partial(
            partial,
            time_received_partial,
            balance,
            curr_difficulty,
        )

        if "error_code" in res_dict and "error_code" == PoolErr.NOT_FOUND.value:
            asyncio.create_task(
                await_and_call(self.pool.process_partial, partial,
                               time_received_partial, balance,
                               curr_difficulty))

        self.pool.log.info(
            f"Returning {res_dict}, time: {time.time() - start_time} "
            f"singleton: {request['payload']['singleton_genesis']}")
        return obj_to_response(res_dict)
Exemple #10
0
    async def post_farmer(self, request_obj) -> web.Response:
        # TODO(pool): add rate limiting
        post_farmer_request: PostFarmerRequest = PostFarmerRequest.from_json_dict(
            await request_obj.json())

        authentication_token_error = check_authentication_token(
            post_farmer_request.payload.launcher_id,
            post_farmer_request.payload.authentication_token,
            self.pool.authentication_token_timeout,
        )
        if authentication_token_error is not None:
            return authentication_token_error

        post_farmer_response = await self.pool.add_farmer(post_farmer_request)

        self.pool.log.info(
            f"post_farmer response {post_farmer_response}, "
            f"launcher_id: {post_farmer_request.payload.launcher_id.hex()}", )
        return obj_to_response(post_farmer_response)
Exemple #11
0
        async def inner(request) -> aiohttp.web.Response:
            request_data = await request.json()
            try:
                res_object = await f(request_data)
                if res_object is None:
                    res_object = {}
            except Exception as e:
                tb = traceback.format_exc()
                self.log.warning(f"Error while handling message: {tb}")
                if len(e.args) > 0:
                    res_object = {
                        "error_code": PoolErr.SERVER_EXCEPTION,
                        "error_message": f"{e.args[0]}"
                    }
                else:
                    res_object = {
                        "error_code": PoolErr.SERVER_EXCEPTION,
                        "error_message": f"{e}"
                    }

            return obj_to_response(res_object)
Exemple #12
0
def error_response(code: PoolErrorCode, message: str):
    error: ErrorResponse = ErrorResponse(uint16(code.value), message)
    return obj_to_response(error)