async def test_create_new_pool_wallet_farm_to_pool(self,
                                                       one_wallet_node_and_rpc,
                                                       fee):
        client, wallet_node_0, full_node_api = one_wallet_node_and_rpc
        wallet_0 = wallet_node_0.wallet_state_manager.main_wallet
        our_ph = await wallet_0.get_new_puzzlehash()
        summaries_response = await client.get_wallets()
        for summary in summaries_response:
            if WalletType(int(summary["type"])) == WalletType.POOLING_WALLET:
                assert False

        creation_tx: TransactionRecord = await client.create_new_pool_wallet(
            our_ph, "http://pool.example.com", 10, "localhost:5000", "new",
            "FARMING_TO_POOL", fee)
        await time_out_assert(
            10,
            full_node_api.full_node.mempool_manager.get_spendbundle,
            creation_tx.spend_bundle,
            creation_tx.name,
        )

        await self.farm_blocks(full_node_api, our_ph, 6)
        assert full_node_api.full_node.mempool_manager.get_spendbundle(
            creation_tx.name) is None

        summaries_response = await client.get_wallets()
        wallet_id: Optional[int] = None
        for summary in summaries_response:
            if WalletType(int(summary["type"])) == WalletType.POOLING_WALLET:
                wallet_id = summary["id"]
        assert wallet_id is not None
        status: PoolWalletInfo = (await client.pw_status(wallet_id))[0]

        assert status.current.state == PoolSingletonState.FARMING_TO_POOL.value
        assert status.target is None
        assert status.current.owner_pubkey == G1Element.from_bytes(
            bytes.fromhex(
                "b286bbf7a10fa058d2a2a758921377ef00bb7f8143e1bd40dd195ae918dbef42cfc481140f01b9eae13b430a0c8fe304"
            ))
        assert status.current.pool_url == "http://pool.example.com"
        assert status.current.relative_lock_height == 10
        assert status.current.version == 1
        # Check that config has been written properly
        full_config: Dict = load_config(
            wallet_0.wallet_state_manager.root_path, "config.yaml")
        pool_list: List[Dict] = full_config["pool"]["pool_list"]
        assert len(pool_list) == 1
        pool_config = pool_list[0]
        assert (
            pool_config["authentication_public_key"] ==
            "0xb3c4b513600729c6b2cf776d8786d620b6acc88f86f9d6f489fa0a0aff81d634262d5348fb7ba304db55185bb4c5c8a4"
        )
        # It can be one of multiple launcher IDs, due to selecting a different coin
        assert pool_config["launcher_id"] in {
            "0x78a1eadf583a2f27a129d7aeba076ec6a5200e1ec8225a72c9d4180342bf91a7",
            "0x2bcab0310e78a7ab04e251ac6bdd5dfc80ce6895132e64f97265029db3d8309a",
            "0x09edf686c318c138cd3461c38e9b4e10e7f21fc476a0929b4480e126b6efcb81",
        }
        assert pool_config["pool_url"] == "http://pool.example.com"
Exemple #2
0
    async def get_unspent_coins_for_wallet(
            self, wallet_id: int) -> Set[WalletCoinRecord]:
        """ Returns set of CoinRecords that have not been spent yet for a wallet. """
        async with self.wallet_cache_lock:
            if wallet_id in self.coin_wallet_record_cache:
                wallet_coins: Dict[
                    bytes32, WalletCoinRecord] = self.coin_wallet_record_cache[
                        wallet_id]
                return set(wallet_coins.values())

            coin_set = set()

            cursor = await self.db_connection.execute(
                "SELECT * from coin_record WHERE spent=0 and wallet_id=?",
                (wallet_id, ),
            )
            rows = await cursor.fetchall()
            await cursor.close()
            cache_dict = {}
            for row in rows:
                coin = Coin(bytes32(bytes.fromhex(row[6])),
                            bytes32(bytes.fromhex(row[5])),
                            uint64.from_bytes(row[7]))
                coin_record = WalletCoinRecord(coin, row[1], row[2],
                                               row[3], row[4],
                                               WalletType(row[8]), row[9])
                coin_set.add(coin_record)
                cache_dict[coin.name()] = coin_record

            self.coin_wallet_record_cache[wallet_id] = cache_dict
            return coin_set
    async def get_derivation_record(
            self, index: uint32,
            wallet_id: uint32) -> Optional[DerivationRecord]:
        """
        Returns the derivation record by index and wallet id.
        """
        cursor = await self.db_connection.execute(
            "SELECT * FROM derivation_paths WHERE derivation_index=? and wallet_id=?;",
            (
                index,
                wallet_id,
            ),
        )
        row = await cursor.fetchone()
        await cursor.close()

        if row is not None and row[0] is not None:
            return DerivationRecord(
                uint32(row[0]),
                bytes32.fromhex(row[2]),
                G1Element.from_bytes(bytes.fromhex(row[1])),
                WalletType(row[3]),
                uint32(row[4]),
            )

        return None
async def print_balances(args: dict, wallet_client: WalletRpcClient,
                         fingerprint: int) -> None:
    summaries_response = await wallet_client.get_wallets()
    config = load_config(DEFAULT_ROOT_PATH, "config.yaml")
    address_prefix = config["network_overrides"]["config"][
        config["selected_network"]]["address_prefix"]

    print(f"Wallet height: {await wallet_client.get_height_info()}")
    print(
        f"Sync status: {'Synced' if (await wallet_client.get_synced()) else 'Not synced'}"
    )
    print(f"Balances, fingerprint: {fingerprint}")
    for summary in summaries_response:
        wallet_id = summary["id"]
        balances = await wallet_client.get_wallet_balance(wallet_id)
        typ = WalletType(int(summary["type"]))
        address_prefix, scale = wallet_coin_unit(typ, address_prefix)
        print(f"Wallet ID {wallet_id} type {typ.name} {summary['name']}")
        print(
            f"   -Total Balance: {print_balance(balances['confirmed_wallet_balance'], scale, address_prefix)}"
        )
        print(
            f"   -Pending Total Balance: {print_balance(balances['unconfirmed_wallet_balance'], scale, address_prefix)}"
        )
        print(
            f"   -Spendable: {print_balance(balances['spendable_balance'], scale, address_prefix)}"
        )
Exemple #5
0
async def print_balances(args: dict, wallet_client: WalletRpcClient, fingerprint: int) -> None:
    summaries_response = await wallet_client.get_wallets()
    config = load_config(DEFAULT_ROOT_PATH, "config.yaml")
    address_prefix = config["network_overrides"]["config"][config["selected_network"]]["address_prefix"]

    print(f"Wallet height: {await wallet_client.get_height_info()}")
    print(f"Sync status: {'Synced' if (await wallet_client.get_synced()) else 'Not synced'}")
    print(f"Balances, fingerprint: {fingerprint}")
    for summary in summaries_response:
        wallet_id = summary["id"]
        balances = await wallet_client.get_wallet_balance(wallet_id)
        typ = WalletType(int(summary["type"])).name
        if typ != "STANDARD_WALLET":
            print(f"Wallet ID {wallet_id} type {typ} {summary['name']}")
            print(f"   -Total Balance: " f"{balances['confirmed_wallet_balance']/units['colouredcoin']}")
            print(f"   -Pending Total Balance: {balances['unconfirmed_wallet_balance']/units['colouredcoin']}")
            print(f"   -Spendable Balance: {balances['spendable_balance']/units['colouredcoin']}")
        else:
            print(f"Wallet ID {wallet_id} type {typ}")
            print(
                f"   -Total Balance: {balances['confirmed_wallet_balance']/units['chia']} {address_prefix} "
                f"({balances['confirmed_wallet_balance']} mojo)"
            )
            print(
                f"   -Pending Total Balance: {balances['unconfirmed_wallet_balance']/units['chia']} {address_prefix} "
                f"({balances['unconfirmed_wallet_balance']} mojo)"
            )
            print(
                f"   -Spendable: {balances['spendable_balance']/units['chia']} {address_prefix} "
                f"({balances['spendable_balance']} mojo)"
            )
 def row_to_record(self, row) -> DerivationRecord:
     return DerivationRecord(
         uint32(row[0]),
         bytes32.fromhex(row[2]),
         G1Element.from_bytes(bytes.fromhex(row[1])),
         WalletType(row[3]),
         uint32(row[4]),
         bool(row[6]),
     )
