예제 #1
0
def test_while_break():
    i = pt.ScratchVar()
    i.store(pt.Int(0))
    items = [
        i.load() < pt.Int(2),
        i.store(i.load() + pt.Int(1)),
        pt.If(i.load() == pt.Int(1), pt.Break()),
    ]
    expr = pt.While(items[0]).Do(pt.Seq(items[1], items[2]))
    assert expr.type_of() == pt.TealType.none
    assert not expr.has_return()

    options.enterLoop()

    expected, condEnd = items[0].__teal__(options)
    do, doEnd = pt.Seq([items[1], items[2]]).__teal__(options)
    expectedBranch = pt.TealConditionalBlock([])
    end = pt.TealSimpleBlock([])

    expectedBranch.setTrueBlock(do)
    expectedBranch.setFalseBlock(end)
    condEnd.setNextBlock(expectedBranch)
    doEnd.setNextBlock(expected)

    breakBlocks, _ = options.exitLoop()

    for block in breakBlocks:
        block.setNextBlock(end)

    actual, _ = expr.__teal__(options)

    assert actual == expected
예제 #2
0
def test_ecdsa_verify_basic(curve: pt.EcdsaCurve):
    args = [pt.Bytes("data"), pt.Bytes("sigA"), pt.Bytes("sigB")]
    pubkey = (pt.Bytes("X"), pt.Bytes("Y"))
    expr = pt.EcdsaVerify(curve, args[0], args[1], args[2], pubkey)
    assert expr.type_of() == pt.TealType.uint64

    expected = pt.TealSimpleBlock([
        pt.TealOp(args[0], pt.Op.byte, '"data"'),
        pt.TealOp(args[1], pt.Op.byte, '"sigA"'),
        pt.TealOp(args[2], pt.Op.byte, '"sigB"'),
        pt.TealOp(pubkey[0], pt.Op.byte, '"X"'),
        pt.TealOp(pubkey[1], pt.Op.byte, '"Y"'),
        pt.TealOp(expr, pt.Op.ecdsa_verify, curve.arg_name),
    ])

    actual, _ = expr.__teal__(curve_options_map[curve])
    actual.addIncoming()
    actual = pt.TealBlock.NormalizeBlocks(actual)

    assert actual == expected

    # compile without errors this is necessary so assembly is also tested
    pt.compileTeal(
        pt.Seq(pt.Pop(expr), pt.Approve()),
        pt.Mode.Application,
        version=curve.min_version,
    )

    with pytest.raises(pt.TealInputError):
        pt.compileTeal(
            pt.Seq(pt.Pop(expr), pt.Approve()),
            pt.Mode.Application,
            version=curve.min_version - 1,
        )
예제 #3
0
def test_ecdsa_decompress(curve: pt.EcdsaCurve):
    compressed_pubkey = pt.Bytes("XY")
    pubkey = pt.EcdsaDecompress(curve, compressed_pubkey)
    assert pubkey.type_of() == pt.TealType.none

    expected = pt.TealSimpleBlock([
        pt.TealOp(compressed_pubkey, pt.Op.byte, '"XY"'),
        pt.TealOp(pubkey, pt.Op.ecdsa_pk_decompress, curve.arg_name),
        pt.TealOp(pubkey.output_slots[1].store(), pt.Op.store,
                  pubkey.output_slots[1]),
        pt.TealOp(pubkey.output_slots[0].store(), pt.Op.store,
                  pubkey.output_slots[0]),
    ])

    actual, _ = pubkey.__teal__(curve_options_map[curve])
    actual.addIncoming()
    actual = pt.TealBlock.NormalizeBlocks(actual)

    with pt.TealComponent.Context.ignoreExprEquality():
        assert actual == expected

    # compile without errors this is necessary so assembly is also tested
    pt.compileTeal(pt.Seq(pubkey, pt.Approve()),
                   pt.Mode.Application,
                   version=curve.min_version)

    with pytest.raises(pt.TealInputError):
        pt.compileTeal(
            pt.Seq(pubkey, pt.Approve()),
            pt.Mode.Application,
            version=curve.min_version - 1,
        )
