OpUp: Budget Increase Utility

Some opcode budget is consumed during execution of every Algorand Smart Contract because every TEAL instruction has a corresponding cost. In order for the evaluation to succeed, the budget consumed must not exceed the budget provided. This constraint may introduce a problem for expensive contracts that quickly consume the initial budget of 700. The OpUp budget increase utility provides a workaround using NoOp inner transactions that increase the transaction group’s pooled compute budget. The funding for issuing the inner transactions is provided by the contract doing the issuing, not the user calling the contract, so the contract must have enough funds for this purpose. Note that there is a context specific limit to the number of inner transactions issued in a transaction group so budget cannot be increased arbitrarily. The available budget when using the OpUp utility will need to be high enough to execute the TEAL code that issues the inner transactions. A budget of ~20 is enough for most use cases.

Usage

The pyteal.OpUp utility is available in two modes: Explicit and OnCall:

OpUp Mode

Description

Explicit

Calls a user provided external app when more budget is requested.

OnCall

Creates and immediately deletes the app to be called when more budget is requested.

Explicit has the benefit of constructing more lightweight inner transactions, but requires the target app ID to be provided in the foreign apps array field of the transaction and the pyteal.OpUp constructor in order for it to be accessible. OnCall is easier to use, but has slightly more overhead because the target app must be created and deleted during the evaluation of an app call.

Ensure Budget

pyteal.OpUp.ensure_budget attempts to ensure that the available budget is at least the budget requested by the caller. If there aren’t enough funds for issuing the inner transactions or the inner transaction limit is exceeded, the evaluation will fail. The typical usage pattern is to insert the pyteal.OpUp.ensure_budget call just before a particularly heavyweight subroutine or expression. Keep in mind that the required budget expression will be evaluated before the inner transactions are issued so it may be prudent to avoid expensive expressions, which may exhaust the budget before it can be increased.

In the example below, the pyteal.Ed25519Verify() expression is used, which costs 1,900.

# The application id to be called when more budget is requested. This should be
# replaced with an id provided by the developer.
target_app_id = Int(1)

# OnCall mode works the exact same way, just omit the target_app_id
opup = OpUp(OpUpMode.Explicit, target_app_id)
program = Seq(
    If(Txn.application_id() != Int(0)).Then(
        Seq(
            opup.ensure_budget(Int(2000)),
            Assert(Ed25519Verify(args[0], args[1], args[2])),
        )
    ),
    Approve(),
)

Maximize Budget

pyteal.OpUp.maximize_budget attempts to issue as many inner transactions as possible with the given fee. This essentially maximizes the available budget while putting a ceiling on the amount of fee spent. Just as with pyteal.OpUp.ensure_budget, the evaluation will fail if there aren’t enough funds for issuing the inner transactions or the inner transaction limit is exceeded. This method may be preferred to pyteal.OpUp.ensure_budget when the fee spent on increasing budget needs to be capped or if the developer would rather just maximize the available budget instead of doing in depth cost analysis on the program.

In the example below, the fee is capped at 3,000 microAlgos for increasing the budget. This works out to 3 inner transactions being issued, each increasing the available budget by ~700.

target_app_id = Int(1) # the application id to be called when more budget is requested

# OnCall mode works the exact same way, just omit the target_app_id
opup = OpUp(OpUpMode.Explicit, target_app_id)
program = Seq(
    If(Txn.application_id() != Int(0)).Then(
        Seq(
            opup.maximize_budget(Int(3000)),
            Assert(Ed25519Verify(args[0], args[1], args[2])),
        )
    ),
    Approve(),
)

If budget increase requests appear multiple times in the program, it may be a good idea to wrap the invocation in a PyTeal Subroutine to improve code reuse and reduce the size of the compiled program.