Exemple #7
0
async def get_wallet_type(wallet_id: int,
                          wallet_client: WalletRpcClient) -> WalletType:
    summaries_response = await wallet_client.get_wallets()
    for summary in summaries_response:
        summary_id: int = summary["id"]
        summary_type: int = summary["type"]
        if wallet_id == summary_id:
            return WalletType(summary_type)

    raise LookupError(f"Wallet ID not found: {wallet_id}")
Exemple #8
0
 async def get_coin_records_by_puzzle_hash(self, puzzle_hash: bytes32) -> List[WalletCoinRecord]:
     """Returns a list of all coin records with the given puzzle hash"""
     coins = set()
     cursor = await self.db_connection.execute("SELECT * from coin_record WHERE puzzle_hash=?", (puzzle_hash.hex(),))
     rows = await cursor.fetchall()
     await cursor.close()
     for row in rows:
         coin = Coin(bytes32(bytes.fromhex(row[6])), bytes32(bytes.fromhex(row[5])), uint64.from_bytes(row[7]))
         coins.add(WalletCoinRecord(coin, row[1], row[2], row[3], row[4], WalletType(row[8]), row[9]))
     return list(coins)
Exemple #9
0
    async def get_coin_record_by_coin_id(self, coin_id: bytes32) -> Optional[WalletCoinRecord]:
        """Returns a coin records with the given name, if it exists"""
        cursor = await self.db_connection.execute("SELECT * from coin_record WHERE coin_name=?", (coin_id.hex(),))
        row = await cursor.fetchone()
        await cursor.close()
        if row is None:
            return None

        coin = Coin(bytes32(bytes.fromhex(row[6])), bytes32(bytes.fromhex(row[5])), uint64.from_bytes(row[7]))
        coin_record = WalletCoinRecord(coin, row[1], row[2], row[3], row[4], WalletType(row[8]), row[9])
        return coin_record
Exemple #10
0
 async def get_coin_record(self, coin_name: bytes32) -> Optional[WalletCoinRecord]:
     """ Returns CoinRecord with specified coin id. """
     if coin_name in self.coin_record_cache:
         return self.coin_record_cache[coin_name]
     cursor = await self.db_connection.execute("SELECT * from coin_record WHERE coin_name=?", (coin_name.hex(),))
     row = await cursor.fetchone()
     await cursor.close()
     if row is not None:
         coin = Coin(bytes32(bytes.fromhex(row[6])), bytes32(bytes.fromhex(row[5])), uint64.from_bytes(row[7]))
         return WalletCoinRecord(coin, row[1], row[2], row[3], row[4], WalletType(row[8]), row[9])
     return None
Exemple #11
0
    async def get_all_coins(self) -> Set[WalletCoinRecord]:
        """ Returns set of all CoinRecords."""
        coins = set()

        cursor = await self.db_connection.execute("SELECT * from coin_record")
        rows = await cursor.fetchall()
        await cursor.close()
        for row in rows:
            coin = Coin(bytes32(bytes.fromhex(row[6])), bytes32(bytes.fromhex(row[5])), uint64.from_bytes(row[7]))
            coins.add(WalletCoinRecord(coin, row[1], row[2], row[3], row[4], WalletType(row[8]), row[9]))
        return coins
Exemple #12
0
    async def get_wallet_action(self, id: int) -> Optional[WalletAction]:
        """
        Return a wallet action by id
        """

        cursor = await self.db_connection.execute("SELECT * from action_queue WHERE id=?", (id,))
        row = await cursor.fetchone()
        await cursor.close()

        if row is None:
            return None

        return WalletAction(row[0], row[1], row[2], WalletType(row[3]), row[4], bool(row[5]), row[6])
    async def wallet_info_for_puzzle_hash(self, puzzle_hash: bytes32) -> Optional[Tuple[uint32, WalletType]]:
        """
        Returns the derivation path for the puzzle_hash.
        Returns None if not present.
        """

        cursor = await self.db_connection.execute(
            "SELECT * from derivation_paths WHERE puzzle_hash=?", (puzzle_hash.hex(),)
        )
        row = await cursor.fetchone()
        await cursor.close()

        if row is not None:
            return row[4], WalletType(row[3])

        return None
Exemple #14
0
    async def get_all_pending_actions(self) -> List[WalletAction]:
        """
        Returns list of all pending action
        """
        result: List[WalletAction] = []
        cursor = await self.db_connection.execute("SELECT * from action_queue WHERE done=?", (0,))
        rows = await cursor.fetchall()
        await cursor.close()

        if rows is None:
            return result

        for row in rows:
            action = WalletAction(row[0], row[1], row[2], WalletType(row[3]), row[4], bool(row[5]), row[6])
            result.append(action)

        return result
Exemple #15
0
def get_backup_info(file_path, private_key):
    json_dict = open_backup_file(file_path, private_key)
    data = json_dict["data"]
    wallet_list_json = data["wallet_list"]

    info_dict = {}
    wallets = []
    for wallet_info in wallet_list_json:
        wallet = {}
        wallet["name"] = wallet_info["name"]
        wallet["type"] = wallet_info["type"]
        wallet["type_name"] = WalletType(wallet_info["type"]).name
        wallet["id"] = wallet_info["id"]
        wallet["data"] = wallet_info["data"]
        wallets.append(wallet)

    info_dict["version"] = data["version"]
    info_dict["fingerprint"] = data["fingerprint"]
    info_dict["timestamp"] = data["timestamp"]
    info_dict["wallets"] = wallets

    return info_dict
    async def get_derivation_record_for_puzzle_hash(self, puzzle_hash: bytes32) -> Optional[DerivationRecord]:
        """
        Returns the derivation record by index and wallet id.
        """
        cursor = await self.db_connection.execute(
            "SELECT * FROM derivation_paths WHERE puzzle_hash=?;",
            (puzzle_hash.hex(),),
        )
        row = await cursor.fetchone()
        await cursor.close()

        if row is not None and row[0] is not None:
            return DerivationRecord(
                uint32(row[0]),
                bytes32.fromhex(row[2]),
                G1Element.from_bytes(bytes.fromhex(row[1])),
                WalletType(row[3]),
                uint32(row[4]),
                bool(row[6]),
            )

        return None
    async def test_absorb_pooling(self, one_wallet_node_and_rpc):
        client, wallet_node_0, full_node_api = one_wallet_node_and_rpc
        wallet_0 = wallet_node_0.wallet_state_manager.main_wallet
        our_ph = await wallet_0.get_new_puzzlehash()
        summaries_response = await client.get_wallets()
        for summary in summaries_response:
            if WalletType(int(summary["type"])) == WalletType.POOLING_WALLET:
                assert False
        # Balance stars at 6 XCH
        assert (await wallet_0.get_confirmed_balance()) == 6000000000000
        creation_tx: TransactionRecord = await client.create_new_pool_wallet(
            our_ph, "http://123.45.67.89", 10, "localhost:5000", "new", "FARMING_TO_POOL"
        )

        await time_out_assert(
            10,
            full_node_api.full_node.mempool_manager.get_spendbundle,
            creation_tx.spend_bundle,
            creation_tx.name,
        )
        await self.farm_blocks(full_node_api, our_ph, 1)
        await asyncio.sleep(2)
        status: PoolWalletInfo = (await client.pw_status(2))[0]

        log.warning(f"{await wallet_0.get_confirmed_balance()}")
        assert status.current.state == PoolSingletonState.FARMING_TO_POOL.value
        plot_id: bytes32 = self.create_pool_plot(status.p2_singleton_puzzle_hash)
        all_blocks = await full_node_api.get_all_full_blocks()
        blocks = bt.get_consecutive_blocks(
            3,
            block_list_input=all_blocks,
            force_plot_id=plot_id,
            farmer_reward_puzzle_hash=our_ph,
            guarantee_transaction_block=True,
        )

        await full_node_api.full_node.respond_block(full_node_protocol.RespondBlock(blocks[-3]))
        await full_node_api.full_node.respond_block(full_node_protocol.RespondBlock(blocks[-2]))
        await full_node_api.full_node.respond_block(full_node_protocol.RespondBlock(blocks[-1]))
        await asyncio.sleep(2)
        bal = await client.get_wallet_balance(2)
        log.warning(f"{await wallet_0.get_confirmed_balance()}")
        # Pooled plots don't have balance
        assert bal["confirmed_wallet_balance"] == 0

        # Claim 2 * 1.75, and farm a new 1.75
        absorb_tx: TransactionRecord = await client.pw_absorb_rewards(2)
        await time_out_assert(
            5,
            full_node_api.full_node.mempool_manager.get_spendbundle,
            absorb_tx.spend_bundle,
            absorb_tx.name,
        )
        await self.farm_blocks(full_node_api, our_ph, 2)
        await asyncio.sleep(2)
        new_status: PoolWalletInfo = (await client.pw_status(2))[0]
        assert status.current == new_status.current
        assert status.tip_singleton_coin_id != new_status.tip_singleton_coin_id
        bal = await client.get_wallet_balance(2)
        log.warning(f"{await wallet_0.get_confirmed_balance()}")
        assert bal["confirmed_wallet_balance"] == 0

        # Claim another 1.75
        absorb_tx: TransactionRecord = await client.pw_absorb_rewards(2)
        absorb_tx.spend_bundle.debug()
        await time_out_assert(
            5,
            full_node_api.full_node.mempool_manager.get_spendbundle,
            absorb_tx.spend_bundle,
            absorb_tx.name,
        )

        await self.farm_blocks(full_node_api, our_ph, 2)
        await asyncio.sleep(2)
        bal = await client.get_wallet_balance(2)
        assert bal["confirmed_wallet_balance"] == 0
        log.warning(f"{await wallet_0.get_confirmed_balance()}")
        self.delete_plot(plot_id)
        assert len(await wallet_node_0.wallet_state_manager.tx_store.get_unconfirmed_for_wallet(2)) == 0
        assert (
            wallet_node_0.wallet_state_manager.get_peak().height == full_node_api.full_node.blockchain.get_peak().height
        )
        # Balance stars at 6 XCH and 5 more blocks are farmed, total 22 XCH
        assert (await wallet_0.get_confirmed_balance()) == 21999999999999
