Skip to content

Commit

Permalink
Upgrade to py-sdk v2.0 (#46)
Browse files Browse the repository at this point in the history
* upgrade to v2 sdk, trying to do stuffs

* remember py3.9

* mypy you happy

* oof my bad

* questionable refactoring
  • Loading branch information
ahangsu authored Jan 11, 2023
1 parent 5c1eeda commit 0241483
Show file tree
Hide file tree
Showing 7 changed files with 58 additions and 73 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ local-blackbox: local-blackbox-smoke integration-test

NOTEBOOK = notebooks/quadratic_factoring_game.ipynb
# assumes already ran `make pip-notebooks`
local-notebook:
local-notebook:
jupyter retro $(NOTEBOOK)

# assumes act is installed, e.g. via `brew install act`:
Expand Down
95 changes: 39 additions & 56 deletions graviton/abi_strategy.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,9 @@
TODO: Leverage Hypothesis!
"""
from abc import ABC, abstractmethod
from collections import OrderedDict
import random
import string
from typing import Callable, Dict, List, Optional, cast
from typing import List, Optional, Sequence, cast

from algosdk import abi, encoding

Expand Down Expand Up @@ -112,17 +111,6 @@ def get(self) -> PyTypes:

raise ValueError(f"Unexpected abi_type {self.abi_type}")

def map(
self,
waterfall: Dict[abi.ABIType, Callable[..., PyTypes]],
*args,
**kwargs,
) -> PyTypes:
for abi_type, call in waterfall.items():
if isinstance(self.abi_type, abi_type):
return call(*args, **kwargs)
return waterfall["DEFAULT"](*args, **kwargs)

def mutate_for_roundtrip(self, py_abi_instance: PyTypes) -> PyTypes:
def not_implemented(_):
raise NotImplementedError(f"Currently cannot handle type {self.abi_type}")
Expand All @@ -140,49 +128,42 @@ def address_logic(x):
)
)

waterfall = OrderedDict(
[
(abi.UfixedType, not_implemented),
(abi.BoolType, lambda x: not x),
(abi.UintType, lambda x: (1 << self.abi_type.bit_size) - 1 - x),
(
abi.ByteType,
lambda x: RandomABIStrategy(abi.UintType(8)).mutate_for_roundtrip(
x
),
),
(
abi.TupleType,
lambda x: [
RandomABIStrategy(child_type).mutate_for_roundtrip(x[i])
for i, child_type in enumerate(self.abi_type.child_types)
],
),
(
abi.ArrayStaticType,
lambda x: [
RandomABIStrategy(
self.abi_type.child_type
).mutate_for_roundtrip(y)
for y in x
],
),
(abi.AddressType, address_logic),
(
abi.ArrayDynamicType,
lambda x: [
RandomABIStrategy(
self.abi_type.child_type
).mutate_for_roundtrip(y)
for y in x
],
),
(abi.StringType, lambda x: "".join(reversed(x))),
("DEFAULT", unexpected_type),
if isinstance(self.abi_type, abi.UfixedType):
return not_implemented(py_abi_instance)
elif isinstance(self.abi_type, abi.BoolType):
return not py_abi_instance
elif isinstance(self.abi_type, abi.UintType):
assert isinstance(py_abi_instance, int)
return (1 << self.abi_type.bit_size) - 1 - py_abi_instance
elif isinstance(self.abi_type, abi.ByteType):
return RandomABIStrategy(abi.UintType(8)).mutate_for_roundtrip(
py_abi_instance
)
elif isinstance(self.abi_type, abi.TupleType):
assert isinstance(py_abi_instance, Sequence)
return [
RandomABIStrategy(child_type).mutate_for_roundtrip(py_abi_instance[i])
for i, child_type in enumerate(self.abi_type.child_types)
]
)

return self.map(waterfall, py_abi_instance)
elif isinstance(self.abi_type, abi.ArrayStaticType):
assert isinstance(py_abi_instance, Sequence)
return [
RandomABIStrategy(self.abi_type.child_type).mutate_for_roundtrip(y)
for y in py_abi_instance
]
elif isinstance(self.abi_type, abi.AddressType):
return address_logic(py_abi_instance)
elif isinstance(self.abi_type, abi.ArrayDynamicType):
assert isinstance(py_abi_instance, Sequence)
return [
RandomABIStrategy(self.abi_type.child_type).mutate_for_roundtrip(y)
for y in py_abi_instance
]
elif isinstance(self.abi_type, abi.StringType):
assert isinstance(py_abi_instance, str)
return "".join(reversed(py_abi_instance))
else:
return unexpected_type(py_abi_instance)


class RandomABIStrategyHalfSized(RandomABIStrategy):
Expand All @@ -199,4 +180,6 @@ def get(self) -> PyTypes:
if not isinstance(self.abi_type, abi.UintType):
return full_random

return full_random % (1 << (self.abi_type.bit_size // 2))
return cast(int, full_random) % (
1 << (cast(abi.UintType, self.abi_type).bit_size // 2)
)
19 changes: 11 additions & 8 deletions graviton/blackbox.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
from algosdk import abi
from algosdk.v2client.algod import AlgodClient
from algosdk.v2client.models import DryrunRequest
from algosdk.future.transaction import (
from algosdk.transaction import (
OnComplete,
StateSchema,
SuggestedParams,
Expand Down Expand Up @@ -725,7 +725,7 @@ def execute_one_dryrun(
args = tuple(args)

if method.returns.type != abi.Returns.VOID:
abi_return_type = method.returns.type
abi_return_type = cast(abi.ABIType, method.returns.type)

encoded_args = DryRunEncoder.encode_args(
args, abi_types=abi_argument_types, validation=validation
Expand All @@ -746,7 +746,7 @@ def execute_one_dryrun(
if verbose:
print(f"{cls}::execute_one_dryrun(): {dryrun_resp=}")
return DryRunInspector.from_single_response(
dryrun_resp, args, encoded_args, abi_type=abi_return_type
dryrun_resp, args, encoded_args, abi_type=cast(abi.ABIType, abi_return_type)
)

@classmethod
Expand Down Expand Up @@ -851,7 +851,10 @@ def argument_types(self, method: Optional[str] = None) -> List[abi.ABIType]:
if not method:
return []

return [arg.type for arg in self.contract.get_method_by_name(method).args]
return [
cast(abi.ABIType, arg.type)
for arg in self.contract.get_method_by_name(method).args
]

def generate_inputs(self, method: Optional[str]) -> List[Sequence[PyTypes]]:
"""
Expand Down Expand Up @@ -890,7 +893,7 @@ def validate_inputs(self, method: Optional[str], inputs: List[Sequence[PyTypes]]
return

arg_types = self.argument_types(method)
selector_if_needed: Optional[str] = None
selector_if_needed: Optional[bytes] = None
if self.handle_selector:
selector_if_needed = self.contract.get_method_by_name(method).get_selector()

Expand All @@ -904,7 +907,7 @@ def validate_inputs(self, method: Optional[str], inputs: List[Sequence[PyTypes]]
break

if targs[0] != selector_if_needed:
error = f"{pfx}expected selector={selector_if_needed} at arg 0 but got {targs[0]!r}"
error = f"{pfx}expected selector={selector_if_needed!r} at arg 0 but got {targs[0]!r}"
break

assert not error, error
Expand Down Expand Up @@ -1018,7 +1021,7 @@ def __init__(
txn_index: int,
args: Sequence[PyTypes],
encoded_args: List[ArgType],
abi_type: abi.ABIType = None,
abi_type: Optional[abi.ABIType] = None,
):
txns = dryrun_resp.get("txns", [])
assert txns, "Dry Run response is missing transactions"
Expand Down Expand Up @@ -1091,7 +1094,7 @@ def from_single_response(
dryrun_resp: dict,
args: Sequence[PyTypes],
encoded_args: List[ArgType],
abi_type: abi.ABIType = None,
abi_type: Optional[abi.ABIType] = None,
) -> "DryRunInspector":
error = dryrun_resp.get("error")
assert not error, f"dryrun response included the following error: [{error}]"
Expand Down
2 changes: 1 addition & 1 deletion graviton/dryrun.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import string
from typing import Any, Dict, List

from algosdk.future import transaction
from algosdk import transaction
from algosdk.encoding import encode_address
from algosdk.v2client.models import (
DryrunRequest,
Expand Down
9 changes: 4 additions & 5 deletions graviton/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
from typing import List, Optional, Sequence, Union

from algosdk.encoding import encode_address
from algosdk.future import transaction
from algosdk.v2client.models import Account, TealKeyValue
from algosdk.transaction import OnComplete
from algosdk.v2client.models.account import Account
from algosdk.v2client.models.teal_key_value import TealKeyValue

ZERO_ADDRESS = encode_address(bytes(32))

Expand All @@ -24,9 +25,7 @@ def get_run_mode(app):
on_complete = (
app.get("on_complete") if isinstance(app, dict) else app.on_complete
)
run_mode = (
"clearp" if on_complete == transaction.OnComplete.ClearStateOC else "approv"
)
run_mode = "clearp" if on_complete == OnComplete.ClearStateOC else "approv"
return run_mode


Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
author="Algorand",
author_email="[email protected]",
python_requires=">=3.9",
install_requires=["py-algorand-sdk>=1.16.1", "tabulate==0.9.0"],
install_requires=["py-algorand-sdk>=2.0.0", "tabulate==0.9.0"],
extras_require={
"development": [
"black==22.10.0",
Expand Down
2 changes: 1 addition & 1 deletion tests/integration/abi_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
from typing import Any, Dict, List, Optional, Tuple

from algosdk import abi
from algosdk.future.transaction import OnComplete
from algosdk.transaction import OnComplete

from graviton.blackbox import (
ABIContractExecutor,
Expand Down

0 comments on commit 0241483

Please sign in to comment.