Beispiel #1
0
def test_createConstantBlocks_small_constant():
    """pt.If a constant cannot be referenced using the intc_[0..3] commands
    and it can be stored in one varuint it byte then pt.Op.pushint is used.
    """

    for cur in range(4, 2**7):
        ops = [
            pt.TealOp(None, pt.Op.int, 0),
            pt.TealOp(None, pt.Op.int, 0),
            pt.TealOp(None, pt.Op.int, 1),
            pt.TealOp(None, pt.Op.int, 1),
            pt.TealOp(None, pt.Op.int, 2),
            pt.TealOp(None, pt.Op.int, 2),
            pt.TealOp(None, pt.Op.int, 3),
            pt.TealOp(None, pt.Op.int, 3),
            pt.TealOp(None, pt.Op.int, cur),
            pt.TealOp(None, pt.Op.int, cur),
        ]

        expected = [
            pt.TealOp(None, pt.Op.intcblock, 0, 1, 2, 3),
            pt.TealOp(None, pt.Op.intc_0, "//", 0),
            pt.TealOp(None, pt.Op.intc_0, "//", 0),
            pt.TealOp(None, pt.Op.intc_1, "//", 1),
            pt.TealOp(None, pt.Op.intc_1, "//", 1),
            pt.TealOp(None, pt.Op.intc_2, "//", 2),
            pt.TealOp(None, pt.Op.intc_2, "//", 2),
            pt.TealOp(None, pt.Op.intc_3, "//", 3),
            pt.TealOp(None, pt.Op.intc_3, "//", 3),
            pt.TealOp(None, pt.Op.pushint, cur, "//", cur),
            pt.TealOp(None, pt.Op.pushint, cur, "//", cur),
        ]

        actual = createConstantBlocks(ops)
        assert actual == expected
Beispiel #2
0
def test_createConstantBlocks_tmpl_int_mixed():
    ops = [
        pt.TealOp(None, pt.Op.int, "TMPL_INT_1"),
        pt.TealOp(None, pt.Op.int, "TMPL_INT_1"),
        pt.TealOp(None, pt.Op.eq),
        pt.TealOp(None, pt.Op.int, "TMPL_INT_2"),
        pt.TealOp(None, pt.Op.add),
        pt.TealOp(None, pt.Op.int, 0),
        pt.TealOp(None, pt.Op.int, 0),
        pt.TealOp(None, pt.Op.add),
        pt.TealOp(None, pt.Op.int, 1),
        pt.TealOp(None, pt.Op.add),
    ]

    expected = [
        pt.TealOp(None, pt.Op.intcblock, "TMPL_INT_1", 0),
        pt.TealOp(None, pt.Op.intc_0, "//", "TMPL_INT_1"),
        pt.TealOp(None, pt.Op.intc_0, "//", "TMPL_INT_1"),
        pt.TealOp(None, pt.Op.eq),
        pt.TealOp(None, pt.Op.pushint, "TMPL_INT_2", "//", "TMPL_INT_2"),
        pt.TealOp(None, pt.Op.add),
        pt.TealOp(None, pt.Op.intc_1, "//", 0),
        pt.TealOp(None, pt.Op.intc_1, "//", 0),
        pt.TealOp(None, pt.Op.add),
        pt.TealOp(None, pt.Op.pushint, 1, "//", 1),
        pt.TealOp(None, pt.Op.add),
    ]

    actual = createConstantBlocks(ops)
    assert actual == expected