Exemple #18
0
    async def test_leave_pool(self, setup, fee, trusted):
        """This tests self-pooling -> pooling -> escaping -> self pooling"""
        full_nodes, wallet_nodes, receive_address, client, rpc_cleanup = setup
        our_ph = receive_address[0]
        wallets = [wallet_n.wallet_state_manager.main_wallet for wallet_n in wallet_nodes]
        pool_ph = receive_address[1]
        full_node_api = full_nodes[0]
        if trusted:
            wallet_nodes[0].config["trusted_peers"] = {
                full_node_api.full_node.server.node_id.hex(): full_node_api.full_node.server.node_id.hex()
            }
        else:
            wallet_nodes[0].config["trusted_peers"] = {}

        await wallet_nodes[0].server.start_client(
            PeerInfo(self_hostname, uint16(full_node_api.full_node.server._port)), None
        )

        WAIT_SECS = 200

        try:
            summaries_response = await client.get_wallets()
            for summary in summaries_response:
                if WalletType(int(summary["type"])) == WalletType.POOLING_WALLET:
                    assert False

            async def have_chia():
                await self.farm_blocks(full_node_api, our_ph, 1)
                return (await wallets[0].get_confirmed_balance()) > 0

            await time_out_assert(timeout=WAIT_SECS, function=have_chia)

            creation_tx: TransactionRecord = await client.create_new_pool_wallet(
                our_ph, "", 0, "localhost:5000", "new", "SELF_POOLING", fee
            )

            await time_out_assert(
                10,
                full_node_api.full_node.mempool_manager.get_spendbundle,
                creation_tx.spend_bundle,
                creation_tx.name,
            )

            await self.farm_blocks(full_node_api, our_ph, 6)
            assert full_node_api.full_node.mempool_manager.get_spendbundle(creation_tx.name) is None

            summaries_response = await client.get_wallets()
            wallet_id: Optional[int] = None
            for summary in summaries_response:
                if WalletType(int(summary["type"])) == WalletType.POOLING_WALLET:
                    wallet_id = summary["id"]
            assert wallet_id is not None
            status: PoolWalletInfo = (await client.pw_status(wallet_id))[0]

            assert status.current.state == PoolSingletonState.SELF_POOLING.value
            assert status.target is None

            join_pool_tx: TransactionRecord = await client.pw_join_pool(
                wallet_id,
                pool_ph,
                "https://pool.example.com",
                5,
                fee,
            )
            assert join_pool_tx is not None

            status: PoolWalletInfo = (await client.pw_status(wallet_id))[0]

            assert status.current.state == PoolSingletonState.SELF_POOLING.value
            assert status.current.pool_url is None
            assert status.current.relative_lock_height == 0
            assert status.current.state == 1
            assert status.current.version == 1

            assert status.target.pool_url == "https://pool.example.com"
            assert status.target.relative_lock_height == 5
            assert status.target.state == 3
            assert status.target.version == 1

            async def status_is_farming_to_pool():
                await self.farm_blocks(full_node_api, our_ph, 1)
                pw_status: PoolWalletInfo = (await client.pw_status(wallet_id))[0]
                return pw_status.current.state == PoolSingletonState.FARMING_TO_POOL.value

            await time_out_assert(timeout=WAIT_SECS, function=status_is_farming_to_pool)

            status: PoolWalletInfo = (await client.pw_status(wallet_id))[0]

            leave_pool_tx: TransactionRecord = await client.pw_self_pool(wallet_id, fee)
            assert leave_pool_tx.wallet_id == wallet_id
            assert leave_pool_tx.amount == 1

            async def status_is_leaving():
                await self.farm_blocks(full_node_api, our_ph, 1)
                pw_status: PoolWalletInfo = (await client.pw_status(wallet_id))[0]
                return pw_status.current.state == PoolSingletonState.LEAVING_POOL.value

            await time_out_assert(timeout=WAIT_SECS, function=status_is_leaving)

            async def status_is_self_pooling():
                # Farm enough blocks to wait for relative_lock_height
                await self.farm_blocks(full_node_api, our_ph, 1)
                pw_status: PoolWalletInfo = (await client.pw_status(wallet_id))[0]
                return pw_status.current.state == PoolSingletonState.SELF_POOLING.value

            await time_out_assert(timeout=WAIT_SECS, function=status_is_self_pooling)
            assert len(await wallets[0].wallet_state_manager.tx_store.get_unconfirmed_for_wallet(2)) == 0

        finally:
            client.close()
            await client.await_closed()
            await rpc_cleanup()
