Exemplo n.º 1
0
    def test_unknown_ops_last_bits(self):

        # The last byte is ignored for no-op unknown ops
        for suffix in [b"\x3f", b"\x0f", b"\x00", b"\x2c"]:
            # the cost is unchanged by the last byte
            self.assertEqual(default_unknown_op(b"\x3c" + suffix, SExp.null()),
                             (61, SExp.null()))
Exemplo n.º 2
0
    def test_listp(self):
        self.assertEqual(SExp.to(42).listp(), False)
        self.assertEqual(SExp.to(b"").listp(), False)
        self.assertEqual(SExp.to(b"1337").listp(), False)

        self.assertEqual(SExp.to((1337, 42)).listp(), True)
        self.assertEqual(SExp.to([1337, 42]).listp(), True)
Exemplo n.º 3
0
    def test_long_list(self):
        d = [1337] * 1000
        v = SExp.to(d)
        for i in range(1000 - 1):
            self.assertEqual(v.as_pair()[0].as_int(), d[i])
            v = v.as_pair()[1]

        self.assertEqual(v.as_atom(), SExp.null())
Exemplo n.º 4
0
 def test_cons(self):
     # list
     self.assertEqual(
         SExp.to(H01).cons(SExp.to(H02).cons(SExp.null())).as_python(),
         [H01, H02],
     )
     # cons-box of two values
     self.assertEqual(SExp.to(H01).cons(SExp.to(H02).as_python()), (H01, H02))
def parse_aggsig(args: SExp) -> List[bytes]:
    pubkey = args.first().atom
    args = args.rest()
    message = args.first().atom
    if len(pubkey) != 48:
        raise ValidationError(Err.INVALID_CONDITION)
    if len(message) > 1024:
        raise ValidationError(Err.INVALID_CONDITION)
    return [pubkey, message]
Exemplo n.º 6
0
    def test_invalid_tuple(self):
        with self.assertRaises(ValueError):
            s = SExp.to((dummy_class, dummy_class))
            # conversions are deferred, this is where it will fail:
            b = list(s.as_iter())
            print(b)

        with self.assertRaises(ValueError):
            s = SExp.to((dummy_class, dummy_class, dummy_class))
Exemplo n.º 7
0
 def test_unknown_op(self):
     self.assertRaises(
         EvalError, lambda: OPERATOR_LOOKUP(b'\xff\xff1337', SExp.to(1337)))
     od = OperatorDict(OPERATOR_LOOKUP,
                       unknown_op_handler=lambda name, args: self.
                       unknown_handler(name, args))
     cost, ret = od(b'\xff\xff1337', SExp.to(1337))
     self.assertTrue(self.handler_called)
     self.assertEqual(cost, 42)
     self.assertEqual(ret, SExp.to(b'foobar'))
Exemplo n.º 8
0
def spend_bundle_to_serialized_coin_solution_entry_list(
        bundle: SpendBundle) -> bytes:
    r = b""
    for coin_solution in bundle.coin_solutions:
        r += b"\xff"
        r += b"\xff" + SExp.to(coin_solution.coin.parent_coin_info).as_bin()
        r += b"\xff" + bytes(coin_solution.puzzle_reveal)
        r += b"\xff" + SExp.to(coin_solution.coin.amount).as_bin()
        r += b"\xff" + bytes(coin_solution.solution)
        r += b"\x80"
    r += b"\x80"
    return r
Exemplo n.º 9
0
def compress_clvm_spend_bundle(sb):
    # print(sb)
    compressed_cses = []
    for cse in sb.as_iter():
        a = cse.first()
        b = cse.rest().first().first()
        c = cse.rest().first().rest()
        s = b.rest().rest().first().rest().first().rest()
        p = SExp.to([a, [bytes(s), c.first()]])
        compressed_cses.append(p)
        # print(p)
    return SExp.to([compressed_cses])
Exemplo n.º 10
0
    def test_long_linked_list(self):
        d = b""
        for i in range(1000):
            d = (b"2", d)
        v = SExp.to(d)
        for i in range(1000):
            self.assertEqual(v.as_pair()[0].as_atom(), d[0])
            v = v.as_pair()[1]
            d = d[1]

        self.assertEqual(v.as_atom(), SExp.null())
        self.assertEqual(d, b"")
Exemplo n.º 11
0
    def test_deep_recursion(self):
        d = b"2"
        for i in range(1000):
            d = [d]
        v = SExp.to(d)
        for i in range(1000):
            self.assertEqual(v.as_pair()[1].as_atom(), SExp.null())
            v = v.as_pair()[0]
            d = d[0]

        self.assertEqual(v.as_atom(), b"2")
        self.assertEqual(d, b"2")
