This commit is contained in:
Yostra 2020-04-20 17:12:30 -07:00
parent 01a11a9da8
commit f4aac42870
9 changed files with 113 additions and 134 deletions

View File

@ -76,16 +76,18 @@ def hash_key_pairs_for_conditions_dict(
coin_name: bytes32 = None,
) -> List[BLSSignature.PkMessagePair]:
pairs: List[BLSSignature.PkMessagePair] = []
for cvp in conditions_dict.get(ConditionOpcode.AGG_SIG, []):
# TODO: check types
# assert len(_) == 3
blspubkey: BLSPublicKey = BLSPublicKey(cvp.var1)
message: bytes32 = bytes32(blspy.Util.hash256(cvp.var2))
pairs.append(BLSSignature.PkMessagePair(blspubkey, message))
for cvp in conditions_dict.get(ConditionOpcode.AGG_SIG_ME, []):
aggsigme_blspubkey: BLSPublicKey = BLSPublicKey(cvp.var1)
aggsigme_message: bytes32 = bytes32(blspy.Util.hash256(cvp.var2 + coin_name))
pairs.append(BLSSignature.PkMessagePair(aggsigme_blspubkey, aggsigme_message))
if coin_name is None:
for cvp in conditions_dict.get(ConditionOpcode.AGG_SIG, []):
# TODO: check types
# assert len(_) == 3
blspubkey: BLSPublicKey = BLSPublicKey(cvp.var1)
message: bytes32 = bytes32(blspy.Util.hash256(cvp.var2))
pairs.append(BLSSignature.PkMessagePair(blspubkey, message))
if coin_name is not None:
for cvp in conditions_dict.get(ConditionOpcode.AGG_SIG_ME, []):
aggsigme_blspubkey: BLSPublicKey = BLSPublicKey(cvp.var1)
aggsigme_message: bytes32 = bytes32(blspy.Util.hash256(cvp.var2 + coin_name))
pairs.append(BLSSignature.PkMessagePair(aggsigme_blspubkey, aggsigme_message))
return pairs

View File