예제 #4
0
def test_for():
    i = pt.ScratchVar()
    items = [
        (i.store(pt.Int(0))),
        i.load() < pt.Int(10),
        i.store(i.load() + pt.Int(1)),
        pt.App.globalPut(pt.Itob(i.load()), i.load() * pt.Int(2)),
    ]
    expr = pt.For(items[0], items[1], items[2]).Do(pt.Seq([items[3]]))

    assert expr.type_of() == pt.TealType.none
    assert not expr.has_return()

    expected, varEnd = items[0].__teal__(options)
    condStart, condEnd = items[1].__teal__(options)
    stepStart, stepEnd = items[2].__teal__(options)
    do, doEnd = pt.Seq([items[3]]).__teal__(options)
    expectedBranch = pt.TealConditionalBlock([])
    end = pt.TealSimpleBlock([])

    varEnd.setNextBlock(condStart)
    doEnd.setNextBlock(stepStart)

    expectedBranch.setTrueBlock(do)
    expectedBranch.setFalseBlock(end)
    condEnd.setNextBlock(expectedBranch)
    stepEnd.setNextBlock(condStart)

    actual, _ = expr.__teal__(options)

    assert actual == expected
예제 #5
0
def test_opup_explicit():
    mode = OpUpMode.Explicit
    with pytest.raises(pt.TealInputError) as err:
        opup = OpUp(mode)
    assert "target_app_id must be specified in Explicit OpUp mode" in str(
        err.value)

    with pytest.raises(pt.TealTypeError):
        opup = OpUp(mode, pt.Bytes("appid"))

    opup = OpUp(mode, pt.Int(1))

    with pytest.raises(pt.TealTypeError):
        opup.ensure_budget(pt.Bytes("budget"))

    with pytest.raises(pt.TealTypeError):
        opup.maximize_budget(pt.Bytes("fee"))

    assert opup.target_app_id == pt.Int(1)

    # verify correct usage doesn't cause an error
    _ = pt.Seq(opup.ensure_budget(pt.Int(500) + pt.Int(1000)),
               pt.Return(pt.Int(1)))

    _ = pt.Seq(opup.maximize_budget(pt.Txn.fee() - pt.Int(100)),
               pt.Return(pt.Int(1)))
예제 #6
0
def test_on_complete_action():
    with pytest.raises(pt.TealInputError) as contradict_err:
        pt.OnCompleteAction(action=pt.Seq(), call_config=pt.CallConfig.NEVER)
    assert "contradicts" in str(contradict_err)
    assert pt.OnCompleteAction.never().is_empty()
    assert pt.OnCompleteAction.call_only(pt.Seq()).call_config == pt.CallConfig.CALL
    assert pt.OnCompleteAction.create_only(pt.Seq()).call_config == pt.CallConfig.CREATE
    assert pt.OnCompleteAction.always(pt.Seq()).call_config == pt.CallConfig.ALL
예제 #7
0
def test_seq_invalid():
    with pytest.raises(pt.TealTypeError):
        pt.Seq([pt.Int(1), pt.Pop(pt.Int(2))])

    with pytest.raises(pt.TealTypeError):
        pt.Seq([pt.Int(1), pt.Int(2)])

    with pytest.raises(pt.TealTypeError):
        pt.Seq([pt.Seq([pt.Pop(pt.Int(1)), pt.Int(2)]), pt.Int(3)])
예제 #8
0
def test_seq_zero():
    for expr in (pt.Seq(), pt.Seq([])):
        assert expr.type_of() == pt.TealType.none
        assert not expr.has_return()

        expected = pt.TealSimpleBlock([])

        actual, _ = expr.__teal__(options)

        assert actual == expected
예제 #9
0
def test_wrap_handler_bare_call():
    BARE_CALL_CASES = [
        dummy_doing_nothing,
        safe_clear_state_delete,
        pt.Approve(),
        pt.Log(pt.Bytes("message")),
    ]
    for bare_call in BARE_CALL_CASES:
        wrapped: pt.Expr = ASTBuilder.wrap_handler(False, bare_call)
        expected: pt.Expr
        match bare_call:
            case pt.Expr():
                if bare_call.has_return():
                    expected = bare_call
                else:
                    expected = pt.Seq(bare_call, pt.Approve())
            case pt.SubroutineFnWrapper() | pt.ABIReturnSubroutine():
                expected = pt.Seq(bare_call(), pt.Approve())
            case _:
                raise pt.TealInputError("how you got here?")
        wrapped_assemble = assemble_helper(wrapped)
        wrapped_helper = assemble_helper(expected)
        with pt.TealComponent.Context.ignoreExprEquality():
            assert wrapped_assemble == wrapped_helper

    ERROR_CASES = [
        (
            pt.Int(1),
            f"bare appcall handler should be TealType.none not {pt.TealType.uint64}.",
        ),
        (
            returning_u64,
            f"subroutine call should be returning TealType.none not {pt.TealType.uint64}.",
        ),
        (
            mult_over_u64_and_log,
            "subroutine call should take 0 arg for bare-app call. this subroutine takes 2.",
        ),
        (
            eine_constant,
            f"abi-returning subroutine call should be returning void not {pt.abi.Uint64TypeSpec()}.",
        ),
        (
            take_abi_and_log,
            "abi-returning subroutine call should take 0 arg for bare-app call. this abi-returning subroutine takes 1.",
        ),
        (
            1,
            "bare appcall can only accept: none type Expr, or Subroutine/ABIReturnSubroutine with none return and no arg",
        ),
    ]
    for error_case, error_msg in ERROR_CASES:
        with pytest.raises(pt.TealInputError) as bug:
            ASTBuilder.wrap_handler(False, error_case)
        assert error_msg in str(bug)
