Пример #1
0
    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)
Пример #2
0
    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(),
        }
Пример #3
0
    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(),
        }
Пример #4
0
 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)
Пример #5
0
    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}
Пример #6
0
 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
Пример #7
0
    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)
Пример #8
0
    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