This commit is contained in:
Yostra 2020-01-31 12:03:52 -08:00
parent bb09b90c28
commit cc796768aa
3 changed files with 58 additions and 54 deletions

View File

@ -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]

View File

@ -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):

View File

@ -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)