Beispiel #3
0
def test_createConstantBlocks_intc():
    """Test scenario where there are more than 4 constants in the intcblock.
    pt.If the 4th constant can't fit in one varuint byte (more than 2**7) it
    should be referenced with the pt.Op.intc 4 command.
    """

    ops = [
        pt.TealOp(None, pt.Op.int, 0),
        pt.TealOp(None, pt.Op.int, 0),
        pt.TealOp(None, pt.Op.int, 1),
        pt.TealOp(None, pt.Op.int, 1),
        pt.TealOp(None, pt.Op.int, 2),
        pt.TealOp(None, pt.Op.int, 2),
        pt.TealOp(None, pt.Op.int, 3),
        pt.TealOp(None, pt.Op.int, 3),
        pt.TealOp(None, pt.Op.int, 2**7),
        pt.TealOp(None, pt.Op.int, 2**7),
    ]

    expected = [
        pt.TealOp(None, pt.Op.intcblock, 0, 1, 2, 3, 2**7),
        pt.TealOp(None, pt.Op.intc_0, "//", 0),
        pt.TealOp(None, pt.Op.intc_0, "//", 0),
        pt.TealOp(None, pt.Op.intc_1, "//", 1),
        pt.TealOp(None, pt.Op.intc_1, "//", 1),
        pt.TealOp(None, pt.Op.intc_2, "//", 2),
        pt.TealOp(None, pt.Op.intc_2, "//", 2),
        pt.TealOp(None, pt.Op.intc_3, "//", 3),
        pt.TealOp(None, pt.Op.intc_3, "//", 3),
        pt.TealOp(None, pt.Op.intc, 4, "//", 2**7),
        pt.TealOp(None, pt.Op.intc, 4, "//", 2**7),
    ]

    actual = createConstantBlocks(ops)
    assert actual == expected
Beispiel #4
0
def test_createConstantBlocks_tmpl_bytes_mixed():
    ops = [
        pt.TealOp(None, pt.Op.byte, "TMPL_BYTES_1"),
        pt.TealOp(None, pt.Op.byte, "TMPL_BYTES_1"),
        pt.TealOp(None, pt.Op.eq),
        pt.TealOp(None, pt.Op.byte, "TMPL_BYTES_2"),
        pt.TealOp(None, pt.Op.concat),
        pt.TealOp(None, pt.Op.byte, "0x00"),
        pt.TealOp(None, pt.Op.byte, "0x00"),
        pt.TealOp(None, pt.Op.concat),
        pt.TealOp(None, pt.Op.byte, "0x01"),
        pt.TealOp(None, pt.Op.concat),
    ]

    expected = [
        pt.TealOp(None, pt.Op.bytecblock, "TMPL_BYTES_1", "0x00"),
        pt.TealOp(None, pt.Op.bytec_0, "//", "TMPL_BYTES_1"),
        pt.TealOp(None, pt.Op.bytec_0, "//", "TMPL_BYTES_1"),
        pt.TealOp(None, pt.Op.eq),
        pt.TealOp(None, pt.Op.pushbytes, "TMPL_BYTES_2", "//", "TMPL_BYTES_2"),
        pt.TealOp(None, pt.Op.concat),
        pt.TealOp(None, pt.Op.bytec_1, "//", "0x00"),
        pt.TealOp(None, pt.Op.bytec_1, "//", "0x00"),
        pt.TealOp(None, pt.Op.concat),
        pt.TealOp(None, pt.Op.pushbytes, "0x01", "//", "0x01"),
        pt.TealOp(None, pt.Op.concat),
    ]

    actual = createConstantBlocks(ops)
    assert actual == expected
Beispiel #5
0
def test_createConstantBlocks_intblock_pushint():
    ops = [
        pt.TealOp(None, pt.Op.int, 1),
        pt.TealOp(None, pt.Op.int, "OptIn"),
        pt.TealOp(None, pt.Op.add),
        pt.TealOp(None, pt.Op.int, 2),
        pt.TealOp(None, pt.Op.int, 3),
        pt.TealOp(None, pt.Op.add),
        pt.TealOp(None, pt.Op.int, 3),
        pt.TealOp(None, pt.Op.int, "ClearState"),
        pt.TealOp(None, pt.Op.add),
    ]

    expected = [
        pt.TealOp(None, pt.Op.intcblock, 3, 1),
        pt.TealOp(None, pt.Op.intc_1, "//", 1),
        pt.TealOp(None, pt.Op.intc_1, "//", "OptIn"),
        pt.TealOp(None, pt.Op.add),
        pt.TealOp(None, pt.Op.pushint, 2, "//", 2),
        pt.TealOp(None, pt.Op.intc_0, "//", 3),
        pt.TealOp(None, pt.Op.add),
        pt.TealOp(None, pt.Op.intc_0, "//", 3),
        pt.TealOp(None, pt.Op.intc_0, "//", "ClearState"),
        pt.TealOp(None, pt.Op.add),
    ]

    actual = createConstantBlocks(ops)
    assert actual == expected
