From c8e17b74559b1ea74d93904ff52f54f18aaa0cd4 Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Tue, 7 Dec 2021 19:41:50 -0600 Subject: [PATCH 01/32] initial commit --- test/scripts/e2e.sh | 40 ++--- test/scripts/e2e_subs/goal/__init__.py | 1 + test/scripts/e2e_subs/goal/atomic_abi.py | 192 +++++++++++++++++++++++ test/scripts/e2e_subs/goal/goal.py | 44 ++++-- test/scripts/e2e_subs/min-balance.py | 135 ++++++++++++++++ 5 files changed, 380 insertions(+), 32 deletions(-) create mode 100644 test/scripts/e2e_subs/goal/atomic_abi.py create mode 100755 test/scripts/e2e_subs/min-balance.py diff --git a/test/scripts/e2e.sh b/test/scripts/e2e.sh index 0b4844654a..bf29f1bc34 100755 --- a/test/scripts/e2e.sh +++ b/test/scripts/e2e.sh @@ -33,11 +33,11 @@ while getopts ":c:nhi" opt; do ;; h ) echo "${HELP}" exit 0 - ;; + ;; i ) echo " Interactive session" - echo "######################################################################" - INTERACTIVE=true - ;; + echo "######################################################################" + INTERACTIVE=true + ;; \? ) echo "${HELP}" exit 2 ;; @@ -123,24 +123,26 @@ if [ -z "$E2E_TEST_FILTER" ] || [ "$E2E_TEST_FILTER" == "SCRIPTS" ]; then python3 -m venv "${TEMPDIR}/ve" . "${TEMPDIR}/ve/bin/activate" "${TEMPDIR}/ve/bin/pip3" install --upgrade pip - "${TEMPDIR}/ve/bin/pip3" install --upgrade py-algorand-sdk cryptography + "${TEMPDIR}/ve/bin/pip3" install --upgrade cryptography git+git://github.com/algorand/py-algorand-sdk + # enable remote debugging: + "${TEMPDIR}/ve/bin/pip3" install --upgrade debugpy duration "e2e client setup" if [ $INTERACTIVE ]; then - echo "********** READY **********" - echo "The test environment is now set. Run the tests using the following command on a different terminal after setting the path." - echo "" - echo "export VIRTUAL_ENV=\"${TEMPDIR}/ve\"" - echo "export PATH=\"\$VIRTUAL_ENV/bin:\$PATH\"" - echo "" - echo "${TEMPDIR}/ve/bin/python3" test/scripts/e2e_client_runner.py ${RUN_KMD_WITH_UNSAFE_SCRYPT} "$SRCROOT"/test/scripts/e2e_subs/SCRIPT_FILE_NAME - echo "" - echo "Press enter to shut down the test environment..." - read a - echo -n "deactivating..." - deactivate - echo "done" - exit + echo "********** READY **********" + echo "The test environment is now set. Run the tests using the following command on a different terminal after setting the path." + echo "" + echo "export VIRTUAL_ENV=\"${TEMPDIR}/ve\"" + echo "export PATH=\"\$VIRTUAL_ENV/bin:\$PATH\"" + echo "" + echo "${TEMPDIR}/ve/bin/python3" test/scripts/e2e_client_runner.py ${RUN_KMD_WITH_UNSAFE_SCRYPT} "$SRCROOT"/test/scripts/e2e_subs/SCRIPT_FILE_NAME + echo "" + echo "Press enter to shut down the test environment..." + read a + echo -n "deactivating..." + deactivate + echo "done" + exit fi "${TEMPDIR}/ve/bin/python3" e2e_client_runner.py ${RUN_KMD_WITH_UNSAFE_SCRYPT} "$SRCROOT"/test/scripts/e2e_subs/*.{sh,py} diff --git a/test/scripts/e2e_subs/goal/__init__.py b/test/scripts/e2e_subs/goal/__init__.py index 2835cc126c..b7bb42f26d 100755 --- a/test/scripts/e2e_subs/goal/__init__.py +++ b/test/scripts/e2e_subs/goal/__init__.py @@ -1 +1,2 @@ from .goal import * +from .atomic_abi import * diff --git a/test/scripts/e2e_subs/goal/atomic_abi.py b/test/scripts/e2e_subs/goal/atomic_abi.py new file mode 100644 index 0000000000..8ee9bb341d --- /dev/null +++ b/test/scripts/e2e_subs/goal/atomic_abi.py @@ -0,0 +1,192 @@ +import json +from typing import Callable, List, Union, Tuple +from pathlib import Path +import types + +from goal import Goal, text + +import algosdk.atomic_transaction_composer as atc +import algosdk.abi as abi +import algosdk.future.transaction as txn + + +class AtomicABI: + def __init__( + self, + goal: Goal, + app_id: int, + contract_abi_json: Union[Path, str], + sender: str, + signer: atc.TransactionSigner = None, + sp: txn.SuggestedParams = None, + ): + """ + Note: app_id will over-write whatever app_id was defined in `contract_abi_json` + + Also, I'm assuming a single signer for all the methods in the atomic transaction. + """ + self.goal = goal + self.app_id = app_id + self.contract_abi_json_path: str = None + + self.method_args: List[list] = [] + self.execution_results: atc.AtomicTransactionResponse = None + self.execution_summaries: List[MethodCallSummary] = None + + # try very hard to parse the ABI contract + cajson = text(contract_abi_json) + if cajson: + self.contract_abi_json_path = contract_abi_json + else: + cajson = contract_abi_json + cadict = json.loads(cajson) + cadict["appId"] = self.app_id + self.contract: abi.Contract = abi.Contract.from_json(json.dumps(cadict)) + + self.sender = sender + self.sp = sp + self.signer = signer + + if not self.signer: + # gonna just try and get the signer from the sender + self.signer = self.get_atxn_signer(sender) + + self.atomic_transaction_composer = atc.AtomicTransactionComposer() + + for abi_meth in self.contract.methods: + self._attach_dynamic_method_call(abi_meth.name, self._factory(abi_meth)) + + def execute_all_methods( + self, wait_rounds: int = 5 + ) -> Tuple[atc.AtomicTransactionResponse, List["MethodCallSummary"]]: + assert ( + self.execution_results is None + ), "Cannot execute this Atomic ABI twice. Instantiate a new object to execute again." + self.execution_results = self.atomic_transaction_composer.execute( + self.goal.algod, wait_rounds + ) + + self.execution_summaries = self._build_summaries() + return self.execution_results, self.execution_summaries + + def _build_summaries(self) -> List["MethodCallSummary"]: + assert ( + self.execution_results + ), "Cannot summarize before calling 'execute_all_methods()'" + summaries = [] + i = 0 + for meth in self.atomic_transaction_composer.method_dict.values(): + summaries.append( + MethodCallSummary( + meth, + self.method_args[i], + self.execution_results.abi_results[i], + ) + ) + i += 1 + return summaries + + @staticmethod + def _factory(abi_meth: abi.method.Method): + def func( + self, + *args, + sp: txn.SuggestedParams = None, + on_complete: txn.OnComplete = txn.OnComplete.NoOpOC, + note: bytes = None, + lease: bytes = None, + rekey_to: str = None, + ): + return self.add_method_call( + abi_meth, + method_args=args, + sp=sp, + on_complete=on_complete, + note=note, + lease=lease, + rekey_to=rekey_to, + ) + + return func + + def get_suggested_params(self) -> txn.SuggestedParams: + if not self.sp: + self.sp = self.goal.algod.suggested_params() + + return self.sp + + def get_atxn_signer(self, sender: str = None) -> atc.AccountTransactionSigner: + if not sender: + sender = self.sender + sk = self.goal.internal_wallet.get(sender) + if not sk: + raise Exception("Cannot create AccountTransactionSigner") + # TODO: handle querying kmd in the case that sk isn't in the internal wallet + + return atc.AccountTransactionSigner(sk) + + def get_txn_with_signer( + self, txn: txn.Transaction, signer: atc.TransactionSigner = None + ) -> atc.TransactionWithSigner: + if not signer: + signer = self.signer + + return atc.TransactionWithSigner(txn, signer) + + def add_method_call( + self, + method: abi.method.Method, + method_args: list = [], + sp: txn.SuggestedParams = None, + on_complete: txn.OnComplete = txn.OnComplete.NoOpOC, + note: bytes = None, + lease: bytes = None, + rekey_to: str = None, + ) -> "AtomicABI": + if not sp: + sp = self.get_suggested_params() + + self.atomic_transaction_composer.add_method_call( + self.app_id, + method, + self.sender, + sp, + self.signer, + method_args=method_args, + on_complete=on_complete, + note=note, + lease=lease, + rekey_to=rekey_to, + ) + + self.method_args.append(method_args) + + return self + + def _attach_dynamic_method_call(self, name: str, func: Callable) -> None: + """ + For an abi method such as "factorial(uint64)uint64" + this allows usages such as: + >>> abi.next_abi_call_factorial(5) + which will delegate to AtomicTransactionComposer with + atc.add_method_call(app_id, abi_factorial_method, ...) + """ + meth = types.MethodType(func, self) + setattr(self, self.abi_composer_name(name), meth) + + @classmethod + def abi_composer_name(cls, method_name: str) -> str: + return f"next_abi_call_{method_name}" + + +class MethodCallSummary: + def __init__(self, method: abi.Method, args: list, result: atc.ABIResult): + self.method = method + self.args = args + self.result = result + + def __str__(self) -> str: + return f"""SELECTOR<<<0x{self.method.get_selector().hex()}>>> +{self.method.get_signature()}: {self.args} + -> +{self.result.return_value}""" diff --git a/test/scripts/e2e_subs/goal/goal.py b/test/scripts/e2e_subs/goal/goal.py index 921d2c3ea2..1ddf140a8b 100755 --- a/test/scripts/e2e_subs/goal/goal.py +++ b/test/scripts/e2e_subs/goal/goal.py @@ -87,6 +87,18 @@ def __init__( self.autosend = autosend + def show_endpoint_info(self) -> dict: + return { + "algod": { + "url": self.algod.algod_address, + "auth": self.algod.algod_token, + }, + "kmd": { + "url": self.kmd.kmd_address, + "auth": self.kmd.kmd_token, + }, + } + def open_algod(self, algodata, algod_address=None): if algod_address: algod_token = algodata @@ -163,8 +175,7 @@ def send_group(self, txns, confirm=True): # out the unsigned tx if tx is sigged, logigsigged or # multisgged utxns = [ - tx if isinstance(tx, txn.Transaction) else tx.transaction - for tx in txns + tx if isinstance(tx, txn.Transaction) else tx.transaction for tx in txns ] gid = txn.calculate_group_id(utxns) for tx in txns: @@ -225,13 +236,21 @@ def finish(self, tx, send): return self.send(tx, confirm=True) return tx - def keyreg(self, sender, votekey=None, selkey=None, votefst=None, - votelst=None, votekd=None, - send=None, **kwargs): + def keyreg( + self, + sender, + votekey=None, + selkey=None, + votefst=None, + votelst=None, + votekd=None, + send=None, + **kwargs, + ): params = self.algod.suggested_params() - tx = txn.KeyregTxn(sender, params, - votekey, selkey, votefst, votelst, votekd, - **kwargs) + tx = txn.KeyregTxn( + sender, params, votekey, selkey, votefst, votelst, votekd, **kwargs + ) return self.finish(tx, send) def pay(self, sender, receiver, amt: int, send=None, **kwargs): @@ -252,9 +271,7 @@ def asset_create(self, sender, **kwargs): def axfer(self, sender, receiver, amt: int, index: int, send=None, **kwargs): params = self.algod.suggested_params() - tx = txn.AssetTransferTxn( - sender, params, receiver, amt, index, **kwargs - ) + tx = txn.AssetTransferTxn(sender, params, receiver, amt, index, **kwargs) return self.finish(tx, send) def asset_optin(self, sender, index: int, **kwargs): @@ -273,8 +290,9 @@ def coerce_schema(self, values): return values return txn.StateSchema(num_uints=values[0], num_byte_slices=values[1]) - def appl(self, sender, index: int, on_complete=txn.OnComplete.NoOpOC, - send=None, **kwargs): + def appl( + self, sender, index: int, on_complete=txn.OnComplete.NoOpOC, send=None, **kwargs + ): params = self.algod.suggested_params() local_schema = self.coerce_schema(kwargs.pop("local_schema", None)) global_schema = self.coerce_schema(kwargs.pop("global_schema", None)) diff --git a/test/scripts/e2e_subs/min-balance.py b/test/scripts/e2e_subs/min-balance.py new file mode 100755 index 0000000000..c7979c269e --- /dev/null +++ b/test/scripts/e2e_subs/min-balance.py @@ -0,0 +1,135 @@ +#!/usr/bin/env python + +from datetime import datetime +from pathlib import PurePath +import sys + +from goal import Goal, AtomicABI + + +def initialize_debugger(port): + import multiprocessing + + if multiprocessing.current_process().pid > 1: + import debugpy + + debugpy.listen(("0.0.0.0", port)) + print("Debugger is ready to be attached, press F5", flush=True) + debugpy.wait_for_client() + print("Visual Studio Code debugger is now attached", flush=True) + + +# uncomment out the following to run a remote interactive debug session: +initialize_debugger(1339) + + +script_path, WALLET = sys.argv +ppath = PurePath(script_path) + +CWD, SCRIPT = ppath.parent, ppath.name +# TEAL_DIR = CWD / "tealprogs" + +stamp = datetime.now().strftime("%Y%m%d_%H%M%S") +print(f"Running {SCRIPT} inside {CWD} @ {stamp}") + +# Initialize goal and fund a new account joe +goal = Goal(WALLET, autosend=True) + +joe = goal.new_account() +flo = goal.new_account() +print(f"Joe & Flo: {joe}, {flo}") + +txinfo, err = goal.pay(goal.account, joe, amt=50_000_000) +txinfo, err = goal.pay(goal.account, flo, amt=100_000_000) + +abi = AtomicABI( + goal, +) + +""" + ledger.NewAccount(ep.Txn.Txn.Sender, 234) + ledger.NewAccount(ep.Txn.Txn.Receiver, 123) + + testApp(t, "int 0; min_balance; int 1001; ==", ep) + // Sender makes an asset, min balance goes up + ledger.NewAsset(ep.Txn.Txn.Sender, 7, basics.AssetParams{Total: 1000}) + testApp(t, "int 0; min_balance; int 2002; ==", ep) + schemas := makeApp(1, 2, 3, 4) + ledger.NewApp(ep.Txn.Txn.Sender, 77, schemas) + // create + optin + 10 schema base + 4 ints + 6 bytes (local + // and global count b/c NewApp opts the creator in) + minb := 2*1002 + 10*1003 + 4*1004 + 6*1005 + testApp(t, fmt.Sprintf("int 0; min_balance; int %d; ==", 2002+minb), ep) + // request extra program pages, min balance increase + withepp := makeApp(1, 2, 3, 4) + withepp.ExtraProgramPages = 2 + ledger.NewApp(ep.Txn.Txn.Sender, 77, withepp) + minb += 2 * 1002 + testApp(t, fmt.Sprintf("int 0; min_balance; int %d; ==", 2002+minb), ep) + + testApp(t, "int 1; min_balance; int 1001; ==", ep) // 1 == Accounts[0] + testProg(t, "txn Accounts 1; min_balance; int 1001; ==", directRefEnabledVersion-1, + expect{2, "min_balance arg 0 wanted type uint64..."}) + testProg(t, "txn Accounts 1; min_balance; int 1001; ==", directRefEnabledVersion) + testApp(t, "txn Accounts 1; min_balance; int 1001; ==", ep) // 1 == Accounts[0] + // Receiver opts in + ledger.NewHolding(ep.Txn.Txn.Receiver, 7, 1, true) + testApp(t, "int 1; min_balance; int 2002; ==", ep) // 1 == Accounts[0] + + testApp(t, "int 2; min_balance; int 1001; ==", ep, "invalid Account reference 2") +""" + +teal = """ +#pragma version 6 + txn ApplicationID + bz end + // Pay the sender and Accounts[1]. Force the second fee to default high + itxn_begin + int pay + itxn_field TypeEnum + + txn Sender + itxn_field Receiver + + int 5 + itxn_field Amount + + int 0 + itxn_field Fee // No fee, so 2nd fee is doubled + + itxn_next + + int pay + itxn_field TypeEnum + + txn Accounts 1 + itxn_field Receiver + + int 5 + itxn_field Amount + + itxn_submit + + itxn Fee + int 2000 + == + assert + +end: + int 1 +""" + +txinfo, err = goal.app_create(joe, goal.assemble(teal)) +assert not err, err +app_id = txinfo["application-index"] +assert app_id + +# Fund the app account +txinfo, err = goal.pay(goal.account, goal.app_address(app_id), amt=400_000) +assert not err, err + + +txinfo, err = goal.app_call(joe, app_id, accounts=[goal.account]) +assert not err, err + +print(f"{os.path.basename(sys.argv[0])} OK {stamp}") From f8edde8b4371efebd5b72491016aa34fc34ee1b8 Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Wed, 8 Dec 2021 11:26:38 -0600 Subject: [PATCH 02/32] don't run the debugger on circle --- test/scripts/e2e_subs/min-balance.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/scripts/e2e_subs/min-balance.py b/test/scripts/e2e_subs/min-balance.py index c7979c269e..fba9c3d1d5 100755 --- a/test/scripts/e2e_subs/min-balance.py +++ b/test/scripts/e2e_subs/min-balance.py @@ -132,4 +132,6 @@ def initialize_debugger(port): txinfo, err = goal.app_call(joe, app_id, accounts=[goal.account]) assert not err, err -print(f"{os.path.basename(sys.argv[0])} OK {stamp}") + +stamp = datetime.now().strftime("%Y%m%d_%H%M%S") +print(f"Running {SCRIPT} inside {CWD} @ {stamp}") From ee5451c0a22c3dcde0934b194adf455032b2a988 Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Wed, 8 Dec 2021 23:28:05 -0600 Subject: [PATCH 03/32] can query TEAL for stateful min_balance. Next up: get algod to do the same thing --- test/scripts/e2e_subs/goal/atomic_abi.py | 79 ++++++++++++-- .../{min-balance.py => min_balance.py} | 78 ++++++++++++-- .../e2e_subs/tealprogs/abi-min_balance.json | 69 ++++++++++++ .../e2e_subs/tealprogs/abi-min_balance.teal | 102 ++++++++++++++++++ 4 files changed, 310 insertions(+), 18 deletions(-) rename test/scripts/e2e_subs/{min-balance.py => min_balance.py} (58%) create mode 100644 test/scripts/e2e_subs/tealprogs/abi-min_balance.json create mode 100644 test/scripts/e2e_subs/tealprogs/abi-min_balance.teal diff --git a/test/scripts/e2e_subs/goal/atomic_abi.py b/test/scripts/e2e_subs/goal/atomic_abi.py index 8ee9bb341d..4a84c2e4fa 100644 --- a/test/scripts/e2e_subs/goal/atomic_abi.py +++ b/test/scripts/e2e_subs/goal/atomic_abi.py @@ -1,5 +1,5 @@ import json -from typing import Callable, List, Union, Tuple +from typing import Callable, Dict, List, Union, Tuple from pathlib import Path import types @@ -11,6 +11,8 @@ class AtomicABI: + CALL_TWICE_ERROR = "Cannot execute this Atomic ABI twice. Instantiate a new object to execute again." + def __init__( self, goal: Goal, @@ -27,9 +29,13 @@ def __init__( """ self.goal = goal self.app_id = app_id + self.contract_abi_json = contract_abi_json # for cloning only self.contract_abi_json_path: str = None self.method_args: List[list] = [] + self.sigs2selector: Dict[str, str] = {} + self.handle2meth: Dict[str, dict] = {} + self.execution_results: atc.AtomicTransactionResponse = None self.execution_summaries: List[MethodCallSummary] = None @@ -54,25 +60,76 @@ def __init__( self.atomic_transaction_composer = atc.AtomicTransactionComposer() for abi_meth in self.contract.methods: - self._attach_dynamic_method_call(abi_meth.name, self._factory(abi_meth)) + handle, meth_name, meth = self._attach_dynamic_method_call( + abi_meth.name, self._amc_factory(abi_meth) + ) + signature = abi_meth.get_signature() + selector = "0x" + abi_meth.get_selector().hex() + self.sigs2selector[signature] = selector + self.handle2meth[handle] = { + "signature": signature, + "selector": selector, + "abi_meth": abi_meth, + "adder_meth_name": meth_name, + "adder_meth": meth, + } + + @classmethod + def factory(cls, obj): + return cls( + obj.goal, + obj.app_id, + obj.contract_abi_json, + obj.sender, + signer=obj.signer, + sp=obj.sp, + ) - def execute_all_methods( + def clone(self): + return self.factory(self) + + def execute_atomic_group( self, wait_rounds: int = 5 ) -> Tuple[atc.AtomicTransactionResponse, List["MethodCallSummary"]]: - assert ( - self.execution_results is None - ), "Cannot execute this Atomic ABI twice. Instantiate a new object to execute again." + assert self.execution_results is None, self.CALL_TWICE_ERROR self.execution_results = self.atomic_transaction_composer.execute( self.goal.algod, wait_rounds ) - self.execution_summaries = self._build_summaries() return self.execution_results, self.execution_summaries + def execute_singleton( + self, + method_handle: str, + method_args: list, + wait_rounds: int = 5, + sp: txn.SuggestedParams = None, + on_complete: txn.OnComplete = txn.OnComplete.NoOpOC, + note: bytes = None, + lease: bytes = None, + rekey_to: str = None, + ) -> Tuple[atc.AtomicTransactionResponse, "MethodCallSummary"]: + assert self.execution_results is None, self.CALL_TWICE_ERROR + abi_meth = self.handle2meth[method_handle]["abi_meth"] + self.add_method_call( + abi_meth, + method_args, + sp=sp, + on_complete=on_complete, + note=note, + lease=lease, + rekey_to=rekey_to, + ) + _, s = self.execute_atomic_group(wait_rounds=wait_rounds) + return s[0].result.return_value + + def dump_selectors(self) -> str: + return json.dumps(self.sigs2selector, indent=4, sort_keys=True) + def _build_summaries(self) -> List["MethodCallSummary"]: assert ( self.execution_results - ), "Cannot summarize before calling 'execute_all_methods()'" + ), "Cannot summarize before calling 'execute_atomic_group()'" summaries = [] i = 0 for meth in self.atomic_transaction_composer.method_dict.values(): @@ -87,7 +144,7 @@ def _build_summaries(self) -> List["MethodCallSummary"]: return summaries @staticmethod - def _factory(abi_meth: abi.method.Method): + def _amc_factory(abi_meth: abi.method.Method): def func( self, *args, @@ -172,7 +229,9 @@ def _attach_dynamic_method_call(self, name: str, func: Callable) -> None: atc.add_method_call(app_id, abi_factorial_method, ...) """ meth = types.MethodType(func, self) - setattr(self, self.abi_composer_name(name), meth) + meth_name = self.abi_composer_name(name) + setattr(self, meth_name, meth) + return name, meth_name, meth @classmethod def abi_composer_name(cls, method_name: str) -> str: diff --git a/test/scripts/e2e_subs/min-balance.py b/test/scripts/e2e_subs/min_balance.py similarity index 58% rename from test/scripts/e2e_subs/min-balance.py rename to test/scripts/e2e_subs/min_balance.py index fba9c3d1d5..0e6653083e 100755 --- a/test/scripts/e2e_subs/min-balance.py +++ b/test/scripts/e2e_subs/min_balance.py @@ -4,6 +4,8 @@ from pathlib import PurePath import sys +import algosdk.future.transaction as txn + from goal import Goal, AtomicABI @@ -20,31 +22,91 @@ def initialize_debugger(port): # uncomment out the following to run a remote interactive debug session: -initialize_debugger(1339) +initialize_debugger(1330) script_path, WALLET = sys.argv ppath = PurePath(script_path) CWD, SCRIPT = ppath.parent, ppath.name -# TEAL_DIR = CWD / "tealprogs" +TEAL_DIR = CWD / "tealprogs" stamp = datetime.now().strftime("%Y%m%d_%H%M%S") print(f"Running {SCRIPT} inside {CWD} @ {stamp}") # Initialize goal and fund a new account joe -goal = Goal(WALLET, autosend=True) +goal = Goal(WALLET, autosend=False) joe = goal.new_account() flo = goal.new_account() print(f"Joe & Flo: {joe}, {flo}") -txinfo, err = goal.pay(goal.account, joe, amt=50_000_000) -txinfo, err = goal.pay(goal.account, flo, amt=100_000_000) +txinfo, err = goal.pay(goal.account, joe, amt=50_000_000, send=True) +txinfo, err = goal.pay(goal.account, flo, amt=100_000_000, send=True) + +# App create +approval_teal_path = TEAL_DIR / "abi-min_balance.teal" +print(f"approval_teal_path: {approval_teal_path}") +approval_teal = goal.assemble(approval_teal_path) + +txinfo, err = goal.app_create(joe, approval_teal, send=True) +print(f"txinfo for create request: {txinfo}") +app_id = txinfo["application-index"] + +abi = AtomicABI(goal, app_id, TEAL_DIR / "abi-min_balance.json", flo) + +# Dummy complement call (for now) +abi.next_abi_call_complement(bytes.fromhex("00ff00ff")) +executed_methods, summary = abi.execute_atomic_group() + + +# def min_balances(abi, joe, flo): +# abi = abi.clone() + +# joe_sig = abi.get_atxn_signer(sender=joe) +# flo_sig = abi.get_atxn_signer(sender=flo) + +# joe_pymt = txn.PaymentTxn(joe, abi.get_suggested_params(), flo, 10_000) +# joe_tx_sig = abi.get_txn_with_signer(joe_pymt, signer=joe_sig) + +# flo_pymt = txn.PaymentTxn(flo, abi.get_suggested_params(), joe, 10_000) +# flo_tx_sig = abi.get_txn_with_signer(flo_pymt, signer=flo_sig) + +# abi.next_abi_call_sender_min_balance(joe_tx_sig) +# abi.next_abi_call_sender_min_balance(flo_tx_sig) +# _, summaries = abi.execute_atomic_group() +# return { +# "joe_minb": summaries[0].result.return_value, +# "flo_minb": summaries[1].result.return_value, +# } + + +def min_balance(abi, sender, receiver): + abi = abi.clone() + + sender_sig = abi.get_atxn_signer(sender=sender) + sender_pymt = txn.PaymentTxn(sender, abi.get_suggested_params(), receiver, 10_000) + sender_tx_sig = abi.get_txn_with_signer(sender_pymt, signer=sender_sig) + + return abi.execute_singleton("sender_min_balance", method_args=[sender_tx_sig]) + + +joe_minb = min_balance(abi, joe, flo) +flo_minb = min_balance(abi, flo, joe) + +x = 42 +# abi.next_abi_call_add(29, 13) +# abi.next_abi_call_sub(3, 1) +# abi.next_abi_call_div(4, 2) +# abi.next_abi_call_mul(3, 2) +# abi.next_abi_call_qrem(27, 5) +# abi.next_abi_call_reverse("desrever yllufsseccus") +# abi.next_abi_call_txntest(10_000, txn_sgn, 1000) + -abi = AtomicABI( - goal, -) +# flo_mb1 = min_balance(flo) +# joe_mb1 = min_balance(joe) +x = 42 """ ledger.NewAccount(ep.Txn.Txn.Sender, 234) diff --git a/test/scripts/e2e_subs/tealprogs/abi-min_balance.json b/test/scripts/e2e_subs/tealprogs/abi-min_balance.json new file mode 100644 index 0000000000..47d2be090b --- /dev/null +++ b/test/scripts/e2e_subs/tealprogs/abi-min_balance.json @@ -0,0 +1,69 @@ +{ + "name": "opCodes", + "appId": null, + "methods": [ + { + "name": "sender_min_balance", + "desc": "Calculate the minimum balance of sender for referenced pay txn arg", + "args": [ + { + "type": "pay" + } + ], + "returns": { + "type": "uint64" + } + }, + { + "name": "complement", + "desc": "The complement (aka b~) of arg0 viewed as a bitstring", + "args": [ + { + "type": "byte[]" + } + ], + "returns": { + "type": "byte[]" + } + }, + { + "name": "base64_decode", + "desc": "Decode base64 arg1 using the encoding defined by arg0 (either 'URLEncoding' or 'StdEncoding') ", + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "returns": { + "type": "string" + } + }, + { + "name": "_optIn", + "desc": "just opt in", + "args": [ + { + "type": "uint64" + } + ], + "returns": { + "type": "uint64" + } + }, + { + "name": "_closeOut", + "desc": "just close out", + "args": [ + { + "type": "uint64" + } + ], + "returns": { + "type": "uint64" + } + } + ] +} \ No newline at end of file diff --git a/test/scripts/e2e_subs/tealprogs/abi-min_balance.teal b/test/scripts/e2e_subs/tealprogs/abi-min_balance.teal new file mode 100644 index 0000000000..0f2ae16339 --- /dev/null +++ b/test/scripts/e2e_subs/tealprogs/abi-min_balance.teal @@ -0,0 +1,102 @@ +#pragma version 6 + // TODO - some explanation + // TODO - comply with best practices (optin, delete, etc...) + txn ApplicationID + bz handle_no_questions_asked + + txn OnCompletion + int NoOp + == + bnz handle_noop + err // TODO - handle more than just NoOp's + +handle_noop: + txna ApplicationArgs 0 + byte 0x80630032 // _closeOut(uint64)uint64 + == + bnz handle_no_questions_asked + + txna ApplicationArgs 0 + byte 0x9b122fc1 // _optIn(uint64)uint64 + == + bnz handle_no_questions_asked + + txn ApplicationArgs 0 + byte 0x4f30c3ce // base64_decode(string,string)string + == + bnz handle_base64_decode + + txn ApplicationArgs 0 + byte 0xd363f563 // complement(byte[])byte[] (tilde "~"" is too exotic for official signature) + == + bnz handle_b~ + + txn ApplicationArgs 0 + byte 0xa9c9f612 // sender_min_balance(pay)uint64 + == + bnz handle_min_balance + + err + +handle_no_questions_asked: + int 1 + b return_uint64 + +// opCodes + +handle_min_balance: + txn Accounts 0 + min_balance + b return_uint64 + +handle_base64_decode: +handle_b~: + byte "abcde" + b return_bytes + +handle_base64URL_decode: + callsub extract_abi_string_arg1 + base64_decode URLAlph + b return_bytes + +handle_base64Std_decode: + callsub extract_abi_string_arg1 + base64_decode StdAlph + b return_bytes + +extract_abi_string_arg1: + txna ApplicationArgs 1 + extract 2 0 + retsub + +// Return handling based on type + +return_2_uint64: + itob + swap + itob + swap + b end_return + +return_bytes: + dup + len + itob + extract 6 2 + swap + concat + b end_return + +return_uint64: + itob + b end_return + +// ABI return prefix and logging + +end_return: + byte 0x151f7c75 + swap + concat + log + int 1 + return From 7e4daef761fc83165b5081c7be7992b550b5af1b Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Thu, 9 Dec 2021 12:24:23 -0600 Subject: [PATCH 04/32] adding facade, but no content --- cmd/goal/account.go | 2 + daemon/algod/api/algod.oas2.json | 7 +- daemon/algod/api/algod.oas3.yml | 5 + .../api/server/v2/generated/private/routes.go | 152 ++++---- .../api/server/v2/generated/private/types.go | 3 + .../algod/api/server/v2/generated/routes.go | 345 +++++++++--------- daemon/algod/api/server/v2/generated/types.go | 3 + daemon/algod/api/server/v2/test/helpers.go | 1 + test/scripts/e2e_subs/min_balance.sh | 28 ++ 9 files changed, 297 insertions(+), 249 deletions(-) create mode 100755 test/scripts/e2e_subs/min_balance.sh diff --git a/cmd/goal/account.go b/cmd/goal/account.go index 7d20af38f3..664f750f95 100644 --- a/cmd/goal/account.go +++ b/cmd/goal/account.go @@ -693,6 +693,8 @@ func printAccountInfo(client libgoal.Client, address string, account generatedV2 fmt.Fprintf(report, "\tID %d, local state used %d/%d uints, %d/%d byte slices\n", localState.Id, usedInts, allocatedInts, usedBytes, allocatedBytes) } + fmt.Fprintf(report, "Minimum Balance:\t%v microAlgos\n", account.MinBalance) + if hasError { fmt.Fprint(os.Stderr, errorReport.String()) } diff --git a/daemon/algod/api/algod.oas2.json b/daemon/algod/api/algod.oas2.json index 0eb127d8cb..bfd8587ad5 100644 --- a/daemon/algod/api/algod.oas2.json +++ b/daemon/algod/api/algod.oas2.json @@ -1354,7 +1354,8 @@ "pending-rewards", "amount-without-pending-rewards", "rewards", - "status" + "status", + "min-balance" ], "properties": { "address": { @@ -1365,6 +1366,10 @@ "description": "\\[algo\\] total number of MicroAlgos in the account", "type": "integer" }, + "min-balance": { + "description": "\\[algo\\] total number of MicroAlgos needed to allow transacting from account", + "type": "integer" + }, "amount-without-pending-rewards": { "description": "specifies the amount of MicroAlgos in the account, without the pending rewards.", "type": "integer" diff --git a/daemon/algod/api/algod.oas3.yml b/daemon/algod/api/algod.oas3.yml index b302823104..6e81750d64 100644 --- a/daemon/algod/api/algod.oas3.yml +++ b/daemon/algod/api/algod.oas3.yml @@ -726,6 +726,10 @@ }, "type": "array" }, + "min-balance": { + "description": "\\[algo\\] total number of MicroAlgos needed to allow transacting from account", + "type": "integer" + }, "participation": { "$ref": "#/components/schemas/AccountParticipation" }, @@ -763,6 +767,7 @@ "address", "amount", "amount-without-pending-rewards", + "min-balance", "pending-rewards", "rewards", "round", diff --git a/daemon/algod/api/server/v2/generated/private/routes.go b/daemon/algod/api/server/v2/generated/private/routes.go index e294ea1e75..1e3a72aaa5 100644 --- a/daemon/algod/api/server/v2/generated/private/routes.go +++ b/daemon/algod/api/server/v2/generated/private/routes.go @@ -337,82 +337,82 @@ var swaggerSpec = []string{ "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", } // GetSwagger returns the Swagger specification corresponding to the generated code diff --git a/daemon/algod/api/server/v2/generated/private/types.go b/daemon/algod/api/server/v2/generated/private/types.go index 78137ac3ea..5e10e78d89 100644 --- a/daemon/algod/api/server/v2/generated/private/types.go +++ b/daemon/algod/api/server/v2/generated/private/types.go @@ -49,6 +49,9 @@ type Account struct { // Note: the raw account uses `map[int] -> Asset` for this type. CreatedAssets *[]Asset `json:"created-assets,omitempty"` + // \[algo\] total number of MicroAlgos needed to allow transacting from account + MinBalance uint64 `json:"min-balance"` + // AccountParticipation describes the parameters used by this account in consensus protocol. Participation *AccountParticipation `json:"participation,omitempty"` diff --git a/daemon/algod/api/server/v2/generated/routes.go b/daemon/algod/api/server/v2/generated/routes.go index 2962a328a6..21187c4d54 100644 --- a/daemon/algod/api/server/v2/generated/routes.go +++ b/daemon/algod/api/server/v2/generated/routes.go @@ -617,178 +617,179 @@ func RegisterHandlers(router interface { var swaggerSpec = []string{ "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", - "HcEdLqVk55g78cPl/wsAAP//K7GmSonxAAA=", + "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", + "gWEPF/IAAA==", } // GetSwagger returns the Swagger specification corresponding to the generated code diff --git a/daemon/algod/api/server/v2/generated/types.go b/daemon/algod/api/server/v2/generated/types.go index b9066ba0ec..b3dafaf6b1 100644 --- a/daemon/algod/api/server/v2/generated/types.go +++ b/daemon/algod/api/server/v2/generated/types.go @@ -49,6 +49,9 @@ type Account struct { // Note: the raw account uses `map[int] -> Asset` for this type. CreatedAssets *[]Asset `json:"created-assets,omitempty"` + // \[algo\] total number of MicroAlgos needed to allow transacting from account + MinBalance uint64 `json:"min-balance"` + // AccountParticipation describes the parameters used by this account in consensus protocol. Participation *AccountParticipation `json:"participation,omitempty"` diff --git a/daemon/algod/api/server/v2/test/helpers.go b/daemon/algod/api/server/v2/test/helpers.go index 31e6053a60..dda7357836 100644 --- a/daemon/algod/api/server/v2/test/helpers.go +++ b/daemon/algod/api/server/v2/test/helpers.go @@ -73,6 +73,7 @@ var poolAddrResponseGolden = generatedV2.AccountResponse{ AppsLocalState: &appLocalStates, AppsTotalSchema: &appsTotalSchema, CreatedApps: &appCreatedApps, + MinBalance: 100000, } var txnPoolGolden = make([]transactions.SignedTxn, 2) diff --git a/test/scripts/e2e_subs/min_balance.sh b/test/scripts/e2e_subs/min_balance.sh new file mode 100755 index 0000000000..94c58b73f7 --- /dev/null +++ b/test/scripts/e2e_subs/min_balance.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +set -e +set -x +set -o pipefail +export SHELLOPTS + +WALLET=$1 + +echo "NETDIR=$NETDIR" + +# Directory of this bash program +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" + +gcmd="goal -w ${WALLET}" + +ACCOUNT=$(${gcmd} account list|awk '{ print $3 }') + +echo `$gcmd account list` +echo $ACCOUNT + +echo `$gcmd account balance -a $ACCOUNT` + +echo `$gcmd account info -a $ACCOUNT` + +echo `$gcmd account export -a $ACCOUNT` + +exit 1 \ No newline at end of file From 5dafabb2d611a0f630bb46cf698e8aeb58d51949 Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Thu, 9 Dec 2021 12:33:37 -0600 Subject: [PATCH 05/32] revert --- test/scripts/e2e.sh | 40 +++++++++++++++++++--------------------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/test/scripts/e2e.sh b/test/scripts/e2e.sh index bf29f1bc34..0b4844654a 100755 --- a/test/scripts/e2e.sh +++ b/test/scripts/e2e.sh @@ -33,11 +33,11 @@ while getopts ":c:nhi" opt; do ;; h ) echo "${HELP}" exit 0 - ;; + ;; i ) echo " Interactive session" - echo "######################################################################" - INTERACTIVE=true - ;; + echo "######################################################################" + INTERACTIVE=true + ;; \? ) echo "${HELP}" exit 2 ;; @@ -123,26 +123,24 @@ if [ -z "$E2E_TEST_FILTER" ] || [ "$E2E_TEST_FILTER" == "SCRIPTS" ]; then python3 -m venv "${TEMPDIR}/ve" . "${TEMPDIR}/ve/bin/activate" "${TEMPDIR}/ve/bin/pip3" install --upgrade pip - "${TEMPDIR}/ve/bin/pip3" install --upgrade cryptography git+git://github.com/algorand/py-algorand-sdk - # enable remote debugging: - "${TEMPDIR}/ve/bin/pip3" install --upgrade debugpy + "${TEMPDIR}/ve/bin/pip3" install --upgrade py-algorand-sdk cryptography duration "e2e client setup" if [ $INTERACTIVE ]; then - echo "********** READY **********" - echo "The test environment is now set. Run the tests using the following command on a different terminal after setting the path." - echo "" - echo "export VIRTUAL_ENV=\"${TEMPDIR}/ve\"" - echo "export PATH=\"\$VIRTUAL_ENV/bin:\$PATH\"" - echo "" - echo "${TEMPDIR}/ve/bin/python3" test/scripts/e2e_client_runner.py ${RUN_KMD_WITH_UNSAFE_SCRYPT} "$SRCROOT"/test/scripts/e2e_subs/SCRIPT_FILE_NAME - echo "" - echo "Press enter to shut down the test environment..." - read a - echo -n "deactivating..." - deactivate - echo "done" - exit + echo "********** READY **********" + echo "The test environment is now set. Run the tests using the following command on a different terminal after setting the path." + echo "" + echo "export VIRTUAL_ENV=\"${TEMPDIR}/ve\"" + echo "export PATH=\"\$VIRTUAL_ENV/bin:\$PATH\"" + echo "" + echo "${TEMPDIR}/ve/bin/python3" test/scripts/e2e_client_runner.py ${RUN_KMD_WITH_UNSAFE_SCRYPT} "$SRCROOT"/test/scripts/e2e_subs/SCRIPT_FILE_NAME + echo "" + echo "Press enter to shut down the test environment..." + read a + echo -n "deactivating..." + deactivate + echo "done" + exit fi "${TEMPDIR}/ve/bin/python3" e2e_client_runner.py ${RUN_KMD_WITH_UNSAFE_SCRYPT} "$SRCROOT"/test/scripts/e2e_subs/*.{sh,py} From 4ed06175c824f19800be2e66fed324eac457f263 Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Thu, 9 Dec 2021 12:36:12 -0600 Subject: [PATCH 06/32] remote debugging --- test/scripts/e2e.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/scripts/e2e.sh b/test/scripts/e2e.sh index 0b4844654a..1df23e0b88 100755 --- a/test/scripts/e2e.sh +++ b/test/scripts/e2e.sh @@ -124,6 +124,8 @@ if [ -z "$E2E_TEST_FILTER" ] || [ "$E2E_TEST_FILTER" == "SCRIPTS" ]; then . "${TEMPDIR}/ve/bin/activate" "${TEMPDIR}/ve/bin/pip3" install --upgrade pip "${TEMPDIR}/ve/bin/pip3" install --upgrade py-algorand-sdk cryptography + # enable remote debugging: + "${TEMPDIR}/ve/bin/pip3" install --upgrade debugpy duration "e2e client setup" if [ $INTERACTIVE ]; then From 88544cf6983dab7988caf704c2c5c74e78b96be8 Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Thu, 9 Dec 2021 12:40:37 -0600 Subject: [PATCH 07/32] add get_endpoint_info to e2e python Goal --- test/scripts/e2e_subs/goal/goal.py | 44 +++++++++--------------------- 1 file changed, 13 insertions(+), 31 deletions(-) diff --git a/test/scripts/e2e_subs/goal/goal.py b/test/scripts/e2e_subs/goal/goal.py index 1ddf140a8b..921d2c3ea2 100755 --- a/test/scripts/e2e_subs/goal/goal.py +++ b/test/scripts/e2e_subs/goal/goal.py @@ -87,18 +87,6 @@ def __init__( self.autosend = autosend - def show_endpoint_info(self) -> dict: - return { - "algod": { - "url": self.algod.algod_address, - "auth": self.algod.algod_token, - }, - "kmd": { - "url": self.kmd.kmd_address, - "auth": self.kmd.kmd_token, - }, - } - def open_algod(self, algodata, algod_address=None): if algod_address: algod_token = algodata @@ -175,7 +163,8 @@ def send_group(self, txns, confirm=True): # out the unsigned tx if tx is sigged, logigsigged or # multisgged utxns = [ - tx if isinstance(tx, txn.Transaction) else tx.transaction for tx in txns + tx if isinstance(tx, txn.Transaction) else tx.transaction + for tx in txns ] gid = txn.calculate_group_id(utxns) for tx in txns: @@ -236,21 +225,13 @@ def finish(self, tx, send): return self.send(tx, confirm=True) return tx - def keyreg( - self, - sender, - votekey=None, - selkey=None, - votefst=None, - votelst=None, - votekd=None, - send=None, - **kwargs, - ): + def keyreg(self, sender, votekey=None, selkey=None, votefst=None, + votelst=None, votekd=None, + send=None, **kwargs): params = self.algod.suggested_params() - tx = txn.KeyregTxn( - sender, params, votekey, selkey, votefst, votelst, votekd, **kwargs - ) + tx = txn.KeyregTxn(sender, params, + votekey, selkey, votefst, votelst, votekd, + **kwargs) return self.finish(tx, send) def pay(self, sender, receiver, amt: int, send=None, **kwargs): @@ -271,7 +252,9 @@ def asset_create(self, sender, **kwargs): def axfer(self, sender, receiver, amt: int, index: int, send=None, **kwargs): params = self.algod.suggested_params() - tx = txn.AssetTransferTxn(sender, params, receiver, amt, index, **kwargs) + tx = txn.AssetTransferTxn( + sender, params, receiver, amt, index, **kwargs + ) return self.finish(tx, send) def asset_optin(self, sender, index: int, **kwargs): @@ -290,9 +273,8 @@ def coerce_schema(self, values): return values return txn.StateSchema(num_uints=values[0], num_byte_slices=values[1]) - def appl( - self, sender, index: int, on_complete=txn.OnComplete.NoOpOC, send=None, **kwargs - ): + def appl(self, sender, index: int, on_complete=txn.OnComplete.NoOpOC, + send=None, **kwargs): params = self.algod.suggested_params() local_schema = self.coerce_schema(kwargs.pop("local_schema", None)) global_schema = self.coerce_schema(kwargs.pop("global_schema", None)) From d0cacfe1c12a2b5f156dd0a33b8080a39e7ac1ce Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Thu, 9 Dec 2021 12:41:47 -0600 Subject: [PATCH 08/32] add get_endpoint_info to e2e python Goal --- test/scripts/e2e_subs/goal/goal.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/test/scripts/e2e_subs/goal/goal.py b/test/scripts/e2e_subs/goal/goal.py index 921d2c3ea2..6f6fe6f145 100755 --- a/test/scripts/e2e_subs/goal/goal.py +++ b/test/scripts/e2e_subs/goal/goal.py @@ -112,6 +112,18 @@ def open_kmd(self, algodata, kmd_address=None): kmd_address = "http://" + net return algosdk.kmd.KMDClient(kmd_token, kmd_address) + def get_endpoint_info(self) -> dict: + return { + "algod": { + "url": self.algod.algod_address, + "auth": self.algod.algod_token, + }, + "kmd": { + "url": self.kmd.kmd_address, + "auth": self.kmd.kmd_token, + }, + } + def open_wallet(self, name): if name: self.wallet_name = name From 1f1fc88371d23cf8d071de431ccd0385e24ca7fc Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Thu, 9 Dec 2021 14:10:58 -0600 Subject: [PATCH 09/32] testing --- test/scripts/e2e_subs/min_balance.py | 1 + 1 file changed, 1 insertion(+) diff --git a/test/scripts/e2e_subs/min_balance.py b/test/scripts/e2e_subs/min_balance.py index 0e6653083e..384d77429e 100755 --- a/test/scripts/e2e_subs/min_balance.py +++ b/test/scripts/e2e_subs/min_balance.py @@ -36,6 +36,7 @@ def initialize_debugger(port): # Initialize goal and fund a new account joe goal = Goal(WALLET, autosend=False) +rest_endpoints = goal.get_endpoint_info() joe = goal.new_account() flo = goal.new_account() From bd90ea6a36c386739a2b60482be3a443813d2d8d Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Fri, 10 Dec 2021 03:54:35 -0600 Subject: [PATCH 10/32] tests basically passing --- cmd/tealdbg/local_test.go | 2 +- daemon/algod/api/server/v2/account.go | 3 +- daemon/algod/api/server/v2/account_test.go | 4 +- daemon/algod/api/server/v2/handlers.go | 12 +- test/scripts/e2e_subs/goal/atomic_abi.py | 56 ++-- test/scripts/e2e_subs/min_balance.py | 289 +++++++++++---------- 6 files changed, 194 insertions(+), 172 deletions(-) diff --git a/cmd/tealdbg/local_test.go b/cmd/tealdbg/local_test.go index d78c402e80..75109f9774 100644 --- a/cmd/tealdbg/local_test.go +++ b/cmd/tealdbg/local_test.go @@ -984,7 +984,7 @@ func TestLocalBalanceAdapterIndexer(t *testing.T) { case strings.HasPrefix(r.URL.Path, accountPath): w.WriteHeader(200) if r.URL.Path[len(accountPath):] == brs.Addr.String() { - account, err := v2.AccountDataToAccount(brs.Addr.String(), &brs.AccountData, map[basics.AssetIndex]string{}, 100, basics.MicroAlgos{Raw: 0}) + account, err := v2.AccountDataToAccount(brs.Addr.String(), &brs.AccountData, map[basics.AssetIndex]string{}, 100, basics.MicroAlgos{Raw: 0}, basics.MicroAlgos{Raw: 100000}) a.NoError(err) accountResponse := AccountIndexerResponse{Account: account, CurrentRound: 100} response, err := json.Marshal(accountResponse) diff --git a/daemon/algod/api/server/v2/account.go b/daemon/algod/api/server/v2/account.go index 2187a1068b..2493fde6c2 100644 --- a/daemon/algod/api/server/v2/account.go +++ b/daemon/algod/api/server/v2/account.go @@ -30,7 +30,7 @@ import ( // AccountDataToAccount converts basics.AccountData to v2.generated.Account func AccountDataToAccount( address string, record *basics.AccountData, assetsCreators map[basics.AssetIndex]string, - lastRound basics.Round, amountWithoutPendingRewards basics.MicroAlgos, + lastRound basics.Round, amountWithoutPendingRewards basics.MicroAlgos, minBalance basics.MicroAlgos, ) (generated.Account, error) { assets := make([]generated.AssetHolding, 0, len(record.Assets)) @@ -126,6 +126,7 @@ func AccountDataToAccount( AppsLocalState: &appsLocalState, AppsTotalSchema: &totalAppSchema, AppsTotalExtraPages: numOrNil(totalExtraPages), + MinBalance: minBalance.Raw, }, nil } diff --git a/daemon/algod/api/server/v2/account_test.go b/daemon/algod/api/server/v2/account_test.go index f7dd96d807..a2ccce0b72 100644 --- a/daemon/algod/api/server/v2/account_test.go +++ b/daemon/algod/api/server/v2/account_test.go @@ -102,7 +102,7 @@ func TestAccount(t *testing.T) { b := a.WithUpdatedRewards(proto, 100) addr := basics.Address{}.String() - conv, err := AccountDataToAccount(addr, &b, map[basics.AssetIndex]string{}, round, a.MicroAlgos) + conv, err := AccountDataToAccount(addr, &b, map[basics.AssetIndex]string{}, round, a.MicroAlgos, basics.MicroAlgos{Raw: 100000}) require.NoError(t, err) require.Equal(t, addr, conv.Address) require.Equal(t, b.MicroAlgos.Raw, conv.Amount) @@ -196,7 +196,7 @@ func TestAccount(t *testing.T) { // convert the same account a few more times to make sure we always // produce the same generated.Account for i := 0; i < 10; i++ { - anotherConv, err := AccountDataToAccount(addr, &b, map[basics.AssetIndex]string{}, round, a.MicroAlgos) + anotherConv, err := AccountDataToAccount(addr, &b, map[basics.AssetIndex]string{}, round, a.MicroAlgos, basics.MicroAlgos{Raw: 100000}) require.NoError(t, err) require.Equal(t, protocol.EncodeJSON(conv), protocol.EncodeJSON(anotherConv)) diff --git a/daemon/algod/api/server/v2/handlers.go b/daemon/algod/api/server/v2/handlers.go index da47ce3508..0f7b0661bb 100644 --- a/daemon/algod/api/server/v2/handlers.go +++ b/daemon/algod/api/server/v2/handlers.go @@ -238,6 +238,14 @@ func (v2 *Handlers) AccountInformation(ctx echo.Context, address string, params if err != nil { return internalError(ctx, err, errFailedLookingUpLedger, v2.Log) } + block, _, err := myLedger.BlockCert(basics.Round(lastRound)) + if err != nil { + return internalError(ctx, err, errFailedLookingUpLedger, v2.Log) + } + consensus, ok := config.Consensus[block.CurrentProtocol] + if !ok { + return notFound(ctx, errors.New(errInternalFailure), errInternalFailure, v2.Log) + } if handle == protocol.CodecHandle { data, err := encode(handle, record) @@ -270,7 +278,9 @@ func (v2 *Handlers) AccountInformation(ctx echo.Context, address string, params } } - account, err := AccountDataToAccount(address, &record, assetsCreators, lastRound, amountWithoutPendingRewards) + minBalance := record.MinBalance(&consensus) + + account, err := AccountDataToAccount(address, &record, assetsCreators, lastRound, amountWithoutPendingRewards, minBalance) if err != nil { return internalError(ctx, err, errInternalFailure, v2.Log) } diff --git a/test/scripts/e2e_subs/goal/atomic_abi.py b/test/scripts/e2e_subs/goal/atomic_abi.py index 4a84c2e4fa..7a8f29063d 100644 --- a/test/scripts/e2e_subs/goal/atomic_abi.py +++ b/test/scripts/e2e_subs/goal/atomic_abi.py @@ -1,4 +1,5 @@ import json +from subprocess import call from typing import Callable, Dict, List, Union, Tuple from pathlib import Path import types @@ -18,28 +19,30 @@ def __init__( goal: Goal, app_id: int, contract_abi_json: Union[Path, str], - sender: str, - signer: atc.TransactionSigner = None, + caller_acct: str, sp: txn.SuggestedParams = None, ): """ Note: app_id will over-write whatever app_id was defined in `contract_abi_json` - Also, I'm assuming a single signer for all the methods in the atomic transaction. + Also, we're assuming a single caller_account which is also the signer for all the transactions. """ self.goal = goal self.app_id = app_id self.contract_abi_json = contract_abi_json # for cloning only - self.contract_abi_json_path: str = None + self.caller_acct = caller_acct + self.sp = sp - self.method_args: List[list] = [] - self.sigs2selector: Dict[str, str] = {} - self.handle2meth: Dict[str, dict] = {} + assert ( + self.app_id and self.app_id > 0 + ), f"must have already created the app but have app_id {self.app_id}" - self.execution_results: atc.AtomicTransactionResponse = None - self.execution_summaries: List[MethodCallSummary] = None + assert ( + self.caller_acct in self.goal.internal_wallet + ), "aborting AtomicABI - will not be able to transact without signing authority" # try very hard to parse the ABI contract + self.contract_abi_json_path: str = None cajson = text(contract_abi_json) if cajson: self.contract_abi_json_path = contract_abi_json @@ -49,13 +52,18 @@ def __init__( cadict["appId"] = self.app_id self.contract: abi.Contract = abi.Contract.from_json(json.dumps(cadict)) - self.sender = sender self.sp = sp - self.signer = signer + assert ( + self.caller_acct + ), "aborting AtomicABI - cannot execute without a caller_acct" + self.signer = self.get_atxn_signer() - if not self.signer: - # gonna just try and get the signer from the sender - self.signer = self.get_atxn_signer(sender) + self.method_args: List[list] = [] + self.sigs2selector: Dict[str, str] = {} + self.handle2meth: Dict[str, dict] = {} + + self.execution_results: atc.AtomicTransactionResponse = None + self.execution_summaries: List[MethodCallSummary] = None self.atomic_transaction_composer = atc.AtomicTransactionComposer() @@ -75,23 +83,23 @@ def __init__( } @classmethod - def factory(cls, obj): + def factory(cls, obj, caller_acct: str = None): return cls( obj.goal, obj.app_id, obj.contract_abi_json, - obj.sender, - signer=obj.signer, + caller_acct if caller_acct else obj.caller_acct, sp=obj.sp, ) - def clone(self): - return self.factory(self) + def clone(self, caller_acct: str = None): + return self.factory(self, caller_acct=caller_acct) def execute_atomic_group( self, wait_rounds: int = 5 ) -> Tuple[atc.AtomicTransactionResponse, List["MethodCallSummary"]]: assert self.execution_results is None, self.CALL_TWICE_ERROR + self.execution_results = self.atomic_transaction_composer.execute( self.goal.algod, wait_rounds ) @@ -172,10 +180,10 @@ def get_suggested_params(self) -> txn.SuggestedParams: return self.sp - def get_atxn_signer(self, sender: str = None) -> atc.AccountTransactionSigner: - if not sender: - sender = self.sender - sk = self.goal.internal_wallet.get(sender) + def get_atxn_signer(self, caller_acct: str = None) -> atc.AccountTransactionSigner: + if not caller_acct: + caller_acct = self.caller_acct + sk = self.goal.internal_wallet.get(caller_acct) if not sk: raise Exception("Cannot create AccountTransactionSigner") # TODO: handle querying kmd in the case that sk isn't in the internal wallet @@ -206,7 +214,7 @@ def add_method_call( self.atomic_transaction_composer.add_method_call( self.app_id, method, - self.sender, + self.caller_acct, sp, self.signer, method_args=method_args, diff --git a/test/scripts/e2e_subs/min_balance.py b/test/scripts/e2e_subs/min_balance.py index 384d77429e..316fde319f 100755 --- a/test/scripts/e2e_subs/min_balance.py +++ b/test/scripts/e2e_subs/min_balance.py @@ -1,5 +1,8 @@ #!/usr/bin/env python +import subprocess +import sys + from datetime import datetime from pathlib import PurePath import sys @@ -8,21 +11,64 @@ from goal import Goal, AtomicABI +CONSENSUS_MIN_BALANCE = 100_000 +ASSET_MIN_BALANCE = 100_000 +APP_MIN_BALANCE = 100_000 +OPTIN_MIN_BALANCE = 100_000 +# app schemas: +APP_KV_MIN_BALANCE = 25_000 +APP_INTS_MIN_BALANCE = 3_500 +APP_BYTES_MIN_BALANCE = 25_000 + +EXTRA_PAGE_MIN_BALANCE = ( + APP_MIN_BALANCE # per userBalance.go::MinBalance() as of Dec 2021 +) + + +# Set True if you want to run a remote debugger interactively on the given PORT +INTERACTIVE, DEBUGPORT = True, 4312 -def initialize_debugger(port): + +def initialize_debugger(): import multiprocessing if multiprocessing.current_process().pid > 1: import debugpy - debugpy.listen(("0.0.0.0", port)) + debugpy.listen(("0.0.0.0", DEBUGPORT)) print("Debugger is ready to be attached, press F5", flush=True) debugpy.wait_for_client() print("Visual Studio Code debugger is now attached", flush=True) -# uncomment out the following to run a remote interactive debug session: -initialize_debugger(1330) +if INTERACTIVE: + initialize_debugger() + + +def get_algod_min_balance(goal, account): + return goal.algod.account_info(account)["min-balance"] + + +def get_teal_min_balance(abi, account): + # can't execute an abi object twice so must clone it before each execution: + abi = abi.clone(caller_acct=account) + sender_pymt = txn.PaymentTxn(account, abi.get_suggested_params(), account, 10_000) + sender_tx_sig = abi.get_txn_with_signer(sender_pymt) + + # TODO: abi.sender_min_balance(sender_tx_sig) + return abi.execute_singleton("sender_min_balance", method_args=[sender_tx_sig]) + + +def assert_min_balance(abi_or_goal, account, expected_min_balance, skip_abi=False): + goal = abi_or_goal if skip_abi else abi_or_goal.goal + algod_mb = get_algod_min_balance(goal, account) + assert ( + algod_mb == expected_min_balance + ), f"case 1: {algod_mb} != {expected_min_balance}" + if not skip_abi: + abi = abi_or_goal + teal_mb = get_teal_min_balance(abi, account) + assert algod_mb == teal_mb, f"case 2: {algod_mb} != {teal_mb}" script_path, WALLET = sys.argv @@ -34,167 +80,124 @@ def initialize_debugger(port): stamp = datetime.now().strftime("%Y%m%d_%H%M%S") print(f"Running {SCRIPT} inside {CWD} @ {stamp}") -# Initialize goal and fund a new account joe +# Initialize goal goal = Goal(WALLET, autosend=False) -rest_endpoints = goal.get_endpoint_info() - -joe = goal.new_account() -flo = goal.new_account() -print(f"Joe & Flo: {joe}, {flo}") +if INTERACTIVE: + # good to know so you can query the temp REST endpoints + rest_endpoints = goal.get_endpoint_info() -txinfo, err = goal.pay(goal.account, joe, amt=50_000_000, send=True) -txinfo, err = goal.pay(goal.account, flo, amt=100_000_000, send=True) - -# App create +# Initialize AtomicABI using the min-balance TEAL app: approval_teal_path = TEAL_DIR / "abi-min_balance.teal" print(f"approval_teal_path: {approval_teal_path}") approval_teal = goal.assemble(approval_teal_path) -txinfo, err = goal.app_create(joe, approval_teal, send=True) +txinfo, err = goal.app_create(goal.account, approval_teal, send=True) print(f"txinfo for create request: {txinfo}") app_id = txinfo["application-index"] +assert_min_balance( + goal, goal.account, CONSENSUS_MIN_BALANCE + APP_MIN_BALANCE, skip_abi=True +) -abi = AtomicABI(goal, app_id, TEAL_DIR / "abi-min_balance.json", flo) - -# Dummy complement call (for now) -abi.next_abi_call_complement(bytes.fromhex("00ff00ff")) -executed_methods, summary = abi.execute_atomic_group() - - -# def min_balances(abi, joe, flo): -# abi = abi.clone() - -# joe_sig = abi.get_atxn_signer(sender=joe) -# flo_sig = abi.get_atxn_signer(sender=flo) - -# joe_pymt = txn.PaymentTxn(joe, abi.get_suggested_params(), flo, 10_000) -# joe_tx_sig = abi.get_txn_with_signer(joe_pymt, signer=joe_sig) +# ABI needs funded accounts: +joe = goal.new_account() +flo = goal.new_account() -# flo_pymt = txn.PaymentTxn(flo, abi.get_suggested_params(), joe, 10_000) -# flo_tx_sig = abi.get_txn_with_signer(flo_pymt, signer=flo_sig) +print(f"Joe & Flo: {joe}, {flo}") -# abi.next_abi_call_sender_min_balance(joe_tx_sig) -# abi.next_abi_call_sender_min_balance(flo_tx_sig) -# _, summaries = abi.execute_atomic_group() -# return { -# "joe_minb": summaries[0].result.return_value, -# "flo_minb": summaries[1].result.return_value, -# } +txinfo, err = goal.pay(goal.account, joe, amt=50_000_000, send=True) +txinfo, err = goal.pay(goal.account, flo, amt=100_000_000, send=True) -def min_balance(abi, sender, receiver): - abi = abi.clone() +abi = AtomicABI(goal, app_id, TEAL_DIR / "abi-min_balance.json", joe) - sender_sig = abi.get_atxn_signer(sender=sender) - sender_pymt = txn.PaymentTxn(sender, abi.get_suggested_params(), receiver, 10_000) - sender_tx_sig = abi.get_txn_with_signer(sender_pymt, signer=sender_sig) - return abi.execute_singleton("sender_min_balance", method_args=[sender_tx_sig]) +# starting out, should be at global min +assert_min_balance(abi, flo, CONSENSUS_MIN_BALANCE) +assert_min_balance(abi, joe, CONSENSUS_MIN_BALANCE) -joe_minb = min_balance(abi, joe, flo) -flo_minb = min_balance(abi, flo, joe) - -x = 42 -# abi.next_abi_call_add(29, 13) -# abi.next_abi_call_sub(3, 1) -# abi.next_abi_call_div(4, 2) -# abi.next_abi_call_mul(3, 2) -# abi.next_abi_call_qrem(27, 5) -# abi.next_abi_call_reverse("desrever yllufsseccus") -# abi.next_abi_call_txntest(10_000, txn_sgn, 1000) - - -# flo_mb1 = min_balance(flo) -# joe_mb1 = min_balance(joe) -x = 42 - -""" - ledger.NewAccount(ep.Txn.Txn.Sender, 234) - ledger.NewAccount(ep.Txn.Txn.Receiver, 123) - - testApp(t, "int 0; min_balance; int 1001; ==", ep) - // Sender makes an asset, min balance goes up - ledger.NewAsset(ep.Txn.Txn.Sender, 7, basics.AssetParams{Total: 1000}) - testApp(t, "int 0; min_balance; int 2002; ==", ep) - schemas := makeApp(1, 2, 3, 4) - ledger.NewApp(ep.Txn.Txn.Sender, 77, schemas) - // create + optin + 10 schema base + 4 ints + 6 bytes (local - // and global count b/c NewApp opts the creator in) - minb := 2*1002 + 10*1003 + 4*1004 + 6*1005 - testApp(t, fmt.Sprintf("int 0; min_balance; int %d; ==", 2002+minb), ep) - // request extra program pages, min balance increase - withepp := makeApp(1, 2, 3, 4) - withepp.ExtraProgramPages = 2 - ledger.NewApp(ep.Txn.Txn.Sender, 77, withepp) - minb += 2 * 1002 - testApp(t, fmt.Sprintf("int 0; min_balance; int %d; ==", 2002+minb), ep) - - testApp(t, "int 1; min_balance; int 1001; ==", ep) // 1 == Accounts[0] - testProg(t, "txn Accounts 1; min_balance; int 1001; ==", directRefEnabledVersion-1, - expect{2, "min_balance arg 0 wanted type uint64..."}) - testProg(t, "txn Accounts 1; min_balance; int 1001; ==", directRefEnabledVersion) - testApp(t, "txn Accounts 1; min_balance; int 1001; ==", ep) // 1 == Accounts[0] - // Receiver opts in - ledger.NewHolding(ep.Txn.Txn.Receiver, 7, 1, true) - testApp(t, "int 1; min_balance; int 2002; ==", ep) // 1 == Accounts[0] - - testApp(t, "int 2; min_balance; int 1001; ==", ep, "invalid Account reference 2") -""" - -teal = """ -#pragma version 6 - txn ApplicationID - bz end - // Pay the sender and Accounts[1]. Force the second fee to default high - itxn_begin - int pay - itxn_field TypeEnum - - txn Sender - itxn_field Receiver - - int 5 - itxn_field Amount - - int 0 - itxn_field Fee // No fee, so 2nd fee is doubled - - itxn_next - - int pay - itxn_field TypeEnum - - txn Accounts 1 - itxn_field Receiver - - int 5 - itxn_field Amount - - itxn_submit - - itxn Fee - int 2000 - == - assert - -end: - int 1 -""" - -txinfo, err = goal.app_create(joe, goal.assemble(teal)) +# flo creates an asset +txinfo, err = goal.asset_create( + flo, total=10_000, unit_name="oz", asset_name="Gold", manager=flo, send=True +) assert not err, err -app_id = txinfo["application-index"] -assert app_id - -# Fund the app account -txinfo, err = goal.pay(goal.account, goal.app_address(app_id), amt=400_000) +assets = {"Gold": txinfo["asset-index"]} + +expected_mb = CONSENSUS_MIN_BALANCE + ASSET_MIN_BALANCE +assert_min_balance(abi, flo, expected_mb) + + +# goal creates 2 assets +for total, unit, asset in [(1000, "oz", "Silver"), (100, "oz", "Platinum")]: + txinfo, err = goal.asset_create( + goal.account, + total=total, + unit_name=unit, + asset_name=asset, + manager=goal.account, + send=True, + ) + assets[asset] = txinfo["asset-index"] + assert not err, err + +expected_mb = CONSENSUS_MIN_BALANCE + APP_MIN_BALANCE + 2 * ASSET_MIN_BALANCE +assert_min_balance(goal, goal.account, expected_mb, skip_abi=True) + +# joe opts into Gold and Silver: +txinfo, err = goal.axfer(joe, joe, 0, assets["Gold"], send=True) +txinfo, err = goal.axfer(joe, joe, 0, assets["Silver"], send=True) assert not err, err +expected_mb = CONSENSUS_MIN_BALANCE + 2 * ASSET_MIN_BALANCE +assert_min_balance(abi, joe, expected_mb) - -txinfo, err = goal.app_call(joe, app_id, accounts=[goal.account]) +# next, destroy Gold and Silver +txinfo, err = goal.acfg(flo, index=assets["Gold"], send=True) assert not err, err +expected_mb = CONSENSUS_MIN_BALANCE +assert_min_balance(abi, flo, expected_mb) +txinfo, err = goal.acfg(goal.account, index=assets["Silver"], send=True) +assert not err, err +expected_mb = CONSENSUS_MIN_BALANCE + APP_MIN_BALANCE + ASSET_MIN_BALANCE +assert_min_balance(goal, goal.account, expected_mb, skip_abi=True) + +# let flo created app with 2 global schema ints, 10 global schema bytes, 1 extra page +txinfo, err = goal.app_create( + flo, + approval_teal, + local_schema=(2, 0), + global_schema=(0, 10), + extra_pages=1, + send=True, +) +assert not err, err +expected_mb = ( + CONSENSUS_MIN_BALANCE + + APP_MIN_BALANCE + # Not these because not opting in + # + 2 * APP_KV_MIN_BALANCE + # + 2 * APP_INTS_MIN_BALANCE + + 10 * APP_KV_MIN_BALANCE + + 10 * APP_BYTES_MIN_BALANCE + + EXTRA_PAGE_MIN_BALANCE +) +assert_min_balance(abi, flo, expected_mb) + +# Finally, let flo additionally opt into her app (2 local schema ints) +app_id = txinfo["application-index"] +txinfo, err = goal.app_optin(flo, app_id, send=True) +expected_mb += ( + APP_MIN_BALANCE + + 2 * APP_KV_MIN_BALANCE + + 2 * APP_INTS_MIN_BALANCE + # Not these because only creator pays for the globals: + # + 10 * APP_KV_MIN_BALANCE + # + 10 * APP_BYTES_MIN_BALANCE + # + EXTRA_PAGE_MIN_BALANCE +) +assert_min_balance(abi, flo, expected_mb) stamp = datetime.now().strftime("%Y%m%d_%H%M%S") print(f"Running {SCRIPT} inside {CWD} @ {stamp}") + +assert False, "yay, got to the end!!!" From 035432d8456658f814f9101ab62d0bf34edbde66 Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Fri, 10 Dec 2021 09:47:43 -0600 Subject: [PATCH 11/32] simple goal e2e test is passing --- test/scripts/e2e_subs/min_balance.sh | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/test/scripts/e2e_subs/min_balance.sh b/test/scripts/e2e_subs/min_balance.sh index 94c58b73f7..94a961a81b 100755 --- a/test/scripts/e2e_subs/min_balance.sh +++ b/test/scripts/e2e_subs/min_balance.sh @@ -12,6 +12,9 @@ echo "NETDIR=$NETDIR" # Directory of this bash program DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" +echo "DIR=$DIR" + + gcmd="goal -w ${WALLET}" ACCOUNT=$(${gcmd} account list|awk '{ print $3 }') @@ -23,6 +26,14 @@ echo `$gcmd account balance -a $ACCOUNT` echo `$gcmd account info -a $ACCOUNT` -echo `$gcmd account export -a $ACCOUNT` +MINBAL=$(${gcmd} account info -a ${ACCOUNT}|grep 'Minimum Balance:'| awk '{ print $3 }') + +echo "Minimum Balance --> $MINBAL" + +EXPECTED="100000" +if [[ ${MINBAL} != ${EXPECTED} ]]; then + date '+min_balance FAIL goal account info should return expected Minimum Ballance %Y%m%d_%H%M%S' + false +fi -exit 1 \ No newline at end of file +# see ./min_balance.py for more complicated scenarios From 85de603c40c45be575c567189482fdfb94f48407 Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Fri, 10 Dec 2021 10:43:02 -0600 Subject: [PATCH 12/32] test passing -knock on wood- --- test/scripts/e2e.sh | 4 ++- test/scripts/e2e_subs/min_balance.py | 29 ++++--------------- .../e2e_subs/tealprogs/abi-min_balance.teal | 18 ++++++++---- 3 files changed, 21 insertions(+), 30 deletions(-) diff --git a/test/scripts/e2e.sh b/test/scripts/e2e.sh index 1df23e0b88..07fc7fe7de 100755 --- a/test/scripts/e2e.sh +++ b/test/scripts/e2e.sh @@ -123,7 +123,9 @@ if [ -z "$E2E_TEST_FILTER" ] || [ "$E2E_TEST_FILTER" == "SCRIPTS" ]; then python3 -m venv "${TEMPDIR}/ve" . "${TEMPDIR}/ve/bin/activate" "${TEMPDIR}/ve/bin/pip3" install --upgrade pip - "${TEMPDIR}/ve/bin/pip3" install --upgrade py-algorand-sdk cryptography + "${TEMPDIR}/ve/bin/pip3" install --upgrade cryptograpy + # get the latest tip of our python SDK main branch as opposed to what's on pypi: + "${TEMPDIR}/ve/bin/pip3" install --upgrade git+git://github.com/algorand/py-algorand-sdk@master # enable remote debugging: "${TEMPDIR}/ve/bin/pip3" install --upgrade debugpy duration "e2e client setup" diff --git a/test/scripts/e2e_subs/min_balance.py b/test/scripts/e2e_subs/min_balance.py index 316fde319f..d53da31bbf 100755 --- a/test/scripts/e2e_subs/min_balance.py +++ b/test/scripts/e2e_subs/min_balance.py @@ -1,8 +1,5 @@ #!/usr/bin/env python -import subprocess -import sys - from datetime import datetime from pathlib import PurePath import sys @@ -25,8 +22,8 @@ ) -# Set True if you want to run a remote debugger interactively on the given PORT -INTERACTIVE, DEBUGPORT = True, 4312 +# Set INTERACTIVE True if you want to run a remote debugger interactively on the given PORT +INTERACTIVE, DEBUGPORT = False, 4312 def initialize_debugger(): @@ -45,7 +42,7 @@ def initialize_debugger(): initialize_debugger() -def get_algod_min_balance(goal, account): +def get_pysdk_min_balance(goal, account): return goal.algod.account_info(account)["min-balance"] @@ -61,7 +58,7 @@ def get_teal_min_balance(abi, account): def assert_min_balance(abi_or_goal, account, expected_min_balance, skip_abi=False): goal = abi_or_goal if skip_abi else abi_or_goal.goal - algod_mb = get_algod_min_balance(goal, account) + algod_mb = get_pysdk_min_balance(goal, account) assert ( algod_mb == expected_min_balance ), f"case 1: {algod_mb} != {expected_min_balance}" @@ -174,7 +171,7 @@ def assert_min_balance(abi_or_goal, account, expected_min_balance, skip_abi=Fals expected_mb = ( CONSENSUS_MIN_BALANCE + APP_MIN_BALANCE - # Not these because not opting in + # Not these local var requirements because not opting in # + 2 * APP_KV_MIN_BALANCE # + 2 * APP_INTS_MIN_BALANCE + 10 * APP_KV_MIN_BALANCE @@ -183,21 +180,5 @@ def assert_min_balance(abi_or_goal, account, expected_min_balance, skip_abi=Fals ) assert_min_balance(abi, flo, expected_mb) -# Finally, let flo additionally opt into her app (2 local schema ints) -app_id = txinfo["application-index"] -txinfo, err = goal.app_optin(flo, app_id, send=True) -expected_mb += ( - APP_MIN_BALANCE - + 2 * APP_KV_MIN_BALANCE - + 2 * APP_INTS_MIN_BALANCE - # Not these because only creator pays for the globals: - # + 10 * APP_KV_MIN_BALANCE - # + 10 * APP_BYTES_MIN_BALANCE - # + EXTRA_PAGE_MIN_BALANCE -) -assert_min_balance(abi, flo, expected_mb) - stamp = datetime.now().strftime("%Y%m%d_%H%M%S") print(f"Running {SCRIPT} inside {CWD} @ {stamp}") - -assert False, "yay, got to the end!!!" diff --git a/test/scripts/e2e_subs/tealprogs/abi-min_balance.teal b/test/scripts/e2e_subs/tealprogs/abi-min_balance.teal index 0f2ae16339..e0bd46af5f 100644 --- a/test/scripts/e2e_subs/tealprogs/abi-min_balance.teal +++ b/test/scripts/e2e_subs/tealprogs/abi-min_balance.teal @@ -8,6 +8,12 @@ int NoOp == bnz handle_noop + + txn OnCompletion + int OptIn + == + bnz handle_optIn + err // TODO - handle more than just NoOp's handle_noop: @@ -16,11 +22,6 @@ handle_noop: == bnz handle_no_questions_asked - txna ApplicationArgs 0 - byte 0x9b122fc1 // _optIn(uint64)uint64 - == - bnz handle_no_questions_asked - txn ApplicationArgs 0 byte 0x4f30c3ce // base64_decode(string,string)string == @@ -38,6 +39,13 @@ handle_noop: err +handle_optIn: + txna ApplicationArgs 0 + byte 0x9b122fc1 // _optIn(uint64)uint64 + == + bnz handle_no_questions_asked + + handle_no_questions_asked: int 1 b return_uint64 From d6034e5aee47ed0d8f52f79fa50dfc945057dd5e Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Fri, 10 Dec 2021 13:17:41 -0600 Subject: [PATCH 13/32] Update daemon/algod/api/algod.oas2.json Go with @winder's suggestion --- daemon/algod/api/algod.oas2.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/daemon/algod/api/algod.oas2.json b/daemon/algod/api/algod.oas2.json index bfd8587ad5..e1036f1a5e 100644 --- a/daemon/algod/api/algod.oas2.json +++ b/daemon/algod/api/algod.oas2.json @@ -1367,7 +1367,7 @@ "type": "integer" }, "min-balance": { - "description": "\\[algo\\] total number of MicroAlgos needed to allow transacting from account", + "description": "MicroAlgo balance required by the account, the requirement starts at 1000 and grows based on the asset and application usage", "type": "integer" }, "amount-without-pending-rewards": { From 3bcb8bc96384fa0266003baa44bff50e5af5e324 Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Fri, 10 Dec 2021 13:39:58 -0600 Subject: [PATCH 14/32] better wording --- daemon/algod/api/algod.oas2.json | 2 +- daemon/algod/api/algod.oas3.yml | 2 +- .../api/server/v2/generated/private/routes.go | 273 +++++++------- .../api/server/v2/generated/private/types.go | 4 +- .../algod/api/server/v2/generated/routes.go | 346 +++++++++--------- daemon/algod/api/server/v2/generated/types.go | 4 +- test/scripts/e2e_subs/min_balance.py | 2 +- 7 files changed, 319 insertions(+), 314 deletions(-) diff --git a/daemon/algod/api/algod.oas2.json b/daemon/algod/api/algod.oas2.json index e1036f1a5e..88e28a692b 100644 --- a/daemon/algod/api/algod.oas2.json +++ b/daemon/algod/api/algod.oas2.json @@ -1367,7 +1367,7 @@ "type": "integer" }, "min-balance": { - "description": "MicroAlgo balance required by the account, the requirement starts at 1000 and grows based on the asset and application usage", + "description": "MicroAlgo balance required by the account.\n\nThe requirement starts at 100,000 and grows based on asset and application usage.", "type": "integer" }, "amount-without-pending-rewards": { diff --git a/daemon/algod/api/algod.oas3.yml b/daemon/algod/api/algod.oas3.yml index 6e81750d64..b5887291ae 100644 --- a/daemon/algod/api/algod.oas3.yml +++ b/daemon/algod/api/algod.oas3.yml @@ -727,7 +727,7 @@ "type": "array" }, "min-balance": { - "description": "\\[algo\\] total number of MicroAlgos needed to allow transacting from account", + "description": "MicroAlgo balance required by the account.\n\nThe requirement starts at 100,000 and grows based on asset and application usage.", "type": "integer" }, "participation": { diff --git a/daemon/algod/api/server/v2/generated/private/routes.go b/daemon/algod/api/server/v2/generated/private/routes.go index 1e3a72aaa5..648c8779c0 100644 --- a/daemon/algod/api/server/v2/generated/private/routes.go +++ b/daemon/algod/api/server/v2/generated/private/routes.go @@ -277,142 +277,143 @@ func RegisterHandlers(router interface { // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ - "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", } // GetSwagger returns the Swagger specification corresponding to the generated code diff --git a/daemon/algod/api/server/v2/generated/private/types.go b/daemon/algod/api/server/v2/generated/private/types.go index 5e10e78d89..0f561e36b2 100644 --- a/daemon/algod/api/server/v2/generated/private/types.go +++ b/daemon/algod/api/server/v2/generated/private/types.go @@ -49,7 +49,9 @@ type Account struct { // Note: the raw account uses `map[int] -> Asset` for this type. CreatedAssets *[]Asset `json:"created-assets,omitempty"` - // \[algo\] total number of MicroAlgos needed to allow transacting from account + // MicroAlgo balance required by the account. + // + // The requirement starts at 100,000 and grows based on asset and application usage. MinBalance uint64 `json:"min-balance"` // AccountParticipation describes the parameters used by this account in consensus protocol. diff --git a/daemon/algod/api/server/v2/generated/routes.go b/daemon/algod/api/server/v2/generated/routes.go index 21187c4d54..ffd0c35ae2 100644 --- a/daemon/algod/api/server/v2/generated/routes.go +++ b/daemon/algod/api/server/v2/generated/routes.go @@ -617,179 +617,179 @@ func RegisterHandlers(router interface { var swaggerSpec = []string{ "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", - "gWEPF/IAAA==", + "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", } // GetSwagger returns the Swagger specification corresponding to the generated code diff --git a/daemon/algod/api/server/v2/generated/types.go b/daemon/algod/api/server/v2/generated/types.go index b3dafaf6b1..79f8435e47 100644 --- a/daemon/algod/api/server/v2/generated/types.go +++ b/daemon/algod/api/server/v2/generated/types.go @@ -49,7 +49,9 @@ type Account struct { // Note: the raw account uses `map[int] -> Asset` for this type. CreatedAssets *[]Asset `json:"created-assets,omitempty"` - // \[algo\] total number of MicroAlgos needed to allow transacting from account + // MicroAlgo balance required by the account. + // + // The requirement starts at 100,000 and grows based on asset and application usage. MinBalance uint64 `json:"min-balance"` // AccountParticipation describes the parameters used by this account in consensus protocol. diff --git a/test/scripts/e2e_subs/min_balance.py b/test/scripts/e2e_subs/min_balance.py index d53da31bbf..33ec6451ba 100755 --- a/test/scripts/e2e_subs/min_balance.py +++ b/test/scripts/e2e_subs/min_balance.py @@ -158,7 +158,7 @@ def assert_min_balance(abi_or_goal, account, expected_min_balance, skip_abi=Fals expected_mb = CONSENSUS_MIN_BALANCE + APP_MIN_BALANCE + ASSET_MIN_BALANCE assert_min_balance(goal, goal.account, expected_mb, skip_abi=True) -# let flo created app with 2 global schema ints, 10 global schema bytes, 1 extra page +# flo creates an app with 2 global schema ints, 10 global schema bytes, 1 extra page txinfo, err = goal.app_create( flo, approval_teal, From 2b7a8b56d81c6080ac4984e492216aa3a90bfb74 Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Sat, 11 Dec 2021 09:56:53 -0600 Subject: [PATCH 15/32] comment on its own line --- test/scripts/e2e_subs/min_balance.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/test/scripts/e2e_subs/min_balance.py b/test/scripts/e2e_subs/min_balance.py index 33ec6451ba..c0984a66e4 100755 --- a/test/scripts/e2e_subs/min_balance.py +++ b/test/scripts/e2e_subs/min_balance.py @@ -17,9 +17,8 @@ APP_INTS_MIN_BALANCE = 3_500 APP_BYTES_MIN_BALANCE = 25_000 -EXTRA_PAGE_MIN_BALANCE = ( - APP_MIN_BALANCE # per userBalance.go::MinBalance() as of Dec 2021 -) +# per userBalance.go::MinBalance() as of Dec 2021: +EXTRA_PAGE_MIN_BALANCE = APP_MIN_BALANCE # Set INTERACTIVE True if you want to run a remote debugger interactively on the given PORT From 9edf2e06d660522419a471c1a7d29bdf0d65b17f Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Mon, 13 Dec 2021 11:38:07 -0500 Subject: [PATCH 16/32] improvments in python abi e2e test wrapper --- test/scripts/e2e_subs/goal/atomic_abi.py | 98 +++++++++--- test/scripts/e2e_subs/goal/atomic_abi_test.py | 147 ++++++++++++++++++ test/scripts/e2e_subs/min_balance.py | 10 +- 3 files changed, 232 insertions(+), 23 deletions(-) create mode 100644 test/scripts/e2e_subs/goal/atomic_abi_test.py diff --git a/test/scripts/e2e_subs/goal/atomic_abi.py b/test/scripts/e2e_subs/goal/atomic_abi.py index 7a8f29063d..da7f881176 100644 --- a/test/scripts/e2e_subs/goal/atomic_abi.py +++ b/test/scripts/e2e_subs/goal/atomic_abi.py @@ -43,11 +43,13 @@ def __init__( # try very hard to parse the ABI contract self.contract_abi_json_path: str = None - cajson = text(contract_abi_json) - if cajson: + try: + cajson = open(contract_abi_json, "rt").read().strip() self.contract_abi_json_path = contract_abi_json - else: + except Exception: cajson = contract_abi_json + + self.contract_abi_json_path = contract_abi_json cadict = json.loads(cajson) cadict["appId"] = self.app_id self.contract: abi.Contract = abi.Contract.from_json(json.dumps(cadict)) @@ -68,8 +70,14 @@ def __init__( self.atomic_transaction_composer = atc.AtomicTransactionComposer() for abi_meth in self.contract.methods: - handle, meth_name, meth = self._attach_dynamic_method_call( - abi_meth.name, self._amc_factory(abi_meth) + ( + handle, + am_name, + adder_meth, + rn_name, + run_now_meth, + ) = self._attach_dynamic_method_calls( + abi_meth.name, *self._method_factories(abi_meth) ) signature = abi_meth.get_signature() selector = "0x" + abi_meth.get_selector().hex() @@ -78,22 +86,35 @@ def __init__( "signature": signature, "selector": selector, "abi_meth": abi_meth, - "adder_meth_name": meth_name, - "adder_meth": meth, + "adder_meth_name": am_name, + "adder_meth": adder_meth, + "run_now_meth_name": rn_name, + "run_now_meth": run_now_meth, } @classmethod - def factory(cls, obj, caller_acct: str = None): + def factory( + cls, obj, caller_acct: str = None, new_suggested_params: bool = True + ) -> "AtomicABI": + """ + new_suggested_params defaults to True because we don't want an intentionally + cloned transaction to clash with a previous one (unless it's in the same round) + """ + sp = obj.goal.algod.suggested_params() if new_suggested_params else obj.sp return cls( obj.goal, obj.app_id, obj.contract_abi_json, caller_acct if caller_acct else obj.caller_acct, - sp=obj.sp, + sp=sp, ) - def clone(self, caller_acct: str = None): - return self.factory(self, caller_acct=caller_acct) + def clone( + self, caller_acct: str = None, new_suggested_params: bool = True + ) -> "AtomicABI": + return self.factory( + self, caller_acct=caller_acct, new_suggested_params=new_suggested_params + ) def execute_atomic_group( self, wait_rounds: int = 5 @@ -152,8 +173,8 @@ def _build_summaries(self) -> List["MethodCallSummary"]: return summaries @staticmethod - def _amc_factory(abi_meth: abi.method.Method): - def func( + def _method_factories(abi_meth: abi.method.Method) -> Tuple[Callable, Callable]: + def func_add_method_call( self, *args, sp: txn.SuggestedParams = None, @@ -172,7 +193,30 @@ def func( rekey_to=rekey_to, ) - return func + def func_run_now( + self, + *args, + wait_rounds: int = 5, + sp: txn.SuggestedParams = None, + on_complete: txn.OnComplete = txn.OnComplete.NoOpOC, + note: bytes = None, + lease: bytes = None, + rekey_to: str = None, + ): + abi = self.clone() + abi.add_method_call( + abi_meth, + method_args=args, + sp=sp, + on_complete=on_complete, + note=note, + lease=lease, + rekey_to=rekey_to, + ) + _, s = abi.execute_atomic_group(wait_rounds=wait_rounds) + return s[0].result.return_value + + return func_add_method_call, func_run_now def get_suggested_params(self) -> txn.SuggestedParams: if not self.sp: @@ -228,23 +272,39 @@ def add_method_call( return self - def _attach_dynamic_method_call(self, name: str, func: Callable) -> None: + def _attach_dynamic_method_calls( + self, name: str, adder_func: Callable, run_now_func: Callable + ) -> tuple: """ For an abi method such as "factorial(uint64)uint64" this allows usages such as: >>> abi.next_abi_call_factorial(5) which will delegate to AtomicTransactionComposer with atc.add_method_call(app_id, abi_factorial_method, ...) + + For immediate execuation, the following usages are supported: + >>> abi.run_factorial(5) + which will run add the method call as above, and then run + execute_atomic_group() """ - meth = types.MethodType(func, self) - meth_name = self.abi_composer_name(name) - setattr(self, meth_name, meth) - return name, meth_name, meth + adder_meth = types.MethodType(adder_func, self) + adder_meth_name = self.abi_composer_name(name) + setattr(self, adder_meth_name, adder_meth) + + run_now_meth = types.MethodType(run_now_func, self) + rn_meth_name = self.run_now_method_name(name) + setattr(self, rn_meth_name, run_now_meth) + + return name, adder_meth_name, adder_meth, rn_meth_name, run_now_meth @classmethod def abi_composer_name(cls, method_name: str) -> str: return f"next_abi_call_{method_name}" + @classmethod + def run_now_method_name(cls, method_name: str) -> str: + return f"run_{method_name}" + class MethodCallSummary: def __init__(self, method: abi.Method, args: list, result: atc.ABIResult): diff --git a/test/scripts/e2e_subs/goal/atomic_abi_test.py b/test/scripts/e2e_subs/goal/atomic_abi_test.py new file mode 100644 index 0000000000..e7cf153207 --- /dev/null +++ b/test/scripts/e2e_subs/goal/atomic_abi_test.py @@ -0,0 +1,147 @@ +import json +from os import confstr_names +from unittest.mock import Mock, patch + +import algosdk.atomic_transaction_composer as atc + +from .atomic_abi import AtomicABI + + +contract = { + "name": "demo-abi", + "appId": None, + "methods": [ + { + "name": "add", + "desc": "Add 2 integers", + "args": [{"type": "uint64"}, {"type": "uint64"}], + "returns": {"type": "uint64"}, + }, + { + "name": "sub", + "desc": "Subtract 2 integers", + "args": [{"type": "uint64"}, {"type": "uint64"}], + "returns": {"type": "uint64"}, + }, + { + "name": "mul", + "desc": "Multiply 2 integers", + "args": [{"type": "uint64"}, {"type": "uint64"}], + "returns": {"type": "uint64"}, + }, + { + "name": "div", + "desc": "Divide 2 integers, throw away the remainder", + "args": [{"type": "uint64"}, {"type": "uint64"}], + "returns": {"type": "uint64"}, + }, + { + "name": "qrem", + "desc": "Divide 2 integers, return both the quotient and remainder", + "args": [{"type": "uint64"}, {"type": "uint64"}], + "returns": {"type": "(uint64,uint64)"}, + }, + { + "name": "reverse", + "desc": "Reverses a string", + "args": [{"type": "string"}], + "returns": {"type": "string"}, + }, + { + "name": "txntest", + "desc": "just check it", + "args": [{"type": "uint64"}, {"type": "pay"}, {"type": "uint64"}], + "returns": {"type": "uint64"}, + }, + { + "name": "concat_strings", + "desc": "concat some strings", + "args": [{"type": "string[]"}], + "returns": {"type": "string"}, + }, + { + "name": "manyargs", + "desc": "Try to send 20 arguments", + "args": [ + {"type": "uint64"}, + {"type": "uint64"}, + {"type": "uint64"}, + {"type": "uint64"}, + {"type": "uint64"}, + {"type": "uint64"}, + {"type": "uint64"}, + {"type": "uint64"}, + {"type": "uint64"}, + {"type": "uint64"}, + {"type": "uint64"}, + {"type": "uint64"}, + {"type": "uint64"}, + {"type": "uint64"}, + {"type": "uint64"}, + {"type": "uint64"}, + {"type": "uint64"}, + {"type": "uint64"}, + {"type": "uint64"}, + {"type": "uint64"}, + ], + "returns": {"type": "uint64"}, + }, + { + "name": "_optIn", + "desc": "just opt in", + "args": [{"type": "uint64"}], + "returns": {"type": "uint64"}, + }, + { + "name": "_closeOut", + "desc": "just close out", + "args": [{"type": "uint64"}], + "returns": {"type": "uint64"}, + }, + ], +} + + +def test_fixture(): + num_methods = len(contract["methods"]) + assert num_methods == 11 + assert json.loads(json.dumps(contract))["appId"] is None + + +def test_init(init_only=False): + goal = Mock() + caller_account = "mega whale" + sk = Mock() + goal.internal_wallet = {caller_account: sk} + + app_id = 42 + contract_abi_json = json.dumps(contract) + sp = Mock() + abi = AtomicABI(goal, app_id, contract_abi_json, caller_account, sp=sp) + if init_only: + return abi + + assert abi.app_id == app_id + assert abi.caller_acct == caller_account + assert abi.sp == sp + + assert abi.contract_abi_json == contract_abi_json + assert abi.contract.name == "demo-abi" + assert abi.contract.app_id == app_id + + assert abi.signer.private_key == sk + num_methods = len(contract["methods"]) + assert num_methods == len(abi.contract.methods) + + +def test_dynamic_methods(): + + abi = test_init(init_only=True) + + for meth in contract["methods"]: + name = meth["name"] + adder_meth_name = abi.abi_composer_name(name) + assert getattr(abi, adder_meth_name, None) + + run_now_method_name = abi.run_now_method_name(name) + assert getattr(abi, run_now_method_name, None) diff --git a/test/scripts/e2e_subs/min_balance.py b/test/scripts/e2e_subs/min_balance.py index c0984a66e4..8c8ddabee8 100755 --- a/test/scripts/e2e_subs/min_balance.py +++ b/test/scripts/e2e_subs/min_balance.py @@ -48,11 +48,13 @@ def get_pysdk_min_balance(goal, account): def get_teal_min_balance(abi, account): # can't execute an abi object twice so must clone it before each execution: abi = abi.clone(caller_acct=account) - sender_pymt = txn.PaymentTxn(account, abi.get_suggested_params(), account, 10_000) - sender_tx_sig = abi.get_txn_with_signer(sender_pymt) - # TODO: abi.sender_min_balance(sender_tx_sig) - return abi.execute_singleton("sender_min_balance", method_args=[sender_tx_sig]) + def get_txn_sig(): + return abi.get_txn_with_signer( + txn.PaymentTxn(account, abi.goal.algod.suggested_params(), account, 10_000) + ) + + return abi.run_sender_min_balance(get_txn_sig()) def assert_min_balance(abi_or_goal, account, expected_min_balance, skip_abi=False): From 4894d95c10b5c5d5b6e5f81ab9c8530d5e489d15 Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Mon, 13 Dec 2021 15:08:37 -0500 Subject: [PATCH 17/32] per reviewer suggestions - use block header instead of block + add consensus to AccountDataToAccount method --- cmd/tealdbg/local_test.go | 3 ++- daemon/algod/api/server/v2/account.go | 6 +++++- daemon/algod/api/server/v2/account_test.go | 4 ++-- daemon/algod/api/server/v2/handlers.go | 14 +++++++------- 4 files changed, 16 insertions(+), 11 deletions(-) diff --git a/cmd/tealdbg/local_test.go b/cmd/tealdbg/local_test.go index 75109f9774..0546835c5c 100644 --- a/cmd/tealdbg/local_test.go +++ b/cmd/tealdbg/local_test.go @@ -26,6 +26,7 @@ import ( "strings" "testing" + "github.com/algorand/go-algorand/config" v2 "github.com/algorand/go-algorand/daemon/algod/api/server/v2" "github.com/algorand/go-algorand/data/basics" "github.com/algorand/go-algorand/data/transactions" @@ -984,7 +985,7 @@ func TestLocalBalanceAdapterIndexer(t *testing.T) { case strings.HasPrefix(r.URL.Path, accountPath): w.WriteHeader(200) if r.URL.Path[len(accountPath):] == brs.Addr.String() { - account, err := v2.AccountDataToAccount(brs.Addr.String(), &brs.AccountData, map[basics.AssetIndex]string{}, 100, basics.MicroAlgos{Raw: 0}, basics.MicroAlgos{Raw: 100000}) + account, err := v2.AccountDataToAccount(brs.Addr.String(), &brs.AccountData, map[basics.AssetIndex]string{}, 100, &config.ConsensusParams{MinBalance: 100000}, basics.MicroAlgos{Raw: 0}) a.NoError(err) accountResponse := AccountIndexerResponse{Account: account, CurrentRound: 100} response, err := json.Marshal(accountResponse) diff --git a/daemon/algod/api/server/v2/account.go b/daemon/algod/api/server/v2/account.go index 2493fde6c2..a723db72ff 100644 --- a/daemon/algod/api/server/v2/account.go +++ b/daemon/algod/api/server/v2/account.go @@ -22,6 +22,7 @@ import ( "math" "sort" + "github.com/algorand/go-algorand/config" "github.com/algorand/go-algorand/crypto" "github.com/algorand/go-algorand/daemon/algod/api/server/v2/generated" "github.com/algorand/go-algorand/data/basics" @@ -30,7 +31,8 @@ import ( // AccountDataToAccount converts basics.AccountData to v2.generated.Account func AccountDataToAccount( address string, record *basics.AccountData, assetsCreators map[basics.AssetIndex]string, - lastRound basics.Round, amountWithoutPendingRewards basics.MicroAlgos, minBalance basics.MicroAlgos, + lastRound basics.Round, consensus *config.ConsensusParams, + amountWithoutPendingRewards basics.MicroAlgos, ) (generated.Account, error) { assets := make([]generated.AssetHolding, 0, len(record.Assets)) @@ -108,6 +110,8 @@ func AccountDataToAccount( return generated.Account{}, errors.New("overflow on pending reward calculation") } + minBalance := record.MinBalance(consensus) + return generated.Account{ SigType: nil, Round: uint64(lastRound), diff --git a/daemon/algod/api/server/v2/account_test.go b/daemon/algod/api/server/v2/account_test.go index a2ccce0b72..3aca8012f8 100644 --- a/daemon/algod/api/server/v2/account_test.go +++ b/daemon/algod/api/server/v2/account_test.go @@ -102,7 +102,7 @@ func TestAccount(t *testing.T) { b := a.WithUpdatedRewards(proto, 100) addr := basics.Address{}.String() - conv, err := AccountDataToAccount(addr, &b, map[basics.AssetIndex]string{}, round, a.MicroAlgos, basics.MicroAlgos{Raw: 100000}) + conv, err := AccountDataToAccount(addr, &b, map[basics.AssetIndex]string{}, round, &config.ConsensusParams{MinBalance: 100000}, a.MicroAlgos) require.NoError(t, err) require.Equal(t, addr, conv.Address) require.Equal(t, b.MicroAlgos.Raw, conv.Amount) @@ -196,7 +196,7 @@ func TestAccount(t *testing.T) { // convert the same account a few more times to make sure we always // produce the same generated.Account for i := 0; i < 10; i++ { - anotherConv, err := AccountDataToAccount(addr, &b, map[basics.AssetIndex]string{}, round, a.MicroAlgos, basics.MicroAlgos{Raw: 100000}) + anotherConv, err := AccountDataToAccount(addr, &b, map[basics.AssetIndex]string{}, round, &config.ConsensusParams{MinBalance: 100000}, a.MicroAlgos) require.NoError(t, err) require.Equal(t, protocol.EncodeJSON(conv), protocol.EncodeJSON(anotherConv)) diff --git a/daemon/algod/api/server/v2/handlers.go b/daemon/algod/api/server/v2/handlers.go index 0f7b0661bb..5916aa121e 100644 --- a/daemon/algod/api/server/v2/handlers.go +++ b/daemon/algod/api/server/v2/handlers.go @@ -238,13 +238,15 @@ func (v2 *Handlers) AccountInformation(ctx echo.Context, address string, params if err != nil { return internalError(ctx, err, errFailedLookingUpLedger, v2.Log) } - block, _, err := myLedger.BlockCert(basics.Round(lastRound)) + + latestBlkHdr, err := myLedger.BlockHdr(lastRound) if err != nil { - return internalError(ctx, err, errFailedLookingUpLedger, v2.Log) + return internalError(ctx, err, errFailedRetrievingLatestBlockHeaderStatus, v2.Log) } - consensus, ok := config.Consensus[block.CurrentProtocol] + + consensus, ok := config.Consensus[latestBlkHdr.CurrentProtocol] if !ok { - return notFound(ctx, errors.New(errInternalFailure), errInternalFailure, v2.Log) + return notFound(ctx, errors.New(errInternalFailure), "could not retrieve consensus information for current protocol", v2.Log) } if handle == protocol.CodecHandle { @@ -278,9 +280,7 @@ func (v2 *Handlers) AccountInformation(ctx echo.Context, address string, params } } - minBalance := record.MinBalance(&consensus) - - account, err := AccountDataToAccount(address, &record, assetsCreators, lastRound, amountWithoutPendingRewards, minBalance) + account, err := AccountDataToAccount(address, &record, assetsCreators, lastRound, &consensus, amountWithoutPendingRewards) if err != nil { return internalError(ctx, err, errInternalFailure, v2.Log) } From 42adb53efdb41f22591e38506617a8dadacaa306 Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Mon, 13 Dec 2021 15:28:53 -0500 Subject: [PATCH 18/32] longer if clearer name for execute_singleton() --- test/scripts/e2e_subs/goal/atomic_abi.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/test/scripts/e2e_subs/goal/atomic_abi.py b/test/scripts/e2e_subs/goal/atomic_abi.py index da7f881176..bacc979757 100644 --- a/test/scripts/e2e_subs/goal/atomic_abi.py +++ b/test/scripts/e2e_subs/goal/atomic_abi.py @@ -29,7 +29,7 @@ def __init__( """ self.goal = goal self.app_id = app_id - self.contract_abi_json = contract_abi_json # for cloning only + self.contract_abi_json = contract_abi_json self.caller_acct = caller_acct self.sp = sp @@ -127,7 +127,7 @@ def execute_atomic_group( self.execution_summaries = self._build_summaries() return self.execution_results, self.execution_summaries - def execute_singleton( + def execute_singleton_group( self, method_handle: str, method_args: list, @@ -138,6 +138,13 @@ def execute_singleton( lease: bytes = None, rekey_to: str = None, ) -> Tuple[atc.AtomicTransactionResponse, "MethodCallSummary"]: + """ + Note: the run_XYZ() dynamically generated methods are recommended over execute_singleton_group() + in most situation because they clone() the AtomicABI object first before execution. + + However, in cases when method signatures are not known a-priori and only a single method + needs to be executed, execute_singleton_group() is needed. + """ assert self.execution_results is None, self.CALL_TWICE_ERROR abi_meth = self.handle2meth[method_handle]["abi_meth"] self.add_method_call( From 7dd6db4fc418e32b43e9cb38dcf25817a8b4043c Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Tue, 14 Dec 2021 09:23:20 -0500 Subject: [PATCH 19/32] Pass one .exp test and update the README --- test/e2e-go/cli/goal/expect/README.md | 9 +++++++++ test/e2e-go/cli/goal/expect/goalAccountInfoTest.exp | 9 ++++++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/test/e2e-go/cli/goal/expect/README.md b/test/e2e-go/cli/goal/expect/README.md index ea3dd026dd..cde94390f3 100644 --- a/test/e2e-go/cli/goal/expect/README.md +++ b/test/e2e-go/cli/goal/expect/README.md @@ -77,6 +77,15 @@ go test -v test/e2e-go/cli/goal/expect/goal_expect_test.go TESTFILTER=foobar[0-9]Test TESTDIR=baz go test -v test/e2e-go/cli/goal/expect/goal_expect_test.go ``` +In particular, if you want to run `goalAccountInfoTest.exp` you'll need to create a temporary directory such as `deletemeTemp` with +``` +mkdir test/e2e-go/cli/goal/expect/deletemeTemp +``` +and then run the following command: +``` +TESTFILTER=goalAccountInfoTest TESTDIR=deletemeTemp go test -v test/e2e-go/cli/goal/expect/goal_expect_test.go +``` +If you're running **exactly the same command again**, make sure to _delete_ and _re-create_ the temp directory first. > Of course, a test can always be run directly by `expect`, i.e. `expect rekeyTest.exp $TESTDIR $TESTDATADIR`. diff --git a/test/e2e-go/cli/goal/expect/goalAccountInfoTest.exp b/test/e2e-go/cli/goal/expect/goalAccountInfoTest.exp index 4ba7ce1732..a7e9ad1e32 100644 --- a/test/e2e-go/cli/goal/expect/goalAccountInfoTest.exp +++ b/test/e2e-go/cli/goal/expect/goalAccountInfoTest.exp @@ -40,7 +40,8 @@ Held Assets: Created Apps: \t Opted In Apps: -\t" +\t +Minimum Balance:\t100000 microAlgos" # Check info with no assets puts "goal account info -w $PRIMARY_WALLET_NAME -a $PRIMARY_ACCOUNT_ADDRESS -d $TEST_PRIMARY_NODE_DIR" @@ -97,7 +98,8 @@ Held Assets: Created Apps: \t Opted In Apps: -\t" +\t +Minimum Balance:\t500000 microAlgos" # Check info with assets puts "goal account info -w $PRIMARY_WALLET_NAME -a $PRIMARY_ACCOUNT_ADDRESS -d $TEST_PRIMARY_NODE_DIR" @@ -137,7 +139,8 @@ Created Apps: \tID $GSTATE_APP_ID, $GSTATE_EXTRA_PAGES extra pages, global state used 0/0 uints, 1/$GSTATE_GLOBAL_BYTE_SLICES byte slices \tID $LSTATE_APP_ID, global state used 0/0 uints, 0/$LSTATE_GLOBAL_BYTE_SLICES byte slices Opted In Apps: -\tID $LSTATE_APP_ID, local state used 0/1 uints, 1/$LSTATE_LOCAL_BYTE_SLICES byte slices" +\tID $LSTATE_APP_ID, local state used 0/1 uints, 1/$LSTATE_LOCAL_BYTE_SLICES byte slices +Minimum Balance:\t1578500 microAlgos" # Check info with assets and apps puts "goal account info -w $PRIMARY_WALLET_NAME -a $PRIMARY_ACCOUNT_ADDRESS -d $TEST_PRIMARY_NODE_DIR" From 5ecd5b0a91e5ef5f5fcc05ad90c46ad614c8f117 Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Tue, 14 Dec 2021 18:25:56 -0500 Subject: [PATCH 20/32] Less TEAL, more python testing comments. --- test/scripts/e2e.sh | 4 +- test/scripts/e2e_subs/goal/atomic_abi.py | 57 +++++++++++-------- test/scripts/e2e_subs/goal/atomic_abi_test.py | 2 - .../e2e_subs/tealprogs/abi-min_balance.json | 39 ------------- .../e2e_subs/tealprogs/abi-min_balance.teal | 42 +++----------- 5 files changed, 45 insertions(+), 99 deletions(-) diff --git a/test/scripts/e2e.sh b/test/scripts/e2e.sh index 07fc7fe7de..49273fe075 100755 --- a/test/scripts/e2e.sh +++ b/test/scripts/e2e.sh @@ -124,8 +124,8 @@ if [ -z "$E2E_TEST_FILTER" ] || [ "$E2E_TEST_FILTER" == "SCRIPTS" ]; then . "${TEMPDIR}/ve/bin/activate" "${TEMPDIR}/ve/bin/pip3" install --upgrade pip "${TEMPDIR}/ve/bin/pip3" install --upgrade cryptograpy - # get the latest tip of our python SDK main branch as opposed to what's on pypi: - "${TEMPDIR}/ve/bin/pip3" install --upgrade git+git://github.com/algorand/py-algorand-sdk@master + # pin a version of our python SDK's: + "${TEMPDIR}/ve/bin/pip3" install py-algorand-sdk==1.9.0b1 # enable remote debugging: "${TEMPDIR}/ve/bin/pip3" install --upgrade debugpy duration "e2e client setup" diff --git a/test/scripts/e2e_subs/goal/atomic_abi.py b/test/scripts/e2e_subs/goal/atomic_abi.py index bacc979757..420a6d559c 100644 --- a/test/scripts/e2e_subs/goal/atomic_abi.py +++ b/test/scripts/e2e_subs/goal/atomic_abi.py @@ -12,6 +12,29 @@ class AtomicABI: + """ + AtomicABI allows for easier usage of ABI methods in Python. + + For an abi method such as `factorial(uint64)uint64` + this allows usages such as: + + >>> result = abi.run_factorial(5) + which will: + * create an atomic transaction composer + * add a single metod + + or for an atomic transaction group, and another method + such as `add(uint64,uint64)uint64` + you build up the group with: + + >>> abi.next_abi_call_factorial(5) + >>> abi.next_abi_call_add(29, 13) + + and then execute the group with: + + >>> abi.execute_atomic_group() + """ + CALL_TWICE_ERROR = "Cannot execute this Atomic ABI twice. Instantiate a new object to execute again." def __init__( @@ -34,14 +57,13 @@ def __init__( self.sp = sp assert ( - self.app_id and self.app_id > 0 + self.app_id ), f"must have already created the app but have app_id {self.app_id}" assert ( self.caller_acct in self.goal.internal_wallet ), "aborting AtomicABI - will not be able to transact without signing authority" - # try very hard to parse the ABI contract self.contract_abi_json_path: str = None try: cajson = open(contract_abi_json, "rt").read().strip() @@ -49,7 +71,6 @@ def __init__( except Exception: cajson = contract_abi_json - self.contract_abi_json_path = contract_abi_json cadict = json.loads(cajson) cadict["appId"] = self.app_id self.contract: abi.Contract = abi.Contract.from_json(json.dumps(cadict)) @@ -60,9 +81,11 @@ def __init__( ), "aborting AtomicABI - cannot execute without a caller_acct" self.signer = self.get_atxn_signer() + # list of lists of method_args for each of the methods to be called: self.method_args: List[list] = [] - self.sigs2selector: Dict[str, str] = {} - self.handle2meth: Dict[str, dict] = {} + + self.sig2selector: Dict[str, str] = {} + self._meth_dict: Dict[str, dict] = {} self.execution_results: atc.AtomicTransactionResponse = None self.execution_summaries: List[MethodCallSummary] = None @@ -81,8 +104,8 @@ def __init__( ) signature = abi_meth.get_signature() selector = "0x" + abi_meth.get_selector().hex() - self.sigs2selector[signature] = selector - self.handle2meth[handle] = { + self.sig2selector[signature] = selector + self._meth_dict[handle] = { "signature": signature, "selector": selector, "abi_meth": abi_meth, @@ -93,7 +116,7 @@ def __init__( } @classmethod - def factory( + def _clone( cls, obj, caller_acct: str = None, new_suggested_params: bool = True ) -> "AtomicABI": """ @@ -112,7 +135,7 @@ def factory( def clone( self, caller_acct: str = None, new_suggested_params: bool = True ) -> "AtomicABI": - return self.factory( + return self._clone( self, caller_acct=caller_acct, new_suggested_params=new_suggested_params ) @@ -146,7 +169,7 @@ def execute_singleton_group( needs to be executed, execute_singleton_group() is needed. """ assert self.execution_results is None, self.CALL_TWICE_ERROR - abi_meth = self.handle2meth[method_handle]["abi_meth"] + abi_meth = self._meth_dict[method_handle]["abi_meth"] self.add_method_call( abi_meth, method_args, @@ -160,7 +183,7 @@ def execute_singleton_group( return s[0].result.return_value def dump_selectors(self) -> str: - return json.dumps(self.sigs2selector, indent=4, sort_keys=True) + return json.dumps(self.sig2selector, indent=4, sort_keys=True) def _build_summaries(self) -> List["MethodCallSummary"]: assert ( @@ -282,18 +305,6 @@ def add_method_call( def _attach_dynamic_method_calls( self, name: str, adder_func: Callable, run_now_func: Callable ) -> tuple: - """ - For an abi method such as "factorial(uint64)uint64" - this allows usages such as: - >>> abi.next_abi_call_factorial(5) - which will delegate to AtomicTransactionComposer with - atc.add_method_call(app_id, abi_factorial_method, ...) - - For immediate execuation, the following usages are supported: - >>> abi.run_factorial(5) - which will run add the method call as above, and then run - execute_atomic_group() - """ adder_meth = types.MethodType(adder_func, self) adder_meth_name = self.abi_composer_name(name) setattr(self, adder_meth_name, adder_meth) diff --git a/test/scripts/e2e_subs/goal/atomic_abi_test.py b/test/scripts/e2e_subs/goal/atomic_abi_test.py index e7cf153207..3ea3502ebd 100644 --- a/test/scripts/e2e_subs/goal/atomic_abi_test.py +++ b/test/scripts/e2e_subs/goal/atomic_abi_test.py @@ -135,9 +135,7 @@ def test_init(init_only=False): def test_dynamic_methods(): - abi = test_init(init_only=True) - for meth in contract["methods"]: name = meth["name"] adder_meth_name = abi.abi_composer_name(name) diff --git a/test/scripts/e2e_subs/tealprogs/abi-min_balance.json b/test/scripts/e2e_subs/tealprogs/abi-min_balance.json index 47d2be090b..48adb1f5cc 100644 --- a/test/scripts/e2e_subs/tealprogs/abi-min_balance.json +++ b/test/scripts/e2e_subs/tealprogs/abi-min_balance.json @@ -25,45 +25,6 @@ "returns": { "type": "byte[]" } - }, - { - "name": "base64_decode", - "desc": "Decode base64 arg1 using the encoding defined by arg0 (either 'URLEncoding' or 'StdEncoding') ", - "args": [ - { - "type": "string" - }, - { - "type": "string" - } - ], - "returns": { - "type": "string" - } - }, - { - "name": "_optIn", - "desc": "just opt in", - "args": [ - { - "type": "uint64" - } - ], - "returns": { - "type": "uint64" - } - }, - { - "name": "_closeOut", - "desc": "just close out", - "args": [ - { - "type": "uint64" - } - ], - "returns": { - "type": "uint64" - } } ] } \ No newline at end of file diff --git a/test/scripts/e2e_subs/tealprogs/abi-min_balance.teal b/test/scripts/e2e_subs/tealprogs/abi-min_balance.teal index e0bd46af5f..b333e8d95a 100644 --- a/test/scripts/e2e_subs/tealprogs/abi-min_balance.teal +++ b/test/scripts/e2e_subs/tealprogs/abi-min_balance.teal @@ -1,6 +1,9 @@ #pragma version 6 - // TODO - some explanation - // TODO - comply with best practices (optin, delete, etc...) + // Program for testing some simple functions using the ABI. + // + // * See min_balance.json for the companion ABI Contract. + // * For how to call using ABI conventions, see min_balance.py + txn ApplicationID bz handle_no_questions_asked @@ -12,21 +15,11 @@ txn OnCompletion int OptIn == - bnz handle_optIn - - err // TODO - handle more than just NoOp's - -handle_noop: - txna ApplicationArgs 0 - byte 0x80630032 // _closeOut(uint64)uint64 - == bnz handle_no_questions_asked - txn ApplicationArgs 0 - byte 0x4f30c3ce // base64_decode(string,string)string - == - bnz handle_base64_decode + err +handle_noop: txn ApplicationArgs 0 byte 0xd363f563 // complement(byte[])byte[] (tilde "~"" is too exotic for official signature) == @@ -39,13 +32,6 @@ handle_noop: err -handle_optIn: - txna ApplicationArgs 0 - byte 0x9b122fc1 // _optIn(uint64)uint64 - == - bnz handle_no_questions_asked - - handle_no_questions_asked: int 1 b return_uint64 @@ -57,19 +43,9 @@ handle_min_balance: min_balance b return_uint64 -handle_base64_decode: handle_b~: - byte "abcde" - b return_bytes - -handle_base64URL_decode: - callsub extract_abi_string_arg1 - base64_decode URLAlph - b return_bytes - -handle_base64Std_decode: - callsub extract_abi_string_arg1 - base64_decode StdAlph + b extract_abi_string_arg1 + b~ b return_bytes extract_abi_string_arg1: From 277c6ceb0f477897cfe4ca6af256c2a0043bd9ae Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Wed, 15 Dec 2021 10:41:43 -0500 Subject: [PATCH 21/32] notFound --> internalError --- daemon/algod/api/server/v2/handlers.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/daemon/algod/api/server/v2/handlers.go b/daemon/algod/api/server/v2/handlers.go index 5916aa121e..757eaa07dd 100644 --- a/daemon/algod/api/server/v2/handlers.go +++ b/daemon/algod/api/server/v2/handlers.go @@ -246,7 +246,7 @@ func (v2 *Handlers) AccountInformation(ctx echo.Context, address string, params consensus, ok := config.Consensus[latestBlkHdr.CurrentProtocol] if !ok { - return notFound(ctx, errors.New(errInternalFailure), "could not retrieve consensus information for current protocol", v2.Log) + return internalError(ctx, errors.New(errInternalFailure), "could not retrieve consensus information for current protocol", v2.Log) } if handle == protocol.CodecHandle { From 992609b5b800035eb5a6117c08b6507a7cc526de Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Thu, 16 Dec 2021 15:31:12 -0500 Subject: [PATCH 22/32] removing ABI dependency --- test/scripts/e2e.sh | 7 +- test/scripts/e2e_subs/goal/__init__.py | 1 - test/scripts/e2e_subs/goal/atomic_abi.py | 337 ------------------ test/scripts/e2e_subs/goal/atomic_abi_test.py | 145 -------- test/scripts/e2e_subs/min_balance.py | 138 ++++--- .../e2e_subs/tealprogs/abi-min_balance.json | 30 -- ...{abi-min_balance.teal => min_balance.teal} | 0 7 files changed, 96 insertions(+), 562 deletions(-) delete mode 100644 test/scripts/e2e_subs/goal/atomic_abi.py delete mode 100644 test/scripts/e2e_subs/goal/atomic_abi_test.py delete mode 100644 test/scripts/e2e_subs/tealprogs/abi-min_balance.json rename test/scripts/e2e_subs/tealprogs/{abi-min_balance.teal => min_balance.teal} (100%) diff --git a/test/scripts/e2e.sh b/test/scripts/e2e.sh index 49273fe075..e1a7fd3cdd 100755 --- a/test/scripts/e2e.sh +++ b/test/scripts/e2e.sh @@ -124,9 +124,12 @@ if [ -z "$E2E_TEST_FILTER" ] || [ "$E2E_TEST_FILTER" == "SCRIPTS" ]; then . "${TEMPDIR}/ve/bin/activate" "${TEMPDIR}/ve/bin/pip3" install --upgrade pip "${TEMPDIR}/ve/bin/pip3" install --upgrade cryptograpy - # pin a version of our python SDK's: + + # Pin a version of our python SDK's so that breaking changes don't spuriously break our tests. + # Please update as necessary. "${TEMPDIR}/ve/bin/pip3" install py-algorand-sdk==1.9.0b1 - # enable remote debugging: + + # Enable remote debugging: "${TEMPDIR}/ve/bin/pip3" install --upgrade debugpy duration "e2e client setup" diff --git a/test/scripts/e2e_subs/goal/__init__.py b/test/scripts/e2e_subs/goal/__init__.py index b7bb42f26d..2835cc126c 100755 --- a/test/scripts/e2e_subs/goal/__init__.py +++ b/test/scripts/e2e_subs/goal/__init__.py @@ -1,2 +1 @@ from .goal import * -from .atomic_abi import * diff --git a/test/scripts/e2e_subs/goal/atomic_abi.py b/test/scripts/e2e_subs/goal/atomic_abi.py deleted file mode 100644 index 420a6d559c..0000000000 --- a/test/scripts/e2e_subs/goal/atomic_abi.py +++ /dev/null @@ -1,337 +0,0 @@ -import json -from subprocess import call -from typing import Callable, Dict, List, Union, Tuple -from pathlib import Path -import types - -from goal import Goal, text - -import algosdk.atomic_transaction_composer as atc -import algosdk.abi as abi -import algosdk.future.transaction as txn - - -class AtomicABI: - """ - AtomicABI allows for easier usage of ABI methods in Python. - - For an abi method such as `factorial(uint64)uint64` - this allows usages such as: - - >>> result = abi.run_factorial(5) - which will: - * create an atomic transaction composer - * add a single metod - - or for an atomic transaction group, and another method - such as `add(uint64,uint64)uint64` - you build up the group with: - - >>> abi.next_abi_call_factorial(5) - >>> abi.next_abi_call_add(29, 13) - - and then execute the group with: - - >>> abi.execute_atomic_group() - """ - - CALL_TWICE_ERROR = "Cannot execute this Atomic ABI twice. Instantiate a new object to execute again." - - def __init__( - self, - goal: Goal, - app_id: int, - contract_abi_json: Union[Path, str], - caller_acct: str, - sp: txn.SuggestedParams = None, - ): - """ - Note: app_id will over-write whatever app_id was defined in `contract_abi_json` - - Also, we're assuming a single caller_account which is also the signer for all the transactions. - """ - self.goal = goal - self.app_id = app_id - self.contract_abi_json = contract_abi_json - self.caller_acct = caller_acct - self.sp = sp - - assert ( - self.app_id - ), f"must have already created the app but have app_id {self.app_id}" - - assert ( - self.caller_acct in self.goal.internal_wallet - ), "aborting AtomicABI - will not be able to transact without signing authority" - - self.contract_abi_json_path: str = None - try: - cajson = open(contract_abi_json, "rt").read().strip() - self.contract_abi_json_path = contract_abi_json - except Exception: - cajson = contract_abi_json - - cadict = json.loads(cajson) - cadict["appId"] = self.app_id - self.contract: abi.Contract = abi.Contract.from_json(json.dumps(cadict)) - - self.sp = sp - assert ( - self.caller_acct - ), "aborting AtomicABI - cannot execute without a caller_acct" - self.signer = self.get_atxn_signer() - - # list of lists of method_args for each of the methods to be called: - self.method_args: List[list] = [] - - self.sig2selector: Dict[str, str] = {} - self._meth_dict: Dict[str, dict] = {} - - self.execution_results: atc.AtomicTransactionResponse = None - self.execution_summaries: List[MethodCallSummary] = None - - self.atomic_transaction_composer = atc.AtomicTransactionComposer() - - for abi_meth in self.contract.methods: - ( - handle, - am_name, - adder_meth, - rn_name, - run_now_meth, - ) = self._attach_dynamic_method_calls( - abi_meth.name, *self._method_factories(abi_meth) - ) - signature = abi_meth.get_signature() - selector = "0x" + abi_meth.get_selector().hex() - self.sig2selector[signature] = selector - self._meth_dict[handle] = { - "signature": signature, - "selector": selector, - "abi_meth": abi_meth, - "adder_meth_name": am_name, - "adder_meth": adder_meth, - "run_now_meth_name": rn_name, - "run_now_meth": run_now_meth, - } - - @classmethod - def _clone( - cls, obj, caller_acct: str = None, new_suggested_params: bool = True - ) -> "AtomicABI": - """ - new_suggested_params defaults to True because we don't want an intentionally - cloned transaction to clash with a previous one (unless it's in the same round) - """ - sp = obj.goal.algod.suggested_params() if new_suggested_params else obj.sp - return cls( - obj.goal, - obj.app_id, - obj.contract_abi_json, - caller_acct if caller_acct else obj.caller_acct, - sp=sp, - ) - - def clone( - self, caller_acct: str = None, new_suggested_params: bool = True - ) -> "AtomicABI": - return self._clone( - self, caller_acct=caller_acct, new_suggested_params=new_suggested_params - ) - - def execute_atomic_group( - self, wait_rounds: int = 5 - ) -> Tuple[atc.AtomicTransactionResponse, List["MethodCallSummary"]]: - assert self.execution_results is None, self.CALL_TWICE_ERROR - - self.execution_results = self.atomic_transaction_composer.execute( - self.goal.algod, wait_rounds - ) - self.execution_summaries = self._build_summaries() - return self.execution_results, self.execution_summaries - - def execute_singleton_group( - self, - method_handle: str, - method_args: list, - wait_rounds: int = 5, - sp: txn.SuggestedParams = None, - on_complete: txn.OnComplete = txn.OnComplete.NoOpOC, - note: bytes = None, - lease: bytes = None, - rekey_to: str = None, - ) -> Tuple[atc.AtomicTransactionResponse, "MethodCallSummary"]: - """ - Note: the run_XYZ() dynamically generated methods are recommended over execute_singleton_group() - in most situation because they clone() the AtomicABI object first before execution. - - However, in cases when method signatures are not known a-priori and only a single method - needs to be executed, execute_singleton_group() is needed. - """ - assert self.execution_results is None, self.CALL_TWICE_ERROR - abi_meth = self._meth_dict[method_handle]["abi_meth"] - self.add_method_call( - abi_meth, - method_args, - sp=sp, - on_complete=on_complete, - note=note, - lease=lease, - rekey_to=rekey_to, - ) - _, s = self.execute_atomic_group(wait_rounds=wait_rounds) - return s[0].result.return_value - - def dump_selectors(self) -> str: - return json.dumps(self.sig2selector, indent=4, sort_keys=True) - - def _build_summaries(self) -> List["MethodCallSummary"]: - assert ( - self.execution_results - ), "Cannot summarize before calling 'execute_atomic_group()'" - summaries = [] - i = 0 - for meth in self.atomic_transaction_composer.method_dict.values(): - summaries.append( - MethodCallSummary( - meth, - self.method_args[i], - self.execution_results.abi_results[i], - ) - ) - i += 1 - return summaries - - @staticmethod - def _method_factories(abi_meth: abi.method.Method) -> Tuple[Callable, Callable]: - def func_add_method_call( - self, - *args, - sp: txn.SuggestedParams = None, - on_complete: txn.OnComplete = txn.OnComplete.NoOpOC, - note: bytes = None, - lease: bytes = None, - rekey_to: str = None, - ): - return self.add_method_call( - abi_meth, - method_args=args, - sp=sp, - on_complete=on_complete, - note=note, - lease=lease, - rekey_to=rekey_to, - ) - - def func_run_now( - self, - *args, - wait_rounds: int = 5, - sp: txn.SuggestedParams = None, - on_complete: txn.OnComplete = txn.OnComplete.NoOpOC, - note: bytes = None, - lease: bytes = None, - rekey_to: str = None, - ): - abi = self.clone() - abi.add_method_call( - abi_meth, - method_args=args, - sp=sp, - on_complete=on_complete, - note=note, - lease=lease, - rekey_to=rekey_to, - ) - _, s = abi.execute_atomic_group(wait_rounds=wait_rounds) - return s[0].result.return_value - - return func_add_method_call, func_run_now - - def get_suggested_params(self) -> txn.SuggestedParams: - if not self.sp: - self.sp = self.goal.algod.suggested_params() - - return self.sp - - def get_atxn_signer(self, caller_acct: str = None) -> atc.AccountTransactionSigner: - if not caller_acct: - caller_acct = self.caller_acct - sk = self.goal.internal_wallet.get(caller_acct) - if not sk: - raise Exception("Cannot create AccountTransactionSigner") - # TODO: handle querying kmd in the case that sk isn't in the internal wallet - - return atc.AccountTransactionSigner(sk) - - def get_txn_with_signer( - self, txn: txn.Transaction, signer: atc.TransactionSigner = None - ) -> atc.TransactionWithSigner: - if not signer: - signer = self.signer - - return atc.TransactionWithSigner(txn, signer) - - def add_method_call( - self, - method: abi.method.Method, - method_args: list = [], - sp: txn.SuggestedParams = None, - on_complete: txn.OnComplete = txn.OnComplete.NoOpOC, - note: bytes = None, - lease: bytes = None, - rekey_to: str = None, - ) -> "AtomicABI": - if not sp: - sp = self.get_suggested_params() - - self.atomic_transaction_composer.add_method_call( - self.app_id, - method, - self.caller_acct, - sp, - self.signer, - method_args=method_args, - on_complete=on_complete, - note=note, - lease=lease, - rekey_to=rekey_to, - ) - - self.method_args.append(method_args) - - return self - - def _attach_dynamic_method_calls( - self, name: str, adder_func: Callable, run_now_func: Callable - ) -> tuple: - adder_meth = types.MethodType(adder_func, self) - adder_meth_name = self.abi_composer_name(name) - setattr(self, adder_meth_name, adder_meth) - - run_now_meth = types.MethodType(run_now_func, self) - rn_meth_name = self.run_now_method_name(name) - setattr(self, rn_meth_name, run_now_meth) - - return name, adder_meth_name, adder_meth, rn_meth_name, run_now_meth - - @classmethod - def abi_composer_name(cls, method_name: str) -> str: - return f"next_abi_call_{method_name}" - - @classmethod - def run_now_method_name(cls, method_name: str) -> str: - return f"run_{method_name}" - - -class MethodCallSummary: - def __init__(self, method: abi.Method, args: list, result: atc.ABIResult): - self.method = method - self.args = args - self.result = result - - def __str__(self) -> str: - return f"""SELECTOR<<<0x{self.method.get_selector().hex()}>>> -{self.method.get_signature()}: {self.args} - -> -{self.result.return_value}""" diff --git a/test/scripts/e2e_subs/goal/atomic_abi_test.py b/test/scripts/e2e_subs/goal/atomic_abi_test.py deleted file mode 100644 index 3ea3502ebd..0000000000 --- a/test/scripts/e2e_subs/goal/atomic_abi_test.py +++ /dev/null @@ -1,145 +0,0 @@ -import json -from os import confstr_names -from unittest.mock import Mock, patch - -import algosdk.atomic_transaction_composer as atc - -from .atomic_abi import AtomicABI - - -contract = { - "name": "demo-abi", - "appId": None, - "methods": [ - { - "name": "add", - "desc": "Add 2 integers", - "args": [{"type": "uint64"}, {"type": "uint64"}], - "returns": {"type": "uint64"}, - }, - { - "name": "sub", - "desc": "Subtract 2 integers", - "args": [{"type": "uint64"}, {"type": "uint64"}], - "returns": {"type": "uint64"}, - }, - { - "name": "mul", - "desc": "Multiply 2 integers", - "args": [{"type": "uint64"}, {"type": "uint64"}], - "returns": {"type": "uint64"}, - }, - { - "name": "div", - "desc": "Divide 2 integers, throw away the remainder", - "args": [{"type": "uint64"}, {"type": "uint64"}], - "returns": {"type": "uint64"}, - }, - { - "name": "qrem", - "desc": "Divide 2 integers, return both the quotient and remainder", - "args": [{"type": "uint64"}, {"type": "uint64"}], - "returns": {"type": "(uint64,uint64)"}, - }, - { - "name": "reverse", - "desc": "Reverses a string", - "args": [{"type": "string"}], - "returns": {"type": "string"}, - }, - { - "name": "txntest", - "desc": "just check it", - "args": [{"type": "uint64"}, {"type": "pay"}, {"type": "uint64"}], - "returns": {"type": "uint64"}, - }, - { - "name": "concat_strings", - "desc": "concat some strings", - "args": [{"type": "string[]"}], - "returns": {"type": "string"}, - }, - { - "name": "manyargs", - "desc": "Try to send 20 arguments", - "args": [ - {"type": "uint64"}, - {"type": "uint64"}, - {"type": "uint64"}, - {"type": "uint64"}, - {"type": "uint64"}, - {"type": "uint64"}, - {"type": "uint64"}, - {"type": "uint64"}, - {"type": "uint64"}, - {"type": "uint64"}, - {"type": "uint64"}, - {"type": "uint64"}, - {"type": "uint64"}, - {"type": "uint64"}, - {"type": "uint64"}, - {"type": "uint64"}, - {"type": "uint64"}, - {"type": "uint64"}, - {"type": "uint64"}, - {"type": "uint64"}, - ], - "returns": {"type": "uint64"}, - }, - { - "name": "_optIn", - "desc": "just opt in", - "args": [{"type": "uint64"}], - "returns": {"type": "uint64"}, - }, - { - "name": "_closeOut", - "desc": "just close out", - "args": [{"type": "uint64"}], - "returns": {"type": "uint64"}, - }, - ], -} - - -def test_fixture(): - num_methods = len(contract["methods"]) - assert num_methods == 11 - assert json.loads(json.dumps(contract))["appId"] is None - - -def test_init(init_only=False): - goal = Mock() - caller_account = "mega whale" - sk = Mock() - goal.internal_wallet = {caller_account: sk} - - app_id = 42 - contract_abi_json = json.dumps(contract) - sp = Mock() - abi = AtomicABI(goal, app_id, contract_abi_json, caller_account, sp=sp) - if init_only: - return abi - - assert abi.app_id == app_id - assert abi.caller_acct == caller_account - assert abi.sp == sp - - assert abi.contract_abi_json == contract_abi_json - assert abi.contract.name == "demo-abi" - assert abi.contract.app_id == app_id - - assert abi.signer.private_key == sk - num_methods = len(contract["methods"]) - assert num_methods == len(abi.contract.methods) - - -def test_dynamic_methods(): - abi = test_init(init_only=True) - for meth in contract["methods"]: - name = meth["name"] - adder_meth_name = abi.abi_composer_name(name) - assert getattr(abi, adder_meth_name, None) - - run_now_method_name = abi.run_now_method_name(name) - assert getattr(abi, run_now_method_name, None) diff --git a/test/scripts/e2e_subs/min_balance.py b/test/scripts/e2e_subs/min_balance.py index 8c8ddabee8..0c29997822 100755 --- a/test/scripts/e2e_subs/min_balance.py +++ b/test/scripts/e2e_subs/min_balance.py @@ -1,12 +1,13 @@ #!/usr/bin/env python +from base64 import b64decode from datetime import datetime from pathlib import PurePath import sys import algosdk.future.transaction as txn -from goal import Goal, AtomicABI +from goal import Goal CONSENSUS_MIN_BALANCE = 100_000 ASSET_MIN_BALANCE = 100_000 @@ -37,6 +38,25 @@ def initialize_debugger(): print("Visual Studio Code debugger is now attached", flush=True) +TEAL = f"""#pragma version 6 + byte "Hello Min Balance!" + log + + // even when creating the app, calc the min balance: + byte "min_balance=" + log + + txn Accounts 0 + min_balance + itob + log + b handle_gtg + +handle_gtg: + int 1 + return""" + + if INTERACTIVE: initialize_debugger() @@ -45,28 +65,45 @@ def get_pysdk_min_balance(goal, account): return goal.algod.account_info(account)["min-balance"] -def get_teal_min_balance(abi, account): - # can't execute an abi object twice so must clone it before each execution: - abi = abi.clone(caller_acct=account) +def create_sender_min_balance_app(goal): + txinfo, err = goal.app_create(goal.account, goal.assemble(TEAL)) + assert not err, f"err: {err}" + + appid = txinfo["application-index"] + creator_min_balance = int.from_bytes(b64decode(txinfo["logs"][2]), byteorder="big") + return appid, creator_min_balance - def get_txn_sig(): - return abi.get_txn_with_signer( - txn.PaymentTxn(account, abi.goal.algod.suggested_params(), account, 10_000) - ) - return abi.run_sender_min_balance(get_txn_sig()) +def assert_teal_min_balance( + goal, account, expected_account_mb, expected_goal_mb, goal_only=False +): + appid, goal_mb = create_sender_min_balance_app(goal) + assert ( + goal_mb == expected_goal_mb + ), f"GOAL teal v. expected: {goal_mb} != {expected_goal_mb}" + txinfo, err = goal.app_call(account, appid) + assert not err, f"err = {err}" -def assert_min_balance(abi_or_goal, account, expected_min_balance, skip_abi=False): - goal = abi_or_goal if skip_abi else abi_or_goal.goal + if goal_only: + return + + min_balance = int.from_bytes(b64decode(txinfo["logs"][2]), byteorder="big") + assert ( + min_balance == expected_account_mb + ), f"SENDER teal v. expected: {min_balance} != {expected_account_mb}" + + +def assert_min_balance( + goal, account, expected_sender_mb, expected_goal_mb, goal_only=False +): algod_mb = get_pysdk_min_balance(goal, account) assert ( - algod_mb == expected_min_balance - ), f"case 1: {algod_mb} != {expected_min_balance}" - if not skip_abi: - abi = abi_or_goal - teal_mb = get_teal_min_balance(abi, account) - assert algod_mb == teal_mb, f"case 2: {algod_mb} != {teal_mb}" + algod_mb == expected_sender_mb + ), f"SENDER algod v. expected: {algod_mb} != {expected_sender_mb}" + assert_teal_min_balance( + goal, account, expected_sender_mb, expected_goal_mb, goal_only=goal_only + ) script_path, WALLET = sys.argv @@ -79,24 +116,11 @@ def assert_min_balance(abi_or_goal, account, expected_min_balance, skip_abi=Fals print(f"Running {SCRIPT} inside {CWD} @ {stamp}") # Initialize goal -goal = Goal(WALLET, autosend=False) -if INTERACTIVE: - # good to know so you can query the temp REST endpoints - rest_endpoints = goal.get_endpoint_info() +goal = Goal(WALLET, autosend=True) +rest_endpoints = goal.get_endpoint_info() +print(f"Python Goal cennected to {rest_endpoints}") -# Initialize AtomicABI using the min-balance TEAL app: -approval_teal_path = TEAL_DIR / "abi-min_balance.teal" -print(f"approval_teal_path: {approval_teal_path}") -approval_teal = goal.assemble(approval_teal_path) -txinfo, err = goal.app_create(goal.account, approval_teal, send=True) -print(f"txinfo for create request: {txinfo}") -app_id = txinfo["application-index"] -assert_min_balance( - goal, goal.account, CONSENSUS_MIN_BALANCE + APP_MIN_BALANCE, skip_abi=True -) - -# ABI needs funded accounts: joe = goal.new_account() flo = goal.new_account() @@ -106,12 +130,12 @@ def assert_min_balance(abi_or_goal, account, expected_min_balance, skip_abi=Fals txinfo, err = goal.pay(goal.account, flo, amt=100_000_000, send=True) -abi = AtomicABI(goal, app_id, TEAL_DIR / "abi-min_balance.json", joe) - - # starting out, should be at global min -assert_min_balance(abi, flo, CONSENSUS_MIN_BALANCE) -assert_min_balance(abi, joe, CONSENSUS_MIN_BALANCE) +expected_goal_mb = CONSENSUS_MIN_BALANCE + APP_MIN_BALANCE +assert_min_balance(goal, flo, CONSENSUS_MIN_BALANCE, expected_goal_mb) + +expected_goal_mb += APP_MIN_BALANCE +assert_min_balance(goal, joe, CONSENSUS_MIN_BALANCE, expected_goal_mb) # flo creates an asset @@ -122,7 +146,8 @@ def assert_min_balance(abi_or_goal, account, expected_min_balance, skip_abi=Fals assets = {"Gold": txinfo["asset-index"]} expected_mb = CONSENSUS_MIN_BALANCE + ASSET_MIN_BALANCE -assert_min_balance(abi, flo, expected_mb) +expected_goal_mb += APP_MIN_BALANCE +assert_min_balance(goal, flo, expected_mb, expected_goal_mb) # goal creates 2 assets @@ -138,31 +163,49 @@ def assert_min_balance(abi_or_goal, account, expected_min_balance, skip_abi=Fals assets[asset] = txinfo["asset-index"] assert not err, err -expected_mb = CONSENSUS_MIN_BALANCE + APP_MIN_BALANCE + 2 * ASSET_MIN_BALANCE -assert_min_balance(goal, goal.account, expected_mb, skip_abi=True) +expected_goal_mb += 2 * ASSET_MIN_BALANCE +assert_min_balance( + goal, + goal.account, + expected_goal_mb, + expected_goal_mb + APP_MIN_BALANCE, + goal_only=True, +) +expected_goal_mb += APP_MIN_BALANCE # joe opts into Gold and Silver: txinfo, err = goal.axfer(joe, joe, 0, assets["Gold"], send=True) txinfo, err = goal.axfer(joe, joe, 0, assets["Silver"], send=True) assert not err, err + expected_mb = CONSENSUS_MIN_BALANCE + 2 * ASSET_MIN_BALANCE -assert_min_balance(abi, joe, expected_mb) +expected_goal_mb += APP_MIN_BALANCE +assert_min_balance(goal, joe, expected_mb, expected_goal_mb) # next, destroy Gold and Silver txinfo, err = goal.acfg(flo, index=assets["Gold"], send=True) assert not err, err expected_mb = CONSENSUS_MIN_BALANCE -assert_min_balance(abi, flo, expected_mb) +expected_goal_mb += APP_MIN_BALANCE +assert_min_balance(goal, flo, expected_mb, expected_goal_mb) txinfo, err = goal.acfg(goal.account, index=assets["Silver"], send=True) assert not err, err -expected_mb = CONSENSUS_MIN_BALANCE + APP_MIN_BALANCE + ASSET_MIN_BALANCE -assert_min_balance(goal, goal.account, expected_mb, skip_abi=True) +expected_goal_mb -= ASSET_MIN_BALANCE +assert_min_balance( + goal, + goal.account, + expected_goal_mb, + expected_goal_mb + APP_MIN_BALANCE, + goal_only=True, +) +expected_goal_mb += APP_MIN_BALANCE + # flo creates an app with 2 global schema ints, 10 global schema bytes, 1 extra page txinfo, err = goal.app_create( flo, - approval_teal, + goal.assemble(TEAL), local_schema=(2, 0), global_schema=(0, 10), extra_pages=1, @@ -179,7 +222,8 @@ def assert_min_balance(abi_or_goal, account, expected_min_balance, skip_abi=Fals + 10 * APP_BYTES_MIN_BALANCE + EXTRA_PAGE_MIN_BALANCE ) -assert_min_balance(abi, flo, expected_mb) +expected_goal_mb += APP_MIN_BALANCE +assert_min_balance(goal, flo, expected_mb, expected_goal_mb) stamp = datetime.now().strftime("%Y%m%d_%H%M%S") print(f"Running {SCRIPT} inside {CWD} @ {stamp}") diff --git a/test/scripts/e2e_subs/tealprogs/abi-min_balance.json b/test/scripts/e2e_subs/tealprogs/abi-min_balance.json deleted file mode 100644 index 48adb1f5cc..0000000000 --- a/test/scripts/e2e_subs/tealprogs/abi-min_balance.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "name": "opCodes", - "appId": null, - "methods": [ - { - "name": "sender_min_balance", - "desc": "Calculate the minimum balance of sender for referenced pay txn arg", - "args": [ - { - "type": "pay" - } - ], - "returns": { - "type": "uint64" - } - }, - { - "name": "complement", - "desc": "The complement (aka b~) of arg0 viewed as a bitstring", - "args": [ - { - "type": "byte[]" - } - ], - "returns": { - "type": "byte[]" - } - } - ] -} \ No newline at end of file diff --git a/test/scripts/e2e_subs/tealprogs/abi-min_balance.teal b/test/scripts/e2e_subs/tealprogs/min_balance.teal similarity index 100% rename from test/scripts/e2e_subs/tealprogs/abi-min_balance.teal rename to test/scripts/e2e_subs/tealprogs/min_balance.teal From 5d20acb9d5d6cc7ed691eeec1ae4621475411308 Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Thu, 16 Dec 2021 16:31:21 -0500 Subject: [PATCH 23/32] remove the teal file --- .../e2e_subs/tealprogs/min_balance.teal | 86 ------------------- 1 file changed, 86 deletions(-) delete mode 100644 test/scripts/e2e_subs/tealprogs/min_balance.teal diff --git a/test/scripts/e2e_subs/tealprogs/min_balance.teal b/test/scripts/e2e_subs/tealprogs/min_balance.teal deleted file mode 100644 index b333e8d95a..0000000000 --- a/test/scripts/e2e_subs/tealprogs/min_balance.teal +++ /dev/null @@ -1,86 +0,0 @@ -#pragma version 6 - // Program for testing some simple functions using the ABI. - // - // * See min_balance.json for the companion ABI Contract. - // * For how to call using ABI conventions, see min_balance.py - - txn ApplicationID - bz handle_no_questions_asked - - txn OnCompletion - int NoOp - == - bnz handle_noop - - txn OnCompletion - int OptIn - == - bnz handle_no_questions_asked - - err - -handle_noop: - txn ApplicationArgs 0 - byte 0xd363f563 // complement(byte[])byte[] (tilde "~"" is too exotic for official signature) - == - bnz handle_b~ - - txn ApplicationArgs 0 - byte 0xa9c9f612 // sender_min_balance(pay)uint64 - == - bnz handle_min_balance - - err - -handle_no_questions_asked: - int 1 - b return_uint64 - -// opCodes - -handle_min_balance: - txn Accounts 0 - min_balance - b return_uint64 - -handle_b~: - b extract_abi_string_arg1 - b~ - b return_bytes - -extract_abi_string_arg1: - txna ApplicationArgs 1 - extract 2 0 - retsub - -// Return handling based on type - -return_2_uint64: - itob - swap - itob - swap - b end_return - -return_bytes: - dup - len - itob - extract 6 2 - swap - concat - b end_return - -return_uint64: - itob - b end_return - -// ABI return prefix and logging - -end_return: - byte 0x151f7c75 - swap - concat - log - int 1 - return From 19ed86601234736bc8ad76d10c8cfacf1e35db3f Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Thu, 16 Dec 2021 17:57:03 -0500 Subject: [PATCH 24/32] revert --- test/scripts/e2e_subs/goal/goal.py | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/test/scripts/e2e_subs/goal/goal.py b/test/scripts/e2e_subs/goal/goal.py index 6f6fe6f145..921d2c3ea2 100755 --- a/test/scripts/e2e_subs/goal/goal.py +++ b/test/scripts/e2e_subs/goal/goal.py @@ -112,18 +112,6 @@ def open_kmd(self, algodata, kmd_address=None): kmd_address = "http://" + net return algosdk.kmd.KMDClient(kmd_token, kmd_address) - def get_endpoint_info(self) -> dict: - return { - "algod": { - "url": self.algod.algod_address, - "auth": self.algod.algod_token, - }, - "kmd": { - "url": self.kmd.kmd_address, - "auth": self.kmd.kmd_token, - }, - } - def open_wallet(self, name): if name: self.wallet_name = name From 19e2a400332846239d8e99558006d7522734205c Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Thu, 16 Dec 2021 18:01:53 -0500 Subject: [PATCH 25/32] reorder functions --- test/scripts/e2e_subs/min_balance.py | 44 ++++++++++++++++++---------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/test/scripts/e2e_subs/min_balance.py b/test/scripts/e2e_subs/min_balance.py index 0c29997822..57c98d5360 100755 --- a/test/scripts/e2e_subs/min_balance.py +++ b/test/scripts/e2e_subs/min_balance.py @@ -9,19 +9,6 @@ from goal import Goal -CONSENSUS_MIN_BALANCE = 100_000 -ASSET_MIN_BALANCE = 100_000 -APP_MIN_BALANCE = 100_000 -OPTIN_MIN_BALANCE = 100_000 -# app schemas: -APP_KV_MIN_BALANCE = 25_000 -APP_INTS_MIN_BALANCE = 3_500 -APP_BYTES_MIN_BALANCE = 25_000 - -# per userBalance.go::MinBalance() as of Dec 2021: -EXTRA_PAGE_MIN_BALANCE = APP_MIN_BALANCE - - # Set INTERACTIVE True if you want to run a remote debugger interactively on the given PORT INTERACTIVE, DEBUGPORT = False, 4312 @@ -38,6 +25,22 @@ def initialize_debugger(): print("Visual Studio Code debugger is now attached", flush=True) +if INTERACTIVE: + initialize_debugger() + + +CONSENSUS_MIN_BALANCE = 100_000 +ASSET_MIN_BALANCE = 100_000 +APP_MIN_BALANCE = 100_000 +OPTIN_MIN_BALANCE = 100_000 +# app schemas: +APP_KV_MIN_BALANCE = 25_000 +APP_INTS_MIN_BALANCE = 3_500 +APP_BYTES_MIN_BALANCE = 25_000 + +# per userBalance.go::MinBalance() as of Dec 2021: +EXTRA_PAGE_MIN_BALANCE = APP_MIN_BALANCE + TEAL = f"""#pragma version 6 byte "Hello Min Balance!" log @@ -57,8 +60,17 @@ def initialize_debugger(): return""" -if INTERACTIVE: - initialize_debugger() +def get_endpoint_info(goal) -> dict: + return { + "algod": { + "url": goal.algod.algod_address, + "auth": goal.algod.algod_token, + }, + "kmd": { + "url": goal.kmd.kmd_address, + "auth": goal.kmd.kmd_token, + }, + } def get_pysdk_min_balance(goal, account): @@ -117,7 +129,7 @@ def assert_min_balance( # Initialize goal goal = Goal(WALLET, autosend=True) -rest_endpoints = goal.get_endpoint_info() +rest_endpoints = get_endpoint_info(goal) print(f"Python Goal cennected to {rest_endpoints}") From 084adf08a98610ae0c5caf4215dabc3e093ba0d9 Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Thu, 16 Dec 2021 18:13:06 -0500 Subject: [PATCH 26/32] better endpoint description --- daemon/algod/api/algod.oas2.json | 29 +- daemon/algod/api/algod.oas3.yml | 2 +- .../api/server/v2/generated/private/routes.go | 274 +++++++++--------- .../api/server/v2/generated/private/types.go | 2 +- .../algod/api/server/v2/generated/routes.go | 228 +++++++-------- daemon/algod/api/server/v2/generated/types.go | 2 +- 6 files changed, 267 insertions(+), 270 deletions(-) diff --git a/daemon/algod/api/algod.oas2.json b/daemon/algod/api/algod.oas2.json index 88e28a692b..8884300db3 100644 --- a/daemon/algod/api/algod.oas2.json +++ b/daemon/algod/api/algod.oas2.json @@ -1056,7 +1056,7 @@ "name": "application-id", "in": "path", "required": true - } + } ] }, "/v2/assets/{asset-id}": { @@ -1119,7 +1119,7 @@ "name": "asset-id", "in": "path", "required": true - } + } ] }, "/v2/teal/compile": { @@ -1367,7 +1367,7 @@ "type": "integer" }, "min-balance": { - "description": "MicroAlgo balance required by the account.\n\nThe requirement starts at 100,000 and grows based on asset and application usage.", + "description": "MicroAlgo balance required by the account.\n\nThe requirement grows based on asset and application usage.", "type": "integer" }, "amount-without-pending-rewards": { @@ -1513,8 +1513,8 @@ "properties": { "amount": { "description": "\\[a\\] number of units held.", - "type": "integer", - "x-algorand-format": "uint64" + "type": "integer", + "x-algorand-format": "uint64" }, "asset-id": { "description": "Asset ID of the holding.", @@ -2000,7 +2000,7 @@ "accounts": { "type": "array", "items": { - "$ref": "#/definitions/Account" + "$ref": "#/definitions/Account" } }, "apps": { @@ -2135,7 +2135,7 @@ "asset-index": { "description": "The asset index if the transaction was found and it created an asset.", "type": "integer" - }, + }, "application-index": { "description": "The application index if the transaction was found and it created an application.", "type": "integer" @@ -2196,7 +2196,7 @@ }, "txn": { "description": "The raw signed transaction.", - "type": "object", + "type": "object", "x-algorand-format": "SignedTransaction" } } @@ -2444,7 +2444,7 @@ } } }, - "CatchpointAbortResponse":{ + "CatchpointAbortResponse": { "tags": [ "private" ], @@ -2565,7 +2565,6 @@ } } }, - "ParticipationKeysResponse": { "description": "A list of participation keys", "schema": { @@ -2581,15 +2580,15 @@ "$ref": "#/definitions/ParticipationKey" } }, - "DeleteParticipationIdResponse" : { + "DeleteParticipationIdResponse": { "description": "Participation key got deleted by ID" }, - "PostParticipationResponse" : { + "PostParticipationResponse": { "description": "Participation ID of the submission", "schema": { "type": "object", "required": [ - "partId" + "partId" ], "properties": { "partId": { @@ -2598,9 +2597,7 @@ } } } - }, - "PostTransactionsResponse": { "description": "Transaction ID of the submission.", "schema": { @@ -2769,4 +2766,4 @@ "name": "private" } ] -} +} \ No newline at end of file diff --git a/daemon/algod/api/algod.oas3.yml b/daemon/algod/api/algod.oas3.yml index b5887291ae..86ac76a5d0 100644 --- a/daemon/algod/api/algod.oas3.yml +++ b/daemon/algod/api/algod.oas3.yml @@ -727,7 +727,7 @@ "type": "array" }, "min-balance": { - "description": "MicroAlgo balance required by the account.\n\nThe requirement starts at 100,000 and grows based on asset and application usage.", + "description": "MicroAlgo balance required by the account.\n\nThe requirement grows based on asset and application usage.", "type": "integer" }, "participation": { diff --git a/daemon/algod/api/server/v2/generated/private/routes.go b/daemon/algod/api/server/v2/generated/private/routes.go index 648c8779c0..56baf1f2be 100644 --- a/daemon/algod/api/server/v2/generated/private/routes.go +++ b/daemon/algod/api/server/v2/generated/private/routes.go @@ -277,143 +277,143 @@ func RegisterHandlers(router interface { // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ - "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", + "GUfr6/fX/xsAAP//tpthUSegAAA=", } // GetSwagger returns the Swagger specification corresponding to the generated code diff --git a/daemon/algod/api/server/v2/generated/private/types.go b/daemon/algod/api/server/v2/generated/private/types.go index 0f561e36b2..9e6d5685b8 100644 --- a/daemon/algod/api/server/v2/generated/private/types.go +++ b/daemon/algod/api/server/v2/generated/private/types.go @@ -51,7 +51,7 @@ type Account struct { // MicroAlgo balance required by the account. // - // The requirement starts at 100,000 and grows based on asset and application usage. + // The requirement grows based on asset and application usage. MinBalance uint64 `json:"min-balance"` // AccountParticipation describes the parameters used by this account in consensus protocol. diff --git a/daemon/algod/api/server/v2/generated/routes.go b/daemon/algod/api/server/v2/generated/routes.go index ffd0c35ae2..4d3d7bd11f 100644 --- a/daemon/algod/api/server/v2/generated/routes.go +++ b/daemon/algod/api/server/v2/generated/routes.go @@ -676,120 +676,120 @@ var swaggerSpec = []string{ "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", + "pZTsHHMnfrj8fwEAAP///pnN5DLyAAA=", } // GetSwagger returns the Swagger specification corresponding to the generated code diff --git a/daemon/algod/api/server/v2/generated/types.go b/daemon/algod/api/server/v2/generated/types.go index 79f8435e47..41d33126d8 100644 --- a/daemon/algod/api/server/v2/generated/types.go +++ b/daemon/algod/api/server/v2/generated/types.go @@ -51,7 +51,7 @@ type Account struct { // MicroAlgo balance required by the account. // - // The requirement starts at 100,000 and grows based on asset and application usage. + // The requirement grows based on asset and application usage. MinBalance uint64 `json:"min-balance"` // AccountParticipation describes the parameters used by this account in consensus protocol. From 125bfbfed5ccded551d74eeddb72eb961abcfcf0 Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Thu, 16 Dec 2021 18:13:20 -0500 Subject: [PATCH 27/32] INTERACTIVE switch at the top --- test/scripts/e2e_subs/min_balance.py | 29 +++++++++++++--------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/test/scripts/e2e_subs/min_balance.py b/test/scripts/e2e_subs/min_balance.py index 57c98d5360..701b467a62 100755 --- a/test/scripts/e2e_subs/min_balance.py +++ b/test/scripts/e2e_subs/min_balance.py @@ -42,22 +42,19 @@ def initialize_debugger(): EXTRA_PAGE_MIN_BALANCE = APP_MIN_BALANCE TEAL = f"""#pragma version 6 - byte "Hello Min Balance!" - log - - // even when creating the app, calc the min balance: - byte "min_balance=" - log - - txn Accounts 0 - min_balance - itob - log - b handle_gtg - -handle_gtg: - int 1 - return""" +byte "Hello Min Balance!" +log + +// even when creating the app, calc the min balance: +byte "min_balance=" +log + +txn Accounts 0 +min_balance +itob +log + +int 1""" def get_endpoint_info(goal) -> dict: From ae82da2202ed63a278f0a436a335d6dae5a3e4a4 Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Thu, 16 Dec 2021 18:32:49 -0500 Subject: [PATCH 28/32] revert formatting changes --- daemon/algod/api/algod.oas2.json | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/daemon/algod/api/algod.oas2.json b/daemon/algod/api/algod.oas2.json index 8884300db3..c6e2816d85 100644 --- a/daemon/algod/api/algod.oas2.json +++ b/daemon/algod/api/algod.oas2.json @@ -1056,7 +1056,7 @@ "name": "application-id", "in": "path", "required": true - } + } ] }, "/v2/assets/{asset-id}": { @@ -1119,7 +1119,7 @@ "name": "asset-id", "in": "path", "required": true - } + } ] }, "/v2/teal/compile": { @@ -1513,8 +1513,8 @@ "properties": { "amount": { "description": "\\[a\\] number of units held.", - "type": "integer", - "x-algorand-format": "uint64" + "type": "integer", + "x-algorand-format": "uint64" }, "asset-id": { "description": "Asset ID of the holding.", @@ -2000,7 +2000,7 @@ "accounts": { "type": "array", "items": { - "$ref": "#/definitions/Account" + "$ref": "#/definitions/Account" } }, "apps": { @@ -2135,7 +2135,7 @@ "asset-index": { "description": "The asset index if the transaction was found and it created an asset.", "type": "integer" - }, + }, "application-index": { "description": "The application index if the transaction was found and it created an application.", "type": "integer" @@ -2196,7 +2196,7 @@ }, "txn": { "description": "The raw signed transaction.", - "type": "object", + "type": "object", "x-algorand-format": "SignedTransaction" } } @@ -2444,7 +2444,7 @@ } } }, - "CatchpointAbortResponse": { + "CatchpointAbortResponse":{ "tags": [ "private" ], @@ -2565,6 +2565,7 @@ } } }, + "ParticipationKeysResponse": { "description": "A list of participation keys", "schema": { @@ -2580,15 +2581,15 @@ "$ref": "#/definitions/ParticipationKey" } }, - "DeleteParticipationIdResponse": { + "DeleteParticipationIdResponse" : { "description": "Participation key got deleted by ID" }, - "PostParticipationResponse": { + "PostParticipationResponse" : { "description": "Participation ID of the submission", "schema": { "type": "object", "required": [ - "partId" + "partId" ], "properties": { "partId": { @@ -2597,7 +2598,9 @@ } } } + }, + "PostTransactionsResponse": { "description": "Transaction ID of the submission.", "schema": { @@ -2766,4 +2769,4 @@ "name": "private" } ] -} \ No newline at end of file +} From 5efca2cd5d5e0f277cc1039171b3089bc919c0d5 Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Thu, 16 Dec 2021 18:33:39 -0500 Subject: [PATCH 29/32] more realistic consensus params --- daemon/algod/api/server/v2/account_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/daemon/algod/api/server/v2/account_test.go b/daemon/algod/api/server/v2/account_test.go index 3aca8012f8..61498fbe4d 100644 --- a/daemon/algod/api/server/v2/account_test.go +++ b/daemon/algod/api/server/v2/account_test.go @@ -102,7 +102,7 @@ func TestAccount(t *testing.T) { b := a.WithUpdatedRewards(proto, 100) addr := basics.Address{}.String() - conv, err := AccountDataToAccount(addr, &b, map[basics.AssetIndex]string{}, round, &config.ConsensusParams{MinBalance: 100000}, a.MicroAlgos) + conv, err := AccountDataToAccount(addr, &b, map[basics.AssetIndex]string{}, round, &proto, a.MicroAlgos) require.NoError(t, err) require.Equal(t, addr, conv.Address) require.Equal(t, b.MicroAlgos.Raw, conv.Amount) @@ -196,7 +196,7 @@ func TestAccount(t *testing.T) { // convert the same account a few more times to make sure we always // produce the same generated.Account for i := 0; i < 10; i++ { - anotherConv, err := AccountDataToAccount(addr, &b, map[basics.AssetIndex]string{}, round, &config.ConsensusParams{MinBalance: 100000}, a.MicroAlgos) + anotherConv, err := AccountDataToAccount(addr, &b, map[basics.AssetIndex]string{}, round, &proto, a.MicroAlgos) require.NoError(t, err) require.Equal(t, protocol.EncodeJSON(conv), protocol.EncodeJSON(anotherConv)) From bb5d4a9bf3b29e2eb6b373effccec0a775f5cd82 Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Fri, 17 Dec 2021 10:48:26 -0500 Subject: [PATCH 30/32] Per reviewer suggestions --- daemon/algod/api/server/v2/handlers.go | 9 ++------- test/scripts/e2e_subs/min_balance.py | 2 +- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/daemon/algod/api/server/v2/handlers.go b/daemon/algod/api/server/v2/handlers.go index 757eaa07dd..6541311a34 100644 --- a/daemon/algod/api/server/v2/handlers.go +++ b/daemon/algod/api/server/v2/handlers.go @@ -239,14 +239,9 @@ func (v2 *Handlers) AccountInformation(ctx echo.Context, address string, params return internalError(ctx, err, errFailedLookingUpLedger, v2.Log) } - latestBlkHdr, err := myLedger.BlockHdr(lastRound) + consensus, err := myLedger.ConsensusParams(lastRound) if err != nil { - return internalError(ctx, err, errFailedRetrievingLatestBlockHeaderStatus, v2.Log) - } - - consensus, ok := config.Consensus[latestBlkHdr.CurrentProtocol] - if !ok { - return internalError(ctx, errors.New(errInternalFailure), "could not retrieve consensus information for current protocol", v2.Log) + return internalError(ctx, err, fmt.Sprintf("could not retrieve consensus information for last round (%d)", lastRound), v2.Log) } if handle == protocol.CodecHandle { diff --git a/test/scripts/e2e_subs/min_balance.py b/test/scripts/e2e_subs/min_balance.py index 701b467a62..922c18e9ab 100755 --- a/test/scripts/e2e_subs/min_balance.py +++ b/test/scripts/e2e_subs/min_balance.py @@ -41,7 +41,7 @@ def initialize_debugger(): # per userBalance.go::MinBalance() as of Dec 2021: EXTRA_PAGE_MIN_BALANCE = APP_MIN_BALANCE -TEAL = f"""#pragma version 6 +TEAL = f"""#pragma version 5 byte "Hello Min Balance!" log From c50f1f8fc850373506204edcba2838f86f4dadc5 Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Fri, 17 Dec 2021 10:51:17 -0500 Subject: [PATCH 31/32] Update test/scripts/e2e_subs/min_balance.py --- test/scripts/e2e_subs/min_balance.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/scripts/e2e_subs/min_balance.py b/test/scripts/e2e_subs/min_balance.py index 922c18e9ab..4ff9b909ba 100755 --- a/test/scripts/e2e_subs/min_balance.py +++ b/test/scripts/e2e_subs/min_balance.py @@ -139,8 +139,9 @@ def assert_min_balance( txinfo, err = goal.pay(goal.account, flo, amt=100_000_000, send=True) -# starting out, should be at global min expected_goal_mb = CONSENSUS_MIN_BALANCE + APP_MIN_BALANCE + +# starting out, should be at global min assert_min_balance(goal, flo, CONSENSUS_MIN_BALANCE, expected_goal_mb) expected_goal_mb += APP_MIN_BALANCE From af2acec592020c665835e1003e196f72020d3678 Mon Sep 17 00:00:00 2001 From: Zeph Grunschlag Date: Fri, 17 Dec 2021 10:51:47 -0500 Subject: [PATCH 32/32] Update test/scripts/e2e_subs/min_balance.py --- test/scripts/e2e_subs/min_balance.py | 1 - 1 file changed, 1 deletion(-) diff --git a/test/scripts/e2e_subs/min_balance.py b/test/scripts/e2e_subs/min_balance.py index 4ff9b909ba..b7376fd37f 100755 --- a/test/scripts/e2e_subs/min_balance.py +++ b/test/scripts/e2e_subs/min_balance.py @@ -138,7 +138,6 @@ def assert_min_balance( txinfo, err = goal.pay(goal.account, joe, amt=50_000_000, send=True) txinfo, err = goal.pay(goal.account, flo, amt=100_000_000, send=True) - expected_goal_mb = CONSENSUS_MIN_BALANCE + APP_MIN_BALANCE # starting out, should be at global min