Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Simulate endpoint tests #265

Merged
merged 18 commits into from
Mar 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .env
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
VERBOSE_HARNESS=0

# Used to determine sandbox build type:
TYPE="channel" # OR "source"
TYPE="source" # OR "source"

# Used when TYPE==channel:
ALGOD_CHANNEL="nightly"
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ These reside in the [integration features directory](features/integration)
| @kmd | Test the kmd REST endpoints. |
| @rekey_v1 | Test the rekeying transactions. |
| @send | Test the ability to submit transactions to algod. |
| @simulate | Test the ability to simulate transactions with algod. |

### Test Implementation Status

Expand Down
4 changes: 2 additions & 2 deletions features/integration/abi.feature
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Feature: ABI Interaction
And a kmd client
And wallet information
And suggested transaction parameters from the algod v2 client
And I create a new transient account and fund it with 100000000 microalgos.
And I create a new transient account and fund it with 10000000 microalgos.
algochoi marked this conversation as resolved.
Show resolved Hide resolved
And I make a transaction signer for the transient account.
And I build an application transaction with the transient account, the current application, suggested params, operation "create", approval-program "programs/abi_method_call.teal.tok", clear-program "programs/one.teal.tok", global-bytes 0, global-ints 0, local-bytes 1, local-ints 0, app-args "", foreign-apps "", foreign-assets "", app-accounts "", extra-pages 0, boxes ""
And I sign and submit the transaction, saving the txid. If there is an error it is "".
Expand Down Expand Up @@ -98,7 +98,7 @@ Feature: ABI Interaction
And The app should have returned "ABRnb29kYnllIEFsZ29yYW5kIEZhbg==".

Scenario: Method call delete execution
Given I create a new transient account and fund it with 100000000 microalgos.
Given I create a new transient account and fund it with 10000000 microalgos.
And I make a transaction signer for the transient account.
And I build an application transaction with the transient account, the current application, suggested params, operation "create", approval-program "programs/abi_method_call.teal.tok", clear-program "programs/one.teal.tok", global-bytes 0, global-ints 0, local-bytes 1, local-ints 0, app-args "", foreign-apps "", foreign-assets "", app-accounts "", extra-pages 0, boxes ""
And I sign and submit the transaction, saving the txid. If there is an error it is "".
Expand Down
6 changes: 3 additions & 3 deletions features/integration/c2c.feature
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Feature: Contract to Contract Interaction
* a kmd client
* wallet information
* suggested transaction parameters from the algod v2 client
* I create a new transient account and fund it with 100000000 microalgos.
* I create a new transient account and fund it with 10000000 microalgos.
* I make a transaction signer for the transient account.
* I reset the array of application IDs to remember.

Expand Down Expand Up @@ -47,7 +47,7 @@ Feature: Contract to Contract Interaction
And I wait for the transaction to be confirmed.
Given I remember the new application ID.
# Need to fund RandomByte because it pays for calling RandomInteger:
And I fund the current application's address with 100000000 microalgos.
And I fund the current application's address with 10000000 microalgos.

Given a new AtomicTransactionComposer

Expand Down Expand Up @@ -85,7 +85,7 @@ Feature: Contract to Contract Interaction
And I wait for the transaction to be confirmed.
Given I remember the new application ID.
# Need to fund SlotMachine because it pays for calling RandomByte:
And I fund the current application's address with 100000000 microalgos.
And I fund the current application's address with 10000000 microalgos.

Given a new AtomicTransactionComposer

Expand Down
122 changes: 122 additions & 0 deletions features/integration/simulate.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
Feature: Simulating transactions
Background:
Given an algod v2 client
And a kmd client
And wallet information
And suggested transaction parameters from the algod v2 client
And I create a new transient account and fund it with 10000000 microalgos.
And I make a transaction signer for the transient account.

@simulate
Scenario Outline: Simulating successful payment transactions
Given default transaction with parameters <amt> "<note>"
When I get the private key
And I sign the transaction with the private key
tzaffi marked this conversation as resolved.
Show resolved Hide resolved
And I simulate the transaction
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think it's worth distinguishing between simulating with signed transactions and simulating without ?

If so, this step could instead by:

And I simulate-signed the transaction

leaving room for the future

And I simulate-unsigned the transaction

