Skip to content

Commit

Permalink
[CHIA-504] Add support for external signers (PLEASE SQUASH) (#18199)
Browse files Browse the repository at this point in the history
* Repin hsms

* Add to sdist only allowed list

* Signer protocol tweaks

* Convert wallet RPC client to deserialized types

* Introduce @tx_out_cmd decorator

* Make execute_signing_instructions RPC

* Add transport layer support

* Add signer commands

* Rework wallet execute_signing_instructions

* Inadvertent merge changes

* Fix signer command tests

* Try a different approach: recursive flattening

* Bump hsms

* Add comments

* Test coverage

* Coverage ignores

* Remove inadvertent time traveler

* Bring in lost time traveler

* pylint

* Attempt to make qr test less flaky

* Actually test coverage ignore

* Small refactor for test coverage

* transport -> translation

* missed one

* transport -> translation

* Fix asdict error

* coverage

* Forgoe rotation testing for now

* Test coverage

* jsonify_unsigned_txs -> full_jsonify

* Move a class

* Add better type checking to framework

* explicitly state kwargs on _CommandParsingStage

Co-authored-by: Kyle Altendorf <sda@fstab.net>

* Address comments by @altendky

* Consolidate add_private_key and add_public_key

* Consolidate get_key_for_fingerprint and get_public_key_for_fingerprint

* Test fix

* Merge fix

* Bad merge

* Bad merge

* oops

* pylint

* Tweak keychain_proxy.get_key_for_fingerprint

* Fix wallet RPC test?

* pragma: no cover

* Redesign clvm_streamable

* Fix test imports

* black

* fix one more test

* Address comments by @altendky

* Test coverage

* bytes32

* Better CLI mnemonic check

* Use functools.partial

* Rename full jsonify to chip 29

* whoops missed a couple

* Better CLI mnemonic check

* black

* pylint

* Missed one

* black

* Farm at least one block

* Revert last change and fix 0 block farming

* black

* bad merge

* Merge fix

* Inadvertent changes

* Inadvertent changes

* Syncronize with quex.tx_out_decorator2

* These are no longer dictionaries.

* Use new clvm_streamable pattern

* Fix offer endpoint

* Add @tx_out_cmd decorator

* Bump ecdsa version

* Fix @marshal util to return proper transactions

* Add get_public_key

* port `chia wallet send` to @tx_out_cmd

* merge fix of puzzle hash derivation

* Port `chia wallet coins` to @tx_out_cmd

* Port chia wallet clawback to @tx_out_cmd

* Port `chia wallet take/cancel_offer` to @tx_out_cmd

* Port `chia wallet did ...` to @tx_out_cmd

* Port `chia wallet nft ...` to @tx_out_cmd

* Port `chia wallet notifications send` to @tx_out_cmd

* Port `chia wallet vcs ...` to @tx_out_cmd

* Port `chia dao ...` to @tx_out_cmd

* Exclude data layer and plotnft functions

* [no ci]

* Address comments by @AmineKhaldi

* Fix rpc util

* add test for BSTLSigningInstructions

* [UNDO] d9c6f54

* [UNDO] 7fc1d2a

* [UNDO] 23c9ee8

* [UNDO] aacc9f0

* [UNDO] 5484654

* Undo unintentional changes

* Stuff that's not part of this

* More stuff that doesn't belong

* One last thing that doesn't belong

* Unintentional change

---------

Co-authored-by: Kyle Altendorf <sda@fstab.net>
Co-authored-by: Amine Khaldi <amine.khaldi@reactos.org>
  • Loading branch information
3 people authored Jun 26, 2024
1 parent b705350 commit c25eeb0
Show file tree
Hide file tree
Showing 44 changed files with 2,817 additions and 868 deletions.
49 changes: 29 additions & 20 deletions chia/_tests/cmds/cmd_test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

import chia.cmds.wallet_funcs
from chia._tests.cmds.testing_classes import create_test_block_record
from chia._tests.cmds.wallet.test_consts import STD_TX, STD_UTX
from chia.cmds.chia import cli as chia_cli
from chia.cmds.cmds_util import _T_RpcClient, node_config_section_names
from chia.consensus.block_record import BlockRecord
Expand All @@ -18,6 +19,7 @@
from chia.rpc.farmer_rpc_client import FarmerRpcClient
from chia.rpc.full_node_rpc_client import FullNodeRpcClient
from chia.rpc.rpc_client import RpcClient
from chia.rpc.wallet_request_types import SendTransactionMultiResponse
from chia.rpc.wallet_rpc_client import WalletRpcClient
from chia.simulator.simulator_full_node_rpc_client import SimulatorFullNodeRpcClient
from chia.types.blockchain_format.sized_bytes import bytes32
Expand Down Expand Up @@ -252,26 +254,33 @@ async def send_transaction_multi(
tx_config: TXConfig,
coins: Optional[List[Coin]] = None,
fee: uint64 = uint64(0),
) -> TransactionRecord:
self.add_to_log("send_transaction_multi", (wallet_id, additions, tx_config, coins, fee))
return TransactionRecord(
confirmed_at_height=uint32(1),
created_at_time=uint64(1234),
to_puzzle_hash=bytes32([1] * 32),
amount=uint64(12345678),
fee_amount=uint64(1234567),
confirmed=False,
sent=uint32(0),
spend_bundle=SpendBundle([], G2Element()),
additions=[Coin(bytes32([1] * 32), bytes32([2] * 32), uint64(12345678))],
removals=[Coin(bytes32([2] * 32), bytes32([4] * 32), uint64(12345678))],
wallet_id=uint32(1),
sent_to=[("aaaaa", uint8(1), None)],
trade_id=None,
type=uint32(TransactionType.OUTGOING_TX.value),
name=bytes32([2] * 32),
memos=[(bytes32([3] * 32), [bytes([4] * 32)])],
valid_times=ConditionValidTimes(),
push: bool = True,
) -> SendTransactionMultiResponse:
self.add_to_log("send_transaction_multi", (wallet_id, additions, tx_config, coins, fee, push))
name = bytes32([2] * 32)
return SendTransactionMultiResponse(
[STD_UTX],
[STD_TX],
TransactionRecord(
confirmed_at_height=uint32(1),
created_at_time=uint64(1234),
to_puzzle_hash=bytes32([1] * 32),
amount=uint64(12345678),
fee_amount=uint64(1234567),
confirmed=False,
sent=uint32(0),
spend_bundle=SpendBundle([], G2Element()),
additions=[Coin(bytes32([1] * 32), bytes32([2] * 32), uint64(12345678))],
removals=[Coin(bytes32([2] * 32), bytes32([4] * 32), uint64(12345678))],
wallet_id=uint32(1),
sent_to=[("aaaaa", uint8(1), None)],
trade_id=None,
type=uint32(TransactionType.OUTGOING_TX.value),
name=name,
memos=[(bytes32([3] * 32), [bytes([4] * 32)])],
valid_times=ConditionValidTimes(),
),
name,
)


Expand Down
3 changes: 3 additions & 0 deletions chia/_tests/cmds/wallet/test_coins.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ async def select_coins(
Coin(get_bytes32(3), get_bytes32(4), uint64(1234560000)),
],
1000000000,
True,
),
(
1,
Expand All @@ -155,6 +156,7 @@ async def select_coins(
Coin(get_bytes32(5), get_bytes32(6), uint64(300000000000)),
],
1000000000,
True,
),
],
}
Expand Down Expand Up @@ -216,6 +218,7 @@ async def get_coin_records_by_names(
DEFAULT_TX_CONFIG,
[Coin(get_bytes32(1), get_bytes32(2), uint64(100000000000))],
1000000000,
True,
)
],
}
Expand Down
8 changes: 6 additions & 2 deletions chia/_tests/cmds/wallet/test_consts.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@

