Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Boxes: Add support for Boxes #348

Merged
merged 35 commits into from
Nov 2, 2022
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
d8b805c
Make StateSchema.undictify() return an object
Jun 2, 2022
31c50a9
Make StateSchema.undictify() return an object (#340)
tzaffi Jun 2, 2022
953e596
Merge branch 'feature/box-storage' of github.com:algorand/py-algorand…
Jun 3, 2022
06ddedf
Merge remote-tracking branch 'origin/develop' into feature/box-storage
Jun 3, 2022
faa13be
CHANGELOG item for `StateSchema.undictify()` (#343)
tzaffi Jun 3, 2022
d056766
Box support for Application calls and Atomic Transaction Composer (#338)
algochoi Jun 15, 2022
bf89b22
Merge branch 'develop' into feature/box-storage
algochoi Jun 15, 2022
6083ec3
Merge branch 'develop' into feature/box-storage
algochoi Jun 21, 2022
7204e50
Format imports
algochoi Jun 21, 2022
9d6e98c
Sort imports
algochoi Jun 21, 2022
0a30487
Format import again...
algochoi Jun 21, 2022
0727844
Add back tests that were lost during merge
algochoi Jun 21, 2022
256dc72
Add Algod endpoint for GetApplicationBoxByName (#346)
algochoi Jun 30, 2022
96f4a27
Box Storage: Add GetApplicationBoxes API and cucumber steps (#359)
algochoi Jul 15, 2022
d9c0dd9
Merge branch 'develop' into feature/box-storage
algochoi Aug 2, 2022
34bc453
Add back sourcemap import in other steps
algochoi Aug 3, 2022
783514f
Merge develop into feature/box-storage (#372)
algochoi Aug 24, 2022
c83d813
Merge in files from develop
algochoi Aug 24, 2022
9ea8676
Enhancement: Merge `develop` to `feature/box-storage` (#379)
ahangsu Sep 2, 2022
c0dd456
Merge branch 'develop' into feature/box-storage
ahangsu Sep 2, 2022
346aeb3
Box support for Indexer endpoints (#366)
algochoi Sep 6, 2022
ef8be90
Enhancement: Boxes Indexer Integration test (#382)
ahangsu Sep 14, 2022
1445548
Merge branch 'develop' into feature/box-storage
ahangsu Sep 20, 2022
3c12ca2
remove unnecessary @applications tag
ahangsu Sep 20, 2022
35a1c43
Refactor dev mode sleeps
algochoi Sep 20, 2022
840b8e9
Update algosdk/v2client/algod.py
algochoi Sep 20, 2022
6f8d51c
Fix sleep method
algochoi Sep 20, 2022
1b8624d
Merge branch 'feature/box-storage' of https://github.com/algorand/py-…
algochoi Sep 20, 2022
98c0d3e
Cast int type
algochoi Sep 20, 2022
9ebde7d
Add back context to step
algochoi Sep 20, 2022
54dd40f
Minor improvements to boxes branch (#388)
jasonpaulos Sep 30, 2022
a6551ba
Merge branch 'develop' into update_again
michaeldiamant Oct 31, 2022
64780f0
Update comments
michaeldiamant Oct 31, 2022
bc03ab2
Merge pull request #393 from michaeldiamant/update_again
michaeldiamant Oct 31, 2022
8e0ccd6
Revert SDK_TESTING_BRANCH to master
michaeldiamant Nov 1, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

# BOX-STORAGE-VERSION TBD

## Changed

- `class StateSchema`'s method `undictify()` now returns a `StateSchema` object instead of a python `dict`
tzaffi marked this conversation as resolved.
Show resolved Hide resolved

tzaffi marked this conversation as resolved.
Show resolved Hide resolved
# v1.15.0

## What's Changed
Expand Down
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
UNITS = "@unit.abijson or @unit.abijson.byname or @unit.algod or @unit.algod.ledger_refactoring or @unit.applications or @unit.atc_method_args or @unit.atomic_transaction_composer or @unit.dryrun or @unit.dryrun.trace.application or @unit.feetest or @unit.indexer or @unit.indexer.ledger_refactoring or @unit.indexer.logs or @unit.offline or @unit.rekey or @unit.transactions.keyreg or @unit.responses or @unit.responses.231 or @unit.tealsign or @unit.transactions or @unit.transactions.payment or @unit.responses.unlimited_assets"
UNITS = "@unit.abijson or @unit.abijson.byname or @unit.algod or @unit.algod.ledger_refactoring or @unit.applications or @unit.applications.boxes or @unit.atc_method_args or @unit.atomic_transaction_composer or @unit.dryrun or @unit.dryrun.trace.application or @unit.feetest or @unit.indexer or @unit.indexer.ledger_refactoring or @unit.indexer.logs or @unit.offline or @unit.rekey or @unit.transactions.keyreg or @unit.responses or @unit.responses.231 or @unit.tealsign or @unit.transactions or @unit.transactions.payment or @unit.responses.unlimited_assets"
unit:
behave --tags=$(UNITS) tests -f progress2

INTEGRATIONS = "@abi or @algod or @applications or @applications.verified or @assets or @auction or @c2c or @compile or @dryrun or @dryrun.testing or @indexer or @indexer.231 or @indexer.applications or @kmd or @rekey or @send.keyregtxn or @send"
INTEGRATIONS = "@abi or @algod or @applications or @applications.verified or @applications.boxes or @assets or @auction or @c2c or @compile or @dryrun or @dryrun.testing or @indexer or @indexer.231 or @indexer.applications or @kmd or @rekey or @send.keyregtxn or @send"
integration:
behave --tags=$(INTEGRATIONS) tests -f progress2

Expand Down
8 changes: 6 additions & 2 deletions algosdk/atomic_transaction_composer.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from abc import ABC, abstractmethod
import base64
import copy
from abc import ABC, abstractmethod
from enum import IntEnum
from typing import Any, List, Optional, TypeVar, Union
from typing import Any, List, Optional, Tuple, TypeVar, Union

from algosdk import abi, error
from algosdk.abi.address_type import AddressType
Expand Down Expand Up @@ -173,6 +173,7 @@ def add_method_call(
note: bytes = None,
lease: bytes = None,
rekey_to: str = None,
boxes: List[Tuple[int, bytes]] = None,
) -> "AtomicTransactionComposer":
"""
Add a smart contract method call to this atomic group.
Expand Down Expand Up @@ -210,6 +211,7 @@ def add_method_call(
with the same sender and lease can be confirmed in this
transaction's valid rounds
rekey_to (str, optional): additionally rekey the sender to this address
boxes (list[(int, bytes)], optional): list of tuples specifying app id and key for boxes the app may access

"""
if self.status != AtomicTransactionComposerStatus.BUILDING:
Expand Down Expand Up @@ -259,6 +261,7 @@ def add_method_call(
accounts = accounts[:] if accounts else []
foreign_apps = foreign_apps[:] if foreign_apps else []
foreign_assets = foreign_assets[:] if foreign_assets else []
boxes = boxes[:] if boxes else []

app_args = []
raw_values = []
Expand Down Expand Up @@ -350,6 +353,7 @@ def add_method_call(
lease=lease,
rekey_to=rekey_to,
extra_pages=extra_pages,
boxes=boxes,
)
txn_with_signer = TransactionWithSigner(method_txn, signer)
txn_list.append(txn_with_signer)
Expand Down
94 changes: 94 additions & 0 deletions algosdk/box_reference.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
from collections import OrderedDict
from typing import List, Tuple, Union

from algosdk import encoding, error


class BoxReference:
"""
Represents a box reference with a foreign app index and the box name.

Args:
app_index (int): index of the application in the foreign app array
name (bytes): key for the box in bytes
"""

def __init__(self, app_index: int, name: bytes):
if app_index < 0:
raise ValueError(
f"Box app index must be a non-negative integer: {app_index}"
)
self.app_index = app_index
self.name = name

@staticmethod
def translate_box_reference(
ref: Tuple[int, Union[bytes, bytearray, str, int]],
foreign_apps: List[int],
this_app_id: int,
) -> "BoxReference":
# Try checking reference id and name type.
ref_id, ref_name = ref[0], encoding.encode_as_bytes(ref[1])
if not isinstance(ref_id, int):
raise TypeError("Box reference ID must be an int")

index = 0
try:
# Foreign apps start from index 1; index 0 is its own app ID.
index = foreign_apps.index(ref_id) + 1
except (ValueError, AttributeError):
# Check if the app referenced is itself after checking the
# foreign apps array (in case its own app id is in its own
# foreign apps array).
if ref_id != 0 and ref_id != this_app_id:
raise error.InvalidForeignIndexError(
f"Box ref with appId {ref_id} not in foreign-apps"
)
return BoxReference(index, ref_name)

@staticmethod
def translate_box_references(
references: List[Tuple[int, Union[bytes, bytearray, str, int]]],
foreign_apps: List[int],
this_app_id: int,
) -> List["BoxReference"]:
"""
Translates a list of tuples with app IDs and names into an array of
BoxReferences with foreign indices.

Args:
references (list[(int, bytes)]): list of tuples specifying app id
and key for boxes the app may access
foreign_apps (list[int]): list of other applications in appl call
this_app_id (int): app ID of the box being references
"""
if not references:
return []

return [
BoxReference.translate_box_reference(
ref, foreign_apps, this_app_id
)
for ref in references
]

def dictify(self):
d = dict()
if self.app_index:
d["i"] = self.app_index
if self.name:
d["n"] = self.name
od = OrderedDict(sorted(d.items()))
return od

@staticmethod
def undictify(d):
return BoxReference(
d["i"] if "i" in d else None,
d["n"] if "n" in d else None,
jasonpaulos marked this conversation as resolved.
Show resolved Hide resolved
)

def __eq__(self, other):
if not isinstance(other, BoxReference):
return False
return self.app_index == other.app_index and self.name == other.name
21 changes: 19 additions & 2 deletions algosdk/encoding.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import base64
import msgpack
from collections import OrderedDict
from typing import Union

import msgpack
from Cryptodome.Hash import SHA512
from . import transaction, error, auction, constants, future

from algosdk import auction, constants, error, future, transaction


def msgpack_encode(obj):
Expand Down Expand Up @@ -235,3 +238,17 @@ def checksum(data):
chksum = SHA512.new(truncate="256")
chksum.update(data)
return chksum.digest()


def encode_as_bytes(
e: Union[bytes, bytearray, str, int]
) -> Union[bytes, bytearray]:
"""Confirm or coerce element to bytes."""
if isinstance(e, (bytes, bytearray)):
return e
if isinstance(e, str):
return e.encode()
if isinstance(e, int):
# Uses 8 bytes, big endian to match TEAL's btoi
return e.to_bytes(8, "big") # raises for negative or too big
raise TypeError("{} is not bytes, bytearray, str, or int".format(e))
5 changes: 5 additions & 0 deletions algosdk/error.py
Original file line number Diff line number Diff line change
Expand Up @@ -222,3 +222,8 @@ def __init__(self, msg):
class AtomicTransactionComposerError(Exception):
def __init__(self, msg):
super().__init__(msg)


class InvalidForeignIndexError(Exception):
def __init__(self, msg):
super().__init__(msg)
Loading