예제 #10
0
def string_mult(s: pt.ScratchVar, n):
    i = pt.ScratchVar(pt.TealType.uint64)
    tmp = pt.ScratchVar(pt.TealType.bytes)
    start = pt.Seq(i.store(pt.Int(1)), tmp.store(s.load()),
                   s.store(pt.Bytes("")))
    step = i.store(i.load() + pt.Int(1))
    return pt.Seq(
        pt.For(start,
               i.load() <= n, step).Do(s.store(pt.Concat(s.load(),
                                                         tmp.load()))),
        s.load(),
    )
예제 #11
0
def test_nested_for_compiles():
    i = pt.ScratchVar()
    expr = pt.For(i.store(pt.Int(0)), pt.Int(1), i.store(i.load() + pt.Int(1))).Do(
        pt.Seq(
            [
                pt.For(i.store(pt.Int(0)), pt.Int(1), i.store(i.load() + pt.Int(1))).Do(
                    pt.Seq([i.store(pt.Int(0))])
                )
            ]
        )
    )
    assert expr.type_of() == pt.TealType.none
    assert not expr.has_return()
예제 #12
0
def test_seq_overloads_equivalence():
    items = [
        pt.App.localPut(pt.Int(0), pt.Bytes("key1"), pt.Int(1)),
        pt.App.localPut(pt.Int(1), pt.Bytes("key2"), pt.Bytes("value2")),
        pt.Pop(pt.Bytes("end")),
    ]
    expr1 = pt.Seq(items)
    expr2 = pt.Seq(*items)

    expected = expr1.__teal__(options)
    actual = expr2.__teal__(options)

    assert actual == expected
예제 #13
0
def fac_by_ref_args():
    n = pt.ScratchVar(pt.TealType.uint64)
    return pt.Seq(
        pt.If(
            pt.Or(
                pt.App.id() == pt.Int(0),
                pt.Txn.application_args.length() == pt.Int(0),
            )).Then(pt.Int(1)).Else(
                pt.Seq(
                    n.store(pt.Btoi(pt.Txn.application_args[0])),
                    factorial(n),
                    n.load(),
                )))
예제 #14
0
def test_seq_has_return():
    exprWithReturn = pt.Seq(
        [
            pt.App.localPut(pt.Int(0), pt.Bytes("key1"), pt.Int(1)),
            pt.Return(pt.Int(1)),
        ]
    )
    assert exprWithReturn.has_return()

    exprWithoutReturn = pt.Seq(
        [pt.App.localPut(pt.Int(0), pt.Bytes("key1"), pt.Int(1)), pt.Int(1)]
    )
    assert not exprWithoutReturn.has_return()
예제 #15
0
def fast_fibonacci(n):
    i = pt.ScratchVar(pt.TealType.uint64)
    a = pt.ScratchVar(pt.TealType.uint64)
    b = pt.ScratchVar(pt.TealType.uint64)
    return pt.Seq(
        a.store(pt.Int(0)),
        b.store(pt.Int(1)),
        pt.For(i.store(pt.Int(1)),
               i.load() <= n, i.store(i.load() + pt.Int(1))).Do(
                   pt.Seq(
                       b.store(a.load() + b.load()),
                       a.store(b.load() - a.load()),
                   )),
        a.load(),
    )
예제 #16
0
def logcat(some_bytes, an_int):
    catted = pt.ScratchVar(pt.TealType.bytes)
    return pt.Seq(
        catted.store(pt.Concat(some_bytes, pt.Itob(an_int))),
        pt.Log(catted.load()),
        catted.load(),
    )
예제 #17
0
def test_while_compiles():

    i = pt.ScratchVar()
    expr = pt.While(pt.Int(2)).Do(pt.Seq([i.store(pt.Int(0))]))
    assert expr.type_of() == pt.TealType.none
    assert not expr.has_return()
    expr.__teal__(options)
