def get_name_puzzle_conditions_rust(generator: BlockGenerator, max_cost: int,
                                    *, cost_per_byte: int,
                                    safe_mode: bool) -> NPCResult:
    block_program, block_program_args = setup_generator_args(generator)
    max_cost -= len(bytes(generator.program)) * cost_per_byte
    if max_cost < 0:
        return NPCResult(uint16(Err.INVALID_BLOCK_COST.value), [], uint64(0))

    flags = STRICT_MODE if safe_mode else 0
    err, result, clvm_cost = GENERATOR_MOD.run_as_generator(
        max_cost, flags, block_program, block_program_args)
    if err is not None:
        return NPCResult(uint16(err), [], uint64(0))
    else:
        npc_list = []
        for r in result:
            conditions = []
            for c in r.conditions:
                cwa = []
                for cond_list in c[1]:
                    cwa.append(
                        ConditionWithArgs(
                            ConditionOpcode(bytes([cond_list.opcode])),
                            cond_list.vars))
                conditions.append((ConditionOpcode(bytes([c[0]])), cwa))
            npc_list.append(NPC(r.coin_name, r.puzzle_hash, conditions))
        return NPCResult(None, npc_list, uint64(clvm_cost))
Ejemplo n.º 2
0
    def test_get_name_puzzle_conditions(self):
        # this tests that extra block or coin data doesn't confuse `get_name_puzzle_conditions`

        gen = block_generator()
        cost, r = run_generator(gen, max_cost=MAX_COST)
        print(r)

        npc_result = get_name_puzzle_conditions(gen,
                                                max_cost=MAX_COST,
                                                cost_per_byte=COST_PER_BYTE,
                                                safe_mode=False)
        assert npc_result.error is None
        assert npc_result.clvm_cost == EXPECTED_COST
        cond_1 = ConditionWithArgs(
            ConditionOpcode.CREATE_COIN,
            [bytes([0] * 31 + [1]), int_to_bytes(500)])
        CONDITIONS = [
            (ConditionOpcode.CREATE_COIN, [cond_1]),
        ]

        npc = NPC(
            coin_name=bytes32.fromhex(
                "e8538c2d14f2a7defae65c5c97f5d4fae7ee64acef7fec9d28ad847a0880fd03"
            ),
            puzzle_hash=bytes32.fromhex(
                "9dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2"
            ),
            conditions=CONDITIONS,
        )

        assert npc_result.npc_list == [npc]
Ejemplo n.º 3
0
def get_name_puzzle_conditions(
    generator: BlockGenerator, max_cost: int, *, cost_per_byte: int, mempool_mode: bool
) -> NPCResult:
    block_program, block_program_args = setup_generator_args(generator)
    max_cost -= len(bytes(generator.program)) * cost_per_byte
    if max_cost < 0:
        return NPCResult(uint16(Err.INVALID_BLOCK_COST.value), [], uint64(0))

    flags = MEMPOOL_MODE if mempool_mode else 0
    try:
        err, result, clvm_cost = GENERATOR_MOD.run_as_generator(max_cost, flags, block_program, block_program_args)
        if err is not None:
            return NPCResult(uint16(err), [], uint64(0))
        else:
            npc_list = []
            for r in result:
                conditions = []
                for c in r.conditions:
                    cwa = []
                    for cond_list in c[1]:
                        cwa.append(ConditionWithArgs(ConditionOpcode(bytes([cond_list.opcode])), cond_list.vars))
                    conditions.append((ConditionOpcode(bytes([c[0]])), cwa))
                npc_list.append(NPC(r.coin_name, r.puzzle_hash, conditions))
            return NPCResult(None, npc_list, uint64(clvm_cost))
    except BaseException as e:
        log.debug(f"get_name_puzzle_condition failed: {e}")
        return NPCResult(uint16(Err.GENERATOR_RUNTIME_ERROR.value), [], uint64(0))
