示例#1
0
def check_idempotency(f, args):
    cost, curried = curry(f, args)

    r = disassemble(curried)
    f_0, args_0 = uncurry(curried)

    assert disassemble(f_0) == disassemble(f)
    assert disassemble(args_0) == disassemble(args)
    return r
示例#2
0
    async def get_discrepancies_for_offer(
            self, file_path: Path
    ) -> Tuple[bool, Optional[Dict], Optional[Exception]]:
        try:
            self.log.info(f"trade offer: {file_path}")
            cc_discrepancies: Dict[bytes32, int] = dict()
            trade_offer_hex = file_path.read_text()
            trade_offer = SpendBundle.from_bytes(
                bytes.fromhex(trade_offer_hex))
            for coinsol in trade_offer.coin_solutions:
                puzzle = coinsol.solution.first()
                solution = coinsol.solution.rest().first()

                # work out the deficits between coin amount and expected output for each
                if cc_wallet_puzzles.check_is_cc_puzzle(puzzle):
                    parent_info = binutils.disassemble(
                        solution.rest().first()).split(" ")
                    if len(parent_info) > 1:
                        colour = cc_wallet_puzzles.get_genesis_from_puzzle(
                            binutils.disassemble(puzzle))
                        # get puzzle and solution
                        innerpuzzlereveal = solution.rest().rest().rest(
                        ).first()
                        innersol = solution.rest().rest().rest().rest().first()
                        # Get output amounts by running innerpuzzle and solution
                        out_amount = cc_wallet_puzzles.get_output_amount_for_puzzle_and_solution(
                            innerpuzzlereveal, innersol)
                        # add discrepancy to dict of discrepancies
                        if colour in cc_discrepancies:
                            cc_discrepancies[
                                colour] += coinsol.coin.amount - out_amount
                        else:
                            cc_discrepancies[
                                colour] = coinsol.coin.amount - out_amount
                else:  # standard chia coin
                    coin_amount = coinsol.coin.amount
                    out_amount = cc_wallet_puzzles.get_output_amount_for_puzzle_and_solution(
                        puzzle, solution)
                    diff = coin_amount - out_amount
                    if "chia" in cc_discrepancies:
                        cc_discrepancies[
                            "chia"] = cc_discrepancies["chia"] + diff
                    else:
                        cc_discrepancies["chia"] = diff

            return True, cc_discrepancies, None
        except Exception as e:
            return False, None, e
示例#3
0
 async def test_clvm_strict_mode(self, rust_checker: bool):
     block = Program.from_bytes(bytes(SMALL_BLOCK_GENERATOR.program))
     disassembly = binutils.disassemble(block)
     # this is a valid generator program except the first clvm
     # if-condition, that depends on executing an unknown operator
     # ("0xfe"). In strict mode, this should fail, but in non-strict
     # mode, the unknown operator should be treated as if it returns ().
     program = SerializedProgram.from_bytes(
         binutils.assemble(
             f"(i (0xfe (q . 0)) (q . ()) {disassembly})").as_bin())
     generator = BlockGenerator(program, [])
     npc_result: NPCResult = get_name_puzzle_conditions(
         generator,
         test_constants.MAX_BLOCK_COST_CLVM,
         cost_per_byte=test_constants.COST_PER_BYTE,
         safe_mode=True,
         rust_checker=rust_checker,
     )
     assert npc_result.error is not None
     npc_result = get_name_puzzle_conditions(
         generator,
         test_constants.MAX_BLOCK_COST_CLVM,
         cost_per_byte=test_constants.COST_PER_BYTE,
         safe_mode=False,
         rust_checker=rust_checker,
     )
     assert npc_result.error is None
    async def test_clvm_max_cost(self):

        block = Program.from_bytes(bytes(SMALL_BLOCK_GENERATOR.program))
        disassembly = binutils.disassemble(block)
        # this is a valid generator program except the first clvm
        # if-condition, that depends on executing an unknown operator
        # ("0xfe"). In strict mode, this should fail, but in non-strict
        # mode, the unknown operator should be treated as if it returns ().
        # the CLVM program has a cost of 391969
        program = SerializedProgram.from_bytes(
            binutils.assemble(
                f"(i (softfork (q . 10000000)) (q . ()) {disassembly})").
            as_bin())

        # ensure we fail if the program exceeds the cost
        generator = BlockGenerator(program, [])
        npc_result: NPCResult = get_name_puzzle_conditions(
            generator, 10000000, False)

        assert npc_result.error is not None
        assert npc_result.clvm_cost == 0

        # raise the max cost to make sure this passes
        # ensure we pass if the program does not exceeds the cost
        npc_result: NPCResult = get_name_puzzle_conditions(
            generator, 20000000, False)

        assert npc_result.error is None
        assert npc_result.clvm_cost > 10000000