from chia.types.blockchain_format.sized_bytes import bytes32
from chia.types.spend_bundle import SpendBundle
from chia.util.ints import uint8, uint32, uint64
from chia.util.ints import uint32, uint64
from chia.wallet.conditions import ConditionValidTimes
from chia.wallet.signer_protocol import KeyHints, SigningInstructions, TransactionInfo, UnsignedTransaction
from chia.wallet.transaction_record import TransactionRecord
from chia.wallet.util.transaction_type import TransactionType

Expand Down Expand Up @@ -34,10 +35,13 @@ def get_bytes32(bytes_index: int) -> bytes32:
additions=[Coin(get_bytes32(1), get_bytes32(2), uint64(12345678))],
removals=[Coin(get_bytes32(2), get_bytes32(4), uint64(12345678))],
wallet_id=uint32(1),
sent_to=[("aaaaa", uint8(1), None)],
sent_to=[],
trade_id=None,
type=uint32(TransactionType.OUTGOING_TX.value),
name=get_bytes32(2),
memos=[(get_bytes32(3), [bytes([4] * 32)])],
valid_times=ConditionValidTimes(),
)


STD_UTX = UnsignedTransaction(TransactionInfo([]), SigningInstructions(KeyHints([], []), []))
74 changes: 48 additions & 26 deletions chia/_tests/cmds/wallet/test_dao.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,17 @@
from typing_extensions import override

