diff --git a/.circleci/config.yml b/.circleci/config.yml index 76a9f1f1..258dcdf9 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,4 +1,6 @@ version: 2.1 +orbs: + slack: circleci/slack@4.12.5 workflows: version: 2 diff --git a/.github/workflows/create-release-pr.yml b/.github/workflows/create-release-pr.yml new file mode 100644 index 00000000..2324bf21 --- /dev/null +++ b/.github/workflows/create-release-pr.yml @@ -0,0 +1,229 @@ +name: Create Release PR + +on: + workflow_dispatch: + inputs: + release_version: + description: 'The release_version used for the release branch name, e.g. release/vx.x.x' + default: 'vx.x.x' + required: true + type: string + pre_release_version: + description: "Pre-Release version, e.g. 'b1', will be added behind the release_version in setup.py." + required: false + type: string + +env: + RELEASE_VERSION: ${{ inputs.release_version }} + PRE_RELEASE_VERSION: ${{ inputs.pre_release_version }} + RELEASE_BRANCH: release/${{ inputs.release_version }} + +jobs: + create-release-pr: + runs-on: ubuntu-latest + + steps: + - name: Set Release Version and Branch to Check Out + id: set-release + run: | + if [[ $RELEASE_VERSION =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + if [[ $PRE_RELEASE_VERSION =~ ^[a-z.0-9]+$ ]]; then + echo "release-tag: $RELEASE_VERSION$PRE_RELEASE_VERSION" + echo "release-tag=$RELEASE_VERSION$PRE_RELEASE_VERSION" >> $GITHUB_OUTPUT + elif [[ -n $PRE_RELEASE_VERSION ]]; then + echo "Input pre_release_version is not empty, but does not match the regex pattern ^[a-z.0-9]+$" + exit 1 + else + echo "release-tag: $RELEASE_VERSION" + echo "release-tag=$RELEASE_VERSION" >> $GITHUB_OUTPUT + fi + else + echo "Version input doesn't match the regex pattern ^v[0-9]+\.[0-9]+\.[0-9]+$" + exit 1 + fi + + - name: Checkout + uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Create Release Branch if it does not exist + run: | + if ! git show-ref --verify --quiet "refs/remotes/origin/$RELEASE_BRANCH"; then + git checkout -b $RELEASE_BRANCH + git push --set-upstream origin $RELEASE_BRANCH + elif [[ $(git rev-parse --abbrev-ref HEAD) != "$RELEASE_BRANCH" ]]; then + echo "Current Branch: $(git rev-parse --abbrev-ref HEAD)" + echo "Release branch exists, make sure you're using the workflow from the release branch or delete the existing release branch." + exit 1 + else + echo "Release branch exists and used as workflow ref." + fi + + - name: Get Latest Release + id: get-release + run: | + if [[ -n $PRE_RELEASE_VERSION ]]; then + echo "Get the latest release" + tag=$(curl -L \ + --header "Accept: application/vnd.github.v3+json" \ + "https://api.github.com/repos/${{ github.repository }}/releases" | jq -r '.[0].tag_name') + echo "latest-tag=$tag" >> $GITHUB_OUTPUT + else + echo "Get the latest stable release" + tag=$(curl -L \ + --header "Accept: application/vnd.github.v3+json" \ + "https://api.github.com/repos/${{ github.repository }}/releases/latest" | jq -r '.tag_name') + echo "latest-tag=$tag" >> $GITHUB_OUTPUT + fi + + - name: Build Changelog + uses: mikepenz/release-changelog-builder-action@v3.7.2 + id: build-changelog + env: + PREVIOUS_VERSION: ${{ steps.get-release.outputs.latest-tag }} + with: + fromTag: ${{ env.PREVIOUS_VERSION }} + toTag: ${{ env.RELEASE_BRANCH }} + failOnError: true + configurationJson: | + { + "categories": [ + { + "title": "## New Features", + "labels": [ + "New Feature" + ] + }, + { + "title": "## Enhancement", + "labels": [ + "Enhancement" + ] + }, + { + "title": "## Bug Fixes", + "labels": [ + "Bug-Fix" + ] + }, + { + "title": "## Not Yet Enabled", + "labels": [ + "Not-Yet-Enabled" + ] + } + ], + "ignore_labels": [ + "Skip-Release-Notes" + ], + "sort": { + "order": "ASC", + "on_property": "mergedAt" + }, + "template": "#{{CHANGELOG}}", + "pr_template": "- #{{TITLE}} by #{{AUTHOR}} in ##{{NUMBER}}" + } + + - name: Update Changelog + if: ${{ env.PRE_RELEASE_VERSION == '' }} + env: + CHANGELOG_CONTENT: ${{ steps.build-changelog.outputs.changelog }} + PREVIOUS_VERSION: ${{ steps.get-release.outputs.latest-tag }} + run: | + echo "$(tail -n +2 CHANGELOG.md)" > CHANGELOG.md + echo -e "# Changelog\n\n# ${RELEASE_VERSION}\n\n${CHANGELOG_CONTENT}**Full Changelog**: https://github.com/${{ github.repository }}/compare/${PREVIOUS_VERSION}...${RELEASE_VERSION}" | cat - CHANGELOG.md > temp && mv temp CHANGELOG.md + + - name: Update version in setup.py + env: + RELEASE_TAG: ${{ steps.set-release.outputs.release-tag }} + run: | + python3 scripts/bump_version.py ${RELEASE_TAG:1} + + - name: Commit Changes + uses: EndBug/add-and-commit@v9.1.3 + env: + RELEASE_TAG: ${{ steps.set-release.outputs.release-tag }} + with: + message: "bump up version to ${{ env.RELEASE_TAG }}" + + - name: Create Pull Request to Master + env: + CHANGELOG_CONTENT: ${{ steps.build-changelog.outputs.changelog }} + PREVIOUS_VERSION: ${{ steps.get-release.outputs.latest-tag }} + GH_TOKEN: ${{ github.token }} + RELEASE_TAG: ${{ steps.set-release.outputs.release-tag }} + run: | + echo -e "# ${RELEASE_TAG}\n\n${CHANGELOG_CONTENT}**Full Changelog**: https://github.com/${{ github.repository }}/compare/${PREVIOUS_VERSION}...${RELEASE_TAG}" > tmp_msg_body.txt + export msg_body=$(cat tmp_msg_body.txt) + rm tmp_msg_body.txt + # Note: There's an issue adding teams as reviewers, see https://github.com/cli/cli/issues/6395 + PULL_REQUEST_URL=$(gh pr create --base "master" \ + --title "FOR REVIEW ONLY: py-algorand-sdk $RELEASE_TAG" \ + --label "Skip-Release-Notes" \ + --body "$msg_body" | tail -n 1) + if [[ $PULL_REQUEST_URL =~ ^https://github.com/${{ github.repository }}/pull/[0-9]+$ ]]; then + PULL_REQUEST_NUM=$(echo $PULL_REQUEST_URL | sed 's:.*/::') + echo "pull-request-master=$PULL_REQUEST_URL" >> $GITHUB_ENV + echo "pull-request-master-num=$PULL_REQUEST_NUM" >> $GITHUB_ENV + echo "Pull request to Master created: $PULL_REQUEST_URL" + else + echo "There was an issue creating the pull request to master branch." + exit 1 + fi + + - name: Create Pull Request to Develop + if: ${{ env.PRE_RELEASE_VERSION == '' }} + env: + GH_TOKEN: ${{ github.token }} + RELEASE_TAG: ${{ steps.set-release.outputs.release-tag }} + run: | + # Note: There's an issue adding teams as reviewers, see https://github.com/cli/cli/issues/6395 + PULL_REQUEST_URL=$(gh pr create --base "develop" \ + --title "FOR REVIEW ONLY: Merge back py-algorand-sdk $RELEASE_TAG to develop" \ + --label "Skip-Release-Notes" \ + --body "Merge back version changes to develop." | tail -n 1) + if [[ $PULL_REQUEST_URL =~ ^https://github.com/${{ github.repository }}/pull/[0-9]+$ ]]; then + echo "Pull request to Develop created: $PULL_REQUEST_URL" + DEVELOP_PR_MESSAGE="\nPull Request to develop: $PULL_REQUEST_URL" + echo "pull-request-develop-message=$DEVELOP_PR_MESSAGE" >> $GITHUB_ENV + else + echo "There was an issue creating the pull request to develop branch." + exit 1 + fi + + - name: Send Slack Message + id: slack + uses: slackapi/slack-github-action@v1.24.0 + env: + RELEASE_TAG: ${{ steps.set-release.outputs.release-tag }} + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} + SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK + SDK_DEPLOYMENT_URL: ${{ secrets.SDK_DEPLOYMENT_URL }} + with: + payload: | + { + "blocks": [ + { + "type": "header", + "text": { + "type": "plain_text", + "text": "${{ github.event.repository.name }} Release PR for ${{ env.RELEASE_TAG }}" + } + }, + { + "type": "section", + "text": { + "type": "mrkdwn", + "text": "*Approvals needed for*:\nPull Request to master: ${{ env.pull-request-master}}${{ env.pull-request-develop-message }}" + } + }, + { + "type": "section", + "text": { + "type": "mrkdwn", + "text": "*After approvals*\nDeploy SDK using the <${{ env.SDK_DEPLOYMENT_URL }}|Deployment Pipeline> with the following parameters:\n*SDK*: ${{ github.event.repository.name }}\n*RELEASE_PR_NUM*: ${{ env.pull-request-master-num }}\n*RELEASE_VERSION*: ${{ env.RELEASE_VERSION }}\n*PRE_RELEASE_VERSION*: ${{ env.PRE_RELEASE_VERSION }}" + } + } + ] + } diff --git a/.test-env b/.test-env index df783a4f..049289d7 100644 --- a/.test-env +++ b/.test-env @@ -5,7 +5,7 @@ SDK_TESTING_HARNESS="test-harness" INSTALL_ONLY=0 -VERBOSE_HARNESS=0 +VERBOSE_HARNESS=1 # WARNING: If set to 1, new features will be LOST when downloading the test harness. # REGARDLESS: modified features are ALWAYS overwritten. diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c8ba1d0..8955c02e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,26 @@ # Changelog +# v2.3.0 + +## New Features + +- Algod: Simulation run with extra budget per transaction group by ahangsu in #484 + +## Enhancement + +- tweak: reorder GenericSignedTransaction type alias by tzaffi in #478 +- Enhancement: Adding `box_reference.py` to Read The Docs by tzaffi in #481 +- DevOps: Update CODEOWNERS to only refer to the devops group by onetechnical in #482 +- algod: State delta endpoints by algochoi in #483 +- CICD: Release PR Creation Workflow and Slack Messaging by algobarb in #497 +- algod: Add msgpack query param to deltas endpoints by Eric-Warehime in #499 + +## Bug Fixes + +- bugfix: incorrect indexer docs by tzaffi in #476 + +**Full Changelog**: https://github.com/algorand/py-algorand-sdk/compare/v2.2.0...v2.3.0 + # v2.2.0 ## What's Changed diff --git a/CODEOWNERS b/CODEOWNERS index aa26c82a..3c88c6e7 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1,2 +1,2 @@ -.github/ @algorand/dev -.circleci/ @algorand/dev +.github/ @algorand/devops +.circleci/ @algorand/devops diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 00000000..966aa2cf --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,128 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, religion, or sexual identity +and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our +community include: + +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +* Focusing on what is best not just for us as individuals, but for the + overall community + +Examples of unacceptable behavior include: + +* The use of sexualized language or imagery, and sexual attention or + advances of any kind +* Trolling, insulting or derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or email + address, without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official e-mail address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement at +conduct@algorand.com. +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series +of actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or +permanent ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within +the community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.0, available at +https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. + +Community Impact Guidelines were inspired by [Mozilla's code of conduct +enforcement ladder](https://github.com/mozilla/diversity). + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see the FAQ at +https://www.contributor-covenant.org/faq. Translations are available at +https://www.contributor-covenant.org/translations. diff --git a/README.md b/README.md index 6231e464..173c0f50 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,8 @@ Run non-test-harness related unit tests * `make pytest-unit` +We use cucumber testing for all of our SDKs, including this one. Please refer to [algorand-sdk-testing](https://github.com/algorand/algorand-sdk-testing#readme) for guidance and existing tests that you may need to update. Depending on the type of update you wish to contribute, you may also need to have corresponding updates in the other SDKs (Go, JS, and Java). Feel welcome to ask for collaboration on that front. + ## Quick start Here's a simple example you can run without a node. diff --git a/algosdk/atomic_transaction_composer.py b/algosdk/atomic_transaction_composer.py index 66291934..24d325aa 100644 --- a/algosdk/atomic_transaction_composer.py +++ b/algosdk/atomic_transaction_composer.py @@ -272,10 +272,12 @@ def __init__( max_log_calls: Optional[int] = None, max_log_size: Optional[int] = None, allow_empty_signatures: Optional[bool] = None, + extra_opcode_budget: Optional[int] = None, ) -> None: self.max_log_calls = max_log_calls self.max_log_size = max_log_size self.allow_empty_signatures = allow_empty_signatures + self.extra_opcode_budget = extra_opcode_budget @staticmethod def from_simulation_result( @@ -295,6 +297,10 @@ def from_simulation_result( eval_override.allow_empty_signatures = eval_override_dict[ "allow-empty-signatures" ] + if "extra-opcode-budget" in eval_override_dict: + eval_override.extra_opcode_budget = eval_override_dict[ + "extra-opcode-budget" + ] return eval_override diff --git a/algosdk/transaction.py b/algosdk/transaction.py index 80123894..09e2a923 100644 --- a/algosdk/transaction.py +++ b/algosdk/transaction.py @@ -3036,6 +3036,13 @@ def __eq__(self, other): return False +GenericSignedTransaction = Union[ + SignedTransaction, + LogicSigTransaction, + MultisigTransaction, +] + + def write_to_file(txns, path, overwrite=True): """ Write signed or unsigned transactions to a file. @@ -3233,7 +3240,7 @@ def wait_for_confirmation( def create_dryrun( client: algod.AlgodClient, - txns: List["GenericSignedTransaction"], + txns: List[GenericSignedTransaction], protocol_version=None, latest_timestamp=None, round=None, @@ -3361,10 +3368,3 @@ def decode_programs(app): app["params"]["clear-state-program"] ) return app - - -GenericSignedTransaction = Union[ - SignedTransaction, - LogicSigTransaction, - MultisigTransaction, -] diff --git a/algosdk/v2client/algod.py b/algosdk/v2client/algod.py index c07d3296..73bec63c 100644 --- a/algosdk/v2client/algod.py +++ b/algosdk/v2client/algod.py @@ -718,6 +718,67 @@ def set_timestamp_offset( req = f"/devmode/blocks/offset/{offset}" return self.algod_request("POST", req, **kwargs) + def get_ledger_state_delta( + self, round: int, response_format: str = "json", **kwargs: Any + ) -> AlgodResponseType: + """ + Get the ledger state delta for a round. + + Args: + round (int): The round for the desired state delta + response_format (str): The format in which the response is returned: either + "json" or "msgpack" + + Returns: + Dict[str, Any]: Response from algod + """ + query = {"format": response_format} + req = f"/deltas/{round}" + return self.algod_request( + "GET", req, params=query, response_format=response_format, **kwargs + ) + + def get_transaction_group_ledger_state_deltas_for_round( + self, round: int, response_format: str = "json", **kwargs: Any + ) -> AlgodResponseType: + """ + Get the ledger state deltas for all transaction groups in a given round. + + Args: + round (int): The round for the desired state delta + response_format (str): The format in which the response is returned: either + "json" or "msgpack" + + Returns: + Dict[str, Any]: Response from algod + """ + query = {"format": response_format} + req = f"/deltas/{round}/txn/group" + return self.algod_request( + "GET", req, params=query, response_format=response_format, **kwargs + ) + + def get_ledger_state_delta_for_transaction_group( + self, id: str, response_format: str = "json", **kwargs: Any + ) -> AlgodResponseType: + """ + Get the ledger state delta for a transaction group given the + transaction or group ID. + + Args: + id (str): A transaction ID or transaction group ID + response_format (str): The format in which the response is returned: either + "json" or "msgpack" + + Returns: + Dict[str, Any]: Response from algod + """ + query = {"format": response_format} + req = f"/deltas/txn/group/{id}" + return self.algod_request( + "GET", req, params=query, response_format=response_format, **kwargs + ) + def _specify_round_string( block: Union[int, None], round_num: Union[int, None] diff --git a/algosdk/v2client/indexer.py b/algosdk/v2client/indexer.py index 9054fe4e..d5cf67e8 100644 --- a/algosdk/v2client/indexer.py +++ b/algosdk/v2client/indexer.py @@ -123,19 +123,26 @@ def accounts( max_balance (int, optional): results should have an amount less than this value (results with an amount equal to this value are excluded) - block (int, optional): include results for the specified round; - for performance reasons, this parameter may be disabled on - some configurations + block (int, optional): this is a synonym for round_num. Do not + include both. auth_addr (str, optional): Include accounts configured to use this spending key. application_id (int, optional): results should filter on this application - round_num (int, optional): alias for block; only specify one of - these + round_num (int, optional): Include results for the specified round. + For performance reasons, this parameter may be disabled on some configurations. + Using application-id or asset-id filters will return both creator and opt-in accounts. + Filtering by include-all will return creator and opt-in accounts for deleted assets and accounts. + Non-opt-in managers are not included in the results when asset-id is used. + If specified, do not include block include_all (bool, optional): include all items including closed accounts, deleted applications, destroyed assets, opted-out asset holdings, and closed-out application localstates. Defaults to false. + exclude (str optional): Exclude additional items such as asset holdings, + application local data stored for this account, + asset parameters created by this account, + and application parameters created by this account. """ req = "/accounts" query = dict() @@ -186,11 +193,6 @@ def asset_balances( max_balance (int, optional): results should have an amount less than this value (results with an amount equal to this value are excluded) - block (int, optional): include results for the specified round; - for performance reasons, this parameter may be disabled on - some configurations - round_num (int, optional): alias for block; only specify one of - these include_all (bool, optional): include all items including closed accounts, deleted applications, destroyed assets, opted-out asset holdings, and closed-out application localstates. Defaults @@ -243,13 +245,16 @@ def account_info( Args: address (str): account public key - block (int, optional): use results from the specified round - round_num (int, optional): alias for block; only specify one of - these - include_all (bool, optional): include all items including closed - accounts, deleted applications, destroyed assets, opted-out - asset holdings, and closed-out application localstates. Defaults - to false. + block (int, optional): this is a synonym for round_num. Do not + include both. + round_num (int, optional): Include results for the specified round. + If specified, do not include block + include_all (bool, optional): Include all items including closed accounts, deleted applications, + destroyed assets, opted-out asset holdings, and closed-out application localstates. + Defaults to false. + exclude (str optional): Exclude additional items such as asset holdings, + application local data stored for this account, asset parameters created by this account, + and application parameters created by this account. """ req = "/accounts/" + address query = dict() @@ -282,9 +287,10 @@ def lookup_account_assets( token provided by the previous results asset_id (int): include transactions for the specified asset - block (int, optional): use results from the specified round - round_num (int, optional): alias for block; only specify one of - these + block (int, optional): this is a synonym for round_num. Do not + include both. + round_num (int, optional): Include results for the specified round. + If specified, do not include block include_all (bool, optional): include all items including closed accounts, deleted applications, destroyed assets, opted-out asset holdings, and closed-out application localstates. Defaults @@ -325,9 +331,10 @@ def lookup_account_asset_by_creator( token provided by the previous results asset_id (int): include transactions for the specified asset - block (int, optional): use results from the specified round - round_num (int, optional): alias for block; only specify one of - these + block (int, optional): this is a synonym for round_num. Do not + include both. + round_num (int, optional): Include results for the specified round. + If specified, do not include block include_all (bool, optional): include all items including closed accounts, deleted applications, destroyed assets, opted-out asset holdings, and closed-out application localstates. Defaults @@ -367,9 +374,10 @@ def lookup_account_application_local_state( next_page (str, optional): the next page of results; use the next token provided by the previous results application_id (int, optional): restrict search to application index - block (int, optional): use results from the specified round - round_num (int, optional): alias for block; only specify one of - these + block (int, optional): this is a synonym for round_num. Do not + include both. + round_num (int, optional): Include results for the specified round. + If specified, do not include block include_all (bool, optional): include all items including closed accounts, deleted applications, destroyed assets, opted-out asset holdings, and closed-out application localstates. Defaults @@ -409,9 +417,10 @@ def lookup_account_application_by_creator( next_page (str, optional): the next page of results; use the next token provided by the previous results application_id (int, optional): restrict search to application index - block (int, optional): use results from the specified round - round_num (int, optional): alias for block; only specify one of - these + block (int, optional): this is a synonym for round_num. Do not + include both. + round_num (int, optional): Include results for the specified round. + If specified, do not include block include_all (bool, optional): include all items including closed accounts, deleted applications, destroyed assets, opted-out asset holdings, and closed-out application localstates. Defaults @@ -487,10 +496,10 @@ def search_transactions( specified round asset_id (int, optional): include transactions for the specified asset - end_time (str, optional): include results before the given time; - must be an RFC 3339 formatted string start_time (str, optional): include results after the given time; must be an RFC 3339 formatted string + end_time (str, optional): include results before the given time; + must be an RFC 3339 formatted string min_amount (int, optional): results should have an amount greater than this value; microalgos are the default currency unless an asset-id is provided, in which case the asset will be used @@ -593,17 +602,18 @@ def search_transactions_by_address( sig_type (str, optional): type of signature; one of "sig", "msig", "lsig" txid (str, optional): lookup a specific transaction by ID - block (int, optional): include results for the specified round + block (int, optional): this is a synonym for round_num. Do not + include both. min_round (int, optional): include results at or after the specified round max_round (int, optional): include results at or before the specified round asset_id (int, optional): include transactions for the specified asset - end_time (str, optional): include results before the given time; - must be an RFC 3339 formatted string start_time (str, optional): include results after the given time; must be an RFC 3339 formatted string + end_time (str, optional): include results before the given time; + must be an RFC 3339 formatted string min_amount (int, optional): results should have an amount greater than this value; microalgos are the default currency unless an asset-id is provided, in which case the asset will be used @@ -612,8 +622,8 @@ def search_transactions_by_address( asset-id is provided, in which case the asset will be used rekey_to (bool, optional): include results which include the rekey-to field - round_num (int, optional): alias for block; only specify one of - these + round_num (int, optional): Include results for the specified round. + If specified, do not include block """ req = "/accounts/" + address + "/transactions" query = dict() @@ -688,17 +698,18 @@ def search_asset_transactions( sig_type (str, optional): type of signature; one of "sig", "msig", "lsig" txid (str, optional): lookup a specific transaction by ID - block (int, optional): include results for the specified round + block (int, optional): this is a synonym for round_num. Do not + include both. min_round (int, optional): include results at or after the specified round max_round (int, optional): include results at or before the specified round address (str, optional): only include transactions with this address in one of the transaction fields - end_time (str, optional): include results before the given time; - must be an RFC 3339 formatted string start_time (str, optional): include results after the given time; must be an RFC 3339 formatted string + end_time (str, optional): include results before the given time; + must be an RFC 3339 formatted string min_amount (int, optional): results should have an amount greater than this value; microalgos are the default currency unless an asset-id is provided, in which case the asset will be used @@ -715,8 +726,8 @@ def search_asset_transactions( to true rekey_to (bool, optional): include results which include the rekey-to field - round_num (int, optional): alias for block; only specify one of - these + round_num (int, optional): Include results for the specified round. + If specified, do not include block """ req = "/assets/" + str(asset_id) + "/transactions" query = dict() @@ -864,9 +875,11 @@ def search_applications( Args: application_id (int, optional): restrict search to application index + creator (str, optional): filter just assets with the given creator + address round (int, optional): not supported, DO NOT USE! limit (int, optional): restrict number of results to limit - next_page (string, optional): used for pagination + next_page (str, optional): used for pagination round_num (int, optional): not supported, DO NOT USE! include_all (bool, optional): include all items including closed accounts, deleted applications, destroyed assets, opted-out @@ -908,9 +921,9 @@ def application_logs( limit (int, optional): limit maximum number of results to return min_round (int, optional): only include results at or after the specified round max_round (int, optional): only include results at or before the specified round - next_page (string, optional): used for pagination - sender_addr (string, optional): only include transactions with this sender address - txid (string, optional): only include results with this transaction ID + next_page (str, optional): used for pagination + sender_addr (str, optional): only include transactions with this sender address + txid (str, optional): only include results with this transaction ID """ req = "/applications/{}/logs".format(application_id) query = dict() @@ -960,7 +973,7 @@ def application_boxes( application_id (int): The ID of the application to look up. limit (int, optional): Max number of box names to return. If max is not set, or max == 0, returns all box-names up to queried indexer's `defaultBoxesLimit`. - next_page (string, optional): used for pagination + next_page (str, optional): used for pagination """ req = "/applications/" + str(application_id) + "/boxes" params = {} diff --git a/algosdk/v2client/models/simulate_request.py b/algosdk/v2client/models/simulate_request.py index 909eb223..3bdd651d 100644 --- a/algosdk/v2client/models/simulate_request.py +++ b/algosdk/v2client/models/simulate_request.py @@ -20,6 +20,7 @@ class SimulateRequest(object): txn_groups: List[SimulateRequestTransactionGroup] allow_more_logs: bool allow_empty_signatures: bool + extra_opcode_budget: int def __init__( self, @@ -27,10 +28,12 @@ def __init__( txn_groups: List[SimulateRequestTransactionGroup], allow_more_logs: bool = False, allow_empty_signatures: bool = False, + extra_opcode_budget: int = 0, ) -> None: self.txn_groups = txn_groups self.allow_more_logs = allow_more_logs self.allow_empty_signatures = allow_empty_signatures + self.extra_opcode_budget = extra_opcode_budget def dictify(self) -> Dict[str, Any]: return { @@ -39,4 +42,5 @@ def dictify(self) -> Dict[str, Any]: ], "allow-more-logging": self.allow_more_logs, "allow-empty-signatures": self.allow_empty_signatures, + "extra-opcode-budget": self.extra_opcode_budget, } diff --git a/docs/algosdk/box_reference.rst b/docs/algosdk/box_reference.rst new file mode 100644 index 00000000..67cc8a77 --- /dev/null +++ b/docs/algosdk/box_reference.rst @@ -0,0 +1,7 @@ +box_reference +============= + +.. automodule:: algosdk.box_reference + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/algosdk/index.rst b/docs/algosdk/index.rst index 18cd8399..07adab58 100644 --- a/docs/algosdk/index.rst +++ b/docs/algosdk/index.rst @@ -7,10 +7,10 @@ algosdk account atomic_transaction_composer auction + box_reference constants encoding error - future/index kmd logic mnemonic diff --git a/docs/conf.py b/docs/conf.py index 7eb2d22d..872b0ac4 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -19,7 +19,7 @@ # -- Project information ----------------------------------------------------- project = "algosdk" -copyright = "2022 Algorand" +copyright = "2023 Algorand" author = "Algorand" @@ -75,4 +75,4 @@ # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ["_static"] +# html_static_path = ["_static"] diff --git a/scripts/bump_version.py b/scripts/bump_version.py new file mode 100755 index 00000000..cd388da3 --- /dev/null +++ b/scripts/bump_version.py @@ -0,0 +1,34 @@ +# This script bumps up the version in setup.py for new releases. +# Usage: python bump_version.py {new_version} (--setup_py_path ) + +import argparse +import re + + +def bump_version(new_version, setup_py_path): + with open(setup_py_path, "r") as file: + setup_py = file.read() + + new_setup_py = re.sub( + 'version="[0-9]+\.[0-9]+\.[a-z.0-9]+"', + f'version="{new_version}"', + setup_py, + ) + + with open(setup_py_path, "w") as file: + file.write(new_setup_py) + + +if __name__ == "__main__": + parser = argparse.ArgumentParser( + description="updates the version for a release", + formatter_class=argparse.ArgumentDefaultsHelpFormatter, + ) + parser.add_argument("new_version", help="New Version as major.minor.patch") + parser.add_argument( + "-s", "--setup_py_path", default="setup.py", help="path to setup.py" + ) + + args = parser.parse_args() + + bump_version(args.new_version, args.setup_py_path) diff --git a/setup.py b/setup.py index 424859ef..19296aa6 100644 --- a/setup.py +++ b/setup.py @@ -9,7 +9,7 @@ description="Algorand SDK in Python", author="Algorand", author_email="pypiservice@algorand.com", - version="2.2.0", + version="2.3.0", long_description=long_description, long_description_content_type="text/markdown", url="https://github.com/algorand/py-algorand-sdk", diff --git a/tests/integration.tags b/tests/integration.tags index d2c62ff4..a3bbdd24 100644 --- a/tests/integration.tags +++ b/tests/integration.tags @@ -16,3 +16,4 @@ @send.keyregtxn @simulate @simulate.lift_log_limits +@simulate.extra_opcode_budget diff --git a/tests/steps/other_v2_steps.py b/tests/steps/other_v2_steps.py index 0d213911..1b128ef2 100644 --- a/tests/steps/other_v2_steps.py +++ b/tests/steps/other_v2_steps.py @@ -1499,7 +1499,7 @@ def simulate_group_with_request(context): @then("I check the simulation result has power packs allow-more-logging.") -def power_pack_simulation_should_pass(context): +def power_pack_simulation_should_have_more_logging(context): assert context.atomic_transaction_composer_return.eval_overrides assert ( context.atomic_transaction_composer_return.eval_overrides.max_log_calls @@ -1510,13 +1510,24 @@ def power_pack_simulation_should_pass(context): @when("I prepare the transaction without signatures for simulation") -def step_impl(context): +def prepare_txn_without_signatures(context): context.stx = transaction.SignedTransaction(context.txn, None) -@when("we make a GetLedgerStateDelta call against round {round}") -def get_ledger_state_delta_call(context, round): - context.response = context.acl.get_ledger_state_delta(round) +@then("I allow {budget} more budget on that simulate request.") +def allow_more_budget_simulation(context, budget): + context.simulate_request.extra_opcode_budget = int(budget) + + +@then( + "I check the simulation result has power packs extra-opcode-budget with extra budget {budget}." +) +def power_pack_simulation_should_have_extra_budget(context, budget): + assert context.atomic_transaction_composer_return.eval_overrides + assert ( + context.atomic_transaction_composer_return.eval_overrides.extra_opcode_budget + == int(budget) + ) @when("we make a SetSyncRound call against round {round}") @@ -1547,3 +1558,32 @@ def set_block_timestamp_offset(context, offset): @when("we make a GetBlockTimeStampOffset call") def get_block_timestamp_offset(context): context.response = context.acl.get_timestamp_offset() + + +@when("we make a GetLedgerStateDelta call against round {round}") +def get_ledger_state_delta_call(context, round): + context.response = context.acl.get_ledger_state_delta( + round, response_format="msgpack" + ) + + +@when( + "we make a TransactionGroupLedgerStateDeltaForRoundResponse call for round {round}" +) +def get_transaction_group_ledger_state_deltas_for_round(context, round): + context.response = ( + context.acl.get_transaction_group_ledger_state_deltas_for_round( + round, response_format="msgpack" + ) + ) + + +@when( + 'we make a LedgerStateDeltaForTransactionGroupResponse call for ID "{id}"' +) +def get_ledger_state_delta_for_transaction_group(context, id): + context.response = ( + context.acl.get_ledger_state_delta_for_transaction_group( + id, response_format="msgpack" + ) + ) diff --git a/tests/unit.tags b/tests/unit.tags index b6b057ce..71ae9e27 100644 --- a/tests/unit.tags +++ b/tests/unit.tags @@ -25,11 +25,13 @@ @unit.responses.timestamp @unit.responses.unlimited_assets @unit.sourcemap +@unit.statedelta +@unit.stateproof.paths +@unit.stateproof.responses @unit.sync @unit.tealsign @unit.timestamp @unit.transactions @unit.transactions.keyreg @unit.transactions.payment -@unit.stateproof.paths -@unit.stateproof.responses +@unit.txngroupdeltas