示例#5
0
 def as_generate_secret_hash(self, secret):
     secret_hash_cl = f"(sha256 (q {secret}))"
     sec = f"({secret})"
     cost, secret_hash_preformat = clvm.run_program(
         binutils.assemble("(sha256 (f (a)))"), binutils.assemble(sec))
     secret_hash = binutils.disassemble(secret_hash_preformat)
     return secret_hash
示例#6
0
def puzzle_for_m_of_public_key_list(m, public_key_list):
    format_tuple = tuple(
        binutils.disassemble(Program.to(_))
        for _ in (puzzle_prog_template, m, public_key_list))
    puzzle_src = "((c (q %s) (c (q %s) (c (q %s) (a)))))" % format_tuple
    puzzle_prog = binutils.assemble(puzzle_src)
    return Program.to(puzzle_prog)
def puzzle_for_synthetic_public_key(synthetic_public_key):
    puzzle_src = "((c (q %s) (c (q 0x%s) (a))))" % (
        binutils.disassemble(puzzle_prog_template),
        synthetic_public_key.hex(),
    )
    puzzle_prog = binutils.assemble(puzzle_src)
    return Program(puzzle_prog)
def update_auditors_in_solution(solution: SExp, auditor_info):
    old_solution = binutils.disassemble(solution)
    # auditor is (primary_input, innerpuzzlehash, amount)
    new_solution = old_solution.replace(
        "))) ()) () ()))",
        f"))) ()) (0x{auditor_info[0]} 0x{auditor_info[1]} {auditor_info[2]}) ()))",
    )
    return binutils.assemble(new_solution)
示例#9
0
 def as_generate_secret_hash(self, secret):
     secret_hash_cl = "(sha256 (q %s))" % (secret)
     sec = "(%s)" % secret
     secret_hash_preformat = clvm.eval_f(
         clvm.eval_f, binutils.assemble("(sha256 (f (a)))"),
         binutils.assemble(sec))
     secret_hash = binutils.disassemble(secret_hash_preformat)
     return secret_hash
示例#10
0
    async def test_strict_mode(self, rust_checker: bool):
        wallet_tool = bt.get_pool_wallet_tool()
        ph = wallet_tool.get_new_puzzlehash()

        num_blocks = 3
        blocks = bt.get_consecutive_blocks(num_blocks, [],
                                           guarantee_transaction_block=True,
                                           pool_reward_puzzle_hash=ph,
                                           farmer_reward_puzzle_hash=ph)

        coinbase = None
        for coin in blocks[2].get_included_reward_coins():
            if coin.puzzle_hash == ph:
                coinbase = coin
                break
        assert coinbase is not None
        spend_bundle = wallet_tool.generate_signed_transaction(
            coinbase.amount,
            BURN_PUZZLE_HASH,
            coinbase,
        )
        assert spend_bundle is not None

        pk = bytes.fromhex(
            "88bc9360319e7c54ab42e19e974288a2d7a817976f7633f4b43f36ce72074e59c4ab8ddac362202f3e366f0aebbb6280"
        )
        puzzle = p2_delegated_puzzle_or_hidden_puzzle.puzzle_for_pk(pk)
        disassembly = binutils.disassemble(puzzle)
        program = SerializedProgram.from_bytes(
            binutils.assemble(
                f"(q ((0x3d2331635a58c0d49912bc1427d7db51afe3f20a7b4bcaffa17ee250dcbcbfaa {disassembly} 300"
                f"  (() (q . ((65 '00000000000000000000000000000000' 0x0cbba106e000))) ()))))"
            ).as_bin())
        generator = BlockGenerator(program, [])
        npc_result: NPCResult = get_name_puzzle_conditions(
            generator,
            test_constants.MAX_BLOCK_COST_CLVM,
            cost_per_byte=test_constants.COST_PER_BYTE,
            safe_mode=True,
            rust_checker=rust_checker,
        )
        assert npc_result.error is not None
        npc_result = get_name_puzzle_conditions(
            generator,
            test_constants.MAX_BLOCK_COST_CLVM,
            cost_per_byte=test_constants.COST_PER_BYTE,
            safe_mode=False,
            rust_checker=rust_checker,
        )
        assert npc_result.error is None

        coin_name = npc_result.npc_list[0].coin_name
        error, puzzle, solution = get_puzzle_and_solution_for_coin(
            generator, coin_name, test_constants.MAX_BLOCK_COST_CLVM)
        assert error is None