Beispiel #6
0
def test_createConstantBlocks_empty():
    ops = []

    expected = ops[:]

    actual = createConstantBlocks(ops)
    assert actual == expected
Beispiel #7
0
def test_createConstantBlocks_tmpl_all():
    ops = [
        pt.TealOp(None, pt.Op.byte, "TMPL_BYTES_1"),
        pt.TealOp(None, pt.Op.byte, "TMPL_BYTES_1"),
        pt.TealOp(None, pt.Op.eq),
        pt.TealOp(None, pt.Op.byte, "TMPL_BYTES_2"),
        pt.TealOp(None, pt.Op.concat),
        pt.TealOp(None, pt.Op.byte, "0x00"),
        pt.TealOp(None, pt.Op.byte, "0x00"),
        pt.TealOp(None, pt.Op.concat),
        pt.TealOp(None, pt.Op.byte, "0x01"),
        pt.TealOp(None, pt.Op.concat),
        pt.TealOp(None, pt.Op.len),
        pt.TealOp(None, pt.Op.int, "TMPL_INT_1"),
        pt.TealOp(None, pt.Op.int, "TMPL_INT_1"),
        pt.TealOp(None, pt.Op.eq),
        pt.TealOp(None, pt.Op.int, "TMPL_INT_2"),
        pt.TealOp(None, pt.Op.add),
        pt.TealOp(None, pt.Op.int, 0),
        pt.TealOp(None, pt.Op.int, 0),
        pt.TealOp(None, pt.Op.add),
        pt.TealOp(None, pt.Op.int, 1),
        pt.TealOp(None, pt.Op.add),
        pt.TealOp(None, pt.Op.eq),
    ]

    expected = [
        pt.TealOp(None, pt.Op.intcblock, "TMPL_INT_1", 0),
        pt.TealOp(None, pt.Op.bytecblock, "TMPL_BYTES_1", "0x00"),
        pt.TealOp(None, pt.Op.bytec_0, "//", "TMPL_BYTES_1"),
        pt.TealOp(None, pt.Op.bytec_0, "//", "TMPL_BYTES_1"),
        pt.TealOp(None, pt.Op.eq),
        pt.TealOp(None, pt.Op.pushbytes, "TMPL_BYTES_2", "//", "TMPL_BYTES_2"),
        pt.TealOp(None, pt.Op.concat),
        pt.TealOp(None, pt.Op.bytec_1, "//", "0x00"),
        pt.TealOp(None, pt.Op.bytec_1, "//", "0x00"),
        pt.TealOp(None, pt.Op.concat),
        pt.TealOp(None, pt.Op.pushbytes, "0x01", "//", "0x01"),
        pt.TealOp(None, pt.Op.concat),
        pt.TealOp(None, pt.Op.len),
        pt.TealOp(None, pt.Op.intc_0, "//", "TMPL_INT_1"),
        pt.TealOp(None, pt.Op.intc_0, "//", "TMPL_INT_1"),
        pt.TealOp(None, pt.Op.eq),
        pt.TealOp(None, pt.Op.pushint, "TMPL_INT_2", "//", "TMPL_INT_2"),
        pt.TealOp(None, pt.Op.add),
        pt.TealOp(None, pt.Op.intc_1, "//", 0),
        pt.TealOp(None, pt.Op.intc_1, "//", 0),
        pt.TealOp(None, pt.Op.add),
        pt.TealOp(None, pt.Op.pushint, 1, "//", 1),
        pt.TealOp(None, pt.Op.add),
        pt.TealOp(None, pt.Op.eq),
    ]

    actual = createConstantBlocks(ops)
    assert actual == expected
Beispiel #8
0
def test_createConstantBlocks_no_consts():
    ops = [
        pt.TealOp(None, pt.Op.txn, "Sender"),
        pt.TealOp(None, pt.Op.txn, "Receiver"),
        pt.TealOp(None, pt.Op.eq),
    ]

    expected = ops[:]

    actual = createConstantBlocks(ops)
    assert actual == expected
