Skip to content

Commit

Permalink
[CHIA-1015] Add a fee option to push_transactions (#18378)
Browse files Browse the repository at this point in the history
Add a `fee` option to `push_transactions`
  • Loading branch information
Quexington authored Aug 1, 2024
1 parent 74b14ce commit a1be3a9
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 24 deletions.
25 changes: 18 additions & 7 deletions chia/_tests/wallet/rpc/test_wallet_rpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,7 @@ async def test_push_transactions(wallet_rpc_environment: WalletRpcTestEnvironmen
full_node_api: FullNodeSimulator = env.full_node.api
client: WalletRpcClient = env.wallet_1.rpc_client

await generate_funds(full_node_api, env.wallet_1)
await generate_funds(full_node_api, env.wallet_1, num_blocks=2)

outputs = await create_tx_outputs(wallet, [(1234321, None)])

Expand All @@ -394,18 +394,29 @@ async def test_push_transactions(wallet_rpc_environment: WalletRpcTestEnvironmen
)
).signed_tx

await client.push_transactions([tx])
resp = await client.fetch("push_transactions", {"transactions": [tx.to_json_dict_convenience(wallet_node.config)]})
resp_client = await client.push_transactions([tx], fee=uint64(10))
resp = await client.fetch(
"push_transactions", {"transactions": [tx.to_json_dict_convenience(wallet_node.config)], "fee": 10}
)
assert resp["success"]
resp = await client.fetch("push_transactions", {"transactions": [tx.to_json_dict()]})
resp = await client.fetch("push_transactions", {"transactions": [tx.to_json_dict()], "fee": 10})
assert resp["success"]

spend_bundle = tx.spend_bundle
spend_bundle = SpendBundle.aggregate(
[
# We ARE checking that the spendbundle is not None but mypy can't recognize this
TransactionRecord.from_json_dict_convenience(tx).spend_bundle # type: ignore[misc]
for tx in resp_client["transactions"]
if tx["spend_bundle"] is not None
]
)
assert spend_bundle is not None
await farm_transaction(full_node_api, wallet_node, spend_bundle)

tx = await client.get_transaction(transaction_id=tx.name)
assert tx.confirmed
for tx_json in resp_client["transactions"]:
tx = TransactionRecord.from_json_dict_convenience(tx_json)
tx = await client.get_transaction(transaction_id=tx.name)
assert tx.confirmed


@pytest.mark.anyio
Expand Down
78 changes: 63 additions & 15 deletions chia/rpc/wallet_rpc_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
from chia.server.outbound_message import NodeType
from chia.server.ws_connection import WSChiaConnection
from chia.types.blockchain_format.coin import Coin, coin_as_list
from chia.types.blockchain_format.program import Program
from chia.types.blockchain_format.program import INFINITE_COST, Program
from chia.types.blockchain_format.sized_bytes import bytes32
from chia.types.coin_record import CoinRecord
from chia.types.coin_spend import CoinSpend
Expand All @@ -61,6 +61,7 @@
Condition,
CreateCoinAnnouncement,
CreatePuzzleAnnouncement,
parse_conditions_non_consensus,
)
from chia.wallet.dao_wallet.dao_info import DAORules
from chia.wallet.dao_wallet.dao_utils import (
Expand Down Expand Up @@ -616,21 +617,68 @@ async def push_tx(self, request: Dict[str, Any]) -> EndpointResult:
await self.service.push_tx(SpendBundle.from_bytes(hexstr_to_bytes(request["spend_bundle"])))
return {}

async def push_transactions(self, request: Dict[str, Any]) -> EndpointResult:
txs: List[TransactionRecord] = []
for transaction_hexstr_or_json in request["transactions"]:
if isinstance(transaction_hexstr_or_json, str):
tx = TransactionRecord.from_bytes(hexstr_to_bytes(transaction_hexstr_or_json))
txs.append(tx)
else:
try:
tx = TransactionRecord.from_json_dict_convenience(transaction_hexstr_or_json)
except AttributeError:
tx = TransactionRecord.from_json_dict(transaction_hexstr_or_json)
txs.append(tx)
@tx_endpoint(push=True)
async def push_transactions(
self,
request: Dict[str, Any],
action_scope: WalletActionScope,
tx_config: TXConfig = DEFAULT_TX_CONFIG,
extra_conditions: Tuple[Condition, ...] = tuple(),
) -> EndpointResult:
if not action_scope.config.push:
raise ValueError("Cannot push transactions if push is False")
async with action_scope.use() as interface:
for transaction_hexstr_or_json in request["transactions"]:
if isinstance(transaction_hexstr_or_json, str):
tx = TransactionRecord.from_bytes(hexstr_to_bytes(transaction_hexstr_or_json))
interface.side_effects.transactions.append(tx)
else:
try:
tx = TransactionRecord.from_json_dict_convenience(transaction_hexstr_or_json)
except AttributeError:
tx = TransactionRecord.from_json_dict(transaction_hexstr_or_json)
interface.side_effects.transactions.append(tx)

if request.get("fee", 0) != 0:
all_conditions_and_origins = [
(condition, cs.coin.name())
for tx in interface.side_effects.transactions
if tx.spend_bundle is not None
for cs in tx.spend_bundle.coin_spends
for condition in cs.puzzle_reveal.run_with_cost(INFINITE_COST, cs.solution)[1].as_iter()
]
create_coin_announcement = next(
condition
for condition in parse_conditions_non_consensus(
[con for con, coin in all_conditions_and_origins], abstractions=False
)
if isinstance(condition, CreateCoinAnnouncement)
)
announcement_origin = next(
coin
for condition, coin in all_conditions_and_origins
if condition == create_coin_announcement.to_program()
)
async with self.service.wallet_state_manager.new_action_scope(push=False) as inner_action_scope:
await self.service.wallet_state_manager.main_wallet.create_tandem_xch_tx(
uint64(request["fee"]),
dataclasses.replace(
tx_config,
excluded_coin_ids=[
*tx_config.excluded_coin_ids,
*(c.name() for tx in interface.side_effects.transactions for c in tx.removals),
],
),
inner_action_scope,
(
*extra_conditions,
CreateCoinAnnouncement(
create_coin_announcement.msg, announcement_origin
).corresponding_assertion(),
),
)

async with self.service.wallet_state_manager.lock:
await self.service.wallet_state_manager.add_pending_transactions(txs, sign=request.get("sign", False))
interface.side_effects.transactions.extend(inner_action_scope.side_effects.transactions)

return {}

Expand Down
6 changes: 4 additions & 2 deletions chia/rpc/wallet_rpc_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,10 +148,12 @@ async def get_height_info(self) -> uint32:
async def push_tx(self, spend_bundle: SpendBundle) -> Dict[str, Any]:
return await self.fetch("push_tx", {"spend_bundle": bytes(spend_bundle).hex()})

async def push_transactions(self, txs: List[TransactionRecord], sign: bool = False) -> Dict[str, Any]:
async def push_transactions(
self, txs: List[TransactionRecord], fee: uint64 = uint64(0), sign: bool = False
) -> Dict[str, Any]:
transactions = [bytes(tx).hex() for tx in txs]

return await self.fetch("push_transactions", {"transactions": transactions, "sign": sign})
return await self.fetch("push_transactions", {"transactions": transactions, "fee": fee, "sign": sign})

async def farm_block(self, address: str) -> Dict[str, Any]:
return await self.fetch("farm_block", {"address": address})
Expand Down

0 comments on commit a1be3a9

Please sign in to comment.