Ejemplo n.º 4
0
def get_name_puzzle_conditions(
    block_program: SerializedProgram, safe_mode: bool
) -> Tuple[Optional[str], Optional[List[NPC]], Optional[uint64]]:
    # TODO: allow generator mod to take something (future)
    # TODO: write more tests
    block_program_args = SerializedProgram.from_bytes(b"\x80")

    try:
        if safe_mode:
            cost, result = GENERATOR_MOD.run_safe_with_cost(
                block_program, block_program_args)
        else:
            cost, result = GENERATOR_MOD.run_with_cost(block_program,
                                                       block_program_args)
        npc_list: List[NPC] = []
        opcodes: Set[bytes] = set(item.value for item in ConditionOpcode)

        for res in result.as_iter():
            conditions_list: List[ConditionWithArgs] = []

            spent_coin_parent_id: bytes32 = res.first().first().as_atom()
            spent_coin_puzzle_hash: bytes32 = res.first().rest().first(
            ).as_atom()
            spent_coin_amount: uint64 = uint64(
                res.first().rest().rest().first().as_int())
            spent_coin: Coin = Coin(spent_coin_parent_id,
                                    spent_coin_puzzle_hash, spent_coin_amount)

            for cond in res.rest().first().as_iter():
                if cond.first().as_atom() in opcodes:
                    opcode: ConditionOpcode = ConditionOpcode(
                        cond.first().as_atom())
                elif not safe_mode:
                    opcode = ConditionOpcode.UNKNOWN
                else:
                    return "Unknown operator in safe mode.", None, None
                conditions_list.append(
                    ConditionWithArgs(opcode,
                                      cond.rest().as_atom_list()))
            conditions_dict = conditions_by_opcode(conditions_list)
            if conditions_dict is None:
                conditions_dict = {}
            npc_list.append(
                NPC(spent_coin.name(), spent_coin.puzzle_hash,
                    [(a, b) for a, b in conditions_dict.items()]))
        return None, npc_list, uint64(cost)
    except Exception:
        tb = traceback.format_exc()
        return tb, None, None
def get_name_puzzle_conditions(block_program: SerializedProgram,
                               safe_mode: bool):
    # TODO: allow generator mod to take something (future)
    # TODO: write more tests
    block_program_args = SerializedProgram.from_bytes(b"\x80")

    try:
        if safe_mode:
            cost, result = GENERATOR_MOD.run_safe_with_cost(
                block_program, block_program_args)
        else:
            cost, result = GENERATOR_MOD.run_with_cost(block_program,
                                                       block_program_args)
        npc_list = []
        opcodes = set(item.value for item in ConditionOpcode)
        for res in result.as_iter():
            conditions_list = []
            name = std_hash(
                bytes(res.first().first().as_atom() +
                      res.first().rest().first().as_atom() +
                      res.first().rest().rest().first().as_atom()))
            puzzle_hash = bytes32(res.first().rest().first().as_atom())
            for cond in res.rest().first().as_iter():
                if cond.first().as_atom() in opcodes:
                    opcode = ConditionOpcode(cond.first().as_atom())
                elif not safe_mode:
                    opcode = ConditionOpcode.UNKNOWN
                else:
                    return "Unknown operator in safe mode.", None, None
                if len(list(cond.as_iter())) > 1:
                    cond_var_list = []
                    for cond_1 in cond.rest().as_iter():
                        cond_var_list.append(cond_1.as_atom())
                    cvl = ConditionVarPair(opcode, cond_var_list)
                else:
                    cvl = ConditionVarPair(opcode, [])
                conditions_list.append(cvl)
            conditions_dict = conditions_by_opcode(conditions_list)
            if conditions_dict is None:
                conditions_dict = {}
            npc_list.append(
                NPC(name, puzzle_hash,
                    [(a, b) for a, b in conditions_dict.items()]))
        return None, npc_list, uint64(cost)
    except Exception:
        tb = traceback.format_exc()
        return tb, None, None
def get_name_puzzle_conditions(generator: BlockGenerator, max_cost: int,
                               safe_mode: bool) -> NPCResult:
    try:
        block_program, block_program_args = setup_generator_args(generator)
        if safe_mode:
            cost, result = GENERATOR_MOD.run_safe_with_cost(
                max_cost, block_program, block_program_args)
        else:
            cost, result = GENERATOR_MOD.run_with_cost(max_cost, block_program,
                                                       block_program_args)
        npc_list: List[NPC] = []
        opcodes: Set[bytes] = set(item.value for item in ConditionOpcode)

        for res in result.as_iter():
            conditions_list: List[ConditionWithArgs] = []

            spent_coin_parent_id: bytes32 = res.first().first().as_atom()
            spent_coin_puzzle_hash: bytes32 = res.first().rest().first(
            ).as_atom()
            spent_coin_amount: uint64 = uint64(
                res.first().rest().rest().first().as_int())
            spent_coin: Coin = Coin(spent_coin_parent_id,
                                    spent_coin_puzzle_hash, spent_coin_amount)

            for cond in res.rest().first().as_iter():
                if cond.first().as_atom() in opcodes:
                    opcode: ConditionOpcode = ConditionOpcode(
                        cond.first().as_atom())
                elif not safe_mode:
                    opcode = ConditionOpcode.UNKNOWN
                else:
                    return NPCResult(uint16(Err.GENERATOR_RUNTIME_ERROR.value),
                                     [], uint64(0))
                cvl = ConditionWithArgs(opcode, cond.rest().as_atom_list())
                conditions_list.append(cvl)
            conditions_dict = conditions_by_opcode(conditions_list)
            if conditions_dict is None:
                conditions_dict = {}
            npc_list.append(
                NPC(spent_coin.name(), spent_coin.puzzle_hash,
                    [(a, b) for a, b in conditions_dict.items()]))
        return NPCResult(None, npc_list, uint64(cost))
    except Exception:
        return NPCResult(uint16(Err.GENERATOR_RUNTIME_ERROR.value), [],
                         uint64(0))