def parse_condition(cond: SExp, safe_mode: bool) -> Tuple[int, Optional[ConditionWithArgs]]:
    condition = cond.first().as_atom()
    if condition in CONDITION_OPCODES:
        opcode: ConditionOpcode = ConditionOpcode(condition)
        cost, args = parse_condition_args(cond.rest(), opcode, safe_mode)
        cvl = ConditionWithArgs(opcode, args) if args is not None else None
    elif not safe_mode:
        opcode = ConditionOpcode.UNKNOWN
        cvl = ConditionWithArgs(opcode, cond.rest().as_atom_list())
        cost = 0
    else:
        raise ValidationError(Err.INVALID_CONDITION)
    return cost, cvl
def parse_create_coin(args: SExp, safe_mode: bool) -> List[bytes]:
    puzzle_hash = args.first().atom
    args = args.rest()
    if len(puzzle_hash) != 32:
        raise ValidationError(Err.INVALID_CONDITION)
    amount_int = sanitize_int(args.first(), safe_mode)
    if amount_int >= 2**64:
        raise ValidationError(Err.COIN_AMOUNT_EXCEEDS_MAXIMUM)
    if amount_int < 0:
        raise ValidationError(Err.COIN_AMOUNT_NEGATIVE)
    # note that this may change the representation of amount. If the original
    # buffer had redundant leading zeroes, they will be stripped
    return [puzzle_hash, int_to_bytes(amount_int)]
Exemplo n.º 14
0
    def test_unknown_op_reserved(self):

        # any op that starts with ffff is reserved, and results in a hard
        # failure
        with self.assertRaises(EvalError):
            default_unknown_op(b"\xff\xff", SExp.null())

        for suffix in [b"\xff", b"0", b"\x00", b"\xcc\xcc\xfe\xed\xfa\xce"]:
            with self.assertRaises(EvalError):
                default_unknown_op(b"\xff\xff" + suffix, SExp.null())

        with self.assertRaises(EvalError):
            # an empty atom is not a valid opcode
            self.assertEqual(default_unknown_op(b"", SExp.null()),
                             (1, SExp.null()))

        # a single ff is not sufficient to be treated as a reserved opcode
        self.assertEqual(default_unknown_op(b"\xff", SExp.null()),
                         (CONCAT_BASE_COST, SExp.null()))

        # leading zeroes count, and this does not count as a ffff-prefix
        # the cost is 0xffff00 = 16776960
        self.assertEqual(
            default_unknown_op(b"\x00\xff\xff\x00\x00", SExp.null()),
            (16776961, SExp.null()))
Exemplo n.º 15
0
def _tree_hash(node: SExp, precalculated: Set[bytes32]) -> bytes32:
    """
    Hash values in `precalculated` are presumed to have been hashed already.
    """
    if node.listp():
        left = _tree_hash(node.first(), precalculated)
        right = _tree_hash(node.rest(), precalculated)
        s = b"\2" + left + right
    else:
        atom = node.as_atom()
        if atom in precalculated:
            return bytes32(atom)
        s = b"\1" + atom
    return bytes32(std_hash(s))
Exemplo n.º 16
0
    def test_as_iter(self):
        val = list(SExp.to((1, (2, (3, (4, b""))))).as_iter())
        self.assertEqual(val, [1, 2, 3, 4])

        val = list(SExp.to(b"").as_iter())
        self.assertEqual(val, [])

        val = list(SExp.to((1, b"")).as_iter())
        self.assertEqual(val, [1])

        # these fail because the lists are not null-terminated
        self.assertRaises(EvalError, lambda: list(SExp.to(1).as_iter()))
        self.assertRaises(
            EvalError, lambda: list(SExp.to((1, (2, (3, (4, 5))))).as_iter())
        )
def parse_condition(
        cond: SExp,
        safe_mode: bool) -> Tuple[int, Optional[ConditionWithArgs]]:
    condition = cond.first().as_atom()
    if condition in CONDITION_OPCODES:
        opcode: ConditionOpcode = ConditionOpcode(condition)
        cost, args = parse_condition_args(cond.rest(), opcode, safe_mode)
        cvl = ConditionWithArgs(opcode, args) if args is not None else None
    elif not safe_mode:
        # we don't need to save unknown conditions. We can't do anything with them anyway
        # safe_mode just tells us whether we can tolerate them or not
        return 0, None
    else:
        raise ValidationError(Err.INVALID_CONDITION)
    return cost, cvl
def parse_aggsig(args: SExp) -> List[bytes]:
    pubkey = args.first().atom
    args = args.rest()
    message = args.first().atom
    if len(pubkey) != 48:
        raise ValidationError(Err.INVALID_CONDITION)
    if len(message) > 1024:
        raise ValidationError(Err.INVALID_CONDITION)
    # agg sig conditions only take 2 parameters
    args = args.rest()
    # the list is terminated by having a right-element that's not another pair,
    # just like as_atom_list() (see chia/types/blockchain_format/program.py)
    if args.pair is not None:
        raise ValidationError(Err.INVALID_CONDITION)
    return [pubkey, message]
Exemplo n.º 19
0
 def test_spend_byndle_coin_solution(self):
     for i in range(0, 10):
         sb: SpendBundle = make_spend_bundle(i)
         cs1 = SExp.to(
             spend_bundle_to_coin_solution_entry_list(sb)).as_bin()
         cs2 = spend_bundle_to_serialized_coin_solution_entry_list(sb)
         assert cs1 == cs2