示例#11
0
def check_is_cc_puzzle(puzzle: Program):
    puzzle_string = binutils.disassemble(puzzle)
    inner_puzzle = extract_hex_64(puzzle_string, idx=0)
    if inner_puzzle is None:
        return False
    if all(c in string.hexdigits for c in inner_puzzle) is not True:
        return False
    genesisCoin = get_genesis_from_puzzle(puzzle)
    if all(c in string.hexdigits for c in genesisCoin) is not True:
        return False
    return cc_make_puzzle(inner_puzzle, cc_make_core(genesisCoin)) == puzzle
示例#12
0
def curry_cmd(program, args, treehash, dump, include):
    prog = parse_program(program, include)
    curry_args = [assemble(arg) for arg in args]

    prog_final = prog.curry(*curry_args)
    if treehash:
        print(prog_final.get_tree_hash())
    elif dump:
        print(prog_final)
    else:
        print(disassemble(prog_final))
示例#13
0
 def pull_preimage(self, body, removals):
     for coin in removals:
         for swap in self.as_swap_list:
             if coin.puzzle_hash.hex() == swap["outgoing puzzlehash"]:
                 l = [(puzzle_hash, puzzle_solution_program)
                      for (puzzle_hash, puzzle_solution_program
                           ) in self.as_solution_list(body.solution_program)
                      ]
                 for x in l:
                     if x[0].hex() == coin.puzzle_hash.hex():
                         pre1 = binutils.disassemble(x[1])
                         preimage = pre1[(len(pre1) - 515):(len(pre1) - 3)]
                         swap["secret"] = preimage
def adaptor_for_singleton_inner_puzzle(puzzle: Program) -> Program:
    """
    The singleton puzzle requires an inner puzzle which gets passed some "truths" from
    the singleton that are guaranteed to be correct. Using these truths may reduce the
    size of the inner puzzle, since any values can be used knowing they are checked elsewhere.
    However, an inner puzzle that is not aware that this first argument contains these
    values can be "adapted" using this function to ignore the first argument (and slide
    the subsequent arguments over), allowing any inner puzzle that thinks it's an outer
    puzzle to work as a singleton inner puzzle.
    """
    # this is pretty slow and lame
    return Program.to(
        binutils.assemble("(a (q . %s) 3)" % binutils.disassemble(puzzle)))
示例#15
0
 async def test_clvm_strict_mode(self):
     block = Program.from_bytes(bytes(SMALL_BLOCK_GENERATOR))
     disassembly = binutils.disassemble(block)
     # this is a valid generator program except the first clvm
     # if-condition, that depends on executing an unknown operator
     # ("0xfe"). In strict mode, this should fail, but in non-strict
     # mode, the unknown operator should be treated as if it returns ().
     program = SerializedProgram.from_bytes(
         binutils.assemble(
             f"(i (0xfe (q . 0)) (q . ()) {disassembly})").as_bin())
     error, npc_list, cost = get_name_puzzle_conditions(program, True)
     assert error is not None
     error, npc_list, cost = get_name_puzzle_conditions(program, False)
     assert error is None
def check_is_cc_puzzle(puzzle: Program):
    puzzle_string = binutils.disassemble(puzzle)
    if len(puzzle_string) < 4000:
        return False
    inner_puzzle = puzzle_string[11:75]
    if all(c in string.hexdigits for c in inner_puzzle) is not True:
        return False
    genesisCoin = get_genesis_from_puzzle(puzzle_string)
    if all(c in string.hexdigits for c in genesisCoin) is not True:
        return False
    if cc_make_puzzle(inner_puzzle, cc_make_core(genesisCoin)) == puzzle:
        return True
    else:
        return False
def get_output_amount_for_puzzle_and_solution(puzzle, solution):
    conditions = run_program(puzzle, solution)[1]
    amount = 0
    while conditions != b"":
        opcode = conditions.first().first()
        if opcode == b"3":  # Check if CREATE_COIN
            amount_str = binutils.disassemble(
                conditions.first().rest().rest().first())
            if amount_str == "()":
                conditions = conditions.rest()
                continue
            elif amount_str[0:2] == "0x":  # Check for wonky decompilation
                amount += int(amount_str, 16)
            else:
                amount += int(amount_str, 10)
        conditions = conditions.rest()
    return amount