Exemple #19
0
    async def create_more_puzzle_hashes(self, from_zero: bool = False):
        """
        For all wallets in the user store, generates the first few puzzle hashes so
        that we can restore the wallet from only the private keys.
        """
        targets = list(self.wallets.keys())

        unused: Optional[
            uint32] = await self.puzzle_store.get_unused_derivation_path()
        if unused is None:
            # This handles the case where the database has entries but they have all been used
            unused = await self.puzzle_store.get_last_derivation_path()
            if unused is None:
                # This handles the case where the database is empty
                unused = uint32(0)

        if self.new_wallet:
            to_generate = self.config["initial_num_public_keys_new_wallet"]
        else:
            to_generate = self.config["initial_num_public_keys"]

        for wallet_id in targets:
            target_wallet = self.wallets[wallet_id]

            last: Optional[
                uint32] = await self.puzzle_store.get_last_derivation_path_for_wallet(
                    wallet_id)

            start_index = 0
            derivation_paths: List[DerivationRecord] = []

            if last is not None:
                start_index = last + 1

            # If the key was replaced (from_zero=True), we should generate the puzzle hashes for the new key
            if from_zero:
                start_index = 0

            for index in range(start_index, unused + to_generate):
                if WalletType(target_wallet.type()) == WalletType.RATE_LIMITED:
                    if target_wallet.rl_info.initialized is False:
                        break
                    wallet_type = target_wallet.rl_info.type
                    if wallet_type == "user":
                        rl_pubkey = G1Element.from_bytes(
                            target_wallet.rl_info.user_pubkey)
                    else:
                        rl_pubkey = G1Element.from_bytes(
                            target_wallet.rl_info.admin_pubkey)
                    rl_puzzle: Program = target_wallet.puzzle_for_pk(rl_pubkey)
                    puzzle_hash: bytes32 = rl_puzzle.get_tree_hash()

                    rl_index = self.get_derivation_index(rl_pubkey)
                    if rl_index == -1:
                        break

                    derivation_paths.append(
                        DerivationRecord(
                            uint32(rl_index),
                            puzzle_hash,
                            rl_pubkey,
                            target_wallet.type(),
                            uint32(target_wallet.id()),
                        ))
                    break

                pubkey: G1Element = self.get_public_key(uint32(index))
                puzzle: Program = target_wallet.puzzle_for_pk(bytes(pubkey))
                if puzzle is None:
                    self.log.warning(
                        f"Unable to create puzzles with wallet {target_wallet}"
                    )
                    break
                puzzlehash: bytes32 = puzzle.get_tree_hash()
                self.log.info(
                    f"Puzzle at index {index} wallet ID {wallet_id} puzzle hash {puzzlehash.hex()}"
                )
                derivation_paths.append(
                    DerivationRecord(
                        uint32(index),
                        puzzlehash,
                        pubkey,
                        target_wallet.type(),
                        uint32(target_wallet.id()),
                    ))

            await self.puzzle_store.add_derivation_paths(derivation_paths)
        if unused > 0:
            await self.puzzle_store.set_used_up_to(uint32(unused - 1))
 def coin_record_from_row(self, row: sqlite3.Row) -> WalletCoinRecord:
     coin = Coin(bytes32(bytes.fromhex(row[6])),
                 bytes32(bytes.fromhex(row[5])), uint64.from_bytes(row[7]))
     return WalletCoinRecord(coin, uint32(row[1]), uint32(row[2]),
                             bool(row[3]), bool(row[4]), WalletType(row[8]),
                             row[9])
    async def test_change_pools_reorg(self, setup):
        """This tests Pool A -> escaping -> reorg -> escaping -> Pool B"""
        full_nodes, wallets, receive_address, client, rpc_cleanup = setup
        our_ph = receive_address[0]
        pool_a_ph = receive_address[1]
        pool_b_ph = await wallets[1].get_new_puzzlehash()

        full_node_api = full_nodes[0]
        WAIT_SECS = 30

        try:
            summaries_response = await client.get_wallets()
            for summary in summaries_response:
                if WalletType(int(summary["type"])) == WalletType.POOLING_WALLET:
                    assert False

            async def have_chia():
                await self.farm_blocks(full_node_api, our_ph, 1)
                return (await wallets[0].get_confirmed_balance()) > 0

            await time_out_assert(timeout=WAIT_SECS, function=have_chia)

            creation_tx: TransactionRecord = await client.create_new_pool_wallet(
                pool_a_ph, "https://pool-a.org", 5, "localhost:5000", "new", "FARMING_TO_POOL"
            )

            await time_out_assert(
                10,
                full_node_api.full_node.mempool_manager.get_spendbundle,
                creation_tx.spend_bundle,
                creation_tx.name,
            )

            await self.farm_blocks(full_node_api, our_ph, 6)
            assert full_node_api.full_node.mempool_manager.get_spendbundle(creation_tx.name) is None

            summaries_response = await client.get_wallets()
            wallet_id: Optional[int] = None
            for summary in summaries_response:
                if WalletType(int(summary["type"])) == WalletType.POOLING_WALLET:
                    wallet_id = summary["id"]
            assert wallet_id is not None
            status: PoolWalletInfo = (await client.pw_status(wallet_id))[0]

            assert status.current.state == PoolSingletonState.FARMING_TO_POOL.value
            assert status.target is None

            async def status_is_farming_to_pool():
                await self.farm_blocks(full_node_api, our_ph, 1)
                pw_status: PoolWalletInfo = (await client.pw_status(wallet_id))[0]
                return pw_status.current.state == PoolSingletonState.FARMING_TO_POOL.value

            await time_out_assert(timeout=WAIT_SECS, function=status_is_farming_to_pool)

            pw_info: PoolWalletInfo = (await client.pw_status(wallet_id))[0]
            assert pw_info.current.pool_url == "https://pool-a.org"
            assert pw_info.current.relative_lock_height == 5

            original_height = full_node_api.full_node.blockchain.get_peak().height
            join_pool_tx: TransactionRecord = await client.pw_join_pool(
                wallet_id,
                pool_b_ph,
                "https://pool-b.org",
                10,
            )
            assert join_pool_tx is not None
            await time_out_assert(
                10,
                full_node_api.full_node.mempool_manager.get_spendbundle,
                join_pool_tx.spend_bundle,
                join_pool_tx.name,
            )
            await self.farm_blocks(full_node_api, our_ph, 1)

            async def status_is_leaving_no_blocks():
                pw_status: PoolWalletInfo = (await client.pw_status(wallet_id))[0]
                return pw_status.current.state == PoolSingletonState.LEAVING_POOL.value

            async def status_is_farming_to_pool_no_blocks():
                pw_status: PoolWalletInfo = (await client.pw_status(wallet_id))[0]
                return pw_status.current.state == PoolSingletonState.FARMING_TO_POOL.value

            await time_out_assert(timeout=WAIT_SECS, function=status_is_leaving_no_blocks)

            log.warning(f"Doing reorg: {original_height - 1} {original_height + 2}")
            current_blocks = await full_node_api.get_all_full_blocks()
            more_blocks = full_node_api.bt.get_consecutive_blocks(
                3,
                farmer_reward_puzzle_hash=pool_a_ph,
                pool_reward_puzzle_hash=pool_b_ph,
                block_list_input=current_blocks[:-1],
                force_overflow=True,
                guarantee_transaction_block=True,
                seed=32 * b"4",
                transaction_data=join_pool_tx.spend_bundle,
            )

            for block in more_blocks[-3:]:
                await full_node_api.full_node.respond_block(RespondBlock(block))

            await asyncio.sleep(5)
            await time_out_assert(timeout=WAIT_SECS, function=status_is_leaving_no_blocks)

            # Eventually, leaves pool
            await time_out_assert(timeout=WAIT_SECS, function=status_is_farming_to_pool)

        finally:
            client.close()
            await client.await_closed()
            await rpc_cleanup()
    async def test_change_pools(self, setup):
        """This tests Pool A -> escaping -> Pool B"""
        full_nodes, wallets, receive_address, client, rpc_cleanup = setup
        our_ph = receive_address[0]
        pool_a_ph = receive_address[1]
        pool_b_ph = await wallets[1].get_new_puzzlehash()

        full_node_api = full_nodes[0]
        WAIT_SECS = 200

        try:
            summaries_response = await client.get_wallets()
            for summary in summaries_response:
                if WalletType(int(summary["type"])) == WalletType.POOLING_WALLET:
                    assert False

            async def have_chia():
                await self.farm_blocks(full_node_api, our_ph, 1)
                return (await wallets[0].get_confirmed_balance()) > 0

            await time_out_assert(timeout=WAIT_SECS, function=have_chia)

            creation_tx: TransactionRecord = await client.create_new_pool_wallet(
                pool_a_ph, "https://pool-a.org", 5, "localhost:5000", "new", "FARMING_TO_POOL"
            )

            await time_out_assert(
                10,
                full_node_api.full_node.mempool_manager.get_spendbundle,
                creation_tx.spend_bundle,
                creation_tx.name,
            )

            await self.farm_blocks(full_node_api, our_ph, 6)
            assert full_node_api.full_node.mempool_manager.get_spendbundle(creation_tx.name) is None

            summaries_response = await client.get_wallets()
            wallet_id: Optional[int] = None
            for summary in summaries_response:
                if WalletType(int(summary["type"])) == WalletType.POOLING_WALLET:
                    wallet_id = summary["id"]
            assert wallet_id is not None
            status: PoolWalletInfo = (await client.pw_status(wallet_id))[0]

            assert status.current.state == PoolSingletonState.FARMING_TO_POOL.value
            assert status.target is None

            async def status_is_farming_to_pool():
                await self.farm_blocks(full_node_api, our_ph, 1)
                pw_status: PoolWalletInfo = (await client.pw_status(wallet_id))[0]
                return pw_status.current.state == PoolSingletonState.FARMING_TO_POOL.value

            await time_out_assert(timeout=WAIT_SECS, function=status_is_farming_to_pool)

            pw_info: PoolWalletInfo = (await client.pw_status(wallet_id))[0]
            assert pw_info.current.pool_url == "https://pool-a.org"
            assert pw_info.current.relative_lock_height == 5
            status: PoolWalletInfo = (await client.pw_status(wallet_id))[0]

            join_pool_tx: TransactionRecord = await client.pw_join_pool(
                wallet_id,
                pool_b_ph,
                "https://pool-b.org",
                10,
            )
            assert join_pool_tx is not None

            async def status_is_leaving():
                await self.farm_blocks(full_node_api, our_ph, 1)
                pw_status: PoolWalletInfo = (await client.pw_status(wallet_id))[0]
                return pw_status.current.state == PoolSingletonState.LEAVING_POOL.value

            await time_out_assert(timeout=WAIT_SECS, function=status_is_leaving)
            pw_info: PoolWalletInfo = (await client.pw_status(wallet_id))[0]

            await time_out_assert(timeout=WAIT_SECS, function=status_is_farming_to_pool)
            pw_info: PoolWalletInfo = (await client.pw_status(wallet_id))[0]
            assert pw_info.current.pool_url == "https://pool-b.org"
            assert pw_info.current.relative_lock_height == 10
            assert len(await wallets[0].wallet_state_manager.tx_store.get_unconfirmed_for_wallet(2)) == 0

        finally:
            client.close()
            await client.await_closed()
            await rpc_cleanup()
    async def test_leave_pool(self, setup):
        """This tests self-pooling -> pooling -> escaping -> self pooling"""
        full_nodes, wallets, receive_address, client, rpc_cleanup = setup
        our_ph = receive_address[0]
        pool_ph = receive_address[1]
        full_node_api = full_nodes[0]
        WAIT_SECS = 200

        try:
            summaries_response = await client.get_wallets()
            for summary in summaries_response:
                if WalletType(int(summary["type"])) == WalletType.POOLING_WALLET:
                    assert False

            async def have_chia():
                await self.farm_blocks(full_node_api, our_ph, 1)
                return (await wallets[0].get_confirmed_balance()) > 0

            await time_out_assert(timeout=WAIT_SECS, function=have_chia)

            creation_tx: TransactionRecord = await client.create_new_pool_wallet(
                our_ph, "", 0, "localhost:5000", "new", "SELF_POOLING"
            )

            await time_out_assert(
                10,
                full_node_api.full_node.mempool_manager.get_spendbundle,
                creation_tx.spend_bundle,
                creation_tx.name,
            )

            await self.farm_blocks(full_node_api, our_ph, 6)
            assert full_node_api.full_node.mempool_manager.get_spendbundle(creation_tx.name) is None

            summaries_response = await client.get_wallets()
            wallet_id: Optional[int] = None
            for summary in summaries_response:
                if WalletType(int(summary["type"])) == WalletType.POOLING_WALLET:
                    wallet_id = summary["id"]
            assert wallet_id is not None
            status: PoolWalletInfo = (await client.pw_status(wallet_id))[0]

            assert status.current.state == PoolSingletonState.SELF_POOLING.value
            assert status.target is None

            join_pool_tx: TransactionRecord = await client.pw_join_pool(
                wallet_id,
                pool_ph,
                "https://pool.example.com",
                5,
            )
            assert join_pool_tx is not None

            status: PoolWalletInfo = (await client.pw_status(wallet_id))[0]

            assert status.current.state == PoolSingletonState.SELF_POOLING.value
            assert status.current.to_json_dict() == {
                "owner_pubkey": "0xb286bbf7a10fa058d2a2a758921377ef00bb7f8143e1bd40dd195ae918dbef42cfc481140f01b9eae13b430a0c8fe304",
                "pool_url": None,
                "relative_lock_height": 0,
                "state": 1,
                "target_puzzle_hash": "0x738127e26cb61ffe5530ce0cef02b5eeadb1264aa423e82204a6d6bf9f31c2b7",
                "version": 1,
            }
            assert status.target.to_json_dict() == {
                "owner_pubkey": "0xb286bbf7a10fa058d2a2a758921377ef00bb7f8143e1bd40dd195ae918dbef42cfc481140f01b9eae13b430a0c8fe304",
                "pool_url": "https://pool.example.com",
                "relative_lock_height": 5,
                "state": 3,
                "target_puzzle_hash": "0x9ba327777484b8300d60427e4f3b776ac81948dfedd069a8d3f55834e101696e",
                "version": 1,
            }

            async def status_is_farming_to_pool():
                await self.farm_blocks(full_node_api, our_ph, 1)
                pw_status: PoolWalletInfo = (await client.pw_status(wallet_id))[0]
                return pw_status.current.state == PoolSingletonState.FARMING_TO_POOL.value

            await time_out_assert(timeout=WAIT_SECS, function=status_is_farming_to_pool)

            status: PoolWalletInfo = (await client.pw_status(wallet_id))[0]

            leave_pool_tx: TransactionRecord = await client.pw_self_pool(wallet_id)
            assert leave_pool_tx.wallet_id == wallet_id
            assert leave_pool_tx.amount == 1

            async def status_is_leaving():
                await self.farm_blocks(full_node_api, our_ph, 1)
                pw_status: PoolWalletInfo = (await client.pw_status(wallet_id))[0]
                return pw_status.current.state == PoolSingletonState.LEAVING_POOL.value

            await time_out_assert(timeout=WAIT_SECS, function=status_is_leaving)
            pw_info: PoolWalletInfo = (await client.pw_status(wallet_id))[0]

            async def status_is_self_pooling():
                # Farm enough blocks to wait for relative_lock_height
                await self.farm_blocks(full_node_api, our_ph, 1)
                pw_status: PoolWalletInfo = (await client.pw_status(wallet_id))[0]
                return pw_status.current.state == PoolSingletonState.SELF_POOLING.value

            await time_out_assert(timeout=WAIT_SECS, function=status_is_self_pooling)
            pw_info: PoolWalletInfo = (await client.pw_status(wallet_id))[0]
            assert len(await wallets[0].wallet_state_manager.tx_store.get_unconfirmed_for_wallet(2)) == 0

        finally:
            client.close()
            await client.await_closed()
            await rpc_cleanup()