Beispiel #9
0
def test_createConstantBlocks_pushint():
    ops = [
        pt.TealOp(None, pt.Op.int, 0),
        pt.TealOp(None, pt.Op.int, "OptIn"),
        pt.TealOp(None, pt.Op.add),
    ]

    expected = [
        pt.TealOp(None, pt.Op.pushint, 0, "//", 0),
        pt.TealOp(None, pt.Op.pushint, 1, "//", "OptIn"),
        pt.TealOp(None, pt.Op.add),
    ]

    actual = createConstantBlocks(ops)
    assert actual == expected
Beispiel #10
0
def test_createConstantBlocks_intblock_single():
    ops = [
        pt.TealOp(None, pt.Op.int, 1),
        pt.TealOp(None, pt.Op.int, "OptIn"),
        pt.TealOp(None, pt.Op.add),
    ]

    expected = [
        pt.TealOp(None, pt.Op.intcblock, 1),
        pt.TealOp(None, pt.Op.intc_0, "//", 1),
        pt.TealOp(None, pt.Op.intc_0, "//", "OptIn"),
        pt.TealOp(None, pt.Op.add),
    ]

    actual = createConstantBlocks(ops)
    assert actual == expected
Beispiel #11
0
def test_createConstantBlocks_pushbytes():
    ops = [
        pt.TealOp(None, pt.Op.byte, "0x0102"),
        pt.TealOp(None, pt.Op.byte, "0x0103"),
        pt.TealOp(None, pt.Op.method_signature, '"empty()void"'),
        pt.TealOp(None, pt.Op.concat),
    ]

    expected = [
        pt.TealOp(None, pt.Op.pushbytes, "0x0102", "//", "0x0102"),
        pt.TealOp(None, pt.Op.pushbytes, "0x0103", "//", "0x0103"),
        pt.TealOp(None, pt.Op.pushbytes, "0xa88c26a5", "//", '"empty()void"'),
        pt.TealOp(None, pt.Op.concat),
    ]

    actual = createConstantBlocks(ops)
    assert actual == expected
Beispiel #12
0
def test_createConstantBlocks_byteblock_pushbytes():
    ops = [
        pt.TealOp(None, pt.Op.byte, "0x0102"),
        pt.TealOp(None, pt.Op.byte, "base64(AQI=)"),
        pt.TealOp(None, pt.Op.concat),
        pt.TealOp(None, pt.Op.byte, "base32(AEBA====)"),
        pt.TealOp(None, pt.Op.concat),
        pt.TealOp(None, pt.Op.byte, '"test"'),
        pt.TealOp(None, pt.Op.concat),
        pt.TealOp(None, pt.Op.byte, "base32(ORSXG5A=)"),
        pt.TealOp(None, pt.Op.concat),
        pt.TealOp(
            None,
            pt.Op.addr,
            "WSJHNPJ6YCLX5K4GUMQ4ISPK3ABMS3AL3F6CSVQTCUI5F4I65PWEMCWT3M",
        ),
        pt.TealOp(None, pt.Op.concat),
    ]

    expected = [
        pt.TealOp(None, pt.Op.bytecblock, "0x0102", "0x74657374"),
        pt.TealOp(None, pt.Op.bytec_0, "//", "0x0102"),
        pt.TealOp(None, pt.Op.bytec_0, "//", "base64(AQI=)"),
        pt.TealOp(None, pt.Op.concat),
        pt.TealOp(None, pt.Op.bytec_0, "//", "base32(AEBA====)"),
        pt.TealOp(None, pt.Op.concat),
        pt.TealOp(None, pt.Op.bytec_1, "//", '"test"'),
        pt.TealOp(None, pt.Op.concat),
        pt.TealOp(None, pt.Op.bytec_1, "//", "base32(ORSXG5A=)"),
        pt.TealOp(None, pt.Op.concat),
        pt.TealOp(
            None,
            pt.Op.pushbytes,
            "0xb49276bd3ec0977eab86a321c449ead802c96c0bd97c2956131511d2f11eebec",
            "//",
            "WSJHNPJ6YCLX5K4GUMQ4ISPK3ABMS3AL3F6CSVQTCUI5F4I65PWEMCWT3M",
        ),
        pt.TealOp(None, pt.Op.concat),
    ]

    actual = createConstantBlocks(ops)
    assert actual == expected