예제 #18
0
def swap(x: pt.ScratchVar, y: pt.ScratchVar):
    z = pt.ScratchVar(pt.TealType.anytype)
    return pt.Seq(
        z.store(x.load()),
        x.store(y.load()),
        y.store(z.load()),
    )
예제 #19
0
 def fn_mixed_annotations_0_with_ret(a: pt.ScratchVar, b: pt.Expr,
                                     c: pt.abi.Byte, *,
                                     output: pt.abi.Uint64) -> pt.Expr:
     return pt.Seq(
         a.store(c.get() * pt.Int(0x0FF1CE) * b),
         output.set(a.load()),
     )
예제 #20
0
def test_evaluate_subroutine_no_args():
    cases = (
        (pt.TealType.none, pt.Return()),
        (pt.TealType.uint64, pt.Int(1) + pt.Int(2)),
        (pt.TealType.uint64, pt.Return(pt.Int(1) + pt.Int(2))),
        (pt.TealType.bytes, pt.Bytes("value")),
        (pt.TealType.bytes, pt.Return(pt.Bytes("value"))),
    )

    for (returnType, returnValue) in cases:

        def mySubroutine():
            return returnValue

        definition = pt.SubroutineDefinition(mySubroutine, returnType)
        declaration = evaluate_subroutine(definition)

        assert isinstance(declaration, pt.SubroutineDeclaration)
        assert declaration.subroutine is definition

        assert declaration.type_of() == returnValue.type_of()
        assert declaration.has_return() == returnValue.has_return()

        options.setSubroutine(definition)
        expected, _ = pt.Seq([returnValue]).__teal__(options)

        actual, _ = declaration.__teal__(options)
        options.setSubroutine(None)
        assert actual == expected
예제 #21
0
def test_wrap_handler_method_txn_types():
    wrapped: pt.Expr = ASTBuilder.wrap_handler(True, multiple_txn)
    actual: pt.TealBlock = assemble_helper(wrapped)

    args: list[pt.abi.Transaction] = [
        pt.abi.ApplicationCallTransaction(),
        pt.abi.AssetTransferTransaction(),
        pt.abi.PaymentTransaction(),
        pt.abi.Transaction(),
    ]
    output_temp = pt.abi.Uint64()
    expected_ast = pt.Seq(
        args[0]._set_index(pt.Txn.group_index() - pt.Int(4)),
        pt.Assert(args[0].get().type_enum() == pt.TxnType.ApplicationCall),
        args[1]._set_index(pt.Txn.group_index() - pt.Int(3)),
        pt.Assert(args[1].get().type_enum() == pt.TxnType.AssetTransfer),
        args[2]._set_index(pt.Txn.group_index() - pt.Int(2)),
        pt.Assert(args[2].get().type_enum() == pt.TxnType.Payment),
        args[3]._set_index(pt.Txn.group_index() - pt.Int(1)),
        multiple_txn(*args).store_into(output_temp),
        pt.abi.MethodReturn(output_temp),
        pt.Approve(),
    )

    expected = assemble_helper(expected_ast)
    with pt.TealComponent.Context.ignoreScratchSlotEquality(), pt.TealComponent.Context.ignoreExprEquality():
        assert actual == expected

    assert pt.TealBlock.MatchScratchSlotReferences(
        pt.TealBlock.GetReferencedScratchSlots(actual),
        pt.TealBlock.GetReferencedScratchSlots(expected),
    )
예제 #22
0
def fac_by_ref_BAD():
    n = pt.ScratchVar(pt.TealType.uint64)
    return pt.Seq(
        n.store(pt.Int(10)),
        factorial_BAD(n),
        n.load(),
    )
예제 #23
0
def test_opup_oncall():
    mode = OpUpMode.OnCall
    opup = OpUp(mode)

    with pytest.raises(pt.TealTypeError):
        opup.ensure_budget(pt.Bytes("budget"))

    with pytest.raises(pt.TealTypeError):
        opup.maximize_budget(pt.Bytes("fee"))

    # verify correct usage doesn't cause an error
    _ = pt.Seq(opup.ensure_budget(pt.Int(500) + pt.Int(1000)),
               pt.Return(pt.Int(1)))

    _ = pt.Seq(opup.maximize_budget(pt.Txn.fee() - pt.Int(100)),
               pt.Return(pt.Int(1)))