Exemple #24
0
    async def test_self_pooling_to_pooling(self, setup, fee, trusted):
        """This tests self-pooling -> pooling"""
        num_blocks = 4  # Num blocks to farm at a time
        total_blocks = 0  # Total blocks farmed so far
        full_nodes, wallet_nodes, receive_address, client, rpc_cleanup = setup
        wallets = [wallet_n.wallet_state_manager.main_wallet for wallet_n in wallet_nodes]
        wallet_node_0 = wallet_nodes[0]
        our_ph = receive_address[0]
        pool_ph = receive_address[1]
        full_node_api = full_nodes[0]
        if trusted:
            wallet_node_0.config["trusted_peers"] = {
                full_node_api.full_node.server.node_id.hex(): full_node_api.full_node.server.node_id.hex()
            }
        else:
            wallet_node_0.config["trusted_peers"] = {}

        await wallet_node_0.server.start_client(
            PeerInfo(self_hostname, uint16(full_node_api.full_node.server._port)), None
        )

        try:
            total_blocks += await self.farm_blocks(full_node_api, our_ph, num_blocks)
            total_block_rewards = await self.get_total_block_rewards(total_blocks)

            await time_out_assert(10, wallets[0].get_unconfirmed_balance, total_block_rewards)
            await time_out_assert(10, wallets[0].get_confirmed_balance, total_block_rewards)
            await time_out_assert(10, wallets[0].get_spendable_balance, total_block_rewards)
            assert total_block_rewards > 0

            summaries_response = await client.get_wallets()
            for summary in summaries_response:
                if WalletType(int(summary["type"])) == WalletType.POOLING_WALLET:
                    assert False

            creation_tx: TransactionRecord = await client.create_new_pool_wallet(
                our_ph, "", 0, "localhost:5000", "new", "SELF_POOLING", fee
            )
            creation_tx_2: TransactionRecord = await client.create_new_pool_wallet(
                our_ph, "", 0, "localhost:5000", "new", "SELF_POOLING", fee
            )

            await time_out_assert(
                10,
                full_node_api.full_node.mempool_manager.get_spendbundle,
                creation_tx.spend_bundle,
                creation_tx.name,
            )
            await time_out_assert(
                10,
                full_node_api.full_node.mempool_manager.get_spendbundle,
                creation_tx_2.spend_bundle,
                creation_tx_2.name,
            )

            await self.farm_blocks(full_node_api, our_ph, 6)
            assert full_node_api.full_node.mempool_manager.get_spendbundle(creation_tx.name) is None

            summaries_response = await client.get_wallets()
            wallet_id: Optional[int] = None
            wallet_id_2: Optional[int] = None
            for summary in summaries_response:
                if WalletType(int(summary["type"])) == WalletType.POOLING_WALLET:
                    if wallet_id is not None:
                        wallet_id_2 = summary["id"]
                    else:
                        wallet_id = summary["id"]
            await asyncio.sleep(1)
            assert wallet_id is not None
            assert wallet_id_2 is not None
            status: PoolWalletInfo = (await client.pw_status(wallet_id))[0]
            status_2: PoolWalletInfo = (await client.pw_status(wallet_id_2))[0]

            assert status.current.state == PoolSingletonState.SELF_POOLING.value
            assert status_2.current.state == PoolSingletonState.SELF_POOLING.value
            assert status.target is None
            assert status_2.target is None

            log.warning("JOINING POOL")
            join_pool_tx: TransactionRecord = await client.pw_join_pool(
                wallet_id,
                pool_ph,
                "https://pool.example.com",
                10,
                fee,
            )
            join_pool_tx_2: TransactionRecord = await client.pw_join_pool(
                wallet_id_2,
                pool_ph,
                "https://pool.example.com",
                10,
                fee,
            )
            assert join_pool_tx is not None
            assert join_pool_tx_2 is not None

            status: PoolWalletInfo = (await client.pw_status(wallet_id))[0]
            status_2: PoolWalletInfo = (await client.pw_status(wallet_id_2))[0]

            async def tx_is_in_mempool(wid, tx: TransactionRecord):
                fetched: Optional[TransactionRecord] = await client.get_transaction(wid, tx.name)
                return fetched is not None and fetched.is_in_mempool()

            await time_out_assert(5, tx_is_in_mempool, True, wallet_id, join_pool_tx)
            await time_out_assert(5, tx_is_in_mempool, True, wallet_id_2, join_pool_tx_2)

            assert status.current.state == PoolSingletonState.SELF_POOLING.value
            assert status.target is not None
            assert status.target.state == PoolSingletonState.FARMING_TO_POOL.value
            assert status_2.current.state == PoolSingletonState.SELF_POOLING.value
            assert status_2.target is not None
            assert status_2.target.state == PoolSingletonState.FARMING_TO_POOL.value

            await self.farm_blocks(full_node_api, our_ph, 6)

            total_blocks += await self.farm_blocks(full_node_api, our_ph, num_blocks)

            async def status_is_farming_to_pool(w_id: int):
                pw_status: PoolWalletInfo = (await client.pw_status(w_id))[0]
                return pw_status.current.state == PoolSingletonState.FARMING_TO_POOL.value

            await time_out_assert(20, status_is_farming_to_pool, True, wallet_id)
            await time_out_assert(20, status_is_farming_to_pool, True, wallet_id_2)
            assert len(await wallets[0].wallet_state_manager.tx_store.get_unconfirmed_for_wallet(2)) == 0

        finally:
            client.close()
            await client.await_closed()
            await rpc_cleanup()
    async def test_absorb_self(self, one_wallet_node_and_rpc):
        client, wallet_node_0, full_node_api = one_wallet_node_and_rpc
        wallet_0 = wallet_node_0.wallet_state_manager.main_wallet
        our_ph = await wallet_0.get_new_puzzlehash()
        summaries_response = await client.get_wallets()
        for summary in summaries_response:
            if WalletType(int(summary["type"])) == WalletType.POOLING_WALLET:
                assert False

        creation_tx: TransactionRecord = await client.create_new_pool_wallet(
            our_ph, "", 0, "localhost:5000", "new", "SELF_POOLING"
        )

        await time_out_assert(
            10,
            full_node_api.full_node.mempool_manager.get_spendbundle,
            creation_tx.spend_bundle,
            creation_tx.name,
        )
        await self.farm_blocks(full_node_api, our_ph, 1)
        await asyncio.sleep(2)
        status: PoolWalletInfo = (await client.pw_status(2))[0]

        assert status.current.state == PoolSingletonState.SELF_POOLING.value
        plot_id: bytes32 = self.create_pool_plot(status.p2_singleton_puzzle_hash)
        all_blocks = await full_node_api.get_all_full_blocks()
        blocks = bt.get_consecutive_blocks(
            3,
            block_list_input=all_blocks,
            force_plot_id=plot_id,
            farmer_reward_puzzle_hash=our_ph,
            guarantee_transaction_block=True,
        )

        await full_node_api.full_node.respond_block(full_node_protocol.RespondBlock(blocks[-3]))
        await full_node_api.full_node.respond_block(full_node_protocol.RespondBlock(blocks[-2]))
        await full_node_api.full_node.respond_block(full_node_protocol.RespondBlock(blocks[-1]))
        await asyncio.sleep(2)

        bal = await client.get_wallet_balance(2)
        assert bal["confirmed_wallet_balance"] == 2 * 1750000000000

        # Claim 2 * 1.75, and farm a new 1.75
        absorb_tx: TransactionRecord = await client.pw_absorb_rewards(2)
        await time_out_assert(
            5,
            full_node_api.full_node.mempool_manager.get_spendbundle,
            absorb_tx.spend_bundle,
            absorb_tx.name,
        )
        await self.farm_blocks(full_node_api, our_ph, 2)
        await asyncio.sleep(2)
        new_status: PoolWalletInfo = (await client.pw_status(2))[0]
        assert status.current == new_status.current
        assert status.tip_singleton_coin_id != new_status.tip_singleton_coin_id
        bal = await client.get_wallet_balance(2)
        assert bal["confirmed_wallet_balance"] == 1 * 1750000000000

        # Claim another 1.75
        absorb_tx: TransactionRecord = await client.pw_absorb_rewards(2)
        absorb_tx.spend_bundle.debug()
        await time_out_assert(
            5,
            full_node_api.full_node.mempool_manager.get_spendbundle,
            absorb_tx.spend_bundle,
            absorb_tx.name,
        )

        await self.farm_blocks(full_node_api, our_ph, 2)
        await asyncio.sleep(2)
        bal = await client.get_wallet_balance(2)
        assert bal["confirmed_wallet_balance"] == 0

        assert len(await wallet_node_0.wallet_state_manager.tx_store.get_unconfirmed_for_wallet(2)) == 0

        tr: TransactionRecord = await client.send_transaction(
            1, 100, encode_puzzle_hash(status.p2_singleton_puzzle_hash, "txch")
        )
        await time_out_assert(
            10,
            full_node_api.full_node.mempool_manager.get_spendbundle,
            tr.spend_bundle,
            tr.name,
        )
        await self.farm_blocks(full_node_api, our_ph, 2)
        # Balance ignores non coinbase TX
        bal = await client.get_wallet_balance(2)
        assert bal["confirmed_wallet_balance"] == 0

        with pytest.raises(ValueError):
            await client.pw_absorb_rewards(2)

        self.delete_plot(plot_id)
    async def test_create_multiple_pool_wallets(self, one_wallet_node_and_rpc):
        client, wallet_node_0, full_node_api = one_wallet_node_and_rpc
        wallet_0 = wallet_node_0.wallet_state_manager.main_wallet
        our_ph_1 = await wallet_0.get_new_puzzlehash()
        our_ph_2 = await wallet_0.get_new_puzzlehash()
        summaries_response = await client.get_wallets()
        for summary in summaries_response:
            if WalletType(int(summary["type"])) == WalletType.POOLING_WALLET:
                assert False

        creation_tx: TransactionRecord = await client.create_new_pool_wallet(
            our_ph_1, "", 0, "localhost:5000", "new", "SELF_POOLING"
        )
        creation_tx_2: TransactionRecord = await client.create_new_pool_wallet(
            our_ph_1, "localhost", 12, "localhost:5000", "new", "FARMING_TO_POOL"
        )

        await time_out_assert(
            10,
            full_node_api.full_node.mempool_manager.get_spendbundle,
            creation_tx.spend_bundle,
            creation_tx.name,
        )
        await time_out_assert(
            10,
            full_node_api.full_node.mempool_manager.get_spendbundle,
            creation_tx_2.spend_bundle,
            creation_tx_2.name,
        )

        await self.farm_blocks(full_node_api, our_ph_2, 6)
        assert full_node_api.full_node.mempool_manager.get_spendbundle(creation_tx.name) is None
        assert full_node_api.full_node.mempool_manager.get_spendbundle(creation_tx_2.name) is None

        await asyncio.sleep(3)
        status_2: PoolWalletInfo = (await client.pw_status(2))[0]
        status_3: PoolWalletInfo = (await client.pw_status(3))[0]

        if status_2.current.state == PoolSingletonState.SELF_POOLING.value:
            assert status_3.current.state == PoolSingletonState.FARMING_TO_POOL.value
        else:
            assert status_2.current.state == PoolSingletonState.FARMING_TO_POOL.value
            assert status_3.current.state == PoolSingletonState.SELF_POOLING.value

        full_config: Dict = load_config(wallet_0.wallet_state_manager.root_path, "config.yaml")
        pool_list: List[Dict] = full_config["pool"]["pool_list"]
        assert len(pool_list) == 2

        p2_singleton_ph_2: bytes32 = status_2.p2_singleton_puzzle_hash
        p2_singleton_ph_3: bytes32 = status_3.p2_singleton_puzzle_hash
        assert (
            await wallet_node_0.wallet_state_manager.interested_store.get_interested_puzzle_hash_wallet_id(
                p2_singleton_ph_2
            )
        ) is not None
        assert (
            await wallet_node_0.wallet_state_manager.interested_store.get_interested_puzzle_hash_wallet_id(
                p2_singleton_ph_3
            )
        ) is not None
        assert len(await wallet_node_0.wallet_state_manager.tx_store.get_unconfirmed_for_wallet(2)) == 0
        assert len(await wallet_node_0.wallet_state_manager.tx_store.get_unconfirmed_for_wallet(3)) == 0
        # Doing a reorg reverts and removes the pool wallets
        await full_node_api.reorg_from_index_to_new_index(ReorgProtocol(uint32(0), uint32(20), our_ph_2))
        await asyncio.sleep(5)
        summaries_response = await client.get_wallets()
        assert len(summaries_response) == 1

        with pytest.raises(ValueError):
            await client.pw_status(2)
        with pytest.raises(ValueError):
            await client.pw_status(3)
        # It also removed interested PH, so we can recreated the pool wallet with another wallet_id later
        assert (
            await wallet_node_0.wallet_state_manager.interested_store.get_interested_puzzle_hash_wallet_id(
                p2_singleton_ph_2
            )
        ) is None
        assert (
            await wallet_node_0.wallet_state_manager.interested_store.get_interested_puzzle_hash_wallet_id(
                p2_singleton_ph_3
            )
        ) is None