from chia._tests.cmds.cmd_test_utils import TestRpcClients, TestWalletRpcClient, run_cli_command_and_assert
from chia._tests.cmds.wallet.test_consts import FINGERPRINT_ARG
from chia._tests.cmds.wallet.test_consts import FINGERPRINT_ARG, STD_TX, STD_UTX
from chia.rpc.wallet_request_types import (
CreateNewDAOWalletResponse,
DAOAddFundsToTreasuryResponse,
DAOCloseProposalResponse,
DAOCreateProposalResponse,
DAOExitLockupResponse,
DAOFreeCoinsFromFinishedProposalsResponse,
DAOSendToLockupResponse,
DAOVoteOnProposalResponse,
)
from chia.types.blockchain_format.sized_bytes import bytes32
from chia.util.bech32m import encode_puzzle_hash
from chia.util.ints import uint8, uint32, uint64
Expand Down Expand Up @@ -38,17 +48,22 @@ async def create_new_dao_wallet(
name: Optional[str] = None,
fee: uint64 = uint64(0),
fee_for_cat: uint64 = uint64(0),
) -> Dict[str, Union[str, int, bytes32]]:
push: bool = True,
) -> CreateNewDAOWalletResponse:
if not treasury_id:
treasury_id = bytes32(token_bytes(32))
return {
"success": True,
"type": "DAO",
"wallet_id": 2,
"treasury_id": treasury_id,
"cat_wallet_id": 3,
"dao_cat_wallet_id": 4,
}
return CreateNewDAOWalletResponse.from_json_dict(
{
"success": True,
"transactions": [STD_TX.to_json_dict()],
"unsigned_transactions": [STD_UTX.to_json_dict()],
"type": WalletType.DAO,
"wallet_id": 2,
"treasury_id": treasury_id,
"cat_wallet_id": 3,
"dao_cat_wallet_id": 4,
}
)

inst_rpc_client = DAOCreateRpcClient() # pylint: disable=no-value-for-parameter
test_rpc_clients.wallet_rpc_client = inst_rpc_client
Expand Down Expand Up @@ -126,8 +141,9 @@ async def dao_add_funds_to_treasury(
tx_config: TXConfig,
fee: uint64 = uint64(0),
reuse_puzhash: Optional[bool] = None,
) -> Dict[str, Union[str, bool]]:
return {"success": True, "tx_id": bytes32(b"1" * 32).hex()}
push: bool = True,
) -> DAOAddFundsToTreasuryResponse:
return DAOAddFundsToTreasuryResponse([STD_UTX], [STD_TX], STD_TX.name, STD_TX)

async def dao_get_rules(
self,
Expand Down Expand Up @@ -264,8 +280,9 @@ async def dao_vote_on_proposal(
tx_config: TXConfig,
is_yes_vote: bool,
fee: uint64 = uint64(0),
) -> Dict[str, Union[str, bool]]:
return {"success": True, "tx_id": bytes32(b"1" * 32).hex()}
push: bool = True,
) -> DAOVoteOnProposalResponse:
return DAOVoteOnProposalResponse([STD_UTX], [STD_TX], STD_TX.name, STD_TX)