示例#18
0
def lower_quote(prog, macro_lookup=None, symbol_table=None, run_program=None):
    if prog.nullp():
        return prog

    if prog.listp():
        if prog.first().as_atom() == b"quote":
            # Note: quote should have exactly one arg, so the length of
            # quoted list should be 2: "(quote arg)"
            if not prog.rest().rest().nullp():
                raise SyntaxError(
                    "Compilation error while compiling [%s]. quote takes exactly one argument."
                    % disassemble(prog))
            return prog.to(quote(lower_quote(prog.rest().first())))
        else:
            return prog.to(
                (lower_quote(prog.first()), lower_quote(prog.rest())))
    else:
        return prog
示例#19
0
    async def create_spend_bundle_relative_amount(self,
                                                  cc_amount,
                                                  zero_coin: Coin = None):
        # If we're losing value then get coloured coins with at least that much value
        # If we're gaining value then our amount doesn't matter
        if cc_amount < 0:
            cc_spends = await self.select_coins(abs(cc_amount))
        else:
            if zero_coin is None:
                return None
            cc_spends = set()
            cc_spends.add(zero_coin)

        if cc_spends is None:
            return None

        # Calculate output amount given relative difference and sum of actual values
        spend_value = sum([coin.amount for coin in cc_spends])
        cc_amount = spend_value + cc_amount

        # Loop through coins and create solution for innerpuzzle
        list_of_solutions = []
        output_created = None
        sigs: List[G2Element] = []
        for coin in cc_spends:
            if output_created is None:
                newinnerpuzhash = await self.get_new_inner_hash()
                innersol = self.standard_wallet.make_solution(
                    primaries=[{
                        "puzzlehash": newinnerpuzhash,
                        "amount": cc_amount
                    }])
                output_created = coin
            else:
                innersol = self.standard_wallet.make_solution()
            innerpuz: Program = await self.inner_puzzle_for_cc_puzzle(
                coin.puzzle_hash)

            parent_info = await self.get_parent_for_coin(coin)
            assert parent_info is not None
            assert self.cc_info.my_core is not None
            # Use coin info to create solution and add coin and solution to list of CoinSolutions
            solution = cc_wallet_puzzles.cc_make_solution(
                self.cc_info.my_core,
                (
                    parent_info.parent_name,
                    parent_info.inner_puzzle_hash,
                    parent_info.amount,
                ),
                coin.amount,
                binutils.disassemble(innerpuz),
                binutils.disassemble(innersol),
                None,
                None,
            )
            list_of_solutions.append(
                CoinSolution(
                    coin,
                    Program.to([
                        cc_wallet_puzzles.cc_make_puzzle(
                            innerpuz.get_tree_hash(), self.cc_info.my_core),
                        solution,
                    ]),
                ))
            sigs = sigs + await self.get_sigs(innerpuz, innersol)

        aggsig = AugSchemeMPL.aggregate(sigs)
        spend_bundle = SpendBundle(list_of_solutions, aggsig)
        return spend_bundle
