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)
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 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))
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'))
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
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])
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 test_g1element(self): b = fh( "b3b8ac537f4fd6bde9b26221d49b54b17a506be147347dae5" "d081c0a6572b611d8484e338f3432971a9823976c6a232b" ) v = SExp.to(G1Element(b)) self.assertEqual(v.atom, b)
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
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())
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 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
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))
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 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())
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"")
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), [])
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
def curry(program, args): """ ;; A "curry" binds values to a function, making them constant, ;; and returning a new function that returns fewer arguments (since the ;; arguments are now fixed). ;; Example: (defun add2 (V1 V2) (+ V1 V2)) ; add two values ;; (curry add2 15) ; this yields a function that accepts ONE argument, and adds 15 to it `program`: an SExp `args`: an SExp that is a list of constants to be bound to `program` """ args = SExp.to((program, args)) r = run_program( CURRY_OBJ_CODE, args, quote_kw=KEYWORD_TO_ATOM["q"], operator_lookup=OPERATOR_LOOKUP, ) return r
def ir_new(type: int, val: CastableType, offset: typing.Optional[int] = None) -> SExp: if offset is not None: type = SExp.to((type, offset)) return SExp.to((type, val))
def test_int(self): v = SExp.to(42) self.assertEqual(v.atom, bytes([42]))
def _serialize(node) -> bytes: if type(node) == SerializedProgram: return bytes(node) else: return SExp.to(node).as_bin()
def test_empty_list(self): v = SExp.to([]) self.assertEqual(v.atom, b"")
def test_repr(self): self.assertEqual(repr(SExp.to(1)), "SExp(01)") self.assertEqual(repr(SExp.to(1337)), "SExp(820539)") self.assertEqual(repr(SExp.to(-1)), "SExp(81ff)") self.assertEqual(repr(gen_tree(1)), "SExp(ff820539820539)") self.assertEqual(repr(gen_tree(2)), "SExp(ffff820539820539ff820539820539)")
def callback_f(r): log_entry[-1] = SExp.to(r)
def test_str(self): self.assertEqual(str(SExp.to(1)), "01") self.assertEqual(str(SExp.to(1337)), "820539") self.assertEqual(str(SExp.to(-1)), "81ff") self.assertEqual(str(gen_tree(1)), "ff820539820539") self.assertEqual(str(gen_tree(2)), "ffff820539820539ff820539820539")
def test_nullp(self): self.assertEqual(SExp.to(b"").nullp(), True) self.assertEqual(SExp.to(b"1337").nullp(), False) self.assertEqual(SExp.to((b"", b"")).nullp(), False)
def test_none(self): v = SExp.to(None) self.assertEqual(v.atom, b"")
def test_rest(self): val = SExp.to(1) self.assertRaises(EvalError, lambda: val.rest()) val = SExp.to((42, val)) self.assertEqual(val.rest(), SExp.to(1))
def check_as_python(self, p): v = SExp.to(p) p1 = v.as_python() self.assertEqual(p, p1)