async def dao_close_proposal(
self,
Expand All @@ -275,8 +292,9 @@ async def dao_close_proposal(
fee: uint64 = uint64(0),
self_destruct: bool = False,
reuse_puzhash: Optional[bool] = None,
) -> Dict[str, Union[str, bool]]:
return {"success": True, "tx_id": bytes32(b"1" * 32).hex()}
push: bool = True,
) -> DAOCloseProposalResponse:
return DAOCloseProposalResponse([STD_UTX], [STD_TX], STD_TX.name, STD_TX)

async def dao_create_proposal(
self,
Expand All @@ -292,8 +310,9 @@ async def dao_create_proposal(
new_dao_rules: Optional[Dict[str, uint64]] = None,
fee: uint64 = uint64(0),
reuse_puzhash: Optional[bool] = None,
) -> Dict[str, Union[str, bool]]:
return {"success": True, "proposal_id": "0xCAFEF00D"}
push: bool = True,
) -> DAOCreateProposalResponse:
return DAOCreateProposalResponse([STD_UTX], [STD_TX], bytes32([0] * 32), STD_TX.name, STD_TX)

async def get_wallets(self, wallet_type: Optional[WalletType] = None) -> List[Dict[str, Union[str, int]]]:
return [{"id": 1, "type": 0}, {"id": 2, "type": 14}]
Expand Down Expand Up @@ -405,7 +424,7 @@ async def get_transaction(self, transaction_id: bytes32) -> TransactionRecord:
"-m 0.1",
"--reuse",
]
proposal_asserts = ["Successfully created proposal", "Proposal ID: 0xCAFEF00D"]
proposal_asserts = ["Successfully created proposal", f"Proposal ID: {bytes32([0] * 32).hex()}"]
run_cli_command_and_assert(capsys, root_dir, spend_args, proposal_asserts)

bad_spend_args = [
Expand All @@ -423,7 +442,7 @@ async def get_transaction(self, transaction_id: bytes32) -> TransactionRecord:
"-m 0.1",
"--reuse",
]
proposal_asserts = ["Successfully created proposal", "Proposal ID: 0xCAFEF00D"]
proposal_asserts = ["Successfully created proposal", f"Proposal ID: {bytes32([0] * 32).hex()}"]
with pytest.raises(ValueError) as e_info:
run_cli_command_and_assert(capsys, root_dir, bad_spend_args, proposal_asserts)
assert e_info.value.args[0] == "Must include a json specification or an address / amount pair."
Expand Down Expand Up @@ -475,17 +494,19 @@ async def dao_send_to_lockup(
tx_config: TXConfig,
fee: uint64 = uint64(0),
reuse_puzhash: Optional[bool] = None,
) -> Dict[str, Union[str, int]]:
return {"success": True, "tx_id": bytes32(b"x" * 32).hex()}
push: bool = True,
) -> DAOSendToLockupResponse:
return DAOSendToLockupResponse([STD_UTX], [STD_TX], STD_TX.name, [STD_TX])

async def dao_free_coins_from_finished_proposals(
self,
wallet_id: int,
tx_config: TXConfig,
fee: uint64 = uint64(0),
reuse_puzhash: Optional[bool] = None,
) -> Dict[str, Union[str, int]]:
return {"success": True, "tx_id": bytes32(b"x" * 32).hex()}
push: bool = True,
) -> DAOFreeCoinsFromFinishedProposalsResponse:
return DAOFreeCoinsFromFinishedProposalsResponse([STD_UTX], [STD_TX], STD_TX.name, STD_TX)

async def dao_exit_lockup(
self,
Expand All @@ -494,8 +515,9 @@ async def dao_exit_lockup(
coins: Optional[List[Dict[str, Union[str, int]]]] = None,
fee: uint64 = uint64(0),
reuse_puzhash: Optional[bool] = None,
) -> Dict[str, Union[str, int]]:
return {"success": True, "tx_id": bytes32(b"x" * 32).hex()}
push: bool = True,
) -> DAOExitLockupResponse:
return DAOExitLockupResponse([STD_UTX], [STD_TX], STD_TX.name, STD_TX)

@override
async def get_transaction(self, transaction_id: bytes32) -> TransactionRecord:
Expand Down
Loading

0 comments on commit c25eeb0

Please sign in to comment.