示例#20
0
    async def generate_signed_transaction(
        self,
        amount: uint64,
        to_address: bytes32,
        fee: uint64 = uint64(0),
        origin_id: bytes32 = None,
        coins: Set[Coin] = None,
    ) -> Optional[TransactionRecord]:
        sigs: List[G2Element] = []

        # Get coins and calculate amount of change required
        if coins is None:
            selected_coins: Optional[Set[Coin]] = await self.select_coins(
                amount)
        else:
            selected_coins = coins
        if selected_coins is None:
            return None

        total_amount = sum([x.amount for x in selected_coins])
        change = total_amount - amount

        # first coin becomes the auditor special case
        auditor = selected_coins.pop()
        puzzle_hash = auditor.puzzle_hash
        inner_puzzle: Program = await self.inner_puzzle_for_cc_puzzle(
            puzzle_hash)

        auditor_info = (
            auditor.parent_coin_info,
            inner_puzzle.get_tree_hash(),
            auditor.amount,
        )
        list_of_solutions = []

        # auditees should be (primary_input, innerpuzhash, coin_amount, output_amount)
        auditees = [(
            auditor.parent_coin_info,
            inner_puzzle.get_tree_hash(),
            auditor.amount,
            total_amount,
        )]
        for coin in selected_coins:
            coin_inner_puzzle: Program = await self.inner_puzzle_for_cc_puzzle(
                coin.puzzle_hash)
            auditees.append((
                coin.parent_coin_info,
                coin_inner_puzzle[coin],
                coin.amount,
                0,
            ))

        primaries = [{"puzzlehash": to_address, "amount": amount}]
        if change > 0:
            changepuzzlehash = await self.get_new_inner_hash()
            primaries.append({
                "puzzlehash": changepuzzlehash,
                "amount": change
            })

        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,
            (
                parent_info.parent_name,
                parent_info.inner_puzzle_hash,
                parent_info.amount,
            ),
            auditor.amount,
            binutils.disassemble(inner_puzzle),
            binutils.disassemble(innersol),
            auditor_info,
            auditees,
            False,
        )

        main_coin_solution = CoinSolution(
            auditor,
            Program.to([
                cc_wallet_puzzles.cc_make_puzzle(
                    inner_puzzle.get_tree_hash(),
                    self.cc_info.my_core,
                ),
                solution,
            ]),
        )
        list_of_solutions.append(main_coin_solution)
        # main = SpendBundle([main_coin_solution], ZERO96)

        ephemeral_coin_solution = create_spend_for_ephemeral(
            auditor, auditor, total_amount)
        list_of_solutions.append(ephemeral_coin_solution)
        # eph = SpendBundle([ephemeral_coin_solution], ZERO96)

        auditor_coin_colution = create_spend_for_auditor(auditor, auditor)
        list_of_solutions.append(auditor_coin_colution)
        # aud = SpendBundle([auditor_coin_colution], ZERO96)

        # loop through remaining spends, treating them as aggregatees
        for coin in selected_coins:
            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(
                self.cc_info.my_core,
                (
                    parent_info.parent_name,
                    parent_info.inner_puzzle_hash,
                    parent_info.amount,
                ),
                coin.amount,
                binutils.disassemble(coin_inner_puzzle),
                binutils.disassemble(innersol),
                auditor_info,
                None,
            )
            list_of_solutions.append(
                CoinSolution(
                    coin,
                    Program.to([
                        cc_wallet_puzzles.cc_make_puzzle(
                            coin_inner_puzzle.get_tree_hash(),
                            self.cc_info.my_core,
                        ),
                        solution,
                    ]),
                ))
            list_of_solutions.append(
                create_spend_for_ephemeral(coin, auditor, 0))
            list_of_solutions.append(create_spend_for_auditor(auditor, coin))

        aggsig = AugSchemeMPL.aggregate(sigs)
        spend_bundle = SpendBundle(list_of_solutions, aggsig)

        tx_record = TransactionRecord(
            confirmed_at_index=uint32(0),
            created_at_time=uint64(int(time.time())),
            to_puzzle_hash=to_address,
            amount=uint64(amount),
            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=self.wallet_info.id,
            sent_to=[],
            trade_id=None,
        )

        return tx_record
示例#21
0
    async def search_for_parent_info(self, block_program: Program,
                                     removals: List[Coin]) -> bool:
        """
        Returns an error if it's unable to evaluate, otherwise
        returns a list of NPC (coin_name, solved_puzzle_hash, conditions_dict)
        """
        cost_sum = 0
        try:
            cost_run, sexp = run_program(block_program, [])
            cost_sum += cost_run
        except EvalError:
            return False

        for name_solution in sexp.as_iter():
            _ = name_solution.as_python()
            if len(_) != 2:
                return False
            if not isinstance(_[0], bytes) or len(_[0]) != 32:
                return False
            coin_name = bytes32(_[0])
            if not isinstance(_[1], list) or len(_[1]) != 2:
                return False
            puzzle_solution_program = name_solution.rest().first()
            puzzle_program = puzzle_solution_program.first()
            try:
                error, conditions_dict, cost_run = conditions_dict_for_solution(
                    puzzle_solution_program)
                cost_sum += cost_run
                if error:
                    return False
            except EvalError:

                return False
            if conditions_dict is None:
                conditions_dict = {}

            if ConditionOpcode.CREATE_COIN in conditions_dict:
                created_output_conditions = conditions_dict[
                    ConditionOpcode.CREATE_COIN]
            else:
                continue
            for cvp in created_output_conditions:
                result = await self.wallet_state_manager.puzzle_store.wallet_info_for_puzzle_hash(
                    cvp.var1)
                if result is None:
                    continue

                wallet_id, wallet_type = result
                if wallet_id != self.wallet_info.id:
                    continue

                coin = None
                for removed in removals:
                    if removed.name() == coin_name:
                        coin = removed
                        break

                if coin is not None:
                    if cc_wallet_puzzles.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

        return False