예제 #24
0
def test_ecdsa_verify_recovered_pk():
    curve = pt.EcdsaCurve.Secp256k1
    args = [pt.Bytes("data"), pt.Int(1), pt.Bytes("sigA"), pt.Bytes("sigB")]
    pubkey = pt.EcdsaRecover(curve, args[0], args[1], args[2], args[3])
    expr = pt.EcdsaVerify(curve, args[0], args[2], args[3], pubkey)
    assert expr.type_of() == pt.TealType.uint64

    expected = pt.TealSimpleBlock([
        pt.TealOp(args[0], pt.Op.byte, '"data"'),
        pt.TealOp(args[1], pt.Op.int, 1),
        pt.TealOp(args[2], pt.Op.byte, '"sigA"'),
        pt.TealOp(args[3], pt.Op.byte, '"sigB"'),
        pt.TealOp(pubkey, pt.Op.ecdsa_pk_recover, curve.arg_name),
        pt.TealOp(pubkey.output_slots[1].store(), pt.Op.store,
                  pubkey.output_slots[1]),
        pt.TealOp(pubkey.output_slots[0].store(), pt.Op.store,
                  pubkey.output_slots[0]),
        pt.TealOp(args[0], pt.Op.byte, '"data"'),
        pt.TealOp(args[1], pt.Op.byte, '"sigA"'),
        pt.TealOp(args[2], pt.Op.byte, '"sigB"'),
        pt.TealOp(pubkey.output_slots[0].load(), pt.Op.load,
                  pubkey.output_slots[0]),
        pt.TealOp(pubkey.output_slots[1].load(), pt.Op.load,
                  pubkey.output_slots[1]),
        pt.TealOp(expr, pt.Op.ecdsa_verify, curve.arg_name),
    ])

    actual, _ = expr.__teal__(curve_options_map[curve])
    actual.addIncoming()
    actual = pt.TealBlock.NormalizeBlocks(actual)

    with pt.TealComponent.Context.ignoreExprEquality():
        assert actual == expected

    # compile without errors this is necessary so assembly is also tested
    pt.compileTeal(
        pt.Seq(pt.Pop(expr), pt.Approve()),
        pt.Mode.Application,
        version=curve.min_version,
    )

    with pytest.raises(pt.TealInputError):
        pt.compileTeal(
            pt.Seq(pt.Pop(expr), pt.Approve()),
            pt.Mode.Application,
            version=curve.min_version - 1,
        )
예제 #25
0
def factorial_BAD(n: pt.ScratchVar):
    tmp = pt.ScratchVar(pt.TealType.uint64)
    return (pt.If(n.load() <= pt.Int(1)).Then(n.store(pt.Int(1))).Else(
        pt.Seq(
            tmp.store(n.load() - pt.Int(1)),
            factorial_BAD(tmp),
            n.store(n.load() * tmp.load()),
        )))
예제 #26
0
def plus_one(n: pt.ScratchVar):
    tmp = pt.ScratchVar(pt.TealType.uint64)
    return (pt.If(n.load() == pt.Int(0)).Then(n.store(pt.Int(1))).Else(
        pt.Seq(
            tmp.store(n.load() - pt.Int(1)),
            plus_one(tmp),
            n.store(tmp.load() + pt.Int(1)),
        )))
예제 #27
0
def subr_string_mult(s: pt.ScratchVar, n):
    tmp = pt.ScratchVar(pt.TealType.bytes)
    return (pt.If(n == pt.Int(0)).Then(s.store(pt.Bytes(""))).Else(
        pt.Seq(
            tmp.store(s.load()),
            subr_string_mult(s, n - pt.Int(1)),
            s.store(pt.Concat(s.load(), tmp.load())),
        )))
예제 #28
0
def test_use_seq_if_multiple_overloads_equivalence():
    items = [pt.Pop(pt.Int(1)), pt.Int(2)]
    expr = _use_seq_if_multiple(items)

    expected = pt.Seq(items).__teal__(options)
    actual = expr.__teal__(options)

    assert actual == expected
예제 #29
0
def string_mult():
    s = pt.ScratchVar(pt.TealType.bytes)
    return pt.Seq(
        s.store(pt.Txn.application_args[0]),
        subr_string_mult(s, pt.Btoi(pt.Txn.application_args[1])),
        pt.Log(s.load()),
        pt.Int(100),
    )
예제 #30
0
def test_continue_break():
    i = pt.ScratchVar()
    expr = pt.For(i.store(pt.Int(0)), pt.Int(1), i.store(i.load() + pt.Int(1))).Do(
        pt.Seq([pt.If(pt.Int(1), pt.Break(), pt.Continue())])
    )
    assert expr.type_of() == pt.TealType.none
    assert not expr.has_return()
    expr.__teal__(options)