Ejemplo n.º 7
0
def run_generator(
    block_generator: BlockGenerator, constants: ConsensusConstants, max_cost: int, height: uint32
) -> List[CAT]:

    if height >= DEFAULT_CONSTANTS.SOFT_FORK_HEIGHT:
        # conditions must use integers in canonical encoding (i.e. no redundant
        # leading zeros)
        # the division operator may not be used with negative operands
        flags = COND_CANON_INTS | NO_NEG_DIV
    else:
        flags = 0

    _, result = block_generator.program.run_with_cost(max_cost, flags, block_generator.generator_refs)

    coin_spends = result.first()

    cat_list: List[CAT] = []
    for spend in coin_spends.as_iter():

        parent, puzzle, amount, solution = spend.as_iter()

        matched, curried_args = match_cat_puzzle(puzzle)

        if not matched:
            continue

        _, tail_hash, _ = curried_args
        memo = ""

        result = puzzle.run(solution)

        conds: Dict[ConditionOpcode, List[ConditionWithArgs]] = {}

        for condition in result.as_python():
            op = ConditionOpcode(condition[0])

            if op not in conds:
                conds[op] = []

            if condition[0] != ConditionOpcode.CREATE_COIN or len(condition) < 4:
                conds[op].append(ConditionWithArgs(op, [i for i in condition[1:3]]))
                continue

            # If only 3 elements (opcode + 2 args), there is no memo, this is ph, amount
            if type(condition[3]) != list:
                # If it's not a list, it's not the correct format
                conds[op].append(ConditionWithArgs(op, [i for i in condition[1:3]]))
                continue

            conds[op].append(ConditionWithArgs(op, [i for i in condition[1:3]] + [condition[3][0]]))

            # special retirement address
            if condition[3][0].hex() != "0000000000000000000000000000000000000000000000000000000000000000":
                continue

            if len(condition[3]) >= 2:
                try:
                    memo = condition[3][1].decode("utf-8", errors="strict")
                except UnicodeError:
                    pass  # ignore this error which should leave memo as empty string

            # technically there could be more such create_coin ops in the list but our wallet does not
            # so leaving it for the future
            break

        puzzle_hash = puzzle.get_tree_hash()
        coin = Coin(parent.atom, puzzle_hash, int_from_bytes(amount.atom))
        cat_list.append(
            CAT(
                tail_hash=bytes(tail_hash).hex()[2:],
                memo=memo,
                npc=NPC(coin.name(), puzzle_hash, [(op, cond) for op, cond in conds.items()]),
            )
        )

    return cat_list
def get_name_puzzle_conditions_python(generator: BlockGenerator, max_cost: int,
                                      *, cost_per_byte: int,
                                      safe_mode: bool) -> NPCResult:
    """
    This executes the generator program and returns the coins and their
    conditions. If the cost of the program (size, CLVM execution and conditions)
    exceed max_cost, the function fails. In order to accurately take the size
    of the program into account when calculating cost, cost_per_byte must be
    specified.
    safe_mode determines whether the clvm program and conditions are executed in
    strict mode or not. When in safe/strict mode, unknow operations or conditions
    are considered failures. This is the mode when accepting transactions into
    the mempool.
    """
    block_program, block_program_args = setup_generator_args(generator)
    max_cost -= len(bytes(generator.program)) * cost_per_byte
    if max_cost < 0:
        return NPCResult(uint16(Err.INVALID_BLOCK_COST.value), [], uint64(0))
    if safe_mode:
        clvm_cost, result = GENERATOR_MOD.run_safe_with_cost(
            max_cost, block_program, block_program_args)
    else:
        clvm_cost, result = GENERATOR_MOD.run_with_cost(
            max_cost, block_program, block_program_args)

    max_cost -= clvm_cost
    if max_cost < 0:
        return NPCResult(uint16(Err.INVALID_BLOCK_COST.value), [], uint64(0))
    npc_list: List[NPC] = []

    for res in result.first().as_iter():
        conditions_list: List[ConditionWithArgs] = []

        if len(res.first().atom) != 32:
            raise ValidationError(Err.INVALID_CONDITION)
        spent_coin_parent_id: bytes32 = res.first().as_atom()
        res = res.rest()
        if len(res.first().atom) != 32:
            raise ValidationError(Err.INVALID_CONDITION)
        spent_coin_puzzle_hash: bytes32 = res.first().as_atom()
        res = res.rest()
        spent_coin_amount: uint64 = uint64(sanitize_int(
            res.first(), safe_mode))
        res = res.rest()
        spent_coin: Coin = Coin(spent_coin_parent_id, spent_coin_puzzle_hash,
                                spent_coin_amount)

        for cond in res.first().as_iter():
            cost, cvl = parse_condition(cond, safe_mode)
            max_cost -= cost
            if max_cost < 0:
                return NPCResult(uint16(Err.INVALID_BLOCK_COST.value), [],
                                 uint64(0))
            if cvl is not None:
                conditions_list.append(cvl)

        conditions_dict = conditions_by_opcode(conditions_list)
        if conditions_dict is None:
            conditions_dict = {}
        npc_list.append(
            NPC(spent_coin.name(), spent_coin.puzzle_hash,
                [(a, b) for a, b in conditions_dict.items()]))
    return NPCResult(None, npc_list, uint64(clvm_cost))