But if the API is going to be the same (i.e. simulate just takes the transactions as they are and doesn't need special methods to handle unsigned), then we don't need to change this step.

We could also punt this to #267 and if the API changes at a later date, we would change the steps as well - though that would be a bit annoying.

Copy link
Contributor Author

@algochoi algochoi Mar 3, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think the API would change, so no need for two separate steps.

Currently, the simulate endpoint itself sends the msgpack encoded transaction (bytearray-like object). As a part of #267 , we probably need helper methods to encode unsigned transactions into msgpack, and then send that to the simulate endpoint. Currently, we have explicit checks in the SDKs to look for signatures before doing this encoding.

Then the simulation should succeed without any failure message
tzaffi marked this conversation as resolved.
Show resolved Hide resolved

Examples:
| amt | note |
| 0 | X4Bl4wQ9rCo= |
| 1234523 | X4Bl4wQ9rCo= |

@simulate
Scenario: Simulating unsigned payment transaction
Given default transaction with parameters 100001 "X4Bl4wQ9rCo="
When I prepare the transaction without signatures for simulation
And I simulate the transaction
Then the simulation should report missing signatures at group "0", transactions "0"

@simulate
Scenario: Simulating duplicate transactions in a group and overspending errors
Given a new AtomicTransactionComposer
When I build a payment transaction with sender "transient", receiver "transient", amount 100001, close remainder to ""
And I create a transaction with signer with the current transaction.
And I add the current transaction with signer to the composer.
Then I build the transaction group with the composer. If there is an error it is "".
And I gather signatures with the composer.
And I simulate the current transaction group with the composer
And the simulation should succeed without any failure message

# Check for duplicate transaction errors
And I clone the composer.
When I add the current transaction with signer to the composer.
Then I build the transaction group with the composer. If there is an error it is "".
And I gather signatures with the composer.
And I simulate the current transaction group with the composer
And the simulation should report a failure at group "0", path "1" with message "transaction already in ledger"

# Check for overspending errors
Given a new AtomicTransactionComposer
When I build a payment transaction with sender "transient", receiver "transient", amount 999999999, close remainder to ""
And I create a transaction with signer with the current transaction.
And I add the current transaction with signer to the composer.
Then I simulate the current transaction group with the composer
And the simulation should report a failure at group "0", path "0" with message "overspend"

@simulate
Scenario: Simulating unsigned transactions in the ATC group
Given a new AtomicTransactionComposer
When I build a payment transaction with sender "transient", receiver "transient", amount 100001, close remainder to ""
And I create a transaction with an empty signer with the current transaction.
And I add the current transaction with signer to the composer.
Then I simulate the current transaction group with the composer
And the simulation should report missing signatures at group "0", transactions "0"

# Add another unsigned transaction
And I clone the composer.
When I build a payment transaction with sender "transient", receiver "transient", amount 100002, close remainder to ""
And I create a transaction with an empty signer with the current transaction.
And I add the current transaction with signer to the composer.
Then I simulate the current transaction group with the composer
And the simulation should report missing signatures at group "0", transactions "0,1"

@simulate
Scenario: Simulating bad inner transactions in the ATC
Given a new AtomicTransactionComposer
# Create an app at context index 0: FakeRandom
tzaffi marked this conversation as resolved.
Show resolved Hide resolved
When I build an application transaction with the transient account, the current application, suggested params, operation "create", approval-program "programs/fake_random.teal", clear-program "programs/six.teal", global-bytes 0, global-ints 1, local-bytes 0, local-ints 0, app-args "", foreign-apps "", foreign-assets "", app-accounts "", extra-pages 0, boxes ""
And I sign and submit the transaction, saving the txid. If there is an error it is "".
And I wait for the transaction to be confirmed.
Given I remember the new application ID.

# Create another app at context index 1: RandomByte
When I build an application transaction with the transient account, the current application, suggested params, operation "create", approval-program "programs/random_byte.teal", clear-program "programs/six.teal", global-bytes 0, global-ints 0, local-bytes 0, local-ints 0, app-args "", foreign-apps "", foreign-assets "", app-accounts "", extra-pages 0, boxes ""
And I sign and submit the transaction, saving the txid. If there is an error it is "".
And I wait for the transaction to be confirmed.
Given I remember the new application ID.

# Need to fund RandomByte because it pays for calling RandomInteger in FakeRandom:
And I fund the current application's address with 10000000 microalgos.

# First, check that inner transaction simulation is okay.
# The following two steps are taken from c2c.feature
# randElement("hello",RandomByte) -> (c, witnessString)
Given I add the nonce "Thing One"
When I create the Method object from method signature "randElement(string,application)(byte,byte[17])"
* I create a new method arguments array.
* I append the encoded arguments "AAVoZWxsbw==,ctxAppIdx:0" to the method arguments array.
* I add a nonced method call with the transient account, the current application, suggested params, on complete "noop", current transaction signer, current method arguments.

# randElement("goodbye",RandomByte) -> (c, witnessString)
Given I add the nonce "Thing Two"
When I create the Method object from method signature "randElement(string,application)(byte,byte[17])"
* I create a new method arguments array.
* I append the encoded arguments "AAdnb29kYnll,ctxAppIdx:0" to the method arguments array.
* I add a nonced method call with the transient account, the current application, suggested params, on complete "noop", current transaction signer, current method arguments.

# The simulation should succeed with an ABI return
Then I simulate the current transaction group with the composer
And The app should have returned ABI types "(byte,byte[17]):(byte,byte[17])".
And The 0th atomic result for randElement("hello") proves correct
And The 1th atomic result for randElement("goodbye") proves correct

# Clone the composer and add a bad inner transaction call.
Then I clone the composer.
Given I add the nonce "Thing Three"
When I create the Method object from method signature "badMethod(string,application)void"
And I add a nonced method call with the transient account, the current application, suggested params, on complete "noop", current transaction signer, current method arguments.

# The simulation should fail at the third transaction's first inner transaction (2,0) due to no app args being passed into the app.
Then I simulate the current transaction group with the composer
And the simulation should report a failure at group "0", path "2,0" with message "invalid ApplicationArgs"
20 changes: 18 additions & 2 deletions features/resources/programs/random_byte.teal
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,15 @@
txn ApplicationID
bz finish // creating ok

txn ApplicationArgs 0
method "badMethod(string,application)void"
==
bnz err_program // Call FakeRandom app in inner txn with bad app args (should error)

txn ApplicationArgs 0
method "randElement(string,application)(byte,byte[17])"
==
assert // other than create, only the app call is allowed
assert // other than create, only badMethod and randElement method call is allowed

itxn_begin
int appl
Expand Down Expand Up @@ -87,4 +92,15 @@ log

finish:
int 1
return
return

err_program:
itxn_begin
int appl
itxn_field TypeEnum

txn Applications 1 // FakeRandom
itxn_field ApplicationID
itxn_submit

b finish