async def pprint_pool_wallet_state(
    wallet_client: WalletRpcClient,
    wallet_id: int,
    pool_wallet_info: PoolWalletInfo,
    address_prefix: str,
    pool_state_dict: Dict,
    unconfirmed_transactions: List[TransactionRecord],
):
    if pool_wallet_info.current.state == PoolSingletonState.LEAVING_POOL and pool_wallet_info.target is None:
        expected_leave_height = pool_wallet_info.singleton_block_height + pool_wallet_info.current.relative_lock_height
        print(
            f"Current state: INVALID_STATE. Please leave/join again after block height {expected_leave_height}"
        )
    else:
        print(
            f"Current state: {PoolSingletonState(pool_wallet_info.current.state).name}"
        )
    print(
        f"Current state from block height: {pool_wallet_info.singleton_block_height}"
    )
    print(f"Launcher ID: {pool_wallet_info.launcher_id}")
    print(
        "Target address (not for plotting): "
        f"{encode_puzzle_hash(pool_wallet_info.current.target_puzzle_hash, address_prefix)}"
    )
    print(f"Owner public key: {pool_wallet_info.current.owner_pubkey}")

    print(
        f"P2 singleton address (pool contract address for plotting): "
        f"{encode_puzzle_hash(pool_wallet_info.p2_singleton_puzzle_hash, address_prefix)}"
    )
    if pool_wallet_info.target is not None:
        print(
            f"Target state: {PoolSingletonState(pool_wallet_info.target.state).name}"
        )
        print(f"Target pool URL: {pool_wallet_info.target.pool_url}")
    if pool_wallet_info.current.state == PoolSingletonState.SELF_POOLING.value:
        balances: Dict = await wallet_client.get_wallet_balance(str(wallet_id))
        balance = balances["confirmed_wallet_balance"]
        typ = WalletType(int(WalletType.POOLING_WALLET))
        address_prefix, scale = wallet_coin_unit(typ, address_prefix)
        print(
            f"Claimable balance: {print_balance(balance, scale, address_prefix)}"
        )
    if pool_wallet_info.current.state == PoolSingletonState.FARMING_TO_POOL:
        print(f"Current pool URL: {pool_wallet_info.current.pool_url}")
        if pool_wallet_info.launcher_id in pool_state_dict:
            print(
                f"Current difficulty: {pool_state_dict[pool_wallet_info.launcher_id]['current_difficulty']}"
            )
            print(
                f"Points balance: {pool_state_dict[pool_wallet_info.launcher_id]['current_points']}"
            )
        print(
            f"Relative lock height: {pool_wallet_info.current.relative_lock_height} blocks"
        )
        payout_instructions: str = pool_state_dict[
            pool_wallet_info.launcher_id]["pool_config"]["payout_instructions"]
        try:
            payout_address = encode_puzzle_hash(
                bytes32.fromhex(payout_instructions), address_prefix)
            print(
                f"Payout instructions (pool will pay to this address): {payout_address}"
            )
        except Exception:
            print(
                f"Payout instructions (pool will pay you with this): {payout_instructions}"
            )
    if pool_wallet_info.current.state == PoolSingletonState.LEAVING_POOL:
        expected_leave_height = pool_wallet_info.singleton_block_height + pool_wallet_info.current.relative_lock_height
        if pool_wallet_info.target is not None:
            print(
                f"Expected to leave after block height: {expected_leave_height}"
            )
