def __init__( self, farmer_config: Dict, pool_config: Dict, keychain: Keychain, consensus_constants: ConsensusConstants, ): self.config = farmer_config self.harvester_responses_proofs: Dict[Tuple, ProofOfSpace] = {} self.harvester_responses_proof_hash_to_info: Dict[bytes32, Tuple] = {} self.header_hash_to_pos: Dict[bytes32, ProofOfSpace] = {} self.challenges: Dict[ uint128, List[farmer_protocol.ProofOfSpaceFinalized]] = {} self.challenge_to_weight: Dict[bytes32, uint128] = {} self.challenge_to_height: Dict[bytes32, uint32] = {} self.challenge_to_best_iters: Dict[bytes32, uint64] = {} self.challenge_to_estimates: Dict[bytes32, List[float]] = {} self.seen_challenges: Set[bytes32] = set() self.unfinished_challenges: Dict[uint128, List[bytes32]] = {} self.current_weight: uint128 = uint128(0) self.proof_of_time_estimate_ips: uint64 = uint64(100000) self.constants = consensus_constants self._shut_down = False self.server = None self.keychain = keychain self.state_changed_callback: Optional[Callable] = None if len(self._get_public_keys()) == 0: error_str = "No keys exist. Please run 'chia keys generate' or open the UI." raise RuntimeError(error_str) # This is the farmer configuration self.wallet_target = decode_puzzle_hash( self.config["xch_target_address"]) self.pool_public_keys = [ G1Element.from_bytes(bytes.fromhex(pk)) for pk in self.config["pool_public_keys"] ] # This is the pool configuration, which should be moved out to the pool once it exists self.pool_target = decode_puzzle_hash( pool_config["xch_target_address"]) self.pool_sks_map: Dict = {} for key in self._get_private_keys(): self.pool_sks_map[bytes(key.get_g1())] = key assert len(self.wallet_target) == 32 assert len(self.pool_target) == 32 if len(self.pool_sks_map) == 0: error_str = "No keys exist. Please run 'chia keys generate' or open the UI." raise RuntimeError(error_str)
async def cc_spend(self, request): assert self.service.wallet_state_manager is not None wallet_id = int(request["wallet_id"]) wallet: CCWallet = self.service.wallet_state_manager.wallets[wallet_id] puzzle_hash: bytes32 = decode_puzzle_hash(request["inner_address"]) if not isinstance(request["amount"], int) or not isinstance( request["amount"], int ): raise ValueError("An integer amount or fee is required (too many decimals)") amount: uint64 = uint64(request["amount"]) if "fee" in request: fee = uint64(request["fee"]) else: fee = uint64(0) tx: TransactionRecord = await wallet.generate_signed_transaction( [amount], [puzzle_hash], fee ) await wallet.wallet_state_manager.add_pending_transaction(tx) return { "transaction": tx, "transaction_id": tx.name(), }
async def send_transaction(self, request): assert self.service.wallet_state_manager is not None wallet_id = int(request["wallet_id"]) wallet = self.service.wallet_state_manager.wallets[wallet_id] if not isinstance(request["amount"], int) or not isinstance( request["amount"], int ): raise ValueError("An integer amount or fee is required (too many decimals)") amount: uint64 = uint64(request["amount"]) puzzle_hash: bytes32 = decode_puzzle_hash(request["address"]) if "fee" in request: fee = uint64(request["fee"]) else: fee = uint64(0) tx: TransactionRecord = await wallet.generate_signed_transaction( amount, puzzle_hash, fee ) await wallet.push_transaction(tx) # Transaction may not have been included in the mempool yet. Use get_transaction to check. return { "transaction": tx, "transaction_id": tx.name(), }
async def generate_signed_transaction_dict( self, data: Dict[str, Any] ) -> Optional[TransactionRecord]: if not isinstance(data["amount"], int) or not isinstance(data["amount"], int): raise ValueError("An integer amount or fee is required (too many decimals)") amount = uint64(data["amount"]) puzzle_hash = decode_puzzle_hash(data["puzzle_hash"]) return await self.rl_generate_signed_transaction(amount, puzzle_hash)
async def farm_block(self, request): puzzle_hash = request["puzzle_hash"] raw_puzzle_hash = decode_puzzle_hash(puzzle_hash) request = FarmNewBlockProtocol(raw_puzzle_hash) msg = OutboundMessage( NodeType.FULL_NODE, Message("farm_new_block", request), Delivery.BROADCAST, ) self.service.server.push_message(msg) return {"success": True}
async def get_transactions( self, wallet_id: str, ) -> List[TransactionRecord]: res = await self.fetch( "get_transactions", {"wallet_id": wallet_id}, ) reverted_tx: List[TransactionRecord] = [] for modified_tx in res["transactions"]: # Server returns address instead of ph, but TransactionRecord requires ph modified_tx["to_puzzle_hash"] = decode_puzzle_hash( modified_tx["to_address"]).hex() del modified_tx["to_address"] reverted_tx.append(TransactionRecord.from_json_dict(modified_tx)) return reverted_tx
async def generate_signed_transaction_dict( self, data: Dict[str, Any] ) -> Optional[TransactionRecord]: """ Use this to generate transaction. """ # Check that both are integers if not isinstance(data["amount"], int) or not isinstance(data["amount"], int): raise ValueError("An integer amount or fee is required (too many decimals)") amount = uint64(data["amount"]) if "fee" in data: fee = uint64(data["fee"]) else: fee = uint64(0) puzzle_hash = decode_puzzle_hash(data["puzzle_hash"]) return await self.generate_signed_transaction(amount, puzzle_hash, fee)
async def cc_spend(self, request): wallet_id = int(request["wallet_id"]) wallet: CCWallet = self.service.wallet_state_manager.wallets[wallet_id] encoded_puzzle_hash = request["innerpuzhash"] puzzle_hash = decode_puzzle_hash(encoded_puzzle_hash) try: tx = await wallet.generate_signed_transaction( request["amount"], puzzle_hash ) except Exception as e: data = {"status": "FAILED", "reason": f"{e}", "id": wallet_id} return data if tx is None: data = { "status": "FAILED", "reason": "Failed to generate signed transaction", "id": wallet_id, } return data try: await wallet.wallet_state_manager.add_pending_transaction(tx) except Exception as e: data = { "status": "FAILED", "reason": f"Failed to push transaction {e}", } return data sent = False start = time.time() while time.time() - start < TIMEOUT: sent_to: List[ Tuple[str, MempoolInclusionStatus, Optional[str]] ] = await self.service.wallet_state_manager.get_transaction_status( tx.name() ) if len(sent_to) == 0: await asyncio.sleep(0.1) continue status, err = sent_to[0][1], sent_to[0][2] if status == MempoolInclusionStatus.SUCCESS: data = {"status": "SUCCESS", "id": wallet_id} sent = True break elif status == MempoolInclusionStatus.PENDING: assert err is not None data = {"status": "PENDING", "reason": err, "id": wallet_id} sent = True break elif status == MempoolInclusionStatus.FAILED: assert err is not None data = {"status": "FAILED", "reason": err, "id": wallet_id} sent = True break if not sent: data = { "status": "FAILED", "reason": "Timed out. Transaction may or may not have been sent.", "id": wallet_id, } return data