async def respond_proof_of_space( self, response: harvester_protocol.RespondProofOfSpace): """ This is a response from the harvester with a proof of space. We check it's validity, and request a pool partial, a header signature, or both, if the proof is good enough. """ if response.proof.pool_pubkey not in self.pool_public_keys: raise RuntimeError("Pool pubkey not in list of approved keys") challenge_hash: bytes32 = self.harvester_responses_challenge[ response.quality_string] challenge_weight: uint128 = self.challenge_to_weight[challenge_hash] challenge_height: uint32 = self.challenge_to_height[challenge_hash] new_proof_height: uint32 = uint32(challenge_height + 1) difficulty: uint64 = uint64(0) for posf in self.challenges[challenge_weight]: if posf.challenge_hash == challenge_hash: difficulty = posf.difficulty if difficulty == 0: raise RuntimeError("Did not find challenge") computed_quality_string = response.proof.verify_and_get_quality_string( ) if response.quality_string != computed_quality_string: raise RuntimeError("Invalid quality for proof of space") self.harvester_responses_proofs[ response.quality_string] = response.proof self.harvester_responses_proof_hash_to_qual[ response.proof.get_hash()] = response.quality_string estimate_min = (self.proof_of_time_estimate_ips * self.constants["BLOCK_TIME_TARGET"] / self.constants["MIN_ITERS_PROPORTION"]) number_iters: uint64 = calculate_iterations_quality( computed_quality_string, response.proof.size, difficulty, estimate_min, ) estimate_secs: float = number_iters / self.proof_of_time_estimate_ips if estimate_secs < self.config["pool_share_threshold"]: request1 = harvester_protocol.RequestPartialProof( response.quality_string, self.wallet_target, ) yield OutboundMessage( NodeType.HARVESTER, Message("request_partial_proof", request1), Delivery.RESPOND, ) if estimate_secs < self.config["propagate_threshold"]: pool_pk = bytes(response.proof.pool_pubkey) if pool_pk not in self.pool_sks_map: log.error( f"Don't have the private key for the pool key used by harvester: {pool_pk.hex()}" ) return sk = self.pool_sks_map[pool_pk] coinbase_reward = uint64( calculate_block_reward(uint32(new_proof_height))) coinbase, signature = create_coinbase_coin_and_signature( new_proof_height, self.pool_target, coinbase_reward, sk, ) request2 = farmer_protocol.RequestHeaderHash( challenge_hash, coinbase, signature, self.wallet_target, response.proof, ) yield OutboundMessage( NodeType.FULL_NODE, Message("request_header_hash", request2), Delivery.BROADCAST, )
async def respond_proof_of_space( self, response: harvester_protocol.RespondProofOfSpace): """ This is a response from the harvester with a proof of space. We check it's validity, and request a pool partial, a header signature, or both, if the proof is good enough. """ pool_sks: List[PrivateKey] = [ PrivateKey.from_bytes(bytes.fromhex(ce)) for ce in self.key_config["pool_sks"] ] assert response.proof.pool_pubkey in [ sk.get_public_key() for sk in pool_sks ] challenge_hash: bytes32 = self.harvester_responses_challenge[ response.quality] challenge_weight: uint64 = self.challenge_to_weight[challenge_hash] challenge_height: uint32 = self.challenge_to_height[challenge_hash] new_proof_height: uint32 = uint32(challenge_height + 1) difficulty: uint64 = uint64(0) for posf in self.challenges[challenge_weight]: if posf.challenge_hash == challenge_hash: difficulty = posf.difficulty if difficulty == 0: raise RuntimeError("Did not find challenge") computed_quality = response.proof.verify_and_get_quality() assert response.quality == computed_quality self.harvester_responses_proofs[response.quality] = response.proof self.harvester_responses_proof_hash_to_qual[ response.proof.get_hash()] = response.quality number_iters: uint64 = calculate_iterations_quality( computed_quality, response.proof.size, difficulty, self.proof_of_time_estimate_ips, constants["MIN_BLOCK_TIME"], ) estimate_secs: float = number_iters / self.proof_of_time_estimate_ips if estimate_secs < self.config["pool_share_threshold"]: request1 = harvester_protocol.RequestPartialProof( response.quality, sha256(bytes.fromhex( self.key_config["farmer_target"])).digest(), ) yield OutboundMessage( NodeType.HARVESTER, Message("request_partial_proof", request1), Delivery.RESPOND, ) if estimate_secs < self.config["propagate_threshold"]: if new_proof_height not in self.coinbase_rewards: log.error( f"Don't have coinbase transaction for height {new_proof_height}, cannot submit PoS" ) return coinbase, signature = self.coinbase_rewards[new_proof_height] request2 = farmer_protocol.RequestHeaderHash( challenge_hash, coinbase, signature, bytes.fromhex(self.key_config["farmer_target"]), response.proof, ) yield OutboundMessage( NodeType.FULL_NODE, Message("request_header_hash", request2), Delivery.BROADCAST, )
async def respond_proof_of_space( self, response: harvester_protocol.RespondProofOfSpace ): """ This is a response from the harvester with a proof of space. We check it's validity, and request a pool partial, a header signature, or both, if the proof is good enough. """ challenge_hash: bytes32 = response.proof.challenge_hash challenge_weight: uint128 = self.challenge_to_weight[challenge_hash] difficulty: uint64 = uint64(0) for posf in self.challenges[challenge_weight]: if posf.challenge_hash == challenge_hash: difficulty = posf.difficulty if difficulty == 0: raise RuntimeError("Did not find challenge") computed_quality_string = response.proof.verify_and_get_quality_string( self.constants.NUMBER_ZERO_BITS_CHALLENGE_SIG ) if computed_quality_string is None: raise RuntimeError("Invalid proof of space") self.harvester_responses_proofs[ (response.proof.challenge_hash, response.plot_id, response.response_number) ] = response.proof self.harvester_responses_proof_hash_to_info[response.proof.get_hash()] = ( response.proof.challenge_hash, response.plot_id, response.response_number, ) estimate_min = ( self.proof_of_time_estimate_ips * self.constants.BLOCK_TIME_TARGET / self.constants.MIN_ITERS_PROPORTION ) estimate_min = uint64(int(estimate_min)) number_iters: uint64 = calculate_iterations_quality( computed_quality_string, response.proof.size, difficulty, estimate_min, ) estimate_secs: float = number_iters / self.proof_of_time_estimate_ips if estimate_secs < self.config["pool_share_threshold"]: # TODO: implement pooling pass if estimate_secs < self.config["propagate_threshold"]: pool_pk = bytes(response.proof.pool_public_key) if pool_pk not in self.pool_sks_map: log.error( f"Don't have the private key for the pool key used by harvester: {pool_pk.hex()}" ) return pool_target: PoolTarget = PoolTarget(self.pool_target, uint32(0)) pool_target_signature: G2Element = AugSchemeMPL.sign( self.pool_sks_map[pool_pk], bytes(pool_target) ) request2 = farmer_protocol.RequestHeaderHash( challenge_hash, response.proof, pool_target, pool_target_signature, self.wallet_target, ) yield OutboundMessage( NodeType.FULL_NODE, Message("request_header_hash", request2), Delivery.BROADCAST, )