chia 0.9.0

A meta-crate that exports all of the Chia crates in the workspace.
Documentation
from typing import List, Optional

import string
import chia_rs
from chia.types.blockchain_format.program import Program as ChiaProgram
from chia.types.blockchain_format.serialized_program import SerializedProgram
from random import Random


def rand_bytes(rnd: Random) -> bytes:
    size = rnd.randint(0, 4)
    ret = bytearray()
    for _ in range(size):
        ret.append(rnd.getrandbits(8))
    return bytes(ret)


def rand_string(rnd: Random) -> str:
    size = rnd.randint(1, 10)
    return "".join(rnd.choices(string.ascii_uppercase + string.digits, k=size))


def rand_int(rnd: Random) -> int:
    return rnd.randint(0, 100000000000000)


def rand_list(rnd: Random) -> List:
    size = rnd.randint(0, 3)
    ret = []
    for _ in range(size):
        ret.append(rand_object(rnd))
    return ret


def rand_program(rnd: Random) -> ChiaProgram:
    return ChiaProgram.from_bytes(b"\xff\x01\xff\x04\x01")


def rand_rust_program(rnd: Random) -> chia_rs.Program:
    return chia_rs.Program.from_bytes(b"\xff\x01\xff\x04\x01")


def rand_optional(rnd: Random) -> Optional[object]:
    if rnd.randint(0, 1) == 0:
        return None
    return rand_object(rnd)


def rand_object(rnd: Random) -> object:
    types = [
        rand_optional,
        rand_int,
        rand_string,
        rand_bytes,
        rand_program,
        rand_list,
        rand_rust_program,
    ]
    return rnd.sample(types, 1)[0](rnd)


def recursive_replace(o: object) -> object:
    if isinstance(o, list):
        ret = []
        for i in o:
            ret.append(recursive_replace(i))
        return ret
    elif isinstance(o, chia_rs.Program):
        return SerializedProgram.from_bytes(o.to_bytes())
    else:
        return o


def test_run_program() -> None:

    rust_identity = chia_rs.Program.from_bytes(b"\x01")
    py_identity = SerializedProgram.from_bytes(b"\x01")

    rnd = Random()
    for _ in range(10000):
        args = rand_object(rnd)

        # the python SerializedProgram treats itself specially, the rust
        # Program treats itself specially, but they don't recognize each other,
        # so they will produce different results in this regard
        rust_ret = rust_identity._run(10000, 0, args)

        # Replace rust Program with the python SerializedProgram.
        args = recursive_replace(args)

        py_ret = py_identity._run(10000, 0, args)

        assert rust_ret == py_ret


def test_tree_hash() -> None:

    rnd = Random()
    for _ in range(10000):
        py_prg = ChiaProgram.to(rand_object(rnd))
        rust_prg = chia_rs.Program.from_bytes(bytes(py_prg))

        assert py_prg.get_tree_hash() == rust_prg.get_tree_hash()


def test_uncurry() -> None:

    rnd = Random()
    for _ in range(10000):
        py_prg = ChiaProgram.to(rand_object(rnd))
        py_prg = py_prg.curry(rand_object(rnd))
        rust_prg = chia_rs.Program.from_program(py_prg)
        assert py_prg.uncurry() == rust_prg.uncurry()

        py_prg = py_prg.curry(rand_object(rnd), rand_object(rnd))
        rust_prg = chia_rs.Program.from_program(py_prg)
        assert py_prg.uncurry() == rust_prg.uncurry()


def test_round_trip() -> None:

    rnd = Random()
    for _ in range(10000):
        obj = rand_object(rnd)
        py_prg = ChiaProgram.to(obj)
        rust_prg = chia_rs.Program.from_program(py_prg)
        rust_prg2 = chia_rs.Program.to(obj)

        assert py_prg == rust_prg.to_program()
        assert py_prg == rust_prg2.to_program()

        assert bytes(py_prg) == bytes(rust_prg)
        assert bytes(py_prg) == bytes(rust_prg2)