State
Applications that need to maintain state can declare the state they need as part of the Application.
See the developer docs for details.
Warning
The static
option on state values is enforced only when using the methods provided by the objects described here.
It is still possible to overwrite or delete the values using the accessors provided by PyTeal or TEAL directly.
Warning
When using the GlobalStateBlob
or LocalStateBlob
, the keys used to store data are 1 byte in the range [0-255]. Care must be taken to prevent any other state values from overwriting those keys.
For example if ReservedLocalStateValue
tries to write to key 0x00
and a blob is already using that key, bad things will happen.
For documentation on box storage please see the Boxes page
Global State
Global State holds the stateful values for the Application.
The GlobalStateStorage
class is produced automatically by the Application
, there is no need to create it directly.
Global State Value
- class beaker.state.GlobalStateValue[source]
Allows storage of state values for an application (global state)
- stack_type
The type of the state value (either TealType.bytes or TealType.uint64)
- key
key to use to store the the value, default is name of class variable
- default
Default value for the state value
- static
Boolean flag to denote that this state value can only be set once and not deleted.
- descr
Description of the state value to provide some information to clients
- delete() Expr [source]
deletes the key from state, if the value is static it will be a compile time error
- exists() Expr [source]
checks if the value is set (to whatever value. Returns Int(1) if value is set, Int(0) otherwise.
- get_else(val: Expr) Expr [source]
gets the value stored at the key. if none is stored, return the value passed
Reserved Global State Value
- class beaker.state.ReservedGlobalStateValue[source]
Reserved Application State (global state)
Used when there should be a number of reserved state fields but the keys are uncertain at build time.
- stack_type
The type of the state value (either TealType.bytes or TealType.uint64)
- Type
TealType
- key_gen
A subroutine returning TealType.bytes, used to create a key where some data is stored.
- Type
SubroutineFnWrapper
- __init__(stack_type: ~typing.Literal[<TealType.bytes: 1>, <TealType.uint64: 0>], max_keys: int, key_gen: ~typing.Optional[~typing.Union[~collections.abc.Callable[[~pyteal.Expr], ~pyteal.Expr], ~pyteal.SubroutineFnWrapper]] = None, descr: ~typing.Optional[str] = None, *, prefix: ~typing.Optional[str] = None)[source]
Global State Blob
- class beaker.state.GlobalStateBlob[source]
-
- read(start: Expr, stop: Expr) Expr [source]
Reads some bytes from the buffer
- Parameters
start – An
Expr
that represents the start index to read from. Should evaluate touint64
.stop – An
Expr
that represents the stop index to read until. Should evaluate touint64
.
- Returns
The bytes read from the blob from start to stop
- read_byte(idx: Expr) Expr [source]
Reads a single byte from the given index
- Parameters
idx – An
Expr
that represents the index into the blob to read the byte from. Should evaluate touint64
.- Returns
A single byte as a
uint64
Local State
If your application requires storage of state at the Account level, declare the state values at the class
level and the Application class will detect them on initialization.
Algorand refers to Account state as Local State
The LocalStateStorage
class is produced automatically by the Application
, there is no need to create it directly.
LocalStateValue
- class beaker.state.LocalStateValue[source]
Allows storage of keyed values for an account opted into an application (local state)
- stack_type
The type of the state value (either TealType.bytes or TealType.uint64)
- key
key to use to store the the value, default is name of class variable
- default
Default value for the state value
- static
Boolean flag to denote that this state value can only be set once and not deleted.
- descr
Description of the state value to provide some information to clients
- __init__(stack_type: ~typing.Literal[<TealType.bytes: 1>, <TealType.uint64: 0>], key: ~typing.Optional[~typing.Union[~pyteal.Expr, str]] = None, default: ~typing.Optional[~pyteal.Expr] = None, static: bool = False, descr: ~typing.Optional[str] = None)[source]
- delete() Expr [source]
deletes the key from state, if the value is static it will be a compile time error
- exists() Expr [source]
checks if the value is set (to whatever value. Returns Int(1) if value is set, Int(0) otherwise.
- get_else(val: Expr) Expr [source]
gets the value stored at the key. if none is stored, return the value passed
ReservedLocalStateValue
- class beaker.state.ReservedLocalStateValue[source]
Reserved Account State (local state)
Used when there should be a number of reserved state fields but the keys are uncertain at build time.
- stack_type
The type of the state value (either TealType.bytes or TealType.uint64)
- Type
TealType
- key_gen
A subroutine returning TealType.bytes, used to create a key where some data is stored.
- Type
SubroutineFnWrapper
- __init__(stack_type: ~typing.Literal[<TealType.bytes: 1>, <TealType.uint64: 0>], max_keys: int, key_gen: ~typing.Optional[~typing.Union[~collections.abc.Callable[[~pyteal.Expr], ~pyteal.Expr], ~pyteal.SubroutineFnWrapper]] = None, descr: ~typing.Optional[str] = None, *, prefix: ~typing.Optional[str] = None)[source]
Local State Blob
- class beaker.state.LocalStateBlob[source]
-
- read(start: Expr, stop: Expr) Expr [source]
Reads some bytes from the buffer
- Parameters
start – An
Expr
that represents the start index to read from. Should evaluate touint64
.stop – An
Expr
that represents the stop index to read until. Should evaluate touint64
.
- Returns
The bytes read from the blob from start to stop
- read_byte(idx: Expr) Expr [source]
Reads a single byte from the given index
- Parameters
idx – An
Expr
that represents the index into the blob to read the byte from. Should evaluate touint64
.- Returns
A single byte as a
uint64
Full Example
import pyteal as pt
import beaker
class ExampleState:
declared_global_value = beaker.GlobalStateValue(
stack_type=pt.TealType.bytes,
default=pt.Bytes(
"A declared state value that is protected with the `static` flag"
),
descr="A static declared variable, nothing at the protocol level protects it, "
"only the methods defined on ApplicationState do",
static=True,
)
reserved_global_value = beaker.ReservedGlobalStateValue(
stack_type=pt.TealType.uint64,
max_keys=32,
descr="A reserved app state variable, with 32 possible keys",
)
global_blob = beaker.GlobalStateBlob(
keys=16,
)
declared_local_value = beaker.LocalStateValue(
stack_type=pt.TealType.uint64,
default=pt.Int(1),
descr="An int stored for each account that opts in",
)
reserved_local_value = beaker.ReservedLocalStateValue(
stack_type=pt.TealType.bytes,
max_keys=8,
descr="A reserved state value, allowing 8 keys to be reserved, "
"in this case byte type",
)
local_blob = beaker.LocalStateBlob(keys=3)
app = (
beaker.Application("StateExample", state=ExampleState())
.apply(beaker.unconditional_create_approval, initialize_global_state=True)
.apply(beaker.unconditional_opt_in_approval, initialize_local_state=True)
)
@app.external
def write_local_blob(v: pt.abi.String) -> pt.Expr:
return app.state.local_blob.write(pt.Int(0), v.get())
@app.external
def read_local_blob(*, output: pt.abi.DynamicBytes) -> pt.Expr:
return output.set(
app.state.local_blob.read(
pt.Int(0), app.state.local_blob.blob.max_bytes - pt.Int(1)
)
)
@app.external
def write_global_blob(v: pt.abi.String) -> pt.Expr:
return app.state.global_blob.write(pt.Int(0), v.get())
@app.external
def read_global_blob(*, output: pt.abi.DynamicBytes) -> pt.Expr:
return output.set(
app.state.global_blob.read(
pt.Int(0), app.state.global_blob.blob.max_bytes - pt.Int(1)
)
)
@app.external
def set_global_state_val(v: pt.abi.String) -> pt.Expr:
# This will fail, since it was declared as `static` and initialized to
# a default value during create
return app.state.declared_global_value.set(v.get())
@app.external(read_only=True)
def get_global_state_val(*, output: pt.abi.String) -> pt.Expr:
return output.set(app.state.declared_global_value)
@app.external
def set_reserved_global_state_val(k: pt.abi.Uint8, v: pt.abi.Uint64) -> pt.Expr:
# Accessing the key with square brackets, accepts both Expr and an ABI type
# If the value is an Expr it must evaluate to `TealType.bytes`
# If the value is an ABI type, the `encode` method is used to convert it to bytes
return app.state.reserved_global_value[k].set(v.get())
@app.external(read_only=True)
def get_reserved_global_state_val(k: pt.abi.Uint8, *, output: pt.abi.Uint64) -> pt.Expr:
return output.set(app.state.reserved_global_value[k])
@app.external
def set_local_state_val(v: pt.abi.Uint64) -> pt.Expr:
# Accessing with `[Txn.sender()]` is redundant but
# more clear what is happening
return app.state.declared_local_value[pt.Txn.sender()].set(v.get())
@app.external
def incr_local_state_val(v: pt.abi.Uint64) -> pt.Expr:
# Omitting [Txn.sender()] just for demo purposes
return app.state.declared_local_value.increment(v.get())
@app.external(read_only=True)
def get_local_state_val(*, output: pt.abi.Uint64) -> pt.Expr:
return output.set(app.state.declared_local_value[pt.Txn.sender()])
@app.external
def set_reserved_local_state_val(k: pt.abi.Uint8, v: pt.abi.String) -> pt.Expr:
return app.state.reserved_local_value[k][pt.Txn.sender()].set(v.get())
@app.external(read_only=True)
def get_reserved_local_state_val(k: pt.abi.Uint8, *, output: pt.abi.String) -> pt.Expr:
return output.set(app.state.reserved_local_value[k][pt.Txn.sender()])