示例#22
0
def do_com_prog(prog, macro_lookup, symbol_table, run_program):
    """
    Turn the given program `prog` into a clvm program using
    the macros to do transformation.

    prog is an uncompiled s-expression.

    Return a new expanded s-expression PROG_EXP that is equivalent by rewriting
    based upon the operator, where "equivalent" means

    (a (com (q PROG) (MACROS)) ARGS) == (a (q PROG_EXP) ARGS)
    for all ARGS.

    Also, (opt (com (q PROG) (MACROS))) == (opt (com (q PROG_EXP) (MACROS)))
    """

    # lower "quote" to "q"
    prog = lower_quote(prog, macro_lookup, symbol_table, run_program)

    # quote atoms
    if prog.nullp() or not prog.listp():
        atom = prog.as_atom()
        if atom == b"@":
            return prog.to(TOP.as_path())
        for pair in symbol_table.as_iter():
            symbol, value = pair.first(), pair.rest().first()
            if symbol == atom:
                return prog.to(value)

        return prog.to(quote(prog))

    operator = prog.first()
    if operator.listp():
        # (com ((OP) . RIGHT)) => (a (com (q OP)) 1)
        inner_exp = eval(
            prog.to([
                b"com",
                quote(operator),
                quote(macro_lookup),
                quote(symbol_table)
            ]), TOP.as_path())
        return prog.to([inner_exp])

    as_atom = operator.as_atom()

    for macro_pair in macro_lookup.as_iter():
        macro_name = macro_pair.first().as_atom()
        if macro_name == as_atom:
            macro_code = macro_pair.rest().first()
            post_prog = brun(macro_code, prog.rest())
            return eval(
                post_prog.to([
                    b"com", post_prog,
                    quote(macro_lookup),
                    quote(symbol_table)
                ]), TOP.as_short_path())

    if as_atom in COMPILE_BINDINGS:
        f = COMPILE_BINDINGS[as_atom]
        post_prog = f(prog.rest(), macro_lookup, symbol_table, run_program)
        return eval(prog.to(quote(post_prog)), TOP.as_path())

    if operator == QUOTE_ATOM:
        return prog

    compiled_args = [
        do_com_prog(_, macro_lookup, symbol_table, run_program)
        for _ in prog.rest().as_iter()
    ]

    r = prog.to([operator] + compiled_args)

    if as_atom in PASS_THROUGH_OPERATORS or as_atom.startswith(b"_"):
        return r

    for (symbol, value) in symbol_table.as_python():
        if symbol == b"*":
            return r
        if symbol == as_atom:
            new_args = eval(
                prog.to([
                    b"opt",
                    [
                        b"com",
                        quote([b"list"] + list(prog.rest().as_iter())),
                        quote(macro_lookup),
                        quote(symbol_table)
                    ]
                ]), TOP.as_path())
            r = prog.to(
                [APPLY_ATOM, value, [CONS_ATOM,
                                     LEFT.as_path(), new_args]])
            return r

    raise SyntaxError("can't compile %s, unknown operator" % disassemble(prog))
