-
Notifications
You must be signed in to change notification settings - Fork 143
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement new step asserting that AtomicTransactionComposer's attempt to add a method can fail with a particular error #347
Changes from all commits
7ab587c
c5f282b
9bf3149
aaa7f77
9ad1a76
608ebf1
7d79134
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,7 +7,11 @@ | |
|
||
from algosdk import abi, atomic_transaction_composer, encoding, mnemonic | ||
from algosdk.abi.contract import NetworkInfo | ||
from algosdk.error import ABITypeError, IndexerHTTPError | ||
from algosdk.error import ( | ||
ABITypeError, | ||
IndexerHTTPError, | ||
AtomicTransactionComposerError, | ||
) | ||
from algosdk.future import transaction | ||
|
||
from test.steps.other_v2_steps import read_program | ||
|
@@ -85,16 +89,32 @@ def s512_256_uint64(witness): | |
return int.from_bytes(encoding.checksum(witness)[:8], "big") | ||
|
||
|
||
@step( | ||
'I sign and submit the transaction, saving the txid. If there is an error it is "{error_string:MaybeString}".' | ||
) | ||
def sign_submit_save_txid_with_error(context, error_string): | ||
try: | ||
signed_app_transaction = context.app_transaction.sign( | ||
context.transient_sk | ||
) | ||
context.app_txid = context.app_acl.send_transaction( | ||
signed_app_transaction | ||
) | ||
except Exception as e: | ||
if not error_string or error_string not in str(e): | ||
raise RuntimeError( | ||
"error string " | ||
+ error_string | ||
+ " not in actual error " | ||
+ str(e) | ||
) | ||
|
||
|
||
@when("we make a GetApplicationByID call for applicationID {app_id}") | ||
def application_info(context, app_id): | ||
context.response = context.acl.application_info(int(app_id)) | ||
|
||
|
||
@when("we make a LookupApplications call with applicationID {app_id}") | ||
def lookup_application(context, app_id): | ||
context.response = context.icl.applications(int(app_id)) | ||
|
||
|
||
@when( | ||
'we make a LookupApplicationLogsByID call with applicationID {app_id} limit {limit} minRound {min_round} maxRound {max_round} nextToken "{next_token:MaybeString}" sender "{sender:MaybeString}" and txID "{txid:MaybeString}"' | ||
) | ||
|
@@ -159,8 +179,13 @@ def lookup_application_include_all2( | |
context.response = json.loads(str(e)) | ||
|
||
|
||
@when("we make a LookupApplications call with applicationID {app_id}") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. moved closer to similar function |
||
def lookup_application(context, app_id): | ||
context.response = context.icl.applications(int(app_id)) | ||
|
||
|
||
@when("I use {indexer} to lookup application with {application_id}") | ||
def lookup_application(context, indexer, application_id): | ||
def lookup_application2(context, indexer, application_id): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. renamed to avoid method name collision |
||
context.response = context.icls[indexer].applications( | ||
application_id=int(application_id) | ||
) | ||
|
@@ -514,33 +539,33 @@ def add_transaction_to_composer(context): | |
|
||
def process_abi_args(context, method, arg_tokens): | ||
method_args = [] | ||
for arg_index, arg in enumerate(method.args): | ||
# Skip arg if it does not have a type | ||
for arg_index, arg_token in enumerate(arg_tokens): | ||
if arg_index >= len(method.args): | ||
method_args.append(arg_token) | ||
continue | ||
|
||
arg = method.args[arg_index] | ||
if isinstance(arg.type, abi.ABIType): | ||
method_arg = arg.type.decode( | ||
base64.b64decode(arg_tokens[arg_index]) | ||
) | ||
method_arg = arg.type.decode(base64.b64decode(arg_token)) | ||
method_args.append(method_arg) | ||
elif arg.type == abi.ABIReferenceType.ACCOUNT: | ||
method_arg = abi.AddressType().decode( | ||
base64.b64decode(arg_tokens[arg_index]) | ||
) | ||
method_arg = abi.AddressType().decode(base64.b64decode(arg_token)) | ||
method_args.append(method_arg) | ||
elif ( | ||
arg.type == abi.ABIReferenceType.APPLICATION | ||
or arg.type == abi.ABIReferenceType.ASSET | ||
): | ||
parts = arg_tokens[arg_index].split(":") | ||
parts = arg_token.split(":") | ||
if len(parts) == 2 and parts[0] == "ctxAppIdx": | ||
method_arg = context.app_ids[int(parts[1])] | ||
else: | ||
method_arg = abi.UintType(64).decode( | ||
base64.b64decode(arg_tokens[arg_index]) | ||
base64.b64decode(arg_token) | ||
) | ||
method_args.append(method_arg) | ||
else: | ||
# Append the transaction signer as is | ||
method_args.append(arg_tokens[arg_index]) | ||
method_args.append(arg_token) | ||
return method_args | ||
|
||
|
||
|
@@ -561,7 +586,7 @@ def append_txn_to_method_args(context): | |
) | ||
def append_app_args_to_method_args(context, method_args): | ||
# Returns a list of ABI method arguments | ||
app_args = method_args.split(",") | ||
app_args = method_args.split(",") if method_args else [] | ||
context.method_args += app_args | ||
|
||
|
||
|
@@ -583,6 +608,7 @@ def abi_method_adder( | |
local_ints=None, | ||
extra_pages=None, | ||
force_unique_transactions=False, | ||
exception_key="none", | ||
): | ||
if account_type == "transient": | ||
sender = context.transient_pk | ||
|
@@ -621,39 +647,66 @@ def int_if_given(given): | |
app_args = process_abi_args( | ||
context, context.abi_method, context.method_args | ||
) | ||
context.app_args = app_args | ||
note = None | ||
if force_unique_transactions: | ||
note = ( | ||
b"I should be unique thanks to this nonce: " | ||
+ context.nonce.encode() | ||
) | ||
|
||
context.atomic_transaction_composer.add_method_call( | ||
app_id=app_id, | ||
method=context.abi_method, | ||
sender=sender, | ||
sp=context.suggested_params, | ||
signer=context.transaction_signer, | ||
method_args=app_args, | ||
on_complete=operation_string_to_enum(operation), | ||
local_schema=local_schema, | ||
global_schema=global_schema, | ||
approval_program=approval_program, | ||
clear_program=clear_program, | ||
extra_pages=extra_pages, | ||
note=note, | ||
) | ||
try: | ||
context.atomic_transaction_composer.add_method_call( | ||
app_id=app_id, | ||
method=context.abi_method, | ||
sender=sender, | ||
sp=context.suggested_params, | ||
signer=context.transaction_signer, | ||
method_args=app_args, | ||
on_complete=operation_string_to_enum(operation), | ||
local_schema=local_schema, | ||
global_schema=global_schema, | ||
approval_program=approval_program, | ||
clear_program=clear_program, | ||
extra_pages=extra_pages, | ||
note=note, | ||
) | ||
except AtomicTransactionComposerError as atce: | ||
assert ( | ||
exception_key != "none" | ||
), f"cucumber step asserted that no exception resulted, but the following exception actually occurred: {atce}" | ||
|
||
arglen_exception = "argument_count_mismatch" | ||
known_exception_keys = [arglen_exception] | ||
assert ( | ||
exception_key in known_exception_keys | ||
), f"encountered exception key '{exception_key}' which is not in known set: {known_exception_keys}" | ||
|
||
if exception_key == arglen_exception: | ||
exception_msg = ( | ||
"number of method arguments do not match the method signature" | ||
) | ||
assert exception_msg in str( | ||
atce | ||
), f"expected argument count mismatch error such as '{exception_msg}' but got the following instead: {atce}" | ||
return | ||
|
||
assert ( | ||
exception_key == "none" | ||
), f"should have encountered an AtomicTransactionComposerError keyed by '{exception_key}', but no such exception has been detected" | ||
|
||
|
||
@step( | ||
'I add a nonced method call with the {account_type} account, the current application, suggested params, on complete "{operation}", current transaction signer, current method arguments.' | ||
'I add a method call with the {account_type} account, the current application, suggested params, on complete "{operation}", current transaction signer, current method arguments; any resulting exception has key "{exception_key}".' | ||
) | ||
def add_abi_method_call_nonced(context, account_type, operation): | ||
def add_abi_method_call_with_exception( | ||
context, account_type, operation, exception_key | ||
): | ||
abi_method_adder( | ||
context, | ||
account_type, | ||
operation, | ||
force_unique_transactions=True, | ||
exception_key=exception_key, | ||
) | ||
|
||
|
||
|
@@ -718,6 +771,18 @@ def add_abi_method_call_creation( | |
) | ||
|
||
|
||
@step( | ||
'I add a nonced method call with the {account_type} account, the current application, suggested params, on complete "{operation}", current transaction signer, current method arguments.' | ||
) | ||
def add_abi_method_call_nonced(context, account_type, operation): | ||
abi_method_adder( | ||
context, | ||
account_type, | ||
operation, | ||
force_unique_transactions=True, | ||
) | ||
|
||
|
||
@step( | ||
'I build the transaction group with the composer. If there is an error it is "{error_string:MaybeString}".' | ||
) | ||
|
@@ -827,7 +892,7 @@ def serialize_method_to_json(context): | |
@when( | ||
'I create the Method object with name "{method_name}" method description "{method_desc}" first argument type "{first_arg_type}" first argument description "{first_arg_desc}" second argument type "{second_arg_type}" second argument description "{second_arg_desc}" and return type "{return_arg_type}"' | ||
) | ||
def create_method_from_test_with_arg_name( | ||
def create_method_from_test_with_arg_name_and_desc( | ||
context, | ||
method_name, | ||
method_desc, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -604,7 +604,7 @@ def txns_by_addr( | |
@when( | ||
'we make a Lookup Account Transactions call against account "{account:MaybeString}" with NotePrefix "{notePrefixB64:MaybeString}" TxType "{txType:MaybeString}" SigType "{sigType:MaybeString}" txid "{txid:MaybeString}" round {block} minRound {minRound} maxRound {maxRound} limit {limit} beforeTime "{beforeTime:MaybeString}" afterTime "{afterTime:MaybeString}" currencyGreaterThan {currencyGreaterThan} currencyLessThan {currencyLessThan} assetIndex {index}' | ||
) | ||
def txns_by_addr( | ||
def txns_by_addr2( | ||
context, | ||
account, | ||
notePrefixB64, | ||
|
@@ -1406,27 +1406,6 @@ def algod_v2_client(context): | |
context.app_acl = algod.AlgodClient(daemon_token, algod_address) | ||
|
||
|
||
@step( | ||
'I sign and submit the transaction, saving the txid. If there is an error it is "{error_string:MaybeString}".' | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. moved this to |
||
) | ||
def sign_submit_save_txid_with_error(context, error_string): | ||
try: | ||
signed_app_transaction = context.app_transaction.sign( | ||
context.transient_sk | ||
) | ||
context.app_txid = context.app_acl.send_transaction( | ||
signed_app_transaction | ||
) | ||
except Exception as e: | ||
if not error_string or error_string not in str(e): | ||
raise RuntimeError( | ||
"error string " | ||
+ error_string | ||
+ " not in actual error " | ||
+ str(e) | ||
) | ||
|
||
|
||
@when('I compile a teal program "{program}"') | ||
def compile_step(context, program): | ||
data = load_resource(program) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
moved unchanged from
other_v2_steps
after I realized that this is meant for application transactions