@ -2,7 +2,7 @@ import logging
import string
import clvm
from typing import Dict, Optional, List, Any, Set, Tuple
from typing import Dict, Optional, List, Any, Set
from clvm_tools import binutils
from clvm.EvalError import EvalError
from src.types.BLSSignature import BLSSignature
@ -22,7 +22,6 @@ from src.wallet.BLSPrivateKey import BLSPrivateKey
from src.wallet.block_record import BlockRecord
from src.wallet.cc_wallet.cc_info import CCInfo
from src.wallet.cc_wallet.cc_wallet_puzzles import (
cc_make_solution,
get_innerpuzzle_from_puzzle,
cc_generate_eve_spend,
create_spend_for_auditor,
@ -54,9 +53,9 @@ class CCWallet:
cc_coin_record: WalletCoinRecord
cc_info: CCInfo
standard_wallet: Wallet
base_puzzle_program: Program
base_inner_puzzle_hash: bytes32
sexp_cache: Dict[str, SExp]
base_puzzle_program: Optional[Program]
base_inner_puzzle_hash: Optional[bytes32]
sexp_cache: Optional[Dict[str, SExp]]
@staticmethod
async def create_new_cc(
@ -266,20 +265,20 @@ class CCWallet:
coin = removed
break
if self.check_is_cc_puzzle(puzzle_program):
puzzle_string = binutils.disassemble(puzzle_program)
inner_puzzle_hash = hexstr_to_bytes(
get_innerpuzzle_from_puzzle(puzzle_string)
)
self.log.info(
f"parent: {coin_name} inner_puzzle for parent is {inner_puzzle_hash}"
)
await self.add_parent(
coin_name,
CCParent(coin.parent_coin_info, inner_puzzle_hash, coin.amount),
)
# else:
# await self.add_parent(coin_name, None)
if coin is not None:
if self.check_is_cc_puzzle(puzzle_program):
puzzle_string = binutils.disassemble(puzzle_program)
inner_puzzle_hash = hexstr_to_bytes(
get_innerpuzzle_from_puzzle(puzzle_string)
)
self.log.info(
f"parent: {coin_name} inner_puzzle for parent is {inner_puzzle_hash.hex()}"
)
await self.add_parent(
coin_name,
CCParent(coin.parent_coin_info, inner_puzzle_hash, coin.amount),
)
return True
@ -292,9 +291,10 @@ class CCWallet:
block: BlockRecord = await self.wallet_state_manager.wallet_store.get_block_record(
header_hash
)
parent_found = await self.search_for_parent_info(generator, block.removals)
if parent_found:
await self.wallet_state_manager.set_action_done(action_id)
if block.removals is not None:
parent_found = await self.search_for_parent_info(generator, block.removals)
if parent_found:
await self.wallet_state_manager.set_action_done(action_id)
async def get_new_inner_hash(self) -> bytes32:
return await self.standard_wallet.get_new_puzzlehash()
@ -302,7 +302,9 @@ class CCWallet:
def do_replace(self, sexp, magic, magic_replacement):
""" Generic way to replace anything inside a SEXP, not used currentyl """
if sexp.listp():
return self.do_replace(sexp.first(), magic, magic_replacement).cons(self.do_replace(sexp.rest(), magic, magic_replacement))
return self.do_replace(sexp.first(), magic, magic_replacement).cons(
self.do_replace(sexp.rest(), magic, magic_replacement)
)
if sexp.as_atom() == magic:
return sexp.to(magic_replacement)
return sexp
@ -346,12 +348,16 @@ class CCWallet:
return result
def fast_cc_puzzle(self, inner_puzzle_hash) -> Program:
new_sexp = self.specific_replace(self.base_puzzle_program, self.base_inner_puzzle_hash, inner_puzzle_hash)
new_sexp = self.specific_replace(
self.base_puzzle_program, self.base_inner_puzzle_hash, inner_puzzle_hash
)
program = Program(new_sexp)
return program
def puzzle_for_pk(self, pubkey) -> Program:
inner_puzzle_hash = self.standard_wallet.puzzle_for_pk(bytes(pubkey)).get_tree_hash()
inner_puzzle_hash = self.standard_wallet.puzzle_for_pk(
bytes(pubkey)
).get_tree_hash()
if self.base_puzzle_program is None:
cc_puzzle: Program = cc_wallet_puzzles.cc_make_puzzle(
inner_puzzle_hash, self.cc_info.my_core
@ -359,7 +365,7 @@ class CCWallet:
self.base_puzzle_program = cc_puzzle
self.base_inner_puzzle_hash = inner_puzzle_hash
else:
cc_puzzle: Program = self.fast_cc_puzzle(inner_puzzle_hash)
cc_puzzle = self.fast_cc_puzzle(inner_puzzle_hash)
return cc_puzzle
async def get_new_cc_puzzle_hash(self):
@ -372,7 +378,7 @@ class CCWallet:
# Create a new coin of value 0 with a given colour
async def generate_zero_val_coin(self) -> Optional[SpendBundle]:
if self.cc_info.my_core is None:
return
return None
coins = await self.standard_wallet.select_coins(1)
if coins is None:
return None
@ -392,10 +398,10 @@ class CCWallet:
cc_puzzle_hash = cc_puzzle.get_tree_hash()
spend_bundle = await self.standard_wallet.generate_signed_transaction(
0, cc_puzzle_hash, uint64(0), origin_id, coins
uint64(0), cc_puzzle_hash, uint64(0), origin_id, coins
)
self.log.warning(f"cc_puzzle_hash is {cc_puzzle_hash}")
eve_coin = Coin(origin_id, cc_puzzle_hash, 0)
eve_coin = Coin(origin_id, cc_puzzle_hash, uint64(0))
if spend_bundle is None:
return None
@ -457,17 +463,18 @@ class CCWallet:
self.log.info(f"Successfully selected coins: {used_coins}")
return used_coins
async def get_sigs(self, innerpuz: Program, innersol: Program):
async def get_sigs(self, innerpuz: Program, innersol: Program) -> List[BLSSignature]:
puzzle_hash = innerpuz.get_tree_hash()
pubkey, private = await self.wallet_state_manager.get_keys(puzzle_hash)
private = BLSPrivateKey(private)
sigs = []
sigs: List[BLSSignature] = []
code_ = [innerpuz, innersol]
sexp = Program.to(code_)
error, conditions, cost = conditions_dict_for_solution(sexp)
for _ in hash_key_pairs_for_conditions_dict(conditions):
signature = private.sign(_.message_hash)
sigs.append(signature)
if conditions is not None:
for _ in hash_key_pairs_for_conditions_dict(conditions):
signature = private.sign(_.message_hash)
sigs.append(signature)
return sigs
async def inner_puzzle_for_cc_puzzle(self, cc_hash: bytes32) -> Program:
@ -477,7 +484,7 @@ class CCWallet:
inner_puzzle: Program = self.standard_wallet.puzzle_for_pk(bytes(record.pubkey))
return inner_puzzle
async def get_parent_for_coin(self, coin) -> CCParent:
async def get_parent_for_coin(self, coin) -> Optional[CCParent]:
parent_info = None
for name, ccparent in self.cc_info.parent_info:
if name == coin.parent_coin_info:
@ -488,10 +495,10 @@ class CCWallet:
async def cc_spend(
self, amount: uint64, to_address: bytes32
) -> Optional[SpendBundle]:
sigs = []
sigs: List[BLSSignature] = []
# Get coins and calculate amount of change required
selected_coins: Optional[List[Coin]] = await self.select_coins(amount)
selected_coins: Optional[Set[Coin]] = await self.select_coins(amount)
if selected_coins is None:
return None
@ -535,6 +542,8 @@ class CCWallet:
innersol = self.standard_wallet.make_solution(primaries=primaries)
sigs = sigs + await self.get_sigs(inner_puzzle, innersol)
parent_info = await self.get_parent_for_coin(auditor)
assert parent_info is not None
assert self.cc_info.my_core is not None
solution = cc_wallet_puzzles.cc_make_solution(
self.cc_info.my_core,
@ -577,11 +586,12 @@ class CCWallet:
# loop through remaining spends, treating them as aggregatees
for coin in selected_coins:
coin_inner_puzzle: Program = await self.inner_puzzle_for_cc_puzzle(
coin_inner_puzzle = await self.inner_puzzle_for_cc_puzzle(
coin.puzzle_hash
)
innersol = self.standard_wallet.make_solution()
parent_info = await self.get_parent_for_coin(coin)
assert parent_info is not None
sigs = sigs + await self.get_sigs(coin_inner_puzzle, innersol)
solution = cc_wallet_puzzles.cc_make_solution(
@ -624,7 +634,7 @@ class CCWallet:
async def add_parent(self, name: bytes32, parent: Optional[CCParent]):
self.log.info(f"Adding parent {name}: {parent}")
current_list: List[Tuple[bytes32, CCParent]] = self.cc_info.parent_info.copy()
current_list = self.cc_info.parent_info.copy()
current_list.append((name, parent))
cc_info: CCInfo = CCInfo(
self.cc_info.my_core, current_list, self.cc_info.my_colour_name,
@ -750,3 +760,9 @@ class CCWallet:
aggsig = BLSSignature.aggregate(sigs)
return SpendBundle(list_of_solutions, aggsig)
# Create an offer spend bundle for chia given an amount of relative change (i.e -400 or 1000)
# This is to be aggregated together with a coloured coin offer to ensure that the trade happens
async def create_spend_bundle_relative_chia(self, chia_amount: uint64):
self.log.error("Not implemented")
# TODO MATT: Implement

File diff suppressed because one or more lines are too long

View File

@ -1,7 +1,5 @@
from typing import Dict, Optional, List, Tuple, Set, Any
import clvm
from blspy import ExtendedPrivateKey, PublicKey
from clvm_tools import binutils
import logging
from src.types.BLSSignature import BLSSignature
from src.types.coin import Coin
@ -14,8 +12,7 @@ from src.util.condition_tools import (
conditions_by_opcode,
hash_key_pairs_for_conditions_dict,
)
from src.types.mempool_inclusion_status import MempoolInclusionStatus
from src.util.ints import uint64, uint32
from src.util.ints import uint64
from src.wallet.BLSPrivateKey import BLSPrivateKey
from src.wallet.puzzles.p2_conditions import puzzle_for_conditions
from src.wallet.puzzles.p2_delegated_puzzle import puzzle_for_pk
@ -27,10 +24,7 @@ from src.wallet.puzzles.puzzle_utils import (
make_assert_fee_condition,
)
from src.wallet.wallet_coin_record import WalletCoinRecord
from src.wallet.transaction_record import TransactionRecord
from src.wallet.wallet_info import WalletInfo
from src.wallet.util.wallet_types import WalletType
from src.wallet.cc_wallet import cc_wallet_puzzles
class Wallet:
@ -338,45 +332,3 @@ class Wallet:
await self.wallet_state_manager.add_pending_transaction(
spend_bundle, self.wallet_info.id
)
# Create an offer spend bundle for chia given an amount of relative change (i.e -400 or 1000)
# This is to be aggregated together with a coloured coin offer to ensure that the trade happens
async def create_spend_bundle_relative_chia(self, chia_amount: uint64):
list_of_solutions = []
utxos = None
# If we're losing value then get coins with at least that much value
# If we're gaining value then our amount doesn't matter
if chia_amount < 0:
utxos = self.select_coins(abs(chia_amount))
else:
utxos = [self.select_coins(1)]
if utxos is None:
return None
# Calculate output amount given sum of utxos
spend_value = sum([coin.amount for coin in utxos])
chia_amount = spend_value + chia_amount
# Create coin solutions for each utxo
output_created = None
sigs = []
for coin in utxos:
pubkey, secretkey = self.wallet_state_manager.get_keys(coin.puzzle_hash)
puzzle = self.puzzle_for_pk(bytes(pubkey))
if output_created is None:
newpuzhash = self.get_new_puzzlehash()
primaries = [{"puzzlehash": newpuzhash, "amount": chia_amount}]
solution = self.make_solution(primaries=primaries)
output_created = coin
else:
solution = self.make_solution(consumed=[output_created.name()])
list_of_solutions.append(
CoinSolution(coin, clvm.to_sexp_f([puzzle, solution]))
)
sigs = sigs + self.get_sigs_for_innerpuz_with_innersol(puzzle, solution)
aggsig = BLSSignature.aggregate(sigs)
spend_bundle = SpendBundle(list_of_solutions, aggsig)
return spend_bundle

View File

@ -118,7 +118,7 @@ class WalletActionStore:
"""
Returns list of all pending action
"""
result = []
result: List[WalletAction] = []
cursor = await self.db_connection.execute(
"SELECT * from action_queue WHERE done=?", (0,)
)

View File

@ -948,10 +948,11 @@ class WalletNode:
)
request_all_removals = False
for coin in additions:
record_info: DerivationRecord = await self.wallet_state_manager.puzzle_store.get_derivation_record_for_puzzle_hash(
puzzle_store = self.wallet_state_manager.puzzle_store
record_info: Optional[DerivationRecord] = await puzzle_store.get_derivation_record_for_puzzle_hash(
coin.puzzle_hash.hex()
)
if record_info.wallet_type == WalletType.COLOURED_COIN:
if record_info is not None and record_info.wallet_type == WalletType.COLOURED_COIN:
request_all_removals = True
break
@ -1101,12 +1102,13 @@ class WalletNode:
The full node respond with transaction generator
"""
wrapper = response.generatorResponse
self.log.info(
f"generator received {wrapper.header_hash} {wrapper.generator.get_tree_hash()} {wrapper.height}"
)
await self.wallet_state_manager.generator_received(
wrapper.height, wrapper.header_hash, wrapper.generator
)
if wrapper.generator is not None:
self.log.info(
f"generator received {wrapper.header_hash} {wrapper.generator.get_tree_hash()} {wrapper.height}"
)
await self.wallet_state_manager.generator_received(
wrapper.height, wrapper.header_hash, wrapper.generator
)
@api_request
async def reject_generator(self, response: wallet_protocol.RejectGeneratorRequest):

View File

@ -133,7 +133,7 @@ class WalletStateManager:
if wallet_info.type == WalletType.STANDARD_WALLET:
if wallet_info.id == 1:
continue
wallet = await Wallet.create(config, key_config, self, main_wallet_info)
wallet = await Wallet.create(config, wallet_info)
self.wallets[wallet_info.id] = wallet
elif wallet_info.type == WalletType.RATE_LIMITED:
wallet = await RLWallet.create(
@ -206,7 +206,7 @@ class WalletStateManager:
return pubkey, private
async def create_more_puzzle_hashes(
self, from_zero: bool = False, for_wallet: any = None
self, from_zero: bool = False, for_wallet: Any = None
):
"""
For all wallets in the user store, generates the first few puzzle hashes so
@ -214,7 +214,7 @@ class WalletStateManager:
"""
if for_wallet is None:
targets = self.wallets.keys()
targets = list(self.wallets.keys())
else:
targets = [for_wallet]
@ -524,6 +524,7 @@ class WalletStateManager:
wallet: CCWallet = self.wallets[wallet_id]
header_hash: bytes32 = self.height_to_hash[index]
block: BlockRecord = await self.wallet_store.get_block_record(header_hash)
assert block.removals is not None
await wallet.coin_added(coin, index, header_hash, block.removals)
async def add_pending_transaction(self, spend_bundle: SpendBundle, wallet_id):
@ -705,8 +706,9 @@ class WalletStateManager:
record = await self.puzzle_store.get_derivation_record_for_puzzle_hash(
addition.puzzle_hash.hex()
)
if record is None:
continue
index = record.index
assert index is not None
await self.puzzle_store.set_used_up_to(index)
await self.create_more_puzzle_hashes()
@ -740,9 +742,9 @@ class WalletStateManager:
while True:
if tip_hash == fork_hash or tip_hash == self.genesis.header_hash:
break
record = self.block_records[tip_hash]
blocks_to_add.append(record)
tip_hash = record.prev_header_hash
block_record: BlockRecord = self.block_records[tip_hash]
blocks_to_add.append(block_record)
tip_hash = block_record.prev_header_hash
blocks_to_add.reverse()
for path_block in blocks_to_add:
@ -1216,7 +1218,9 @@ class WalletStateManager:
for addition in reorg_block.additions:
unspent_coin_names.add(addition.name())
for removal in reorg_block.removals:
record = await self.puzzle_store.get_derivation_record_for_puzzle_hash(removal.puzzle_hash)
record = await self.puzzle_store.get_derivation_record_for_puzzle_hash(
removal.puzzle_hash
)
if record is None:
continue
unspent_coin_names.remove(removal)
@ -1324,8 +1328,8 @@ class WalletStateManager:
return wallet
return None
async def add_new_wallet(self, wallet: any, id: int):
self.wallets[id] = wallet
async def add_new_wallet(self, wallet: Any, id: int):
self.wallets[uint32(id)] = wallet
await self.create_more_puzzle_hashes(for_wallet=id)
async def get_coin_records_by_spent(self, spent: bool):
@ -1380,10 +1384,11 @@ class WalletStateManager:
if stored_header_hash == header_hash and stored_height == height:
if action.done:
return
wallet = self.wallets[action.wallet_id]
wallet = self.wallets[uint32(action.wallet_id)]
callback_str = action.wallet_callback
callback = getattr(wallet, callback_str)
await callback(height, header_hash, program, action.id)
if callback_str is not None:
callback = getattr(wallet, callback_str)
await callback(height, header_hash, program, action.id)
async def get_transaction_status(
self, tx_id: SpendBundle

View File

@ -58,7 +58,7 @@ class WalletUserStore:
async def create_wallet(
self, name: str, wallet_type: WalletType, data: str
) -> WalletInfo:
) -> Optional[WalletInfo]:
cursor = await self.db_connection.execute(
"INSERT INTO users_wallets VALUES(?, ?, ?, ?)",
(None, name, wallet_type.value, data),

View File

@ -224,13 +224,13 @@ class WebSocketServer:
cc_wallet: CCWallet = await CCWallet.create_new_cc(
wallet_state_manager, main_wallet, request["amount"]
)
response = {"success": True, "type": "cc_wallet"}
response = {"success": True, "type": cc_wallet.wallet_info.type.name}
return await websocket.send(format_response(response_api, response))
elif request["mode"] == "existing":
cc_wallet: CCWallet = await CCWallet.create_wallet_for_cc(
wallet_state_manager, main_wallet, request["colour"]
)
response = {"success": True, "type": "cc_wallet"}
response = {"success": True, "type": cc_wallet.wallet_info.type.name}
return await websocket.send(format_response(response_api, response))
response = {"success": False}
@ -561,7 +561,7 @@ class WebSocketServer:
auditees[colour].append(
(
parent_info,
Program(innerpuzzlereveal).get_hash(),
Program(innerpuzzlereveal).get_tree_hash(),
coinsol.coin.amount,
out_amount,
)
@ -570,7 +570,7 @@ class WebSocketServer:
auditees[colour] = [
(
parent_info,
Program(innerpuzzlereveal).get_hash(),
Program(innerpuzzlereveal).get_tree_hash(),
coinsol.coin.amount,
out_amount,
)
@ -622,10 +622,11 @@ class WebSocketServer:
)
auditor_info = (
auditor.parent_coin_info,
auditor_innerpuz.get_hash(),
auditor_innerpuz.get_tree_hash(),
auditor.amount,
)
auditor_formatted = f"(0x{auditor.parent_coin_info} 0x{auditor_innerpuz.get_hash()} {auditor.amount})"
inner_hash = auditor_innerpuz.get_tree_hash()
auditor_formatted = f"(0x{auditor.parent_coin_info} 0x{inner_hash} {auditor.amount})"
core = cc_wallet_puzzles.cc_make_core(colour)
# complete the non-auditor CoinSolutions
@ -674,7 +675,7 @@ class WebSocketServer:
clvm.to_sexp_f(
[
cc_wallet_puzzles.cc_make_puzzle(
innerpuz.get_hash(), core,
innerpuz.get_tree_hash(), core,
),
solution,
]
@ -747,7 +748,7 @@ class WebSocketServer:
clvm.to_sexp_f(
[
cc_wallet_puzzles.cc_make_puzzle(
auditor_innerpuz.get_hash(), core
auditor_innerpuz.get_tree_hash(), core
),
solution,
]