Exemplo n.º 20
0
def ir_offset(ir_sexp: SExp) -> int:
    the_offset = ir_sexp.first()
    if the_offset.listp():
        the_offset = the_offset.rest().as_atom()
    else:
        the_offset = b"\xff"
    return casts.int_from_bytes(the_offset)
Exemplo n.º 21
0
 def test_g1element(self):
     b = fh(
         "b3b8ac537f4fd6bde9b26221d49b54b17a506be147347dae5"
         "d081c0a6572b611d8484e338f3432971a9823976c6a232b"
     )
     v = SExp.to(G1Element(b))
     self.assertEqual(v.atom, b)
def parse_fee(args: SExp, safe_mode: bool) -> List[bytes]:
    fee_int = sanitize_int(args.first(), safe_mode)
    if fee_int >= 2**64 or fee_int < 0:
        raise ValidationError(Err.RESERVE_FEE_CONDITION_FAILED)
    # note that this may change the representation of the fee. If the original
    # buffer had redundant leading zeroes, they will be stripped
    return [int_to_bytes(fee_int)]
Exemplo n.º 23
0
def simple_solution_generator(bundle: SpendBundle) -> BlockGenerator:
    """
    Simply quotes the solutions we know.
    """
    cse_list = spend_bundle_to_coin_solution_entry_list(bundle)
    block_program = SerializedProgram.from_bytes(SExp.to((binutils.assemble("#q"), cse_list)).as_bin())
    generator = BlockGenerator(block_program, [])
    return generator
Exemplo n.º 24
0
 def test_list_of_one(self):
     v = SExp.to([1])
     self.assertEqual(type(v.pair[0]), CLVMObject)
     self.assertEqual(type(v.pair[1]), CLVMObject)
     self.assertEqual(type(v.as_pair()[0]), SExp)
     self.assertEqual(type(v.as_pair()[1]), SExp)
     self.assertEqual(v.pair[0].atom, b"\x01")
     self.assertEqual(v.pair[1].atom, b"")
def parse_amount(args: SExp, safe_mode: bool) -> List[bytes]:
    amount_int = sanitize_int(args.first(), safe_mode)
    if amount_int < 0:
        raise ValidationError(Err.ASSERT_MY_AMOUNT_FAILED)
    if amount_int >= 2**64:
        raise ValidationError(Err.ASSERT_MY_AMOUNT_FAILED)
    # note that this may change the representation of amount. If the original
    # buffer had redundant leading zeroes, they will be stripped
    return [int_to_bytes(amount_int)]
def parse_height(args: SExp, safe_mode: bool, error_code: Err) -> Optional[List[bytes]]:
    height_int = sanitize_int(args.first(), safe_mode)
    # this condition is inherently satisified, there is no need to keep it
    if height_int < 0:
        return None
    if height_int >= 2 ** 32:
        raise ValidationError(error_code)
    # note that this may change the representation of the height. If the original
    # buffer had redundant leading zeroes, they will be stripped
    return [int_to_bytes(height_int)]
Exemplo n.º 27
0
    def test_eq(self):
        val = SExp.to(1)

        self.assertTrue(val == 1)
        self.assertFalse(val == 2)

        # mismatching types
        self.assertFalse(val == [1])
        self.assertFalse(val == [1, 2])
        self.assertFalse(val == (1, 2))
        self.assertFalse(val == (dummy_class, dummy_class))
Exemplo n.º 28
0
def best_solution_program(bundle: SpendBundle) -> SerializedProgram:
    """
    This could potentially do a lot of clever and complicated compression
    optimizations in conjunction with choosing the set of SpendBundles to include.

    For now, we just quote the solutions we know.
    """
    r = []
    for coin_solution in bundle.coin_solutions:
        entry = [coin_solution.coin.name(), coin_solution.solution]
        r.append(entry)
    return SerializedProgram.from_bytes(SExp.to((binutils.assemble("#q"), r)).as_bin())
Exemplo n.º 29
0
def simple_solution_generator(bundle: SpendBundle) -> BlockGenerator:
    """
    Simply quotes the solutions we know.
    """
    cse_list = spend_bundle_to_serialized_coin_solution_entry_list(bundle)
    block_program = b"\xff"

    block_program += SExp.to(binutils.assemble("#q")).as_bin()

    block_program += b"\xff" + cse_list + b"\x80"

    return BlockGenerator(SerializedProgram.from_bytes(block_program), [])
Exemplo n.º 30
0
    def pre_eval_f(sexp, args):
        sexp, args = [SExp.to(_) for _ in [sexp, args]]
        if symbol_table:
            h = sha256tree(sexp).hex()
            if h not in symbol_table:
                return None
        log_entry = [sexp, args, None]
        log_entries.append(log_entry)

        def callback_f(r):
            log_entry[-1] = SExp.to(r)

        return callback_f