Exemple #28
0
async def pprint_pool_wallet_state(
    wallet_client: WalletRpcClient,
    wallet_id: int,
    pool_wallet_info: PoolWalletInfo,
    address_prefix: str,
    pool_state_dict: Dict,
    plot_counts: Counter,
):
    if pool_wallet_info.current.state == PoolSingletonState.LEAVING_POOL and pool_wallet_info.target is None:
        expected_leave_height = pool_wallet_info.singleton_block_height + pool_wallet_info.current.relative_lock_height
        print(
            f"Current state: INVALID_STATE. Please leave/join again after block height {expected_leave_height}"
        )
    else:
        print(
            f"Current state: {PoolSingletonState(pool_wallet_info.current.state).name}"
        )
    print(
        f"Current state from block height: {pool_wallet_info.singleton_block_height}"
    )
    print(f"Launcher ID: {pool_wallet_info.launcher_id}")
    print(
        "Target address (not for plotting): "
        f"{encode_puzzle_hash(pool_wallet_info.current.target_puzzle_hash, address_prefix)}"
    )
    print(
        f"Number of plots: {plot_counts[pool_wallet_info.p2_singleton_puzzle_hash]}"
    )
    print(f"Owner public key: {pool_wallet_info.current.owner_pubkey}")

    print(
        f"Pool contract address (use ONLY for plotting - do not send money to this address): "
        f"{encode_puzzle_hash(pool_wallet_info.p2_singleton_puzzle_hash, address_prefix)}"
    )
    if pool_wallet_info.target is not None:
        print(
            f"Target state: {PoolSingletonState(pool_wallet_info.target.state).name}"
        )
        print(f"Target pool URL: {pool_wallet_info.target.pool_url}")
    if pool_wallet_info.current.state == PoolSingletonState.SELF_POOLING.value:
        balances: Dict = await wallet_client.get_wallet_balance(str(wallet_id))
        balance = balances["confirmed_wallet_balance"]
        typ = WalletType(int(WalletType.POOLING_WALLET))
        address_prefix, scale = wallet_coin_unit(typ, address_prefix)
        print(
            f"Claimable balance: {print_balance(balance, scale, address_prefix)}"
        )
    if pool_wallet_info.current.state == PoolSingletonState.FARMING_TO_POOL:
        print(f"Current pool URL: {pool_wallet_info.current.pool_url}")
        if pool_wallet_info.launcher_id in pool_state_dict:
            pool_state = pool_state_dict[pool_wallet_info.launcher_id]
            print(
                f"Current difficulty: {pool_state_dict[pool_wallet_info.launcher_id]['current_difficulty']}"
            )
            print(
                f"Points balance: {pool_state_dict[pool_wallet_info.launcher_id]['current_points']}"
            )
            points_found_24h = [
                points for timestamp, points in pool_state["points_found_24h"]
            ]
            points_acknowledged_24h = [
                points
                for timestamp, points in pool_state["points_acknowledged_24h"]
            ]
            summed_points_found_24h = sum(points_found_24h)
            summed_points_acknowledged_24h = sum(points_acknowledged_24h)
            if summed_points_found_24h == 0:
                success_pct = 0.0
            else:
                success_pct = summed_points_acknowledged_24h / summed_points_found_24h
            print(f"Points found (24h): {summed_points_found_24h}")
            print(f"Percent Successful Points (24h): {success_pct:.2%}")
        print(
            f"Relative lock height: {pool_wallet_info.current.relative_lock_height} blocks"
        )
        payout_instructions: str = pool_state_dict[
            pool_wallet_info.launcher_id]["pool_config"]["payout_instructions"]
        try:
            payout_address = encode_puzzle_hash(
                bytes32.fromhex(payout_instructions), address_prefix)
            print(
                f"Payout instructions (pool will pay to this address): {payout_address}"
            )
        except Exception:
            print(
                f"Payout instructions (pool will pay you with this): {payout_instructions}"
            )
    if pool_wallet_info.current.state == PoolSingletonState.LEAVING_POOL:
        expected_leave_height = pool_wallet_info.singleton_block_height + pool_wallet_info.current.relative_lock_height
        if pool_wallet_info.target is not None:
            print(
                f"Expected to leave after block height: {expected_leave_height}"
            )
