Skip to content

Commit

Permalink
Add coin announcement to create signed transaction rpc call (#9735)
Browse files Browse the repository at this point in the history
This will allow pool operators and developers to have more control of the types of transactions they create using the wallet RPC.
  • Loading branch information
jack60612 committed Jan 7, 2022
1 parent e7270df commit d22976a
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 6 deletions.
26 changes: 23 additions & 3 deletions chia/rpc/wallet_rpc_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import logging
import time
from pathlib import Path
from typing import Callable, Dict, List, Optional, Tuple
from typing import Callable, Dict, List, Optional, Tuple, Set

from blspy import PrivateKey, G1Element

Expand Down Expand Up @@ -1185,14 +1185,34 @@ async def create_signed_transaction(self, request, hold_lock=True):
if "coins" in request and len(request["coins"]) > 0:
coins = set([Coin.from_json_dict(coin_json) for coin_json in request["coins"]])

coin_announcements: Optional[Set[bytes32]] = None
if (
"coin_announcements" in request
and request["coin_announcements"] is not None
and len(request["coin_announcements"]) > 0
):
coin_announcements = set([hexstr_to_bytes(announcement) for announcement in request["coin_announcements"]])

if hold_lock:
async with self.service.wallet_state_manager.lock:
signed_tx = await self.service.wallet_state_manager.main_wallet.generate_signed_transaction(
amount_0, puzzle_hash_0, fee, coins=coins, ignore_max_send_amount=True, primaries=additional_outputs
amount_0,
puzzle_hash_0,
fee,
coins=coins,
ignore_max_send_amount=True,
primaries=additional_outputs,
announcements_to_consume=coin_announcements,
)
else:
signed_tx = await self.service.wallet_state_manager.main_wallet.generate_signed_transaction(
amount_0, puzzle_hash_0, fee, coins=coins, ignore_max_send_amount=True, primaries=additional_outputs
amount_0,
puzzle_hash_0,
fee,
coins=coins,
ignore_max_send_amount=True,
primaries=additional_outputs,
announcements_to_consume=coin_announcements,
)
return {"signed_tx": signed_tx}

Expand Down
27 changes: 24 additions & 3 deletions chia/rpc/wallet_rpc_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,17 +180,38 @@ async def get_farmed_amount(self) -> Dict:
return await self.fetch("get_farmed_amount", {})

async def create_signed_transaction(
self, additions: List[Dict], coins: List[Coin] = None, fee: uint64 = uint64(0)
self,
additions: List[Dict],
coins: List[Coin] = None,
fee: uint64 = uint64(0),
coin_announcements: List[bytes32] = None,
) -> TransactionRecord:
# Converts bytes to hex for puzzle hashes
additions_hex = [{"amount": ad["amount"], "puzzle_hash": ad["puzzle_hash"].hex()} for ad in additions]
# Converts bytes to hex for coin announcements and does not if it is none.
coin_announcements_hex: Optional[List[str]] = None
if coin_announcements is not None and len(coin_announcements) > 0:
coin_announcements_hex = [announcement.hex() for announcement in coin_announcements]
if coins is not None and len(coins) > 0:
coins_json = [c.to_json_dict() for c in coins]
response: Dict = await self.fetch(
"create_signed_transaction", {"additions": additions_hex, "coins": coins_json, "fee": fee}
"create_signed_transaction",
{
"additions": additions_hex,
"coins": coins_json,
"fee": fee,
"coin_announcements": coin_announcements_hex,
},
)
else:
response = await self.fetch("create_signed_transaction", {"additions": additions_hex, "fee": fee})
response = await self.fetch(
"create_signed_transaction",
{
"additions": additions_hex,
"fee": fee,
"coin_announcements": coin_announcements_hex,
},
)
return TransactionRecord.from_json_dict(response["signed_tx"])

async def create_new_did_wallet(self, amount):
Expand Down
20 changes: 20 additions & 0 deletions tests/wallet/rpc/test_wallet_rpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from chia.types.peer_info import PeerInfo
from chia.util.bech32m import encode_puzzle_hash
from chia.consensus.coinbase import create_puzzlehash_for_pk
from chia.util.hash import std_hash
from chia.wallet.derive_keys import master_sk_to_wallet_sk
from chia.util.ints import uint16, uint32
from chia.wallet.transaction_record import TransactionRecord
Expand Down Expand Up @@ -137,6 +138,25 @@ async def eventual_balance():
ph_4 = await wallet_node_2.wallet_state_manager.main_wallet.get_new_puzzlehash()
ph_5 = await wallet_node_2.wallet_state_manager.main_wallet.get_new_puzzlehash()

# Test basic transaction to one output and coin announcement
signed_tx_amount = 888000
tx_coin_announcements = [std_hash(b"extra_stuff"), std_hash(b"more_stuff")]
tx_res: TransactionRecord = await client.create_signed_transaction(
[{"amount": signed_tx_amount, "puzzle_hash": ph_3}], coin_announcements=tx_coin_announcements
)

assert tx_res.fee_amount == 0
assert tx_res.amount == signed_tx_amount
assert len(tx_res.additions) == 2 # The output and the change
assert any([addition.amount == signed_tx_amount for addition in tx_res.additions])
# check error for a ASSERT_ANNOUNCE_CONSUMED_FAILED and if the error is not there throw a value error
try:
push_res = await client_node.push_tx(tx_res.spend_bundle)
except ValueError as error:
error_string = error.args[0]["error"] # noqa: # pylint: disable=E1126
if error_string.find("ASSERT_ANNOUNCE_CONSUMED_FAILED") == -1:
raise ValueError from error

# Test basic transaction to one output
signed_tx_amount = 888000
tx_res: TransactionRecord = await client.create_signed_transaction(
Expand Down

0 comments on commit d22976a

Please sign in to comment.