示例#23
0
    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_hex = file_path.read_text()
        trade_offer: TradeRecord = TradeRecord.from_bytes(
            hexstr_to_bytes(trade_offer_hex))
        offer_spend_bundle = trade_offer.spend_bundle

        coinsols = []  # [] of CoinSolutions
        cc_coinsol_outamounts: Dict[bytes32, List[Tuple[Any, int]]] = dict()
        # Used for generating auditor solution, key is colour
        auditees: Dict[bytes32, List[Tuple[bytes32, bytes32, 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 = coinsol.solution.first()
            solution = coinsol.solution.rest().first()

            # work out the deficits between coin amount and expected output for each
            if cc_wallet_puzzles.check_is_cc_puzzle(puzzle):

                if not cc_wallet_puzzles.is_ephemeral_solution(solution):
                    # Calculate output amounts
                    colour = cc_wallet_puzzles.get_genesis_from_puzzle(puzzle)
                    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"
                    innerpuzzlereveal = cc_wallet_puzzles.inner_puzzle(
                        solution)
                    innersol = cc_wallet_puzzles.inner_puzzle_solution(
                        solution)
                    out_amount = cc_wallet_puzzles.get_output_amount_for_puzzle_and_solution(
                        innerpuzzlereveal, innersol)

                    if colour in cc_discrepancies:
                        cc_discrepancies[
                            colour] += coinsol.coin.amount - out_amount
                    else:
                        cc_discrepancies[
                            colour] = coinsol.coin.amount - out_amount
                    # Store coinsol and output amount for later
                    if colour in cc_coinsol_outamounts:
                        cc_coinsol_outamounts[colour].append(
                            (coinsol, out_amount))
                    else:
                        cc_coinsol_outamounts[colour] = [(coinsol, out_amount)]

                    # auditees should be (primary_input, innerpuzhash, coin_amount, output_amount)
                    if colour in auditees:
                        auditees[colour].append((
                            coinsol.coin.parent_coin_info,
                            Program(innerpuzzlereveal).get_tree_hash(),
                            coinsol.coin.amount,
                            out_amount,
                        ))
                    else:
                        auditees[colour] = [(
                            coinsol.coin.parent_coin_info,
                            Program(innerpuzzlereveal).get_tree_hash(),
                            coinsol.coin.amount,
                            out_amount,
                        )]
                else:
                    coinsols.append(coinsol)
            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 = cc_wallet_puzzles.get_output_discrepancy_for_puzzle_and_solution(
                        coinsol.coin, puzzle, solution)
                else:
                    chia_discrepancy += cc_wallet_puzzles.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, [])

        zero_spend_list: List[SpendBundle] = []
        # 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"

            auditor = my_cc_spends.pop()
            auditor_inner_puzzle = await self.get_inner_puzzle_for_puzzle_hash(
                auditor.puzzle_hash)
            assert auditor_inner_puzzle is not None
            inner_hash = auditor_inner_puzzle.get_tree_hash()

            auditor_info = (
                auditor.parent_coin_info,
                inner_hash,
                auditor.amount,
            )
            core = cc_wallet_puzzles.cc_make_core(colour)
            parent_info = await wallets[colour].get_parent_for_coin(auditor)

            for coloured_coin in my_cc_spends:
                inner_solution = self.wallet_state_manager.main_wallet.make_solution(
                    consumed=[auditor.name()])
                sig = await wallets[
                    colour].get_sigs_for_innerpuz_with_innersol(
                        await self.get_inner_puzzle_for_puzzle_hash(
                            coloured_coin.puzzle_hash),
                        inner_solution,
                    )
                aggsig = AugSchemeMPL.aggregate([sig, aggsig])
                inner_puzzle = await self.get_inner_puzzle_for_puzzle_hash(
                    coloured_coin.puzzle_hash)
                assert inner_puzzle is not None
                # auditees should be (primary_input, innerpuzhash, coin_amount, output_amount)
                auditees[colour].append((
                    coloured_coin.parent_coin_info,
                    inner_puzzle.get_tree_hash(),
                    coloured_coin.amount,
                    0,
                ))

                solution = cc_wallet_puzzles.cc_make_solution(
                    core,
                    (
                        parent_info.parent_name,
                        parent_info.inner_puzzle_hash,
                        parent_info.amount,
                    ),
                    coloured_coin.amount,
                    binutils.disassemble(inner_puzzle),
                    binutils.disassemble(inner_solution),
                    auditor_info,
                    None,
                )
                coin_spend = CoinSolution(
                    coloured_coin,
                    Program.to([
                        cc_wallet_puzzles.cc_make_puzzle(
                            inner_puzzle.get_tree_hash(),
                            core,
                        ),
                        solution,
                    ]),
                )
                coinsols.append(coin_spend)

                ephemeral = cc_wallet_puzzles.create_spend_for_ephemeral(
                    coloured_coin, auditor, 0)
                coinsols.append(ephemeral)

                auditor = cc_wallet_puzzles.create_spend_for_auditor(
                    auditor, coloured_coin)
                coinsols.append(auditor)

            # Tweak the offer's solution to include the new auditor
            for cc_coinsol_out in cc_coinsol_outamounts[colour]:
                cc_coinsol = cc_coinsol_out[0]
                new_solution = cc_wallet_puzzles.update_auditors_in_solution(
                    cc_coinsol.solution, auditor_info)
                new_coinsol = CoinSolution(cc_coinsol.coin, new_solution)
                coinsols.append(new_coinsol)

                eph = cc_wallet_puzzles.create_spend_for_ephemeral(
                    cc_coinsol.coin, auditor, cc_coinsol_out[1])
                coinsols.append(eph)

                aud = cc_wallet_puzzles.create_spend_for_auditor(
                    auditor, cc_coinsol.coin)
                coinsols.append(aud)

            # Finish the auditor CoinSolution with new information
            newinnerpuzhash = await wallets[colour].get_new_inner_hash()
            outputamount = (sum([c.amount for c in my_cc_spends]) +
                            cc_discrepancies[colour] + auditor.amount)
            innersol = self.wallet_state_manager.main_wallet.make_solution(
                primaries=[{
                    "puzzlehash": newinnerpuzhash,
                    "amount": outputamount
                }])
            parent_info = await wallets[colour].get_parent_for_coin(auditor)

            auditees[colour].append((
                auditor.parent_coin_info,
                auditor_inner_puzzle.get_tree_hash(),
                auditor.amount,
                outputamount,
            ))

            sigs: List[G2Element] = await wallets[colour].get_sigs(
                auditor_inner_puzzle, innersol)
            aggsig = AugSchemeMPL.aggregate(sigs + [aggsig])

            solution = cc_wallet_puzzles.cc_make_solution(
                core,
                (
                    parent_info.parent_name,
                    parent_info.inner_puzzle_hash,
                    parent_info.amount,
                ),
                auditor.amount,
                binutils.disassemble(auditor_inner_puzzle),
                binutils.disassemble(innersol),
                auditor_info,
                auditees[colour],
            )

            cs = CoinSolution(
                auditor,
                Program.to([
                    cc_wallet_puzzles.cc_make_puzzle(
                        auditor_inner_puzzle.get_tree_hash(), core),
                    solution,
                ]),
            )
            coinsols.append(cs)

            cs_eph = create_spend_for_ephemeral(auditor, auditor, outputamount)
            coinsols.append(cs_eph)

            cs_aud = create_spend_for_auditor(auditor, auditor)
            coinsols.append(cs_aud)

        spend_bundle = SpendBundle(coinsols, aggsig)
        my_tx_records = []

        if zero_spend_list is not None:
            zero_spend_list.append(spend_bundle)
            spend_bundle = SpendBundle.aggregate(zero_spend_list)

        # Add transaction history hor this trade
        now = uint64(int(time.time()))
        if chia_spend_bundle is not None:
            spend_bundle = SpendBundle.aggregate(
                [spend_bundle, chia_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
示例#24
0
def adaptor_for_singleton_inner_puzzle(puzzle: Program) -> Program:
    # this is prety slow
    return Program.to(
        binutils.assemble("(a (q . %s) 3)" % binutils.disassemble(puzzle)))
示例#25
0
def get_genesis_from_puzzle(puzzle: SExp):
    return extract_hex_64(binutils.disassemble(puzzle))
示例#26
0
def compile_mod(args, macro_lookup, symbol_table, run_program):
    """
    Deal with the "mod" keyword.
    """
    (functions, constants, macros) = compile_mod_stage_1(args, run_program)

    # move macros into the macro lookup

    macro_lookup_program = build_macro_lookup_program(macro_lookup, macros,
                                                      run_program)

    # get a list of all symbols that are possibly used

    all_constants_names = build_used_constants_names(functions, constants,
                                                     macros)
    has_constants_tree = len(all_constants_names) > 0

    # build defuns table, with function names as keys

    constants_tree = args.to(build_tree(all_constants_names))

    constants_root_node = LEFT
    if has_constants_tree:
        args_root_node = RIGHT
    else:
        args_root_node = TOP

    constants_symbol_table = symbol_table_for_tree(constants_tree,
                                                   constants_root_node)

    compiled_functions = compile_functions(functions, macro_lookup_program,
                                           constants_symbol_table,
                                           args_root_node)

    main_path_src = binutils.disassemble(compiled_functions[MAIN_NAME])

    if has_constants_tree:
        all_constants_lookup = {
            k: v
            for k, v in compiled_functions.items() if k in all_constants_names
        }
        all_constants_lookup.update(constants)

        all_constants_list = [
            all_constants_lookup[_] for _ in all_constants_names
        ]
        all_constants_tree_program = args.to(
            build_tree_program(all_constants_list))

        all_constants_tree_src = binutils.disassemble(
            all_constants_tree_program)
        arg_tree_src = "(c %s 1)" % all_constants_tree_src
    else:
        arg_tree_src = "1"

    main_code = "(opt (q . (a %s %s)))" % (main_path_src, arg_tree_src)

    if has_constants_tree:
        build_symbol_dump(all_constants_lookup, run_program, "main.sym")

    return binutils.assemble(main_code)
示例#27
0
# tool to decompile a fuzz_run_program test case to human readable form

import sys
import io
from ir import reader
from clvm_tools import binutils
from clvm.serialize import sexp_from_stream
from clvm import to_sexp_f

with open(sys.argv[1], 'rb') as f:
    blob = f.read()
    sexp = sexp_from_stream(io.BytesIO(blob), to_sexp_f)
    print(binutils.disassemble(sexp))

示例#28
0
def disassemble_cmd(programs):
    for program in programs:
        print(disassemble(parse_program(program)))