Exemple #29
0
async def show(args: dict, wallet_client: WalletRpcClient,
               fingerprint: int) -> None:

    config = load_config(DEFAULT_ROOT_PATH, "config.yaml")
    self_hostname = config["self_hostname"]
    farmer_rpc_port = config["farmer"]["rpc_port"]
    farmer_client = await FarmerRpcClient.create(self_hostname,
                                                 uint16(farmer_rpc_port),
                                                 DEFAULT_ROOT_PATH, config)
    address_prefix = config["network_overrides"]["config"][
        config["selected_network"]]["address_prefix"]
    summaries_response = await wallet_client.get_wallets()
    wallet_id_passed_in = args.get("id", None)
    plot_counts: Counter = Counter()
    try:
        pool_state_list: List = (await
                                 farmer_client.get_pool_state())["pool_state"]
        harvesters = await farmer_client.get_harvesters()
        for d in harvesters["harvesters"]:
            for plot in d["plots"]:
                if plot.get("pool_contract_puzzle_hash", None) is not None:
                    # Non pooled plots will have a None pool_contract_puzzle_hash
                    plot_counts[hexstr_to_bytes(
                        plot["pool_contract_puzzle_hash"])] += 1
    except Exception as e:
        if isinstance(e, aiohttp.ClientConnectorError):
            print(
                f"Connection error. Check if farmer is running at {farmer_rpc_port}."
                f" You can run the farmer by:\n    chia start farmer-only")
        else:
            print(f"Exception from 'wallet' {e}")
        farmer_client.close()
        await farmer_client.await_closed()
        return
    pool_state_dict: Dict[bytes32, Dict] = {
        bytes32.from_hexstr(pool_state_item["pool_config"]["launcher_id"]):
        pool_state_item
        for pool_state_item in pool_state_list
    }
    if wallet_id_passed_in is not None:
        for summary in summaries_response:
            typ = WalletType(int(summary["type"]))
            if summary[
                    "id"] == wallet_id_passed_in and typ != WalletType.POOLING_WALLET:
                print(
                    f"Wallet with id: {wallet_id_passed_in} is not a pooling wallet. Please provide a different id."
                )
                return
        pool_wallet_info, _ = await wallet_client.pw_status(wallet_id_passed_in
                                                            )
        await pprint_pool_wallet_state(
            wallet_client,
            wallet_id_passed_in,
            pool_wallet_info,
            address_prefix,
            pool_state_dict,
            plot_counts,
        )
    else:
        print(f"Wallet height: {await wallet_client.get_height_info()}")
        print(
            f"Sync status: {'Synced' if (await wallet_client.get_synced()) else 'Not synced'}"
        )
        for summary in summaries_response:
            wallet_id = summary["id"]
            typ = WalletType(int(summary["type"]))
            if typ == WalletType.POOLING_WALLET:
                print(f"Wallet id {wallet_id}: ")
                pool_wallet_info, _ = await wallet_client.pw_status(wallet_id)
                await pprint_pool_wallet_state(
                    wallet_client,
                    wallet_id,
                    pool_wallet_info,
                    address_prefix,
                    pool_state_dict,
                    plot_counts,
                )
                print("")
    farmer_client.close()
    await farmer_client.await_closed()
    async def test_self_pooling_to_pooling(self, setup):
        """This tests self-pooling -> pooling"""
        num_blocks = 4  # Num blocks to farm at a time
        total_blocks = 0  # Total blocks farmed so far
        full_nodes, wallets, receive_address, client, rpc_cleanup = setup
        our_ph = receive_address[0]
        pool_ph = receive_address[1]
        full_node_api = full_nodes[0]

        try:
            total_blocks += await self.farm_blocks(full_node_api, our_ph, num_blocks)
            total_block_rewards = await self.get_total_block_rewards(total_blocks)

            await time_out_assert(10, wallets[0].get_unconfirmed_balance, total_block_rewards)
            await time_out_assert(10, wallets[0].get_confirmed_balance, total_block_rewards)
            await time_out_assert(10, wallets[0].get_spendable_balance, total_block_rewards)
            assert total_block_rewards > 0

            summaries_response = await client.get_wallets()
            for summary in summaries_response:
                if WalletType(int(summary["type"])) == WalletType.POOLING_WALLET:
                    assert False

            creation_tx: TransactionRecord = await client.create_new_pool_wallet(
                our_ph, "", 0, "localhost:5000", "new", "SELF_POOLING"
            )
            creation_tx_2: TransactionRecord = await client.create_new_pool_wallet(
                our_ph, "", 0, "localhost:5000", "new", "SELF_POOLING"
            )

            await time_out_assert(
                10,
                full_node_api.full_node.mempool_manager.get_spendbundle,
                creation_tx.spend_bundle,
                creation_tx.name,
            )
            await time_out_assert(
                10,
                full_node_api.full_node.mempool_manager.get_spendbundle,
                creation_tx_2.spend_bundle,
                creation_tx_2.name,
            )

            await self.farm_blocks(full_node_api, our_ph, 6)
            assert full_node_api.full_node.mempool_manager.get_spendbundle(creation_tx.name) is None

            summaries_response = await client.get_wallets()
            wallet_id: Optional[int] = None
            wallet_id_2: Optional[int] = None
            for summary in summaries_response:
                if WalletType(int(summary["type"])) == WalletType.POOLING_WALLET:
                    if wallet_id is not None:
                        wallet_id_2 = summary["id"]
                    else:
                        wallet_id = summary["id"]
            assert wallet_id is not None
            assert wallet_id_2 is not None
            status: PoolWalletInfo = (await client.pw_status(wallet_id))[0]
            status_2: PoolWalletInfo = (await client.pw_status(wallet_id))[0]

            assert status.current.state == PoolSingletonState.SELF_POOLING.value
            assert status_2.current.state == PoolSingletonState.SELF_POOLING.value
            assert status.target is None
            assert status_2.target is None

            join_pool_tx: TransactionRecord = await client.pw_join_pool(
                wallet_id,
                pool_ph,
                "https://pool.example.com",
                10,
            )
            join_pool_tx_2: TransactionRecord = await client.pw_join_pool(
                wallet_id_2,
                pool_ph,
                "https://pool.example.com",
                10,
            )
            assert join_pool_tx is not None
            assert join_pool_tx_2 is not None

            status: PoolWalletInfo = (await client.pw_status(wallet_id))[0]
            status_2: PoolWalletInfo = (await client.pw_status(wallet_id_2))[0]

            assert status.current.state == PoolSingletonState.SELF_POOLING.value
            assert status.target is not None
            assert status.target.state == PoolSingletonState.FARMING_TO_POOL.value
            assert status_2.current.state == PoolSingletonState.SELF_POOLING.value
            assert status_2.target is not None
            assert status_2.target.state == PoolSingletonState.FARMING_TO_POOL.value

            await self.farm_blocks(full_node_api, our_ph, 6)

            total_blocks += await self.farm_blocks(full_node_api, our_ph, num_blocks)

            async def status_is_farming_to_pool(w_id: int):
                pw_status: PoolWalletInfo = (await client.pw_status(w_id))[0]
                return pw_status.current.state == PoolSingletonState.FARMING_TO_POOL.value

            await time_out_assert(20, status_is_farming_to_pool, True, wallet_id)
            await time_out_assert(20, status_is_farming_to_pool, True, wallet_id_2)
            assert len(await wallets[0].wallet_state_manager.tx_store.get_unconfirmed_for_wallet(2)) == 0

        finally:
            client.close()
            await client.await_closed()
            await rpc_cleanup()