def load_clvm(clvm_filename, package_or_requirement=__name__) -> Program: """ This function takes a .clvm file in the given package and compiles it to a .clvm.hex file if the .hex file is missing or older than the .clvm file, then returns the contents of the .hex file as a `Program`. clvm_filename: file name package_or_requirement: usually `__name__` if the clvm file is in the same package """ hex_filename = f"{clvm_filename}.hex" try: if pkg_resources.resource_exists(package_or_requirement, clvm_filename): full_path = pathlib.Path( pkg_resources.resource_filename(package_or_requirement, clvm_filename)) output = full_path.parent / hex_filename compile_clvm(full_path, output) except NotImplementedError: # pyinstaller doesn't support `pkg_resources.resource_exists` # so we just fall through to loading the hex clvm pass clvm_hex = pkg_resources.resource_string(package_or_requirement, hex_filename).decode("utf8") clvm_blob = bytes.fromhex(clvm_hex) return Program.from_bytes(clvm_blob)
async def create_wallet_for_cc( wallet_state_manager: Any, wallet: Wallet, genesis_checker_hex: str, name: str = None, ): self = CCWallet() self.base_puzzle_program = None self.base_inner_puzzle_hash = None self.standard_wallet = wallet if name: self.log = logging.getLogger(name) else: self.log = logging.getLogger(__name__) self.wallet_state_manager = wallet_state_manager self.cc_info = CCInfo( Program.from_bytes(bytes.fromhex(genesis_checker_hex)), []) info_as_string = bytes(self.cc_info).hex() self.wallet_info = await wallet_state_manager.user_store.create_wallet( "CC Wallet", WalletType.COLOURED_COIN.value, info_as_string) if self.wallet_info is None: raise Exception("wallet_info is None") await self.wallet_state_manager.add_new_wallet(self, self.wallet_info.id) return self
def batch_pre_validate_sub_blocks( constants_dict: Dict, sub_blocks_pickled: Dict[bytes, bytes], header_blocks_pickled: List[bytes], transaction_generators: List[Optional[bytes]], check_filter: bool, expected_difficulty: List[uint64], expected_sub_slot_iters: List[uint64], ) -> List[bytes]: assert len(header_blocks_pickled) == len(transaction_generators) sub_blocks = {} for k, v in sub_blocks_pickled.items(): sub_blocks[k] = SubBlockRecord.from_bytes(v) results: List[PreValidationResult] = [] constants: ConsensusConstants = dataclass_from_dict( ConsensusConstants, constants_dict) for i in range(len(header_blocks_pickled)): try: header_block: HeaderBlock = HeaderBlock.from_bytes( header_blocks_pickled[i]) generator: Optional[bytes] = transaction_generators[i] required_iters, error = validate_finished_header_block( constants, sub_blocks, header_block, check_filter, expected_difficulty[i], expected_sub_slot_iters[i], ) cost_result = None error_int: Optional[uint16] = None if error is not None: error_int = uint16(error.code.value) if not error and generator is not None: cost_result = calculate_cost_of_program( Program.from_bytes(generator), constants.CLVM_COST_RATIO_CONSTANT) results.append( PreValidationResult(error_int, required_iters, cost_result)) except Exception: error_stack = traceback.format_exc() log.error(f"Exception: {error_stack}") results.append( PreValidationResult(uint16(Err.UNKNOWN.value), None, None)) return [bytes(r) for r in results]
def load_clvm(clvm_filename, package_or_requirement=__name__): """ This function takes a .clvm file in the given package and compiles it to a .clvm.hex file if the .hex file is missing or older than the .clvm file, then returns the contents of the .hex file as a `Program`. clvm_filename: file name package_or_requirement: usually `__name__` if the clvm file is in the same package """ hex_filename = f"{clvm_filename}.hex" if pkg_resources.resource_exists(package_or_requirement, clvm_filename): full_path = pathlib.Path( pkg_resources.resource_filename(package_or_requirement, clvm_filename)) output = full_path.parent / hex_filename compile_clvm(full_path, output) clvm_hex = pkg_resources.resource_string(package_or_requirement, hex_filename).decode("utf8") clvm_blob = bytes.fromhex(clvm_hex) return Program.from_bytes(clvm_blob)
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) program = Program.from_bytes(new_sexp) return program
cc_puzzle_hash_for_inner_puzzle_hash, spendable_cc_list_from_coin_solution, spend_bundle_for_spendable_ccs, CC_MOD, ) from src.wallet.puzzles.genesis_by_coin_id_with_0 import create_genesis_or_zero_coin_checker from src.wallet.puzzles.genesis_by_puzzle_hash_with_0 import create_genesis_puzzle_or_zero_coin_checker CONDITIONS = dict( (k, bytes(v)[0]) for k, v in ConditionOpcode.__members__.items()) NULL_SIGNATURE = G2Element.generator() * 0 ANYONE_CAN_SPEND_PUZZLE = Program.to(1) # simply return the conditions NULL_F = Program.from_bytes(bytes.fromhex("ff01ff8080")) # (q ()) PUZZLE_TABLE: Dict[bytes32, Program] = dict( (_.get_tree_hash(), _) for _ in [ANYONE_CAN_SPEND_PUZZLE]) def hash_to_puzzle_f(puzzle_hash: bytes32) -> Optional[Program]: return PUZZLE_TABLE.get(puzzle_hash) def add_puzzles_to_puzzle_preimage_db(puzzles: List[Program]) -> None: for _ in puzzles: PUZZLE_TABLE[_.get_tree_hash()] = _ def int_as_bytes32(v: int) -> bytes32:
def test_serialization(self): s0 = SerializedProgram.from_bytes(b"\x00") p0 = Program.from_bytes(b"\x00") print(s0, p0)
def load_clvm(filename): clvm_hex = pkg_resources.resource_string(__name__, "%s.hex" % filename).decode("utf8") clvm_blob = bytes.fromhex(clvm_hex) return Program.from_bytes(clvm_blob)
from src.types.sized_bytes import bytes32 from src.util.clvm import int_from_bytes from src.util.condition_tools import ConditionOpcode, conditions_by_opcode from src.util.errors import Err import time from src.util.ints import uint64, uint32 # Sourced from puzzles/generator.clvm GENERATOR_MOD = Program.from_bytes( bytes.fromhex( "ffff05ffff01ffffff05ff04ffff05ff02f" "fff05ffffff05ff03ffff01ff80808080ffff01ffff8080808080808080ffff05ffff" "01ffffffff05ffff04ff05ffff01ffffff05ff04ffff05ff02ffff05ff0dffff05fff" "f05ffffff05ff0affff05ff02ffff05ff09ffff01ff808080808080ff0b80ffff01ff8" "080808080808080ffff01ff0b8080ff018080ffffff05ffff04ffffff05ffff04ffff0af" "f1dffff01ff808080ffff01ffffff05ffff04ffff0aff75ffff01ff808080ffff01ffff" "ff05ffff04ffff0affff11ff0980ffff01ff208080ffff01ffff01ff018080ffff01fff" "f01ff80808080ff01808080ffff01ffff01ff80808080ff01808080ffff01ffff01ff808" "08080ff018080ffff01ffff05ff09ffff05ffffff05ff0effff05ff02ffff05ff25ffff01" "ff808080808080ffff05ffffff05ff25ff558080ffff01ff808080808080ffff01ffff098" "08080ff018080ffff05ffff04ffff08ff0580ffff01ffff0bffff01ff0280ffffff05ff0e" "ffff05ff02ffff05ff09ffff01ff808080808080ffffff05ff0effff05ff02ffff05ff0df" "fff01ff8080808080808080ffff01ffff0bffff01ff0180ff05808080ff01808080ff01808080" )) GENERATOR_FOR_SINGLE_COIN_MOD = Program.from_bytes( bytes.fromhex( "ffff05ffff01ffffff05ff02ffff05ff02ffff05ffffff05ff05ffff01ff80808080f" "fff05ff0bffff01ff8080808080808080ffff05ffff01ffffff05ffff04ff05ffff01" "ffffff05ffff04ffff0aff11ff0b80ffff01ffff05ff49ffff05ff8200a9ffff01ff8" "080808080ffff01ffffff05ff02ffff05ff02ffff05ff0dffff05ff0bffff01ff8080" "80808080808080ff01808080ffff01ffff09808080ff01808080ff01808080"))
async def respond_to_offer( self, file_path: Path ) -> Tuple[bool, Optional[TradeRecord], Optional[str]]: has_wallets = await self.maybe_create_wallets_for_offer(file_path) if not has_wallets: return False, None, "Unknown Error" trade_offer = None try: trade_offer_hex = file_path.read_text() trade_offer = TradeRecord.from_bytes( hexstr_to_bytes(trade_offer_hex)) except Exception as e: return False, None, f"Error: {e}" if trade_offer is not None: offer_spend_bundle: SpendBundle = trade_offer.spend_bundle coinsols = [] # [] of CoinSolutions cc_coinsol_outamounts: Dict[bytes32, List[Tuple[Any, int]]] = dict() aggsig = offer_spend_bundle.aggregated_signature cc_discrepancies: Dict[bytes32, int] = dict() chia_discrepancy = None wallets: Dict[bytes32, Any] = dict() # colour to wallet dict for coinsol in offer_spend_bundle.coin_solutions: puzzle: Program = coinsol.solution.first() solution: Program = coinsol.solution.rest().first() # work out the deficits between coin amount and expected output for each r = cc_utils.uncurry_cc(puzzle) if r: # Calculate output amounts mod_hash, genesis_checker, inner_puzzle = r colour = bytes(genesis_checker).hex() if colour not in wallets: wallets[ colour] = await self.wallet_state_manager.get_wallet_for_colour( colour) unspent = ( await self.wallet_state_manager.get_spendable_coins_for_wallet( wallets[colour].wallet_info.id)) if coinsol.coin in [record.coin for record in unspent]: return False, None, "can't respond to own offer" innersol = solution.first() total = get_output_amount_for_puzzle_and_solution( inner_puzzle, innersol) if colour in cc_discrepancies: cc_discrepancies[colour] += coinsol.coin.amount - total else: cc_discrepancies[colour] = coinsol.coin.amount - total # Store coinsol and output amount for later if colour in cc_coinsol_outamounts: cc_coinsol_outamounts[colour].append((coinsol, total)) else: cc_coinsol_outamounts[colour] = [(coinsol, total)] else: # standard chia coin unspent = (await self.wallet_state_manager. get_spendable_coins_for_wallet(1)) if coinsol.coin in [record.coin for record in unspent]: return False, None, "can't respond to own offer" if chia_discrepancy is None: chia_discrepancy = get_output_discrepancy_for_puzzle_and_solution( coinsol.coin, puzzle, solution) else: chia_discrepancy += get_output_discrepancy_for_puzzle_and_solution( coinsol.coin, puzzle, solution) coinsols.append(coinsol) chia_spend_bundle: Optional[SpendBundle] = None if chia_discrepancy is not None: chia_spend_bundle = await self.wallet_state_manager.main_wallet.create_spend_bundle_relative_chia( chia_discrepancy, []) if chia_spend_bundle is not None: for coinsol in coinsols: chia_spend_bundle.coin_solutions.append(coinsol) zero_spend_list: List[SpendBundle] = [] spend_bundle = None # create coloured coin self.log.info(cc_discrepancies) for colour in cc_discrepancies.keys(): if cc_discrepancies[colour] < 0: my_cc_spends = await wallets[colour].select_coins( abs(cc_discrepancies[colour])) else: if chia_spend_bundle is None: to_exclude: List = [] else: to_exclude = chia_spend_bundle.removals() my_cc_spends = await wallets[colour].select_coins(0) if my_cc_spends is None or my_cc_spends == set(): zero_spend_bundle: SpendBundle = await wallets[ colour].generate_zero_val_coin(False, to_exclude) if zero_spend_bundle is None: return ( False, None, "Unable to generate zero value coin. Confirm that you have chia available", ) zero_spend_list.append(zero_spend_bundle) additions = zero_spend_bundle.additions() removals = zero_spend_bundle.removals() my_cc_spends = set() for add in additions: if add not in removals and add.amount == 0: my_cc_spends.add(add) if my_cc_spends == set() or my_cc_spends is None: return False, None, "insufficient funds" # Create SpendableCC list and innersol_list with both my coins and the offered coins # Firstly get the output coin my_output_coin = my_cc_spends.pop() spendable_cc_list = [] innersol_list = [] genesis_id = genesis_coin_id_for_genesis_coin_checker( Program.from_bytes(bytes.fromhex(colour))) # Make the rest of the coins assert the output coin is consumed for coloured_coin in my_cc_spends: inner_solution = self.wallet_state_manager.main_wallet.make_solution( consumed=[my_output_coin.name()]) inner_puzzle = await self.get_inner_puzzle_for_puzzle_hash( coloured_coin.puzzle_hash) assert inner_puzzle is not None sigs = await wallets[colour].get_sigs( inner_puzzle, inner_solution, ) sigs.append(aggsig) aggsig = AugSchemeMPL.aggregate(sigs) lineage_proof = await wallets[ colour].get_lineage_proof_for_coin(coloured_coin) spendable_cc_list.append( SpendableCC(coloured_coin, genesis_id, inner_puzzle, lineage_proof)) innersol_list.append(inner_solution) # Create SpendableCC for each of the coloured coins received for cc_coinsol_out in cc_coinsol_outamounts[colour]: cc_coinsol = cc_coinsol_out[0] puzzle = cc_coinsol.solution.first() solution = cc_coinsol.solution.rest().first() r = uncurry_cc(puzzle) if r: mod_hash, genesis_coin_checker, inner_puzzle = r inner_solution = solution.first() lineage_proof = solution.rest().rest().first() spendable_cc_list.append( SpendableCC(cc_coinsol.coin, genesis_id, inner_puzzle, lineage_proof)) innersol_list.append(inner_solution) # Finish the output coin SpendableCC with new information newinnerpuzhash = await wallets[colour].get_new_inner_hash() outputamount = (sum([c.amount for c in my_cc_spends]) + cc_discrepancies[colour] + my_output_coin.amount) inner_solution = self.wallet_state_manager.main_wallet.make_solution( primaries=[{ "puzzlehash": newinnerpuzhash, "amount": outputamount }]) inner_puzzle = await self.get_inner_puzzle_for_puzzle_hash( my_output_coin.puzzle_hash) assert inner_puzzle is not None lineage_proof = await wallets[colour].get_lineage_proof_for_coin( my_output_coin) spendable_cc_list.append( SpendableCC(my_output_coin, genesis_id, inner_puzzle, lineage_proof)) innersol_list.append(inner_solution) sigs = await wallets[colour].get_sigs( inner_puzzle, inner_solution, ) sigs.append(aggsig) aggsig = AugSchemeMPL.aggregate(sigs) if spend_bundle is None: spend_bundle = spend_bundle_for_spendable_ccs( CC_MOD, Program.from_bytes(bytes.fromhex(colour)), spendable_cc_list, innersol_list, [aggsig], ) else: new_spend_bundle = spend_bundle_for_spendable_ccs( CC_MOD, Program.from_bytes(bytes.fromhex(colour)), spendable_cc_list, innersol_list, [aggsig], ) spend_bundle = SpendBundle.aggregate( [spend_bundle, new_spend_bundle]) # reset sigs and aggsig so that they aren't included next time around sigs = [] aggsig = AugSchemeMPL.aggregate(sigs) my_tx_records = [] if zero_spend_list is not None and spend_bundle is not None: zero_spend_list.append(spend_bundle) spend_bundle = SpendBundle.aggregate(zero_spend_list) if spend_bundle is None: return False, None, "spend_bundle missing" # Add transaction history for this trade now = uint64(int(time.time())) if chia_spend_bundle is not None: spend_bundle = SpendBundle.aggregate( [spend_bundle, chia_spend_bundle]) # debug_spend_bundle(spend_bundle) if chia_discrepancy < 0: tx_record = TransactionRecord( confirmed_at_index=uint32(0), created_at_time=now, to_puzzle_hash=token_bytes(), amount=uint64(abs(chia_discrepancy)), fee_amount=uint64(0), incoming=False, confirmed=False, sent=uint32(10), spend_bundle=chia_spend_bundle, additions=chia_spend_bundle.additions(), removals=chia_spend_bundle.removals(), wallet_id=uint32(1), sent_to=[], trade_id=std_hash(spend_bundle.name() + bytes(now)), ) else: tx_record = TransactionRecord( confirmed_at_index=uint32(0), created_at_time=uint64(int(time.time())), to_puzzle_hash=token_bytes(), amount=uint64(abs(chia_discrepancy)), fee_amount=uint64(0), incoming=True, confirmed=False, sent=uint32(10), spend_bundle=chia_spend_bundle, additions=chia_spend_bundle.additions(), removals=chia_spend_bundle.removals(), wallet_id=uint32(1), sent_to=[], trade_id=std_hash(spend_bundle.name() + bytes(now)), ) my_tx_records.append(tx_record) for colour, amount in cc_discrepancies.items(): wallet = wallets[colour] if chia_discrepancy > 0: tx_record = TransactionRecord( confirmed_at_index=uint32(0), created_at_time=uint64(int(time.time())), to_puzzle_hash=token_bytes(), amount=uint64(abs(amount)), fee_amount=uint64(0), incoming=False, confirmed=False, sent=uint32(10), spend_bundle=spend_bundle, additions=spend_bundle.additions(), removals=spend_bundle.removals(), wallet_id=wallet.wallet_info.id, sent_to=[], trade_id=std_hash(spend_bundle.name() + bytes(now)), ) else: tx_record = TransactionRecord( confirmed_at_index=uint32(0), created_at_time=uint64(int(time.time())), to_puzzle_hash=token_bytes(), amount=uint64(abs(amount)), fee_amount=uint64(0), incoming=True, confirmed=False, sent=uint32(10), spend_bundle=spend_bundle, additions=spend_bundle.additions(), removals=spend_bundle.removals(), wallet_id=wallet.wallet_info.id, sent_to=[], trade_id=std_hash(spend_bundle.name() + bytes(now)), ) my_tx_records.append(tx_record) tx_record = TransactionRecord( confirmed_at_index=uint32(0), created_at_time=uint64(int(time.time())), to_puzzle_hash=token_bytes(), amount=uint64(0), fee_amount=uint64(0), incoming=False, confirmed=False, sent=uint32(0), spend_bundle=spend_bundle, additions=spend_bundle.additions(), removals=spend_bundle.removals(), wallet_id=uint32(0), sent_to=[], trade_id=std_hash(spend_bundle.name() + bytes(now)), ) now = uint64(int(time.time())) trade_record: TradeRecord = TradeRecord( confirmed_at_index=uint32(0), accepted_at_time=now, created_at_time=now, my_offer=False, sent=uint32(0), spend_bundle=offer_spend_bundle, tx_spend_bundle=spend_bundle, additions=spend_bundle.additions(), removals=spend_bundle.removals(), trade_id=std_hash(spend_bundle.name() + bytes(now)), status=uint32(TradeStatus.PENDING_CONFIRM.value), sent_to=[], ) await self.save_trade(trade_record) await self.wallet_state_manager.add_pending_transaction(tx_record) for tx in my_tx_records: await self.wallet_state_manager.add_transaction(tx) return True, trade_record, None
from typing import Union from blspy import G1Element from clvm.casts import int_from_bytes from src.types.program import Program from src.types.sized_bytes import bytes32 from .load_clvm import load_clvm from .p2_conditions import puzzle_for_conditions DEFAULT_HIDDEN_PUZZLE = Program.from_bytes( bytes.fromhex("ff0980") ) # this puzzle `(x)` always fails MOD = load_clvm("p2_delegated_puzzle_or_hidden_puzzle.clvm") SYNTHETIC_MOD = load_clvm("calculate_synthetic_public_key.clvm") PublicKeyProgram = Union[bytes, Program] def calculate_synthetic_offset( public_key: G1Element, hidden_puzzle_hash: bytes32 ) -> int: blob = hashlib.sha256(bytes(public_key) + hidden_puzzle_hash).digest() return int_from_bytes(blob)
""" import hashlib from typing import Union from blspy import G1Element from clvm.casts import int_from_bytes from src.types.program import Program from src.types.sized_bytes import bytes32 from .load_clvm import load_clvm from .p2_conditions import puzzle_for_conditions DEFAULT_HIDDEN_PUZZLE = Program.from_bytes(bytes.fromhex("ff0980")) DEFAULT_HIDDEN_PUZZLE_HASH = (DEFAULT_HIDDEN_PUZZLE.get_tree_hash() ) # this puzzle `(x)` always fails MOD = load_clvm("p2_delegated_puzzle_or_hidden_puzzle.clvm") SYNTHETIC_MOD = load_clvm("calculate_synthetic_public_key.clvm") PublicKeyProgram = Union[bytes, Program] GROUP_ORDER = 0x73EDA753299D7D483339D80809A1D80553BDA402FFFE5BFEFFFFFFFF00000001 def calculate_synthetic_offset(public_key: G1Element, hidden_puzzle_hash: bytes32) -> int:
from src.types.sized_bytes import bytes32 from src.types.spend_bundle import CoinSolution, SpendBundle from src.util.condition_tools import conditions_dict_for_solution from src.util.ints import uint64 from src.wallet.puzzles.cc_loader import CC_MOD from src.wallet.puzzles.genesis_by_coin_id_with_0 import ( lineage_proof_for_genesis, lineage_proof_for_coin, lineage_proof_for_zero, genesis_coin_id_for_genesis_coin_checker, ) NULL_SIGNATURE = G2Element.generator() * 0 LOCK_INNER_PUZZLE = Program.from_bytes(bytes.fromhex("ff01ff8080")) # (q ()) ANYONE_CAN_SPEND_PUZZLE = Program.to(1) # simply return the conditions # information needed to spend a cc # if we ever support more genesis conditions, like a re-issuable coin, # we may need also to save the `genesis_coin_mod` or its hash @dataclasses.dataclass class SpendableCC: coin: Coin genesis_coin_id: bytes32 inner_puzzle: Program lineage_proof: Program
def load_clvm(clvm_filename, package_or_requirement=__name__) -> Program: return Program.from_bytes(bytes(load_serialized_clvm(clvm_filename, package_or_requirement=__name__)))