diff --git a/src/wallet/puzzles/puzzle_utils.py b/src/wallet/puzzles/puzzle_utils.py index f78ed0a2..1f1430d8 100644 --- a/src/wallet/puzzles/puzzle_utils.py +++ b/src/wallet/puzzles/puzzle_utils.py @@ -6,6 +6,10 @@ def make_create_coin_condition(puzzle_hash, amount): return [ConditionOpcode.CREATE_COIN, puzzle_hash, amount] +def make_assert_aggsig_condition(pubkey): + return [ConditionOpcode.AGG_SIG, pubkey] + + def make_assert_coin_consumed_condition(coin_name): return [ConditionOpcode.ASSERT_COIN_CONSUMED, coin_name] diff --git a/tests/test_mempool.py b/tests/test_mempool.py index cfab6e76..a8ada436 100644 --- a/tests/test_mempool.py +++ b/tests/test_mempool.py @@ -32,7 +32,7 @@ class TestMempool: block = blocks[1] async for _ in full_node_1.block(peer_protocol.Block(block)): - spend_bundle = wallet_a.generate_signed_transaction(1000, receiver_puzzlehash, [block.body.coinbase]) + spend_bundle = wallet_a.generate_signed_transaction(1000, receiver_puzzlehash, block.body.coinbase) tx: peer_protocol.Transaction = peer_protocol.Transaction(spend_bundle) async for _ in full_node_1.transaction(tx): outbound: OutboundMessage = _ @@ -54,7 +54,7 @@ class TestMempool: async for _ in full_node_1.block(peer_protocol.Block(block)): pass - spend_bundle1 = wallet_a.generate_signed_transaction(1000, receiver_puzzlehash, [block.body.coinbase]) + spend_bundle1 = wallet_a.generate_signed_transaction(1000, receiver_puzzlehash, block.body.coinbase) tx1: peer_protocol.Transaction = peer_protocol.Transaction(spend_bundle1) async for _ in full_node_1.transaction(tx1): outbound: OutboundMessage = _ @@ -62,7 +62,7 @@ class TestMempool: assert outbound.message.function == "maybe_transaction" other_receiver = WalletTool() - spend_bundle2 = wallet_a.generate_signed_transaction(1000, other_receiver.get_new_puzzlehash(), [block.body.coinbase]) + spend_bundle2 = wallet_a.generate_signed_transaction(1000, other_receiver.get_new_puzzlehash(), block.body.coinbase) tx2: peer_protocol.Transaction = peer_protocol.Transaction(spend_bundle2) async for _ in full_node_1.transaction(tx2): pass @@ -88,14 +88,14 @@ class TestMempool: async for _ in full_node_1.block(peer_protocol.Block(block)): pass - spend_bundle1 = wallet_a.generate_signed_transaction(1000, receiver_puzzlehash, [block.body.coinbase]) + spend_bundle1 = wallet_a.generate_signed_transaction(1000, receiver_puzzlehash, block.body.coinbase) tx1: peer_protocol.Transaction = peer_protocol.Transaction(spend_bundle1) async for _ in full_node_1.transaction(tx1): outbound: OutboundMessage = _ # Maybe transaction means that it's accepted in mempool assert outbound.message.function == "maybe_transaction" - spend_bundle2 = wallet_a.generate_signed_transaction(1000, receiver_puzzlehash, [block.body.coinbase], 1) + spend_bundle2 = wallet_a.generate_signed_transaction(1000, receiver_puzzlehash, block.body.coinbase, fee=1) tx2: peer_protocol.Transaction = peer_protocol.Transaction(spend_bundle2) async for _ in full_node_1.transaction(tx2): diff --git a/tests/wallet_tools.py b/tests/wallet_tools.py index 7815f106..b905b99c 100644 --- a/tests/wallet_tools.py +++ b/tests/wallet_tools.py @@ -1,17 +1,20 @@ -from typing import List, Optional +from typing import List, Optional, Dict import clvm from os import urandom from blspy import ExtendedPrivateKey from src.types.hashable import ProgramHash, CoinSolution, SpendBundle, Program, BLSSignature, Coin -from src.util.Conditions import conditions_by_opcode +from src.util.Conditions import conditions_by_opcode, ConditionVarPair, ConditionOpcode from src.util.consensus import hash_key_pairs_for_conditions_dict, conditions_for_solution +from src.wallet import keychain from src.wallet.BLSPrivateKey import BLSPrivateKey from src.wallet.puzzles.p2_conditions import puzzle_for_conditions +from src.wallet.puzzles.p2_delegated_conditions import solution_for_conditions from src.wallet.puzzles.p2_delegated_puzzle import puzzle_for_pk from src.wallet.puzzles.puzzle_utils import make_assert_coin_consumed_condition, make_assert_min_time_condition, \ - make_assert_my_coin_id_condition, make_create_coin_condition + make_assert_my_coin_id_condition, make_create_coin_condition, make_assert_block_index_exceeds_condition, \ + make_assert_block_age_exceeds_condition, make_assert_aggsig_condition class WalletTool: @@ -68,41 +71,50 @@ class WalletTool: blskey = BLSPrivateKey(privatekey) return blskey.sign(value) - def make_solution(self, primaries=[], min_time=0, me={}, consumed=[]): + def make_solution(self, condition_dic: Dict[ConditionOpcode, List[ConditionVarPair]]): ret = [] - for primary in primaries: - ret.append(make_create_coin_condition( - primary['puzzlehash'], primary['amount'])) - for coin in consumed: - ret.append(make_assert_coin_consumed_condition(coin)) - if min_time > 0: - ret.append(make_assert_min_time_condition(min_time)) - if me: - ret.append(make_assert_my_coin_id_condition(me['id'])) + + for con_list in condition_dic.values(): + for cvp in con_list: + if cvp.opcode == ConditionOpcode.CREATE_COIN: + ret.append(make_create_coin_condition(cvp.var1, cvp.var2)) + if cvp.opcode == ConditionOpcode.AGG_SIG: + ret.append(make_assert_aggsig_condition(cvp.var1)) + if cvp.opcode == ConditionOpcode.ASSERT_COIN_CONSUMED: + ret.append(make_assert_coin_consumed_condition(cvp.var1)) + if cvp.opcode == ConditionOpcode.ASSERT_MIN_TIME: + ret.append(make_assert_min_time_condition(cvp.var1)) + if cvp.opcode == ConditionOpcode.ASSERT_MY_COIN_ID: + ret.append(make_assert_my_coin_id_condition(cvp.var1)) + if cvp.opcode == ConditionOpcode.ASSERT_BLOCK_INDEX_EXCEEDS: + ret.append(make_assert_block_index_exceeds_condition(cvp.var1)) + if cvp.opcode == ConditionOpcode.ASSERT_BLOCK_AGE_EXCEEDS: + ret.append(make_assert_block_age_exceeds_condition(cvp.var1)) + return clvm.to_sexp_f([puzzle_for_conditions(ret), []]) - def generate_unsigned_transaction(self, amount, newpuzzlehash, utxos: List[Coin], fee: int = 0): + def generate_unsigned_transaction(self, amount, newpuzzlehash, coin: Coin, + condition_dic: Dict[ConditionOpcode, List[ConditionVarPair]]= {}, fee: int = 0): spends = [] - output_created = False - spend_value = sum([coin.amount for coin in utxos]) + spend_value = coin.amount change = spend_value - amount - fee - for coin in utxos: - puzzle_hash = coin.puzzle_hash + puzzle_hash = coin.puzzle_hash + pubkey, secretkey = self.get_keys(puzzle_hash) + puzzle = puzzle_for_pk(pubkey.serialize()) + if ConditionOpcode.CREATE_COIN not in condition_dic: + condition_dic = {ConditionOpcode.CREATE_COIN: []} - pubkey, secretkey = self.get_keys(puzzle_hash) - puzzle = puzzle_for_pk(pubkey.serialize()) - if output_created is False: - primaries = [{'puzzlehash': newpuzzlehash, 'amount': amount}] - if change > 0: - changepuzzlehash = self.get_new_puzzlehash() - primaries.append( - {'puzzlehash': changepuzzlehash, 'amount': change}) - # add change coin into temp_utxo set - solution = self.make_solution(primaries=primaries) - output_created = True - else: - solution = self.make_solution(consumed=[coin.name()]) - spends.append((puzzle, CoinSolution(coin, solution))) + output = ConditionVarPair(ConditionOpcode.CREATE_COIN, newpuzzlehash, amount) + condition_dic[output.opcode].append(output) + if change > 0: + changepuzzlehash = self.get_new_puzzlehash() + change_output = ConditionVarPair(ConditionOpcode.CREATE_COIN, changepuzzlehash, change) + condition_dic[output.opcode].append(change_output) + solution = self.make_solution(condition_dic) + else: + solution = self.make_solution(condition_dic) + + spends.append((puzzle, CoinSolution(coin, solution))) return spends def sign_transaction(self, spends: (Program, [CoinSolution])): @@ -124,22 +136,10 @@ class WalletTool: spend_bundle = SpendBundle(solution_list, aggsig) return spend_bundle - def generate_signed_transaction(self, amount, newpuzzlehash, coins: List[Coin], fee: int = 0) -> Optional[SpendBundle]: - transaction = self.generate_unsigned_transaction(amount, newpuzzlehash, coins, fee) + def generate_signed_transaction(self, amount, newpuzzlehash, coin: Coin, + condition_dic: Dict[ConditionOpcode, List[ConditionVarPair]] = {}, + fee: int = 0) -> Optional[SpendBundle]: + transaction = self.generate_unsigned_transaction(amount, newpuzzlehash, coin, condition_dic, fee) if transaction is None: return None - return self.sign_transaction(transaction) - - -""" -Copyright 2018 Chia Network Inc -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -""" + return self.sign_transaction(transaction) \ No newline at end of file