def get_name_puzzle_conditions(generator: BlockGenerator,
                               max_cost: int,
                               *,
                               cost_per_byte: int,
                               mempool_mode: bool,
                               height: Optional[uint32] = None) -> NPCResult:
    block_program, block_program_args = setup_generator_args(generator)
    size_cost = len(bytes(generator.program)) * cost_per_byte
    max_cost -= size_cost
    if max_cost < 0:
        return NPCResult(uint16(Err.INVALID_BLOCK_COST.value), [], uint64(0))

    # in mempool mode, the height doesn't matter, because it's always strict.
    # But otherwise, height must be specified to know which rules to apply
    assert mempool_mode or height is not None

    # mempool mode also has these rules apply
    assert (MEMPOOL_MODE & COND_CANON_INTS) != 0
    assert (MEMPOOL_MODE & NO_NEG_DIV) != 0

    if mempool_mode:
        flags = MEMPOOL_MODE
    elif unwrap(height) >= DEFAULT_CONSTANTS.SOFT_FORK_HEIGHT:
        # conditions must use integers in canonical encoding (i.e. no redundant
        # leading zeros)
        # the division operator may not be used with negative operands
        flags = COND_CANON_INTS | NO_NEG_DIV
    else:
        flags = 0

    try:
        err, result = GENERATOR_MOD.run_as_generator(max_cost, flags,
                                                     block_program,
                                                     block_program_args)

        if err is not None:
            assert err != 0
            return NPCResult(uint16(err), [], uint64(0))

        first = True
        npc_list = []
        for r in result.spends:
            conditions: Dict[ConditionOpcode, List[ConditionWithArgs]] = {}
            if r.height_relative is not None:
                add_int_cond(conditions,
                             ConditionOpcode.ASSERT_HEIGHT_RELATIVE,
                             r.height_relative)
            if r.seconds_relative > 0:
                add_int_cond(conditions,
                             ConditionOpcode.ASSERT_SECONDS_RELATIVE,
                             r.seconds_relative)
            for cc in r.create_coin:
                if cc[2] == b"":
                    add_cond(conditions, ConditionOpcode.CREATE_COIN,
                             [cc[0], int_to_bytes(cc[1])])
                else:
                    add_cond(conditions, ConditionOpcode.CREATE_COIN,
                             [cc[0], int_to_bytes(cc[1]), cc[2]])
            for sig in r.agg_sig_me:
                add_cond(conditions, ConditionOpcode.AGG_SIG_ME,
                         [sig[0], sig[1]])

            # all conditions that aren't tied to a specific spent coin, we roll into the first one
            if first:
                first = False
                if result.reserve_fee > 0:
                    add_int_cond(conditions, ConditionOpcode.RESERVE_FEE,
                                 result.reserve_fee)
                if result.height_absolute > 0:
                    add_int_cond(conditions,
                                 ConditionOpcode.ASSERT_HEIGHT_ABSOLUTE,
                                 result.height_absolute)
                if result.seconds_absolute > 0:
                    add_int_cond(conditions,
                                 ConditionOpcode.ASSERT_SECONDS_ABSOLUTE,
                                 result.seconds_absolute)
                for sig in result.agg_sig_unsafe:
                    add_cond(conditions, ConditionOpcode.AGG_SIG_UNSAFE,
                             [sig[0], sig[1]])

            npc_list.append(
                NPC(r.coin_id, r.puzzle_hash,
                    [(op, cond) for op, cond in conditions.items()]))

        return NPCResult(None, npc_list, uint64(result.cost + size_cost))

    except BaseException as e:
        log.debug(f"get_name_puzzle_condition failed: {e}")
        return NPCResult(uint16(Err.GENERATOR_RUNTIME_ERROR.value), [],
                         uint64(0))