Beispiel #13
0
def test_createConstantBlocks_byteblock_single():
    ops = [
        pt.TealOp(None, pt.Op.byte, "0x0102"),
        pt.TealOp(None, pt.Op.byte, "base64(AQI=)"),
        pt.TealOp(None, pt.Op.concat),
        pt.TealOp(None, pt.Op.byte, "base32(AEBA====)"),
        pt.TealOp(None, pt.Op.concat),
    ]

    expected = [
        pt.TealOp(None, pt.Op.bytecblock, "0x0102"),
        pt.TealOp(None, pt.Op.bytec_0, "//", "0x0102"),
        pt.TealOp(None, pt.Op.bytec_0, "//", "base64(AQI=)"),
        pt.TealOp(None, pt.Op.concat),
        pt.TealOp(None, pt.Op.bytec_0, "//", "base32(AEBA====)"),
        pt.TealOp(None, pt.Op.concat),
    ]

    actual = createConstantBlocks(ops)
    assert actual == expected
Beispiel #14
0
def compileTeal(
    ast: Expr,
    mode: Mode,
    *,
    version: int = DEFAULT_PROGRAM_VERSION,
    assembleConstants: bool = False,
    optimize: OptimizeOptions = None,
) -> str:
    """Compile a PyTeal expression into TEAL assembly.

    Args:
        ast: The PyTeal expression to assemble.
        mode: The mode of the program to assemble. Must be Signature or Application.
        version (optional): The program version used to assemble the program. This will determine which
            expressions and fields are able to be used in the program and how expressions compile to
            TEAL opcodes. Defaults to 2 if not included.
        assembleConstants (optional): When true, the compiler will produce a program with fully
            assembled constants, rather than using the pseudo-ops `int`, `byte`, and `addr`. These
            constants will be assembled in the most space-efficient way, so enabling this may reduce
            the compiled program's size. Enabling this option requires a minimum program version of 3.
            Defaults to false.
        optimize (optional): OptimizeOptions that determine which optimizations will be applied.

    Returns:
        A TEAL assembly program compiled from the input expression.

    Raises:
        TealInputError: if an operation in ast is not supported by the supplied mode and version.
        TealInternalError: if an internal error is encounter during compilation.
    """
    if (not (MIN_PROGRAM_VERSION <= version <= MAX_PROGRAM_VERSION)
            or type(version) is not int):
        raise TealInputError(
            "Unsupported program version: {}. Excepted an integer in the range [{}, {}]"
            .format(version, MIN_PROGRAM_VERSION, MAX_PROGRAM_VERSION))

    options = CompileOptions(mode=mode, version=version, optimize=optimize)

    subroutineGraph: Dict[SubroutineDefinition,
                          Set[SubroutineDefinition]] = dict()
    subroutine_start_blocks: Dict[Optional[SubroutineDefinition],
                                  TealBlock] = dict()
    subroutine_end_blocks: Dict[Optional[SubroutineDefinition],
                                TealBlock] = dict()
    compileSubroutine(ast, options, subroutineGraph, subroutine_start_blocks,
                      subroutine_end_blocks)

    # note: optimizations are off by default, in which case, apply_global_optimizations
    # won't make any changes. Because the optimizer is invoked on a subroutine's
    # control flow graph, the optimizer requires context across block boundaries. This
    # is necessary for the dependency checking of local slots. Global slots, slots
    # used by DynamicScratchVar, and reserved slots are not optimized.
    if options.optimize.scratch_slots:
        options.optimize._skip_slots = collect_unoptimized_slots(
            subroutine_start_blocks)
        for start in subroutine_start_blocks.values():
            apply_global_optimizations(start, options.optimize)

    localSlotAssignments = assignScratchSlotsToSubroutines(
        subroutine_start_blocks)

    subroutineMapping: Dict[Optional[SubroutineDefinition],
                            List[TealComponent]] = sort_subroutine_blocks(
                                subroutine_start_blocks, subroutine_end_blocks)

    spillLocalSlotsDuringRecursion(version, subroutineMapping, subroutineGraph,
                                   localSlotAssignments)

    subroutineLabels = resolveSubroutines(subroutineMapping)
    teal = flattenSubroutines(subroutineMapping, subroutineLabels)

    verifyOpsForVersion(teal, options.version)
    verifyOpsForMode(teal, options.mode)

    if assembleConstants:
        if version < 3:
            raise TealInternalError(
                "The minimum program version required to enable assembleConstants is 3. The current version is {}"
                .format(version))
        teal = createConstantBlocks(teal)

    lines = ["#pragma version {}".format(version)]
    lines += [i.assemble() for i in teal]
    return "\n".join(lines)
