Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a full node RPC endpoint, get_mempool_items_by_coin_name #16019

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions chia/rpc/full_node_rpc_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
from chia.types.full_block import FullBlock
from chia.types.generator_types import BlockGenerator
from chia.types.mempool_inclusion_status import MempoolInclusionStatus
from chia.types.mempool_item import MempoolItem
from chia.types.spend_bundle import SpendBundle
from chia.types.unfinished_header_block import UnfinishedHeaderBlock
from chia.util.byte_types import hexstr_to_bytes
Expand Down Expand Up @@ -113,6 +114,7 @@ def get_routes(self) -> Dict[str, Endpoint]:
"/get_all_mempool_tx_ids": self.get_all_mempool_tx_ids,
"/get_all_mempool_items": self.get_all_mempool_items,
"/get_mempool_item_by_tx_id": self.get_mempool_item_by_tx_id,
"/get_mempool_items_by_coin_name": self.get_mempool_items_by_coin_name,
# Fee estimation
"/get_fee_estimate": self.get_fee_estimate,
}
Expand Down Expand Up @@ -792,6 +794,15 @@ async def get_mempool_item_by_tx_id(self, request: Dict[str, Any]) -> EndpointRe

return {"mempool_item": item.to_json_dict()}

async def get_mempool_items_by_coin_name(self, request: Dict[str, Any]) -> EndpointResult:
if "coin_name" not in request:
raise ValueError("No coin_name in request")

coin_name: bytes32 = bytes32.from_hexstr(request["coin_name"])
items: List[MempoolItem] = self.service.mempool_manager.mempool.get_items_by_coin_id(coin_name)

return {"mempool_items": [item.to_json_dict() for item in items]}

def _get_spendbundle_type_cost(self, name: str) -> uint64:
"""
This is a stopgap until we modify the wallet RPCs to get exact costs for created SpendBundles
Expand Down
4 changes: 4 additions & 0 deletions chia/rpc/full_node_rpc_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,10 @@ async def get_mempool_item_by_tx_id(
except Exception:
return None

async def get_mempool_items_by_coin_name(self, coin_name: bytes32) -> Dict[str, Any]:
response = await self.fetch("get_mempool_items_by_coin_name", {"coin_name": coin_name.hex()})
return response

async def get_recent_signage_point_or_eos(
self, sp_hash: Optional[bytes32], challenge_hash: Optional[bytes32]
) -> Optional[Any]:
Expand Down
111 changes: 111 additions & 0 deletions tests/core/test_full_node_rpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
from chia.simulator.simulator_protocol import FarmNewBlockProtocol, ReorgProtocol
from chia.simulator.time_out_assert import time_out_assert
from chia.simulator.wallet_tools import WalletTool
from chia.types.blockchain_format.coin import Coin
from chia.types.blockchain_format.sized_bytes import bytes32
from chia.types.coin_spend import compute_additions
from chia.types.condition_opcodes import ConditionOpcode
from chia.types.condition_with_args import ConditionWithArgs
Expand Down Expand Up @@ -515,3 +517,112 @@ async def test_get_blockchain_state(self, one_wallet_and_one_simulator_services,
# Checks that the RPC manages to stop the node
client.close()
await client.await_closed()

@pytest.mark.asyncio
async def test_coin_name_not_in_request(self, one_node, self_hostname):
[full_node_service], _, _ = one_node

try:
client = await FullNodeRpcClient.create(
self_hostname,
full_node_service.rpc_server.listen_port,
full_node_service.root_path,
full_node_service.config,
)
with pytest.raises(ValueError, match="No coin_name in request"):
await client.fetch("get_mempool_items_by_coin_name", {})
finally:
# Checks that the RPC manages to stop the node
client.close()
await client.await_closed()

@pytest.mark.asyncio
async def test_coin_name_not_found_in_mempool(self, one_node, self_hostname):
[full_node_service], _, _ = one_node

try:
client = await FullNodeRpcClient.create(
self_hostname,
full_node_service.rpc_server.listen_port,
full_node_service.root_path,
full_node_service.config,
)

empty_coin_name = bytes32([0] * 32)
mempool_item = await client.get_mempool_items_by_coin_name(empty_coin_name)
assert mempool_item["success"] == True
assert "mempool_items" in mempool_item
assert len(mempool_item["mempool_items"]) == 0
finally:
client.close()
await client.await_closed()

@pytest.mark.asyncio
async def test_coin_name_found_in_mempool(self, one_node, self_hostname):
[full_node_service], _, bt = one_node
full_node_api = full_node_service._api

try:
client = await FullNodeRpcClient.create(
self_hostname,
full_node_service.rpc_server.listen_port,
full_node_service.root_path,
full_node_service.config,
)

blocks = bt.get_consecutive_blocks(2)
blocks = bt.get_consecutive_blocks(2, block_list_input=blocks, guarantee_transaction_block=True)

for block in blocks:
unf = UnfinishedBlock(
block.finished_sub_slots,
block.reward_chain_block.get_unfinished(),
block.challenge_chain_sp_proof,
block.reward_chain_sp_proof,
block.foliage,
block.foliage_transaction_block,
block.transactions_info,
block.transactions_generator,
[],
)
await full_node_api.full_node.add_unfinished_block(unf, None)
await full_node_api.full_node.add_block(block, None)

wallet = WalletTool(full_node_api.full_node.constants)
wallet_receiver = WalletTool(full_node_api.full_node.constants, AugSchemeMPL.key_gen(std_hash(b"123123")))
ph = wallet.get_new_puzzlehash()
ph_receiver = wallet_receiver.get_new_puzzlehash()

blocks = bt.get_consecutive_blocks(
2,
block_list_input=blocks,
guarantee_transaction_block=True,
farmer_reward_puzzle_hash=ph,
pool_reward_puzzle_hash=ph,
)
for block in blocks[-2:]:
await full_node_api.full_node.add_block(block)

# empty mempool
assert len(await client.get_all_mempool_items()) == 0

coin_to_spend = list(blocks[-1].get_included_reward_coins())[0]
spend_bundle = wallet.generate_signed_transaction(coin_to_spend.amount, ph_receiver, coin_to_spend)
await client.push_tx(spend_bundle)

# mempool with one item
assert len(await client.get_all_mempool_items()) == 1

mempool_item = await client.get_mempool_items_by_coin_name(coin_to_spend.name())

# found coin in coin spends
assert mempool_item["success"] == True
assert "mempool_items" in mempool_item
assert len(mempool_item["mempool_items"]) > 0
for item in mempool_item["mempool_items"]:
removals = [Coin.from_json_dict(coin) for coin in item["removals"]]
assert coin_to_spend.name() in [coin.name() for coin in removals]

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