Beispiel #15
0
def test_createConstantBlocks_byteblock_multiple():
    ops = [
        pt.TealOp(None, pt.Op.byte, "0x0102"),
        pt.TealOp(None, pt.Op.byte, "base64(AQI=)"),
        pt.TealOp(None, pt.Op.concat),
        pt.TealOp(None, pt.Op.byte, "base32(AEBA====)"),
        pt.TealOp(None, pt.Op.concat),
        pt.TealOp(None, pt.Op.byte, '"test"'),
        pt.TealOp(None, pt.Op.concat),
        pt.TealOp(None, pt.Op.byte, "base32(ORSXG5A=)"),
        pt.TealOp(None, pt.Op.concat),
        pt.TealOp(
            None,
            pt.Op.byte,
            "0xb49276bd3ec0977eab86a321c449ead802c96c0bd97c2956131511d2f11eebec",
        ),
        pt.TealOp(None, pt.Op.concat),
        pt.TealOp(
            None,
            pt.Op.addr,
            "WSJHNPJ6YCLX5K4GUMQ4ISPK3ABMS3AL3F6CSVQTCUI5F4I65PWEMCWT3M",
        ),
        pt.TealOp(None, pt.Op.concat),
        pt.TealOp(None, pt.Op.method_signature, '"closeOut()string"'),
        pt.TealOp(None, pt.Op.concat),
        pt.TealOp(None, pt.Op.byte, "base64(qfQrPQ==)"),
    ]

    expected = [
        pt.TealOp(
            None,
            pt.Op.bytecblock,
            "0x0102",
            "0x74657374",
            "0xb49276bd3ec0977eab86a321c449ead802c96c0bd97c2956131511d2f11eebec",
            "0xa9f42b3d",
        ),
        pt.TealOp(None, pt.Op.bytec_0, "//", "0x0102"),
        pt.TealOp(None, pt.Op.bytec_0, "//", "base64(AQI=)"),
        pt.TealOp(None, pt.Op.concat),
        pt.TealOp(None, pt.Op.bytec_0, "//", "base32(AEBA====)"),
        pt.TealOp(None, pt.Op.concat),
        pt.TealOp(None, pt.Op.bytec_1, "//", '"test"'),
        pt.TealOp(None, pt.Op.concat),
        pt.TealOp(None, pt.Op.bytec_1, "//", "base32(ORSXG5A=)"),
        pt.TealOp(None, pt.Op.concat),
        pt.TealOp(
            None,
            pt.Op.bytec_2,
            "//",
            "0xb49276bd3ec0977eab86a321c449ead802c96c0bd97c2956131511d2f11eebec",
        ),
        pt.TealOp(None, pt.Op.concat),
        pt.TealOp(
            None,
            pt.Op.bytec_2,
            "//",
            "WSJHNPJ6YCLX5K4GUMQ4ISPK3ABMS3AL3F6CSVQTCUI5F4I65PWEMCWT3M",
        ),
        pt.TealOp(None, pt.Op.concat),
        pt.TealOp(None, pt.Op.bytec_3, "//", '"closeOut()string"'),
        pt.TealOp(None, pt.Op.concat),
        pt.TealOp(None, pt.Op.bytec_3, "//", "base64(qfQrPQ==)"),
    ]

    actual = createConstantBlocks(ops)
    assert actual == expected